1 2/* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7#include <nxt_main.h> 8 9 10/* sendfile() has been introduced in MacOSX 10.5 (Leopard) */ 11 12#ifdef NXT_TEST_BUILD_MACOSX_SENDFILE 13 14ssize_t nxt_macosx_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, 15 size_t limit); 16 17static int nxt_sys_sendfile(int fd, int s, off_t offset, off_t *len, 18 struct sf_hdtr *hdtr, int flags) 19{ 20 return -1; 21} 22 23#else 24#define nxt_sys_sendfile sendfile 25#endif 26 27 28ssize_t
| 1 2/* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7#include <nxt_main.h> 8 9 10/* sendfile() has been introduced in MacOSX 10.5 (Leopard) */ 11 12#ifdef NXT_TEST_BUILD_MACOSX_SENDFILE 13 14ssize_t nxt_macosx_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, 15 size_t limit); 16 17static int nxt_sys_sendfile(int fd, int s, off_t offset, off_t *len, 18 struct sf_hdtr *hdtr, int flags) 19{ 20 return -1; 21} 22 23#else 24#define nxt_sys_sendfile sendfile 25#endif 26 27 28ssize_t
|
31{ 32 size_t hd_size, file_size; 33 ssize_t n; 34 nxt_buf_t *fb; 35 nxt_err_t err; 36 nxt_off_t sent; 37 nxt_uint_t nhd, ntr; 38 struct iovec hd[NXT_IOBUF_MAX], tr[NXT_IOBUF_MAX]; 39 struct sf_hdtr hdtr, *ht; 40 nxt_sendbuf_coalesce_t sb; 41 42 sb.buf = b; 43 sb.iobuf = hd; 44 sb.nmax = NXT_IOBUF_MAX; 45 sb.sync = 0; 46 sb.size = 0; 47 sb.limit = limit; 48 49 nhd = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); 50 51 if (nhd == 0 && sb.sync) { 52 return 0; 53 } 54 55 if (sb.buf == NULL || !nxt_buf_is_file(sb.buf)) { 56 return nxt_event_conn_io_writev(c, hd, nhd); 57 } 58 59 hd_size = sb.size; 60 fb = sb.buf; 61 62 file_size = nxt_sendbuf_file_coalesce(&sb); 63 64 if (file_size == 0) { 65 return nxt_event_conn_io_writev(c, hd, nhd); 66 } 67 68 sb.iobuf = tr; 69 70 ntr = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); 71 72 /* 73 * Disposal of surplus kernel operations if there are no headers 74 * and trailers. Besides sendfile() returns EINVAL if a sf_hdtr's 75 * count is 0, but corresponding pointer is not NULL. 76 */ 77 78 nxt_memzero(&hdtr, sizeof(struct sf_hdtr)); 79 ht = NULL; 80 81 if (nhd != 0) { 82 ht = &hdtr; 83 hdtr.headers = hd; 84 hdtr.hdr_cnt = nhd; 85 } 86 87 if (ntr != 0) { 88 ht = &hdtr; 89 hdtr.trailers = tr; 90 hdtr.trl_cnt = ntr; 91 } 92 93 /* 94 * MacOSX has the same bug as old FreeBSD (http://bugs.freebsd.org/33771). 95 * However this bug has never been fixed and instead of this it has been 96 * documented as a feature in MacOSX 10.7 (Lion) sendfile(2): 97 * 98 * When a header or trailer is specified, the value of len argument 99 * indicates the maximum number of bytes in the header and/or file 100 * to be sent. It does not control the trailer; if a trailer exists, 101 * all of it will be sent. 102 */ 103 sent = hd_size + file_size; 104 105 nxt_log_debug(c->socket.log, 106 "sendfile(%FD, %d, @%O, %O) hd:%ui tr:%ui hs:%uz", 107 fb->file->fd, c->socket.fd, fb->file_pos, sent, 108 nhd, ntr, hd_size); 109 110 n = nxt_sys_sendfile(fb->file->fd, c->socket.fd, 111 fb->file_pos, &sent, ht, 0); 112 113 err = (n == -1) ? nxt_errno : 0; 114 115 nxt_debug(c->socket.task, "sendfile(): %d sent:%O", n, sent); 116 117 if (n == -1) { 118 switch (err) { 119 120 case NXT_EAGAIN: 121 c->socket.write_ready = 0; 122 break; 123 124 case NXT_EINTR: 125 break; 126 127 default: 128 c->socket.error = err; 129 nxt_log(c->socket.task, nxt_socket_error_level(err), 130 "sendfile(%FD, %d, %O, %O) failed %E \"%FN\" hd:%ui tr:%ui", 131 fb->file->fd, c->socket.fd, fb->file_pos, sent, err, 132 fb->file->name, nhd, ntr); 133 134 return NXT_ERROR; 135 } 136 137 nxt_debug(c->socket.task, "sendfile() %E", err); 138 139 return sent; 140 } 141 142 if (sent == 0) { 143 nxt_log(c->socket.task, NXT_LOG_ERR, 144 "file \"%FN\" was truncated while sendfile()", fb->file->name); 145 146 return NXT_ERROR; 147 } 148 149 if (sent < (nxt_off_t) sb.size) { 150 c->socket.write_ready = 0; 151 } 152 153 return sent; 154}
| 30{ 31 size_t hd_size, file_size; 32 ssize_t n; 33 nxt_buf_t *fb; 34 nxt_err_t err; 35 nxt_off_t sent; 36 nxt_uint_t nhd, ntr; 37 struct iovec hd[NXT_IOBUF_MAX], tr[NXT_IOBUF_MAX]; 38 struct sf_hdtr hdtr, *ht; 39 nxt_sendbuf_coalesce_t sb; 40 41 sb.buf = b; 42 sb.iobuf = hd; 43 sb.nmax = NXT_IOBUF_MAX; 44 sb.sync = 0; 45 sb.size = 0; 46 sb.limit = limit; 47 48 nhd = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); 49 50 if (nhd == 0 && sb.sync) { 51 return 0; 52 } 53 54 if (sb.buf == NULL || !nxt_buf_is_file(sb.buf)) { 55 return nxt_event_conn_io_writev(c, hd, nhd); 56 } 57 58 hd_size = sb.size; 59 fb = sb.buf; 60 61 file_size = nxt_sendbuf_file_coalesce(&sb); 62 63 if (file_size == 0) { 64 return nxt_event_conn_io_writev(c, hd, nhd); 65 } 66 67 sb.iobuf = tr; 68 69 ntr = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); 70 71 /* 72 * Disposal of surplus kernel operations if there are no headers 73 * and trailers. Besides sendfile() returns EINVAL if a sf_hdtr's 74 * count is 0, but corresponding pointer is not NULL. 75 */ 76 77 nxt_memzero(&hdtr, sizeof(struct sf_hdtr)); 78 ht = NULL; 79 80 if (nhd != 0) { 81 ht = &hdtr; 82 hdtr.headers = hd; 83 hdtr.hdr_cnt = nhd; 84 } 85 86 if (ntr != 0) { 87 ht = &hdtr; 88 hdtr.trailers = tr; 89 hdtr.trl_cnt = ntr; 90 } 91 92 /* 93 * MacOSX has the same bug as old FreeBSD (http://bugs.freebsd.org/33771). 94 * However this bug has never been fixed and instead of this it has been 95 * documented as a feature in MacOSX 10.7 (Lion) sendfile(2): 96 * 97 * When a header or trailer is specified, the value of len argument 98 * indicates the maximum number of bytes in the header and/or file 99 * to be sent. It does not control the trailer; if a trailer exists, 100 * all of it will be sent. 101 */ 102 sent = hd_size + file_size; 103 104 nxt_log_debug(c->socket.log, 105 "sendfile(%FD, %d, @%O, %O) hd:%ui tr:%ui hs:%uz", 106 fb->file->fd, c->socket.fd, fb->file_pos, sent, 107 nhd, ntr, hd_size); 108 109 n = nxt_sys_sendfile(fb->file->fd, c->socket.fd, 110 fb->file_pos, &sent, ht, 0); 111 112 err = (n == -1) ? nxt_errno : 0; 113 114 nxt_debug(c->socket.task, "sendfile(): %d sent:%O", n, sent); 115 116 if (n == -1) { 117 switch (err) { 118 119 case NXT_EAGAIN: 120 c->socket.write_ready = 0; 121 break; 122 123 case NXT_EINTR: 124 break; 125 126 default: 127 c->socket.error = err; 128 nxt_log(c->socket.task, nxt_socket_error_level(err), 129 "sendfile(%FD, %d, %O, %O) failed %E \"%FN\" hd:%ui tr:%ui", 130 fb->file->fd, c->socket.fd, fb->file_pos, sent, err, 131 fb->file->name, nhd, ntr); 132 133 return NXT_ERROR; 134 } 135 136 nxt_debug(c->socket.task, "sendfile() %E", err); 137 138 return sent; 139 } 140 141 if (sent == 0) { 142 nxt_log(c->socket.task, NXT_LOG_ERR, 143 "file \"%FN\" was truncated while sendfile()", fb->file->name); 144 145 return NXT_ERROR; 146 } 147 148 if (sent < (nxt_off_t) sb.size) { 149 c->socket.write_ready = 0; 150 } 151 152 return sent; 153}
|