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