def test_reuse_same_address_port(self): # NOTE: This test should ensure that same address port can be used by two # sockets. This to prevent accidental changes to socket options. In Windows # SO_REUSEADDR flag allows two sockets to bind to same address:port combination. # Windows should always use SO_EXCLUSIVEADDRUSE sock1 = sockets.create_server(self.HOST1, 0) try: _, PORT1 = sock1.getsockname() with pytest.raises(Exception): sockets.create_server(self.HOST1, PORT1) finally: sockets.close_socket(sock1)
def test_reuse_same_port(self): try: sock1, sock2 = None, None sock1 = sockets.create_server(self.HOST1, 0) _, PORT1 = sock1.getsockname() sock2 = sockets.create_server(self.HOST2, PORT1) assert sock1.getsockname() == (self.HOST1, PORT1) assert sock2.getsockname() == (self.HOST2, PORT1) except Exception: pytest.fail() finally: if sock1 is not None: sockets.close_socket(sock1) if sock2 is not None: sockets.close_socket(sock2)
def listen(self): self._server_socket = sockets.create_server("127.0.0.1", 0, self.TIMEOUT) _, self.port = self._server_socket.getsockname() self._server_socket.listen(0) def accept_worker(): log.info( "Listening for incoming connection from {0} on port {1}...", self, self.port, ) server_socket = self._server_socket if server_socket is None: return # concurrent close() try: sock, _ = server_socket.accept() except socket.timeout: if self._server_socket is None: return else: log.reraise_exception( "Timed out waiting for {0} to connect", self) except Exception: if self._server_socket is None: return else: log.reraise_exception( "Error accepting connection for {0}:", self) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) log.info("Incoming connection from {0} accepted.", self) self._socket = sock self._setup_stream() accept_thread = threading.Thread(target=accept_worker, name=fmt("{0} listener", self)) accept_thread.daemon = True accept_thread.start()
def listen(address, settrace_kwargs): # Errors below are logged with level="info", because the caller might be catching # and handling exceptions, and we don't want to spam their stderr unnecessarily. import subprocess server_access_token = compat.force_str(codecs.encode(os.urandom(32), "hex")) try: endpoints_listener = sockets.create_server("127.0.0.1", 0, timeout=10) except Exception as exc: log.swallow_exception("Can't listen for adapter endpoints:") raise RuntimeError("can't listen for adapter endpoints: " + str(exc)) endpoints_host, endpoints_port = endpoints_listener.getsockname() log.info( "Waiting for adapter endpoints on {0}:{1}...", endpoints_host, endpoints_port ) host, port = address adapter_args = [ sys.executable, os.path.dirname(adapter.__file__), "--for-server", str(endpoints_port), "--host", host, "--port", str(port), "--server-access-token", server_access_token, ] if log.log_dir is not None: adapter_args += ["--log-dir", log.log_dir] log.info("debugpy.listen() spawning adapter: {0!j}", adapter_args) # On Windows, detach the adapter from our console, if any, so that it doesn't # receive Ctrl+C from it, and doesn't keep it open once we exit. creationflags = 0 if sys.platform == "win32": creationflags |= 0x08000000 # CREATE_NO_WINDOW creationflags |= 0x00000200 # CREATE_NEW_PROCESS_GROUP # Adapter will outlive this process, so we shouldn't wait for it. However, we # need to ensure that the Popen instance for it doesn't get garbage-collected # by holding a reference to it in a non-local variable, to avoid triggering # https://bugs.python.org/issue37380. try: global _adapter_process _adapter_process = subprocess.Popen( adapter_args, close_fds=True, creationflags=creationflags ) if os.name == "posix": # It's going to fork again to daemonize, so we need to wait on it to # clean it up properly. _adapter_process.wait() else: # Suppress misleading warning about child process still being alive when # this process exits (https://bugs.python.org/issue38890). _adapter_process.returncode = 0 pydevd.add_dont_terminate_child_pid(_adapter_process.pid) except Exception as exc: log.swallow_exception("Error spawning debug adapter:", level="info") raise RuntimeError("error spawning debug adapter: " + str(exc)) try: sock, _ = endpoints_listener.accept() try: sock.settimeout(None) sock_io = sock.makefile("rb", 0) try: endpoints = json.loads(sock_io.read().decode("utf-8")) finally: sock_io.close() finally: sockets.close_socket(sock) except socket.timeout: log.swallow_exception("Timed out waiting for adapter to connect:", level="info") raise RuntimeError("timed out waiting for adapter to connect") except Exception as exc: log.swallow_exception("Error retrieving adapter endpoints:", level="info") raise RuntimeError("error retrieving adapter endpoints: " + str(exc)) log.info("Endpoints received from adapter: {0!j}", endpoints) if "error" in endpoints: raise RuntimeError(str(endpoints["error"])) try: server_host = str(endpoints["server"]["host"]) server_port = int(endpoints["server"]["port"]) client_host = str(endpoints["client"]["host"]) client_port = int(endpoints["client"]["port"]) except Exception as exc: log.swallow_exception( "Error parsing adapter endpoints:\n{0!j}\n", endpoints, level="info" ) raise RuntimeError("error parsing adapter endpoints: " + str(exc)) log.info( "Adapter is accepting incoming client connections on {0}:{1}", client_host, client_port, ) _settrace( host=server_host, port=server_port, wait_for_ready_to_run=False, block_until_connected=True, access_token=server_access_token, **settrace_kwargs ) log.info("pydevd is connected to adapter at {0}:{1}", server_host, server_port) return client_host, client_port