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,75 @@
|
|
1
|
+
# Written by Bram Cohen
|
2
|
+
# see LICENSE.txt for license information
|
3
|
+
|
4
|
+
from clock import clock
|
5
|
+
try:
|
6
|
+
True
|
7
|
+
except:
|
8
|
+
True = 1
|
9
|
+
False = 0
|
10
|
+
|
11
|
+
FACTOR = 0.999
|
12
|
+
|
13
|
+
class RateMeasure:
|
14
|
+
def __init__(self):
|
15
|
+
self.last = None
|
16
|
+
self.time = 1.0
|
17
|
+
self.got = 0.0
|
18
|
+
self.remaining = None
|
19
|
+
self.broke = False
|
20
|
+
self.got_anything = False
|
21
|
+
self.last_checked = None
|
22
|
+
self.rate = 0
|
23
|
+
self.lastten = False
|
24
|
+
|
25
|
+
def data_came_in(self, amount):
|
26
|
+
if not self.got_anything:
|
27
|
+
self.got_anything = True
|
28
|
+
self.last = clock()
|
29
|
+
return
|
30
|
+
self.update(amount)
|
31
|
+
|
32
|
+
def data_rejected(self, amount):
|
33
|
+
pass
|
34
|
+
|
35
|
+
def get_time_left(self, left):
|
36
|
+
t = clock()
|
37
|
+
if not self.got_anything:
|
38
|
+
return None
|
39
|
+
if t - self.last > 15:
|
40
|
+
self.update(0)
|
41
|
+
try:
|
42
|
+
remaining = left/self.rate
|
43
|
+
if not self.lastten and remaining <= 10:
|
44
|
+
self.lastten = True
|
45
|
+
if self.lastten:
|
46
|
+
return remaining
|
47
|
+
delta = max(remaining/20,2)
|
48
|
+
if self.remaining is None:
|
49
|
+
self.remaining = remaining
|
50
|
+
elif abs(self.remaining-remaining) > delta:
|
51
|
+
self.remaining = remaining
|
52
|
+
else:
|
53
|
+
self.remaining -= t - self.last_checked
|
54
|
+
except ZeroDivisionError:
|
55
|
+
self.remaining = None
|
56
|
+
if self.remaining is not None and self.remaining < 0.1:
|
57
|
+
self.remaining = 0.1
|
58
|
+
self.last_checked = t
|
59
|
+
return self.remaining
|
60
|
+
|
61
|
+
def update(self, amount):
|
62
|
+
t = clock()
|
63
|
+
t1 = int(t)
|
64
|
+
l1 = int(self.last)
|
65
|
+
for i in xrange(l1,t1):
|
66
|
+
self.time *= FACTOR
|
67
|
+
self.got *= FACTOR
|
68
|
+
self.got += amount
|
69
|
+
if t - self.last < 20:
|
70
|
+
self.time += t - self.last
|
71
|
+
self.last = t
|
72
|
+
try:
|
73
|
+
self.rate = self.got / self.time
|
74
|
+
except ZeroDivisionError:
|
75
|
+
pass
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# Written by Bram Cohen
|
2
|
+
# see LICENSE.txt for license information
|
3
|
+
|
4
|
+
from bisect import insort
|
5
|
+
from SocketHandler import SocketHandler, UPnP_ERROR
|
6
|
+
import socket
|
7
|
+
from cStringIO import StringIO
|
8
|
+
from traceback import print_exc
|
9
|
+
from select import error
|
10
|
+
from threading import Thread, Event
|
11
|
+
from time import sleep
|
12
|
+
from clock import clock
|
13
|
+
import sys
|
14
|
+
try:
|
15
|
+
True
|
16
|
+
except:
|
17
|
+
True = 1
|
18
|
+
False = 0
|
19
|
+
|
20
|
+
|
21
|
+
def autodetect_ipv6():
|
22
|
+
try:
|
23
|
+
assert sys.version_info >= (2,3)
|
24
|
+
assert socket.has_ipv6
|
25
|
+
socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
26
|
+
except:
|
27
|
+
return 0
|
28
|
+
return 1
|
29
|
+
|
30
|
+
def autodetect_socket_style():
|
31
|
+
if sys.platform.find('linux') < 0:
|
32
|
+
return 1
|
33
|
+
else:
|
34
|
+
try:
|
35
|
+
f = open('/proc/sys/net/ipv6/bindv6only','r')
|
36
|
+
dual_socket_style = int(f.read())
|
37
|
+
f.close()
|
38
|
+
return int(not dual_socket_style)
|
39
|
+
except:
|
40
|
+
return 0
|
41
|
+
|
42
|
+
|
43
|
+
READSIZE = 100000
|
44
|
+
|
45
|
+
class RawServer:
|
46
|
+
def __init__(self, doneflag, timeout_check_interval, timeout, noisy = True,
|
47
|
+
ipv6_enable = True, failfunc = lambda x: None, errorfunc = None,
|
48
|
+
sockethandler = None, excflag = Event()):
|
49
|
+
self.timeout_check_interval = timeout_check_interval
|
50
|
+
self.timeout = timeout
|
51
|
+
self.servers = {}
|
52
|
+
self.single_sockets = {}
|
53
|
+
self.dead_from_write = []
|
54
|
+
self.doneflag = doneflag
|
55
|
+
self.noisy = noisy
|
56
|
+
self.failfunc = failfunc
|
57
|
+
self.errorfunc = errorfunc
|
58
|
+
self.exccount = 0
|
59
|
+
self.funcs = []
|
60
|
+
self.externally_added = []
|
61
|
+
self.finished = Event()
|
62
|
+
self.tasks_to_kill = []
|
63
|
+
self.excflag = excflag
|
64
|
+
|
65
|
+
if sockethandler is None:
|
66
|
+
sockethandler = SocketHandler(timeout, ipv6_enable, READSIZE)
|
67
|
+
self.sockethandler = sockethandler
|
68
|
+
self.add_task(self.scan_for_timeouts, timeout_check_interval)
|
69
|
+
|
70
|
+
def get_exception_flag(self):
|
71
|
+
return self.excflag
|
72
|
+
|
73
|
+
def _add_task(self, func, delay, id = None):
|
74
|
+
assert float(delay) >= 0
|
75
|
+
insort(self.funcs, (clock() + delay, func, id))
|
76
|
+
|
77
|
+
def add_task(self, func, delay = 0, id = None):
|
78
|
+
assert float(delay) >= 0
|
79
|
+
self.externally_added.append((func, delay, id))
|
80
|
+
|
81
|
+
def scan_for_timeouts(self):
|
82
|
+
self.add_task(self.scan_for_timeouts, self.timeout_check_interval)
|
83
|
+
self.sockethandler.scan_for_timeouts()
|
84
|
+
|
85
|
+
def bind(self, port, bind = '', reuse = False,
|
86
|
+
ipv6_socket_style = 1, upnp = False):
|
87
|
+
self.sockethandler.bind(port, bind, reuse, ipv6_socket_style, upnp)
|
88
|
+
|
89
|
+
def find_and_bind(self, minport, maxport, bind = '', reuse = False,
|
90
|
+
ipv6_socket_style = 1, upnp = 0, randomizer = False):
|
91
|
+
return self.sockethandler.find_and_bind(minport, maxport, bind, reuse,
|
92
|
+
ipv6_socket_style, upnp, randomizer)
|
93
|
+
|
94
|
+
def start_connection_raw(self, dns, socktype, handler = None):
|
95
|
+
return self.sockethandler.start_connection_raw(dns, socktype, handler)
|
96
|
+
|
97
|
+
def start_connection(self, dns, handler = None, randomize = False):
|
98
|
+
return self.sockethandler.start_connection(dns, handler, randomize)
|
99
|
+
|
100
|
+
def get_stats(self):
|
101
|
+
return self.sockethandler.get_stats()
|
102
|
+
|
103
|
+
def pop_external(self):
|
104
|
+
while self.externally_added:
|
105
|
+
(a, b, c) = self.externally_added.pop(0)
|
106
|
+
self._add_task(a, b, c)
|
107
|
+
|
108
|
+
|
109
|
+
def listen_forever(self, handler):
|
110
|
+
self.sockethandler.set_handler(handler)
|
111
|
+
try:
|
112
|
+
while not self.doneflag.isSet():
|
113
|
+
try:
|
114
|
+
self.pop_external()
|
115
|
+
self._kill_tasks()
|
116
|
+
if self.funcs:
|
117
|
+
period = self.funcs[0][0] + 0.001 - clock()
|
118
|
+
else:
|
119
|
+
period = 2 ** 30
|
120
|
+
if period < 0:
|
121
|
+
period = 0
|
122
|
+
events = self.sockethandler.do_poll(period)
|
123
|
+
if self.doneflag.isSet():
|
124
|
+
return
|
125
|
+
while self.funcs and self.funcs[0][0] <= clock():
|
126
|
+
garbage1, func, id = self.funcs.pop(0)
|
127
|
+
if id in self.tasks_to_kill:
|
128
|
+
pass
|
129
|
+
try:
|
130
|
+
# print func.func_name
|
131
|
+
func()
|
132
|
+
except (SystemError, MemoryError), e:
|
133
|
+
self.failfunc(str(e))
|
134
|
+
return
|
135
|
+
except KeyboardInterrupt:
|
136
|
+
# self.exception(True)
|
137
|
+
return
|
138
|
+
except:
|
139
|
+
if self.noisy:
|
140
|
+
self.exception()
|
141
|
+
self.sockethandler.close_dead()
|
142
|
+
self.sockethandler.handle_events(events)
|
143
|
+
if self.doneflag.isSet():
|
144
|
+
return
|
145
|
+
self.sockethandler.close_dead()
|
146
|
+
except (SystemError, MemoryError), e:
|
147
|
+
self.failfunc(str(e))
|
148
|
+
return
|
149
|
+
except error:
|
150
|
+
if self.doneflag.isSet():
|
151
|
+
return
|
152
|
+
except KeyboardInterrupt:
|
153
|
+
# self.exception(True)
|
154
|
+
return
|
155
|
+
except:
|
156
|
+
self.exception()
|
157
|
+
if self.exccount > 10:
|
158
|
+
return
|
159
|
+
finally:
|
160
|
+
# self.sockethandler.shutdown()
|
161
|
+
self.finished.set()
|
162
|
+
|
163
|
+
def is_finished(self):
|
164
|
+
return self.finished.isSet()
|
165
|
+
|
166
|
+
def wait_until_finished(self):
|
167
|
+
self.finished.wait()
|
168
|
+
|
169
|
+
def _kill_tasks(self):
|
170
|
+
if self.tasks_to_kill:
|
171
|
+
new_funcs = []
|
172
|
+
for (t, func, id) in self.funcs:
|
173
|
+
if id not in self.tasks_to_kill:
|
174
|
+
new_funcs.append((t, func, id))
|
175
|
+
self.funcs = new_funcs
|
176
|
+
self.tasks_to_kill = []
|
177
|
+
|
178
|
+
def kill_tasks(self, id):
|
179
|
+
self.tasks_to_kill.append(id)
|
180
|
+
|
181
|
+
def exception(self, kbint = False):
|
182
|
+
if not kbint:
|
183
|
+
self.excflag.set()
|
184
|
+
self.exccount += 1
|
185
|
+
if self.errorfunc is None:
|
186
|
+
print_exc()
|
187
|
+
else:
|
188
|
+
data = StringIO()
|
189
|
+
print_exc(file = data)
|
190
|
+
# print data.getvalue() # report exception here too
|
191
|
+
if not kbint: # don't report here if it's a keyboard interrupt
|
192
|
+
self.errorfunc(data.getvalue())
|
193
|
+
|
194
|
+
def shutdown(self):
|
195
|
+
self.sockethandler.shutdown()
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# Written by John Hoffman
|
2
|
+
# see LICENSE.txt for license information
|
3
|
+
|
4
|
+
from cStringIO import StringIO
|
5
|
+
#from RawServer import RawServer
|
6
|
+
try:
|
7
|
+
True
|
8
|
+
except:
|
9
|
+
True = 1
|
10
|
+
False = 0
|
11
|
+
|
12
|
+
from BT1.Encrypter import protocol_name
|
13
|
+
|
14
|
+
default_task_id = []
|
15
|
+
|
16
|
+
class SingleRawServer:
|
17
|
+
def __init__(self, info_hash, multihandler, doneflag, protocol):
|
18
|
+
self.info_hash = info_hash
|
19
|
+
self.doneflag = doneflag
|
20
|
+
self.protocol = protocol
|
21
|
+
self.multihandler = multihandler
|
22
|
+
self.rawserver = multihandler.rawserver
|
23
|
+
self.finished = False
|
24
|
+
self.running = False
|
25
|
+
self.handler = None
|
26
|
+
self.taskqueue = []
|
27
|
+
|
28
|
+
def shutdown(self):
|
29
|
+
if not self.finished:
|
30
|
+
self.multihandler.shutdown_torrent(self.info_hash)
|
31
|
+
|
32
|
+
def _shutdown(self):
|
33
|
+
if not self.finished:
|
34
|
+
self.finished = True
|
35
|
+
self.running = False
|
36
|
+
self.rawserver.kill_tasks(self.info_hash)
|
37
|
+
if self.handler:
|
38
|
+
self.handler.close_all()
|
39
|
+
|
40
|
+
def _external_connection_made(self, c, options, already_read):
|
41
|
+
if self.running:
|
42
|
+
c.set_handler(self.handler)
|
43
|
+
self.handler.externally_handshaked_connection_made(
|
44
|
+
c, options, already_read)
|
45
|
+
|
46
|
+
### RawServer functions ###
|
47
|
+
|
48
|
+
def add_task(self, func, delay=0, id = default_task_id):
|
49
|
+
if id is default_task_id:
|
50
|
+
id = self.info_hash
|
51
|
+
if not self.finished:
|
52
|
+
self.rawserver.add_task(func, delay, id)
|
53
|
+
|
54
|
+
# def bind(self, port, bind = '', reuse = False):
|
55
|
+
# pass # not handled here
|
56
|
+
|
57
|
+
def start_connection(self, dns, handler = None):
|
58
|
+
if not handler:
|
59
|
+
handler = self.handler
|
60
|
+
c = self.rawserver.start_connection(dns, handler)
|
61
|
+
return c
|
62
|
+
|
63
|
+
# def listen_forever(self, handler):
|
64
|
+
# pass # don't call with this
|
65
|
+
|
66
|
+
def start_listening(self, handler):
|
67
|
+
self.handler = handler
|
68
|
+
self.running = True
|
69
|
+
return self.shutdown # obviously, doesn't listen forever
|
70
|
+
|
71
|
+
def is_finished(self):
|
72
|
+
return self.finished
|
73
|
+
|
74
|
+
def get_exception_flag(self):
|
75
|
+
return self.rawserver.get_exception_flag()
|
76
|
+
|
77
|
+
|
78
|
+
class NewSocketHandler: # hand a new socket off where it belongs
|
79
|
+
def __init__(self, multihandler, connection):
|
80
|
+
self.multihandler = multihandler
|
81
|
+
self.connection = connection
|
82
|
+
connection.set_handler(self)
|
83
|
+
self.closed = False
|
84
|
+
self.buffer = StringIO()
|
85
|
+
self.complete = False
|
86
|
+
self.next_len, self.next_func = 1, self.read_header_len
|
87
|
+
self.multihandler.rawserver.add_task(self._auto_close, 15)
|
88
|
+
|
89
|
+
def _auto_close(self):
|
90
|
+
if not self.complete:
|
91
|
+
self.close()
|
92
|
+
|
93
|
+
def close(self):
|
94
|
+
if not self.closed:
|
95
|
+
self.connection.close()
|
96
|
+
self.closed = True
|
97
|
+
|
98
|
+
|
99
|
+
# header format:
|
100
|
+
# connection.write(chr(len(protocol_name)) + protocol_name +
|
101
|
+
# (chr(0) * 8) + self.encrypter.download_id + self.encrypter.my_id)
|
102
|
+
|
103
|
+
# copied from Encrypter and modified
|
104
|
+
|
105
|
+
def read_header_len(self, s):
|
106
|
+
l = ord(s)
|
107
|
+
return l, self.read_header
|
108
|
+
|
109
|
+
def read_header(self, s):
|
110
|
+
self.protocol = s
|
111
|
+
return 8, self.read_reserved
|
112
|
+
|
113
|
+
def read_reserved(self, s):
|
114
|
+
self.options = s
|
115
|
+
return 20, self.read_download_id
|
116
|
+
|
117
|
+
def read_download_id(self, s):
|
118
|
+
if self.multihandler.singlerawservers.has_key(s):
|
119
|
+
if self.multihandler.singlerawservers[s].protocol == self.protocol:
|
120
|
+
return True
|
121
|
+
return None
|
122
|
+
|
123
|
+
def read_dead(self, s):
|
124
|
+
return None
|
125
|
+
|
126
|
+
def data_came_in(self, garbage, s):
|
127
|
+
while True:
|
128
|
+
if self.closed:
|
129
|
+
return
|
130
|
+
i = self.next_len - self.buffer.tell()
|
131
|
+
if i > len(s):
|
132
|
+
self.buffer.write(s)
|
133
|
+
return
|
134
|
+
self.buffer.write(s[:i])
|
135
|
+
s = s[i:]
|
136
|
+
m = self.buffer.getvalue()
|
137
|
+
self.buffer.reset()
|
138
|
+
self.buffer.truncate()
|
139
|
+
try:
|
140
|
+
x = self.next_func(m)
|
141
|
+
except:
|
142
|
+
self.next_len, self.next_func = 1, self.read_dead
|
143
|
+
raise
|
144
|
+
if x is None:
|
145
|
+
self.close()
|
146
|
+
return
|
147
|
+
if x == True: # ready to process
|
148
|
+
self.multihandler.singlerawservers[m]._external_connection_made(
|
149
|
+
self.connection, self.options, s)
|
150
|
+
self.complete = True
|
151
|
+
return
|
152
|
+
self.next_len, self.next_func = x
|
153
|
+
|
154
|
+
def connection_flushed(self, ss):
|
155
|
+
pass
|
156
|
+
|
157
|
+
def connection_lost(self, ss):
|
158
|
+
self.closed = True
|
159
|
+
|
160
|
+
class MultiHandler:
|
161
|
+
def __init__(self, rawserver, doneflag):
|
162
|
+
self.rawserver = rawserver
|
163
|
+
self.masterdoneflag = doneflag
|
164
|
+
self.singlerawservers = {}
|
165
|
+
self.connections = {}
|
166
|
+
self.taskqueues = {}
|
167
|
+
|
168
|
+
def newRawServer(self, info_hash, doneflag, protocol=protocol_name):
|
169
|
+
new = SingleRawServer(info_hash, self, doneflag, protocol)
|
170
|
+
self.singlerawservers[info_hash] = new
|
171
|
+
return new
|
172
|
+
|
173
|
+
def shutdown_torrent(self, info_hash):
|
174
|
+
self.singlerawservers[info_hash]._shutdown()
|
175
|
+
del self.singlerawservers[info_hash]
|
176
|
+
|
177
|
+
def listen_forever(self):
|
178
|
+
self.rawserver.listen_forever(self)
|
179
|
+
for srs in self.singlerawservers.values():
|
180
|
+
srs.finished = True
|
181
|
+
srs.running = False
|
182
|
+
srs.doneflag.set()
|
183
|
+
|
184
|
+
### RawServer handler functions ###
|
185
|
+
# be wary of name collisions
|
186
|
+
|
187
|
+
def external_connection_made(self, ss):
|
188
|
+
NewSocketHandler(self, ss)
|