Source code for toxiccore.socks

# -*- coding: utf-8 -*-
# Copyright 2023 Juca Crispim <juca@poraodojuca.net>

# This file is part of toxiccore.

# toxiccore is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# toxiccore is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with toxiccore. If not, see <http://www.gnu.org/licenses/>.

import asyncio

WRITE_CHUNK_LEN = 4096
READ_CHUNK_LEN = 1024


[docs]async def read_stream(reader, timeout=None): """ Reads the input stream. First reads the bytes until the first "\\n". These first bytes are the length of the full message. :param reader: An instance of :class:`asyncio.StreamReader` :param timeout: Timeout for the operation. If None there is no timeout """ async def do_read(qbytes): r = await asyncio.wait_for(reader.read(qbytes), timeout) return r data = await do_read(1) if not data or data == b'\n': raw_data = b'' raw_data_list = [b''] else: char = None while char != b'\n' and char != b'': char = await do_read(1) data += char len_data = int(data) if len_data <= READ_CHUNK_LEN: raw_data = await do_read(len_data) else: raw_data = await do_read(READ_CHUNK_LEN) raw_data_len = len(raw_data) raw_data_list = [raw_data] while raw_data_len < len_data: left = len_data - raw_data_len next_chunk = left if left < READ_CHUNK_LEN else READ_CHUNK_LEN new_data = await do_read(next_chunk) raw_data_len += len(new_data) raw_data_list.append(new_data) return b''.join(raw_data_list)
[docs]async def write_stream(writer, data, timeout=None): """ Writes ``data`` to output. Encodes data to utf-8 and prepend the lenth of the data before sending it. :param writer: An instance of asyncio.StreamWriter :param data: String data to be sent. :param timeout: Timeout for the write operation. If None there is no timeout """ if writer is None: return False data = data.encode('utf-8') data = '{}\n'.format(len(data)).encode('utf-8') + data init = 0 chunk = data[:WRITE_CHUNK_LEN] while chunk: writer.write(chunk) await asyncio.wait_for(writer.drain(), timeout) init += WRITE_CHUNK_LEN chunk = data[init: init + WRITE_CHUNK_LEN] return True