int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs) { // Due to the complexities of NAT and network environments (multiple NICs, tunnels, etc) // and security concerns automation is the enemy of network configuration. // If a preference cannot be accommodate the network must fail to start. // // Preferred IP: Attempt if set, else, try 0.0.0.0 (all interfaces) // Preferred Port: Attempt if set, else, try c_defaultListenPort or 0 (random) // TODO: throw instead of returning -1 and rename NetworkPreferences to NetworkConfig bi::address listenIP; try { listenIP = _netPrefs.listenIPAddress.empty() ? bi::address_v4() : bi::address::from_string(_netPrefs.listenIPAddress); } catch (...) { LOG(WARNING) << "Couldn't start accepting connections on host. Failed to accept socket on " << listenIP << ":" << _netPrefs.listenPort << ".\n" << boost::current_exception_diagnostic_information(); return -1; } bool requirePort = (bool)_netPrefs.listenPort; for (unsigned i = 0; i < 2; ++i) { bi::tcp::endpoint endpoint(listenIP, requirePort ? _netPrefs.listenPort : (i ? 0 : c_defaultListenPort)); try { #if defined(_WIN32) bool reuse = false; #else bool reuse = true; #endif _acceptor.open(endpoint.protocol()); _acceptor.set_option(ba::socket_base::reuse_address(reuse)); _acceptor.bind(endpoint); _acceptor.listen(); return _acceptor.local_endpoint().port(); } catch (...) { // bail if this is first attempt && port was specificed, or second attempt failed (random port) if (i || requirePort) { // both attempts failed LOG(WARNING) << "Couldn't start accepting connections on host. Failed to accept socket on " << listenIP << ":" << _netPrefs.listenPort << ".\n" << boost::current_exception_diagnostic_information(); _acceptor.close(); return -1; } _acceptor.close(); continue; } } return -1; }
int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs) { int retport = -1; if (_netPrefs.listenIPAddress.empty()) for (unsigned i = 0; i < 2; ++i) { // try to connect w/listenPort, else attempt net-allocated port bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : _netPrefs.listenPort); try { _acceptor.open(endpoint.protocol()); _acceptor.set_option(ba::socket_base::reuse_address(true)); _acceptor.bind(endpoint); _acceptor.listen(); retport = _acceptor.local_endpoint().port(); break; } catch (...) { if (i) { // both attempts failed cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information(); } // first attempt failed _acceptor.close(); continue; } } else { bi::tcp::endpoint endpoint(bi::address::from_string(_netPrefs.listenIPAddress), _netPrefs.listenPort); try { _acceptor.open(endpoint.protocol()); _acceptor.set_option(ba::socket_base::reuse_address(true)); _acceptor.bind(endpoint); _acceptor.listen(); retport = _acceptor.local_endpoint().port(); assert(retport == _netPrefs.listenPort); } catch (...) { clog(NetWarn) << "Couldn't start accepting connections on host. Failed to accept socket.\n" << boost::current_exception_diagnostic_information(); } return retport; } return retport; }