diff --git a/common.cpp b/common.cpp index a81fce8..9411d01 100644 --- a/common.cpp +++ b/common.cpp @@ -953,7 +953,7 @@ int new_listen_socket2(int &fd,address_t &addr) int yes = 1; if (::bind(fd, (struct sockaddr*) &addr.inner, addr.get_len()) == -1) { - mylog(log_fatal,"socket bind error\n"); + mylog(log_fatal,"socket bind error=%s\n",get_sock_error()); //perror("socket bind error"); myexit(1); } @@ -964,13 +964,26 @@ int new_listen_socket2(int &fd,address_t &addr) return 0; } -int new_connected_socket2(int &fd,address_t &addr) +int new_connected_socket2(int &fd,address_t &addr,bool bind_enabled,address_t &bind_addr,char interface_string[]) { fd = socket(addr.get_type(), SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { mylog(log_warn, "[%s]create udp_fd error\n", addr.get_str()); return -1; } + + if (bind_enabled && ::bind(fd, (struct sockaddr*) &bind_addr.inner, bind_addr.get_len()) == -1) { + mylog(log_fatal,"socket bind error=%s\n", get_sock_error()); + //perror("socket bind error"); + myexit(1); + } + + if (strlen(interface_string) > 0 && ::setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface_string, strlen(interface_string)) < 0) { + mylog(log_fatal,"socket interface bind error=%s\n", get_sock_error()); + //perror("socket bind error"); + myexit(1); + } + setnonblocking(fd); set_buf_size(fd, socket_buf_size); diff --git a/common.h b/common.h index fe70434..1f04186 100644 --- a/common.h +++ b/common.h @@ -451,7 +451,7 @@ int new_listen_socket(int &fd,u32_t ip,int port); int new_connected_socket(int &fd,u32_t ip,int port); int new_listen_socket2(int &fd,address_t &addr); -int new_connected_socket2(int &fd,address_t &addr); +int new_connected_socket2(int &fd,address_t &addr,bool bind_enabled,address_t &bind_addr,char interface_string[]); struct not_copy_able_t { diff --git a/main.cpp b/main.cpp index 9212333..1285de2 100644 --- a/main.cpp +++ b/main.cpp @@ -37,6 +37,8 @@ static void print_help() printf(" --report turn on send/recv report, and set a period for reporting, unit: s\n"); printf("advanced options:\n"); + printf(" -b,--bind ip:port force all output packets to go through this address. Set port to 0 to use a random one.\n"); + printf(" --interface force all output packets to go through this interface.\n"); printf(" --mode fec-mode,available values: 0,1; mode 0(default) costs less bandwidth,no mtu problem.\n"); printf(" mode 1 usually introduces less latency, but you have to care about mtu.\n"); printf(" --mtu mtu. for mode 0, the program will split packet to segment smaller than mtu value.\n"); diff --git a/misc.cpp b/misc.cpp index 634b334..f60d8da 100644 --- a/misc.cpp +++ b/misc.cpp @@ -28,7 +28,10 @@ int output_interval_max=0*1000; int fix_latency=0; -address_t local_addr,remote_addr; +char interface_string[16]; + +bool has_b=false; +address_t local_addr,remote_addr,bind_addr; //u32_t local_ip_uint32,remote_ip_uint32=0; //char local_ip[100], remote_ip[100]; //int local_port = -1, remote_port = -1; @@ -648,12 +651,14 @@ void process_arg(int argc, char *argv[]) {"report", required_argument, 0, 1}, {"delay-capacity", required_argument, 0, 1}, {"mtu", required_argument, 0, 1}, + {"interface", required_argument, 0, 1}, {"mode", required_argument, 0,1}, {"timeout", required_argument, 0,1}, {"decode-buf", required_argument, 0,1}, {"queue-len", required_argument, 0,'q'}, {"fec", required_argument, 0,'f'}, {"jitter", required_argument, 0,'j'}, + {"bind", required_argument, 0,'b'}, {"header-overhead", required_argument, 0, 1}, //{"debug-fec", no_argument, 0, 1}, {"debug-fec-enc", no_argument, 0, 1}, @@ -717,7 +722,7 @@ void process_arg(int argc, char *argv[]) int no_l = 1, no_r = 1; - while ((opt = getopt_long(argc, argv, "l:r:hcsk:j:f:p:n:i:q:",long_options,&option_index)) != -1) + while ((opt = getopt_long(argc, argv, "l:r:hcsk:j:f:p:n:i:q:b",long_options,&option_index)) != -1) { //string opt_key; //opt_key+=opt; @@ -824,6 +829,10 @@ void process_arg(int argc, char *argv[]) no_r = 0; remote_addr.from_str(optarg); break; + case 'b': + has_b = true; + bind_addr.from_str(optarg); + break; case 'h': break; case 1: @@ -944,6 +953,16 @@ void process_arg(int argc, char *argv[]) myexit(-1); } } + else if(strcmp(long_options[option_index].name,"interface")==0) + { + sscanf(optarg,"%s\n",interface_string); + mylog(log_debug,"interface=%s\n",interface_string); + if(strlen(interface_string)==0) + { + mylog(log_fatal,"interface_string len=0??\n"); + myexit(-1); + } + } else if(strcmp(long_options[option_index].name,"timeout")==0) { sscanf(optarg,"%d",&g_fec_par.timeout); diff --git a/misc.h b/misc.h index 23928bc..1bfd495 100644 --- a/misc.h +++ b/misc.h @@ -39,7 +39,10 @@ extern int fix_latency; //extern char local_ip[100], remote_ip[100]; //extern int local_port, remote_port; -extern address_t local_addr,remote_addr; +extern char interface_string[16]; + +extern bool has_b; +extern address_t local_addr,remote_addr,bind_addr; extern conn_manager_t conn_manager; extern delay_manager_t delay_manager; diff --git a/tunnel_client.cpp b/tunnel_client.cpp index 0c46d61..93a4bde 100644 --- a/tunnel_client.cpp +++ b/tunnel_client.cpp @@ -295,7 +295,7 @@ int tunnel_client_event_loop() int & remote_fd=conn_info.remote_fd; fd64_t &remote_fd64=conn_info.remote_fd64; - assert(new_connected_socket2(remote_fd,remote_addr)==0); + assert(new_connected_socket2(remote_fd,remote_addr,has_b,bind_addr,interface_string)==0); remote_fd64=fd_manager.create(remote_fd); mylog(log_debug,"remote_fd64=%llu\n",remote_fd64); diff --git a/tunnel_server.cpp b/tunnel_server.cpp index 6689705..97e674b 100644 --- a/tunnel_server.cpp +++ b/tunnel_server.cpp @@ -232,7 +232,7 @@ static void local_listen_cb(struct ev_loop *loop, struct ev_io *watcher, int rev } int new_udp_fd; - ret=new_connected_socket2(new_udp_fd,remote_addr); + ret=new_connected_socket2(new_udp_fd,remote_addr,has_b,bind_addr,interface_string); if (ret != 0) { mylog(log_warn, "[%s]new_connected_socket failed\n",addr.get_str());