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/* Simple echo daemon, designed to be used for network throughput 18 * benchmarks. The aim is to allow us to monitor changes in performance 19 * of APR networking code, nothing more. 20 */ 21 22#include <stdio.h> 23#include <stdlib.h> /* for atexit() */ 24 25#include "apr.h" 26#include "apr_network_io.h" 27#include "apr_strings.h" 28 29#define BUF_SIZE 4096 30 31static void reportError(const char *msg, apr_status_t rv, 32 apr_pool_t *pool) 33{ 34 fprintf(stderr, "%s\nError: %d\n'%s'\n", msg, rv, 35 apr_psprintf(pool, "%pm", &rv)); 36} 37 38static apr_status_t talkTalk(apr_socket_t *socket, apr_pool_t *parent) 39{ 40 apr_pool_t *pool; 41 apr_size_t len; 42 char *buf; 43 apr_status_t rv; 44 45 if (apr_pool_create(&pool, parent) != APR_SUCCESS) 46 return APR_ENOPOOL; 47 48 49 buf = apr_palloc(pool, BUF_SIZE); 50 if (!buf) 51 return ENOMEM; 52 53 do { 54 len = BUF_SIZE; 55 rv = apr_socket_recv(socket, buf, &len); 56 if (APR_STATUS_IS_EOF(rv) || len == 0 || rv != APR_SUCCESS) 57 break; 58 rv = apr_socket_send(socket, buf, &len); 59 if (len == 0 || rv != APR_SUCCESS) 60 break; 61 } while (rv == APR_SUCCESS); 62 63 apr_pool_clear(pool); 64 return APR_SUCCESS; 65} 66 67static apr_status_t glassToWall(apr_int16_t port, apr_pool_t *parent) 68{ 69 apr_sockaddr_t *sockAddr; 70 apr_socket_t *listener, *accepted; 71 apr_status_t rv; 72 73 rv = apr_socket_create(&listener, APR_INET, SOCK_STREAM, APR_PROTO_TCP, 74 parent); 75 if (rv != APR_SUCCESS) { 76 reportError("Unable to create socket", rv, parent); 77 return rv; 78 } 79 80 rv = apr_sockaddr_info_get(&sockAddr, "127.0.0.1", APR_UNSPEC, 81 port, 0, parent); 82 if (rv != APR_SUCCESS) { 83 reportError("Unable to get socket info", rv, parent); 84 apr_socket_close(listener); 85 return rv; 86 } 87 88 if ((rv = apr_socket_bind(listener, sockAddr)) != APR_SUCCESS || 89 (rv = apr_socket_listen(listener, 5)) != APR_SUCCESS) { 90 reportError("Unable to bind or listen to socket", rv, parent); 91 apr_socket_close(listener); 92 return rv; 93 } 94 95 for (;;) { 96 rv = apr_socket_accept(&accepted, listener, parent); 97 if (rv != APR_SUCCESS) { 98 reportError("Error accepting on socket", rv, parent); 99 break; 100 } 101 printf("\tAnswering connection\n"); 102 rv = talkTalk(accepted, parent); 103 apr_socket_close(accepted); 104 printf("\tConnection closed\n"); 105 if (rv != APR_SUCCESS) 106 break; 107 } 108 109 apr_socket_close(listener); 110 return APR_SUCCESS; 111} 112 113int main(int argc, char **argv) 114{ 115 apr_pool_t *pool; 116 apr_int16_t theport = 4747; 117 118 printf("APR Test Application: echod\n"); 119 120 apr_initialize(); 121 atexit(apr_terminate); 122 123 apr_pool_create(&pool, NULL); 124 125 if (argc >= 2) { 126 printf("argc = %d, port = '%s'\n", argc, argv[1]); 127 theport = atoi(argv[1]); 128 } 129 130 fprintf(stdout, "Starting to listen on port %d\n", theport); 131 glassToWall(theport, pool); 132 133 return 0; 134} 135