From a1344ede16f93a4b361b86658a09ab223f44adf8 Mon Sep 17 00:00:00 2001 From: sethdelliott Date: Mon, 26 Jul 2010 21:30:34 +0000 Subject: [PATCH] Added support for binding (-B) to a specific interface --- src/iperf.h | 1 + src/iperf_api.c | 9 +++++++-- src/iperf_client_api.c | 6 ++---- src/iperf_error.h | 3 ++- src/iperf_server_api.c | 5 ++--- src/iperf_tcp.c | 37 +++++++++++++++++++++++++++++++------ src/iperf_udp.c | 6 +++--- src/net.c | 36 ++++++++++++++++++++++++++++-------- src/net.h | 2 +- 9 files changed, 77 insertions(+), 28 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 6f486e5..355445d 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -116,6 +116,7 @@ struct iperf_test struct protocol *protocol; char state; char *server_hostname; /* -c option */ + char *bind_address; /* -B option */ int server_port; int duration; /* total duration of test (-t flag) */ diff --git a/src/iperf_api.c b/src/iperf_api.c index d088555..72fe629 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -164,6 +164,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"port", required_argument, NULL, 'p'}, {"parallel", required_argument, NULL, 'P'}, {"udp", no_argument, NULL, 'u'}, + {"bind", required_argument, NULL, 'B'}, {"tcpInfo", no_argument, NULL, 'T'}, {"bandwidth", required_argument, NULL, 'b'}, {"length", required_argument, NULL, 'l'}, @@ -192,7 +193,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) }; char ch; - while ((ch = getopt_long(argc, argv, "c:p:st:uP:b:l:w:i:n:mRNTvhVdM:f:", longopts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "c:p:st:uP:B:b:l:w:i:n:mRNTvhVdM:f:", longopts, NULL)) != -1) { switch (ch) { case 'c': if (test->role == 's') { @@ -201,7 +202,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) } else { test->role = 'c'; test->server_hostname = (char *) malloc(strlen(optarg)+1); - strncpy(test->server_hostname, optarg, strlen(optarg)); + strncpy(test->server_hostname, optarg, strlen(optarg)+1); } break; case 'p': @@ -245,6 +246,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) return (-1); } break; + case 'B': + test->bind_address = (char *) malloc(strlen(optarg)+1); + strncpy(test->bind_address, optarg, strlen(optarg)+1); + break; case 'b': if (test->role == 's') { i_errno = IECLIENTONLY; diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 293a0dd..4cb3512 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -98,7 +98,7 @@ iperf_handle_message_client(struct iperf_test *test) return (-1); } - return 0; + return (0); } @@ -107,15 +107,13 @@ iperf_handle_message_client(struct iperf_test *test) int iperf_connect(struct iperf_test *test) { -// printf("Connecting to host %s, port %d\n", test->server_hostname, test->server_port); - FD_ZERO(&test->read_set); FD_ZERO(&test->write_set); get_uuid(test->cookie); /* Create and connect the control channel */ - test->ctrl_sck = netdial(Ptcp, test->server_hostname, test->server_port); + test->ctrl_sck = netdial(Ptcp, test->bind_address, test->server_hostname, test->server_port); if (test->ctrl_sck < 0) { i_errno = IECONNECT; return (-1); diff --git a/src/iperf_error.h b/src/iperf_error.h index 61e9d3e..3418bf4 100644 --- a/src/iperf_error.h +++ b/src/iperf_error.h @@ -13,8 +13,9 @@ char *iperf_strerror(int); extern int i_errno; enum { - /* Parameter errors */ IENONE = 0, // No error + + /* Parameter errors */ IESERVCLIENT = 1, // Iperf cannot be both server and client IENOROLE = 2, // Iperf must either be a client (-c) or server (-s) IECLIENTONLY = 3, // This option is client only diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 4868bd8..dbabb43 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -52,7 +52,7 @@ iperf_server_listen(struct iperf_test *test) char ubuf[UNIT_LEN]; int x; - if((test->listener = netannounce(Ptcp, NULL, test->server_port)) < 0) { + if((test->listener = netannounce(Ptcp, test->bind_address, test->server_port)) < 0) { i_errno = IELISTEN; return (-1); } @@ -331,7 +331,6 @@ iperf_run_server(struct iperf_test *test) test->max_fd = (s > test->max_fd) ? s : test->max_fd; streams_accepted++; -// connect_msg(sp); if (test->on_new_stream) test->on_new_stream(sp); } @@ -346,7 +345,7 @@ iperf_run_server(struct iperf_test *test) if (test->no_delay || test->settings->mss) { FD_CLR(test->listener, &test->read_set); close(test->listener); - if ((s = netannounce(Ptcp, NULL, test->server_port)) < 0) { + if ((s = netannounce(Ptcp, test->bind_address, test->server_port)) < 0) { i_errno = IELISTEN; return (-1); } diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 560a763..dc101ff 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -116,6 +116,7 @@ iperf_tcp_listen(struct iperf_test *test) { int s, opt; struct sockaddr_in sa; + struct hostent *hent; s = test->listener; if (test->no_delay || test->settings->mss) { @@ -149,7 +150,15 @@ iperf_tcp_listen(struct iperf_test *test) memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; - sa.sin_addr.s_addr = htonl(INADDR_ANY); + if (test->bind_address) { + if ((hent = gethostbyname(test->bind_address)) == NULL) { + i_errno = IESTREAMLISTEN; + return (-1); + } + memcpy(&sa.sin_addr, hent->h_addr_list[0], 4); + } else { + sa.sin_addr.s_addr = htonl(INADDR_ANY); + } sa.sin_port = htons(test->server_port); if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) { @@ -178,18 +187,34 @@ int iperf_tcp_connect(struct iperf_test *test) { int s, opt; - struct sockaddr_in sa; + struct sockaddr_in sa, local; struct hostent *hent; - if ((hent = gethostbyname(test->server_hostname)) == 0) { - i_errno = IESTREAMCONNECT; - return (-1); - } if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { i_errno = IESTREAMCONNECT; return (-1); } + if (test->bind_address) { + if ((hent = gethostbyname(test->bind_address)) == NULL) { + /* XXX: Make IESTREAMBIND? */ + i_errno = IESTREAMCONNECT; + return (-1); + } + memset(&local, 0, sizeof(local)); + memcpy(&local.sin_addr, hent->h_addr_list[0], 4); + local.sin_family = AF_INET; + + if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { + i_errno = IESTREAMCONNECT; + return (-1); + } + } + + if ((hent = gethostbyname(test->server_hostname)) == 0) { + i_errno = IESTREAMCONNECT; + return (-1); + } memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; memcpy(&sa.sin_addr.s_addr, hent->h_addr, sizeof(sa.sin_addr.s_addr)); diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 54ab286..27e1604 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -170,7 +170,7 @@ iperf_udp_accept(struct iperf_test *test) return (-1); } - test->prot_listener = netannounce(Pudp, NULL, test->server_port); + test->prot_listener = netannounce(Pudp, test->bind_address, test->server_port); if (test->prot_listener < 0) { i_errno = IESTREAMLISTEN; return (-1); @@ -198,7 +198,7 @@ iperf_udp_listen(struct iperf_test *test) { int s; - if ((s = netannounce(Pudp, NULL, test->server_port)) < 0) { + if ((s = netannounce(Pudp, test->bind_address, test->server_port)) < 0) { i_errno = IESTREAMLISTEN; return (-1); } @@ -216,7 +216,7 @@ iperf_udp_connect(struct iperf_test *test) { int s, buf; - if ((s = netdial(Pudp, test->server_hostname, test->server_port)) < 0) { + if ((s = netdial(Pudp, test->bind_address, test->server_hostname, test->server_port)) < 0) { i_errno = IESTREAMCONNECT; return (-1); } diff --git a/src/net.c b/src/net.c index 14183e2..898dca6 100644 --- a/src/net.c +++ b/src/net.c @@ -18,24 +18,35 @@ */ /* make connection to server */ -// XXX: Change client to server? int -netdial(int proto, char *client, int port) +netdial(int proto, char *local, char *server, int port) { int s; struct hostent *hent; - struct sockaddr_in sa; - - /* XXX: This is not working for non-fully qualified host names use getaddrinfo() instead? */ - if ((hent = gethostbyname(client)) == 0) { - return (-1); - } + struct sockaddr_in sa, lo; s = socket(AF_INET, proto, 0); if (s < 0) { return (-1); } + if (local) { + if ((hent = gethostbyname(local)) == 0) + return (-1); + + memset(&lo, 0, sizeof(lo)); + memmove(&lo.sin_addr, hent->h_addr_list[0], 4); + lo.sin_family = AF_INET; + + if (bind(s, (struct sockaddr *) &lo, sizeof(lo)) < 0) + return (-1); + } + + /* XXX: This is not working for non-fully qualified host names use getaddrinfo() instead? */ + if ((hent = gethostbyname(server)) == 0) { + return (-1); + } + memset(&sa, 0, sizeof sa); memmove(&sa.sin_addr, hent->h_addr, 4); sa.sin_port = htons(port); @@ -55,6 +66,7 @@ netannounce(int proto, char *local, int port) { int s; struct sockaddr_in sa; + struct hostent *hent; /* XXX: implement binding to a local address rather than * */ memset((void *) &sa, 0, sizeof sa); @@ -66,6 +78,14 @@ netannounce(int proto, char *local, int port) int opt = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)); + if (local) { + if ((hent = gethostbyname(local)) == NULL) + return (-1); + memcpy(&sa.sin_addr, hent->h_addr_list[0], 4); + } else { + sa.sin_addr.s_addr = htonl(INADDR_ANY); + } + sa.sin_port = htons(port); sa.sin_family = AF_INET; diff --git a/src/net.h b/src/net.h index 2764b71..ac12700 100644 --- a/src/net.h +++ b/src/net.h @@ -1,7 +1,7 @@ #ifndef __NET_H #define __NET_H -int netdial(int, char *, int); +int netdial(int, char *, char *, int); int netannounce(int, char *, int); int Nwrite(int, void *, int, int); int Nread(int, void *, int, int);