diff options
Diffstat (limited to 'test/sockperf.c')
-rw-r--r-- | test/sockperf.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/test/sockperf.c b/test/sockperf.c new file mode 100644 index 0000000..28368ef --- /dev/null +++ b/test/sockperf.c @@ -0,0 +1,256 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* sockperf.c + * This simple network client tries to connect to an echo daemon (echod) + * listening on a port it supplies, then time how long it takes to + * reply with packets of varying sizes. + * It prints results once completed. + * + * To run, + * + * ./echod & + * ./sockperf + */ + +#include <stdio.h> +#include <stdlib.h> /* for atexit() */ + +#include "apr.h" +#include "apr_network_io.h" +#include "apr_strings.h" + +#define MAX_ITERS 10 +#define TEST_SIZE 1024 + +struct testSet { + char c; + apr_size_t size; + int iters; +} testRuns[] = { + { 'a', 1, 3 }, + { 'b', 4, 3 }, + { 'c', 16, 5 }, + { 'd', 64, 5 }, + { 'e', 256, 10 }, +}; + +struct testResult { + int size; + int iters; + apr_time_t msecs[MAX_ITERS]; + apr_time_t avg; +}; + +static apr_int16_t testPort = 4747; +static apr_sockaddr_t *sockAddr = NULL; + +static void reportError(const char *msg, apr_status_t rv, + apr_pool_t *pool) +{ + fprintf(stderr, "%s\n", msg); + if (rv != APR_SUCCESS) + fprintf(stderr, "Error: %d\n'%s'\n", rv, + apr_psprintf(pool, "%pm", &rv)); + +} + +static void closeConnection(apr_socket_t *sock) +{ + apr_size_t len = 0; + apr_socket_send(sock, NULL, &len); +} + +static apr_status_t sendRecvBuffer(apr_time_t *t, const char *buf, + apr_size_t size, apr_pool_t *pool) +{ + apr_socket_t *sock; + apr_status_t rv; + apr_size_t len = size, thistime = size; + char *recvBuf; + apr_time_t testStart = apr_time_now(), testEnd; + int i; + + if (! sockAddr) { + rv = apr_sockaddr_info_get(&sockAddr, "127.0.0.1", APR_UNSPEC, + testPort, 0, pool); + if (rv != APR_SUCCESS) { + reportError("Unable to get socket info", rv, pool); + return rv; + } + + /* make sure we can connect to daemon before we try tests */ + + rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, APR_PROTO_TCP, + pool); + if (rv != APR_SUCCESS) { + reportError("Unable to create IPv4 stream socket", rv, pool); + return rv; + } + + rv = apr_socket_connect(sock, sockAddr); + if (rv != APR_SUCCESS) { + reportError("Unable to connect to echod!", rv, pool); + apr_socket_close(sock); + return rv; + } + apr_socket_close(sock); + + } + + recvBuf = apr_palloc(pool, size); + if (! recvBuf) { + reportError("Unable to allocate buffer", ENOMEM, pool); + return ENOMEM; + } + + *t = 0; + + /* START! */ + testStart = apr_time_now(); + rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, APR_PROTO_TCP, + pool); + if (rv != APR_SUCCESS) { + reportError("Unable to create IPv4 stream socket", rv, pool); + return rv; + } + + rv = apr_socket_connect(sock, sockAddr); + if (rv != APR_SUCCESS) { + reportError("Unable to connect to echod!", rv, pool); + apr_socket_close(sock); + return rv; + } + + for (i = 0; i < 3; i++) { + + len = size; + thistime = size; + + rv = apr_socket_send(sock, buf, &len); + if (rv != APR_SUCCESS || len != size) { + reportError(apr_psprintf(pool, + "Unable to send data correctly (iteration %d of 3)", + i) , rv, pool); + closeConnection(sock); + apr_socket_close(sock); + return rv; + } + + do { + len = thistime; + rv = apr_socket_recv(sock, &recvBuf[size - thistime], &len); + if (rv != APR_SUCCESS) { + reportError("Error receiving from socket", rv, pool); + break; + } + thistime -= len; + } while (thistime); + } + + closeConnection(sock); + apr_socket_close(sock); + testEnd = apr_time_now(); + /* STOP! */ + + if (thistime) { + reportError("Received less than we sent :-(", rv, pool); + return rv; + } + if (strncmp(recvBuf, buf, size) != 0) { + reportError("Received corrupt data :-(", 0, pool); + printf("We sent:\n%s\nWe received:\n%s\n", buf, recvBuf); + return EINVAL; + } + *t = testEnd - testStart; + return APR_SUCCESS; +} + +static apr_status_t runTest(struct testSet *ts, struct testResult *res, + apr_pool_t *pool) +{ + char *buffer; + apr_status_t rv = APR_SUCCESS; + int i; + apr_size_t sz = ts->size * TEST_SIZE; + + buffer = apr_palloc(pool, sz); + if (!buffer) { + reportError("Unable to allocate buffer", ENOMEM, pool); + return ENOMEM; + } + memset(buffer, ts->c, sz); + + res->iters = ts->iters > MAX_ITERS ? MAX_ITERS : ts->iters; + + for (i = 0; i < res->iters; i++) { + apr_time_t iterTime; + rv = sendRecvBuffer(&iterTime, buffer, sz, pool); + if (rv != APR_SUCCESS) { + res->iters = i; + break; + } + res->msecs[i] = iterTime; + } + + return rv; +} + +int main(int argc, char **argv) +{ + apr_pool_t *pool; + apr_status_t rv; + int i; + int nTests = sizeof(testRuns) / sizeof(testRuns[0]); + struct testResult *results; + + printf("APR Test Application: sockperf\n"); + + apr_initialize(); + atexit(apr_terminate); + + apr_pool_create(&pool, NULL); + + results = (struct testResult *)apr_pcalloc(pool, + sizeof(*results) * nTests); + + for (i = 0; i < nTests; i++) { + printf("Test -> %c\n", testRuns[i].c); + results[i].size = testRuns[i].size * (apr_size_t)TEST_SIZE; + rv = runTest(&testRuns[i], &results[i], pool); + if (rv != APR_SUCCESS) { + /* error already reported */ + exit(1); + } + } + + printf("Tests Complete!\n"); + for (i = 0; i < nTests; i++) { + int j; + apr_time_t totTime = 0; + printf("%10d byte block:\n", results[i].size); + printf("\t%2d iterations : ", results[i].iters); + for (j = 0; j < results[i].iters; j++) { + printf("%6" APR_TIME_T_FMT, results[i].msecs[j]); + totTime += results[i].msecs[j]; + } + printf("<\n"); + printf("\t Average: %6" APR_TIME_T_FMT "\n", + totTime / results[i].iters); + } + + return 0; +} |