UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifdef __gnu_linux__ 30 #define _GNU_SOURCE 31 #endif 32 33 #include <unistd.h> 34 #include <stdlib.h> 35 36 #ifdef XP_UNIX 37 #include <sys/uio.h> 38 #include <sys/uio.h> 39 #endif 40 41 #ifdef XP_WIN32 42 43 #endif 44 45 #if defined(LINUX) || defined(SOLARIS) 46 #include <sys/sendfile.h> 47 #define WS_SENDFILE 48 #elif defined(BSD) 49 #if defined(__NetBSD__) || defined(__OpenBSD__) 50 #define net_sys_sendfile net_fallback_sendfile 51 #else 52 #define WS_SENDFILE 53 #endif 54 #endif 55 56 #ifdef WS_SENDFILE 57 #define NET_SYS_SENDFILE net_sys_sendfile 58 #else 59 #define NET_SYS_SENDFILE net_fallback_sendfile 60 #endif 61 62 63 64 #include "../daemon/vfs.h" 65 #include "io.h" 66 #include "pool.h" 67 #include "../daemon/netsite.h" 68 #include "../daemon/event.h" 69 #include "ucx/utils.h" 70 71 IOStream native_io_funcs = { 72 (io_write_f)net_sys_write, 73 (io_writev_f)net_sys_writev, 74 (io_read_f)net_sys_read, 75 (io_sendfile_f)NET_SYS_SENDFILE, 76 (io_close_f)net_sys_close, 77 NULL, 78 (io_setmode_f)net_sys_setmode, 79 (io_poll_f)net_sys_poll, 80 0 81 }; 82 83 IOStream http_io_funcs = { 84 (io_write_f)net_http_write, 85 (io_writev_f)net_http_writev, 86 (io_read_f)net_http_read, 87 (io_sendfile_f)net_http_sendfile, 88 (io_close_f)net_http_close, 89 (io_finish_f)net_http_finish, 90 (io_setmode_f)net_http_setmode, 91 (io_poll_f)net_http_poll, 92 0 93 }; 94 95 IOStream ssl_io_funcs = { 96 (io_write_f)net_ssl_write, 97 (io_writev_f)net_ssl_writev, 98 (io_read_f)net_ssl_read, 99 NULL, 100 (io_close_f)net_ssl_close, 101 (io_finish_f)net_ssl_finish, 102 (io_setmode_f)net_ssl_setmode, 103 (io_poll_f)net_ssl_poll, 104 0 105 }; 106 107 108 /* 109 * SysStream implementation 110 */ 111 112 IOStream* sysstream_new(pool_handle_t *pool, SYS_SOCKET fd) { 113 SysStream *st = pool_malloc(pool, sizeof(SysStream)); 114 st->st = native_io_funcs; 115 st->fd = fd; 116 return (IOStream*)st; 117 } 118 119 #ifdef XP_UNIX 120 ssize_t net_sys_write(SysStream *st, void *buf, size_t nbytes) { 121 return write(st->fd, buf, nbytes); 122 } 123 124 ssize_t net_sys_writev(SysStream *st, struct iovec *iovec, int iovcnt) { 125 return writev(st->fd, iovec, iovcnt); 126 } 127 128 ssize_t net_sys_read(SysStream *st, void *buf, size_t nbytes) { 129 return read(st->fd, buf, nbytes); 130 } 131 132 #ifdef WS_SENDFILE 133 ssize_t net_sys_sendfile(SysStream *st, sendfiledata *sfd) { 134 ssize_t ret = 0; 135 off_t fileoffset = sfd->offset; 136 if(sfd->fd->fd != -1) { 137 #ifdef BSD 138 struct iovec hdvec; 139 hdvec.iov_base = (void*)sfd->header; 140 hdvec.iov_len = sfd->hlen; 141 struct iovec trvec; 142 trvec.iov_base = (void*)sfd->trailer; 143 trvec.iov_len = sfd->tlen; 144 struct sf_hdtr hdtr; 145 hdtr.headers = &hdvec; 146 hdtr.hdr_cnt = 1; 147 hdtr.trailers = &trvec; 148 hdtr.trl_cnt = 1; 149 150 off_t len = sfd->len; 151 #ifdef OSX 152 ret = sendfile(sfd->fd->fd, st->fd, fileoffset, &len, &hdtr, 0); 153 #else // BSD 154 ret = sendfile( 155 sfd->fd->fd, 156 st->fd, 157 fileoffset, 158 sfd->len, 159 &hdtr, 160 NULL, 161 0); 162 #endif 163 #else // Solaris/Linux 164 if(sfd->header) { 165 ret += write(st->fd, sfd->header, sfd->hlen); 166 } 167 ret += sendfile(st->fd, sfd->fd->fd, &fileoffset, sfd->len); 168 if(sfd->trailer) { 169 ret += write(st->fd, sfd->trailer, sfd->tlen); 170 } 171 #endif 172 } else { 173 return net_fallback_sendfile((IOStream*)st, sfd); 174 } 175 176 return ret; 177 } 178 #endif 179 180 void net_sys_close(SysStream *st) { 181 system_close(st->fd); 182 } 183 184 void net_sys_setmode(SysStream *st, int mode) { 185 int flags; 186 if (-1 == (flags = fcntl(st->fd, F_GETFL, 0))) { 187 flags = 0; 188 } 189 if(mode == IO_MODE_BLOCKING) { 190 if (fcntl(st->fd, F_SETFL, flags & ~O_NONBLOCK) != 0) { 191 perror("fcntl"); 192 // TODO: error 193 } 194 } else if(mode == IO_MODE_NONBLOCKING) { 195 if (fcntl(st->fd, F_SETFL, flags | O_NONBLOCK) != 0) { 196 perror("fcntl"); 197 // TODO: error 198 } 199 } 200 } 201 202 int net_sys_poll(SysStream *st, EventHandler *ev, int events, Event *cb) { 203 switch(events) { 204 default: return -1; 205 case IO_POLL_NONE: return ev_remove_poll(ev, st->fd); 206 case IO_POLL_IN: return ev_pollin(ev, st->fd, cb); 207 case IO_POLL_OUT: return ev_pollout(ev, st->fd, cb); 208 case IO_POLL_IN | IO_POLL_OUT: return -1; // TODO: implement 209 } 210 } 211 212 #elif defined(XP_WIN32) 213 214 ssize_t net_sys_write(SysStream *st, void *buf, size_t nbytes) { 215 int ret = send(st->fd, buf, nbytes, 0); 216 if(ret == SOCKET_ERROR) { 217 return IO_ERROR; 218 } 219 return ret; 220 } 221 222 ssize_t net_sys_writev(SysStream *st, struct iovec *iovec, int iovcnt) { 223 // TODO 224 } 225 226 ssize_t net_sys_read(SysStream *st, void *buf, size_t nbytes) { 227 int ret = recv(st->fd, buf, nbytes, 0); 228 if(ret == SOCKET_ERROR) { 229 return IO_ERROR; 230 } 231 return ret; 232 } 233 234 ssize_t net_sys_sendfile(SysStream *st, sendfiledata *sfd) { 235 // TODO 236 } 237 238 void net_sys_close(SysStream *st) { 239 closesocket(st->fd); 240 } 241 242 #endif 243 244 245 /* 246 * HttpStream implementation 247 */ 248 249 IOStream* httpstream_new(pool_handle_t *pool, IOStream *fd) { 250 HttpStream *st = pool_malloc(pool, sizeof(HttpStream)); 251 st->st = http_io_funcs; 252 st->fd = fd; 253 st->max_read = 0; 254 st->read = 0; 255 st->chunked_enc = WS_FALSE; 256 st->buffered = WS_FALSE; 257 return (IOStream*)st; 258 } 259 260 ssize_t net_http_write(HttpStream *st, void *buf, size_t nbytes) { 261 IOStream *fd = st->fd; 262 if(st->chunked_enc) { 263 // TODO: on some plattforms iov_len is smaller than size_t 264 struct iovec io[3]; 265 char chunk_len[16]; 266 io[0].iov_base = chunk_len; 267 io[0].iov_len = snprintf(chunk_len, 16, "%zx\r\n", nbytes); 268 io[1].iov_base = buf; 269 io[1].iov_len = nbytes; 270 io[2].iov_base = "\r\n"; 271 io[2].iov_len = 2; 272 ssize_t r = fd->writev(fd, io, 3); 273 return r - io[0].iov_len; 274 } else { 275 return fd->write(fd, buf, nbytes); 276 } 277 } 278 279 ssize_t net_http_writev(HttpStream *st, struct iovec *iovec, int iovcnt) { 280 IOStream *fd = st->fd; 281 if(st->chunked_enc) { 282 struct iovec *io = calloc(iovcnt + 1, sizeof(struct iovec)); 283 char chunk_len[16]; 284 io[0].iov_base = chunk_len; 285 size_t len = 0; 286 for(int i=0;i<iovcnt;i++) { 287 len += iovec[i].iov_len; 288 } 289 io[0].iov_len = snprintf(chunk_len, 16, "\r\n%zx\r\n", len); 290 memcpy(io + 1, iovec, iovcnt * sizeof(struct iovec)); 291 ssize_t r = fd->writev(fd, io, iovcnt + 1); 292 return r - io[0].iov_len; 293 } else { 294 return fd->writev(fd, iovec, iovcnt); 295 } 296 } 297 298 ssize_t net_http_read(HttpStream *st, void *buf, size_t nbytes) { 299 if(st->max_read != 0 && st->read >= st->max_read) { 300 return 0; 301 } 302 ssize_t r = st->fd->read(st->fd, buf, nbytes); 303 st->read += r; 304 return r; 305 } 306 307 ssize_t net_http_sendfile(HttpStream *st, sendfiledata *sfd) { 308 ssize_t ret = 0; 309 // TODO: support chunked transfer encoding 310 if(st->fd->sendfile) { 311 ret = st->fd->sendfile(st->fd, sfd); 312 } else { 313 ret = net_fallback_sendfile((IOStream*)st, sfd); 314 } 315 316 return ret; 317 } 318 319 void net_http_close(HttpStream *st) { 320 st->fd->close(st->fd); 321 } 322 323 void net_http_finish(HttpStream *st) { 324 if(st->chunked_enc) { 325 st->fd->write(st->fd, "0\r\n\r\n", 5); 326 } 327 } 328 329 void net_http_setmode(HttpStream *st, int mode) { 330 st->fd->setmode(st->fd, mode); 331 } 332 333 int net_http_poll(HttpStream *st, EventHandler *ev, int events, Event *cb) { 334 return st->fd->poll(st->fd, ev, events, cb); 335 } 336 337 338 /* 339 * SSLStream implementation 340 */ 341 342 IOStream* sslstream_new(pool_handle_t *pool, SSL *ssl) { 343 SSLStream *st = pool_malloc(pool, sizeof(SSLStream)); 344 st->st = ssl_io_funcs; 345 st->ssl = ssl; 346 st->error = 0; 347 return (IOStream*)st; 348 } 349 350 ssize_t net_ssl_write(SSLStream *st, void *buf, size_t nbytes) { 351 int ret = SSL_write(st->ssl, buf, nbytes); 352 if(ret <= 0) { 353 st->error = SSL_get_error(st->ssl, ret); 354 } 355 return ret; 356 } 357 358 ssize_t net_ssl_writev(SSLStream *st, struct iovec *iovec, int iovcnt) { 359 ssize_t r = 0; 360 for(int i=0;i<iovcnt;i++) { 361 int ret = SSL_write(st->ssl, iovec[i].iov_base, iovec[i].iov_len); 362 if(ret <= 0) { 363 st->error = SSL_get_error(st->ssl, ret); 364 return 0; 365 } 366 r += ret; 367 } 368 return r; 369 } 370 371 ssize_t net_ssl_read(SSLStream *st, void *buf, size_t nbytes) { 372 int ret = SSL_read(st->ssl, buf, nbytes); 373 if(ret <= 0) { 374 st->error = SSL_get_error(st->ssl, ret); 375 } 376 return ret; 377 } 378 379 void net_ssl_close(SSLStream *st) { 380 int ret = SSL_shutdown(st->ssl); 381 if(ret != 1) { 382 st->error = SSL_get_error(st->ssl, ret); 383 } 384 system_close(SSL_get_fd(st->ssl)); 385 } 386 387 void net_ssl_finish(SSLStream *st) { 388 389 } 390 391 void net_ssl_setmode(SSLStream *st, int mode) { 392 int flags; 393 if (-1 == (flags = fcntl(SSL_get_fd(st->ssl), F_GETFL, 0))) { 394 flags = 0; 395 } 396 if(mode == IO_MODE_BLOCKING) { 397 if (fcntl(SSL_get_fd(st->ssl), F_SETFL, flags & ~O_NONBLOCK) != 0) { 398 perror("fcntl"); 399 // TODO: error 400 } 401 } else if(mode == IO_MODE_NONBLOCKING) { 402 if (fcntl(SSL_get_fd(st->ssl), F_SETFL, flags | O_NONBLOCK) != 0) { 403 perror("fcntl"); 404 // TODO: error 405 } 406 } 407 } 408 409 int net_ssl_poll(SSLStream *st, EventHandler *ev, int events, Event *cb) { 410 int fd = SSL_get_fd(st->ssl); 411 switch(events) { 412 default: return -1; 413 case IO_POLL_NONE: return ev_remove_poll(ev, fd); 414 case IO_POLL_IN: return ev_pollin(ev, fd, cb); 415 case IO_POLL_OUT: return ev_pollout(ev, fd, cb); 416 case IO_POLL_IN | IO_POLL_OUT: return -1; // TODO: implement 417 } 418 } 419 420 /* -------------------- public nsapi network functions -------------------- */ 421 422 ssize_t net_read(SYS_NETFD fd, void *buf, size_t nbytes) { 423 ssize_t r = ((IOStream*)fd)->read(fd, buf, nbytes); 424 if(r == 0) { 425 return IO_EOF; 426 } else if(r < 0) { 427 ((IOStream*)fd)->io_errno = errno; 428 return IO_ERROR; 429 } 430 return r; 431 } 432 433 ssize_t net_write(SYS_NETFD fd, void *buf, size_t nbytes) { 434 ssize_t r = ((IOStream*)fd)->write(fd, buf, nbytes); 435 if(r < 0) { 436 ((IOStream*)fd)->io_errno = errno; 437 return IO_ERROR; 438 } 439 return r; 440 } 441 442 ssize_t net_writev(SYS_NETFD fd, struct iovec *iovec, int iovcnt) { 443 ssize_t r = ((IOStream*)fd)->writev(fd, iovec, iovcnt); 444 if(r < 0) { 445 ((IOStream*)fd)->io_errno = errno; 446 return IO_ERROR; 447 } 448 return r; 449 } 450 451 ssize_t net_printf(SYS_NETFD fd, char *format, ...) { 452 va_list arg; 453 va_start(arg, format); 454 sstr_t buf = ucx_vasprintf(ucx_default_allocator(), format, arg); 455 ssize_t r = net_write(fd, buf.ptr, buf.length); 456 free(buf.ptr); 457 va_end(arg); 458 if(r < 0) { 459 ((IOStream*)fd)->io_errno = errno; 460 } 461 return r; 462 } 463 464 ssize_t net_sendfile(SYS_NETFD fd, sendfiledata *sfd) { 465 IOStream *out = fd; 466 if(out->sendfile && sfd->fd && sfd->fd->fd != -1) { 467 ssize_t r = out->sendfile(fd, sfd); 468 if(r < 0) { 469 out->io_errno = errno; 470 return IO_ERROR; 471 } 472 return r; 473 } else { 474 // stream/file does not support sendfile 475 // do regular copy 476 return net_fallback_sendfile(out, sfd); 477 } 478 } 479 480 // private 481 ssize_t net_fallback_sendfile(IOStream *fd, sendfiledata *sfd) { 482 char *buf = malloc(4096); 483 if(!buf) { 484 // TODO: out of memory error 485 return IO_ERROR; 486 } 487 char *header = (char*)sfd->header; 488 int hlen = sfd->hlen; 489 char *trailer = (char*)sfd->trailer; 490 int tlen = sfd->tlen; 491 if(header == NULL) { 492 hlen = 0; 493 } 494 if(trailer == NULL) { 495 tlen = 0; 496 } 497 498 ssize_t r; 499 while(hlen > 0) { 500 r = fd->write(fd, header, hlen); 501 header += r; 502 hlen -= r; 503 if(r <= 0) { 504 free(buf); 505 fd->io_errno = errno; 506 return IO_ERROR; 507 } 508 } 509 510 if(system_lseek(sfd->fd, sfd->offset, SEEK_SET) == -1) { 511 free(buf); 512 fd->io_errno = errno; 513 return IO_ERROR; 514 } 515 516 size_t length = sfd->len; 517 while(length > 0) { 518 // TODO: remove 519 if(length > sfd->len) { 520 log_ereport(LOG_WARN, "net_fallback_sendfile: length > sfd->len: %zu > %zu", length, sfd->len); 521 free(buf); 522 return IO_ERROR; 523 } 524 525 if((r = system_fread(sfd->fd, buf, 4096)) <= 0) { 526 break; 527 } 528 char *write_buf = buf; 529 while(r > 0) { 530 ssize_t w = fd->write(fd, write_buf, r); 531 // TODO: remove 532 if(w > r) { 533 log_ereport(LOG_WARN, "net_fallback_sendfile: w > r, %zd > %zd", w, r); 534 w = 0; 535 } 536 537 if(w <= 0) { 538 free(buf); 539 fd->io_errno = errno; 540 return IO_ERROR; 541 } 542 r -= w; 543 length -= w; 544 write_buf += w; 545 } 546 } 547 free(buf); 548 if(length > 0) { 549 fd->io_errno = errno; 550 return IO_ERROR; 551 } 552 553 while(tlen > 0) { 554 r = fd->write(fd, trailer, tlen); 555 trailer += r; 556 tlen -= r; 557 if(r <= 0) { 558 fd->io_errno = errno; 559 return IO_ERROR; 560 } 561 } 562 563 return sfd->hlen + sfd->len + sfd->tlen; 564 } 565 566 int net_flush(SYS_NETFD sd) { 567 // TODO: implement 568 return 0; 569 } 570 571 void net_close(SYS_NETFD fd) { 572 ((IOStream*)fd)->close(fd); 573 } 574 575 int net_setnonblock(SYS_NETFD fd, int nonblock) { 576 ((IOStream*)fd)->setmode( 577 fd, 578 nonblock ? IO_MODE_NONBLOCKING : IO_MODE_BLOCKING); 579 return 0; 580 } 581 582 int net_errno(SYS_NETFD fd) { 583 return ((IOStream*)fd)->io_errno; 584 } 585 586 // private 587 void net_finish(SYS_NETFD fd) { 588 ((IOStream*)fd)->finish(fd); 589 } 590