10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 30Sigor@sysoev.ru * Copyright (C) Igor Sysoev 40Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 50Sigor@sysoev.ru */ 60Sigor@sysoev.ru 70Sigor@sysoev.ru #include <nxt_main.h> 80Sigor@sysoev.ru 90Sigor@sysoev.ru 100Sigor@sysoev.ru /* 110Sigor@sysoev.ru * sendfilev() has been introduced in Solaris 8 (7/01). 120Sigor@sysoev.ru * According to sendfilev(3EXT) it can write to: 130Sigor@sysoev.ru * 140Sigor@sysoev.ru * a file descriptor to a regular file or to a AF_NCA, AF_INET, or 150Sigor@sysoev.ru * AF_INET6 family type SOCK_STREAM socket that is open for writing. 160Sigor@sysoev.ru */ 170Sigor@sysoev.ru 180Sigor@sysoev.ru ssize_t nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t *c, nxt_buf_t *b, 190Sigor@sysoev.ru size_t limit); 200Sigor@sysoev.ru static size_t nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, 210Sigor@sysoev.ru int32_t *nsfv, nxt_bool_t *sync, size_t limit); 220Sigor@sysoev.ru 230Sigor@sysoev.ru 240Sigor@sysoev.ru ssize_t 250Sigor@sysoev.ru nxt_solaris_event_conn_io_sendfilev(nxt_event_conn_t *c, nxt_buf_t *b, 260Sigor@sysoev.ru size_t limit) 270Sigor@sysoev.ru { 280Sigor@sysoev.ru size_t sent; 290Sigor@sysoev.ru ssize_t n; 300Sigor@sysoev.ru int32_t nsfv; 310Sigor@sysoev.ru nxt_err_t err; 320Sigor@sysoev.ru nxt_off_t size; 330Sigor@sysoev.ru nxt_bool_t sync; 340Sigor@sysoev.ru sendfilevec_t sfv[NXT_IOBUF_MAX]; 350Sigor@sysoev.ru 360Sigor@sysoev.ru if (c->sendfile == 0) { 370Sigor@sysoev.ru /* AF_UNIX does not support sendfilev(). */ 380Sigor@sysoev.ru return nxt_event_conn_io_sendbuf(c, b, limit); 390Sigor@sysoev.ru } 400Sigor@sysoev.ru 410Sigor@sysoev.ru sync = 0; 420Sigor@sysoev.ru 430Sigor@sysoev.ru size = nxt_solaris_buf_coalesce(b, sfv, &nsfv, &sync, limit); 440Sigor@sysoev.ru 45*13Sigor@sysoev.ru nxt_debug(c->socket.task, "sendfilev(%d, %D)", c->socket.fd, nsfv); 460Sigor@sysoev.ru 470Sigor@sysoev.ru if (nsfv == 0 && sync) { 480Sigor@sysoev.ru return 0; 490Sigor@sysoev.ru } 500Sigor@sysoev.ru 510Sigor@sysoev.ru sent = 0; 520Sigor@sysoev.ru n = sendfilev(c->socket.fd, sfv, nsfv, &sent); 530Sigor@sysoev.ru 540Sigor@sysoev.ru err = (n == -1) ? nxt_errno : 0; 550Sigor@sysoev.ru 56*13Sigor@sysoev.ru nxt_debug(c->socket.task, "sendfilev(): %d sent:%uz", n, sent); 570Sigor@sysoev.ru 580Sigor@sysoev.ru if (n == -1) { 590Sigor@sysoev.ru switch (err) { 600Sigor@sysoev.ru 610Sigor@sysoev.ru case NXT_EAGAIN: 620Sigor@sysoev.ru c->socket.write_ready = 0; 630Sigor@sysoev.ru break; 640Sigor@sysoev.ru 650Sigor@sysoev.ru case NXT_EINTR: 660Sigor@sysoev.ru break; 670Sigor@sysoev.ru 680Sigor@sysoev.ru default: 690Sigor@sysoev.ru c->socket.error = err; 70*13Sigor@sysoev.ru nxt_log(c->socket.task, nxt_socket_error_level(err), 71*13Sigor@sysoev.ru "sendfilev(%d, %D) failed %E", c->socket.fd, nsfv, err); 720Sigor@sysoev.ru 730Sigor@sysoev.ru return NXT_ERROR; 740Sigor@sysoev.ru } 750Sigor@sysoev.ru 76*13Sigor@sysoev.ru nxt_debug(c->socket.task, "sendfilev() %E", err); 770Sigor@sysoev.ru 780Sigor@sysoev.ru return sent; 790Sigor@sysoev.ru } 800Sigor@sysoev.ru 810Sigor@sysoev.ru if ((nxt_off_t) sent < size) { 820Sigor@sysoev.ru c->socket.write_ready = 0; 830Sigor@sysoev.ru } 840Sigor@sysoev.ru 850Sigor@sysoev.ru return sent; 860Sigor@sysoev.ru } 870Sigor@sysoev.ru 880Sigor@sysoev.ru 890Sigor@sysoev.ru static size_t 900Sigor@sysoev.ru nxt_solaris_buf_coalesce(nxt_buf_t *b, sendfilevec_t *sfv, int32_t *nsfv, 910Sigor@sysoev.ru nxt_bool_t *sync, size_t limit) 920Sigor@sysoev.ru { 930Sigor@sysoev.ru size_t size, total; 940Sigor@sysoev.ru nxt_fd_t fd, last_fd; 950Sigor@sysoev.ru nxt_int_t i; 960Sigor@sysoev.ru nxt_off_t pos, last_pos; 970Sigor@sysoev.ru 980Sigor@sysoev.ru i = -1; 990Sigor@sysoev.ru last_fd = -1; 1000Sigor@sysoev.ru last_pos = 0; 1010Sigor@sysoev.ru total = 0; 1020Sigor@sysoev.ru 1030Sigor@sysoev.ru for (total = 0; b != NULL && total < limit; b = b->next) { 1040Sigor@sysoev.ru 1050Sigor@sysoev.ru if (nxt_buf_is_file(b)) { 1060Sigor@sysoev.ru 1070Sigor@sysoev.ru fd = b->file->fd; 1080Sigor@sysoev.ru pos = b->file_pos; 1090Sigor@sysoev.ru size = b->file_end - pos; 1100Sigor@sysoev.ru 1110Sigor@sysoev.ru if (size == 0) { 1120Sigor@sysoev.ru continue; 1130Sigor@sysoev.ru } 1140Sigor@sysoev.ru 1150Sigor@sysoev.ru if (total + size > limit) { 1160Sigor@sysoev.ru size = limit - total; 1170Sigor@sysoev.ru } 1180Sigor@sysoev.ru 1190Sigor@sysoev.ru } else if (nxt_buf_is_mem(b)) { 1200Sigor@sysoev.ru 1210Sigor@sysoev.ru fd = SFV_FD_SELF; 1220Sigor@sysoev.ru pos = (uintptr_t) b->mem.pos; 1230Sigor@sysoev.ru size = b->mem.free - b->mem.pos; 1240Sigor@sysoev.ru 1250Sigor@sysoev.ru if (size == 0) { 1260Sigor@sysoev.ru continue; 1270Sigor@sysoev.ru } 1280Sigor@sysoev.ru 1290Sigor@sysoev.ru if (total + size > limit) { 1300Sigor@sysoev.ru size = limit - total; 1310Sigor@sysoev.ru } 1320Sigor@sysoev.ru 1330Sigor@sysoev.ru } else { 1340Sigor@sysoev.ru *sync = 1; 1350Sigor@sysoev.ru continue; 1360Sigor@sysoev.ru } 1370Sigor@sysoev.ru 1380Sigor@sysoev.ru if (size == 0) { 1390Sigor@sysoev.ru break; 1400Sigor@sysoev.ru } 1410Sigor@sysoev.ru 1420Sigor@sysoev.ru if (fd != last_fd || pos != last_pos) { 1430Sigor@sysoev.ru 1440Sigor@sysoev.ru if (++i >= NXT_IOBUF_MAX) { 1450Sigor@sysoev.ru goto done; 1460Sigor@sysoev.ru } 1470Sigor@sysoev.ru 1480Sigor@sysoev.ru sfv[i].sfv_fd = fd; 1490Sigor@sysoev.ru sfv[i].sfv_flag = 0; 1500Sigor@sysoev.ru sfv[i].sfv_off = pos; 1510Sigor@sysoev.ru sfv[i].sfv_len = size; 1520Sigor@sysoev.ru 1530Sigor@sysoev.ru } else { 1540Sigor@sysoev.ru sfv[i].sfv_len += size; 1550Sigor@sysoev.ru } 1560Sigor@sysoev.ru 1570Sigor@sysoev.ru total += size; 1580Sigor@sysoev.ru last_pos = pos + size; 1590Sigor@sysoev.ru last_fd = fd; 1600Sigor@sysoev.ru } 1610Sigor@sysoev.ru 1620Sigor@sysoev.ru i++; 1630Sigor@sysoev.ru 1640Sigor@sysoev.ru done: 1650Sigor@sysoev.ru 1660Sigor@sysoev.ru *nsfv = i; 1670Sigor@sysoev.ru 1680Sigor@sysoev.ru return total; 1690Sigor@sysoev.ru } 170