Blame | Last modification | View Log | Download
# Written by Bram Cohen# see LICENSE.txt for license informationfrom cStringIO import StringIOfrom binascii import b2a_hexfrom socket import error as socketerrorfrom urllib import quotefrom traceback import print_excimport Connectertry:Trueexcept:True = 1False = 0DEBUG = Falseprotocol_name = 'BitTorrent protocol'option_pattern = chr(0)*8def toint(s):return long(b2a_hex(s), 16)def tobinary(i):return (chr(i >> 24) + chr((i >> 16) & 0xFF) +chr((i >> 8) & 0xFF) + chr(i & 0xFF))hexchars = '0123456789ABCDEF'hexmap = []for i in xrange(256):hexmap.append(hexchars[(i&0xF0)/16]+hexchars[i&0x0F])def tohex(s):r = []for c in s:r.append(hexmap[ord(c)])return ''.join(r)def make_readable(s):if not s:return ''if quote(s).find('%') >= 0:return tohex(s)return '"'+s+'"'def toint(s):return long(b2a_hex(s), 16)# header, reserved, download id, my id, [length, message]streamno = 0class StreamCheck:def __init__(self):global streamnoself.no = streamnostreamno += 1self.buffer = StringIO()self.next_len, self.next_func = 1, self.read_header_lendef read_header_len(self, s):if ord(s) != len(protocol_name):print self.no, 'BAD HEADER LENGTH'return len(protocol_name), self.read_headerdef read_header(self, s):if s != protocol_name:print self.no, 'BAD HEADER'return 8, self.read_reserveddef read_reserved(self, s):return 20, self.read_download_iddef read_download_id(self, s):if DEBUG:print self.no, 'download ID ' + tohex(s)return 20, self.read_peer_iddef read_peer_id(self, s):if DEBUG:print self.no, 'peer ID' + make_readable(s)return 4, self.read_lendef read_len(self, s):l = toint(s)if l > 2 ** 23:print self.no, 'BAD LENGTH: '+str(l)+' ('+s+')'return l, self.read_messagedef read_message(self, s):if not s:return 4, self.read_lenm = s[0]if ord(m) > 8:print self.no, 'BAD MESSAGE: '+str(ord(m))if m == Connecter.REQUEST:if len(s) != 13:print self.no, 'BAD REQUEST SIZE: '+str(len(s))return 4, self.read_lenindex = toint(s[1:5])begin = toint(s[5:9])length = toint(s[9:])print self.no, 'Request: '+str(index)+': '+str(begin)+'-'+str(begin)+'+'+str(length)elif m == Connecter.CANCEL:if len(s) != 13:print self.no, 'BAD CANCEL SIZE: '+str(len(s))return 4, self.read_lenindex = toint(s[1:5])begin = toint(s[5:9])length = toint(s[9:])print self.no, 'Cancel: '+str(index)+': '+str(begin)+'-'+str(begin)+'+'+str(length)elif m == Connecter.PIECE:index = toint(s[1:5])begin = toint(s[5:9])length = len(s)-9print self.no, 'Piece: '+str(index)+': '+str(begin)+'-'+str(begin)+'+'+str(length)else:print self.no, 'Message '+str(ord(m))+' (length '+str(len(s))+')'return 4, self.read_lendef write(self, s):while True:i = self.next_len - self.buffer.tell()if i > len(s):self.buffer.write(s)returnself.buffer.write(s[:i])s = s[i:]m = self.buffer.getvalue()self.buffer.reset()self.buffer.truncate()x = self.next_func(m)self.next_len, self.next_func = x