~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/server.py

  • Committer: Andrew Bennetts
  • Date: 2010-08-31 07:12:18 UTC
  • mto: This revision was merged to the branch mainline in revision 5401.
  • Revision ID: andrew.bennetts@canonical.com-20100831071218-4kjieu3ejqcdmdom
Use has_id rather than __contains__; expand NEWS entry; add What's New entry.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
import errno
20
20
import os.path
21
 
import select
22
21
import socket
23
22
import sys
24
23
import threading
52
51
    hooks: An instance of SmartServerHooks.
53
52
    """
54
53
 
55
 
    def __init__(self, backing_transport, root_client_path='/'):
 
54
    def __init__(self, backing_transport, host='127.0.0.1', port=0,
 
55
                 root_client_path='/'):
56
56
        """Construct a new server.
57
57
 
58
58
        To actually start it running, call either start_background_thread or
59
59
        serve.
60
60
 
61
61
        :param backing_transport: The transport to serve.
 
62
        :param host: Name of the interface to listen on.
 
63
        :param port: TCP port to listen on, or 0 to allocate a transient port.
62
64
        :param root_client_path: The client path that will correspond to root
63
65
            of backing_transport.
64
66
        """
65
 
        self.backing_transport = backing_transport
66
 
        self.root_client_path = root_client_path
67
 
 
68
 
    def start_server(self, host, port):
69
 
        """Create the server listening socket.
70
 
 
71
 
        :param host: Name of the interface to listen on.
72
 
        :param port: TCP port to listen on, or 0 to allocate a transient port.
73
 
        """
74
67
        # let connections timeout so that we get a chance to terminate
75
68
        # Keep a reference to the exceptions we want to catch because the socket
76
69
        # module's globals get set to None during interpreter shutdown.
96
89
        self.port = self._sockname[1]
97
90
        self._server_socket.listen(1)
98
91
        self._server_socket.settimeout(1)
 
92
        self.backing_transport = backing_transport
99
93
        self._started = threading.Event()
100
94
        self._stopped = threading.Event()
 
95
        self.root_client_path = root_client_path
101
96
 
102
 
    def _backing_urls(self):
 
97
    def serve(self, thread_name_suffix=''):
 
98
        self._should_terminate = False
 
99
        # for hooks we are letting code know that a server has started (and
 
100
        # later stopped).
103
101
        # There are three interesting urls:
104
102
        # The URL the server can be contacted on. (e.g. bzr://host/)
105
103
        # The URL that a commit done on the same machine as the server will
115
113
        # The latter two urls are different aliases to the servers url,
116
114
        # so we group those in a list - as there might be more aliases
117
115
        # in the future.
118
 
        urls = [self.backing_transport.base]
 
116
        backing_urls = [self.backing_transport.base]
119
117
        try:
120
 
            urls.append(self.backing_transport.external_url())
 
118
            backing_urls.append(self.backing_transport.external_url())
121
119
        except errors.InProcessTransport:
122
120
            pass
123
 
        return urls
124
 
 
125
 
    def run_server_started_hooks(self, backing_urls=None):
126
 
        if backing_urls is None:
127
 
            backing_urls = self._backing_urls()
128
121
        for hook in SmartTCPServer.hooks['server_started']:
129
122
            hook(backing_urls, self.get_url())
130
123
        for hook in SmartTCPServer.hooks['server_started_ex']:
131
124
            hook(backing_urls, self)
132
 
 
133
 
    def run_server_stopped_hooks(self, backing_urls=None):
134
 
        if backing_urls is None:
135
 
            backing_urls = self._backing_urls()
136
 
        for hook in SmartTCPServer.hooks['server_stopped']:
137
 
            hook(backing_urls, self.get_url())
138
 
 
139
 
    def serve(self, thread_name_suffix=''):
140
 
        self._should_terminate = False
141
 
        # for hooks we are letting code know that a server has started (and
142
 
        # later stopped).
143
 
        self.run_server_started_hooks()
144
125
        self._started.set()
145
126
        try:
146
127
            try:
174
155
            except self._socket_error:
175
156
                # ignore errors on close
176
157
                pass
177
 
            self.run_server_stopped_hooks()
 
158
            for hook in SmartTCPServer.hooks['server_stopped']:
 
159
                hook(backing_urls, self.get_url())
178
160
 
179
161
    def get_url(self):
180
162
        """Return the url of the server"""
190
172
        thread_name = 'smart-server-child' + thread_name_suffix
191
173
        connection_thread = threading.Thread(
192
174
            None, handler.serve, name=thread_name)
193
 
        # FIXME: This thread is never joined, it should at least be collected
194
 
        # somewhere so that tests that want to check for leaked threads can get
195
 
        # rid of them -- vila 20100531
196
175
        connection_thread.setDaemon(True)
197
176
        connection_thread.start()
198
 
        return connection_thread
199
177
 
200
178
    def start_background_thread(self, thread_name_suffix=''):
201
179
        self._started.clear()
346
324
                host = medium.BZR_DEFAULT_INTERFACE
347
325
            if port is None:
348
326
                port = medium.BZR_DEFAULT_PORT
349
 
            smart_server = SmartTCPServer(self.transport)
350
 
            smart_server.start_server(host, port)
 
327
            smart_server = SmartTCPServer(self.transport, host=host, port=port)
351
328
            trace.note('listening on port: %s' % smart_server.port)
352
329
        self.smart_server = smart_server
353
330