/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1
# Copyright (C) 2006 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
17
"""The 'medium' layer for the smart servers and clients.
18
19
"Medium" here is the noun meaning "a means of transmission", not the adjective
20
for "the quality between big and small."
21
22
Media carry the bytes of the requests somehow (e.g. via TCP, wrapped in HTTP, or
23
over SSH), and pass them to and from the protocol logic.  See the overview in
24
bzrlib/transport/smart/__init__.py.
25
"""
26
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
27
import os
28
import socket
2018.5.162 by Andrew Bennetts
Add some missing _ensure_real calls, and a missing import.
29
import sys
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
30
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
31
from bzrlib import (
32
    errors,
3118.2.1 by Andrew Bennetts
(andrew) Fix #115781 by passing no more than 64k at a time to socket.sendall.
33
    osutils,
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
34
    symbol_versioning,
35
    )
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
36
from bzrlib.smart.protocol import (
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
37
    MESSAGE_VERSION_THREE,
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
38
    REQUEST_VERSION_TWO,
3241.1.1 by Andrew Bennetts
Shift protocol version querying from RemoteBzrDirFormat into SmartClientMedium.
39
    SmartClientRequestProtocolOne,
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
40
    SmartServerRequestProtocolOne,
41
    SmartServerRequestProtocolTwo,
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
42
    build_server_protocol_three
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
43
    )
3066.2.1 by John Arbash Meinel
We don't require paramiko for bzr+ssh.
44
from bzrlib.transport import ssh
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
45
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
46
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
47
class SmartServerStreamMedium(object):
48
    """Handles smart commands coming over a stream.
49
50
    The stream may be a pipe connected to sshd, or a tcp socket, or an
51
    in-process fifo for testing.
52
53
    One instance is created for each connected client; it can serve multiple
54
    requests in the lifetime of the connection.
55
56
    The server passes requests through to an underlying backing transport, 
57
    which will typically be a LocalTransport looking at the server's filesystem.
58
    """
59
60
    def __init__(self, backing_transport):
61
        """Construct new server.
62
63
        :param backing_transport: Transport for the directory served.
64
        """
65
        # backing_transport could be passed to serve instead of __init__
66
        self.backing_transport = backing_transport
67
        self.finished = False
3236.3.2 by Andrew Bennetts
Fix SmartServerPipeStreamMedium._get_line too.
68
        self.push_back = None
69
70
    def _push_back(self, bytes):
71
        assert self.push_back is None, (
72
            "_push_back called when self.push is %r" % (self.push_back,))
73
        if bytes == '':
74
            return
75
        self.push_back = bytes
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
76
77
    def serve(self):
78
        """Serve requests until the client disconnects."""
79
        # Keep a reference to stderr because the sys module's globals get set to
80
        # None during interpreter shutdown.
81
        from sys import stderr
82
        try:
83
            while not self.finished:
2432.2.3 by Andrew Bennetts
Merge from bzr.dev.
84
                server_protocol = self._build_protocol()
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
85
                self._serve_one_request(server_protocol)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
86
        except Exception, e:
87
            stderr.write("%s terminating on exception %s\n" % (self, e))
88
            raise
89
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
90
    def _build_protocol(self):
2432.2.8 by Andrew Bennetts
NEWS entry, greatly improved docstring in bzrlib.smart.
91
        """Identifies the version of the incoming request, and returns an
92
        a protocol object that can interpret it.
93
94
        If more bytes than the version prefix of the request are read, they will
95
        be fed into the protocol before it is returned.
96
97
        :returns: a SmartServerRequestProtocol.
98
        """
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
99
        # Identify the protocol version.
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
100
        bytes = self._get_line()
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
101
        if bytes.startswith(MESSAGE_VERSION_THREE):
102
            protocol_factory = build_server_protocol_three
103
            bytes = bytes[len(MESSAGE_VERSION_THREE):]
104
        elif bytes.startswith(REQUEST_VERSION_TWO):
105
            protocol_factory = SmartServerRequestProtocolTwo
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
106
            bytes = bytes[len(REQUEST_VERSION_TWO):]
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
107
        else:
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
108
            protocol_factory = SmartServerRequestProtocolOne
