Update and clean Tomato RAF files
[tomato.git] / release / src / router / nginx / src / os / unix / ngx_linux_sendfile_chain.c
blobe8f3d5a894e05dcd235dfcd8317cc3ec3e7eed2e
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
8 #include <ngx_config.h>
9 #include <ngx_core.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
30 #if (IOV_MAX > 64)
31 #define NGX_HEADERS 64
32 #else
33 #define NGX_HEADERS IOV_MAX
34 #endif
37 ngx_chain_t *
38 ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
40 int rc, tcp_nodelay;
41 off_t size, send, prev_send, aligned, sent, fprev;
42 u_char *prev;
43 size_t file_size;
44 ngx_err_t err;
45 ngx_buf_t *file;
46 ngx_uint_t eintr, complete;
47 ngx_array_t header;
48 ngx_event_t *wev;
49 ngx_chain_t *cl;
50 struct iovec *iov, headers[NGX_HEADERS];
51 #if (NGX_HAVE_SENDFILE64)
52 off_t offset;
53 #else
54 int32_t offset;
55 #endif
57 wev = c->write;
59 if (!wev->ready) {
60 return in;
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;
71 send = 0;
73 header.elts = headers;
74 header.size = sizeof(struct iovec);
75 header.nalloc = NGX_HEADERS;
76 header.pool = c->pool;
78 for ( ;; ) {
79 file = NULL;
80 file_size = 0;
81 eintr = 0;
82 complete = 0;
83 prev_send = send;
85 header.nelts = 0;
87 prev = NULL;
88 iov = NULL;
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)) {
95 continue;
98 #if 1
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",
103 cl->buf->temporary,
104 cl->buf->recycled,
105 cl->buf->in_file,
106 cl->buf->start,
107 cl->buf->pos,
108 cl->buf->last,
109 cl->buf->file,
110 cl->buf->file_pos,
111 cl->buf->file_last);
113 ngx_debug_point();
115 return NGX_CHAIN_ERROR;
117 #endif
119 if (!ngx_buf_in_memory_only(cl->buf)) {
120 break;
123 size = cl->buf->last - cl->buf->pos;
125 if (send + size > limit) {
126 size = limit - send;
129 if (prev == cl->buf->pos) {
130 iov->iov_len += (size_t) size;
132 } else {
133 if (header.nelts >= IOV_MAX) {
134 break;
137 iov = ngx_array_push(&header);
138 if (iov == NULL) {
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;
147 send += size;
150 /* set TCP_CORK if there is a header before a file */
152 if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET
153 && header.nelts != 0
154 && cl
155 && cl->buf->in_file)
157 /* the TCP_CORK and TCP_NODELAY are mutually exclusive */
159 if (c->tcp_nodelay == NGX_TCP_NODELAY_SET) {
161 tcp_nodelay = 0;
163 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
164 (const void *) &tcp_nodelay, sizeof(int)) == -1)
166 err = ngx_errno;
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) {
175 wev->error = 1;
176 ngx_connection_error(c, err,
177 "setsockopt(TCP_NODELAY) failed");
178 return NGX_CHAIN_ERROR;
181 } else {
182 c->tcp_nodelay = NGX_TCP_NODELAY_UNSET;
184 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
185 "no tcp_nodelay");
189 if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
191 if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
192 err = ngx_errno;
195 * there is a tiny chance to be interrupted, however,
196 * we continue a processing without the TCP_CORK
199 if (err != NGX_EINTR) {
200 wev->error = 1;
201 ngx_connection_error(c, err,
202 ngx_tcp_nopush_n " failed");
203 return NGX_CHAIN_ERROR;
206 } else {
207 c->tcp_nopush = NGX_TCP_NOPUSH_SET;
209 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
210 "tcp_nopush");
215 /* get the file buf */
217 if (header.nelts == 0 && cl && cl->buf->in_file && send < limit) {
218 file = cl->buf;
220 /* coalesce the neighbouring file bufs */
222 do {
223 size = cl->buf->file_last - cl->buf->file_pos;
225 if (send + size > limit) {
226 size = limit - send;
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;
237 send += size;
238 fprev = cl->buf->file_pos + size;
239 cl = cl->next;
241 } while (cl
242 && cl->buf->in_file
243 && send < limit
244 && file->file->fd == cl->buf->file->fd
245 && fprev == cl->buf->file_pos);
248 if (file) {
249 #if 1
250 if (file_size == 0) {
251 ngx_debug_point();
252 return NGX_CHAIN_ERROR;
254 #endif
255 #if (NGX_HAVE_SENDFILE64)
256 offset = file->file_pos;
257 #else
258 offset = (int32_t) file->file_pos;
259 #endif
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);
266 if (rc == -1) {
267 err = ngx_errno;
269 switch (err) {
270 case NGX_EAGAIN:
271 break;
273 case NGX_EINTR:
274 eintr = 1;
275 break;
277 default:
278 wev->error = 1;
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);
293 } else {
294 rc = writev(c->fd, header.elts, header.nelts);
296 if (rc == -1) {
297 err = ngx_errno;
299 switch (err) {
300 case NGX_EAGAIN:
301 break;
303 case NGX_EINTR:
304 eintr = 1;
305 break;
307 default:
308 wev->error = 1;
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) {
323 complete = 1;
326 c->sent += sent;
328 for (cl = in; cl; cl = cl->next) {
330 if (ngx_buf_special(cl->buf)) {
331 continue;
334 if (sent == 0) {
335 break;
338 size = ngx_buf_size(cl->buf);
340 if (sent >= size) {
341 sent -= size;
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;
351 continue;
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;
362 break;
365 if (eintr) {
366 continue;
369 if (!complete) {
370 wev->ready = 0;
371 return cl;
374 if (send >= limit || cl == NULL) {
375 return cl;
378 in = cl;