/ libi2pd_client / I2CP.cpp
I2CP.cpp
1 /* 2 * Copyright (c) 2013-2026, The PurpleI2P Project 3 * 4 * This file is part of Purple i2pd project and licensed under BSD3 5 * 6 * See full license text in LICENSE file at top of project tree 7 */ 8 9 #include <string.h> 10 #include <stdlib.h> 11 #include <openssl/rand.h> 12 #include "I2PEndian.h" 13 #include "Log.h" 14 #include "Timestamp.h" 15 #include "LeaseSet.h" 16 #include "ClientContext.h" 17 #include "Transports.h" 18 #include "Signature.h" 19 #include "Config.h" 20 #include "I2CP.h" 21 22 namespace i2p 23 { 24 namespace client 25 { 26 27 I2CPDestination::I2CPDestination (boost::asio::io_context& service, std::shared_ptr<I2CPSession> owner, 28 std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, bool isSameThread, 29 const i2p::util::Mapping& params): 30 LeaseSetDestination (service, isPublic, ¶ms), 31 m_Owner (owner), m_Identity (identity), m_IsCreatingLeaseSet (false), m_IsSameThread (isSameThread), 32 m_LeaseSetCreationTimer (service), m_ReadinessCheckTimer (service) 33 { 34 } 35 36 void I2CPDestination::Stop () 37 { 38 m_LeaseSetCreationTimer.cancel (); 39 m_ReadinessCheckTimer.cancel (); 40 LeaseSetDestination::Stop (); 41 m_Owner = nullptr; 42 } 43 44 void I2CPDestination::SetEncryptionPrivateKey (i2p::data::CryptoKeyType keyType, const uint8_t * key) 45 { 46 bool exist = false; 47 auto it = m_EncryptionKeys.find (keyType); 48 if (it != m_EncryptionKeys.end () && !memcmp (it->second->priv.data (), key, it->second->priv.size ())) // new key? 49 exist = true; 50 if (!exist) 51 { 52 auto encryptionKey = std::make_shared<i2p::crypto::LocalEncryptionKey> (keyType); 53 memcpy (encryptionKey->priv.data (), key, encryptionKey->priv.size ()); 54 encryptionKey->CreateDecryptor (); // from private key 55 m_EncryptionKeys.insert_or_assign (keyType, encryptionKey); 56 } 57 } 58 59 void I2CPDestination::SetECIESx25519EncryptionPrivateKey (i2p::data::CryptoKeyType keyType, const uint8_t * key) 60 { 61 bool exist = false; 62 auto it = m_EncryptionKeys.find (keyType); 63 if (it != m_EncryptionKeys.end () && !memcmp (it->second->priv.data (), key, it->second->priv.size ())) // new key? 64 exist = true; 65 if (!exist) 66 { 67 auto encryptionKey = std::make_shared<i2p::crypto::LocalEncryptionKey> (keyType); 68 memcpy (encryptionKey->priv.data (), key, encryptionKey->priv.size ()); 69 // create decryptor manually 70 auto decryptor = std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key, true); // calculate publicKey 71 encryptionKey->decryptor = decryptor; 72 // assign public key from decryptor 73 memcpy (encryptionKey->pub.data (), decryptor->GetPubicKey (), encryptionKey->pub.size ()); 74 // insert or replace new 75 m_EncryptionKeys.insert_or_assign (keyType, encryptionKey); 76 } 77 } 78 79 bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const 80 { 81 std::shared_ptr<i2p::crypto::LocalEncryptionKey> encryptionKey; 82 if (!m_EncryptionKeys.empty ()) 83 { 84 if (m_EncryptionKeys.rbegin ()->first == preferredCrypto) 85 encryptionKey = m_EncryptionKeys.rbegin ()->second; 86 else 87 { 88 auto it = m_EncryptionKeys.find (preferredCrypto); 89 if (it != m_EncryptionKeys.end ()) 90 encryptionKey = it->second; 91 } 92 if (!encryptionKey) 93 encryptionKey = m_EncryptionKeys.rbegin ()->second; 94 } 95 if (encryptionKey) 96 return encryptionKey->decryptor->Decrypt (encrypted, data); 97 else 98 LogPrint (eLogError, "I2CP: Decryptor is not set"); 99 return false; 100 } 101 102 const uint8_t * I2CPDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const 103 { 104 auto it = m_EncryptionKeys.find (keyType); 105 if (it != m_EncryptionKeys.end ()) 106 return it->second->pub.data (); 107 return nullptr; 108 } 109 110 bool I2CPDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const 111 { 112 #if __cplusplus >= 202002L // C++20 113 return m_EncryptionKeys.contains (keyType); 114 #else 115 return m_EncryptionKeys.count (keyType) > 0; 116 #endif 117 } 118 119 i2p::data::CryptoKeyType I2CPDestination::GetPreferredCryptoType () const 120 { 121 return !m_EncryptionKeys.empty () ? m_EncryptionKeys.rbegin ()->first : 0; 122 } 123 124 i2p::data::CryptoKeyType I2CPDestination::GetRatchetsHighestCryptoType () const 125 { 126 if (m_EncryptionKeys.empty ()) return 0; 127 auto cryptoType = m_EncryptionKeys.rbegin ()->first; 128 return cryptoType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? cryptoType : 0; 129 } 130 131 void I2CPDestination::ScheduleSessionResponseTimer (std::shared_ptr<i2p::garlic::ECIESX25519AEADRatchetSession> session) 132 { 133 if (!session) return; 134 auto timer = std::make_shared<boost::asio::steady_timer>(GetService ()); 135 timer->expires_after (std::chrono::milliseconds(I2CP_RATCHETS_RESPONSE_TIMEOUT)); 136 timer->async_wait ([session, s = GetSharedFromThis (), timer](const boost::system::error_code& ecode) 137 { 138 if (ecode != boost::asio::error::operation_aborted && 139 !session->IsTerminated () && session->IsResponseRequired () && // response still required 140 session->GetDestinationPtr ()) // we know ident hash 141 { 142 auto pool = s->GetTunnelPool (); 143 if (!pool) return; 144 auto ls = s->FindLeaseSet (*session->GetDestinationPtr ()); 145 if (!ls) return; 146 auto garlic = session->WrapSingleMessage (nullptr); // no data messages 147 if (!garlic) return; 148 auto leases = ls->GetNonExpiredLeases (false); 149 if (!leases.empty ()) 150 { 151 auto remoteLease = leases[s->GetRng ()() % leases.size ()]; 152 auto outboundTunnel = pool->GetNextOutboundTunnel (); 153 if (outboundTunnel) 154 { 155 LogPrint (eLogDebug, "I2CP: Sending ratchets session response"); 156 s->SendMsg (garlic, outboundTunnel, remoteLease); 157 } 158 } 159 } 160 }); 161 } 162 163 void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len, 164 i2p::garlic::ECIESX25519AEADRatchetSession * from) 165 { 166 uint32_t length = bufbe32toh (buf); 167 if (length > len - 4) length = len - 4; 168 if (m_Owner) 169 m_Owner->SendMessagePayloadMessage (buf + 4, length); 170 } 171 172 void I2CPDestination::CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels) 173 { 174 boost::asio::post (GetService (), std::bind (&I2CPDestination::PostCreateNewLeaseSet, GetSharedFromThis (), tunnels)); 175 } 176 177 void I2CPDestination::PostCreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels) 178 { 179 if (m_IsCreatingLeaseSet) 180 { 181 LogPrint (eLogInfo, "I2CP: LeaseSet is being created"); 182 return; 183 } 184 m_ReadinessCheckTimer.cancel (); 185 auto pool = GetTunnelPool (); 186 if (!pool || pool->GetOutboundTunnels ().empty ()) 187 { 188 // try again later 189 m_ReadinessCheckTimer.expires_from_now (boost::posix_time::seconds(I2CP_DESTINATION_READINESS_CHECK_INTERVAL)); 190 m_ReadinessCheckTimer.async_wait( 191 [s=GetSharedFromThis (), tunnels=std::move(tunnels)](const boost::system::error_code& ecode) 192 { 193 if (ecode != boost::asio::error::operation_aborted) 194 s->PostCreateNewLeaseSet (tunnels); 195 }); 196 return; 197 } 198 uint8_t priv[256] = {0}; 199 i2p::data::LocalLeaseSet ls (m_Identity, priv, tunnels); // we don't care about encryption key, we need leases only 200 m_LeaseSetExpirationTime = ls.GetExpirationTime (); 201 uint8_t * leases = ls.GetLeases (); 202 int numLeases = leases[-1]; 203 if (m_Owner && numLeases) 204 { 205 uint16_t sessionID = m_Owner->GetSessionID (); 206 if (sessionID != 0xFFFF) 207 { 208 m_IsCreatingLeaseSet = true; 209 htobe16buf (leases - 3, sessionID); 210 size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*numLeases; 211 m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l); 212 m_LeaseSetCreationTimer.expires_from_now (boost::posix_time::seconds (I2CP_LEASESET_CREATION_TIMEOUT)); 213 auto s = GetSharedFromThis (); 214 m_LeaseSetCreationTimer.async_wait ([s](const boost::system::error_code& ecode) 215 { 216 if (ecode != boost::asio::error::operation_aborted) 217 { 218 LogPrint (eLogInfo, "I2CP: LeaseSet creation timeout expired. Terminate"); 219 if (s->m_Owner) s->m_Owner->Stop (); 220 } 221 }); 222 } 223 } 224 else 225 LogPrint (eLogError, "I2CP: Can't request LeaseSet"); 226 } 227 228 void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len) 229 { 230 m_IsCreatingLeaseSet = false; 231 m_LeaseSetCreationTimer.cancel (); 232 auto ls = std::make_shared<i2p::data::LocalLeaseSet> (m_Identity, buf, len); 233 ls->SetExpirationTime (m_LeaseSetExpirationTime); 234 SetLeaseSet (ls); 235 } 236 237 void I2CPDestination::LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len) 238 { 239 m_IsCreatingLeaseSet = false; 240 m_LeaseSetCreationTimer.cancel (); 241 auto ls = (storeType == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) ? 242 std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (m_Identity, buf, len): 243 std::make_shared<i2p::data::LocalLeaseSet2> (storeType, m_Identity, buf, len); 244 ls->SetExpirationTime (m_LeaseSetExpirationTime); 245 SetLeaseSet (ls); 246 } 247 248 void I2CPDestination::SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce) 249 { 250 auto msg = m_I2NPMsgsPool.AcquireSharedMt (); 251 uint8_t * buf = msg->GetPayload (); 252 htobe32buf (buf, len); 253 memcpy (buf + 4, payload, len); 254 msg->len += len + 4; 255 msg->FillI2NPMessageHeader (eI2NPData); 256 auto remote = FindLeaseSet (ident); 257 if (remote) 258 { 259 if (m_IsSameThread) 260 { 261 // send right a way 262 bool sent = SendMsg (msg, remote); 263 if (m_Owner) 264 m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure); 265 } 266 else 267 { 268 // send in destination's thread 269 auto s = GetSharedFromThis (); 270 boost::asio::post (GetService (), 271 [s, msg, remote, nonce]() 272 { 273 bool sent = s->SendMsg (msg, remote); 274 if (s->m_Owner) 275 s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure); 276 }); 277 } 278 } 279 else 280 { 281 auto s = GetSharedFromThis (); 282 RequestDestination (ident, 283 [s, msg, nonce](std::shared_ptr<i2p::data::LeaseSet> ls) 284 { 285 if (ls) 286 { 287 bool sent = s->SendMsg (msg, ls); 288 if (s->m_Owner) 289 s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure); 290 } 291 else if (s->m_Owner) 292 s->m_Owner->SendMessageStatusMessage (nonce, eI2CPMessageStatusNoLeaseSet); 293 }); 294 } 295 } 296 297 bool I2CPDestination::SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote) 298 { 299 auto remoteSession = GetRoutingSession (remote, true); 300 if (!remoteSession) 301 { 302 LogPrint (eLogError, "I2CP: Failed to create remote session"); 303 return false; 304 } 305 auto garlic = remoteSession->WrapSingleMessage (msg); // shared routing path mitgh be dropped here 306 auto path = remoteSession->GetSharedRoutingPath (); 307 std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel; 308 std::shared_ptr<const i2p::data::Lease> remoteLease; 309 if (path) 310 { 311 if (!remoteSession->CleanupUnconfirmedTags ()) // no stuck tags 312 { 313 outboundTunnel = path->outboundTunnel; 314 remoteLease = path->remoteLease; 315 } 316 else 317 remoteSession->SetSharedRoutingPath (nullptr); 318 } 319 if (!outboundTunnel || !remoteLease) 320 { 321 auto leases = remote->GetNonExpiredLeases (false); // without threshold 322 if (leases.empty ()) 323 leases = remote->GetNonExpiredLeases (true); // with threshold 324 if (!leases.empty ()) 325 { 326 remoteLease = leases[GetRng ()() % leases.size ()]; 327 auto leaseRouter = i2p::data::netdb.FindRouter (remoteLease->tunnelGateway); 328 auto pool = GetTunnelPool (); 329 if (pool) 330 outboundTunnel = pool->GetNextOutboundTunnel (nullptr, 331 leaseRouter ? leaseRouter->GetCompatibleTransports (false) : (i2p::data::RouterInfo::CompatibleTransports)i2p::data::RouterInfo::eAllTransports); 332 else 333 outboundTunnel = nullptr; 334 } 335 if (remoteLease && outboundTunnel) 336 remoteSession->SetSharedRoutingPath (std::make_shared<i2p::garlic::GarlicRoutingPath> ( 337 i2p::garlic::GarlicRoutingPath{outboundTunnel, remoteLease, 10000, 0})); // 10 secs RTT 338 else 339 remoteSession->SetSharedRoutingPath (nullptr); 340 } 341 m_Owner->AddRoutingSession (remote->GetIdentity ()->GetStandardIdentity ().signingKey + 96, remoteSession); // last 32 bytes 342 return SendMsg (garlic, outboundTunnel, remoteLease); 343 } 344 345 bool I2CPDestination::SendMsg (std::shared_ptr<I2NPMessage> garlic, 346 std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel, std::shared_ptr<const i2p::data::Lease> remoteLease) 347 { 348 if (remoteLease && outboundTunnel) 349 { 350 outboundTunnel->SendTunnelDataMsgs ( 351 { 352 i2p::tunnel::TunnelMessageBlock 353 { 354 i2p::tunnel::eDeliveryTypeTunnel, 355 remoteLease->tunnelGateway, remoteLease->tunnelID, 356 garlic 357 } 358 }); 359 return true; 360 } 361 else 362 { 363 if (outboundTunnel) 364 LogPrint (eLogWarning, "I2CP: Failed to send message. All leases expired"); 365 else 366 LogPrint (eLogWarning, "I2CP: Failed to send message. No outbound tunnels"); 367 return false; 368 } 369 } 370 371 bool I2CPDestination::SendMsg (const uint8_t * payload, size_t len, 372 std::shared_ptr<i2p::garlic::GarlicRoutingSession> remoteSession, uint32_t nonce) 373 { 374 if (!remoteSession) return false; 375 auto path = remoteSession->GetSharedRoutingPath (); 376 if (!path) return false; 377 // get tunnels 378 std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel; 379 std::shared_ptr<const i2p::data::Lease> remoteLease; 380 if (!remoteSession->CleanupUnconfirmedTags ()) // no stuck tags 381 { 382 outboundTunnel = path->outboundTunnel; 383 remoteLease = path->remoteLease; 384 } 385 else 386 { 387 remoteSession->SetSharedRoutingPath (nullptr); 388 return false; 389 } 390 // create Data message 391 auto msg = m_I2NPMsgsPool.AcquireSharedMt (); 392 uint8_t * buf = msg->GetPayload (); 393 htobe32buf (buf, len); 394 memcpy (buf + 4, payload, len); 395 msg->len += len + 4; 396 msg->FillI2NPMessageHeader (eI2NPData); 397 // wrap in gralic 398 auto garlic = remoteSession->WrapSingleMessage (msg); 399 // send 400 bool sent = SendMsg (garlic, outboundTunnel, remoteLease); 401 m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure); 402 if (!sent) 403 remoteSession->SetSharedRoutingPath (nullptr); 404 return sent; 405 } 406 407 void I2CPDestination::CleanupDestination () 408 { 409 m_I2NPMsgsPool.CleanUpMt (); 410 if (m_Owner) m_Owner->CleanupRoutingSessions (); 411 } 412 413 RunnableI2CPDestination::RunnableI2CPDestination (std::shared_ptr<I2CPSession> owner, 414 std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const i2p::util::Mapping& params): 415 RunnableService ("I2CP"), 416 I2CPDestination (GetIOService (), owner, identity, isPublic, false, params) 417 { 418 } 419 420 RunnableI2CPDestination::~RunnableI2CPDestination () 421 { 422 if (IsRunning ()) 423 Stop (); 424 } 425 426 void RunnableI2CPDestination::Start () 427 { 428 if (!IsRunning ()) 429 { 430 I2CPDestination::Start (); 431 StartIOService (); 432 } 433 } 434 435 void RunnableI2CPDestination::Stop () 436 { 437 if (IsRunning ()) 438 { 439 I2CPDestination::Stop (); 440 StopIOService (); 441 } 442 } 443 444 I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket): 445 m_Owner (owner), m_Socket (socket), m_SessionID (0xFFFF), m_MessageID (0), 446 m_IsSendAccepted (true), m_IsSending (false) 447 { 448 } 449 450 I2CPSession::~I2CPSession () 451 { 452 Terminate (); 453 } 454 455 void I2CPSession::Start () 456 { 457 if (m_Socket) 458 { 459 m_Socket->set_option (boost::asio::socket_base::receive_buffer_size (I2CP_MAX_MESSAGE_LENGTH)); 460 m_Socket->set_option (boost::asio::socket_base::send_buffer_size (I2CP_MAX_MESSAGE_LENGTH)); 461 } 462 ReadProtocolByte (); 463 } 464 465 void I2CPSession::Stop () 466 { 467 Terminate (); 468 } 469 470 void I2CPSession::ReadProtocolByte () 471 { 472 if (m_Socket) 473 { 474 auto s = shared_from_this (); 475 m_Socket->async_read_some (boost::asio::buffer (m_Header, 1), 476 [s](const boost::system::error_code& ecode, std::size_t bytes_transferred) 477 { 478 if (!ecode && bytes_transferred > 0 && s->m_Header[0] == I2CP_PROTOCOL_BYTE) 479 s->ReceiveHeader (); 480 else 481 s->Terminate (); 482 }); 483 } 484 } 485 486 void I2CPSession::ReceiveHeader () 487 { 488 if (!m_Socket) 489 { 490 LogPrint (eLogError, "I2CP: Can't receive header"); 491 return; 492 } 493 boost::asio::async_read (*m_Socket, boost::asio::buffer (m_Header, I2CP_HEADER_SIZE), 494 boost::asio::transfer_all (), 495 std::bind (&I2CPSession::HandleReceivedHeader, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); 496 } 497 498 void I2CPSession::HandleReceivedHeader (const boost::system::error_code& ecode, std::size_t bytes_transferred) 499 { 500 if (ecode) 501 Terminate (); 502 else 503 { 504 m_PayloadLen = bufbe32toh (m_Header + I2CP_HEADER_LENGTH_OFFSET); 505 if (m_PayloadLen > 0) 506 { 507 if (m_PayloadLen <= I2CP_MAX_MESSAGE_LENGTH) 508 { 509 if (!m_Socket) return; 510 boost::system::error_code ec; 511 size_t moreBytes = m_Socket->available(ec); 512 if (!ec) 513 { 514 if (moreBytes >= m_PayloadLen) 515 { 516 // read and process payload immediately if available 517 moreBytes = boost::asio::read (*m_Socket, boost::asio::buffer(m_Payload, m_PayloadLen), boost::asio::transfer_all (), ec); 518 HandleReceivedPayload (ec, moreBytes); 519 } 520 else 521 ReceivePayload (); 522 } 523 else 524 { 525 LogPrint (eLogWarning, "I2CP: Socket error: ", ec.message ()); 526 Terminate (); 527 } 528 } 529 else 530 { 531 LogPrint (eLogError, "I2CP: Unexpected payload length ", m_PayloadLen); 532 Terminate (); 533 } 534 } 535 else // no following payload 536 { 537 HandleMessage (); 538 ReceiveHeader (); // next message 539 } 540 } 541 } 542 543 void I2CPSession::ReceivePayload () 544 { 545 if (!m_Socket) 546 { 547 LogPrint (eLogError, "I2CP: Can't receive payload"); 548 return; 549 } 550 boost::asio::async_read (*m_Socket, boost::asio::buffer (m_Payload, m_PayloadLen), 551 boost::asio::transfer_all (), 552 std::bind (&I2CPSession::HandleReceivedPayload, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); 553 } 554 555 void I2CPSession::HandleReceivedPayload (const boost::system::error_code& ecode, std::size_t bytes_transferred) 556 { 557 if (ecode) 558 Terminate (); 559 else 560 { 561 HandleMessage (); 562 m_PayloadLen = 0; 563 ReceiveHeader (); // next message 564 } 565 } 566 567 void I2CPSession::HandleMessage () 568 { 569 auto handler = m_Owner.GetMessagesHandlers ()[m_Header[I2CP_HEADER_TYPE_OFFSET]]; 570 if (handler) 571 (this->*handler)(m_Payload, m_PayloadLen); 572 else 573 LogPrint (eLogError, "I2CP: Unknown I2CP message ", (int)m_Header[I2CP_HEADER_TYPE_OFFSET]); 574 } 575 576 void I2CPSession::Terminate () 577 { 578 if (m_Destination) 579 { 580 m_Destination->Stop (); 581 m_Destination = nullptr; 582 } 583 if (m_Socket) 584 { 585 m_Socket->close (); 586 m_Socket = nullptr; 587 } 588 if (!m_SendQueue.IsEmpty ()) 589 m_SendQueue.CleanUp (); 590 if (m_SessionID != 0xFFFF) 591 { 592 m_Owner.RemoveSession (GetSessionID ()); 593 LogPrint (eLogDebug, "I2CP: Session ", m_SessionID, " terminated"); 594 m_SessionID = 0xFFFF; 595 } 596 } 597 598 void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len) 599 { 600 auto l = len + I2CP_HEADER_SIZE; 601 if (l > I2CP_MAX_MESSAGE_LENGTH) 602 { 603 LogPrint (eLogError, "I2CP: Message to send is too long ", l); 604 return; 605 } 606 auto sendBuf = m_IsSending ? std::make_shared<i2p::stream::SendBuffer> (l) : nullptr; 607 uint8_t * buf = sendBuf ? sendBuf->buf : m_SendBuffer; 608 htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len); 609 buf[I2CP_HEADER_TYPE_OFFSET] = type; 610 memcpy (buf + I2CP_HEADER_SIZE, payload, len); 611 if (sendBuf) 612 { 613 if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE) 614 m_SendQueue.Add (std::move(sendBuf)); 615 else 616 { 617 LogPrint (eLogWarning, "I2CP: Send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); 618 return; 619 } 620 } 621 else 622 { 623 auto socket = m_Socket; 624 if (socket) 625 { 626 m_IsSending = true; 627 boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l), 628 boost::asio::transfer_all (), std::bind(&I2CPSession::HandleI2CPMessageSent, 629 shared_from_this (), std::placeholders::_1, std::placeholders::_2)); 630 } 631 } 632 } 633 634 void I2CPSession::HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) 635 { 636 if (ecode) 637 { 638 if (ecode != boost::asio::error::operation_aborted) 639 Terminate (); 640 } 641 else if (!m_SendQueue.IsEmpty ()) 642 { 643 auto socket = m_Socket; 644 if (socket) 645 { 646 auto len = m_SendQueue.Get (m_SendBuffer, I2CP_MAX_MESSAGE_LENGTH); 647 boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, len), 648 boost::asio::transfer_all (),std::bind(&I2CPSession::HandleI2CPMessageSent, 649 shared_from_this (), std::placeholders::_1, std::placeholders::_2)); 650 } 651 else 652 m_IsSending = false; 653 } 654 else 655 m_IsSending = false; 656 } 657 658 void I2CPSession::GetDateMessageHandler (const uint8_t * buf, size_t len) 659 { 660 constexpr std::string_view version(I2P_VERSION); 661 std::array<uint8_t, version.size() + 8 + 1> payload; 662 // set date 663 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 664 htobe64buf (payload.data(), ts); 665 // send our version back 666 i2p::util::Mapping::WriteString (version, payload.data() + 8, payload.size() - 8); 667 SendI2CPMessage (I2CP_SET_DATE_MESSAGE, payload.data(), payload.size()); 668 } 669 670 void I2CPSession::CreateSessionMessageHandler (const uint8_t * buf, size_t len) 671 { 672 RAND_bytes ((uint8_t *)&m_SessionID, 2); 673 auto identity = std::make_shared<i2p::data::IdentityEx>(); 674 size_t offset = identity->FromBuffer (buf, len); 675 if (!offset) 676 { 677 LogPrint (eLogError, "I2CP: Create session malformed identity"); 678 SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid 679 return; 680 } 681 if (m_Owner.FindSessionByIdentHash (identity->GetIdentHash ())) 682 { 683 LogPrint (eLogError, "I2CP: Create session duplicate address ", identity->GetIdentHash ().ToBase32 ()); 684 SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid 685 return; 686 } 687 uint16_t optionsSize = bufbe16toh (buf + offset); 688 offset += 2; 689 if (optionsSize > len - offset) 690 { 691 LogPrint (eLogError, "I2CP: Options size ", optionsSize, "exceeds message size"); 692 SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid 693 return; 694 } 695 i2p::util::Mapping params; 696 params.FromBuffer (optionsSize, buf + offset, len - offset); 697 offset += optionsSize; // options 698 if (params[I2CP_PARAM_MESSAGE_RELIABILITY] == "none") m_IsSendAccepted = false; 699 700 offset += 8; // date 701 if (identity->Verify (buf, offset, buf + offset)) // signature 702 { 703 if (!m_Destination) 704 { 705 m_Destination = m_Owner.IsSingleThread () ? 706 std::make_shared<I2CPDestination>(m_Owner.GetService (), shared_from_this (), identity, true, true, params): 707 std::make_shared<RunnableI2CPDestination>(shared_from_this (), identity, true, params); 708 if (m_Owner.InsertSession (shared_from_this ())) 709 { 710 LogPrint (eLogDebug, "I2CP: Session ", m_SessionID, " created"); 711 m_Destination->Start (); 712 SendSessionStatusMessage (eI2CPSessionStatusCreated); // created 713 } 714 else 715 { 716 LogPrint (eLogError, "I2CP: Session already exists"); 717 SendSessionStatusMessage (eI2CPSessionStatusRefused); 718 } 719 } 720 else 721 { 722 LogPrint (eLogError, "I2CP: Session already exists"); 723 SendSessionStatusMessage (eI2CPSessionStatusRefused); // refused 724 } 725 } 726 else 727 { 728 LogPrint (eLogError, "I2CP: Create session signature verification failed"); 729 SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid 730 } 731 } 732 733 void I2CPSession::DestroySessionMessageHandler (const uint8_t * buf, size_t len) 734 { 735 SendSessionStatusMessage (eI2CPSessionStatusDestroyed); // destroy 736 LogPrint (eLogDebug, "I2CP: Session ", m_SessionID, " destroyed"); 737 Terminate (); 738 } 739 740 void I2CPSession::ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len) 741 { 742 I2CPSessionStatus status = eI2CPSessionStatusInvalid; // rejected 743 if(len > sizeof(uint16_t)) 744 { 745 uint16_t sessionID = bufbe16toh(buf); 746 if(sessionID == m_SessionID) 747 { 748 buf += sizeof(uint16_t); 749 const uint8_t * body = buf; 750 i2p::data::IdentityEx ident; 751 if(ident.FromBuffer(buf, len - sizeof(uint16_t))) 752 { 753 if (ident == *m_Destination->GetIdentity()) 754 { 755 size_t identsz = ident.GetFullLen(); 756 buf += identsz; 757 uint16_t optssize = bufbe16toh(buf); 758 if (optssize <= len - sizeof(uint16_t) - sizeof(uint64_t) - identsz - ident.GetSignatureLen() - sizeof(uint16_t)) 759 { 760 buf += sizeof(uint16_t); 761 i2p::util::Mapping opts; 762 opts.FromBuffer (optssize, buf, optssize); 763 buf += optssize; 764 //uint64_t date = bufbe64toh(buf); 765 buf += sizeof(uint64_t); 766 const uint8_t * sig = buf; 767 if(ident.Verify(body, len - sizeof(uint16_t) - ident.GetSignatureLen(), sig)) 768 { 769 if(m_Destination->Reconfigure(opts)) 770 { 771 LogPrint(eLogInfo, "I2CP: Reconfigured destination"); 772 status = eI2CPSessionStatusUpdated; // updated 773 } 774 else 775 LogPrint(eLogWarning, "I2CP: Failed to reconfigure destination"); 776 } 777 else 778 LogPrint(eLogError, "I2CP: Invalid reconfigure message signature"); 779 } 780 else 781 LogPrint(eLogError, "I2CP: Mapping size mismatch"); 782 } 783 else 784 LogPrint(eLogError, "I2CP: Destination mismatch"); 785 } 786 else 787 LogPrint(eLogError, "I2CP: Malfromed destination"); 788 } 789 else 790 LogPrint(eLogError, "I2CP: Session mismatch"); 791 } 792 else 793 LogPrint(eLogError, "I2CP: Short message"); 794 SendSessionStatusMessage (status); 795 } 796 797 void I2CPSession::SendSessionStatusMessage (I2CPSessionStatus status) 798 { 799 uint8_t buf[3]; 800 htobe16buf (buf, m_SessionID); 801 buf[2] = (uint8_t)status; 802 SendI2CPMessage (I2CP_SESSION_STATUS_MESSAGE, buf, 3); 803 } 804 805 void I2CPSession::SendMessageStatusMessage (uint32_t nonce, I2CPMessageStatus status) 806 { 807 if (!nonce) return; // don't send status with zero nonce 808 uint8_t buf[15]; 809 htobe16buf (buf, m_SessionID); 810 htobe32buf (buf + 2, m_MessageID++); 811 buf[6] = (uint8_t)status; 812 memset (buf + 7, 0, 4); // size 813 htobe32buf (buf + 11, nonce); 814 SendI2CPMessage (I2CP_MESSAGE_STATUS_MESSAGE, buf, 15); 815 } 816 817 void I2CPSession::AddRoutingSession (const i2p::data::IdentHash& signingKey, std::shared_ptr<i2p::garlic::GarlicRoutingSession> remoteSession) 818 { 819 if (!remoteSession) return; 820 remoteSession->SetAckRequestInterval (I2CP_SESSION_ACK_REQUEST_INTERVAL); 821 std::lock_guard<std::mutex> l(m_RoutingSessionsMutex); 822 m_RoutingSessions[signingKey] = remoteSession; 823 } 824 825 void I2CPSession::CleanupRoutingSessions () 826 { 827 std::lock_guard<std::mutex> l(m_RoutingSessionsMutex); 828 for (auto it = m_RoutingSessions.begin (); it != m_RoutingSessions.end ();) 829 { 830 if (it->second->IsTerminated ()) 831 it = m_RoutingSessions.erase (it); 832 else 833 it++; 834 } 835 } 836 837 void I2CPSession::CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len) 838 { 839 uint16_t sessionID = bufbe16toh (buf); 840 if (sessionID == m_SessionID) 841 { 842 size_t offset = 2; 843 if (m_Destination) 844 { 845 offset += i2p::crypto::DSA_PRIVATE_KEY_LENGTH; // skip signing private key 846 // we always assume this field as 20 bytes (DSA) regardless actual size 847 // instead of 848 //offset += m_Destination->GetIdentity ()->GetSigningPrivateKeyLen (); 849 m_Destination->SetEncryptionPrivateKey (i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, buf + offset); 850 offset += 256; 851 m_Destination->LeaseSetCreated (buf + offset, len - offset); 852 } 853 } 854 else 855 LogPrint (eLogError, "I2CP: Unexpected sessionID ", sessionID); 856 } 857 858 void I2CPSession::CreateLeaseSet2MessageHandler (const uint8_t * buf, size_t len) 859 { 860 uint16_t sessionID = bufbe16toh (buf); 861 if (sessionID == m_SessionID) 862 { 863 size_t offset = 2; 864 if (m_Destination) 865 { 866 uint8_t storeType = buf[offset]; offset++; // store type 867 i2p::data::LeaseSet2 ls (storeType, buf + offset, len - offset); // outer layer only for encrypted 868 if (!ls.IsValid ()) 869 { 870 LogPrint (eLogError, "I2CP: Invalid LeaseSet2 of type ", storeType); 871 return; 872 } 873 offset += ls.GetBufferLen (); 874 // private keys 875 int numPrivateKeys = buf[offset]; offset++; 876 for (int i = 0; i < numPrivateKeys; i++) 877 { 878 if (offset + 4 > len) return; 879 uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption type 880 uint16_t keyLen = bufbe16toh (buf + offset); offset += 2; // private key length 881 if (offset + keyLen > len) return; 882 if (keyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) 883 m_Destination->SetECIESx25519EncryptionPrivateKey (keyType, buf + offset); 884 else 885 m_Destination->SetEncryptionPrivateKey (keyType, buf + offset); // from identity 886 offset += keyLen; 887 } 888 889 m_Destination->LeaseSet2Created (storeType, ls.GetBuffer (), ls.GetBufferLen ()); 890 } 891 } 892 else 893 LogPrint (eLogError, "I2CP: Unexpected sessionID ", sessionID); 894 } 895 896 void I2CPSession::SendMessageMessageHandler (const uint8_t * buf, size_t len) 897 { 898 uint16_t sessionID = bufbe16toh (buf); 899 if (sessionID == m_SessionID) 900 { 901 size_t offset = 2; 902 if (m_Destination) 903 { 904 const uint8_t * ident = buf + offset; 905 size_t identSize = i2p::data::GetIdentityBufferLen (ident, len - offset); 906 if (identSize) 907 { 908 offset += identSize; 909 uint32_t payloadLen = bufbe32toh (buf + offset); 910 if (payloadLen + offset <= len) 911 { 912 offset += 4; 913 uint32_t nonce = bufbe32toh (buf + offset + payloadLen); 914 if (m_Destination->IsReady ()) 915 { 916 if (m_IsSendAccepted) 917 SendMessageStatusMessage (nonce, eI2CPMessageStatusAccepted); // accepted 918 std::shared_ptr<i2p::garlic::GarlicRoutingSession> remoteSession; 919 { 920 std::lock_guard<std::mutex> l(m_RoutingSessionsMutex); 921 auto it = m_RoutingSessions.find (ident + i2p::data::DEFAULT_IDENTITY_SIZE - 35); // 32 bytes signing key 922 if (it != m_RoutingSessions.end ()) 923 { 924 if (!it->second->IsTerminated () && it->second->IsReadyToSend ()) 925 remoteSession = it->second; 926 else 927 m_RoutingSessions.erase (it); 928 } 929 } 930 if (!remoteSession || !m_Destination->SendMsg (buf + offset, payloadLen, remoteSession, nonce)) 931 { 932 i2p::data::IdentHash identHash; 933 SHA256(ident, identSize, identHash); // calculate ident hash, because we don't need full identity 934 m_Destination->SendMsgTo (buf + offset, payloadLen, identHash, nonce); 935 } 936 } 937 else 938 { 939 LogPrint(eLogInfo, "I2CP: Destination is not ready"); 940 SendMessageStatusMessage (nonce, eI2CPMessageStatusNoLocalTunnels); 941 } 942 } 943 else 944 LogPrint(eLogError, "I2CP: Cannot send message, too big"); 945 } 946 else 947 LogPrint(eLogError, "I2CP: Invalid identity"); 948 } 949 } 950 else 951 LogPrint (eLogError, "I2CP: Unexpected sessionID ", sessionID); 952 } 953 954 void I2CPSession::SendMessageExpiresMessageHandler (const uint8_t * buf, size_t len) 955 { 956 SendMessageMessageHandler (buf, len - 8); // ignore flags(2) and expiration(6) 957 } 958 959 void I2CPSession::HostLookupMessageHandler (const uint8_t * buf, size_t len) 960 { 961 uint16_t sessionID = bufbe16toh (buf); 962 if (sessionID == m_SessionID || sessionID == 0xFFFF) // -1 means without session 963 { 964 uint32_t requestID = bufbe32toh (buf + 2); 965 //uint32_t timeout = bufbe32toh (buf + 6); 966 i2p::data::IdentHash ident; 967 switch (buf[10]) 968 { 969 case 0: // hash 970 ident = i2p::data::IdentHash (buf + 11); 971 break; 972 case 1: // address 973 { 974 auto name = i2p::util::Mapping::ExtractString (buf + 11, len - 11); 975 auto addr = i2p::client::context.GetAddressBook ().GetAddress (name); 976 if (!addr || !addr->IsIdentHash ()) 977 { 978 // TODO: handle blinded addresses 979 LogPrint (eLogError, "I2CP: Address ", name, " not found"); 980 SendHostReplyMessage (requestID, nullptr); 981 return; 982 } 983 else 984 ident = addr->identHash; 985 break; 986 } 987 default: 988 LogPrint (eLogError, "I2CP: Request type ", (int)buf[10], " is not supported"); 989 SendHostReplyMessage (requestID, nullptr); 990 return; 991 } 992 993 std::shared_ptr<LeaseSetDestination> destination = m_Destination; 994 if(!destination) destination = i2p::client::context.GetSharedLocalDestination (); 995 if (destination) 996 { 997 auto ls = destination->FindLeaseSet (ident); 998 if (ls) 999 SendHostReplyMessage (requestID, ls->GetIdentity ()); 1000 else 1001 { 1002 auto s = shared_from_this (); 1003 destination->RequestDestination (ident, 1004 [s, requestID](std::shared_ptr<i2p::data::LeaseSet> leaseSet) 1005 { 1006 s->SendHostReplyMessage (requestID, leaseSet ? leaseSet->GetIdentity () : nullptr); 1007 }); 1008 } 1009 } 1010 else 1011 SendHostReplyMessage (requestID, nullptr); 1012 } 1013 else 1014 LogPrint (eLogError, "I2CP: Unexpected sessionID ", sessionID); 1015 } 1016 1017 void I2CPSession::SendHostReplyMessage (uint32_t requestID, std::shared_ptr<const i2p::data::IdentityEx> identity) 1018 { 1019 if (identity) 1020 { 1021 size_t l = identity->GetFullLen () + 7; 1022 uint8_t * buf = new uint8_t[l]; 1023 htobe16buf (buf, m_SessionID); 1024 htobe32buf (buf + 2, requestID); 1025 buf[6] = 0; // result code 1026 identity->ToBuffer (buf + 7, l - 7); 1027 SendI2CPMessage (I2CP_HOST_REPLY_MESSAGE, buf, l); 1028 delete[] buf; 1029 } 1030 else 1031 { 1032 uint8_t buf[7]; 1033 htobe16buf (buf, m_SessionID); 1034 htobe32buf (buf + 2, requestID); 1035 buf[6] = 1; // result code 1036 SendI2CPMessage (I2CP_HOST_REPLY_MESSAGE, buf, 7); 1037 } 1038 } 1039 1040 void I2CPSession::DestLookupMessageHandler (const uint8_t * buf, size_t len) 1041 { 1042 if (m_Destination) 1043 { 1044 auto ls = m_Destination->FindLeaseSet (buf); 1045 if (ls) 1046 { 1047 auto l = ls->GetIdentity ()->GetFullLen (); 1048 uint8_t * identBuf = new uint8_t[l]; 1049 ls->GetIdentity ()->ToBuffer (identBuf, l); 1050 SendI2CPMessage (I2CP_DEST_REPLY_MESSAGE, identBuf, l); 1051 delete[] identBuf; 1052 } 1053 else 1054 { 1055 auto s = shared_from_this (); 1056 i2p::data::IdentHash ident (buf); 1057 m_Destination->RequestDestination (ident, 1058 [s, ident](std::shared_ptr<i2p::data::LeaseSet> leaseSet) 1059 { 1060 if (leaseSet) // found 1061 { 1062 auto l = leaseSet->GetIdentity ()->GetFullLen (); 1063 uint8_t * identBuf = new uint8_t[l]; 1064 leaseSet->GetIdentity ()->ToBuffer (identBuf, l); 1065 s->SendI2CPMessage (I2CP_DEST_REPLY_MESSAGE, identBuf, l); 1066 delete[] identBuf; 1067 } 1068 else 1069 s->SendI2CPMessage (I2CP_DEST_REPLY_MESSAGE, ident, 32); // not found 1070 }); 1071 } 1072 } 1073 else 1074 SendI2CPMessage (I2CP_DEST_REPLY_MESSAGE, buf, 32); 1075 } 1076 1077 void I2CPSession::GetBandwidthLimitsMessageHandler (const uint8_t * buf, size_t len) 1078 { 1079 uint8_t limits[64]; 1080 memset (limits, 0, 64); 1081 uint32_t limit; i2p::config::GetOption("i2cp.inboundlimit", limit); 1082 if (!limit) limit = i2p::context.GetBandwidthLimit (); 1083 htobe32buf (limits, limit); // inbound 1084 i2p::config::GetOption("i2cp.outboundlimit", limit); 1085 if (!limit) limit = i2p::context.GetBandwidthLimit (); 1086 htobe32buf (limits + 4, limit); // outbound 1087 SendI2CPMessage (I2CP_BANDWIDTH_LIMITS_MESSAGE, limits, 64); 1088 } 1089 1090 void I2CPSession::SendMessagePayloadMessage (const uint8_t * payload, size_t len) 1091 { 1092 // we don't use SendI2CPMessage to eliminate additional copy 1093 auto l = len + 10 + I2CP_HEADER_SIZE; 1094 if (l > I2CP_MAX_MESSAGE_LENGTH) 1095 { 1096 LogPrint (eLogError, "I2CP: Message to send is too long ", l); 1097 return; 1098 } 1099 auto sendBuf = m_IsSending ? std::make_shared<i2p::stream::SendBuffer> (l) : nullptr; 1100 uint8_t * buf = sendBuf ? sendBuf->buf : m_SendBuffer; 1101 htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10); 1102 buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE; 1103 htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID); 1104 htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++); 1105 htobe32buf (buf + I2CP_HEADER_SIZE + 6, len); 1106 memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len); 1107 if (sendBuf) 1108 { 1109 if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE) 1110 m_SendQueue.Add (std::move(sendBuf)); 1111 else 1112 { 1113 LogPrint (eLogWarning, "I2CP: Send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); 1114 return; 1115 } 1116 } 1117 else 1118 { 1119 auto socket = m_Socket; 1120 if (socket) 1121 { 1122 m_IsSending = true; 1123 boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l), 1124 boost::asio::transfer_all (), std::bind(&I2CPSession::HandleI2CPMessageSent, 1125 shared_from_this (), std::placeholders::_1, std::placeholders::_2)); 1126 } 1127 } 1128 } 1129 1130 I2CPServer::I2CPServer (const std::string& interface, uint16_t port, bool isSingleThread): 1131 RunnableService ("I2CP"), m_IsSingleThread (isSingleThread), 1132 m_Acceptor (GetIOService (), 1133 boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(interface), port)) 1134 { 1135 memset (m_MessagesHandlers, 0, sizeof (m_MessagesHandlers)); 1136 m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler; 1137 m_MessagesHandlers[I2CP_CREATE_SESSION_MESSAGE] = &I2CPSession::CreateSessionMessageHandler; 1138 m_MessagesHandlers[I2CP_DESTROY_SESSION_MESSAGE] = &I2CPSession::DestroySessionMessageHandler; 1139 m_MessagesHandlers[I2CP_RECONFIGURE_SESSION_MESSAGE] = &I2CPSession::ReconfigureSessionMessageHandler; 1140 m_MessagesHandlers[I2CP_CREATE_LEASESET_MESSAGE] = &I2CPSession::CreateLeaseSetMessageHandler; 1141 m_MessagesHandlers[I2CP_CREATE_LEASESET2_MESSAGE] = &I2CPSession::CreateLeaseSet2MessageHandler; 1142 m_MessagesHandlers[I2CP_SEND_MESSAGE_MESSAGE] = &I2CPSession::SendMessageMessageHandler; 1143 m_MessagesHandlers[I2CP_SEND_MESSAGE_EXPIRES_MESSAGE] = &I2CPSession::SendMessageExpiresMessageHandler; 1144 m_MessagesHandlers[I2CP_HOST_LOOKUP_MESSAGE] = &I2CPSession::HostLookupMessageHandler; 1145 m_MessagesHandlers[I2CP_DEST_LOOKUP_MESSAGE] = &I2CPSession::DestLookupMessageHandler; 1146 m_MessagesHandlers[I2CP_GET_BANDWIDTH_LIMITS_MESSAGE] = &I2CPSession::GetBandwidthLimitsMessageHandler; 1147 } 1148 1149 I2CPServer::~I2CPServer () 1150 { 1151 if (IsRunning ()) 1152 Stop (); 1153 } 1154 1155 void I2CPServer::Start () 1156 { 1157 Accept (); 1158 StartIOService (); 1159 } 1160 1161 void I2CPServer::Stop () 1162 { 1163 m_Acceptor.cancel (); 1164 1165 decltype(m_Sessions) sessions; 1166 m_Sessions.swap (sessions); 1167 for (auto& it: sessions) 1168 it.second->Stop (); 1169 1170 StopIOService (); 1171 } 1172 1173 void I2CPServer::Accept () 1174 { 1175 auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (GetIOService ()); 1176 m_Acceptor.async_accept (*newSocket, std::bind (&I2CPServer::HandleAccept, this, 1177 std::placeholders::_1, newSocket)); 1178 } 1179 1180 void I2CPServer::HandleAccept(const boost::system::error_code& ecode, 1181 std::shared_ptr<boost::asio::ip::tcp::socket> socket) 1182 { 1183 if (!ecode && socket) 1184 { 1185 boost::system::error_code ec; 1186 auto ep = socket->remote_endpoint (ec); 1187 if (!ec) 1188 { 1189 LogPrint (eLogDebug, "I2CP: New connection from ", ep); 1190 auto session = std::make_shared<I2CPSession>(*this, socket); 1191 session->Start (); 1192 } 1193 else 1194 LogPrint (eLogError, "I2CP: Incoming connection error ", ec.message ()); 1195 } 1196 else 1197 LogPrint (eLogError, "I2CP: Accept error: ", ecode.message ()); 1198 1199 if (ecode != boost::asio::error::operation_aborted) 1200 Accept (); 1201 } 1202 1203 bool I2CPServer::InsertSession (std::shared_ptr<I2CPSession> session) 1204 { 1205 if (!session) return false; 1206 if (!m_Sessions.insert({session->GetSessionID (), session}).second) 1207 { 1208 LogPrint (eLogError, "I2CP: Duplicate session id ", session->GetSessionID ()); 1209 return false; 1210 } 1211 return true; 1212 } 1213 1214 void I2CPServer::RemoveSession (uint16_t sessionID) 1215 { 1216 m_Sessions.erase (sessionID); 1217 } 1218 1219 std::shared_ptr<I2CPSession> I2CPServer::FindSessionByIdentHash (const i2p::data::IdentHash& ident) const 1220 { 1221 for (const auto& it: m_Sessions) 1222 { 1223 if (it.second) 1224 { 1225 auto dest = it.second->GetDestination (); 1226 if (dest && dest->GetIdentHash () == ident) 1227 return it.second; 1228 } 1229 } 1230 return nullptr; 1231 } 1232 } 1233 }