74
80
return protocol_factory, bytes
77
class SmartServerStreamMedium(object):
83
def _get_line(read_bytes_func):
84
"""Read bytes using read_bytes_func until a newline byte.
86
This isn't particularly efficient, so should only be used when the
87
expected size of the line is quite short.
89
:returns: a tuple of two strs: (line, excess)
93
while newline_pos == -1:
94
new_bytes = read_bytes_func(1)
97
# Ran out of bytes before receiving a complete line.
99
newline_pos = bytes.find('\n')
100
line = bytes[:newline_pos+1]
101
excess = bytes[newline_pos+1:]
105
class SmartMedium(object):
106
"""Base class for smart protocol media, both client- and server-side."""
109
self._push_back_buffer = None
111
def _push_back(self, bytes):
112
"""Return unused bytes to the medium, because they belong to the next
115
This sets the _push_back_buffer to the given bytes.
117
if self._push_back_buffer is not None:
118
raise AssertionError(
119
"_push_back called when self._push_back_buffer is %r"
120
% (self._push_back_buffer,))
123
self._push_back_buffer = bytes
125
def _get_push_back_buffer(self):
126
if self._push_back_buffer == '':
127
raise AssertionError(
128
'%s._push_back_buffer should never be the empty string, '
129
'which can be confused with EOF' % (self,))
130
bytes = self._push_back_buffer
131
self._push_back_buffer = None
134
def read_bytes(self, desired_count):
135
"""Read some bytes from this medium.
137
:returns: some bytes, possibly more or less than the number requested
138
in 'desired_count' depending on the medium.
140
if self._push_back_buffer is not None:
141
return self._get_push_back_buffer()
142
bytes_to_read = min(desired_count, _MAX_READ_SIZE)
143
return self._read_bytes(bytes_to_read)
145
def _read_bytes(self, count):
146
raise NotImplementedError(self._read_bytes)
149
"""Read bytes from this request's response until a newline byte.
151
This isn't particularly efficient, so should only be used when the
152
expected size of the line is quite short.
154
:returns: a string of bytes ending in a newline (byte 0x0A).
156
line, excess = _get_line(self.read_bytes)
157
self._push_back(excess)
161
class SmartServerStreamMedium(SmartMedium):
78
162
"""Handles smart commands coming over a stream.
80
164
The stream may be a pipe connected to sshd, or a tcp socket, or an
101
185
self.backing_transport = backing_transport
102
186
self.root_client_path = root_client_path
103
187
self.finished = False
104
self._push_back_buffer = None
106
def _push_back(self, bytes):
107
"""Return unused bytes to the medium, because they belong to the next
110
This sets the _push_back_buffer to the given bytes.
112
if self._push_back_buffer is not None:
113
raise AssertionError(
114
"_push_back called when self._push_back_buffer is %r"
115
% (self._push_back_buffer,))
118
self._push_back_buffer = bytes
120
def _get_push_back_buffer(self):
121
if self._push_back_buffer == '':
122
raise AssertionError(
123
'%s._push_back_buffer should never be the empty string, '
124
'which can be confused with EOF' % (self,))
125
bytes = self._push_back_buffer
126
self._push_back_buffer = None
188
SmartMedium.__init__(self)
130
191
"""Serve requests until the client disconnects."""
171
232
"""Called when an unhandled exception from the protocol occurs."""
172
233
raise NotImplementedError(self.terminate_due_to_error)
174
def _get_bytes(self, desired_count):
235
def _read_bytes(self, desired_count):
175
236
"""Get some bytes from the medium.
177
238
:param desired_count: number of bytes we want to read.
179
raise NotImplementedError(self._get_bytes)
182
"""Read bytes from this request's response until a newline byte.
184
This isn't particularly efficient, so should only be used when the
185
expected size of the line is quite short.
187
:returns: a string of bytes ending in a newline (byte 0x0A).
191
while newline_pos == -1:
192
new_bytes = self._get_bytes(1)
195
# Ran out of bytes before receiving a complete line.
197
newline_pos = bytes.find('\n')
198
line = bytes[:newline_pos+1]
199
self._push_back(bytes[newline_pos+1:])
240
raise NotImplementedError(self._read_bytes)
203
243
class SmartServerSocketStreamMedium(SmartServerStreamMedium):
216
256
def _serve_one_request_unguarded(self, protocol):
217
257
while protocol.next_read_size():
218
bytes = self._get_bytes(4096)
258
# We can safely try to read large chunks. If there is less data
259
# than _MAX_READ_SIZE ready, the socket wil just return a short
260
# read immediately rather than block.
261
bytes = self.read_bytes(_MAX_READ_SIZE)
220
263
self.finished = True
224
267
self._push_back(protocol.unused_data)
226
def _get_bytes(self, desired_count):
227
if self._push_back_buffer is not None:
228
return self._get_push_back_buffer()
269
def _read_bytes(self, desired_count):
229
270
# We ignore the desired_count because on sockets it's more efficient to
231
return self.socket.recv(4096)
271
# read large chunks (of _MAX_READ_SIZE bytes) at a time.
272
return self.socket.recv(_MAX_READ_SIZE)
233
274
def terminate_due_to_error(self):
234
275
# TODO: This should log to a server log file, but no such thing
235
276
# exists yet. Andrew Bennetts 2006-09-29.
263
304
def _serve_one_request_unguarded(self, protocol):
306
# We need to be careful not to read past the end of the current
307
# request, or else the read from the pipe will block, so we use
308
# protocol.next_read_size().
265
309
bytes_to_read = protocol.next_read_size()
266
310
if bytes_to_read == 0:
267
311
# Finished serving this request.
268
312
self._out.flush()
270
bytes = self._get_bytes(bytes_to_read)
314
bytes = self.read_bytes(bytes_to_read)
272
316
# Connection has been closed.
273
317
self.finished = True
276
320
protocol.accept_bytes(bytes)
278
def _get_bytes(self, desired_count):
279
if self._push_back_buffer is not None:
280
return self._get_push_back_buffer()
322
def _read_bytes(self, desired_count):
281
323
return self._in.read(desired_count)
283
325
def terminate_due_to_error(self):
397
439
return self._read_bytes(count)
399
441
def _read_bytes(self, count):
400
"""Helper for read_bytes.
442
"""Helper for SmartClientMediumRequest.read_bytes.
402
444
read_bytes checks the state of the request to determing if bytes
403
445
should be read. After that it hands off to _read_bytes to do the
448
By default this forwards to self._medium.read_bytes because we are
449
operating on the medium's stream.
406
raise NotImplementedError(self._read_bytes)
451
return self._medium.read_bytes(count)
408
453
def read_line(self):
409
"""Read bytes from this request's response until a newline byte.
454
line = self._read_line()
455
if not line.endswith('\n'):
456
# end of file encountered reading from server
457
raise errors.ConnectionReset(
458
"please check connectivity and permissions",
459
"(and try -Dhpss if further diagnosis is required)")
462
def _read_line(self):
463
"""Helper for SmartClientMediumRequest.read_line.
411
This isn't particularly efficient, so should only be used when the
412
expected size of the line is quite short.
414
:returns: a string of bytes ending in a newline (byte 0x0A).
465
By default this forwards to self._medium._get_line because we are
466
operating on the medium's stream.
416
# XXX: this duplicates SmartClientRequestProtocolOne._recv_tuple
418
while not line or line[-1] != '\n':
419
new_char = self.read_bytes(1)
422
# end of file encountered reading from server
423
raise errors.ConnectionReset(
424
"please check connectivity and permissions",
425
"(and try -Dhpss if further diagnosis is required)")
429
class SmartClientMedium(object):
468
return self._medium._get_line()
471
class SmartClientMedium(SmartMedium):
430
472
"""Smart client is a medium for sending smart protocol requests over."""
432
474
def __init__(self, base):