109
        protocol = protocol_factory(self.backing_transport, self._write_out)
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
110
        protocol.accept_bytes(bytes)
111
        return protocol
112
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
113
    def _serve_one_request(self, protocol):
114
        """Read one request from input, process, send back a response.
115
        
116
        :param protocol: a SmartServerRequestProtocol.
117
        """
118
        try:
119
            self._serve_one_request_unguarded(protocol)
120
        except KeyboardInterrupt:
121
            raise
122
        except Exception, e:
123
            self.terminate_due_to_error()
124
125
    def terminate_due_to_error(self):
126
        """Called when an unhandled exception from the protocol occurs."""
127
        raise NotImplementedError(self.terminate_due_to_error)
128
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
129
    def _get_bytes(self, desired_count):
130
        """Get some bytes from the medium.
131
132
        :param desired_count: number of bytes we want to read.
133
        """
134
        raise NotImplementedError(self._get_bytes)
135
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
136
    def _get_line(self):
137
        """Read bytes from this request's response until a newline byte.
138
        
139
        This isn't particularly efficient, so should only be used when the
140
        expected size of the line is quite short.
141
142
        :returns: a string of bytes ending in a newline (byte 0x0A).
143
        """
3236.3.2 by Andrew Bennetts
Fix SmartServerPipeStreamMedium._get_line too.
144
        newline_pos = -1
145
        bytes = ''
146
        while newline_pos == -1:
147
            new_bytes = self._get_bytes(1)
148
            bytes += new_bytes
149
            if new_bytes == '':
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
150
                # Ran out of bytes before receiving a complete line.
3236.3.2 by Andrew Bennetts
Fix SmartServerPipeStreamMedium._get_line too.
151
                return bytes
152
            newline_pos = bytes.find('\n')
153
        line = bytes[:newline_pos+1]
154
        self._push_back(bytes[newline_pos+1:])
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
155
        return line
3236.3.2 by Andrew Bennetts
Fix SmartServerPipeStreamMedium._get_line too.
156
 
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
157
158
class SmartServerSocketStreamMedium(SmartServerStreamMedium):
159
160
    def __init__(self, sock, backing_transport):
161
        """Constructor.
162
163
        :param sock: the socket the server will read from.  It will be put
164
            into blocking mode.
165
        """
166
        SmartServerStreamMedium.__init__(self, backing_transport)
3195.3.18 by Andrew Bennetts
call_with_body_bytes now works with v3 (e.g. test_copy_content_remote_to_local passes). Lots of debugging cruft, though.
167
        self.push_back = None
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
168
        sock.setblocking(True)
169
        self.socket = sock
170
3195.3.18 by Andrew Bennetts
call_with_body_bytes now works with v3 (e.g. test_copy_content_remote_to_local passes). Lots of debugging cruft, though.
171
    def _push_back(self, bytes):
172
        assert self.push_back is None
173
        if bytes == '':
174
            return
175
        self.push_back = bytes
176
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
177
    def _serve_one_request_unguarded(self, protocol):
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
178
        #print >> sys.stderr, '***', protocol
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
179
        while protocol.next_read_size():
180
            if self.push_back:
181
                protocol.accept_bytes(self.push_back)
3195.3.18 by Andrew Bennetts
call_with_body_bytes now works with v3 (e.g. test_copy_content_remote_to_local passes). Lots of debugging cruft, though.
182
                self.push_back = None
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
183
            else:
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
184
                bytes = self._get_bytes(4096)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
185
                #print >> sys.stderr, '---', repr(bytes)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
186
                if bytes == '':
187
                    self.finished = True
188
                    return
189
                protocol.accept_bytes(bytes)
190
        
3195.3.18 by Andrew Bennetts
call_with_body_bytes now works with v3 (e.g. test_copy_content_remote_to_local passes). Lots of debugging cruft, though.
191
        self._push_back(protocol.excess_buffer)
192
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
193
    def _get_bytes(self, desired_count):
