1 /*
2     SPDX-FileCopyrightText: 2012 Joris Guisson <joris.guisson@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "rpcmsgfactory.h"
8 #include "announcereq.h"
9 #include "announcersp.h"
10 #include "dht.h"
11 #include "errmsg.h"
12 #include "findnodereq.h"
13 #include "findnodersp.h"
14 #include "getpeersrsp.h"
15 #include "pingreq.h"
16 #include "pingrsp.h"
17 #include "rpcserver.h"
18 #include <bcodec/bnode.h>
19 #include <util/error.h>
20 #include <util/functions.h>
21 #include <util/log.h>
22 
23 using namespace bt;
24 
25 namespace dht
26 {
RPCMsgFactory()27 RPCMsgFactory::RPCMsgFactory()
28 {
29 }
30 
~RPCMsgFactory()31 RPCMsgFactory::~RPCMsgFactory()
32 {
33 }
34 
buildRequest(BDictNode * dict)35 RPCMsg::Ptr RPCMsgFactory::buildRequest(BDictNode *dict)
36 {
37     BDictNode *args = dict->getDict(ARG);
38     if (!args)
39         throw bt::Error("Invalid request, arguments missing");
40 
41     RPCMsg::Ptr msg;
42     QString str = dict->getString(REQ, nullptr);
43     if (str == "ping") {
44         msg = RPCMsg::Ptr(new PingReq());
45         msg->parse(dict);
46         return msg;
47     } else if (str == "find_node") {
48         msg = RPCMsg::Ptr(new FindNodeReq());
49         msg->parse(dict);
50         return msg;
51     } else if (str == "get_peers") {
52         msg = RPCMsg::Ptr(new GetPeersReq());
53         msg->parse(dict);
54         return msg;
55     } else if (str == "announce_peer") {
56         msg = RPCMsg::Ptr(new AnnounceReq());
57         msg->parse(dict);
58         return msg;
59     } else if (str == "vote") {
60         // Some µTorrent extension to rate torrents, just ignore
61         return msg;
62     } else
63         throw bt::Error(QString("Invalid request type %1").arg(str));
64 }
65 
buildResponse(BDictNode * dict,dht::RPCMethodResolver * method_resolver)66 RPCMsg::Ptr RPCMsgFactory::buildResponse(BDictNode *dict, dht::RPCMethodResolver *method_resolver)
67 {
68     BDictNode *args = dict->getDict(RSP);
69     if (!args)
70         throw bt::Error("Arguments missing for DHT response");
71 
72     QByteArray mtid = dict->getByteArray(TID);
73     // check for empty byte arrays should prevent 144416
74     if (mtid.size() == 0)
75         throw bt::Error("Empty transaction ID in DHT response");
76 
77     RPCMsg::Ptr msg;
78 
79     // find the call
80     Method method = method_resolver->findMethod(mtid);
81     switch (method) {
82     case PING:
83         msg = RPCMsg::Ptr(new PingRsp());
84         msg->parse(dict);
85         break;
86     case FIND_NODE:
87         msg = RPCMsg::Ptr(new FindNodeRsp());
88         msg->parse(dict);
89         break;
90     case GET_PEERS:
91         msg = RPCMsg::Ptr(new GetPeersRsp());
92         msg->parse(dict);
93         break;
94     case ANNOUNCE_PEER:
95         msg = RPCMsg::Ptr(new AnnounceRsp());
96         msg->parse(dict);
97         break;
98     case NONE:
99     default:
100         throw bt::Error(QString("Unknown DHT rpc call (transaction id = %1)").arg(mtid[0]));
101     }
102 
103     return msg;
104 }
105 
build(bt::BDictNode * dict,RPCMethodResolver * method_resolver)106 RPCMsg::Ptr RPCMsgFactory::build(bt::BDictNode *dict, RPCMethodResolver *method_resolver)
107 {
108     QString t = dict->getString(TYP, nullptr);
109     if (t == REQ) {
110         return buildRequest(dict);
111     } else if (t == RSP) {
112         return buildResponse(dict, method_resolver);
113     } else if (t == ERR_DHT) {
114         RPCMsg::Ptr msg(new ErrMsg());
115         msg->parse(dict);
116         return msg;
117     } else
118         throw bt::Error(QString("Unknown message type %1").arg(t));
119 }
120 
121 }
122