~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/os/unix/ngx_darwin_sendfile_chain.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  */
  5 
  6 
  7 #include <ngx_config.h>
  8 #include <ngx_core.h>
  9 #include <ngx_event.h>
 10 
 11 
 12 /*
 13  * It seems that Darwin 9.4 (Mac OS X 1.5) sendfile() has the same
 14  * old bug as early FreeBSD sendfile() syscall:
 15  * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771
 16  *
 17  * Besides sendfile() has another bug: if one calls sendfile()
 18  * with both a header and a trailer, then sendfile() ignores a file part
 19  * at all and sends only the header and the trailer together.
 20  * For this reason we send a trailer only if there is no a header.
 21  *
 22  * Although sendfile() allows to pass a header or a trailer,
 23  * it may send the header or the trailer and a part of the file
 24  * in different packets.  And FreeBSD workaround (TCP_NOPUSH option)
 25  * does not help.
 26  */
 27 
 28 
 29 #if (IOV_MAX > 64)
 30 #define NGX_HEADERS   64
 31 #define NGX_TRAILERS  64
 32 #else
 33 #define NGX_HEADERS   IOV_MAX
 34 #define NGX_TRAILERS  IOV_MAX
 35 #endif
 36 
 37 
 38 ngx_chain_t *
 39 ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
 40 {
 41     int              rc;
 42     u_char          *prev;
 43     off_t            size, send, prev_send, aligned, sent, fprev;
 44     off_t            header_size, file_size;
 45     ngx_uint_t       eintr, complete;
 46     ngx_err_t        err;
 47     ngx_buf_t       *file;
 48     ngx_array_t      header, trailer;
 49     ngx_event_t     *wev;
 50     ngx_chain_t     *cl;
 51     struct sf_hdtr   hdtr;
 52     struct iovec    *iov, headers[NGX_HEADERS], trailers[NGX_TRAILERS];
 53 
 54     wev = c->write;
 55 
 56     if (!wev->ready) {
 57         return in;
 58     }
 59 
 60 #if (NGX_HAVE_KQUEUE)
 61 
 62     if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) {
 63         (void) ngx_connection_error(c, wev->kq_errno,
 64                                "kevent() reported about an closed connection");
 65         wev->error = 1;
 66         return NGX_CHAIN_ERROR;
 67     }
 68 
 69 #endif
 70 
 71     /* the maximum limit size is the maximum size_t value - the page size */
 72 
 73     if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
 74         limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
 75     }
 76 
 77     send = 0;
 78 
 79     header.elts = headers;
 80     header.size = sizeof(struct iovec);
 81     header.nalloc = NGX_HEADERS;
 82     header.pool = c->pool;
 83 
 84     trailer.elts = trailers;
 85     trailer.size = sizeof(struct iovec);
 86     trailer.nalloc = NGX_TRAILERS;
 87     trailer.pool = c->pool;
 88 
 89     for ( ;; ) {
 90         file = NULL;
 91         file_size = 0;
 92         header_size = 0;
 93         eintr = 0;
 94         complete = 0;
 95         prev_send = send;
 96 
 97         header.nelts = 0;
 98         trailer.nelts = 0;
 99 
100         /* create the header iovec and coalesce the neighbouring bufs */
101 
102         prev = NULL;
103         iov = NULL;
104 
105         for (cl = in;
106              cl && header.nelts < IOV_MAX && send < limit;
107              cl = cl->next)
108         {
109             if (ngx_buf_special(cl->buf)) {
110                 continue;
111             }
112 
113             if (!ngx_buf_in_memory_only(cl->buf)) {
114                 break;
115             }
116 
117             size = cl->buf->last - cl->buf->pos;
118 
119             if (send + size > limit) {
120                 size = limit - send;
121             }
122 
123             if (prev == cl->buf->pos) {
124                 iov->iov_len += (size_t) size;
125 
126             } else {
127                 iov = ngx_array_push(&header);
128                 if (iov == NULL) {
129                     return NGX_CHAIN_ERROR;
130                 }
131 
132                 iov->iov_base = (void *) cl->buf->pos;
133                 iov->iov_len = (size_t) size;
134             }
135 
136             prev = cl->buf->pos + (size_t) size;
137             header_size += size;
138             send += size;
139         }
140 
141 
142         if (cl && cl->buf->in_file && send < limit) {
143             file = cl->buf;
144 
145             /* coalesce the neighbouring file bufs */
146 
147             do {
148                 size = cl->buf->file_last - cl->buf->file_pos;
149 
150                 if (send + size > limit) {
151                     size = limit - send;
152 
153                     aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
154                                & ~((off_t) ngx_pagesize - 1);
155 
156                     if (aligned <= cl->buf->file_last) {
157                         size = aligned - cl->buf->file_pos;
158                     }
159                 }
160 
161                 file_size += size;
162                 send += size;
163                 fprev = cl->buf->file_pos + size;
164                 cl = cl->next;
165 
166             } while (cl
167                      && cl->buf->in_file
168                      && send < limit
169                      && file->file->fd == cl->buf->file->fd
170                      && fprev == cl->buf->file_pos);
171         }
172 
173         if (file && header.nelts == 0) {
174 
175             /* create the tailer iovec and coalesce the neighbouring bufs */
176 
177             prev = NULL;
178             iov = NULL;
179 
180             while (cl && header.nelts < IOV_MAX && send < limit) {
181 
182                 if (ngx_buf_special(cl->buf)) {
183                     cl = cl->next;
184                     continue;
185                 }
186 
187                 if (!ngx_buf_in_memory_only(cl->buf)) {
188                     break;
189                 }
190 
191                 size = cl->buf->last - cl->buf->pos;
192 
193                 if (send + size > limit) {
194                     size = limit - send;
195                 }
196 
197                 if (prev == cl->buf->pos) {
198                     iov->iov_len += (size_t) size;
199 
200                 } else {
201                     iov = ngx_array_push(&trailer);
202                     if (iov == NULL) {
203                         return NGX_CHAIN_ERROR;
204                     }
205 
206                     iov->iov_base = (void *) cl->buf->pos;
207                     iov->iov_len = (size_t) size;
208                 }
209 
210                 prev = cl->buf->pos + (size_t) size;
211                 send += size;
212                 cl = cl->next;
213             }
214         }
215 
216         if (file) {
217 
218             /*
219              * sendfile() returns EINVAL if sf_hdtr's count is 0,
220              * but corresponding pointer is not NULL
221              */
222 
223             hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL;
224             hdtr.hdr_cnt = header.nelts;
225             hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL;
226             hdtr.trl_cnt = trailer.nelts;
227 
228             sent = header_size + file_size;
229 
230             ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
231                            "sendfile: @%O %O h:%O",
232                            file->file_pos, sent, header_size);
233 
234             rc = sendfile(file->file->fd, c->fd, file->file_pos,
235                           &sent, &hdtr, 0);
236 
237             if (rc == -1) {
238                 err = ngx_errno;
239 
240                 switch (err) {
241                 case NGX_EAGAIN:
242                     break;
243 
244                 case NGX_EINTR:
245                     eintr = 1;
246                     break;
247 
248                 default:
249                     wev->error = 1;
250                     (void) ngx_connection_error(c, err, "sendfile() failed");
251                     return NGX_CHAIN_ERROR;
252                 }
253 
254                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
255                                "sendfile() sent only %O bytes", sent);
256             }
257 
258             if (rc == 0 && sent == 0) {
259 
260                 /*
261                  * if rc and sent equal to zero, then someone
262                  * has truncated the file, so the offset became beyond
263                  * the end of the file
264                  */
265 
266                 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
267                               "sendfile() reported that \"%s\" was truncated",
268                               file->file->name.data);
269 
270                 return NGX_CHAIN_ERROR;
271             }
272 
273             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
274                            "sendfile: %d, @%O %O:%O",
275                            rc, file->file_pos, sent, file_size + header_size);
276 
277         } else {
278             rc = writev(c->fd, header.elts, header.nelts);
279 
280             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
281                            "writev: %d of %uz", rc, send);
282 
283             if (rc == -1) {
284                 err = ngx_errno;
285 
286                 switch (err) {
287                 case NGX_EAGAIN:
288                     break;
289 
290                 case NGX_EINTR:
291                     eintr = 1;
292                     break;
293 
294                 default:
295                     wev->error = 1;
296                     ngx_connection_error(c, err, "writev() failed");
297                     return NGX_CHAIN_ERROR;
298                 }
299 
300                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
301                                "writev() not ready");
302             }
303 
304             sent = rc > 0 ? rc : 0;
305         }
306 
307         if (send - prev_send == sent) {
308             complete = 1;
309         }
310 
311         c->sent += sent;
312 
313         for (cl = in; cl; cl = cl->next) {
314 
315             if (ngx_buf_special(cl->buf)) {
316                 continue;
317             }
318 
319             if (sent == 0) {
320                 break;
321             }
322 
323             size = ngx_buf_size(cl->buf);
324 
325             if (sent >= size) {
326                 sent -= size;
327 
328                 if (ngx_buf_in_memory(cl->buf)) {
329                     cl->buf->pos = cl->buf->last;
330                 }
331 
332                 if (cl->buf->in_file) {
333                     cl->buf->file_pos = cl->buf->file_last;
334                 }
335 
336                 continue;
337             }
338 
339             if (ngx_buf_in_memory(cl->buf)) {
340                 cl->buf->pos += (size_t) sent;
341             }
342 
343             if (cl->buf->in_file) {
344                 cl->buf->file_pos += sent;
345             }
346 
347             break;
348         }
349 
350         if (eintr) {
351             continue;
352         }
353 
354         if (!complete) {
355             wev->ready = 0;
356             return cl;
357         }
358 
359         if (send >= limit || cl == NULL) {
360             return cl;
361         }
362 
363         in = cl;
364     }
365 }
366 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.