1 # Written by Arno Bakker, Jie Yang
2 # see LICENSE.txt for license information
6 from binascii import b2a_hex
7 from struct import pack,unpack
8 from StringIO import StringIO
10 from BaseLib.Core.Overlay.SecureOverlay import OLPROTO_VER_CURRENT
14 current_version = OLPROTO_VER_CURRENT
17 protocol_name = "BitTorrent protocol"
18 # Enable Tribler extensions:
19 # Left-most bit = Azureus Enhanced Messaging Protocol (AEMP)
20 # Left+42 bit = Tribler Simple Merkle Hashes extension v0. Outdated, but still sent for compatibility.
21 # Left+43 bit = Tribler Overlay swarm extension
22 # Right-most bit = BitTorrent DHT extension
23 tribler_option_pattern = '\x00\x00\x00\x00\x00\x30\x00\x00'
24 overlay_infohash = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
27 return long(b2a_hex(s), 16)
30 return (chr(i >> 24) + chr((i >> 16) & 0xFF) +
31 chr((i >> 8) & 0xFF) + chr(i & 0xFF))
34 def __init__(self,hostname,port,opensock=None,user_option_pattern=None,user_infohash=None,myid=None,mylistenport=None,myoversion=None):
35 assert user_option_pattern is None or isinstance(user_option_pattern, str)
36 assert user_option_pattern is None or len(user_option_pattern) == 8
37 assert user_infohash is None or isinstance(user_infohash, str)
38 assert user_infohash is None or len(user_infohash) == 20
39 assert myid is None or isinstance(myid, str)
40 assert myid is None or len(myid) == 20
42 self.buffer = StringIO()
43 if mylistenport is None:
46 self.myport = mylistenport
48 self.myid = "".zfill(20)
49 if myoversion is None:
50 myoversion = current_version
51 self.myid = self.myid[:16] + pack('<H', lowest_version) + pack('<H', myoversion)
52 self.myid = self.myid[:14] + pack('<H', self.myport) + self.myid[16:]
60 self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
61 self.s.connect((hostname, port))
62 handshake = chr(len(protocol_name))
63 handshake += protocol_name
64 if user_option_pattern is None:
65 handshake += tribler_option_pattern
67 handshake += user_option_pattern
69 if user_infohash is None:
70 self.expected_infohash = overlay_infohash
72 self.expected_infohash = user_infohash
73 handshake += self.expected_infohash
74 handshake += self.myid
76 print >>sys.stderr,"btconn: Sending handshake len",len(handshake)
77 self.s.send(handshake)
85 def get_my_fake_listen_port(self):
88 def read_handshake(self):
89 data = self._readn(68)
90 assert(data[0] == chr(len(protocol_name)))
91 assert(data[1:20] == protocol_name)
92 assert(data[20:28] == tribler_option_pattern)
93 assert(data[28:48] == self.expected_infohash)
94 self.hisid = data[48:68]
95 hisport = unpack('<H', self.hisid[14:16])[0]
96 assert(hisport == self.hisport)
97 low_ver = unpack('<H', self.hisid[16:18])[0]
98 assert(low_ver == lowest_version)
99 cur_ver = unpack('<H', self.hisid[18:20])[0]
101 # print >> sys.stderr, "btconn: his cur_ver: ", cur_ver
102 # print >> sys.stderr, "btconn: my curr_ver: ", current_version
103 assert(cur_ver == current_version)
105 def read_handshake_medium_rare(self,close_ok = False):
106 data = self._readn(68)
111 assert(len(data) > 0)
112 assert(data[0] == chr(len(protocol_name)))
113 assert(data[1:20] == protocol_name)
114 assert(data[20:28] == tribler_option_pattern)
115 assert(data[28:48] == self.expected_infohash)
116 self.hisid = data[48:68]
117 # don't check encoded fields
123 """ send length-prefixed message """
124 self.s.send(tobinary(len(data)))
128 """ received length-prefixed message """
129 size_data = self._readn(4)
130 if len(size_data) == 0:
132 size = toint(size_data)
133 if DEBUG and size > 10000:
134 print >> sys.stderr,"btconn: waiting for message size",size
136 # BT keep alive message, don't report upwards
139 return self._readn(size)
142 """ read n bytes from socket stream """
146 data = self.s.recv(nwant)
147 except socket.error, e:
149 # WSAEWOULDBLOCK on Windows
152 # WSAECONNRESET on Windows
153 print >>sys.stderr,"btconn:",e,"converted to EOF"
154 return '' # convert to EOF
158 print >> sys.stderr,"btconn: _readn got",len(data),"bytes"
160 #raise socket.error(ECONNRESET,'arno says connection closed')
163 self.buffer.write(data)
167 data = self.buffer.read(n)