1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
22
#include "apr_network_io.h"
23
#include "apr_errno.h"
24
#include "apr_general.h"
31
"This program won't work on this platform because there is no "
32
"support for sendfile().\n");
35
#else /* !APR_HAS_SENDFILE */
37
#define FILE_LENGTH 200000
39
#define FILE_DATA_CHAR '0'
41
#define HDR1 "1234567890ABCD\n"
43
#define HDR3_LEN 80000
45
#define TRL1 "IJKLMNOPQRSTUVWXYZ\n"
46
#define TRL2 "!@#$%&*()\n"
47
#define TRL3_LEN 90000
50
#define TESTSF_PORT 8021
52
#define TESTFILE "testsf.dat"
54
typedef enum {BLK, NONBLK, TIMEOUT} client_socket_mode_t;
56
static void apr_setup(apr_pool_t **p, apr_socket_t **sock, int *family)
61
rv = apr_initialize();
62
if (rv != APR_SUCCESS) {
63
fprintf(stderr, "apr_initialize()->%d/%s\n",
65
apr_strerror(rv, buf, sizeof buf));
69
atexit(apr_terminate);
71
rv = apr_pool_create(p, NULL);
72
if (rv != APR_SUCCESS) {
73
fprintf(stderr, "apr_pool_create()->%d/%s\n",
75
apr_strerror(rv, buf, sizeof buf));
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",
84
apr_strerror(rv, buf, sizeof buf));
88
if (*family == APR_UNSPEC) {
89
apr_sockaddr_t *localsa;
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",
95
apr_strerror(rv, buf, sizeof buf));
98
*family = localsa->family;
102
static void create_testfile(apr_pool_t *p, const char *fname)
104
apr_file_t *f = NULL;
110
printf("Creating a test file...\n");
111
rv = apr_file_open(&f, fname,
112
APR_CREATE | APR_WRITE | APR_TRUNCATE | APR_BUFFERED,
113
APR_UREAD | APR_UWRITE, p);
115
fprintf(stderr, "apr_file_open()->%d/%s\n",
116
rv, apr_strerror(rv, buf, sizeof buf));
120
buf[0] = FILE_DATA_CHAR;
122
for (i = 0; i < FILE_LENGTH; i++) {
123
/* exercise apr_file_putc() and apr_file_puts() on buffered files */
125
rv = apr_file_putc(buf[0], f);
127
fprintf(stderr, "apr_file_putc()->%d/%s\n",
128
rv, apr_strerror(rv, buf, sizeof buf));
133
rv = apr_file_puts(buf, f);
135
fprintf(stderr, "apr_file_puts()->%d/%s\n",
136
rv, apr_strerror(rv, buf, sizeof buf));
142
rv = apr_file_close(f);
144
fprintf(stderr, "apr_file_close()->%d/%s\n",
145
rv, apr_strerror(rv, buf, sizeof buf));
149
rv = apr_stat(&finfo, fname, APR_FINFO_NORM, p);
150
if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
151
fprintf(stderr, "apr_stat()->%d/%s\n",
152
rv, apr_strerror(rv, buf, sizeof buf));
156
if (finfo.size != FILE_LENGTH) {
158
"test file %s should be %ld-bytes long\n"
159
"instead it is %ld-bytes long\n",
161
(long int)FILE_LENGTH,
162
(long int)finfo.size);
167
static int client(client_socket_mode_t socket_mode, char *host)
169
apr_status_t rv, tmprv;
173
apr_file_t *f = NULL;
175
apr_size_t expected_len;
176
apr_off_t current_file_offset;
178
struct iovec headers[3];
179
struct iovec trailers[3];
180
apr_size_t bytes_read;
185
apr_sockaddr_t *destsa;
188
apr_setup(&p, &sock, &family);
189
create_testfile(p, TESTFILE);
191
rv = apr_file_open(&f, TESTFILE, APR_READ, 0, p);
192
if (rv != APR_SUCCESS) {
193
fprintf(stderr, "apr_file_open()->%d/%s\n",
195
apr_strerror(rv, buf, sizeof buf));
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",
206
apr_strerror(rv, buf, sizeof buf));
210
rv = apr_socket_connect(sock, destsa);
211
if (rv != APR_SUCCESS) {
212
fprintf(stderr, "apr_socket_connect()->%d/%s\n",
214
apr_strerror(rv, buf, sizeof buf));
218
switch(socket_mode) {
220
/* leave it blocking */
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",
228
apr_strerror(rv, buf, sizeof buf));
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",
238
apr_strerror(rv, buf, sizeof buf));
246
printf("Sending the file...\n");
248
hdtr.headers = headers;
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;
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;
271
strlen(HDR1) + strlen(HDR2) + HDR3_LEN +
272
strlen(TRL1) + strlen(TRL2) + TRL3_LEN +
275
if (socket_mode == BLK) {
276
current_file_offset = 0;
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",
282
apr_strerror(rv, buf, sizeof buf));
286
printf("apr_socket_sendfile() updated offset with %ld\n",
287
(long int)current_file_offset);
289
printf("apr_socket_sendfile() updated len with %ld\n",
292
printf("bytes really sent: %" APR_SIZE_T_FMT "\n",
295
if (len != expected_len) {
296
fprintf(stderr, "apr_socket_sendfile() didn't report the correct "
297
"number of bytes sent!\n");
302
/* non-blocking... wooooooo */
303
apr_size_t total_bytes_sent;
307
rv = apr_pollset_create(&pset, 1, p, 0);
310
pfd.desc_type = APR_POLL_SOCKET;
311
pfd.reqevents = APR_POLLOUT;
314
pfd.client_data = NULL;
316
rv = apr_pollset_add(pset, &pfd);
319
total_bytes_sent = 0;
320
current_file_offset = 0;
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);
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);
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);
344
if (APR_STATUS_IS_EAGAIN(rv)) {
347
tmprv = apr_pollset_poll(pset, -1, &nsocks, NULL);
354
total_bytes_sent += tmplen;
356
/* Adjust hdtr to compensate for partially-written
360
/* First, skip over any header data which might have
363
while (tmplen && hdtr.numheaders) {
364
if (tmplen >= hdtr.headers[0].iov_len) {
365
tmplen -= hdtr.headers[0].iov_len;
370
hdtr.headers[0].iov_len -= tmplen;
371
hdtr.headers[0].iov_base =
372
(char*) hdtr.headers[0].iov_base + tmplen;
377
/* Now, skip over any file data which might have been
382
current_file_offset += tmplen;
389
current_file_offset = 0;
392
/* Last, skip over any trailer data which might have
396
while (tmplen && hdtr.numtrailers) {
397
if (tmplen >= hdtr.trailers[0].iov_len) {
398
tmplen -= hdtr.trailers[0].iov_len;
403
hdtr.trailers[0].iov_len -= tmplen;
404
hdtr.trailers[0].iov_base =
405
(char *)hdtr.trailers[0].iov_base + tmplen;
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) {
415
"client problem: sent %ld of %ld bytes\n",
416
(long)total_bytes_sent, (long)expected_len);
422
"client problem: rv %d\n",
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",
433
apr_strerror(rv, buf, sizeof buf));
437
printf("After apr_socket_sendfile(), the kernel file pointer is "
439
(long int)current_file_offset);
441
rv = apr_socket_shutdown(sock, APR_SHUTDOWN_WRITE);
442
if (rv != APR_SUCCESS) {
443
fprintf(stderr, "apr_socket_shutdown()->%d/%s\n",
445
apr_strerror(rv, buf, sizeof buf));
449
/* in case this is the non-blocking test, set socket timeout;
450
* we're just waiting for EOF */
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",
456
apr_strerror(rv, buf, sizeof buf));
461
rv = apr_socket_recv(sock, buf, &bytes_read);
463
fprintf(stderr, "apr_socket_recv()->%d/%s (expected APR_EOF)\n",
465
apr_strerror(rv, buf, sizeof buf));
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);
475
printf("client: apr_socket_sendfile() worked as expected!\n");
477
rv = apr_file_remove(TESTFILE, p);
478
if (rv != APR_SUCCESS) {
479
fprintf(stderr, "apr_file_remove()->%d/%s\n",
481
apr_strerror(rv, buf, sizeof buf));
488
static int server(void)
495
apr_socket_t *newsock = NULL;
496
apr_size_t bytes_read;
497
apr_sockaddr_t *localsa;
501
apr_setup(&p, &sock, &family);
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",
507
apr_strerror(rv, buf, sizeof buf));
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",
515
apr_strerror(rv, buf, sizeof buf));
519
rv = apr_socket_bind(sock, localsa);
520
if (rv != APR_SUCCESS) {
521
fprintf(stderr, "apr_socket_bind()->%d/%s\n",
523
apr_strerror(rv, buf, sizeof buf));
527
rv = apr_socket_listen(sock, 5);
528
if (rv != APR_SUCCESS) {
529
fprintf(stderr, "apr_socket_listen()->%d/%s\n",
531
apr_strerror(rv, buf, sizeof buf));
535
printf("Waiting for a client to connect...\n");
537
rv = apr_socket_accept(&newsock, sock, p);
538
if (rv != APR_SUCCESS) {
539
fprintf(stderr, "apr_socket_accept()->%d/%s\n",
541
apr_strerror(rv, buf, sizeof buf));
545
printf("Processing a client...\n");
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",
553
apr_strerror(rv, buf, sizeof buf));
556
if (bytes_read != strlen(HDR1)) {
557
fprintf(stderr, "wrong data read (1)\n");
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);
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",
573
apr_strerror(rv, buf, sizeof buf));
576
if (bytes_read != strlen(HDR2)) {
577
fprintf(stderr, "wrong data read (3)\n");
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);
587
for (i = 0; i < HDR3_LEN; i++) {
589
rv = apr_socket_recv(newsock, buf, &bytes_read);
590
if (rv != APR_SUCCESS) {
591
fprintf(stderr, "apr_socket_recv()->%d/%s\n",
593
apr_strerror(rv, buf, sizeof buf));
596
if (bytes_read != 1) {
597
fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n",
598
(long int)bytes_read);
601
if (buf[0] != HDR3_CHAR) {
603
"problem with data read (byte %d of hdr 3):\n",
605
fprintf(stderr, "read `%c' (0x%x) from client; expected "
607
buf[0], buf[0], HDR3_CHAR);
612
for (i = 0; i < FILE_LENGTH; i++) {
614
rv = apr_socket_recv(newsock, buf, &bytes_read);
615
if (rv != APR_SUCCESS) {
616
fprintf(stderr, "apr_socket_recv()->%d/%s\n",
618
apr_strerror(rv, buf, sizeof buf));
621
if (bytes_read != 1) {
622
fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n",
623
(long int)bytes_read);
626
if (buf[0] != FILE_DATA_CHAR) {
628
"problem with data read (byte %d of file):\n",
630
fprintf(stderr, "read `%c' (0x%x) from client; expected "
632
buf[0], buf[0], FILE_DATA_CHAR);
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",
643
apr_strerror(rv, buf, sizeof buf));
646
if (bytes_read != strlen(TRL1)) {
647
fprintf(stderr, "wrong data read (5)\n");
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);
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",
663
apr_strerror(rv, buf, sizeof buf));
666
if (bytes_read != strlen(TRL2)) {
667
fprintf(stderr, "wrong data read (7)\n");
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);
677
for (i = 0; i < TRL3_LEN; i++) {
679
rv = apr_socket_recv(newsock, buf, &bytes_read);
680
if (rv != APR_SUCCESS) {
681
fprintf(stderr, "apr_socket_recv()->%d/%s\n",
683
apr_strerror(rv, buf, sizeof buf));
686
if (bytes_read != 1) {
687
fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n",
688
(long int)bytes_read);
691
if (buf[0] != TRL3_CHAR) {
693
"problem with data read (byte %d of trl 3):\n",
695
fprintf(stderr, "read `%c' (0x%x) from client; expected "
697
buf[0], buf[0], TRL3_CHAR);
703
rv = apr_socket_recv(newsock, buf, &bytes_read);
705
fprintf(stderr, "apr_socket_recv()->%d/%s (expected APR_EOF)\n",
707
apr_strerror(rv, buf, sizeof buf));
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]);
717
printf("server: apr_socket_sendfile() worked as expected!\n");
722
int main(int argc, char *argv[])
725
signal(SIGPIPE, SIG_IGN);
728
/* Gee whiz this is goofy logic but I wanna drive sendfile right now,
729
* not dork around with the command line!
731
if (argc >= 3 && !strcmp(argv[1], "client")) {
736
if (!strcmp(argv[2], "blocking")) {
737
return client(BLK, host);
739
else if (!strcmp(argv[2], "timeout")) {
740
return client(TIMEOUT, host);
742
else if (!strcmp(argv[2], "nonblocking")) {
743
return client(NONBLK, host);
746
else if (argc == 2 && !strcmp(argv[1], "server")) {
751
"Usage: %s client {blocking|nonblocking|timeout}\n"
757
#endif /* !APR_HAS_SENDFILE */