master
h 114 lines 3.28 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef WS_CLIENT_H
4 #define WS_CLIENT_H
5
6 #define WS_CLIENT_NEED_MORE_BYTES 0x10
7 #define WS_CLIENT_PARSING_DONE 0x11
8 #define WS_CLIENT_CONNECTION_CLOSED 0x12
9 #define WS_CLIENT_CONNECTION_REMOTE_CLOSED 0x13
10 #define WS_CLIENT_PROTOCOL_ERROR -0x10
11 #define WS_CLIENT_BUFFER_FULL -0x11
12 #define WS_CLIENT_INTERNAL_ERROR -0x12
13
14 enum websocket_client_conn_state {
15 WS_RAW = 0,
16 WS_HANDSHAKE,
17 WS_ESTABLISHED,
18 WS_ERROR, // connection has to be restarted if this is reached
19 WS_CONN_CLOSED_GRACEFUL,
20 WS_CONN_CLOSED_GRACEFUL_BY_REMOTE,
21 };
22
23 enum websocket_client_hdr_parse_state {
24 WS_HDR_HTTP = 0, // need to check HTTP/1.1
25 WS_HDR_RC, // need to read HTTP code
26 WS_HDR_ENDLINE, // need to read rest of the first line
27 WS_HDR_PARSE_HEADERS, // rest of the header until CRLF CRLF
28 WS_HDR_PARSE_DONE,
29 WS_HDR_ALL_DONE
30 };
31
32 enum websocket_client_rx_ws_parse_state {
33 WS_FIRST_2BYTES = 0,
34 WS_PAYLOAD_EXTENDED_16,
35 WS_PAYLOAD_EXTENDED_64,
36 WS_PAYLOAD_DATA, // BINARY payload to be passed to MQTT
37 WS_PAYLOAD_CONNECTION_CLOSE,
38 WS_PAYLOAD_CONNECTION_CLOSE_EC,
39 WS_PAYLOAD_CONNECTION_CLOSE_MSG,
40 WS_PAYLOAD_SKIP_UNKNOWN_PAYLOAD,
41 WS_PAYLOAD_PING_REQ_PAYLOAD, // PING payload to be sent back as PONG
42 WS_PACKET_DONE
43 };
44
45 enum websocket_opcode {
46 WS_OP_CONTINUATION_FRAME = 0x0,
47 WS_OP_TEXT_FRAME = 0x1,
48 WS_OP_BINARY_FRAME = 0x2,
49 WS_OP_CONNECTION_CLOSE = 0x8,
50 WS_OP_PING = 0x9,
51 WS_OP_PONG = 0xA
52 };
53
54 struct ws_op_close_payload {
55 uint16_t ec;
56 char *reason;
57 };
58
59 struct http_header {
60 char *key;
61 char *value;
62 struct http_header *next;
63 };
64
65 typedef struct websocket_client {
66 enum websocket_client_conn_state state;
67
68 struct ws_handshake {
69 enum websocket_client_hdr_parse_state hdr_state;
70 char *nonce_reply;
71 int nonce_matched;
72 int http_code;
73 char *http_reply_msg;
74 struct http_header *headers;
75 struct http_header *headers_tail;
76 int hdr_count;
77 } hs;
78
79 struct ws_rx {
80 enum websocket_client_rx_ws_parse_state parse_state;
81 enum websocket_opcode opcode;
82 bool remote_closed;
83 uint64_t payload_length;
84 uint64_t payload_processed;
85 union {
86 struct ws_op_close_payload op_close;
87 char *ping_msg;
88 } specific_data;
89 } rx;
90
91 rbuf_t buf_read; // from SSL
92 rbuf_t buf_write; // to SSL and then to socket
93 // TODO if ringbuffer gets multiple tail support
94 // we can work without buf_to_mqtt and thus reduce
95 // memory usage and remove one more memcpy buf_read->buf_to_mqtt
96 rbuf_t buf_to_mqtt; // RAW data for MQTT lib
97
98 // careful host is borrowed, don't free
99 char **host;
100 } ws_client;
101
102 ws_client *ws_client_new(size_t buf_size, char **host);
103 void ws_client_destroy(ws_client *client);
104 void ws_client_reset(ws_client *client);
105
106 int ws_client_start_handshake(ws_client *client);
107
108 int ws_client_want_write(const ws_client *client);
109
110 int ws_client_process(ws_client *client);
111
112 int ws_client_send(const ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size);
113
114 #endif /* WS_CLIENT_H */