Skip to content

Commit 110a221

Browse files
committed
net: websocket: client: Simple API for Websocket client
Implement simple API to do Websocket client requests. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 7769f9e commit 110a221

File tree

8 files changed

+1344
-0
lines changed

8 files changed

+1344
-0
lines changed

include/net/websocket.h

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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 <kernel.h>
17+
18+
#include <net/net_ip.h>
19+
#include <net/http_parser.h>
20+
#include <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+
* @ingroup networking
30+
* @{
31+
*/
32+
33+
/** Message type values. Returned in websocket_recv_msg() */
34+
#define WEBSOCKET_FLAG_FINAL 0x00000001 /**< Final frame */
35+
#define WEBSOCKET_FLAG_TEXT 0x00000002 /**< Textual data */
36+
#define WEBSOCKET_FLAG_BINARY 0x00000004 /**< Binary data */
37+
#define WEBSOCKET_FLAG_CLOSE 0x00000008 /**< Closing connection */
38+
#define WEBSOCKET_FLAG_PING 0x00000010 /**< Ping message */
39+
#define WEBSOCKET_FLAG_PONG 0x00000011 /**< Pong message */
40+
41+
enum websocket_opcode {
42+
WEBSOCKET_OPCODE_CONTINUE = 0x00,
43+
WEBSOCKET_OPCODE_DATA_TEXT = 0x01,
44+
WEBSOCKET_OPCODE_DATA_BINARY = 0x02,
45+
WEBSOCKET_OPCODE_CLOSE = 0x08,
46+
WEBSOCKET_OPCODE_PING = 0x09,
47+
WEBSOCKET_OPCODE_PONG = 0x0A,
48+
};
49+
50+
/**
51+
* @typedef websocket_connect_cb_t
52+
* @brief Callback called after Websocket connection is established.
53+
*
54+
* @param sock Websocket id
55+
* @param req HTTP handshake request
56+
* @param user_data A valid pointer on some user data or NULL
57+
*
58+
* @return 0 if ok, <0 if there is an error and connection should be aborted
59+
*/
60+
typedef int (*websocket_connect_cb_t)(int ws_sock, struct http_request *req,
61+
void *user_data);
62+
63+
/**
64+
* Websocket client connection request. This contains all the data that is
65+
* needed when doing a Websocket connection request.
66+
*/
67+
struct websocket_request {
68+
/** Host of the Websocket server when doing HTTP handshakes. */
69+
const char *host;
70+
71+
/** URL of the Websocket. */
72+
const char *url;
73+
74+
/** User supplied callback function to call when optional headers need
75+
* to be sent. This can be NULL, in which case the optional_headers
76+
* field in http_request is used. The idea of this optional_headers
77+
* callback is to allow user to send more HTTP header data that is
78+
* practical to store in allocated memory.
79+
*/
80+
http_header_cb_t optional_headers_cb;
81+
82+
/** A NULL terminated list of any optional headers that
83+
* should be added to the HTTP request. May be NULL.
84+
* If the optional_headers_cb is specified, then this field is ignored.
85+
*/
86+
const char **optional_headers;
87+
88+
/** User supplied callback function to call when a connection is
89+
* established.
90+
*/
91+
websocket_connect_cb_t cb;
92+
93+
/** User supplied list of callback functions if the calling application
94+
* wants to know the parsing status or the HTTP fields during the
95+
* handshake. This is optional parameter and normally not needed but
96+
* is useful if the caller wants to know something about
97+
* the fields that the server is sending.
98+
*/
99+
const struct http_parser_settings *http_cb;
100+
101+
/** User supplied buffer where HTTP connection data is stored */
102+
u8_t *tmp_buf;
103+
104+
/** Length of the user supplied temp buffer */
105+
size_t tmp_buf_len;
106+
};
107+
108+
/**
109+
* @brief Connect to a server that provides Websocket service. The callback is
110+
* called after connection is established. The returned value is a new socket
111+
* descriptor that can be used to send / receive data using the BSD socket API.
112+
*
113+
* @param http_sock Socket id to the server. Note that this socket is used to do
114+
* HTTP handshakes etc. The actual Websocket connectivity is done via the
115+
* returned websocket id. Note that the http_sock must not be closed
116+
* after this function returns as it is used to deliver the Websocket
117+
* packets to the Websocket server.
118+
* @param req Websocket request. User should allocate and fill the request
119+
* data.
120+
* @param timeout Max timeout to wait for the connection. The timeout value
121+
* cannot be 0 as there would be no time to receive the data.
122+
* @param user_data User specified data that is passed to the callback.
123+
*
124+
* @return Websocket id to be used when sending/receiving Websocket data.
125+
*/
126+
int websocket_connect(int http_sock, struct websocket_request *req,
127+
s32_t timeout, void *user_data);
128+
129+
/**
130+
* @brief Send websocket msg to peer.
131+
*
132+
* @details The function will automatically add websocket header to the
133+
* message.
134+
*
135+
* @param ws_sock Websocket id returned by websocket_connect().
136+
* @param payload Websocket data to send.
137+
* @param payload_len Length of the data to be sent.
138+
* @param opcode Operation code (text, binary, ping, pong, close)
139+
* @param mask Mask the data, see RFC 6455 for details
140+
* @param final Is this final message for this message send. If final == false,
141+
* then the first message must have valid opcode and subsequent messages
142+
* must have opcode WEBSOCKET_OPCODE_CONTINUE. If final == true and this
143+
* is the only message, then opcode should have proper opcode (text or
144+
* binary) set.
145+
* @param timeout How long to try to send the message.
146+
*
147+
* @return <0 if error, >=0 amount of bytes sent
148+
*/
149+
int websocket_send_msg(int ws_sock, const u8_t *payload, size_t payload_len,
150+
enum websocket_opcode opcode, bool mask, bool final,
151+
s32_t timeout);
152+
153+
/**
154+
* @brief Receive websocket msg from peer.
155+
*
156+
* @details The function will automatically remove websocket header from the
157+
* message.
158+
*
159+
* @param ws_sock Websocket id returned by websocket_connect().
160+
* @param buf Buffer where websocket data is read.
161+
* @param buf_len Length of the data buffer.
162+
* @param message_type Type of the message.
163+
* @param remaining How much there is data left in the message after this read.
164+
* @param timeout How long to try to receive the message.
165+
*
166+
* @return <0 if error, >=0 amount of bytes received
167+
*/
168+
int websocket_recv_msg(int ws_sock, u8_t *buf, size_t buf_len,
169+
u32_t *message_type, u64_t *remaining, s32_t timeout);
170+
171+
/**
172+
* @brief Close websocket.
173+
*
174+
* @details One must call websocket_connect() after this call to re-establish
175+
* the connection.
176+
*
177+
* @param ws_sock Websocket id returned by websocket_connect().
178+
*/
179+
int websocket_disconnect(int ws_sock);
180+
181+
#if defined(CONFIG_WEBSOCKET_CLIENT)
182+
void websocket_init(void);
183+
#else
184+
static inline void websocket_init(void)
185+
{
186+
}
187+
#endif
188+
189+
#ifdef __cplusplus
190+
}
191+
#endif
192+
193+
/**
194+
* @}
195+
*/
196+
197+
#endif /* ZEPHYR_INCLUDE_NET_WEBSOCKET_H_ */