3195.3.18 by Andrew Bennetts
call_with_body_bytes now works with v3 (e.g. test_copy_content_remote_to_local passes). Lots of debugging cruft, though.
194
        pr('_get_bytes...')
195
        if self.push_back is not None:
3236.3.1 by Andrew Bennetts
Fix a bug in SmartServerSocketStreamMedium._get_line, and add some asserts to catch this sort of mistake sooner.
196
            assert self.push_back != '', (
197
                'self.push_back should never be the empty string, which can be '
198
                'confused with EOF')
3195.3.18 by Andrew Bennetts
call_with_body_bytes now works with v3 (e.g. test_copy_content_remote_to_local passes). Lots of debugging cruft, though.
199
            bytes = self.push_back
200
            self.push_back = None
201
            pr('...: (push back) %r' % bytes)
202
            return bytes
203
        bytes = self.socket.recv(desired_count)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
204
        #import sys; print >> sys.stderr, 'bytes:', repr(bytes)
3195.3.18 by Andrew Bennetts
call_with_body_bytes now works with v3 (e.g. test_copy_content_remote_to_local passes). Lots of debugging cruft, though.
205
        pr('...: (recv) %r' % bytes)
3195.3.17 by Andrew Bennetts
Some tests now passing using protocol 3.
206
        return bytes
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
207
    
208
    def terminate_due_to_error(self):
209
        self.socket.close()
210
        self.finished = True
211
212
    def _write_out(self, bytes):
3118.2.1 by Andrew Bennetts
(andrew) Fix #115781 by passing no more than 64k at a time to socket.sendall.
213
        osutils.send_all(self.socket, bytes)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
214
215
216
class SmartServerPipeStreamMedium(SmartServerStreamMedium):
217
218
    def __init__(self, in_file, out_file, backing_transport):
219
        """Construct new server.
220
221
        :param in_file: Python file from which requests can be read.
222
        :param out_file: Python file to write responses.
223
        :param backing_transport: Transport for the directory served.
224
        """
225
        SmartServerStreamMedium.__init__(self, backing_transport)
2018.5.161 by Andrew Bennetts
Reinstate forcing binary mode on windows in SmartServerStreamMedium.
226
        if sys.platform == 'win32':
227
            # force binary mode for files
228
            import msvcrt
229
            for f in (in_file, out_file):
230
                fileno = getattr(f, 'fileno', None)
231
                if fileno:
232
                    msvcrt.setmode(fileno(), os.O_BINARY)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
233
        self._in = in_file
234
        self._out = out_file
235
236
    def _serve_one_request_unguarded(self, protocol):
237
        while True:
238
            bytes_to_read = protocol.next_read_size()
239
            if bytes_to_read == 0:
240
                # Finished serving this request.
241
                self._out.flush()
242
                return
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
243
            bytes = self._get_bytes(bytes_to_read)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
244
            if bytes == '':
245
                # Connection has been closed.
246
                self.finished = True
247
                self._out.flush()
248
                return
249
            protocol.accept_bytes(bytes)
250
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
251
    def _get_bytes(self, desired_count):
3236.3.2 by Andrew Bennetts
Fix SmartServerPipeStreamMedium._get_line too.
252
        if self.push_back is not None:
253
            assert self.push_back != '', (
254
                'self.push_back should never be the empty string, which can be '
255
                'confused with EOF')
256
            bytes = self.push_back
257
            self.push_back = None
258
            return bytes
2432.2.2 by Andrew Bennetts
Smart server mediums now detect which protocol version a request is and dispatch accordingly.
259
        return self._in.read(desired_count)
260
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
261
    def terminate_due_to_error(self):
262
        # TODO: This should log to a server log file, but no such thing
263
        # exists yet.  Andrew Bennetts 2006-09-29.
264
        self._out.close()
265
        self.finished = True
266
267
    def _write_out(self, bytes):
268
        self._out.write(bytes)
