From cc5496e34a14a49931cee715082a7261a6596fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 22 Nov 2006 16:57:22 +0000 Subject: [PATCH] Extended the TCP tester app a bit: * you can now instruct it to drop specific packets * you can now also define a round trip time for the packets * added a "send" command to send arbitrarily sized buffers over TCP. Not surprising, the current implementation of TCP doesn't do anything with those (other than crashing as soon as you try to send data). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19362 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/tests/kits/net/tcp_tester.cpp | 229 +++++++++++++++++++++++++++++- 1 file changed, 226 insertions(+), 3 deletions(-) diff --git a/src/tests/kits/net/tcp_tester.cpp b/src/tests/kits/net/tcp_tester.cpp index 2f6d764e1d..c6ec457126 100644 --- a/src/tests/kits/net/tcp_tester.cpp +++ b/src/tests/kits/net/tcp_tester.cpp @@ -1,3 +1,12 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + #include "argv.h" #include "tcp.h" #include "utility.h" @@ -13,8 +22,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -46,7 +57,12 @@ extern struct net_socket_module_info gNetSocketModule; struct net_protocol_module_info *gTCPModule; struct net_socket *gServerSocket, *gClientSocket; -bool gTCPDump = true; +static set sDropList; +static bigtime_t sRoundTripTime = 0; +static bool sIncreasingRoundTrip = false; +static bool sRandomRoundTrip = false; +static bool sTCPDump = true; +static bigtime_t sStartTime; static struct net_domain sDomain = { "ipv4", @@ -290,6 +306,63 @@ socket_listen(net_socket *socket, int backlog) } +ssize_t +socket_send(net_socket *socket, const void *data, size_t length, int flags) +{ + if (socket->peer.ss_len == 0) + return EDESTADDRREQ; + + if (socket->address.ss_len == 0) { + // try to bind first + status_t status = socket_bind(socket, NULL, 0); + if (status < B_OK) + return status; + } + + // TODO: useful, maybe even computed header space! + net_buffer *buffer = gNetBufferModule.create(256); + if (buffer == NULL) + return ENOBUFS; + + // copy data into buffer + if (gNetBufferModule.append(buffer, data, length) < B_OK) { + gNetBufferModule.free(buffer); + return ENOBUFS; + } + + buffer->flags = flags; + //buffer->source = (sockaddr *)&socket->address; + //buffer->destination = (sockaddr *)&socket->peer; + memcpy(&buffer->source, &socket->address, socket->address.ss_len); + memcpy(&buffer->destination, &socket->peer, socket->peer.ss_len); + + status_t status = socket->first_info->send_data(socket->first_protocol, buffer); + if (status < B_OK) { + gNetBufferModule.free(buffer); + return status; + } + + return length; +} + + +ssize_t +socket_recv(net_socket *socket, void *data, size_t length, int flags) +{ + net_buffer *buffer; + status_t status = socket->first_info->read_data( + socket->first_protocol, length, flags, &buffer); + if (status < B_OK) + return status; + + ssize_t bytesReceived = buffer->size; + gNetBufferModule.read(buffer, 0, data, bytesReceived); + gNetBufferModule.free(buffer); + + return bytesReceived; +} + + status_t socket_spawn_pending(net_socket *parent, net_socket **_socket) { @@ -644,15 +717,36 @@ status_t domain_receive_data(net_buffer *buffer) { static uint32 packetNumber = 1; + static bigtime_t lastTime = 0; - if (gTCPDump) { + bool drop = false; + if (sDropList.find(packetNumber) != sDropList.end()) + drop = true; + + if (!drop && (sRoundTripTime > 0 || sRandomRoundTrip || sIncreasingRoundTrip)) { + bigtime_t add = 0; + if (sRandomRoundTrip) + add = (bigtime_t)(1.0 * rand() / RAND_MAX * 500000); + if (sIncreasingRoundTrip) + sRoundTripTime += (bigtime_t)(1.0 * rand() / RAND_MAX * 150000); + + snooze(sRoundTripTime / 2 + add); + } + + if (sTCPDump) { NetBufferHeader bufferHeader(buffer); if (bufferHeader.Status() < B_OK) return bufferHeader.Status(); tcp_header &header = bufferHeader.Data(); - printf("% 3ld ", packetNumber++); + bigtime_t now = system_time(); + if (lastTime == 0) + lastTime = now; + + printf("% 3ld %8.6f (%8.6f) ", packetNumber, (now - sStartTime) / 1000000.0, + (now - lastTime) / 1000000.0); + lastTime = now; if (is_server((sockaddr *)&buffer->source)) printf("\33[31mserver > client: "); @@ -727,9 +821,19 @@ domain_receive_data(net_buffer *buffer) } } + if (drop) + printf(" "); printf("\33[0m\n"); bufferHeader.Detach(); + } else if (drop) + printf("<**** DROPPED %ld ****>\n", packetNumber); + + packetNumber++; + + if (drop) { + gNetBufferModule.free(buffer); + return B_OK; } return gTCPModule->receive_data(buffer); @@ -817,6 +921,8 @@ do_connect(int argc, char** argv) if (argc > 1) port = atoi(argv[1]); + sStartTime = system_time(); + sockaddr_in address; memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; @@ -830,6 +936,120 @@ do_connect(int argc, char** argv) } +static void +do_send(int argc, char** argv) +{ + size_t size = 1024; + if (argc > 1 && isdigit(argv[1][0])) { + char *unit; + size = strtoul(argv[1], &unit, 0); + if (unit != NULL && unit[0]) { + if (unit[0] == 'k' || unit[0] == 'K') + size *= 1024; + else if (unit[0] == 'm' || unit[0] == 'M') + size *= 1024 * 1024; + else { + fprintf(stderr, "unknown unit specified!\n"); + return; + } + } + } else if (argc > 1) { + fprintf(stderr, "invalid args!\n"); + return; + } + + if (size > 4 * 1024 * 1024) { + printf("amount to send will be limited to 4 MB\n"); + size = 4 * 1024 * 1024; + } + + char *buffer = (char *)malloc(size); + if (buffer == NULL) { + fprintf(stderr, "not enough memory!\n"); + return; + } + + // initialize buffer with some not so random data + for (uint32 i = 0; i < size; i++) { + buffer[i] = (char)(i & 0xff); + } + + ssize_t bytesWritten = socket_send(gClientSocket, buffer, size, 0); + if (bytesWritten < B_OK) { + fprintf(stderr, "failed sending buffer: %s\n", strerror(bytesWritten)); + return; + } +} + + +static void +do_drop(int argc, char** argv) +{ + if (argc == 1) { + // show list of dropped packets + printf("Drop pakets:\n"); + + set::iterator iterator = sDropList.begin(); + uint32 count = 0; + for (; iterator != sDropList.end(); iterator++) { + printf("%4lu\n", *iterator); + count++; + } + + if (count == 0) + printf("\n"); + } else if (!strcmp(argv[1], "-f")) { + // flush drop list + sDropList.clear(); + puts("drop list cleared."); + } else if (isdigit(argv[1][0])) { + // add to drop list + for (int i = 1; i < argc; i++) { + uint32 packet = strtoul(argv[i], NULL, 0); + if (packet == 0) { + fprintf(stderr, "invalid packet number: %s\n", argv[i]); + break; + } + + sDropList.insert(packet); + } + } else { + // print usage + puts("usage: drop [...]\n" + " or: drop [-f]\n\n" + "Specifiying -f flushes the drop list; if you called drop without\n" + "any arguments, the current drop list is dumped."); + } +} + + +static void +do_round_trip_time(int argc, char** argv) +{ + if (argc == 1) { + // show current time + printf("Current round trip time: %g ms\n", sRoundTripTime / 1000.0); + } else if (!strcmp(argv[1], "-r")) { + // toggle random time + sRandomRoundTrip = !sRandomRoundTrip; + printf("Round trip time is now %s.\n", sRandomRoundTrip ? "random" : "fixed"); + } else if (!strcmp(argv[1], "-i")) { + // toggle increasing time + sIncreasingRoundTrip = !sIncreasingRoundTrip; + printf("Round trip time is now %s.\n", sIncreasingRoundTrip ? "increasing" : "fixed"); + } else if (isdigit(argv[1][0])) { + // set time + sRoundTripTime = 1000LL * strtoul(argv[1], NULL, 0); + } else { + // print usage + puts("usage: rtt