I2PService.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. #include "Destination.h"
  2. #include "Identity.h"
  3. #include "ClientContext.h"
  4. #include "I2PService.h"
  5. #include <boost/asio/error.hpp>
  6. namespace i2p
  7. {
  8. namespace client
  9. {
  10. static const i2p::data::SigningKeyType I2P_SERVICE_DEFAULT_KEY_TYPE = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519;
  11. I2PService::I2PService (std::shared_ptr<ClientDestination> localDestination):
  12. m_LocalDestination (localDestination ? localDestination :
  13. i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)),
  14. m_ReadyTimer(m_LocalDestination->GetService()),
  15. m_ReadyTimerTriggered(false),
  16. m_ConnectTimeout(0),
  17. isUpdated (true)
  18. {
  19. m_LocalDestination->Acquire ();
  20. }
  21. I2PService::I2PService (i2p::data::SigningKeyType kt):
  22. m_LocalDestination (i2p::client::context.CreateNewLocalDestination (false, kt)),
  23. m_ReadyTimer(m_LocalDestination->GetService()),
  24. m_ConnectTimeout(0),
  25. isUpdated (true)
  26. {
  27. m_LocalDestination->Acquire ();
  28. }
  29. I2PService::~I2PService ()
  30. {
  31. ClearHandlers ();
  32. if (m_LocalDestination) m_LocalDestination->Release ();
  33. }
  34. void I2PService::ClearHandlers ()
  35. {
  36. if(m_ConnectTimeout)
  37. m_ReadyTimer.cancel();
  38. std::unique_lock<std::mutex> l(m_HandlersMutex);
  39. for (auto it: m_Handlers)
  40. it->Terminate ();
  41. m_Handlers.clear();
  42. }
  43. void I2PService::SetConnectTimeout(uint32_t timeout)
  44. {
  45. m_ConnectTimeout = timeout;
  46. }
  47. void I2PService::AddReadyCallback(ReadyCallback cb)
  48. {
  49. uint32_t now = i2p::util::GetSecondsSinceEpoch();
  50. uint32_t tm = (m_ConnectTimeout) ? now + m_ConnectTimeout : NEVER_TIMES_OUT;
  51. LogPrint(eLogDebug, "I2PService::AddReadyCallback() ", tm, " ", now);
  52. m_ReadyCallbacks.push_back({cb, tm});
  53. if (!m_ReadyTimerTriggered) TriggerReadyCheckTimer();
  54. }
  55. void I2PService::TriggerReadyCheckTimer()
  56. {
  57. m_ReadyTimer.expires_from_now(boost::posix_time::seconds (1));
  58. m_ReadyTimer.async_wait(std::bind(&I2PService::HandleReadyCheckTimer, shared_from_this (), std::placeholders::_1));
  59. m_ReadyTimerTriggered = true;
  60. }
  61. void I2PService::HandleReadyCheckTimer(const boost::system::error_code &ec)
  62. {
  63. if(ec || m_LocalDestination->IsReady())
  64. {
  65. for(auto & itr : m_ReadyCallbacks)
  66. itr.first(ec);
  67. m_ReadyCallbacks.clear();
  68. }
  69. else if(!m_LocalDestination->IsReady())
  70. {
  71. // expire timed out requests
  72. uint32_t now = i2p::util::GetSecondsSinceEpoch ();
  73. auto itr = m_ReadyCallbacks.begin();
  74. while(itr != m_ReadyCallbacks.end())
  75. {
  76. if(itr->second != NEVER_TIMES_OUT && now >= itr->second)
  77. {
  78. itr->first(boost::asio::error::timed_out);
  79. itr = m_ReadyCallbacks.erase(itr);
  80. }
  81. else
  82. ++itr;
  83. }
  84. }
  85. if(!ec && m_ReadyCallbacks.size())
  86. TriggerReadyCheckTimer();
  87. else
  88. m_ReadyTimerTriggered = false;
  89. }
  90. void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
  91. assert(streamRequestComplete);
  92. auto address = i2p::client::context.GetAddressBook ().GetAddress (dest);
  93. if (address)
  94. CreateStream(streamRequestComplete, address, port);
  95. else
  96. {
  97. LogPrint (eLogWarning, "I2PService: Remote destination not found: ", dest);
  98. streamRequestComplete (nullptr);
  99. }
  100. }
  101. void I2PService::CreateStream(StreamRequestComplete streamRequestComplete, std::shared_ptr<const Address> address, int port)
  102. {
  103. if(m_ConnectTimeout && !m_LocalDestination->IsReady())
  104. {
  105. AddReadyCallback([this, streamRequestComplete, address, port] (const boost::system::error_code & ec) {
  106. if(ec)
  107. {
  108. LogPrint(eLogWarning, "I2PService::CeateStream() ", ec.message());
  109. streamRequestComplete(nullptr);
  110. }
  111. else
  112. { if (address->IsIdentHash ())
  113. this->m_LocalDestination->CreateStream(streamRequestComplete, address->identHash, port);
  114. else
  115. this->m_LocalDestination->CreateStream (streamRequestComplete, address->blindedPublicKey, port);
  116. }
  117. });
  118. }
  119. else
  120. {
  121. if (address->IsIdentHash ())
  122. m_LocalDestination->CreateStream (streamRequestComplete, address->identHash, port);
  123. else
  124. m_LocalDestination->CreateStream (streamRequestComplete, address->blindedPublicKey, port);
  125. }
  126. }
  127. TCPIPPipe::TCPIPPipe(I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream)
  128. {
  129. boost::asio::socket_base::receive_buffer_size option(TCP_IP_PIPE_BUFFER_SIZE);
  130. upstream->set_option(option);
  131. downstream->set_option(option);
  132. }
  133. TCPIPPipe::~TCPIPPipe()
  134. {
  135. Terminate();
  136. }
  137. void TCPIPPipe::Start()
  138. {
  139. AsyncReceiveUpstream();
  140. AsyncReceiveDownstream();
  141. }
  142. void TCPIPPipe::Terminate()
  143. {
  144. if(Kill()) return;
  145. if (m_up)
  146. {
  147. if (m_up->is_open())
  148. m_up->close();
  149. m_up = nullptr;
  150. }
  151. if (m_down)
  152. {
  153. if (m_down->is_open())
  154. m_down->close();
  155. m_down = nullptr;
  156. }
  157. Done(shared_from_this());
  158. }
  159. void TCPIPPipe::AsyncReceiveUpstream()
  160. {
  161. if (m_up)
  162. {
  163. m_up->async_read_some(boost::asio::buffer(m_upstream_to_down_buf, TCP_IP_PIPE_BUFFER_SIZE),
  164. std::bind(&TCPIPPipe::HandleUpstreamReceived, shared_from_this(),
  165. std::placeholders::_1, std::placeholders::_2));
  166. }
  167. else
  168. LogPrint(eLogError, "TCPIPPipe: upstream receive: no socket");
  169. }
  170. void TCPIPPipe::AsyncReceiveDownstream()
  171. {
  172. if (m_down) {
  173. m_down->async_read_some(boost::asio::buffer(m_downstream_to_up_buf, TCP_IP_PIPE_BUFFER_SIZE),
  174. std::bind(&TCPIPPipe::HandleDownstreamReceived, shared_from_this(),
  175. std::placeholders::_1, std::placeholders::_2));
  176. }
  177. else
  178. LogPrint(eLogError, "TCPIPPipe: downstream receive: no socket");
  179. }
  180. void TCPIPPipe::UpstreamWrite(size_t len)
  181. {
  182. if (m_up)
  183. {
  184. LogPrint(eLogDebug, "TCPIPPipe: upstream: ", (int) len, " bytes written");
  185. boost::asio::async_write(*m_up, boost::asio::buffer(m_upstream_buf, len),
  186. boost::asio::transfer_all(),
  187. std::bind(&TCPIPPipe::HandleUpstreamWrite,
  188. shared_from_this(),
  189. std::placeholders::_1));
  190. }
  191. else
  192. LogPrint(eLogError, "TCPIPPipe: upstream write: no socket");
  193. }
  194. void TCPIPPipe::DownstreamWrite(size_t len)
  195. {
  196. if (m_down)
  197. {
  198. LogPrint(eLogDebug, "TCPIPPipe: downstream: ", (int) len, " bytes written");
  199. boost::asio::async_write(*m_down, boost::asio::buffer(m_downstream_buf, len),
  200. boost::asio::transfer_all(),
  201. std::bind(&TCPIPPipe::HandleDownstreamWrite,
  202. shared_from_this(),
  203. std::placeholders::_1));
  204. }
  205. else
  206. LogPrint(eLogError, "TCPIPPipe: downstream write: no socket");
  207. }
  208. void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
  209. {
  210. LogPrint(eLogDebug, "TCPIPPipe: downstream: ", (int) bytes_transfered, " bytes received");
  211. if (ecode)
  212. {
  213. LogPrint(eLogError, "TCPIPPipe: downstream read error:" , ecode.message());
  214. if (ecode != boost::asio::error::operation_aborted)
  215. Terminate();
  216. } else {
  217. if (bytes_transfered > 0 )
  218. memcpy(m_upstream_buf, m_downstream_to_up_buf, bytes_transfered);
  219. UpstreamWrite(bytes_transfered);
  220. }
  221. }
  222. void TCPIPPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) {
  223. if (ecode)
  224. {
  225. LogPrint(eLogError, "TCPIPPipe: downstream write error:" , ecode.message());
  226. if (ecode != boost::asio::error::operation_aborted)
  227. Terminate();
  228. }
  229. else
  230. AsyncReceiveUpstream();
  231. }
  232. void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) {
  233. if (ecode)
  234. {
  235. LogPrint(eLogError, "TCPIPPipe: upstream write error:" , ecode.message());
  236. if (ecode != boost::asio::error::operation_aborted)
  237. Terminate();
  238. }
  239. else
  240. AsyncReceiveDownstream();
  241. }
  242. void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
  243. {
  244. LogPrint(eLogDebug, "TCPIPPipe: upstream ", (int)bytes_transfered, " bytes received");
  245. if (ecode)
  246. {
  247. LogPrint(eLogError, "TCPIPPipe: upstream read error:" , ecode.message());
  248. if (ecode != boost::asio::error::operation_aborted)
  249. Terminate();
  250. } else {
  251. if (bytes_transfered > 0 )
  252. memcpy(m_downstream_buf, m_upstream_to_down_buf, bytes_transfered);
  253. DownstreamWrite(bytes_transfered);
  254. }
  255. }
  256. void TCPIPAcceptor::Start ()
  257. {
  258. m_Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), m_LocalEndpoint));
  259. //update the local end point in case port has been set zero and got updated now
  260. m_LocalEndpoint = m_Acceptor->local_endpoint();
  261. m_Acceptor->listen ();
  262. Accept ();
  263. }
  264. void TCPIPAcceptor::Stop ()
  265. {
  266. if (m_Acceptor)
  267. {
  268. m_Acceptor->close();
  269. m_Acceptor.reset (nullptr);
  270. }
  271. m_Timer.cancel ();
  272. ClearHandlers();
  273. }
  274. void TCPIPAcceptor::Accept ()
  275. {
  276. auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
  277. m_Acceptor->async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this,
  278. std::placeholders::_1, newSocket));
  279. }
  280. void TCPIPAcceptor::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
  281. {
  282. if (!ecode)
  283. {
  284. LogPrint(eLogDebug, "I2PService: ", GetName(), " accepted");
  285. auto handler = CreateHandler(socket);
  286. if (handler)
  287. {
  288. AddHandler(handler);
  289. handler->Handle();
  290. }
  291. else
  292. socket->close();
  293. Accept();
  294. }
  295. else
  296. {
  297. if (ecode != boost::asio::error::operation_aborted)
  298. LogPrint (eLogError, "I2PService: ", GetName(), " closing socket on accept because: ", ecode.message ());
  299. }
  300. }
  301. }
  302. }