1 ## Copyright 2002-2003 Andrew Loewenstern, All Rights Reserved
2 # see LICENSE.txt for license information
4 from twisted.internet.defer import Deferred
5 from twisted.protocols import basic
6 from bencode import bencode, bdecode
7 from twisted.internet import protocol
9 from twisted.internet import reactor
13 from traceback import format_exception
20 KRPC_ERROR_METHOD_UNKNOWN = 2
21 KRPC_ERROR_RECEIVED_UNKNOWN = 3
22 KRPC_ERROR_TIMEOUT = 4
32 class hostbroker(protocol.DatagramProtocol):
33 def __init__(self, server):
35 # this should be changed to storage that drops old entries
38 def datagramReceived(self, datagram, addr):
39 #print `addr`, `datagram`
40 #if addr != self.addr:
41 c = self.connectionForAddr(addr)
42 c.datagramReceived(datagram, addr)
44 # del self.connections[addr]
46 def connectionForAddr(self, addr):
49 if not self.connections.has_key(addr):
50 conn = self.protocol(addr, self.server, self.transport)
51 self.connections[addr] = conn
53 conn = self.connections[addr]
56 def makeConnection(self, transport):
57 protocol.DatagramProtocol.makeConnection(self, transport)
58 tup = transport.getHost()
59 self.addr = (tup.host, tup.port)
64 def __init__(self, addr, server, transport):
65 self.transport = transport
71 def datagramReceived(self, str, addr):
77 print "response decode error: " + `e`
86 # tell factory to handle
87 f = getattr(self.factory ,"krpc_" + msg[REQ], None)
88 msg[ARG]['_krpc_sender'] = self.addr
91 ret = apply(f, (), msg[ARG])
94 out = bencode({TID:msg[TID], TYP:ERR, ERR :`format_exception(type(e), e, sys.exc_info()[2])`})
96 self.transport.write(out, addr)
100 out = bencode({TID : msg[TID], TYP : RSP, RSP : ret})
102 out = bencode({TID : msg[TID], TYP : RSP, RSP : {}})
105 self.transport.write(out, addr)
109 print "don't know about method %s" % msg[REQ]
111 out = bencode({TID:msg[TID], TYP:ERR, ERR : KRPC_ERROR_METHOD_UNKNOWN})
113 self.transport.write(out, addr)
115 print "%s %s >>> %s - %s %s %s" % (time.asctime(), addr, self.factory.node.port,
116 ilen, msg[REQ], olen)
117 elif msg[TYP] == RSP:
120 if self.tids.has_key(msg[TID]):
121 df = self.tids[msg[TID]]
123 del(self.tids[msg[TID]])
124 df.callback({'rsp' : msg[RSP], '_krpc_sender': addr})
126 print 'timeout ' + `msg[RSP]['id']`
127 # no tid, this transaction timed out already...
128 elif msg[TYP] == ERR:
131 if self.tids.has_key(msg[TID]):
132 df = self.tids[msg[TID]]
135 del(self.tids[msg[TID]])
137 # day late and dollar short
140 print "unknown message type " + `msg`
141 # unknown message type
142 df = self.tids[msg[TID]]
144 df.errback(KRPC_ERROR_RECEIVED_UNKNOWN)
145 del(self.tids[msg[TID]])
147 def sendRequest(self, method, args):
150 msg = {TID : chr(self.mtid), TYP : REQ, REQ : method, ARG : args}
151 self.mtid = (self.mtid + 1) % 256
154 self.tids[msg[TID]] = d
155 def timeOut(tids = self.tids, id = msg[TID]):
159 print ">>>>>> KRPC_ERROR_TIMEOUT"
160 df.errback(KRPC_ERROR_TIMEOUT)
161 reactor.callLater(KRPC_TIMEOUT, timeOut)
162 self.transport.write(str, self.addr)