1
# Copyright (C) 2005-2011 Canonical Ltd
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
class DisconnectingTCPServer(object):
25
"""A TCP server that immediately closes any connection made to it."""
27
def start_server(self):
28
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
29
self.sock.bind(('127.0.0.1', 0))
31
self.port = self.sock.getsockname()[1]
32
self.thread = threading.Thread(
33
name='%s (port %d)' % (self.__class__.__name__, self.port),
34
target=self.accept_and_close)
35
self._please_stop = False
38
def accept_and_close(self):
39
fd = self.sock.fileno()
40
self.sock.setblocking(False)
41
while not self._please_stop:
43
# We can't just accept here, because accept is not interrupted
44
# by the listen socket being asynchronously closed by
45
# stop_server. However, select will be interrupted.
46
select.select([fd], [fd], [fd], 10)
47
conn, addr = self.sock.accept()
48
except (select.error, socket.error), e:
49
en = getattr(e, 'errno') or e[0]
51
# Probably (hopefully) because the stop method was called
54
elif en == errno.EAGAIN or en == errno.EWOULDBLOCK:
58
conn.shutdown(socket.SHUT_RDWR)
62
return 'bzr://127.0.0.1:%d/' % (self.port,)
64
def stop_server(self):
65
self._please_stop = True
67
# make sure the thread dies by connecting to the listening socket,
68
# just in case the test failed to do so.
69
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
70
conn.connect(self.sock.getsockname())