1 #include "first.h" 2 3 #include "network_write.h" 4 5 #include "base.h" 6 #include "log.h" 7 8 #include <sys/types.h> 9 #include "sys-socket.h" 10 11 #include <errno.h> 12 #include <string.h> 13 #include <unistd.h> 14 15 16 /* on linux 2.4.x you get either sendfile or LFS */ 17 #if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILE \ 18 && (!defined _LARGEFILE_SOURCE || defined HAVE_SENDFILE64) \ 19 && defined(__linux__) && !defined HAVE_SENDFILE_BROKEN 20 # ifdef NETWORK_WRITE_USE_SENDFILE 21 # error "can't have more than one sendfile implementation" 22 # endif 23 # define NETWORK_WRITE_USE_SENDFILE "linux-sendfile" 24 # define NETWORK_WRITE_USE_LINUX_SENDFILE 25 #endif 26 27 #if defined HAVE_SENDFILE && (defined(__FreeBSD__) || defined(__DragonFly__)) 28 # ifdef NETWORK_WRITE_USE_SENDFILE 29 # error "can't have more than one sendfile implementation" 30 # endif 31 # define NETWORK_WRITE_USE_SENDFILE "freebsd-sendfile" 32 # define NETWORK_WRITE_USE_FREEBSD_SENDFILE 33 #endif 34 35 #if defined HAVE_SENDFILE && defined(__APPLE__) 36 # ifdef NETWORK_WRITE_USE_SENDFILE 37 # error "can't have more than one sendfile implementation" 38 # endif 39 # define NETWORK_WRITE_USE_SENDFILE "darwin-sendfile" 40 # define NETWORK_WRITE_USE_DARWIN_SENDFILE 41 #endif 42 43 #if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILEV && defined(__sun) 44 # ifdef NETWORK_WRITE_USE_SENDFILE 45 # error "can't have more than one sendfile implementation" 46 # endif 47 # define NETWORK_WRITE_USE_SENDFILE "solaris-sendfilev" 48 # define NETWORK_WRITE_USE_SOLARIS_SENDFILEV 49 #endif 50 51 /* not supported so far 52 #if defined HAVE_SEND_FILE && defined(__aix) 53 # ifdef NETWORK_WRITE_USE_SENDFILE 54 # error "can't have more than one sendfile implementation" 55 # endif 56 # define NETWORK_WRITE_USE_SENDFILE "aix-sendfile" 57 # define NETWORK_WRITE_USE_AIX_SENDFILE 58 #endif 59 */ 60 61 #if defined HAVE_SYS_UIO_H && defined HAVE_WRITEV 62 # define NETWORK_WRITE_USE_WRITEV 63 #endif 64 65 #if defined HAVE_SYS_MMAN_H && defined HAVE_MMAP && defined ENABLE_MMAP 66 # define NETWORK_WRITE_USE_MMAP 67 #endif 68 69 70 static int network_write_error(server *srv, int fd) { 71 #if defined(__WIN32) 72 int lastError = WSAGetLastError(); 73 switch (lastError) { 74 case WSAEINTR: 75 case WSAEWOULDBLOCK: 76 return -3; 77 case WSAECONNRESET: 78 case WSAETIMEDOUT: 79 case WSAECONNABORTED: 80 return -2; 81 default: 82 log_error_write(srv, __FILE__, __LINE__, "sdd", 83 "send failed: ", lastError, fd); 84 return -1; 85 } 86 #else /* __WIN32 */ 87 switch (errno) { 88 case EAGAIN: 89 case EINTR: 90 return -3; 91 case EPIPE: 92 case ECONNRESET: 93 return -2; 94 default: 95 log_error_write(srv, __FILE__, __LINE__, "ssd", 96 "write failed:", strerror(errno), fd); 97 return -1; 98 } 99 #endif /* __WIN32 */ 100 } 101 102 inline 103 static ssize_t network_write_data_len(int fd, const char *data, off_t len) { 104 #if defined(__WIN32) 105 return send(fd, data, len, 0); 106 #else /* __WIN32 */ 107 return write(fd, data, len); 108 #endif /* __WIN32 */ 109 } 110 111 112 113 114 /* write next chunk(s); finished chunks are removed afterwards after successful writes. 115 * return values: similar as backends (0 succes, -1 error, -2 remote close, -3 try again later (EINTR/EAGAIN)) */ 116 /* next chunk must be MEM_CHUNK. use write()/send() */ 117 static int network_write_mem_chunk(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) { 118 chunk* const c = cq->first; 119 ssize_t wr; 120 off_t c_len = (off_t)buffer_string_length(c->mem); 121 force_assert(c->offset >= 0 && c->offset <= c_len); 122 c_len -= c->offset; 123 if (c_len > *p_max_bytes) c_len = *p_max_bytes; 124 125 if (0 == c_len) { 126 chunkqueue_remove_finished_chunks(cq); 127 return 0; 128 } 129 130 wr = network_write_data_len(fd, c->mem->ptr + c->offset, c_len); 131 if (wr >= 0) { 132 *p_max_bytes -= wr; 133 chunkqueue_mark_written(cq, wr); 134 return (wr > 0 && wr == c_len) ? 0 : -3; 135 } else { 136 return network_write_error(srv, fd); 137 } 138 } 139 140 141 142 143 #if !defined(NETWORK_WRITE_USE_MMAP) 144 145 static int network_write_file_chunk_no_mmap(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) { 146 chunk* const c = cq->first; 147 off_t offset, toSend; 148 ssize_t wr; 149 150 force_assert(c->offset >= 0 && c->offset <= c->file.length); 151 152 offset = c->file.start + c->offset; 153 toSend = c->file.length - c->offset; 154 if (toSend > *p_max_bytes) toSend = *p_max_bytes; 155 156 if (0 == toSend) { 157 chunkqueue_remove_finished_chunks(cq); 158 return 0; 159 } 160 161 if (0 != chunkqueue_open_file_chunk(srv, cq)) return -1; 162 163 if (toSend > 64*1024) toSend = 64*1024; /* max read 64kb in one step */ 164 buffer_string_prepare_copy(srv->tmp_buf, toSend); 165 166 if (-1 == lseek(c->file.fd, offset, SEEK_SET)) { 167 log_error_write(srv, __FILE__, __LINE__, "ss","lseek:",strerror(errno)); 168 return -1; 169 } 170 if (-1 == (toSend = read(c->file.fd, srv->tmp_buf->ptr, toSend))) { 171 log_error_write(srv, __FILE__, __LINE__, "ss","read:",strerror(errno)); 172 return -1; 173 } 174 175 wr = network_write_data_len(fd, srv->tmp_buf->ptr, toSend); 176 if (wr >= 0) { 177 *p_max_bytes -= wr; 178 chunkqueue_mark_written(cq, wr); 179 return (wr > 0 && wr == toSend) ? 0 : -3; 180 } else { 181 return network_write_error(srv, fd); 182 } 183 } 184 185 #endif 186 187 188 189 190 #if defined(NETWORK_WRITE_USE_MMAP) 191 192 #include "sys-mmap.h" 193 194 #include <setjmp.h> 195 #include <signal.h> 196 197 #define MMAP_CHUNK_SIZE (512*1024) 198 199 static off_t mmap_align_offset(off_t start) { 200 static long pagesize = 0; 201 if (0 == pagesize) { 202 pagesize = sysconf(_SC_PAGESIZE); 203 force_assert(pagesize < MMAP_CHUNK_SIZE); 204 } 205 force_assert(start >= (start % pagesize)); 206 return start - (start % pagesize); 207 } 208 209 static volatile int sigbus_jmp_valid; 210 static sigjmp_buf sigbus_jmp; 211 212 static void sigbus_handler(int sig) { 213 UNUSED(sig); 214 if (sigbus_jmp_valid) siglongjmp(sigbus_jmp, 1); 215 log_failed_assert(__FILE__, __LINE__, "SIGBUS"); 216 } 217 218 /* next chunk must be FILE_CHUNK. send mmap()ed file with write() */ 219 static int network_write_file_chunk_mmap(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) { 220 chunk* const c = cq->first; 221 off_t offset, toSend, file_end; 222 ssize_t r; 223 size_t mmap_offset, mmap_avail; 224 const char *data; 225 226 force_assert(c->offset >= 0 && c->offset <= c->file.length); 227 228 offset = c->file.start + c->offset; 229 toSend = c->file.length - c->offset; 230 if (toSend > *p_max_bytes) toSend = *p_max_bytes; 231 file_end = c->file.start + c->file.length; /*file end offset in this chunk*/ 232 233 if (0 == toSend) { 234 chunkqueue_remove_finished_chunks(cq); 235 return 0; 236 } 237 238 if (0 != chunkqueue_open_file_chunk(srv, cq)) return -1; 239 240 /* mmap buffer if offset is outside old mmap area or not mapped at all */ 241 if (MAP_FAILED == c->file.mmap.start 242 || offset < c->file.mmap.offset 243 || offset >= (off_t)(c->file.mmap.offset + c->file.mmap.length)) { 244 245 if (MAP_FAILED != c->file.mmap.start) { 246 munmap(c->file.mmap.start, c->file.mmap.length); 247 c->file.mmap.start = MAP_FAILED; 248 } 249 250 /* Optimizations for the future: 251 * 252 * adaptive mem-mapping 253 * the problem: 254 * we mmap() the whole file. If someone has alot large files and 255 * 32-bit machine the virtual address area will be unrun and we 256 * will have a failing mmap() call. 257 * solution: 258 * only mmap 16M in one chunk and move the window as soon as we have 259 * finished the first 8M 260 * 261 * read-ahead buffering 262 * the problem: 263 * sending out several large files in parallel trashes read-ahead 264 * of the kernel leading to long wait-for-seek times. 265 * solutions: (increasing complexity) 266 * 1. use madvise 267 * 2. use a internal read-ahead buffer in the chunk-structure 268 * 3. use non-blocking IO for file-transfers 269 * */ 270 271 c->file.mmap.offset = mmap_align_offset(offset); 272 273 /* all mmap()ed areas are MMAP_CHUNK_SIZE 274 * except the last which might be smaller */ 275 c->file.mmap.length = MMAP_CHUNK_SIZE; 276 if (c->file.mmap.offset > file_end - (off_t)c->file.mmap.length) { 277 c->file.mmap.length = file_end - c->file.mmap.offset; 278 } 279 280 c->file.mmap.start = mmap(NULL, c->file.mmap.length, PROT_READ, 281 MAP_SHARED, c->file.fd, c->file.mmap.offset); 282 if (MAP_FAILED == c->file.mmap.start) { 283 log_error_write(srv, __FILE__, __LINE__, "ssbdoo", "mmap failed:", 284 strerror(errno), c->mem, c->file.fd, 285 c->file.mmap.offset, (off_t) c->file.mmap.length); 286 return -1; 287 } 288 289 #if defined(HAVE_MADVISE) 290 /* don't advise files < 64Kb */ 291 if (c->file.mmap.length > (64*1024)) { 292 /* darwin 7 is returning EINVAL all the time and I don't know how to 293 * detect this at runtime. 294 * 295 * ignore the return value for now */ 296 madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED); 297 } 298 #endif 299 } 300 301 force_assert(offset >= c->file.mmap.offset); 302 mmap_offset = offset - c->file.mmap.offset; 303 force_assert(c->file.mmap.length > mmap_offset); 304 mmap_avail = c->file.mmap.length - mmap_offset; 305 if (toSend > (off_t) mmap_avail) toSend = mmap_avail; 306 307 data = c->file.mmap.start + mmap_offset; 308 309 /* setup SIGBUS handler, but don't activate sigbus_jmp_valid yet */ 310 if (0 == sigsetjmp(sigbus_jmp, 1)) { 311 signal(SIGBUS, sigbus_handler); 312 313 sigbus_jmp_valid = 1; 314 r = network_write_data_len(fd, data, toSend); 315 sigbus_jmp_valid = 0; 316 } else { 317 sigbus_jmp_valid = 0; 318 319 log_error_write(srv, __FILE__, __LINE__, "sbd", "SIGBUS in mmap:", 320 c->mem, c->file.fd); 321 322 munmap(c->file.mmap.start, c->file.mmap.length); 323 c->file.mmap.start = MAP_FAILED; 324 return -1; 325 } 326 327 if (r >= 0) { 328 *p_max_bytes -= r; 329 chunkqueue_mark_written(cq, r); 330 return (r > 0 && r == toSend) ? 0 : -3; 331 } else { 332 return network_write_error(srv, fd); 333 } 334 } 335 336 #endif /* NETWORK_WRITE_USE_MMAP */ 337 338 339 340 341 #if defined(NETWORK_WRITE_USE_WRITEV) 342 343 #if defined(HAVE_SYS_UIO_H) 344 # include <sys/uio.h> 345 #endif 346 347 #if defined(UIO_MAXIOV) 348 # define SYS_MAX_CHUNKS UIO_MAXIOV 349 #elif defined(IOV_MAX) 350 /* new name for UIO_MAXIOV since IEEE Std 1003.1-2001 */ 351 # define SYS_MAX_CHUNKS IOV_MAX 352 #elif defined(_XOPEN_IOV_MAX) 353 /* minimum value for sysconf(_SC_IOV_MAX); posix requires this to be at least 16, which is good enough - no need to call sysconf() */ 354 # define SYS_MAX_CHUNKS _XOPEN_IOV_MAX 355 #else 356 # error neither UIO_MAXIOV nor IOV_MAX nor _XOPEN_IOV_MAX are defined 357 #endif 358 359 /* allocate iovec[MAX_CHUNKS] on stack, so pick a sane limit: 360 * - each entry will use 1 pointer + 1 size_t 361 * - 32 chunks -> 256 / 512 bytes (32-bit/64-bit pointers) 362 */ 363 #define STACK_MAX_ALLOC_CHUNKS 32 364 #if SYS_MAX_CHUNKS > STACK_MAX_ALLOC_CHUNKS 365 # define MAX_CHUNKS STACK_MAX_ALLOC_CHUNKS 366 #else 367 # define MAX_CHUNKS SYS_MAX_CHUNKS 368 #endif 369 370 /* next chunk must be MEM_CHUNK. send multiple mem chunks using writev() */ 371 static int network_writev_mem_chunks(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) { 372 struct iovec chunks[MAX_CHUNKS]; 373 size_t num_chunks = 0; 374 off_t max_bytes = *p_max_bytes; 375 off_t toSend = 0; 376 ssize_t r; 377 378 for (const chunk *c = cq->first; 379 NULL != c && MEM_CHUNK == c->type 380 && num_chunks < MAX_CHUNKS && toSend < max_bytes; 381 c = c->next) { 382 size_t c_len = buffer_string_length(c->mem); 383 force_assert(c->offset >= 0 && c->offset <= (off_t)c_len); 384 c_len -= c->offset; 385 if (c_len > 0) { 386 toSend += c_len; 387 388 chunks[num_chunks].iov_base = c->mem->ptr + c->offset; 389 chunks[num_chunks].iov_len = c_len; 390 391 ++num_chunks; 392 } 393 } 394 395 if (0 == num_chunks) { 396 chunkqueue_remove_finished_chunks(cq); 397 return 0; 398 } 399 400 r = writev(fd, chunks, num_chunks); 401 402 if (r < 0) switch (errno) { 403 case EAGAIN: 404 case EINTR: 405 break; 406 case EPIPE: 407 case ECONNRESET: 408 return -2; 409 default: 410 log_error_write(srv, __FILE__, __LINE__, "ssd", 411 "writev failed:", strerror(errno), fd); 412 return -1; 413 } 414 415 if (r >= 0) { 416 *p_max_bytes -= r; 417 chunkqueue_mark_written(cq, r); 418 } 419 420 return (r > 0 && r == toSend) ? 0 : -3; 421 } 422 423 #endif /* NETWORK_WRITE_USE_WRITEV */ 424 425 426 427 428 #if defined(NETWORK_WRITE_USE_SENDFILE) 429 430 #if defined(NETWORK_WRITE_USE_LINUX_SENDFILE) \ 431 || defined(NETWORK_WRITE_USE_SOLARIS_SENDFILEV) 432 #include <sys/sendfile.h> 433 #endif 434 435 #if defined(NETWORK_WRITE_USE_FREEBSD_SENDFILE) \ 436 || defined(NETWORK_WRITE_USE_DARWIN_SENDFILE) 437 #include <sys/uio.h> 438 #endif 439 440 static int network_write_file_chunk_sendfile(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) { 441 chunk * const c = cq->first; 442 ssize_t r; 443 off_t offset; 444 off_t toSend; 445 off_t written = 0; 446 447 force_assert(c->offset >= 0 && c->offset <= c->file.length); 448 449 offset = c->file.start + c->offset; 450 toSend = c->file.length - c->offset; 451 if (toSend > *p_max_bytes) toSend = *p_max_bytes; 452 453 if (0 == toSend) { 454 chunkqueue_remove_finished_chunks(cq); 455 return 0; 456 } 457 458 if (0 != chunkqueue_open_file_chunk(srv, cq)) return -1; 459 460 /* Darwin, FreeBSD, and Solaris variants support iovecs and could 461 * be optimized to send more than just file in single syscall */ 462 463 #if defined(NETWORK_WRITE_USE_LINUX_SENDFILE) 464 465 r = sendfile(fd, c->file.fd, &offset, toSend); 466 if (r > 0) written = (off_t)r; 467 468 #elif defined(NETWORK_WRITE_USE_DARWIN_SENDFILE) 469 470 written = toSend; 471 r = sendfile(c->file.fd, fd, offset, &written, NULL, 0); 472 /* (for EAGAIN/EINTR written still contains the sent bytes) */ 473 474 #elif defined(NETWORK_WRITE_USE_FREEBSD_SENDFILE) 475 476 r = sendfile(c->file.fd, fd, offset, toSend, NULL, &written, 0); 477 /* (for EAGAIN/EINTR written still contains the sent bytes) */ 478 479 #elif defined(NETWORK_WRITE_USE_SOLARIS_SENDFILEV) 480 { 481 sendfilevec_t fvec; 482 fvec.sfv_fd = c->file.fd; 483 fvec.sfv_flag = 0; 484 fvec.sfv_off = offset; 485 fvec.sfv_len = toSend; 486 487 /* Solaris sendfilev() */ 488 r = sendfilev(fd, &fvec, 1, (size_t *)&written); 489 /* (for EAGAIN/EINTR written still contains the sent bytes) */ 490 } 491 #else 492 493 r = -1; 494 errno = ENOSYS; 495 496 #endif 497 498 if (-1 == r) { 499 switch(errno) { 500 case EAGAIN: 501 case EINTR: 502 break; /* try again later */ 503 case EPIPE: 504 case ECONNRESET: 505 case ENOTCONN: 506 return -2; 507 case EINVAL: 508 case ENOSYS: 509 #if defined(ENOTSUP) && (!defined(EOPNOTSUPP) || EOPNOTSUPP != ENOTSUP) 510 case ENOTSUP: 511 #endif 512 #ifdef EOPNOTSUPP 513 case EOPNOTSUPP: 514 #endif 515 #ifdef ESOCKTNOSUPPORT 516 case ESOCKTNOSUPPORT: 517 #endif 518 #ifdef EAFNOSUPPORT 519 case EAFNOSUPPORT: 520 #endif 521 #ifdef NETWORK_WRITE_USE_MMAP 522 return network_write_file_chunk_mmap(srv, fd, cq, p_max_bytes); 523 #else 524 return network_write_file_chunk_no_mmap(srv, fd, cq, p_max_bytes); 525 #endif 526 default: 527 log_error_write(srv, __FILE__, __LINE__, "ssdSd", 528 "sendfile():", strerror(errno), errno, "fd:", fd); 529 return -1; 530 } 531 } 532 533 if (written >= 0) { /*(always true)*/ 534 chunkqueue_mark_written(cq, written); 535 *p_max_bytes -= written; 536 } 537 538 return (r >= 0 && written == toSend) ? 0 : -3; 539 } 540 541 #endif 542 543 544 545 546 /* return values: 547 * >= 0 : no error 548 * -1 : error (on our side) 549 * -2 : remote close 550 */ 551 552 static int network_write_chunkqueue_write(server *srv, int fd, chunkqueue *cq, off_t max_bytes) { 553 while (max_bytes > 0 && NULL != cq->first) { 554 int r = -1; 555 556 switch (cq->first->type) { 557 case MEM_CHUNK: 558 r = network_write_mem_chunk(srv, fd, cq, &max_bytes); 559 break; 560 case FILE_CHUNK: 561 #ifdef NETWORK_WRITE_USE_MMAP 562 r = network_write_file_chunk_mmap(srv, fd, cq, &max_bytes); 563 #else 564 r = network_write_file_chunk_no_mmap(srv, fd, cq, &max_bytes); 565 #endif 566 break; 567 } 568 569 if (-3 == r) return 0; 570 if (0 != r) return r; 571 } 572 573 return 0; 574 } 575 576 #if defined(NETWORK_WRITE_USE_WRITEV) 577 static int network_write_chunkqueue_writev(server *srv, int fd, chunkqueue *cq, off_t max_bytes) { 578 while (max_bytes > 0 && NULL != cq->first) { 579 int r = -1; 580 581 switch (cq->first->type) { 582 case MEM_CHUNK: 583 #if defined(NETWORK_WRITE_USE_WRITEV) 584 r = network_writev_mem_chunks(srv, fd, cq, &max_bytes); 585 #else 586 r = network_write_mem_chunk(srv, fd, cq, &max_bytes); 587 #endif 588 break; 589 case FILE_CHUNK: 590 #ifdef NETWORK_WRITE_USE_MMAP 591 r = network_write_file_chunk_mmap(srv, fd, cq, &max_bytes); 592 #else 593 r = network_write_file_chunk_no_mmap(srv, fd, cq, &max_bytes); 594 #endif 595 break; 596 } 597 598 if (-3 == r) return 0; 599 if (0 != r) return r; 600 } 601 602 return 0; 603 } 604 #endif 605 606 #if defined(NETWORK_WRITE_USE_SENDFILE) 607 static int network_write_chunkqueue_sendfile(server *srv, int fd, chunkqueue *cq, off_t max_bytes) { 608 while (max_bytes > 0 && NULL != cq->first) { 609 int r = -1; 610 611 switch (cq->first->type) { 612 case MEM_CHUNK: 613 #if defined(NETWORK_WRITE_USE_WRITEV) 614 r = network_writev_mem_chunks(srv, fd, cq, &max_bytes); 615 #else 616 r = network_write_mem_chunk(srv, fd, cq, &max_bytes); 617 #endif 618 break; 619 case FILE_CHUNK: 620 #if defined(NETWORK_WRITE_USE_SENDFILE) 621 r = network_write_file_chunk_sendfile(srv, fd, cq, &max_bytes); 622 #elif defined(NETWORK_WRITE_USE_MMAP) 623 r = network_write_file_chunk_mmap(srv, fd, cq, &max_bytes); 624 #else 625 r = network_write_file_chunk_no_mmap(srv, fd, cq, &max_bytes); 626 #endif 627 break; 628 } 629 630 if (-3 == r) return 0; 631 if (0 != r) return r; 632 } 633 634 return 0; 635 } 636 #endif 637 638 int network_write_init(server *srv) { 639 typedef enum { 640 NETWORK_BACKEND_UNSET, 641 NETWORK_BACKEND_WRITE, 642 NETWORK_BACKEND_WRITEV, 643 NETWORK_BACKEND_SENDFILE, 644 } network_backend_t; 645 646 network_backend_t backend; 647 648 struct nb_map { 649 network_backend_t nb; 650 const char *name; 651 } network_backends[] = { 652 /* lowest id wins */ 653 { NETWORK_BACKEND_SENDFILE, "sendfile" }, 654 { NETWORK_BACKEND_SENDFILE, "linux-sendfile" }, 655 { NETWORK_BACKEND_SENDFILE, "freebsd-sendfile" }, 656 { NETWORK_BACKEND_SENDFILE, "solaris-sendfilev" }, 657 { NETWORK_BACKEND_WRITEV, "writev" }, 658 { NETWORK_BACKEND_WRITE, "write" }, 659 { NETWORK_BACKEND_UNSET, NULL } 660 }; 661 662 /* get a useful default */ 663 backend = network_backends[0].nb; 664 665 /* match name against known types */ 666 if (!buffer_string_is_empty(srv->srvconf.network_backend)) { 667 const char *name; 668 for (size_t i = 0; NULL != (name = network_backends[i].name); ++i) { 669 if (0 == strcmp(srv->srvconf.network_backend->ptr, name)) { 670 backend = network_backends[i].nb; 671 break; 672 } 673 } 674 if (NULL == name) { 675 log_error_write(srv, __FILE__, __LINE__, "sb", 676 "server.network-backend has an unknown value:", 677 srv->srvconf.network_backend); 678 return -1; 679 } 680 } 681 682 switch(backend) { 683 case NETWORK_BACKEND_SENDFILE: 684 #if defined(NETWORK_WRITE_USE_SENDFILE) 685 srv->network_backend_write = network_write_chunkqueue_sendfile; 686 break; 687 #endif 688 case NETWORK_BACKEND_WRITEV: 689 #if defined(NETWORK_WRITE_USE_WRITEV) 690 srv->network_backend_write = network_write_chunkqueue_writev; 691 break; 692 #endif 693 case NETWORK_BACKEND_WRITE: 694 srv->network_backend_write = network_write_chunkqueue_write; 695 break; 696 default: 697 return -1; 698 } 699 700 return 0; 701 } 702 703 const char * network_write_show_handlers(void) { 704 return 705 "\nNetwork handler:\n\n" 706 #if defined NETWORK_WRITE_USE_LINUX_SENDFILE 707 "\t+ linux-sendfile\n" 708 #else 709 "\t- linux-sendfile\n" 710 #endif 711 #if defined NETWORK_WRITE_USE_FREEBSD_SENDFILE 712 "\t+ freebsd-sendfile\n" 713 #else 714 "\t- freebsd-sendfile\n" 715 #endif 716 #if defined NETWORK_WRITE_USE_DARWIN_SENDFILE 717 "\t+ darwin-sendfile\n" 718 #else 719 "\t- darwin-sendfile\n" 720 #endif 721 #if defined NETWORK_WRITE_USE_SOLARIS_SENDFILEV 722 "\t+ solaris-sendfilev\n" 723 #else 724 "\t- solaris-sendfilev\n" 725 #endif 726 #if defined NETWORK_WRITE_USE_WRITEV 727 "\t+ writev\n" 728 #else 729 "\t- writev\n" 730 #endif 731 "\t+ write\n" 732 #ifdef NETWORK_WRITE_USE_MMAP 733 "\t+ mmap support\n" 734 #else 735 "\t- mmap support\n" 736 #endif 737 ; 738 } 739