1 /** @file
2  * @brief Websocket API
3  *
4  * An API for applications to setup websocket connections
5  */
6 
7 /*
8  * Copyright (c) 2019 Intel Corporation
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 
13 #ifndef ZEPHYR_INCLUDE_NET_WEBSOCKET_H_
14 #define ZEPHYR_INCLUDE_NET_WEBSOCKET_H_
15 
16 #include <zephyr/kernel.h>
17 
18 #include <zephyr/net/net_ip.h>
19 #include <zephyr/net/http/parser.h>
20 #include <zephyr/net/http/client.h>
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25 
26 /**
27  * @brief Websocket API
28  * @defgroup websocket Websocket API
29  * @since 1.12
30  * @version 0.1.0
31  * @ingroup networking
32  * @{
33  */
34 
35 /** Message type values. Returned in websocket_recv_msg() */
36 #define WEBSOCKET_FLAG_FINAL  0x00000001 /**< Final frame        */
37 #define WEBSOCKET_FLAG_TEXT   0x00000002 /**< Textual data       */
38 #define WEBSOCKET_FLAG_BINARY 0x00000004 /**< Binary data        */
39 #define WEBSOCKET_FLAG_CLOSE  0x00000008 /**< Closing connection */
40 #define WEBSOCKET_FLAG_PING   0x00000010 /**< Ping message       */
41 #define WEBSOCKET_FLAG_PONG   0x00000020 /**< Pong message       */
42 
43 /** @brief Websocket option codes */
44 enum websocket_opcode  {
45 	WEBSOCKET_OPCODE_CONTINUE     = 0x00, /**< Message continues */
46 	WEBSOCKET_OPCODE_DATA_TEXT    = 0x01, /**< Textual data */
47 	WEBSOCKET_OPCODE_DATA_BINARY  = 0x02, /**< Binary data */
48 	WEBSOCKET_OPCODE_CLOSE        = 0x08, /**< Closing connection */
49 	WEBSOCKET_OPCODE_PING         = 0x09, /**< Ping message */
50 	WEBSOCKET_OPCODE_PONG         = 0x0A, /**< Pong message */
51 };
52 
53 /**
54  * @typedef websocket_connect_cb_t
55  * @brief Callback called after Websocket connection is established.
56  *
57  * @param ws_sock Websocket id
58  * @param req HTTP handshake request
59  * @param user_data A valid pointer on some user data or NULL
60  *
61  * @return 0 if ok, <0 if there is an error and connection should be aborted
62  */
63 typedef int (*websocket_connect_cb_t)(int ws_sock, struct http_request *req,
64 				      void *user_data);
65 
66 /**
67  * Websocket client connection request. This contains all the data that is
68  * needed when doing a Websocket connection request.
69  */
70 struct websocket_request {
71 	/** Host of the Websocket server when doing HTTP handshakes. */
72 	const char *host;
73 
74 	/** URL of the Websocket. */
75 	const char *url;
76 
77 	/** User supplied callback function to call when optional headers need
78 	 * to be sent. This can be NULL, in which case the optional_headers
79 	 * field in http_request is used. The idea of this optional_headers
80 	 * callback is to allow user to send more HTTP header data that is
81 	 * practical to store in allocated memory.
82 	 */
83 	http_header_cb_t optional_headers_cb;
84 
85 	/** A NULL terminated list of any optional headers that
86 	 * should be added to the HTTP request. May be NULL.
87 	 * If the optional_headers_cb is specified, then this field is ignored.
88 	 */
89 	const char **optional_headers;
90 
91 	/** User supplied callback function to call when a connection is
92 	 * established.
93 	 */
94 	websocket_connect_cb_t cb;
95 
96 	/** User supplied list of callback functions if the calling application
97 	 * wants to know the parsing status or the HTTP fields during the
98 	 * handshake. This is optional parameter and normally not needed but
99 	 * is useful if the caller wants to know something about
100 	 * the fields that the server is sending.
101 	 */
102 	const struct http_parser_settings *http_cb;
103 
104 	/** User supplied buffer where HTTP connection data is stored */
105 	uint8_t *tmp_buf;
106 
107 	/** Length of the user supplied temp buffer */
108 	size_t tmp_buf_len;
109 };
110 
111 /**
112  * @brief Connect to a server that provides Websocket service. The callback is
113  * called after connection is established. The returned value is a new socket
114  * descriptor that can be used to send / receive data using the BSD socket API.
115  *
116  * @param http_sock Socket id to the server. Note that this socket is used to do
117  *        HTTP handshakes etc. The actual Websocket connectivity is done via the
118  *        returned websocket id. Note that the http_sock must not be closed
119  *        after this function returns as it is used to deliver the Websocket
120  *        packets to the Websocket server.
121  * @param req Websocket request. User should allocate and fill the request
122  *        data.
123  * @param timeout Max timeout to wait for the connection. The timeout value is
124  *        in milliseconds. Value SYS_FOREVER_MS means to wait forever.
125  * @param user_data User specified data that is passed to the callback.
126  *
127  * @return Websocket id to be used when sending/receiving Websocket data.
128  */
129 int websocket_connect(int http_sock, struct websocket_request *req,
130 		      int32_t timeout, void *user_data);
131 
132 /**
133  * @brief Send websocket msg to peer.
134  *
135  * @details The function will automatically add websocket header to the
136  * message.
137  *
138  * @param ws_sock Websocket id returned by websocket_connect().
139  * @param payload Websocket data to send.
140  * @param payload_len Length of the data to be sent.
141  * @param opcode Operation code (text, binary, ping, pong, close)
142  * @param mask Mask the data, see RFC 6455 for details
143  * @param final Is this final message for this message send. If final == false,
144  *        then the first message must have valid opcode and subsequent messages
145  *        must have opcode WEBSOCKET_OPCODE_CONTINUE. If final == true and this
146  *        is the only message, then opcode should have proper opcode (text or
147  *        binary) set.
148  * @param timeout How long to try to send the message. The value is in
149  *        milliseconds. Value SYS_FOREVER_MS means to wait forever.
150  *
151  * @return <0 if error, >=0 amount of bytes sent
152  */
153 int websocket_send_msg(int ws_sock, const uint8_t *payload, size_t payload_len,
154 		       enum websocket_opcode opcode, bool mask, bool final,
155 		       int32_t timeout);
156 
157 /**
158  * @brief Receive websocket msg from peer.
159  *
160  * @details The function will automatically remove websocket header from the
161  * message.
162  *
163  * @param ws_sock Websocket id returned by websocket_connect().
164  * @param buf Buffer where websocket data is read.
165  * @param buf_len Length of the data buffer.
166  * @param message_type Type of the message.
167  * @param remaining How much there is data left in the message after this read.
168  * @param timeout How long to try to receive the message.
169  *        The value is in milliseconds. Value SYS_FOREVER_MS means to wait
170  *        forever.
171  *
172  * @retval >=0 amount of bytes received.
173  * @retval -EAGAIN on timeout.
174  * @retval -ENOTCONN on socket close.
175  * @retval -errno other negative errno value in case of failure.
176  */
177 int websocket_recv_msg(int ws_sock, uint8_t *buf, size_t buf_len,
178 		       uint32_t *message_type, uint64_t *remaining,
179 		       int32_t timeout);
180 
181 /**
182  * @brief Close websocket.
183  *
184  * @details One must call websocket_connect() after this call to re-establish
185  * the connection.
186  *
187  * @param ws_sock Websocket id returned by websocket_connect().
188  *
189  * @return <0 if error, 0 the connection was closed successfully
190  */
191 int websocket_disconnect(int ws_sock);
192 
193 /**
194  * @brief Register a socket as websocket. This is called by HTTP server
195  *        when a connection is upgraded to a websocket connection.
196  *
197  * @param http_sock Underlying socket connection socket.
198  * @param recv_buf Temporary receive buffer for websocket parsing. This must
199  *        point to a memory area that is valid for the duration of the whole
200  *        websocket session.
201  * @param recv_buf_len Length of the temporary receive buffer.
202  *
203  * @return <0 if error, >=0 the actual websocket to be used by application
204  */
205 int websocket_register(int http_sock, uint8_t *recv_buf, size_t recv_buf_len);
206 
207 /**
208  * @brief Unregister a websocket. This is called when we no longer need
209  *        the underlying "real" socket. This will close first the websocket
210  *        and then the original socket.
211  *
212  * @param ws_sock Websocket connection socket.
213  *
214  * @return <0 if error, 0 the websocket connection is now fully closed
215  */
216 int websocket_unregister(int ws_sock);
217 
218 /** @cond INTERNAL_HIDDEN */
219 
220 #if defined(CONFIG_WEBSOCKET_CLIENT)
221 void websocket_init(void);
222 #else
websocket_init(void)223 static inline void websocket_init(void)
224 {
225 }
226 #endif
227 
228 /** @endcond */
229 
230 #ifdef __cplusplus
231 }
232 #endif
233 
234 /**
235  * @}
236  */
237 
238 #endif /* ZEPHYR_INCLUDE_NET_WEBSOCKET_H_ */
239