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 FreeBSD 3.1, 12 * however, early implementation had various bugs. 13 * This code supports FreeBSD 5.0 implementation. 14 */ 15 16 #ifdef NXT_TEST_BUILD_FREEBSD_SENDFILE 17 18 ssize_t nxt_freebsd_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, 19 size_t limit); 20 21 static int nxt_sys_sendfile(int fd, int s, off_t offset, size_t nbytes, 22 struct sf_hdtr *hdtr, off_t *sbytes, int flags) 23 { 24 return -1; 25 } 26 27 #else 28 #define nxt_sys_sendfile sendfile 29 #endif 30 31 32 ssize_t 33 nxt_freebsd_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, 34 size_t limit) 35 { 36 size_t file_size; 37 ssize_t n; 38 nxt_buf_t *fb; 39 nxt_err_t err; 40 nxt_off_t sent; 41 nxt_uint_t nhd, ntr; 42 struct iovec hd[NXT_IOBUF_MAX], tr[NXT_IOBUF_MAX]; 43 struct sf_hdtr hdtr, *ht; 44 nxt_sendbuf_coalesce_t sb; 45 46 sb.buf = b; 47 sb.iobuf = hd; 48 sb.nmax = NXT_IOBUF_MAX; 49 sb.sync = 0; 50 sb.size = 0; 51 sb.limit = limit; 52 53 nhd = nxt_sendbuf_mem_coalesce(&sb); 54 55 if (nhd == 0 && sb.sync) { 56 return 0; 57 } 58 59 if (sb.buf == NULL || !nxt_buf_is_file(sb.buf)) { 60 return nxt_event_conn_io_writev(c, hd, nhd); 61 } 62 63 fb = sb.buf; 64 65 file_size = nxt_sendbuf_file_coalesce(&sb); 66 67 if (file_size == 0) { 68 return nxt_event_conn_io_writev(c, hd, nhd); 69 } 70 71 sb.iobuf = tr; 72 73 ntr = nxt_sendbuf_mem_coalesce(&sb); 74 75 /* 76 * Disposal of surplus kernel operations 77 * if there are no headers or trailers. 78 */ 79 80 ht = NULL; 81 nxt_memzero(&hdtr, sizeof(struct sf_hdtr)); 82 83 if (nhd != 0) { 84 ht = &hdtr; 85 hdtr.headers = hd; 86 hdtr.hdr_cnt = nhd; 87 } 88 89 if (ntr != 0) { 90 ht = &hdtr; 91 hdtr.trailers = tr; 92 hdtr.trl_cnt = ntr; 93 } 94 95 nxt_log_debug(c->socket.log, "sendfile(%FD, %d, @%O, %uz) hd:%ui tr:%ui", 96 fb->file->fd, c->socket.fd, fb->file_pos, file_size, 97 nhd, ntr); 98 99 sent = 0; 100 n = nxt_sys_sendfile(fb->file->fd, c->socket.fd, fb->file_pos, 101 file_size, ht, &sent, 0); 102 103 err = (n == -1) ? nxt_errno : 0; 104 105 nxt_log_debug(c->socket.log, "sendfile(): %d sent:%O", n, sent); 106 107 if (n == -1) { 108 switch (err) { 109 110 case NXT_EAGAIN: 111 c->socket.write_ready = 0; 112 break; 113 114 case NXT_EINTR: 115 break; 116 117 default: 118 c->socket.error = err; 119 nxt_log_error(nxt_socket_error_level(err, c->socket.log_error), 120 c->socket.log, "sendfile(%FD, %d, %O, %uz) failed " 121 "%E \"%FN\" hd:%ui tr:%ui", fb->file->fd, 122 c->socket.fd, fb->file_pos, file_size, 123 err, fb->file->name, nhd, ntr); 124 125 return NXT_ERROR; 126 } 127 128 nxt_log_debug(c->socket.log, "sendfile() %E", err); 129 130 return sent; 131 132 } else if (sent == 0) { 133 nxt_log_error(NXT_LOG_ERR, c->socket.log, 134 "file \"%FN\" was truncated while sendfile()", 135 fb->file->name); 136 137 return NXT_ERROR; 138 } 139 140 if (sent < (nxt_off_t) sb.size) { 141 c->socket.write_ready = 0; 142 } 143 144 return sent; 145 } 146