예제 #1
0
    async def attempt_connect(nursery, previous_attempt_failed):
        # Wait until either the previous attempt failed, or the timeout
        # expires (unless this is the first invocation, in which case we just
        # go ahead).
        if previous_attempt_failed is not None:
            with trio.move_on_after(happy_eyeballs_delay):
                await previous_attempt_failed.wait()

        # Claim our target.
        try:
            *socket_args, _, target_sockaddr = next(targets_iter)
        except StopIteration:
            return

        # Then kick off the next attempt.
        this_attempt_failed = trio.Event()
        nursery.start_soon(attempt_connect, nursery, this_attempt_failed)

        # Then make this invocation's attempt
        try:
            with close_on_error(socket(*socket_args)) as sock:
                await sock.connect(target_sockaddr)
        except OSError as exc:
            # This connection attempt failed, but the next one might
            # succeed. Save the error for later so we can report it if
            # everything fails, and tell the next attempt that it should go
            # ahead (if it hasn't already).
            oserrors.append(exc)
            this_attempt_failed.set()
        else:
            # Success! Save the winning socket and cancel all outstanding
            # connection attempts.
            winning_sockets.append(sock)
            nursery.cancel_scope.cancel()
예제 #2
0
async def init_conn(bridge, iface=""):
    *sarg, _, rbridge = (await socket.getaddrinfo(*bridge,
                                                  type=socket.SOCK_STREAM))[0]
    retry = 3
    for _ in range(retry):
        sa = socket.socket(*sarg)
        sa.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        await sa.connect(rbridge)
        priv_host, priv_port = sa.getsockname()  # self, private
        if iface:
            priv_host, priv_port = get_priv_host(iface), 0
        try:
            s_cona = await bound_socket(
                (priv_host, priv_port))  # for connect, a
            if iface:
                _, priv_port = s_cona.getsockname()
            s_conb = await bound_socket(
                (priv_host, priv_port))  # for connect, b
            s_acp = await bound_socket(('', priv_port))  # for accept
            break
        except OSError:  # NOTE: albeit SO_REUSEADDR set, bind still occassionally fails
            logger.debug(
                f"cannot bind to private addr {priv_host}:{priv_port}, retry")
            sa.close()
            await trio.sleep(0.1)
            continue
    else:
        raise OSError("failed to bind to a local address")
    logger.debug(f"self's private addr {priv_host}:{priv_port}")
    return trio.SocketStream(
        sa), f"{priv_host}:{priv_port}", s_acp, s_cona, s_conb
예제 #3
0
async def open_unix_socket(filename):
    """Opens a connection to the specified
    `Unix domain socket <https://en.wikipedia.org/wiki/Unix_domain_socket>`__.

    You must have read/write permission on the specified file to connect.

    Args:
      filename (str or bytes): The filename to open the connection to.

    Returns:
      SocketStream: a :class:`~trio.abc.Stream` connected to the given file.

    Raises:
      OSError: If the socket file could not be connected to.
      RuntimeError: If AF_UNIX sockets are not supported.
    """
    if not has_unix:
        raise RuntimeError("Unix sockets are not supported on this platform")

    # much more simplified logic vs tcp sockets - one socket type and only one
    # possible location to connect to
    sock = socket(AF_UNIX, SOCK_STREAM)
    with close_on_error(sock):
        await sock.connect(os.fspath(filename))

    return trio.SocketStream(sock)
예제 #4
0
    async def attempt_connect(nursery, previous_attempt_failed):
        # Wait until either the previous attempt failed, or the timeout
        # expires (unless this is the first invocation, in which case we just
        # go ahead).
        if previous_attempt_failed is not None:
            with trio.move_on_after(happy_eyeballs_delay):
                await previous_attempt_failed.wait()

        # Claim our target.
        try:
            *socket_args, _, target_sockaddr = next(targets_iter)
        except StopIteration:
            return

        # Then kick off the next attempt.
        this_attempt_failed = trio.Event()
        nursery.start_soon(attempt_connect, nursery, this_attempt_failed)

        # Then make this invocation's attempt
        try:
            with close_on_error(socket(*socket_args)) as sock:
                await sock.connect(target_sockaddr)
        except OSError as exc:
            # This connection attempt failed, but the next one might
            # succeed. Save the error for later so we can report it if
            # everything fails, and tell the next attempt that it should go
            # ahead (if it hasn't already).
            oserrors.append(exc)
            this_attempt_failed.set()
        else:
            # Success! Save the winning socket and cancel all outstanding
            # connection attempts.
            winning_sockets.append(sock)
            nursery.cancel_scope.cancel()
