Esempio n. 1
0
async def _connect_streams(reader: asyncio.StreamReader,
                           writer: asyncio.StreamWriter,
                           queue: "asyncio.Queue[int]",
                           token: CancelToken) -> None:
    try:
        while not token.triggered:
            if reader.at_eof():
                break

            try:
                size = queue.get_nowait()
            except asyncio.QueueEmpty:
                await asyncio.sleep(0)
                continue
            data = await token.cancellable_wait(reader.readexactly(size))
            writer.write(data)
            queue.task_done()
            await token.cancellable_wait(writer.drain())
    except OperationCancelled:
        pass
    finally:
        writer.write_eof()

    if reader.at_eof():
        reader.feed_eof()
async def echo(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
    print('Opened a new connection')
    try:
        while True:
            message: bytes = await reader.readline()
            message_str: str = message.decode().replace('\r',
                                                        '').replace('\n', '')

            print(f'Got message: {message_str}')

            if message_str in ['quit', '', 'q']:
                writer.write(b'Bye bye\n\r')
                await writer.drain()
                break

            writer.write(message.upper())
            # Drain нужен для того, чтоб убедиться что запись
            # в сокет проведена, т.к. может записаться в буфер
            await writer.drain()

    except asyncio.CancelledError:
        writer.write(
            b'Sorry, server is shutting down. Your connection will be closed\r\n'
        )
        writer.write_eof()
        await writer.drain()
        print('Task was cancelled')

    finally:
        print('Leaving connection')
        # raise Exception('Test exception')
        # Закрывать reader не нужно.
        writer.close()
 async def _relay_data_side(
     self,
     reader: asyncio.StreamReader,
     writer: asyncio.StreamWriter,
     log_name: str,
 ) -> None:
     try:
         while True:
             buf = await reader.read(self._bufsize)
             if not buf:  # EOF
                 break
             self._logger.debug('%s passing data', log_name)
             writer.write(buf)
             await writer.drain()
         try:
             self._logger.debug('%s passing EOF', log_name)
             writer.write_eof()
             await writer.drain()
         except OSError as e:
             if e.errno == errno.ENOTCONN:
                 self._logger.debug(
                     '%s endpoint already closed when passing EOF',
                     log_name)
                 return
             raise
     except Exception as e:
         self._logger.info('%s caught exception: %r', log_name, e)
         raise
Esempio n. 4
0
 async def remove_client(self, writer: asyncio.StreamWriter):
     ''' Close the cient input & output streams '''
     if writer.can_write_eof():
         writer.write_eof()
     writer.close()
     await writer.wait_closed()
     self._logger.info("Disconnected client")
Esempio n. 5
0
        async def handle_request(
            reader: asyncio.StreamReader,
            writer: asyncio.StreamWriter,
        ) -> None:
            firstline = (await reader.readline()).decode().rstrip('\r\n')
            if firstline != "evaluation request":
                raise RuntimeError(
                    f"evaluation request mismatch: {firstline!r}")
            # print(f"<<< EVALUATION SERVER >>> received header")

            request = json.loads(await reader.readline())
            # print(f"<<< EVALUATION SERVER >>> received {request}")
            seed = request['seed'][0]
            params = request['params'][0]
            if len(params) != len(space.params):
                raise RuntimeError(
                    f"Parameter mismatch.\n"
                    f"  received: {sorted(params)}\n"
                    f"  expected: {sorted(p.name for p in space.params)}\n")

            x = [params[p.name] for p in space.params]
            y, _cost = await objective(x, RandomState(seed))
            all_x.append(x)
            all_y.append(y)
            # print(f"<<< EVALUATION SERVER >>> f({x}) = {y}")

            writer.write(json.dumps({'y': y}).encode())
            writer.write_eof()
Esempio n. 6
0
    async def _server_callback(self, reader: asyncio.StreamReader,
                               writer: asyncio.StreamWriter) -> None:
        """Callback when a connection is made to the server

        Read the data sent from the client, execute the requested command, and
        send the reply back to the client.
        """
        try:
            logger.debug("Connection made to server")
            data = await reader.read()
            logger.debug("EOF received by server")

            req, is_json = _IPC.unpack(data)
        except IPCError:
            logger.warning("Invalid data received, closing connection")
        else:
            rep = self.handler(req)

            result = _IPC.pack(rep, is_json=is_json)

            logger.debug("Sending result on receive EOF")
            writer.write(result)
            logger.debug("Closing connection on receive EOF")
            writer.write_eof()
        finally:
            writer.close()
            await writer.wait_closed()
Esempio n. 7
0
    async def request_file_handler(self, writer: StreamWriter, file_path: str, block_index: int):
        # read data
        def read_file():
            with open(file_path, mode="r+b") as f:
                f.seek(block_index * config.file_block_size)
                data = f.read(config.file_block_size)
            if config.enable_gzip:
                data = zlib.compress(data)
            return data

        data = await self._loop.run_in_executor(None, read_file)

        # encryption
        if self._encryption:
            salt = get_random_bytes(AES.block_size)
            pk = hashlib.scrypt(config.pre_shared_key, salt=salt, n=2 ** 14, r=8, p=1, dklen=32)
            cipher_config = AES.new(pk, AES.MODE_GCM)
            encrypted, tag = cipher_config.encrypt_and_digest(data)
            msg = pickle.dumps({
                "salt": salt,
                "cipher": encrypted,
                "tag": tag,
                "nonce": cipher_config.nonce
            })
            data = msg

        writer.write(int.to_bytes(MsgType.RES_FILE.value, 1, "big"))
        writer.write(int.to_bytes(len(data), 8, "big"))
        writer.write(data)
        writer.write_eof()
Esempio n. 8
0
 async def request_index_handler(self, writer: StreamWriter, client_index: dict):
     client_ip = writer.get_extra_info("peername")[0]
     # response with local index
     local_index = pickle.dumps(self._file_mgr.file_index)
     writer.write(int.to_bytes(MsgType.RES_INDEX.value, 1, "big"))
     writer.write(int.to_bytes(len(local_index), 8, "big"))
     writer.write(local_index)
     writer.write_eof()
     await self.sync(client_index, client_ip)
Esempio n. 9
0
 async def request_index_update_handler(self, writer: StreamWriter, client_index: dict):
     client_ip = writer.get_extra_info("peername")[0]
     # response
     data = b"OK"
     writer.write(int.to_bytes(MsgType.RES_INDEX_UPDATE.value, 1, "big"))
     writer.write(int.to_bytes(len(data), 8, "big"))
     writer.write(data)
     writer.write_eof()
     await self.sync(client_index, client_ip)
Esempio n. 10
0
 async def handle_client(
     self,
     reader: asyncio.StreamReader,
     writer: asyncio.StreamWriter,
 ):
     self.DATA.append(await reader.readline())
     async with self.condition:
         self.condition.notify_all()
     writer.write_eof()
     writer.close()
Esempio n. 11
0
 def run_on_connected(reader: asyncio.StreamReader,
                      writer: asyncio.StreamWriter):
     if self.connection_task is not None:
         logger.warning(
             'Trying to connect, but controller already connected.')
         writer.write('Already connected'.encode())
         writer.write_eof()
         return
     self.remote_addr = writer.transport.get_extra_info('peername')
     self.connection_task = asyncio.ensure_future(
         on_connected(reader, writer))
Esempio n. 12
0
 async def tcp_received(self, reader: aio.StreamReader,
                        writer: aio.StreamWriter) -> None:
     logging.debug(f'Tcp connected {writer.get_extra_info("peername")}')
     try:
         await aio.wait_for(self._tcp_received(reader, writer),
                            timeout=self._TCP_TIME_LIMIT)
     except Exception:
         pass
     finally:
         writer.write_eof()
         writer.close()
         logging.debug('Done TCP')
Esempio n. 13
0
async def _read_fd_write_stream(loop: asyncio.AbstractEventLoop, rfd: int,
                                writer: StreamWriter) -> None:
    f = os.fdopen(rfd, mode="rb")
    try:
        while True:
            b = await loop.run_in_executor(None, f.read, CHUNK_SIZE)
            if not b:
                break
            writer.write(b)
        writer.write_eof()
        await writer.drain()
    finally:
        f.close()
async def _relay_data_side(
        reader: asyncio.StreamReader,
        writer: asyncio.StreamWriter,
) -> None:
    """Pass data and EOF from reader to writer."""
    while True:
        buf = await reader.read(BUF_SIZE)
        if not buf:  # EOF
            break
        writer.write(buf)
        await writer.drain()
    writer.write_eof()
    await writer.drain()
Esempio n. 15
0
async def send_response(
    writer: asyncio.StreamWriter, response: Dict[Any, Any],
) -> None:
    """
    Sends a response to a connection and then closes writing to that connection

    :param writer: StreamWriter to write to
    :param response: Dict[Any, Any] response
    :return: None
    """
    writer.write(bencode.encode(response))
    writer.write_eof()
    await writer.drain()
Esempio n. 16
0
async def _relay_data_side(
    reader: asyncio.StreamReader,
    writer: asyncio.StreamWriter,
) -> None:
    """Pass data and EOF from reader to writer."""
    while True:
        buf = await reader.read(BUF_SIZE)
        if not buf:  # EOF
            break
        writer.write(buf)
        await writer.drain()
    writer.write_eof()
    await writer.drain()
Esempio n. 17
0
 async def handle_client_connection(self, reader: asyncio.StreamReader,
                                    writer: asyncio.StreamWriter):
     service_name = self.__router.determine_service(reader, writer)
     responsible_services = list(
         filter(lambda s: s.get_service_name() == service_name,
                self.__services))
     if len(responsible_services) != 0:
         for service in responsible_services:
             await service.client_connected(reader, writer)
     else:
         writer.write(ERROR_MESSAGE)
         writer.write_eof()
         await writer.drain()
         writer.close()
Esempio n. 18
0
async def echo(reader: StreamReader, writer: StreamWriter):
    print('New connection.')
    try:
        while True:
            data: bytes = await reader.readline()
            if data in [b'', b'quit']:
                break
            writer.write(data.upper())
            await writer.drain()
        print('Leaving Connection.')
    except CancelledError:
        writer.write_eof()
        print('Cancelled')
    finally:
        writer.close()
Esempio n. 19
0
async def poll_client(reader: StreamReader, process: Process, stdin: StreamWriter):
    """
    Continuously waits to receive a stdin message from the client.
    """
    while True:
        (message_type, body) = await read_client(reader)
        if message_type == MESSAGE_STDIN:
            if len(body) == 0:
                stdin.write_eof()
            else:
                stdin.write(body)
        elif message_type == MESSAGE_SIGNAL:
            signal = int.from_bytes(body, "big", signed=False)
            print("Got signal", signal)
            process.send_signal(signal)
    async def _ext_or_port_handler(
            self,
            reader: asyncio.StreamReader,
            writer: asyncio.StreamWriter,
    ) -> None:
        # This callback function should not close writer when exiting. After
        # all, the API consumer may decide to stash reader and writer somewhere
        # for use later and return from their supplied callback function early.
        async with contexts.log_unhandled_exc(self._logger):
            try:
                auth_result = await self._authenticator.authenticate(
                    reader, writer)
            except (OSError, asyncio.IncompleteReadError) as e:
                self._logger.warning(
                    'Error during ExtOrPort SafeCookie authentication: %r', e)
                return
            if not auth_result:
                self._logger.warning(
                    'ExtOrPort SafeCookie authentication failed')
                return
            transport = host = port = None
            while True:
                command, body = await self._read_ext_msg(reader)
                if command == enums.ExtOrPortCommand.DONE:
                    break
                elif command == enums.ExtOrPortCommand.USERADDR:
                    host, port = str_utils.parse_hostport(body.decode('ascii'))
                    host = ipaddress.ip_address(host)
                elif command == enums.ExtOrPortCommand.TRANSPORT:
                    transport = body.decode('ascii')
                    str_utils.validate_transport_name(transport)
                else:
                    self._logger.info(
                        'Received unknown ExtOrPort command %r, body %r',
                        command, body)
            connection_info = ExtOrPortClientConnection(transport, host, port)
            if self._preconnect_cb is not None:
                accept = await self._preconnect_cb(connection_info)
            else:
                accept = True
            if not accept:
                await self._write_ext_msg(
                    writer, enums.ExtOrPortReply.DENY, b'')
                writer.write_eof()
                return
            await self._write_ext_msg(writer, enums.ExtOrPortReply.OKAY, b'')

            await self._cb(reader, writer, connection_info)
Esempio n. 21
0
    async def _ext_or_port_handler(
        self,
        reader: asyncio.StreamReader,
        writer: asyncio.StreamWriter,
    ) -> None:
        # This callback function should not close writer when exiting. After
        # all, the API consumer may decide to stash reader and writer somewhere
        # for use later and return from their supplied callback function early.
        async with contexts.log_unhandled_exc(self._logger):
            try:
                auth_result = await self._authenticator.authenticate(
                    reader, writer)
            except (OSError, asyncio.IncompleteReadError) as e:
                self._logger.warning(
                    'Error during ExtOrPort SafeCookie authentication: %r', e)
                return
            if not auth_result:
                self._logger.warning(
                    'ExtOrPort SafeCookie authentication failed')
                return
            transport = host = port = None
            while True:
                command, body = await self._read_ext_msg(reader)
                if command == enums.ExtOrPortCommand.DONE:
                    break
                elif command == enums.ExtOrPortCommand.USERADDR:
                    host, port = str_utils.parse_hostport(body.decode('ascii'))
                    host = ipaddress.ip_address(host)
                elif command == enums.ExtOrPortCommand.TRANSPORT:
                    transport = body.decode('ascii')
                    str_utils.validate_transport_name(transport)
                else:
                    self._logger.info(
                        'Received unknown ExtOrPort command %r, body %r',
                        command, body)
            connection_info = ExtOrPortClientConnection(transport, host, port)
            if self._preconnect_cb is not None:
                accept = await self._preconnect_cb(connection_info)
            else:
                accept = True
            if not accept:
                await self._write_ext_msg(writer, enums.ExtOrPortReply.DENY,
                                          b'')
                writer.write_eof()
                return
            await self._write_ext_msg(writer, enums.ExtOrPortReply.OKAY, b'')

            await self._cb(reader, writer, connection_info)
Esempio n. 22
0
    def test_put(self, loop):
        result = 39
        result_queue = Queue()
        called_write = Queue()
        called_write_eof = Queue()
        writer = StreamWriter(None, None, None, None)
        unix_socket = UnixSocket(None, loop)
        unix_socket.writer = writer

        def write(data):
            called_write.put(True)

            if data != b'\n':
                result_queue.put(unix_socket.decode(data))

        def write_eof():
            called_write_eof.put(True)

        writer.write = write
        writer.write_eof = write_eof

        async def run():
            unix_socket.ready.set()
            await unix_socket.put(result)

        loop.run_until_complete(run())
        check_queue_multi(called_write, [True] * 2)
        check_queue(result_queue, result)
 async def _reply(self, dwriter: asyncio.StreamWriter, reply: SOCKS5Reply,
                  host: HostType, port: int) -> None:
     if isinstance(host, ipaddress.IPv4Address):
         b_addr = SOCKS5AddressType.IPV4_ADDRESS + host.packed
     elif isinstance(host, ipaddress.IPv6Address):
         b_addr = SOCKS5AddressType.IPV6_ADDRESS + host.packed
     else:
         b_addr = host.encode('idna')
         b_addr = (SOCKS5AddressType.DOMAIN_NAME +
                   len(b_addr).to_bytes(1, 'big') + b_addr)
     dwriter.write(b'\x05' + reply + b'\x00' + b_addr +
                   port.to_bytes(2, 'big'))
     if reply is not SOCKS5Reply.SUCCESS:
         dwriter.write_eof()
     await dwriter.drain()
     self._logger.debug('%r sent reply %s',
                        dwriter.get_extra_info('peername'), reply)
Esempio n. 24
0
async def handle_connection(reader: asyncio.StreamReader,
                            writer: asyncio.StreamWriter):
    host, port = writer.get_extra_info('peername')
    logger = main_logger.getChild(f"{host}:{port}")
    logger.info("Connection opened from %s", writer.get_extra_info('peername'))
    writer.write("DNEVNIK-RU-BKEND-62-02\n".encode())
    writer.write("Посчитайте средний балл для каждого ученика\n".encode())
    writer.write(
        "Если ученик не набрал оценок за период следует вывести н/а\n".encode(
        ))
    task = Task()
    remaining = 450
    while remaining and not writer.is_closing():
        logger.info(f"{remaining} tasks left")
        writer.write(f"Осталось {remaining} заданий\n".encode())
        try:
            task_s = task.get_task()
            writer.write(task_s.encode())
            line = await reader.readuntil()
            logger.info(f"{len(line)} bytes received")
            try:
                correct = task.check_task(line)
            except Exception as e:
                writer.write("Неверный формат ответа\n".encode())
                logger.info("presentation error")
                continue
            if correct:
                remaining -= 1
                writer.write("Верно\n".encode())
                logger.info("correct")
            else:
                writer.write("Неверно\n".encode())
                logger.info("incorrect")
                break
        except Exception as e:
            writer.write("Непредвиденная ошибка\n".encode())
            logger.error(e)
            break
    if remaining <= 0:
        logger.info("solved")
        flag = FLAG
        writer.write(f"Ваш флаг: {flag}\n".encode())
    writer.write(f"До свидания!\n".encode())
    writer.write_eof()
    await writer.wait_closed()
Esempio n. 25
0
async def _connection_wrapper(application: core.ApplicationType, client_connections: "Set[asyncio.Task[None]]", container: core.Container, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
    """
    Run an ASGI application in an asyncio server.

    This function is suitable for passing to ``start_server`` or
    ``start_unix_server``, with the ``application`` and ``client_connections``
    parameters bound via a ``functools.partial`` or similar.

    :param application: The ASGI application.
    :param client_connections: A set of Task objects, to which this connection
        is added on entry to and removed on exit from this function.
    :param container: The ASGI container to use.
    :param reader: The stream reader for the connection.
    :param writer: The stream writer for the connection.
    """
    # Add this task to the set of open client connections.
    task = asyncio.current_task()
    assert task is not None, "_connection_wrapper must be called inside a task"
    client_connections.add(task)
    try:
        try:
            # aioscgi.run expects callables to read a chunk and write a chunk,
            # the latter taking a drain boolean; adapt the writing side to the
            # stream model (the reader is handled with a functools.partial).
            async def write_cb(data: bytes, drain: bool) -> None:
                writer.write(data)
                if drain:
                    await writer.drain()
            # Run the application.
            await container.run(application, functools.partial(reader.read, io.DEFAULT_BUFFER_SIZE), write_cb)
        except Exception:  # pylint: disable=broad-except
            logging.getLogger(__name__).error("Uncaught exception in application callable", exc_info=True)
        finally:
            # Close the connection.
            try:
                if writer.can_write_eof():
                    writer.write_eof()
                writer.close()
            except Exception:  # pylint: disable=broad-except
                # If something went wrong while closing the connection, there’s
                # nothing interesting to report.
                pass
    finally:
        # Remove this task from the set of open client connections.
        client_connections.remove(task)
Esempio n. 26
0
async def login(reader: StreamReader, writer: StreamWriter, name: str) -> bool:
    global mysql_pool
    if mysql_pool is None:
        writer.write(b"database error\n")
        return False
    bitsize = 256
    str_len = bitsize // 4 + 2
    client_eph: int
    server_eph: int

    writer.write(b"exchange\n")
    client_eph_str = await reader.readline()
    client_eph_str = client_eph_str.strip()
    if len(client_eph_str) != str_len:
        writer.write(b"too short\n")
        return False
    try:
        client_eph = int(client_eph_str, 16)
    except ValueError:
        writer.write(b"not a number\n")
        return False

    server_eph = randbits(bitsize)
    server_eph_str = hex(server_eph).encode()
    writer.write(server_eph_str + b"\n")

    data = hex(server_eph * client_eph).encode()
    signature = b64decode(await reader.readline())
    async with mysql_pool.acquire() as conn:
        async with conn.cursor() as cur:
            await cur.execute("select certificate from users where name = %s",
                              (name, ))
            (public_key, ) = await cur.fetchone()

    try:
        key = crypto.load_certificate(crypto.FILETYPE_PEM, public_key.encode())
        crypto.verify(key, signature, data, "sha256")
    except crypto.Error as e:
        print(f"Verification failed: {e}")
        writer.write(b"fail\n")
        writer.write_eof()
        return False

    writer.write(b"ok\n")
    return True
Esempio n. 27
0
        async def on_connected(reader: asyncio.StreamReader,
                               writer: asyncio.StreamWriter):
            logger.info('Connected from %s', self.remote_addr)
            self.begin_control()

            while not reader.at_eof():
                line = await reader.readline()
                line = line.decode().strip()
                if not line:
                    if not reader.at_eof():
                        logger.warning('Empty command received')
                    continue
                self._process_command(line)

            logger.info('Disonnected')
            writer.write_eof()
            self.end_control()
            self.connection_task = None
Esempio n. 28
0
    async def communicate(
        self,
        reader: StreamReader,
        writer: StreamWriter,
    ):
        protocol = Protocol(reader, writer)
        request_writer_task = self.create_task(self._request_writer(protocol))

        client_host, client_port = writer.get_extra_info("peername")[:2]
        if ":" in client_host:
            client_host = f"[{client_host}]"

        log.info(
            "Start communication with tcp://%s:%d",
            client_host,
            client_port,
        )

        # noinspection PyBroadException
        try:
            async for payload in protocol:
                if payload.request is not None:
                    self.create_task(self.execute(protocol, payload.request), )
                if payload.response is not None:
                    self._on_response(payload.response)
        except Exception:
            log.exception(
                "Error when communication tcp://%s:%d/",
                client_host,
                client_port,
            )
        finally:
            if writer.can_write_eof():
                writer.write_eof()
            writer.close()
            log.info(
                "Communication with tcp://%s:%d finished",
                client_host,
                client_port,
            )

            await cancel_tasks([request_writer_task])
            await writer.wait_closed()
Esempio n. 29
0
File: ipc.py Progetto: zero77/qtile
    async def _server_callback(self, reader: asyncio.StreamReader,
                               writer: asyncio.StreamWriter) -> None:
        """Callback when a connection is made to the server

        Read the data sent from the client, execute the requested command, and
        send the reply back to the client.
        """
        try:
            logger.debug("Connection made to server")
            data = await reader.read()
            logger.debug("EOF received by server")

            req, is_json = _IPC.unpack(data)
        except IPCError:
            logger.warn("Invalid data received, closing connection")
        else:
            if req[1] == "restart":
                # if we are going to restart, close the connection first, as we won't be back
                logger.debug("Closing connection on restart")
                writer.write_eof()

            rep = self.handler(req)

            result = _IPC.pack(rep, is_json=is_json)

            logger.debug("Sending result on receive EOF")
            writer.write(result)
            logger.debug("Closing connection on receive EOF")
            writer.write_eof()
        finally:
            # the resoure isn't closed immediately on the close call, but is on
            # the next loop iteration, this is exposed as the wait_closed
            # method in 3.7, but requires a manual loop iteration in earlier
            # versions
            writer.close()
            if sys.version_info >= (3, 7):
                await writer.wait_closed()
            else:
                await asyncio.sleep(0)
Esempio n. 30
0
async def handle_req(reader: asyncio.StreamReader,
                     writer: asyncio.StreamWriter, filename: Path) -> None:
    """Send data."""
    try:
        LOG.info("Connection started...")
        if filename.suffix == ".gz":
            LOG.info("Opening gzfile...")
            fp_ = gzip.open(filename, "rb")
        elif zipfile.is_zipfile(filename):
            LOG.info("Opening zipfile...")
            zfile = zipfile.ZipFile(filename)
            fp_ = zfile.open(zfile.filelist[0], "r")
        else:
            fp_ = filename.open("rb")
        await reader.read(4026)

        while True:
            line = fp_.readline()
            if not line:
                LOG.info(
                    "No remaining line...sending term line and breaking...")
                break
            writer.write(line)
            await writer.drain()
        writer.write_eof()
        writer.close()
        await writer.wait_closed()
        LOG.debug("All lines sent...closing...")
    except (ConnectionResetError, BrokenPipeError, CancelledError):
        LOG.info("Cancel received..shutting down...")
        writer.close()

    except Exception as err:
        LOG.info(f"Unexepcted error! {err}")
        try:
            writer.close()
        except:
            pass
    LOG.info("Exiting...")
Esempio n. 31
0
	async def ahandle_peer(self, reader: StreamReader, writer: StreamWriter) -> None:
		"""Read all DNS queries from the peer stream and schedule their resolution via a DnsResolver instance."""
		tasks: Union[List[Task], Set[Task]] = []
		wlock = aio.Lock()

		logging.debug(f'Got TCP DNS query stream from {writer.transport.get_extra_info("peername")}')

		while True:
			# Parse a DNS query packet off of the wire
			try:
				query_size = int.from_bytes(await reader.readexactly(2), 'big')
				query = await reader.readexactly(query_size)

			# Check if our peer has finished writing to the stream
			except aio.IncompleteReadError:
				break

			# Schedule the processing of the query
			tasks.append(aio.create_task(self.ahandle_query(writer, wlock, query)))

		# Wait for all scheduled query processing to finish
		while tasks:
			done, tasks = await aio.wait(tasks, return_when=aio.FIRST_COMPLETED)

			for task in done:
				error = task.exception()

				if error is not None:
					logging.warning(f'TCP DNS query resolution encountered an error - {error!r}')

		if not writer.is_closing():
			# Indicate we are done writing to the stream
			if writer.can_write_eof():
				writer.write_eof()

			# Close the stream
			writer.close()
			await writer.wait_closed()
Esempio n. 32
0
    async def _handle_msg(self, reader: asyncio.StreamReader,
                          writer: asyncio.StreamWriter):
        """Handle incoming messages."""
        msg = Cmd(await reader.read())
        addr = writer.get_extra_info("peername")
        print_addr = addr if addr else "localhost"
        self.server_logger.debug(f"Received from {print_addr}")

        if msg.cmd in self.cmd_to_callback:
            self.server_logger.debug(f"Got cmd: {msg.cmd}")
            response = await self.cmd_to_callback[msg.cmd](msg)
        else:
            self.server_logger.warning(
                f"Got unrecognized command: {msg.cmd.value}")
            response = badResponse()
            response.error = ERRORS.UNRECOGNIZED_COMMAND

        writer.write(response.get_bytes())
        writer.write_eof()
        await writer.drain()

        self.server_logger.debug(f"Closed connection from {print_addr}")
        writer.close()
Esempio n. 33
0
    async def _handle_socks5_connection(self, dreader: asyncio.StreamReader,
                                        dwriter: asyncio.StreamWriter):
        log_name = '{!r} <=> ()'.format(
            dwriter.transport.get_extra_info('peername'))

        try:  # catch, log and suppress all exceptions in outermost layer
            with ExitStack() as stack:
                stack.enter_context(
                    self._connections.with_this(asyncio.Task.current_task()))
                stack.enter_context(finally_close(dwriter))
                self._logger.debug('%s accepted downstream connection',
                                   log_name)

                # Negotiate incoming SOCKS5 connection
                # Authentication
                buf = await dreader.readexactly(1)  # Version marker
                if buf[0] != 5:
                    raise RuntimeError('%s invalid SOCKS version' % log_name)
                buf = await dreader.readexactly(1)  # number of auth methods
                buf = await dreader.readexactly(buf[0])  # offered auth methods
                if SOCKS5AuthType.NO_AUTH not in buf:
                    self._logger.info('%s did not offer "no auth", offers: %r',
                                      log_name, buf)
                    dwriter.write(
                        bytes((5, SOCKS5AuthType.NO_OFFERS_ACCEPTABLE)))
                    dwriter.write_eof()
                    await dwriter.drain()
                    return
                dwriter.write(bytes((5, SOCKS5AuthType.NO_AUTH)))

                # client command
                buf = await dreader.readexactly(4)  # ver, cmd, rsv, addr_type
                if buf[0] != 5 or buf[2] != 0:
                    raise RuntimeError('%s malformed SOCKS5 command' %
                                       log_name)
                cmd = buf[1]
                addr_type = buf[3]
                if addr_type == SOCKS5AddressType.IPV4_ADDRESS:
                    uhost = ipaddress.IPv4Address(
                        await dreader.readexactly(4)).compressed
                elif addr_type == SOCKS5AddressType.IPV6_ADDRESS:
                    uhost = ipaddress.IPv6Address(
                        await dreader.readexactly(16)).compressed
                elif addr_type == SOCKS5AddressType.DOMAIN_NAME:
                    buf = await dreader.readexactly(1)  # address len
                    uhost = (await dreader.readexactly(buf[0])).decode('utf-8')
                else:
                    raise RuntimeError('%s illegal address type' % log_name)
                uport = int.from_bytes(await dreader.readexactly(2), 'big')
                log_name = '{!r} <=> ({!r}, {!r})'.format(
                    dwriter.transport.get_extra_info('peername'), uhost, uport)
                self._logger.debug('%s parsed target address', log_name)
                if cmd != SOCKS5Command.CONNECT:
                    self._logger.info('%s command %r not supported', log_name,
                                      cmd)
                    dwriter.write(
                        self._make_socks5_command_reply(
                            SOCKS5Reply.COMMAND_NOT_SUPPORTED, '0.0.0.0', 0))
                    dwriter.write_eof()
                    await dwriter.drain()
                    return
                self._logger.info('%s received CONNECT command', log_name)

                # determine detour state of host name
                # Since getting and setting detour state is separated quite far,
                # multiple connections to the same host will quite possibly
                # make the state inconsistent. However that does not have much
                # adverse effects on the operation.
                detour_state = self._whitelist.state(uhost)
                if not detour_state[0]:
                    self._logger.info('%s try direct connection', log_name)
                    try:
                        ureader, uwriter = await asyncio.wait_for(
                            asyncio.open_connection(
                                uhost,
                                uport,
                                loop=self._loop,
                                limit=self.RELAY_BUFFER_SIZE),
                            self.DETOUR_TIMEOUT,
                            loop=self._loop)
                    except (OSError, asyncio.TimeoutError) as e:
                        self._logger.info('%s direct connection error: %r',
                                          log_name, e)
                        self._whitelist.add_to_temp_wl(uhost)
                        # continue to making detoured connection
                    else:
                        self._logger.info('%s direct connection successful',
                                          log_name)
                        stack.enter_context(finally_close(uwriter))
                        dwriter.write(
                            self._make_socks5_command_reply(
                                SOCKS5Reply.SUCCESS,
                                *(uwriter.transport.get_extra_info('sockname')
                                  [:2])))
                        try:
                            await self._relay_data(dreader, dwriter, ureader,
                                                   uwriter, (uhost, uport))
                        except UpstreamNetworkError as e:
                            self._logger.info(
                                '%s direct connection upstream '
                                'error during relay: %r', log_name,
                                e.__cause__)
                            self._whitelist.add_to_temp_wl(uhost)
                            raise
                        self._logger.info(
                            '%s direct connection completed '
                            'without error', log_name)
                        # not going to make a detoured connection and try again
                        # because retrying means resending all sent data
                        return
                self._logger.info('%s try detoured connection', log_name)
                try:
                    ureader, uwriter = await aiosocks.open_connection(
                        self._upstream_addr,
                        self._upstream_auth, (uhost, uport),
                        remote_resolve=True,
                        loop=self._loop,
                        limit=self.RELAY_BUFFER_SIZE)
                except (OSError, aiosocks.SocksError) as e:
                    self._logger.info('%s detour connection error: %r',
                                      log_name, e)
                    dwriter.write(
                        self._make_socks5_command_reply(
                            SOCKS5Reply.GENERAL_SOCKS_SERVER_FAILURE,
                            '0.0.0.0', 0))
                    dwriter.write_eof()
                    await dwriter.drain()
                    if detour_state[0] == DetourState.TEMP:
                        self._whitelist.remove_from_temp_wl(detour_state[1])
                    return
                self._logger.info('%s detour connection successful', log_name)
                stack.enter_context(finally_close(uwriter))
                dwriter.write(
                    self._make_socks5_command_reply(
                        SOCKS5Reply.SUCCESS,
                        *uwriter.transport.get_extra_info('sockname')[:2]))
                try:
                    await self._relay_data(dreader, dwriter, ureader, uwriter,
                                           (uhost, uport))
                except UpstreamNetworkError as e:
                    self._logger.info(
                        '%s detoured connection upstream error '
                        'during relay: %r', log_name, e.__cause__)
                    if detour_state[0] == DetourState.TEMP:
                        self._whitelist.remove_from_temp_wl(detour_state[1])
                    raise
                self._logger.info(
                    '%s detoured connection completed without '
                    'error', log_name)
                if detour_state[0] == DetourState.TEMP:
                    self._whitelist.add_to_perm_wl(detour_state[1])
        except asyncio.CancelledError:
            self._logger.debug('%s cancelled', log_name)
            raise
        except (
                RuntimeError,
                OSError,
                UpstreamNetworkError,
        ) as e:  # not logging stack trace for normal errors
            self._logger.info('%s %r', log_name, e)
        except Exception as e:
            self._logger.error('%s %r', log_name, e, exc_info=True)
        finally:
            self._logger.debug('%s connection done', log_name)
Esempio n. 34
0
def fdms_session(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
    online = None
    ''':type: (FdmsHeader, FdmsTransaction)'''
    add_on = None
    ''':type: (FdmsHeader, FdmsTransaction)'''
    offline = list()

    writer.write(bytes((ENQ,)))
    yield from writer.drain()

    while True:

        # Get Request
        attempt = 0
        while True:
            try:
                if attempt > 4:
                    return

                request = yield from asyncio.wait_for(read_fdms_packet(reader), timeout=15.0)
                if len(request) == 0:
                    return

                control_byte = request[0]
                if control_byte == STX:
                    lrs = functools.reduce(lambda x, y: x ^ int(y), request[2:-1], int(request[1]))
                    if lrs != request[-1]:
                        raise ValueError('LRS sum')

                    pos, header = parse_header(request)
                    txn = header.create_txn()
                    txn.parse(request[pos:-2])
                    if header.txn_type == FdmsTransactionType.Online.value:
                        if online is None:
                            online = (header, txn)
                        else:
                            add_on = (header, txn)
                    else:
                        offline.append((header, txn))

                    if header.protocol_type == '2':
                        break

                    # Respond with ACK
                    attempt = 0
                    writer.write(bytes((ACK,)))

                elif control_byte == EOT:
                    break

            # Close session
            except asyncio.TimeoutError:
                return

            # Respond with NAK
            except Exception as e:
                logging.getLogger(LOG_NAME).debug('Request error: %s', str(e))
                attempt += 1
                writer.write(bytes((NAK,)))

            yield from writer.drain()

        if online is None:
            return

        # Process Transactions & Send Response
        for txn in offline:
            rs = process_txn(txn)
        offline.clear()

        if add_on is not None:
            process_add_on_txn(online, add_on)
        add_on = None

        rs = process_txn(online)

        # Send Response
        rs_bytes = rs.response()

        if rs.action_code == FdmsActionCode.HostSpecificPoll or rs.action_code == FdmsActionCode.RevisionInquiry:
            writer.write(rs_bytes)
            yield from writer.drain()
        else:
            attempt = 0
            while True:
                if attempt >= 4:
                    return

                writer.write(rs_bytes)
                yield from writer.drain()

                control_byte = 0
                try:
                    while True:
                        rs_head = yield from asyncio.wait_for(reader.read(1), timeout=4.0)
                        if len(rs_head) == 0:
                            return
                        control_byte = rs_head[0] & 0x7f
                        if control_byte == ACK:
                            break
                        elif control_byte == NAK:
                            break
                # Close session
                except asyncio.TimeoutError as e:
                    return

                if control_byte == ACK:
                    break
                else:
                    attempt += 1

            if online[0].wcc in {'B', 'C'}:
                # Send ENQ
                writer.write(bytes((ENQ,)))
                yield from writer.drain()
                continue
            else:
                break

    writer.write(bytes((EOT,)))
    yield from writer.drain()
    if writer.can_write_eof():
        writer.write_eof()