xref: /unit/src/nxt_macosx_sendfile.c (revision 62:5e1efcc7b740)
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 /* sendfile() has been introduced in MacOSX 10.5 (Leopard) */
110Sigor@sysoev.ru 
120Sigor@sysoev.ru #ifdef NXT_TEST_BUILD_MACOSX_SENDFILE
130Sigor@sysoev.ru 
140Sigor@sysoev.ru ssize_t nxt_macosx_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b,
150Sigor@sysoev.ru     size_t limit);
160Sigor@sysoev.ru 
nxt_sys_sendfile(int fd,int s,off_t offset,off_t * len,struct sf_hdtr * hdtr,int flags)170Sigor@sysoev.ru static int nxt_sys_sendfile(int fd, int s, off_t offset, off_t *len,
180Sigor@sysoev.ru     struct sf_hdtr *hdtr, int flags)
190Sigor@sysoev.ru {
200Sigor@sysoev.ru     return -1;
210Sigor@sysoev.ru }
220Sigor@sysoev.ru 
230Sigor@sysoev.ru #else
240Sigor@sysoev.ru #define nxt_sys_sendfile  sendfile
250Sigor@sysoev.ru #endif
260Sigor@sysoev.ru 
270Sigor@sysoev.ru 
280Sigor@sysoev.ru ssize_t
nxt_macosx_event_conn_io_sendfile(nxt_conn_t * c,nxt_buf_t * b,size_t limit)29*62Sigor@sysoev.ru nxt_macosx_event_conn_io_sendfile(nxt_conn_t *c, nxt_buf_t *b, size_t limit)
300Sigor@sysoev.ru {
310Sigor@sysoev.ru     size_t                  hd_size, file_size;
320Sigor@sysoev.ru     ssize_t                 n;
330Sigor@sysoev.ru     nxt_buf_t               *fb;
340Sigor@sysoev.ru     nxt_err_t               err;
350Sigor@sysoev.ru     nxt_off_t               sent;
360Sigor@sysoev.ru     nxt_uint_t              nhd, ntr;
370Sigor@sysoev.ru     struct iovec            hd[NXT_IOBUF_MAX], tr[NXT_IOBUF_MAX];
380Sigor@sysoev.ru     struct sf_hdtr          hdtr, *ht;
390Sigor@sysoev.ru     nxt_sendbuf_coalesce_t  sb;
400Sigor@sysoev.ru 
410Sigor@sysoev.ru     sb.buf = b;
420Sigor@sysoev.ru     sb.iobuf = hd;
430Sigor@sysoev.ru     sb.nmax = NXT_IOBUF_MAX;
440Sigor@sysoev.ru     sb.sync = 0;
450Sigor@sysoev.ru     sb.size = 0;
460Sigor@sysoev.ru     sb.limit = limit;
470Sigor@sysoev.ru 
481Sigor@sysoev.ru     nhd = nxt_sendbuf_mem_coalesce(c->socket.task, &sb);
490Sigor@sysoev.ru 
500Sigor@sysoev.ru     if (nhd == 0 && sb.sync) {
510Sigor@sysoev.ru         return 0;
520Sigor@sysoev.ru     }
530Sigor@sysoev.ru 
540Sigor@sysoev.ru     if (sb.buf == NULL || !nxt_buf_is_file(sb.buf)) {
550Sigor@sysoev.ru         return nxt_event_conn_io_writev(c, hd, nhd);
560Sigor@sysoev.ru     }
570Sigor@sysoev.ru 
580Sigor@sysoev.ru     hd_size = sb.size;
590Sigor@sysoev.ru     fb = sb.buf;
600Sigor@sysoev.ru 
610Sigor@sysoev.ru     file_size = nxt_sendbuf_file_coalesce(&sb);
620Sigor@sysoev.ru 
630Sigor@sysoev.ru     if (file_size == 0) {
640Sigor@sysoev.ru         return nxt_event_conn_io_writev(c, hd, nhd);
650Sigor@sysoev.ru     }
660Sigor@sysoev.ru 
670Sigor@sysoev.ru     sb.iobuf = tr;
680Sigor@sysoev.ru 
691Sigor@sysoev.ru     ntr = nxt_sendbuf_mem_coalesce(c->socket.task, &sb);
700Sigor@sysoev.ru 
710Sigor@sysoev.ru     /*
720Sigor@sysoev.ru      * Disposal of surplus kernel operations if there are no headers
730Sigor@sysoev.ru      * and trailers.  Besides sendfile() returns EINVAL if a sf_hdtr's
740Sigor@sysoev.ru      * count is 0, but corresponding pointer is not NULL.
750Sigor@sysoev.ru      */
760Sigor@sysoev.ru 
770Sigor@sysoev.ru     nxt_memzero(&hdtr, sizeof(struct sf_hdtr));
780Sigor@sysoev.ru     ht = NULL;
790Sigor@sysoev.ru 
800Sigor@sysoev.ru     if (nhd != 0) {
810Sigor@sysoev.ru         ht = &hdtr;
820Sigor@sysoev.ru         hdtr.headers = hd;
830Sigor@sysoev.ru         hdtr.hdr_cnt = nhd;
840Sigor@sysoev.ru     }
850Sigor@sysoev.ru 
860Sigor@sysoev.ru     if (ntr != 0) {
870Sigor@sysoev.ru         ht = &hdtr;
880Sigor@sysoev.ru         hdtr.trailers = tr;
890Sigor@sysoev.ru         hdtr.trl_cnt = ntr;
900Sigor@sysoev.ru     }
910Sigor@sysoev.ru 
920Sigor@sysoev.ru     /*
930Sigor@sysoev.ru      * MacOSX has the same bug as old FreeBSD (http://bugs.freebsd.org/33771).
940Sigor@sysoev.ru      * However this bug has never been fixed and instead of this it has been
950Sigor@sysoev.ru      * documented as a feature in MacOSX 10.7 (Lion) sendfile(2):
960Sigor@sysoev.ru      *
970Sigor@sysoev.ru      *   When a header or trailer is specified, the value of len argument
980Sigor@sysoev.ru      *   indicates the maximum number of bytes in the header and/or file
990Sigor@sysoev.ru      *   to be sent.  It does not control the trailer; if a trailer exists,
1000Sigor@sysoev.ru      *   all of it will be sent.
1010Sigor@sysoev.ru      */
1020Sigor@sysoev.ru     sent = hd_size + file_size;
1030Sigor@sysoev.ru 
1040Sigor@sysoev.ru     nxt_log_debug(c->socket.log,
1050Sigor@sysoev.ru                   "sendfile(%FD, %d, @%O, %O) hd:%ui tr:%ui hs:%uz",
1060Sigor@sysoev.ru                   fb->file->fd, c->socket.fd, fb->file_pos, sent,
1070Sigor@sysoev.ru                   nhd, ntr, hd_size);
1080Sigor@sysoev.ru 
1090Sigor@sysoev.ru     n = nxt_sys_sendfile(fb->file->fd, c->socket.fd,
1100Sigor@sysoev.ru                          fb->file_pos, &sent, ht, 0);
1110Sigor@sysoev.ru 
1120Sigor@sysoev.ru     err = (n == -1) ? nxt_errno : 0;
1130Sigor@sysoev.ru 
11413Sigor@sysoev.ru     nxt_debug(c->socket.task, "sendfile(): %d sent:%O", n, sent);
1150Sigor@sysoev.ru 
1160Sigor@sysoev.ru     if (n == -1) {
1170Sigor@sysoev.ru         switch (err) {
1180Sigor@sysoev.ru 
1190Sigor@sysoev.ru         case NXT_EAGAIN:
1200Sigor@sysoev.ru             c->socket.write_ready = 0;
1210Sigor@sysoev.ru             break;
1220Sigor@sysoev.ru 
1230Sigor@sysoev.ru         case NXT_EINTR:
1240Sigor@sysoev.ru             break;
1250Sigor@sysoev.ru 
1260Sigor@sysoev.ru         default:
1270Sigor@sysoev.ru             c->socket.error = err;
12813Sigor@sysoev.ru             nxt_log(c->socket.task, nxt_socket_error_level(err),
12913Sigor@sysoev.ru                     "sendfile(%FD, %d, %O, %O) failed %E \"%FN\" hd:%ui tr:%ui",
13013Sigor@sysoev.ru                     fb->file->fd, c->socket.fd, fb->file_pos, sent, err,
13113Sigor@sysoev.ru                     fb->file->name, nhd, ntr);
1320Sigor@sysoev.ru 
1330Sigor@sysoev.ru             return NXT_ERROR;
1340Sigor@sysoev.ru         }
1350Sigor@sysoev.ru 
13613Sigor@sysoev.ru         nxt_debug(c->socket.task, "sendfile() %E", err);
1370Sigor@sysoev.ru 
1380Sigor@sysoev.ru         return sent;
1390Sigor@sysoev.ru     }
1400Sigor@sysoev.ru 
1410Sigor@sysoev.ru     if (sent == 0) {
14213Sigor@sysoev.ru         nxt_log(c->socket.task, NXT_LOG_ERR,
14313Sigor@sysoev.ru                 "file \"%FN\" was truncated while sendfile()", fb->file->name);
1440Sigor@sysoev.ru 
1450Sigor@sysoev.ru         return NXT_ERROR;
1460Sigor@sysoev.ru     }
1470Sigor@sysoev.ru 
1480Sigor@sysoev.ru     if (sent < (nxt_off_t) sb.size) {
1490Sigor@sysoev.ru         c->socket.write_ready = 0;
1500Sigor@sysoev.ru     }
1510Sigor@sysoev.ru 
1520Sigor@sysoev.ru     return sent;
1530Sigor@sysoev.ru }
154