3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
13 * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit
14 * offsets only, and the including <sys/sendfile.h> breaks the compiling,
15 * if off_t is 64 bit wide. So we use own sendfile() definition, where offset
16 * parameter is int32_t, and use sendfile() for the file parts below 2G only,
17 * see src/os/unix/ngx_linux_config.h
19 * Linux 2.4.21 has a new sendfile64() syscall #239.
26 ngx_chain_t
*ngx_linux_sendfile_chain(ngx_connection_t
*c
, ngx_chain_t
*in
,
31 off_t size
, send
, prev_send
, aligned
, sent
, fprev
;
33 ngx_uint_t eintr
, complete
;
39 struct iovec
*iov
, headers
[NGX_HEADERS
];
40 #if (NGX_HAVE_SENDFILE64)
53 /* the maximum limit size is the maximum size_t value - the page size */
55 if (limit
== 0 || limit
> NGX_MAX_SIZE_T_VALUE
- ngx_pagesize
) {
56 limit
= NGX_MAX_SIZE_T_VALUE
- ngx_pagesize
;
62 header
.elts
= headers
;
63 header
.size
= sizeof(struct iovec
);
64 header
.nalloc
= NGX_HEADERS
;
65 header
.pool
= c
->pool
;
79 /* create the iovec and coalesce the neighbouring bufs */
82 cl
&& header
.nelts
< IOV_MAX
&& send
< limit
;
85 if (ngx_buf_special(cl
->buf
)) {
90 if (!ngx_buf_in_memory(cl
->buf
) && !cl
->buf
->in_file
) {
91 ngx_log_error(NGX_LOG_ALERT
, c
->log
, 0,
92 "zero size buf in sendfile "
93 "t:%d r:%d f:%d %p %p-%p %p %O-%O",
106 return NGX_CHAIN_ERROR
;
110 if (!ngx_buf_in_memory_only(cl
->buf
)) {
114 size
= cl
->buf
->last
- cl
->buf
->pos
;
116 if (send
+ size
> limit
) {
120 if (prev
== cl
->buf
->pos
) {
121 iov
->iov_len
+= (size_t) size
;
124 if (!(iov
= ngx_array_push(&header
))) {
125 return NGX_CHAIN_ERROR
;
128 iov
->iov_base
= (void *) cl
->buf
->pos
;
129 iov
->iov_len
= (size_t) size
;
132 prev
= cl
->buf
->pos
+ (size_t) size
;
136 /* set TCP_CORK if there is a header before a file */
138 if (c
->tcp_nopush
== NGX_TCP_NOPUSH_UNSET
143 /* the TCP_CORK and TCP_NODELAY are mutually exclusive */
145 if (c
->tcp_nodelay
== NGX_TCP_NODELAY_SET
) {
149 if (setsockopt(c
->fd
, IPPROTO_TCP
, TCP_NODELAY
,
150 (const void *) &tcp_nodelay
, sizeof(int)) == -1)
155 * there is a tiny chance to be interrupted, however,
156 * we continue a processing with the TCP_NODELAY
157 * and without the TCP_CORK
160 if (err
!= NGX_EINTR
) {
162 ngx_connection_error(c
, err
,
163 "setsockopt(TCP_NODELAY) failed");
164 return NGX_CHAIN_ERROR
;
168 c
->tcp_nodelay
= NGX_TCP_NODELAY_UNSET
;
170 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, c
->log
, 0,
175 if (c
->tcp_nodelay
== NGX_TCP_NODELAY_UNSET
) {
177 if (ngx_tcp_nopush(c
->fd
) == NGX_ERROR
) {
181 * there is a tiny chance to be interrupted, however,
182 * we continue a processing without the TCP_CORK
185 if (err
!= NGX_EINTR
) {
187 ngx_connection_error(c
, err
,
188 ngx_tcp_nopush_n
" failed");
189 return NGX_CHAIN_ERROR
;
193 c
->tcp_nopush
= NGX_TCP_NOPUSH_SET
;
195 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
201 /* get the file buf */
203 if (header
.nelts
== 0 && cl
&& cl
->buf
->in_file
&& send
< limit
) {
206 /* coalesce the neighbouring file bufs */
209 size
= cl
->buf
->file_last
- cl
->buf
->file_pos
;
211 if (send
+ size
> limit
) {
214 aligned
= (cl
->buf
->file_pos
+ size
+ ngx_pagesize
- 1)
215 & ~(ngx_pagesize
- 1);
217 if (aligned
<= cl
->buf
->file_last
) {
218 size
= aligned
- cl
->buf
->file_pos
;
222 file_size
+= (size_t) size
;
224 fprev
= cl
->buf
->file_pos
+ size
;
230 && file
->file
->fd
== cl
->buf
->file
->fd
231 && fprev
== cl
->buf
->file_pos
);
235 #if (NGX_HAVE_SENDFILE64)
236 offset
= file
->file_pos
;
238 offset
= (int32_t) file
->file_pos
;
240 rc
= sendfile(c
->fd
, file
->file
->fd
, &offset
, file_size
);
245 if (err
== NGX_EAGAIN
|| err
== NGX_EINTR
) {
246 if (err
== NGX_EINTR
) {
250 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, err
,
251 "sendfile() is not ready");
255 ngx_connection_error(c
, err
, "sendfile() failed");
256 return NGX_CHAIN_ERROR
;
260 sent
= rc
> 0 ? rc
: 0;
262 ngx_log_debug4(NGX_LOG_DEBUG_EVENT
, c
->log
, 0,
263 "sendfile: %d, @%O %O:%uz",
264 rc
, file
->file_pos
, sent
, file_size
);
267 rc
= writev(c
->fd
, header
.elts
, header
.nelts
);
272 if (err
== NGX_EAGAIN
|| err
== NGX_EINTR
) {
273 if (err
== NGX_EINTR
) {
277 ngx_log_debug0(NGX_LOG_DEBUG_EVENT
, c
->log
, err
,
278 "writev() not ready");
282 ngx_connection_error(c
, err
, "writev() failed");
283 return NGX_CHAIN_ERROR
;
287 sent
= rc
> 0 ? rc
: 0;
289 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, c
->log
, 0, "writev: %O", sent
);
292 if (send
- prev_send
== sent
) {
298 for (cl
= in
; cl
; cl
= cl
->next
) {
300 if (ngx_buf_special(cl
->buf
)) {
308 size
= ngx_buf_size(cl
->buf
);
313 if (ngx_buf_in_memory(cl
->buf
)) {
314 cl
->buf
->pos
= cl
->buf
->last
;
317 if (cl
->buf
->in_file
) {
318 cl
->buf
->file_pos
= cl
->buf
->file_last
;
324 if (ngx_buf_in_memory(cl
->buf
)) {
325 cl
->buf
->pos
+= (size_t) sent
;
328 if (cl
->buf
->in_file
) {
329 cl
->buf
->file_pos
+= sent
;
344 if (send
>= limit
|| cl
== NULL
) {