~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/server.py

Merge bzr.dev into cleanup

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
21
22
import socket
22
23
import sys
23
24
import threading
51
52
    hooks: An instance of SmartServerHooks.
52
53
    """
53
54
 
54
 
    def __init__(self, backing_transport, host='127.0.0.1', port=0,
55
 
                 root_client_path='/'):
 
55
    def __init__(self, backing_transport, 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 root_client_path: The client path that will correspond to root
 
63
            of backing_transport.
 
64
        """
 
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
 
62
71
        :param host: Name of the interface to listen on.
63
72
        :param port: TCP port to listen on, or 0 to allocate a transient port.
64
 
        :param root_client_path: The client path that will correspond to root
65
 
            of backing_transport.
66
73
        """
67
74
        # let connections timeout so that we get a chance to terminate
68
75
        # Keep a reference to the exceptions we want to catch because the socket
89
96
        self.port = self._sockname[1]
90
97
        self._server_socket.listen(1)
91
98
        self._server_socket.settimeout(1)
92
 
        self.backing_transport = backing_transport
93
99
        self._started = threading.Event()
94
100
        self._stopped = threading.Event()
95
 
        self.root_client_path = root_client_path
96
101
 
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).
 
102
    def _backing_urls(self):
101
103
        # There are three interesting urls:
102
104
        # The URL the server can be contacted on. (e.g. bzr://host/)
103
105
        # The URL that a commit done on the same machine as the server will
113
115
        # The latter two urls are different aliases to the servers url,
114
116
        # so we group those in a list - as there might be more aliases
115
117
        # in the future.
116
 
        backing_urls = [self.backing_transport.base]
 
118
        urls = [self.backing_transport.base]
117
119
        try:
118
 
            backing_urls.append(self.backing_transport.external_url())
 
120
            urls.append(self.backing_transport.external_url())
119
121
        except errors.InProcessTransport:
120
122
            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()
121
128
        for hook in SmartTCPServer.hooks['server_started']:
122
129
            hook(backing_urls, self.get_url())
123
130
        for hook in SmartTCPServer.hooks['server_started_ex']:
124
131
            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()
125
144
        self._started.set()
126
145
        try:
127
146
            try:
155
174
            except self._socket_error:
156
175
                # ignore errors on close
157
176
                pass
158
 
            for hook in SmartTCPServer.hooks['server_stopped']:
159
 
                hook(backing_urls, self.get_url())
 
177
            self.run_server_stopped_hooks()
160
178
 
161
179
    def get_url(self):
162
180
        """Return the url of the server"""
172
190
        thread_name = 'smart-server-child' + thread_name_suffix
173
191
        connection_thread = threading.Thread(
174
192
            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
175
196
        connection_thread.setDaemon(True)
176
197
        connection_thread.start()
 
198
        return connection_thread
177
199
 
178
200
    def start_background_thread(self, thread_name_suffix=''):
179
201
        self._started.clear()
324
346
                host = medium.BZR_DEFAULT_INTERFACE
325
347
            if port is None:
326
348
                port = medium.BZR_DEFAULT_PORT
327
 
            smart_server = SmartTCPServer(self.transport, host=host, port=port)
 
349
            smart_server = SmartTCPServer(self.transport)
 
350
            smart_server.start_server(host, port)
328
351
            trace.note('listening on port: %s' % smart_server.port)
329
352
        self.smart_server = smart_server
330
353