1 /*
2 * buffer2socket.c
3 * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
4 * All rights reserved.
5 *
6 * $Id: buffer2socket.c,v 1.15 2015/03/14 06:11:24 marc Exp marc $
7 *
8 */
9
10 #include "headers.h"
11 #include <sys/uio.h>
12 #include "misc/mysendfile.h"
13
14 static const char rcsid[] __attribute__ ((used)) = "$Id: buffer2socket.c,v 1.15 2015/03/14 06:11:24 marc Exp marc $";
15
calculate_shape(struct context * ctx)16 static int calculate_shape(struct context *ctx)
17 {
18 /*
19 * Dealing with tv_usec probably isn't worth it, as our transfer buffer is
20 * far too large for handling arbitrary precision.
21 */
22 if (ctx->shape_bandwidth)
23 ctx->tv_shape.tv_sec = ctx->transferstart - io_now.tv_sec + (time_t) (ctx->bytecount / ctx->shape_bandwidth);
24 else
25 ctx->tv_shape.tv_sec = 0;
26 return ctx->tv_shape.tv_sec > 0;
27 }
28
set_out(struct context * ctx,int i)29 static void set_out(struct context *ctx, int i __attribute__ ((unused)))
30 {
31 Debug((DEBUG_PROC, "set_out(%d)\n", ctx->dfn));
32 if (ctx && ctx->dfn > -1) {
33 io_sched_pop(ctx->io, ctx);
34 io_set_o(ctx->io, ctx->dfn);
35 }
36 }
37
buffer2socket(struct context * ctx,int cur)38 void buffer2socket(struct context *ctx, int cur __attribute__ ((unused)))
39 {
40 ssize_t l = -1;
41 struct buffer *db;
42
43 DebugIn(DEBUG_BUFFER);
44
45 io_sched_renew_proc(ctx->io, ctx, (void *) cleanup);
46
47 sigbus_cur = ctx->ffn;
48
49 ctx->buffer_filled = 0;
50
51 if (ctx->iomode == IOMODE_read
52 #ifdef WITH_MMAP
53 || ctx->iomode == IOMODE_mmap
54 #endif /* WITH_MMAP */
55 )
56
57 if (ctx->filename[0] && chunk_get(ctx, &ctx->io_offset)) {
58 reply(ctx, MSG_451_Internal_error);
59 cleanup_file(ctx, ctx->ffn);
60 cleanup_data(ctx, ctx->dfn);
61 Debug((DEBUG_BUFFER, "- %s: chunk_get failure\n", __func__));
62 return;
63 }
64
65 db = ctx->dbufi;
66
67 #ifdef WITH_ZLIB
68 if (ctx->mode == 'z' && ctx->dbufi && !ctx->filename[0]) {
69 struct buffer *out, *in;
70 ctx->deflate_level = 9;
71 ctx->zstream = Xcalloc(1, sizeof(z_stream));
72 Debug((DEBUG_PROC, "deflate_level = %d\n", ctx->deflate_level));
73 if (Z_OK != deflateInit2(ctx->zstream, ctx->deflate_level, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY)) {
74 deflateEnd(ctx->zstream);
75 Xfree(&ctx->zstream);
76 goto fatal;
77 }
78 in = ctx->dbufi;
79 ctx->dbufi = NULL;
80 db = ctx->dbuf = out = buffer_get();
81
82 ctx->zstream->avail_out = out->size - out->length;
83
84 ctx->filesize = 0;
85
86 while (in) {
87 int len;
88 int res;
89
90 if (out->length == out->size || ctx->zstream->avail_out == 0) {
91 out = buffer_append(out, buffer_get());
92 out = out->next;
93 }
94
95 ctx->zstream->next_in = (u_char *) in->buf + in->offset;
96 ctx->zstream->avail_in = in->length - in->offset;
97
98 ctx->zstream->next_out = (u_char *) out->buf + out->length;
99 ctx->zstream->avail_out = out->size - out->length;
100
101 res = deflate(ctx->zstream, in->next ? Z_NO_FLUSH : Z_FINISH);
102 len = (int) ((char *) ctx->zstream->next_in - in->buf - in->offset);
103 ctx->filesize += len;
104 out->length = (char *) ctx->zstream->next_out - out->buf;
105 switch (res) {
106 case Z_OK:
107 Debug((DEBUG_PROC, "Z_OK\n"));
108 in = buffer_truncate(in, (off_t) len);
109 break;
110 case Z_STREAM_END:
111 Debug((DEBUG_PROC, "Z_STREAM_END\n"));
112 in = buffer_free(in);
113 deflateEnd(ctx->zstream);
114 Xfree(&ctx->zstream);
115 break;
116 default:
117 in = buffer_free(in);
118 deflateEnd(ctx->zstream);
119 Xfree(&ctx->zstream);
120 goto fatal;
121 }
122 }
123 }
124 #endif
125
126 if (!ctx->dbufi && !ctx->dbuf
127 #ifdef WITH_SENDFILE
128 && ctx->iomode != IOMODE_sendfile
129 #endif /* WITH_SENDFILE */
130 #ifdef WITH_ZLIB
131 && !ctx->zstream
132 #endif
133 ) {
134 if (ctx->mode != 'z' || ctx->filesize == 0
135 #ifdef WITH_ZLIB
136 || ctx->deflate_level == 0
137 #endif
138 )
139 reply(ctx, MSG_226_Transfer_complete);
140 else
141 replyf(ctx, MSG_226_Transfer_completeZ, (int) (100 * ctx->bytecount / ctx->filesize), ctx->filesize - ctx->bytecount);
142
143 cleanup_file(ctx, ctx->ffn);
144 cleanup_data(ctx, ctx->dfn);
145 Debug((DEBUG_BUFFER, "- %s: buffer empty\n", __func__));
146 return;
147 } else
148 #ifdef WITH_SENDFILE
149 if (ctx->iomode == IOMODE_sendfile) {
150 size_t min;
151
152 if (ctx->io_offset > 0) {
153 ctx->offset = lseek(ctx->ffn, ctx->io_offset, SEEK_SET);
154 ctx->remaining -= ctx->io_offset;
155 ctx->io_offset = 0;
156 }
157
158 min = (size_t) MIN(ctx->remaining, (off_t) bufsize);
159
160 Debug((DEBUG_PROC, "sendfile (%d, %d, %lld, %lld)\n", ctx->dfn, ctx->ffn, (long long) ctx->offset, (long long) min));
161
162 if (min > 0)
163 l = mysendfile(ctx->dfn, ctx->ffn, (off_t *) & ctx->offset, min);
164 else
165 l = 0, ctx->remaining = 0;
166
167 if (l < 0 && (!ctx->iomode_fixed || errno == EOVERFLOW)) {
168 #ifdef WITH_MMAP
169 if (use_mmap)
170 ctx->iomode = IOMODE_mmap, ctx->iomode_fixed = 0;
171 else
172 #endif /* WITH_MMAP */
173 ctx->iomode = IOMODE_read, ctx->iomode_fixed = 1;
174 ctx->io_offset = ctx->offset, ctx->remaining += ctx->offset;
175 ctx->offset = 0;
176 Debug((DEBUG_BUFFER, "- %s: sendfile fallback\n", __func__));
177 return;
178 }
179 ctx->iomode_fixed = 1, ctx->remaining -= l;
180 } /* IOMODE_sendfile */
181 else
182 #endif /* WITH_SENDFILE */
183 #ifdef WITH_ZLIB
184 if (ctx->conversion == CONV_GZ || (ctx->mode == 'z' && ctx->filename[0])) {
185 struct buffer *b;
186 char trailer[8];
187 int res;
188
189 int windowBits = (ctx->mode == 'z') ? 15 : -15;
190
191 if (!ctx->zstream) {
192 acl_set_deflate_level(ctx);
193 ctx->zstream = Xcalloc(1, sizeof(z_stream));
194 if (Z_OK != deflateInit2(ctx->zstream, ctx->deflate_level, Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY)) {
195 deflateEnd(ctx->zstream);
196 Xfree(&ctx->zstream);
197 goto fatal;
198 }
199 ctx->zcrc32 = crc32(0, NULL, 0);
200 if (ctx->mode != 'z')
201 ctx->dbuf = buffer_write(ctx->dbuf, "\037\213\010\0\0\0\0\0\0\03", 10);
202 }
203
204 ctx->zstream->next_in = (u_char *) ctx->chunk_start;
205 ctx->zstream->avail_in = ctx->chunk_length;
206
207 if (ctx->dbuf && ctx->dbuf->length < ctx->dbuf->size)
208 b = ctx->dbuf;
209 else {
210 b = buffer_get();
211 ctx->dbuf = buffer_append(ctx->dbuf, b);
212 }
213
214 ctx->zstream->next_out = (u_char *) b->buf + b->length;
215 ctx->zstream->avail_out = b->size - b->length;
216
217 res = deflate(ctx->zstream, ctx->chunk_length ? Z_NO_FLUSH : Z_FINISH);
218 switch (res) {
219 case Z_OK:
220 Debug((DEBUG_BUFFER, "Z_OK\n"));
221 if (ctx->chunk_length) {
222 int len = (int)
223 ((char *) ctx->zstream->next_in - ctx->chunk_start);
224 if (ctx->mode != 'z')
225 ctx->zcrc32 = crc32(ctx->zcrc32, (u_char *) ctx->chunk_start, len);
226 chunk_release(ctx, len);
227 }
228 b->length = (char *) ctx->zstream->next_out - b->buf;
229 break;
230 case Z_STREAM_END:
231 Debug((DEBUG_BUFFER, "Z_STREAM_END\n"));
232 b->length = (char *) ctx->zstream->next_out - b->buf;
233 if (ctx->mode != 'z') {
234 trailer[0] = 0xff & (ctx->zcrc32);
235 trailer[1] = 0xff & (ctx->zcrc32 >> 8);
236 trailer[2] = 0xff & (ctx->zcrc32 >> 16);
237 trailer[3] = 0xff & (ctx->zcrc32 >> 24);
238 trailer[4] = 0xff & (ctx->zstream->total_in);
239 trailer[5] = 0xff & (ctx->zstream->total_in >> 8);
240 trailer[6] = 0xff & (ctx->zstream->total_in >> 16);
241 trailer[7] = 0xff & (ctx->zstream->total_in >> 24);
242 b = buffer_write(b, trailer, 8);
243 }
244 deflateEnd(ctx->zstream);
245 Xfree(&ctx->zstream);
246 break;
247 default:
248 deflateEnd(ctx->zstream);
249 Xfree(&ctx->zstream);
250 goto fatal;
251 }
252 db = ctx->dbuf;
253 } else
254 #endif
255 if (ctx->use_ascii && !ctx->ascii_in_buffer) {
256 if (ctx->chunk_start && ctx->chunk_length > 0) {
257 char lastchar = ctx->lastchar;
258 char *t, *u = ctx->chunk_start;
259 char *tl, *ul = ctx->chunk_start + ctx->chunk_length;
260 struct buffer *buf = buffer_get();
261 ctx->dbuf = buffer_append(ctx->dbuf, buf);
262
263 t = buf->buf;
264 tl = t + buf->size;
265
266 if (ctx->chunk_length > buf->size) {
267 for (; t < tl; *t++ = lastchar = *u++)
268 if (*u == '\n' && lastchar != '\r')
269 *t++ = '\r';
270 } else
271 for (; u < ul && t < tl; *t++ = lastchar = *u++)
272 if (*u == '\n' && lastchar != '\r')
273 *t++ = '\r';
274
275 buf->length = (int) (t - buf->buf);
276
277 chunk_release(ctx, (int) (u - ctx->chunk_start));
278
279 ctx->lastchar = lastchar;
280
281 if (ctx->io_offset > 0)
282 ctx->dbuf = buffer_release(ctx->dbuf, &ctx->io_offset);
283 } else
284 l = 0;
285 db = ctx->dbuf;
286 }
287 /* ascii */
288 if (db) {
289 #ifdef WITH_SSL
290 if (ctx->ssl_d) {
291 l = io_SSL_write(ctx->ssl_d, db->buf + db->offset, db->length - db->offset, ctx->io, ctx->dfn, (void *) buffer2socket);
292 } else
293 #endif /* WITH_SSL */
294 {
295 struct iovec v[10];
296 int count = 10;
297 buffer_setv(db, v, &count, bufsize);
298 if (count)
299 l = writev(ctx->dfn, v, count);
300 }
301 }
302
303 if (l < 0) {
304 if (errno != EAGAIN) {
305 #ifdef WITH_ZLIB
306 fatal:
307 #endif
308 if (ctx->filename[0])
309 ftp_log(ctx, LOG_TRANSFER, "o");
310 reply(ctx, MSG_451_Transfer_incomplete);
311 cleanup_file(ctx, ctx->ffn);
312 cleanup_data(ctx, ctx->dfn);
313 }
314 Debug((DEBUG_BUFFER, "- %s: incomplete\n", __func__));
315 return;
316 }
317
318 ctx->bytecount += l, ctx->traffic_total += l;
319 if (ctx->filename[0])
320 ctx->traffic_files += l;
321
322 if ((ctx->use_ascii && !ctx->ascii_in_buffer)
323 || ctx->conversion == CONV_GZ || (ctx->mode == 'z')) {
324 if (ctx->dbuf) {
325 off_t o = (off_t) l;
326 ctx->dbuf = buffer_release(ctx->dbuf, &o);
327 }
328 } else if (ctx->dbufi && ctx->mode != 'z' && ctx->conversion != CONV_GZ)
329 chunk_release(ctx, l);
330
331 if (!ctx->remaining)
332 cleanup_file(ctx, ctx->ffn);
333
334 if (!ctx->remaining && !ctx->dbufi && !ctx->dbuf
335 #ifdef WITH_ZLIB
336 && !ctx->zstream
337 #endif
338 ) {
339 if (ctx->filename[0])
340 ftp_log(ctx, LOG_TRANSFER, "O");
341 if (ctx->mode != 'z' || ctx->filesize == 0
342 #ifdef WITH_ZLIB
343 || ctx->deflate_level == 0
344 #endif
345 )
346 reply(ctx, MSG_226_Transfer_complete);
347 else
348 replyf(ctx, MSG_226_Transfer_completeZ, (int) (100 * ctx->bytecount / ctx->filesize), ctx->filesize - ctx->bytecount);
349 ctx->bytecount = 0;
350 cleanup_data(ctx, ctx->dfn);
351 } else if (calculate_shape(ctx)) {
352 io_clr_o(ctx->io, ctx->dfn);
353 io_sched_add(ctx->io, ctx, (void *) set_out, ctx->tv_shape.tv_sec, ctx->tv_shape.tv_usec);
354 }
355
356 DebugOut(DEBUG_BUFFER);
357 }
358