Example #1
0
 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)
Example #2
0
 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)
Example #3
0
    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:
                    raise log.exception("Timed out waiting for {0} to connect",
                                        self)
            except Exception:
                if self._server_socket is None:
                    return
                else:
                    raise log.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 _accept_connection_from(self, what, address, timeout=None):
        """Sets up a listening socket, accepts an incoming connection on it, sets
        up a message stream over that connection, and passes it on to what().

        Can be used in a with-statement to obtain the actual address of the listener
        socket before blocking on accept()::

            with accept_connection_from_server(...) as (host, port):
                # listen() returned - listening on (host, port) now
                ...
            # accept() returned - connection established
        """

        host, port = address
        listener = sockets.create_server(host, port, timeout)
        host, port = listener.getsockname()
        log.info(
            "{0} waiting for incoming connection from {1} on {2}:{3}...",
            self,
            what.__name__,
            host,
            port,
        )
        yield host, port

        try:
            sock, (other_host, other_port) = listener.accept()
        finally:
            listener.close()
        log.info(
            "{0} accepted incoming connection {1} from {2}:{3}.",
            self,
            what.__name__,
            other_host,
            other_port,
        )
        stream = messaging.JsonIOStream.from_socket(sock, what)
        what(self, stream)
Example #5
0
File: api.py Project: int19h/ptvsd
def enable_attach(dont_trace_start_patterns, dont_trace_end_patterns):
    # 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

    if hasattr(enable_attach, "adapter"):
        raise AssertionError("enable_attach() can only be called once per process")

    server_access_token = compat.force_str(codecs.encode(os.urandom(32), "hex"))

    try:
        endpoints_listener = sockets.create_server("127.0.0.1", 0, timeout=5)
    except Exception as exc:
        log.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
    )

    adapter_args = [
        sys.executable,
        os.path.dirname(adapter.__file__),
        "--for-server",
        str(endpoints_port),
        "--host",
        options.host,
        "--port",
        str(options.port),
        "--server-access-token",
        server_access_token,
    ]
    if log.log_dir is not None:
        adapter_args += ["--log-dir", log.log_dir]
    log.info("enable_attach() 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:
        enable_attach.adapter = 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.
            enable_attach.adapter.wait()
        else:
            # Suppress misleading warning about child process still being alive when
            # this process exits (https://bugs.python.org/issue38890).
            enable_attach.adapter.returncode = 0
            pydevd.add_dont_terminate_child_pid(enable_attach.adapter.pid)
    except Exception as exc:
        log.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.exception("Timed out waiting for adapter to connect:", level="info")
        raise RuntimeError("timed out waiting for adapter to connect")
    except Exception as exc:
        log.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:
        host = str(endpoints["server"]["host"])
        port = int(endpoints["server"]["port"])
        options.port = int(endpoints["ide"]["port"])
    except Exception as exc:
        log.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 IDE connections on {0}:{1}",
        options.host,
        options.port,
    )

    _settrace(
        host=host,
        port=port,
        suspend=False,
        patch_multiprocessing=options.multiprocess,
        wait_for_ready_to_run=False,
        block_until_connected=True,
        dont_trace_start_patterns=dont_trace_start_patterns,
        dont_trace_end_patterns=dont_trace_end_patterns,
        access_token=server_access_token,
        client_access_token=options.client_access_token,
    )
    log.info("pydevd is connected to adapter at {0}:{1}", host, port)
    return options.host, options.port