예제 #5
0
async def get_socket_port(server):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    await s.bind((server, 0))
    s.listen(1)
    port = s.getsockname()[1]
    s.close()
    return port
예제 #6
0
async def bound_socket(local_addr):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    if hasattr(socket, "SO_REUSEPORT"):
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
    await s.bind(local_addr)
    logger.debug(f"socket bound to {local_addr} created")
    return s
예제 #7
0
            async def _serve(listen_address):
                log_util.set_listen_address(listen_address)

                with socket.socket(family=get_ip_family(listen_address),
                                   type=socket.SOCK_DGRAM) as udp_sock:
                    await udp_sock.bind(listen_address)
                    logger.info('Started listening')
                    await run_accept_loop(udp_sock, resource_id, encoders)
예제 #8
0
 async def _create_socket(self):
     self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
                                socket.IPPROTO_UDP)
     self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     await self._sock.bind((self.multicast_group, self.port))
     mreq = struct.pack("4sl", socket.inet_aton(self.multicast_group),
                        socket.INADDR_ANY)
     self._sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
                           mreq)
예제 #9
0
    async def main_loop(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        await self.sock.bind((interface['addr'], ARTNET_PORT))

        #nodes = [ node async for node in search_nodes(self.sock, self.interface) ]
        #print(nodes)

        while True:
            #I DONT KNOW WHAT TO DO UNTIL I HAVE A FRAMEWORK TO FRAME MY WORK AROUND
            pass
예제 #10
0
async def serve(host, port, stream_changes, allow_remote_class_registration,
                allow_import_from_main, max_queue_size):
    # todo: catch and send back errors (ignoring socket closing errors?)
    global MAX_QUEUE_SIZE
    MAX_QUEUE_SIZE = max_queue_size
    thread_executor = ThreadExecutor()

    executor = ProcessSocketServer(executor=thread_executor)
    executor.stream_changes = stream_changes
    executor.allow_remote_class_registration = allow_remote_class_registration
    executor.allow_import_from_main = allow_import_from_main

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_address = (host, port)
    await sock.bind(server_address)
    sock.listen()

    async def handler(stream: SocketStream):
        data = await executor.read_decode_json_buffers(stream)
        if data.get('eof', False):
            # todo: close in a nicer way by not accepting new requests
            nursery.cancel_scope.cancel()
            return

        channel = data.get('stream', None)

        try:
            if channel is None:
                await socket_handler(executor, stream)
            elif channel == 'data':
                await socket_data_stream_handler(executor, stream,
                                                 data['data'])
            else:
                await socket_stream_handler(executor, stream, channel,
                                            data['data'])
        except BrokenResourceError:
            # if channel is None, all errors are caught and sent to client.
            # Otherwise, and errors when channel != None are a client socket
            # issue so we can just drop it
            pass

    with ExecutorContext(thread_executor):
        async with thread_executor:
            async with trio.open_nursery() as nursery:
                nursery.start_soon(serve_listeners, handler,
                                   [SocketListener(sock)])
예제 #11
0
async def run_receive_loop(connection_opened, connection_closed, write_blocks, resource_id, connection_config):
    with socket.socket(family=get_ip_family(connection_config.address), type=socket.SOCK_DGRAM) as udp_sock:
        async with trio.open_nursery() as nursery:
            child_nursery, shutdown_trigger = await spawn_child_nursery(nursery.start_soon, shutdown_timeout=3)

            with trio.CancelScope() as cancel_scope:
                await udp_sock.connect(connection_config.address)
                log_util.set_listen_address(udp_sock.getsockname()[:2])
                log_util.set_remote_address(connection_config.address)

                @once
                def shutdown():
                    # coordinate shutdown with higher order protocol instance
                    connection_closed()
                    # trigger child nursery timeout
                    shutdown_trigger.set()
                    # cancel receive loop
                    cancel_scope.cancel()
                    logger.debug('Closed connection')

                spawn = child_nursery.start_soon

                async def send(packet_to_send):
                    packet_bytes = packet_to_send.to_bytes()
                    await udp_sock.send(packet_bytes)

                connection = ClientSideConnection(shutdown, spawn, send, write_blocks, resource_id,
                                                  connection_config.sending_rate, connection_config.reverse)
                # coordinate startup with higher order protocol instance
                connection_opened(connection)

                while True:
                    try:
                        data = await udp_sock.recv(2048)
                        packet = PacketType.parse_packet(data)
                    except (ConnectionResetError, ConnectionRefusedError):
                        # maybe handle this error
                        # however, it is not guaranteed that we will receive an error when sending into the void
                        pass
                    except ValueError as exc:
                        logger.exception(exc)
                    else:
                        await connection.handle_packet(packet)
예제 #12
0
    async def attempt_connect(socket_args, sockaddr, attempt_failed):
        nonlocal winning_socket

        try:
            sock = socket(*socket_args)
            open_sockets.add(sock)

            await sock.connect(sockaddr)

            # Success! Save the winning socket and cancel all outstanding
            # connection attempts.
            winning_socket = sock
            nursery.cancel_scope.cancel()
        except OSError as exc:
            # This connection attempt failed, but the next one might
            # succeed. Save the error for later so we can report it if
            # everything fails, and tell the next attempt that it should go
            # ahead (if it hasn't already).
            oserrors.append(exc)
            attempt_failed.set()
예제 #13
0
파일: serve53.py 프로젝트: gc-ss/named1
async def serve53(addr, resolve, task_status=trio.TASK_STATUS_IGNORED):
    with socket(AF_INET6 if ":" in addr[0] else AF_INET, SOCK_DGRAM) as sock:
        try:
            sock.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
            await sock.bind(addr)
            print(f"[Serve53] listening on {addr}")
        except OSError as e:
            if e.errno == 13: reason = "permission denied (run with sudo?)"
            elif e.errno in (48, 49):
                reason = "already in use (is another DNS server running?)"
            else:
                reason = str(e)
            print(f"[Serve53] {addr} {reason}")
            return
        finally:
            task_status.started()
        async with trio.open_nursery() as resolvers:
            while True:
                data, addr = await sock.recvfrom(8192)
                resolvers.start_soon(_process, sock, resolve, data, addr)
예제 #14
0
    async def _run_servers(self):
        import trio
        
        print('hello')
        listeners = await trio.open_tcp_listeners(self.port)


        if self.unix_socket:
            from trio.socket import socket, SOCK_STREAM, AF_UNIX, SOL_SOCKET, SO_REUSEADDR
            
            sock = socket(AF_UNIX, SOCK_STREAM)
            sock.setsockopt(
                SOL_SOCKET, SO_REUSEADDR, 1
            )
            await sock.bind(self.unix_socket)
            sock.listen(10)
            listeners.append(trio.SocketListener(sock))

        print(listeners)
        await trio.serve_listeners(self.handle_client, listeners)
예제 #15
0
    async def open_socket(self) -> SocketStream:
        """Opens socket, sends channel=None, reads the response and returns
        the socket stream.

        :return:
        """
        data = self.encode({'stream': None})

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_address = (self.server, self.port)
        await sock.connect(server_address)

        stream = SocketStream(sock)
        try:
            await self.write_socket(data, stream)
            await self.read_decode_json_buffers(stream)
        except Exception:
            await stream.aclose()
            raise

        return stream
예제 #16
0
    async def _init(self):
        family, socktype, proto, canonname, sockaddr = (
            await socket.getaddrinfo(
                None if self.multicast else self.host,
                self.port,
                socket.AF_INET6 if self.ipv6 else socket.AF_UNSPEC,
                socket.SOCK_DGRAM,
                0,
                socket.AI_PASSIVE,
            ))[0]

        self._sock = socket.socket(family, socktype, proto)
        self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        await self._sock.bind(sockaddr)

        if self.multicast:
            if hasattr(socket, "SO_REUSEPORT"):
                self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT,
                                      1)

            val = None
            if family == socket.AF_INET:
                assert "." in self.host
                val = struct.pack("4sl", socket.inet_aton(self.host),
                                  socket.INADDR_ANY)
            elif family == socket.AF_INET6:
                raise NotImplementedError("IPv6 support not ready yet")
            else:
                raise ValueError("Unsupported network address family")

            self._sock.setsockopt(
                socket.IPPROTO_IPV6 if self.ipv6 else socket.IPPROTO_IP,
                socket.IP_ADD_MEMBERSHIP,
                val,
            )
            self._sock.setsockopt(
                socket.IPPROTO_IPV6 if self.ipv6 else socket.IPPROTO_IP,
                socket.IP_MULTICAST_LOOP,
                0,
            )
