1# Written by Arno Bakker
2# see LICENSE.txt for license information
3#
4# Python implementation of the on-the-wire part of the swift protocol
5# (PPSP-04 draft) for simple tests.
6#
7
8import sys
9import socket
10import struct
11import os
12
13import binascii
14
15
16HASH_ZERO = '\x00' * 20
17
18
19TSBYTES_LEN = 8
20
21IPV4BYTES_LEN = (32/8)+2
22IPV6BYTES_LEN = (128/8)+2
23
24
25CHUNK_SPEC_ID_BIN32 = '\x00'
26CHUNK_SPEC_ID_BYTE64 = '\x01'
27CHUNK_SPEC_ID_CHUNK32 = '\x02'
28CHUNK_SPEC_ID_BIN64 = '\x03'
29CHUNK_SPEC_ID_CHUNK64 = '\x04'
30
31
32class Encodable:
33    def to_bytes(self):
34        pass
35    def from_bytes(bytes):
36        pass
37    from_bytes = staticmethod(from_bytes)
38    def get_bytes_length():
39        pass
40    def __repr__(self):
41        return self.__str__()
42
43#
44# Chunk Addressing
45#
46
47class Bin(Encodable):
48    def __init__(self,i):
49        self.i = i
50        #print >>sys.stderr,"Bin: set:",self.i
51    def to_bytes(self):
52        return struct.pack(">I",self.i)
53    def from_bytes(bytes):
54        [i] = struct.unpack(">I",bytes)
55        return Bin(i)
56    from_bytes = staticmethod(from_bytes)
57    def get_bytes_length():
58        return 4
59    get_bytes_length = staticmethod(get_bytes_length)
60    def get_id():
61        return CHUNK_SPEC_ID_BIN32
62    get_id = staticmethod(get_id)
63    def __str__(self):
64        return "Bin("+str(self.i)+")"
65
66
67BIN_ALL  = Bin(0x7fffffff)
68BIN_NONE = Bin(0xffffffff)
69
70
71class ChunkRange(Encodable):
72    def __init__(self,s,e):
73        self.s = s
74        self.e = e
75        #print >>sys.stderr,"ChunkRange: set:",s,e
76    def to_bytes(self):
77        return struct.pack(">II",self.s,self.e)
78    def from_bytes(bytes):
79        [s,e] = struct.unpack(">II",bytes)
80        return ChunkRange(s,e)
81    from_bytes = staticmethod(from_bytes)
82    def get_bytes_length():
83        return 8
84    get_bytes_length = staticmethod(get_bytes_length)
85    def get_id():
86        return CHUNK_SPEC_ID_CHUNK32
87    get_id = staticmethod(get_id)
88    def __str__(self):
89        return "ChunkRange("+str(self.s)+","+str(self.e)+")"
90
91#
92# TimeStamp
93#
94
95class TimeStamp(Encodable):
96    def __init__(self,ts):
97        self.ts = ts
98    def to_bytes(self):
99        return struct.pack(">Q",self.ts)
100    def from_bytes(bytes):
101        [ts] = struct.unpack(">Q",bytes)
102        return TimeStamp(ts)
103    from_bytes = staticmethod(from_bytes)
104    def get_bytes_length():
105        return 8
106    get_bytes_length = staticmethod(get_bytes_length)
107    def get_id():
108        return None
109    get_id = staticmethod(get_id)
110    def __str__(self):
111        return "TimeStamp("+str(self.s)+","+str(self.e)+")"
112
113
114class IPv4Port(Encodable):
115    def __init__(self,ipport): # Python tuple
116        self.ipport = ipport
117    def to_bytes(self):
118        ipbytes = socket.inet_aton(self.ipport[0])
119        portbytes = struct.pack(">H",self.ipport[1])
120        chain = [ipbytes,portbytes]
121        return "".join(chain)
122    def from_bytes(bytes):
123        ipbytes = bytes[0:4]
124        ip = socket.inet_ntoa(ipbytes)
125        portbytes = bytes[4:6]
126        [port] = struct.unpack(">H",portbytes)
127        return IPv4Port((ip,port))
128    from_bytes = staticmethod(from_bytes)
129    def get_bytes_length():
130        return 6
131    get_bytes_length = staticmethod(get_bytes_length)
132    def get_id():
133        return None
134    get_id = staticmethod(get_id)
135    def __str__(self):
136        return str(self.ipport)
137
138
139class IPv6Port(Encodable):
140    def __init__(self,ipport): # Python tuple
141        self.ipport = ipport
142    def to_bytes(self):
143        if sys.platform == "win32":
144            ipbytes = inet_pton6(self.ipport[0])
145        else:
146            ipbytes = socket.inet_pton(socket.AF_INET6, self.ipport[0])
147
148        portbytes = struct.pack(">H",self.ipport[1])
149        chain = [ipbytes,portbytes]
150        return "".join(chain)
151    def from_bytes(bytes):
152        ipbytes = bytes[0:16]
153        ip = socket.inet_ntop(socket.AF_INET6, ipbytes)
154        portbytes = bytes[16:18]
155        [port] = struct.unpack(">H",portbytes)
156        return IPv4Port((ip,port))
157    from_bytes = staticmethod(from_bytes)
158    def get_bytes_length():
159        return 18
160    get_bytes_length = staticmethod(get_bytes_length)
161    def get_id():
162        return None
163    get_id = staticmethod(get_id)
164    def __str__(self):
165        return str(self.ipport)
166
167
168# Known deficiency: don't handle :: in the middle right.
169def inet_pton6(p):
170    #print >>sys.stderr,"inet_pton: Input",p,len(p)
171    if '.' in p:
172        # IPv4 mapped
173        idx = p.rfind(':')
174        p4 = p[idx+1:]
175        n4 = socket.inet_aton(p4)
176        n = '\x00' * 10
177        n += '\xff' * 2
178        n += n4
179        #print >>sys.stderr,"inet_pton: IPv4mapped",binascii.hexlify(n)
180        return n
181
182    s = ''
183    q = p
184    sidx = len(q)
185    while sidx > 0:
186        sidx = q.rfind(':')
187        if sidx == -1:
188            sidx = -1
189        diff = len(q)-1 - sidx
190        #print >>sys.stderr,"sidx",sidx
191        elem = q[sidx+1:]
192        #print >>sys.stderr,"inet_pton: elem",elem,diff
193        if diff < 4:
194            pad = '0' * (4-diff)
195            newelem = pad+elem
196        else:
197            newelem = elem
198        s = newelem+s
199
200        #print >>sys.stderr,"inet_pton: while s",s
201        q = q[0:sidx]
202
203    if len(s) != 32:
204        diff = 32-len(s)
205        ndiff = diff / 4
206        pre = '0000' * ndiff
207        s = pre+s
208
209    #print >>sys.stderr,"inet_pton: s",s
210    return binascii.unhexlify(s)
211
212#
213# ProtocolOptions
214#
215
216POPT_VER_TYPE = '\x00'
217POPT_VER_SWIFT = '\x00'
218POPT_VER_PPSP = '\x01'
219
220POPT_MIN_VER_TYPE = '\x01'
221POPT_SWARMID_TYPE = '\x02'
222POPT_CIPM_TYPE = '\x03'
223POPT_MHF_TYPE = '\x04'
224POPT_LSA_TYPE = '\x05'
225POPT_CAM_TYPE = '\x06'
226POPT_LDW_TYPE = '\x07'
227POPT_MSGS_TYPE = '\x08'
228POPT_END_TYPE = '\xff'
229
230POPT_CIPM_NONE = '\x00'
231POPT_CIPM_MERKLE = '\x01'
232POPT_CIPM_SIGNALL = '\x02'
233POPT_CIPM_UNIFIED_MERKLE = '\x03'
234
235POPT_MHF_SHA1 = '\x00'
236POPT_MHF_SHA224 = '\x01'
237POPT_MHF_SHA256 = '\x02'
238POPT_MHF_SHA384 = '\x03'
239POPT_MHF_SHA512 = '\x04'
240
241# POPT_CHUNK_ADDR_BIN32, see CHUNK_SPEC_ID_BIN32
242
243POPT_LSA_DH = '\x02'
244POPT_LSA_DSA = '\x03'
245POPT_LSA_RSASHA1 = '\x05'
246POPT_LSA_DSA_NSEC3_SHA1 = '\x06'
247POPT_LSA_RSASHA1_NSEC3_SHA1 = '\x07'
248POPT_LSA_RSASHA256 = '\x08'
249POPT_LSA_RSASHA512 = '\x0a'
250POPT_LSA_ECC_GOST =   '\x0c'
251POPT_LSA_ECDSAP256SHA256 = '\x0d'
252POPT_LSA_ECDSAP384SHA384 = '\x0e'
253POPT_LSA_PRIVATEDNS = '\xfd'
254
255POPT_LDW_ALL_CHUNK32 = '\xff\xff\xff\xff'
256
257# SIGNPEAKTODO
258DUMMY_DEFAULT_SIG_LENGTH  = 20
259
260#
261# Messages
262#
263
264
265MSG_ID_HANDSHAKE = '\x00'
266MSG_ID_DATA = '\x01'
267MSG_ID_ACK = '\x02'
268MSG_ID_HAVE = '\x03'
269MSG_ID_INTEGRITY = '\x04'
270MSG_ID_PEX_RESv4 = '\x05'
271MSG_ID_PEX_REQ = '\x06'
272MSG_ID_SIGNED_INTEGRITY = '\x07'
273MSG_ID_REQUEST = '\x08'
274MSG_ID_CANCEL = '\x09'
275MSG_ID_CHOKE = '\x0a'
276MSG_ID_UNCHOKE = '\x0b'
277MSG_ID_PEX_RESv6 = '\x0c'
278MSG_ID_PEX_REScert = '\x0d'
279
280
281
282
283
284class HandshakeMessage(Encodable):
285    def __init__(self,chanid,ver,minver=None,swarmid=None,cipm=None,mhf=None,lsa=None,cam=None,ldw=None,msgdata=None):
286        self.chanid = chanid
287        self.ver = ver
288        self.minver = minver
289        self.swarmid = swarmid
290        self.cipm = cipm
291        self.mhf = mhf
292        self.lsa = lsa
293        self.cam = cam
294        self.ldw = ldw
295        self.msgdata = msgdata
296    def to_bytes(self):
297        chain = []
298        chain.append(HandshakeMessage.get_id())
299        chain.append(self.chanid.to_bytes())
300        if self.ver == POPT_VER_PPSP:
301            # TODO, make each ProtocolOption an Encodable
302            chain.append(POPT_VER_TYPE)
303            chain.append(self.ver)
304            if self.minver is not None:
305                chain.append(POPT_MIN_VER_TYPE)
306                chain.append(self.minver)
307            if self.swarmid is not None:
308                chain.append(POPT_SWARMID_TYPE)
309                s = len(self.swarmid)
310                sbytes = struct.pack(">H",s)
311                if len(sbytes) != 2:
312                    print >>sys.stderr,"HandshakeMessage: SWARM SIZE WRONG PACK"
313                chain.append(sbytes)
314                chain.append(self.swarmid)
315            if self.cipm is not None:
316                chain.append(POPT_CIPM_TYPE)
317                chain.append(self.cipm)
318            if self.mhf is not None:
319                chain.append(POPT_MHF_TYPE)
320                chain.append(self.mhf)
321            if self.lsa is not None:
322                chain.append(POPT_LSA_TYPE)
323                chain.append(self.lsa)
324            if self.cam is not None:
325                chain.append(POPT_CAM_TYPE)
326                chain.append(self.cam)
327            if self.ldw is not None:
328                chain.append(POPT_LDW_TYPE)
329                chain.append(self.ldw)
330            if self.msgdata is not None:
331                chain.append(POPT_MSGDATA_TYPE)
332                s = len(msgdata)
333                sbytes = struct.pack(">H",s)
334                chain.append(sbytes)
335                chain.append(self.msgdata)
336            chain.append(POPT_END_TYPE)
337        return "".join(chain)
338        #print >>sys.stderr,"HS ON THE WIRE",binascii.hexlify(ret)
339        #return ret
340
341    def from_bytes(t,bytes,off):
342        off += 1
343        chanid = ChannelID.from_bytes( bytes[off:off+ChannelID.get_bytes_length()])
344        #print >>sys.stderr,"hs:",`chanid`
345        off += chanid.get_bytes_length()
346        ver = None
347        minver = None
348        swarmid = None
349        cipm = None
350        mhf = None
351        lsa = None
352        cam = None
353        ldw = None
354        msgdata = None
355        if t.get_version() == POPT_VER_PPSP:
356            while off < len(bytes):
357                popt = bytes[off]
358
359                #print >>sys.stderr,"hs: popt is",`popt`
360                off += 1
361                if popt == POPT_VER_TYPE:
362                    ver = bytes[off]
363                    off += 1
364                elif popt == POPT_MIN_VER_TYPE:
365                    minver = bytes[off]
366                    off += 1
367                elif popt == POPT_SWARMID_TYPE:
368                    sbytes = bytes[off:off+2]
369                    off += len(sbytes)
370                    [s] = struct.unpack(">H",sbytes)
371                    swarmid = bytes[off:off+s]
372                    off += len(swarmid)
373                elif popt == POPT_CIPM_TYPE:
374                    cipm = bytes[off]
375                    off += 1
376                elif popt == POPT_MHF_TYPE:
377                    mhf = bytes[off]
378                    off += 1
379                elif popt == POPT_LSA_TYPE:
380                    lsa = bytes[off]
381                    off += 1
382                elif popt == POPT_CAM_TYPE:
383                    cam = bytes[off]
384                    off += 1
385                elif popt == POPT_LDW_TYPE:
386                    ldwsize = 8
387                    if cam == CHUNK_SPEC_ID_BIN32 or cam == CHUNK_SPEC_ID_CHUNK32:
388                        ldwsize = 4
389                    ldw = bytes[off:off+ldwsize]
390                    off += ldwsize
391                elif popt == POPT_MSGS_TYPE:
392                    sbytes = bytes[off:off+1]
393                    off += len(sbytes)
394                    [s] = struct.unpack(">H",sbytes)
395                    msgdata = bytes[off:off+s]
396                    off += len(msgdata)
397                elif popt == POPT_END_TYPE:
398                    break
399
400        return [HandshakeMessage(chanid,ver,minver,swarmid,cipm,mhf,lsa,cam,ldw,msgdata),off]
401
402    from_bytes = staticmethod(from_bytes)
403    def get_bytes_length():
404        return None # variable
405    get_bytes_length = staticmethod(get_bytes_length)
406    def get_id():
407        return MSG_ID_HANDSHAKE
408    get_id = staticmethod(get_id)
409    def __str__(self):
410        return "HANDSHAKE(ver="+`self.ver`+"minver="+`self.minver`+",sid="+`self.swarmid`+",cam="+`self.cam`+")"
411
412
413
414
415
416class DataMessage(Encodable):
417    def __init__(self,chunkspec,timestamp,chunk): # timestamp MUST be None for POPT_VER_SWIFT
418        self.chunkspec = chunkspec
419        self.ts = timestamp
420        self.chunk  = chunk
421    def to_bytes(self):
422        if self.ts is None:
423            chain = [DataMessage.get_id(),self.chunkspec.to_bytes(),self.chunk]
424        else:
425            chain = [DataMessage.get_id(),self.chunkspec.to_bytes(),self.ts.to_bytes(),self.chunk]
426        return "".join(chain)
427    def from_bytes(t,bytes,off):
428        off += 1
429        cabytes = bytes[off:off+t.get_chunkspec().get_bytes_length()]
430        off += len(cabytes)
431        chunkspec = t.chunkspec.from_bytes(cabytes)
432        tsbytes = bytes[off:off+TimeStamp.get_bytes_length()]
433        ts = TimeStamp.from_bytes(tsbytes)
434        off += len(tsbytes)
435        chunk = bytes[off:]
436        off = len(bytes)
437        return [DataMessage(chunkspec,ts,chunk),off]
438    from_bytes = staticmethod(from_bytes)
439    def get_bytes_length():
440        return None # variable
441    get_bytes_length = staticmethod(get_bytes_length)
442    def get_id():
443        return MSG_ID_DATA
444    get_id = staticmethod(get_id)
445    def __str__(self):
446        return "DATA("+`self.chunkspec`+",ts,chunk)"
447
448
449class AckMessage(Encodable):
450    def __init__(self,chunkspec,timestamp):
451        self.chunkspec = chunkspec
452        self.ts = timestamp
453    def to_bytes(self):
454        chain = [AckMessage.get_id(),self.chunkspec.to_bytes(),self.ts.to_bytes()]
455        return "".join(chain)
456    def from_bytes(t,bytes,off):
457        off += 1
458        cabytes = bytes[off:off+t.get_chunkspec().get_bytes_length()]
459        off += len(cabytes)
460        chunkspec = t.chunkspec.from_bytes(cabytes)
461        tsbytes = bytes[off:off+TimeStamp.get_bytes_length()]
462        ts = TimeStamp.from_bytes(tsbytes)
463        off += len(tsbytes)
464        return [AckMessage(chunkspec,ts),off]
465    from_bytes = staticmethod(from_bytes)
466    def get_bytes_length():
467        return None # variable due to chunkspec
468    get_bytes_length = staticmethod(get_bytes_length)
469    def get_id():
470        return MSG_ID_ACK
471    get_id = staticmethod(get_id)
472    def __str__(self):
473        return "ACK("+`self.chunkspec`+",ts)"
474
475
476class HaveMessage(Encodable):
477    def __init__(self,chunkspec):
478        self.chunkspec = chunkspec
479    def to_bytes(self):
480        chain = [HaveMessage.get_id(),self.chunkspec.to_bytes()]
481        return "".join(chain)
482    def from_bytes(t,bytes,off):
483        off += 1
484        cabytes = bytes[off:off+t.get_chunkspec().get_bytes_length()]
485        off += len(cabytes)
486        chunkspec = t.chunkspec.from_bytes(cabytes)
487        return [HaveMessage(chunkspec),off]
488    from_bytes = staticmethod(from_bytes)
489    def get_bytes_length():
490        return None # variable due to chunkspec
491    get_bytes_length = staticmethod(get_bytes_length)
492    def get_id():
493        return MSG_ID_HAVE
494    get_id = staticmethod(get_id)
495    def __str__(self):
496        return "HAVE("+`self.chunkspec`+")"
497
498
499class IntegrityMessage(Encodable):
500    def __init__(self,chunkspec,intbytes):
501        self.chunkspec = chunkspec
502        self.intbytes  = intbytes
503    def to_bytes(self):
504        chain = [IntegrityMessage.get_id(),self.chunkspec.to_bytes(),self.intbytes]
505        return "".join(chain)
506    def from_bytes(t,bytes,off):
507        off += 1
508        cabytes = bytes[off:off+t.get_chunkspec().get_bytes_length()]
509        off += len(cabytes)
510        chunkspec = t.chunkspec.from_bytes(cabytes)
511        intbytes = bytes[off:off+t.get_hash_length()]
512        off += len(intbytes)
513        return [IntegrityMessage(chunkspec,intbytes),off]
514    from_bytes = staticmethod(from_bytes)
515    def get_bytes_length():
516        return None # variable
517    get_bytes_length = staticmethod(get_bytes_length)
518    def get_id():
519        return MSG_ID_INTEGRITY
520    get_id = staticmethod(get_id)
521    def __str__(self):
522        return "INTEGRITY("+`self.chunkspec`+",intbytes)"
523
524class PexResv4Message(Encodable):
525    def __init__(self,ipp):
526        self.ipp = ipp
527    def to_bytes(self):
528        chain = [PexResv4Message.get_id(),self.ipp.to_bytes()]
529        return "".join(chain)
530    def from_bytes(t,bytes,off):
531        off += 1
532        ippbytes = bytes[off:off+IPv4Port.get_bytes_length()]
533        off += len(ippbytes)
534        ipp = IPv4Port.from_bytes(ippbytes)
535        return [PexResv4Message(ipp),off]
536    from_bytes = staticmethod(from_bytes)
537    def get_bytes_length():
538        return None # variable due to chunkspec
539    get_bytes_length = staticmethod(get_bytes_length)
540    def get_id():
541        return MSG_ID_PEX_RESv4
542    get_id = staticmethod(get_id)
543    def __str__(self):
544        return "PEX_RESv4("+`self.ipp`+")"
545
546class PexReqMessage(Encodable):
547    def __init__(self):
548        pass
549    def to_bytes(self):
550        chain = [PexReqMessage.get_id()]
551        return "".join(chain)
552    def from_bytes(t,bytes,off):
553        off += 1
554        return [PexReqMessage(),off]
555    from_bytes = staticmethod(from_bytes)
556    def get_bytes_length():
557        return 1 # just MSG_ID
558    get_bytes_length = staticmethod(get_bytes_length)
559    def get_id():
560        return MSG_ID_PEX_REQ
561    get_id = staticmethod(get_id)
562    def __str__(self):
563        return "PEX_REQ()"
564
565
566class SignedIntegrityMessage(Encodable):
567    def __init__(self,t,chunkspec,timestamp,intbytes):
568        self.chunkspec = chunkspec
569        self.timestamp = timestamp
570        self.intbytes  = intbytes
571    def to_bytes(self):
572        chain = [SignedIntegrity.get_id(),self.chunkspec.to_bytes(),self.timestamp,self.intbytes]
573        return "".join(chain)
574    def from_bytes(t,bytes,off):
575        off += 1
576        cabytes = bytes[off:off+t.get_chunkspec().get_bytes_length()]
577        off += len(cabytes)
578        chunkspec = t.chunkspec.from_bytes(cabytes)
579        timestamp = bytes[off:off+8]
580        off += 8
581        if t.lsa == POPT_LSA_ECDSAP256SHA256:
582            siglen = 64
583        elif t.lsa == POPT_LSA_ECDSAP384SHA384:
584            siglen = 96
585        else:
586            print >>sys.stderr,"swiftconn: SignedIntegrityMessage: LSA not implemented",ord(t.lsa)
587            os._exit(-1)
588        intbytes = bytes[off:off+siglen]
589        off += len(intbytes)
590        return [SignedIntegrityMessage(t,chunkspec,timestamp,intbytes),off]
591    from_bytes = staticmethod(from_bytes)
592    def get_bytes_length():
593        return None # variable
594    get_bytes_length = staticmethod(get_bytes_length)
595    def get_id():
596        return MSG_ID_SIGNED_INTEGRITY
597    get_id = staticmethod(get_id)
598    def __str__(self):
599        return "SIGNED_INTEGRITY("+`self.chunkspec`+",intbytes)"
600
601
602class RequestMessage(Encodable):
603    def __init__(self,chunkspec):
604        self.chunkspec = chunkspec
605    def to_bytes(self):
606        chain = [RequestMessage.get_id(),self.chunkspec.to_bytes()]
607        return "".join(chain)
608    def from_bytes(t,bytes,off):
609        off += 1
610        cabytes = bytes[off:off+t.get_chunkspec().get_bytes_length()]
611        off += len(cabytes)
612        chunkspec = t.chunkspec.from_bytes(cabytes)
613        return [RequestMessage(chunkspec),off]
614    from_bytes = staticmethod(from_bytes)
615    def get_bytes_length():
616        return None # variable due to chunkspec
617    get_bytes_length = staticmethod(get_bytes_length)
618    def get_id():
619        return MSG_ID_REQUEST
620    get_id = staticmethod(get_id)
621    def __str__(self):
622        return "REQUEST("+`self.chunkspec`+")"
623
624class CancelMessage(Encodable):
625    def __init__(self,chunkspec):
626        self.chunkspec = chunkspec
627    def to_bytes(self):
628        chain = [CancelMessage.get_id(),self.chunkspec.to_bytes()]
629        return "".join(chain)
630    def from_bytes(t,bytes,off):
631        off += 1
632        cabytes = bytes[off:off+t.get_chunkspec().get_bytes_length()]
633        off += len(cabytes)
634        chunkspec = t.chunkspec.from_bytes(cabytes)
635        return [CancelMessage(chunkspec),off]
636    from_bytes = staticmethod(from_bytes)
637    def get_bytes_length():
638        return None # variable due to chunkspec
639    get_bytes_length = staticmethod(get_bytes_length)
640    def get_id():
641        return MSG_ID_CANCEL
642    get_id = staticmethod(get_id)
643    def __str__(self):
644        return "CANCEL("+`self.chunkspec`+")"
645
646
647class ChokeMessage(Encodable):
648    def __init__(self):
649        pass
650    def to_bytes(self):
651        chain = [ChokeMessage.get_id()]
652        return "".join(chain)
653    def from_bytes(t,bytes,off):
654        off += 1
655        return [ChokeMessage(),off]
656    from_bytes = staticmethod(from_bytes)
657    def get_bytes_length():
658        return 1 # just MSG_ID
659    get_bytes_length = staticmethod(get_bytes_length)
660    def get_id():
661        return MSG_ID_CHOKE
662    get_id = staticmethod(get_id)
663    def __str__(self):
664        return "CHOKE()"
665
666
667class UnchokeMessage(Encodable):
668    def __init__(self):
669        pass
670    def to_bytes(self):
671        chain = [UnchokeMessage.get_id()]
672        return "".join(chain)
673    def from_bytes(t,bytes,off):
674        off += 1
675        return [UnchokeMessage(),off]
676    from_bytes = staticmethod(from_bytes)
677    def get_bytes_length():
678        return 1 # just MSG_ID
679    get_bytes_length = staticmethod(get_bytes_length)
680    def get_id():
681        return MSG_ID_UNCHOKE
682    get_id = staticmethod(get_id)
683    def __str__(self):
684        return "UNCHOKE()"
685
686
687
688class PexResv6Message(Encodable):
689    def __init__(self,ipp):
690        self.ipp = ipp
691    def to_bytes(self):
692        chain = [PexResv6Message.get_id(),self.ipp.to_bytes()]
693        return "".join(chain)
694    def from_bytes(t,bytes,off):
695        ippbytes = bytes[off:off+IPv6Port.get_bytes_length()]
696        off += len(ippbytes)
697        ipp = IPv6Port.from_bytes(cabytes)
698        return [PexResv6Message(ipp),off]
699    from_bytes = staticmethod(from_bytes)
700    def get_bytes_length():
701        return None # variable due to chunkspec
702    get_bytes_length = staticmethod(get_bytes_length)
703    def get_id():
704        return MSG_ID_PEX_RESv6
705    get_id = staticmethod(get_id)
706    def __str__(self):
707        return "PEX_RESv6("+`self.ipp`+")"
708
709
710class PexResCertMessage(Encodable):
711    def __init__(self,certbytes):
712        self.certbytes = certbytes
713    def to_bytes(self):
714        sbytes = struct.pack(">H",len(self.certbytes))
715        chain = [PexResCertMessage.get_id(),sbytes,self.certbytes]
716        return "".join(chain)
717    def from_bytes(t,bytes,off):
718        sbytes = bytes[off:off+1]
719        off += len(sbytes)
720        [s] = struct.unpack(">H",sbytes)
721        certbytes = bytes[2:2+s]
722        off += len(certbytes)
723        return [PexRescertMessage(certbytes),off]
724    from_bytes = staticmethod(from_bytes)
725    def get_bytes_length():
726        return None # variable due to certificate
727    get_bytes_length = staticmethod(get_bytes_length)
728    def get_id():
729        return MSG_ID_PEX_REScert
730    get_id = staticmethod(get_id)
731    def __str__(self):
732        return "PEX_REScert(cert)"
733
734
735class KeepAliveMessage(Encodable):
736    def __init__(self):
737        pass
738    def to_bytes(self):
739        return ""
740    def from_bytes(t,bytes,off):
741        return [KeepAliveMessage(),off]
742    from_bytes = staticmethod(from_bytes)
743    def get_bytes_length():
744        return 0
745    get_bytes_length = staticmethod(get_bytes_length)
746    def get_id():
747        return -1
748    get_id = staticmethod(get_id)
749    def __str__(self):
750        return "KEEPALIVE"
751
752
753#
754# Transfer
755#
756
757
758class Transfer:
759
760    def __init__(self,swarmid,version,chunkspec,cipm,lsa,socket):
761        self.swarmid = swarmid
762        self.version = version
763        self.chunkspec = chunkspec
764        self.cipm = cipm
765        self.lsa = lsa
766        self.socket = socket
767
768    def get_swarm_id(self):
769        return self.swarmid
770
771    def get_version(self):
772        return self.version
773
774    def get_hash_length(self):
775        return len(HASH_ZERO)
776
777    def get_chunkspec(self):
778        return self.chunkspec
779
780    def get_socket(self):
781        return self.socket
782
783
784
785class ChannelID(Encodable):
786    def __init__(self,id):
787        self.id = id
788    def to_bytes(self):
789        return self.id
790    def from_bytes(bytes):
791        id = bytes[0:4]
792        return ChannelID(id)
793    from_bytes = staticmethod(from_bytes)
794    def get_bytes_length():
795        return 4
796    get_bytes_length = staticmethod(get_bytes_length)
797    def get_id():
798        return None
799    get_id = staticmethod(get_id)
800    def __str__(self):
801        return "ChannelID("+`self.id`+")"
802
803
804#
805# Datagram
806#
807
808class Datagram(Encodable):
809    """ Serialization """
810    def __init__(self,t=None,data=None):
811        self.t = t
812        if data is None: # send
813            self.chain = []
814        else:
815            self.data = data
816            self.off = 0
817
818    def set_t(self,t):
819        self.t = t
820
821    def add(self,e):
822        self.chain.append(e)
823
824    def to_bytes(self):
825        wire = ''
826        for e in self.chain:
827            #print >>sys.stderr,"dgram: Add",`e`
828            wire += e.to_bytes()
829        return wire
830
831    def get_channel_id(self):
832        #print >>sys.stderr,"dgram: get_channel_id"
833        x = ChannelID.from_bytes( self.data[0:ChannelID.get_bytes_length()])
834        self.off += ChannelID.get_bytes_length()
835        return x
836
837    def get_message(self):
838        if self.off == len(self.data):
839            return None
840
841        msgid = self.data[self.off:self.off+len(MSG_ID_HANDSHAKE)]
842        print >>sys.stderr,"dgram: get_message: GOT msgid",`msgid`,"off",self.off
843
844        if msgid == MSG_ID_HANDSHAKE:
845            [msg,self.off] = HandshakeMessage.from_bytes(self.t,self.data,self.off)
846        elif msgid == MSG_ID_DATA:
847            [msg,self.off] = DataMessage.from_bytes(self.t,self.data,self.off)
848        elif msgid == MSG_ID_ACK:
849            [msg,self.off] = AckMessage.from_bytes(self.t,self.data,self.off)
850        elif msgid == MSG_ID_HAVE:
851            [msg,self.off] = HaveMessage.from_bytes(self.t,self.data,self.off)
852        elif msgid == MSG_ID_INTEGRITY:
853            [msg,self.off] = IntegrityMessage.from_bytes(self.t,self.data,self.off)
854        elif msgid == MSG_ID_PEX_RESv4:
855            [msg,self.off] = PexResv4Message.from_bytes(self.t,self.data,self.off)
856        elif msgid == MSG_ID_PEX_REQ:
857            [msg,self.off] = PexReqMessage.from_bytes(self.t,self.data,self.off)
858        elif msgid == MSG_ID_SIGNED_INTEGRITY:
859            [msg,self.off] = SignedIntegrityMessage.from_bytes(self.t,self.data,self.off)
860        elif msgid == MSG_ID_REQUEST:
861            [msg,self.off] = RequestMessage.from_bytes(self.t,self.data,self.off)
862        elif msgid == MSG_ID_CANCEL:
863            [msg,self.off] = CancelMessage.from_bytes(self.t,self.data,self.off)
864        elif msgid == MSG_ID_CHOKE:
865            [msg,self.off] = ChokeMessage.from_bytes(self.t,self.data,self.off)
866        elif msgid == MSG_ID_UNCHOKE:
867            [msg,self.off] = UnchokeMessage.from_bytes(self.t,self.data,self.off)
868        elif msgid == MSG_ID_PEX_RESv6:
869            [msg,self.off] = PexResv6Message.from_bytes(self.t,self.data,self.off)
870        elif msgid == MSG_ID_PEX_REScert:
871            [msg,self.off] = PexRescertMessage.from_bytes(self.t,self.data,self.off)
872        else:
873            print >>sys.stderr,"dgram: get_message: unknown msgid",`msgid`,"off",self.off,"bytes left",len(self.data)-self.off
874            msg = None
875        return msg
876
877
878CONN_STATE_INIT = 0
879CONN_STATE_WAIT4HIS = 1
880CONN_STATE_WAIT4MINE = 2
881CONN_STATE_ESTABLISHED = 3
882
883CHAN_ID_ZERO = ChannelID.from_bytes('\x00' * 4)
884
885
886DGRAM_MAX_RECV = 65536
887
888class Channel:
889    def __init__(self,t,addr,localinit):
890        self.t = t
891        self.addr = addr
892        self.localinit = localinit
893        self.mychanid = ChannelID.from_bytes('6778')
894        self.hischanid = CHAN_ID_ZERO
895
896    def send(self,d):
897        self.t.get_socket().sendto(d,self.addr)
898
899    def recv(self,d):
900        while True:
901            msg = d.get_message()
902            if msg is None:
903                break
904            print >>sys.stderr,"chan: Parsed",`msg`
905            if msg.get_id() == MSG_ID_HANDSHAKE:
906                self.hischanid = msg.chanid
907
908    def get_my_chanid(self):
909        return self.mychanid
910
911    def get_his_chanid(self):
912        return self.hischanid
913
914    def set_his_chanid(self,chanid):
915        self.hischanid = chanid
916
917
918
919class Socket:
920    def __init__(self,myaddr,family=socket.AF_INET):
921        self.myaddr = myaddr
922        socket.setdefaulttimeout(10.0)
923        self.sock = socket.socket(family, socket.SOCK_DGRAM)
924        print >>sys.stderr,"Socket: __init__: bind",myaddr,family
925        self.sock.bind(myaddr)
926
927    def recv(self):
928        [data,addr] = self.sock.recvfrom(DGRAM_MAX_RECV)
929        print >>sys.stderr,"Socket: recv len",len(data)
930
931        return [addr,Datagram(None,data)]
932
933    def sendto(self,d,addr):
934        data = d.to_bytes()
935        return self.sock.sendto(data,addr)
936
937    def listen(self,swarmid,autochanid=True,hs=True):
938        [addr,d] = self.recv()
939        s = SwiftConnection(self.myaddr,addr,swarmid,listensock=self,hs=hs)
940        if autochanid:
941            chanid = d.get_channel_id()
942            print >>sys.stderr,"Socket: listen: Got ChannelID",`chanid`
943        d.set_t(s.t)
944        return [s,d]
945
946
947class SwiftConnection:
948    def __init__(self,myaddr,hisaddr,swarmid,listensock=None,hs=True,ver=POPT_VER_PPSP,minver=POPT_VER_PPSP,cipm=POPT_CIPM_MERKLE,mhf=POPT_MHF_SHA1,lsa=None,cam=CHUNK_SPEC_ID_CHUNK32,ldw=None,msgdata=None,chunkspec=ChunkRange(0,0)):
949
950        if listensock is None:
951            self.s = Socket(myaddr)
952        else:
953            self.s = listensock
954        #t = Transfer(swarmid,POPT_VER_PPSP,BIN_ALL,self.s)
955        self.t = Transfer(swarmid,ver,chunkspec,cipm,lsa,self.s)
956        self.c = Channel(self.t,hisaddr,listensock is None)
957
958        if hs:
959            d = Datagram(self.t)
960            if self.t.version == POPT_VER_SWIFT:
961                d.add( self.c.get_his_chanid() )
962                d.add( IntegrityMessage(BIN_ALL,self.t.get_swarm_id()) )
963                d.add( HandshakeMessage(self.c.get_my_chanid(),POPT_VER_SWIFT) )
964                self.c.send(d)
965            else:
966                d.add( self.c.get_his_chanid() )
967                d.add( HandshakeMessage(self.c.get_my_chanid(),ver=ver,minver=minver,swarmid=self.t.get_swarm_id(),cipm=cipm,mhf=mhf,lsa=lsa,cam=cam,ldw=ldw,msgdata=msgdata) )
968                self.c.send(d)
969
970    def makeDatagram(self,autochanid=True):
971        d = Datagram(self.t)
972        if autochanid:
973            d.add( self.c.get_his_chanid() )
974        return d
975
976    def send(self,d):
977        self.c.send(d)
978
979    def recv(self,autochanid=True):
980        [addr,d] = self.s.recv()
981        d.set_t(self.t)
982        if autochanid:
983            chanid = d.get_channel_id()
984        return d
985
986
987
988if __name__ == "__main__":
989
990    x = inet_pton6("::1")
991    print >>sys.stderr,"FINAL",`x`
992
993    #x = inet_pton6("2001:0:5ef5:79fb:385c:2235:3f57:ff99")
994    #print >>sys.stderr,"FINAL",`x`
995
996    #x = inet_pton6("fe80::385c:2235:3f57:ff99")
997    #print >>sys.stderr,"FINAL",x
998
999    #x = inet_pton6("::ffff:130.37.193.64")
1000    #print >>sys.stderr,"FINAL",x
1001
1002
1003