UPnP.cpp 5.2 KB

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