예제 #17
0
    async def start_executor(self):
        if self._process is not None:
            raise TypeError('Executor already started')

        port = self.port
        if not port:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            await s.bind((self.server, 0))
            s.listen(1)
            port = self.port = s.getsockname()[1]
            s.close()

        env = os.environ.copy()
        env['KIVY_NO_ARGS'] = '1'
        self._process = await trio.open_process([
            sys.executable, '-m', 'pymoa_remote.app.multiprocessing', '--host',
            str(self.server), '--port',
            str(port), '--stream_changes',
            str(self.stream_changes), '--remote_class_registration',
            str(self.allow_remote_class_registration), '--import_from_main',
            str(self.allow_import_from_main)
        ],
                                                env=env)

        # wait until the process is ready
        ts = time.perf_counter()
        while True:
            try:
                async with self.create_socket_context():
                    break
            except OSError:
                if time.perf_counter() - ts >= 5:
                    raise
                await trio.sleep(.01)

        await super(MultiprocessSocketExecutor, self).start_executor()
예제 #18
0
    async def attempt_connect(socket_args, sockaddr, attempt_failed):
        nonlocal winning_socket

        try:
            sock = socket(*socket_args)
            open_sockets.add(sock)

            if local_address is not None:
                # TCP connections are identified by a 4-tuple:
                #
                #   (local IP, local port, remote IP, remote port)
                #
                # So if a single local IP wants to make multiple connections
                # to the same (remote IP, remote port) pair, then those
                # connections have to use different local ports, or else TCP
                # won't be able to tell them apart. OTOH, if you have multiple
                # connections to different remote IP/ports, then those
                # connections can share a local port.
                #
                # Normally, when you call bind(), the kernel will immediately
                # assign a specific local port to your socket. At this point
                # the kernel doesn't know which (remote IP, remote port)
                # you're going to use, so it has to pick a local port that
                # *no* other connection is using. That's the only way to
                # guarantee that this local port will be usable later when we
                # call connect(). (Alternatively, you can set SO_REUSEADDR to
                # allow multiple nascent connections to share the same port,
                # but then connect() might fail with EADDRNOTAVAIL if we get
                # unlucky and our TCP 4-tuple ends up colliding with another
                # unrelated connection.)
                #
                # So calling bind() before connect() works, but it disables
                # sharing of local ports. This is inefficient: it makes you
                # more likely to run out of local ports.
                #
                # But on some versions of Linux, we can re-enable sharing of
                # local ports by setting a special flag. This flag tells
                # bind() to only bind the IP, and not the port. That way,
                # connect() is allowed to pick the the port, and it can do a
                # better job of it because it knows the remote IP/port.
                try:
                    sock.setsockopt(trio.socket.IPPROTO_IP,
                                    trio.socket.IP_BIND_ADDRESS_NO_PORT, 1)
                except (OSError, AttributeError):
                    pass
                try:
                    await sock.bind((local_address, 0))
                except OSError:
                    raise OSError(
                        f"local_address={local_address!r} is incompatible "
                        f"with remote address {sockaddr}")

            await sock.connect(sockaddr)

            # Success! Save the winning socket and cancel all outstanding
            # connection attempts.
            winning_socket = sock
            nursery.cancel_scope.cancel()
        except OSError as exc:
            # This connection attempt failed, but the next one might
            # succeed. Save the error for later so we can report it if
            # everything fails, and tell the next attempt that it should go
            # ahead (if it hasn't already).
            oserrors.append(exc)
            attempt_failed.set()