From abf8edf1b869c52139d6ddf2e5f6806d5a357be7 Mon Sep 17 00:00:00 2001 From: hiddenalpha.ch Date: Tue, 20 Oct 2026 22:48:56 +0200 Subject: Throw in a 1st draft of a Websocket client --- include/qntan/Qntan.h | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) (limited to 'include') diff --git a/include/qntan/Qntan.h b/include/qntan/Qntan.h index a7d2c85..8144bc6 100644 --- a/include/qntan/Qntan.h +++ b/include/qntan/Qntan.h @@ -97,6 +97,7 @@ struct Qntan_JsonDec; struct Qntan_JsonDec_Mentor; struct Qntan_JsonTreeDec_JsonNode; struct Qntan_JsonTreeDec; +struct Qntan_WebsocketClient; struct Qntan_Websocket; struct Qntan_XmlDec; struct Qntan_XmlDec_Mentor; @@ -1836,9 +1837,113 @@ struct Qntan_JsonTreeDec { +#ifndef Qntan_WebsocketClient_onIncommingMsg +# define Qntan_WebsocketClient_onIncommingMsg(A, B, C) (*A)->onIncommingMsg(A, B, C) +#endif +#ifndef Qntan_WebsocketClient_sendMsg +# define Qntan_WebsocketClient_sendMsg(A, B, C, D, E, F) (*A)->sendMsg(A, B, C, D, E, F) +#endif +#ifndef Qntan_WebsocketClient_ping +# define Qntan_WebsocketClient_ping(A, B, C, D, E, F) (*A)->ping(A, B, C, D, E, F) +#endif +#ifndef Qntan_WebsocketClient_pong +# define Qntan_WebsocketClient_pong(A, B, C, D, E, F) (*A)->pong(A, B, C, D, E, F) +#endif +#ifndef Qntan_WebsocketClient_shutdown +# define Qntan_WebsocketClient_shutdown(A, B, C, D, E) (*A)->shutdown(A, B, C, D, E) +#endif + +struct Qntan_WebsocketClient { + /* Websocket client for + * https://www.rfc-editor.org/info/rfc6455/ + */ + // + void (*onIncomingMsg)( struct Qntan_WebsocketClient**, + void(*onMsg)(Qntan_Cls c1, + int flgs, char const*payload, int64_t payload_len, + struct Qntan_WebsocketClient**ws, + void(*onMsgDone)(Qntan_Cls c2), Qntan_Cls c2), + Qntan_Cls c1 ); + /* Sets `onMsg` as the handler for incoming websocket messages. + * + * `flgs & 1`: `buf` is of type `utf8`. + * `flgs & 2`: This is "just another chunk" to the same message as before. + * `flgs & 4`: This is the last chunk of this message. + * `flgs & 8`: This is a `PING` message. + * `flgs & 16`: This is a `PONG` message. + * `flgs & 32`: This is a "connection-close" websocket message. + * + * `ws` is a reference to this websocket for convenience reasons. + * + * `buf` stays valid until `onMsgDone` gets called. + */ + // + void (*sendMsg)( struct Qntan_WebsocketClient**, + char const *payload, int64_t payload_len, int flg, + void(*onDone)(int,Qntan_Cls), Qntan_Cls ); + /* `flg & 1` indicates this msg is fragmented and more frames will + * follow. + * `flg & 2` sets the message to be a `text` frame. If not set, + * the message defaults to a `binary` payload. + * `flg & 4` indicates that this is the last message on this + * websocket channel. If set, this has the same effect of calling + * `ws.shutdown()` after sending the message. + * 'payload' MUST stay valid until `onDone` got called. + * Calls to `sendMsg()` MUST NOT overlap. So as long a send call + * is in progress, `sendMsg()` MUST NOT be called meanwhile. + * `onDone`: negative `int` indicates errors. + */ + // + void (*ping)( struct Qntan_WebsocketClient**, + char const*payload, int payload_len, int flg, + void(*onDone)(int,Qntan_cls), Qntan_cls ); + /* Send a ping message. Same as `Qntan_Websocket.ping()`. Meaning of + * `flg` see `sendMsg()`. WARN: Be aware, only the `text` flag can + * be used for `ping` messages. For example as `ping` is a control + * frame, it MUST NOT be fragmeted and so that flag makes no sense. + */ + // + void (*pong)( struct Qntan_WebsocketClient**, + char const*payload, int payload_len, int flg, + void(*onDone)(int,Qntan_Cls), Qntan_Cls ); + /* Send a pong reply. `payload` MUST contain the data received in + * the `ping` we respond to. (Same as 'Qntan_Websocket.pong()'). Meaning + * of `flg` see `sendMsg()`. WARN: Be aware, only the `text` flag can be + * used for `ping` messages. For example as `ping` is a control frame, it + * MUST NOT be fragmeted and so that flag makes no sense. + */ + // + void (*shutdown)( struct Qntan_WebsocketClient**, + char const*payload, int payload_len, + void(*onDone)(int err,Qntan_Cls), Qntan_Cls ); + /* Same as 'Qntan_Websocket.shutdown()': Indicates we're done sending + * messages. The implementation will send a `ConnectionClose` (if none + * sent yet) message and then TCP-FIN the underlying connection. + * + * `payload_len` MUST be in range `0..125`. `payload[0]` (if status + * present) MUST be the most significant octet of the status code of + * type u16. `payload[1]` (if status present) MUST be the least + * significant octet of the status code of type u16. If present, the + * status message follows from `payload[2]` onwards. + * + * `err` below zero indicates errors. + */ +}; + + + + + + + + + + struct Qntan_Websocket { /* CoDec for * https://www.rfc-editor.org/info/rfc6455/ + * + * TODO rename to `Qntan_WebsocketServer`. */ // void (*reset)( struct Qntan_Websocket**, -- cgit v1.3.1