ws_client.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // SPDX-License-Identifier: GPL-3.0-only
  2. // Copyright (C) 2020 Timotej Šiškovič
  3. #ifndef WS_CLIENT_H
  4. #define WS_CLIENT_H
  5. #include "c-rbuf/cringbuffer.h"
  6. #include "mqtt_wss_log.h"
  7. #include <stdint.h>
  8. #define WS_CLIENT_NEED_MORE_BYTES 0x10
  9. #define WS_CLIENT_PARSING_DONE 0x11
  10. #define WS_CLIENT_CONNECTION_CLOSED 0x12
  11. #define WS_CLIENT_PROTOCOL_ERROR -0x10
  12. #define WS_CLIENT_BUFFER_FULL -0x11
  13. #define WS_CLIENT_INTERNAL_ERROR -0x12
  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. };
  21. enum websocket_client_hdr_parse_state {
  22. WS_HDR_HTTP = 0, // need to check HTTP/1.1
  23. WS_HDR_RC, // need to read HTTP code
  24. WS_HDR_ENDLINE, // need to read rest of the first line
  25. WS_HDR_PARSE_HEADERS, // rest of the header until CRLF CRLF
  26. WS_HDR_PARSE_DONE,
  27. WS_HDR_ALL_DONE
  28. };
  29. enum websocket_client_rx_ws_parse_state {
  30. WS_FIRST_2BYTES = 0,
  31. WS_PAYLOAD_EXTENDED_16,
  32. WS_PAYLOAD_EXTENDED_64,
  33. WS_PAYLOAD_DATA, // BINARY payload to be passed to MQTT
  34. WS_PAYLOAD_CONNECTION_CLOSE,
  35. WS_PAYLOAD_CONNECTION_CLOSE_EC,
  36. WS_PAYLOAD_CONNECTION_CLOSE_MSG,
  37. WS_PAYLOAD_SKIP_UNKNOWN_PAYLOAD,
  38. WS_PAYLOAD_PING_REQ_PAYLOAD, // PING payload to be sent back as PONG
  39. WS_PACKET_DONE
  40. };
  41. enum websocket_opcode {
  42. WS_OP_CONTINUATION_FRAME = 0x0,
  43. WS_OP_TEXT_FRAME = 0x1,
  44. WS_OP_BINARY_FRAME = 0x2,
  45. WS_OP_CONNECTION_CLOSE = 0x8,
  46. WS_OP_PING = 0x9,
  47. WS_OP_PONG = 0xA
  48. };
  49. struct ws_op_close_payload {
  50. uint16_t ec;
  51. char *reason;
  52. };
  53. struct http_header {
  54. char *key;
  55. char *value;
  56. struct http_header *next;
  57. };
  58. typedef struct websocket_client {
  59. enum websocket_client_conn_state state;
  60. struct ws_handshake {
  61. enum websocket_client_hdr_parse_state hdr_state;
  62. char *nonce_reply;
  63. int nonce_matched;
  64. int http_code;
  65. char *http_reply_msg;
  66. struct http_header *headers;
  67. struct http_header *headers_tail;
  68. int hdr_count;
  69. } hs;
  70. struct ws_rx {
  71. enum websocket_client_rx_ws_parse_state parse_state;
  72. enum websocket_opcode opcode;
  73. uint64_t payload_length;
  74. uint64_t payload_processed;
  75. union {
  76. struct ws_op_close_payload op_close;
  77. char *ping_msg;
  78. } specific_data;
  79. } rx;
  80. rbuf_t buf_read; // from SSL
  81. rbuf_t buf_write; // to SSL and then to socket
  82. // TODO if ringbuffer gets multiple tail support
  83. // we can work without buf_to_mqtt and thus reduce
  84. // memory usage and remove one more memcpy buf_read->buf_to_mqtt
  85. rbuf_t buf_to_mqtt; // RAW data for MQTT lib
  86. int entropy_fd;
  87. // careful host is borrowed, don't free
  88. char **host;
  89. mqtt_wss_log_ctx_t log;
  90. } ws_client;
  91. ws_client *ws_client_new(size_t buf_size, char **host, mqtt_wss_log_ctx_t log);
  92. void ws_client_destroy(ws_client *client);
  93. void ws_client_reset(ws_client *client);
  94. int ws_client_start_handshake(ws_client *client);
  95. int ws_client_want_write(ws_client *client);
  96. int ws_client_process(ws_client *client);
  97. int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size);
  98. #endif /* WS_CLIENT_H */