| 36 |
kaklik |
1 |
# Written by Bram Cohen
|
|
|
2 |
# see LICENSE.txt for license information
|
|
|
3 |
|
|
|
4 |
from cStringIO import StringIO
|
|
|
5 |
from binascii import b2a_hex
|
|
|
6 |
from socket import error as socketerror
|
|
|
7 |
from urllib import quote
|
|
|
8 |
from traceback import print_exc
|
|
|
9 |
import Connecter
|
|
|
10 |
try:
|
|
|
11 |
True
|
|
|
12 |
except:
|
|
|
13 |
True = 1
|
|
|
14 |
False = 0
|
|
|
15 |
|
|
|
16 |
DEBUG = False
|
|
|
17 |
|
|
|
18 |
|
|
|
19 |
protocol_name = 'BitTorrent protocol'
|
|
|
20 |
option_pattern = chr(0)*8
|
|
|
21 |
|
|
|
22 |
def toint(s):
|
|
|
23 |
return long(b2a_hex(s), 16)
|
|
|
24 |
|
|
|
25 |
def tobinary(i):
|
|
|
26 |
return (chr(i >> 24) + chr((i >> 16) & 0xFF) +
|
|
|
27 |
chr((i >> 8) & 0xFF) + chr(i & 0xFF))
|
|
|
28 |
|
|
|
29 |
hexchars = '0123456789ABCDEF'
|
|
|
30 |
hexmap = []
|
|
|
31 |
for i in xrange(256):
|
|
|
32 |
hexmap.append(hexchars[(i&0xF0)/16]+hexchars[i&0x0F])
|
|
|
33 |
|
|
|
34 |
def tohex(s):
|
|
|
35 |
r = []
|
|
|
36 |
for c in s:
|
|
|
37 |
r.append(hexmap[ord(c)])
|
|
|
38 |
return ''.join(r)
|
|
|
39 |
|
|
|
40 |
def make_readable(s):
|
|
|
41 |
if not s:
|
|
|
42 |
return ''
|
|
|
43 |
if quote(s).find('%') >= 0:
|
|
|
44 |
return tohex(s)
|
|
|
45 |
return '"'+s+'"'
|
|
|
46 |
|
|
|
47 |
def toint(s):
|
|
|
48 |
return long(b2a_hex(s), 16)
|
|
|
49 |
|
|
|
50 |
# header, reserved, download id, my id, [length, message]
|
|
|
51 |
|
|
|
52 |
streamno = 0
|
|
|
53 |
|
|
|
54 |
|
|
|
55 |
class StreamCheck:
|
|
|
56 |
def __init__(self):
|
|
|
57 |
global streamno
|
|
|
58 |
self.no = streamno
|
|
|
59 |
streamno += 1
|
|
|
60 |
self.buffer = StringIO()
|
|
|
61 |
self.next_len, self.next_func = 1, self.read_header_len
|
|
|
62 |
|
|
|
63 |
def read_header_len(self, s):
|
|
|
64 |
if ord(s) != len(protocol_name):
|
|
|
65 |
print self.no, 'BAD HEADER LENGTH'
|
|
|
66 |
return len(protocol_name), self.read_header
|
|
|
67 |
|
|
|
68 |
def read_header(self, s):
|
|
|
69 |
if s != protocol_name:
|
|
|
70 |
print self.no, 'BAD HEADER'
|
|
|
71 |
return 8, self.read_reserved
|
|
|
72 |
|
|
|
73 |
def read_reserved(self, s):
|
|
|
74 |
return 20, self.read_download_id
|
|
|
75 |
|
|
|
76 |
def read_download_id(self, s):
|
|
|
77 |
if DEBUG:
|
|
|
78 |
print self.no, 'download ID ' + tohex(s)
|
|
|
79 |
return 20, self.read_peer_id
|
|
|
80 |
|
|
|
81 |
def read_peer_id(self, s):
|
|
|
82 |
if DEBUG:
|
|
|
83 |
print self.no, 'peer ID' + make_readable(s)
|
|
|
84 |
return 4, self.read_len
|
|
|
85 |
|
|
|
86 |
def read_len(self, s):
|
|
|
87 |
l = toint(s)
|
|
|
88 |
if l > 2 ** 23:
|
|
|
89 |
print self.no, 'BAD LENGTH: '+str(l)+' ('+s+')'
|
|
|
90 |
return l, self.read_message
|
|
|
91 |
|
|
|
92 |
def read_message(self, s):
|
|
|
93 |
if not s:
|
|
|
94 |
return 4, self.read_len
|
|
|
95 |
m = s[0]
|
|
|
96 |
if ord(m) > 8:
|
|
|
97 |
print self.no, 'BAD MESSAGE: '+str(ord(m))
|
|
|
98 |
if m == Connecter.REQUEST:
|
|
|
99 |
if len(s) != 13:
|
|
|
100 |
print self.no, 'BAD REQUEST SIZE: '+str(len(s))
|
|
|
101 |
return 4, self.read_len
|
|
|
102 |
index = toint(s[1:5])
|
|
|
103 |
begin = toint(s[5:9])
|
|
|
104 |
length = toint(s[9:])
|
|
|
105 |
print self.no, 'Request: '+str(index)+': '+str(begin)+'-'+str(begin)+'+'+str(length)
|
|
|
106 |
elif m == Connecter.CANCEL:
|
|
|
107 |
if len(s) != 13:
|
|
|
108 |
print self.no, 'BAD CANCEL SIZE: '+str(len(s))
|
|
|
109 |
return 4, self.read_len
|
|
|
110 |
index = toint(s[1:5])
|
|
|
111 |
begin = toint(s[5:9])
|
|
|
112 |
length = toint(s[9:])
|
|
|
113 |
print self.no, 'Cancel: '+str(index)+': '+str(begin)+'-'+str(begin)+'+'+str(length)
|
|
|
114 |
elif m == Connecter.PIECE:
|
|
|
115 |
index = toint(s[1:5])
|
|
|
116 |
begin = toint(s[5:9])
|
|
|
117 |
length = len(s)-9
|
|
|
118 |
print self.no, 'Piece: '+str(index)+': '+str(begin)+'-'+str(begin)+'+'+str(length)
|
|
|
119 |
else:
|
|
|
120 |
print self.no, 'Message '+str(ord(m))+' (length '+str(len(s))+')'
|
|
|
121 |
return 4, self.read_len
|
|
|
122 |
|
|
|
123 |
def write(self, s):
|
|
|
124 |
while True:
|
|
|
125 |
i = self.next_len - self.buffer.tell()
|
|
|
126 |
if i > len(s):
|
|
|
127 |
self.buffer.write(s)
|
|
|
128 |
return
|
|
|
129 |
self.buffer.write(s[:i])
|
|
|
130 |
s = s[i:]
|
|
|
131 |
m = self.buffer.getvalue()
|
|
|
132 |
self.buffer.reset()
|
|
|
133 |
self.buffer.truncate()
|
|
|
134 |
x = self.next_func(m)
|
|
|
135 |
self.next_len, self.next_func = x
|