269
270
271
class SmartClientMediumRequest(object):
272
    """A request on a SmartClientMedium.
273
274
    Each request allows bytes to be provided to it via accept_bytes, and then
275
    the response bytes to be read via read_bytes.
276
277
    For instance:
278
    request.accept_bytes('123')
279
    request.finished_writing()
280
    result = request.read_bytes(3)
281
    request.finished_reading()
282
283
    It is up to the individual SmartClientMedium whether multiple concurrent
284
    requests can exist. See SmartClientMedium.get_request to obtain instances 
285
    of SmartClientMediumRequest, and the concrete Medium you are using for 
286
    details on concurrency and pipelining.
287
    """
288
289
    def __init__(self, medium):
290
        """Construct a SmartClientMediumRequest for the medium medium."""
291
        self._medium = medium
292
        # we track state by constants - we may want to use the same
293
        # pattern as BodyReader if it gets more complex.
294
        # valid states are: "writing", "reading", "done"
295
        self._state = "writing"
296
297
    def accept_bytes(self, bytes):
298
        """Accept bytes for inclusion in this request.
299
300
        This method may not be be called after finished_writing() has been
301
        called.  It depends upon the Medium whether or not the bytes will be
302
        immediately transmitted. Message based Mediums will tend to buffer the
303
        bytes until finished_writing() is called.
304
305
        :param bytes: A bytestring.
306
        """
307
        if self._state != "writing":
308
            raise errors.WritingCompleted(self)
309
        self._accept_bytes(bytes)
310
311
    def _accept_bytes(self, bytes):
312
        """Helper for accept_bytes.
313
314
        Accept_bytes checks the state of the request to determing if bytes
315
        should be accepted. After that it hands off to _accept_bytes to do the
316
        actual acceptance.
317
        """
318
        raise NotImplementedError(self._accept_bytes)
319
320
    def finished_reading(self):
321
        """Inform the request that all desired data has been read.
322
323
        This will remove the request from the pipeline for its medium (if the
324
        medium supports pipelining) and any further calls to methods on the
325
        request will raise ReadingCompleted.
326
        """
327
        if self._state == "writing":
328
            raise errors.WritingNotComplete(self)
329
        if self._state != "reading":
330
            raise errors.ReadingCompleted(self)
331
        self._state = "done"
332
        self._finished_reading()
333
334
    def _finished_reading(self):
335
        """Helper for finished_reading.
336
337
        finished_reading checks the state of the request to determine if 
338
        finished_reading is allowed, and if it is hands off to _finished_reading
339
        to perform the action.
340
        """
341
        raise NotImplementedError(self._finished_reading)
342
343
    def finished_writing(self):
344
        """Finish the writing phase of this request.
345
346
        This will flush all pending data for this request along the medium.
347
        After calling finished_writing, you may not call accept_bytes anymore.
348
        """
349
        if self._state != "writing":
350
            raise errors.WritingCompleted(self)
351
        self._state = "reading"
352
        self._finished_writing()
353
354
    def _finished_writing(self):
355
        """Helper for finished_writing.
356
357
        finished_writing checks the state of the request to determine if 
358
        finished_writing is allowed, and if it is hands off to _finished_writing
359
        to perform the action.
360
        """
361
        raise NotImplementedError(self._finished_writing)
362
363
    def read_bytes(self, count):
364
        """Read bytes from this requests response.
365
366
        This method will block and wait for count bytes to be read. It may not
367
        be invoked until finished_writing() has been called - this is to ensure
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
368
        a message-based approach to requests, for compatibility with message
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
369
        based mediums like HTTP.
370
        """
371
        if self._state == "writing":
372
            raise errors.WritingNotComplete(self)
373
        if self._state != "reading":
374
            raise errors.ReadingCompleted(self)
375
        return self._read_bytes(count)
376
377
    def _read_bytes(self, count):
378
        """Helper for read_bytes.
379
380
        read_bytes checks the state of the request to determing if bytes
381
        should be read. After that it hands off to _read_bytes to do the
382
        actual read.
383
        """
384
        raise NotImplementedError(self._read_bytes)
385
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
386
    def read_line(self):
