Added support for binding (-B) to a specific interface

This commit is contained in:
sethdelliott 2010-07-26 21:30:34 +00:00
parent bb0677cdfb
commit a1344ede16
9 changed files with 77 additions and 28 deletions

View File

@ -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) */

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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));

View File

@ -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);
}

View File

@ -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;

View File

@ -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);