1 /* 2 * coap_ws_internal.h -- WebSockets Transport Layer Support for libcoap 3 * 4 * Copyright (C) 2023 Olaf Bergmann <bergmann@tzi.org> 5 * Copyright (C) 2023 Jon Shallow <supjps-libcoap@jpshallow.com> 6 * 7 * SPDX-License-Identifier: BSD-2-Clause 8 * 9 * This file is part of the CoAP library libcoap. Please see README for terms 10 * of use. 11 */ 12 13 /** 14 * @file coap_ws_internal.h 15 * @brief Internal CoAP WebSockets support 16 */ 17 18 #ifndef COAP_WS_INTERNAL_H_ 19 #define COAP_WS_INTERNAL_H_ 20 21 #include "coap_internal.h" 22 23 /** 24 * @ingroup internal_api 25 * @defgroup ws_internal WebSockets Support 26 * Internal API for WebSockets Support (RFC8323) 27 * @{ 28 */ 29 30 31 /* Frame size: Min Header + (Opt) Ext payload length + (Opt) Masking key */ 32 #define COAP_MAX_FS (2 + 8 + 4) 33 34 /** 35 * WebSockets session state 36 */ 37 typedef struct coap_ws_state_t { 38 coap_session_type_t state; /**< Client or Server */ 39 uint8_t up; /**< WebSockets established */ 40 uint8_t seen_first; /**< Seen first request/response HTTP header */ 41 uint8_t seen_host; /**< Seen Host: HTTP header (server) */ 42 uint8_t seen_upg; /**< Seen Upgrade: HTTP header */ 43 uint8_t seen_conn; /**< Seen Connection: HTTP header */ 44 uint8_t seen_key; /**< Seen Key: HTTP header */ 45 uint8_t seen_proto; /**< Seen Protocol: HTTP header */ 46 uint8_t seen_ver; /**< Seen version: HTTP header (server) */ 47 uint8_t sent_close; /**< Close has been sent */ 48 uint8_t recv_close; /**< Close has been received */ 49 uint16_t close_reason; /**< Reason for closing */ 50 int all_hdr_in; /**< Frame header available */ 51 int hdr_ofs; /**< Current offset into rd_header */ 52 uint8_t rd_header[COAP_MAX_FS]; /**< (Partial) frame */ 53 uint8_t mask_key[4]; /**< Masking key */ 54 uint32_t http_ofs; /**< Current offset into http_hdr */ 55 uint8_t http_hdr[80]; /**< (Partial) HTTP header */ 56 size_t data_ofs; /**< Offset into user provided buffer */ 57 size_t data_size; /**< Data size as indicated by WebSocket frame */ 58 uint8_t key[16]; /**< Random, but agreed key value */ 59 } coap_ws_state_t; 60 61 /* 62 * WebSockets Frame 63 * 64 * 0 1 2 3 65 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 66 * +-+-+-+-+-------+-+-------------+-------------------------------+ 67 * |F|R|R|R| opcode|M| Payload len | Extended payload length | 68 * |I|S|S|S| (4) |A| (7) | (16/64) | 69 * |N|V|V|V| |S| | (if payload len==126/127) | 70 * | |1|2|3| |K| | | 71 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + 72 * | Extended payload length continued, if payload len == 127 | 73 * + - - - - - - - - - - - - - - - +-------------------------------+ 74 * | |Masking-key, if MASK set to 1 | 75 * +-------------------------------+-------------------------------+ 76 * | Masking-key (continued) | Payload Data | 77 * +-------------------------------- - - - - - - - - - - - - - - - + 78 * : Payload Data continued ... : 79 * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 80 * | Payload Data continued ... | 81 * +---------------------------------------------------------------+ 82 */ 83 84 #define WS_B0_FIN_BIT 0x80 85 #define WS_B0_RSV_MASK 0x70 86 #define WS_B0_OP_MASK 0x0f 87 88 #define WS_B1_MASK_BIT 0x80 89 #define WS_B1_LEN_MASK 0x7f 90 91 typedef enum { 92 WS_OP_CONT = 0x0, 93 WS_OP_TEXT, 94 WS_OP_BINARY, 95 WS_OP_CLOSE = 0x8, 96 WS_OP_PING, 97 WS_OP_PONG 98 } coap_ws_opcode_t; 99 100 /** 101 * Function interface for websockets data transmission. This function returns 102 * the number of bytes that have been transmitted, or a value less than zero 103 * on error. The number of bytes written may be less than datalen because of 104 * congestion control. 105 * 106 * @param session Session to send data on. 107 * @param data The data to send. 108 * @param datalen The actual length of @p data. 109 * 110 * @return The number of bytes written on success, or a value 111 * less than zero on error. 112 */ 113 ssize_t coap_ws_write(coap_session_t *session, 114 const uint8_t *data, size_t datalen); 115 116 /** 117 * Function interface for websockets data receiving. This function returns 118 * the number of bytes that have been read, or a value less than zero 119 * on error. The number of bytes read may be less than datalen because of 120 * congestion control. 121 * 122 * @param session Session to receive data on. 123 * @param data The data to receive. 124 * @param datalen The maximum length of @p data. 125 * 126 * @return The number of bytes read on success, or a value 127 * less than zero on error. 128 */ 129 ssize_t coap_ws_read(coap_session_t *session, uint8_t *data, 130 size_t datalen); 131 132 /** 133 * Layer function interface for layer below WebSockets accept/connect being 134 * established. This function initiates the WebSockets layer. 135 * 136 * If this layer is properly established on invocation, then the next layer 137 * must get called by calling 138 * session->lfunc[COAP_LAYER_WS].establish(session) 139 * (or done at any point when WebSockets is established). 140 * 141 * @param session Session that the lower layer accept/connect was done on. 142 * 143 */ 144 void coap_ws_establish(coap_session_t *session); 145 146 /** 147 * Layer function interface for WebSockets close for a session. 148 * 149 * @param session Session to do the WebSockets close on. 150 */ 151 void coap_ws_close(coap_session_t *session); 152 153 /** @} */ 154 155 #endif /* COAP_WS_INTERNAL_H */ 156