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