| 545 | } |
| 546 | |
| 547 | bool SSU2Session::SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg) |
| 548 | { |
| 549 | if (!msg) return false; |
| 550 | size_t lastFragmentSize = (msg->GetNTCP2Length () + 3 - m_MaxPayloadSize) % (m_MaxPayloadSize - 8); |
| 551 | size_t extraSize = m_MaxPayloadSize - lastFragmentSize; |
| 552 | bool ackBlockSent = false; |
| 553 | uint32_t msgID; |
| 554 | memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4); |
| 555 | auto ts = i2p::util::GetMillisecondsSinceEpoch (); |
| 556 | auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); |
| 557 | if (extraSize >= 8) |
| 558 | { |
| 559 | packet->payloadSize = CreateAckBlock (packet->payload, extraSize); |
| 560 | ackBlockSent = true; |
| 561 | if (packet->payloadSize + 12 < m_MaxPayloadSize) |
| 562 | { |
| 563 | uint32_t packetNum = SendData (packet->payload, packet->payloadSize); |
| 564 | packet->sendTime = ts; |
| 565 | m_SentPackets.emplace (packetNum, packet); |
| 566 | packet = m_Server.GetSentPacketsPool ().AcquireShared (); |
| 567 | } |
| 568 | else |
| 569 | extraSize -= packet->payloadSize; |
| 570 | } |
| 571 | size_t offset = extraSize > 0 ? (m_Server.GetRng ()() % extraSize) : 0; |
| 572 | if (offset + packet->payloadSize >= m_MaxPayloadSize) offset = 0; |
| 573 | auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - offset - packet->payloadSize, msg); |
| 574 | if (!size) return false; |
| 575 | extraSize -= offset; |
| 576 | packet->payloadSize += size; |
| 577 | uint32_t firstPacketNum = SendData (packet->payload, packet->payloadSize); |
| 578 | packet->sendTime = ts; |
| 579 | m_SentPackets.emplace (firstPacketNum, packet); |
| 580 | uint8_t fragmentNum = 0; |
| 581 | while (msg->offset < msg->len) |
| 582 | { |
| 583 | offset = extraSize > 0 ? (m_Server.GetRng ()() % extraSize) : 0; |
| 584 | packet = m_Server.GetSentPacketsPool ().AcquireShared (); |
| 585 | packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - offset, msg, fragmentNum, msgID); |
| 586 | extraSize -= offset; |
| 587 | uint8_t flags = 0; |
| 588 | if (msg->offset >= msg->len && packet->payloadSize + 16 < m_MaxPayloadSize) // last fragment |
| 589 | { |
| 590 | packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); |
| 591 | if (fragmentNum > 2) // 3 or more fragments |
| 592 | flags |= SSU2_FLAG_IMMEDIATE_ACK_REQUESTED; |
| 593 | } |
| 594 | uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize, flags); |
| 595 | packet->sendTime = ts; |
| 596 | m_SentPackets.emplace (followonPacketNum, packet); |
| 597 | } |
| 598 | return ackBlockSent; |
| 599 | } |
| 600 | |
| 601 | size_t SSU2Session::Resend (uint64_t ts) |
| 602 | { |
no test coverage detected