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