1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 9 10 /* 11 * sendfile() has been introduced in Linux 2.2. 12 * It supported 32-bit offsets only. 13 * 14 * Linux 2.4.21 has introduced sendfile64(). However, even on 64-bit 15 * platforms it returns EINVAL if the count argument is more than 2G-1 bytes. 16 * In Linux 2.6.17 sendfile() has been internally changed to splice() 17 * and this limitation has gone. 18 */ 19 20 #ifdef NXT_TEST_BUILD_LINUX_SENDFILE 21 22 #define MSG_NOSIGNAL 0x4000 23 #define MSG_MORE 0x8000 24 25 ssize_t nxt_linux_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, 26 size_t limit); 27 28 static ssize_t nxt_sys_sendfile(int out_fd, int in_fd, off_t *offset, 29 size_t count) 30 { 31 return -1; 32 } 33 34 #else 35 #define nxt_sys_sendfile sendfile 36 #endif 37 38 39 static ssize_t nxt_linux_send(nxt_event_conn_t *c, void *buf, size_t size, 40 nxt_uint_t flags); 41 static ssize_t nxt_linux_sendmsg(nxt_event_conn_t *c, 42 nxt_sendbuf_coalesce_t *sb, nxt_uint_t niov, nxt_uint_t flags); 43 44 45 ssize_t 46 nxt_linux_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, 47 size_t limit) 48 { 49 size_t size; 50 ssize_t n; 51 nxt_buf_t *fb; 52 nxt_err_t err; 53 nxt_off_t offset; 54 nxt_uint_t niov, flags; 55 struct iovec iov[NXT_IOBUF_MAX]; 56 nxt_sendbuf_coalesce_t sb; 57 58 sb.buf = b; 59 sb.iobuf = iov; 60 sb.nmax = NXT_IOBUF_MAX; 61 sb.sync = 0; 62 sb.size = 0; 63 sb.limit = limit; 64 65 niov = nxt_sendbuf_mem_coalesce(&sb); 66 67 if (niov == 0 && sb.sync) { 68 return 0; 69 } 70 71 fb = (sb.buf != NULL && nxt_buf_is_file(sb.buf)) ? sb.buf : NULL; 72 73 if (niov != 0) { 74 75 flags = MSG_NOSIGNAL; 76 77 if (fb != NULL) { 78 /* 79 * The Linux-specific MSG_MORE flag is cheaper 80 * than additional setsockopt(TCP_CORK) syscall. 81 */ 82 flags |= MSG_MORE; 83 } 84 85 if (niov == 1) { 86 /* 87 * Disposal of surplus kernel msghdr 88 * and iovec copy-in operations. 89 */ 90 return nxt_linux_send(c, iov->iov_base, iov->iov_len, flags); 91 } 92 93 return nxt_linux_sendmsg(c, &sb, niov, flags); 94 } 95 96 size = nxt_sendbuf_file_coalesce(&sb); 97 98 nxt_log_debug(c->socket.log, "sendfile(%d, %FD, @%O, %uz)", 99 c->socket.fd, fb->file->fd, fb->file_pos, size); 100 101 offset = fb->file_pos; 102 103 n = nxt_sys_sendfile(c->socket.fd, fb->file->fd, &offset, size); 104 105 err = (n == -1) ? nxt_errno : 0; 106 107 nxt_log_debug(c->socket.log, "sendfile(): %d", n); 108 109 if (n == -1) { 110 switch (err) { 111 112 case NXT_EAGAIN: 113 c->socket.write_ready = 0; 114 break; 115 116 case NXT_EINTR: 117 break; 118 119 default: 120 c->socket.error = err; 121 nxt_log_error(nxt_socket_error_level(err, c->socket.log_error), 122 c->socket.log, 123 "sendfile(%d, %FD, %O, %uz) failed %E \"%FN\"", 124 c->socket.fd, fb->file->fd, fb->file_pos, size, 125 err, fb->file->name); 126 127 return NXT_ERROR; 128 } 129 130 nxt_log_debug(c->socket.log, "sendfile() %E", err); 131 132 return 0; 133 } 134 135 if (n < (ssize_t) size) { 136 c->socket.write_ready = 0; 137 } 138 139 return n; 140 } 141 142 143 static ssize_t 144 nxt_linux_send(nxt_event_conn_t *c, void *buf, size_t size, nxt_uint_t flags) 145 { 146 ssize_t n; 147 nxt_err_t err; 148 149 n = send(c->socket.fd, buf, size, flags); 150 151 err = (n == -1) ? nxt_errno : 0; 152 153 nxt_log_debug(c->socket.log, "send(%d, %p, %uz, 0x%uXi): %z", 154 c->socket.fd, buf, size, flags, n); 155 156 if (n == -1) { 157 switch (err) { 158 159 case NXT_EAGAIN: 160 c->socket.write_ready = 0; 161 break; 162 163 case NXT_EINTR: 164 break; 165 166 default: 167 c->socket.error = err; 168 nxt_log_error(nxt_socket_error_level(err, c->socket.log_error), 169 c->socket.log, "send(%d, %p, %uz, 0x%uXi) failed %E", 170 c->socket.fd, buf, size, flags, err); 171 172 return NXT_ERROR; 173 } 174 175 nxt_log_debug(c->socket.log, "send() %E", err); 176 177 return 0; 178 } 179 180 if (n < (ssize_t) size) { 181 c->socket.write_ready = 0; 182 } 183 184 return n; 185 } 186 187 188 static ssize_t 189 nxt_linux_sendmsg(nxt_event_conn_t *c, nxt_sendbuf_coalesce_t *sb, 190 nxt_uint_t niov, nxt_uint_t flags) 191 { 192 ssize_t n; 193 nxt_err_t err; 194 struct msghdr msg; 195 196 msg.msg_name = NULL; 197 msg.msg_namelen = 0; 198 msg.msg_iov = sb->iobuf; 199 msg.msg_iovlen = niov; 200 msg.msg_control = NULL; 201 msg.msg_controllen = 0; 202 msg.msg_flags = 0; 203 204 n = sendmsg(c->socket.fd, &msg, flags); 205 206 err = (n == -1) ? nxt_errno : 0; 207 208 nxt_log_debug(c->socket.log, "sendmsg(%d, %ui, 0x%uXi): %d", 209 c->socket.fd, niov, flags, n); 210 211 if (n == -1) { 212 switch (err) { 213 214 case NXT_EAGAIN: 215 c->socket.write_ready = 0; 216 break; 217 218 case NXT_EINTR: 219 break; 220 221 default: 222 c->socket.error = err; 223 nxt_log_error(nxt_socket_error_level(err, c->socket.log_error), 224 c->socket.log, "sendmsg(%d, %ui, 0x%uXi) failed %E", 225 c->socket.fd, niov, flags, err); 226 227 return NXT_ERROR; 228 } 229 230 nxt_log_debug(c->socket.log, "sendmsg() %E", err); 231 232 return 0; 233 } 234 235 if (n < (ssize_t) sb->size) { 236 c->socket.write_ready = 0; 237 } 238 239 return n; 240 } 241