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