387
        """Read bytes from this request's response until a newline byte.
388
        
389
        This isn't particularly efficient, so should only be used when the
390
        expected size of the line is quite short.
391
392
        :returns: a string of bytes ending in a newline (byte 0x0A).
393
        """
394
        # XXX: this duplicates SmartClientRequestProtocolOne._recv_tuple
395
        line = ''
396
        while not line or line[-1] != '\n':
397
            new_char = self.read_bytes(1)
398
            line += new_char
399
            if new_char == '':
3195.2.1 by Andrew Bennetts
Improve test coverage, and fix a bug revealed by the improved coverage.
400
                # end of file encountered reading from server
401
                raise errors.ConnectionReset(
402
                    "please check connectivity and permissions",
403
                    "(and try -Dhpss if further diagnosis is required)")
2432.2.7 by Andrew Bennetts
Use less confusing version strings, and define REQUEST_VERSION_TWO/RESPONSE_VERSION_TWO constants for them.
404
        return line
405
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
406
407
class SmartClientMedium(object):
408
    """Smart client is a medium for sending smart protocol requests over."""
409
3241.1.1 by Andrew Bennetts
Shift protocol version querying from RemoteBzrDirFormat into SmartClientMedium.
410
    def __init__(self):
411
        super(SmartClientMedium, self).__init__()
412
        self._protocol_version = None
413
414
    def protocol_version(self):
415
        """Find out the best protocol version to use."""
416
        if self._protocol_version is None:
417
            medium_request = self.get_request()
3241.1.2 by Andrew Bennetts
Tidy comments.
418
            # Send a 'hello' request in protocol version one, for maximum
419
            # backwards compatibility.
3241.1.1 by Andrew Bennetts
Shift protocol version querying from RemoteBzrDirFormat into SmartClientMedium.
420
            client_protocol = SmartClientRequestProtocolOne(medium_request)
421
            self._protocol_version = client_protocol.query_version()
422
        return self._protocol_version
423
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
424
    def disconnect(self):
425
        """If this medium maintains a persistent connection, close it.
426
        
427
        The default implementation does nothing.
428
        """
429
        
430
431
class SmartClientStreamMedium(SmartClientMedium):
432
    """Stream based medium common class.
433
434
    SmartClientStreamMediums operate on a stream. All subclasses use a common
435
    SmartClientStreamMediumRequest for their requests, and should implement
436
    _accept_bytes and _read_bytes to allow the request objects to send and
437
    receive bytes.
438
    """
439
440
    def __init__(self):
3241.1.1 by Andrew Bennetts
Shift protocol version querying from RemoteBzrDirFormat into SmartClientMedium.
441
        SmartClientMedium.__init__(self)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
442
        self._current_request = None
3213.1.1 by Andrew Bennetts
Recover (by reconnecting) if the server turns out not to understand the new requests in 1.2 that send bodies.
443
        # Be optimistic: we assume the remote end can accept new remote
444
        # requests until we get an error saying otherwise.  (1.2 adds some
445
        # requests that send bodies, which confuses older servers.)
446
        self._remote_is_at_least_1_2 = True
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
447
448
    def accept_bytes(self, bytes):
449
        self._accept_bytes(bytes)
450
451
    def __del__(self):
452
        """The SmartClientStreamMedium knows how to close the stream when it is
453
        finished with it.
454
        """
455
        self.disconnect()
456
457
    def _flush(self):
458
        """Flush the output stream.
459
        
460
        This method is used by the SmartClientStreamMediumRequest to ensure that
461
        all data for a request is sent, to avoid long timeouts or deadlocks.
462
        """
463
        raise NotImplementedError(self._flush)
464
465
    def get_request(self):
466
        """See SmartClientMedium.get_request().
467
468
        SmartClientStreamMedium always returns a SmartClientStreamMediumRequest
469
        for get_request.
470
        """
471
        return SmartClientStreamMediumRequest(self)
472
473
    def read_bytes(self, count):
474
        return self._read_bytes(count)
475
476
477
class SmartSimplePipesClientMedium(SmartClientStreamMedium):
478
    """A client medium using simple pipes.
479
    
480
    This client does not manage the pipes: it assumes they will always be open.
481
    """
