Browse Source

pr fixes. refactor of network code. moved network-start methods into static methods, as they can only be called during certain stages or do not need Host class. Mutex start/stop. Added m_ifAddresses and removed m_addresses. Rewrite determinePublic. IP address preference is now: user-supplied public > user-supplied private (if localnetwork enabled) > first public4 interface > upnp4 > first private4 interface (if localnetwork enabled) > unspecified. IPv6 addresses are currently ignored (unless manually entered by user) until link-local addresses can be properly detected.

cl-refactor
subtly 10 years ago
parent
commit
24bbbefd5d
  1. 519
      libp2p/Host.cpp
  2. 40
      libp2p/Host.h
  3. 2
      libp2p/Session.cpp

519
libp2p/Host.cpp

@ -55,16 +55,167 @@ static const set<bi::address> c_rejectAddresses = {
{bi::address_v6::from_string("::")} {bi::address_v6::from_string("::")}
}; };
std::vector<bi::address> Host::getInterfaceAddresses()
{
std::vector<bi::address> addresses;
#ifdef _WIN32
WSAData wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
BOOST_THROW_EXCEPTION(NoNetworking());
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name.";
WSACleanup();
BOOST_THROW_EXCEPTION(NoNetworking());
}
struct hostent* phe = gethostbyname(ac);
if (phe == 0)
{
clog(NetWarn) << "Bad host lookup.";
WSACleanup();
BOOST_THROW_EXCEPTION(NoNetworking());
}
for (int i = 0; phe->h_addr_list[i] != 0; ++i)
{
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
char *addrStr = inet_ntoa(addr);
bi::address address(bi::address::from_string(addrStr));
if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end())
addresses.push_back(ad.to_v4());
}
WSACleanup();
#else
ifaddrs* ifaddr;
if (getifaddrs(&ifaddr) == -1)
BOOST_THROW_EXCEPTION(NoNetworking());
for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (!ifa->ifa_addr || string(ifa->ifa_name) == "lo0")
continue;
if (ifa->ifa_addr->sa_family == AF_INET)
{
in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr));
if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end())
addresses.push_back(address);
}
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
sockaddr_in6* sockaddr = ((struct sockaddr_in6 *)ifa->ifa_addr);
in6_addr addr = sockaddr->sin6_addr;
boost::asio::ip::address_v6::bytes_type bytes;
memcpy(&bytes[0], addr.s6_addr, 16);
boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id);
if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end())
addresses.push_back(address);
}
}
if (ifaddr!=NULL) freeifaddrs(ifaddr);
#endif
return std::move(addresses);
}
int Host::listen4(bi::tcp::acceptor* _acceptor, unsigned short _listenPort)
{
int retport = -1;
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 : _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();
_acceptor->close();
}
// first attempt failed
_acceptor->close();
continue;
}
}
return retport;
}
bi::tcp::endpoint Host::traverseNAT(std::vector<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr)
{
asserts(_listenPort);
UPnP* upnp;
try
{
upnp = new UPnP;
}
// let m_upnp continue as null - we handle it properly.
catch (NoUPnPDevice) {}
bi::tcp::endpoint upnpep;
if (upnp && upnp->isValid())
{
bi::address paddr;
int p;
for (auto const& addr : _ifAddresses)
if (addr.is_v4() && isPrivateAddress(addr) && (p = upnp->addRedirect(addr.to_string().c_str(), _listenPort)))
{
paddr = addr;
break;
}
auto eip = upnp->externalIP();
bi::address eipaddr(bi::address::from_string(eip));
if (p && eip != string("0.0.0.0") && !isPrivateAddress(eipaddr))
{
clog(NetNote) << "Punched through NAT and mapped local port" << _listenPort << "onto external port" << p << ".";
clog(NetNote) << "External addr:" << eip;
o_upnpifaddr = paddr;
upnpep = bi::tcp::endpoint(eipaddr, (unsigned short)p);
}
else
clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place).";
if(upnp)
delete upnp;
}
return upnpep;
}
Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool _start): Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool _start):
Worker("p2p", 0), Worker("p2p", 0),
m_clientVersion(_clientVersion), m_clientVersion(_clientVersion),
m_netPrefs(_n), m_netPrefs(_n),
m_ifAddresses(getInterfaceAddresses()),
m_ioService(new ba::io_service), m_ioService(new ba::io_service),
m_acceptor(new bi::tcp::acceptor(*m_ioService)), m_acceptor(new bi::tcp::acceptor(*m_ioService)),
m_socket(new bi::tcp::socket(*m_ioService)), m_socket(new bi::tcp::socket(*m_ioService)),
m_key(KeyPair::create()) m_key(KeyPair::create())
{ {
populateAddresses(); for (auto address: m_ifAddresses)
if (address.is_v4())
clog(NetNote) << "IP Address: " << address << " = " << (isPrivateAddress(address) ? "[LOCAL]" : "[PEER]");
clog(NetNote) << "Id:" << id().abridged(); clog(NetNote) << "Id:" << id().abridged();
if (_start) if (_start)
start(); start();
@ -82,11 +233,16 @@ void Host::start()
void Host::stop() void Host::stop()
{ {
// flag transition to shutdown network {
// prevent m_run from being set to false at same time as set to true by start()
lock_guard<mutex> l(x_runtimer);
// once m_run is false the scheduler will shutdown network and stopWorking() // once m_run is false the scheduler will shutdown network and stopWorking()
m_run = false; m_run = false;
}
// we know shutdown is complete when m_timer is reset
while (m_timer) while (m_timer)
this_thread::sleep_for(chrono::milliseconds(100)); this_thread::sleep_for(chrono::milliseconds(50));
stopWorking(); stopWorking();
} }
@ -142,162 +298,6 @@ void Host::seal(bytes& _b)
_b[7] = len & 0xff; _b[7] = len & 0xff;
} }
void Host::determinePublic(string const& _publicAddress, bool _upnp)
{
if (_upnp)
try
{
m_upnp = new UPnP;
}
catch (NoUPnPDevice) {} // let m_upnp continue as null - we handle it properly.
if (m_upnp && m_upnp->isValid() && m_peerAddresses.size())
{
clog(NetNote) << "External addr:" << m_upnp->externalIP();
int p;
// iterate m_peerAddresses (populated by populateAddresses())
for (auto const& addr : m_peerAddresses)
if (addr.is_v4() && (p = m_upnp->addRedirect(addr.to_string().c_str(), m_listenPort)))
break;
if (p)
clog(NetNote) << "Punched through NAT and mapped local port" << m_listenPort << "onto external port" << p << ".";
else
{
// couldn't map
clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place). Assuming" << m_listenPort << "is local & external port.";
p = m_listenPort;
}
auto eip = m_upnp->externalIP();
if (eip == string("0.0.0.0") && _publicAddress.empty())
m_public = bi::tcp::endpoint(bi::address(), (unsigned short)p);
else
{
bi::address adr = bi::address::from_string(eip);
try
{
adr = bi::address::from_string(_publicAddress);
}
catch (...) {}
m_public = bi::tcp::endpoint(adr, (unsigned short)p);
m_addresses.push_back(m_public.address());
}
}
else
{
// No UPnP - fallback on given public address or, if empty, the assumed peer address.
bi::address adr;
if (m_peerAddresses.size())
{
// prefer local ipv4 over local ipv6
for (auto const& ip: m_peerAddresses)
if (ip.is_v4())
{
adr = ip;
break;
}
if (adr.is_unspecified())
adr = m_peerAddresses[0];
}
try
{
adr = bi::address::from_string(_publicAddress);
}
catch (...) {}
m_public = bi::tcp::endpoint(adr, m_listenPort);
m_addresses.push_back(adr);
}
}
void Host::populateAddresses()
{
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (!m_ioService)
return;
#ifdef _WIN32
WSAData wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
BOOST_THROW_EXCEPTION(NoNetworking());
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name.";
WSACleanup();
BOOST_THROW_EXCEPTION(NoNetworking());
}
struct hostent* phe = gethostbyname(ac);
if (phe == 0)
{
clog(NetWarn) << "Bad host lookup.";
WSACleanup();
BOOST_THROW_EXCEPTION(NoNetworking());
}
for (int i = 0; phe->h_addr_list[i] != 0; ++i)
{
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
char *addrStr = inet_ntoa(addr);
bi::address ad(bi::address::from_string(addrStr));
m_addresses.push_back(ad.to_v4());
bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end();
if (!isLocal)
m_peerAddresses.push_back(ad.to_v4());
clog(NetNote) << "Address: " << ac << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]");
}
WSACleanup();
#else
ifaddrs* ifaddr;
if (getifaddrs(&ifaddr) == -1)
BOOST_THROW_EXCEPTION(NoNetworking());
for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr || (strlen(ifa->ifa_name) > 2 && !strncmp(ifa->ifa_name, "lo0", 3))) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET)
{
in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr));
if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end())
m_peerAddresses.push_back(address);
// Log IPv4 Address:
auto addr4 = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
char addressBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, addr4, addressBuffer, INET_ADDRSTRLEN);
printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
}
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
sockaddr_in6* sockaddr = ((struct sockaddr_in6 *)ifa->ifa_addr);
in6_addr addr = sockaddr->sin6_addr;
boost::asio::ip::address_v6::bytes_type bytes;
memcpy(&bytes[0], addr.s6_addr, 16);
boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id);
if (std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), address) == c_rejectAddresses.end())
m_peerAddresses.push_back(address);
// Log IPv6 Address:
auto addr6 = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
char addressBuffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, addr6, addressBuffer, INET6_ADDRSTRLEN);
printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
}
}
if (ifaddr!=NULL) freeifaddrs(ifaddr);
#endif
}
shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId) shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId)
{ {
RecursiveGuard l(x_peers); RecursiveGuard l(x_peers);
@ -375,6 +375,69 @@ Nodes Host::potentialPeers(RangeMask<unsigned> const& _known)
return ret; return ret;
} }
void Host::determinePublic(string const& _publicAddress, bool _upnp)
{
m_peerAddresses.clear();
// no point continuing if there are no interface addresses or valid listen port
if (!m_ifAddresses.size() || m_listenPort < 1)
return;
// populate interfaces we'll listen on (eth listens on all interfaces); ignores local
for (auto addr: m_ifAddresses)
if ((m_netPrefs.localNetworking || !isPrivateAddress(addr)) && find(c_rejectAddresses.begin(), c_rejectAddresses.end(), addr) == c_rejectAddresses.end())
m_peerAddresses.insert(addr);
// if user supplied address is a public address then we use it
// if user supplied address is private, and localnetworking is enabled, we use it
bi::address reqpublicaddr(bi::address(_publicAddress.empty() ? bi::address() : bi::address::from_string(_publicAddress)));
bi::tcp::endpoint reqpublic(reqpublicaddr, m_listenPort);
bool isprivate = isPrivateAddress(reqpublicaddr);
bool ispublic = isprivate ? false : find(c_rejectAddresses.begin(), c_rejectAddresses.end(), reqpublicaddr) == c_rejectAddresses.end();
if (!reqpublicaddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking)))
{
if (!m_peerAddresses.count(reqpublicaddr))
m_peerAddresses.insert(reqpublicaddr);
m_public = reqpublic;
return;
}
// if address wasn't provided, then use first public ipv4 address found
for (auto addr: m_peerAddresses)
if (addr.is_v4() && !isPrivateAddress(addr))
{
m_public = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort);
return;
}
// or find address via upnp
if (_upnp)
{
bi::address upnpifaddr;
bi::tcp::endpoint upnpep = traverseNAT(m_ifAddresses, m_listenPort, upnpifaddr);
if (!upnpep.address().is_unspecified() && !upnpifaddr.is_unspecified())
{
if (!m_peerAddresses.count(upnpep.address()))
m_peerAddresses.insert(upnpep.address());
m_public = upnpep;
return;
}
}
// or if no address provided, use private ipv4 address if local networking is enabled
if (reqpublicaddr.is_unspecified())
if (m_netPrefs.localNetworking)
for (auto addr: m_peerAddresses)
if (addr.is_v4() && isPrivateAddress(addr))
{
m_public = bi::tcp::endpoint(addr, m_listenPort);
return;
}
// otherwise address is unspecified
m_public = bi::tcp::endpoint(bi::address(), m_listenPort);
}
void Host::ensureAccepting() void Host::ensureAccepting()
{ {
// return if there's no io-server (quit called) or we're not listening // return if there's no io-server (quit called) or we're not listening
@ -636,79 +699,49 @@ void Host::run(boost::system::error_code const& error)
static unsigned s_lasttick = 0; static unsigned s_lasttick = 0;
s_lasttick += c_timerInterval; s_lasttick += c_timerInterval;
if (error) if (error || !m_ioService)
// tood: error handling.
{ {
// timer died or io service went away, so stop here
m_timer.reset(); m_timer.reset();
return; return;
} }
// no timer means this is first run and network must be started // network running
if (!m_timer) if (m_run)
// run once when host worker thread calls startedWorking()
{ {
// reset io service and create deadline timer if (s_lasttick == c_timerInterval * 50)
m_ioService->reset();
m_timer.reset(new boost::asio::deadline_timer(*m_ioService));
m_run = true;
// try to open acceptor (ipv4; todo: update for ipv6)
for (unsigned i = 0; i < 2; ++i)
{ {
// try to connect w/listenPort, else attempt net-allocated port growPeers();
bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : m_netPrefs.listenPort); prunePeers();
try s_lasttick = 0;
{
m_acceptor->open(endpoint.protocol());
m_acceptor->set_option(ba::socket_base::reuse_address(true));
m_acceptor->bind(endpoint);
m_acceptor->listen();
m_listenPort = i ? m_acceptor->local_endpoint().port() : m_netPrefs.listenPort;
break;
} }
catch (...)
{ if (m_hadNewNodes)
if (i)
{ {
// both attempts failed for (auto p: m_peers)
cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information(); if (auto pp = p.second.lock())
m_listenPort = -1; pp->serviceNodesRequest();
}
// first attempt failed m_hadNewNodes = false;
m_acceptor->close();
continue;
}
} }
// start capability threads if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s.
for (auto const& h: m_capabilities)
h.second->onStarting();
// determine public IP, but only if we're able to listen for connections
// todo: visualize when listen is unavailable in UI
if (m_listenPort)
{ {
determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); for (auto p: m_peers)
ensureAccepting(); if (auto pp = p.second.lock())
if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60))
pp->disconnect(PingTimeout);
pingAll();
} }
// if m_public address is valid then add us to node list auto runcb = [this](boost::system::error_code const& error) -> void{ run(error); };
// todo: abstract empty() and emplace logic m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval));
if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) m_timer->async_wait(runcb);
noteNode(id(), m_public, Origin::Perfect, false);
clog(NetNote) << "Id:" << id().abridged();
}
// io service went away, so stop here
if (!m_ioService)
{
m_timer.reset();
return; return;
} }
// network stopped; disconnect peers // network stopping
if (!m_run) if (!m_run)
{ {
// close acceptor // close acceptor
@ -745,50 +778,60 @@ void Host::run(boost::system::error_code const& error)
if (m_socket->is_open()) if (m_socket->is_open())
m_socket->close(); m_socket->close();
if (m_upnp != nullptr)
delete m_upnp;
// m_run is false, so we're stopping; kill timer // m_run is false, so we're stopping; kill timer
s_lasttick = 0; s_lasttick = 0;
// causes parent thread's stop() to continue which calls stopWorking()
m_timer.reset(); m_timer.reset();
// stop ioservice (stops blocking worker thread, allowing thread to join)
if (!!m_ioService) if (!!m_ioService)
m_ioService->stop(); m_ioService->stop();
return; return;
} }
}
void Host::startedWorking()
{
if (asserts(!m_timer))
{
// no timer means this is first run and network must be started
// (run once when host worker thread calls startedWorking())
if (s_lasttick == c_timerInterval * 10)
{ {
growPeers(); // prevent m_run from being set to true at same time as set to false by stop()
prunePeers(); // don't release mutex until m_timer is set so in case stop() is called at same
s_lasttick = 0; // time, stop will wait on m_timer and graceful network shutdown.
lock_guard<mutex> l(x_runtimer);
// reset io service and create deadline timer
m_timer.reset(new boost::asio::deadline_timer(*m_ioService));
m_run = true;
} }
m_ioService->reset();
if (m_hadNewNodes) // try to open acceptor (todo: ipv6)
{ m_listenPort = listen4(m_acceptor.get(), m_netPrefs.listenPort);
for (auto p: m_peers)
if (auto pp = p.second.lock())
pp->serviceNodesRequest();
m_hadNewNodes = false; // start capability threads
} for (auto const& h: m_capabilities)
h.second->onStarting();
if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s. // determine public IP, but only if we're able to listen for connections
// todo: GUI when listen is unavailable in UI
if (m_listenPort)
{ {
for (auto p: m_peers) determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp);
if (auto pp = p.second.lock()) ensureAccepting();
if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60))
pp->disconnect(PingTimeout);
pingAll();
} }
auto runcb = [this](boost::system::error_code const& error) -> void{ run(error); }; // if m_public address is valid then add us to node list
m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval)); // todo: abstract empty() and emplace logic
m_timer->async_wait(runcb); if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id()))
noteNode(id(), m_public, Origin::Perfect, false);
clog(NetNote) << "Id:" << id().abridged();
} }
void Host::startedWorking()
{
run(boost::system::error_code()); run(boost::system::error_code());
} }

