From f4997daeacd0e0e92e02857e366451747a7e9a52 Mon Sep 17 00:00:00 2001 From: Robert Watson Date: Wed, 5 Oct 2005 12:10:35 +0000 Subject: [PATCH] Add simple TCP connect and TCP receive benchmark components, intended to measure the rate of TCP connection round trips supported by a host at the socket layer. --- tools/tools/netrate/tcpconnect/Makefile | 7 + tools/tools/netrate/tcpconnect/tcpconnect.c | 135 ++++++++++++++++++++ tools/tools/netrate/tcpreceive/Makefile | 7 + tools/tools/netrate/tcpreceive/tcpreceive.c | 113 ++++++++++++++++ 4 files changed, 262 insertions(+) create mode 100644 tools/tools/netrate/tcpconnect/Makefile create mode 100644 tools/tools/netrate/tcpconnect/tcpconnect.c create mode 100644 tools/tools/netrate/tcpreceive/Makefile create mode 100644 tools/tools/netrate/tcpreceive/tcpreceive.c diff --git a/tools/tools/netrate/tcpconnect/Makefile b/tools/tools/netrate/tcpconnect/Makefile new file mode 100644 index 000000000000..4a3f5ad57e19 --- /dev/null +++ b/tools/tools/netrate/tcpconnect/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +PROG= tcpconnect +WARNS= 3 +NO_MAN= + +.include diff --git a/tools/tools/netrate/tcpconnect/tcpconnect.c b/tools/tools/netrate/tcpconnect/tcpconnect.c new file mode 100644 index 000000000000..efcde7681244 --- /dev/null +++ b/tools/tools/netrate/tcpconnect/tcpconnect.c @@ -0,0 +1,135 @@ +/*- + * Copyright (c) 2005 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +/* + * Simple micro-benchmark to see how many connections/second can be created + * in a serialized fashion against a given server. A timer signal is used + * to interrupt the loop and assess the cost. + */ +#define SECONDS 60 +#define PORT 6060 + +static int timer_fired; + +/* + * Signal timer, which both interrupts the in-progress socket operation, and + * flags the timer as having fired so the main loop can exit. + */ +static void +alarm_handler(__unused int signum) +{ + + timer_fired = 1; +} + +/* + * Build a connection. In order to make sure the signal interrupts us as + * we wait, use non-blocking sockets and select(). Return 0 on success, or + * -1 if we were interrupted. Exit with a failure if we get an unspected + * error. + */ +static int +try_connect(struct sockaddr_in *sin) +{ + struct + fd_set read_set; + int i, s; + + s = socket(PF_INET, SOCK_STREAM, 0); + if (s < 0) + err(-1, "socket(PF_INET, SOCK_STREAM)"); + + i = 1; + if (fcntl(s, F_SETFL, FIONBIO, &i) < 0) + err(-1, "fcntl(s, FIOBIO, 1)"); + + FD_ZERO(&read_set); + FD_SET(s, &read_set); + + if (connect(s, (struct sockaddr *)sin, sizeof(*sin)) < 0 && + errno != EINPROGRESS) + err(-1, "connect(%s)", inet_ntoa(sin->sin_addr)); + + if (select(s + 1, &read_set, &read_set, &read_set, NULL) < 0) { + if ((errno == EINTR && !timer_fired) || (errno != EINTR)) + err(-1, "select"); + return (-1); + } + + close(s); + return (0); +} + + +int +main(int argc, char *argv[]) +{ + struct sockaddr_in sin; + u_int64_t counter; + + if (argc != 2) + err(-1, "usage: tcpconnect [ip]"); + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(sin); + sin.sin_addr.s_addr = inet_addr(argv[1]); + sin.sin_port = htons(PORT); + + if (signal(SIGALRM, alarm_handler) == SIG_ERR) + err(-1, "signal(SIGALRM)"); + + alarm(SECONDS); + + counter = 0; + while (!timer_fired) { + if (try_connect(&sin) == 0) + counter++; + } + printf("%llu count\n", counter); + printf("%llu connections/second\n", counter / SECONDS); + + return (0); +} diff --git a/tools/tools/netrate/tcpreceive/Makefile b/tools/tools/netrate/tcpreceive/Makefile new file mode 100644 index 000000000000..06d58ce8e245 --- /dev/null +++ b/tools/tools/netrate/tcpreceive/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +PROG= tcpreceive +WARNS= 3 +NO_MAN= + +.include diff --git a/tools/tools/netrate/tcpreceive/tcpreceive.c b/tools/tools/netrate/tcpreceive/tcpreceive.c new file mode 100644 index 000000000000..09e60a306de2 --- /dev/null +++ b/tools/tools/netrate/tcpreceive/tcpreceive.c @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 2005 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Back end to a variety of TCP-related benchmarks. This program accepts TCP + * connections on a port, and echoes all received data back to the sender. + * It is capable of handling only one connection at a time out of a single + * thread. + */ +#include +#include + +#include + +#include + +#include +#include +#include +#include + +/* + * Simple micro-benchmark to see how many connections/second can be created + * in a serialized fashion against a given server. A timer signal is used + * to interrupt the loop and assess the cost, and uses a fixed maximum + * buffer size. It makes no attempt to time out old connections. + */ +#define BUFFERSIZE 128*1024 +#define PORT 6060 + +static void +handle_connection(int accept_sock) +{ + u_char buffer[BUFFERSIZE]; + ssize_t len, recvlen, sofar; + int s; + + s = accept(accept_sock, NULL, NULL); + if (s < 0) { + warn("accept"); + return; + } + + while (1) { + recvlen = recv(s, buffer, BUFFERSIZE, 0); + if (recvlen < 0 || recvlen == 0) { + close(s); + return; + } + sofar = 0; + while (sofar < recvlen) { + len = send(s, buffer + sofar, recvlen - sofar, 0); + if (len < 0) { + close(s); + return; + } + sofar += len; + } + } +} + +int +main(int argc, char *argv[]) +{ + struct sockaddr_in sin; + int accept_sock; + + accept_sock = socket(PF_INET, SOCK_STREAM, 0); + if (accept_sock < 0) + err(-1, "socket(PF_INET, SOCKET_STREAM, 0)"); + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(sin); + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons(PORT); + + if (bind(accept_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) + err(-1, "bind"); + + if (listen(accept_sock, -1) < 0) + err(-1, "listen"); + + while (1) + handle_connection(accept_sock); + + return (0); +}