subsys/net/ip/net_core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ LOG_MODULE_REGISTER(net_core, CONFIG_NET_CORE_LOG_LEVEL);
2727
#include <net/net_core.h>
2828
#include <net/dns_resolve.h>
2929
#include <net/gptp.h>
30+
#include <net/websocket.h>
3031

3132
#if defined(CONFIG_NET_LLDP)
3233
#include <net/lldp.h>
@@ -450,6 +451,7 @@ static inline int services_init(void)
450451
}
451452

452453
dns_init_resolver();
454+
websocket_init();
453455

454456
net_shell_init();
455457

subsys/net/lib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ if(CONFIG_HTTP_PARSER_URL OR CONFIG_HTTP_PARSER OR CONFIG_HTTP_CLIENT)
2121
add_subdirectory(http)
2222
endif()
2323

24+
add_subdirectory_ifdef(CONFIG_WEBSOCKET_CLIENT websocket)
2425
add_subdirectory_ifdef(CONFIG_OPENTHREAD_PLAT openthread)

subsys/net/lib/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ source "subsys/net/lib/mqtt/Kconfig"
1414

1515
source "subsys/net/lib/http/Kconfig"
1616

17+
source "subsys/net/lib/websocket/Kconfig"
18+
1719
source "subsys/net/lib/lwm2m/Kconfig"
1820

1921
source "subsys/net/lib/socks/Kconfig"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library_named(websocket_client)
4+
zephyr_include_directories(${ZEPHYR_BASE}/subsys/net/lib/sockets)
5+
6+
zephyr_library_sources(
7+
websocket.c
8+
)
9+
10+
zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS)

subsys/net/lib/websocket/Kconfig

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Copyright (c) 2019 Intel Corporation
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
#
5+
6+
menuconfig WEBSOCKET_CLIENT
7+
bool "Websocket client support [EXPERIMENTAL]"
8+
select NET_SOCKETS
9+
select HTTP_PARSER
10+
select HTTP_PARSER_URL
11+
select HTTP_CLIENT
12+
select MBEDTLS
13+
select BASE64
14+
help
15+
Enable Websocket client library.
16+
17+
if WEBSOCKET_CLIENT
18+
19+
config WEBSOCKET_MAX_CONTEXTS
20+
int "Max number of websockets to allocate"
21+
default 1
22+
help
23+
How many Websockets can be created in the system.
24+
25+
module = NET_WEBSOCKET
26+
module-dep = NET_LOG
27+
module-str = Log level for Websocket
28+
module-help = Enable debug message of Websocket client library.
29+
source "subsys/net/Kconfig.template.log_config.net"
30+
31+
endif

0 commit comments

Comments
 (0)