Bug 1293982 - TcpTransport.close() has to force a shutdown of the socket.
When the Marionette client closes the socket connection it currently only calls close() on it.
This will actually decrease the reference counter, and keeps the OS socket around until it gets
garbage collected by the system. This can cause port in use failures for socket connections
created shortly after eg. restarts of the appication. By using shutdown() the client indicates
that the socket has to be closed immediately.
MozReview-Commit-ID: 3jUgaWnujLc
--- a/testing/marionette/client/marionette_driver/transport.py
+++ b/testing/marionette/client/marionette_driver/transport.py
@@ -127,19 +127,17 @@ class TcpTransport(object):
self.addr = addr
self.port = port
self.socket_timeout = socket_timeout
self.protocol = 1
self.application_type = None
self.last_id = 0
self.expected_response = None
-
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.sock.settimeout(self.socket_timeout)
+ self.sock = None
def _unmarshal(self, packet):
msg = None
# protocol 3 and above
if self.protocol >= 3:
typ = int(packet[1])
if typ == Command.TYPE:
@@ -205,16 +203,19 @@ class TcpTransport(object):
def connect(self):
"""Connect to the server and process the hello message we expect
to receive in response.
Returns a tuple of the protocol level and the application type.
"""
try:
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.settimeout(self.socket_timeout)
+
self.sock.connect((self.addr, self.port))
except:
# Unset self.sock so that the next attempt to send will cause
# another connection attempt.
self.sock = None
raise
with SocketTimeout(self.sock, 2.0):
@@ -271,34 +272,36 @@ class TcpTransport(object):
self.last_id = self.last_id + 1
cmd = Command(self.last_id, name, params)
self.send(cmd)
return self.receive()
def close(self):
"""Close the socket."""
if self.sock:
+ self.sock.shutdown(socket.SHUT_RDWR)
self.sock.close()
+ self.sock = None
def __del__(self):
self.close()
- self.sock = None
def wait_for_port(host, port, timeout=60):
"""Wait for the specified host/port to become available."""
starttime = datetime.datetime.now()
poll_interval = 0.1
while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
sock = None
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(0.5)
sock.connect((host, port))
data = sock.recv(16)
+ sock.shutdown(socket.SHUT_RDWR)
sock.close()
if ":" in data:
return True
except socket.error:
pass
finally:
if sock is not None:
sock.close()