482
483
    def __init__(self, readable_pipe, writeable_pipe):
484
        SmartClientStreamMedium.__init__(self)
485
        self._readable_pipe = readable_pipe
486
        self._writeable_pipe = writeable_pipe
487
488
    def _accept_bytes(self, bytes):
489
        """See SmartClientStreamMedium.accept_bytes."""
490
        self._writeable_pipe.write(bytes)
491
492
    def _flush(self):
493
        """See SmartClientStreamMedium._flush()."""
494
        self._writeable_pipe.flush()
495
496
    def _read_bytes(self, count):
497
        """See SmartClientStreamMedium._read_bytes."""
498
        return self._readable_pipe.read(count)
499
500
501
class SmartSSHClientMedium(SmartClientStreamMedium):
502
    """A client medium using SSH."""
503
    
504
    def __init__(self, host, port=None, username=None, password=None,
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
505
            vendor=None, bzr_remote_path=None):
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
506
        """Creates a client that will connect on the first use.
507
        
508
        :param vendor: An optional override for the ssh vendor to use. See
509
            bzrlib.transport.ssh for details on ssh vendors.
510
        """
511
        SmartClientStreamMedium.__init__(self)
512
        self._connected = False
513
        self._host = host
514
        self._password = password
515
        self._port = port
516
        self._username = username
517
        self._read_from = None
518
        self._ssh_connection = None
519
        self._vendor = vendor
520
        self._write_to = None
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
521
        self._bzr_remote_path = bzr_remote_path
522
        if self._bzr_remote_path is None:
523
            symbol_versioning.warn(
524
                'bzr_remote_path is required as of bzr 0.92',
525
                DeprecationWarning, stacklevel=2)
526
            self._bzr_remote_path = os.environ.get('BZR_REMOTE_PATH', 'bzr')
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
527
528
    def _accept_bytes(self, bytes):
529
        """See SmartClientStreamMedium.accept_bytes."""
530
        self._ensure_connection()
531
        self._write_to.write(bytes)
532
533
    def disconnect(self):
534
        """See SmartClientMedium.disconnect()."""
535
        if not self._connected:
536
            return
537
        self._read_from.close()
538
        self._write_to.close()
539
        self._ssh_connection.close()
540
        self._connected = False
541
542
    def _ensure_connection(self):
543
        """Connect this medium if not already connected."""
544
        if self._connected:
545
            return
546
        if self._vendor is None:
547
            vendor = ssh._get_ssh_vendor()
548
        else:
549
            vendor = self._vendor
550
        self._ssh_connection = vendor.connect_ssh(self._username,
551
                self._password, self._host, self._port,
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
552
                command=[self._bzr_remote_path, 'serve', '--inet',
553
                         '--directory=/', '--allow-writes'])
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
554
        self._read_from, self._write_to = \
555
            self._ssh_connection.get_filelike_channels()
556
        self._connected = True
557
558
    def _flush(self):
559
        """See SmartClientStreamMedium._flush()."""
560
        self._write_to.flush()
561
562
    def _read_bytes(self, count):
563
        """See SmartClientStreamMedium.read_bytes."""
564
        if not self._connected:
565
            raise errors.MediumNotConnected(self)
566
        return self._read_from.read(count)
567
568
3004.2.1 by Vincent Ladeuil
Fix 150860 by leaving port as user specified it.
569
# Port 4155 is the default port for bzr://, registered with IANA.
570
BZR_DEFAULT_INTERFACE = '0.0.0.0'
571
BZR_DEFAULT_PORT = 4155
572
573
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
574
class SmartTCPClientMedium(SmartClientStreamMedium):
575
    """A client medium using TCP."""
576
    
577
    def __init__(self, host, port):
578
        """Creates a client that will connect on the first use."""
579
        SmartClientStreamMedium.__init__(self)
580
        self._connected = False
581
        self._host = host
582
        self._port = port
583
        self._socket = None
584
585
    def _accept_bytes(self, bytes):
586
        """See SmartClientMedium.accept_bytes."""