40
libp2p/Host.h

@ -121,6 +121,17 @@ class Host: public Worker
friend class HostCapabilityFace; friend class HostCapabilityFace;
friend struct Node; friend struct Node;
/// Static network interface methods
public:
/// @returns public and private interface addresses
static std::vector<bi::address> getInterfaceAddresses();
/// Try to bind and listen on _listenPort, else attempt net-allocated port.
static int listen4(bi::tcp::acceptor* _acceptor, unsigned short _listenPort);
/// Return public endpoint of upnp interface. If successful o_upnpifaddr will be a private interface address and endpoint will contain public address and port.
static bi::tcp::endpoint traverseNAT(std::vector<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr);
public: public:
/// Start server, listening for connections on the given port. /// Start server, listening for connections on the given port.
Host(std::string const& _clientVersion, NetworkPreferences const& _n = NetworkPreferences(), bool _start = false); Host(std::string const& _clientVersion, NetworkPreferences const& _n = NetworkPreferences(), bool _start = false);
@ -144,7 +155,7 @@ public:
void connect(bi::tcp::endpoint const& _ep); void connect(bi::tcp::endpoint const& _ep);
void connect(std::shared_ptr<Node> const& _n); void connect(std::shared_ptr<Node> const& _n);
/// @returns true if we have the a peer of the given id. /// @returns true iff we have a peer of the given id.
bool havePeer(NodeId _id) const; bool havePeer(NodeId _id) const;
/// Set ideal number of peers. /// Set ideal number of peers.
@ -172,14 +183,14 @@ public:
void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); } void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); }
/// Start network. /// Start network. @threadsafe
void start(); void start();
/// Stop network. /// Stop network. @threadsafe
void stop(); void stop();
/// @returns if network is running /// @returns if network is running.
bool isStarted() const { return isWorking(); } bool isStarted() const { return m_run; }
/// Reset acceptor, socket, and IO service. Called by deallocator. Maybe called by implementation when ordered deallocation is required. /// Reset acceptor, socket, and IO service. Called by deallocator. Maybe called by implementation when ordered deallocation is required.
void quit(); void quit();
@ -191,14 +202,13 @@ public:
std::shared_ptr<Node> node(NodeId _id) const { if (m_nodes.count(_id)) return m_nodes.at(_id); return std::shared_ptr<Node>(); } std::shared_ptr<Node> node(NodeId _id) const { if (m_nodes.count(_id)) return m_nodes.at(_id); return std::shared_ptr<Node>(); }
private: private:
void seal(bytes& _b); /// Populate m_peerAddresses with available public addresses.
void populateAddresses();
/// Try UPNP or listen to assumed address. Requires valid m_listenPort.
void determinePublic(std::string const& _publicAddress, bool _upnp); void determinePublic(std::string const& _publicAddress, bool _upnp);
void ensureAccepting(); void ensureAccepting();
void seal(bytes& _b);
void growPeers(); void growPeers();
void prunePeers(); void prunePeers();
@ -206,7 +216,6 @@ private:
virtual void startedWorking(); virtual void startedWorking();
/// Called by startedWorking. Not thread-safe; to be called only be worker callback. /// Called by startedWorking. Not thread-safe; to be called only be worker callback.
void run(boost::system::error_code const& error); ///< Run network. Called serially via ASIO deadline timer. Manages connection state transitions. void run(boost::system::error_code const& error); ///< Run network. Called serially via ASIO deadline timer. Manages connection state transitions.
bool m_run = false;
/// Run network /// Run network
virtual void doWork(); virtual void doWork();
@ -214,10 +223,16 @@ private:
std::shared_ptr<Node> noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = NodeId()); std::shared_ptr<Node> noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = NodeId());
Nodes potentialPeers(RangeMask<unsigned> const& _known); Nodes potentialPeers(RangeMask<unsigned> const& _known);
bool m_run = false; ///< Whether network is running.
std::mutex x_runtimer; ///< Start/stop mutex.
std::string m_clientVersion; ///< Our version string. std::string m_clientVersion; ///< Our version string.
NetworkPreferences m_netPrefs; ///< Network settings. NetworkPreferences m_netPrefs; ///< Network settings.
/// Interface addresses (private, public)
std::vector<bi::address> m_ifAddresses; ///< Interface addresses.
int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized. int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized.
std::unique_ptr<ba::io_service> m_ioService; ///< IOService for network stuff. std::unique_ptr<ba::io_service> m_ioService; ///< IOService for network stuff.
@ -227,7 +242,6 @@ private:
std::unique_ptr<boost::asio::deadline_timer> m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms. std::unique_ptr<boost::asio::deadline_timer> m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms.
static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected. static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected.
UPnP* m_upnp = nullptr; ///< UPnP helper.
bi::tcp::endpoint m_public; ///< Our public listening endpoint. bi::tcp::endpoint m_public; ///< Our public listening endpoint.
KeyPair m_key; ///< Our unique ID. KeyPair m_key; ///< Our unique ID.
@ -251,9 +265,7 @@ private:
unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to. unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to.
// Our addresses. std::set<bi::address> m_peerAddresses; ///< Public addresses that peers (can) know us by.
std::vector<bi::address> m_addresses; ///< Addresses for us.
std::vector<bi::address> m_peerAddresses; ///< Addresses that peers (can) know us by.
// Our capabilities. // Our capabilities.
std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities; ///< Each of the capabilities we support. std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities; ///< Each of the capabilities we support.

2
libp2p/Session.cpp

@ -344,7 +344,7 @@ bool Session::interpret(RLP const& _r)
// goto CONTINUE; // Wierd port. // goto CONTINUE; // Wierd port.
// Avoid our random other addresses that they might end up giving us. // Avoid our random other addresses that they might end up giving us.
for (auto i: m_server->m_addresses) for (auto i: m_server->m_peerAddresses)
if (ep.address() == i && ep.port() == m_server->listenPort()) if (ep.address() == i && ep.port() == m_server->listenPort())
goto CONTINUE; goto CONTINUE;

Loading…
Cancel
Save