1
# Written by Bram Cohen
2
# see LICENSE.txt for license information
4
from CurrentRateMeasure import Measure
7
def __init__(self, connection, choker, storage,
8
max_slice_length, max_rate_period, fudge):
9
self.connection = connection
11
self.storage = storage
12
self.max_slice_length = max_slice_length
13
self.max_rate_period = max_rate_period
15
self.interested = False
17
self.measure = Measure(max_rate_period, fudge)
18
if storage.do_I_have_anything():
19
connection.send_bitfield(storage.get_have_list())
21
def got_not_interested(self):
23
self.interested = False
25
self.choker.not_interested(self.connection)
27
def got_interested(self):
28
if not self.interested:
29
self.interested = True
30
self.choker.interested(self.connection)
33
while len(self.buffer) > 0 and self.connection.is_flushed():
34
index, begin, length = self.buffer[0]
36
piece = self.storage.get_piece(index, begin, length)
38
self.connection.close()
40
self.measure.update_rate(len(piece))
41
self.connection.send_piece(index, begin, piece)
43
def got_request(self, index, begin, length):
44
if not self.interested or length > self.max_slice_length:
45
self.connection.close()
48
self.buffer.append((index, begin, length))
51
def got_cancel(self, index, begin, length):
53
self.buffer.remove((index, begin, length))
61
self.connection.send_choke()
66
self.connection.send_unchoke()
71
def is_interested(self):
72
return self.interested
74
def has_queries(self):
75
return len(self.buffer) > 0
78
return self.measure.get_rate()
80
class DummyConnection:
81
def __init__(self, events):
85
def send_bitfield(self, bitfield):
86
self.events.append(('bitfield', bitfield))
92
self.events.append('closed')
94
def send_piece(self, index, begin, piece):
95
self.events.append(('piece', index, begin, piece))
98
self.events.append('choke')
100
def send_unchoke(self):
101
self.events.append('unchoke')
104
def __init__(self, events):
107
def interested(self, connection):
108
self.events.append('interested')
110
def not_interested(self, connection):
111
self.events.append('not interested')
114
def __init__(self, events):
117
def do_I_have_anything(self):
118
self.events.append('do I have')
121
def get_have_list(self):
122
self.events.append('get have list')
125
def get_piece(self, index, begin, length):
126
self.events.append(('get piece', index, begin, length))
131
def test_skip_over_choke():
133
dco = DummyConnection(events)
134
dch = DummyChoker(events)
135
ds = DummyStorage(events)
136
u = Upload(dco, dch, ds, 100, 20, 5)
138
assert not u.is_interested()
140
assert u.is_interested()
141
u.got_request(0, 0, 3)
144
assert events == ['do I have', 'get have list',
145
('bitfield', [False, True]), 'interested']
147
def test_bad_piece():
149
dco = DummyConnection(events)
150
dch = DummyChoker(events)
151
ds = DummyStorage(events)
152
u = Upload(dco, dch, ds, 100, 20, 5)
154
assert not u.is_interested()
156
assert u.is_interested()
158
assert not u.is_choked()
159
u.got_request(0, 0, 4)
162
assert events == ['do I have', 'get have list',
163
('bitfield', [False, True]), 'interested', 'unchoke',
164
('get piece', 0, 0, 4), 'closed']
166
def test_still_rejected_after_unchoke():
168
dco = DummyConnection(events)
169
dch = DummyChoker(events)
170
ds = DummyStorage(events)
171
u = Upload(dco, dch, ds, 100, 20, 5)
173
assert not u.is_interested()
175
assert u.is_interested()
177
assert not u.is_choked()
178
u.got_request(0, 0, 3)
183
assert events == ['do I have', 'get have list',
184
('bitfield', [False, True]), 'interested', 'unchoke',
187
def test_sends_when_flushed():
189
dco = DummyConnection(events)
190
dch = DummyChoker(events)
191
ds = DummyStorage(events)
192
u = Upload(dco, dch, ds, 100, 20, 5)
195
u.got_request(0, 1, 3)
199
assert events == ['do I have', 'get have list',
200
('bitfield', [False, True]), 'unchoke', 'interested',
201
('get piece', 0, 1, 3), ('piece', 0, 1, 'aaa')]
203
def test_sends_immediately():
205
dco = DummyConnection(events)
206
dch = DummyChoker(events)
207
ds = DummyStorage(events)
208
u = Upload(dco, dch, ds, 100, 20, 5)
212
u.got_request(0, 1, 3)
213
assert events == ['do I have', 'get have list',
214
('bitfield', [False, True]), 'unchoke', 'interested',
215
('get piece', 0, 1, 3), ('piece', 0, 1, 'aaa')]
219
dco = DummyConnection(events)
220
dch = DummyChoker(events)
221
ds = DummyStorage(events)
222
u = Upload(dco, dch, ds, 100, 20, 5)
225
u.got_request(0, 1, 3)
226
u.got_cancel(0, 1, 3)
227
u.got_cancel(0, 1, 2)
230
assert events == ['do I have', 'get have list',
231
('bitfield', [False, True]), 'unchoke', 'interested']
233
def test_clears_on_not_interested():
235
dco = DummyConnection(events)
236
dch = DummyChoker(events)
237
ds = DummyStorage(events)
238
u = Upload(dco, dch, ds, 100, 20, 5)
241
u.got_request(0, 1, 3)
242
u.got_not_interested()
245
assert events == ['do I have', 'get have list',
246
('bitfield', [False, True]), 'unchoke', 'interested',
249
def test_close_when_sends_on_not_interested():
251
dco = DummyConnection(events)
252
dch = DummyChoker(events)
253
ds = DummyStorage(events)
254
u = Upload(dco, dch, ds, 100, 20, 5)
255
u.got_request(0, 1, 3)
256
assert events == ['do I have', 'get have list',
257
('bitfield', [False, True]), 'closed']
259
def test_close_over_max_length():
261
dco = DummyConnection(events)
262
dch = DummyChoker(events)
263
ds = DummyStorage(events)
264
u = Upload(dco, dch, ds, 100, 20, 5)
266
u.got_request(0, 1, 101)
267
assert events == ['do I have', 'get have list',
268
('bitfield', [False, True]), 'interested', 'closed']
270
def test_no_bitfield_on_start_empty():
272
dco = DummyConnection(events)
273
dch = DummyChoker(events)
274
ds = DummyStorage(events)
275
ds.do_I_have_anything = lambda: False
276
u = Upload(dco, dch, ds, 100, 20, 5)