murder 0.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/LICENSE +17 -0
- data/README +224 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/dist/BitTornado/BT1/Choker.py +128 -0
- data/dist/BitTornado/BT1/Connecter.py +288 -0
- data/dist/BitTornado/BT1/Downloader.py +594 -0
- data/dist/BitTornado/BT1/DownloaderFeedback.py +155 -0
- data/dist/BitTornado/BT1/Encrypter.py +333 -0
- data/dist/BitTornado/BT1/FileSelector.py +245 -0
- data/dist/BitTornado/BT1/Filter.py +12 -0
- data/dist/BitTornado/BT1/HTTPDownloader.py +251 -0
- data/dist/BitTornado/BT1/NatCheck.py +95 -0
- data/dist/BitTornado/BT1/PiecePicker.py +320 -0
- data/dist/BitTornado/BT1/Rerequester.py +426 -0
- data/dist/BitTornado/BT1/Statistics.py +177 -0
- data/dist/BitTornado/BT1/Storage.py +584 -0
- data/dist/BitTornado/BT1/StorageWrapper.py +1045 -0
- data/dist/BitTornado/BT1/StreamCheck.py +135 -0
- data/dist/BitTornado/BT1/T2T.py +193 -0
- data/dist/BitTornado/BT1/Uploader.py +145 -0
- data/dist/BitTornado/BT1/__init__.py +1 -0
- data/dist/BitTornado/BT1/btformats.py +100 -0
- data/dist/BitTornado/BT1/fakeopen.py +89 -0
- data/dist/BitTornado/BT1/makemetafile.py +263 -0
- data/dist/BitTornado/BT1/track.py +1067 -0
- data/dist/BitTornado/ConfigDir.py +401 -0
- data/dist/BitTornado/ConfigReader.py +1068 -0
- data/dist/BitTornado/ConnChoice.py +31 -0
- data/dist/BitTornado/CreateIcons.py +105 -0
- data/dist/BitTornado/CurrentRateMeasure.py +37 -0
- data/dist/BitTornado/HTTPHandler.py +167 -0
- data/dist/BitTornado/PSYCO.py +5 -0
- data/dist/BitTornado/RateLimiter.py +153 -0
- data/dist/BitTornado/RateMeasure.py +75 -0
- data/dist/BitTornado/RawServer.py +195 -0
- data/dist/BitTornado/ServerPortHandler.py +188 -0
- data/dist/BitTornado/SocketHandler.py +375 -0
- data/dist/BitTornado/__init__.py +63 -0
- data/dist/BitTornado/bencode.py +319 -0
- data/dist/BitTornado/bitfield.py +162 -0
- data/dist/BitTornado/clock.py +27 -0
- data/dist/BitTornado/download_bt1.py +882 -0
- data/dist/BitTornado/inifile.py +169 -0
- data/dist/BitTornado/iprangeparse.py +194 -0
- data/dist/BitTornado/launchmanycore.py +381 -0
- data/dist/BitTornado/natpunch.py +254 -0
- data/dist/BitTornado/parseargs.py +137 -0
- data/dist/BitTornado/parsedir.py +150 -0
- data/dist/BitTornado/piecebuffer.py +86 -0
- data/dist/BitTornado/selectpoll.py +109 -0
- data/dist/BitTornado/subnetparse.py +218 -0
- data/dist/BitTornado/torrentlistparse.py +38 -0
- data/dist/BitTornado/zurllib.py +100 -0
- data/dist/murder_client.py +291 -0
- data/dist/murder_make_torrent.py +46 -0
- data/dist/murder_tracker.py +28 -0
- data/doc/examples/Capfile +28 -0
- data/lib/capistrano/recipes/deploy/strategy/murder.rb +52 -0
- data/lib/murder.rb +43 -0
- data/lib/murder/admin.rb +47 -0
- data/lib/murder/murder.rb +121 -0
- data/murder.gemspec +101 -0
- metadata +129 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
# Written by John Hoffman
|
2
|
+
# see LICENSE.txt for license information
|
3
|
+
|
4
|
+
from array import array
|
5
|
+
from threading import Lock
|
6
|
+
# import inspect
|
7
|
+
try:
|
8
|
+
True
|
9
|
+
except:
|
10
|
+
True = 1
|
11
|
+
False = 0
|
12
|
+
|
13
|
+
DEBUG = False
|
14
|
+
|
15
|
+
class SingleBuffer:
|
16
|
+
def __init__(self, pool):
|
17
|
+
self.pool = pool
|
18
|
+
self.buf = array('c')
|
19
|
+
|
20
|
+
def init(self):
|
21
|
+
if DEBUG:
|
22
|
+
print self.count
|
23
|
+
'''
|
24
|
+
for x in xrange(6,1,-1):
|
25
|
+
try:
|
26
|
+
f = inspect.currentframe(x).f_code
|
27
|
+
print (f.co_filename,f.co_firstlineno,f.co_name)
|
28
|
+
del f
|
29
|
+
except:
|
30
|
+
pass
|
31
|
+
print ''
|
32
|
+
'''
|
33
|
+
self.length = 0
|
34
|
+
|
35
|
+
def append(self, s):
|
36
|
+
l = self.length+len(s)
|
37
|
+
self.buf[self.length:l] = array('c',s)
|
38
|
+
self.length = l
|
39
|
+
|
40
|
+
def __len__(self):
|
41
|
+
return self.length
|
42
|
+
|
43
|
+
def __getslice__(self, a, b):
|
44
|
+
if b > self.length:
|
45
|
+
b = self.length
|
46
|
+
if b < 0:
|
47
|
+
b += self.length
|
48
|
+
if a == 0 and b == self.length and len(self.buf) == b:
|
49
|
+
return self.buf # optimization
|
50
|
+
return self.buf[a:b]
|
51
|
+
|
52
|
+
def getarray(self):
|
53
|
+
return self.buf[:self.length]
|
54
|
+
|
55
|
+
def release(self):
|
56
|
+
if DEBUG:
|
57
|
+
print -self.count
|
58
|
+
self.pool.release(self)
|
59
|
+
|
60
|
+
|
61
|
+
class BufferPool:
|
62
|
+
def __init__(self):
|
63
|
+
self.pool = []
|
64
|
+
self.lock = Lock()
|
65
|
+
if DEBUG:
|
66
|
+
self.count = 0
|
67
|
+
|
68
|
+
def new(self):
|
69
|
+
self.lock.acquire()
|
70
|
+
if self.pool:
|
71
|
+
x = self.pool.pop()
|
72
|
+
else:
|
73
|
+
x = SingleBuffer(self)
|
74
|
+
if DEBUG:
|
75
|
+
self.count += 1
|
76
|
+
x.count = self.count
|
77
|
+
x.init()
|
78
|
+
self.lock.release()
|
79
|
+
return x
|
80
|
+
|
81
|
+
def release(self, x):
|
82
|
+
self.pool.append(x)
|
83
|
+
|
84
|
+
|
85
|
+
_pool = BufferPool()
|
86
|
+
PieceBuffer = _pool.new
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# Written by Bram Cohen
|
2
|
+
# see LICENSE.txt for license information
|
3
|
+
|
4
|
+
from select import select, error
|
5
|
+
from time import sleep
|
6
|
+
from types import IntType
|
7
|
+
from bisect import bisect
|
8
|
+
POLLIN = 1
|
9
|
+
POLLOUT = 2
|
10
|
+
POLLERR = 8
|
11
|
+
POLLHUP = 16
|
12
|
+
|
13
|
+
class poll:
|
14
|
+
def __init__(self):
|
15
|
+
self.rlist = []
|
16
|
+
self.wlist = []
|
17
|
+
|
18
|
+
def register(self, f, t):
|
19
|
+
if type(f) != IntType:
|
20
|
+
f = f.fileno()
|
21
|
+
if (t & POLLIN):
|
22
|
+
insert(self.rlist, f)
|
23
|
+
else:
|
24
|
+
remove(self.rlist, f)
|
25
|
+
if (t & POLLOUT):
|
26
|
+
insert(self.wlist, f)
|
27
|
+
else:
|
28
|
+
remove(self.wlist, f)
|
29
|
+
|
30
|
+
def unregister(self, f):
|
31
|
+
if type(f) != IntType:
|
32
|
+
f = f.fileno()
|
33
|
+
remove(self.rlist, f)
|
34
|
+
remove(self.wlist, f)
|
35
|
+
|
36
|
+
def poll(self, timeout = None):
|
37
|
+
if self.rlist or self.wlist:
|
38
|
+
try:
|
39
|
+
r, w, e = select(self.rlist, self.wlist, [], timeout)
|
40
|
+
except ValueError:
|
41
|
+
return None
|
42
|
+
else:
|
43
|
+
sleep(timeout)
|
44
|
+
return []
|
45
|
+
result = []
|
46
|
+
for s in r:
|
47
|
+
result.append((s, POLLIN))
|
48
|
+
for s in w:
|
49
|
+
result.append((s, POLLOUT))
|
50
|
+
return result
|
51
|
+
|
52
|
+
def remove(list, item):
|
53
|
+
i = bisect(list, item)
|
54
|
+
if i > 0 and list[i-1] == item:
|
55
|
+
del list[i-1]
|
56
|
+
|
57
|
+
def insert(list, item):
|
58
|
+
i = bisect(list, item)
|
59
|
+
if i == 0 or list[i-1] != item:
|
60
|
+
list.insert(i, item)
|
61
|
+
|
62
|
+
def test_remove():
|
63
|
+
x = [2, 4, 6]
|
64
|
+
remove(x, 2)
|
65
|
+
assert x == [4, 6]
|
66
|
+
x = [2, 4, 6]
|
67
|
+
remove(x, 4)
|
68
|
+
assert x == [2, 6]
|
69
|
+
x = [2, 4, 6]
|
70
|
+
remove(x, 6)
|
71
|
+
assert x == [2, 4]
|
72
|
+
x = [2, 4, 6]
|
73
|
+
remove(x, 5)
|
74
|
+
assert x == [2, 4, 6]
|
75
|
+
x = [2, 4, 6]
|
76
|
+
remove(x, 1)
|
77
|
+
assert x == [2, 4, 6]
|
78
|
+
x = [2, 4, 6]
|
79
|
+
remove(x, 7)
|
80
|
+
assert x == [2, 4, 6]
|
81
|
+
x = [2, 4, 6]
|
82
|
+
remove(x, 5)
|
83
|
+
assert x == [2, 4, 6]
|
84
|
+
x = []
|
85
|
+
remove(x, 3)
|
86
|
+
assert x == []
|
87
|
+
|
88
|
+
def test_insert():
|
89
|
+
x = [2, 4]
|
90
|
+
insert(x, 1)
|
91
|
+
assert x == [1, 2, 4]
|
92
|
+
x = [2, 4]
|
93
|
+
insert(x, 3)
|
94
|
+
assert x == [2, 3, 4]
|
95
|
+
x = [2, 4]
|
96
|
+
insert(x, 5)
|
97
|
+
assert x == [2, 4, 5]
|
98
|
+
x = [2, 4]
|
99
|
+
insert(x, 2)
|
100
|
+
assert x == [2, 4]
|
101
|
+
x = [2, 4]
|
102
|
+
insert(x, 4)
|
103
|
+
assert x == [2, 4]
|
104
|
+
x = [2, 3, 4]
|
105
|
+
insert(x, 3)
|
106
|
+
assert x == [2, 3, 4]
|
107
|
+
x = []
|
108
|
+
insert(x, 3)
|
109
|
+
assert x == [3]
|
@@ -0,0 +1,218 @@
|
|
1
|
+
# Written by John Hoffman
|
2
|
+
# see LICENSE.txt for license information
|
3
|
+
|
4
|
+
from bisect import bisect, insort
|
5
|
+
|
6
|
+
try:
|
7
|
+
True
|
8
|
+
except:
|
9
|
+
True = 1
|
10
|
+
False = 0
|
11
|
+
bool = lambda x: not not x
|
12
|
+
|
13
|
+
hexbinmap = {
|
14
|
+
'0': '0000',
|
15
|
+
'1': '0001',
|
16
|
+
'2': '0010',
|
17
|
+
'3': '0011',
|
18
|
+
'4': '0100',
|
19
|
+
'5': '0101',
|
20
|
+
'6': '0110',
|
21
|
+
'7': '0111',
|
22
|
+
'8': '1000',
|
23
|
+
'9': '1001',
|
24
|
+
'a': '1010',
|
25
|
+
'b': '1011',
|
26
|
+
'c': '1100',
|
27
|
+
'd': '1101',
|
28
|
+
'e': '1110',
|
29
|
+
'f': '1111',
|
30
|
+
'x': '0000',
|
31
|
+
}
|
32
|
+
|
33
|
+
chrbinmap = {}
|
34
|
+
for n in xrange(256):
|
35
|
+
b = []
|
36
|
+
nn = n
|
37
|
+
for i in xrange(8):
|
38
|
+
if nn & 0x80:
|
39
|
+
b.append('1')
|
40
|
+
else:
|
41
|
+
b.append('0')
|
42
|
+
nn <<= 1
|
43
|
+
chrbinmap[n] = ''.join(b)
|
44
|
+
|
45
|
+
|
46
|
+
def to_bitfield_ipv4(ip):
|
47
|
+
ip = ip.split('.')
|
48
|
+
if len(ip) != 4:
|
49
|
+
raise ValueError, "bad address"
|
50
|
+
b = []
|
51
|
+
for i in ip:
|
52
|
+
b.append(chrbinmap[int(i)])
|
53
|
+
return ''.join(b)
|
54
|
+
|
55
|
+
def to_bitfield_ipv6(ip):
|
56
|
+
b = ''
|
57
|
+
doublecolon = False
|
58
|
+
|
59
|
+
if ip == '':
|
60
|
+
raise ValueError, "bad address"
|
61
|
+
if ip == '::': # boundary handling
|
62
|
+
ip = ''
|
63
|
+
elif ip[:2] == '::':
|
64
|
+
ip = ip[1:]
|
65
|
+
elif ip[0] == ':':
|
66
|
+
raise ValueError, "bad address"
|
67
|
+
elif ip[-2:] == '::':
|
68
|
+
ip = ip[:-1]
|
69
|
+
elif ip[-1] == ':':
|
70
|
+
raise ValueError, "bad address"
|
71
|
+
for n in ip.split(':'):
|
72
|
+
if n == '': # double-colon
|
73
|
+
if doublecolon:
|
74
|
+
raise ValueError, "bad address"
|
75
|
+
doublecolon = True
|
76
|
+
b += ':'
|
77
|
+
continue
|
78
|
+
if n.find('.') >= 0: # IPv4
|
79
|
+
n = to_bitfield_ipv4(n)
|
80
|
+
b += n + '0'*(32-len(n))
|
81
|
+
continue
|
82
|
+
n = ('x'*(4-len(n))) + n
|
83
|
+
for i in n:
|
84
|
+
b += hexbinmap[i]
|
85
|
+
if doublecolon:
|
86
|
+
pos = b.find(':')
|
87
|
+
b = b[:pos]+('0'*(129-len(b)))+b[pos+1:]
|
88
|
+
if len(b) != 128: # always check size
|
89
|
+
raise ValueError, "bad address"
|
90
|
+
return b
|
91
|
+
|
92
|
+
ipv4addrmask = to_bitfield_ipv6('::ffff:0:0')[:96]
|
93
|
+
|
94
|
+
class IP_List:
|
95
|
+
def __init__(self):
|
96
|
+
self.ipv4list = []
|
97
|
+
self.ipv6list = []
|
98
|
+
|
99
|
+
def __nonzero__(self):
|
100
|
+
return bool(self.ipv4list or self.ipv6list)
|
101
|
+
|
102
|
+
|
103
|
+
def append(self, ip, depth = 256):
|
104
|
+
if ip.find(':') < 0: # IPv4
|
105
|
+
insort(self.ipv4list,to_bitfield_ipv4(ip)[:depth])
|
106
|
+
else:
|
107
|
+
b = to_bitfield_ipv6(ip)
|
108
|
+
if b.startswith(ipv4addrmask):
|
109
|
+
insort(self.ipv4list,b[96:][:depth-96])
|
110
|
+
else:
|
111
|
+
insort(self.ipv6list,b[:depth])
|
112
|
+
|
113
|
+
|
114
|
+
def includes(self, ip):
|
115
|
+
if not (self.ipv4list or self.ipv6list):
|
116
|
+
return False
|
117
|
+
if ip.find(':') < 0: # IPv4
|
118
|
+
b = to_bitfield_ipv4(ip)
|
119
|
+
else:
|
120
|
+
b = to_bitfield_ipv6(ip)
|
121
|
+
if b.startswith(ipv4addrmask):
|
122
|
+
b = b[96:]
|
123
|
+
if len(b) > 32:
|
124
|
+
l = self.ipv6list
|
125
|
+
else:
|
126
|
+
l = self.ipv4list
|
127
|
+
for map in l[bisect(l,b)-1:]:
|
128
|
+
if b.startswith(map):
|
129
|
+
return True
|
130
|
+
if map > b:
|
131
|
+
return False
|
132
|
+
return False
|
133
|
+
|
134
|
+
|
135
|
+
def read_fieldlist(self, file): # reads a list from a file in the format 'ip/len <whatever>'
|
136
|
+
f = open(file, 'r')
|
137
|
+
while True:
|
138
|
+
line = f.readline()
|
139
|
+
if not line:
|
140
|
+
break
|
141
|
+
line = line.strip().expandtabs()
|
142
|
+
if not line or line[0] == '#':
|
143
|
+
continue
|
144
|
+
try:
|
145
|
+
line, garbage = line.split(' ',1)
|
146
|
+
except:
|
147
|
+
pass
|
148
|
+
try:
|
149
|
+
line, garbage = line.split('#',1)
|
150
|
+
except:
|
151
|
+
pass
|
152
|
+
try:
|
153
|
+
ip, depth = line.split('/')
|
154
|
+
except:
|
155
|
+
ip = line
|
156
|
+
depth = None
|
157
|
+
try:
|
158
|
+
if depth is not None:
|
159
|
+
depth = int(depth)
|
160
|
+
self.append(ip,depth)
|
161
|
+
except:
|
162
|
+
print '*** WARNING *** could not parse IP range: '+line
|
163
|
+
f.close()
|
164
|
+
|
165
|
+
|
166
|
+
def set_intranet_addresses(self):
|
167
|
+
self.append('127.0.0.1',8)
|
168
|
+
self.append('10.0.0.0',8)
|
169
|
+
self.append('172.16.0.0',12)
|
170
|
+
self.append('192.168.0.0',16)
|
171
|
+
self.append('169.254.0.0',16)
|
172
|
+
self.append('::1')
|
173
|
+
self.append('fe80::',16)
|
174
|
+
self.append('fec0::',16)
|
175
|
+
|
176
|
+
def set_ipv4_addresses(self):
|
177
|
+
self.append('::ffff:0:0',96)
|
178
|
+
|
179
|
+
def ipv6_to_ipv4(ip):
|
180
|
+
ip = to_bitfield_ipv6(ip)
|
181
|
+
if not ip.startswith(ipv4addrmask):
|
182
|
+
raise ValueError, "not convertible to IPv4"
|
183
|
+
ip = ip[-32:]
|
184
|
+
x = ''
|
185
|
+
for i in range(4):
|
186
|
+
x += str(int(ip[:8],2))
|
187
|
+
if i < 3:
|
188
|
+
x += '.'
|
189
|
+
ip = ip[8:]
|
190
|
+
return x
|
191
|
+
|
192
|
+
def to_ipv4(ip):
|
193
|
+
if is_ipv4(ip):
|
194
|
+
_valid_ipv4(ip)
|
195
|
+
return ip
|
196
|
+
return ipv6_to_ipv4(ip)
|
197
|
+
|
198
|
+
def is_ipv4(ip):
|
199
|
+
return ip.find(':') < 0
|
200
|
+
|
201
|
+
def _valid_ipv4(ip):
|
202
|
+
ip = ip.split('.')
|
203
|
+
if len(ip) != 4:
|
204
|
+
raise ValueError
|
205
|
+
for i in ip:
|
206
|
+
chr(int(i))
|
207
|
+
|
208
|
+
def is_valid_ip(ip):
|
209
|
+
try:
|
210
|
+
if not ip:
|
211
|
+
return False
|
212
|
+
if is_ipv4(ip):
|
213
|
+
_valid_ipv4(ip)
|
214
|
+
return True
|
215
|
+
to_bitfield_ipv6(ip)
|
216
|
+
return True
|
217
|
+
except:
|
218
|
+
return False
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Written by John Hoffman
|
2
|
+
# see LICENSE.txt for license information
|
3
|
+
|
4
|
+
from binascii import unhexlify
|
5
|
+
|
6
|
+
try:
|
7
|
+
True
|
8
|
+
except:
|
9
|
+
True = 1
|
10
|
+
False = 0
|
11
|
+
|
12
|
+
|
13
|
+
# parses a list of torrent hashes, in the format of one hash per line in hex format
|
14
|
+
|
15
|
+
def parsetorrentlist(filename, parsed):
|
16
|
+
new_parsed = {}
|
17
|
+
added = {}
|
18
|
+
removed = parsed
|
19
|
+
f = open(filename, 'r')
|
20
|
+
while True:
|
21
|
+
l = f.readline()
|
22
|
+
if not l:
|
23
|
+
break
|
24
|
+
l = l.strip()
|
25
|
+
try:
|
26
|
+
if len(l) != 40:
|
27
|
+
raise ValueError, 'bad line'
|
28
|
+
h = unhexlify(l)
|
29
|
+
except:
|
30
|
+
print '*** WARNING *** could not parse line in torrent list: '+l
|
31
|
+
if parsed.has_key(h):
|
32
|
+
del removed[h]
|
33
|
+
else:
|
34
|
+
added[h] = True
|
35
|
+
new_parsed[h] = True
|
36
|
+
f.close()
|
37
|
+
return (new_parsed, added, removed)
|
38
|
+
|