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