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,155 @@
|
|
1
|
+
# Written by Bram Cohen
|
2
|
+
# see LICENSE.txt for license information
|
3
|
+
|
4
|
+
from cStringIO import StringIO
|
5
|
+
from urllib import quote
|
6
|
+
from threading import Event
|
7
|
+
|
8
|
+
try:
|
9
|
+
True
|
10
|
+
except:
|
11
|
+
True = 1
|
12
|
+
False = 0
|
13
|
+
|
14
|
+
class DownloaderFeedback:
|
15
|
+
def __init__(self, choker, httpdl, add_task, upfunc, downfunc,
|
16
|
+
ratemeasure, leftfunc, file_length, finflag, sp, statistics,
|
17
|
+
statusfunc = None, interval = None):
|
18
|
+
self.choker = choker
|
19
|
+
self.httpdl = httpdl
|
20
|
+
self.add_task = add_task
|
21
|
+
self.upfunc = upfunc
|
22
|
+
self.downfunc = downfunc
|
23
|
+
self.ratemeasure = ratemeasure
|
24
|
+
self.leftfunc = leftfunc
|
25
|
+
self.file_length = file_length
|
26
|
+
self.finflag = finflag
|
27
|
+
self.sp = sp
|
28
|
+
self.statistics = statistics
|
29
|
+
self.lastids = []
|
30
|
+
self.spewdata = None
|
31
|
+
self.doneprocessing = Event()
|
32
|
+
self.doneprocessing.set()
|
33
|
+
if statusfunc:
|
34
|
+
self.autodisplay(statusfunc, interval)
|
35
|
+
|
36
|
+
|
37
|
+
def _rotate(self):
|
38
|
+
cs = self.choker.connections
|
39
|
+
for id in self.lastids:
|
40
|
+
for i in xrange(len(cs)):
|
41
|
+
if cs[i].get_id() == id:
|
42
|
+
return cs[i:] + cs[:i]
|
43
|
+
return cs
|
44
|
+
|
45
|
+
def spews(self):
|
46
|
+
l = []
|
47
|
+
cs = self._rotate()
|
48
|
+
self.lastids = [c.get_id() for c in cs]
|
49
|
+
for c in cs:
|
50
|
+
a = {}
|
51
|
+
a['id'] = c.get_readable_id()
|
52
|
+
a['ip'] = c.get_ip()
|
53
|
+
a['optimistic'] = (c is self.choker.connections[0])
|
54
|
+
if c.is_locally_initiated():
|
55
|
+
a['direction'] = 'L'
|
56
|
+
else:
|
57
|
+
a['direction'] = 'R'
|
58
|
+
u = c.get_upload()
|
59
|
+
a['uprate'] = int(u.measure.get_rate())
|
60
|
+
a['uinterested'] = u.is_interested()
|
61
|
+
a['uchoked'] = u.is_choked()
|
62
|
+
d = c.get_download()
|
63
|
+
a['downrate'] = int(d.measure.get_rate())
|
64
|
+
a['dinterested'] = d.is_interested()
|
65
|
+
a['dchoked'] = d.is_choked()
|
66
|
+
a['snubbed'] = d.is_snubbed()
|
67
|
+
a['utotal'] = d.connection.upload.measure.get_total()
|
68
|
+
a['dtotal'] = d.connection.download.measure.get_total()
|
69
|
+
if len(d.connection.download.have) > 0:
|
70
|
+
a['completed'] = float(len(d.connection.download.have)-d.connection.download.have.numfalse)/float(len(d.connection.download.have))
|
71
|
+
else:
|
72
|
+
a['completed'] = 1.0
|
73
|
+
a['speed'] = d.connection.download.peermeasure.get_rate()
|
74
|
+
|
75
|
+
l.append(a)
|
76
|
+
|
77
|
+
for dl in self.httpdl.get_downloads():
|
78
|
+
if dl.goodseed:
|
79
|
+
a = {}
|
80
|
+
a['id'] = 'http seed'
|
81
|
+
a['ip'] = dl.baseurl
|
82
|
+
a['optimistic'] = False
|
83
|
+
a['direction'] = 'L'
|
84
|
+
a['uprate'] = 0
|
85
|
+
a['uinterested'] = False
|
86
|
+
a['uchoked'] = False
|
87
|
+
a['downrate'] = int(dl.measure.get_rate())
|
88
|
+
a['dinterested'] = True
|
89
|
+
a['dchoked'] = not dl.active
|
90
|
+
a['snubbed'] = not dl.active
|
91
|
+
a['utotal'] = None
|
92
|
+
a['dtotal'] = dl.measure.get_total()
|
93
|
+
a['completed'] = 1.0
|
94
|
+
a['speed'] = None
|
95
|
+
|
96
|
+
l.append(a)
|
97
|
+
|
98
|
+
return l
|
99
|
+
|
100
|
+
|
101
|
+
def gather(self, displayfunc = None):
|
102
|
+
s = {'stats': self.statistics.update()}
|
103
|
+
if self.sp.isSet():
|
104
|
+
s['spew'] = self.spews()
|
105
|
+
else:
|
106
|
+
s['spew'] = None
|
107
|
+
s['up'] = self.upfunc()
|
108
|
+
if self.finflag.isSet():
|
109
|
+
s['done'] = self.file_length
|
110
|
+
return s
|
111
|
+
s['down'] = self.downfunc()
|
112
|
+
obtained, desired = self.leftfunc()
|
113
|
+
s['done'] = obtained
|
114
|
+
s['wanted'] = desired
|
115
|
+
if desired > 0:
|
116
|
+
s['frac'] = float(obtained)/desired
|
117
|
+
else:
|
118
|
+
s['frac'] = 1.0
|
119
|
+
if desired == obtained:
|
120
|
+
s['time'] = 0
|
121
|
+
else:
|
122
|
+
s['time'] = self.ratemeasure.get_time_left(desired-obtained)
|
123
|
+
return s
|
124
|
+
|
125
|
+
|
126
|
+
def display(self, displayfunc):
|
127
|
+
if not self.doneprocessing.isSet():
|
128
|
+
return
|
129
|
+
self.doneprocessing.clear()
|
130
|
+
stats = self.gather()
|
131
|
+
if self.finflag.isSet():
|
132
|
+
displayfunc(dpflag = self.doneprocessing,
|
133
|
+
upRate = stats['up'],
|
134
|
+
statistics = stats['stats'], spew = stats['spew'])
|
135
|
+
elif stats['time'] is not None:
|
136
|
+
displayfunc(dpflag = self.doneprocessing,
|
137
|
+
fractionDone = stats['frac'], sizeDone = stats['done'],
|
138
|
+
downRate = stats['down'], upRate = stats['up'],
|
139
|
+
statistics = stats['stats'], spew = stats['spew'],
|
140
|
+
timeEst = stats['time'])
|
141
|
+
else:
|
142
|
+
displayfunc(dpflag = self.doneprocessing,
|
143
|
+
fractionDone = stats['frac'], sizeDone = stats['done'],
|
144
|
+
downRate = stats['down'], upRate = stats['up'],
|
145
|
+
statistics = stats['stats'], spew = stats['spew'])
|
146
|
+
|
147
|
+
|
148
|
+
def autodisplay(self, displayfunc, interval):
|
149
|
+
self.displayfunc = displayfunc
|
150
|
+
self.interval = interval
|
151
|
+
self._autodisplay()
|
152
|
+
|
153
|
+
def _autodisplay(self):
|
154
|
+
self.add_task(self._autodisplay, self.interval)
|
155
|
+
self.display(self.displayfunc)
|
@@ -0,0 +1,333 @@
|
|
1
|
+
# Written by Bram Cohen
|
2
|
+
# see LICENSE.txt for license information
|
3
|
+
|
4
|
+
from cStringIO import StringIO
|
5
|
+
from binascii import b2a_hex
|
6
|
+
from socket import error as socketerror
|
7
|
+
from urllib import quote
|
8
|
+
from traceback import print_exc
|
9
|
+
try:
|
10
|
+
True
|
11
|
+
except:
|
12
|
+
True = 1
|
13
|
+
False = 0
|
14
|
+
|
15
|
+
MAX_INCOMPLETE = 8
|
16
|
+
|
17
|
+
protocol_name = 'BitTorrent protocol'
|
18
|
+
option_pattern = chr(0)*8
|
19
|
+
|
20
|
+
def toint(s):
|
21
|
+
return long(b2a_hex(s), 16)
|
22
|
+
|
23
|
+
def tobinary(i):
|
24
|
+
return (chr(i >> 24) + chr((i >> 16) & 0xFF) +
|
25
|
+
chr((i >> 8) & 0xFF) + chr(i & 0xFF))
|
26
|
+
|
27
|
+
hexchars = '0123456789ABCDEF'
|
28
|
+
hexmap = []
|
29
|
+
for i in xrange(256):
|
30
|
+
hexmap.append(hexchars[(i&0xF0)/16]+hexchars[i&0x0F])
|
31
|
+
|
32
|
+
def tohex(s):
|
33
|
+
r = []
|
34
|
+
for c in s:
|
35
|
+
r.append(hexmap[ord(c)])
|
36
|
+
return ''.join(r)
|
37
|
+
|
38
|
+
def make_readable(s):
|
39
|
+
if not s:
|
40
|
+
return ''
|
41
|
+
if quote(s).find('%') >= 0:
|
42
|
+
return tohex(s)
|
43
|
+
return '"'+s+'"'
|
44
|
+
|
45
|
+
|
46
|
+
class IncompleteCounter:
|
47
|
+
def __init__(self):
|
48
|
+
self.c = 0
|
49
|
+
def increment(self):
|
50
|
+
self.c += 1
|
51
|
+
def decrement(self):
|
52
|
+
self.c -= 1
|
53
|
+
def toomany(self):
|
54
|
+
return self.c >= MAX_INCOMPLETE
|
55
|
+
|
56
|
+
incompletecounter = IncompleteCounter()
|
57
|
+
|
58
|
+
|
59
|
+
# header, reserved, download id, my id, [length, message]
|
60
|
+
|
61
|
+
class Connection:
|
62
|
+
def __init__(self, Encoder, connection, id, ext_handshake=False):
|
63
|
+
self.Encoder = Encoder
|
64
|
+
self.connection = connection
|
65
|
+
self.connecter = Encoder.connecter
|
66
|
+
self.id = id
|
67
|
+
self.readable_id = make_readable(id)
|
68
|
+
self.locally_initiated = (id != None)
|
69
|
+
self.complete = False
|
70
|
+
self.keepalive = lambda: None
|
71
|
+
self.closed = False
|
72
|
+
self.buffer = StringIO()
|
73
|
+
if self.locally_initiated:
|
74
|
+
incompletecounter.increment()
|
75
|
+
if self.locally_initiated or ext_handshake:
|
76
|
+
self.connection.write(chr(len(protocol_name)) + protocol_name +
|
77
|
+
option_pattern + self.Encoder.download_id)
|
78
|
+
if ext_handshake:
|
79
|
+
self.Encoder.connecter.external_connection_made += 1
|
80
|
+
self.connection.write(self.Encoder.my_id)
|
81
|
+
self.next_len, self.next_func = 20, self.read_peer_id
|
82
|
+
else:
|
83
|
+
self.next_len, self.next_func = 1, self.read_header_len
|
84
|
+
self.Encoder.raw_server.add_task(self._auto_close, 15)
|
85
|
+
|
86
|
+
def get_ip(self, real=False):
|
87
|
+
return self.connection.get_ip(real)
|
88
|
+
|
89
|
+
def get_id(self):
|
90
|
+
return self.id
|
91
|
+
|
92
|
+
def get_readable_id(self):
|
93
|
+
return self.readable_id
|
94
|
+
|
95
|
+
def is_locally_initiated(self):
|
96
|
+
return self.locally_initiated
|
97
|
+
|
98
|
+
def is_flushed(self):
|
99
|
+
return self.connection.is_flushed()
|
100
|
+
|
101
|
+
def read_header_len(self, s):
|
102
|
+
if ord(s) != len(protocol_name):
|
103
|
+
return None
|
104
|
+
return len(protocol_name), self.read_header
|
105
|
+
|
106
|
+
def read_header(self, s):
|
107
|
+
if s != protocol_name:
|
108
|
+
return None
|
109
|
+
return 8, self.read_reserved
|
110
|
+
|
111
|
+
def read_reserved(self, s):
|
112
|
+
return 20, self.read_download_id
|
113
|
+
|
114
|
+
def read_download_id(self, s):
|
115
|
+
if s != self.Encoder.download_id:
|
116
|
+
return None
|
117
|
+
if not self.locally_initiated:
|
118
|
+
self.Encoder.connecter.external_connection_made += 1
|
119
|
+
self.connection.write(chr(len(protocol_name)) + protocol_name +
|
120
|
+
option_pattern + self.Encoder.download_id + self.Encoder.my_id)
|
121
|
+
return 20, self.read_peer_id
|
122
|
+
|
123
|
+
def read_peer_id(self, s):
|
124
|
+
if not self.id:
|
125
|
+
self.id = s
|
126
|
+
self.readable_id = make_readable(s)
|
127
|
+
else:
|
128
|
+
if s != self.id:
|
129
|
+
return None
|
130
|
+
self.complete = self.Encoder.got_id(self)
|
131
|
+
if not self.complete:
|
132
|
+
return None
|
133
|
+
if self.locally_initiated:
|
134
|
+
self.connection.write(self.Encoder.my_id)
|
135
|
+
incompletecounter.decrement()
|
136
|
+
c = self.Encoder.connecter.connection_made(self)
|
137
|
+
self.keepalive = c.send_keepalive
|
138
|
+
return 4, self.read_len
|
139
|
+
|
140
|
+
def read_len(self, s):
|
141
|
+
l = toint(s)
|
142
|
+
if l > self.Encoder.max_len:
|
143
|
+
return None
|
144
|
+
return l, self.read_message
|
145
|
+
|
146
|
+
def read_message(self, s):
|
147
|
+
if s != '':
|
148
|
+
self.connecter.got_message(self, s)
|
149
|
+
return 4, self.read_len
|
150
|
+
|
151
|
+
def read_dead(self, s):
|
152
|
+
return None
|
153
|
+
|
154
|
+
def _auto_close(self):
|
155
|
+
if not self.complete:
|
156
|
+
self.close()
|
157
|
+
|
158
|
+
def close(self):
|
159
|
+
if not self.closed:
|
160
|
+
self.connection.close()
|
161
|
+
self.sever()
|
162
|
+
|
163
|
+
def sever(self):
|
164
|
+
self.closed = True
|
165
|
+
del self.Encoder.connections[self.connection]
|
166
|
+
if self.complete:
|
167
|
+
self.connecter.connection_lost(self)
|
168
|
+
elif self.locally_initiated:
|
169
|
+
incompletecounter.decrement()
|
170
|
+
|
171
|
+
def send_message_raw(self, message):
|
172
|
+
if not self.closed:
|
173
|
+
self.connection.write(message)
|
174
|
+
|
175
|
+
def data_came_in(self, connection, s):
|
176
|
+
self.Encoder.measurefunc(len(s))
|
177
|
+
while True:
|
178
|
+
if self.closed:
|
179
|
+
return
|
180
|
+
i = self.next_len - self.buffer.tell()
|
181
|
+
if i > len(s):
|
182
|
+
self.buffer.write(s)
|
183
|
+
return
|
184
|
+
self.buffer.write(s[:i])
|
185
|
+
s = s[i:]
|
186
|
+
m = self.buffer.getvalue()
|
187
|
+
self.buffer.reset()
|
188
|
+
self.buffer.truncate()
|
189
|
+
try:
|
190
|
+
x = self.next_func(m)
|
191
|
+
except:
|
192
|
+
self.next_len, self.next_func = 1, self.read_dead
|
193
|
+
raise
|
194
|
+
if x is None:
|
195
|
+
self.close()
|
196
|
+
return
|
197
|
+
self.next_len, self.next_func = x
|
198
|
+
|
199
|
+
def connection_flushed(self, connection):
|
200
|
+
if self.complete:
|
201
|
+
self.connecter.connection_flushed(self)
|
202
|
+
|
203
|
+
def connection_lost(self, connection):
|
204
|
+
if self.Encoder.connections.has_key(connection):
|
205
|
+
self.sever()
|
206
|
+
|
207
|
+
|
208
|
+
class Encoder:
|
209
|
+
def __init__(self, connecter, raw_server, my_id, max_len,
|
210
|
+
schedulefunc, keepalive_delay, download_id,
|
211
|
+
measurefunc, config):
|
212
|
+
self.raw_server = raw_server
|
213
|
+
self.connecter = connecter
|
214
|
+
self.my_id = my_id
|
215
|
+
self.max_len = max_len
|
216
|
+
self.schedulefunc = schedulefunc
|
217
|
+
self.keepalive_delay = keepalive_delay
|
218
|
+
self.download_id = download_id
|
219
|
+
self.measurefunc = measurefunc
|
220
|
+
self.config = config
|
221
|
+
self.connections = {}
|
222
|
+
self.banned = {}
|
223
|
+
self.to_connect = []
|
224
|
+
self.paused = False
|
225
|
+
if self.config['max_connections'] == 0:
|
226
|
+
self.max_connections = 2 ** 30
|
227
|
+
else:
|
228
|
+
self.max_connections = self.config['max_connections']
|
229
|
+
schedulefunc(self.send_keepalives, keepalive_delay)
|
230
|
+
|
231
|
+
def send_keepalives(self):
|
232
|
+
self.schedulefunc(self.send_keepalives, self.keepalive_delay)
|
233
|
+
if self.paused:
|
234
|
+
return
|
235
|
+
for c in self.connections.values():
|
236
|
+
c.keepalive()
|
237
|
+
|
238
|
+
def start_connections(self, list):
|
239
|
+
if not self.to_connect:
|
240
|
+
self.raw_server.add_task(self._start_connection_from_queue)
|
241
|
+
self.to_connect = list
|
242
|
+
|
243
|
+
def _start_connection_from_queue(self):
|
244
|
+
if self.connecter.external_connection_made:
|
245
|
+
max_initiate = self.config['max_initiate']
|
246
|
+
else:
|
247
|
+
max_initiate = int(self.config['max_initiate']*1.5)
|
248
|
+
cons = len(self.connections)
|
249
|
+
if cons >= self.max_connections or cons >= max_initiate:
|
250
|
+
delay = 60
|
251
|
+
elif self.paused or incompletecounter.toomany():
|
252
|
+
delay = 1
|
253
|
+
else:
|
254
|
+
delay = 0
|
255
|
+
dns, id = self.to_connect.pop(0)
|
256
|
+
self.start_connection(dns, id)
|
257
|
+
if self.to_connect:
|
258
|
+
self.raw_server.add_task(self._start_connection_from_queue, delay)
|
259
|
+
|
260
|
+
def start_connection(self, dns, id):
|
261
|
+
if ( self.paused
|
262
|
+
or len(self.connections) >= self.max_connections
|
263
|
+
or id == self.my_id
|
264
|
+
or self.banned.has_key(dns[0]) ):
|
265
|
+
return True
|
266
|
+
for v in self.connections.values():
|
267
|
+
if v is None:
|
268
|
+
continue
|
269
|
+
if id and v.id == id:
|
270
|
+
return True
|
271
|
+
ip = v.get_ip(True)
|
272
|
+
if self.config['security'] and ip != 'unknown' and ip == dns[0]:
|
273
|
+
return True
|
274
|
+
try:
|
275
|
+
c = self.raw_server.start_connection(dns)
|
276
|
+
con = Connection(self, c, id)
|
277
|
+
self.connections[c] = con
|
278
|
+
c.set_handler(con)
|
279
|
+
except socketerror:
|
280
|
+
return False
|
281
|
+
return True
|
282
|
+
|
283
|
+
def _start_connection(self, dns, id):
|
284
|
+
def foo(self=self, dns=dns, id=id):
|
285
|
+
self.start_connection(dns, id)
|
286
|
+
|
287
|
+
self.schedulefunc(foo, 0)
|
288
|
+
|
289
|
+
def got_id(self, connection):
|
290
|
+
if connection.id == self.my_id:
|
291
|
+
self.connecter.external_connection_made -= 1
|
292
|
+
return False
|
293
|
+
ip = connection.get_ip(True)
|
294
|
+
if self.config['security'] and self.banned.has_key(ip):
|
295
|
+
return False
|
296
|
+
for v in self.connections.values():
|
297
|
+
if connection is not v:
|
298
|
+
if connection.id == v.id:
|
299
|
+
return False
|
300
|
+
if self.config['security'] and ip != 'unknown' and ip == v.get_ip(True):
|
301
|
+
v.close()
|
302
|
+
return True
|
303
|
+
|
304
|
+
def external_connection_made(self, connection):
|
305
|
+
if self.paused or len(self.connections) >= self.max_connections:
|
306
|
+
connection.close()
|
307
|
+
return False
|
308
|
+
con = Connection(self, connection, None)
|
309
|
+
self.connections[connection] = con
|
310
|
+
connection.set_handler(con)
|
311
|
+
return True
|
312
|
+
|
313
|
+
def externally_handshaked_connection_made(self, connection, options, already_read):
|
314
|
+
if self.paused or len(self.connections) >= self.max_connections:
|
315
|
+
connection.close()
|
316
|
+
return False
|
317
|
+
con = Connection(self, connection, None, True)
|
318
|
+
self.connections[connection] = con
|
319
|
+
connection.set_handler(con)
|
320
|
+
if already_read:
|
321
|
+
con.data_came_in(con, already_read)
|
322
|
+
return True
|
323
|
+
|
324
|
+
def close_all(self):
|
325
|
+
for c in self.connections.values():
|
326
|
+
c.close()
|
327
|
+
self.connections = {}
|
328
|
+
|
329
|
+
def ban(self, ip):
|
330
|
+
self.banned[ip] = 1
|
331
|
+
|
332
|
+
def pause(self, flag):
|
333
|
+
self.paused = flag
|