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, &current_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, &current_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, &current_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