3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
13 * Although FreeBSD sendfile() allows to pass a header and a trailer
14 * it can not send a header with a part of the file in one packet until
15 * FreeBSD 5.3. Besides over the fast ethernet connection sendfile()
16 * may send the partially filled packets, i.e. the 8 file pages may be sent
17 * as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet,
18 * and then again the 11 full 1460-bytes packets.
20 * So we use the TCP_NOPUSH option (similar to Linux's TCP_CORK)
21 * to postpone the sending - it not only sends a header and the first part
22 * of the file in one packet but also sends the file pages in the full packets.
24 * But until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush a pending
25 * data that less than MSS so that data may be sent with 5 second delay.
26 * So we do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used
27 * for non-keepalive HTTP connections.
32 #define NGX_TRAILERS 4
35 ngx_chain_t
*ngx_freebsd_sendfile_chain(ngx_connection_t
*c
, ngx_chain_t
*in
,
40 off_t size
, send
, prev_send
, aligned
, sent
, fprev
;
41 size_t header_size
, file_size
;
42 ngx_uint_t eintr
, eagain
, complete
;
45 ngx_array_t header
, trailer
;
49 struct iovec
*iov
, headers
[NGX_HEADERS
], trailers
[NGX_TRAILERS
];
59 if ((ngx_event_flags
& NGX_USE_KQUEUE_EVENT
) && wev
->pending_eof
) {
60 ngx_log_error(NGX_LOG_INFO
, c
->log
, wev
->kq_errno
,
61 "kevent() reported about an closed connection");
64 return NGX_CHAIN_ERROR
;
69 /* the maximum limit size is the maximum size_t value - the page size */
71 if (limit
== 0 || limit
> MAX_SIZE_T_VALUE
- ngx_pagesize
) {
72 limit
= MAX_SIZE_T_VALUE
- ngx_pagesize
;
78 header
.elts
= headers
;
79 header
.size
= sizeof(struct iovec
);
80 header
.nalloc
= NGX_HEADERS
;
81 header
.pool
= c
->pool
;
83 trailer
.elts
= trailers
;
84 trailer
.size
= sizeof(struct iovec
);
85 trailer
.nalloc
= NGX_TRAILERS
;
86 trailer
.pool
= c
->pool
;
99 /* create the header iovec and coalesce the neighbouring bufs */
105 cl
&& header
.nelts
< IOV_MAX
&& send
< limit
;
108 if (ngx_buf_special(cl
->buf
)) {
112 if (!ngx_buf_in_memory_only(cl
->buf
)) {
116 size
= cl
->buf
->last
- cl
->buf
->pos
;
118 if (send
+ size
> limit
) {
122 if (prev
== cl
->buf
->pos
) {
123 iov
->iov_len
+= (size_t) size
;
126 if (!(iov
= ngx_array_push(&header
))) {
127 return NGX_CHAIN_ERROR
;
130 iov
->iov_base
= (void *) cl
->buf
->pos
;
131 iov
->iov_len
= (size_t) size
;
134 prev
= cl
->buf
->pos
+ (size_t) size
;
135 header_size
+= (size_t) size
;
140 if (cl
&& cl
->buf
->in_file
&& send
< limit
) {
143 /* coalesce the neighbouring file bufs */
146 size
= cl
->buf
->file_last
- cl
->buf
->file_pos
;
148 if (send
+ size
> limit
) {
151 aligned
= (cl
->buf
->file_pos
+ size
+ ngx_pagesize
- 1)
152 & ~(ngx_pagesize
- 1);
154 if (aligned
<= cl
->buf
->file_last
) {
155 size
= aligned
- cl
->buf
->file_pos
;
159 file_size
+= (size_t) size
;
161 fprev
= cl
->buf
->file_pos
+ size
;
167 && file
->file
->fd
== cl
->buf
->file
->fd
168 && fprev
== cl
->buf
->file_pos
);
174 /* create the tailer iovec and coalesce the neighbouring bufs */
179 while (cl
&& header
.nelts
< IOV_MAX
&& send
< limit
) {
181 if (ngx_buf_special(cl
->buf
)) {
186 if (!ngx_buf_in_memory_only(cl
->buf
)) {
190 size
= cl
->buf
->last
- cl
->buf
->pos
;
192 if (send
+ size
> limit
) {
196 if (prev
== cl
->buf
->pos
) {
197 iov
->iov_len
+= (size_t) size
;
200 if (!(iov
= ngx_array_push(&trailer
))) {
201 return NGX_CHAIN_ERROR
;
204 iov
->iov_base
= (void *) cl
->buf
->pos
;
205 iov
->iov_len
= (size_t) size
;
208 prev
= cl
->buf
->pos
+ (size_t) size
;
216 if (ngx_freebsd_use_tcp_nopush
217 && c
->tcp_nopush
== NGX_TCP_NOPUSH_UNSET
)
219 if (ngx_tcp_nopush(c
->fd
) == NGX_ERROR
) {
223 * there is a tiny chance to be interrupted, however
224 * we continue a processing without the TCP_NOPUSH
227 if (err
!= NGX_EINTR
) {
229 ngx_connection_error(c
, err
,
230 ngx_tcp_nopush_n
" failed");
231 return NGX_CHAIN_ERROR
;
235 c
->tcp_nopush
= NGX_TCP_NOPUSH_SET
;
237 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
242 hdtr
.headers
= (struct iovec
*) header
.elts
;
243 hdtr
.hdr_cnt
= header
.nelts
;
244 hdtr
.trailers
= (struct iovec
*) trailer
.elts
;
245 hdtr
.trl_cnt
= trailer
.nelts
;
248 * the "nbytes bug" of the old sendfile() syscall:
249 * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771
252 if (ngx_freebsd_sendfile_nbytes_bug
== 0) {
258 rc
= sendfile(file
->file
->fd
, c
->fd
, file
->file_pos
,
259 file_size
+ header_size
, &hdtr
, &sent
, 0);
264 if (err
== NGX_EAGAIN
|| err
== NGX_EINTR
) {
265 if (err
== NGX_EINTR
) {
272 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, err
,
273 "sendfile() sent only %O bytes", sent
);
277 ngx_connection_error(c
, err
, "sendfile() failed");
278 return NGX_CHAIN_ERROR
;
282 if (rc
== 0 && sent
== 0) {
285 * rc and sent are equals to zero when someone has truncated
286 * the file, so the offset became beyond the end of the file
289 ngx_log_error(NGX_LOG_ALERT
, c
->log
, 0,
290 "sendfile() reported that \"%s\" was truncated",
291 file
->file
->name
.data
);
293 return NGX_CHAIN_ERROR
;
296 ngx_log_debug4(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
297 "sendfile: %d, @%O %O:%uz",
298 rc
, file
->file_pos
, sent
, file_size
+ header_size
);
301 rc
= writev(c
->fd
, header
.elts
, header
.nelts
);
303 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
304 "writev: %d of %uz", rc
, header_size
);
309 if (err
== NGX_EAGAIN
|| err
== NGX_EINTR
) {
310 if (err
== NGX_EINTR
) {
314 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, err
,
315 "writev() not ready");
319 ngx_connection_error(c
, err
, "writev() failed");
320 return NGX_CHAIN_ERROR
;
324 sent
= rc
> 0 ? rc
: 0;
327 if (send
- prev_send
== sent
) {
333 for (cl
= in
; cl
; cl
= cl
->next
) {
335 if (ngx_buf_special(cl
->buf
)) {
343 size
= ngx_buf_size(cl
->buf
);
348 if (ngx_buf_in_memory(cl
->buf
)) {
349 cl
->buf
->pos
= cl
->buf
->last
;
352 if (cl
->buf
->in_file
) {
353 cl
->buf
->file_pos
= cl
->buf
->file_last
;
359 if (ngx_buf_in_memory(cl
->buf
)) {
360 cl
->buf
->pos
+= (size_t) sent
;
363 if (cl
->buf
->in_file
) {
364 cl
->buf
->file_pos
+= sent
;
373 * sendfile() can return EAGAIN even if it has sent
374 * a whole file part but the successive sendfile() call would
375 * return EAGAIN right away and would not send anything.
376 * We use it as a hint.
392 if (send
>= limit
|| cl
== NULL
) {