Mercurial > hg > nginx
comparison src/os/unix/ngx_linux_sendfile_chain.c @ 97:70d2345a903f
nginx-0.0.1-2003-05-29-17:02:09 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Thu, 29 May 2003 13:02:09 +0000 |
parents | |
children | 8dee38ea9117 |
comparison
equal
deleted
inserted
replaced
96:a23d010f356d | 97:70d2345a903f |
---|---|
1 | |
2 #include <ngx_config.h> | |
3 #include <ngx_core.h> | |
4 #include <ngx_linux_init.h> | |
5 | |
6 | |
7 ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) | |
8 { | |
9 int rc, on, off; | |
10 char *prev; | |
11 size_t hsize, size; | |
12 ssize_t sent; | |
13 struct iovec *iov; | |
14 struct sf_hdtr hdtr; | |
15 ngx_err_t err; | |
16 ngx_array_t header, trailer; | |
17 ngx_hunk_t *file; | |
18 ngx_chain_t *ce; | |
19 | |
20 ce = in; | |
21 file = NULL; | |
22 hsize = 0; | |
23 | |
24 on = 1; | |
25 off = 0; | |
26 | |
27 ngx_init_array(header, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); | |
28 ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); | |
29 | |
30 /* create the header iovec */ | |
31 if (ngx_hunk_in_memory_only(ce->hunk)) { | |
32 prev = NULL; | |
33 iov = NULL; | |
34 | |
35 /* create the iovec and coalesce the neighbouring chain entries */ | |
36 while (ce && ngx_hunk_in_memory_only(ce->hunk)) { | |
37 | |
38 if (prev == ce->hunk->pos) { | |
39 iov->iov_len += ce->hunk->last - ce->hunk->pos; | |
40 prev = ce->hunk->last; | |
41 | |
42 } else { | |
43 ngx_test_null(iov, ngx_push_array(&header), NGX_CHAIN_ERROR); | |
44 iov->iov_base = ce->hunk->pos; | |
45 iov->iov_len = ce->hunk->last - ce->hunk->pos; | |
46 prev = ce->hunk->last; | |
47 } | |
48 | |
49 if (ngx_freebsd_sendfile_nbytes_bug) { | |
50 hsize += ce->hunk->last - ce->hunk->pos; | |
51 } | |
52 | |
53 ce = ce->next; | |
54 } | |
55 } | |
56 | |
57 /* TODO: coalesce the neighbouring file hunks */ | |
58 if (ce && (ce->hunk->type & NGX_HUNK_FILE)) { | |
59 file = ce->hunk; | |
60 ce = ce->next; | |
61 } | |
62 | |
63 /* create the trailer iovec */ | |
64 if (ce && ngx_hunk_in_memory_only(ce->hunk)) { | |
65 prev = NULL; | |
66 iov = NULL; | |
67 | |
68 /* create the iovec and coalesce the neighbouring chain entries */ | |
69 while (ce && ngx_hunk_in_memory_only(ce->hunk)) { | |
70 | |
71 if (prev == ce->hunk->pos) { | |
72 iov->iov_len += ce->hunk->last - ce->hunk->pos; | |
73 prev = ce->hunk->last; | |
74 | |
75 } else { | |
76 ngx_test_null(iov, ngx_push_array(&trailer), NGX_CHAIN_ERROR); | |
77 iov->iov_base = ce->hunk->pos; | |
78 iov->iov_len = ce->hunk->last - ce->hunk->pos; | |
79 prev = ce->hunk->last; | |
80 } | |
81 | |
82 ce = ce->next; | |
83 } | |
84 } | |
85 | |
86 if (file) { | |
87 if (setsockopt(c->fd, IPPROTO_TCP, TCP_CORK, | |
88 (const void *) &on, sizeof(int)) == -1) { | |
89 ngx_log_error(NGX_LOG_CRIT, c->log, err, | |
90 "setsockopt(TCP_CORK, 1) failed"); | |
91 return NGX_CHAIN_ERROR; | |
92 } | |
93 | |
94 | |
95 rc = sendfile(c->fd, file->file->fd, file->file_pos, | |
96 (size_t) (file->file_last - file->file_pos)); | |
97 | |
98 if (rc == -1) { | |
99 err = ngx_errno; | |
100 if (err == NGX_EAGAIN) { | |
101 ngx_log_error(NGX_LOG_INFO, c->log, err, "senfile() EAGAIN"); | |
102 | |
103 } else if (err == NGX_EINTR) { | |
104 ngx_log_error(NGX_LOG_INFO, c->log, err, "senfile() EINTR"); | |
105 | |
106 } else { | |
107 ngx_log_error(NGX_LOG_CRIT, c->log, err, "sendfile() failed"); | |
108 return NGX_CHAIN_ERROR; | |
109 } | |
110 } | |
111 | |
112 sent = rc > 0 ? rc : 0; | |
113 | |
114 #if (NGX_DEBUG_WRITE_CHAIN) | |
115 ngx_log_debug(c->log, "sendfile: %d, @%qd %d:%d" _ | |
116 rc _ file->file_pos _ sent _ | |
117 (size_t) (file->file_last - file->file_pos)); | |
118 #endif | |
119 | |
120 } else { | |
121 rc = writev(c->fd, (struct iovec *) header.elts, header.nelts); | |
122 | |
123 if (rc == -1) { | |
124 err = ngx_errno; | |
125 if (err == NGX_EAGAIN) { | |
126 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN"); | |
127 | |
128 } else if (err == NGX_EINTR) { | |
129 ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR"); | |
130 | |
131 } else { | |
132 ngx_log_error(NGX_LOG_CRIT, c->log, err, "writev() failed"); | |
133 return NGX_CHAIN_ERROR; | |
134 } | |
135 } | |
136 | |
137 sent = rc > 0 ? rc : 0; | |
138 | |
139 #if (NGX_DEBUG_WRITE_CHAIN) | |
140 ngx_log_debug(c->log, "writev: %d" _ sent); | |
141 #endif | |
142 } | |
143 | |
144 c->sent += sent; | |
145 | |
146 for (ce = in; ce && sent > 0; ce = ce->next) { | |
147 | |
148 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { | |
149 size = ce->hunk->last - ce->hunk->pos; | |
150 } else { | |
151 size = ce->hunk->file_last - ce->hunk->file_pos; | |
152 } | |
153 | |
154 if (sent >= size) { | |
155 sent -= size; | |
156 | |
157 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { | |
158 ce->hunk->pos = ce->hunk->last; | |
159 } | |
160 | |
161 if (ce->hunk->type & NGX_HUNK_FILE) { | |
162 ce->hunk->file_pos = ce->hunk->file_last; | |
163 } | |
164 | |
165 continue; | |
166 } | |
167 | |
168 if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { | |
169 ce->hunk->pos += sent; | |
170 } | |
171 | |
172 if (ce->hunk->type & NGX_HUNK_FILE) { | |
173 ce->hunk->file_pos += sent; | |
174 } | |
175 | |
176 break; | |
177 } | |
178 | |
179 ngx_destroy_array(&trailer); | |
180 ngx_destroy_array(&header); | |
181 | |
182 return ce; | |
183 } |