{"id":17022099,"url":"https://github.com/trigary/doublesocket","last_synced_at":"2025-08-21T15:43:48.062Z","repository":{"id":193083819,"uuid":"141333277","full_name":"Trigary/DoubleSocket","owner":"Trigary","description":"Synchronized UDP-TCP socket pair library in C#.","archived":false,"fork":false,"pushed_at":"2018-08-18T08:25:51.000Z","size":179,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-27T21:33:14.981Z","etag":null,"topics":["api","csharp","library","networking","packet","packets","socket","socket-programming","sockets","tcp","tcp-socket","udp","udp-socket"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Trigary.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-17T19:19:13.000Z","updated_at":"2022-11-12T10:28:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"4f7d0788-02cc-40d8-9dba-093ebe004cae","html_url":"https://github.com/Trigary/DoubleSocket","commit_stats":null,"previous_names":["trigary/doublesocket"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Trigary%2FDoubleSocket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Trigary%2FDoubleSocket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Trigary%2FDoubleSocket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Trigary%2FDoubleSocket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Trigary","download_url":"https://codeload.github.com/Trigary/DoubleSocket/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244994209,"owners_count":20544120,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","csharp","library","networking","packet","packets","socket","socket-programming","sockets","tcp","tcp-socket","udp","udp-socket"],"created_at":"2024-10-14T07:09:20.221Z","updated_at":"2025-03-22T17:29:02.359Z","avatar_url":"https://github.com/Trigary.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DoubleSocket\n\nA library which exposes a TCP-UDP socket pair, letting you send time-critical, but unimportant data through the UDP socket\nand optionally large quantities of must-arrive data through the TCP socket.\n\nA connection-based protocol is implemented on top of UDP with the help of the TCP connection, synchronizing their states.\n\n\n\n## Protocol\n\nThis section describes how the connections should be established and authenticated for the TCP and UDP sockets and how data can be transferred over them.\n\n### TCP handshake\n\nA TCP connection is created between the server and the client.\n\n### TCP authentication - client\n\nThe client sends data of not predetermined size (it is up to the user of this library), based on which the server will accept or deny the connection.\nThis is the only TCP packet which is not encrypted since it is assumed that the data sent in this step contains the encryption key (encrypted using another key, which only the servers know).\nAll TCP packets contain a 16-bit packet size prefix (these 16 bits are not included in that).\nAfter this prefix, the undetermined data follows, there is nothing else.\nThe client is kicked if this packet is not sent in time.\n\n### TCP authentication - server\n\nThe server examines the received data and accepts or denies the client based on it.\nAll packets from now on, including this one, are encrypted: all bytes, except the 16-bit packet size prefix, are transformed using AES-128.\nThe server needs to be able to provide the encryption key based on the received data it examined.\nIf the client got denied, then a single encrypted packet containing an 8-bit error code will be sent, then the connection will be closed.\nIf the client got accepted, the server sends an 8-bit long sequence id value bound, a 64-bit long UDP authentication key and a 64-bit long connection-start timestamp.\nAll three of these are saved internally, linked to the specific client instance.\nMultiple clients must not get the same UDP authentication key.\nIf the client got accepted and the count of authenticated client equals the client limit then all non-authenticated (but connected) clients are kicked and new clients are no longer accepted until an authenticated client disconnects.\n\n### UDP authentication\n\nWhen the client receives the 64-bit long UDP authentication key over TCP, it continuously sends it over UDP until a timeout happens or the server responds.\nThe server's response is a single byte with the value of zero over TCP, which informs the client that the UDP connection has been authenticated.\nWith this step done, both the TCP and the UDP connections are authenticated and are ready to send/receive data.\n\n### TCP payloads\n\nAll TCP packets still contain the 16-bit unencrypted long packet size prefix, but now an 8-bit long encrypted sequence id follows it.\nThese 8 bits, which are used to combat replay attacks, are included in the packet size prefix.\nTwo sequence ids are saved on both ends: the sent and the received sequence id.\nThe newly sent packet's sequence id is one greater than the previously sent packet's sequence id and the newly received packet's sequence id must be one greater than the previously received packet's sequence id.\nThe first packet's sequence id is 0.\nIn case the sequence id check fails, the packet should be ignored.\nIf the new sequence id's value would be equal to the sequence id value bound (specified by the server in the TCP authentication step) then the new sequence id's value should be 0 instead.\n\n### UDP payloads\n\nAll UDP packets are fully encrypted: they contain no unencrypted bits.\nThe first 32 bits are the CRC-32 calculated from the rest of the packet.\nThe next 16 bits are the milliseconds which passed since the timestamp specified by the server in the TCP authentication step divided by 10.\nThis means that these 16 bits specify when the packet was sent (with a 10ms precision), allowing the ordering of packets, the dropping out-of-order ones, latency measurement and even protection against replay attacks.\nThis data is not used by this library, it is up to the user to use it or ignore it (and just keep its replay attack protection property).\nThis elapsed time counter wraps around after ~10.92 minutes, this has to be handled.\n\n### Disconnects\n\nIf it is detected that the TCP connection is no longer working, then both the TCP and the UDP connections get fully closed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrigary%2Fdoublesocket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrigary%2Fdoublesocket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrigary%2Fdoublesocket/lists"}