tcp_shell: Add send_loop command.

Useful for sending more data than fits in one buffer.
With "send_loop 100m", the traffic stalls are readily
reproduced.
This commit is contained in:
Augustin Cavalier
2023-12-30 16:30:14 -05:00
parent dbb0ad7129
commit dc8bc8c1ce
@@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved. * Copyright 2006-2023, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -12,6 +12,7 @@
#include "pcap.h" #include "pcap.h"
#include "utility.h" #include "utility.h"
#include <AutoDeleter.h>
#include <NetBufferUtilities.h> #include <NetBufferUtilities.h>
#include <net_buffer.h> #include <net_buffer.h>
#include <net_datalink.h> #include <net_datalink.h>
@@ -1439,13 +1440,11 @@ do_connect(int argc, char** argv)
} }
static void static ssize_t
do_send(int argc, char** argv) parse_size(const char* arg)
{ {
size_t size = 1024;
if (argc > 1 && isdigit(argv[1][0])) {
char *unit; char *unit;
size = strtoul(argv[1], &unit, 0); ssize_t size = strtoul(arg, &unit, 0);
if (unit != NULL && unit[0]) { if (unit != NULL && unit[0]) {
if (unit[0] == 'k' || unit[0] == 'K') if (unit[0] == 'k' || unit[0] == 'K')
size *= 1024; size *= 1024;
@@ -1453,9 +1452,21 @@ do_send(int argc, char** argv)
size *= 1024 * 1024; size *= 1024 * 1024;
else { else {
fprintf(stderr, "unknown unit specified!\n"); fprintf(stderr, "unknown unit specified!\n");
return -1;
}
}
return size;
}
static void
do_send(int argc, char** argv)
{
ssize_t size = 1024;
if (argc > 1 && isdigit(argv[1][0])) {
size = parse_size(argv[1]);
if (size < 0)
return; return;
}
}
} else if (argc > 1) { } else if (argc > 1) {
fprintf(stderr, "invalid args!\n"); fprintf(stderr, "invalid args!\n");
return; return;
@@ -1471,6 +1482,7 @@ do_send(int argc, char** argv)
fprintf(stderr, "not enough memory!\n"); fprintf(stderr, "not enough memory!\n");
return; return;
} }
MemoryDeleter bufferDeleter(buffer);
// initialize buffer with some not so random data // initialize buffer with some not so random data
for (uint32 i = 0; i < size; i++) { for (uint32 i = 0; i < size; i++) {
@@ -1485,6 +1497,43 @@ do_send(int argc, char** argv)
} }
static void
do_send_loop(int argc, char** argv)
{
if (argc != 2 || !isdigit(argv[1][0])) {
fprintf(stderr, "invalid args!\n");
return;
}
ssize_t size = parse_size(argv[1]);
if (size < 0)
return;
const size_t bufferSize = 4096;
char *buffer = (char *)malloc(bufferSize);
if (buffer == NULL) {
fprintf(stderr, "not enough memory!\n");
return;
}
MemoryDeleter bufferDeleter(buffer);
// initialize buffer with some not so random data
for (uint32 i = 0; i < bufferSize; i++) {
buffer[i] = (char)(i & 0xff);
}
for (ssize_t total = 0; total < size; ) {
ssize_t bytesWritten = socket_send(gClientSocket, buffer, bufferSize, 0);
if (bytesWritten < B_OK) {
fprintf(stderr, "failed sending buffer (after %" B_PRIdSSIZE "): %s\n",
total, strerror(bytesWritten));
return;
}
total += bufferSize;
}
}
static void static void
do_close(int argc, char** argv) do_close(int argc, char** argv)
{ {
@@ -1667,6 +1716,7 @@ do_dprintf(int argc, char** argv)
static cmd_entry sBuiltinCommands[] = { static cmd_entry sBuiltinCommands[] = {
{"connect", do_connect, "Connects the client"}, {"connect", do_connect, "Connects the client"},
{"send", do_send, "Sends data from the client to the server"}, {"send", do_send, "Sends data from the client to the server"},
{"send_loop", do_send_loop, "Sends data in a loop"},
{"close", do_close, "Performs an active or simultaneous close"}, {"close", do_close, "Performs an active or simultaneous close"},
{"dprintf", do_dprintf, "Toggles debug output"}, {"dprintf", do_dprintf, "Toggles debug output"},
{"drop", do_drop, "Lets you drop packets during transfer"}, {"drop", do_drop, "Lets you drop packets during transfer"},