src/server/util/io.c

changeset 110
43a746e905f6
parent 106
b122f34ddc80
child 112
b962d83124bc
equal deleted inserted replaced
109:8a0a7754f123 110:43a746e905f6
35 #include <sys/uio.h> 35 #include <sys/uio.h>
36 #include <sys/uio.h> 36 #include <sys/uio.h>
37 #ifndef BSD 37 #ifndef BSD
38 #include <sys/sendfile.h> 38 #include <sys/sendfile.h>
39 #endif 39 #endif
40 #include <limits.h> /* asprintf */
41 40
42 #include "../daemon/vfs.h" 41 #include "../daemon/vfs.h"
43 #include "io.h" 42 #include "io.h"
44 #include "pool.h" 43 #include "pool.h"
44 #include "ucx/utils.h"
45 45
46 IOStream native_io_funcs = { 46 IOStream native_io_funcs = {
47 system_write, 47 (io_write_f)net_sys_write,
48 system_writev, 48 (io_writev_f)net_sys_writev,
49 system_read, 49 (io_read_f)net_sys_read,
50 NULL, 50 (io_sendfile_f)net_sys_sendfile,
51 NULL, 51 (io_close_f)net_sys_close,
52 NULL 52 NULL
53 }; 53 };
54 54
55 IOStream net_io_funcs = { 55 IOStream http_io_funcs = {
56 (io_write_f)net_stream_write, 56 (io_write_f)net_http_write,
57 (io_writev_f)net_stream_writev, 57 (io_writev_f)net_http_writev,
58 (io_read_f)net_stream_read, 58 (io_read_f)net_http_read,
59 (io_sendfile_f)net_stream_sendfile, 59 (io_sendfile_f)net_http_sendfile,
60 (io_close_f)net_stream_close, 60 (io_close_f)net_http_close,
61 (io_finish_f)net_stream_finish 61 (io_finish_f)net_http_finish
62 }; 62 };
63 63
64 IOStream ssl_io_funcs = { 64 IOStream ssl_io_funcs = {
65 (io_write_f)net_ssl_write, 65 (io_write_f)net_ssl_write,
66 (io_writev_f)net_ssl_writev, 66 (io_writev_f)net_ssl_writev,
69 (io_close_f)net_ssl_close, 69 (io_close_f)net_ssl_close,
70 (io_finish_f)net_ssl_finish 70 (io_finish_f)net_ssl_finish
71 }; 71 };
72 72
73 73
74 IOStream* stream_new_from_fd(pool_handle_t *pool, int fd) { 74 /*
75 SystemIOStream *st = pool_malloc(pool, sizeof(SystemIOStream)); 75 * SysStream implementation
76 */
77
78 IOStream* sysstream_new(pool_handle_t *pool, int fd) {
79 SysStream *st = pool_malloc(pool, sizeof(SysStream));
76 st->st = native_io_funcs; 80 st->st = native_io_funcs;
77 st->fd = fd; 81 st->fd = fd;
78 return (IOStream*)st; 82 return (IOStream*)st;
79 } 83 }
80 84
81 ssize_t system_write(IOStream *st, void *buf, size_t nbytes) { 85 #ifdef XP_UNIX
82 return write(((SystemIOStream*)st)->fd, buf, nbytes); 86 ssize_t net_sys_write(SysStream *st, void *buf, size_t nbytes) {
83 } 87 return write(st->fd, buf, nbytes);
84 88 }
85 ssize_t system_writev(IOStream *st, struct iovec *iovec, int iovcnt) { 89
86 return writev(((SystemIOStream*)st)->fd, iovec, iovcnt); 90 ssize_t net_sys_writev(SysStream *st, struct iovec *iovec, int iovcnt) {
87 } 91 return writev(st->fd, iovec, iovcnt);
88 92 }
89 ssize_t system_read(IOStream *st, void *buf, size_t nbytes) { 93
90 return read(((SystemIOStream*)st)->fd, buf, nbytes); 94 ssize_t net_sys_read(SysStream *st, void *buf, size_t nbytes) {
91 } 95 return read(st->fd, buf, nbytes);
92 96 }
93 97
94 IOStream* net_stream_from_fd(pool_handle_t *pool, int fd) { 98 ssize_t net_sys_sendfile(SysStream *st, sendfiledata *sfd) {
95 NetIOStream *st = pool_malloc(pool, sizeof(NetIOStream));
96 st->st = net_io_funcs;
97 st->fd = fd;
98 st->max_read = 0;
99 st->read = 0;
100 st->chunked_enc = 0;
101 st->buffered = 0;
102 return (IOStream*)st;
103 }
104
105 ssize_t net_stream_write(NetIOStream *st, void *buf, size_t nbytes) {
106 if(st->chunked_enc) {
107 // TODO: on some plattforms iov_len is smaller than size_t
108 struct iovec io[2];
109 char chunk_len[16];
110 io[0].iov_base = chunk_len;
111 io[0].iov_len = snprintf(chunk_len, 16, "\r\n%zx\r\n", nbytes);
112 io[1].iov_base = buf;
113 io[1].iov_len = nbytes;
114 ssize_t r = writev(st->fd, io, 2);
115 return r - io[0].iov_len;
116 } else {
117 return write(st->fd, buf, nbytes);
118 }
119 }
120
121 ssize_t net_stream_writev(NetIOStream *st, struct iovec *iovec, int iovcnt) {
122 if(st->chunked_enc) {
123 struct iovec *io = calloc(iovcnt + 1, sizeof(struct iovec));
124 char chunk_len[16];
125 io[0].iov_base = chunk_len;
126 size_t len = 0;
127 for(int i=0;i<iovcnt;i++) {
128 len += iovec[i].iov_len;
129 }
130 io[0].iov_len = snprintf(chunk_len, 16, "\r\n%zx\r\n", len);
131 memcpy(io + 1, iovec, iovcnt * sizeof(struct iovec));
132 ssize_t r = writev(st->fd, io, iovcnt + 1);
133 return r - io[0].iov_len;
134 } else {
135 return writev(st->fd, iovec, iovcnt);
136 }
137 }
138
139 ssize_t net_stream_read(NetIOStream *st, void *buf, size_t nbytes) {
140 if(st->max_read != 0 && st->read >= st->max_read) {
141 return 0;
142 }
143 ssize_t r = read(st->fd, buf, nbytes);
144 st->read += r;
145 return r;
146 }
147
148 ssize_t net_stream_sendfile(NetIOStream *st, sendfiledata *sfd) {
149 ssize_t ret = 0; 99 ssize_t ret = 0;
150 off_t fileoffset = sfd->offset; 100 off_t fileoffset = sfd->offset;
151 if(sfd->fd->fd != -1) { 101 if(sfd->fd->fd != -1) {
152 #ifdef BSD 102 #ifdef BSD
153 struct iovec hdvec; 103 struct iovec hdvec;
190 } 140 }
191 141
192 return ret; 142 return ret;
193 } 143 }
194 144
195 void net_stream_close(NetIOStream *st) { 145 void net_sys_close(SysStream *st) {
196 close(st->fd); 146 close(st->fd);
197 } 147 }
198 148
199 void net_stream_finish(NetIOStream *st) { 149 #elif defined(XP_WIN32)
150
151 ssize_t net_sys_write(SysStream *st, void *buf, size_t nbytes) {
152 int ret = send(st->socket, buf, nbytes, 0);
153 if(ret == SOCKET_ERROR) {
154 return IO_ERROR;
155 }
156 return ret;
157 }
158
159 ssize_t net_sys_writev(SysStream *st, struct iovec *iovec, int iovcnt) {
160 // TODO
161 }
162
163 ssize_t net_sys_read(SysStream *st, void *buf, size_t nbytes) {
164 int ret = recv(st->socket, buf, nbytes, 0);
165 if(ret == SOCKET_ERROR) {
166 return IO_ERROR;
167 }
168 return ret;
169 }
170
171 ssize_t net_sys_sendfile(SysStream *st, sendfiledata *sfd) {
172 // TODO
173 }
174
175 void net_sys_close(SysStream *st) {
176 closesocket(st->socket);
177 }
178
179 #endif
180
181
182 /*
183 * HttpStream implementation
184 */
185
186 IOStream* httpstream_new(pool_handle_t *pool, IOStream *fd) {
187 HttpStream *st = pool_malloc(pool, sizeof(HttpStream));
188 st->st = http_io_funcs;
189 st->fd = fd;
190 st->max_read = 0;
191 st->read = 0;
192 st->chunked_enc = WS_FALSE;
193 st->buffered = WS_FALSE;
194 return (IOStream*)st;
195 }
196
197 ssize_t net_http_write(HttpStream *st, void *buf, size_t nbytes) {
198 IOStream *fd = st->fd;
200 if(st->chunked_enc) { 199 if(st->chunked_enc) {
201 write(st->fd, "0\r\n\r\n", 5); 200 // TODO: on some plattforms iov_len is smaller than size_t
202 } 201 struct iovec io[2];
203 } 202 char chunk_len[16];
204 203 io[0].iov_base = chunk_len;
205 204 io[0].iov_len = snprintf(chunk_len, 16, "\r\n%zx\r\n", nbytes);
206 /* ssl stream */ 205 io[1].iov_base = buf;
207 IOStream* net_ssl_stream(pool_handle_t *pool, SSL *ssl) { 206 io[1].iov_len = nbytes;
207 ssize_t r = fd->writev(fd, io, 2);
208 return r - io[0].iov_len;
209 } else {
210 return fd->write(fd, buf, nbytes);
211 }
212 }
213
214 ssize_t net_http_writev(HttpStream *st, struct iovec *iovec, int iovcnt) {
215 IOStream *fd = st->fd;
216 if(st->chunked_enc) {
217 struct iovec *io = calloc(iovcnt + 1, sizeof(struct iovec));
218 char chunk_len[16];
219 io[0].iov_base = chunk_len;
220 size_t len = 0;
221 for(int i=0;i<iovcnt;i++) {
222 len += iovec[i].iov_len;
223 }
224 io[0].iov_len = snprintf(chunk_len, 16, "\r\n%zx\r\n", len);
225 memcpy(io + 1, iovec, iovcnt * sizeof(struct iovec));
226 ssize_t r = fd->writev(fd, io, iovcnt + 1);
227 return r - io[0].iov_len;
228 } else {
229 return fd->writev(fd, iovec, iovcnt);
230 }
231 }
232
233 ssize_t net_http_read(HttpStream *st, void *buf, size_t nbytes) {
234 if(st->max_read != 0 && st->read >= st->max_read) {
235 return 0;
236 }
237 ssize_t r = st->fd->read(st->fd, buf, nbytes);
238 st->read += r;
239 return r;
240 }
241
242 ssize_t net_http_sendfile(HttpStream *st, sendfiledata *sfd) {
243 ssize_t ret = 0;
244 if(st->fd->sendfile) {
245 ret = st->fd->sendfile(st->fd, sfd);
246 } else {
247
248 }
249
250 return ret;
251 }
252
253 void net_http_close(HttpStream *st) {
254 st->fd->close(st->fd);
255 }
256
257 void net_http_finish(HttpStream *st) {
258 if(st->chunked_enc) {
259 st->fd->write(st->fd, "0\r\n\r\n", 5);
260 }
261 }
262
263
264 /*
265 * SSLStream implementation
266 */
267
268 IOStream* sslstream_new(pool_handle_t *pool, SSL *ssl) {
208 SSLStream *st = pool_malloc(pool, sizeof(SSLStream)); 269 SSLStream *st = pool_malloc(pool, sizeof(SSLStream));
209 st->st = ssl_io_funcs; 270 st->st = ssl_io_funcs;
210 st->ssl = ssl; 271 st->ssl = ssl;
211 return (IOStream*)st; 272 return (IOStream*)st;
212 } 273 }
239 void net_ssl_finish(SSLStream *st) { 300 void net_ssl_finish(SSLStream *st) {
240 301
241 } 302 }
242 303
243 304
305 /* -------------------- public nsapi network functions -------------------- */
306
244 ssize_t net_read(SYS_NETFD fd, void *buf, size_t nbytes) { 307 ssize_t net_read(SYS_NETFD fd, void *buf, size_t nbytes) {
245 ssize_t r = ((IOStream*)fd)->read(fd, buf, nbytes); 308 ssize_t r = ((IOStream*)fd)->read(fd, buf, nbytes);
246 if(r == 0) { 309 if(r == 0) {
247 return IO_EOF; 310 return IO_EOF;
248 } 311 }
266 } 329 }
267 330
268 ssize_t net_printf(SYS_NETFD fd, char *format, ...) { 331 ssize_t net_printf(SYS_NETFD fd, char *format, ...) {
269 va_list arg; 332 va_list arg;
270 va_start(arg, format); 333 va_start(arg, format);
271 char *buf; 334 sstr_t buf = ucx_vasprintf(ucx_default_allocator(), format, arg);
272 ssize_t len = vasprintf(&buf, format, arg); 335 ssize_t r = net_write(fd, buf.ptr, buf.length);
273 ssize_t r = net_write(fd, buf, len); 336 free(buf.ptr);
274 free(buf);
275 return r; 337 return r;
276 } 338 }
277 339
278 ssize_t net_sendfile(SYS_NETFD fd, sendfiledata *sfd) { 340 ssize_t net_sendfile(SYS_NETFD fd, sendfiledata *sfd) {
279 NetIOStream *out = fd; 341 IOStream *out = fd;
280 if(out->st.sendfile && sfd->fd && sfd->fd->fd != -1) { 342 if(out->sendfile && sfd->fd && sfd->fd->fd != -1) {
281 ssize_t r = ((IOStream*)fd)->sendfile(fd, sfd); 343 ssize_t r = out->sendfile(fd, sfd);
282 if(r < 0) { 344 if(r < 0) {
283 return IO_ERROR; 345 return IO_ERROR;
284 } 346 }
285 } else { 347 } else {
286 // stream/file does not support sendfile 348 // stream/file does not support sendfile
287 // do regular copy 349 // do regular copy
288 char *buf = malloc(4096); 350 return net_copy_file(out, sfd);
289 if(!buf) { 351 }
290 // TODO: out of memory error 352 return IO_ERROR;
291 return IO_ERROR; 353 }
292 } 354
293 char *header = (char*)sfd->header; 355 // private
294 int hlen = sfd->hlen; 356 ssize_t net_copy_file(IOStream *fd, sendfiledata *sfd) {
295 char *trailer = (char*)sfd->trailer; 357 char *buf = malloc(4096);
296 int tlen = sfd->tlen; 358 if(!buf) {
297 if(header == NULL) { 359 // TODO: out of memory error
298 hlen = 0; 360 return IO_ERROR;
299 } 361 }
300 if(trailer == NULL) { 362 char *header = (char*)sfd->header;
301 tlen = 0; 363 int hlen = sfd->hlen;
302 } 364 char *trailer = (char*)sfd->trailer;
303 365 int tlen = sfd->tlen;
304 ssize_t r; 366 if(header == NULL) {
305 while(hlen > 0) { 367 hlen = 0;
306 r = out->st.write(fd, header, hlen); 368 }
307 header += r; 369 if(trailer == NULL) {
308 hlen -= r; 370 tlen = 0;
309 if(r <= 0) { 371 }
310 free(buf); 372
311 return IO_ERROR; 373 ssize_t r;
312 } 374 while(hlen > 0) {
313 } 375 r = fd->write(fd, header, hlen);
314 376 header += r;
315 if(system_lseek(sfd->fd, sfd->offset, SEEK_SET) == -1) { 377 hlen -= r;
378 if(r <= 0) {
316 free(buf); 379 free(buf);
317 return IO_ERROR; 380 return IO_ERROR;
318 } 381 }
319 382 }
320 size_t length = sfd->len; 383
321 while(length > 0) { 384 if(system_lseek(sfd->fd, sfd->offset, SEEK_SET) == -1) {
322 if((r = system_fread(sfd->fd, buf, 4096)) <= 0) {
323 break;
324 }
325 char *write_buf = buf;
326 while(r > 0) {
327 ssize_t w = out->st.write(fd, write_buf, r);
328 r -= w;
329 length -= w;
330 write_buf += w;
331 }
332 }
333 free(buf); 385 free(buf);
334 if(length > 0) { 386 return IO_ERROR;
387 }
388
389 size_t length = sfd->len;
390 while(length > 0) {
391 if((r = system_fread(sfd->fd, buf, 4096)) <= 0) {
392 break;
393 }
394 char *write_buf = buf;
395 while(r > 0) {
396 ssize_t w = fd->write(fd, write_buf, r);
397 r -= w;
398 length -= w;
399 write_buf += w;
400 }
401 }
402 free(buf);
403 if(length > 0) {
404 return IO_ERROR;
405 }
406
407 while(tlen > 0) {
408 r = fd->write(fd, trailer, tlen);
409 trailer += r;
410 tlen -= r;
411 if(r <= 0) {
335 return IO_ERROR; 412 return IO_ERROR;
336 } 413 }
337 414 }
338 while(tlen > 0) { 415
339 r = out->st.write(fd, trailer, tlen); 416 return sfd->hlen + sfd->len + sfd->tlen;
340 trailer += r;
341 tlen -= r;
342 if(r <= 0) {
343 return IO_ERROR;
344 }
345 }
346
347 return sfd->hlen + sfd->len + sfd->tlen;
348 }
349 return IO_ERROR;
350 } 417 }
351 418
352 int net_flush(SYS_NETFD sd) { 419 int net_flush(SYS_NETFD sd) {
353 // TODO: implement 420 // TODO: implement
354 return 0; 421 return 0;
356 423
357 void net_close(SYS_NETFD fd) { 424 void net_close(SYS_NETFD fd) {
358 ((IOStream*)fd)->close(fd); 425 ((IOStream*)fd)->close(fd);
359 } 426 }
360 427
428 // private
361 void net_finish(SYS_NETFD fd) { 429 void net_finish(SYS_NETFD fd) {
362 ((IOStream*)fd)->finish(fd); 430 ((IOStream*)fd)->finish(fd);
363 } 431 }
364
365
366 /* iovec buffer */
367 iovec_buf_t *iovec_buf_create(pool_handle_t *pool) {
368 iovec_buf_t *buf = pool_malloc(pool, sizeof(iovec_buf_t));
369
370 buf->pool = pool;
371 buf->iov = pool_calloc(pool, 32, sizeof(struct iovec));
372 buf->maxiovec = 32;
373 buf->iovctn = 0;
374
375 return buf;
376 }
377
378 void iovec_buf_write(iovec_buf_t *io, void *buf, size_t nbyte) {
379 if(io->iovctn >= io->maxiovec) {
380 io->iov = pool_realloc(
381 io->pool,
382 io->iov,
383 (io->maxiovec + 16) * sizeof(struct iovec));
384 }
385
386 io->iov[io->iovctn].iov_base = buf;
387 io->iov[io->iovctn].iov_len = nbyte;
388 io->iovctn++;
389 }
390
391 ssize_t iovec_buf_flush(iovec_buf_t *io, int fd) {
392 return writev(fd, io->iov, io->iovctn);
393 }
394
395
396 /* TODO: add asprintf to new file */
397
398 /*
399 * asprintf implementation for Solaris 10
400 * source from OpenSolaris
401 * file: /onnv/onnv-gate/usr/src/lib/libc/port/print/asprintf.c
402 */
403
404 /*
405 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
406 * Use is subject to license terms.
407 */
408
409 /*
410 * Copyright (c) 2004 Darren Tucker.
411 *
412 * Based originally on asprintf.c from OpenBSD:
413 * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
414 *
415 * Permission to use, copy, modify, and distribute this software for any
416 * purpose with or without fee is hereby granted, provided that the above
417 * copyright notice and this permission notice appear in all copies.
418 *
419 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
420 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
421 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
422 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
423 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
424 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
425 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
426 */
427
428 #ifdef __SunOS_5_10
429
430 #define INIT_SZ 128
431
432 /* VARARGS2 */
433 int
434 vasprintf(char **str, const char *format, va_list ap)
435 {
436 char string[INIT_SZ];
437 char *newstr;
438 int ret;
439 size_t len;
440
441 *str = NULL;
442 ret = vsnprintf(string, INIT_SZ, format, ap);
443 if (ret < 0) /* retain the value of errno from vsnprintf() */
444 return (-1);
445 if (ret < INIT_SZ) {
446 len = ret + 1;
447 if ((newstr = malloc(len)) == NULL)
448 return (-1); /* retain errno from malloc() */
449 (void) strlcpy(newstr, string, len);
450 *str = newstr;
451 return (ret);
452 }
453 /*
454 * We will perform this loop more than once only if some other
455 * thread modifies one of the vasprintf() arguments after our
456 * previous call to vsnprintf().
457 */
458 for (;;) {
459 if (ret == INT_MAX) { /* Bad length */
460 errno = ENOMEM;
461 return (-1);
462 }
463 len = ret + 1;
464 if ((newstr = malloc(len)) == NULL)
465 return (-1); /* retain errno from malloc() */
466 ret = vsnprintf(newstr, len, format, ap);
467 if (ret < 0) { /* retain errno from vsnprintf() */
468 free(newstr);
469 return (-1);
470 }
471 if (ret < len) {
472 *str = newstr;
473 return (ret);
474 }
475 free(newstr);
476 }
477 }
478
479 int
480 asprintf(char **str, const char *format, ...)
481 {
482 va_list ap;
483 int ret;
484
485 *str = NULL;
486 va_start(ap, format);
487 ret = vasprintf(str, format, ap);
488 va_end(ap);
489
490 return (ret);
491 }
492
493 #endif

mercurial