Skip to content

Commit c418b58

Browse files
committed
samples: net: websocket: App for doing Websocket client requests
This is BSD sockets based application for connecting to Websocket server. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 5e25763 commit c418b58

File tree

6 files changed

+318
-0
lines changed

6 files changed

+318
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.13.1)
4+
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
5+
project(http_client)
6+
7+
FILE(GLOB app_sources src/*.c)
8+
target_sources(app PRIVATE ${app_sources})
9+
10+
set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/)
11+
12+
generate_inc_file_for_target(
13+
app
14+
src/echo-apps-cert.der
15+
${gen_dir}/echo-apps-cert.der.inc
16+
)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Networking config
2+
CONFIG_NETWORKING=y
3+
CONFIG_NET_IPV4=y
4+
CONFIG_NET_IPV6=n
5+
CONFIG_NET_TCP=y
6+
CONFIG_NET_SHELL=y
7+
8+
# Sockets
9+
CONFIG_NET_SOCKETS=y
10+
CONFIG_NET_SOCKETS_POSIX_NAMES=y
11+
CONFIG_NET_SOCKETS_POLL_MAX=4
12+
13+
# Network driver config
14+
CONFIG_TEST_RANDOM_GENERATOR=y
15+
16+
# Network address config
17+
CONFIG_NET_CONFIG_SETTINGS=y
18+
CONFIG_NET_CONFIG_NEED_IPV4=y
19+
CONFIG_NET_CONFIG_NEED_IPV6=n
20+
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1"
21+
CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2"
22+
# Address of HTTP IPv4 server
23+
CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2"
24+
CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1"
25+
# Address of HTTP IPv6 server
26+
CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2"
27+
28+
# HTTP & Websocket
29+
CONFIG_HTTP_CLIENT=y
30+
CONFIG_WEBSOCKET_CLIENT=y
31+
32+
# Network debug config
33+
CONFIG_LOG=y
34+
CONFIG_LOG_IMMEDIATE=y
35+
CONFIG_NET_LOG=y
36+
CONFIG_NET_SOCKETS_LOG_LEVEL_DBG=n
37+
CONFIG_NET_HTTP_LOG_LEVEL_DBG=y
38+
CONFIG_NET_WEBSOCKET_LOG_LEVEL_DBG=y
39+
#CONFIG_NET_CONTEXT_LOG_LEVEL_DBG=y
40+
#CONFIG_NET_TCP_LOG_LEVEL_DBG=y
41+
42+
CONFIG_MAIN_STACK_SIZE=2048
43+
CONFIG_HEAP_MEM_POOL_SIZE=1500
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
common:
2+
tags: net http websocket_client
3+
sample:
4+
description: Websocket client sample
5+
name: websocket_client
6+
tests:
7+
sample.net.sockets.websocket_client:
8+
harness: net
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright (c) 2019 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define CA_CERTIFICATE_TAG 1
8+
9+
#define TLS_PEER_HOSTNAME "localhost"
10+
11+
/* This is the same cert as what is found in net-tools/echo-apps-cert.pem file
12+
*/
13+
static const unsigned char ca_certificate[] = {
14+
#include "echo-apps-cert.der.inc"
15+
};
767 Bytes
Binary file not shown.
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/*
2+
* Copyright (c) 2019 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <logging/log.h>
8+
LOG_MODULE_REGISTER(net_websocket_client_sample, LOG_LEVEL_DBG);
9+
10+
#include <net/net_ip.h>
11+
#include <net/socket.h>
12+
#include <net/tls_credentials.h>
13+
#include <net/websocket.h>
14+
15+
#include "ca_certificate.h"
16+
17+
#define PORT 9001
18+
19+
#if defined(CONFIG_NET_CONFIG_PEER_IPV6_ADDR)
20+
#define SERVER_ADDR6 CONFIG_NET_CONFIG_PEER_IPV6_ADDR
21+
#else
22+
#define SERVER_ADDR6 ""
23+
#endif
24+
25+
#if defined(CONFIG_NET_CONFIG_PEER_IPV4_ADDR)
26+
#define SERVER_ADDR4 CONFIG_NET_CONFIG_PEER_IPV4_ADDR
27+
#else
28+
#define SERVER_ADDR4 ""
29+
#endif
30+
31+
#define MAX_RECV_BUF_LEN 512
32+
33+
static u8_t recv_buf_ipv4[MAX_RECV_BUF_LEN];
34+
static u8_t recv_buf_ipv6[MAX_RECV_BUF_LEN];
35+
36+
/* Generated by http://www.lipsum.com/
37+
* 2 paragraphs, 179 words, 1160 bytes of Lorem Ipsum
38+
*/
39+
const char lorem_ipsum[] =
40+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque "
41+
"sodales lorem lorem, sed congue enim vehicula a. Sed finibus diam sed "
42+
"odio ultrices pharetra. Nullam dictum arcu ultricies turpis congue, "
43+
"vel venenatis turpis venenatis. Nam tempus arcu eros, ac congue libero "
44+
"tristique congue. Proin velit lectus, euismod sit amet quam in, "
45+
"maximus condimentum urna. Cras vel erat luctus, mattis orci ut, varius "
46+
"urna. Nam eu lobortis velit."
47+
"\n"
48+
"Nullam sit amet diam vel odio sodales cursus vehicula eu arcu. Proin "
49+
"fringilla, enim nec consectetur mollis, lorem orci interdum nisi, "
50+
"vitae suscipit nisi mauris eu mi. Proin diam enim, mollis ac rhoncus "
51+
"vitae, placerat et eros. Suspendisse convallis, ipsum nec rhoncus "
52+
"aliquam, ex augue ultrices nisl, id aliquet mi diam quis ante. "
53+
"Pellentesque venenatis ornare ultrices. Quisque et porttitor lectus. "
54+
"Ut venenatis nunc et urna imperdiet porttitor non laoreet massa. Donec "
55+
"eleifend eros in mi sagittis egestas. Sed et mi nunc. Nunc vulputate, "
56+
"mauris non ullamcorper viverra, lorem nulla vulputate diam, et congue "
57+
"dui velit non erat. Duis interdum leo et ipsum tempor consequat. In "
58+
"faucibus enim quis purus vulputate nullam."
59+
"\n";
60+
61+
const int ipsum_len = sizeof(lorem_ipsum) - 1;
62+
63+
static int setup_socket(sa_family_t family, const char *server, int port,
64+
int *sock, struct sockaddr *addr, socklen_t addr_len)
65+
{
66+
const char *family_str = family == AF_INET ? "IPv4" : "IPv6";
67+
int ret = 0;
68+
69+
memset(addr, 0, addr_len);
70+
71+
if (family == AF_INET) {
72+
net_sin(addr)->sin_family = AF_INET;
73+
net_sin(addr)->sin_port = htons(port);
74+
inet_pton(family, server, &net_sin(addr)->sin_addr);
75+
} else {
76+
net_sin6(addr)->sin6_family = AF_INET6;
77+
net_sin6(addr)->sin6_port = htons(port);
78+
inet_pton(family, server, &net_sin6(addr)->sin6_addr);
79+
}
80+
81+
if (IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS)) {
82+
sec_tag_t sec_tag_list[] = {
83+
CA_CERTIFICATE_TAG,
84+
};
85+
86+
*sock = socket(family, SOCK_STREAM, IPPROTO_TLS_1_2);
87+
if (*sock >= 0) {
88+
ret = setsockopt(*sock, SOL_TLS, TLS_SEC_TAG_LIST,
89+
sec_tag_list, sizeof(sec_tag_list));
90+
if (ret < 0) {
91+
LOG_ERR("Failed to set %s secure option (%d)",
92+
family_str, -errno);
93+
ret = -errno;
94+
}
95+
96+
ret = setsockopt(*sock, SOL_TLS, TLS_HOSTNAME,
97+
TLS_PEER_HOSTNAME,
98+
sizeof(TLS_PEER_HOSTNAME));
99+
if (ret < 0) {
100+
LOG_ERR("Failed to set %s TLS_HOSTNAME "
101+
"option (%d)", family_str, -errno);
102+
ret = -errno;
103+
} }
104+
} else {
105+
*sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
106+
}
107+
108+
if (*sock < 0) {
109+
LOG_ERR("Failed to create %s HTTP socket (%d)", family_str,
110+
-errno);
111+
}
112+
113+
return ret;
114+
}
115+
116+
static int connect_socket(sa_family_t family, const char *server, int port,
117+
int *sock, struct sockaddr *addr, socklen_t addr_len)
118+
{
119+
int ret;
120+
121+
ret = setup_socket(family, server, port, sock, addr, addr_len);
122+
if (ret < 0 || *sock < 0) {
123+
return -1;
124+
}
125+
126+
ret = connect(*sock, addr, addr_len);
127+
if (ret < 0) {
128+
LOG_ERR("Cannot connect to %s remote (%d)",
129+
family == AF_INET ? "IPv4" : "IPv6",
130+
-errno);
131+
ret = -errno;
132+
}
133+
134+
return ret;
135+
}
136+
137+
static int connect_cb(int sock, struct http_request *req, void *user_data)
138+
{
139+
LOG_INF("Websocket %d for %s connected.", sock, (char *)user_data);
140+
141+
return 0;
142+
}
143+
144+
static ssize_t sendall(int sock, const void *buf, size_t len)
145+
{
146+
return websocket_send_msg(sock, buf, len, WEBSOCKET_OPCODE_DATA_TEXT,
147+
true, true, K_FOREVER);
148+
}
149+
150+
static size_t how_much_to_send(size_t max_len)
151+
{
152+
size_t amount;
153+
154+
do {
155+
amount = sys_rand32_get() % max_len;
156+
} while (amount == 0U);
157+
158+
return amount;
159+
}
160+
161+
void main(void)
162+
{
163+
struct sockaddr_in6 addr6;
164+
struct sockaddr_in addr4;
165+
int sock4 = -1, sock6 = -1;
166+
int websock4 = -1, websock6 = -1;
167+
s32_t timeout = K_FOREVER;
168+
size_t amount;
169+
int ret;
170+
171+
if (IS_ENABLED(CONFIG_NET_IPV4)) {
172+
(void)connect_socket(AF_INET, SERVER_ADDR4, PORT,
173+
&sock4, (struct sockaddr *)&addr4,
174+
sizeof(addr4));
175+
}
176+
177+
if (IS_ENABLED(CONFIG_NET_IPV6)) {
178+
(void)connect_socket(AF_INET6, SERVER_ADDR6, PORT,
179+
&sock6, (struct sockaddr *)&addr6,
180+
sizeof(addr6));
181+
}
182+
183+
if (sock4 < 0 && sock6 < 0) {
184+
LOG_ERR("Cannot create HTTP connection.");
185+
exit(1);
186+
}
187+
188+
if (sock4 >= 0 && IS_ENABLED(CONFIG_NET_IPV4)) {
189+
websock4 = websocket_connect(sock4, SERVER_ADDR4, "/", NULL,
190+
connect_cb, NULL,
191+
recv_buf_ipv4,
192+
sizeof(recv_buf_ipv4),
193+
timeout, "IPv4");
194+
if (websock4 < 0) {
195+
LOG_ERR("Cannot connect to %s:%d", SERVER_ADDR4, PORT);
196+
close(sock4);
197+
}
198+
}
199+
200+
if (sock6 >= 0 && IS_ENABLED(CONFIG_NET_IPV6)) {
201+
websock6 = websocket_connect(sock6, SERVER_ADDR6, "/", NULL,
202+
connect_cb, NULL,
203+
recv_buf_ipv6,
204+
sizeof(recv_buf_ipv6),
205+
timeout, "IPv6");
206+
if (websock6 < 0) {
207+
LOG_ERR("Cannot connect to [%s]:%d", SERVER_ADDR6,
208+
PORT);
209+
close(sock6);
210+
}
211+
}
212+
213+
LOG_INF("Websocket IPv4 %d IPv6 %d", websock4, websock6);
214+
215+
while (1) {
216+
amount = how_much_to_send(ipsum_len);
217+
218+
if (websock4 >= 0) {
219+
ret = sendall(websock4, lorem_ipsum, amount);
220+
if (ret < 0) {
221+
LOG_ERR("%s failed to send data (%d)",
222+
"IPv4", ret);
223+
break;
224+
} else if (ret == 0) {
225+
LOG_DBG("%s connection closed", "IPv4");
226+
break;
227+
} else {
228+
LOG_DBG("%s sent %d bytes", "IPv4", ret);
229+
}
230+
}
231+
232+
k_sleep(K_SECONDS(1));
233+
}
234+
235+
k_sleep(K_FOREVER);
236+
}

0 commit comments

Comments
 (0)