murder 0.0.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|