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
nxt_sys_sendfile(int fd,int s,off_t offset,size_t nbytes,struct sf_hdtr * hdtr,off_t * sbytes,int flags)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
nxt_freebsd_event_conn_io_sendfile(nxt_event_conn_t * c,nxt_buf_t * b,size_t limit)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(c->socket.task, &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(c->socket.task, &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_debug(c->socket.task, "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_debug(c->socket.task, "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(c->socket.task, nxt_socket_error_level(err),
120 "sendfile(%FD, %d, %O, %uz) failed %E \"%FN\" hd:%ui tr:%ui",
121 fb->file->fd, c->socket.fd, fb->file_pos, file_size, err,
122 fb->file->name, nhd, ntr);
123
124 return NXT_ERROR;
125 }
126
127 nxt_debug(c->socket.task, "sendfile() %E", err);
128
129 return sent;
130
131 } else if (sent == 0) {
132 nxt_log(c->socket.task, NXT_LOG_ERR,
133 "file \"%FN\" was truncated while sendfile()", fb->file->name);
134
135 return NXT_ERROR;
136 }
137
138 if (sent < (nxt_off_t) sb.size) {
139 c->socket.write_ready = 0;
140 }
141
142 return sent;
143 }
144