Browse Source

Fledgling UPnP support.

cl-refactor
Gav Wood 11 years ago
parent
commit
98bf9e7be6
  1. 2
      alephzero/alephzero.pro
  2. 1
      eth/CMakeLists.txt
  3. 1
      libethereum/CMakeLists.txt
  4. 190
      libethereum/PeerNetwork.cpp
  5. 8
      libethereum/PeerNetwork.h
  6. 1
      test/CMakeLists.txt

2
alephzero/alephzero.pro

@ -14,7 +14,7 @@ CONFIG(debug, debug|release): DEFINES += ETH_DEBUG
QMAKE_CXXFLAGS += -std=c++11 QMAKE_CXXFLAGS += -std=c++11
QMAKE_LIBDIR += ../../cpp-ethereum-build/libethereum ../../secp256k1 ../../cryptopp562 QMAKE_LIBDIR += ../../cpp-ethereum-build/libethereum ../../secp256k1 ../../cryptopp562
LIBS += -Wl,-rpath,../../cpp-ethereum-build/libethereum -Wl,-rpath,../../secp256k1 -Wl,-rpath,../../cryptopp562 -lethereum -lsecp256k1 -lleveldb -lcryptopp -lgmp -lboost_filesystem -lboost_system LIBS += -Wl,-rpath,../../cpp-ethereum-build/libethereum -Wl,-rpath,../../secp256k1 -Wl,-rpath,../../cryptopp562 -lethereum -lminiupnpc -lsecp256k1 -lleveldb -lcryptopp -lgmp -lboost_filesystem -lboost_system
INCLUDEPATH = ../../secp256k1/include ../../cryptopp562 ../../cpp-ethereum INCLUDEPATH = ../../secp256k1/include ../../cryptopp562 ../../cpp-ethereum
SOURCES += main.cpp \ SOURCES += main.cpp \

1
eth/CMakeLists.txt

@ -16,6 +16,7 @@ add_executable(eth ${SRC_LIST})
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(eth ethereum) target_link_libraries(eth ethereum)
target_link_libraries(eth miniupnpc)
target_link_libraries(eth leveldb) target_link_libraries(eth leveldb)
target_link_libraries(eth secp256k1) target_link_libraries(eth secp256k1)
target_link_libraries(eth cryptopp) target_link_libraries(eth cryptopp)

1
libethereum/CMakeLists.txt

@ -12,6 +12,7 @@ add_library(ethereum ${SRC_LIST})
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(ethereum secp256k1) target_link_libraries(ethereum secp256k1)
target_link_libraries(ethereum miniupnpc)
target_link_libraries(ethereum leveldb) target_link_libraries(ethereum leveldb)
target_link_libraries(ethereum cryptopp) target_link_libraries(ethereum cryptopp)
target_link_libraries(ethereum gmp) target_link_libraries(ethereum gmp)

190
libethereum/PeerNetwork.cpp

