"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "ftp_data_filters.c" see the
Fossies "Dox" file reference documentation.
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Original Copyright (c) 2005 Covalent Technologies
19 *
20 * FTP Protocol module for Apache 2.0
21 */
22
23 #include "mod_ftp.h"
24 #include "ftp_internal.h"
25
26 /* Reimplement the core i/o filters to insert two-channel
27 * data socket buckets for send or retrieve, monitoring
28 * the control channel for sideband ABOR-like commands.
29 *
30 * These filters sit below
31 */
32
33 static apr_status_t datasock_bucket_read(apr_bucket * a, const char **str,
34 apr_size_t * len, apr_read_type_e block)
35 {
36 ftp_connection *fc = a->data;
37 apr_socket_t *sd = fc->datasock;
38 char *buf;
39 apr_status_t rv;
40 apr_interval_time_t timeout;
41 apr_interval_time_t polltimeout;
42 apr_pollfd_t pollset[2];
43 int n;
44
45 /* command socket heard already? (e.g. already polled) */
46 rv = ftp_read_ahead_request(fc);
47
48 if ((rv != APR_SUCCESS) &&
49 !(APR_STATUS_IS_EINTR(rv) || (APR_STATUS_IS_EAGAIN(rv)) ||
50 APR_STATUS_IS_EOF(rv))) {
51 return rv;
52 }
53
54 apr_socket_timeout_get(sd, &timeout);
55
56 if (block == APR_NONBLOCK_READ) {
57 apr_socket_timeout_set(sd, 0);
58 polltimeout = 0;
59 }
60 else {
61 polltimeout = timeout;
62 }
63
64 *str = NULL;
65 /* buf allocation must mirror *len initalization below */
66 buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, a->list);
67
68 pollset[0].desc_type = APR_POLL_SOCKET;
69 pollset[0].desc.s = fc->datasock;
70 pollset[0].reqevents = APR_POLLIN; /* APR_POLLOUT for write */
71 pollset[1].desc_type = APR_POLL_SOCKET;
72 pollset[1].desc.s = fc->cntlsock;
73 pollset[1].reqevents = (APR_POLLIN | APR_POLLPRI);
74 pollset[1].rtnevents = 0; /* For poll(1), pretend poll answered this */
75
76 /* XXX: evil, no apr_socket_pool_get accessor available, though */
77 pollset[1].p = pollset[0].p = *((apr_pool_t **) fc->datasock);
78
79 do {
80 /* Unset so we don't trip over the len when we don't call recv */
81 *len = 0;
82
83 /*
84 * If we have already assembled our next_request, don't bother
85 * polling the control connection - we won't read ahead two commands
86 */
87 rv = apr_poll(pollset, fc->next_request ? 1 : 2,
88 &n, polltimeout);
89 /* pedantic sanity check, this should never happen */
90 if ((rv == APR_SUCCESS) && (n < 0)) {
91 rv = APR_EGENERAL;
92 }
93
94 if (rv != APR_SUCCESS) {
95 /*
96 * The loss of either socket here means the death of the data
97 * connection. Unset the length to avoid looping
98 */
99 break;
100 }
101 if (pollset[1].rtnevents & (APR_POLLIN | APR_POLLPRI)) {
102 /* command socket heard - but with a full line yet? */
103 rv = ftp_read_ahead_request(fc);
104
105 if ((rv != APR_SUCCESS) &&
106 !(APR_STATUS_IS_EINTR(rv) || (APR_STATUS_IS_EAGAIN(rv)) ||
107 APR_STATUS_IS_EOF(rv))) {
108 apr_bucket_free(buf);
109 return rv;
110 }
111 }
112
113 if (pollset[0].rtnevents & APR_POLLIN) {
114 /* *len must mirror the apr_bucket_alloc above. */
115 *len = APR_BUCKET_BUFF_SIZE;
116 rv = apr_socket_recv(sd, buf, len);
117 }
118 } while (APR_STATUS_IS_EINTR(rv)
119 || (APR_STATUS_IS_EAGAIN(rv) && (block == APR_BLOCK_READ)));
120 /*
121 * EINTR, above, is obvious, EAGAIN is less so - win32 (perhaps others)
122 * can trigger POLLIN a little too early, before the recieved packet has
123 * actually been disassembled - so loop again.
124 */
125
126 if (block == APR_NONBLOCK_READ) {
127 apr_socket_timeout_set(sd, timeout);
128 }
129
130 if (rv != APR_SUCCESS && !APR_STATUS_IS_EOF(rv)) {
131 apr_bucket_free(buf);
132 return rv;
133 }
134 /*
135 * If there's more to read we have to keep the rest of the socket
136 * for later. XXX: Note that more complicated bucket types that
137 * refer to data not in memory and must therefore have a read()
138 * function similar to this one should be wary of copying this
139 * code because if they have a destroy function they probably
140 * want to migrate the bucket's subordinate structure from the
141 * old bucket to a raw new one and adjust it as appropriate,
142 * rather than destroying the old one and creating a completely
143 * new bucket.
144 *
145 * Even if there is nothing more to read, don't close the socket here
146 * as we have to use it to send any response :) We could shut it
147 * down for reading, but there is no benefit to doing so.
148 */
149 if (*len > 0) {
150 apr_bucket_heap *h;
151 /* Change the current bucket to refer to what we read */
152 a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free);
153 h = a->data;
154 h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */
155 *str = buf;
156 APR_BUCKET_INSERT_AFTER(a, ftp_bucket_datasock_create(fc, a->list));
157 }
158 else {
159 apr_bucket_free(buf);
160 a = apr_bucket_immortal_make(a, "", 0);
161 *str = a->data;
162 }
163 return APR_SUCCESS;
164 }
165
166 static apr_bucket *ftp_bucket_datasock_make(apr_bucket * b, ftp_connection *fc)
167 {
168 /*
169 * Note that typically the socket is allocated from the connection pool
170 * so it will disappear when the connection is finished.
171 */
172 b->type = &ftp_bucket_type_datasock;
173 b->length = (apr_size_t) (-1);
174 b->start = -1;
175 b->data = fc;
176
177 return b;
178 }
179
180 apr_bucket *ftp_bucket_datasock_create(ftp_connection *fc,
181 apr_bucket_alloc_t * list)
182 {
183 apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
184
185 APR_BUCKET_INIT(b);
186 b->free = apr_bucket_free;
187 b->list = list;
188 return ftp_bucket_datasock_make(b, fc);
189 }
190
191 const apr_bucket_type_t ftp_bucket_type_datasock = {
192 "DATASOCK",
193 5,
194 APR_BUCKET_DATA,
195 apr_bucket_destroy_noop,
196 datasock_bucket_read,
197 apr_bucket_setaside_notimpl,
198 apr_bucket_split_notimpl,
199 apr_bucket_copy_notimpl
200 };
201
202
203 apr_status_t ftp_data_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
204 {
205 ftp_connection *fc = f->ctx;
206 ftp_server_config *fsc;
207 conn_rec *c = fc->connection;
208 apr_status_t rv;
209 apr_interval_time_t polltimeout;
210 apr_pollfd_t pollset[2];
211 apr_bucket_brigade *next_bb;
212 apr_bucket *e;
213 int n;
214
215 /* command socket heard already? (e.g. already polled) */
216 rv = ftp_read_ahead_request(fc);
217
218 if ((rv != APR_SUCCESS) &&
219 !(APR_STATUS_IS_EINTR(rv) || (APR_STATUS_IS_EAGAIN(rv)) ||
220 APR_STATUS_IS_EOF(rv))) {
221 f->c->aborted = 1;
222 return rv;
223 }
224
225 fsc = ftp_get_module_config(fc->orig_server->module_config);
226
227 while (!APR_BRIGADE_EMPTY(bb)) {
228
229 /*
230 * The brigade can be far to 'chunky' to respect the ABOR tests we
231 * perform below. Dice up the raw response stream into chuncks
232 * (48000 bytes by default) and and check between each chunk for a
233 * control channel command. At 48000 this is at least 1/minute on a
234 * very slow 9600 baud line.
235 */
236 rv = apr_brigade_partition(bb, fsc->data_block_size, &e);
237 if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
238 return rv;
239 }
240 next_bb = apr_brigade_split(bb, e);
241
242 /*
243 * Poll to see if we are are prepared to pass on the brigade and the
244 * client hasn't ABORted us yet.
245 */
246 apr_socket_timeout_get(fc->datasock, &polltimeout);
247
248 pollset[0].desc_type = APR_POLL_SOCKET;
249 pollset[0].desc.s = fc->datasock;
250 pollset[0].reqevents = APR_POLLOUT;
251 pollset[1].desc_type = APR_POLL_SOCKET;
252 pollset[1].desc.s = fc->cntlsock;
253 pollset[1].reqevents = (APR_POLLIN | APR_POLLPRI);
254 pollset[1].rtnevents = 0; /* For poll(1), pretend poll answered
255 * this */
256
257 /* XXX: evil, no apr_socket_pool_get accessor available, though */
258 pollset[1].p = pollset[0].p = *((apr_pool_t **) fc->datasock);
259
260 do {
261 /*
262 * If we have already assembled our next_request, don't bother
263 * polling the control connection - we won't read ahead two
264 * commands
265 */
266 rv = apr_poll(pollset, fc->next_request ? 1 : 2,
267 &n, polltimeout);
268 /* pedantic sanity check, this should never happen */
269 if ((rv == APR_SUCCESS) && (n < 0)) {
270 rv = APR_EGENERAL;
271 }
272
273 if (rv != APR_SUCCESS) {
274 /*
275 * The loss of either socket here means the death of the data
276 * connection.
277 */
278 break;
279 }
280
281 if (pollset[1].rtnevents & (APR_POLLIN | APR_POLLPRI)) {
282 /* command socket heard - but with a full line yet? */
283 rv = ftp_read_ahead_request(fc);
284
285 if ((rv != APR_SUCCESS) &&
286 !(APR_STATUS_IS_EINTR(rv) || (APR_STATUS_IS_EAGAIN(rv)) ||
287 APR_STATUS_IS_EOF(rv))) {
288 f->c->aborted = 1;
289 return rv;
290 }
291 }
292
293 if ((rv == APR_SUCCESS) && (pollset[0].rtnevents & APR_POLLOUT)) {
294 break;
295 }
296 } while (APR_STATUS_IS_EINTR(rv) || APR_STATUS_IS_EAGAIN(rv));
297 /*
298 * EINTR, above, is obvious, EAGAIN is less so - win32 (perhaps
299 * others) can trigger POLLIN a little too early, before the recieved
300 * packet has actually been disassembled - so loop again.
301 */
302
303 if (c->aborted || f->c->aborted) {
304 return AP_FILTER_ERROR;
305 }
306
307 rv = ap_pass_brigade(f->next, bb);
308 if (rv != APR_SUCCESS) {
309 f->c->aborted = 1;
310 return rv;
311 }
312 bb = next_bb;
313 }
314
315 return APR_SUCCESS;
316 }