diff --git a/network.cpp b/network.cpp index c49b3ff..d7b23e6 100644 --- a/network.cpp +++ b/network.cpp @@ -84,7 +84,7 @@ void Connection::setup( void ) } } -Connection::Connection() /* server */ +Connection::Connection( const char *desired_ip ) /* server */ : sock( -1 ), remote_addr(), server( true ), @@ -103,11 +103,26 @@ Connection::Connection() /* server */ { setup(); - /* Bind to free local port. + /* Attempt to bind free local port, with + address client used to connect to us. + This usage does not seem to be endorsed by POSIX. */ + struct sockaddr_in local_addr; local_addr.sin_family = AF_INET; local_addr.sin_port = htons( 0 ); + if ( desired_ip + && inet_aton( desired_ip, &local_addr.sin_addr ) + && (bind( sock, (sockaddr *)&local_addr, sizeof( local_addr ) ) == 0) ) { + return; + } + + if ( desired_ip ) { + fprintf( stderr, "Could not bind to desired local address %s.\n", desired_ip ); + } + + /* Could not bind to that IP (maybe we are behind NAT). + Try again with any IP. */ local_addr.sin_addr.s_addr = INADDR_ANY; if ( bind( sock, (sockaddr *)&local_addr, sizeof( local_addr ) ) < 0 ) { throw NetworkException( "bind", errno ); diff --git a/network.hpp b/network.hpp index 0bac534..4a8204e 100644 --- a/network.hpp +++ b/network.hpp @@ -85,8 +85,8 @@ namespace Network { void update_MTU( void ); public: - Connection(); - Connection( const char *key_str, const char *ip, int port ); + Connection( const char *desired_ip ); /* server */ + Connection( const char *key_str, const char *ip, int port ); /* client */ void send( string s ); string recv( void ); diff --git a/networktransport.cpp b/networktransport.cpp index 5d8ead1..1702f05 100644 --- a/networktransport.cpp +++ b/networktransport.cpp @@ -9,8 +9,9 @@ using namespace Network; using namespace std; template -Transport::Transport( MyState &initial_state, RemoteState &initial_remote ) - : connection(), +Transport::Transport( MyState &initial_state, RemoteState &initial_remote, + const char *desired_ip ) + : connection( desired_ip ), sender( &connection, initial_state ), received_states( 1, TimestampedState( timestamp(), 0, initial_remote ) ), last_receiver_state( initial_remote ), diff --git a/networktransport.hpp b/networktransport.hpp index 1412b5e..927152e 100644 --- a/networktransport.hpp +++ b/networktransport.hpp @@ -34,7 +34,7 @@ namespace Network { bool verbose; public: - Transport( MyState &initial_state, RemoteState &initial_remote ); + Transport( MyState &initial_state, RemoteState &initial_remote, const char *desired_ip ); Transport( MyState &initial_state, RemoteState &initial_remote, const char *key_str, const char *ip, int port ); diff --git a/ntester.cpp b/ntester.cpp index caf6ade..63f7f3f 100644 --- a/ntester.cpp +++ b/ntester.cpp @@ -29,7 +29,7 @@ int main( int argc, char *argv[] ) n = new Transport( me, remote, key, ip, port ); } else { - n = new Transport( me, remote ); + n = new Transport( me, remote, NULL ); } } catch ( CryptoException e ) { fprintf( stderr, "Fatal error: %s\n", e.text.c_str() ); diff --git a/stm-server.cpp b/stm-server.cpp index b68f3d3..8e7f668 100644 --- a/stm-server.cpp +++ b/stm-server.cpp @@ -20,12 +20,22 @@ #include "networktransport.cpp" -void serve( int host_fd ); +void serve( int host_fd, const char *desired_ip ); using namespace std; -int main( void ) +int main( int argc, char *argv[] ) { + char *desired_ip = NULL; + if ( argc == 1 ) { + desired_ip = NULL; + } else if ( argc == 2 ) { + desired_ip = argv[ 1 ]; + } else { + fprintf( stderr, "Usage: %s [LOCALADDR]\n", argv[ 0 ] ); + exit( 1 ); + } + int master; struct termios child_termios; @@ -98,7 +108,7 @@ int main( void ) exit( 0 ); } else { /* parent */ - serve( master ); + serve( master, desired_ip ); if ( close( master ) < 0 ) { perror( "close" ); exit( 1 ); @@ -110,7 +120,7 @@ int main( void ) return 0; } -void serve( int host_fd ) +void serve( int host_fd, const char *desired_ip ) { /* establish fd for shutdown signals */ sigset_t signal_mask; @@ -151,7 +161,7 @@ void serve( int host_fd ) /* open network */ Network::UserStream blank; - Network::Transport< Terminal::Complete, Network::UserStream > network( terminal, blank ); + Network::Transport< Terminal::Complete, Network::UserStream > network( terminal, blank, desired_ip ); network.set_verbose();