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
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, *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;
306 rv = apr_poll_setup(&pfd, 1, p);
308 rv = apr_poll_socket_add(pfd, sock, APR_POLLOUT);
311 total_bytes_sent = 0;
312 current_file_offset = 0;
317 tmplen = len; /* bytes remaining to send from the file */
318 printf("Calling apr_socket_sendfile()...\n");
319 printf("Headers (%d):\n", hdtr.numheaders);
320 for (i = 0; i < hdtr.numheaders; i++) {
321 printf("\t%ld bytes (%c)\n",
322 (long)hdtr.headers[i].iov_len,
323 *(char *)hdtr.headers[i].iov_base);
325 printf("File: %ld bytes from offset %ld\n",
326 (long)tmplen, (long)current_file_offset);
327 printf("Trailers (%d):\n", hdtr.numtrailers);
328 for (i = 0; i < hdtr.numtrailers; i++) {
329 printf("\t%ld bytes\n",
330 (long)hdtr.trailers[i].iov_len);
333 rv = apr_socket_sendfile(sock, f, &hdtr, ¤t_file_offset, &tmplen, 0);
334 printf("apr_socket_sendfile()->%d, sent %ld bytes\n", rv, (long)tmplen);
336 if (APR_STATUS_IS_EAGAIN(rv)) {
339 tmprv = apr_poll(pfd, 1, &nsocks, -1);
346 total_bytes_sent += tmplen;
348 /* Adjust hdtr to compensate for partially-written
352 /* First, skip over any header data which might have
355 while (tmplen && hdtr.numheaders) {
356 if (tmplen >= hdtr.headers[0].iov_len) {
357 tmplen -= hdtr.headers[0].iov_len;
362 hdtr.headers[0].iov_len -= tmplen;
363 hdtr.headers[0].iov_base =
364 (char*) hdtr.headers[0].iov_base + tmplen;
369 /* Now, skip over any file data which might have been
374 current_file_offset += tmplen;
381 current_file_offset = 0;
384 /* Last, skip over any trailer data which might have
388 while (tmplen && hdtr.numtrailers) {
389 if (tmplen >= hdtr.trailers[0].iov_len) {
390 tmplen -= hdtr.trailers[0].iov_len;
395 hdtr.trailers[0].iov_len -= tmplen;
396 hdtr.trailers[0].iov_base =
397 (char *)hdtr.trailers[0].iov_base + tmplen;
402 } while (total_bytes_sent < expected_len &&
403 (rv == APR_SUCCESS ||
404 (APR_STATUS_IS_EAGAIN(rv) && socket_mode != TIMEOUT)));
405 if (total_bytes_sent != expected_len) {
407 "client problem: sent %ld of %ld bytes\n",
408 (long)total_bytes_sent, (long)expected_len);
414 "client problem: rv %d\n",
420 current_file_offset = 0;
421 rv = apr_file_seek(f, APR_CUR, ¤t_file_offset);
422 if (rv != APR_SUCCESS) {
423 fprintf(stderr, "apr_file_seek()->%d/%s\n",
425 apr_strerror(rv, buf, sizeof buf));
429 printf("After apr_socket_sendfile(), the kernel file pointer is "
431 (long int)current_file_offset);
433 rv = apr_socket_shutdown(sock, APR_SHUTDOWN_WRITE);
434 if (rv != APR_SUCCESS) {
435 fprintf(stderr, "apr_socket_shutdown()->%d/%s\n",
437 apr_strerror(rv, buf, sizeof buf));
441 /* in case this is the non-blocking test, set socket timeout;
442 * we're just waiting for EOF */
444 rv = apr_socket_timeout_set(sock, apr_time_from_sec(3));
445 if (rv != APR_SUCCESS) {
446 fprintf(stderr, "apr_socket_timeout_set()->%d/%s\n",
448 apr_strerror(rv, buf, sizeof buf));
453 rv = apr_socket_recv(sock, buf, &bytes_read);
455 fprintf(stderr, "apr_socket_recv()->%d/%s (expected APR_EOF)\n",
457 apr_strerror(rv, buf, sizeof buf));
460 if (bytes_read != 0) {
461 fprintf(stderr, "We expected to get 0 bytes read with APR_EOF\n"
462 "but instead we read %ld bytes.\n",
463 (long int)bytes_read);
467 printf("client: apr_socket_sendfile() worked as expected!\n");
469 rv = apr_file_remove(TESTFILE, p);
470 if (rv != APR_SUCCESS) {
471 fprintf(stderr, "apr_file_remove()->%d/%s\n",
473 apr_strerror(rv, buf, sizeof buf));
480 static int server(void)
487 apr_socket_t *newsock = NULL;
488 apr_size_t bytes_read;
489 apr_sockaddr_t *localsa;
493 apr_setup(&p, &sock, &family);
495 rv = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1);
496 if (rv != APR_SUCCESS) {
497 fprintf(stderr, "apr_socket_opt_set()->%d/%s\n",
499 apr_strerror(rv, buf, sizeof buf));
503 rv = apr_sockaddr_info_get(&localsa, NULL, family, TESTSF_PORT, 0, p);
504 if (rv != APR_SUCCESS) {
505 fprintf(stderr, "apr_sockaddr_info_get()->%d/%s\n",
507 apr_strerror(rv, buf, sizeof buf));
511 rv = apr_socket_bind(sock, localsa);
512 if (rv != APR_SUCCESS) {
513 fprintf(stderr, "apr_socket_bind()->%d/%s\n",
515 apr_strerror(rv, buf, sizeof buf));
519 rv = apr_socket_listen(sock, 5);
520 if (rv != APR_SUCCESS) {
521 fprintf(stderr, "apr_socket_listen()->%d/%s\n",
523 apr_strerror(rv, buf, sizeof buf));
527 printf("Waiting for a client to connect...\n");
529 rv = apr_socket_accept(&newsock, sock, p);
530 if (rv != APR_SUCCESS) {
531 fprintf(stderr, "apr_socket_accept()->%d/%s\n",
533 apr_strerror(rv, buf, sizeof buf));
537 printf("Processing a client...\n");
539 assert(sizeof buf > strlen(HDR1));
540 bytes_read = strlen(HDR1);
541 rv = apr_socket_recv(newsock, buf, &bytes_read);
542 if (rv != APR_SUCCESS) {
543 fprintf(stderr, "apr_socket_recv()->%d/%s\n",
545 apr_strerror(rv, buf, sizeof buf));
548 if (bytes_read != strlen(HDR1)) {
549 fprintf(stderr, "wrong data read (1)\n");
552 if (memcmp(buf, HDR1, strlen(HDR1))) {
553 fprintf(stderr, "wrong data read (2)\n");
554 fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n",
555 (int)bytes_read, buf, HDR1);
559 assert(sizeof buf > strlen(HDR2));
560 bytes_read = strlen(HDR2);
561 rv = apr_socket_recv(newsock, buf, &bytes_read);
562 if (rv != APR_SUCCESS) {
563 fprintf(stderr, "apr_socket_recv()->%d/%s\n",
565 apr_strerror(rv, buf, sizeof buf));
568 if (bytes_read != strlen(HDR2)) {
569 fprintf(stderr, "wrong data read (3)\n");
572 if (memcmp(buf, HDR2, strlen(HDR2))) {
573 fprintf(stderr, "wrong data read (4)\n");
574 fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n",
575 (int)bytes_read, buf, HDR2);
579 for (i = 0; i < HDR3_LEN; i++) {
581 rv = apr_socket_recv(newsock, buf, &bytes_read);
582 if (rv != APR_SUCCESS) {
583 fprintf(stderr, "apr_socket_recv()->%d/%s\n",
585 apr_strerror(rv, buf, sizeof buf));
588 if (bytes_read != 1) {
589 fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n",
590 (long int)bytes_read);
593 if (buf[0] != HDR3_CHAR) {
595 "problem with data read (byte %d of hdr 3):\n",
597 fprintf(stderr, "read `%c' (0x%x) from client; expected "
599 buf[0], buf[0], HDR3_CHAR);
604 for (i = 0; i < FILE_LENGTH; i++) {
606 rv = apr_socket_recv(newsock, buf, &bytes_read);
607 if (rv != APR_SUCCESS) {
608 fprintf(stderr, "apr_socket_recv()->%d/%s\n",
610 apr_strerror(rv, buf, sizeof buf));
613 if (bytes_read != 1) {
614 fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n",
615 (long int)bytes_read);
618 if (buf[0] != FILE_DATA_CHAR) {
620 "problem with data read (byte %d of file):\n",
622 fprintf(stderr, "read `%c' (0x%x) from client; expected "
624 buf[0], buf[0], FILE_DATA_CHAR);
629 assert(sizeof buf > strlen(TRL1));
630 bytes_read = strlen(TRL1);
631 rv = apr_socket_recv(newsock, buf, &bytes_read);
632 if (rv != APR_SUCCESS) {
633 fprintf(stderr, "apr_socket_recv()->%d/%s\n",
635 apr_strerror(rv, buf, sizeof buf));
638 if (bytes_read != strlen(TRL1)) {
639 fprintf(stderr, "wrong data read (5)\n");
642 if (memcmp(buf, TRL1, strlen(TRL1))) {
643 fprintf(stderr, "wrong data read (6)\n");
644 fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n",
645 (int)bytes_read, buf, TRL1);
649 assert(sizeof buf > strlen(TRL2));
650 bytes_read = strlen(TRL2);
651 rv = apr_socket_recv(newsock, buf, &bytes_read);
652 if (rv != APR_SUCCESS) {
653 fprintf(stderr, "apr_socket_recv()->%d/%s\n",
655 apr_strerror(rv, buf, sizeof buf));
658 if (bytes_read != strlen(TRL2)) {
659 fprintf(stderr, "wrong data read (7)\n");
662 if (memcmp(buf, TRL2, strlen(TRL2))) {
663 fprintf(stderr, "wrong data read (8)\n");
664 fprintf(stderr, "received: `%.*s'\nexpected: `%s'\n",
665 (int)bytes_read, buf, TRL2);
669 for (i = 0; i < TRL3_LEN; i++) {
671 rv = apr_socket_recv(newsock, buf, &bytes_read);
672 if (rv != APR_SUCCESS) {
673 fprintf(stderr, "apr_socket_recv()->%d/%s\n",
675 apr_strerror(rv, buf, sizeof buf));
678 if (bytes_read != 1) {
679 fprintf(stderr, "apr_socket_recv()->%ld bytes instead of 1\n",
680 (long int)bytes_read);
683 if (buf[0] != TRL3_CHAR) {
685 "problem with data read (byte %d of trl 3):\n",
687 fprintf(stderr, "read `%c' (0x%x) from client; expected "
689 buf[0], buf[0], TRL3_CHAR);
695 rv = apr_socket_recv(newsock, buf, &bytes_read);
697 fprintf(stderr, "apr_socket_recv()->%d/%s (expected APR_EOF)\n",
699 apr_strerror(rv, buf, sizeof buf));
702 if (bytes_read != 0) {
703 fprintf(stderr, "We expected to get 0 bytes read with APR_EOF\n"
704 "but instead we read %ld bytes (%c).\n",
705 (long int)bytes_read, buf[0]);
709 printf("server: apr_socket_sendfile() worked as expected!\n");
714 int main(int argc, char *argv[])
717 signal(SIGPIPE, SIG_IGN);
720 /* Gee whiz this is goofy logic but I wanna drive sendfile right now,
721 * not dork around with the command line!
723 if (argc >= 3 && !strcmp(argv[1], "client")) {
728 if (!strcmp(argv[2], "blocking")) {
729 return client(BLK, host);
731 else if (!strcmp(argv[2], "timeout")) {
732 return client(TIMEOUT, host);
734 else if (!strcmp(argv[2], "nonblocking")) {
735 return client(NONBLK, host);
738 else if (argc == 2 && !strcmp(argv[1], "server")) {
743 "Usage: %s client {blocking|nonblocking|timeout}\n"
749 #endif /* !APR_HAS_SENDFILE */