587
        self._ensure_connection()
3118.2.1 by Andrew Bennetts
(andrew) Fix #115781 by passing no more than 64k at a time to socket.sendall.
588
        osutils.send_all(self._socket, bytes)
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
589
590
    def disconnect(self):
591
        """See SmartClientMedium.disconnect()."""
592
        if not self._connected:
593
            return
594
        self._socket.close()
595
        self._socket = None
596
        self._connected = False
597
598
    def _ensure_connection(self):
599
        """Connect this medium if not already connected."""
600
        if self._connected:
601
            return
602
        self._socket = socket.socket()
603
        self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
3004.2.1 by Vincent Ladeuil
Fix 150860 by leaving port as user specified it.
604
        if self._port is None:
605
            port = BZR_DEFAULT_PORT
606
        else:
607
            port = int(self._port)
3180.1.1 by Andrew Bennetts
Don't traceback on host name errors when connecting to bzr://...
608
        try:
609
            self._socket.connect((self._host, port))
610
        except socket.error, err:
611
            # socket errors either have a (string) or (errno, string) as their
612
            # args.
613
            if type(err.args) is str:
614
                err_msg = err.args
615
            else:
616
                err_msg = err.args[1]
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
617
            raise errors.ConnectionError("failed to connect to %s:%d: %s" %
3180.1.1 by Andrew Bennetts
Don't traceback on host name errors when connecting to bzr://...
618
                    (self._host, port, err_msg))
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
619
        self._connected = True
620
621
    def _flush(self):
622
        """See SmartClientStreamMedium._flush().
623
        
624
        For TCP we do no flushing. We may want to turn off TCP_NODELAY and 
625
        add a means to do a flush, but that can be done in the future.
626
        """
627
628
    def _read_bytes(self, count):
629
        """See SmartClientMedium.read_bytes."""
630
        if not self._connected:
631
            raise errors.MediumNotConnected(self)
632
        return self._socket.recv(count)
633
634
635
class SmartClientStreamMediumRequest(SmartClientMediumRequest):
636
    """A SmartClientMediumRequest that works with an SmartClientStreamMedium."""
637
638
    def __init__(self, medium):
639
        SmartClientMediumRequest.__init__(self, medium)
640
        # check that we are safe concurrency wise. If some streams start
641
        # allowing concurrent requests - i.e. via multiplexing - then this
642
        # assert should be moved to SmartClientStreamMedium.get_request,
643
        # and the setting/unsetting of _current_request likewise moved into
644
        # that class : but its unneeded overhead for now. RBC 20060922
645
        if self._medium._current_request is not None:
646
            raise errors.TooManyConcurrentRequests(self._medium)
647
        self._medium._current_request = self
648
649
    def _accept_bytes(self, bytes):
650
        """See SmartClientMediumRequest._accept_bytes.
651
        
652
        This forwards to self._medium._accept_bytes because we are operating
653
        on the mediums stream.
654
        """
655
        self._medium._accept_bytes(bytes)
656
657
    def _finished_reading(self):
658
        """See SmartClientMediumRequest._finished_reading.
659
660
        This clears the _current_request on self._medium to allow a new 
661
        request to be created.
662
        """
663
        assert self._medium._current_request is self
664
        self._medium._current_request = None
665
        
666
    def _finished_writing(self):
667
        """See SmartClientMediumRequest._finished_writing.
668
669
        This invokes self._medium._flush to ensure all bytes are transmitted.
670
        """
671
        self._medium._flush()
672
673
    def _read_bytes(self, count):
674
        """See SmartClientMediumRequest._read_bytes.
675
        
676
        This forwards to self._medium._read_bytes because we are operating
677
        on the mediums stream.
678
        """
679
        return self._medium._read_bytes(count)
680
3195.3.18 by Andrew Bennetts
call_with_body_bytes now works with v3 (e.g. test_copy_content_remote_to_local passes). Lots of debugging cruft, though.
681
from thread import get_ident
682
def pr(*args):
683
    return
684
    print '%x' % get_ident(),
685
    for arg in args:
686
        print arg,
687
    print