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 * sendfile() has been introduced in FreeBSD 3.1, 120Sigor@sysoev.ru * however, early implementation had various bugs. 130Sigor@sysoev.ru * This code supports FreeBSD 5.0 implementation. 140Sigor@sysoev.ru */ 150Sigor@sysoev.ru 160Sigor@sysoev.ru #ifdef NXT_TEST_BUILD_FREEBSD_SENDFILE 170Sigor@sysoev.ru 180Sigor@sysoev.ru ssize_t nxt_freebsd_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, 190Sigor@sysoev.ru size_t limit); 200Sigor@sysoev.ru 210Sigor@sysoev.ru static int nxt_sys_sendfile(int fd, int s, off_t offset, size_t nbytes, 220Sigor@sysoev.ru struct sf_hdtr *hdtr, off_t *sbytes, int flags) 230Sigor@sysoev.ru { 240Sigor@sysoev.ru return -1; 250Sigor@sysoev.ru } 260Sigor@sysoev.ru 270Sigor@sysoev.ru #else 280Sigor@sysoev.ru #define nxt_sys_sendfile sendfile 290Sigor@sysoev.ru #endif 300Sigor@sysoev.ru 310Sigor@sysoev.ru 320Sigor@sysoev.ru ssize_t 330Sigor@sysoev.ru nxt_freebsd_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, 340Sigor@sysoev.ru size_t limit) 350Sigor@sysoev.ru { 360Sigor@sysoev.ru size_t file_size; 370Sigor@sysoev.ru ssize_t n; 380Sigor@sysoev.ru nxt_buf_t *fb; 390Sigor@sysoev.ru nxt_err_t err; 400Sigor@sysoev.ru nxt_off_t sent; 410Sigor@sysoev.ru nxt_uint_t nhd, ntr; 420Sigor@sysoev.ru struct iovec hd[NXT_IOBUF_MAX], tr[NXT_IOBUF_MAX]; 430Sigor@sysoev.ru struct sf_hdtr hdtr, *ht; 440Sigor@sysoev.ru nxt_sendbuf_coalesce_t sb; 450Sigor@sysoev.ru 460Sigor@sysoev.ru sb.buf = b; 470Sigor@sysoev.ru sb.iobuf = hd; 480Sigor@sysoev.ru sb.nmax = NXT_IOBUF_MAX; 490Sigor@sysoev.ru sb.sync = 0; 500Sigor@sysoev.ru sb.size = 0; 510Sigor@sysoev.ru sb.limit = limit; 520Sigor@sysoev.ru 531Sigor@sysoev.ru nhd = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); 540Sigor@sysoev.ru 550Sigor@sysoev.ru if (nhd == 0 && sb.sync) { 560Sigor@sysoev.ru return 0; 570Sigor@sysoev.ru } 580Sigor@sysoev.ru 590Sigor@sysoev.ru if (sb.buf == NULL || !nxt_buf_is_file(sb.buf)) { 600Sigor@sysoev.ru return nxt_event_conn_io_writev(c, hd, nhd); 610Sigor@sysoev.ru } 620Sigor@sysoev.ru 630Sigor@sysoev.ru fb = sb.buf; 640Sigor@sysoev.ru 650Sigor@sysoev.ru file_size = nxt_sendbuf_file_coalesce(&sb); 660Sigor@sysoev.ru 670Sigor@sysoev.ru if (file_size == 0) { 680Sigor@sysoev.ru return nxt_event_conn_io_writev(c, hd, nhd); 690Sigor@sysoev.ru } 700Sigor@sysoev.ru 710Sigor@sysoev.ru sb.iobuf = tr; 720Sigor@sysoev.ru 731Sigor@sysoev.ru ntr = nxt_sendbuf_mem_coalesce(c->socket.task, &sb); 740Sigor@sysoev.ru 750Sigor@sysoev.ru /* 760Sigor@sysoev.ru * Disposal of surplus kernel operations 770Sigor@sysoev.ru * if there are no headers or trailers. 780Sigor@sysoev.ru */ 790Sigor@sysoev.ru 800Sigor@sysoev.ru ht = NULL; 810Sigor@sysoev.ru nxt_memzero(&hdtr, sizeof(struct sf_hdtr)); 820Sigor@sysoev.ru 830Sigor@sysoev.ru if (nhd != 0) { 840Sigor@sysoev.ru ht = &hdtr; 850Sigor@sysoev.ru hdtr.headers = hd; 860Sigor@sysoev.ru hdtr.hdr_cnt = nhd; 870Sigor@sysoev.ru } 880Sigor@sysoev.ru 890Sigor@sysoev.ru if (ntr != 0) { 900Sigor@sysoev.ru ht = &hdtr; 910Sigor@sysoev.ru hdtr.trailers = tr; 920Sigor@sysoev.ru hdtr.trl_cnt = ntr; 930Sigor@sysoev.ru } 940Sigor@sysoev.ru 95*13Sigor@sysoev.ru nxt_debug(c->socket.task, "sendfile(%FD, %d, @%O, %uz) hd:%ui tr:%ui", 960Sigor@sysoev.ru fb->file->fd, c->socket.fd, fb->file_pos, file_size, 970Sigor@sysoev.ru nhd, ntr); 980Sigor@sysoev.ru 990Sigor@sysoev.ru sent = 0; 1000Sigor@sysoev.ru n = nxt_sys_sendfile(fb->file->fd, c->socket.fd, fb->file_pos, 1010Sigor@sysoev.ru file_size, ht, &sent, 0); 1020Sigor@sysoev.ru 1030Sigor@sysoev.ru err = (n == -1) ? nxt_errno : 0; 1040Sigor@sysoev.ru 105*13Sigor@sysoev.ru nxt_debug(c->socket.task, "sendfile(): %d sent:%O", n, sent); 1060Sigor@sysoev.ru 1070Sigor@sysoev.ru if (n == -1) { 1080Sigor@sysoev.ru switch (err) { 1090Sigor@sysoev.ru 1100Sigor@sysoev.ru case NXT_EAGAIN: 1110Sigor@sysoev.ru c->socket.write_ready = 0; 1120Sigor@sysoev.ru break; 1130Sigor@sysoev.ru 1140Sigor@sysoev.ru case NXT_EINTR: 1150Sigor@sysoev.ru break; 1160Sigor@sysoev.ru 1170Sigor@sysoev.ru default: 1180Sigor@sysoev.ru c->socket.error = err; 119*13Sigor@sysoev.ru nxt_log(c->socket.task, nxt_socket_error_level(err), 120*13Sigor@sysoev.ru "sendfile(%FD, %d, %O, %uz) failed %E \"%FN\" hd:%ui tr:%ui", 121*13Sigor@sysoev.ru fb->file->fd, c->socket.fd, fb->file_pos, file_size, err, 122*13Sigor@sysoev.ru fb->file->name, nhd, ntr); 1230Sigor@sysoev.ru 1240Sigor@sysoev.ru return NXT_ERROR; 1250Sigor@sysoev.ru } 1260Sigor@sysoev.ru 127*13Sigor@sysoev.ru nxt_debug(c->socket.task, "sendfile() %E", err); 1280Sigor@sysoev.ru 1290Sigor@sysoev.ru return sent; 1300Sigor@sysoev.ru 1310Sigor@sysoev.ru } else if (sent == 0) { 132*13Sigor@sysoev.ru nxt_log(c->socket.task, NXT_LOG_ERR, 133*13Sigor@sysoev.ru "file \"%FN\" was truncated while sendfile()", fb->file->name); 1340Sigor@sysoev.ru 1350Sigor@sysoev.ru return NXT_ERROR; 1360Sigor@sysoev.ru } 1370Sigor@sysoev.ru 1380Sigor@sysoev.ru if (sent < (nxt_off_t) sb.size) { 1390Sigor@sysoev.ru c->socket.write_ready = 0; 1400Sigor@sysoev.ru } 1410Sigor@sysoev.ru 1420Sigor@sysoev.ru return sent; 1430Sigor@sysoev.ru } 144