Mercurial > hg > nginx-ranges
comparison src/os/unix/ngx_darwin_sendfile_chain.c @ 392:0b6053502c55 NGINX_0_7_7
nginx 0.7.7
*) Change: now the EAGAIN error returned by connect() is not considered
as temporary error.
*) Change: now the $ssl_client_cert variable value is a certificate
with TAB character intended before each line except first one; an
unchanged certificate is available in the $ssl_client_raw_cert
variable.
*) Feature: the "ask" parameter in the "ssl_verify_client" directive.
*) Feature: byte-range processing improvements.
Thanks to Maxim Dounin.
*) Feature: the "directio" directive.
*) Feature: MacOSX 1.5 sendfile() support.
*) Bugfix: now in MacOSX and Cygwin locations are tested in case
insensitive mode; however, the compare is provided by single-byte
locales only.
*) Bugfix: mail proxy SSL connections hanged, if select, poll, or
/dev/poll methods were used.
*) Bugfix: UTF-8 encoding usage in the ngx_http_autoindex_module.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Wed, 30 Jul 2008 00:00:00 +0400 |
parents | |
children | d41628eb4d0a |
comparison
equal
deleted
inserted
replaced
389:930e48a26dde | 392:0b6053502c55 |
---|---|
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, eagain, 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 eagain = 0; | |
79 | |
80 header.elts = headers; | |
81 header.size = sizeof(struct iovec); | |
82 header.nalloc = NGX_HEADERS; | |
83 header.pool = c->pool; | |
84 | |
85 trailer.elts = trailers; | |
86 trailer.size = sizeof(struct iovec); | |
87 trailer.nalloc = NGX_TRAILERS; | |
88 trailer.pool = c->pool; | |
89 | |
90 for ( ;; ) { | |
91 file = NULL; | |
92 file_size = 0; | |
93 header_size = 0; | |
94 eintr = 0; | |
95 complete = 0; | |
96 prev_send = send; | |
97 | |
98 header.nelts = 0; | |
99 trailer.nelts = 0; | |
100 | |
101 /* create the header iovec and coalesce the neighbouring bufs */ | |
102 | |
103 prev = NULL; | |
104 iov = NULL; | |
105 | |
106 for (cl = in; | |
107 cl && header.nelts < IOV_MAX && send < limit; | |
108 cl = cl->next) | |
109 { | |
110 if (ngx_buf_special(cl->buf)) { | |
111 continue; | |
112 } | |
113 | |
114 if (!ngx_buf_in_memory_only(cl->buf)) { | |
115 break; | |
116 } | |
117 | |
118 size = cl->buf->last - cl->buf->pos; | |
119 | |
120 if (send + size > limit) { | |
121 size = limit - send; | |
122 } | |
123 | |
124 if (prev == cl->buf->pos) { | |
125 iov->iov_len += (size_t) size; | |
126 | |
127 } else { | |
128 iov = ngx_array_push(&header); | |
129 if (iov == NULL) { | |
130 return NGX_CHAIN_ERROR; | |
131 } | |
132 | |
133 iov->iov_base = (void *) cl->buf->pos; | |
134 iov->iov_len = (size_t) size; | |
135 } | |
136 | |
137 prev = cl->buf->pos + (size_t) size; | |
138 header_size += size; | |
139 send += size; | |
140 } | |
141 | |
142 | |
143 if (cl && cl->buf->in_file && send < limit) { | |
144 file = cl->buf; | |
145 | |
146 /* coalesce the neighbouring file bufs */ | |
147 | |
148 do { | |
149 size = cl->buf->file_last - cl->buf->file_pos; | |
150 | |
151 if (send + size > limit) { | |
152 size = limit - send; | |
153 | |
154 aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) | |
155 & ~((off_t) ngx_pagesize - 1); | |
156 | |
157 if (aligned <= cl->buf->file_last) { | |
158 size = aligned - cl->buf->file_pos; | |
159 } | |
160 } | |
161 | |
162 file_size += size; | |
163 send += size; | |
164 fprev = cl->buf->file_pos + size; | |
165 cl = cl->next; | |
166 | |
167 } while (cl | |
168 && cl->buf->in_file | |
169 && send < limit | |
170 && file->file->fd == cl->buf->file->fd | |
171 && fprev == cl->buf->file_pos); | |
172 } | |
173 | |
174 if (file && header.nelts == 0) { | |
175 | |
176 /* create the tailer iovec and coalesce the neighbouring bufs */ | |
177 | |
178 prev = NULL; | |
179 iov = NULL; | |
180 | |
181 while (cl && header.nelts < IOV_MAX && send < limit) { | |
182 | |
183 if (ngx_buf_special(cl->buf)) { | |
184 cl = cl->next; | |
185 continue; | |
186 } | |
187 | |
188 if (!ngx_buf_in_memory_only(cl->buf)) { | |
189 break; | |
190 } | |
191 | |
192 size = cl->buf->last - cl->buf->pos; | |
193 | |
194 if (send + size > limit) { | |
195 size = limit - send; | |
196 } | |
197 | |
198 if (prev == cl->buf->pos) { | |
199 iov->iov_len += (size_t) size; | |
200 | |
201 } else { | |
202 iov = ngx_array_push(&trailer); | |
203 if (iov == NULL) { | |
204 return NGX_CHAIN_ERROR; | |
205 } | |
206 | |
207 iov->iov_base = (void *) cl->buf->pos; | |
208 iov->iov_len = (size_t) size; | |
209 } | |
210 | |
211 prev = cl->buf->pos + (size_t) size; | |
212 send += size; | |
213 cl = cl->next; | |
214 } | |
215 } | |
216 | |
217 if (file) { | |
218 | |
219 /* | |
220 * sendfile() returns EINVAL if sf_hdtr's count is 0, | |
221 * but corresponding pointer is not NULL | |
222 */ | |
223 | |
224 hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL; | |
225 hdtr.hdr_cnt = header.nelts; | |
226 hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL; | |
227 hdtr.trl_cnt = trailer.nelts; | |
228 | |
229 sent = header_size + file_size; | |
230 | |
231 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
232 "sendfile: @%O %O h:%O", | |
233 file->file_pos, sent, header_size); | |
234 | |
235 rc = sendfile(file->file->fd, c->fd, file->file_pos, | |
236 &sent, &hdtr, 0); | |
237 | |
238 if (rc == -1) { | |
239 err = ngx_errno; | |
240 | |
241 if (err == NGX_EAGAIN || err == NGX_EINTR) { | |
242 if (err == NGX_EINTR) { | |
243 eintr = 1; | |
244 | |
245 } else { | |
246 eagain = 1; | |
247 } | |
248 | |
249 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, | |
250 "sendfile() sent only %O bytes", sent); | |
251 | |
252 } else { | |
253 wev->error = 1; | |
254 (void) ngx_connection_error(c, err, "sendfile() failed"); | |
255 return NGX_CHAIN_ERROR; | |
256 } | |
257 } | |
258 | |
259 if (rc == 0 && sent == 0) { | |
260 | |
261 /* | |
262 * if rc and sent equal to zero, then someone | |
263 * has truncated the file, so the offset became beyond | |
264 * the end of the file | |
265 */ | |
266 | |
267 ngx_log_error(NGX_LOG_ALERT, c->log, 0, | |
268 "sendfile() reported that \"%s\" was truncated", | |
269 file->file->name.data); | |
270 | |
271 return NGX_CHAIN_ERROR; | |
272 } | |
273 | |
274 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
275 "sendfile: %d, @%O %O:%O", | |
276 rc, file->file_pos, sent, file_size + header_size); | |
277 | |
278 } else { | |
279 rc = writev(c->fd, header.elts, header.nelts); | |
280 | |
281 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
282 "writev: %d of %uz", rc, send); | |
283 | |
284 if (rc == -1) { | |
285 err = ngx_errno; | |
286 | |
287 if (err == NGX_EAGAIN || err == NGX_EINTR) { | |
288 if (err == NGX_EINTR) { | |
289 eintr = 1; | |
290 } | |
291 | |
292 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, | |
293 "writev() not ready"); | |
294 | |
295 } else { | |
296 wev->error = 1; | |
297 ngx_connection_error(c, err, "writev() failed"); | |
298 return NGX_CHAIN_ERROR; | |
299 } | |
300 } | |
301 | |
302 sent = rc > 0 ? rc : 0; | |
303 } | |
304 | |
305 if (send - prev_send == sent) { | |
306 complete = 1; | |
307 } | |
308 | |
309 c->sent += sent; | |
310 | |
311 for (cl = in; cl; cl = cl->next) { | |
312 | |
313 if (ngx_buf_special(cl->buf)) { | |
314 continue; | |
315 } | |
316 | |
317 if (sent == 0) { | |
318 break; | |
319 } | |
320 | |
321 size = ngx_buf_size(cl->buf); | |
322 | |
323 if (sent >= size) { | |
324 sent -= size; | |
325 | |
326 if (ngx_buf_in_memory(cl->buf)) { | |
327 cl->buf->pos = cl->buf->last; | |
328 } | |
329 | |
330 if (cl->buf->in_file) { | |
331 cl->buf->file_pos = cl->buf->file_last; | |
332 } | |
333 | |
334 continue; | |
335 } | |
336 | |
337 if (ngx_buf_in_memory(cl->buf)) { | |
338 cl->buf->pos += (size_t) sent; | |
339 } | |
340 | |
341 if (cl->buf->in_file) { | |
342 cl->buf->file_pos += sent; | |
343 } | |
344 | |
345 break; | |
346 } | |
347 | |
348 if (eintr) { | |
349 continue; | |
350 } | |
351 | |
352 if (!complete) { | |
353 wev->ready = 0; | |
354 return cl; | |
355 } | |
356 | |
357 if (send >= limit || cl == NULL) { | |
358 return cl; | |
359 } | |
360 | |
361 in = cl; | |
362 } | |
363 } |