1 /* tcp.c - TCP specific code for echo client */
2 
3 /*
4  * Copyright (c) 2017 Intel Corporation.
5  * Copyright (c) 2018 Nordic Semiconductor ASA.
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_DECLARE(net_echo_client_sample, LOG_LEVEL_DBG);
12 
13 #include <zephyr/kernel.h>
14 #include <errno.h>
15 #include <stdio.h>
16 
17 #include <zephyr/posix/sys/socket.h>
18 #include <zephyr/posix/arpa/inet.h>
19 #include <zephyr/posix/unistd.h>
20 
21 #include <zephyr/net/socket.h>
22 #include <zephyr/net/tls_credentials.h>
23 #include <zephyr/random/random.h>
24 
25 #include "common.h"
26 #include "ca_certificate.h"
27 
28 #define RECV_BUF_SIZE 128
29 
30 /* These proxy server addresses are only used when CONFIG_SOCKS
31  * is enabled. To connect to a proxy server that is not running
32  * under the same IP as the peer or uses a different port number,
33  * modify the values.
34  */
35 #define SOCKS5_PROXY_V6_ADDR CONFIG_NET_CONFIG_PEER_IPV6_ADDR
36 #define SOCKS5_PROXY_V4_ADDR CONFIG_NET_CONFIG_PEER_IPV4_ADDR
37 #define SOCKS5_PROXY_PORT 1080
38 
sendall(int sock,const void * buf,size_t len)39 static ssize_t sendall(int sock, const void *buf, size_t len)
40 {
41 	while (len) {
42 		ssize_t out_len = send(sock, buf, len, 0);
43 
44 		if (out_len < 0) {
45 			return out_len;
46 		}
47 		buf = (const char *)buf + out_len;
48 		len -= out_len;
49 	}
50 
51 	return 0;
52 }
53 
send_tcp_data(struct sample_data * data)54 static int send_tcp_data(struct sample_data *data)
55 {
56 	int ret;
57 
58 	do {
59 		data->tcp.expecting = sys_rand32_get() % ipsum_len;
60 	} while (data->tcp.expecting == 0U);
61 
62 	data->tcp.received = 0U;
63 
64 	ret =  sendall(data->tcp.sock, lorem_ipsum, data->tcp.expecting);
65 
66 	if (ret < 0) {
67 		LOG_ERR("%s TCP: Failed to send data, errno %d", data->proto,
68 			errno);
69 	} else {
70 		if (PRINT_PROGRESS) {
71 			LOG_DBG("%s TCP: Sent %d bytes", data->proto,
72 				data->tcp.expecting);
73 		}
74 	}
75 
76 	return ret;
77 }
78 
compare_tcp_data(struct sample_data * data,const char * buf,uint32_t received)79 static int compare_tcp_data(struct sample_data *data, const char *buf, uint32_t received)
80 {
81 	if (data->tcp.received + received > data->tcp.expecting) {
82 		LOG_ERR("Too much data received: TCP %s", data->proto);
83 		return -EIO;
84 	}
85 
86 	if (memcmp(buf, lorem_ipsum + data->tcp.received, received) != 0) {
87 		LOG_ERR("Invalid data received: TCP %s", data->proto);
88 		return -EIO;
89 	}
90 
91 	return 0;
92 }
93 
start_tcp_proto(struct sample_data * data,sa_family_t family,struct sockaddr * addr,socklen_t addrlen)94 static int start_tcp_proto(struct sample_data *data, sa_family_t family,
95 			   struct sockaddr *addr, socklen_t addrlen)
96 {
97 	int optval;
98 	int ret;
99 
100 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
101 	data->tcp.sock = socket(family, SOCK_STREAM, IPPROTO_TLS_1_2);
102 #else
103 	data->tcp.sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
104 #endif
105 	if (data->tcp.sock < 0) {
106 		LOG_ERR("Failed to create TCP socket (%s): %d", data->proto,
107 			errno);
108 		return -errno;
109 	}
110 
111 	if (IS_ENABLED(CONFIG_SOCKS)) {
112 		struct sockaddr proxy_addr;
113 		socklen_t proxy_addrlen;
114 
115 		if (family == AF_INET) {
116 			struct sockaddr_in *proxy4 =
117 				(struct sockaddr_in *)&proxy_addr;
118 
119 			proxy4->sin_family = AF_INET;
120 			proxy4->sin_port = htons(SOCKS5_PROXY_PORT);
121 			inet_pton(AF_INET, SOCKS5_PROXY_V4_ADDR,
122 				  &proxy4->sin_addr);
123 			proxy_addrlen = sizeof(struct sockaddr_in);
124 		} else if (family == AF_INET6) {
125 			struct sockaddr_in6 *proxy6 =
126 				(struct sockaddr_in6 *)&proxy_addr;
127 
128 			proxy6->sin6_family = AF_INET6;
129 			proxy6->sin6_port = htons(SOCKS5_PROXY_PORT);
130 			inet_pton(AF_INET6, SOCKS5_PROXY_V6_ADDR,
131 				  &proxy6->sin6_addr);
132 			proxy_addrlen = sizeof(struct sockaddr_in6);
133 		} else {
134 			return -EINVAL;
135 		}
136 
137 		ret = setsockopt(data->tcp.sock, SOL_SOCKET, SO_SOCKS5,
138 				 &proxy_addr, proxy_addrlen);
139 		if (ret < 0) {
140 			return ret;
141 		}
142 	}
143 
144 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
145 	sec_tag_t sec_tag_list[] = {
146 		CA_CERTIFICATE_TAG,
147 #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
148 		PSK_TAG,
149 #endif
150 	};
151 
152 	ret = setsockopt(data->tcp.sock, SOL_TLS, TLS_SEC_TAG_LIST,
153 			 sec_tag_list, sizeof(sec_tag_list));
154 	if (ret < 0) {
155 		LOG_ERR("Failed to set TLS_SEC_TAG_LIST option (%s): %d",
156 			data->proto, errno);
157 		ret = -errno;
158 	}
159 
160 	ret = setsockopt(data->tcp.sock, SOL_TLS, TLS_HOSTNAME,
161 			 TLS_PEER_HOSTNAME, sizeof(TLS_PEER_HOSTNAME));
162 	if (ret < 0) {
163 		LOG_ERR("Failed to set TLS_HOSTNAME option (%s): %d",
164 			data->proto, errno);
165 		ret = -errno;
166 	}
167 #endif
168 
169 	/* Prefer IPv6 temporary addresses */
170 	if (family == AF_INET6) {
171 		optval = IPV6_PREFER_SRC_TMP;
172 		(void)setsockopt(data->tcp.sock, IPPROTO_IPV6,
173 				 IPV6_ADDR_PREFERENCES,
174 				 &optval, sizeof(optval));
175 	}
176 
177 	ret = connect(data->tcp.sock, addr, addrlen);
178 	if (ret < 0) {
179 		LOG_ERR("Cannot connect to TCP remote (%s): %d", data->proto,
180 			errno);
181 		ret = -errno;
182 	}
183 
184 	return ret;
185 }
186 
process_tcp_proto(struct sample_data * data)187 static int process_tcp_proto(struct sample_data *data)
188 {
189 	int ret, received;
190 	char buf[RECV_BUF_SIZE];
191 
192 	do {
193 		received = recv(data->tcp.sock, buf, sizeof(buf), MSG_DONTWAIT);
194 
195 		/* No data or error. */
196 		if (received == 0) {
197 			ret = -EIO;
198 			continue;
199 		} else if (received < 0) {
200 			if (errno == EAGAIN || errno == EWOULDBLOCK) {
201 				ret = 0;
202 			} else {
203 				ret = -errno;
204 			}
205 			continue;
206 		}
207 
208 		ret = compare_tcp_data(data, buf, received);
209 		if (ret != 0) {
210 			break;
211 		}
212 
213 		/* Successful comparison. */
214 		data->tcp.received += received;
215 		if (data->tcp.received < data->tcp.expecting) {
216 			continue;
217 		}
218 
219 		if (PRINT_PROGRESS) {
220 			/* Response complete */
221 			LOG_DBG("%s TCP: Received and compared %d bytes, all ok",
222 				data->proto, data->tcp.received);
223 		}
224 
225 		if (++data->tcp.counter % 1000 == 0U) {
226 			LOG_INF("%s TCP: Exchanged %u packets", data->proto,
227 				data->tcp.counter);
228 		}
229 
230 		ret = send_tcp_data(data);
231 		break;
232 	} while (received > 0);
233 
234 	return ret;
235 }
236 
start_tcp(void)237 int start_tcp(void)
238 {
239 	int ret = 0;
240 	struct sockaddr_in addr4;
241 	struct sockaddr_in6 addr6;
242 
243 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
244 		addr6.sin6_family = AF_INET6;
245 		addr6.sin6_port = htons(PEER_PORT);
246 		inet_pton(AF_INET6, CONFIG_NET_CONFIG_PEER_IPV6_ADDR,
247 			  &addr6.sin6_addr);
248 
249 		ret = start_tcp_proto(&conf.ipv6, AF_INET6,
250 				      (struct sockaddr *)&addr6,
251 				      sizeof(addr6));
252 		if (ret < 0) {
253 			return ret;
254 		}
255 	}
256 
257 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
258 		addr4.sin_family = AF_INET;
259 		addr4.sin_port = htons(PEER_PORT);
260 		inet_pton(AF_INET, CONFIG_NET_CONFIG_PEER_IPV4_ADDR,
261 			  &addr4.sin_addr);
262 
263 		ret = start_tcp_proto(&conf.ipv4, AF_INET,
264 				      (struct sockaddr *)&addr4,
265 				      sizeof(addr4));
266 		if (ret < 0) {
267 			return ret;
268 		}
269 	}
270 
271 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
272 		ret = send_tcp_data(&conf.ipv6);
273 		if (ret < 0) {
274 			return ret;
275 		}
276 	}
277 
278 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
279 		ret = send_tcp_data(&conf.ipv4);
280 	}
281 
282 	return ret;
283 }
284 
process_tcp(void)285 int process_tcp(void)
286 {
287 	int ret = 0;
288 
289 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
290 		ret = process_tcp_proto(&conf.ipv6);
291 		if (ret < 0) {
292 			return ret;
293 		}
294 	}
295 
296 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
297 		ret = process_tcp_proto(&conf.ipv4);
298 		if (ret < 0) {
299 			return ret;
300 		}
301 	}
302 
303 	return ret;
304 }
305 
stop_tcp(void)306 void stop_tcp(void)
307 {
308 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
309 		if (conf.ipv6.tcp.sock >= 0) {
310 			(void)close(conf.ipv6.tcp.sock);
311 		}
312 	}
313 
314 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
315 		if (conf.ipv4.tcp.sock >= 0) {
316 			(void)close(conf.ipv4.tcp.sock);
317 		}
318 	}
319 }
320