Limit the maximum packets per second the server will send to a client.
Change-Id: I3cef24d70ae887301b1e8febd787c7bd7ec3bce1
diff --git a/cmds/isoping.cc b/cmds/isoping.cc
index d7b9d1c..18d73f4 100644
--- a/cmds/isoping.cc
+++ b/cmds/isoping.cc
@@ -307,6 +307,7 @@
"\n"
" -f <lines/sec> max output lines per second\n"
" -r <pps> packets per second (default=%g)\n"
+ " in server mode: the highest accepted rate.\n"
" -t <ttl> packet ttl to use (default=2 for safety)\n"
" -q quiet mode (don't print packets)\n"
" -T print timestamps\n",
@@ -314,6 +315,10 @@
exit(99);
}
+void set_packets_per_sec(double new_pps) {
+ DLOG("Setting packets_per_sec to %f\n", new_pps);
+ packets_per_sec = new_pps;
+}
bool CompareSockaddr::operator()(const struct sockaddr_storage &lhs,
const struct sockaddr_storage &rhs) {
@@ -425,8 +430,8 @@
memset(tx, 0, sizeof(*tx));
tx->magic = htonl(MAGIC);
tx->id = rx->id;
- // TODO(pmccurdy): Establish limits on the allowed usec_per_pkt values here
- tx->usec_per_pkt = rx->usec_per_pkt;
+ tx->usec_per_pkt = htonl(
+ std::max(ntohl(rx->usec_per_pkt), (uint32_t)(1e6 / packets_per_sec)));
tx->txtime = now;
tx->clockdiff = htonl(now - ntohl(rx->txtime));
tx->num_lost = htonl(0);
@@ -646,6 +651,7 @@
}
fprintf(stderr, "New client connection: %s\n",
sockaddr_to_str((struct sockaddr *)remoteaddr));
+ // Use the usec_per_pkt value provided by the server.
SessionMap::iterator it = s->NewSession(
now + 10 * 1000, ntohl(rx->usec_per_pkt), remoteaddr, remoteaddr_len);
Session &session = it->second;
@@ -909,7 +915,7 @@
}
break;
case 'r':
- packets_per_sec = atof(optarg);
+ set_packets_per_sec(atof(optarg));
if (packets_per_sec < 0.001 || packets_per_sec > 1e6) {
fprintf(stderr, "%s: packets per sec (-r) must be 0.001..1000000\n",
argv[0]);
diff --git a/cmds/isoping.h b/cmds/isoping.h
index 9c2ee85..33a4438 100644
--- a/cmds/isoping.h
+++ b/cmds/isoping.h
@@ -227,6 +227,9 @@
// currently readable.
int read_incoming_packet(Sessions *s, int sock, uint32_t now, int is_server);
+// Sets the global packets_per_sec value. Used for test purposes only.
+void set_packets_per_sec(double new_pps);
+
// Parses arguments and runs the main loop. Distinct from main() for unit test
// purposes.
int isoping_main(int argc, char **argv);
diff --git a/cmds/isoping_test.cc b/cmds/isoping_test.cc
index ca0c440..9ab5cd9 100644
--- a/cmds/isoping_test.cc
+++ b/cmds/isoping_test.cc
@@ -616,8 +616,10 @@
WVPASSEQ(read_incoming_packet(&s, ssock, sbase + t, is_server), EINVAL);
// Make a new client, who sends more frequently, getting a new source port.
+ // Also establish an upper limit, to verify that the server enforces it.
Sessions c2;
- c2.NewSession(cbase, usec_per_pkt/4, &listenaddr, listenaddr_len);
+ set_packets_per_sec(4e6/usec_per_pkt);
+ c2.NewSession(cbase, usec_per_pkt/10, &listenaddr, listenaddr_len);
int c2sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (!WVPASS(c2sock > 0)) {
perror("client socket 2");
@@ -648,6 +650,8 @@
t += sc_latency;
WVPASS(!read_incoming_packet(&c2, c2sock, cbase+t, is_client));
+ WVPASSEQ(c2Session.usec_per_pkt, usec_per_pkt/4);
+
// Now we can send a validated packet to the server.
t = c2Session.next_send - cbase;
WVPASS(!send_waiting_packets(&c2, c2sock, cbase + t, is_client));