3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
10 #include <ngx_event.h>
14 * Although FreeBSD sendfile() allows to pass a header and a trailer,
15 * it cannot send a header with a part of the file in one packet until
16 * FreeBSD 5.3. Besides, over the fast ethernet connection sendfile()
17 * may send the partially filled packets, i.e. the 8 file pages may be sent
18 * as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet,
19 * and then again the 11 full 1460-bytes packets.
21 * Therefore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK)
22 * to postpone the sending - it not only sends a header and the first part of
23 * the file in one packet, but also sends the file pages in the full packets.
25 * But until FreeBSD 4.5 turning TCP_NOPUSH off does not flush a pending
26 * data that less than MSS, so that data may be sent with 5 second delay.
27 * So we do not use TCP_NOPUSH on FreeBSD prior to 4.5, although it can be used
28 * for non-keepalive HTTP connections.
33 #define NGX_HEADERS 64
34 #define NGX_TRAILERS 64
36 #define NGX_HEADERS IOV_MAX
37 #define NGX_TRAILERS IOV_MAX
42 ngx_freebsd_sendfile_chain(ngx_connection_t
*c
, ngx_chain_t
*in
, off_t limit
)
46 off_t size
, send
, prev_send
, aligned
, sent
, fprev
;
47 size_t header_size
, file_size
;
48 ngx_uint_t eintr
, eagain
, complete
;
51 ngx_array_t header
, trailer
;
55 struct iovec
*iov
, headers
[NGX_HEADERS
], trailers
[NGX_TRAILERS
];
65 if ((ngx_event_flags
& NGX_USE_KQUEUE_EVENT
) && wev
->pending_eof
) {
66 (void) ngx_connection_error(c
, wev
->kq_errno
,
67 "kevent() reported about an closed connection");
69 return NGX_CHAIN_ERROR
;
74 /* the maximum limit size is the maximum size_t value - the page size */
76 if (limit
== 0 || limit
> (off_t
) (NGX_MAX_SIZE_T_VALUE
- ngx_pagesize
)) {
77 limit
= NGX_MAX_SIZE_T_VALUE
- ngx_pagesize
;
84 header
.elts
= headers
;
85 header
.size
= sizeof(struct iovec
);
86 header
.nalloc
= NGX_HEADERS
;
87 header
.pool
= c
->pool
;
89 trailer
.elts
= trailers
;
90 trailer
.size
= sizeof(struct iovec
);
91 trailer
.nalloc
= NGX_TRAILERS
;
92 trailer
.pool
= c
->pool
;
105 /* create the header iovec and coalesce the neighbouring bufs */
110 for (cl
= in
; cl
&& send
< limit
; cl
= cl
->next
) {
112 if (ngx_buf_special(cl
->buf
)) {
116 if (!ngx_buf_in_memory_only(cl
->buf
)) {
120 size
= cl
->buf
->last
- cl
->buf
->pos
;
122 if (send
+ size
> limit
) {
126 if (prev
== cl
->buf
->pos
) {
127 iov
->iov_len
+= (size_t) size
;
130 if (header
.nelts
>= IOV_MAX
){
134 iov
= ngx_array_push(&header
);
136 return NGX_CHAIN_ERROR
;
139 iov
->iov_base
= (void *) cl
->buf
->pos
;
140 iov
->iov_len
= (size_t) size
;
143 prev
= cl
->buf
->pos
+ (size_t) size
;
144 header_size
+= (size_t) size
;
149 if (cl
&& cl
->buf
->in_file
&& send
< limit
) {
152 /* coalesce the neighbouring file bufs */
155 size
= cl
->buf
->file_last
- cl
->buf
->file_pos
;
157 if (send
+ size
> limit
) {
160 aligned
= (cl
->buf
->file_pos
+ size
+ ngx_pagesize
- 1)
161 & ~((off_t
) ngx_pagesize
- 1);
163 if (aligned
<= cl
->buf
->file_last
) {
164 size
= aligned
- cl
->buf
->file_pos
;
168 file_size
+= (size_t) size
;
170 fprev
= cl
->buf
->file_pos
+ size
;
176 && file
->file
->fd
== cl
->buf
->file
->fd
177 && fprev
== cl
->buf
->file_pos
);
183 /* create the trailer iovec and coalesce the neighbouring bufs */
188 while (cl
&& send
< limit
) {
190 if (ngx_buf_special(cl
->buf
)) {
195 if (!ngx_buf_in_memory_only(cl
->buf
)) {
199 size
= cl
->buf
->last
- cl
->buf
->pos
;
201 if (send
+ size
> limit
) {
205 if (prev
== cl
->buf
->pos
) {
206 iov
->iov_len
+= (size_t) size
;
209 if (trailer
.nelts
>= IOV_MAX
){
213 iov
= ngx_array_push(&trailer
);
215 return NGX_CHAIN_ERROR
;
218 iov
->iov_base
= (void *) cl
->buf
->pos
;
219 iov
->iov_len
= (size_t) size
;
222 prev
= cl
->buf
->pos
+ (size_t) size
;
230 if (ngx_freebsd_use_tcp_nopush
231 && c
->tcp_nopush
== NGX_TCP_NOPUSH_UNSET
)
233 if (ngx_tcp_nopush(c
->fd
) == NGX_ERROR
) {
237 * there is a tiny chance to be interrupted, however,
238 * we continue a processing without the TCP_NOPUSH
241 if (err
!= NGX_EINTR
) {
243 (void) ngx_connection_error(c
, err
,
244 ngx_tcp_nopush_n
" failed");
245 return NGX_CHAIN_ERROR
;
249 c
->tcp_nopush
= NGX_TCP_NOPUSH_SET
;
251 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
257 * sendfile() does unneeded work if sf_hdtr's count is 0,
258 * but corresponding pointer is not NULL
261 hdtr
.headers
= header
.nelts
? (struct iovec
*) header
.elts
: NULL
;
262 hdtr
.hdr_cnt
= header
.nelts
;
263 hdtr
.trailers
= trailer
.nelts
? (struct iovec
*) trailer
.elts
: NULL
;
264 hdtr
.trl_cnt
= trailer
.nelts
;
267 * the "nbytes bug" of the old sendfile() syscall:
268 * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771
271 if (!ngx_freebsd_sendfile_nbytes_bug
) {
277 #if (NGX_HAVE_AIO_SENDFILE)
278 flags
= c
->aio_sendfile
? SF_NODISKIO
: 0;
281 rc
= sendfile(file
->file
->fd
, c
->fd
, file
->file_pos
,
282 file_size
+ header_size
, &hdtr
, &sent
, flags
);
296 #if (NGX_HAVE_AIO_SENDFILE)
298 c
->busy_sendfile
= file
;
304 (void) ngx_connection_error(c
, err
, "sendfile() failed");
305 return NGX_CHAIN_ERROR
;
308 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, err
,
309 "sendfile() sent only %O bytes", sent
);
312 * sendfile() in FreeBSD 3.x-4.x may return value >= 0
313 * on success, although only 0 is documented
316 } else if (rc
>= 0 && sent
== 0) {
319 * if rc is OK and sent equal to zero, then someone
320 * has truncated the file, so the offset became beyond
321 * the end of the file
324 ngx_log_error(NGX_LOG_ALERT
, c
->log
, 0,
325 "sendfile() reported that \"%s\" was truncated at %O",
326 file
->file
->name
.data
, file
->file_pos
);
328 return NGX_CHAIN_ERROR
;
331 ngx_log_debug4(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
332 "sendfile: %d, @%O %O:%uz",
333 rc
, file
->file_pos
, sent
, file_size
+ header_size
);
336 rc
= writev(c
->fd
, header
.elts
, header
.nelts
);
338 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
339 "writev: %d of %uz", rc
, header_size
);
354 ngx_connection_error(c
, err
, "writev() failed");
355 return NGX_CHAIN_ERROR
;
358 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, err
,
359 "writev() not ready");
362 sent
= rc
> 0 ? rc
: 0;
365 if (send
- prev_send
== sent
) {
371 for (cl
= in
; cl
; cl
= cl
->next
) {
373 if (ngx_buf_special(cl
->buf
)) {
381 size
= ngx_buf_size(cl
->buf
);
386 if (ngx_buf_in_memory(cl
->buf
)) {
387 cl
->buf
->pos
= cl
->buf
->last
;
390 if (cl
->buf
->in_file
) {
391 cl
->buf
->file_pos
= cl
->buf
->file_last
;
397 if (ngx_buf_in_memory(cl
->buf
)) {
398 cl
->buf
->pos
+= (size_t) sent
;
401 if (cl
->buf
->in_file
) {
402 cl
->buf
->file_pos
+= sent
;
408 #if (NGX_HAVE_AIO_SENDFILE)
409 if (c
->busy_sendfile
) {
417 * sendfile() may return EAGAIN, even if it has sent a whole file
418 * part, it indicates that the successive sendfile() call would
419 * return EAGAIN right away and would not send anything.
420 * We use it as a hint.
436 if (send
>= limit
|| cl
== NULL
) {