• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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