instrumentation: add next-share/
[cs-p2p-next.git] / instrumentation / next-share / BaseLib / Core / BitTornado / BT1 / btformats.py
1 # Written by Bram Cohen
2 # see LICENSE.txt for license information
3
4 import sys
5 from types import UnicodeType, StringType, LongType, IntType, ListType, DictType
6 from re import compile
7
8 #reg = compile(r'^[^/\\.~][^/\\]*$')
9 #reg = compile(r'^[^/\\]*$')
10
11 ints = (LongType, IntType)
12
13 def check_info(info):
14     if type(info) != DictType:
15         raise ValueError, 'bad metainfo - not a dictionary'
16
17     if info.has_key('pieces'):
18         pieces = info.get('pieces')
19         if type(pieces) != StringType or len(pieces) % 20 != 0:
20             raise ValueError, 'bad metainfo - bad pieces key'
21     elif info.has_key('root hash'):
22         # Merkle
23         root_hash = info.get('root hash')
24         if type(root_hash) != StringType or len(root_hash) != 20:
25             raise ValueError, 'bad metainfo - bad root hash key'
26     piecelength = info.get('piece length')
27     if type(piecelength) not in ints or piecelength <= 0:
28         raise ValueError, 'bad metainfo - illegal piece length'
29     name = info.get('name')
30     if StringType != type(name) != UnicodeType:
31         raise ValueError, 'bad metainfo - bad name'
32     #if not reg.match(name):
33     #    raise ValueError, 'name %s disallowed for security reasons' % name
34     if info.has_key('files') == info.has_key('length'):
35         raise ValueError, 'single/multiple file mix'
36     if info.has_key('length'):
37         length = info.get('length')
38         if type(length) not in ints or length < 0:
39             raise ValueError, 'bad metainfo - bad length'
40     else:
41         files = info.get('files')
42         if type(files) != ListType:
43             raise ValueError
44         for f in files:
45             if type(f) != DictType:
46                 raise ValueError, 'bad metainfo - bad file value'
47             length = f.get('length')
48             if type(length) not in ints or length < 0:
49                 raise ValueError, 'bad metainfo - bad length'
50             path = f.get('path')
51             if type(path) != ListType or path == []:
52                 raise ValueError, 'bad metainfo - bad path'
53             for p in path:
54                 if StringType != type(p) != UnicodeType:
55                     raise ValueError, 'bad metainfo - bad path dir'
56                 #if not reg.match(p):
57                 #    raise ValueError, 'path %s disallowed for security reasons' % p
58         for i in xrange(len(files)):
59             for j in xrange(i):
60                 if files[i]['path'] == files[j]['path']:
61                     raise ValueError, 'bad metainfo - duplicate path'
62
63 def check_message(message):
64     if type(message) != DictType:
65         raise ValueError
66     check_info(message.get('info'))
67     if StringType != type(message.get('announce')) != UnicodeType:
68         raise ValueError
69
70 def check_peers(message):
71     if type(message) != DictType:
72         raise ValueError
73     if message.has_key('failure reason'):
74         if type(message['failure reason']) != StringType:
75             raise ValueError
76         return
77     peers = message.get('peers')
78     if peers is not None:
79         if type(peers) == ListType:
80             for p in peers:
81                 if type(p) != DictType:
82                     raise ValueError
83                 if type(p.get('ip')) != StringType:
84                     raise ValueError
85                 port = p.get('port')
86                 if type(port) not in ints or p <= 0:
87                     raise ValueError
88                 if p.has_key('peer id'):
89                     id = p['peer id']
90                     if type(id) != StringType or len(id) != 20:
91                         raise ValueError
92         elif type(peers) != StringType or len(peers) % 6 != 0:
93             raise ValueError
94         
95     # IPv6 Tracker extension. http://www.bittorrent.org/beps/bep_0007.html
96     peers6 = message.get('peers6')
97     if peers6 is not None:
98         if type(peers6) == ListType:
99             for p in peers6:
100                 if type(p) != DictType:
101                     raise ValueError
102                 if type(p.get('ip')) != StringType:
103                     raise ValueError
104                 port = p.get('port')
105                 if type(port) not in ints or p <= 0:
106                     raise ValueError
107                 if p.has_key('peer id'):
108                     id = p['peer id']
109                     if type(id) != StringType or len(id) != 20:
110                         raise ValueError
111         elif type(peers6) != StringType or len(peers6) % 18 != 0:
112             raise ValueError 
113         
114     interval = message.get('interval', 1)
115     if type(interval) not in ints or interval <= 0:
116         raise ValueError
117     minint = message.get('min interval', 1)
118     if type(minint) not in ints or minint <= 0:
119         raise ValueError
120     if type(message.get('tracker id', '')) != StringType:
121         raise ValueError
122     npeers = message.get('num peers', 0)
123     if type(npeers) not in ints or npeers < 0:
124         raise ValueError
125     dpeers = message.get('done peers', 0)
126     if type(dpeers) not in ints or dpeers < 0:
127         raise ValueError
128     last = message.get('last', 0)
129     if type(last) not in ints or last < 0:
130         raise ValueError