├── kcp ├── __init__.py ├── ikcp_setup.py ├── server.py ├── local.py ├── pipe.py ├── updater.py ├── utils.py ├── KCP.pyx └── protocols.py ├── oldversion ├── kcp │ ├── Session.py │ ├── SessionManager.py │ ├── UKCPFactory.py │ └── KCP.py ├── setup.py ├── main.py ├── test_p.py ├── test.py ├── KCPServer.py ├── ServerManager.py ├── ClientManager.py ├── server.py ├── client.py ├── common.py ├── KCPClient.py ├── py_KCP.py └── KCP.pyx ├── reinstall.sh ├── Pipfile ├── .gitignore ├── test ├── local.json ├── server.json ├── test_udp_socket.py └── datagram_endpoint.py ├── setup.py ├── Pipfile.lock ├── README.md └── ikcp ├── ikcp.h └── ikcp.c /kcp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oldversion/kcp/Session.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /reinstall.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | pip uninstall kcp_py -y 3 | python3 setup.py install 4 | rm -rf build dist kcp_py.egg-info 5 | -------------------------------------------------------------------------------- /oldversion/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from Cython.Build import cythonize 3 | 4 | setup( 5 | ext_modules=cythonize("KCP.pyx") 6 | ) 7 | -------------------------------------------------------------------------------- /oldversion/main.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | parser = argparse.ArgumentParser(description="A Fast and Reliable ARQ Protocol Implementation On Python") 4 | 5 | parser.add_argument('-c', help='config from json file') 6 | 7 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.tuna.tsinghua.edu.cn/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | cython = "*" 10 | 11 | [requires] 12 | python_version = "3.7" 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | *.al 3 | *.bak 4 | *.egg-info 5 | *.la 6 | *.lo 7 | *.o 8 | *.orig 9 | *.pyc 10 | *.pyd 11 | *.rej 12 | *.so 13 | *.swp 14 | .cache/ 15 | .idea/ 16 | .tox/ 17 | venv 18 | build/ 19 | dist/ 20 | .vscode 21 | *.log -------------------------------------------------------------------------------- /kcp/ikcp_setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, Extension 2 | from Cython.Build import cythonize 3 | 4 | ext = Extension("KCP", sources=["kcp/KCP.pyx", "ikcp/ikcp.c"]) 5 | 6 | core = cythonize(ext) 7 | 8 | setup( 9 | ext_modules=core, 10 | ) 11 | -------------------------------------------------------------------------------- /test/local.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": "yukityan.cc", 3 | "server_port": 8002, 4 | "local": "127.0.0.1", 5 | "local_port": 8001, 6 | "sndwnd": 512, 7 | "rcvwnd": 2048, 8 | "mtu": 1300, 9 | "interval": 30, 10 | "resend": 2, 11 | "nc": 1, 12 | "nodelay": 0 13 | } 14 | -------------------------------------------------------------------------------- /test/server.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": "127.0.0.1", 3 | "server_port": 22, 4 | "local": "127.0.0.1", 5 | "local_port": 8002, 6 | "sndwnd": 512, 7 | "rcvwnd": 2048, 8 | "mtu": 1300, 9 | "interval": 30, 10 | "resend": 2, 11 | "nc": 1, 12 | "nodelay": 0 13 | } 14 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | from setuptools import setup 3 | 4 | setup( 5 | name='kcp_py', 6 | version='0.0.1', 7 | description='Python binding KCP tunnel', 8 | author='luvjoey1996', 9 | author_email='luvjoey1996@gmail.com', 10 | url='https://github.com/yukityan/kcp-py', 11 | packages=['kcp'], 12 | package_data={ 13 | 'kcp': ['KCP.cpython-37m-x86_64-linux-gnu.so'] 14 | }, 15 | install_requires=[], 16 | entry_points=""" 17 | [console_scripts] 18 | kcp_local = kcp.local:main 19 | kcp_server = kcp.server:main 20 | """, 21 | classifiers=[ 22 | 'Programming Language :: Python :: 3.7' 23 | ] 24 | ) 25 | -------------------------------------------------------------------------------- /test/test_udp_socket.py: -------------------------------------------------------------------------------- 1 | from socket import * 2 | 3 | 4 | def send_to_closed_udp_socket(): 5 | sock = socket(AF_INET, SOCK_DGRAM) 6 | sock.bind(('127.0.0.1', 0)) 7 | sock.sendto(b'hello world', ('127.0.0.1', 9999)) 8 | 9 | 10 | def udp_connection(): 11 | sock = socket(AF_INET, SOCK_DGRAM) 12 | sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 13 | sock.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1) 14 | sock.bind(('localhost', 1234)) 15 | sock.connect(('localhost', 1235)) 16 | sock.send(b'1234') 17 | while True: 18 | data, addr = sock.recvfrom(1024) 19 | print(f"recv data from {addr}") 20 | sock.send(data) 21 | 22 | 23 | if __name__ == '__main__': 24 | udp_connection() 25 | -------------------------------------------------------------------------------- /oldversion/test_p.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from asyncio import protocols 3 | 4 | 5 | class UdpProtocol(protocols.DatagramProtocol): 6 | 7 | def connection_made(self, transport): 8 | self.transport = transport 9 | print(self.transport._extra.items()) 10 | 11 | def datagram_received(self, data, addr) -> None: 12 | self.transport.sendto(data, addr) 13 | 14 | def connection_lost(self, exc): 15 | pass 16 | 17 | 18 | async def main(): 19 | loop = asyncio.get_event_loop() 20 | transport, protocol = await loop.create_datagram_endpoint(UdpProtocol, local_addr=('127.0.0.1', 9999)) 21 | await asyncio.sleep(100) 22 | 23 | 24 | if __name__ == '__main__': 25 | asyncio.run(main()) 26 | -------------------------------------------------------------------------------- /oldversion/test.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | 4 | class Protocol(asyncio.DatagramProtocol): 5 | 6 | def connection_made(self, transport) -> None: 7 | self.transport = transport 8 | 9 | def datagram_received(self, data, addr) -> None: 10 | received = data.decode('utf8') 11 | print(received) 12 | self.transport.sendto(data, addr) 13 | 14 | 15 | async def main(): 16 | loop = asyncio.get_event_loop() 17 | transport, protocol = await loop.create_datagram_endpoint(Protocol, remote_addr=('192.168.1.4', 8000)) 18 | transport.sendto('hello world!'.encode('utf8')) 19 | 20 | 21 | if __name__ == '__main__': 22 | loop = asyncio.get_event_loop() 23 | loop.create_task(main()) 24 | loop.run_forever() 25 | -------------------------------------------------------------------------------- /oldversion/kcp/SessionManager.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from oldversion.kcp.UKCPFactory import UKCPConnector 4 | 5 | 6 | class ClientSession: 7 | 8 | def __init__(self, local_addr, remote_addr, loop): 9 | self.local_addr = local_addr 10 | self.remote_addr = remote_addr 11 | self.loop = loop 12 | self.kcpConnector = UKCPConnector(loop, remote_addr) 13 | 14 | async def server(self): 15 | server = await asyncio.start_server(self.proxy, host=self.local_addr[0], port=self.local_addr[1]) 16 | async with server: 17 | await server.serve_forever() 18 | 19 | async def proxy(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter): 20 | kcpReader, kcpWriter = self.kcpConnector.connect() 21 | while True: 22 | asyncio.wait() 23 | 24 | async def wrap(self, flag, coro): 25 | return flag, await coro 26 | -------------------------------------------------------------------------------- /kcp/server.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import functools 3 | import logging 4 | import os 5 | import signal 6 | import sys 7 | 8 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../')) 9 | 10 | from kcp import utils 11 | from kcp.protocols import ServerDataGramHandlerProtocol 12 | from kcp.pipe import open_pipe 13 | from kcp.updater import updater 14 | 15 | 16 | async def server_main(): 17 | loop = asyncio.get_event_loop() 18 | config = utils.get_config(False) 19 | 20 | def ds_factory(): 21 | return asyncio.open_connection(host=config.server, port=config.server_port) 22 | 23 | protocol = ServerDataGramHandlerProtocol(functools.partial(open_pipe, ds_factory=ds_factory)) 24 | await loop.create_datagram_endpoint(lambda: protocol, local_addr=(config.local, config.local_port)) 25 | logging.info("start server at %s:%s", config.local, config.local_port) 26 | updater.load_config(config) 27 | updater.run() 28 | for signame in {'SIGQUIT', 'SIGTERM'}: 29 | loop.add_signal_handler( 30 | getattr(signal, signame), lambda: asyncio.ensure_future(utils.shutdown(signame, loop))) 31 | e = asyncio.Event() 32 | try: 33 | await e.wait() 34 | except KeyboardInterrupt: 35 | await utils.shutdown('KeyboardInterrupt', loop) 36 | 37 | 38 | def main(): 39 | asyncio.run(server_main()) 40 | 41 | 42 | if __name__ == '__main__': 43 | main() 44 | -------------------------------------------------------------------------------- /kcp/local.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import functools 3 | import logging 4 | import os 5 | import signal 6 | import sys 7 | 8 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../')) 9 | 10 | from kcp import utils 11 | from kcp.pipe import open_pipe 12 | from kcp.protocols import DataGramConnHandlerProtocol 13 | from kcp.updater import updater 14 | 15 | 16 | class LocalServerError(Exception): 17 | """local server error""" 18 | 19 | 20 | async def local_main(): 21 | loop = asyncio.get_event_loop() 22 | utils.check_python() 23 | config = utils.get_config(True) 24 | _, protocol = await loop.create_datagram_endpoint( 25 | lambda: DataGramConnHandlerProtocol(is_local=True), 26 | remote_addr=(config.server, config.server_port) 27 | ) 28 | 29 | server = await asyncio.start_server( 30 | functools.partial(open_pipe, ds_factory=protocol.create_connection), 31 | host=config.local, 32 | port=config.local_port) 33 | 34 | logging.info("starting local at %s:%s", config.local, config.local_port) 35 | updater.load_config(config) 36 | updater.run() 37 | for signame in {'SIGQUIT', 'SIGTERM'}: 38 | loop.add_signal_handler( 39 | getattr(signal, signame), lambda: asyncio.ensure_future(utils.shutdown(signame, loop))) 40 | try: 41 | async with server: 42 | await server.serve_forever() 43 | except asyncio.CancelledError: 44 | await asyncio.sleep(1) 45 | except KeyboardInterrupt: 46 | await utils.shutdown('KeyboardInterrupt', loop) 47 | 48 | 49 | def main(): 50 | asyncio.run(local_main()) 51 | 52 | 53 | if __name__ == '__main__': 54 | main() 55 | -------------------------------------------------------------------------------- /oldversion/KCPServer.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import functools 3 | from typing import Tuple 4 | import uvloop 5 | 6 | from oldversion.KCP import KCP 7 | from oldversion.KCPClient import KCPClientController 8 | 9 | 10 | class KCPServerController(KCPClientController): 11 | 12 | def datagram_received(self, data: bytearray, addr: Tuple[str, int]): 13 | self.client_addr = addr 14 | conv = KCP.ikcp_decode32u(data, 0) 15 | conversation = self.convs.get(conv) 16 | if conversation: 17 | self.input(conv, data) 18 | else: 19 | self.recv_buffers[conv].append(data) 20 | task = self.loop.create_task(self.loop.create_connection( 21 | functools.partial(self.stream_protocol, conv=conv), host=self.remote_addr[0], port=self.remote_addr[1])) 22 | task.add_done_callback(self.flush_input) 23 | 24 | def flush_input(self, fut): 25 | transport, protocol = fut.result() 26 | conv = protocol.conv 27 | buffers = self.input_buffer.get(conv) 28 | while buffers: 29 | self.input(conv, buffers.pop(0)) 30 | 31 | def connection_lost(self, exc: Exception): 32 | self.transport = None 33 | 34 | async def start(self): 35 | await self.loop.create_datagram_endpoint(self.datagram_endpoint, local_addr=self.local_addr) 36 | self.loop.call_soon(self.interval) 37 | 38 | 39 | if __name__ == '__main__': 40 | asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) 41 | loop = asyncio.get_event_loop() 42 | server = KCPServerController(loop, local_addr=('127.0.0.1', 8888), remote_addr=('127.0.0.1', 9999)) 43 | loop.create_task(server.start()) 44 | try: 45 | loop.run_forever() 46 | except KeyboardInterrupt: 47 | loop.close() 48 | -------------------------------------------------------------------------------- /kcp/pipe.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | from asyncio import StreamReader, StreamWriter 4 | from typing import Tuple 5 | 6 | 7 | class DataPipeError(Exception): 8 | """DataPipe Error""" 9 | 10 | 11 | async def open_pipe(us_reader: StreamReader, us_writer: StreamWriter, ds_factory=None): 12 | logging.info("pipe open") 13 | ds_reader, ds_writer = await ds_factory() 14 | pipe = DataPipe((us_reader, us_writer), (ds_reader, ds_writer)) 15 | try: 16 | await pipe.flow(65536, 300) 17 | finally: 18 | logging.info("pipe closed") 19 | us_writer.is_closing() or us_writer.close() 20 | ds_writer.is_closing() or ds_writer.close() 21 | 22 | 23 | class DataPipe: 24 | 25 | def __init__(self, upstream: Tuple[StreamReader, StreamWriter], downstream: Tuple[StreamReader, StreamWriter]): 26 | self.upstream = upstream 27 | self.downstream = downstream 28 | 29 | async def flow(self, size, timeout): 30 | us_reader, us_writer = self.upstream 31 | ds_reader, ds_writer = self.downstream 32 | 33 | async def flowing(reader, writer): 34 | try: 35 | while not reader.at_eof() and not writer.is_closing(): 36 | writer.write(await asyncio.wait_for(reader.read(size), timeout)) 37 | except asyncio.TimeoutError: 38 | logging.info("timeout while reading data") 39 | except DataPipeError: 40 | logging.exception("pipe error") 41 | 42 | tasks = {flowing(us_reader, ds_writer), flowing(ds_reader, us_writer)} 43 | waiting = asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) 44 | try: 45 | done, tasks = await waiting 46 | finally: 47 | for task in tasks: 48 | task.cancel() 49 | -------------------------------------------------------------------------------- /oldversion/ServerManager.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from asyncio import AbstractEventLoop, DatagramProtocol, Future, Queue 3 | from collections import defaultdict 4 | from typing import Union, Text, Tuple 5 | 6 | from oldversion.KCP import KCP 7 | from oldversion.common import AbstractManager 8 | 9 | 10 | class ServerManager(AbstractManager): 11 | 12 | def __init__(self, local_addr: Tuple[str, int], loop: AbstractEventLoop = None): 13 | self.local_addr = local_addr 14 | self.loop = loop or asyncio.get_event_loop() 15 | self.transport, self.protocol = None, None 16 | self.connections = {} 17 | self.recv_wait = defaultdict(Future) 18 | self.remote_addr = None 19 | self.wait_accept = Queue() 20 | 21 | async def start(self): 22 | self.transport, self.protocol = await self.loop.create_datagram_endpoint( 23 | lambda: ServerProtocol(self), local_addr=self.local_addr 24 | ) 25 | self.loop.create_task(self.interval()) 26 | 27 | async def accept(self): 28 | return await self.wait_accept.get() 29 | 30 | 31 | class ServerProtocol(DatagramProtocol): 32 | 33 | def __init__(self, manager: ServerManager): 34 | self.manager = manager 35 | self.transport = None 36 | 37 | def connection_made(self, transport: DatagramProtocol): 38 | self.transport = transport 39 | 40 | def datagram_received(self, data: Union[bytes, Text], addr: Tuple[str, int]): 41 | if not self.manager.remote_addr: 42 | self.manager.remote_addr = addr 43 | conv = KCP.ikcp_decode32u(data, 0) 44 | if conv not in self.manager.connections: 45 | kcp = self.manager.get_session(conv) 46 | self.manager.loop.create_task(self.manager.wait_accept.put(kcp)) 47 | self.manager.input(conv, data) 48 | -------------------------------------------------------------------------------- /kcp/updater.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from KCP import kcp_now 4 | 5 | 6 | class Updater: 7 | 8 | def __init__(self): 9 | self.tunnels = set() 10 | self.interval = 0.05 11 | self.raw_interval = 50 12 | self.register = self.tunnels.add 13 | self.unregister = self.tunnels.remove 14 | 15 | def update(self): 16 | for tunnel in self.tunnels: 17 | now = kcp_now() 18 | sessions = tunnel.sessions 19 | active = tunnel.active_sessions 20 | active_pop = active.pop 21 | active_add = active.add 22 | try: 23 | conv = active_pop() 24 | session = sessions[conv] 25 | kcp = session.kcp 26 | kcp.update(now) 27 | if kcp.state == -1: 28 | tunnel.close_session(session) 29 | else: 30 | peeksize = kcp.peeksize() 31 | if peeksize != 0 and peeksize != -1: 32 | data = bytes(peeksize) 33 | kcp.recv(data, peeksize) 34 | session.protocol.data_received(data) 35 | next_call = kcp.check(now) 36 | session.next_update = next_call 37 | except KeyError: 38 | raw_interval = self.raw_interval 39 | for session in sessions.values(): 40 | if session.next_update - now < raw_interval: 41 | active_add(session.conv) 42 | asyncio.get_event_loop().call_later(self.interval, self.update) 43 | 44 | def load_config(self, config): 45 | self.raw_interval = config.interval 46 | self.interval = config.interval / 1000 47 | 48 | def run(self): 49 | loop = asyncio.get_event_loop() 50 | loop.call_soon(self.update) 51 | 52 | 53 | updater = Updater() 54 | -------------------------------------------------------------------------------- /oldversion/ClientManager.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | from asyncio import AbstractEventLoop, DatagramProtocol, Future 4 | from collections import defaultdict 5 | from typing import Union, Text, Tuple 6 | 7 | from oldversion.KCP import KCP 8 | from oldversion.common import AbstractManager 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | TWELVE_HOUR = 12 * 60 * 60 * 1000 13 | 14 | 15 | class ClientManager(AbstractManager): 16 | 17 | def __init__(self, remote_addr=Tuple[str, int], loop: AbstractEventLoop = None): 18 | self.remote_addr = remote_addr 19 | self.loop = loop or asyncio.get_event_loop() 20 | self.transport, self.protocol = None, None 21 | self.connections = {} 22 | self.recv_wait = defaultdict(Future) 23 | self._conv_generator = (i for i in range(TWELVE_HOUR)) 24 | 25 | async def start(self): 26 | self.transport, self.protocol = await self.loop.create_datagram_endpoint( 27 | lambda: ClientProtocol(self), 28 | remote_addr=self.remote_addr) 29 | await self.loop.create_task(self.interval()) 30 | 31 | @property 32 | def conv(self): 33 | while True: 34 | try: 35 | return next(self._conv_generator) 36 | except StopIteration: 37 | self._conv_generator = (i for i in range(TWELVE_HOUR)) 38 | 39 | 40 | class ClientProtocol(DatagramProtocol): 41 | 42 | def __init__(self, manager: ClientManager): 43 | self.manager = manager 44 | self.transport = None 45 | 46 | def connection_made(self, transport: DatagramProtocol): 47 | logger.info('connecting to server %s:%s', *self.manager.remote_addr) 48 | self.transport = transport 49 | 50 | def datagram_received(self, data: Union[bytes, Text], addr: Tuple[str, int]): 51 | conv = KCP.ikcp_decode32u(data, 0) 52 | if conv in self.manager.connections: 53 | self.manager.input(conv, data) 54 | -------------------------------------------------------------------------------- /oldversion/server.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from oldversion.ServerManager import ServerManager 4 | 5 | 6 | class Server: 7 | 8 | def __init__(self, local_addr, remote_addr, loop): 9 | self.local_addr = local_addr 10 | self.remote_addr = remote_addr 11 | self.loop = loop or asyncio.get_event_loop() 12 | self.manager = ServerManager(local_addr=local_addr, loop=self.loop) 13 | 14 | async def start(self): 15 | await self.manager.start() 16 | while True: 17 | kcp = await self.manager.accept() 18 | self.loop.create_task(self.dispatcher(kcp)) 19 | 20 | async def dispatcher(self, kcp): 21 | reader, writer = await asyncio.open_connection(self.remote_addr[0], self.remote_addr[1], loop=self.loop) 22 | pending = { 23 | self.manager.recv(kcp), 24 | self.read(reader) 25 | } 26 | try: 27 | while True: 28 | done, pending = await asyncio.wait( 29 | pending, 30 | return_when=asyncio.FIRST_COMPLETED, 31 | loop=self.loop 32 | ) 33 | for task in done: 34 | flag, data = task.result() 35 | if flag == 'recv': 36 | writer.write(data) 37 | await writer.drain() 38 | pending.add(self.manager.recv(kcp)) 39 | elif flag == 'read': 40 | self.manager.send(kcp, data) 41 | pending.add(self.read(reader)) 42 | else: 43 | pass 44 | except (asyncio.CancelledError, Exception) as err: 45 | print(err) 46 | finally: 47 | writer.close() 48 | self.manager.close(kcp) 49 | 50 | async def read(self, reader): 51 | return 'read', (await reader.read(1024)) 52 | 53 | 54 | if __name__ == '__main__': 55 | loop = asyncio.get_event_loop() 56 | server = Server(('127.0.0.1', 8888), ('127.0.0.1', 80), loop) 57 | loop.run_until_complete(server.start()) 58 | try: 59 | loop.run_forever() 60 | except KeyboardInterrupt: 61 | loop.close() 62 | -------------------------------------------------------------------------------- /oldversion/client.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from oldversion.ClientManager import ClientManager 4 | 5 | 6 | class Client: 7 | 8 | def __init__(self, local_addr, remote_addr, loop=None): 9 | self.local_addr = local_addr 10 | self.remote_addr = remote_addr 11 | self.loop = loop or asyncio.get_event_loop() 12 | self.manager = ClientManager(remote_addr=remote_addr, loop=self.loop) 13 | 14 | async def start(self, **kwargs): 15 | self.client = await asyncio.start_server(self.dispatcher, host=self.local_addr[0], 16 | port=self.local_addr[1], loop=self.loop) 17 | await self.manager.start() 18 | 19 | async def dispatcher(self, reader, writer): 20 | kcp = self.manager.get_session() 21 | pending = { 22 | self.manager.recv(kcp), 23 | self.read(reader) 24 | } 25 | try: 26 | while True: 27 | done, pending = await asyncio.wait( 28 | pending, 29 | return_when=asyncio.FIRST_COMPLETED, 30 | loop=self.loop 31 | ) 32 | for task in done: 33 | flag, data = task.result() 34 | if flag == 'recv': 35 | writer.write(data) 36 | await writer.drain() 37 | pending.add(self.manager.recv(kcp)) 38 | elif flag == 'read': 39 | self.manager.send(kcp, data) 40 | pending.add(self.read(reader)) 41 | else: 42 | pass 43 | except (asyncio.CancelledError, Exception) as err: 44 | print(err) 45 | finally: 46 | writer.close() 47 | self.manager.close(kcp) 48 | 49 | async def read(self, reader): 50 | return 'read', (await reader.read(1024)) 51 | 52 | 53 | if __name__ == '__main__': 54 | loop = asyncio.get_event_loop() 55 | client = Client(('127.0.0.1', 7777), ('127.0.0.1', 8888), loop) 56 | loop.run_until_complete(client.start()) 57 | try: 58 | loop.run_forever() 59 | except KeyboardInterrupt: 60 | loop.close() 61 | -------------------------------------------------------------------------------- /test/datagram_endpoint.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from asyncio import protocols, transports 3 | 4 | 5 | class DataGramConnProtocol(protocols.DatagramProtocol): 6 | 7 | def connection_made(self, transport: transports.DatagramTransport) -> None: 8 | print("conn established local_addr: {} remote_addr: {}".format( 9 | transport.get_extra_info('sockname'), 10 | transport.get_extra_info('peername') 11 | )) 12 | self.transport = transport 13 | 14 | def datagram_received(self, data: bytes, addr) -> None: 15 | print(f"conn received data from {addr}") 16 | self.transport.sendto(data) 17 | 18 | 19 | class DataGramServerProtocol(protocols.DatagramProtocol): 20 | connections = set() 21 | 22 | def connection_made(self, transport: transports.DatagramTransport) -> None: 23 | print("server start listen") 24 | self.transport = transport 25 | 26 | def datagram_received(self, data: bytes, addr) -> None: 27 | print(f"server received data from {addr}") 28 | print(f'addr {"in" if addr in self.connections else "not in"} self connections') 29 | self.connections.add(addr) 30 | loop = asyncio.get_event_loop() 31 | task = loop.create_task(loop.create_datagram_endpoint( 32 | DataGramConnProtocol, 33 | local_addr=self.transport.get_extra_info('sockname'), 34 | remote_addr=addr, 35 | reuse_address=True 36 | )) 37 | 38 | def client_connected_cb(result: asyncio.Future): 39 | if not result.exception(): 40 | transport, protocol = result.result() 41 | protocol.datagram_received(data, addr) 42 | else: 43 | print(result.exception()) 44 | 45 | task.add_done_callback(client_connected_cb) 46 | 47 | def connection_lost(self, exc) -> None: 48 | pass 49 | 50 | def error_received(self, exc: Exception) -> None: 51 | pass 52 | 53 | 54 | async def main(): 55 | loop = asyncio.get_event_loop() 56 | await loop.create_datagram_endpoint( 57 | DataGramServerProtocol, 58 | local_addr=('127.0.0.1', 1234), 59 | reuse_address=True 60 | ) 61 | fin = asyncio.Event() 62 | await fin.wait() 63 | 64 | 65 | if __name__ == '__main__': 66 | asyncio.run(main()) 67 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "f1cd2bf600330f4f606d74baf5766700fcfb5f8fe40d67b9daef88b3288b98c2" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.tuna.tsinghua.edu.cn/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "cython": { 20 | "hashes": [ 21 | "sha256:07efba7b32c082c519b75e3b03821c2f32848e2b3e9986c784bbd8ffaf0666d7", 22 | "sha256:08db41daf18fabf7b7a85e39aa26954f6246994540043194af026c0df65a4942", 23 | "sha256:19bbe3caf885a1d2e2c30eacc10d1e45dbbefb156493fe1d5d1adc1668cc1269", 24 | "sha256:1c574f2f2ba760b82b2bcf6262e77e75589247dc5ef796a3ff1b2213e50ee452", 25 | "sha256:1dfe672c686e34598bdbaa93c3b30acb3720ae9258232a4f68ba04ee9969063d", 26 | "sha256:283faea84e6c4e54c3f5c8ff89aa2b6c1c3a813aad4f6d48ed3b9cc9043ef9f9", 27 | "sha256:2a145888d0942e7c36e86a7b7c7e2923cb9f7055805a3b72dcb137e3efdb0979", 28 | "sha256:3f75065936e16569d6e13dfd76de988f5eabeae460aa54770c9b961ab6f747fc", 29 | "sha256:4d78124f5f281f1d5d5b7919cbbc65a7073ff93562def81ee78a8307e6e72494", 30 | "sha256:5ba4d088b8e5d59b8a5911ca9c72952acf3c83296b57daf75af92fb2af1e8423", 31 | "sha256:6b19daeda1d5d1dfc973b291246f6a63a663b20c33980724d6d073c562719536", 32 | "sha256:790c7dc80fd1c3e38acefe06027e2f5a8466c128c7e47c6e140fd5316132574d", 33 | "sha256:7f8c4e648881454ba3ba0bcf3b21a9e1878a67d20ea2b8d9ec1c4c628592ab6b", 34 | "sha256:8bcd3f597290f9902548d6355898d7e376e7f3762f89db9cd50b2b58429df9e8", 35 | "sha256:8ffb18f71972a5c718a8600d9f52e3507f0d6fb72a978e03270d34a7035c98fb", 36 | "sha256:92f025df1cb391e09f65775598c7dfb7efad72d74713775db54e267f62ca94a1", 37 | "sha256:93cf1c72472a2fd0ef4c52f6074dab08fc28d475b9c824ba73a52701f7a48ae1", 38 | "sha256:9a7fa692cdc967fdbf6a053c1975137d01f6935dede2ef222c71840b290caf79", 39 | "sha256:a68eb0c1375f2401de881692b30370a51e550052b8e346b2f71bbdbdc74a214f", 40 | "sha256:ac3b7a12ddd52ea910ee3a041e6bc65df7a52f0ba7bd10fb7123502af482c152", 41 | "sha256:b402b700edaf571a0bae18ec35d5b71c266873a6616412b672435c10b6d8f041", 42 | "sha256:c29d069a4a30f472482343c866f7486731ad638ef9af92bfe5fca9c7323d638e", 43 | "sha256:d822311498f185db449b687336b4e5db7638c8d8b03bdf10ae91d74e23c7cc0c", 44 | "sha256:dccc8df9e1ac158b06777bbaaeb4516f245f9b147701ae25e6023960e4a0c2a3", 45 | "sha256:e31f4b946c2765b2f35440fdb4b00c496dfc5babc53c7ae61966b41171d1d59f", 46 | "sha256:eb43f9e582cc221ee2832e25ea6fe5c06f2acc9da6353c562e922f107db12af8", 47 | "sha256:f07822248110fd6213db8bc2745fdbbccef6f2b3d18ac91a7fba29c6bc575da5", 48 | "sha256:ff69854f123b959d4ae14bd5330714bb9ee4360052992dc0fbd0a3dee4261f95" 49 | ], 50 | "index": "pypi", 51 | "version": "==0.29.13" 52 | } 53 | }, 54 | "develop": {} 55 | } 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KCP-PY 2 | 3 | 4 | ### description 5 | - python binding for kcp 6 | - simple tunnel implementation based asyncio module 7 | - [KCP: A Fast and Reliable ARQ Protocol](https://github.com/skywind3000/kcp) 8 | 9 | ### platform 10 | - python3.7 11 | - arch linux 12 | 13 | ### install 14 | ```shell script 15 | git clone https://github.com/yukityan/kcp-py.git 16 | cd kcp-py 17 | python3 -m pip install cython 18 | python3 kcp/ikcp_setup.py build_ext --build-lib=kcp/ 19 | python3 setup.py install 20 | ``` 21 | 22 | ### uninstall 23 | ```shell script 24 | pip uninstall kcp_py 25 | ``` 26 | 27 | ### usage 28 | 29 | #### console_scripts 30 | - kcp_local 31 | ```console 32 | foo@bar:~$ kcp_local -h 33 | usage: kcp_local [-h] [-s SERVER] [-p SERVER_PORT] [-l LOCAL] [-t LOCAL_PORT] 34 | [-c CONFIG] [--sndwnd SNDWND] [--rcvwnd RCVWND] [--mtu MTU] 35 | [--interval {30,40,50}] [--nodelay {0,1}] [--resend {0,1,2}] 36 | [--nc {0,1}] 37 | 38 | Python binding KCP tunnel Local. 39 | 40 | optional arguments: 41 | -h, --help show this help message and exit 42 | -s SERVER, --server SERVER 43 | Host name or IP address of your remote server. 44 | -p SERVER_PORT, --server_port SERVER_PORT 45 | Port number of your remote server. 46 | -l LOCAL, --local LOCAL 47 | Host name or IP address your local server 48 | -t LOCAL_PORT, --local_port LOCAL_PORT 49 | Port number of your local server. 50 | -c CONFIG, --config CONFIG 51 | config file path 52 | --sndwnd SNDWND send window size. (default 128) 53 | --rcvwnd RCVWND receive window size (default 512) 54 | --mtu MTU Maximum Transmission Unit for UDP packets (default: 55 | 1350) 56 | --interval {30,40,50} 57 | Interval of KCP update (ms) 58 | --nodelay {0,1} KCP ack nodelay or delay (default: 0 nodelay) 59 | --resend {0,1,2} Fast resend 60 | --nc {0,1} net control disable or enable (default: 0 enable) 61 | ``` 62 | - kcp_server 63 | ```console 64 | foo@bar:~$ kcp_server -h 65 | usage: kcp_server [-h] [-s SERVER] [-p SERVER_PORT] [-l LOCAL] [-t LOCAL_PORT] 66 | [-c CONFIG] [--sndwnd SNDWND] [--rcvwnd RCVWND] [--mtu MTU] 67 | [--interval {30,40,50}] [--nodelay {0,1}] [--resend {0,1,2}] 68 | [--nc {0,1}] 69 | 70 | Python binding KCP tunnel Server. 71 | 72 | optional arguments: 73 | -h, --help show this help message and exit 74 | -s SERVER, --server SERVER 75 | Host name or IP address of your remote server. 76 | -p SERVER_PORT, --server_port SERVER_PORT 77 | Port number of your remote server. 78 | -l LOCAL, --local LOCAL 79 | Host name or IP address your local server 80 | -t LOCAL_PORT, --local_port LOCAL_PORT 81 | Port number of your local server. 82 | -c CONFIG, --config CONFIG 83 | config file path 84 | --sndwnd SNDWND send window size. (default 128) 85 | --rcvwnd RCVWND receive window size (default 512) 86 | --mtu MTU Maximum Transmission Unit for UDP packets (default: 87 | 1350) 88 | --interval {30,40,50} 89 | Interval of KCP update (ms) 90 | --nodelay {0,1} KCP ack nodelay or delay (default: 0 nodelay) 91 | --resend {0,1,2} Fast resend 92 | --nc {0,1} net control disable or enable (default: 0 enable) 93 | ``` 94 | 95 | #### config example 96 | ```json 97 | { 98 | "server": "kcp_test.com", 99 | "server_port": 8002, 100 | "local": "localhost", 101 | "local_port": 8002, 102 | "sndwnd": 128, 103 | "rcvwnd": 1024, 104 | "mtu": 1300, 105 | "interval": 30, 106 | "resend": 2, 107 | "nc": 1, 108 | "nodelay": 0 109 | } 110 | ``` 111 | 112 | -------------------------------------------------------------------------------- /kcp/utils.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import asyncio 3 | import functools 4 | import json 5 | import logging 6 | import sys 7 | from dataclasses import dataclass 8 | 9 | 10 | def check_python(): 11 | info = sys.version_info 12 | if info[0] != 3 and info[1] < 7: 13 | print('Python 3.7+ required') 14 | sys.exit(1) 15 | 16 | 17 | async def shutdown(signame, loop): 18 | logging.info('caught {0}'.format(signame)) 19 | tasks = [task for task in asyncio.Task.all_tasks() if task is not 20 | asyncio.tasks.Task.current_task()] 21 | list(map(lambda task: task.cancel(), tasks)) 22 | results = await asyncio.gather(*tasks, return_exceptions=True) 23 | logging.info('finished awaiting cancelled tasks, results: %s'.format(results)) 24 | loop.stop() 25 | 26 | 27 | def singleton(cls): 28 | instance = None 29 | 30 | @functools.wraps(cls) 31 | def wrapper(*args, **kwargs): 32 | nonlocal instance 33 | if not instance: 34 | instance = cls(*args, **kwargs) 35 | return instance 36 | 37 | return wrapper 38 | 39 | 40 | @singleton 41 | @dataclass 42 | class KCPConfig: 43 | server: str 44 | server_port: int 45 | local: str 46 | local_port: int 47 | sndwnd: int 48 | rcvwnd: int 49 | mtu: int 50 | interval: int 51 | nodelay: bool 52 | nc: int 53 | resend: int 54 | 55 | 56 | def get_config(is_local): 57 | logging.basicConfig(level=logging.INFO, 58 | format='%(levelname)-s: %(message)s') 59 | parser = argparse.ArgumentParser( 60 | description='Python binding KCP tunnel {}.'.format('Local' if is_local else 'Server')) 61 | config_attr = ['server', 'server_port', 'local', 'local_port', 62 | 'sndwnd', 'rcvwnd', 'mtu', 63 | 'interval', 'nodelay', 'resend', 'nc'] 64 | parser.add_argument('-s', '--server', help='Host name or IP address of your remote server.') 65 | parser.add_argument('-p', '--server_port', help='Port number of your remote server.', type=int) 66 | parser.add_argument('-l', '--local', help='Host name or IP address your local server') 67 | parser.add_argument('-t', '--local_port', help='Port number of your local server.', type=int) 68 | parser.add_argument('-c', '--config', help='config file path') 69 | parser.add_argument( 70 | '--sndwnd', 71 | help='send window size. (default 128)', 72 | type=int, 73 | default=128) 74 | parser.add_argument( 75 | '--rcvwnd', 76 | help='receive window size (default 512)', 77 | type=int, 78 | default=512) 79 | parser.add_argument( 80 | '--mtu', 81 | help='Maximum Transmission Unit for UDP packets (default: 1350)', 82 | type=int, 83 | default=1350) 84 | parser.add_argument( 85 | '--interval', 86 | help='Interval of KCP update (ms)', 87 | type=int, 88 | default=50, 89 | choices=[10, 20, 30, 40, 50]) 90 | parser.add_argument( 91 | '--nodelay', 92 | help='KCP ack nodelay or delay (default: 0 nodelay)', 93 | type=int, 94 | choices=[0, 1], 95 | default=0) 96 | parser.add_argument( 97 | '--resend', 98 | help='Fast resend', 99 | type=int, 100 | default=0, 101 | choices=[0, 1, 2]) 102 | parser.add_argument( 103 | '--nc', 104 | help="net control disable or enable (default: 0 enable)", 105 | type=int, 106 | default=0, 107 | choices=[0, 1]) 108 | args = parser.parse_args() 109 | if args.config: 110 | try: 111 | with open(args.config) as file: 112 | try: 113 | args_list = [] 114 | config_dict = json.load(file) 115 | for k, v in config_dict.items(): 116 | args_list.append(f'--{k}') 117 | args_list.append(f'{v}') 118 | args = parser.parse_args(args_list) 119 | except ValueError: 120 | logging.exception("error format of config file") 121 | exit(1) 122 | except IOError: 123 | logging.exception("error loading config file") 124 | exit(1) 125 | return KCPConfig(**{k: getattr(args, k) for k in config_attr}) 126 | -------------------------------------------------------------------------------- /oldversion/common.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import functools 3 | import time 4 | from asyncio import Future, DatagramProtocol 5 | from typing import Union, Tuple, Dict 6 | 7 | from oldversion.KCP import KCP 8 | 9 | TWELVE_HOUR = 12 * 60 * 60 * 1000 10 | 11 | 12 | def current(): 13 | return int(time.time() * 1000) 14 | 15 | 16 | class UKCP(KCP): 17 | 18 | def __init__(self, conv, manager: 'AbstractManager'): 19 | super(UKCP, self).__init__(conv) 20 | self.manager = manager 21 | 22 | def output(self, buffer: bytearray, size): 23 | self.manager.output(buffer[:size]) 24 | 25 | def __lt__(self, other: 'UKCP'): 26 | _current = current() 27 | return self.check(_current) < other.check(_current) 28 | 29 | def __eq__(self, other: 'UKCP'): 30 | _current = current() 31 | return self.check(_current) == other.check(_current) 32 | 33 | def __gt__(self, other: 'UKCP'): 34 | _current = current() 35 | return self.check(_current) > other.check(_current) 36 | 37 | 38 | class AbstractManager: 39 | transport: DatagramProtocol = None 40 | connections: Dict[int, UKCP] = None 41 | recv_wait: Dict[int, Future] = None 42 | remote_addr: Tuple[str, int] = None 43 | conv: int = None 44 | 45 | def output(self, buffer): 46 | self.transport.sendto(buffer, addr=self.remote_addr) 47 | 48 | def input(self, conv: int, data: Union[bytearray, bytes] = None): 49 | kcp = self.connections.get(conv) 50 | kcp.input(data) 51 | 52 | async def recv(self, kcp): 53 | data = await self.recv_wait[kcp.conv] 54 | self.recv_wait[kcp.conv] = Future() 55 | return 'recv', data 56 | 57 | def send(self, kcp, data): 58 | kcp.send(data) 59 | 60 | async def interval(self): 61 | initial_buffer = 1024 62 | buffer = bytearray() 63 | while True: 64 | await asyncio.sleep(0.1) 65 | for i in self.connections.values(): 66 | i.update(current()) 67 | data_length = i.recv(buffer) 68 | data = None 69 | if data_length < 0: 70 | if data_length == -3: 71 | bigger_buffer = None 72 | times = 2 73 | while data_length == -3: 74 | bigger_buffer = bytearray(initial_buffer * times) 75 | data_length = i.recv(bigger_buffer) 76 | data = bigger_buffer[:data_length] 77 | else: 78 | pass 79 | if data: 80 | if self.recv_wait[i.conv].done(): 81 | self.recv_wait[i.conv].result()[-1:] = data 82 | else: 83 | self.recv_wait[i.conv].set_result(data) 84 | 85 | def get_session(self, conv=None): 86 | if conv is not None: 87 | conv = conv 88 | else: 89 | conv = self.conv 90 | kcp = UKCP(conv, self) 91 | kcp.update(current()) 92 | self.connections[conv] = kcp 93 | return kcp 94 | 95 | 96 | def _with_timeout(name): 97 | def decorator(f): 98 | @functools.wraps(f) 99 | def wrapper(cls, *args, **kwargs): 100 | coro = f(cls, *args, **kwargs) 101 | timeout = getattr(cls, name) 102 | return asyncio.wait_for(coro, timeout, loop=cls.loop) 103 | 104 | return wrapper 105 | 106 | return decorator 107 | 108 | 109 | def with_timeout(name): 110 | """ 111 | Method decorator, wraps method with :py:func:`asyncio.wait_for`. `timeout` 112 | argument takes from `name` decorator argument or "timeout". 113 | 114 | :param name: name of timeout attribute 115 | :type name: :py:class:`str` 116 | 117 | :raises asyncio.TimeoutError: if coroutine does not finished in timeout 118 | 119 | Wait for `self.timeout` 120 | :: 121 | 122 | >>> def __init__(self, ...): 123 | ... 124 | ... self.timeout = 1 125 | ... 126 | ... @with_timeout 127 | ... async def foo(self, ...): 128 | ... 129 | ... pass 130 | 131 | Wait for custom timeout 132 | :: 133 | 134 | >>> def __init__(self, ...): 135 | ... 136 | ... self.foo_timeout = 1 137 | ... 138 | ... @with_timeout("foo_timeout") 139 | ... async def foo(self, ...): 140 | ... 141 | ... pass 142 | 143 | """ 144 | 145 | if isinstance(name, str): 146 | return _with_timeout(name) 147 | else: 148 | return _with_timeout("timeout")(name) 149 | -------------------------------------------------------------------------------- /kcp/KCP.pyx: -------------------------------------------------------------------------------- 1 | from cpython.bytes cimport PyBytes_FromStringAndSize 2 | from cpython.pycapsule cimport * 3 | from libc.stdint cimport uint32_t, int32_t 4 | from posix.time cimport clock_gettime, timespec, CLOCK_REALTIME 5 | 6 | cdef extern from 'stdio.h': 7 | int printf(char *format, ...); 8 | 9 | 10 | cdef extern from "../ikcp/ikcp.h": 11 | ctypedef uint32_t ISTDUINT32; #for linux 12 | ctypedef int32_t ISTDINT32; #for linux 13 | ctypedef ISTDINT32 IINT32; 14 | ctypedef ISTDUINT32 IUINT32; 15 | 16 | struct IQUEUEHEAD: 17 | IQUEUEHEAD *next, *prev 18 | 19 | struct IKCPCB: 20 | IUINT32 conv, mtu, mss, state; 21 | IUINT32 snd_una, snd_nxt, rcv_nxt; 22 | IUINT32 ts_recent, ts_lastack, ssthresh; 23 | IINT32 rx_rttval, rx_srtt, rx_rto, rx_minrto; 24 | IUINT32 snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe; 25 | IUINT32 current, interval, ts_flush, xmit; 26 | IUINT32 nrcv_buf, nsnd_buf; 27 | IUINT32 nrcv_que, nsnd_que; 28 | IUINT32 nodelay, updated; 29 | IUINT32 ts_probe, probe_wait; 30 | IUINT32 dead_link, incr; 31 | IQUEUEHEAD snd_queue; 32 | IQUEUEHEAD rcv_queue; 33 | IQUEUEHEAD snd_buf; 34 | IQUEUEHEAD rcv_buf; 35 | IUINT32 *acklist; 36 | IUINT32 ackcount; 37 | IUINT32 ackblock; 38 | void *user; 39 | char *buffer; 40 | int fastresend; 41 | int nocwnd; 42 | int logmask; 43 | int (*output)(const char *buf, int len, IKCPCB *kcp, void *user); 44 | void (*writelog)(const char *log, IKCPCB *kcp, void *user); 45 | 46 | ctypedef IKCPCB ikcpcb; 47 | ikcpcb *ikcp_create(IUINT32 conv, void *user); 48 | void ikcp_release(ikcpcb *kcp); 49 | int ikcp_recv(ikcpcb *kcp, char *buffer, int length); 50 | int ikcp_send(ikcpcb *kcp, const char *buffer, int length); 51 | void ikcp_update(ikcpcb *kcp, IUINT32 current); 52 | IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current); 53 | int ikcp_input(ikcpcb *kcp, const char *data, long size); 54 | void ikcp_flush(ikcpcb *kcp); 55 | int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd); 56 | int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc); 57 | int ikcp_peeksize(const ikcpcb *kcp); 58 | int ikcp_setmtu(ikcpcb *kcp, int mtu) 59 | void ikcp_setoutput(ikcpcb *kcp, int (*output)(const char *buf, int len, ikcpcb *kcp, void *user)); 60 | IUINT32 ikcp_getconv(const void *ptr); 61 | 62 | 63 | 64 | cdef int output_wrapper(const char *buf, int length, ikcpcb *ikcp, void *user): 65 | cdef object kcp = user 66 | cdef bytes o = PyBytes_FromStringAndSize(buf, length) 67 | kcp.output(o) 68 | return 1 69 | 70 | cpdef uint32_t get_conv(const char *ptr): 71 | return ikcp_getconv(ptr) 72 | 73 | cpdef int kcp_now(): 74 | cdef timespec ts 75 | cdef long current 76 | clock_gettime(CLOCK_REALTIME, &ts) 77 | current = ts.tv_sec * 1000 + (ts.tv_nsec / 1000000) 78 | return current & 0xffffffff 79 | 80 | 81 | 82 | cdef class KCP: 83 | cdef ikcpcb *ckcp 84 | cdef public object output 85 | 86 | @property 87 | def conv(self): 88 | return self.ckcp.conv 89 | 90 | @property 91 | def state(self): 92 | return self.ckcp.state 93 | 94 | @state.setter 95 | def state(self, int s): 96 | self.ckcp.state = s 97 | 98 | def __cinit__(self, conv): 99 | self.ckcp = ikcp_create(conv, self) 100 | 101 | def __dealloc__(self): 102 | ikcp_release(self.ckcp) 103 | 104 | cpdef int recv(self, char *buffer, int length): 105 | return ikcp_recv(self.ckcp, buffer, length) 106 | 107 | cpdef int send(self, char *buffer, int length): 108 | return ikcp_send(self.ckcp, buffer, length) 109 | 110 | cpdef void update(self, IUINT32 current): 111 | ikcp_update(self.ckcp, current) 112 | 113 | cpdef IUINT32 check(self, IUINT32 current): 114 | return ikcp_check(self.ckcp, current) 115 | 116 | cpdef int input(self, char *buffer, int length): 117 | return ikcp_input(self.ckcp, buffer, length) 118 | 119 | cpdef int wndsize(self, int sndwnd, int rcvwnd): 120 | return ikcp_wndsize(self.ckcp, sndwnd, rcvwnd) 121 | 122 | cpdef int nodelay(self, int nodelay, int interval, int resend, int nc): 123 | return ikcp_nodelay(self.ckcp, nodelay, interval, resend, nc) 124 | 125 | cpdef int peeksize(self): 126 | return ikcp_peeksize(self.ckcp) 127 | 128 | cpdef int set_mtu(self, int mtu): 129 | return ikcp_setmtu(self.ckcp, mtu) 130 | 131 | cpdef void flush(self): 132 | ikcp_flush(self.ckcp) 133 | 134 | def set_output(self, output): 135 | self.output = output 136 | ikcp_setoutput(self.ckcp, output_wrapper) 137 | -------------------------------------------------------------------------------- /oldversion/kcp/UKCPFactory.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import functools 3 | from asyncio import StreamReader, StreamWriter 4 | from collections import namedtuple 5 | 6 | from .KCP import KCP 7 | 8 | _DEFAULT_LIMIT = 2 ** 16 # 64 KiB 9 | 10 | 11 | class UKcp(KCP): 12 | 13 | def __init__(self, conv, udp): 14 | super(UKcp, self).__init__(conv) 15 | self.udp = udp 16 | 17 | def output(self, buffer: bytearray, size): 18 | self.udp.output(buffer, size) 19 | 20 | 21 | UKcpStruct = namedtuple('UkcpStruct', ('conn', 'reader', 'writer')) 22 | 23 | 24 | class TransportWrapper: 25 | 26 | def __init__(self, conv, factory): 27 | self._conv = conv 28 | self._factory = factory 29 | 30 | def __getattr__(self, item): 31 | return getattr(self._factory.transport, item) 32 | 33 | def write(self, data): 34 | self._factory.send(self._conv, data) 35 | 36 | 37 | Conn = namedtuple('Conn', ('kcpConn', 'reader', 'writer')) 38 | 39 | 40 | class UKCPFactory: 41 | conns = {} 42 | activeConns = set() 43 | conv = 1 44 | updateSchedule = {} 45 | 46 | def __init__(self, loop: asyncio.AbstractEventLoop): 47 | self._loop = loop 48 | 49 | def interval(self): 50 | for conv in self.activeConns: 51 | self.update(conv) 52 | self.activeConns = set() 53 | self._loop.call_later(0.05, self.interval) 54 | 55 | def update(self, conv): 56 | kcpConn, reader, _ = self.conns[conv] 57 | current = int(self._loop.time() * 1000) 58 | kcpConn.update(current) 59 | if kcpConn.state == -1: 60 | reader.feed_eof() 61 | peeksize = kcpConn.peeksize() 62 | if peeksize not in (0, -1): 63 | data = kcpConn.recv(peeksize) 64 | reader.feed_data(data) 65 | next_call = kcpConn.check(current) 66 | schedule = self._loop.call_later(next_call / 1000, functools.partial(self.update, conv)) 67 | self.updateSchedule[conv] = schedule 68 | 69 | 70 | class UKCPConnector(asyncio.DatagramProtocol, UKCPFactory): 71 | 72 | def __init__(self, loop: asyncio.AbstractEventLoop, remote_addr=None): 73 | UKCPFactory.__init__(self, loop) 74 | self.connecting = asyncio.Event() 75 | self._remote_addr = remote_addr 76 | self._loop.create_datagram_endpoint(self, remote_addr=remote_addr) 77 | 78 | def connection_made(self, transport) -> None: 79 | self.connecting.set() 80 | self._transport = transport 81 | 82 | def datagram_received(self, data, addr): 83 | conv = UKcp.ikcp_decode32u(data, 0) 84 | if conv in self.conns: 85 | self.activeConns.add(conv) 86 | self.conns[conv].kcpConn.input(data) 87 | 88 | def output(self, buffer, size): 89 | self._transport.sendto(buffer[:size], self._remote_addr) 90 | 91 | def send(self, conv, data): 92 | self.activeConns.add(conv) 93 | self.conns[conv].send(data) 94 | 95 | async def connect(self): 96 | await self.connecting.wait() 97 | kcpConn = UKcp(self.conv, self) 98 | reader = StreamReader(limit=_DEFAULT_LIMIT, loop=self._loop) 99 | writer = StreamWriter(TransportWrapper(self.conv, self), self, reader, self._loop) 100 | conn = Conn(kcpConn=kcpConn, reader=reader, writer=writer) 101 | self.conns[self.conv] = conn 102 | self.activeConns.add(self.conv) 103 | self.conv += 1 104 | return reader, writer 105 | 106 | def __call__(self, *args, **kwargs): 107 | return self 108 | 109 | 110 | class UKCPListener(asyncio.DatagramProtocol, UKCPFactory): 111 | cb = None 112 | default_receiver = None 113 | 114 | def __init__(self, loop: asyncio.AbstractEventLoop, local_addr=None): 115 | UKCPFactory.__init__(self, loop) 116 | self.connecting = asyncio.Event() 117 | self._local_addr = local_addr 118 | self._loop.create_datagram_endpoint() 119 | 120 | def connection_made(self, transport) -> None: 121 | self.connecting.set() 122 | self._transport = transport 123 | 124 | def datagram_received(self, data, addr): 125 | self.default_receiver = addr 126 | conv = UKcp.ikcp_decode32u(data, 0) 127 | if conv in self.conns: 128 | self.activeConns.add(conv) 129 | self.conns[conv].kcpConn.input(data) 130 | else: 131 | kcpConn = UKcp(conv, self) 132 | reader = StreamReader(limit=_DEFAULT_LIMIT, loop=self._loop) 133 | writer = StreamWriter(TransportWrapper(conv, self), self, reader, self._loop) 134 | conn = Conn(kcpConn=kcpConn, reader=reader, writer=writer) 135 | self.conns[conv] = conn 136 | self.activeConns.add(conv) 137 | self._loop.create_task(self.cb(reader, writer)) 138 | 139 | def output(self, buffer, size): 140 | self._transport.sendto(buffer[:size], self.default_receiver) 141 | 142 | def send(self, conv, data): 143 | self.activeConns.add(conv) 144 | self.conns[conv].send(data) 145 | 146 | async def listen(self, cb): 147 | await self.connecting 148 | self.cb = cb 149 | -------------------------------------------------------------------------------- /kcp/protocols.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | from asyncio import streams, transports, protocols 4 | from collections import defaultdict 5 | from dataclasses import dataclass 6 | 7 | from kcp.KCP import KCP, get_conv 8 | from kcp.updater import updater 9 | from kcp.utils import KCPConfig 10 | 11 | 12 | def new_kcp(conv, output): 13 | config = KCPConfig() 14 | kcp = KCP(conv) 15 | kcp.set_output(output) 16 | kcp.set_mtu(config.mtu) 17 | kcp.nodelay(config.nodelay, config.interval, config.resend, config.nc) 18 | kcp.wndsize(config.sndwnd, config.rcvwnd) 19 | return kcp 20 | 21 | 22 | class TunnelTransportWrapper(transports.Transport): 23 | 24 | def __init__(self, transport, conn, kcp): 25 | self._transport = transport 26 | self._conn = conn 27 | self._kcp = kcp 28 | self._is_closing = False 29 | 30 | def __getattr__(self, item): 31 | return getattr(self._transport, item) 32 | 33 | def write(self, data): 34 | kcp = self._kcp 35 | self._conn.active_sessions.add(kcp.conv) 36 | kcp.send(data, len(data)) 37 | 38 | def writelines(self, list_of_data): 39 | data = b''.join(list_of_data) 40 | self.write(data) 41 | 42 | def write_eof(self): 43 | pass 44 | 45 | def can_write_eof(self): 46 | return False 47 | 48 | def is_reading(self): 49 | return True 50 | 51 | def pause_reading(self): 52 | pass 53 | 54 | def resume_reading(self): 55 | pass 56 | 57 | def close(self): 58 | self._is_closing = True 59 | self._kcp.state = -1 60 | 61 | def is_closing(self): 62 | return self._is_closing 63 | 64 | 65 | @dataclass 66 | class Session: 67 | protocol: streams.StreamReaderProtocol 68 | transport: transports.Transport 69 | conv: int 70 | kcp: 'KCP' 71 | next_update: int 72 | 73 | 74 | class DataGramConnHandlerProtocol(protocols.DatagramProtocol): 75 | 76 | def __init__(self, is_local, client_connected_cb=None): 77 | self.is_local = is_local 78 | self.client_connected_cb = client_connected_cb 79 | self.conv = 1 80 | self.sessions = dict() 81 | self.active_sessions = set() 82 | self.accept_dict = defaultdict(bytearray) 83 | self.transport = None 84 | 85 | def connection_made(self, transport): 86 | self.transport = transport 87 | updater.register(self) 88 | 89 | async def accept_connection(self, conv): 90 | reader, writer = await self.create_connection(conv) 91 | s = self.sessions[conv] 92 | accept_dict = self.accept_dict 93 | buffer = accept_dict[conv] 94 | s.kcp.input(buffer, len(buffer)) 95 | res = self.client_connected_cb(reader, writer) 96 | loop = asyncio.get_event_loop() 97 | if asyncio.iscoroutine(res): 98 | loop.create_task(res) 99 | del accept_dict[conv] 100 | self.active_sessions.add(conv) 101 | 102 | async def create_connection(self, conv=None): 103 | loop = asyncio.get_event_loop() 104 | if self.is_local: 105 | conv = self.conv 106 | self.conv += 1 107 | else: 108 | assert conv 109 | conv = conv 110 | kcp = new_kcp(conv, self.transport.sendto) 111 | reader = asyncio.StreamReader(loop=loop) 112 | protocol = streams.StreamReaderProtocol(reader, loop=loop) 113 | transport = TunnelTransportWrapper(self.transport, self, kcp) 114 | writer = streams.StreamWriter(transport, protocol, reader, loop) 115 | session = Session(protocol=protocol, transport=transport, kcp=kcp, conv=conv, next_update=0) 116 | self.active_sessions.add(conv) 117 | self.sessions[conv] = session 118 | return reader, writer 119 | 120 | def datagram_received(self, data: bytes, addr): 121 | conv = get_conv(data) 122 | sessions = self.sessions 123 | if conv in sessions: 124 | session = sessions[conv] 125 | kcp = session.kcp 126 | kcp.input(data, len(data)) 127 | peeksize = kcp.peeksize() 128 | if peeksize != 0 and peeksize != -1: 129 | data = bytes(peeksize) 130 | kcp.recv(data, peeksize) 131 | kcp.flush() 132 | session.protocol.data_received(data) 133 | self.active_sessions.add(conv) 134 | else: 135 | if not self.is_local: 136 | if conv not in self.accept_dict: 137 | loop = asyncio.get_event_loop() 138 | loop.create_task(self.accept_connection(conv)) 139 | self.accept_dict[conv].extend(data) 140 | else: 141 | data_len = len(data) 142 | buffer = len(self.accept_dict[conv]) 143 | if buffer + data_len > 65536: 144 | del self.accept_dict[conv] 145 | else: 146 | self.accept_dict[conv].extend(data) 147 | 148 | def connection_lost(self, exc): 149 | logging.info("connection lost for: %s", exc) 150 | updater.unregister(self) 151 | sessions = self.sessions 152 | for session in sessions.values(): 153 | session.protocol.eof_received() 154 | session.protocol.connection_lost(exc) 155 | sessions.clear() 156 | self.accept_dict.clear() 157 | del sessions 158 | 159 | def close_session(self, session): 160 | conv = session.conv 161 | del self.sessions[conv] 162 | if conv in self.active_sessions: 163 | self.active_sessions.remove(conv) 164 | 165 | def error_received(self, exc): 166 | logging.warning("conn received error %s", exc) 167 | 168 | 169 | class ServerDataGramHandlerProtocol(protocols.DatagramProtocol): 170 | conns = defaultdict(bytearray) 171 | 172 | def __init__(self, client_connected_cb): 173 | self.client_connected_cb = client_connected_cb 174 | self.transport = None 175 | 176 | def connection_made(self, transport: transports.DatagramTransport): 177 | self.transport = transport 178 | 179 | def datagram_received(self, data: bytes, addr): 180 | loop = asyncio.get_event_loop() 181 | conns = self.conns 182 | 183 | def connection_accepted_cb(result: asyncio.Future): 184 | if not result.exception(): 185 | transport, protocol = result.result() 186 | buffer = conns[addr] 187 | protocol.datagram_received(buffer, addr) 188 | 189 | if addr not in conns: 190 | task = loop.create_task(loop.create_datagram_endpoint( 191 | lambda: DataGramConnHandlerProtocol(is_local=False, client_connected_cb=self.client_connected_cb), 192 | local_addr=self.transport.get_extra_info('sockname'), 193 | remote_addr=addr, 194 | reuse_address=True, 195 | reuse_port=True 196 | )) 197 | task.add_done_callback(connection_accepted_cb) 198 | self.conns[addr].extend(data) 199 | 200 | def connection_lost(self, exc): 201 | logging.info("server connection lost: %s", exc) 202 | 203 | def error_received(self, exc): 204 | logging.warning("server error: %s", exc) 205 | -------------------------------------------------------------------------------- /oldversion/KCPClient.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import functools 3 | import logging 4 | import traceback 5 | from collections import namedtuple, defaultdict 6 | from typing import Dict, Tuple, Optional 7 | import uvloop 8 | 9 | from oldversion.KCP import KCP 10 | 11 | logger = logging.getLogger("KCP") 12 | 13 | TWELVE_HOUR = 12 * 60 * 60 * 1000 14 | 15 | 16 | class UKCPSession(KCP): 17 | def __init__(self, conv, controller): 18 | super(UKCPSession, self).__init__(conv) 19 | self.controller = controller 20 | 21 | def output(self, buffer, size): 22 | self.controller.output(self.conv, buffer[:size]) 23 | 24 | 25 | class Connection(asyncio.Protocol): 26 | 27 | def __init__(self, conv: int, controller: 'KCPClientController'): 28 | self.conv = conv 29 | self.controller = controller 30 | self.transport = None 31 | self.ready = asyncio.Future() 32 | 33 | def connection_made(self, transport: asyncio.Transport) -> None: 34 | logger.info(f"""stream established sockname: {transport.get_extra_info( 35 | 'sockname')} <-> peername: {transport.get_extra_info('peername')}""") 36 | self.transport = transport 37 | self.ready.set_result(-1) 38 | 39 | def connection_lost(self, exc: Optional[Exception]) -> None: 40 | self.controller.close_conversation(self.conv) 41 | 42 | def data_received(self, data: bytearray) -> None: 43 | self.controller.send(self.conv, data) 44 | 45 | def pause_writing(self) -> None: 46 | self.ready = asyncio.Future() 47 | self.ready.add_done_callback(self.controller.flush_recv) 48 | 49 | def resume_writing(self) -> None: 50 | self.ready.set_result(self.conv) 51 | 52 | 53 | Conversation = namedtuple('Conversation', ('connection', 'session')) 54 | 55 | 56 | class KCPClientController(asyncio.DatagramProtocol): 57 | protocol = Connection 58 | 59 | def __init__(self, loop: asyncio.AbstractEventLoop, remote_addr, local_addr): 60 | self.loop = loop 61 | self.remote_addr = remote_addr 62 | self.local_addr = local_addr 63 | self.convs: Dict[int, Conversation] = {} 64 | self.active_conns = set() 65 | self._conv_generator = (i for i in range(TWELVE_HOUR)) 66 | self.output_buffers = defaultdict(list) 67 | self.recv_buffers = defaultdict(list) 68 | self.input_buffer = defaultdict(list) 69 | self.transport = None 70 | self.update_schedule: Dict[int: asyncio.Task] = {} 71 | self.client_addr = None 72 | 73 | def connection_made(self, transport: asyncio.DatagramTransport): 74 | self.transport = transport 75 | 76 | def datagram_received(self, data: bytearray, addr: Tuple[str, int]): 77 | conv = KCP.ikcp_decode32u(data, 0) 78 | conversation = self.convs.get(conv) 79 | if conversation: 80 | self.input(conv, data) 81 | 82 | def connection_lost(self, exc: Exception): 83 | logger.error('connection lost, trying to reconnect') 84 | traceback.print_exception(type(exc), exc, exc.__traceback__) 85 | self.transport = None 86 | task = self.loop.create_task( 87 | self.loop.create_datagram_endpoint(self.datagram_endpoint, remote_addr=('127.0.0.1', 8888))) 88 | task.add_done_callback(self.flush_output) 89 | 90 | def create_session(self, conv): 91 | session = UKCPSession(conv, self) 92 | session.set_nodelay(1, 10, 2, 1) 93 | return session 94 | 95 | def generate_conv(self): 96 | try: 97 | conv = next(self._conv_generator) 98 | except StopIteration: 99 | self._conv_generator = (i for i in range(TWELVE_HOUR)) 100 | conv = next(self._conv_generator) 101 | return conv 102 | 103 | '''data proxy and data buffer''' 104 | 105 | def output(self, conv, buffer: bytearray): 106 | if self.transport is None: 107 | self.output_buffers[conv].append(buffer) 108 | else: 109 | self.transport.sendto(buffer, getattr(self, 'client_addr')) 110 | 111 | def flush_output(self, fut): 112 | for conv in self.output_buffers: 113 | self._flush_output(conv) 114 | 115 | def _flush_output(self, conv): 116 | buffers = self.output_buffers.get(conv) 117 | while buffers: 118 | self.output(conv, buffers.pop(0)) 119 | del self.output_buffers[conv] 120 | 121 | def input(self, conv, data): 122 | self.active_conns.add(conv) 123 | if conv in self.update_schedule and not self.update_schedule[conv].cancelled(): 124 | self.update_schedule[conv].cancel() 125 | del self.update_schedule[conv] 126 | self.convs[conv].session.input(data) 127 | 128 | def send(self, conv, data: bytearray): 129 | self.active_conns.add(conv) 130 | if conv in self.update_schedule and not self.update_schedule[conv].cancelled(): 131 | self.update_schedule[conv].cancel() 132 | del self.update_schedule[conv] 133 | self.convs[conv].session.send(data) 134 | 135 | def recv(self, conv, data: bytearray): 136 | connection = self.convs[conv].connection 137 | if connection.ready.done(): 138 | connection.transport.write(data) 139 | else: 140 | self.recv_buffers[conv].append(data) 141 | 142 | def flush_recv(self, fut): 143 | conv = fut.result() 144 | if conv != -1: 145 | self._flush_recv(conv) 146 | else: 147 | for conv in self.recv_buffers: 148 | self._flush_recv(conv) 149 | 150 | def _flush_recv(self, conv): 151 | connection = self.convs[conv].connection 152 | buffers = self.recv_buffers.get(conv) 153 | while buffers: 154 | connection.transport.write(buffers.pop(0)) 155 | del self.recv_buffers[conv] 156 | 157 | '''interval management''' 158 | 159 | def interval(self): 160 | while self.active_conns: 161 | conv = self.active_conns.pop() 162 | self.update(conv) 163 | self.loop.call_later(0.01, self.interval) 164 | 165 | def update(self, conv): 166 | current = int(self.loop.time() * 1000) 167 | conversion = self.convs[conv] 168 | session = conversion.session 169 | session.update(current) 170 | if session.state == -1: 171 | self.close_conversation(conv) 172 | peeksize = session.peeksize() 173 | if peeksize not in (0, -1): 174 | data = session.recv(peeksize) 175 | self.recv(conv, data) 176 | next_call = session.check(current) 177 | schedule = self.loop.call_at(next_call / 1000, functools.partial(self.update, conv)) 178 | self.update_schedule[conv] = schedule 179 | 180 | ''' switch protocol''' 181 | 182 | def datagram_endpoint(self): 183 | return self 184 | 185 | def stream_protocol(self, conv=-1): 186 | if conv == -1: 187 | conv = self.generate_conv() 188 | session = self.create_session(conv) 189 | conn = self.protocol(conv, self) 190 | self.convs[conv] = Conversation(connection=conn, session=session) 191 | self.active_conns.add(conv) 192 | return conn 193 | 194 | def close_conversation(self, conv): 195 | if conv in self.output_buffers: 196 | del self.output_buffers[conv] 197 | if conv in self.recv_buffers: 198 | del self.recv_buffers[conv] 199 | if conv in self.update_schedule: 200 | task = self.update_schedule[conv] 201 | if not task.cancelled(): 202 | self.update_schedule[conv].cancel() 203 | del self.update_schedule[conv] 204 | if conv in self.active_conns: 205 | self.active_conns.remove(conv) 206 | self.convs[conv].connection.transport.close() 207 | del self.convs[conv] 208 | 209 | async def start(self): 210 | await self.loop.create_datagram_endpoint(self.datagram_endpoint, remote_addr=self.remote_addr) 211 | await self.loop.create_server(self.stream_protocol, host=self.local_addr[0], port=self.local_addr[1]) 212 | self.loop.call_soon(self.interval) 213 | 214 | 215 | if __name__ == '__main__': 216 | asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) 217 | loop = asyncio.get_event_loop() 218 | client = KCPClientController(loop, local_addr=('127.0.0.1', 7777), remote_addr=('yukityan.cc', 29900)) 219 | loop.create_task(client.start()) 220 | try: 221 | loop.run_forever() 222 | except KeyboardInterrupt: 223 | loop.close() 224 | -------------------------------------------------------------------------------- /ikcp/ikcp.h: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // KCP - A Better ARQ Protocol Implementation 4 | // skywind3000 (at) gmail.com, 2010-2011 5 | // 6 | // Features: 7 | // + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. 8 | // + Maximum RTT reduce three times vs tcp. 9 | // + Lightweight, distributed as a single source file. 10 | // 11 | //===================================================================== 12 | #ifndef __IKCP_H__ 13 | #define __IKCP_H__ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | //===================================================================== 21 | // 32BIT INTEGER DEFINITION 22 | //===================================================================== 23 | #ifndef __INTEGER_32_BITS__ 24 | #define __INTEGER_32_BITS__ 25 | #if defined(_WIN64) || defined(WIN64) || defined(__amd64__) || \ 26 | defined(__x86_64) || defined(__x86_64__) || defined(_M_IA64) || \ 27 | defined(_M_AMD64) 28 | typedef unsigned int ISTDUINT32; 29 | typedef int ISTDINT32; 30 | #elif defined(_WIN32) || defined(WIN32) || defined(__i386__) || \ 31 | defined(__i386) || defined(_M_X86) 32 | typedef unsigned long ISTDUINT32; 33 | typedef long ISTDINT32; 34 | #elif defined(__MACOS__) 35 | typedef UInt32 ISTDUINT32; 36 | typedef SInt32 ISTDINT32; 37 | #elif defined(__APPLE__) && defined(__MACH__) 38 | #include 39 | typedef u_int32_t ISTDUINT32; 40 | typedef int32_t ISTDINT32; 41 | #elif defined(__BEOS__) 42 | #include 43 | typedef u_int32_t ISTDUINT32; 44 | typedef int32_t ISTDINT32; 45 | #elif (defined(_MSC_VER) || defined(__BORLANDC__)) && (!defined(__MSDOS__)) 46 | typedef unsigned __int32 ISTDUINT32; 47 | typedef __int32 ISTDINT32; 48 | #elif defined(__GNUC__) 49 | #include 50 | typedef uint32_t ISTDUINT32; 51 | typedef int32_t ISTDINT32; 52 | #else 53 | typedef unsigned long ISTDUINT32; 54 | typedef long ISTDINT32; 55 | #endif 56 | #endif 57 | 58 | 59 | //===================================================================== 60 | // Integer Definition 61 | //===================================================================== 62 | #ifndef __IINT8_DEFINED 63 | #define __IINT8_DEFINED 64 | typedef char IINT8; 65 | #endif 66 | 67 | #ifndef __IUINT8_DEFINED 68 | #define __IUINT8_DEFINED 69 | typedef unsigned char IUINT8; 70 | #endif 71 | 72 | #ifndef __IUINT16_DEFINED 73 | #define __IUINT16_DEFINED 74 | typedef unsigned short IUINT16; 75 | #endif 76 | 77 | #ifndef __IINT16_DEFINED 78 | #define __IINT16_DEFINED 79 | typedef short IINT16; 80 | #endif 81 | 82 | #ifndef __IINT32_DEFINED 83 | #define __IINT32_DEFINED 84 | typedef ISTDINT32 IINT32; 85 | #endif 86 | 87 | #ifndef __IUINT32_DEFINED 88 | #define __IUINT32_DEFINED 89 | typedef ISTDUINT32 IUINT32; 90 | #endif 91 | 92 | #ifndef __IINT64_DEFINED 93 | #define __IINT64_DEFINED 94 | #if defined(_MSC_VER) || defined(__BORLANDC__) 95 | typedef __int64 IINT64; 96 | #else 97 | typedef long long IINT64; 98 | #endif 99 | #endif 100 | 101 | #ifndef __IUINT64_DEFINED 102 | #define __IUINT64_DEFINED 103 | #if defined(_MSC_VER) || defined(__BORLANDC__) 104 | typedef unsigned __int64 IUINT64; 105 | #else 106 | typedef unsigned long long IUINT64; 107 | #endif 108 | #endif 109 | 110 | #ifndef INLINE 111 | #if defined(__GNUC__) 112 | 113 | #if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) 114 | #define INLINE __inline__ __attribute__((always_inline)) 115 | #else 116 | #define INLINE __inline__ 117 | #endif 118 | 119 | #elif (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)) 120 | #define INLINE __inline 121 | #else 122 | #define INLINE 123 | #endif 124 | #endif 125 | 126 | #if (!defined(__cplusplus)) && (!defined(inline)) 127 | #define inline INLINE 128 | #endif 129 | 130 | 131 | //===================================================================== 132 | // QUEUE DEFINITION 133 | //===================================================================== 134 | #ifndef __IQUEUE_DEF__ 135 | #define __IQUEUE_DEF__ 136 | 137 | struct IQUEUEHEAD { 138 | struct IQUEUEHEAD *next, *prev; 139 | }; 140 | 141 | typedef struct IQUEUEHEAD iqueue_head; 142 | 143 | 144 | //--------------------------------------------------------------------- 145 | // queue init 146 | //--------------------------------------------------------------------- 147 | #define IQUEUE_HEAD_INIT(name) { &(name), &(name) } 148 | #define IQUEUE_HEAD(name) \ 149 | struct IQUEUEHEAD name = IQUEUE_HEAD_INIT(name) 150 | 151 | #define IQUEUE_INIT(ptr) ( \ 152 | (ptr)->next = (ptr), (ptr)->prev = (ptr)) 153 | 154 | #define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 155 | 156 | #define ICONTAINEROF(ptr, type, member) ( \ 157 | (type*)( ((char*)((type*)ptr)) - IOFFSETOF(type, member)) ) 158 | 159 | #define IQUEUE_ENTRY(ptr, type, member) ICONTAINEROF(ptr, type, member) 160 | 161 | 162 | //--------------------------------------------------------------------- 163 | // queue operation 164 | //--------------------------------------------------------------------- 165 | #define IQUEUE_ADD(node, head) ( \ 166 | (node)->prev = (head), (node)->next = (head)->next, \ 167 | (head)->next->prev = (node), (head)->next = (node)) 168 | 169 | #define IQUEUE_ADD_TAIL(node, head) ( \ 170 | (node)->prev = (head)->prev, (node)->next = (head), \ 171 | (head)->prev->next = (node), (head)->prev = (node)) 172 | 173 | #define IQUEUE_DEL_BETWEEN(p, n) ((n)->prev = (p), (p)->next = (n)) 174 | 175 | #define IQUEUE_DEL(entry) (\ 176 | (entry)->next->prev = (entry)->prev, \ 177 | (entry)->prev->next = (entry)->next, \ 178 | (entry)->next = 0, (entry)->prev = 0) 179 | 180 | #define IQUEUE_DEL_INIT(entry) do { \ 181 | IQUEUE_DEL(entry); IQUEUE_INIT(entry); } while (0) 182 | 183 | #define IQUEUE_IS_EMPTY(entry) ((entry) == (entry)->next) 184 | 185 | #define iqueue_init IQUEUE_INIT 186 | #define iqueue_entry IQUEUE_ENTRY 187 | #define iqueue_add IQUEUE_ADD 188 | #define iqueue_add_tail IQUEUE_ADD_TAIL 189 | #define iqueue_del IQUEUE_DEL 190 | #define iqueue_del_init IQUEUE_DEL_INIT 191 | #define iqueue_is_empty IQUEUE_IS_EMPTY 192 | 193 | #define IQUEUE_FOREACH(iterator, head, TYPE, MEMBER) \ 194 | for ((iterator) = iqueue_entry((head)->next, TYPE, MEMBER); \ 195 | &((iterator)->MEMBER) != (head); \ 196 | (iterator) = iqueue_entry((iterator)->MEMBER.next, TYPE, MEMBER)) 197 | 198 | #define iqueue_foreach(iterator, head, TYPE, MEMBER) \ 199 | IQUEUE_FOREACH(iterator, head, TYPE, MEMBER) 200 | 201 | #define iqueue_foreach_entry(pos, head) \ 202 | for( (pos) = (head)->next; (pos) != (head) ; (pos) = (pos)->next ) 203 | 204 | 205 | #define __iqueue_splice(list, head) do { \ 206 | iqueue_head *first = (list)->next, *last = (list)->prev; \ 207 | iqueue_head *at = (head)->next; \ 208 | (first)->prev = (head), (head)->next = (first); \ 209 | (last)->next = (at), (at)->prev = (last); } while (0) 210 | 211 | #define iqueue_splice(list, head) do { \ 212 | if (!iqueue_is_empty(list)) __iqueue_splice(list, head); } while (0) 213 | 214 | #define iqueue_splice_init(list, head) do { \ 215 | iqueue_splice(list, head); iqueue_init(list); } while (0) 216 | 217 | 218 | #ifdef _MSC_VER 219 | #pragma warning(disable:4311) 220 | #pragma warning(disable:4312) 221 | #pragma warning(disable:4996) 222 | #endif 223 | 224 | #endif 225 | 226 | 227 | //--------------------------------------------------------------------- 228 | // WORD ORDER 229 | //--------------------------------------------------------------------- 230 | #ifndef IWORDS_BIG_ENDIAN 231 | #ifdef _BIG_ENDIAN_ 232 | #if _BIG_ENDIAN_ 233 | #define IWORDS_BIG_ENDIAN 1 234 | #endif 235 | #endif 236 | #ifndef IWORDS_BIG_ENDIAN 237 | #if defined(__hppa__) || \ 238 | defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ 239 | (defined(__MIPS__) && defined(__MIPSEB__)) || \ 240 | defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ 241 | defined(__sparc__) || defined(__powerpc__) || \ 242 | defined(__mc68000__) || defined(__s390x__) || defined(__s390__) 243 | #define IWORDS_BIG_ENDIAN 1 244 | #endif 245 | #endif 246 | #ifndef IWORDS_BIG_ENDIAN 247 | #define IWORDS_BIG_ENDIAN 0 248 | #endif 249 | #endif 250 | 251 | 252 | 253 | //===================================================================== 254 | // SEGMENT 255 | //===================================================================== 256 | struct IKCPSEG 257 | { 258 | struct IQUEUEHEAD node; 259 | IUINT32 conv; 260 | IUINT32 cmd; 261 | IUINT32 frg; 262 | IUINT32 wnd; 263 | IUINT32 ts; 264 | IUINT32 sn; 265 | IUINT32 una; 266 | IUINT32 len; 267 | IUINT32 resendts; 268 | IUINT32 rto; 269 | IUINT32 fastack; 270 | IUINT32 xmit; 271 | char data[1]; 272 | }; 273 | 274 | 275 | //--------------------------------------------------------------------- 276 | // IKCPCB 277 | //--------------------------------------------------------------------- 278 | struct IKCPCB 279 | { 280 | IUINT32 conv, mtu, mss, state; 281 | IUINT32 snd_una, snd_nxt, rcv_nxt; 282 | IUINT32 ts_recent, ts_lastack, ssthresh; 283 | IINT32 rx_rttval, rx_srtt, rx_rto, rx_minrto; 284 | IUINT32 snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe; 285 | IUINT32 current, interval, ts_flush, xmit; 286 | IUINT32 nrcv_buf, nsnd_buf; 287 | IUINT32 nrcv_que, nsnd_que; 288 | IUINT32 nodelay, updated; 289 | IUINT32 ts_probe, probe_wait; 290 | IUINT32 dead_link, incr; 291 | struct IQUEUEHEAD snd_queue; 292 | struct IQUEUEHEAD rcv_queue; 293 | struct IQUEUEHEAD snd_buf; 294 | struct IQUEUEHEAD rcv_buf; 295 | IUINT32 *acklist; 296 | IUINT32 ackcount; 297 | IUINT32 ackblock; 298 | void *user; 299 | char *buffer; 300 | int fastresend; 301 | int nocwnd, stream; 302 | int logmask; 303 | int (*output)(const char *buf, int len, struct IKCPCB *kcp, void *user); 304 | void (*writelog)(const char *log, struct IKCPCB *kcp, void *user); 305 | }; 306 | 307 | 308 | typedef struct IKCPCB ikcpcb; 309 | 310 | #define IKCP_LOG_OUTPUT 1 311 | #define IKCP_LOG_INPUT 2 312 | #define IKCP_LOG_SEND 4 313 | #define IKCP_LOG_RECV 8 314 | #define IKCP_LOG_IN_DATA 16 315 | #define IKCP_LOG_IN_ACK 32 316 | #define IKCP_LOG_IN_PROBE 64 317 | #define IKCP_LOG_IN_WINS 128 318 | #define IKCP_LOG_OUT_DATA 256 319 | #define IKCP_LOG_OUT_ACK 512 320 | #define IKCP_LOG_OUT_PROBE 1024 321 | #define IKCP_LOG_OUT_WINS 2048 322 | 323 | #ifdef __cplusplus 324 | extern "C" { 325 | #endif 326 | 327 | //--------------------------------------------------------------------- 328 | // interface 329 | //--------------------------------------------------------------------- 330 | 331 | // create a new kcp control object, 'conv' must equal in two endpoint 332 | // from the same connection. 'user' will be passed to the output callback 333 | // output callback can be setup like this: 'kcp->output = my_udp_output' 334 | ikcpcb* ikcp_create(IUINT32 conv, void *user); 335 | 336 | // release kcp control object 337 | void ikcp_release(ikcpcb *kcp); 338 | 339 | // set output callback, which will be invoked by kcp 340 | void ikcp_setoutput(ikcpcb *kcp, int (*output)(const char *buf, int len, 341 | ikcpcb *kcp, void *user)); 342 | 343 | // user/upper level recv: returns size, returns below zero for EAGAIN 344 | int ikcp_recv(ikcpcb *kcp, char *buffer, int len); 345 | 346 | // user/upper level send, returns below zero for error 347 | int ikcp_send(ikcpcb *kcp, const char *buffer, int len); 348 | 349 | // update state (call it repeatedly, every 10ms-100ms), or you can ask 350 | // ikcp_check when to call it again (without ikcp_input/_send calling). 351 | // 'current' - current timestamp in millisec. 352 | void ikcp_update(ikcpcb *kcp, IUINT32 current); 353 | 354 | // Determine when should you invoke ikcp_update: 355 | // returns when you should invoke ikcp_update in millisec, if there 356 | // is no ikcp_input/_send calling. you can call ikcp_update in that 357 | // time, instead of call update repeatly. 358 | // Important to reduce unnacessary ikcp_update invoking. use it to 359 | // schedule ikcp_update (eg. implementing an epoll-like mechanism, 360 | // or optimize ikcp_update when handling massive kcp connections) 361 | IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current); 362 | 363 | // when you received a low level packet (eg. UDP packet), call it 364 | int ikcp_input(ikcpcb *kcp, const char *data, long size); 365 | 366 | // flush pending data 367 | void ikcp_flush(ikcpcb *kcp); 368 | 369 | // check the size of next message in the recv queue 370 | int ikcp_peeksize(const ikcpcb *kcp); 371 | 372 | // change MTU size, default is 1400 373 | int ikcp_setmtu(ikcpcb *kcp, int mtu); 374 | 375 | // set maximum window size: sndwnd=32, rcvwnd=32 by default 376 | int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd); 377 | 378 | // get how many packet is waiting to be sent 379 | int ikcp_waitsnd(const ikcpcb *kcp); 380 | 381 | // fastest: ikcp_nodelay(kcp, 1, 20, 2, 1) 382 | // nodelay: 0:disable(default), 1:enable 383 | // interval: internal update timer interval in millisec, default is 100ms 384 | // resend: 0:disable fast resend(default), 1:enable fast resend 385 | // nc: 0:normal congestion control(default), 1:disable congestion control 386 | int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc); 387 | 388 | 389 | void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...); 390 | 391 | // setup allocator 392 | void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)); 393 | 394 | // read conv 395 | IUINT32 ikcp_getconv(const void *ptr); 396 | 397 | 398 | #ifdef __cplusplus 399 | } 400 | #endif 401 | 402 | #endif 403 | 404 | -------------------------------------------------------------------------------- /oldversion/kcp/KCP.py: -------------------------------------------------------------------------------- 1 | from typing import List, Union 2 | 3 | IKCP_RTO_NDL = 30 # no delay min rto 4 | IKCP_RTO_MIN = 100 # normal min rto 5 | IKCP_RTO_DEF = 200 6 | IKCP_RTO_MAX = 60000 7 | IKCP_CMD_PUSH = 81 # cmd: push data 8 | IKCP_CMD_ACK = 82 # cmd: ack 9 | IKCP_CMD_WASK = 83 # cmd: window probe (ask) 10 | IKCP_CMD_WINS = 84 # cmd: window size (tell) 11 | IKCP_ASK_SEND = 1 # need to send IKCP_CMD_WASK 12 | IKCP_ASK_TELL = 2 # need to send IKCP_CMD_WINS 13 | IKCP_WND_SND = 32 14 | IKCP_WND_RCV = 32 15 | IKCP_MTU_DEF = 1400 16 | IKCP_ACK_FAST = 3 17 | IKCP_INTERVAL = 100 18 | IKCP_OVERHEAD = 24 19 | IKCP_DEADLINK = 10 20 | IKCP_THRESH_INIT = 2 21 | IKCP_THRESH_MIN = 2 22 | IKCP_PROBE_INIT = 7000 # 7 secs to probe window size 23 | IKCP_PROBE_LIMIT = 120000 # up to 120 secs to probe window 24 | 25 | 26 | class Segment: 27 | # session attribute 28 | 29 | conv = 0 30 | cmd = 0 31 | frg = 0 32 | wnd = 0 33 | ts = 0 34 | sn = 0 35 | una = 0 36 | resendts = 0 37 | rto = 0 38 | fastack = 0 39 | xmit = 0 40 | data: bytearray = None 41 | 42 | def __init__(self, size): 43 | self.data = bytearray(size) 44 | 45 | def encode(self, ptr: bytearray, offset: int): 46 | _offset = offset 47 | 48 | KCP.ikcp_encode32u(ptr, offset, self.conv) 49 | offset += 4 50 | KCP.ikcp_encode8u(ptr, offset, self.cmd) 51 | offset += 1 52 | KCP.ikcp_encode8u(ptr, offset, self.frg) 53 | offset += 1 54 | KCP.ikcp_encode16u(ptr, offset, self.wnd) 55 | offset += 2 56 | KCP.ikcp_encode32u(ptr, offset, self.ts) 57 | offset += 4 58 | KCP.ikcp_encode32u(ptr, offset, self.sn) 59 | offset += 4 60 | KCP.ikcp_encode32u(ptr, offset, self.una) 61 | offset += 4 62 | KCP.ikcp_encode32u(ptr, offset, len(self.data)) 63 | offset += 4 64 | 65 | return offset - _offset 66 | 67 | 68 | class KCP: 69 | # public session attribute 70 | 71 | # static method 72 | 73 | @staticmethod 74 | def ikcp_encode8u(p: Union[bytes, bytearray], offset: int, c: int): 75 | p[0 + offset] = c & 255 76 | 77 | @staticmethod 78 | def ikcp_decode8u(p: Union[bytes, bytearray], offset: int): 79 | return p[0 + offset] 80 | 81 | @staticmethod 82 | def ikcp_encode16u(p: Union[bytes, bytearray], offset: int, w: int): 83 | p[offset + 0] = (w >> 8) & 255 84 | p[offset + 1] = (w >> 0) & 255 85 | 86 | @staticmethod 87 | def ikcp_decode16u(p: Union[bytes, bytearray], offset: int): 88 | return (p[0 + offset] & 0xff) << 8 | (p[1 + offset] & 0xff) 89 | 90 | @staticmethod 91 | def ikcp_encode32u(p: Union[bytes, bytearray], offset: int, l: int): 92 | p[offset + 0] = (l >> 24) & 255 93 | p[offset + 1] = (l >> 16) & 255 94 | p[offset + 2] = (l >> 8) & 255 95 | p[offset + 3] = (l >> 0) & 255 96 | 97 | @staticmethod 98 | def ikcp_decode32u(p: Union[bytes, bytearray], offset: int): 99 | return (p[offset + 0] & 0xff) << 24 \ 100 | | (p[offset + 1] & 0xff) << 16 \ 101 | | (p[offset + 2] & 0xff) << 8 \ 102 | | p[offset + 3] & 0xff 103 | 104 | @staticmethod 105 | def _ibound(lower: int, middle: int, upper: int): 106 | return min(max(lower, middle), upper) 107 | 108 | @staticmethod 109 | def _itimediff(later: int, earlier: int): 110 | return later - earlier 111 | 112 | conv = 0 113 | # user = user 114 | snd_una = 0 115 | snd_nxt = 0 116 | rcv_nxt = 0 117 | ts_recent = 0 118 | ts_lastack = 0 119 | ts_probe = 0 120 | probe_wait = 0 121 | snd_wnd = IKCP_WND_SND 122 | rcv_wnd = IKCP_WND_RCV 123 | rmt_wnd = IKCP_WND_RCV 124 | cwnd = 0 125 | incr = 0 126 | probe = 0 127 | mtu = IKCP_MTU_DEF 128 | mss = mtu - IKCP_OVERHEAD 129 | 130 | state = 0 131 | # long ackblock = 0 132 | # long ackcount = 0 133 | rx_srtt = 0 134 | rx_rttval = 0 135 | rx_rto = IKCP_RTO_DEF 136 | rx_minrto = IKCP_RTO_MIN 137 | current = 0 138 | interval = IKCP_INTERVAL 139 | ts_flush = IKCP_INTERVAL 140 | nodelay = 0 141 | updated = 0 142 | logmask = 0 143 | ssthresh = IKCP_THRESH_INIT 144 | fastresend = 0 145 | nocwnd = 0 146 | xmit = 0 147 | dead_link = IKCP_DEADLINK 148 | 149 | # long output = NULL 150 | # long writelog = NULL 151 | 152 | def __init__(self, conv): 153 | self.conv = conv 154 | self.buffer = bytearray((self.mtu + IKCP_OVERHEAD) * 3) 155 | self.nrcv_buf: List[Segment] = list() 156 | self.nsnd_buf: List[Segment] = list() 157 | self.nrcv_que: List[Segment] = list() 158 | self.nsnd_que: List[Segment] = list() 159 | self.acklist = list() 160 | # self.transport = transport 161 | # self.output_buffer = output_buffer 162 | 163 | def recv(self, size): 164 | """ 165 | Put user data out self.nrcv_que in buffer. 166 | """ 167 | 168 | # there is no available segment in nrcv_que 169 | buffer = bytearray(size) 170 | 171 | if not len(self.nrcv_que): 172 | return -1 173 | 174 | peeksize = self.peeksize() 175 | 176 | if peeksize < 0: 177 | return -2 178 | # if peeksize > len(buffer): 179 | # return -3 180 | 181 | recover = False 182 | 183 | if len(self.nrcv_que) >= self.rcv_wnd: 184 | recover = True 185 | 186 | # merge fragment 187 | count = 0 188 | n = 0 189 | for segment in self.nrcv_que: 190 | segment_len = len(segment.data) 191 | buffer[n: n + segment_len] = segment.data[:] 192 | n += segment_len 193 | count += 1 194 | if segment.frg == 0: 195 | break 196 | 197 | if count > 0: 198 | self.nrcv_que[:] = self.nrcv_que[count:] 199 | 200 | # move available data from nrcv_buf -> nrcv_que 201 | count = 0 202 | for segment in self.nrcv_buf: 203 | if (segment.sn == self.rcv_nxt) and (len(self.nrcv_que) < self.rcv_wnd): 204 | self.nrcv_que.append(segment) 205 | self.rcv_nxt += 1 206 | count += 1 207 | else: 208 | break 209 | 210 | if count > 0: 211 | self.nrcv_buf[:] = self.nrcv_buf[count:] 212 | 213 | # fast recover 214 | if (len(self.nrcv_que) < self.rcv_wnd) and recover: 215 | # ready to send back IKCP_CMD_WINS in ikcp_flush 216 | # tell remote my window size 217 | self.probe |= IKCP_ASK_TELL 218 | return buffer 219 | 220 | def peeksize(self) -> int: 221 | """ 222 | check the size of next message in the recv queue 223 | """ 224 | if 0 == len(self.nrcv_que): 225 | return -1 226 | first = self.nrcv_que[0] 227 | if first.frg == 0: 228 | return len(first.data) 229 | if len(self.nrcv_que) < (first.frg + 1): 230 | return -1 231 | length = 0 232 | for segment in self.nrcv_que: 233 | length += len(segment.data) 234 | if segment.frg == 0: 235 | break 236 | return length 237 | 238 | def send(self, buffer: bytearray): 239 | """ 240 | put user data into send queue 241 | """ 242 | if 0 == len(buffer): 243 | return -1 244 | # split by mss 245 | if len(buffer) < self.mss: 246 | count = 1 247 | else: 248 | count = (len(buffer) + self.mss - 1) // self.mss 249 | 250 | if count > 255: 251 | return -2 252 | 253 | if count == 0: 254 | count = 1 255 | 256 | offset = 0 257 | length = len(buffer) 258 | 259 | # 分片后加入到发送队列 260 | for i in range(count): 261 | size = self.mss if (length > self.mss) else length 262 | segment = Segment(size) 263 | segment.data[:] = buffer[offset: offset + size] 264 | offset += size 265 | segment.frg = count - i - 1 266 | self.nsnd_que.append(segment) 267 | length -= size 268 | return 0 269 | 270 | def update_ack(self, rtt: int): 271 | """parse ack""" 272 | if self.rx_srtt == 0: 273 | self.rx_srtt = rtt 274 | self.rx_rttval = rtt // 2 275 | else: 276 | delta = rtt - self.rx_srtt 277 | if delta < 0: 278 | delta = -delta 279 | self.rx_rttval = (3 * self.rx_rttval + delta) // 4 280 | self.rx_srtt = (7 * self.rx_srtt + rtt) // 8 281 | if self.rx_srtt < 1: 282 | self.rx_srtt = 1 283 | rto = self.rx_srtt + max(1, 4 * self.rx_rttval) 284 | self.rx_rto = self._ibound(self.rx_minrto, rto, IKCP_RTO_MAX) 285 | 286 | def shrink_buf(self): 287 | """计算本地真实snd_una""" 288 | if len(self.nsnd_buf) > 0: 289 | self.snd_una = self.nsnd_buf[0].sn 290 | else: 291 | self.snd_una = self.snd_nxt 292 | 293 | def parse_ack(self, sn: int): 294 | """对端返回的ack,确认发送成功时,对应包从发送缓存中移除""" 295 | if (self._itimediff(sn, self.snd_una) < 0) or (self._itimediff(sn, self.snd_nxt) >= 0): 296 | return 297 | index = 0 298 | for segment in self.nsnd_buf: 299 | if self._itimediff(sn, segment.sn) < 0: 300 | break 301 | segment.fastack += 1 302 | if sn == segment.sn: 303 | self.nsnd_buf.pop(index) 304 | break 305 | index += 1 306 | 307 | def parse_una(self, una: int): 308 | """通过对端传回的una将已经确认发送成功的包从发送缓存中移除""" 309 | count = 0 310 | for segment in self.nsnd_buf: 311 | if self._itimediff(una, segment.sn) > 0: 312 | count += 1 313 | else: 314 | break 315 | if count > 0: 316 | self.nsnd_buf = self.nsnd_buf[count:] 317 | 318 | def ack_push(self, sn: int, ts: int): 319 | """收到数据包之后,将对应ack返回,flush时发送""" 320 | self.acklist.append(sn) 321 | self.acklist.append(ts) 322 | 323 | def parse_data(self, new_segment: Segment): 324 | """用户数据包解析""" 325 | sn = new_segment.sn 326 | repeat = False 327 | if (self._itimediff(sn, self.rcv_nxt + self.rcv_wnd) >= 0) or (self._itimediff(sn, self.rcv_nxt) < 0): 328 | return 329 | n = len(self.nrcv_buf) - 1 330 | after_idx = -1 331 | 332 | # 判断是否重复包,同时计算插入位置 333 | for i in range(n, -1, -1): 334 | segment = self.nrcv_buf[i] 335 | if segment.sn == sn: 336 | repeat = True 337 | break 338 | if self._itimediff(sn, segment.sn) > 0: 339 | after_idx = i 340 | break 341 | 342 | if not repeat: 343 | self.nrcv_buf.insert(after_idx + 1, new_segment) 344 | 345 | # 将连续包加入到接受队列 346 | count = 0 347 | for segment in self.nrcv_buf: 348 | if (segment.sn == self.rcv_nxt) and (len(self.nrcv_que) < self.rcv_wnd): 349 | self.nrcv_que.append(segment) 350 | self.rcv_nxt += 1 351 | count += 1 352 | else: 353 | break 354 | 355 | # 从接受缓存中移除 356 | if count > 0: 357 | self.nrcv_buf = self.nrcv_buf[count:] 358 | 359 | def input(self, data: bytearray): 360 | s_una = self.snd_una 361 | if len(data) < IKCP_OVERHEAD: 362 | return 0 363 | offset = 0 364 | while True: 365 | if (len(data) - offset) < IKCP_OVERHEAD: 366 | break 367 | conv = self.ikcp_decode32u(data, offset) 368 | offset += 4 369 | if self.conv != conv: 370 | return -1 371 | cmd = self.ikcp_decode8u(data, offset) 372 | offset += 1 373 | frg = self.ikcp_decode8u(data, offset) 374 | offset += 1 375 | wnd = self.ikcp_decode16u(data, offset) 376 | offset += 2 377 | ts = self.ikcp_decode32u(data, offset) 378 | offset += 4 379 | sn = self.ikcp_decode32u(data, offset) 380 | offset += 4 381 | una = self.ikcp_decode32u(data, offset) 382 | offset += 4 383 | length = self.ikcp_decode32u(data, offset) 384 | offset += 4 385 | 386 | if (len(data) - offset) < length: 387 | return -2 388 | 389 | if ( 390 | cmd != IKCP_CMD_PUSH 391 | and cmd != IKCP_CMD_ACK 392 | and cmd != IKCP_CMD_WASK 393 | and cmd != IKCP_CMD_WINS 394 | ): 395 | return -3 396 | 397 | self.rmt_wnd = wnd 398 | self.parse_una(una) 399 | self.shrink_buf() 400 | 401 | if IKCP_CMD_ACK == cmd: 402 | if self._itimediff(self.current, ts) >= 0: 403 | self.update_ack(self._itimediff(self.current, ts)) 404 | self.parse_ack(sn) 405 | self.shrink_buf() 406 | elif IKCP_CMD_PUSH == cmd: 407 | if self._itimediff(sn, self.rcv_nxt + self.rcv_wnd) < 0: 408 | self.ack_push(sn, ts) 409 | if self._itimediff(sn, self.rcv_nxt) >= 0: 410 | segment = Segment(length) 411 | segment.conv = conv 412 | segment.cmd = cmd 413 | segment.frg = frg 414 | segment.wnd = wnd 415 | segment.ts = ts 416 | segment.sn = sn 417 | segment.una = una 418 | if length > 0: 419 | segment.data[:] = data[offset:offset + length] 420 | self.parse_data(segment) 421 | elif IKCP_CMD_WASK == cmd: 422 | self.probe |= IKCP_ASK_TELL 423 | elif IKCP_CMD_WINS == cmd: 424 | pass 425 | else: 426 | return -3 427 | offset += length 428 | if self._itimediff(self.snd_una, s_una) > 0: 429 | if self.cwnd < self.rmt_wnd: 430 | mss = self.mss 431 | if self.cwnd < self.ssthresh: 432 | self.cwnd += 1 433 | self.incr += mss 434 | else: 435 | if self.incr < mss: 436 | self.incr = mss 437 | self.incr += (mss * mss) // self.incr + (mss // 16) 438 | if (self.cwnd + 1) * mss <= self.incr: 439 | self.cwnd += 1 440 | if self.cwnd > self.rmt_wnd: 441 | self.cwnd = self.rmt_wnd 442 | self.incr = self.rmt_wnd * mss 443 | return 0 444 | 445 | def wnd_unused(self): 446 | if len(self.nrcv_que) < self.rcv_wnd: 447 | return self.rcv_wnd - len(self.nrcv_que) 448 | return 0 449 | 450 | def flush(self): 451 | current = self.current 452 | change = 0 453 | lost = 0 454 | 455 | if self.updated == 0: 456 | return 457 | 458 | seg = Segment(0) 459 | seg.conv = self.conv 460 | seg.cmd = IKCP_CMD_ACK 461 | seg.wnd = self.wnd_unused() 462 | seg.una = self.rcv_nxt 463 | 464 | count = len(self.acklist) // 2 465 | offset = 0 466 | for i in range(count): 467 | if (offset + IKCP_OVERHEAD) > self.mtu: 468 | self.output(self.buffer, offset) 469 | offset = 0 470 | seg.sn = self.acklist[i * 2] 471 | seg.ts = self.acklist[i * 2 + 1] 472 | offset += seg.encode(self.buffer, offset) 473 | self.acklist.clear() 474 | 475 | # 判断是否需要请求对端接受窗口 476 | if 0 == self.rmt_wnd: 477 | if 0 == self.probe_wait: 478 | self.probe_wait = IKCP_PROBE_INIT 479 | self.ts_probe = self.current + self.probe_wait 480 | else: 481 | # 逐步扩大请求时间间隔 482 | if self._itimediff(self.current, self.ts_probe) >= 0: 483 | if self.probe_wait < IKCP_PROBE_INIT: 484 | self.probe_wait = IKCP_PROBE_INIT 485 | 486 | self.probe_wait += self.probe_wait // 2 487 | if self.probe_wait > IKCP_PROBE_LIMIT: 488 | self.probe_wait = IKCP_PROBE_LIMIT 489 | self.ts_probe = self.current + self.probe_wait 490 | self.probe |= IKCP_ASK_SEND 491 | else: 492 | self.ts_probe = 0 493 | self.probe_wait = 0 494 | 495 | # 请求对端接受窗口 496 | if (self.probe & IKCP_ASK_SEND) != 0: 497 | seg.cmd = IKCP_CMD_WASK 498 | if (offset + IKCP_OVERHEAD) > self.mtu: 499 | self.output(self.buffer, offset) 500 | offset = 0 501 | offset += seg.encode(self.buffer, offset) 502 | 503 | # 告诉对端自己的接受窗口 504 | if (self.probe & IKCP_ASK_TELL) != 0: 505 | seg.cmd = IKCP_CMD_WINS 506 | if (offset + IKCP_OVERHEAD) > self.mtu: 507 | self.output(self.buffer, offset) 508 | offset = 0 509 | offset += seg.encode(self.buffer, offset) 510 | 511 | self.probe = 0 512 | 513 | # 计算 window size 514 | cwnd = min(self.snd_wnd, self.rmt_wnd) 515 | 516 | # 如果采用拥塞控制 517 | if self.nocwnd == 0: 518 | cwnd = min(self.cwnd, cwnd) 519 | 520 | count = 0 521 | 522 | # move data from snd_queue to snd_buf 523 | 524 | for nsnd_que_item in self.nsnd_que: 525 | if (self._itimediff(self.snd_nxt, self.snd_una + cwnd)) >= 0: 526 | break 527 | 528 | new_segment = nsnd_que_item 529 | new_segment.conv = self.conv 530 | new_segment.cmd = IKCP_CMD_PUSH 531 | new_segment.wnd = seg.wnd 532 | new_segment.ts = current 533 | new_segment.sn = self.snd_nxt 534 | new_segment.una = self.rcv_nxt 535 | new_segment.resendts = current 536 | new_segment.rto = self.rx_rto 537 | new_segment.fastack = 0 538 | new_segment.xmit = 0 539 | self.nsnd_buf.append(new_segment) 540 | self.snd_nxt += 1 541 | count += 1 542 | 543 | if count > 0: 544 | self.nsnd_que = self.nsnd_que[count:] 545 | 546 | # calculate resent 547 | resent = self.fastresend if (self.fastresend > 0) else 0xffffffff 548 | rtomin = (self.rx_rto >> 3) if (self.nodelay == 0) else 0 549 | 550 | # flush data segment 551 | for segment in self.nsnd_buf: 552 | need_send = False 553 | if segment.xmit == 0: 554 | # 第一次传输 555 | need_send = True 556 | segment.xmit += 1 557 | segment.rto = self.rx_rto 558 | segment.resendts = current + segment.rto + rtomin 559 | elif self._itimediff(current, segment.resendts) >= 0: 560 | # 丢包重传 561 | need_send = True 562 | segment.xmit += 1 563 | self.xmit += 1 564 | if self.nodelay == 0: 565 | segment.rto += self.rx_rto 566 | else: 567 | segment.rto += self.rx_rto // 2 568 | segment.resendts = current + segment.rto 569 | lost = 1 570 | elif segment.fastack >= resent: 571 | # 快速重传 572 | need_send = True 573 | segment.xmit += 1 574 | segment.fastack = 0 575 | segment.resendts = current + segment.rto 576 | change += 1 577 | 578 | if need_send: 579 | segment.ts = current 580 | segment.wnd = seg.wnd 581 | segment.una = self.rcv_nxt 582 | 583 | need = IKCP_OVERHEAD + len(segment.data) 584 | if (offset + need) >= self.mtu: 585 | self.output(self.buffer, offset) 586 | offset = 0 587 | offset += segment.encode(self.buffer, offset) 588 | if len(segment.data) > 0: 589 | self.buffer[offset: offset + len(segment.data)] = segment.data[:] 590 | offset += len(segment.data) 591 | if segment.xmit >= self.dead_link: 592 | self.state = -1 593 | # flash remain segment 594 | if offset > 0: 595 | self.output(self.buffer, offset) 596 | 597 | # update ssthresh 598 | # 拥塞避免 599 | if change != 0: 600 | inflight = self.snd_nxt - self.snd_una 601 | self.ssthresh = inflight // 2 602 | if self.ssthresh < IKCP_THRESH_MIN: 603 | self.ssthresh = IKCP_THRESH_MIN 604 | self.cwnd = self.ssthresh + resent 605 | self.incr = self.cwnd * self.mss 606 | 607 | if lost != 0: 608 | self.ssthresh = self.cwnd // 2 609 | if self.ssthresh < IKCP_THRESH_MIN: 610 | self.ssthresh = IKCP_THRESH_MIN 611 | self.cwnd = 1 612 | self.incr = self.mss 613 | 614 | if self.cwnd < 1: 615 | self.cwnd = 1 616 | self.incr = self.mss 617 | 618 | def update(self, current: int): 619 | self.current = current 620 | 621 | if 0 == self.updated: 622 | self.updated = 1 623 | self.ts_flush = self.current 624 | 625 | # 两次更新间隔 626 | slap = self._itimediff(self.current, self.ts_flush) 627 | 628 | # interval设置过大或者Update调用间隔太久 629 | if (slap >= 10000) or (slap < -10000): 630 | self.ts_flush = self.current 631 | slap = 0 632 | 633 | if slap >= 0: 634 | self.ts_flush += self.interval 635 | if self._itimediff(self.current, self.ts_flush) >= 0: 636 | self.ts_flush = self.current + self.interval 637 | self.flush() 638 | 639 | def check(self, current): 640 | ts_flush = self.ts_flush 641 | tm_packet = 0x7ffffff 642 | if self.updated == 0: 643 | return current 644 | if (self._itimediff(current, ts_flush) >= 10000) or (self._itimediff(current, ts_flush) < -10000): 645 | ts_flush = current 646 | 647 | if self._itimediff(current, ts_flush) >= 0: 648 | return current 649 | tm_flush = self._itimediff(ts_flush, current) 650 | for seg in self.nsnd_buf: 651 | diff = self._itimediff(seg.resendts, current) 652 | if diff <= 0: 653 | return current 654 | if diff < tm_packet: 655 | tm_packet = diff 656 | minimal = tm_packet if (tm_packet < tm_flush) else tm_flush 657 | if minimal >= self.interval: 658 | minimal = self.interval 659 | 660 | return current + minimal 661 | 662 | def set_mtu(self, mtu): 663 | if (mtu < 50) or (mtu < IKCP_OVERHEAD): 664 | return -1 665 | self.buffer = bytes((self.mtu + IKCP_OVERHEAD) * 3) 666 | self.mtu = mtu 667 | self.mss = self.mtu - IKCP_OVERHEAD 668 | return 0 669 | 670 | def set_interval(self, interval): 671 | if interval > 5000: 672 | interval = 5000 673 | elif interval < 10: 674 | interval = 10 675 | self.interval = interval 676 | return 0 677 | 678 | def set_nodelay(self, nodelay, interval, resend, nc): 679 | if nodelay >= 0: 680 | self.nodelay = nodelay 681 | if nodelay != 0: 682 | self.rx_minrto = IKCP_RTO_NDL 683 | else: 684 | self.rx_minrto = IKCP_RTO_MIN 685 | self.set_interval(interval) 686 | if resend >= 0: 687 | self.fastresend = resend 688 | if nc >= 0: 689 | self.nocwnd = nc 690 | return 0 691 | 692 | def wnd_size(self, snd_wnd, rcv_wnd): 693 | if snd_wnd > 0: 694 | self.snd_wnd = snd_wnd 695 | if rcv_wnd > 0: 696 | self.rcv_wnd = rcv_wnd 697 | return 0 698 | 699 | def wait_snd(self): 700 | return len(self.nsnd_buf) + len(self.nsnd_que) 701 | 702 | def output(self, buffer: bytearray, size): 703 | raise NotImplementedError 704 | -------------------------------------------------------------------------------- /oldversion/py_KCP.py: -------------------------------------------------------------------------------- 1 | from typing import List, Union 2 | 3 | IKCP_RTO_NDL = 30 # no delay min rto 4 | IKCP_RTO_MIN = 100 # normal min rto 5 | IKCP_RTO_DEF = 200 6 | IKCP_RTO_MAX = 60000 7 | IKCP_CMD_PUSH = 81 # cmd: push data 8 | IKCP_CMD_ACK = 82 # cmd: ack 9 | IKCP_CMD_WASK = 83 # cmd: window probe (ask) 10 | IKCP_CMD_WINS = 84 # cmd: window size (tell) 11 | IKCP_ASK_SEND = 1 # need to send IKCP_CMD_WASK 12 | IKCP_ASK_TELL = 2 # need to send IKCP_CMD_WINS 13 | IKCP_WND_SND = 32 14 | IKCP_WND_RCV = 32 15 | IKCP_MTU_DEF = 1400 16 | IKCP_ACK_FAST = 3 17 | IKCP_INTERVAL = 100 18 | IKCP_OVERHEAD = 24 19 | IKCP_DEADLINK = 10 20 | IKCP_THRESH_INIT = 2 21 | IKCP_THRESH_MIN = 2 22 | IKCP_PROBE_INIT = 7000 # 7 secs to probe window size 23 | IKCP_PROBE_LIMIT = 120000 # up to 120 secs to probe window 24 | 25 | 26 | class Segment: 27 | # session attribute 28 | 29 | conv = 0 30 | cmd = 0 31 | frg = 0 32 | wnd = 0 33 | ts = 0 34 | sn = 0 35 | una = 0 36 | resendts = 0 37 | rto = 0 38 | fastack = 0 39 | xmit = 0 40 | data: bytearray = None 41 | 42 | def __init__(self, size): 43 | self.data = bytearray(size) 44 | 45 | def encode(self, ptr: bytearray, offset: int): 46 | _offset = offset 47 | 48 | KCP.ikcp_encode32u(ptr, offset, self.conv) 49 | offset += 4 50 | KCP.ikcp_encode8u(ptr, offset, self.cmd) 51 | offset += 1 52 | KCP.ikcp_encode8u(ptr, offset, self.frg) 53 | offset += 1 54 | KCP.ikcp_encode16u(ptr, offset, self.wnd) 55 | offset += 2 56 | KCP.ikcp_encode32u(ptr, offset, self.ts) 57 | offset += 4 58 | KCP.ikcp_encode32u(ptr, offset, self.sn) 59 | offset += 4 60 | KCP.ikcp_encode32u(ptr, offset, self.una) 61 | offset += 4 62 | KCP.ikcp_encode32u(ptr, offset, len(self.data)) 63 | offset += 4 64 | 65 | return offset - _offset 66 | 67 | 68 | class KCP: 69 | # public session attribute 70 | 71 | # static method 72 | 73 | @staticmethod 74 | def ikcp_encode8u(p: Union[bytes, bytearray], offset: int, c: int): 75 | p[0 + offset] = c & 255 76 | 77 | @staticmethod 78 | def ikcp_decode8u(p: Union[bytes, bytearray], offset: int): 79 | return p[0 + offset] 80 | 81 | @staticmethod 82 | def ikcp_encode16u(p: Union[bytes, bytearray], offset: int, w: int): 83 | p[offset + 0] = (w >> 8) & 255 84 | p[offset + 1] = (w >> 0) & 255 85 | 86 | @staticmethod 87 | def ikcp_decode16u(p: Union[bytes, bytearray], offset: int): 88 | return (p[0 + offset] & 0xff) << 8 | (p[1 + offset] & 0xff) 89 | 90 | @staticmethod 91 | def ikcp_encode32u(p: Union[bytes, bytearray], offset: int, l: int): 92 | p[offset + 0] = (l >> 24) & 255 93 | p[offset + 1] = (l >> 16) & 255 94 | p[offset + 2] = (l >> 8) & 255 95 | p[offset + 3] = (l >> 0) & 255 96 | 97 | @staticmethod 98 | def ikcp_decode32u(p: Union[bytes, bytearray], offset: int): 99 | return (p[offset + 0] & 0xff) << 24 \ 100 | | (p[offset + 1] & 0xff) << 16 \ 101 | | (p[offset + 2] & 0xff) << 8 \ 102 | | p[offset + 3] & 0xff 103 | 104 | @staticmethod 105 | def _ibound(lower: int, middle: int, upper: int): 106 | return min(max(lower, middle), upper) 107 | 108 | @staticmethod 109 | def _itimediff(later: int, earlier: int): 110 | return later - earlier 111 | 112 | conv = 0 113 | # user = user 114 | snd_una = 0 115 | snd_nxt = 0 116 | rcv_nxt = 0 117 | ts_recent = 0 118 | ts_lastack = 0 119 | ts_probe = 0 120 | probe_wait = 0 121 | snd_wnd = IKCP_WND_SND 122 | rcv_wnd = IKCP_WND_RCV 123 | rmt_wnd = IKCP_WND_RCV 124 | cwnd = 0 125 | incr = 0 126 | probe = 0 127 | mtu = IKCP_MTU_DEF 128 | mss = mtu - IKCP_OVERHEAD 129 | 130 | state = 0 131 | # long ackblock = 0 132 | # long ackcount = 0 133 | rx_srtt = 0 134 | rx_rttval = 0 135 | rx_rto = IKCP_RTO_DEF 136 | rx_minrto = IKCP_RTO_MIN 137 | current = 0 138 | interval = IKCP_INTERVAL 139 | ts_flush = IKCP_INTERVAL 140 | nodelay = 0 141 | updated = 0 142 | logmask = 0 143 | ssthresh = IKCP_THRESH_INIT 144 | fastresend = 0 145 | nocwnd = 0 146 | xmit = 0 147 | dead_link = IKCP_DEADLINK 148 | 149 | # long output = NULL 150 | # long writelog = NULL 151 | 152 | def __init__(self, conv): 153 | self.conv = conv 154 | self.buffer = bytearray((self.mtu + IKCP_OVERHEAD) * 3) 155 | self.nrcv_buf: List[Segment] = list() 156 | self.nsnd_buf: List[Segment] = list() 157 | self.nrcv_que: List[Segment] = list() 158 | self.nsnd_que: List[Segment] = list() 159 | self.acklist = list() 160 | # self.transport = transport 161 | # self.output_buffer = output_buffer 162 | 163 | def recv(self, size): 164 | """ 165 | Put user data out self.nrcv_que in buffer. 166 | """ 167 | 168 | # there is no available segment in nrcv_que 169 | buffer = bytearray(size) 170 | 171 | if not len(self.nrcv_que): 172 | return -1 173 | 174 | peeksize = self.peeksize() 175 | 176 | if peeksize < 0: 177 | return -2 178 | # if peeksize > len(buffer): 179 | # return -3 180 | 181 | recover = False 182 | 183 | if len(self.nrcv_que) >= self.rcv_wnd: 184 | recover = True 185 | 186 | # merge fragment 187 | count = 0 188 | n = 0 189 | for segment in self.nrcv_que: 190 | segment_len = len(segment.data) 191 | buffer[n: n + segment_len] = segment.data[:] 192 | n += segment_len 193 | count += 1 194 | if segment.frg == 0: 195 | break 196 | 197 | if count > 0: 198 | self.nrcv_que[:] = self.nrcv_que[count:] 199 | 200 | # move available data from nrcv_buf -> nrcv_que 201 | count = 0 202 | for segment in self.nrcv_buf: 203 | if (segment.sn == self.rcv_nxt) and (len(self.nrcv_que) < self.rcv_wnd): 204 | self.nrcv_que.append(segment) 205 | self.rcv_nxt += 1 206 | count += 1 207 | else: 208 | break 209 | 210 | if count > 0: 211 | self.nrcv_buf[:] = self.nrcv_buf[count:] 212 | 213 | # fast recover 214 | if (len(self.nrcv_que) < self.rcv_wnd) and recover: 215 | # ready to send back IKCP_CMD_WINS in ikcp_flush 216 | # tell remote my window size 217 | self.probe |= IKCP_ASK_TELL 218 | return buffer 219 | 220 | def peeksize(self) -> int: 221 | """ 222 | check the size of next message in the recv queue 223 | """ 224 | if 0 == len(self.nrcv_que): 225 | return -1 226 | first = self.nrcv_que[0] 227 | if first.frg == 0: 228 | return len(first.data) 229 | if len(self.nrcv_que) < (first.frg + 1): 230 | return -1 231 | length = 0 232 | for segment in self.nrcv_que: 233 | length += len(segment.data) 234 | if segment.frg == 0: 235 | break 236 | return length 237 | 238 | def send(self, buffer: bytearray): 239 | """ 240 | put user data into send queue 241 | """ 242 | if 0 == len(buffer): 243 | return -1 244 | # split by mss 245 | if len(buffer) < self.mss: 246 | count = 1 247 | else: 248 | count = (len(buffer) + self.mss - 1) // self.mss 249 | 250 | if count > 255: 251 | return -2 252 | 253 | if count == 0: 254 | count = 1 255 | 256 | offset = 0 257 | length = len(buffer) 258 | 259 | # 分片后加入到发送队列 260 | for i in range(count): 261 | size = self.mss if (length > self.mss) else length 262 | segment = Segment(size) 263 | segment.data[:] = buffer[offset: offset + size] 264 | offset += size 265 | segment.frg = count - i - 1 266 | self.nsnd_que.append(segment) 267 | length -= size 268 | return 0 269 | 270 | def update_ack(self, rtt: int): 271 | """parse ack""" 272 | if self.rx_srtt == 0: 273 | self.rx_srtt = rtt 274 | self.rx_rttval = rtt // 2 275 | else: 276 | delta = rtt - self.rx_srtt 277 | if delta < 0: 278 | delta = -delta 279 | self.rx_rttval = (3 * self.rx_rttval + delta) // 4 280 | self.rx_srtt = (7 * self.rx_srtt + rtt) // 8 281 | if self.rx_srtt < 1: 282 | self.rx_srtt = 1 283 | rto = self.rx_srtt + max(1, 4 * self.rx_rttval) 284 | self.rx_rto = self._ibound(self.rx_minrto, rto, IKCP_RTO_MAX) 285 | 286 | def shrink_buf(self): 287 | """计算本地真实snd_una""" 288 | if len(self.nsnd_buf) > 0: 289 | self.snd_una = self.nsnd_buf[0].sn 290 | else: 291 | self.snd_una = self.snd_nxt 292 | 293 | def parse_ack(self, sn: int): 294 | """对端返回的ack,确认发送成功时,对应包从发送缓存中移除""" 295 | if (self._itimediff(sn, self.snd_una) < 0) or (self._itimediff(sn, self.snd_nxt) >= 0): 296 | return 297 | index = 0 298 | for segment in self.nsnd_buf: 299 | if self._itimediff(sn, segment.sn) < 0: 300 | break 301 | segment.fastack += 1 302 | if sn == segment.sn: 303 | self.nsnd_buf.pop(index) 304 | break 305 | index += 1 306 | 307 | def parse_una(self, una: int): 308 | """通过对端传回的una将已经确认发送成功的包从发送缓存中移除""" 309 | count = 0 310 | for segment in self.nsnd_buf: 311 | if self._itimediff(una, segment.sn) > 0: 312 | count += 1 313 | else: 314 | break 315 | if count > 0: 316 | self.nsnd_buf = self.nsnd_buf[count:] 317 | 318 | def ack_push(self, sn: int, ts: int): 319 | """收到数据包之后,将对应ack返回,flush时发送""" 320 | self.acklist.append(sn) 321 | self.acklist.append(ts) 322 | 323 | def parse_data(self, new_segment: Segment): 324 | """用户数据包解析""" 325 | sn = new_segment.sn 326 | repeat = False 327 | if (self._itimediff(sn, self.rcv_nxt + self.rcv_wnd) >= 0) or (self._itimediff(sn, self.rcv_nxt) < 0): 328 | return 329 | n = len(self.nrcv_buf) - 1 330 | after_idx = -1 331 | 332 | # 判断是否重复包,同时计算插入位置 333 | for i in range(n, -1, -1): 334 | segment = self.nrcv_buf[i] 335 | if segment.sn == sn: 336 | repeat = True 337 | break 338 | if self._itimediff(sn, segment.sn) > 0: 339 | after_idx = i 340 | break 341 | 342 | if not repeat: 343 | self.nrcv_buf.insert(after_idx + 1, new_segment) 344 | 345 | # 将连续包加入到接受队列 346 | count = 0 347 | for segment in self.nrcv_buf: 348 | if (segment.sn == self.rcv_nxt) and (len(self.nrcv_que) < self.rcv_wnd): 349 | self.nrcv_que.append(segment) 350 | self.rcv_nxt += 1 351 | count += 1 352 | else: 353 | break 354 | 355 | # 从接受缓存中移除 356 | if count > 0: 357 | self.nrcv_buf = self.nrcv_buf[count:] 358 | 359 | def input(self, data: bytearray): 360 | s_una = self.snd_una 361 | if len(data) < IKCP_OVERHEAD: 362 | return 0 363 | offset = 0 364 | while True: 365 | if (len(data) - offset) < IKCP_OVERHEAD: 366 | break 367 | conv = self.ikcp_decode32u(data, offset) 368 | offset += 4 369 | if self.conv != conv: 370 | return -1 371 | cmd = self.ikcp_decode8u(data, offset) 372 | offset += 1 373 | frg = self.ikcp_decode8u(data, offset) 374 | offset += 1 375 | wnd = self.ikcp_decode16u(data, offset) 376 | offset += 2 377 | ts = self.ikcp_decode32u(data, offset) 378 | offset += 4 379 | sn = self.ikcp_decode32u(data, offset) 380 | offset += 4 381 | una = self.ikcp_decode32u(data, offset) 382 | offset += 4 383 | length = self.ikcp_decode32u(data, offset) 384 | offset += 4 385 | 386 | if (len(data) - offset) < length: 387 | return -2 388 | 389 | if ( 390 | cmd != IKCP_CMD_PUSH 391 | and cmd != IKCP_CMD_ACK 392 | and cmd != IKCP_CMD_WASK 393 | and cmd != IKCP_CMD_WINS 394 | ): 395 | return -3 396 | 397 | self.rmt_wnd = wnd 398 | self.parse_una(una) 399 | self.shrink_buf() 400 | 401 | if IKCP_CMD_ACK == cmd: 402 | if self._itimediff(self.current, ts) >= 0: 403 | self.update_ack(self._itimediff(self.current, ts)) 404 | self.parse_ack(sn) 405 | self.shrink_buf() 406 | elif IKCP_CMD_PUSH == cmd: 407 | if self._itimediff(sn, self.rcv_nxt + self.rcv_wnd) < 0: 408 | self.ack_push(sn, ts) 409 | if self._itimediff(sn, self.rcv_nxt) >= 0: 410 | segment = Segment(length) 411 | segment.conv = conv 412 | segment.cmd = cmd 413 | segment.frg = frg 414 | segment.wnd = wnd 415 | segment.ts = ts 416 | segment.sn = sn 417 | segment.una = una 418 | if length > 0: 419 | segment.data[:] = data[offset:offset + length] 420 | self.parse_data(segment) 421 | elif IKCP_CMD_WASK == cmd: 422 | self.probe |= IKCP_ASK_TELL 423 | elif IKCP_CMD_WINS == cmd: 424 | pass 425 | else: 426 | return -3 427 | offset += length 428 | if self._itimediff(self.snd_una, s_una) > 0: 429 | if self.cwnd < self.rmt_wnd: 430 | mss = self.mss 431 | if self.cwnd < self.ssthresh: 432 | self.cwnd += 1 433 | self.incr += mss 434 | else: 435 | if self.incr < mss: 436 | self.incr = mss 437 | self.incr += (mss * mss) // self.incr + (mss // 16) 438 | if (self.cwnd + 1) * mss <= self.incr: 439 | self.cwnd += 1 440 | if self.cwnd > self.rmt_wnd: 441 | self.cwnd = self.rmt_wnd 442 | self.incr = self.rmt_wnd * mss 443 | return 0 444 | 445 | def wnd_unused(self): 446 | if len(self.nrcv_que) < self.rcv_wnd: 447 | return self.rcv_wnd - len(self.nrcv_que) 448 | return 0 449 | 450 | def flush(self): 451 | current = self.current 452 | change = 0 453 | lost = 0 454 | 455 | if self.updated == 0: 456 | return 457 | 458 | seg = Segment(0) 459 | seg.conv = self.conv 460 | seg.cmd = IKCP_CMD_ACK 461 | seg.wnd = self.wnd_unused() 462 | seg.una = self.rcv_nxt 463 | 464 | count = len(self.acklist) // 2 465 | offset = 0 466 | for i in range(count): 467 | if (offset + IKCP_OVERHEAD) > self.mtu: 468 | self.output(self.buffer, offset) 469 | offset = 0 470 | seg.sn = self.acklist[i * 2] 471 | seg.ts = self.acklist[i * 2 + 1] 472 | offset += seg.encode(self.buffer, offset) 473 | self.acklist.clear() 474 | 475 | # 判断是否需要请求对端接受窗口 476 | if 0 == self.rmt_wnd: 477 | if 0 == self.probe_wait: 478 | self.probe_wait = IKCP_PROBE_INIT 479 | self.ts_probe = self.current + self.probe_wait 480 | else: 481 | # 逐步扩大请求时间间隔 482 | if self._itimediff(self.current, self.ts_probe) >= 0: 483 | if self.probe_wait < IKCP_PROBE_INIT: 484 | self.probe_wait = IKCP_PROBE_INIT 485 | 486 | self.probe_wait += self.probe_wait // 2 487 | if self.probe_wait > IKCP_PROBE_LIMIT: 488 | self.probe_wait = IKCP_PROBE_LIMIT 489 | self.ts_probe = self.current + self.probe_wait 490 | self.probe |= IKCP_ASK_SEND 491 | else: 492 | self.ts_probe = 0 493 | self.probe_wait = 0 494 | 495 | # 请求对端接受窗口 496 | if (self.probe & IKCP_ASK_SEND) != 0: 497 | seg.cmd = IKCP_CMD_WASK 498 | if (offset + IKCP_OVERHEAD) > self.mtu: 499 | self.output(self.buffer, offset) 500 | offset = 0 501 | offset += seg.encode(self.buffer, offset) 502 | 503 | # 告诉对端自己的接受窗口 504 | if (self.probe & IKCP_ASK_TELL) != 0: 505 | seg.cmd = IKCP_CMD_WINS 506 | if (offset + IKCP_OVERHEAD) > self.mtu: 507 | self.output(self.buffer, offset) 508 | offset = 0 509 | offset += seg.encode(self.buffer, offset) 510 | 511 | self.probe = 0 512 | 513 | # 计算 window size 514 | cwnd = min(self.snd_wnd, self.rmt_wnd) 515 | 516 | # 如果采用拥塞控制 517 | if self.nocwnd == 0: 518 | cwnd = min(self.cwnd, cwnd) 519 | 520 | count = 0 521 | 522 | # move data from snd_queue to snd_buf 523 | 524 | for nsnd_que_item in self.nsnd_que: 525 | if (self._itimediff(self.snd_nxt, self.snd_una + cwnd)) >= 0: 526 | break 527 | 528 | new_segment = nsnd_que_item 529 | new_segment.conv = self.conv 530 | new_segment.cmd = IKCP_CMD_PUSH 531 | new_segment.wnd = seg.wnd 532 | new_segment.ts = current 533 | new_segment.sn = self.snd_nxt 534 | new_segment.una = self.rcv_nxt 535 | new_segment.resendts = current 536 | new_segment.rto = self.rx_rto 537 | new_segment.fastack = 0 538 | new_segment.xmit = 0 539 | self.nsnd_buf.append(new_segment) 540 | self.snd_nxt += 1 541 | count += 1 542 | 543 | if count > 0: 544 | self.nsnd_que = self.nsnd_que[count:] 545 | 546 | # calculate resent 547 | resent = self.fastresend if (self.fastresend > 0) else 0xffffffff 548 | rtomin = (self.rx_rto >> 3) if (self.nodelay == 0) else 0 549 | 550 | # flush data segment 551 | for segment in self.nsnd_buf: 552 | need_send = False 553 | if segment.xmit == 0: 554 | # 第一次传输 555 | need_send = True 556 | segment.xmit += 1 557 | segment.rto = self.rx_rto 558 | segment.resendts = current + segment.rto + rtomin 559 | elif self._itimediff(current, segment.resendts) >= 0: 560 | # 丢包重传 561 | need_send = True 562 | segment.xmit += 1 563 | self.xmit += 1 564 | if self.nodelay == 0: 565 | segment.rto += self.rx_rto 566 | else: 567 | segment.rto += self.rx_rto // 2 568 | segment.resendts = current + segment.rto 569 | lost = 1 570 | elif segment.fastack >= resent: 571 | # 快速重传 572 | need_send = True 573 | segment.xmit += 1 574 | segment.fastack = 0 575 | segment.resendts = current + segment.rto 576 | change += 1 577 | 578 | if need_send: 579 | segment.ts = current 580 | segment.wnd = seg.wnd 581 | segment.una = self.rcv_nxt 582 | 583 | need = IKCP_OVERHEAD + len(segment.data) 584 | if (offset + need) >= self.mtu: 585 | self.output(self.buffer, offset) 586 | offset = 0 587 | offset += segment.encode(self.buffer, offset) 588 | if len(segment.data) > 0: 589 | self.buffer[offset: offset + len(segment.data)] = segment.data[:] 590 | offset += len(segment.data) 591 | if segment.xmit >= self.dead_link: 592 | self.state = -1 593 | # flash remain segment 594 | if offset > 0: 595 | self.output(self.buffer, offset) 596 | 597 | # update ssthresh 598 | # 拥塞避免 599 | if change != 0: 600 | inflight = self.snd_nxt - self.snd_una 601 | self.ssthresh = inflight // 2 602 | if self.ssthresh < IKCP_THRESH_MIN: 603 | self.ssthresh = IKCP_THRESH_MIN 604 | self.cwnd = self.ssthresh + resent 605 | self.incr = self.cwnd * self.mss 606 | 607 | if lost != 0: 608 | self.ssthresh = self.cwnd // 2 609 | if self.ssthresh < IKCP_THRESH_MIN: 610 | self.ssthresh = IKCP_THRESH_MIN 611 | self.cwnd = 1 612 | self.incr = self.mss 613 | 614 | if self.cwnd < 1: 615 | self.cwnd = 1 616 | self.incr = self.mss 617 | 618 | def update(self, current: int): 619 | self.current = current 620 | 621 | if 0 == self.updated: 622 | self.updated = 1 623 | self.ts_flush = self.current 624 | 625 | # 两次更新间隔 626 | slap = self._itimediff(self.current, self.ts_flush) 627 | 628 | # interval设置过大或者Update调用间隔太久 629 | if (slap >= 10000) or (slap < -10000): 630 | self.ts_flush = self.current 631 | slap = 0 632 | 633 | if slap >= 0: 634 | self.ts_flush += self.interval 635 | if self._itimediff(self.current, self.ts_flush) >= 0: 636 | self.ts_flush = self.current + self.interval 637 | self.flush() 638 | 639 | def check(self, current): 640 | ts_flush = self.ts_flush 641 | tm_packet = 0x7ffffff 642 | if self.updated == 0: 643 | return current 644 | if (self._itimediff(current, ts_flush) >= 10000) or (self._itimediff(current, ts_flush) < -10000): 645 | ts_flush = current 646 | 647 | if self._itimediff(current, ts_flush) >= 0: 648 | return current 649 | tm_flush = self._itimediff(ts_flush, current) 650 | for seg in self.nsnd_buf: 651 | diff = self._itimediff(seg.resendts, current) 652 | if diff <= 0: 653 | return current 654 | if diff < tm_packet: 655 | tm_packet = diff 656 | minimal = tm_packet if (tm_packet < tm_flush) else tm_flush 657 | if minimal >= self.interval: 658 | minimal = self.interval 659 | 660 | return current + minimal 661 | 662 | def set_mtu(self, mtu): 663 | if (mtu < 50) or (mtu < IKCP_OVERHEAD): 664 | return -1 665 | self.buffer = bytes((self.mtu + IKCP_OVERHEAD) * 3) 666 | self.mtu = mtu 667 | self.mss = self.mtu - IKCP_OVERHEAD 668 | return 0 669 | 670 | def set_interval(self, interval): 671 | if interval > 5000: 672 | interval = 5000 673 | elif interval < 10: 674 | interval = 10 675 | self.interval = interval 676 | return 0 677 | 678 | def set_nodelay(self, nodelay, interval, resend, nc): 679 | if nodelay >= 0: 680 | self.nodelay = nodelay 681 | if nodelay != 0: 682 | self.rx_minrto = IKCP_RTO_NDL 683 | else: 684 | self.rx_minrto = IKCP_RTO_MIN 685 | self.set_interval(interval) 686 | if resend >= 0: 687 | self.fastresend = resend 688 | if nc >= 0: 689 | self.nocwnd = nc 690 | return 0 691 | 692 | def wnd_size(self, snd_wnd, rcv_wnd): 693 | if snd_wnd > 0: 694 | self.snd_wnd = snd_wnd 695 | if rcv_wnd > 0: 696 | self.rcv_wnd = rcv_wnd 697 | return 0 698 | 699 | def wait_snd(self): 700 | return len(self.nsnd_buf) + len(self.nsnd_que) 701 | 702 | def output(self, buffer: bytearray, size): 703 | raise NotImplementedError 704 | -------------------------------------------------------------------------------- /oldversion/KCP.pyx: -------------------------------------------------------------------------------- 1 | from cpython.bytes cimport PyBytes_FromStringAndSize 2 | 3 | cdef extern from 'stdio.h': 4 | int printf(char *format, ...); 5 | 6 | cdef extern from 'stdlib.h': 7 | void *malloc(size_t size); 8 | void free(void *ptr) 9 | 10 | cdef extern from "string.h": 11 | void *memcpy(void *str1, const void *str2, size_t n) 12 | 13 | cdef void ikcp_encode8u(char *p, int offset, int c): 14 | p[0 + offset] = c & 255 15 | 16 | cdef int ikcp_decode8u(char *p, int offset): 17 | return p[0 + offset] 18 | 19 | cdef void ikcp_encode16u(char *p, int offset, int w): 20 | p[offset + 0] = (w >> 8) & 255 21 | p[offset + 1] = (w >> 0) & 255 22 | 23 | cdef int ikcp_decode16u(char *p, int offset): 24 | return (p[0 + offset] & 0xff) << 8 | (p[1 + offset] & 0xff) 25 | 26 | cdef void ikcp_encode32u(char *p, int offset, int l): 27 | p[offset + 0] = (l >> 24) & 255 28 | p[offset + 1] = (l >> 16) & 255 29 | p[offset + 2] = (l >> 8) & 255 30 | p[offset + 3] = (l >> 0) & 255 31 | 32 | cdef int ikcp_decode32u(char *p, int offset): 33 | return (p[offset + 0] & 0xff) << 24 \ 34 | | (p[offset + 1] & 0xff) << 16 \ 35 | | (p[offset + 2] & 0xff) << 8 \ 36 | | p[offset + 3] & 0xff 37 | 38 | cdef int _imin_(int a, int b): 39 | return a if a <= b else b 40 | 41 | cdef int _imax_(int a, int b): 42 | return a if a >= b else b 43 | 44 | cdef int _ibound_(int lower, int middle, int upper): 45 | return _imin_(_imax_(lower, middle), upper) 46 | 47 | cdef int _itimediff(int later, int earlier): 48 | return later - earlier 49 | 50 | cdef class Segment: 51 | cdef public: 52 | int conv, cmd, frg, wnd, ts, sn, una, resendts, rto, fastack, xmit, size 53 | char *data 54 | 55 | def __cinit__(self, size): 56 | self.conv = 0 57 | self.cmd = 0 58 | self.frg = 0 59 | self.wnd = 0 60 | self.ts = 0 61 | self.sn = 0 62 | self.una = 0 63 | self.resendts = 0 64 | self.rto = 0 65 | self.fastack = 0 66 | self.xmit = 0 67 | self.size = size 68 | self.data = malloc(sizeof(char) * size) 69 | if self.data == NULL: 70 | raise MemoryError() 71 | 72 | def __dealloc__(self): 73 | if self.data != NULL: 74 | free(self.data) 75 | 76 | cdef int encode(self, char*ptr, int offset): 77 | cdef int _offset = offset 78 | ikcp_encode32u(ptr, offset, self.conv) 79 | offset += 4 80 | 81 | ikcp_encode8u(ptr, offset, self.cmd) 82 | offset += 1 83 | 84 | ikcp_encode8u(ptr, offset, self.frg) 85 | offset += 1 86 | 87 | ikcp_encode16u(ptr, offset, self.wnd) 88 | offset += 2 89 | 90 | ikcp_encode32u(ptr, offset, self.ts) 91 | offset += 4 92 | 93 | ikcp_encode32u(ptr, offset, self.sn) 94 | offset += 4 95 | 96 | ikcp_encode32u(ptr, offset, self.una) 97 | offset += 4 98 | 99 | ikcp_encode32u(ptr, offset, self.size) 100 | offset += 4 101 | 102 | return offset - _offset 103 | 104 | cdef int IKCP_RTO_NDL = 30 # no delay min rto 105 | cdef int IKCP_RTO_MIN = 100 # normal min rto 106 | cdef int IKCP_RTO_DEF = 200 107 | cdef int IKCP_RTO_MAX = 60000 108 | cdef int IKCP_CMD_PUSH = 81 # cmd: push data 109 | cdef int IKCP_CMD_ACK = 82 # cmd: ack 110 | cdef int IKCP_CMD_WASK = 83 # cmd: window probe (ask) 111 | cdef int IKCP_CMD_WINS = 84 # cmd: window size (tell) 112 | cdef int IKCP_ASK_SEND = 1 # need to send IKCP_CMD_WASK 113 | cdef int IKCP_ASK_TELL = 2 # need to send IKCP_CMD_WINS 114 | cdef int IKCP_WND_SND = 32 115 | cdef int IKCP_WND_RCV = 32 116 | cdef int IKCP_MTU_DEF = 1400 117 | cdef int IKCP_ACK_FAST = 3 118 | cdef int IKCP_INTERVAL = 100 119 | cdef int IKCP_OVERHEAD = 24 120 | cdef int IKCP_DEADLINK = 10 121 | cdef int IKCP_THRESH_INIT = 2 122 | cdef int IKCP_THRESH_MIN = 2 123 | cdef int IKCP_PROBE_INIT = 7000 # 7 secs to probe window size 124 | cdef int IKCP_PROBE_LIMIT = 120000 # up to 120 secs to probe window 125 | 126 | cdef class KCP: 127 | cdef: 128 | public int conv, current, state 129 | int ts_flush, ts_probe 130 | int snd_una, snd_nxt, rcv_nxt 131 | int ts_recent, ts_lastack, probe_wait 132 | int snd_wnd, rcv_wnd, rmt_wnd 133 | int cwnd, incr, probe, mtu, mss 134 | int dead_link 135 | int rx_srtt, rx_rttval, rx_rto, rx_minrto 136 | int interval, nodelay, updated, logmask, ssthresh 137 | int fastresend, nocwnd, xmit 138 | char *buffer 139 | list nrcv_buf, nsnd_buf, nrcv_que, nsnd_que, acklist 140 | object output 141 | 142 | def __cinit__(self, conv, output): 143 | self.conv = conv 144 | self.snd_una = 0 145 | self.snd_nxt = 0 146 | self.rcv_nxt = 0 147 | self.ts_recent = 0 148 | self.ts_lastack = 0 149 | self.ts_probe = 0 150 | self.probe_wait = 0 151 | self.snd_wnd = IKCP_WND_SND 152 | self.rcv_wnd = IKCP_WND_RCV 153 | self.rmt_wnd = IKCP_WND_RCV 154 | self.cwnd = 0 155 | self.incr = 0 156 | self.probe = 0 157 | self.mtu = IKCP_MTU_DEF 158 | self.mss = self.mtu - IKCP_OVERHEAD 159 | self.state = 0 160 | self.rx_srtt = 0 161 | self.rx_rttval = 0 162 | self.rx_rto = IKCP_RTO_DEF 163 | self.rx_minrto = IKCP_RTO_MIN 164 | self.current = 0 165 | self.interval = IKCP_INTERVAL 166 | self.ts_flush = IKCP_INTERVAL 167 | self.nodelay = 0 168 | self.updated = 0 169 | self.logmask = 0 170 | self.ssthresh = IKCP_THRESH_INIT 171 | self.fastresend = 0 172 | self.nocwnd = 0 173 | self.xmit = 0 174 | self.dead_link = IKCP_DEADLINK 175 | self.buffer = malloc(sizeof(char) * (self.mtu + IKCP_OVERHEAD) * 3) 176 | self.nrcv_buf = list() 177 | self.nsnd_buf = list() 178 | self.nrcv_que = list() 179 | self.nsnd_que = list() 180 | self.acklist = list() 181 | self.output = output 182 | 183 | def __dealloc__(self): 184 | free(self.buffer) 185 | 186 | cpdef int recv(self, char *buffer, int size): 187 | # 判断接受队列长度 188 | if not len(self.nrcv_que): 189 | return -1 190 | cdef int peeksize = self.peeksize() 191 | if peeksize < 0: 192 | return -2 193 | if peeksize > size: 194 | return -3 195 | cdef bint recover = False 196 | if len(self.nrcv_que) >= self.rcv_wnd: 197 | recover = True 198 | 199 | cdef int count = 0 200 | cdef int n = 0 201 | 202 | cdef Segment seg 203 | 204 | for seg in self.nrcv_que: 205 | memcpy(buffer, seg.data, seg.size) 206 | buffer += seg.size 207 | count += 1 208 | if seg.frg == 0: 209 | break 210 | 211 | if count > 0: 212 | self.nrcv_que = self.nrcv_que[count:] 213 | 214 | count = 0 215 | 216 | for seg in self.nrcv_buf: 217 | if (seg.sn == self.rcv_nxt) and (len(self.nrcv_que) < self.rcv_wnd): 218 | self.nrcv_que.append(seg) 219 | self.rcv_nxt += 1 220 | count += 1 221 | else: 222 | break 223 | 224 | if count > 0: 225 | self.nrcv_buf = self.nrcv_buf[count:] 226 | 227 | if (len(self.nrcv_que) < self.rcv_wnd) and recover: 228 | self.probe |= IKCP_ASK_TELL 229 | return 1 230 | 231 | cpdef int peeksize(self): 232 | if 0 == len(self.nrcv_que): 233 | return -1 234 | cdef Segment seg = self.nrcv_que[0] 235 | if seg.frg == 0: 236 | return seg.size 237 | if len(self.nrcv_que) < (seg.frg + 1): 238 | return -1 239 | cdef int length = 0 240 | for seg in self.nrcv_que: 241 | length += seg.size 242 | if seg.frg == 0: 243 | break 244 | return length 245 | 246 | cpdef int send(self, char *buffer, int size): 247 | cdef int idx 248 | cdef int count 249 | if size < self.mss: 250 | count = 1 251 | else: 252 | count = (size + self.mss - 1) / self.mss 253 | 254 | if count > 255: 255 | return -2 256 | 257 | if count == 0: 258 | count = 1 259 | 260 | cdef int i, seg_size 261 | cdef Segment seg 262 | 263 | for i in range(count): 264 | seg_size = self.mss if (size > self.mss) else size 265 | seg = Segment(seg_size) 266 | memcpy(seg.data, buffer, seg_size) 267 | buffer += seg_size 268 | seg.frg = count - i - 1 269 | self.nsnd_que.append(seg) 270 | size -= seg_size 271 | return 0 272 | 273 | cdef void update_ack(self, int rtt): 274 | """parse ack""" 275 | if self.rx_srtt == 0: 276 | self.rx_srtt = rtt 277 | self.rx_rttval = rtt // 2 278 | else: 279 | delta = rtt - self.rx_srtt 280 | if delta < 0: 281 | delta = -delta 282 | self.rx_rttval = (3 * self.rx_rttval + delta) // 4 283 | self.rx_srtt = (7 * self.rx_srtt + rtt) // 8 284 | if self.rx_srtt < 1: 285 | self.rx_srtt = 1 286 | rto = self.rx_srtt + _imax_(1, 4 * self.rx_rttval) 287 | self.rx_rto = _ibound_(self.rx_minrto, rto, IKCP_RTO_MAX) 288 | 289 | cdef void shrink_buf(self): 290 | """计算本地真实snd_una""" 291 | if len(self.nsnd_buf) > 0: 292 | self.snd_una = self.nsnd_buf[0].sn 293 | else: 294 | self.snd_una = self.snd_nxt 295 | 296 | cdef void parse_ack(self, int sn): 297 | """对端返回的ack,确认发送成功时,对应包从发送缓存中移除""" 298 | if (_itimediff(sn, self.snd_una) < 0) or (_itimediff(sn, self.snd_nxt) >= 0): 299 | return 300 | cdef int index = 0 301 | cdef Segment segment 302 | for segment in self.nsnd_buf: 303 | if _itimediff(sn, segment.sn) < 0: 304 | break 305 | segment.fastack += 1 306 | if sn == segment.sn: 307 | self.nsnd_buf.pop(index) 308 | break 309 | index += 1 310 | 311 | cdef parse_una(self, int una): 312 | """通过对端传回的una将已经确认发送成功的包从发送缓存中移除""" 313 | count = 0 314 | for segment in self.nsnd_buf: 315 | if _itimediff(una, segment.sn) > 0: 316 | count += 1 317 | else: 318 | break 319 | if count > 0: 320 | self.nsnd_buf = self.nsnd_buf[count:] 321 | 322 | cdef ack_push(self, int sn, int ts): 323 | """收到数据包之后,将对应ack返回,flush时发送""" 324 | self.acklist.append(sn) 325 | self.acklist.append(ts) 326 | 327 | cdef parse_data(self, Segment new_segment): 328 | """用户数据包解析""" 329 | cdef int sn = new_segment.sn 330 | cdef bint repeat = False 331 | cdef int after_idx = -1 332 | 333 | if (_itimediff(sn, self.rcv_nxt + self.rcv_wnd) >= 0) or (_itimediff(sn, self.rcv_nxt) < 0): 334 | return 335 | n = len(self.nrcv_buf) - 1 336 | 337 | # 判断是否重复包,同时计算插入位置 338 | cdef int i 339 | cdef Segment segment 340 | for i in range(n, -1, -1): 341 | segment = self.nrcv_buf[i] 342 | if segment.sn == sn: 343 | repeat = True 344 | break 345 | if _itimediff(sn, segment.sn) > 0: 346 | after_idx = i 347 | break 348 | 349 | if not repeat: 350 | self.nrcv_buf.insert(after_idx + 1, new_segment) 351 | 352 | # 将连续包加入到接受队列 353 | cdef int count = 0 354 | for segment in self.nrcv_buf: 355 | if (segment.sn == self.rcv_nxt) and (len(self.nrcv_que) < self.rcv_wnd): 356 | self.nrcv_que.append(segment) 357 | self.rcv_nxt += 1 358 | count += 1 359 | else: 360 | break 361 | 362 | # 从接受缓存中移除 363 | if count > 0: 364 | self.nrcv_buf = self.nrcv_buf[count:] 365 | 366 | cpdef input(self, char *data, int size): 367 | cdef int s_una = self.snd_una 368 | if size < IKCP_OVERHEAD: 369 | return 0 370 | cdef int offset 371 | cdef int cmd, frg, wnd, ts, sn, una, length 372 | cdef Segment segment 373 | offset = 0 374 | while True: 375 | """解析data""" 376 | if (size - offset) < IKCP_OVERHEAD: 377 | break 378 | conv = ikcp_decode32u(data, offset) 379 | offset += 4 380 | if self.conv != conv: 381 | return -1 382 | cmd = ikcp_decode8u(data, offset) 383 | offset += 1 384 | frg = ikcp_decode8u(data, offset) 385 | offset += 1 386 | wnd = ikcp_decode16u(data, offset) 387 | offset += 2 388 | ts = ikcp_decode32u(data, offset) 389 | offset += 4 390 | sn = ikcp_decode32u(data, offset) 391 | offset += 4 392 | una = ikcp_decode32u(data, offset) 393 | offset += 4 394 | length = ikcp_decode32u(data, offset) 395 | offset += 4 396 | """长度不对""" 397 | if (size - offset) < length: 398 | return -2 399 | data += offset 400 | if ( 401 | cmd != IKCP_CMD_PUSH 402 | and cmd != IKCP_CMD_ACK 403 | and cmd != IKCP_CMD_WASK 404 | and cmd != IKCP_CMD_WINS 405 | ): 406 | return -3 407 | self.rmt_wnd = wnd 408 | self.parse_una(una) 409 | self.shrink_buf() 410 | 411 | if IKCP_CMD_ACK == cmd: 412 | """ack 包""" 413 | if _itimediff(self.current, ts) >= 0: 414 | self.update_ack(_itimediff(self.current, ts)) 415 | self.parse_ack(sn) 416 | self.shrink_buf() 417 | elif IKCP_CMD_PUSH == cmd: 418 | """数据包""" 419 | if _itimediff(sn, self.rcv_nxt + self.rcv_wnd) < 0: 420 | self.ack_push(sn, ts) 421 | if _itimediff(sn, self.rcv_nxt) >= 0: 422 | segment = Segment(length) 423 | segment.conv = conv 424 | segment.cmd = cmd 425 | segment.frg = frg 426 | segment.wnd = wnd 427 | segment.ts = ts 428 | segment.sn = sn 429 | segment.una = una 430 | if length > 0: 431 | memcpy(segment.data, data, offset + length) 432 | data += length 433 | self.parse_data(segment) 434 | elif IKCP_CMD_WASK == cmd: 435 | self.probe |= IKCP_ASK_TELL 436 | elif IKCP_CMD_WINS == cmd: 437 | pass 438 | else: 439 | return -3 440 | if _itimediff(self.snd_una, s_una) > 0: 441 | if self.cwnd < self.rmt_wnd: 442 | mss = self.mss 443 | if self.cwnd < self.ssthresh: 444 | self.cwnd += 1 445 | self.incr += mss 446 | else: 447 | if self.incr < mss: 448 | self.incr = mss 449 | self.incr += (mss * mss) // self.incr + (mss // 16) 450 | if (self.cwnd + 1) * mss <= self.incr: 451 | self.cwnd += 1 452 | if self.cwnd > self.rmt_wnd: 453 | self.cwnd = self.rmt_wnd 454 | self.incr = self.rmt_wnd * mss 455 | return 0 456 | 457 | cdef int wnd_unused(self): 458 | if len(self.nrcv_que) < self.rcv_wnd: 459 | return self.rcv_wnd - len(self.nrcv_que) 460 | return 0 461 | 462 | cdef void flush(self): 463 | cdef int current 464 | cdef int change, lost 465 | current = self.current 466 | change = 0 467 | lost = 0 468 | cdef char*buffer 469 | 470 | if self.updated == 0: 471 | return 472 | cdef Segment seg = Segment(0) 473 | seg.conv = self.conv 474 | seg.cmd = IKCP_CMD_ACK 475 | seg.wnd = self.wnd_unused() 476 | seg.una = self.rcv_nxt 477 | 478 | cdef int count, offset, i 479 | count = len(self.acklist) // 2 480 | offset = 0 481 | for i in range(count): 482 | if (offset + IKCP_OVERHEAD) > self.mtu: 483 | self.ikcp_output(self.buffer, offset) 484 | offset = 0 485 | seg.sn = self.acklist[i * 2] 486 | seg.ts = self.acklist[i * 2 + 1] 487 | offset += seg.encode(self.buffer, offset) 488 | self.acklist.clear() 489 | 490 | # 判断是否需要请求对端接受窗口 491 | if 0 == self.rmt_wnd: 492 | if 0 == self.probe_wait: 493 | self.probe_wait = IKCP_PROBE_INIT 494 | self.ts_probe = self.current + self.probe_wait 495 | else: 496 | # 逐步扩大请求时间间隔 497 | if _itimediff(self.current, self.ts_probe) >= 0: 498 | if self.probe_wait < IKCP_PROBE_INIT: 499 | self.probe_wait = IKCP_PROBE_INIT 500 | 501 | self.probe_wait += self.probe_wait / 2 502 | if self.probe_wait > IKCP_PROBE_LIMIT: 503 | self.probe_wait = IKCP_PROBE_LIMIT 504 | self.ts_probe = self.current + self.probe_wait 505 | self.probe |= IKCP_ASK_SEND 506 | else: 507 | self.ts_probe = 0 508 | self.probe_wait = 0 509 | 510 | # 请求对端接受窗口 511 | if (self.probe & IKCP_ASK_SEND) != 0: 512 | seg.cmd = IKCP_CMD_WASK 513 | if (offset + IKCP_OVERHEAD) > self.mtu: 514 | self.ikcp_output(self.buffer, offset) 515 | offset = 0 516 | offset += seg.encode(self.buffer, offset) 517 | 518 | # 告诉对端自己的接受窗口 519 | if (self.probe & IKCP_ASK_TELL) != 0: 520 | seg.cmd = IKCP_CMD_WINS 521 | if (offset + IKCP_OVERHEAD) > self.mtu: 522 | self.ikcp_output(self.buffer, offset) 523 | offset = 0 524 | offset += seg.encode(self.buffer, offset) 525 | 526 | self.probe = 0 527 | 528 | # 计算 window size 529 | cdef int cwnd = _imin_(self.snd_wnd, self.rmt_wnd) 530 | 531 | # 如果采用拥塞控制 532 | if self.nocwnd == 0: 533 | cwnd = _imin_(self.cwnd, cwnd) 534 | 535 | count = 0 536 | 537 | # move data from snd_queue to snd_buf 538 | cdef Segment new_segment, nsnd_que_item 539 | for nsnd_que_item in self.nsnd_que: 540 | if (_itimediff(self.snd_nxt, self.snd_una + cwnd)) >= 0: 541 | break 542 | 543 | new_segment = nsnd_que_item 544 | new_segment.conv = self.conv 545 | new_segment.cmd = IKCP_CMD_PUSH 546 | new_segment.wnd = seg.wnd 547 | new_segment.ts = current 548 | new_segment.sn = self.snd_nxt 549 | new_segment.una = self.rcv_nxt 550 | new_segment.resendts = current 551 | new_segment.rto = self.rx_rto 552 | new_segment.fastack = 0 553 | new_segment.xmit = 0 554 | self.nsnd_buf.append(new_segment) 555 | self.snd_nxt += 1 556 | count += 1 557 | 558 | if count > 0: 559 | self.nsnd_que = self.nsnd_que[count:] 560 | 561 | # calculate resent 562 | cdef int resent, rtomin 563 | resent = self.fastresend if (self.fastresend > 0) else 0xffffffff 564 | rtomin = (self.rx_rto >> 3) if (self.nodelay == 0) else 0 565 | 566 | # flush data segment 567 | cdef Segment segment 568 | cdef bint need_send 569 | for segment in self.nsnd_buf: 570 | need_send = False 571 | if segment.xmit == 0: 572 | # 第一次传输 573 | need_send = True 574 | segment.xmit += 1 575 | segment.rto = self.rx_rto 576 | segment.resendts = current + segment.rto + rtomin 577 | elif _itimediff(current, segment.resendts) >= 0: 578 | # 丢包重传 579 | need_send = True 580 | segment.xmit += 1 581 | self.xmit += 1 582 | if self.nodelay == 0: 583 | segment.rto += self.rx_rto 584 | else: 585 | segment.rto += self.rx_rto / 2 586 | segment.resendts = current + segment.rto 587 | lost = 1 588 | elif segment.fastack >= resent: 589 | # 快速重传 590 | need_send = True 591 | segment.xmit += 1 592 | segment.fastack = 0 593 | segment.resendts = current + segment.rto 594 | change += 1 595 | 596 | if need_send: 597 | segment.ts = current 598 | segment.wnd = seg.wnd 599 | segment.una = self.rcv_nxt 600 | 601 | need = IKCP_OVERHEAD + segment.size 602 | if (offset + need) >= self.mtu: 603 | self.ikcp_output(self.buffer, offset) 604 | offset = 0 605 | offset += segment.encode(self.buffer, offset) 606 | 607 | if segment.size > 0: 608 | buffer = self.buffer + offset 609 | memcpy(buffer, segment.data, segment.size) 610 | offset += segment.size 611 | if segment.xmit >= self.dead_link: 612 | self.state = -1 613 | 614 | # flash remain segment 615 | if offset > 0: 616 | self.ikcp_output(self.buffer, offset) 617 | 618 | # update ssthresh 619 | # 拥塞避免 620 | 621 | cdef int inflight 622 | if change != 0: 623 | inflight = self.snd_nxt - self.snd_una 624 | self.ssthresh = inflight / 2 625 | if self.ssthresh < IKCP_THRESH_MIN: 626 | self.ssthresh = IKCP_THRESH_MIN 627 | self.cwnd = self.ssthresh + resent 628 | self.incr = self.cwnd * self.mss 629 | 630 | if lost != 0: 631 | self.ssthresh = self.cwnd / 2 632 | if self.ssthresh < IKCP_THRESH_MIN: 633 | self.ssthresh = IKCP_THRESH_MIN 634 | self.cwnd = 1 635 | self.incr = self.mss 636 | 637 | if self.cwnd < 1: 638 | self.cwnd = 1 639 | self.incr = self.mss 640 | 641 | cpdef update(self, int current): 642 | self.current = current 643 | 644 | if 0 == self.updated: 645 | self.updated = 1 646 | self.ts_flush = self.current 647 | 648 | # 两次更新间隔 649 | cdef int slap = _itimediff(self.current, self.ts_flush) 650 | 651 | # interval设置过大或者Update调用间隔太久 652 | if (slap >= 10000) or (slap < -10000): 653 | self.ts_flush = self.current 654 | slap = 0 655 | 656 | if slap >= 0: 657 | self.ts_flush += self.interval 658 | if _itimediff(self.current, self.ts_flush) >= 0: 659 | self.ts_flush = self.current + self.interval 660 | self.flush() 661 | 662 | cpdef int check(self, current): 663 | cdef int ts_flush = self.ts_flush 664 | cdef int tm_packet = 0x7ffffff 665 | cdef int tm_flush 666 | if self.updated == 0: 667 | return current 668 | if (_itimediff(current, ts_flush) >= 10000) or (_itimediff(current, ts_flush) < -10000): 669 | ts_flush = current 670 | 671 | if _itimediff(current, ts_flush) >= 0: 672 | return current 673 | tm_flush = _itimediff(ts_flush, current) 674 | cdef Segment seg 675 | for seg in self.nsnd_buf: 676 | diff = _itimediff(seg.resendts, current) 677 | if diff <= 0: 678 | return current 679 | if diff < tm_packet: 680 | tm_packet = diff 681 | minimal = tm_packet if (tm_packet < tm_flush) else tm_flush 682 | if minimal >= self.interval: 683 | minimal = self.interval 684 | return current + minimal 685 | 686 | cpdef bint set_mtu(self, int mtu): 687 | if (mtu < 50) or (mtu < IKCP_OVERHEAD): 688 | return False 689 | self.mtu = mtu 690 | self.mss = self.mtu - IKCP_OVERHEAD 691 | free(self.buffer) 692 | cdef char *buffer = malloc(sizeof(char) * (self.mtu + IKCP_OVERHEAD) * 3) 693 | if buffer == NULL: 694 | raise MemoryError() 695 | self.buffer = buffer 696 | return 0 697 | 698 | cpdef int set_interval(self, int interval): 699 | if interval > 5000: 700 | interval = 5000 701 | elif interval < 10: 702 | interval = 10 703 | self.interval = interval 704 | return 0 705 | 706 | cpdef bint set_nodelay(self, int nodelay, int interval, int resend, int nc): 707 | if nodelay >= 0: 708 | self.nodelay = nodelay 709 | if nodelay != 0: 710 | self.rx_minrto = IKCP_RTO_NDL 711 | else: 712 | self.rx_minrto = IKCP_RTO_MIN 713 | self.set_interval(interval) 714 | if resend >= 0: 715 | self.fastresend = resend 716 | if nc >= 0: 717 | self.nocwnd = nc 718 | return True 719 | 720 | cpdef bint wnd_size(self, int snd_wnd, int rcv_wnd): 721 | if snd_wnd > 0: 722 | self.snd_wnd = snd_wnd 723 | if rcv_wnd > 0: 724 | self.rcv_wnd = rcv_wnd 725 | return True 726 | 727 | cpdef int wait_snd(self): 728 | return len(self.nsnd_buf) + len(self.nsnd_que) 729 | 730 | cpdef ikcp_output(self, char *buffer, int size): 731 | self.output(PyBytes_FromStringAndSize(buffer, size), size) 732 | -------------------------------------------------------------------------------- /ikcp/ikcp.c: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // KCP - A Better ARQ Protocol Implementation 4 | // skywind3000 (at) gmail.com, 2010-2011 5 | // 6 | // Features: 7 | // + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. 8 | // + Maximum RTT reduce three times vs tcp. 9 | // + Lightweight, distributed as a single source file. 10 | // 11 | //===================================================================== 12 | #include "ikcp.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | 22 | //===================================================================== 23 | // KCP BASIC 24 | //===================================================================== 25 | const IUINT32 IKCP_RTO_NDL = 30; // no delay min rto 26 | const IUINT32 IKCP_RTO_MIN = 100; // normal min rto 27 | const IUINT32 IKCP_RTO_DEF = 200; 28 | const IUINT32 IKCP_RTO_MAX = 60000; 29 | const IUINT32 IKCP_CMD_PUSH = 81; // cmd: push data 30 | const IUINT32 IKCP_CMD_ACK = 82; // cmd: ack 31 | const IUINT32 IKCP_CMD_WASK = 83; // cmd: window probe (ask) 32 | const IUINT32 IKCP_CMD_WINS = 84; // cmd: window size (tell) 33 | const IUINT32 IKCP_ASK_SEND = 1; // need to send IKCP_CMD_WASK 34 | const IUINT32 IKCP_ASK_TELL = 2; // need to send IKCP_CMD_WINS 35 | const IUINT32 IKCP_WND_SND = 32; 36 | const IUINT32 IKCP_WND_RCV = 128; // must >= max fragment size 37 | const IUINT32 IKCP_MTU_DEF = 1400; 38 | const IUINT32 IKCP_ACK_FAST = 3; 39 | const IUINT32 IKCP_INTERVAL = 100; 40 | const IUINT32 IKCP_OVERHEAD = 24; 41 | const IUINT32 IKCP_DEADLINK = 20; 42 | const IUINT32 IKCP_THRESH_INIT = 2; 43 | const IUINT32 IKCP_THRESH_MIN = 2; 44 | const IUINT32 IKCP_PROBE_INIT = 7000; // 7 secs to probe window size 45 | const IUINT32 IKCP_PROBE_LIMIT = 120000; // up to 120 secs to probe window 46 | 47 | 48 | //--------------------------------------------------------------------- 49 | // encode / decode 50 | //--------------------------------------------------------------------- 51 | 52 | /* encode 8 bits unsigned int */ 53 | static inline char *ikcp_encode8u(char *p, unsigned char c) 54 | { 55 | *(unsigned char*)p++ = c; 56 | return p; 57 | } 58 | 59 | /* decode 8 bits unsigned int */ 60 | static inline const char *ikcp_decode8u(const char *p, unsigned char *c) 61 | { 62 | *c = *(unsigned char*)p++; 63 | return p; 64 | } 65 | 66 | /* encode 16 bits unsigned int (lsb) */ 67 | static inline char *ikcp_encode16u(char *p, unsigned short w) 68 | { 69 | #if IWORDS_BIG_ENDIAN 70 | *(unsigned char*)(p + 0) = (w & 255); 71 | *(unsigned char*)(p + 1) = (w >> 8); 72 | #else 73 | *(unsigned short*)(p) = w; 74 | #endif 75 | p += 2; 76 | return p; 77 | } 78 | 79 | /* decode 16 bits unsigned int (lsb) */ 80 | static inline const char *ikcp_decode16u(const char *p, unsigned short *w) 81 | { 82 | #if IWORDS_BIG_ENDIAN 83 | *w = *(const unsigned char*)(p + 1); 84 | *w = *(const unsigned char*)(p + 0) + (*w << 8); 85 | #else 86 | *w = *(const unsigned short*)p; 87 | #endif 88 | p += 2; 89 | return p; 90 | } 91 | 92 | /* encode 32 bits unsigned int (lsb) */ 93 | static inline char *ikcp_encode32u(char *p, IUINT32 l) 94 | { 95 | #if IWORDS_BIG_ENDIAN 96 | *(unsigned char*)(p + 0) = (unsigned char)((l >> 0) & 0xff); 97 | *(unsigned char*)(p + 1) = (unsigned char)((l >> 8) & 0xff); 98 | *(unsigned char*)(p + 2) = (unsigned char)((l >> 16) & 0xff); 99 | *(unsigned char*)(p + 3) = (unsigned char)((l >> 24) & 0xff); 100 | #else 101 | *(IUINT32*)p = l; 102 | #endif 103 | p += 4; 104 | return p; 105 | } 106 | 107 | /* decode 32 bits unsigned int (lsb) */ 108 | static inline const char *ikcp_decode32u(const char *p, IUINT32 *l) 109 | { 110 | #if IWORDS_BIG_ENDIAN 111 | *l = *(const unsigned char*)(p + 3); 112 | *l = *(const unsigned char*)(p + 2) + (*l << 8); 113 | *l = *(const unsigned char*)(p + 1) + (*l << 8); 114 | *l = *(const unsigned char*)(p + 0) + (*l << 8); 115 | #else 116 | *l = *(const IUINT32*)p; 117 | #endif 118 | p += 4; 119 | return p; 120 | } 121 | 122 | static inline IUINT32 _imin_(IUINT32 a, IUINT32 b) { 123 | return a <= b ? a : b; 124 | } 125 | 126 | static inline IUINT32 _imax_(IUINT32 a, IUINT32 b) { 127 | return a >= b ? a : b; 128 | } 129 | 130 | static inline IUINT32 _ibound_(IUINT32 lower, IUINT32 middle, IUINT32 upper) 131 | { 132 | return _imin_(_imax_(lower, middle), upper); 133 | } 134 | 135 | static inline long _itimediff(IUINT32 later, IUINT32 earlier) 136 | { 137 | return ((IINT32)(later - earlier)); 138 | } 139 | 140 | //--------------------------------------------------------------------- 141 | // manage segment 142 | //--------------------------------------------------------------------- 143 | typedef struct IKCPSEG IKCPSEG; 144 | 145 | static void* (*ikcp_malloc_hook)(size_t) = NULL; 146 | static void (*ikcp_free_hook)(void *) = NULL; 147 | 148 | // internal malloc 149 | static void* ikcp_malloc(size_t size) { 150 | if (ikcp_malloc_hook) 151 | return ikcp_malloc_hook(size); 152 | return malloc(size); 153 | } 154 | 155 | // internal free 156 | static void ikcp_free(void *ptr) { 157 | if (ikcp_free_hook) { 158 | ikcp_free_hook(ptr); 159 | } else { 160 | free(ptr); 161 | } 162 | } 163 | 164 | // redefine allocator 165 | void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)) 166 | { 167 | ikcp_malloc_hook = new_malloc; 168 | ikcp_free_hook = new_free; 169 | } 170 | 171 | // allocate a new kcp segment 172 | static IKCPSEG* ikcp_segment_new(ikcpcb *kcp, int size) 173 | { 174 | return (IKCPSEG*)ikcp_malloc(sizeof(IKCPSEG) + size); 175 | } 176 | 177 | // delete a segment 178 | static void ikcp_segment_delete(ikcpcb *kcp, IKCPSEG *seg) 179 | { 180 | ikcp_free(seg); 181 | } 182 | 183 | // write log 184 | void ikcp_log(ikcpcb *kcp, int mask, const char *fmt, ...) 185 | { 186 | char buffer[1024]; 187 | va_list argptr; 188 | if ((mask & kcp->logmask) == 0 || kcp->writelog == 0) return; 189 | va_start(argptr, fmt); 190 | vsprintf(buffer, fmt, argptr); 191 | va_end(argptr); 192 | kcp->writelog(buffer, kcp, kcp->user); 193 | } 194 | 195 | // check log mask 196 | static int ikcp_canlog(const ikcpcb *kcp, int mask) 197 | { 198 | if ((mask & kcp->logmask) == 0 || kcp->writelog == NULL) return 0; 199 | return 1; 200 | } 201 | 202 | // output segment 203 | static int ikcp_output(ikcpcb *kcp, const void *data, int size) 204 | { 205 | assert(kcp); 206 | assert(kcp->output); 207 | if (ikcp_canlog(kcp, IKCP_LOG_OUTPUT)) { 208 | ikcp_log(kcp, IKCP_LOG_OUTPUT, "[RO] %ld bytes", (long)size); 209 | } 210 | if (size == 0) return 0; 211 | return kcp->output((const char*)data, size, kcp, kcp->user); 212 | } 213 | 214 | // output queue 215 | void ikcp_qprint(const char *name, const struct IQUEUEHEAD *head) 216 | { 217 | #if 0 218 | const struct IQUEUEHEAD *p; 219 | printf("<%s>: [", name); 220 | for (p = head->next; p != head; p = p->next) { 221 | const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node); 222 | printf("(%lu %d)", (unsigned long)seg->sn, (int)(seg->ts % 10000)); 223 | if (p->next != head) printf(","); 224 | } 225 | printf("]\n"); 226 | #endif 227 | } 228 | 229 | 230 | //--------------------------------------------------------------------- 231 | // create a new kcpcb 232 | //--------------------------------------------------------------------- 233 | ikcpcb* ikcp_create(IUINT32 conv, void *user) 234 | { 235 | ikcpcb *kcp = (ikcpcb*)ikcp_malloc(sizeof(struct IKCPCB)); 236 | if (kcp == NULL) return NULL; 237 | kcp->conv = conv; 238 | kcp->user = user; 239 | kcp->snd_una = 0; 240 | kcp->snd_nxt = 0; 241 | kcp->rcv_nxt = 0; 242 | kcp->ts_recent = 0; 243 | kcp->ts_lastack = 0; 244 | kcp->ts_probe = 0; 245 | kcp->probe_wait = 0; 246 | kcp->snd_wnd = IKCP_WND_SND; 247 | kcp->rcv_wnd = IKCP_WND_RCV; 248 | kcp->rmt_wnd = IKCP_WND_RCV; 249 | kcp->cwnd = 0; 250 | kcp->incr = 0; 251 | kcp->probe = 0; 252 | kcp->mtu = IKCP_MTU_DEF; 253 | kcp->mss = kcp->mtu - IKCP_OVERHEAD; 254 | kcp->stream = 0; 255 | 256 | kcp->buffer = (char*)ikcp_malloc((kcp->mtu + IKCP_OVERHEAD) * 3); 257 | if (kcp->buffer == NULL) { 258 | ikcp_free(kcp); 259 | return NULL; 260 | } 261 | 262 | iqueue_init(&kcp->snd_queue); 263 | iqueue_init(&kcp->rcv_queue); 264 | iqueue_init(&kcp->snd_buf); 265 | iqueue_init(&kcp->rcv_buf); 266 | kcp->nrcv_buf = 0; 267 | kcp->nsnd_buf = 0; 268 | kcp->nrcv_que = 0; 269 | kcp->nsnd_que = 0; 270 | kcp->state = 0; 271 | kcp->acklist = NULL; 272 | kcp->ackblock = 0; 273 | kcp->ackcount = 0; 274 | kcp->rx_srtt = 0; 275 | kcp->rx_rttval = 0; 276 | kcp->rx_rto = IKCP_RTO_DEF; 277 | kcp->rx_minrto = IKCP_RTO_MIN; 278 | kcp->current = 0; 279 | kcp->interval = IKCP_INTERVAL; 280 | kcp->ts_flush = IKCP_INTERVAL; 281 | kcp->nodelay = 0; 282 | kcp->updated = 0; 283 | kcp->logmask = 0; 284 | kcp->ssthresh = IKCP_THRESH_INIT; 285 | kcp->fastresend = 0; 286 | kcp->nocwnd = 0; 287 | kcp->xmit = 0; 288 | kcp->dead_link = IKCP_DEADLINK; 289 | kcp->output = NULL; 290 | kcp->writelog = NULL; 291 | 292 | return kcp; 293 | } 294 | 295 | 296 | //--------------------------------------------------------------------- 297 | // release a new kcpcb 298 | //--------------------------------------------------------------------- 299 | void ikcp_release(ikcpcb *kcp) 300 | { 301 | assert(kcp); 302 | if (kcp) { 303 | IKCPSEG *seg; 304 | while (!iqueue_is_empty(&kcp->snd_buf)) { 305 | seg = iqueue_entry(kcp->snd_buf.next, IKCPSEG, node); 306 | iqueue_del(&seg->node); 307 | ikcp_segment_delete(kcp, seg); 308 | } 309 | while (!iqueue_is_empty(&kcp->rcv_buf)) { 310 | seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); 311 | iqueue_del(&seg->node); 312 | ikcp_segment_delete(kcp, seg); 313 | } 314 | while (!iqueue_is_empty(&kcp->snd_queue)) { 315 | seg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node); 316 | iqueue_del(&seg->node); 317 | ikcp_segment_delete(kcp, seg); 318 | } 319 | while (!iqueue_is_empty(&kcp->rcv_queue)) { 320 | seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node); 321 | iqueue_del(&seg->node); 322 | ikcp_segment_delete(kcp, seg); 323 | } 324 | if (kcp->buffer) { 325 | ikcp_free(kcp->buffer); 326 | } 327 | if (kcp->acklist) { 328 | ikcp_free(kcp->acklist); 329 | } 330 | 331 | kcp->nrcv_buf = 0; 332 | kcp->nsnd_buf = 0; 333 | kcp->nrcv_que = 0; 334 | kcp->nsnd_que = 0; 335 | kcp->ackcount = 0; 336 | kcp->buffer = NULL; 337 | kcp->acklist = NULL; 338 | ikcp_free(kcp); 339 | } 340 | } 341 | 342 | 343 | //--------------------------------------------------------------------- 344 | // set output callback, which will be invoked by kcp 345 | //--------------------------------------------------------------------- 346 | void ikcp_setoutput(ikcpcb *kcp, int (*output)(const char *buf, int len, 347 | ikcpcb *kcp, void *user)) 348 | { 349 | kcp->output = output; 350 | } 351 | 352 | 353 | //--------------------------------------------------------------------- 354 | // user/upper level recv: returns size, returns below zero for EAGAIN 355 | //--------------------------------------------------------------------- 356 | int ikcp_recv(ikcpcb *kcp, char *buffer, int len) 357 | { 358 | struct IQUEUEHEAD *p; 359 | int ispeek = (len < 0)? 1 : 0; 360 | int peeksize; 361 | int recover = 0; 362 | IKCPSEG *seg; 363 | assert(kcp); 364 | 365 | if (iqueue_is_empty(&kcp->rcv_queue)) 366 | return -1; 367 | 368 | if (len < 0) len = -len; 369 | 370 | peeksize = ikcp_peeksize(kcp); 371 | 372 | if (peeksize < 0) 373 | return -2; 374 | 375 | if (peeksize > len) 376 | return -3; 377 | 378 | if (kcp->nrcv_que >= kcp->rcv_wnd) 379 | recover = 1; 380 | 381 | // merge fragment 382 | for (len = 0, p = kcp->rcv_queue.next; p != &kcp->rcv_queue; ) { 383 | int fragment; 384 | seg = iqueue_entry(p, IKCPSEG, node); 385 | p = p->next; 386 | 387 | if (buffer) { 388 | memcpy(buffer, seg->data, seg->len); 389 | buffer += seg->len; 390 | } 391 | 392 | len += seg->len; 393 | fragment = seg->frg; 394 | 395 | if (ikcp_canlog(kcp, IKCP_LOG_RECV)) { 396 | ikcp_log(kcp, IKCP_LOG_RECV, "recv sn=%lu", seg->sn); 397 | } 398 | 399 | if (ispeek == 0) { 400 | iqueue_del(&seg->node); 401 | ikcp_segment_delete(kcp, seg); 402 | kcp->nrcv_que--; 403 | } 404 | 405 | if (fragment == 0) 406 | break; 407 | } 408 | 409 | assert(len == peeksize); 410 | 411 | // move available data from rcv_buf -> rcv_queue 412 | while (! iqueue_is_empty(&kcp->rcv_buf)) { 413 | IKCPSEG *seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); 414 | if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) { 415 | iqueue_del(&seg->node); 416 | kcp->nrcv_buf--; 417 | iqueue_add_tail(&seg->node, &kcp->rcv_queue); 418 | kcp->nrcv_que++; 419 | kcp->rcv_nxt++; 420 | } else { 421 | break; 422 | } 423 | } 424 | 425 | // fast recover 426 | if (kcp->nrcv_que < kcp->rcv_wnd && recover) { 427 | // ready to send back IKCP_CMD_WINS in ikcp_flush 428 | // tell remote my window size 429 | kcp->probe |= IKCP_ASK_TELL; 430 | } 431 | 432 | return len; 433 | } 434 | 435 | 436 | //--------------------------------------------------------------------- 437 | // peek data size 438 | //--------------------------------------------------------------------- 439 | int ikcp_peeksize(const ikcpcb *kcp) 440 | { 441 | struct IQUEUEHEAD *p; 442 | IKCPSEG *seg; 443 | int length = 0; 444 | 445 | assert(kcp); 446 | 447 | if (iqueue_is_empty(&kcp->rcv_queue)) return -1; 448 | 449 | seg = iqueue_entry(kcp->rcv_queue.next, IKCPSEG, node); 450 | if (seg->frg == 0) return seg->len; 451 | 452 | if (kcp->nrcv_que < seg->frg + 1) return -1; 453 | 454 | for (p = kcp->rcv_queue.next; p != &kcp->rcv_queue; p = p->next) { 455 | seg = iqueue_entry(p, IKCPSEG, node); 456 | length += seg->len; 457 | if (seg->frg == 0) break; 458 | } 459 | 460 | return length; 461 | } 462 | 463 | 464 | //--------------------------------------------------------------------- 465 | // user/upper level send, returns below zero for error 466 | //--------------------------------------------------------------------- 467 | int ikcp_send(ikcpcb *kcp, const char *buffer, int len) 468 | { 469 | IKCPSEG *seg; 470 | int count, i; 471 | 472 | assert(kcp->mss > 0); 473 | if (len < 0) return -1; 474 | 475 | // append to previous segment in streaming mode (if possible) 476 | if (kcp->stream != 0) { 477 | if (!iqueue_is_empty(&kcp->snd_queue)) { 478 | IKCPSEG *old = iqueue_entry(kcp->snd_queue.prev, IKCPSEG, node); 479 | if (old->len < kcp->mss) { 480 | int capacity = kcp->mss - old->len; 481 | int extend = (len < capacity)? len : capacity; 482 | seg = ikcp_segment_new(kcp, old->len + extend); 483 | assert(seg); 484 | if (seg == NULL) { 485 | return -2; 486 | } 487 | iqueue_add_tail(&seg->node, &kcp->snd_queue); 488 | memcpy(seg->data, old->data, old->len); 489 | if (buffer) { 490 | memcpy(seg->data + old->len, buffer, extend); 491 | buffer += extend; 492 | } 493 | seg->len = old->len + extend; 494 | seg->frg = 0; 495 | len -= extend; 496 | iqueue_del_init(&old->node); 497 | ikcp_segment_delete(kcp, old); 498 | } 499 | } 500 | if (len <= 0) { 501 | return 0; 502 | } 503 | } 504 | 505 | if (len <= (int)kcp->mss) count = 1; 506 | else count = (len + kcp->mss - 1) / kcp->mss; 507 | 508 | if (count >= IKCP_WND_RCV) return -2; 509 | 510 | if (count == 0) count = 1; 511 | 512 | // fragment 513 | for (i = 0; i < count; i++) { 514 | int size = len > (int)kcp->mss ? (int)kcp->mss : len; 515 | seg = ikcp_segment_new(kcp, size); 516 | assert(seg); 517 | if (seg == NULL) { 518 | return -2; 519 | } 520 | if (buffer && len > 0) { 521 | memcpy(seg->data, buffer, size); 522 | } 523 | seg->len = size; 524 | seg->frg = (kcp->stream == 0)? (count - i - 1) : 0; 525 | iqueue_init(&seg->node); 526 | iqueue_add_tail(&seg->node, &kcp->snd_queue); 527 | kcp->nsnd_que++; 528 | if (buffer) { 529 | buffer += size; 530 | } 531 | len -= size; 532 | } 533 | 534 | return 0; 535 | } 536 | 537 | 538 | //--------------------------------------------------------------------- 539 | // parse ack 540 | //--------------------------------------------------------------------- 541 | static void ikcp_update_ack(ikcpcb *kcp, IINT32 rtt) 542 | { 543 | IINT32 rto = 0; 544 | if (kcp->rx_srtt == 0) { 545 | kcp->rx_srtt = rtt; 546 | kcp->rx_rttval = rtt / 2; 547 | } else { 548 | long delta = rtt - kcp->rx_srtt; 549 | if (delta < 0) delta = -delta; 550 | kcp->rx_rttval = (3 * kcp->rx_rttval + delta) / 4; 551 | kcp->rx_srtt = (7 * kcp->rx_srtt + rtt) / 8; 552 | if (kcp->rx_srtt < 1) kcp->rx_srtt = 1; 553 | } 554 | rto = kcp->rx_srtt + _imax_(kcp->interval, 4 * kcp->rx_rttval); 555 | kcp->rx_rto = _ibound_(kcp->rx_minrto, rto, IKCP_RTO_MAX); 556 | } 557 | 558 | static void ikcp_shrink_buf(ikcpcb *kcp) 559 | { 560 | struct IQUEUEHEAD *p = kcp->snd_buf.next; 561 | if (p != &kcp->snd_buf) { 562 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 563 | kcp->snd_una = seg->sn; 564 | } else { 565 | kcp->snd_una = kcp->snd_nxt; 566 | } 567 | } 568 | 569 | static void ikcp_parse_ack(ikcpcb *kcp, IUINT32 sn) 570 | { 571 | struct IQUEUEHEAD *p, *next; 572 | 573 | if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) 574 | return; 575 | 576 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { 577 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 578 | next = p->next; 579 | if (sn == seg->sn) { 580 | iqueue_del(p); 581 | ikcp_segment_delete(kcp, seg); 582 | kcp->nsnd_buf--; 583 | break; 584 | } 585 | if (_itimediff(sn, seg->sn) < 0) { 586 | break; 587 | } 588 | } 589 | } 590 | 591 | static void ikcp_parse_una(ikcpcb *kcp, IUINT32 una) 592 | { 593 | struct IQUEUEHEAD *p, *next; 594 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { 595 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 596 | next = p->next; 597 | if (_itimediff(una, seg->sn) > 0) { 598 | iqueue_del(p); 599 | ikcp_segment_delete(kcp, seg); 600 | kcp->nsnd_buf--; 601 | } else { 602 | break; 603 | } 604 | } 605 | } 606 | 607 | static void ikcp_parse_fastack(ikcpcb *kcp, IUINT32 sn) 608 | { 609 | struct IQUEUEHEAD *p, *next; 610 | 611 | if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) 612 | return; 613 | 614 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) { 615 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 616 | next = p->next; 617 | if (_itimediff(sn, seg->sn) < 0) { 618 | break; 619 | } 620 | else if (sn != seg->sn) { 621 | seg->fastack++; 622 | } 623 | } 624 | } 625 | 626 | 627 | //--------------------------------------------------------------------- 628 | // ack append 629 | //--------------------------------------------------------------------- 630 | static void ikcp_ack_push(ikcpcb *kcp, IUINT32 sn, IUINT32 ts) 631 | { 632 | size_t newsize = kcp->ackcount + 1; 633 | IUINT32 *ptr; 634 | 635 | if (newsize > kcp->ackblock) { 636 | IUINT32 *acklist; 637 | size_t newblock; 638 | 639 | for (newblock = 8; newblock < newsize; newblock <<= 1); 640 | acklist = (IUINT32*)ikcp_malloc(newblock * sizeof(IUINT32) * 2); 641 | 642 | if (acklist == NULL) { 643 | assert(acklist != NULL); 644 | abort(); 645 | } 646 | 647 | if (kcp->acklist != NULL) { 648 | size_t x; 649 | for (x = 0; x < kcp->ackcount; x++) { 650 | acklist[x * 2 + 0] = kcp->acklist[x * 2 + 0]; 651 | acklist[x * 2 + 1] = kcp->acklist[x * 2 + 1]; 652 | } 653 | ikcp_free(kcp->acklist); 654 | } 655 | 656 | kcp->acklist = acklist; 657 | kcp->ackblock = newblock; 658 | } 659 | 660 | ptr = &kcp->acklist[kcp->ackcount * 2]; 661 | ptr[0] = sn; 662 | ptr[1] = ts; 663 | kcp->ackcount++; 664 | } 665 | 666 | static void ikcp_ack_get(const ikcpcb *kcp, int p, IUINT32 *sn, IUINT32 *ts) 667 | { 668 | if (sn) sn[0] = kcp->acklist[p * 2 + 0]; 669 | if (ts) ts[0] = kcp->acklist[p * 2 + 1]; 670 | } 671 | 672 | 673 | //--------------------------------------------------------------------- 674 | // parse data 675 | //--------------------------------------------------------------------- 676 | void ikcp_parse_data(ikcpcb *kcp, IKCPSEG *newseg) 677 | { 678 | struct IQUEUEHEAD *p, *prev; 679 | IUINT32 sn = newseg->sn; 680 | int repeat = 0; 681 | 682 | if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) >= 0 || 683 | _itimediff(sn, kcp->rcv_nxt) < 0) { 684 | ikcp_segment_delete(kcp, newseg); 685 | return; 686 | } 687 | 688 | for (p = kcp->rcv_buf.prev; p != &kcp->rcv_buf; p = prev) { 689 | IKCPSEG *seg = iqueue_entry(p, IKCPSEG, node); 690 | prev = p->prev; 691 | if (seg->sn == sn) { 692 | repeat = 1; 693 | break; 694 | } 695 | if (_itimediff(sn, seg->sn) > 0) { 696 | break; 697 | } 698 | } 699 | 700 | if (repeat == 0) { 701 | iqueue_init(&newseg->node); 702 | iqueue_add(&newseg->node, p); 703 | kcp->nrcv_buf++; 704 | } else { 705 | ikcp_segment_delete(kcp, newseg); 706 | } 707 | 708 | #if 0 709 | ikcp_qprint("rcvbuf", &kcp->rcv_buf); 710 | printf("rcv_nxt=%lu\n", kcp->rcv_nxt); 711 | #endif 712 | 713 | // move available data from rcv_buf -> rcv_queue 714 | while (! iqueue_is_empty(&kcp->rcv_buf)) { 715 | IKCPSEG *seg = iqueue_entry(kcp->rcv_buf.next, IKCPSEG, node); 716 | if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) { 717 | iqueue_del(&seg->node); 718 | kcp->nrcv_buf--; 719 | iqueue_add_tail(&seg->node, &kcp->rcv_queue); 720 | kcp->nrcv_que++; 721 | kcp->rcv_nxt++; 722 | } else { 723 | break; 724 | } 725 | } 726 | 727 | #if 0 728 | ikcp_qprint("queue", &kcp->rcv_queue); 729 | printf("rcv_nxt=%lu\n", kcp->rcv_nxt); 730 | #endif 731 | 732 | #if 1 733 | // printf("snd(buf=%d, queue=%d)\n", kcp->nsnd_buf, kcp->nsnd_que); 734 | // printf("rcv(buf=%d, queue=%d)\n", kcp->nrcv_buf, kcp->nrcv_que); 735 | #endif 736 | } 737 | 738 | 739 | //--------------------------------------------------------------------- 740 | // input data 741 | //--------------------------------------------------------------------- 742 | int ikcp_input(ikcpcb *kcp, const char *data, long size) 743 | { 744 | IUINT32 una = kcp->snd_una; 745 | IUINT32 maxack = 0; 746 | int flag = 0; 747 | 748 | if (ikcp_canlog(kcp, IKCP_LOG_INPUT)) { 749 | ikcp_log(kcp, IKCP_LOG_INPUT, "[RI] %d bytes", size); 750 | } 751 | 752 | if (data == NULL || (int)size < (int)IKCP_OVERHEAD) return -1; 753 | 754 | while (1) { 755 | IUINT32 ts, sn, len, una, conv; 756 | IUINT16 wnd; 757 | IUINT8 cmd, frg; 758 | IKCPSEG *seg; 759 | 760 | if (size < (int)IKCP_OVERHEAD) break; 761 | 762 | data = ikcp_decode32u(data, &conv); 763 | if (conv != kcp->conv) return -1; 764 | 765 | data = ikcp_decode8u(data, &cmd); 766 | data = ikcp_decode8u(data, &frg); 767 | data = ikcp_decode16u(data, &wnd); 768 | data = ikcp_decode32u(data, &ts); 769 | data = ikcp_decode32u(data, &sn); 770 | data = ikcp_decode32u(data, &una); 771 | data = ikcp_decode32u(data, &len); 772 | 773 | size -= IKCP_OVERHEAD; 774 | 775 | if ((long)size < (long)len || (int)len < 0) return -2; 776 | 777 | if (cmd != IKCP_CMD_PUSH && cmd != IKCP_CMD_ACK && 778 | cmd != IKCP_CMD_WASK && cmd != IKCP_CMD_WINS) 779 | return -3; 780 | 781 | kcp->rmt_wnd = wnd; 782 | ikcp_parse_una(kcp, una); 783 | ikcp_shrink_buf(kcp); 784 | 785 | if (cmd == IKCP_CMD_ACK) { 786 | if (_itimediff(kcp->current, ts) >= 0) { 787 | ikcp_update_ack(kcp, _itimediff(kcp->current, ts)); 788 | } 789 | ikcp_parse_ack(kcp, sn); 790 | ikcp_shrink_buf(kcp); 791 | if (flag == 0) { 792 | flag = 1; 793 | maxack = sn; 794 | } else { 795 | if (_itimediff(sn, maxack) > 0) { 796 | maxack = sn; 797 | } 798 | } 799 | if (ikcp_canlog(kcp, IKCP_LOG_IN_ACK)) { 800 | ikcp_log(kcp, IKCP_LOG_IN_DATA, 801 | "input ack: sn=%lu rtt=%ld rto=%ld", sn, 802 | (long)_itimediff(kcp->current, ts), 803 | (long)kcp->rx_rto); 804 | } 805 | } 806 | else if (cmd == IKCP_CMD_PUSH) { 807 | if (ikcp_canlog(kcp, IKCP_LOG_IN_DATA)) { 808 | ikcp_log(kcp, IKCP_LOG_IN_DATA, 809 | "input psh: sn=%lu ts=%lu", sn, ts); 810 | } 811 | if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) < 0) { 812 | ikcp_ack_push(kcp, sn, ts); 813 | if (_itimediff(sn, kcp->rcv_nxt) >= 0) { 814 | seg = ikcp_segment_new(kcp, len); 815 | seg->conv = conv; 816 | seg->cmd = cmd; 817 | seg->frg = frg; 818 | seg->wnd = wnd; 819 | seg->ts = ts; 820 | seg->sn = sn; 821 | seg->una = una; 822 | seg->len = len; 823 | 824 | if (len > 0) { 825 | memcpy(seg->data, data, len); 826 | } 827 | 828 | ikcp_parse_data(kcp, seg); 829 | } 830 | } 831 | } 832 | else if (cmd == IKCP_CMD_WASK) { 833 | // ready to send back IKCP_CMD_WINS in ikcp_flush 834 | // tell remote my window size 835 | kcp->probe |= IKCP_ASK_TELL; 836 | if (ikcp_canlog(kcp, IKCP_LOG_IN_PROBE)) { 837 | ikcp_log(kcp, IKCP_LOG_IN_PROBE, "input probe"); 838 | } 839 | } 840 | else if (cmd == IKCP_CMD_WINS) { 841 | // do nothing 842 | if (ikcp_canlog(kcp, IKCP_LOG_IN_WINS)) { 843 | ikcp_log(kcp, IKCP_LOG_IN_WINS, 844 | "input wins: %lu", (IUINT32)(wnd)); 845 | } 846 | } 847 | else { 848 | return -3; 849 | } 850 | 851 | data += len; 852 | size -= len; 853 | } 854 | 855 | if (flag != 0) { 856 | ikcp_parse_fastack(kcp, maxack); 857 | } 858 | 859 | if (_itimediff(kcp->snd_una, una) > 0) { 860 | if (kcp->cwnd < kcp->rmt_wnd) { 861 | IUINT32 mss = kcp->mss; 862 | if (kcp->cwnd < kcp->ssthresh) { 863 | kcp->cwnd++; 864 | kcp->incr += mss; 865 | } else { 866 | if (kcp->incr < mss) kcp->incr = mss; 867 | kcp->incr += (mss * mss) / kcp->incr + (mss / 16); 868 | if ((kcp->cwnd + 1) * mss <= kcp->incr) { 869 | kcp->cwnd++; 870 | } 871 | } 872 | if (kcp->cwnd > kcp->rmt_wnd) { 873 | kcp->cwnd = kcp->rmt_wnd; 874 | kcp->incr = kcp->rmt_wnd * mss; 875 | } 876 | } 877 | } 878 | 879 | return 0; 880 | } 881 | 882 | 883 | //--------------------------------------------------------------------- 884 | // ikcp_encode_seg 885 | //--------------------------------------------------------------------- 886 | static char *ikcp_encode_seg(char *ptr, const IKCPSEG *seg) 887 | { 888 | ptr = ikcp_encode32u(ptr, seg->conv); 889 | ptr = ikcp_encode8u(ptr, (IUINT8)seg->cmd); 890 | ptr = ikcp_encode8u(ptr, (IUINT8)seg->frg); 891 | ptr = ikcp_encode16u(ptr, (IUINT16)seg->wnd); 892 | ptr = ikcp_encode32u(ptr, seg->ts); 893 | ptr = ikcp_encode32u(ptr, seg->sn); 894 | ptr = ikcp_encode32u(ptr, seg->una); 895 | ptr = ikcp_encode32u(ptr, seg->len); 896 | return ptr; 897 | } 898 | 899 | static int ikcp_wnd_unused(const ikcpcb *kcp) 900 | { 901 | if (kcp->nrcv_que < kcp->rcv_wnd) { 902 | return kcp->rcv_wnd - kcp->nrcv_que; 903 | } 904 | return 0; 905 | } 906 | 907 | 908 | //--------------------------------------------------------------------- 909 | // ikcp_flush 910 | //--------------------------------------------------------------------- 911 | void ikcp_flush(ikcpcb *kcp) 912 | { 913 | IUINT32 current = kcp->current; 914 | char *buffer = kcp->buffer; 915 | char *ptr = buffer; 916 | int count, size, i; 917 | IUINT32 resent, cwnd; 918 | IUINT32 rtomin; 919 | struct IQUEUEHEAD *p; 920 | int change = 0; 921 | int lost = 0; 922 | IKCPSEG seg; 923 | 924 | // 'ikcp_update' haven't been called. 925 | if (kcp->updated == 0) return; 926 | 927 | seg.conv = kcp->conv; 928 | seg.cmd = IKCP_CMD_ACK; 929 | seg.frg = 0; 930 | seg.wnd = ikcp_wnd_unused(kcp); 931 | seg.una = kcp->rcv_nxt; 932 | seg.len = 0; 933 | seg.sn = 0; 934 | seg.ts = 0; 935 | 936 | // flush acknowledges 937 | count = kcp->ackcount; 938 | for (i = 0; i < count; i++) { 939 | size = (int)(ptr - buffer); 940 | if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { 941 | ikcp_output(kcp, buffer, size); 942 | ptr = buffer; 943 | } 944 | ikcp_ack_get(kcp, i, &seg.sn, &seg.ts); 945 | ptr = ikcp_encode_seg(ptr, &seg); 946 | } 947 | 948 | kcp->ackcount = 0; 949 | 950 | // probe window size (if remote window size equals zero) 951 | if (kcp->rmt_wnd == 0) { 952 | if (kcp->probe_wait == 0) { 953 | kcp->probe_wait = IKCP_PROBE_INIT; 954 | kcp->ts_probe = kcp->current + kcp->probe_wait; 955 | } 956 | else { 957 | if (_itimediff(kcp->current, kcp->ts_probe) >= 0) { 958 | if (kcp->probe_wait < IKCP_PROBE_INIT) 959 | kcp->probe_wait = IKCP_PROBE_INIT; 960 | kcp->probe_wait += kcp->probe_wait / 2; 961 | if (kcp->probe_wait > IKCP_PROBE_LIMIT) 962 | kcp->probe_wait = IKCP_PROBE_LIMIT; 963 | kcp->ts_probe = kcp->current + kcp->probe_wait; 964 | kcp->probe |= IKCP_ASK_SEND; 965 | } 966 | } 967 | } else { 968 | kcp->ts_probe = 0; 969 | kcp->probe_wait = 0; 970 | } 971 | 972 | // flush window probing commands 973 | if (kcp->probe & IKCP_ASK_SEND) { 974 | seg.cmd = IKCP_CMD_WASK; 975 | size = (int)(ptr - buffer); 976 | if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { 977 | ikcp_output(kcp, buffer, size); 978 | ptr = buffer; 979 | } 980 | ptr = ikcp_encode_seg(ptr, &seg); 981 | } 982 | 983 | // flush window probing commands 984 | if (kcp->probe & IKCP_ASK_TELL) { 985 | seg.cmd = IKCP_CMD_WINS; 986 | size = (int)(ptr - buffer); 987 | if (size + (int)IKCP_OVERHEAD > (int)kcp->mtu) { 988 | ikcp_output(kcp, buffer, size); 989 | ptr = buffer; 990 | } 991 | ptr = ikcp_encode_seg(ptr, &seg); 992 | } 993 | 994 | kcp->probe = 0; 995 | 996 | // calculate window size 997 | cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd); 998 | if (kcp->nocwnd == 0) cwnd = _imin_(kcp->cwnd, cwnd); 999 | 1000 | // move data from snd_queue to snd_buf 1001 | while (_itimediff(kcp->snd_nxt, kcp->snd_una + cwnd) < 0) { 1002 | IKCPSEG *newseg; 1003 | if (iqueue_is_empty(&kcp->snd_queue)) break; 1004 | 1005 | newseg = iqueue_entry(kcp->snd_queue.next, IKCPSEG, node); 1006 | 1007 | iqueue_del(&newseg->node); 1008 | iqueue_add_tail(&newseg->node, &kcp->snd_buf); 1009 | kcp->nsnd_que--; 1010 | kcp->nsnd_buf++; 1011 | 1012 | newseg->conv = kcp->conv; 1013 | newseg->cmd = IKCP_CMD_PUSH; 1014 | newseg->wnd = seg.wnd; 1015 | newseg->ts = current; 1016 | newseg->sn = kcp->snd_nxt++; 1017 | newseg->una = kcp->rcv_nxt; 1018 | newseg->resendts = current; 1019 | newseg->rto = kcp->rx_rto; 1020 | newseg->fastack = 0; 1021 | newseg->xmit = 0; 1022 | } 1023 | 1024 | // calculate resent 1025 | resent = (kcp->fastresend > 0)? (IUINT32)kcp->fastresend : 0xffffffff; 1026 | rtomin = (kcp->nodelay == 0)? (kcp->rx_rto >> 3) : 0; 1027 | 1028 | // flush data segments 1029 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) { 1030 | IKCPSEG *segment = iqueue_entry(p, IKCPSEG, node); 1031 | int needsend = 0; 1032 | if (segment->xmit == 0) { 1033 | needsend = 1; 1034 | segment->xmit++; 1035 | segment->rto = kcp->rx_rto; 1036 | segment->resendts = current + segment->rto + rtomin; 1037 | } 1038 | else if (_itimediff(current, segment->resendts) >= 0) { 1039 | needsend = 1; 1040 | segment->xmit++; 1041 | kcp->xmit++; 1042 | if (kcp->nodelay == 0) { 1043 | segment->rto += kcp->rx_rto; 1044 | } else { 1045 | segment->rto += kcp->rx_rto / 2; 1046 | } 1047 | segment->resendts = current + segment->rto; 1048 | lost = 1; 1049 | } 1050 | else if (segment->fastack >= resent) { 1051 | needsend = 1; 1052 | segment->xmit++; 1053 | segment->fastack = 0; 1054 | segment->resendts = current + segment->rto; 1055 | change++; 1056 | } 1057 | 1058 | if (needsend) { 1059 | int size, need; 1060 | segment->ts = current; 1061 | segment->wnd = seg.wnd; 1062 | segment->una = kcp->rcv_nxt; 1063 | 1064 | size = (int)(ptr - buffer); 1065 | need = IKCP_OVERHEAD + segment->len; 1066 | 1067 | if (size + need > (int)kcp->mtu) { 1068 | ikcp_output(kcp, buffer, size); 1069 | ptr = buffer; 1070 | } 1071 | 1072 | ptr = ikcp_encode_seg(ptr, segment); 1073 | 1074 | if (segment->len > 0) { 1075 | memcpy(ptr, segment->data, segment->len); 1076 | ptr += segment->len; 1077 | } 1078 | 1079 | if (segment->xmit >= kcp->dead_link) { 1080 | kcp->state = -1; 1081 | } 1082 | } 1083 | } 1084 | 1085 | // flash remain segments 1086 | size = (int)(ptr - buffer); 1087 | if (size > 0) { 1088 | ikcp_output(kcp, buffer, size); 1089 | } 1090 | 1091 | // update ssthresh 1092 | if (change) { 1093 | IUINT32 inflight = kcp->snd_nxt - kcp->snd_una; 1094 | kcp->ssthresh = inflight / 2; 1095 | if (kcp->ssthresh < IKCP_THRESH_MIN) 1096 | kcp->ssthresh = IKCP_THRESH_MIN; 1097 | kcp->cwnd = kcp->ssthresh + resent; 1098 | kcp->incr = kcp->cwnd * kcp->mss; 1099 | } 1100 | 1101 | if (lost) { 1102 | kcp->ssthresh = cwnd / 2; 1103 | if (kcp->ssthresh < IKCP_THRESH_MIN) 1104 | kcp->ssthresh = IKCP_THRESH_MIN; 1105 | kcp->cwnd = 1; 1106 | kcp->incr = kcp->mss; 1107 | } 1108 | 1109 | if (kcp->cwnd < 1) { 1110 | kcp->cwnd = 1; 1111 | kcp->incr = kcp->mss; 1112 | } 1113 | } 1114 | 1115 | 1116 | //--------------------------------------------------------------------- 1117 | // update state (call it repeatedly, every 10ms-100ms), or you can ask 1118 | // ikcp_check when to call it again (without ikcp_input/_send calling). 1119 | // 'current' - current timestamp in millisec. 1120 | //--------------------------------------------------------------------- 1121 | void ikcp_update(ikcpcb *kcp, IUINT32 current) 1122 | { 1123 | IINT32 slap; 1124 | 1125 | kcp->current = current; 1126 | 1127 | if (kcp->updated == 0) { 1128 | kcp->updated = 1; 1129 | kcp->ts_flush = kcp->current; 1130 | } 1131 | 1132 | slap = _itimediff(kcp->current, kcp->ts_flush); 1133 | 1134 | if (slap >= 10000 || slap < -10000) { 1135 | kcp->ts_flush = kcp->current; 1136 | slap = 0; 1137 | } 1138 | 1139 | if (slap >= 0) { 1140 | kcp->ts_flush += kcp->interval; 1141 | if (_itimediff(kcp->current, kcp->ts_flush) >= 0) { 1142 | kcp->ts_flush = kcp->current + kcp->interval; 1143 | } 1144 | ikcp_flush(kcp); 1145 | } 1146 | } 1147 | 1148 | 1149 | //--------------------------------------------------------------------- 1150 | // Determine when should you invoke ikcp_update: 1151 | // returns when you should invoke ikcp_update in millisec, if there 1152 | // is no ikcp_input/_send calling. you can call ikcp_update in that 1153 | // time, instead of call update repeatly. 1154 | // Important to reduce unnacessary ikcp_update invoking. use it to 1155 | // schedule ikcp_update (eg. implementing an epoll-like mechanism, 1156 | // or optimize ikcp_update when handling massive kcp connections) 1157 | //--------------------------------------------------------------------- 1158 | IUINT32 ikcp_check(const ikcpcb *kcp, IUINT32 current) 1159 | { 1160 | IUINT32 ts_flush = kcp->ts_flush; 1161 | IINT32 tm_flush = 0x7fffffff; 1162 | IINT32 tm_packet = 0x7fffffff; 1163 | IUINT32 minimal = 0; 1164 | struct IQUEUEHEAD *p; 1165 | 1166 | if (kcp->updated == 0) { 1167 | return current; 1168 | } 1169 | 1170 | if (_itimediff(current, ts_flush) >= 10000 || 1171 | _itimediff(current, ts_flush) < -10000) { 1172 | ts_flush = current; 1173 | } 1174 | 1175 | if (_itimediff(current, ts_flush) >= 0) { 1176 | return current; 1177 | } 1178 | 1179 | tm_flush = _itimediff(ts_flush, current); 1180 | 1181 | for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) { 1182 | const IKCPSEG *seg = iqueue_entry(p, const IKCPSEG, node); 1183 | IINT32 diff = _itimediff(seg->resendts, current); 1184 | if (diff <= 0) { 1185 | return current; 1186 | } 1187 | if (diff < tm_packet) tm_packet = diff; 1188 | } 1189 | 1190 | minimal = (IUINT32)(tm_packet < tm_flush ? tm_packet : tm_flush); 1191 | if (minimal >= kcp->interval) minimal = kcp->interval; 1192 | 1193 | return current + minimal; 1194 | } 1195 | 1196 | 1197 | 1198 | int ikcp_setmtu(ikcpcb *kcp, int mtu) 1199 | { 1200 | char *buffer; 1201 | if (mtu < 50 || mtu < (int)IKCP_OVERHEAD) 1202 | return -1; 1203 | buffer = (char*)ikcp_malloc((mtu + IKCP_OVERHEAD) * 3); 1204 | if (buffer == NULL) 1205 | return -2; 1206 | kcp->mtu = mtu; 1207 | kcp->mss = kcp->mtu - IKCP_OVERHEAD; 1208 | ikcp_free(kcp->buffer); 1209 | kcp->buffer = buffer; 1210 | return 0; 1211 | } 1212 | 1213 | int ikcp_interval(ikcpcb *kcp, int interval) 1214 | { 1215 | if (interval > 5000) interval = 5000; 1216 | else if (interval < 10) interval = 10; 1217 | kcp->interval = interval; 1218 | return 0; 1219 | } 1220 | 1221 | int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc) 1222 | { 1223 | if (nodelay >= 0) { 1224 | kcp->nodelay = nodelay; 1225 | if (nodelay) { 1226 | kcp->rx_minrto = IKCP_RTO_NDL; 1227 | } 1228 | else { 1229 | kcp->rx_minrto = IKCP_RTO_MIN; 1230 | } 1231 | } 1232 | if (interval >= 0) { 1233 | if (interval > 5000) interval = 5000; 1234 | else if (interval < 10) interval = 10; 1235 | kcp->interval = interval; 1236 | } 1237 | if (resend >= 0) { 1238 | kcp->fastresend = resend; 1239 | } 1240 | if (nc >= 0) { 1241 | kcp->nocwnd = nc; 1242 | } 1243 | return 0; 1244 | } 1245 | 1246 | 1247 | int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd) 1248 | { 1249 | if (kcp) { 1250 | if (sndwnd > 0) { 1251 | kcp->snd_wnd = sndwnd; 1252 | } 1253 | if (rcvwnd > 0) { // must >= max fragment size 1254 | kcp->rcv_wnd = _imax_(rcvwnd, IKCP_WND_RCV); 1255 | } 1256 | } 1257 | return 0; 1258 | } 1259 | 1260 | int ikcp_waitsnd(const ikcpcb *kcp) 1261 | { 1262 | return kcp->nsnd_buf + kcp->nsnd_que; 1263 | } 1264 | 1265 | 1266 | // read conv 1267 | IUINT32 ikcp_getconv(const void *ptr) 1268 | { 1269 | IUINT32 conv; 1270 | ikcp_decode32u((const char*)ptr, &conv); 1271 | return conv; 1272 | } 1273 | 1274 | --------------------------------------------------------------------------------