diff options
Diffstat (limited to 'libktorrent/kademlia/rpcmsg.cpp')
-rw-r--r-- | libktorrent/kademlia/rpcmsg.cpp | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/libktorrent/kademlia/rpcmsg.cpp b/libktorrent/kademlia/rpcmsg.cpp new file mode 100644 index 0000000..97364e1 --- /dev/null +++ b/libktorrent/kademlia/rpcmsg.cpp @@ -0,0 +1,596 @@ +/*************************************************************************** + * Copyright (C) 2005 by Joris Guisson * + * joris.guisson@gmail.com * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include <util/log.h> +#include <torrent/bnode.h> +#include <torrent/globals.h> +#include <torrent/bencoder.h> +#include "rpcmsg.h" +#include "rpccall.h" +#include "rpcserver.h" +#include "dht.h" + +using namespace bt; + +namespace dht +{ + const QString TID = "t"; + const QString REQ = "q"; + const QString RSP = "r"; + const QString TYP = "y"; + const QString ARG = "a"; + // ERR apparently is defined as a macro on solaris in some header file, + // which causes things not to compile on it, so we have changed it to ERR_DHT + const QString ERR_DHT = "e"; + + + MsgBase* MakeMsg(bt::BDictNode* dict); + + + MsgBase* ParseReq(bt::BDictNode* dict) + { + BValueNode* vn = dict->getValue(REQ); + BDictNode* args = dict->getDict(ARG); + if (!vn || !args) + return 0; + + if (!args->getValue("id")) + return 0; + + if (!dict->getValue(TID)) + return 0; + + Key id = Key(args->getValue("id")->data().toByteArray()); + QByteArray mtid_d = dict->getValue(TID)->data().toByteArray(); + if (mtid_d.size() == 0) + return 0; + Uint8 mtid = (Uint8)mtid_d.at(0); + MsgBase* msg = 0; + + QString str = vn->data().toString(); + if (str == "ping") + { + msg = new PingReq(id); + } + else if (str == "find_node") + { + if (args->getValue("target")) + msg = new FindNodeReq(id,Key(args->getValue("target")->data().toByteArray())); + } + else if (str == "get_peers") + { + if (args->getValue("info_hash")) + msg = new GetPeersReq(id,Key(args->getValue("info_hash")->data().toByteArray())); + } + else if (str == "announce_peer") + { + if (args->getValue("info_hash") && args->getValue("port") && args->getValue("token")) + { + msg = new AnnounceReq(id, + Key(args->getValue("info_hash")->data().toByteArray()), + args->getValue("port")->data().toInt(), + Key(args->getValue("token")->data().toByteArray())); + } + } + + if (msg) + msg->setMTID(mtid); + + return msg; + } + + MsgBase* ParseRsp(bt::BDictNode* dict,dht::Method req_method,Uint8 mtid) + { + BDictNode* args = dict->getDict(RSP); + if (!args || !args->getValue("id")) + return 0; + + Key id = Key(args->getValue("id")->data().toByteArray()); + + switch (req_method) + { + case PING : + return new PingRsp(mtid,id); + case FIND_NODE : + if (!args->getValue("nodes")) + return 0; + else + return new FindNodeRsp(mtid,id,args->getValue("nodes")->data().toByteArray()); + case GET_PEERS : + if (args->getValue("token")) + { + Key token = args->getValue("token")->data().toByteArray(); + QByteArray data; + BListNode* vals = args->getList("values"); + DBItemList dbl; + if (vals) + { + for (Uint32 i = 0;i < vals->getNumChildren();i++) + { + BValueNode* vn = dynamic_cast<BValueNode*>(vals->getChild(i)); + if (!vn) + continue; + dbl.append(DBItem((Uint8*)vn->data().toByteArray().data())); + } + return new GetPeersRsp(mtid,id,dbl,token); + } + else if (args->getValue("nodes")) + { + data = args->getValue("nodes")->data().toByteArray(); + return new GetPeersRsp(mtid,id,data,token); + } + else + { + Out(SYS_DHT|LOG_DEBUG) << "No nodes or values in get_peers response" << endl; + return 0; + } + } + else + { + Out(SYS_DHT|LOG_DEBUG) << "No token in get_peers response" << endl; + } + case ANNOUNCE_PEER : + return new AnnounceRsp(mtid,id); + default: + return 0; + } + return 0; + } + + MsgBase* ParseRsp(bt::BDictNode* dict,RPCServer* srv) + { + BDictNode* args = dict->getDict(RSP); + if (!args || !dict->getValue(TID)) + { + Out(SYS_DHT|LOG_DEBUG) << "ParseRsp : args || !args->getValue(id) || !dict->getValue(TID)" << endl; + return 0; + } + + + QByteArray ba = dict->getValue(TID)->data().toByteArray(); + // check for empty byte arrays should prevent 144416 + if (ba.size() == 0) + return 0; + + Uint8 mtid = (Uint8)ba.at(0); + // find the call + const RPCCall* c = srv->findCall(mtid); + if (!c) + { + Out(SYS_DHT|LOG_DEBUG) << "Cannot find RPC call" << endl; + return 0; + } + + return ParseRsp(dict,c->getMsgMethod(),mtid); + } + + MsgBase* ParseErr(bt::BDictNode* dict) + { + BValueNode* vn = dict->getValue(RSP); + BDictNode* args = dict->getDict(ARG); + if (!vn || !args || !args->getValue("id") || !dict->getValue(TID)) + return 0; + + Key id = Key(args->getValue("id")->data().toByteArray()); + QString mt_id = dict->getValue(TID)->data().toString(); + if (mt_id.length() == 0) + return 0; + + Uint8 mtid = (char)mt_id.at(0).latin1(); + QString str = vn->data().toString(); + + return new ErrMsg(mtid,id,str); + } + + + MsgBase* MakeRPCMsg(bt::BDictNode* dict,RPCServer* srv) + { + BValueNode* vn = dict->getValue(TYP); + if (!vn) + return 0; + + if (vn->data().toString() == REQ) + { + return ParseReq(dict); + } + else if (vn->data().toString() == RSP) + { + return ParseRsp(dict,srv); + } + else if (vn->data().toString() == ERR_DHT) + { + return ParseErr(dict); + } + + return 0; + } + + MsgBase* MakeRPCMsgTest(bt::BDictNode* dict,dht::Method req_method) + { + BValueNode* vn = dict->getValue(TYP); + if (!vn) + return 0; + + if (vn->data().toString() == REQ) + { + return ParseReq(dict); + } + else if (vn->data().toString() == RSP) + { + return ParseRsp(dict,req_method,0); + } + else if (vn->data().toString() == ERR_DHT) + { + return ParseErr(dict); + } + + return 0; + } + + MsgBase::MsgBase(Uint8 mtid,Method m,Type type,const Key & id) + : mtid(mtid),method(m),type(type),id(id) + {} + + MsgBase::~MsgBase() + {} + + //////////////////////////////// + + PingReq::PingReq(const Key & id) : MsgBase(0xFF,PING,REQ_MSG,id) + { + } + + PingReq::~PingReq() + {} + + void PingReq::apply(DHT* dh_table) + { + dh_table->ping(this); + } + + void PingReq::print() + { + Out(SYS_DHT|LOG_DEBUG) << QString("REQ: %1 %2 : ping").arg(mtid).arg(id.toString()) << endl; + } + + void PingReq::encode(QByteArray & arr) + { + BEncoder enc(new BEncoderBufferOutput(arr)); + enc.beginDict(); + { + enc.write(ARG); enc.beginDict(); + { + enc.write("id"); enc.write(id.getData(),20); + } + enc.end(); + enc.write(REQ); enc.write("ping"); + enc.write(TID); enc.write(&mtid,1); + enc.write(TYP); enc.write(REQ); + } + enc.end(); + } + + //////////////////////////////// + + FindNodeReq::FindNodeReq(const Key & id,const Key & target) + : MsgBase(0xFF,FIND_NODE,REQ_MSG,id),target(target) + {} + + FindNodeReq::~FindNodeReq() + {} + + void FindNodeReq::apply(DHT* dh_table) + { + dh_table->findNode(this); + } + + void FindNodeReq::print() + { + Out(SYS_DHT|LOG_NOTICE) << QString("REQ: %1 %2 : find_node %3") + .arg(mtid).arg(id.toString()).arg(target.toString()) << endl; + } + + void FindNodeReq::encode(QByteArray & arr) + { + BEncoder enc(new BEncoderBufferOutput(arr)); + enc.beginDict(); + { + enc.write(ARG); enc.beginDict(); + { + enc.write("id"); enc.write(id.getData(),20); + enc.write("target"); enc.write(target.getData(),20); + } + enc.end(); + enc.write(REQ); enc.write("find_node"); + enc.write(TID); enc.write(&mtid,1); + enc.write(TYP); enc.write(REQ); + } + enc.end(); + } + + //////////////////////////////// + + //////////////////////////////// + GetPeersReq::GetPeersReq(const Key & id,const Key & info_hash) + : MsgBase(0xFF,GET_PEERS,REQ_MSG,id),info_hash(info_hash) + {} + + GetPeersReq::~GetPeersReq() + {} + + void GetPeersReq::apply(DHT* dh_table) + { + dh_table->getPeers(this); + } + + void GetPeersReq::print() + { + Out(SYS_DHT|LOG_DEBUG) << QString("REQ: %1 %2 : get_peers %3") + .arg(mtid).arg(id.toString()).arg(info_hash.toString()) << endl; + } + + void GetPeersReq::encode(QByteArray & arr) + { + BEncoder enc(new BEncoderBufferOutput(arr)); + enc.beginDict(); + { + enc.write(ARG); enc.beginDict(); + { + enc.write("id"); enc.write(id.getData(),20); + enc.write("info_hash"); enc.write(info_hash.getData(),20); + } + enc.end(); + enc.write(REQ); enc.write("get_peers"); + enc.write(TID); enc.write(&mtid,1); + enc.write(TYP); enc.write(REQ); + } + enc.end(); + } + + //////////////////////////////// + + AnnounceReq::AnnounceReq(const Key & id,const Key & info_hash,Uint16 port,const Key & token) + : GetPeersReq(id,info_hash),port(port),token(token) + { + method = dht::ANNOUNCE_PEER; + } + + AnnounceReq::~AnnounceReq() {} + + void AnnounceReq::apply(DHT* dh_table) + { + dh_table->announce(this); + } + + void AnnounceReq::print() + { + Out(SYS_DHT|LOG_DEBUG) << QString("REQ: %1 %2 : announce_peer %3 %4 %5") + .arg(mtid).arg(id.toString()).arg(info_hash.toString()) + .arg(port).arg(token.toString()) << endl; + } + + void AnnounceReq::encode(QByteArray & arr) + { + BEncoder enc(new BEncoderBufferOutput(arr)); + enc.beginDict(); + { + enc.write(ARG); enc.beginDict(); + { + enc.write("id"); enc.write(id.getData(),20); + enc.write("info_hash"); enc.write(info_hash.getData(),20); + enc.write("port"); enc.write((Uint32)port); + enc.write("token"); enc.write(token.getData(),20); + } + enc.end(); + enc.write(REQ); enc.write("announce_peer"); + enc.write(TID); enc.write(&mtid,1); + enc.write(TYP); enc.write(REQ); + } + enc.end(); + } + + //////////////////////////////// + + PingRsp::PingRsp(Uint8 mtid,const Key & id) + : MsgBase(mtid,PING,RSP_MSG,id) + {} + + PingRsp::~PingRsp() {} + + void PingRsp::apply(DHT* dh_table) + { + dh_table->response(this); + } + + void PingRsp::print() + { + Out(SYS_DHT|LOG_DEBUG) << QString("RSP: %1 %2 : ping") + .arg(mtid).arg(id.toString()) << endl; + } + + void PingRsp::encode(QByteArray & arr) + { + BEncoder enc(new BEncoderBufferOutput(arr)); + enc.beginDict(); + { + enc.write(RSP); enc.beginDict(); + { + enc.write("id"); enc.write(id.getData(),20); + } + enc.end(); + enc.write(TID); enc.write(&mtid,1); + enc.write(TYP); enc.write(RSP); + } + enc.end(); + } + + //////////////////////////////// + + FindNodeRsp::FindNodeRsp(Uint8 mtid,const Key & id,const QByteArray & nodes) + : MsgBase(mtid,FIND_NODE,RSP_MSG,id),nodes(nodes) + {} + + FindNodeRsp::~FindNodeRsp() {} + + void FindNodeRsp::apply(DHT* dh_table) + { + dh_table->response(this); + } + + void FindNodeRsp::print() + { + Out(SYS_DHT|LOG_DEBUG) << QString("RSP: %1 %2 : find_node") + .arg(mtid).arg(id.toString()) << endl; + } + + void FindNodeRsp::encode(QByteArray & arr) + { + BEncoder enc(new BEncoderBufferOutput(arr)); + enc.beginDict(); + { + enc.write(RSP); enc.beginDict(); + { + enc.write("id"); enc.write(id.getData(),20); + enc.write("nodes"); enc.write(nodes); + } + enc.end(); + enc.write(TID); enc.write(&mtid,1); + enc.write(TYP); enc.write(RSP); + } + enc.end(); + } + + //////////////////////////////// + + GetPeersRsp::GetPeersRsp(Uint8 mtid,const Key & id,const QByteArray & data,const Key & token) + : MsgBase(mtid,dht::GET_PEERS,dht::RSP_MSG,id),token(token),data(data) + { + this->data.detach(); + } + + GetPeersRsp::GetPeersRsp(Uint8 mtid,const Key & id,const DBItemList & values,const Key & token) + : MsgBase(mtid,dht::GET_PEERS,dht::RSP_MSG,id),token(token),items(values) + {} + + GetPeersRsp::~GetPeersRsp() + {} + + void GetPeersRsp::apply(DHT* dh_table) + { + dh_table->response(this); + } + void GetPeersRsp::print() + { + Out() << QString("RSP: %1 %2 : get_peers(%3)") + .arg(mtid).arg(id.toString()).arg(data.size() > 0 ? "nodes" : "values") << endl; + } + + void GetPeersRsp::encode(QByteArray & arr) + { + BEncoder enc(new BEncoderBufferOutput(arr)); + enc.beginDict(); + { + enc.write(RSP); enc.beginDict(); + { + enc.write("id"); enc.write(id.getData(),20); + if (data.size() > 0) + { + enc.write("nodes"); enc.write(data); + enc.write("token"); enc.write(token.getData(),20); + } + else + { + enc.write("token"); enc.write(token.getData(),20); + enc.write("values"); enc.beginList(); + DBItemList::iterator i = items.begin(); + while (i != items.end()) + { + const DBItem & item = *i; + enc.write(item.getData(),6); + i++; + } + enc.end(); + } + } + enc.end(); + enc.write(TID); enc.write(&mtid,1); + enc.write(TYP); enc.write(RSP); + } + enc.end(); + } + + + //////////////////////////////// + //////////////////////////////// + + AnnounceRsp::AnnounceRsp(Uint8 mtid,const Key & id) : MsgBase(mtid,ANNOUNCE_PEER,RSP_MSG,id) + {} + + AnnounceRsp::~AnnounceRsp(){} + + void AnnounceRsp::apply(DHT* dh_table) + { + dh_table->response(this); + } + + void AnnounceRsp::print() + { + Out() << QString("RSP: %1 %2 : announce_peer") + .arg(mtid).arg(id.toString()) << endl; + } + + void AnnounceRsp::encode(QByteArray & arr) + { + BEncoder enc(new BEncoderBufferOutput(arr)); + enc.beginDict(); + { + enc.write(RSP); enc.beginDict(); + { + enc.write("id"); enc.write(id.getData(),20); + } + enc.end(); + enc.write(TID); enc.write(&mtid,1); + enc.write(TYP); enc.write(RSP); + } + enc.end(); + } + + + //////////////////////////////// + + ErrMsg::ErrMsg(Uint8 mtid,const Key & id,const QString & msg) + : MsgBase(mtid,NONE,ERR_MSG,id),msg(msg) + {} + + ErrMsg::~ErrMsg() + {} + + void ErrMsg::apply(DHT* dh_table) + { + dh_table->error(this); + } + + void ErrMsg::print() + { + Out(SYS_DHT|LOG_NOTICE) << "ERR: " << mtid << " " << msg << endl; + } + + void ErrMsg::encode(QByteArray & ) + {} +} |