Fabcoin Core  0.16.2
P2P Digital Currency
UPnP.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
24 #include "UPnP.h"
25 
26 #include <stdio.h>
27 #include <string.h>
28 #if ETH_MINIUPNPC
29 #include <miniupnpc/miniwget.h>
30 #include <miniupnpc/miniupnpc.h>
31 #include <miniupnpc/upnpcommands.h>
32 #endif
33 #include <libdevcore/Exceptions.h>
34 #include <libdevcore/Common.h>
35 #include <libdevcore/CommonIO.h>
36 #include <libdevcore/Log.h>
37 using namespace std;
38 using namespace dev;
39 using namespace dev::p2p;
40 
41 UPnP::UPnP()
42 {
43 #if ETH_MINIUPNPC
44  m_urls = make_shared<UPNPUrls>();
45  m_data = make_shared<IGDdatas>();
46 
47  m_ok = false;
48 
49  struct UPNPDev* devlist;
50  struct UPNPDev* dev;
51  char* descXML;
52  int descXMLsize = 0;
53  int upnperror = 0;
54  memset(m_urls.get(), 0, sizeof(struct UPNPUrls));
55  memset(m_data.get(), 0, sizeof(struct IGDdatas));
56 #if MINIUPNPC_API_VERSION >= 14
57  devlist = upnpDiscover(2000, NULL/*multicast interface*/, NULL/*minissdpd socket path*/, 0/*sameport*/, 0/*ipv6*/, 2/*ttl*/, &upnperror);
58 #else
59  devlist = upnpDiscover(2000, NULL/*multicast interface*/, NULL/*minissdpd socket path*/, 0/*sameport*/, 0/*ipv6*/, &upnperror);
60 #endif
61  if (devlist)
62  {
63  dev = devlist;
64  while (dev)
65  {
66  if (strstr (dev->st, "InternetGatewayDevice"))
67  break;
68  dev = dev->pNext;
69  }
70  if (!dev)
71  dev = devlist; /* defaulting to first device */
72 
73  cnote << "UPnP device:" << dev->descURL << "[st:" << dev->st << "]";
74 #if MINIUPNPC_API_VERSION >= 16
75  int responsecode = 200;
76  descXML = (char*)miniwget(dev->descURL, &descXMLsize, 0, &responsecode);
77 #elif MINIUPNPC_API_VERSION >= 9
78  descXML = (char*)miniwget(dev->descURL, &descXMLsize, 0);
79 #else
80  descXML = (char*)miniwget(dev->descURL, &descXMLsize);
81 #endif
82  if (descXML)
83  {
84  parserootdesc (descXML, descXMLsize, m_data.get());
85  free (descXML); descXML = 0;
86 #if MINIUPNPC_API_VERSION >= 9
87  GetUPNPUrls (m_urls.get(), m_data.get(), dev->descURL, 0);
88 #else
89  GetUPNPUrls (m_urls.get(), m_data.get(), dev->descURL);
90 #endif
91  m_ok = true;
92  }
93  freeUPNPDevlist(devlist);
94  }
95  else
96 #endif
97  {
98  cnote << "UPnP device not found.";
99  BOOST_THROW_EXCEPTION(NoUPnPDevice());
100  }
101 }
102 
103 UPnP::~UPnP()
104 {
105  auto r = m_reg;
106  for (auto i: r)
107  removeRedirect(i);
108 }
109 
110 string UPnP::externalIP()
111 {
112 #if ETH_MINIUPNPC
113  char addr[16];
114  if (!UPNP_GetExternalIPAddress(m_urls->controlURL, m_data->first.servicetype, addr))
115  return addr;
116  else
117 #endif
118  return "0.0.0.0";
119 }
120 
121 int UPnP::addRedirect(char const* _addr, int _port)
122 {
123  (void)_addr;
124  (void)_port;
125 #if ETH_MINIUPNPC
126  if (m_urls->controlURL[0] == '\0')
127  {
128  cwarn << "UPnP::addRedirect() called without proper initialisation?";
129  return -1;
130  }
131 
132  // Try direct mapping first (port external, port internal).
133  char port_str[16];
134  char ext_port_str[16];
135  sprintf(port_str, "%d", _port);
136  if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, port_str, _addr, "ethereum", "TCP", NULL, NULL))
137  return _port;
138 
139  // Failed - now try (random external, port internal) and cycle up to 10 times.
140  srand(time(NULL));
141  for (unsigned i = 0; i < 10; ++i)
142  {
143  _port = rand() % (32768 - 1024) + 1024;
144  sprintf(ext_port_str, "%d", _port);
145  if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, ext_port_str, port_str, _addr, "ethereum", "TCP", NULL, NULL))
146  return _port;
147  }
148 
149  // Failed. Try asking the router to give us a free external port.
150  if (UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, NULL, _addr, "ethereum", "TCP", NULL, NULL))
151  // Failed. Exit.
152  return 0;
153 
154  // We got mapped, but we don't know which ports we got mapped to. Now to find...
155  unsigned num = 0;
156  UPNP_GetPortMappingNumberOfEntries(m_urls->controlURL, m_data->first.servicetype, &num);
157  for (unsigned i = 0; i < num; ++i)
158  {
159  char extPort[16];
160  char intClient[16];
161  char intPort[6];
162  char protocol[4];
163  char desc[80];
164  char enabled[4];
165  char rHost[64];
166  char duration[16];
167  UPNP_GetGenericPortMappingEntry(m_urls->controlURL, m_data->first.servicetype, toString(i).c_str(), extPort, intClient, intPort, protocol, desc, enabled, rHost, duration);
168  if (string("ethereum") == desc)
169  {
170  m_reg.insert(atoi(extPort));
171  return atoi(extPort);
172  }
173  }
174  cerr << "ERROR: Mapped port not found." << endl;
175 #endif
176  return 0;
177 }
178 
179 void UPnP::removeRedirect(int _port)
180 {
181  (void)_port;
182 #if ETH_MINIUPNPC
183  char port_str[16];
184 // int t;
185  printf("TB : upnp_rem_redir (%d)\n", _port);
186  if (m_urls->controlURL[0] == '\0')
187  {
188  printf("TB : the init was not done !\n");
189  return;
190  }
191  sprintf(port_str, "%d", _port);
192  UPNP_DeletePortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, "TCP", NULL);
193  m_reg.erase(_port);
194 #endif
195 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
void printf(const char *fmt, const Args &...args)
Format list of arguments to std::cout, according to the given format string.
Definition: tinyformat.h:972
std::hash for asio::adress
Definition: Common.h:323
std::string toString(string32 const &_s)
Make normal string from fixed-length string.
Definition: CommonData.cpp:141
clock::duration duration
Definition: bench.h:50
#define cwarn
Definition: Log.h:304
#define cnote
Definition: Log.h:303
int atoi(const std::string &str)