subtly
10 years ago
6 changed files with 180 additions and 125 deletions
@ -0,0 +1,112 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file RLPXFrameReader.h
|
|||
* @author Alex Leverington <nessence@gmail.com> |
|||
* @date 2015 |
|||
*/ |
|||
|
|||
|
|||
#pragma once |
|||
|
|||
#include <libdevcore/Guards.h> |
|||
#include "RLPXFrameCoder.h" |
|||
#include "RLPXPacket.h" |
|||
namespace ba = boost::asio; |
|||
namespace bi = boost::asio::ip; |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace p2p |
|||
{ |
|||
|
|||
/**
|
|||
* RLPFrameReader |
|||
* Reads and assembles RLPX frame byte buffers into RLPX packets. Additionally |
|||
* buffers incomplete packets which are pieced into multiple frames (has sequence). |
|||
*/ |
|||
class RLPXFrameReader |
|||
{ |
|||
public: |
|||
RLPXFrameReader(uint16_t _protocolType): m_protocolType(_protocolType) {} |
|||
|
|||
/// Processes a single frame returning complete packets.
|
|||
std::vector<RLPXPacket> demux(RLPXFrameCoder& _coder, bytesRef _frame, bool _sequence = false, uint16_t _seq = 0, uint32_t _totalSize = 0) |
|||
{ |
|||
if (!_coder.authAndDecryptFrame(_frame)) |
|||
BOOST_THROW_EXCEPTION(RLPXFrameDecrytFailed()); |
|||
|
|||
std::vector<RLPXPacket> ret; |
|||
if (!_sequence && (!_frame.size() || _frame.size() > _totalSize)) |
|||
return ret; |
|||
|
|||
// trim mac
|
|||
bytesConstRef buffer = _frame.cropped(0, _frame.size() - h128::size); |
|||
// continue populating incomplete packets
|
|||
if (_sequence && m_incomplete.count(_seq)) |
|||
{ |
|||
uint32_t& remaining = m_incomplete.at(_seq).second; |
|||
if (!_totalSize && buffer.size() > 0 && buffer.size() <= remaining) |
|||
{ |
|||
remaining -= buffer.size(); |
|||
|
|||
RLPXPacket& p = m_incomplete.at(_seq).first; |
|||
if(p.append(buffer) && !remaining) |
|||
ret.push_back(std::move(p)); |
|||
if (!remaining) |
|||
m_incomplete.erase(_seq); |
|||
|
|||
if (!ret.empty() && remaining) |
|||
BOOST_THROW_EXCEPTION(RLPXInvalidPacket()); |
|||
else if (ret.empty() && !remaining) |
|||
BOOST_THROW_EXCEPTION(RLPXInvalidPacket()); |
|||
|
|||
return ret; |
|||
} |
|||
else |
|||
m_incomplete.erase(_seq); |
|||
} |
|||
|
|||
while (!buffer.empty()) |
|||
{ |
|||
auto type = nextRLP(buffer); |
|||
if (type.empty()) |
|||
break; |
|||
buffer = buffer.cropped(type.size()); |
|||
// consume entire buffer if packet has sequence
|
|||
auto packet = _sequence ? buffer : nextRLP(buffer); |
|||
buffer = buffer.cropped(packet.size()); |
|||
RLPXPacket p(m_protocolType, type); |
|||
if (!packet.empty()) |
|||
p.append(packet); |
|||
|
|||
uint32_t remaining = _totalSize - type.size() - packet.size(); |
|||
if (p.isValid()) |
|||
ret.push_back(std::move(p)); |
|||
else if (_sequence && remaining) |
|||
m_incomplete.insert(std::make_pair(_seq, std::make_pair(std::move(p), remaining))); |
|||
// else drop invalid packet
|
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
protected: |
|||
uint16_t m_protocolType; |
|||
std::map<uint16_t, std::pair<RLPXPacket, uint32_t>> m_incomplete; ///< Sequence: Incomplete packet and bytes remaining.
|
|||
}; |
|||
|
|||
} |
|||
} |
Loading…
Reference in new issue