Skip to content

Commit

Permalink
Merge pull request #1427 from esnet/add_common_sockopts
Browse files Browse the repository at this point in the history
Fixes issue #638. Allow setting of TOS/DHCP for reverse tests. Thanks to @disprosium8 for the initial patch.
  • Loading branch information
swlars authored Nov 23, 2022
2 parents e33fddc + a48c610 commit a2ce47a
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 18 deletions.
1 change: 1 addition & 0 deletions src/iperf.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ struct iperf_test
FILE *outfile;

int ctrl_sck;
int mapped_v4;
int listener;
int prot_listener;

Expand Down
71 changes: 53 additions & 18 deletions src/iperf_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,12 @@ iperf_get_test_mss(struct iperf_test *ipt)
return ipt->settings->mss;
}

int
iperf_get_mapped_v4(struct iperf_test* ipt)
{
return ipt->mapped_v4;
}

/************** Setter routines for some fields inside iperf_test *************/

void
Expand Down Expand Up @@ -575,6 +581,12 @@ iperf_set_test_timestamp_format(struct iperf_test *ipt, const char *tf)
ipt->timestamp_format = strdup(tf);
}

void
iperf_set_mapped_v4(struct iperf_test *ipt, const int val)
{
ipt->mapped_v4 = val;
}

static void
check_sender_has_retransmits(struct iperf_test *ipt)
{
Expand Down Expand Up @@ -856,8 +868,10 @@ iperf_on_test_start(struct iperf_test *test)
** old IPv4 format, which is easier on the eyes of network veterans.
**
** If the v6 address is not v4-mapped it is left alone.
**
** Returns 1 if the v6 address is v4-mapped, 0 otherwise.
*/
static void
static int
mapped_v4_to_regular_v4(char *str)
{
char *prefix = "::ffff:";
Expand All @@ -867,7 +881,9 @@ mapped_v4_to_regular_v4(char *str)
if (strncmp(str, prefix, prefix_len) == 0) {
int str_len = strlen(str);
memmove(str, str + prefix_len, str_len - prefix_len + 1);
return 1;
}
return 0;
}

void
Expand Down Expand Up @@ -910,7 +926,9 @@ iperf_on_connect(struct iperf_test *test)
inet_ntop(AF_INET6, &sa_in6P->sin6_addr, ipr, sizeof(ipr));
port = ntohs(sa_in6P->sin6_port);
}
mapped_v4_to_regular_v4(ipr);
if (mapped_v4_to_regular_v4(ipr)) {
iperf_set_mapped_v4(test, 1);
}
if (test->json_output)
cJSON_AddItemToObject(test->json_start, "accepted_connection", iperf_json_printf("host: %s port: %d", ipr, (int64_t) port));
else
Expand Down Expand Up @@ -4293,41 +4311,57 @@ iperf_new_stream(struct iperf_test *test, int s, int sender)

/**************************************************************************/
int
iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
iperf_common_sockopts(struct iperf_test *test, int s)
{
socklen_t len;
int opt;

len = sizeof(struct sockaddr_storage);
if (getsockname(sp->socket, (struct sockaddr *) &sp->local_addr, &len) < 0) {
i_errno = IEINITSTREAM;
return -1;
}
len = sizeof(struct sockaddr_storage);
if (getpeername(sp->socket, (struct sockaddr *) &sp->remote_addr, &len) < 0) {
i_errno = IEINITSTREAM;
return -1;
}

/* Set IP TOS */
if ((opt = test->settings->tos)) {
if (getsockdomain(sp->socket) == AF_INET6) {
if (getsockdomain(s) == AF_INET6) {
#ifdef IPV6_TCLASS
if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) {
if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) {
i_errno = IESETCOS;
return -1;
}

/* if the control connection was established with a mapped v4 address
then set IP_TOS on v6 stream socket as well */
if (iperf_get_mapped_v4(test)) {
if (setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {
/* ignore any failure of v4 TOS in IPv6 case */
}
}
#else
i_errno = IESETCOS;
return -1;
#endif
} else {
if (setsockopt(sp->socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {
if (setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {
i_errno = IESETTOS;
return -1;
}
}
}
return 0;
}

/**************************************************************************/
int
iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
{
int opt;
socklen_t len;

len = sizeof(struct sockaddr_storage);
if (getsockname(sp->socket, (struct sockaddr *) &sp->local_addr, &len) < 0) {
i_errno = IEINITSTREAM;
return -1;
}
len = sizeof(struct sockaddr_storage);
if (getpeername(sp->socket, (struct sockaddr *) &sp->remote_addr, &len) < 0) {
i_errno = IEINITSTREAM;
return -1;
}

#if defined(HAVE_DONT_FRAGMENT)
/* Set Don't Fragment (DF). Only applicable to IPv4/UDP tests. */
Expand Down Expand Up @@ -4368,6 +4402,7 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
#endif /* IP_MTU_DISCOVER */
}
#endif /* HAVE_DONT_FRAGMENT */

return 0;
}

Expand Down
8 changes: 8 additions & 0 deletions src/iperf_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ int iperf_get_test_connect_timeout( struct iperf_test* ipt );
int iperf_get_dont_fragment( struct iperf_test* ipt );
char* iperf_get_test_congestion_control(struct iperf_test* ipt);
int iperf_get_test_mss(struct iperf_test* ipt);
int iperf_get_mapped_v4(struct iperf_test* ipt);

/* Setter routines for some fields inside iperf_test. */
void iperf_set_verbose( struct iperf_test* ipt, int verbose );
Expand Down Expand Up @@ -197,6 +198,7 @@ void iperf_set_test_no_delay( struct iperf_test* ipt, int no_delay);
void iperf_set_dont_fragment( struct iperf_test* ipt, int dont_fragment );
void iperf_set_test_congestion_control(struct iperf_test* ipt, char* cc);
void iperf_set_test_mss(struct iperf_test* ipt, int mss);
void iperf_set_mapped_v4(struct iperf_test* ipt, const int val);

#if defined(HAVE_SSL)
void iperf_set_test_client_username(struct iperf_test *ipt, const char *client_username);
Expand Down Expand Up @@ -283,6 +285,12 @@ int iperf_init_stream(struct iperf_stream *, struct iperf_test *);
*/
void iperf_free_stream(struct iperf_stream * sp);

/**
* iperf_common_sockopts -- init stream socket with common socket options
*
*/
int iperf_common_sockopts(struct iperf_test *, int s);

int has_tcpinfo(void);
int has_tcpinfo_retransmits(void);
void save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp);
Expand Down
7 changes: 7 additions & 0 deletions src/iperf_server_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,13 @@ iperf_run_server(struct iperf_test *test)
return -1;
}

/* apply other common socket options */
if (iperf_common_sockopts(test, s) < 0)
{
cleanup_server(test);
return -1;
}

if (!is_closed(s)) {

#if defined(HAVE_TCP_USER_TIMEOUT)
Expand Down
3 changes: 3 additions & 0 deletions src/iperf_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,9 @@ iperf_tcp_connect(struct iperf_test *test)
}
}

/* Set common socket options */
iperf_common_sockopts(test, s);

if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
saved_errno = errno;
close(s);
Expand Down
3 changes: 3 additions & 0 deletions src/iperf_udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,9 @@ iperf_udp_connect(struct iperf_test *test)
}
}

/* Set common socket options */
iperf_common_sockopts(test, s);

#ifdef SO_RCVTIMEO
/* 30 sec timeout for a case when there is a network problem. */
tv.tv_sec = 30;
Expand Down

0 comments on commit a2ce47a

Please sign in to comment.