]> git.mxchange.org Git - quix0rs-apt-p2p.git/commitdiff
check responses and fail if they don't come from the peer we were
authorburris <burris>
Wed, 22 Jan 2003 07:22:48 +0000 (07:22 +0000)
committerburris <burris>
Wed, 22 Jan 2003 07:22:48 +0000 (07:22 +0000)
expecting them to come from

added bencode.py, whoops

actions.py
airhook.py
bencode.py [new file with mode: 0644]
const.py
knode.py
krpc.py
test_krpc.py

index f367c533f27e44463f8fe8aec52afc9f43d91e56..7a3a5b937f67004332a0e7b8e2180e2449421d6d 100644 (file)
@@ -85,6 +85,7 @@ class FindNode(ActionBase):
     
     def makeMsgFailed(self, node):
         def defaultGotNodes(err, self=self, node=node):
+            print ">>> find failed"
             self.table.table.nodeFailed(node)
             self.outstanding = self.outstanding - 1
             self.schedule()
@@ -195,6 +196,7 @@ class StoreValue(ActionBase):
                 self.schedule()
             
     def storeFailed(self, t, node):
+        print ">>> store failed"
         self.table.nodeFailed(node)
         self.outstanding -= 1
         if self.finished:
index c100cdf12faba2265f639132d08c55e8296995d6..60078bd184dbca881a435d6cd08865b31cbf0fc5 100644 (file)
@@ -101,7 +101,7 @@ class AirhookConnection(protocol.ConnectedDatagramProtocol, interfaces.IUDPConne
         self.lastTransmit = 0  # time we last sent a packet with messages
         self.lastReceieved = 0 # time we last received a packet with messages
         self.lastTransmitSeq = -1 # last sequence we sent a packet
-        self.state = pending
+        self.state = pending # one of pending, sent, confirmed
         
         self.outMsgs = [None] * 256  # outgoing messages  (seq sent, message), index = message number
         self.omsgq = [] # list of messages to go out
@@ -226,7 +226,7 @@ class AirhookConnection(protocol.ConnectedDatagramProtocol, interfaces.IUDPConne
                 ids +=  pack("!L", self.sessionID)
 
         else:
-            if self.state == sent or self.sendSession:
+            if self.state == sent or self.sendSession != None:
                 if self.state == confirmed and (self.obSeq - self.sendSession) % 2**16 < 256:
                     self.sendSession = None
                 else:
diff --git a/bencode.py b/bencode.py
new file mode 100644 (file)
index 0000000..93af407
--- /dev/null
@@ -0,0 +1,254 @@
+# Written by Petru Paler
+# see LICENSE.txt for license information
+
+from types import IntType, LongType, StringType, ListType, TupleType, DictType
+import re
+from cStringIO import StringIO
+
+int_filter = re.compile('(0|-?[1-9][0-9]*)e')
+
+def decode_int(x, f):
+    m = int_filter.match(x, f)
+    if m is None:
+        raise ValueError
+    return (long(m.group(1)), m.end())
+
+string_filter = re.compile('(0|[1-9][0-9]*):')
+
+def decode_string(x, f):
+    m = string_filter.match(x, f)
+    if m is None:
+        raise ValueError
+    l = int(m.group(1))
+    s = m.end()
+    return (x[s:s+l], s + l)
+
+def decode_list(x, f):
+    r = []
+    while x[f] != 'e':
+        v, f = bdecode_rec(x, f)
+        r.append(v)
+    return (r, f + 1)
+
+def decode_dict(x, f):
+    r = {}
+    lastkey = None
+    while x[f] != 'e':
+        k, f = decode_string(x, f)
+        if lastkey is not None and lastkey >= k:
+            raise ValueError
+        lastkey = k
+        v, f = bdecode_rec(x, f)
+        r[k] = v
+    return (r, f + 1)
+
+def bdecode_rec(x, f):
+    t = x[f]
+    if t == 'i':
+        return decode_int(x, f + 1)
+    elif t == 'l':
+        return decode_list(x, f + 1)
+    elif t == 'd':
+        return decode_dict(x, f + 1)
+    else:
+        return decode_string(x, f)
+
+def bdecode(x):
+    try:
+        r, l = bdecode_rec(x, 0)
+    except IndexError:
+        raise ValueError
+    if l != len(x):
+        raise ValueError
+    return r
+
+def test_bdecode():
+    try:
+        bdecode('0:0:')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('ie')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('i341foo382e')
+        assert 0
+    except ValueError:
+        pass
+    assert bdecode('i4e') == 4L
+    assert bdecode('i0e') == 0L
+    assert bdecode('i123456789e') == 123456789L
+    assert bdecode('i-10e') == -10L
+    try:
+        bdecode('i-0e')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('i123')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('i6easd')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('35208734823ljdahflajhdf')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('2:abfdjslhfld')
+        assert 0
+    except ValueError:
+        pass
+    assert bdecode('0:') == ''
+    assert bdecode('3:abc') == 'abc'
+    assert bdecode('10:1234567890') == '1234567890'
+    try:
+        bdecode('02:xy')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('l')
+        assert 0
+    except ValueError:
+        pass
+    assert bdecode('le') == []
+    try:
+        bdecode('leanfdldjfh')
+        assert 0
+    except ValueError:
+        pass
+    assert bdecode('l0:0:0:e') == ['', '', '']
+    try:
+        bdecode('relwjhrlewjh')
+        assert 0
+    except ValueError:
+        pass
+    assert bdecode('li1ei2ei3ee') == [1, 2, 3]
+    assert bdecode('l3:asd2:xye') == ['asd', 'xy']
+    assert bdecode('ll5:Alice3:Bobeli2ei3eee') == [['Alice', 'Bob'], [2, 3]]
+    try:
+        bdecode('d')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('defoobar')
+        assert 0
+    except ValueError:
+        pass
+    assert bdecode('de') == {}
+    assert bdecode('d3:agei25e4:eyes4:bluee') == {'age': 25, 'eyes': 'blue'}
+    assert bdecode('d8:spam.mp3d6:author5:Alice6:lengthi100000eee') == {'spam.mp3': {'author': 'Alice', 'length': 100000}}
+    try:
+        bdecode('d3:fooe')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('di1e0:e')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('d1:b0:1:a0:e')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('d1:a0:1:a0:e')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('i03e')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('l01:ae')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('9999:x')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('l0:')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('d0:0:')
+        assert 0
+    except ValueError:
+        pass
+    try:
+        bdecode('d0:')
+        assert 0
+    except ValueError:
+        pass
+
+def bencode_rec(x, b):
+    t = type(x)
+    if t in (IntType, LongType):
+        b.write('i%de' % x)
+    elif t is StringType:
+        b.write('%d:%s' % (len(x), x))
+    elif t in (ListType, TupleType):
+        b.write('l')
+        for e in x:
+            bencode_rec(e, b)
+        b.write('e')
+    elif t is DictType:
+        b.write('d')
+        keylist = x.keys()
+        keylist.sort()
+        for k in keylist:
+            assert type(k) is StringType
+            bencode_rec(k, b)
+            bencode_rec(x[k], b)
+        b.write('e')
+    else:
+        assert 0
+
+def bencode(x):
+    b = StringIO()
+    bencode_rec(x, b)
+    return b.getvalue()
+
+def test_bencode():
+    assert bencode(4) == 'i4e'
+    assert bencode(0) == 'i0e'
+    assert bencode(-10) == 'i-10e'
+    assert bencode(12345678901234567890L) == 'i12345678901234567890e'
+    assert bencode('') == '0:'
+    assert bencode('abc') == '3:abc'
+    assert bencode('1234567890') == '10:1234567890'
+    assert bencode([]) == 'le'
+    assert bencode([1, 2, 3]) == 'li1ei2ei3ee'
+    assert bencode([['Alice', 'Bob'], [2, 3]]) == 'll5:Alice3:Bobeli2ei3eee'
+    assert bencode({}) == 'de'
+    assert bencode({'age': 25, 'eyes': 'blue'}) == 'd3:agei25e4:eyes4:bluee'
+    assert bencode({'spam.mp3': {'author': 'Alice', 'length': 100000}}) == 'd8:spam.mp3d6:author5:Alice6:lengthi100000eee'
+    try:
+        bencode({1: 'foo'})
+        assert 0
+    except AssertionError:
+        pass
+
index ee1da1fc0d0d4ec46d3973fb460db9ffd394679c..bade7c418cb458302cf69dc795f022a238d7d9c0 100644 (file)
--- a/const.py
+++ b/const.py
@@ -1,9 +1,16 @@
 from twisted.internet.default import SelectReactor ## twistedmatrix.com
 
 reactor = SelectReactor(installSignalHandlers=0)
+
 from twisted.internet import main
 main.installReactor(reactor)
 
+try:
+    import twisted.names.client
+    reactor.installResolver(twisted.names.client.theResolver)
+except IOError:
+    print "no resolv.conf!"
+    
 # magic id to use before we know a peer's id
 NULL_ID =  20 * '\0'
 
index b5ecedcc0bfd6d70b25b2b53a6d689d877f01f94..f952795c6d647634dd156a85487115aa424e83f7 100644 (file)
--- a/knode.py
+++ b/knode.py
@@ -2,26 +2,35 @@ from node import Node
 from twisted.internet.defer import Deferred
 from const import reactor, NULL_ID
 
+
+class IDChecker:
+    def __init__(id):
+        self.id = id
+
 class KNode(Node):
-    def makeResponse(self, df):
-        """ Make our callback cover that checks to make sure the id of the response is the same as what we are expecting """
-        def _callback(dict, d=df):
-            try:
-                senderid = dict['sender']['id']
-            except KeyError:
-                d.errback()
-            else:
-                if self.id != NULL_ID and senderid != self._senderDict['id']:
-                    d.errback()
-                else:
-                    d.callback(dict)
-        return _callback
+    def checkSender(self, dict):
+        try:
+            senderid = dict['sender']['id']
+        except KeyError:
+            raise Exception, "No peer id in response."
+        else:
+            if self.id != NULL_ID and senderid != self.id:
+                raise Exception, "Got response from different node than expected."
+        return dict
         
     def ping(self, sender):
-        return self.conn.protocol.sendRequest('ping', {"sender":sender})
+        df = self.conn.protocol.sendRequest('ping', {"sender":sender})
+        df.addCallback(self.checkSender)
+        return df
     def findNode(self, target, sender):
-        return self.conn.protocol.sendRequest('find_node', {"target" : target, "sender": sender})
+        df = self.conn.protocol.sendRequest('find_node', {"target" : target, "sender": sender})
+        df.addCallback(self.checkSender)
+        return df
     def storeValue(self, key, value, sender):
-        return self.conn.protocol.sendRequest('store_value', {"key" : key, "value" : value, "sender": sender})
+        df = self.conn.protocol.sendRequest('store_value', {"key" : key, "value" : value, "sender": sender})
+        df.addCallback(self.checkSender)
+        return df
     def findValue(self, key, sender):
-        return self.conn.protocol.sendRequest('find_value', {"key" : key, "sender" : sender})
\ No newline at end of file
+        df =  self.conn.protocol.sendRequest('find_value', {"key" : key, "sender" : sender})
+        df.addCallback(self.checkSender)
+        return df
diff --git a/krpc.py b/krpc.py
index 8569bbf817af4fab885416b626fae3e0de556fed..40ed862ce69d340006f0162bf2dd4bbf2cfabeb8 100644 (file)
--- a/krpc.py
+++ b/krpc.py
@@ -3,6 +3,7 @@ from twisted.internet.defer import Deferred
 from twisted.protocols import basic
 from bencode import bencode, bdecode
 from twisted.internet import reactor
+import time
 
 import hash
 
@@ -57,7 +58,7 @@ class KRPC(basic.NetstringReceiver):
                     olen = len(str)
                     self.sendString(str)
                 if self.noisy:
-                    print "%s >>> (%s, %s) - %s %s %s" % (self.transport.addr, self.factory.node.host, self.factory.node.port, 
+                    print "%s %s >>> %s - %s %s %s" % (time.asctime(), self.transport.addr, self.factory.node.port, 
                                                     ilen, msg['req'], olen)
             elif msg['typ'] == 'rsp':
                 # if response
index 5f2c5b74fd9fa0ab94c5c8657ed33c63ac2982e9..42b7b161c6b2272a816d04bde83c904b4b4903c9 100644 (file)
@@ -2,6 +2,8 @@ from unittest import *
 from krpc import *
 from airhook import *
 
+KRPC.noisy = 0
+
 import sys
 
 if __name__ =="__main__":
@@ -31,7 +33,7 @@ class SimpleTest(TestCase):
         self.b = listenAirhookStream(4041, self.bf)
         
     def testSimpleMessage(self):
-        self.noisy = 1
+        self.noisy = 0
         self.a.connectionForAddr(('127.0.0.1', 4041)).protocol.sendRequest('store', {'msg' : "This is a test."})
         reactor.iterate()
         reactor.iterate()