@ -23,6 +23,7 @@
#include <ifaddrs.h> #include <ifaddrs.h>
#include <chrono> #include <chrono>
#include <miniupnpc/miniupnpc.h>
#include "Common.h" #include "Common.h"
#include "BlockChain.h" #include "BlockChain.h"
#include "BlockInfo.h" #include "BlockInfo.h"
@ -450,7 +451,7 @@ void PeerSession::start()
{ {
RLPStream s; RLPStream s;
prep(s); prep(s);
s.appendList(5) << (uint)Hello << (uint)0 << (uint)0 << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0) << m_server->m_acceptor.local_endpoint().port(); s.appendList(5) << (uint)Hello << (uint)0 << (uint)0 << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0) << m_server->m_public.port();
sealAndSend(s); sealAndSend(s);
ping(); ping();
@ -508,16 +509,169 @@ void PeerSession::doRead()
}); });
} }
#include <stdio.h>
#include <string.h>
#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
namespace eth {
struct UPnP
{
UPnP()
{
ok = false;
struct UPNPDev * devlist;
struct UPNPDev * dev;
char * descXML;
int descXMLsize = 0;
int upnperror = 0;
printf("TB : init_upnp()\n");
memset(&urls, 0, sizeof(struct UPNPUrls));
memset(&data, 0, sizeof(struct IGDdatas));
devlist = upnpDiscover(2000, NULL/*multicast interface*/, NULL/*minissdpd socket path*/, 0/*sameport*/, 0/*ipv6*/, &upnperror);
if (devlist)
{
dev = devlist;
while (dev)
{
if (strstr (dev->st, "InternetGatewayDevice"))
break;
dev = dev->pNext;
}
if (!dev)
dev = devlist; /* defaulting to first device */
printf("UPnP device :\n"
" desc: %s\n st: %s\n",
dev->descURL, dev->st);
descXML = (char*)miniwget(dev->descURL, &descXMLsize);
if (descXML)
{
parserootdesc (descXML, descXMLsize, &data);
free (descXML); descXML = 0;
GetUPNPUrls (&urls, &data, dev->descURL);
ok = true;
}
freeUPNPDevlist(devlist);
}
else
{
/* error ! */
}
}
~UPnP()
{
auto r = m_reg;
for (auto i: r)
removeRedirect(i);
}
string externalIP()
{
char addr[16];
UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, addr);
return addr;
}
int addRedirect(char const* addr, int port)
{
char port_str[16];
int r;
printf("TB : upnp_add_redir (%d)\n", port);
if (urls.controlURL[0] == '\0')
{
printf("TB : the init was not done !\n");
return -1;
}
sprintf(port_str, "%d", port);
r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port_str, port_str, addr, "ethereum", "TCP", NULL, NULL);
if (r)
{
printf("AddPortMapping(%s, %s, %s) failed with %d. Trying non-specific external port...\n", port_str, port_str, addr, r);
r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port_str, NULL, addr, "ethereum", "TCP", NULL, NULL);
}
if (r)
{
printf("AddPortMapping(%s, NULL, %s) failed with %d. Trying non-specific internal port...\n", port_str, addr, r);
r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, NULL, port_str, addr, "ethereum", "TCP", NULL, NULL);
}
if (r)
{
printf("AddPortMapping(NULL, %s, %s) failed with %d. Trying non-specific both ports...\n", port_str, addr, r);
r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, NULL, NULL, addr, "ethereum", "TCP", NULL, NULL);
}
if (r)
printf("AddPortMapping(NULL, NULL, %s) failed with %d\n", addr, r);
else
{
unsigned num = 0;
UPNP_GetPortMappingNumberOfEntries(urls.controlURL, data.first.servicetype, &num);
for (unsigned i = 0; i < num; ++i)
{
char extPort[16];
char intClient[16];
char intPort[6];
char protocol[4];
char desc[80];
char enabled[4];
char rHost[64];
char duration[16];
UPNP_GetGenericPortMappingEntry(urls.controlURL, data.first.servicetype, toString(i).c_str(), extPort, intClient, intPort, protocol, desc, enabled, rHost, duration);
if (string("ethereum") == desc)
{
m_reg.insert(atoi(extPort));
return atoi(extPort);
}
}
cerr << "ERROR: Mapped port not found." << endl;
}
return -1;
}
void removeRedirect(int port)
{
char port_str[16];
// int t;
printf("TB : upnp_rem_redir (%d)\n", port);
if (urls.controlURL[0] == '\0')
{
printf("TB : the init was not done !\n");
return;
}
sprintf(port_str, "%d", port);
UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port_str, "TCP", NULL);
m_reg.erase(port);
}
bool isValid() const
{
return ok;
}
set<int> m_reg;
bool ok;
struct UPNPUrls urls;
struct IGDdatas data;
};
}
class NoNetworking: public std::exception {}; class NoNetworking: public std::exception {};
PeerServer::PeerServer(std::string const& _clientVersion, BlockChain const& _ch, uint _networkId, short _port): PeerServer::PeerServer(std::string const& _clientVersion, BlockChain const& _ch, uint _networkId, short _port):
m_clientVersion(_clientVersion), m_clientVersion(_clientVersion),
m_listenPort(_port),
m_chain(&_ch), m_chain(&_ch),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), _port)), m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), _port)),
m_socket(m_ioService), m_socket(m_ioService),
m_requiredNetworkId(_networkId) m_requiredNetworkId(_networkId)
{ {
populateAddresses(); populateAddresses();
determinePublic();
ensureAccepting(); ensureAccepting();
if (m_verbosity) if (m_verbosity)
cout << "Genesis: " << m_chain->genesisHash() << endl; cout << "Genesis: " << m_chain->genesisHash() << endl;
@ -525,6 +679,7 @@ PeerServer::PeerServer(std::string const& _clientVersion, BlockChain const& _ch,
PeerServer::PeerServer(std::string const& _clientVersion, uint _networkId): PeerServer::PeerServer(std::string const& _clientVersion, uint _networkId):
m_clientVersion(_clientVersion), m_clientVersion(_clientVersion),
m_listenPort(-1),
m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)), m_acceptor(m_ioService, bi::tcp::endpoint(bi::tcp::v4(), 0)),
m_socket(m_ioService), m_socket(m_ioService),
m_requiredNetworkId(_networkId) m_requiredNetworkId(_networkId)
@ -540,6 +695,37 @@ PeerServer::~PeerServer()
for (auto const& i: m_peers) for (auto const& i: m_peers)
if (auto p = i.lock()) if (auto p = i.lock())
p->disconnect(); p->disconnect();
delete m_upnp;
}
void PeerServer::determinePublic()
{
m_upnp = new UPnP;
if (m_upnp->isValid() && m_peerAddresses.size())
{
bi::tcp::resolver r(m_ioService);
cout << "external addr: " << m_upnp->externalIP() << endl;
int p = m_upnp->addRedirect(m_peerAddresses[0].to_string().c_str(), m_listenPort);
if (p == -1)
{
// couldn't map
cerr << "*** WARNING: Couldn't punch through NAT (or no NAT in place). Using " << m_listenPort << endl;
p = m_listenPort;
}
auto it = r.resolve({m_upnp->externalIP(), toString(p)});
m_public = it->endpoint();
m_addresses.push_back(m_public.address().to_v4());
}
/* int er;
UPNPDev* dlist = upnpDiscover(250, 0, 0, 0, 0, &er);
for (UPNPDev* d = dlist; d; d = dlist->pNext)
{
IGDdatas data;
parserootdesc(d->descURL, 0, &data);
data.presentationurl()
}
freeUPNPDevlist(dlist);*/
} }
void PeerServer::populateAddresses() void PeerServer::populateAddresses()
@ -588,7 +774,7 @@ void PeerServer::ensureAccepting()
if (m_accepting == false) if (m_accepting == false)
{ {
if (m_verbosity >= 1) if (m_verbosity >= 1)
cout << "Listening on port " << m_acceptor.local_endpoint().port() << endl; cout << "Listening on local port " << m_listenPort << " (public: " << m_public << ")" << endl;
m_accepting = true; m_accepting = true;
m_acceptor.async_accept(m_socket, [&](boost::system::error_code ec) m_acceptor.async_accept(m_socket, [&](boost::system::error_code ec)
{ {

8
libethereum/PeerNetwork.h

@ -117,6 +117,8 @@ enum class NodeMode
PeerServer PeerServer
}; };
class UPnP;
class PeerServer class PeerServer
{ {
friend class PeerSession; friend class PeerSession;
@ -159,6 +161,7 @@ public:
private: private:
void seal(bytes& _b); void seal(bytes& _b);
void populateAddresses(); void populateAddresses();
void determinePublic();
void ensureAccepting(); void ensureAccepting();
std::vector<bi::tcp::endpoint> potentialPeers(); std::vector<bi::tcp::endpoint> potentialPeers();
@ -176,11 +179,16 @@ private:
*/ */
unsigned m_verbosity = 4; unsigned m_verbosity = 4;
short m_listenPort;
BlockChain const* m_chain = nullptr; BlockChain const* m_chain = nullptr;
ba::io_service m_ioService; ba::io_service m_ioService;
bi::tcp::acceptor m_acceptor; bi::tcp::acceptor m_acceptor;
bi::tcp::socket m_socket; bi::tcp::socket m_socket;
UPnP* m_upnp = nullptr;
bi::tcp::endpoint m_public;
uint m_requiredNetworkId; uint m_requiredNetworkId;
std::vector<std::weak_ptr<PeerSession>> m_peers; std::vector<std::weak_ptr<PeerSession>> m_peers;

1
test/CMakeLists.txt

@ -16,6 +16,7 @@ add_executable(testeth ${SRC_LIST})
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(testeth ethereum) target_link_libraries(testeth ethereum)
target_link_libraries(testeth miniupnpc)
target_link_libraries(testeth cryptopp) target_link_libraries(testeth cryptopp)
target_link_libraries(testeth secp256k1) target_link_libraries(testeth secp256k1)
target_link_libraries(testeth gmp) target_link_libraries(testeth gmp)

Loading…
Cancel
Save