3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
10 #include <ngx_event.h>
14 * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit
15 * offsets only, and the including <sys/sendfile.h> breaks the compiling,
16 * if off_t is 64 bit wide. So we use own sendfile() definition, where offset
17 * parameter is int32_t, and use sendfile() for the file parts below 2G only,
18 * see src/os/unix/ngx_linux_config.h
20 * Linux 2.4.21 has the new sendfile64() syscall #239.
22 * On Linux up to 2.6.16 sendfile() does not allow to pass the count parameter
23 * more than 2G-1 bytes even on 64-bit platforms: it returns EINVAL,
24 * so we limit it to 2G-1 bytes.
27 #define NGX_SENDFILE_LIMIT 2147483647L
31 #define NGX_HEADERS 64
33 #define NGX_HEADERS IOV_MAX
38 ngx_linux_sendfile_chain(ngx_connection_t
*c
, ngx_chain_t
*in
, off_t limit
)
41 off_t size
, send
, prev_send
, aligned
, sent
, fprev
;
46 ngx_uint_t eintr
, complete
;
50 struct iovec
*iov
, headers
[NGX_HEADERS
];
51 #if (NGX_HAVE_SENDFILE64)
64 /* the maximum limit size is 2G-1 - the page size */
66 if (limit
== 0 || limit
> (off_t
) (NGX_SENDFILE_LIMIT
- ngx_pagesize
)) {
67 limit
= NGX_SENDFILE_LIMIT
- ngx_pagesize
;
73 header
.elts
= headers
;
74 header
.size
= sizeof(struct iovec
);
75 header
.nalloc
= NGX_HEADERS
;
76 header
.pool
= c
->pool
;
90 /* create the iovec and coalesce the neighbouring bufs */
92 for (cl
= in
; cl
&& send
< limit
; cl
= cl
->next
) {
94 if (ngx_buf_special(cl
->buf
)) {
99 if (!ngx_buf_in_memory(cl
->buf
) && !cl
->buf
->in_file
) {
100 ngx_log_error(NGX_LOG_ALERT
, c
->log
, 0,
101 "zero size buf in sendfile "
102 "t:%d r:%d f:%d %p %p-%p %p %O-%O",
115 return NGX_CHAIN_ERROR
;
119 if (!ngx_buf_in_memory_only(cl
->buf
)) {
123 size
= cl
->buf
->last
- cl
->buf
->pos
;
125 if (send
+ size
> limit
) {
129 if (prev
== cl
->buf
->pos
) {
130 iov
->iov_len
+= (size_t) size
;
133 if (header
.nelts
>= IOV_MAX
) {
137 iov
= ngx_array_push(&header
);
139 return NGX_CHAIN_ERROR
;
142 iov
->iov_base
= (void *) cl
->buf
->pos
;
143 iov
->iov_len
= (size_t) size
;
146 prev
= cl
->buf
->pos
+ (size_t) size
;
150 /* set TCP_CORK if there is a header before a file */
152 if (c
->tcp_nopush
== NGX_TCP_NOPUSH_UNSET
157 /* the TCP_CORK and TCP_NODELAY are mutually exclusive */
159 if (c
->tcp_nodelay
== NGX_TCP_NODELAY_SET
) {
163 if (setsockopt(c
->fd
, IPPROTO_TCP
, TCP_NODELAY
,
164 (const void *) &tcp_nodelay
, sizeof(int)) == -1)
169 * there is a tiny chance to be interrupted, however,
170 * we continue a processing with the TCP_NODELAY
171 * and without the TCP_CORK
174 if (err
!= NGX_EINTR
) {
176 ngx_connection_error(c
, err
,
177 "setsockopt(TCP_NODELAY) failed");
178 return NGX_CHAIN_ERROR
;
182 c
->tcp_nodelay
= NGX_TCP_NODELAY_UNSET
;
184 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, c
->log
, 0,
189 if (c
->tcp_nodelay
== NGX_TCP_NODELAY_UNSET
) {
191 if (ngx_tcp_nopush(c
->fd
) == NGX_ERROR
) {
195 * there is a tiny chance to be interrupted, however,
196 * we continue a processing without the TCP_CORK
199 if (err
!= NGX_EINTR
) {
201 ngx_connection_error(c
, err
,
202 ngx_tcp_nopush_n
" failed");
203 return NGX_CHAIN_ERROR
;
207 c
->tcp_nopush
= NGX_TCP_NOPUSH_SET
;
209 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
215 /* get the file buf */
217 if (header
.nelts
== 0 && cl
&& cl
->buf
->in_file
&& send
< limit
) {
220 /* coalesce the neighbouring file bufs */
223 size
= cl
->buf
->file_last
- cl
->buf
->file_pos
;
225 if (send
+ size
> limit
) {
228 aligned
= (cl
->buf
->file_pos
+ size
+ ngx_pagesize
- 1)
229 & ~((off_t
) ngx_pagesize
- 1);
231 if (aligned
<= cl
->buf
->file_last
) {
232 size
= aligned
- cl
->buf
->file_pos
;
236 file_size
+= (size_t) size
;
238 fprev
= cl
->buf
->file_pos
+ size
;
244 && file
->file
->fd
== cl
->buf
->file
->fd
245 && fprev
== cl
->buf
->file_pos
);
250 if (file_size
== 0) {
252 return NGX_CHAIN_ERROR
;
255 #if (NGX_HAVE_SENDFILE64)
256 offset
= file
->file_pos
;
258 offset
= (int32_t) file
->file_pos
;
261 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
262 "sendfile: @%O %uz", file
->file_pos
, file_size
);
264 rc
= sendfile(c
->fd
, file
->file
->fd
, &offset
, file_size
);
279 ngx_connection_error(c
, err
, "sendfile() failed");
280 return NGX_CHAIN_ERROR
;
283 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, err
,
284 "sendfile() is not ready");
287 sent
= rc
> 0 ? rc
: 0;
289 ngx_log_debug4(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
290 "sendfile: %d, @%O %O:%uz",
291 rc
, file
->file_pos
, sent
, file_size
);
294 rc
= writev(c
->fd
, header
.elts
, header
.nelts
);
309 ngx_connection_error(c
, err
, "writev() failed");
310 return NGX_CHAIN_ERROR
;
313 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, err
,
314 "writev() not ready");
317 sent
= rc
> 0 ? rc
: 0;
319 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0, "writev: %O", sent
);
322 if (send
- prev_send
== sent
) {
328 for (cl
= in
; cl
; cl
= cl
->next
) {
330 if (ngx_buf_special(cl
->buf
)) {
338 size
= ngx_buf_size(cl
->buf
);
343 if (ngx_buf_in_memory(cl
->buf
)) {
344 cl
->buf
->pos
= cl
->buf
->last
;
347 if (cl
->buf
->in_file
) {
348 cl
->buf
->file_pos
= cl
->buf
->file_last
;
354 if (ngx_buf_in_memory(cl
->buf
)) {
355 cl
->buf
->pos
+= (size_t) sent
;
358 if (cl
->buf
->in_file
) {
359 cl
->buf
->file_pos
+= sent
;
374 if (send
>= limit
|| cl
== NULL
) {