Bug 1293982 - TcpTransport.close() has to force a shutdown of the socket. r=ato, a=test-only
authorHenrik Skupin <mail@hskupin.info>
Mon, 15 Aug 2016 13:55:43 +0200
changeset 347804 a71ff2ff3271356643448c19e41b84acbd53f0e4
parent 347803 a38dbd94a596b8b7a987b1b134b0826639dd7311
child 347805 4008796e979af0a7ee9e99990cc4ff08023988b0
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersato, test-only
bugs1293982
milestone50.0a2
Bug 1293982 - TcpTransport.close() has to force a shutdown of the socket. r=ato, a=test-only 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
testing/marionette/client/marionette_driver/transport.py
--- 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()