1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <assert.h> 18#include <errno.h> 19#include <signal.h> 20#include <stdlib.h> 21#include <string.h> 22#include "apr_network_io.h" 23#include "apr_errno.h" 24#include "apr_general.h" 25#include "apr_poll.h" 26 27#if !APR_HAS_SENDFILE 28int main(void) 29{ 30 fprintf(stderr, 31 "This program won't work on this platform because there is no " 32 "support for sendfile().\n"); 33 return 0; 34} 35#else /* !APR_HAS_SENDFILE */ 36 37#define FILE_LENGTH 200000 38 39#define FILE_DATA_CHAR '0' 40 41#define HDR1 "1234567890ABCD\n" 42#define HDR2 "EFGH\n" 43#define HDR3_LEN 80000 44#define HDR3_CHAR '^' 45#define TRL1 "IJKLMNOPQRSTUVWXYZ\n" 46#define TRL2 "!@#$%&*()\n" 47#define TRL3_LEN 90000 48#define TRL3_CHAR '@' 49 50#define TESTSF_PORT 8021 51 52#define TESTFILE "testsf.dat" 53 54typedef enum {BLK, NONBLK, TIMEOUT} client_socket_mode_t; 55 56static void apr_setup(apr_pool_t **p, apr_socket_t **sock, int *family) 57{ 58 char buf[120]; 59 apr_status_t rv; 60 61 rv = apr_initialize(); 62 if (rv != APR_SUCCESS) { 63 fprintf(stderr, "apr_initialize()->%d/%s\n", 64 rv, 65 apr_strerror(rv, buf, sizeof buf)); 66 exit(1); 67 } 68 69 atexit(apr_terminate); 70 71 rv = apr_pool_create(p, NULL); 72 if (rv != APR_SUCCESS) { 73 fprintf(stderr, "apr_pool_create()->%d/%s\n", 74 rv, 75 apr_strerror(rv, buf, sizeof buf)); 76 exit(1); 77 } 78 79 *sock = NULL; 80 rv = apr_socket_create(sock, *family, SOCK_STREAM, 0, *p); 81 if (rv != APR_SUCCESS) { 82 fprintf(stderr, "apr_socket_create()->%d/%s\n", 83 rv, 84 apr_strerror(rv, buf, sizeof buf)); 85 exit(1); 86 } 87 88 if (*family == APR_UNSPEC) { 89 apr_sockaddr_t *localsa; 90 91 rv = apr_socket_addr_get(&localsa, APR_LOCAL, *sock); 92 if (rv != APR_SUCCESS) { 93 fprintf(stderr, "apr_socket_addr_get()->%d/%s\n", 94 rv, 95 apr_strerror(rv, buf, sizeof buf)); 96 exit(1); 97 } 98 *family = localsa->family; 99 } 100} 101 102static void create_testfile(apr_pool_t *p, const char *fname) 103{ 104 apr_file_t *f = NULL; 105 apr_status_t rv; 106 char buf[120]; 107 int i; 108 apr_finfo_t finfo; 109 110 printf("Creating a test file...\n"); 111 rv = apr_file_open(&f, fname, 112 APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_TRUNCATE | APR_FOPEN_BUFFERED, 113 APR_UREAD | APR_UWRITE, p); 114 if (rv) { 115 fprintf(stderr, "apr_file_open()->%d/%s\n", 116 rv, apr_strerror(rv, buf, sizeof buf)); 117 exit(1); 118 } 119 120 buf[0] = FILE_DATA_CHAR; 121 buf[1] = '\0'; 122 for (i = 0; i < FILE_LENGTH; i++) { 123 /* exercise apr_file_putc() and apr_file_puts() on buffered files */ 124 if ((i % 2) == 0) { 125 rv = apr_file_putc(buf[0], f); 126 if (rv) { 127 fprintf(stderr, "apr_file_putc()->%d/%s\n", 128 rv, apr_strerror(rv, buf, sizeof buf)); 129 exit(1); 130 } 131 } 132 else { 133 rv = apr_file_puts(buf, f); 134 if (rv) { 135 fprintf(stderr, "apr_file_puts()->%d/%s\n", 136 rv, apr_strerror(rv, buf, sizeof buf)); 137 exit(1); 138 } 139 } 140 } 141 142 rv = apr_file_close(f); 143 if (rv) { 144 fprintf(stderr, "apr_file_close()->%d/%s\n", 145 rv, apr_strerror(rv, buf, sizeof buf)); 146 exit(1); 147 } 148 149 rv = apr_stat(&finfo, fname, APR_FINFO_NORM, p); 150 if (rv != APR_SUCCESS && ! APR_STATUS_IS_INCOMPLETE(rv)) { 151 fprintf(stderr, "apr_stat()->%d/%s\n", 152 rv, apr_strerror(rv, buf, sizeof buf)); 153 exit(1); 154 } 155 156 if (finfo.size != FILE_LENGTH) { 157 fprintf(stderr, 158 "test file %s should be %ld-bytes long\n" 159 "instead it is %ld-bytes long\n", 160 fname, 161 (long int)FILE_LENGTH, 162 (long int)finfo.size); 163 exit(1); 164 } 165} 166 167static int client(client_socket_mode_t socket_mode, char *host) 168{ 169 apr_status_t rv, tmprv; 170 apr_socket_t *sock; 171 apr_pool_t *p; 172 char buf[120]; 173 apr_file_t *f = NULL; 174 apr_size_t len; 175 apr_size_t expected_len; 176 apr_off_t current_file_offset; 177 apr_hdtr_t hdtr; 178 struct iovec headers[3]; 179 struct iovec trailers[3]; 180 apr_size_t bytes_read; 181 apr_pollset_t *pset; 182 apr_int32_t nsocks; 183 int i; 184 int family; 185 apr_sockaddr_t *destsa; 186 187 family = APR_INET; 188 apr_setup(&p, &sock, &family); 189 create_testfile(p, TESTFILE); 190 191 rv = apr_file_open(&f, TESTFILE, APR_FOPEN_READ, 0, p); 192 if (rv != APR_SUCCESS) { 193 fprintf(stderr, "apr_file_open()->%d/%s\n", 194 rv, 195 apr_strerror(rv, buf, sizeof buf)); 196 exit(1); 197 } 198 199 if (!host) { 200 host = "127.0.0.1"; 201 } 202 rv = apr_sockaddr_info_get(&destsa, host, family, TESTSF_PORT, 0, p); 203 if (rv != APR_SUCCESS) { 204 fprintf(stderr, "apr_sockaddr_info_get()->%d/%s\n", 205 rv, 206 apr_strerror(rv, buf, sizeof buf)); 207 exit(1); 208 } 209 210 rv = apr_socket_connect(sock, destsa); 211 if (rv != APR_SUCCESS) { 212 fprintf(stderr, "apr_socket_connect()->%d/%s\n", 213 rv, 214 apr_strerror(rv, buf, sizeof buf)); 215 exit(1); 216 } 217 218 switch(socket_mode) { 219 case BLK: 220 /* leave it blocking */ 221 break; 222 case NONBLK: 223 /* set it non-blocking */ 224 rv = apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1); 225 if (rv != APR_SUCCESS) { 226 fprintf(stderr, "apr_socket_opt_set(APR_SO_NONBLOCK)->%d/%s\n", 227 rv, 228 apr_strerror(rv, buf, sizeof buf)); 229 exit(1); 230 } 231 break; 232 case TIMEOUT: 233 /* set a timeout */ 234 rv = apr_socket_timeout_set(sock, 100 * APR_USEC_PER_SEC); 235 if (rv != APR_SUCCESS) { 236 fprintf(stderr, "apr_socket_opt_set(APR_SO_NONBLOCK)->%d/%s\n", 237 rv, 238 apr_strerror(rv, buf, sizeof buf)); 239 exit(1); 240 } 241 break; 242 default: 243 assert(1 != 1); 244 } 245 246 printf("Sending the file...\n"); 247 248 hdtr.headers = headers; 249 hdtr.numheaders = 3; 250 hdtr.headers[0].iov_base = HDR1; 251 hdtr.headers[0].iov_len = strlen(hdtr.headers[0].iov_base); 252 hdtr.headers[1].iov_base = HDR2; 253 hdtr.headers[1].iov_len = strlen(hdtr.headers[1].iov_base); 254 hdtr.headers[2].iov_base = malloc(HDR3_LEN); 255 assert(hdtr.headers[2].iov_base); 256 memset(hdtr.headers[2].iov_base, HDR3_CHAR, HDR3_LEN); 257 hdtr.headers[2].iov_len = HDR3_LEN; 258 259 hdtr.trailers = trailers; 260 hdtr.numtrailers = 3; 261 hdtr.trailers[0].iov_base = TRL1; 262 hdtr.trailers[0].iov_len = strlen(hdtr.trailers[0].iov_base); 263 hdtr.trailers[1].iov_base = TRL2; 264 hdtr.trailers[1].iov_len = strlen(hdtr.trailers[1].iov_base); 265 hdtr.trailers[2].iov_base = malloc(TRL3_LEN); 266 memset(hdtr.trailers[2].iov_base, TRL3_CHAR, TRL3_LEN); 267 assert(hdtr.trailers[2].iov_base); 268 hdtr.trailers[2].iov_len = TRL3_LEN; 269 270 expected_len = 271 strlen(HDR1) + strlen(HDR2) + HDR3_LEN + 272 strlen(TRL1) + strlen(TRL2) + TRL3_LEN + 273 FILE_LENGTH; 274 275 if (socket_mode == BLK) { 276 current_file_offset = 0; 277 len = FILE_LENGTH; 278 rv = apr_socket_sendfile(sock, f, &hdtr, ¤t_file_offset, &len, 0); 279 if (rv != APR_SUCCESS) { 280 fprintf(stderr, "apr_socket_sendfile()->%d/%s\n", 281 rv, 282 apr_strerror(rv, buf, sizeof buf)); 283 exit(1); 284 } 285 286 printf("apr_socket_sendfile() updated offset with %ld\n", 287 (long int)current_file_offset); 288 289 printf("apr_socket_sendfile() updated len with %ld\n", 290 (long int)len); 291 292 printf("bytes really sent: %" APR_SIZE_T_FMT "\n", 293 expected_len); 294 295 if (len != expected_len) { 296 fprintf(stderr, "apr_socket_sendfile() didn't report the correct " 297 "number of bytes sent!\n"); 298 exit(1); 299 } 300 } 301 else { 302 /* non-blocking... wooooooo */ 303 apr_size_t total_bytes_sent; 304 apr_pollfd_t pfd; 305 306 pset = NULL; 307 rv = apr_pollset_create(&pset, 1, p, 0); 308 assert(!rv); 309 pfd.p = p; 310 pfd.desc_type = APR_POLL_SOCKET; 311 pfd.reqevents = APR_POLLOUT; 312 pfd.rtnevents = 0; 313 pfd.desc.s = sock; 314 pfd.client_data = NULL; 315 316 rv = apr_pollset_add(pset, &pfd); 317 assert(!rv); 318 319 total_bytes_sent = 0; 320 current_file_offset = 0; 321 len = FILE_LENGTH; 322 do { 323 apr_size_t tmplen; 324 325 tmplen = len; /* bytes remaining to send from the file */ 326 printf("Calling apr_socket_sendfile()...\n"); 327 printf("Headers (%d):\n", hdtr.numheaders); 328 for (i = 0; i < hdtr.numheaders; i++) { 329 printf("\t%ld bytes (%c)\n", 330 (long)hdtr.headers[i].iov_len, 331 *(char *)hdtr.headers[i].iov_base); 332 } 333 printf("File: %ld bytes from offset %ld\n", 334 (long)tmplen, (long)current_file_offset); 335 printf("Trailers (%d):\n", hdtr.numtrailers); 336 for (i = 0; i < hdtr.numtrailers; i++) { 337 printf("\t%ld bytes\n", 338 (long)hdtr.trailers[i].iov_len); 339 } 340 341 rv = apr_socket_sendfile(sock, f, &hdtr, ¤t_file_offset, &tmplen, 0); 342 printf("apr_socket_sendfile()->%d, sent %ld bytes\n", rv, (long)tmplen); 343 if (rv) { 344 if (APR_STATUS_IS_EAGAIN(rv)) { 345 assert(tmplen == 0); 346 nsocks = 1; 347 tmprv = apr_pollset_poll(pset, -1, &nsocks, NULL); 348 assert(!tmprv); 349 assert(nsocks == 1); 350 /* continue; */ 351 } 352 } 353 354 total_bytes_sent += tmplen; 355 356 /* Adjust hdtr to compensate for partially-written 357 * data. 358 */ 359 360 /* First, skip over any header data which might have 361 * been written. 362 */ 363 while (tmplen && hdtr.numheaders) { 364 if (tmplen >= hdtr.headers[0].iov_len) { 365 tmplen -= hdtr.headers[0].iov_len; 366 --hdtr.numheaders; 367 ++hdtr.headers; 368 } 369 else { 370 hdtr.headers[0].iov_len -= tmplen; 371 hdtr.headers[0].iov_base = 372 (char*) hdtr.headers[0].iov_base + tmplen; 373 tmplen = 0; 374 } 375 } 376 377 /* Now, skip over any file data which might have been 378 * written. 379 */ 380 381 if (tmplen <= len) { 382 current_file_offset += tmplen; 383 len -= tmplen; 384 tmplen = 0; 385 } 386 else { 387 tmplen -= len; 388 len = 0; 389 current_file_offset = 0; 390 } 391 392 /* Last, skip over any trailer data which might have 393 * been written. 394 */ 395 396 while (tmplen && hdtr.numtrailers) { 397 if (tmplen >= hdtr.trailers[0].iov_len) { 398 tmplen -= hdtr.trailers[0].iov_len; 399 --hdtr.numtrailers; 400 ++hdtr.trailers; 401 } 402 else { 403 hdtr.trailers[0].iov_len -= tmplen; 404 hdtr.trailers[0].iov_base = 405 (char *)hdtr.trailers[0].iov_base + tmplen; 406 tmplen = 0; 407 } 408 } 409 410 } while (total_bytes_sent < expected_len && 411 (rv == APR_SUCCESS || 412 (APR_STATUS_IS_EAGAIN(rv) && socket_mode != TIMEOUT))); 413 if (total_bytes_sent != expected_len) { 414 fprintf(stderr, 415 "client problem: sent %ld of %ld bytes\n", 416 (long)total_bytes_sent, (long)expected_len); 417 exit(1); 418 } 419 420 if (rv) { 421 fprintf(stderr, 422 "client problem: rv %d\n", 423 rv); 424 exit(1); 425 } 426 } 427 428 current_file_offset = 0; 429 rv = apr_file_seek(f, APR_CUR, ¤t_file_offset); 430 if (rv != APR_SUCCESS) { 431 fprintf(stderr, "apr_file_seek()->%d/%s\n", 432 rv, 433 apr_strerror(rv, buf, sizeof buf)); 434 exit(1); 435 } 436 437 printf("After apr_socket_sendfile(), the kernel file pointer is " 438 "at offset %ld.\n", 439 (long int)current_file_offset); 440 441 rv = apr_socket_shutdown(sock, APR_SHUTDOWN_WRITE); 442 if (rv != APR_SUCCESS) { 443 fprintf(stderr, "apr_socket_shutdown()->%d/%s\n", 444 rv, 445 apr_strerror(rv, buf, sizeof buf)); 446 exit(1); 447 } 448 449 /* in case this is the non-blocking test, set socket timeout; 450 * we're just waiting for EOF */ 451 452 rv = apr_socket_timeout_set(sock, apr_time_from_sec(3)); 453 if (rv != APR_SUCCESS) { 454 fprintf(stderr, "apr_socket_timeout_set()->%d/%s\n", 455 rv, 456 apr_strerror(rv, buf, sizeof buf)); 457 exit(1); 458 } 459 460 bytes_read = 1; 461 rv = apr_socket_recv(sock, buf, &bytes_read); 462 if (rv != APR_EOF) { 463 fprintf(stderr, "apr_socket_recv()->%d/%s (expected APR_EOF)\n", 464 rv, 465 apr_strerror(rv, buf, sizeof buf)); 466 exit(1); 467 } 468 if (bytes_read != 0) { 469 fprintf(stderr, "We expected to get 0 bytes read with APR_EOF\n" 470 "but instead we read %ld bytes.\n", 471 (long int)bytes_read); 472 exit(1); 473 } 474 475 printf("client: apr_socket_sendfile() worked as expected!\n"); 476 477 rv = apr_file_remove(TESTFILE, p); 478 if (rv != APR_SUCCESS) { 479 fprintf(stderr, "apr_file_remove()->%d/%s\n", 480 rv, 481 apr_strerror(rv, buf, sizeof buf)); 482 exit(1); 483 } 484 485 return 0; 486} 487 488static int server(void) 489{ 490 apr_status_t rv; 491 apr_socket_t *sock; 492 apr_pool_t *p; 493 char buf[120]; 494 int i; 495 apr_socket_t *newsock = NULL; 496 apr_size_t bytes_read; 497 apr_sockaddr_t *localsa; 498 int family; 499 500 family = APR_UNSPEC; 501 apr_setup(&p, &sock, &family); 502 503 rv = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1); 504 if (rv != APR_SUCCESS) { 505 fprintf(stderr, "apr_socket_opt_set()->%d/%s\n", 506 rv, 507 apr_strerror(rv, buf, sizeof buf)); 508 exit(1); 509 } 510 511 rv = apr_sockaddr_info_get(&localsa, NULL, family, TESTSF_PORT, 0, p); 512 if (rv != APR_SUCCESS) { 513 fprintf(stderr, "apr_sockaddr_info_get()->%d/%s\n", 514 rv, 515 apr_strerror(rv, buf, sizeof buf)); 516 exit(1); 517 } 518 519 rv = apr_socket_bind(sock, localsa); 520 if (rv != APR_SUCCESS) { 521 fprintf(stderr, "apr_socket_bind()->%d/%s\n", 522 rv, 523 apr_strerror(rv, buf, sizeof buf)); 524 exit(1); 525 } 526 527 rv = apr_socket_listen(sock, 5); 528 if (rv != APR_SUCCESS) { 529 fprintf(stderr, "apr_socket_listen()->%d/%s\n", 530 rv, 531 apr_strerror(rv, buf, sizeof buf)); 532 exit(1); 533 } 534 535 printf("Waiting for a client to connect...\n"); 536 537 rv = apr_socket_accept(&newsock, sock, p); 538 if (rv != APR_SUCCESS) { 539 fprintf(stderr, "apr_socket_accept()->%d/%s\n", 540 rv, 541 apr_strerror(rv, buf, sizeof buf)); 542 exit(1); 543 } 544 545 printf("Processing a client...\n"); 546 547 assert(sizeof buf > strlen(HDR1)); 548 bytes_read = strlen(HDR1); 549 rv = apr_socket_recv(newsock, buf, &bytes_read); 550 if (rv != APR_SUCCESS) { 551 fprintf(stderr, "apr_socket_recv()->%d/%s\n", 552 rv, 553 apr_strerror(rv, buf, sizeof buf)); 554 exit(1); 555 } 556 if (bytes_read != strlen(HDR1)) { 557 fprintf(stderr, "wrong data read (1)\n"); 558 exit(1); 559 } 560 if (memcmp(buf, HDR1, strlen(HDR1))) { 561 fprintf(stderr, "wrong data read (2)\n"); 562 fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n", 563 (int)bytes_read, buf, HDR1); 564 exit(1); 565 } 566 567 assert(sizeof buf > strlen(HDR2)); 568 bytes_read = strlen(HDR2); 569 rv = apr_socket_recv(newsock, buf, &bytes_read); 570 if (rv != APR_SUCCESS) { 571 fprintf(stderr, "apr_socket_recv()->%d/%s\n", 572 rv, 573 apr_strerror(rv, buf, sizeof buf)); 574 exit(1); 575 } 576 if (bytes_read != strlen(HDR2)) { 577 fprintf(stderr, "wrong data read (3)\n"); 578 exit(1); 579 } 580 if (memcmp(buf, HDR2, strlen(HDR2))) { 581 fprintf(stderr, "wrong data read (4)\n"); 582 fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n", 583 (int)bytes_read, buf, HDR2); 584 exit(1); 585 } 586 587 for (i = 0; i < HDR3_LEN; i++) { 588 bytes_read = 1; 589 rv = apr_socket_recv(newsock, buf, &bytes_read); 590 if (rv != APR_SUCCESS) { 591 fprintf(stderr, "apr_socket_recv()->%d/%s\n", 592 rv, 593 apr_strerror(rv, buf, sizeof buf)); 594 exit(1); 595 } 596 if (bytes_read != 1) { 597 fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n", 598 (long int)bytes_read); 599 exit(1); 600 } 601 if (buf[0] != HDR3_CHAR) { 602 fprintf(stderr, 603 "problem with data read (byte %d of hdr 3):\n", 604 i); 605 fprintf(stderr, "read `%c' (0x%x) from client; expected " 606 "`%c'\n", 607 buf[0], buf[0], HDR3_CHAR); 608 exit(1); 609 } 610 } 611 612 for (i = 0; i < FILE_LENGTH; i++) { 613 bytes_read = 1; 614 rv = apr_socket_recv(newsock, buf, &bytes_read); 615 if (rv != APR_SUCCESS) { 616 fprintf(stderr, "apr_socket_recv()->%d/%s\n", 617 rv, 618 apr_strerror(rv, buf, sizeof buf)); 619 exit(1); 620 } 621 if (bytes_read != 1) { 622 fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n", 623 (long int)bytes_read); 624 exit(1); 625 } 626 if (buf[0] != FILE_DATA_CHAR) { 627 fprintf(stderr, 628 "problem with data read (byte %d of file):\n", 629 i); 630 fprintf(stderr, "read `%c' (0x%x) from client; expected " 631 "`%c'\n", 632 buf[0], buf[0], FILE_DATA_CHAR); 633 exit(1); 634 } 635 } 636 637 assert(sizeof buf > strlen(TRL1)); 638 bytes_read = strlen(TRL1); 639 rv = apr_socket_recv(newsock, buf, &bytes_read); 640 if (rv != APR_SUCCESS) { 641 fprintf(stderr, "apr_socket_recv()->%d/%s\n", 642 rv, 643 apr_strerror(rv, buf, sizeof buf)); 644 exit(1); 645 } 646 if (bytes_read != strlen(TRL1)) { 647 fprintf(stderr, "wrong data read (5)\n"); 648 exit(1); 649 } 650 if (memcmp(buf, TRL1, strlen(TRL1))) { 651 fprintf(stderr, "wrong data read (6)\n"); 652 fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n", 653 (int)bytes_read, buf, TRL1); 654 exit(1); 655 } 656 657 assert(sizeof buf > strlen(TRL2)); 658 bytes_read = strlen(TRL2); 659 rv = apr_socket_recv(newsock, buf, &bytes_read); 660 if (rv != APR_SUCCESS) { 661 fprintf(stderr, "apr_socket_recv()->%d/%s\n", 662 rv, 663 apr_strerror(rv, buf, sizeof buf)); 664 exit(1); 665 } 666 if (bytes_read != strlen(TRL2)) { 667 fprintf(stderr, "wrong data read (7)\n"); 668 exit(1); 669 } 670 if (memcmp(buf, TRL2, strlen(TRL2))) { 671 fprintf(stderr, "wrong data read (8)\n"); 672 fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n", 673 (int)bytes_read, buf, TRL2); 674 exit(1); 675 } 676 677 for (i = 0; i < TRL3_LEN; i++) { 678 bytes_read = 1; 679 rv = apr_socket_recv(newsock, buf, &bytes_read); 680 if (rv != APR_SUCCESS) { 681 fprintf(stderr, "apr_socket_recv()->%d/%s\n", 682 rv, 683 apr_strerror(rv, buf, sizeof buf)); 684 exit(1); 685 } 686 if (bytes_read != 1) { 687 fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n", 688 (long int)bytes_read); 689 exit(1); 690 } 691 if (buf[0] != TRL3_CHAR) { 692 fprintf(stderr, 693 "problem with data read (byte %d of trl 3):\n", 694 i); 695 fprintf(stderr, "read `%c' (0x%x) from client; expected " 696 "`%c'\n", 697 buf[0], buf[0], TRL3_CHAR); 698 exit(1); 699 } 700 } 701 702 bytes_read = 1; 703 rv = apr_socket_recv(newsock, buf, &bytes_read); 704 if (rv != APR_EOF) { 705 fprintf(stderr, "apr_socket_recv()->%d/%s (expected APR_EOF)\n", 706 rv, 707 apr_strerror(rv, buf, sizeof buf)); 708 exit(1); 709 } 710 if (bytes_read != 0) { 711 fprintf(stderr, "We expected to get 0 bytes read with APR_EOF\n" 712 "but instead we read %ld bytes (%c).\n", 713 (long int)bytes_read, buf[0]); 714 exit(1); 715 } 716 717 printf("server: apr_socket_sendfile() worked as expected!\n"); 718 719 return 0; 720} 721 722int main(int argc, char *argv[]) 723{ 724#ifdef SIGPIPE 725 signal(SIGPIPE, SIG_IGN); 726#endif 727 728 /* Gee whiz this is goofy logic but I wanna drive sendfile right now, 729 * not dork around with the command line! 730 */ 731 if (argc >= 3 && !strcmp(argv[1], "client")) { 732 char *host = 0; 733 if (argv[3]) { 734 host = argv[3]; 735 } 736 if (!strcmp(argv[2], "blocking")) { 737 return client(BLK, host); 738 } 739 else if (!strcmp(argv[2], "timeout")) { 740 return client(TIMEOUT, host); 741 } 742 else if (!strcmp(argv[2], "nonblocking")) { 743 return client(NONBLK, host); 744 } 745 } 746 else if (argc == 2 && !strcmp(argv[1], "server")) { 747 return server(); 748 } 749 750 fprintf(stderr, 751 "Usage: %s client {blocking|nonblocking|timeout}\n" 752 " %s server\n", 753 argv[0], argv[0]); 754 return -1; 755} 756 757#endif /* !APR_HAS_SENDFILE */ 758