Miguel Freitas
11 years ago
16 changed files with 676 additions and 29 deletions
@ -0,0 +1,330 @@ |
|||||||
|
// Copyright (c) 2014 Miguel Freitas
|
||||||
|
// tunnel DHT requests into tcp connection
|
||||||
|
// see: https://groups.google.com/forum/#!topic/twister-dev/uKjFGSw24yA
|
||||||
|
|
||||||
|
#include <boost/assign/list_of.hpp> // for 'map_list_of()' |
||||||
|
#include <boost/assign.hpp> |
||||||
|
#include <boost/foreach.hpp> |
||||||
|
#include <algorithm> // std::random_shuffle |
||||||
|
|
||||||
|
#include "dhtproxy.h" |
||||||
|
|
||||||
|
#include "libtorrent/alert_manager.hpp" |
||||||
|
#include "libtorrent/alert_types.hpp" |
||||||
|
#include "libtorrent/peer_id.hpp" |
||||||
|
#include "libtorrent/bencode.hpp" |
||||||
|
|
||||||
|
#include "main.h" |
||||||
|
#include "uint256.h" |
||||||
|
#include "script.h" |
||||||
|
#include "init.h" |
||||||
|
#include "twister.h" |
||||||
|
#include "twister_utils.h" |
||||||
|
|
||||||
|
//#define dbgprintf OutputDebugStringF
|
||||||
|
#define dbgprintf(...) // no debug printf
|
||||||
|
|
||||||
|
using namespace libtorrent; |
||||||
|
|
||||||
|
namespace DhtProxy |
||||||
|
{ |
||||||
|
bool fEnabled = true; |
||||||
|
CCriticalSection cs_dhtProxy; |
||||||
|
map<sha1_hash, std::list<alert_manager*> > m_dhtgetMap; |
||||||
|
map<sha1_hash, std::list<CService> > m_dhtgetPeersReq; |
||||||
|
|
||||||
|
class PeerBanStats { |
||||||
|
public: |
||||||
|
PeerBanStats() : active(0), count(0), limit(time_now()) {} |
||||||
|
int active; |
||||||
|
int count; |
||||||
|
ptime limit; |
||||||
|
}; |
||||||
|
map<CService, PeerBanStats> m_peerBanStats; |
||||||
|
size_t numProxiesToUse = 4; |
||||||
|
|
||||||
|
void dhtgetMapAdd(sha1_hash &ih, alert_manager *am) |
||||||
|
{ |
||||||
|
LOCK(cs_dhtProxy); |
||||||
|
m_dhtgetMap[ih].push_back(am); |
||||||
|
} |
||||||
|
|
||||||
|
void dhtgetMapRemove(sha1_hash &ih, alert_manager *am) |
||||||
|
{ |
||||||
|
LOCK(cs_dhtProxy); |
||||||
|
std::map<sha1_hash, std::list<alert_manager*> >::iterator mi = m_dhtgetMap.find(ih); |
||||||
|
if( mi != m_dhtgetMap.end() ) { |
||||||
|
std::list<alert_manager *> &amList = (*mi).second; |
||||||
|
amList.remove(am); |
||||||
|
if( !amList.size() ) { |
||||||
|
m_dhtgetMap.erase(ih); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void dhtgetMapPost(sha1_hash &ih, const alert &a) |
||||||
|
{ |
||||||
|
LOCK(cs_dhtProxy); |
||||||
|
std::map<sha1_hash, std::list<alert_manager*> >::iterator mi = m_dhtgetMap.find(ih); |
||||||
|
if( mi != m_dhtgetMap.end() ) { |
||||||
|
std::list<alert_manager *> &amList = (*mi).second; |
||||||
|
BOOST_FOREACH(alert_manager *am, amList) { |
||||||
|
am->post_alert(a); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
vector<CNode*> getRandomDhtProxies() |
||||||
|
{ |
||||||
|
// (cs_vNodes) lock must be held!
|
||||||
|
vector<CNode*> vNodesProxy; |
||||||
|
BOOST_FOREACH(CNode* pnode, vNodes) { |
||||||
|
if (pnode->nVersion >= DHT_PROXY_VERSION && !pnode->fNoDhtProxy) { |
||||||
|
vNodesProxy.push_back(pnode); |
||||||
|
} |
||||||
|
} |
||||||
|
std::random_shuffle(vNodesProxy.begin(),vNodesProxy.end()); |
||||||
|
if(vNodesProxy.size() > numProxiesToUse) { |
||||||
|
vNodesProxy.resize(numProxiesToUse); |
||||||
|
} |
||||||
|
|
||||||
|
return vNodesProxy; |
||||||
|
} |
||||||
|
|
||||||
|
vector<CNode*> dhtgetStartRequest(std::string const &username, std::string const &resource, bool multi) |
||||||
|
{ |
||||||
|
CDHTGetRequest req; |
||||||
|
req.vchUsername = std::vector<char>(username.begin(), username.end()); |
||||||
|
req.vchResource = std::vector<char>(resource.begin(), resource.end()); |
||||||
|
req.resTypeMulti = multi; |
||||||
|
req.stopReq = false; |
||||||
|
|
||||||
|
LOCK(cs_vNodes); |
||||||
|
vector<CNode*> vNodesReq = getRandomDhtProxies(); |
||||||
|
BOOST_FOREACH(CNode* pnode, vNodesReq) { |
||||||
|
dbgprintf("DhtProxy::dhtgetStartRequest: pushMessage to %s\n", pnode->addr.ToString().c_str()); |
||||||
|
pnode->PushMessage("dhtgetreq", req); |
||||||
|
pnode->AddRef(); |
||||||
|
} |
||||||
|
if( !vNodesReq.size() ) { |
||||||
|
dbgprintf("DhtProxy::dhtgetStartRequest: sorry, no dht proxy found.\n"); |
||||||
|
|
||||||
|
// fake no data to wakeup listener
|
||||||
|
dht_reply_data_done_alert dd("","",false,false,false); |
||||||
|
sha1_hash ih = dhtTargetHash(username, resource, multi ? "m" : "s"); |
||||||
|
dhtgetMapPost(ih, dd); |
||||||
|
} |
||||||
|
return vNodesReq; |
||||||
|
} |
||||||
|
|
||||||
|
void dhtgetStopRequest(vector<CNode*> vNodesReq, std::string const &username, std::string const &resource, bool multi) |
||||||
|
{ |
||||||
|
CDHTGetRequest req; |
||||||
|
req.vchUsername = std::vector<char>(username.begin(), username.end()); |
||||||
|
req.vchResource = std::vector<char>(resource.begin(), resource.end()); |
||||||
|
req.resTypeMulti = multi; |
||||||
|
req.stopReq = true; |
||||||
|
|
||||||
|
BOOST_FOREACH(CNode* pnode, vNodesReq) { |
||||||
|
dbgprintf("DhtProxy::dhtgetStopRequest: pushMessage to %s\n", pnode->addr.ToString().c_str()); |
||||||
|
pnode->PushMessage("dhtgetreq", req); |
||||||
|
pnode->Release(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void dhtgetPeerReqAdd(sha1_hash &ih, const CNode *pnode) |
||||||
|
{ |
||||||
|
LOCK(cs_dhtProxy); |
||||||
|
m_dhtgetPeersReq[ih].push_back(pnode->addr); |
||||||
|
m_peerBanStats[pnode->addr].active++; |
||||||
|
} |
||||||
|
|
||||||
|
void dhtgetPeerReqRemove(sha1_hash &ih, const CNode *pnode) |
||||||
|
{ |
||||||
|
LOCK(cs_dhtProxy); |
||||||
|
std::map<sha1_hash, std::list<CService> >::iterator mi = m_dhtgetPeersReq.find(ih); |
||||||
|
if( mi != m_dhtgetPeersReq.end() ) { |
||||||
|
std::list<CService> &addrList = (*mi).second; |
||||||
|
addrList.remove(pnode->addr); |
||||||
|
if( !addrList.size() ) { |
||||||
|
m_dhtgetPeersReq.erase(ih); |
||||||
|
} |
||||||
|
m_peerBanStats[pnode->addr].active--; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void dhtgetPeerReqReply(sha1_hash &ih, const alert *a) |
||||||
|
{ |
||||||
|
CDHTGetReply reply; |
||||||
|
reply.vchTargetHash = std::vector<char>(ih.begin(), ih.end()); |
||||||
|
dht_reply_data_alert const* rd = alert_cast<dht_reply_data_alert>(a); |
||||||
|
if (rd) { |
||||||
|
bencode(std::back_inserter(reply.vchBencodedData), rd->m_lst); |
||||||
|
} |
||||||
|
|
||||||
|
LOCK(cs_dhtProxy); |
||||||
|
std::map<sha1_hash, std::list<CService> >::iterator mi = m_dhtgetPeersReq.find(ih); |
||||||
|
if( mi != m_dhtgetPeersReq.end() ) { |
||||||
|
std::list<CService> &addrList = (*mi).second; |
||||||
|
BOOST_FOREACH(CService &addr, addrList) { |
||||||
|
LOCK(cs_vNodes); |
||||||
|
BOOST_FOREACH(CNode* pnode, vNodes) { |
||||||
|
if ((CService)pnode->addr == addr) { |
||||||
|
dbgprintf("DhtProxy::dhtgetPeerReqReply: pushMessage to %s\n", pnode->addr.ToString().c_str()); |
||||||
|
pnode->PushMessage("dhtgetreply", reply); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool checkForAbuse(CNode* pfrom) |
||||||
|
{ |
||||||
|
LOCK(cs_dhtProxy); |
||||||
|
|
||||||
|
// logic inspired/copied from dht_tracker.cpp:incoming_packet
|
||||||
|
ptime now = time_now(); |
||||||
|
PeerBanStats *match = &m_peerBanStats[pfrom->addr]; |
||||||
|
match->count++; |
||||||
|
if( match->count >= 500 ) { |
||||||
|
if (now < match->limit) { |
||||||
|
if( match->count == 500 ) { |
||||||
|
dbgprintf("DhtProxy::checkForAbuse: %s misbehaving, too much requests.\n", |
||||||
|
pfrom->addr.ToString().c_str()); |
||||||
|
} |
||||||
|
match->limit = now + minutes(5); |
||||||
|
return true; |
||||||
|
} |
||||||
|
match->count = 0; |
||||||
|
match->limit = now + seconds(5); |
||||||
|
} |
||||||
|
if( match->active > 10 ) { |
||||||
|
dbgprintf("DhtProxy::checkForAbuse: %s misbehaving, max active requests reached.\n", |
||||||
|
pfrom->addr.ToString().c_str()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool dhtgetRequestReceived(const CDHTGetRequest& req, CNode* pfrom) |
||||||
|
{ |
||||||
|
if( fEnabled ) { |
||||||
|
// we are using proxy ourselves, we can't be proxy to anyone else
|
||||||
|
pfrom->PushMessage("nodhtproxy"); |
||||||
|
return true; |
||||||
|
} else if( !req.stopReq && checkForAbuse(pfrom) ) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
std::string username(req.vchUsername.data(), req.vchUsername.size()); |
||||||
|
std::string resource(req.vchResource.data(), req.vchResource.size()); |
||||||
|
bool multi(req.resTypeMulti); |
||||||
|
|
||||||
|
dbgprintf("DhtProxy::dhtgetRequestReceived: (%s,%s,%d,stop=%d) from %s\n", |
||||||
|
username.c_str(), resource.c_str(), multi, req.stopReq, |
||||||
|
pfrom->addr.ToString().c_str()); |
||||||
|
|
||||||
|
sha1_hash ih = dhtTargetHash(username, resource, multi ? "m" : "s"); |
||||||
|
if( !req.stopReq ) { |
||||||
|
dhtgetPeerReqAdd(ih, pfrom); |
||||||
|
dhtGetData(username, resource, multi); |
||||||
|
} else { |
||||||
|
dhtgetPeerReqRemove(ih, pfrom); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool dhtgetReplyReceived(const CDHTGetReply& reply, CNode* pfrom) |
||||||
|
{ |
||||||
|
std::string strTargetHash(reply.vchTargetHash.data(), reply.vchTargetHash.size()); |
||||||
|
sha1_hash ih(strTargetHash); |
||||||
|
|
||||||
|
if( !reply.vchBencodedData.size() ) { |
||||||
|
dbgprintf("DhtProxy::dhtgetReplyReceived: empty data from %s\n", |
||||||
|
pfrom->addr.ToString().c_str()); |
||||||
|
|
||||||
|
// No reply - these fields are not used, we just want cast in twister.cpp:dhtget to fail
|
||||||
|
dht_reply_data_done_alert dd("","",false,false,false); |
||||||
|
dhtgetMapPost(ih, dd); |
||||||
|
} else { |
||||||
|
lazy_entry v; |
||||||
|
int pos; |
||||||
|
libtorrent::error_code ec; |
||||||
|
if (lazy_bdecode(reply.vchBencodedData.data(), reply.vchBencodedData.data() + |
||||||
|
reply.vchBencodedData.size(), v, ec, &pos) == 0 && v.type() == lazy_entry::list_t ) { |
||||||
|
entry lst; |
||||||
|
lst = v; |
||||||
|
dbgprintf("DhtProxy::dhtgetReplyReceived: %zd entries from %s\n", |
||||||
|
lst.list().size(), pfrom->addr.ToString().c_str()); |
||||||
|
dht_reply_data_alert rd(lst.list()); |
||||||
|
dhtgetMapPost(ih, rd); |
||||||
|
} else { |
||||||
|
dbgprintf("DhtProxy::dhtgetReplyReceived: parsing error (data from %s)\n", |
||||||
|
pfrom->addr.ToString().c_str()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void dhtputRequest(std::string const &username, std::string const &resource, bool multi, |
||||||
|
std::string const &str_p, std::string const &sig_p, std::string const &sig_user) |
||||||
|
{ |
||||||
|
CDHTPutRequest req; |
||||||
|
req.vchUsername = std::vector<char>(username.begin(), username.end()); |
||||||
|
req.vchResource = std::vector<char>(resource.begin(), resource.end()); |
||||||
|
req.resTypeMulti = multi; |
||||||
|
req.vchStr_p = std::vector<char>(str_p.begin(), str_p.end()); |
||||||
|
req.vchSig_p = std::vector<char>(sig_p.begin(), sig_p.end()); |
||||||
|
req.vchSig_user = std::vector<char>(sig_user.begin(), sig_user.end()); |
||||||
|
|
||||||
|
LOCK(cs_vNodes); |
||||||
|
vector<CNode*> vNodesReq = getRandomDhtProxies(); |
||||||
|
BOOST_FOREACH(CNode* pnode, vNodesReq) { |
||||||
|
dbgprintf("DhtProxy::dhtputRequest: pushMessage to %s\n", pnode->addr.ToString().c_str()); |
||||||
|
pnode->PushMessage("dhtputreq", req); |
||||||
|
} |
||||||
|
if( !vNodesReq.size() ) { |
||||||
|
dbgprintf("DhtProxy::dhtputRequest: sorry, no dht proxy found.\n"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool dhtputRequestReceived(const CDHTPutRequest& req, CNode* pfrom) |
||||||
|
{ |
||||||
|
if( fEnabled ) { |
||||||
|
// we are using proxy ourselves, we can't be proxy to anyone else
|
||||||
|
pfrom->PushMessage("nodhtproxy"); |
||||||
|
return true; |
||||||
|
} else if( checkForAbuse(pfrom) ) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
std::string username(req.vchUsername.data(), req.vchUsername.size()); |
||||||
|
std::string resource(req.vchResource.data(), req.vchResource.size()); |
||||||
|
bool multi(req.resTypeMulti); |
||||||
|
|
||||||
|
dbgprintf("DhtProxy::dhtputRequestReceived: (%s,%s,%d) from %s\n", |
||||||
|
username.c_str(), resource.c_str(), multi, |
||||||
|
pfrom->addr.ToString().c_str()); |
||||||
|
|
||||||
|
lazy_entry v; |
||||||
|
int pos; |
||||||
|
libtorrent::error_code ec; |
||||||
|
if (lazy_bdecode(req.vchStr_p.data(), req.vchStr_p.data() + |
||||||
|
req.vchStr_p.size(), v, ec, &pos) == 0 ) { |
||||||
|
entry p; |
||||||
|
p = v; |
||||||
|
std::string sig_p(req.vchSig_p.data(), req.vchSig_p.size()); |
||||||
|
std::string sig_user(req.vchSig_user.data(), req.vchSig_user.size()); |
||||||
|
|
||||||
|
dhtPutDataSigned(username,resource,multi,p,sig_p,sig_user, false); |
||||||
|
} else { |
||||||
|
dbgprintf("DhtProxy::dhtputRequestReceived: parsing error (data from %s)\n", |
||||||
|
pfrom->addr.ToString().c_str()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,195 @@ |
|||||||
|
// Copyright (c) 2014 Miguel Freitas
|
||||||
|
|
||||||
|
#ifndef DHTPROXY_H |
||||||
|
#define DHTPROXY_H |
||||||
|
|
||||||
|
#include "serialize.h" |
||||||
|
#include "net.h" |
||||||
|
#include "uint256.h" |
||||||
|
|
||||||
|
#include <vector> |
||||||
|
|
||||||
|
// just a small set of declarations to avoid main.c depending on libtorrent headers
|
||||||
|
namespace libtorrent { |
||||||
|
class alert_manager; |
||||||
|
class big_number; |
||||||
|
typedef big_number sha1_hash; |
||||||
|
class alert; |
||||||
|
} |
||||||
|
|
||||||
|
class CDHTTarget; |
||||||
|
class CDHTGetRequest; |
||||||
|
class CDHTGetReply; |
||||||
|
class CDHTPutRequest; |
||||||
|
|
||||||
|
/**
|
||||||
|
* DHTGet Sequence: |
||||||
|
* |
||||||
|
* Client Server |
||||||
|
* 1) dhtgetMapAdd |
||||||
|
* 2) dhtgetStartRequest |
||||||
|
* => CDHTGetRequest => |
||||||
|
* 3) dhtgetRequestReceived(stopReq=False) |
||||||
|
* 4) (dhtgetPeerReqAdd) |
||||||
|
* 5) (ses->dht_getData) |
||||||
|
* 6.1) dhtgetPeerReqReply (from ThreadSessionAlerts) |
||||||
|
* 6.2) <= CDHTGetReply <= |
||||||
|
* 6.3) dhtgetReplyReceived |
||||||
|
* 6.4) (dhtgetMapPost) |
||||||
|
* [ ..item 6 repeats... ] |
||||||
|
* 7) dhtgetMapRemove |
||||||
|
* 8) dhtgetStopRequest |
||||||
|
* => CDHTGetRequest => |
||||||
|
* 9) dhtgetRequestReceived(stopReq=True) |
||||||
|
* 10) (dhtgetPeerReqRemove) |
||||||
|
* |
||||||
|
** |
||||||
|
* DHTPut Sequence: |
||||||
|
* |
||||||
|
* Client Server |
||||||
|
* 1) dhtputRequest |
||||||
|
* => CDHTPutRequest => |
||||||
|
* 2) dhtputRequestReceived |
||||||
|
* 3) (ses->dht_putDataSigned) |
||||||
|
*/ |
||||||
|
namespace DhtProxy |
||||||
|
{ |
||||||
|
extern bool fEnabled; |
||||||
|
|
||||||
|
// Register a listener for dhtget requests (client side)
|
||||||
|
void dhtgetMapAdd(libtorrent::sha1_hash &ih, libtorrent::alert_manager *am); |
||||||
|
|
||||||
|
// Unregister the dhtget listener (client side)
|
||||||
|
void dhtgetMapRemove(libtorrent::sha1_hash &ih, libtorrent::alert_manager *am); |
||||||
|
|
||||||
|
// Request a dhtget. Returns the list of node the request was sent to. (client side)
|
||||||
|
vector<CNode*> dhtgetStartRequest(std::string const &username, std::string const &resource, bool multi); |
||||||
|
|
||||||
|
// Stop a dhtget request to the nodes listed. (client side)
|
||||||
|
void dhtgetStopRequest(vector<CNode*> vNodesReq, std::string const &username, std::string const &resource, bool multi); |
||||||
|
|
||||||
|
// Handle a dhtget request received from TCP. send request to UDP. (server side)
|
||||||
|
// return true if accepted.
|
||||||
|
bool dhtgetRequestReceived(const CDHTGetRequest& req, CNode* pfrom); |
||||||
|
|
||||||
|
// Handle a dhtget reply received from UDP, send it to the peers that made the request. (server side)
|
||||||
|
void dhtgetPeerReqReply(libtorrent::sha1_hash &ih, const libtorrent::alert *a); |
||||||
|
|
||||||
|
// Handle a dhtget reply received from TCP. Will call dhtgetMapPost as needed. (client side)
|
||||||
|
// return true if accepted.
|
||||||
|
bool dhtgetReplyReceived(const CDHTGetReply& reply, CNode* pfrom); |
||||||
|
|
||||||
|
// Request a dhtput.
|
||||||
|
void dhtputRequest(std::string const &username, std::string const &resource, bool multi, |
||||||
|
std::string const &str_p, std::string const &sig_p, std::string const &sig_user); |
||||||
|
|
||||||
|
// Handle a dhtput request received from TCP. send request to UDP. (server side)
|
||||||
|
// return true if accepted.
|
||||||
|
bool dhtputRequestReceived(const CDHTPutRequest& req, CNode* pfrom); |
||||||
|
} |
||||||
|
|
||||||
|
class CDHTTarget |
||||||
|
{ |
||||||
|
public: |
||||||
|
std::vector<char> vchUsername; |
||||||
|
std::vector<char> vchResource; |
||||||
|
bool resTypeMulti; |
||||||
|
|
||||||
|
CDHTTarget() |
||||||
|
{ |
||||||
|
SetNull(); |
||||||
|
} |
||||||
|
|
||||||
|
IMPLEMENT_SERIALIZE |
||||||
|
( |
||||||
|
READWRITE(vchUsername); |
||||||
|
READWRITE(vchResource); |
||||||
|
READWRITE(resTypeMulti); |
||||||
|
) |
||||||
|
|
||||||
|
void SetNull() |
||||||
|
{ |
||||||
|
vchUsername.clear(); |
||||||
|
vchResource.clear(); |
||||||
|
resTypeMulti = false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class CDHTGetRequest : public CDHTTarget |
||||||
|
{ |
||||||
|
public: |
||||||
|
bool stopReq; |
||||||
|
|
||||||
|
CDHTGetRequest() : CDHTTarget() |
||||||
|
{ |
||||||
|
SetNull(); |
||||||
|
} |
||||||
|
|
||||||
|
IMPLEMENT_SERIALIZE |
||||||
|
( |
||||||
|
CDHTTarget* pthis = (CDHTTarget*)(this); |
||||||
|
READWRITE(*pthis); |
||||||
|
READWRITE(stopReq); |
||||||
|
) |
||||||
|
|
||||||
|
void SetNull() |
||||||
|
{ |
||||||
|
stopReq = false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class CDHTGetReply |
||||||
|
{ |
||||||
|
public: |
||||||
|
std::vector<char> vchTargetHash; |
||||||
|
std::vector<char> vchBencodedData; |
||||||
|
|
||||||
|
CDHTGetReply() |
||||||
|
{ |
||||||
|
SetNull(); |
||||||
|
} |
||||||
|
|
||||||
|
IMPLEMENT_SERIALIZE |
||||||
|
( |
||||||
|
READWRITE(vchTargetHash); |
||||||
|
READWRITE(vchBencodedData); |
||||||
|
) |
||||||
|
|
||||||
|
void SetNull() |
||||||
|
{ |
||||||
|
vchTargetHash.clear(); |
||||||
|
vchBencodedData.clear(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class CDHTPutRequest : public CDHTTarget |
||||||
|
{ |
||||||
|
public: |
||||||
|
std::vector<char> vchStr_p; |
||||||
|
std::vector<char> vchSig_p; |
||||||
|
std::vector<char> vchSig_user; |
||||||
|
|
||||||
|
CDHTPutRequest() : CDHTTarget() |
||||||
|
{ |
||||||
|
SetNull(); |
||||||
|
} |
||||||
|
|
||||||
|
IMPLEMENT_SERIALIZE |
||||||
|
( |
||||||
|
CDHTTarget* pthis = (CDHTTarget*)(this); |
||||||
|
READWRITE(*pthis); |
||||||
|
READWRITE(vchStr_p); |
||||||
|
READWRITE(vchSig_p); |
||||||
|
READWRITE(vchSig_user); |
||||||
|
) |
||||||
|
|
||||||
|
void SetNull() |
||||||
|
{ |
||||||
|
vchStr_p.clear(); |
||||||
|
vchSig_p.clear(); |
||||||
|
vchSig_user.clear(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
#endif |
Loading…
Reference in new issue