{"id":13497175,"url":"https://github.com/mortzdk/Websocket","last_synced_at":"2025-03-28T21:32:03.432Z","repository":{"id":7842263,"uuid":"9213892","full_name":"mortzdk/Websocket","owner":"mortzdk","description":"WSServer is a fast, configurable, and extendable WebSocket Server for UNIX systems written in C (C11).","archived":false,"fork":false,"pushed_at":"2023-09-05T13:36:44.000Z","size":27067,"stargazers_count":199,"open_issues_count":0,"forks_count":67,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-10-29T18:50:40.442Z","etag":null,"topics":["autobahn-testsuite","c","websocket","websocket-server","websockets","wsserver"],"latest_commit_sha":null,"homepage":"https://mortzdk.github.io/Websocket/","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/mortzdk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":"FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null},"funding":{"open_collective":"websocket"}},"created_at":"2013-04-04T08:23:50.000Z","updated_at":"2024-09-12T09:54:40.000Z","dependencies_parsed_at":"2022-08-06T20:15:17.321Z","dependency_job_id":"8534cb2d-84a8-4bc2-b135-98e90814c952","html_url":"https://github.com/mortzdk/Websocket","commit_stats":{"total_commits":100,"total_committers":5,"mean_commits":20.0,"dds":"0.20999999999999996","last_synced_commit":"de767149899e9be366951f2260a69411f1f45841"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mortzdk%2FWebsocket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mortzdk%2FWebsocket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mortzdk%2FWebsocket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mortzdk%2FWebsocket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mortzdk","download_url":"https://codeload.github.com/mortzdk/Websocket/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246105266,"owners_count":20724281,"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":["autobahn-testsuite","c","websocket","websocket-server","websockets","wsserver"],"created_at":"2024-07-31T20:00:25.846Z","updated_at":"2025-03-28T21:32:03.039Z","avatar_url":"https://github.com/mortzdk.png","language":"C","funding_links":["https://opencollective.com/websocket","https://opencollective.com/websocket/"],"categories":["Tools per Language"],"sub_categories":["C"],"readme":"# WSServer a C WebSocket Server\n\n[![Build Status](https://travis-ci.org/mortzdk/Websocket.svg?branch=master)](https://travis-ci.org/mortzdk/Websocket) [![Financial Contributors](https://opencollective.com/websocket/tiers/badge.svg)](https://opencollective.com/websocket/) \n\nWSServer is a fast, configurable, and extendable WebSocket Server for UNIX\nsystems written in C (C11).\n\nAs of version 2.0.0 the WSServer has been completely rewritten with many new\nfeatures, better support, better extendability and generally as a more stable\nWebSocket server.\n\nCurrent Version: **v2.1.0**\n\n### Early history\n\nThe original WebSocket server (v1.0.0 and before) started out as a hobby\nproject in 2012. The idea at the time, was to learn the C language and\nunderstand the basics of WebSockets. The initial version of the server worked\nfor some but not all aspects of the protocols present at that time. At that\ntime, different browsers implemented different versions of the WebSocket\nProtocol, which made it difficult to support all browsers. Today all major\nbrowsers support the [RFC6455](http://tools.ietf.org/html/rfc6455) protocol,\nwhich has been stable for many years. \n\n### Present (2020)\n\nWSServer now supports all aspects of the [RFC6455](http://tools.ietf.org/html/rfc6455) protocol, including the\n[RFC7692](https://tools.ietf.org/html/rfc7692) that enables the `permessage-deflate` extension. The \nimplementation is verified by the [Autobahn testsuite](https://github.com/crossbario/autobahn-testsuite) and by a lot of\nunit tests. It furthermore support the older protocols [HYBI10](https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10) and [HYBI07](https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07)\nas there are no noteable difference between those and the current stable one.\nCurrently there are no support for older versions of the protocol.\n\n### Donate\n\nTo support further development on this project and financially support the \ndeveloper having a nice cup of coffee, you can make a donation of your choice\n[here](https://opencollective.com/websocket).\n\n# How to get started\n\nTo build the WSServer for your UNIX system, simply run: `make release`. This\nwill compile extensions, subprotocols, and the binary that will be available\nfrom: `./bin/WSServer`.\n\nCurrently the WSServer support only one extension namely the `permessage-deflate`\nextension. Read more about this implementation [here](#Permessage-Deflate).\n\nFurthermore it supports two subprotocols: [echo](#Echo) and [broadcast](#Broadcast). \nThe [echo](#Echo) subprotocol is a simple protocol that sends whatever message\nreceived, back to the same client. This is also the default protocol chosen,\nif no subprotocol is provided by the client. The [broadcast](#Broadcast) subprotocol\nis slightly more advanced. It sends a message from one client to all other\nconnected clients. The behaviour is basically as a public chat room.\n\nThe server can be configured by providing a `-c [path_to_config_file.json]`\nflag. If no configuration is provided, the server will run with a default\nconfiguration, that support WebSocket over HTTP on port 80. You can read more\nabout the structure and description of the configuration file in the\n[configuration](#Configuration) section.\n\n### Log\n\nWSServer keeps a log file at `logs/WSServer.log`. The detail of the log is\ndefined by the `log_level` value in the configuration. Default for a release\nbuild is 3 (FATAL, ERROR, WARN, INFO). Default for a test build is 5 (FATAL,\nERROR, WARN, INFO, DEBUG, TRACE).\n\nThe log file is a good tool for discovering misbehavior of the server, such as\nwhen the server isn't able to start, since port 80 is already occupied by\nanother server instance.\n\n### Dependencies\n\nWSServer does in principle not rely on any third-party libraries in order to\nserve as a WebSocket server. However if you want the complete feature set the\n[**zlib**](https://zlib.net/) and one of the SSL libraries [**OpenSSL**](https://www.openssl.org/), \n[**WolfSSL**](https://www.wolfssl.com/), [**BoringSSL**](https://www.boringssl.googlesource.com/boringssl/), [**LibreSSL**](https://www.libressl.org/) must be installed \non your system in order to support the `permessage-deflate` extension and SSL (WSS).\n\n##### Ubuntu\n```\n$ sudo apt-get install zlib1g-dev\n$ sudo apt-get install openssl\n$ sudo apt-get install wolfssl\n```\n\n##### Arch\n```\n$ pacman -S zlib\n$ pacman -S wolfssl\n$ pacman -S libressl\n```\n\n##### MacOS\n```\n$ brew install zlib\n$ brew install openssl\n$ brew install wolfssl\n```\n\n##### FreeBSD\n```\n$ pkg install libressl\n$ pkg install boringssl\n$ pkg install openssl\n$ pkg install zlib\n```\n\nIf the installation method is not listed above or your package manager doesn't\ncontain the software, it can all be build from source.\n\nNo other dependencies are required with regards to building the server with the\nfull feature set.\n\nIf you want to run the [Autobahn testsuite](https://github.com/crossbario/autobahn-testsuite) and the unit tests yourself, further\ndependencies are required. These are [**docker**](https://www.docker.com/) and [**criterion**](https://github.com/Snaipe/Criterion).\n\n##### Ubuntu\n```\n$ sudo apt install docker.io\n$ sudo add-apt-repository ppa:snaipewastaken/ppa\n$ sudo apt-get update\n$ sudo apt-get install criterion-dev\n```\n\n##### Arch\n```\n$ pacman -S docker\n$ pacman -S criterion\n```\n\n##### MacOS\n```\n$ brew install docker\n$ brew install snaipe/soft/criterion\n```\n\n##### FreeBSD\n```\n$ pkg install docker\n```\n\nCriterion can be build for FreeBSD using the following [guide](https://criterion.readthedocs.io/en/latest/setup.html#installation).  \n\n### Configuration\n\nAn example of a configuration file can be found at [here](https://github.com/mortzdk/Websocket/blob/master/conf/wss.json). A lot of different\nthings are configurable through the configuration file. \n\n##### Origins\n\nThe `origins` key define a subset of allowed origins. It is always recommended\nto define this subset. In case no subset is defined a client can connect from\nanywhere.\n\n##### WebSocket URI\n\nA WebSocket URI consists of a *scheme*, *host*, *port*, *path* and a *query*.\nTake for example: \n\n**wss://mortz.dk:9011/websocket?csrf-token=asgjh48hs389hdla**.\n\nThe **wss** part of the URI is defined as the *scheme*, the **mortz.dk** part\nis defined as the host, the **9011** part is defined as the *port*, the\n**/websocket** part is defined as the *path* and the\n**?csrf-token=asgjh48hs389hdla** part is defined as the *query*.  The specific\nallowance of all 5 parts of the WebSocket URI are configurable.\n\nThe `hosts` key define a subset of strings allowed as the host. In the example\nabove, if we only want clients connecting to **mortz.dk**, we can add that\nstring to the subset.\n\nThe `paths` key define a subset of strings allowed as the connecting path. In\nthe example above, if we only want clients connecting through the path\n**/websocket**, we can add that string to the subset. The path **/** will\nalways be a valid connection path. The string values of the `paths` key are\nallowed to use POSIX Extended Regular Expressions syntax.\n\nThe `queries` key define a subset of strings allowed as the queries. In the\nexample above, if we only want clients to use a specific query\n__csrf-token=[^\u0026]*__, we can add that string to the subset. The string values\nof the `paths` key are allowed to use POSIX Extended Regular Expressions\nsyntax. A WebSocket URI without any queries is always allowed.\n\nThe *scheme* and *port* part of the WebSocket URI is checked based on the ports\nchoosen for `http` and `https`.\n\n##### Port\n\nThe `port` key of the `setup` object is used to define the ports that http (ws)\nversion and the https (wss) should be listening to.\n\nA http (ws) version of the server will always be available. The https (wss)\nversion requires further configuration of SSL.\n\n##### Extensions\n\nThe `extensions` key of the `setup` object is used to define an array of\nsupported extensions. Each entry in the array is an object itself containing \na `file` and `config` key. The `file` key should point to the location of the\nshared object representing the extension. The basename of the `file` key is \nused as the extension name. The `config` key can be used to provide extra\nconfiguration to the extension.\n\n##### Subprotocols\n\nThe `subprotocols` key of the `setup` object is used to define an array of\nsupported subprotocols. Each entry in the array is an object itself containing \na `file` and `config` key. The `file` key should point to the location of the\nshared object representing the subprotocol. The basename of the `file` key is \nused as the subprotocol name. The `config` key can be used to provide extra\nconfiguration to the subprotocol. \n\n##### Favicon\n\nThe `favicon` key of the `setup` object is used to define a favicon to serve\nfor HTTP and HTTPS request. A lot of browsers do the request for favicons per\ndefault when performing HTTP and HTTPS requests. By defining this with the path\nto a valid ICO file, the WSServer will return a favicon.\n\n##### Timeouts\n\nThe `timeout` key of the `setup` object is used to define different timeouts of\nthe WSServer.\n\nThe `poll` key define a timeout for event polling. By setting it to a positive\ninteger **n**, the event loop will be interrupted every **n** milliseconds.\n\nThe `read` key define a timeout for the READ event. The timeout is checked\nwhenever the server requires to read more data from the client in order to\nsucceed. By setting it to a positive integer **n** the request will fail if the\nnext read took longer than **n** milliseconds.\n\nThe `write` key define a timeout for the WRITE event. The timeout is checked\nwhenever the server requires to write more data to the client than it is\ncurrently able to buffer. By setting it to a positive integer **n**\nthe request will fail if the next write took longer than **n** milliseconds.\n\nThe `client` key define a timeout for when the client was last active. By\nsetting it to a positive **n** integer, the client will be disconnected if it\nhas not been active the last **n** milliseconds.\n\nThe `pings` key defines the amount of pings performed within the span of the\n`client` timeout key. If this value is set, it is recommended to use a value\nstricly higher than 1, as the internal timing of the server is not 100%\naccurate.\n\n##### Size\n\nA lot of different sizes can be adjusted for the WSServer. All sizes but the\n`ringbuffer` are defined in bytes.\n\nThe `payload` size define how large a size of payload the server is willing to\naccept from the client.\n\nThe `header` size define how large a HTTP header the server will accept from\nthe client.\n\nThe `uri` size define how large a URI the server will accept from the client.\n\nThe `buffer` size define how large the internal read and write buffers should\nbe. \n\nThe `thread` size define how large each thread of the WSServer can maximally be.\n\nThe `ringbuffer` size define how many messages about to be written each client\ncan store in their ringbuffer.\n\nThe `frame` size define the maximal payload size of a single frame.\n\nThe `fragmented` size define how many fragments (frames) one single message can\nconsist of.\n\n##### Pool\n\nInternally the WSServer runs a threadpool to schedule IO work from the clients.\n\nThe `worker` key define the amount of threads the threadpool shall consist of.\nGenerally the rule of thumb is that the higher the load, the more threads.\nHowever the optimal amount of workers is probably system and hardware dependent.\n\n##### SSL (WSS)\n\nWSServer supports the *wss* scheme by the use of one of currently 4 SSL\nlibraries ([**OpenSSL**](https://www.openssl.org/), \n[**WolfSSL**](https://www.wolfssl.com/), [**BoringSSL**](https://www.boringssl.googlesource.com/boringssl/), [**LibreSSL**](https://www.libressl.org/)). \nThe default choice is OpenSSL, but the SSL library can be switched as follows:\n\n```\n# OpenSSL\n$ make\n\n# WolfSSL\n$ make SSL=WOLFSSL\n\n# LibreSSL\n$ make SSL_LIBRARY_PATH=/path/to/libressl\n\n# BoringSSL\n$ make SSL_LIBRARY_PATH=/path/to/boringssl\n```\n\nNote that if compiled with `SSL_LIBRARY_PATH` the binary must be executed with\n`LD_LIBRARY_PATH=/path/to/libressl/lib ./bin/WSServer`.\n\nIf LibreSSL or BoringSSL is installed in place of OpenSSL the compilation should\nwork out of the box by running `make`.\n\nIn order to activate SSL some configuration must be made.\n\nThe `key` key define the path to the SSL private key of the server. The private\nkey must be in the PEM format.\n\nThe `cert` key define the path to the SSL server certificate. The certificate\nmust be in the PEM format.\n\nThe `ca_file` key define the path to the root CA certificate.\n\nThe `ca_path` key define the path to a folder containing the trusted root CA\ncertifates.\n\nThe `dhparam` key define the path to the dhparam file. The dhparam file must be\nin the PEM format.\n\nThe `cipher_list` key define the ciphers that the server allows usage of.\n\nThe `cipher_suites` key define the cipher suites that the server allows usage\nof.\n\nThe `compression` key define whether compression should be used when\ncommunicating over SSL,\n\nThe `peer_cert` key define whether a peer certificate is required by the\nclient.\n\n# WebSocket Extensions\n\nThe WSServer enables usage of an arbitrary number of extensions. Extensions\nprovide a mechanism for implementations to opt-in to additional protocol\nfeatures.\n\nThe extensions themselves can be implemented in any language that is able to\ncompile into a shared object (*.so* file) with the following public\nfunctions:\n\n```\ntypedef void (*setAllocators)(WSS_malloc_t extmalloc, WSS_realloc_t extrealloc, WSS_free_t extfree);\ntypedef void (*onInit)(char *config);\ntypedef void (*onOpen)(int fd, char *param, char **accepted, bool *valid);\ntypedef void (*inFrame)(int fd, wss_frame_t *frame);\ntypedef void (*inFrames)(int fd, wss_frame_t **frames, size_t len);\ntypedef void (*outFrame)(int fd, wss_frame_t *frame);\ntypedef void (*outFrames)(int fd, wss_frame_t **frames, size_t len);\ntypedef void (*onClose)(int fd);\ntypedef void (*onDestroy)();\n```\n\nWhere `WSS_malloc_t`, `WSS_realloc_t`, and `WSS_free_t` are defined\nas:\n\n```\ntypedef void *(*WSS_malloc_t)(size_t size);\ntypedef void *(*WSS_realloc_t)(void *ptr, size_t size);\ntypedef void (*WSS_free_t)(void *ptr);\n```\n\nand `wss_frame_t` is defined as:\n\n```\ntypedef struct {\n    bool fin;\n    bool rsv1;\n    bool rsv2;\n    bool rsv3;\n    uint8_t opcode;\n    bool mask;\n    uint64_t payloadLength;\n    char maskingKey[4];\n    char *payload;\n    uint64_t extensionDataLength;\n    uint64_t applicationDataLength;\n} wss_frame_t;\n```\n\nFor the server to be able to use a custom extension one has to configure the\npath to the shared object in the configuration file as described [above](#Extensions).\n\nYou can have a look at the [extensions](https://github.com/mortzdk/websocket/blob/master/extensions) folder to see how to\nimplement your own extension.\n\n### Permessage-deflate\n\nThe WSServer comes with 1 build-in extension, namely the `permessage-deflate`\nextension defined in [RFC7692](https://tools.ietf.org/html/rfc7692). This\nextension enables compression and decompression of the frames between client\nand server.\n\n# WebSocket Subprotocols\n\nThe WSServer also enables usage of an arbitrary number of subprotocols.\nSubprotocols are application-level protocol layered over the WebSocket Protocol\nthat are used to define the behaviour of the websocket protocol.\n\nThe subprotocols themselves can be implemented in any language that is able to\ncompile into a shared object (*.so* file) with the following public\nfunctions:\n\n```\ntypedef void (*setAllocators)(WSS_malloc_t submalloc, WSS_realloc_t subrealloc, WSS_free_t subfree);\ntypedef void (*onInit)(char *config, WSS_send send);\ntypedef void (*onConnect)(int fd, char *ip, int port, char *path, char *cookies);\ntypedef void (*onMessage)(int fd, wss_opcode_t opcode, char *message, size_t message_length);\ntypedef void (*onWrite)(int fd, char *message, size_t message_length);\ntypedef void (*onClose)(int fd);\ntypedef void (*onDestroy)();\n```\n\nWhere `WSS_send`, `WSS_malloc_t`, `WSS_realloc_t`, and `WSS_free_t` are defined\nas:\n\n```\ntypedef void (*WSS_send)(int fd, wss_opcode_t opcode, char *message, uint64_t message_length);\ntypedef void *(*WSS_malloc_t)(size_t size);\ntypedef void *(*WSS_realloc_t)(void *ptr, size_t size);\ntypedef void (*WSS_free_t)(void *ptr);\n```\n\nand `wss_opcode_t` is defined as:\n\n```\ntypedef enum {\n    CONTINUATION_FRAME = 0x0,\n    TEXT_FRAME         = 0x1,\n    BINARY_FRAME       = 0x2,\n    CLOSE_FRAME        = 0x8,\n    PING_FRAME         = 0x9,\n    PONG_FRAME         = 0xA,\n} wss_opcode_t;\n```\n\nYou can have a look at the [subprotocols](https://github.com/mortzdk/websocket/blob/master/extensions) folder to see how to\nimplement your own subprotocol.\n\n### Client Authentication\n\nClient authentication is not implemented directly in WSServer, but is\nsupported through several means. The `onConnect` call of the subprotocol sends\ninformation about the connection to the subprotocol, this is information such\nas the *ip*, *port*, *path* and *cookies*. This can be used to do client\nauthentication using [cookies](https://coletiv.com/blog/using-websockets-with-cookie-based-authentication/), using query parameters of the path \nor simply by having an initial round of authentication messages between the\nclient and server.\n\nAs always it is strongly advised to use the [origins](#Origins) array of the\nconfiguration to only allow for certain origins to use the server.\n\n### Echo\n\nThe `echo` subprotocol is a very simple subprotocol that just echo's whatever\nthe client send back to the client. This subprotocol is especially useful for\ntesting and is used in the [Autobahn testsuite](https://github.com/crossbario/autobahn-testsuite).\n\n### Broadcast\n\nThe `broadcast` subprotocol is slightly more advanced. It keeps track of when a\nclient is connecting or closing in order to hold a map of those clients that\nshould be broadcastet to. Whenever a client sends a message, the message is\nbroadcastet to all other connected clients.\n\n# Documentation\n\nWSServer automatically generates documentation based on the comments in the\ncode. This documentation can be viewed [here](https://mortzdk.github.io/Websocket/documentation/).\n\nFurthermore one could take a look at the [RFC6455](http://tools.ietf.org/html/rfc6455) protocol and the\n[RFC7692](https://tools.ietf.org/html/rfc7692) protocol to understand how WebSockets and the permessage-deflate\nextension works.\n\n# Testing\n\nWSServer has been heavily tested by the use of unit tests, the \n[Autobahn testsuite](https://github.com/crossbario/autobahn-testsuite) and by having code coverage.\n\n### Unit tests\n\nA lot of unit tests has been written using the [Criterion](https://github.com/Snaipe/Criterion) unit testing library. As of right now the unit tests does not cover all files, and this is still work in progress.\n\nThe tests can be run by running `make test`.\n\n### Autobahn Testsuite\n\nThe Autobahn Testsuite is used to verify that the WSServer complies to the \n[RFC6455](http://tools.ietf.org/html/rfc6455) protocol. These tests can be used\nas both verification and as a measure of performance as a lot of the tests\nactually times the execution of a successful test.\n\nThe tests can be run by running `make autobahn`.\n\nYou can further see the current results of the tests [here](https://mortzdk.github.io/Websocket/autobahn/).\n\n### Code coverage\n\nThe coverage report can be generated by running `make test` and the latest can \nbe seen [here](https://mortzdk.github.io/Websocket/gcov/).\n\n# Further Work\n\nHere is a list of prioritized further work that currently can be done:\n\n1. Test on FreeBSD/MacOS\n2. Use Autoconf to check dependencies\n3. Rate limiting\n    - Rate limiting connections\n        - Count-Min Sketch (Sliding window)\n            * Belongs to the server object\n            * Allocate 60 count-min sketches (one per minute)\n            * Reset sketch if rotated\n    - Rate limiting messages\n        - Can be done by the subprotocols per message?\n    - Rate limiting frames\n        - Counting using Sliding window\n            * Belongs to the session object\n            * Allocate 60 integers (one per minute)\n            * Reset sketch if rotated\n4. Fuzz testing\n5. Support HTTP2\n6. Performance Improvements\n    - Look at 'khash' or 'tommy_hashdyn' instead of 'uthash' since these hashes\n      seems to be faster\n    - Realloc the double size of the current\n    - Refactor `wss_frame_t` structure away. Use the frames as byte strings\n      instead.\n    - Callgrind\n    - Cachegrind\n7. Backwards Specification Compability\n    - hybi-06\n    - hybi-05\n    - hybi-04\n    - hixie-76\n    - hixie-75\n\n# Contributors\n\nHere is a list of the contributors of v2.0.0 and above of the WSServer.\n\n[Morten Houmøller Nygaard](https://github.com/mortzdk/)\n[Nicolas Mora](https://github.com/babelouest/)\n\n### Libraries \n\nWSServer makes use of other Open-Source libraries and code snippets. The links\nlisted below have all been used in some way.\n\n* [Fast Validation of UTF-8](https://github.com/lemire/fastvalidate-utf-8/)\n* [UTF-8 Decoder](http://bjoern.hoehrmann.de/utf-8/decoder/dfa/)\n* [SHA1](https://tools.ietf.org/html/rfc3174)\n* [Ringbuf](https://github.com/rmind/ringbuf)\n* [log.c](https://github.com/rxi/log.c)\n* [b64.c](https://github.com/littlstar/b64.c)\n* [rpmalloc](https://github.com/mjansson/rpmalloc)\n* [Threadpool](https://github.com/mbrossard/threadpool)\n* [json-parser](https://github.com/udp/json-parser)\n* [uthash](https://troydhanson.github.io/uthash/)\n* [Http Status Codes](https://github.com/j-ulrich/http-status-codes-cpp)\n\n# License\n\nWSServer is licenced under the [MIT license](https://github.com/mortzdk/Websocket/blob/master/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmortzdk%2FWebsocket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmortzdk%2FWebsocket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmortzdk%2FWebsocket/lists"}