Skip to content

Commit 6748d58

Browse files
luca-fancellucarlescufi
authored andcommitted
net: zperf: allow TCP receiver to handle multiple connections
Currently the zperf_tcp_receiver can handle only one TCP connection each time, modify the code to poll and handle multiple connections. Take the occasion to unify the bind and listen part of the code between ipv4 and ipv6 part using a structure introduced to handle the multiple connections. Now in case the zsock_recv fails, we can't stop every connection and fail through the error label, so just print the error message and report the failure through the callback. Signed-off-by: Luca Fancellu <[email protected]>
1 parent d485ef0 commit 6748d58

File tree

1 file changed

+93
-71
lines changed

1 file changed

+93
-71
lines changed

subsys/net/lib/zperf/zperf_tcp_receiver.c

Lines changed: 93 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL);
3232
#define TCP_RECEIVER_STACK_SIZE 2048
3333

3434
#define SOCK_ID_IPV4_LISTEN 0
35-
#define SOCK_ID_IPV4_DATA 1
36-
#define SOCK_ID_IPV6_LISTEN 2
37-
#define SOCK_ID_IPV6_DATA 3
38-
#define SOCK_ID_MAX 4
35+
#define SOCK_ID_IPV6_LISTEN 1
36+
#define SOCK_ID_MAX (CONFIG_NET_ZPERF_MAX_SESSIONS + 2)
3937

4038
#define TCP_RECEIVER_BUF_SIZE 1500
4139
#define POLL_TIMEOUT_MS 100
@@ -100,10 +98,50 @@ static void tcp_received(const struct sockaddr *addr, size_t datalen)
10098
}
10199
}
102100

101+
static int tcp_bind_listen_connection(struct zsock_pollfd *pollfd,
102+
struct sockaddr *address)
103+
{
104+
uint16_t port;
105+
int ret;
106+
107+
if (address->sa_family == AF_INET) {
108+
port = ntohs(net_sin(address)->sin_port);
109+
} else {
110+
port = ntohs(net_sin6(address)->sin6_port);
111+
}
112+
113+
ret = zsock_bind(pollfd->fd, address, sizeof(*address));
114+
if (ret < 0) {
115+
NET_ERR("Cannot bind IPv%d TCP port %d (%d)",
116+
(address->sa_family == AF_INET ? 4 : 6), port, errno);
117+
goto out;
118+
}
119+
120+
ret = zsock_listen(pollfd->fd, 1);
121+
if (ret < 0) {
122+
NET_ERR("Cannot listen IPv%d TCP (%d)",
123+
(address->sa_family == AF_INET ? 4 : 6), errno);
124+
goto out;
125+
}
126+
127+
pollfd->events = ZSOCK_POLLIN;
128+
129+
out:
130+
return ret;
131+
}
132+
133+
static void tcp_session_error_report(void)
134+
{
135+
if (tcp_session_cb != NULL) {
136+
tcp_session_cb(ZPERF_SESSION_ERROR, NULL, tcp_user_data);
137+
}
138+
}
139+
103140
static void tcp_server_session(void)
104141
{
105142
static uint8_t buf[TCP_RECEIVER_BUF_SIZE];
106-
struct zsock_pollfd fds[SOCK_ID_MAX] = { 0 };
143+
static struct zsock_pollfd fds[SOCK_ID_MAX];
144+
static struct sockaddr sock_addr[SOCK_ID_MAX];
107145
int ret;
108146

109147
for (int i = 0; i < ARRAY_SIZE(fds); i++) {
@@ -134,7 +172,7 @@ static void tcp_server_session(void)
134172
const struct in_addr *addr =
135173
zperf_get_default_if_in4_addr();
136174
if (!addr) {
137-
NET_ERR("Unable to get IPv4 by default\n");
175+
NET_ERR("Unable to get IPv4 by default");
138176
goto error;
139177
}
140178
memcpy(&in4_addr->sin_addr, addr,
@@ -146,22 +184,15 @@ static void tcp_server_session(void)
146184
NET_INFO("Binding to %s",
147185
net_sprint_ipv4_addr(&in4_addr->sin_addr));
148186

149-
ret = zsock_bind(fds[SOCK_ID_IPV4_LISTEN].fd,
150-
(struct sockaddr *)in4_addr,
151-
sizeof(struct sockaddr_in));
152-
if (ret < 0) {
153-
NET_ERR("Cannot bind IPv4 TCP port %d (%d)",
154-
ntohs(in4_addr->sin_port), errno);
155-
goto error;
156-
}
187+
memcpy(net_sin(&sock_addr[SOCK_ID_IPV4_LISTEN]), in4_addr,
188+
sizeof(struct sockaddr_in));
157189

158-
ret = zsock_listen(fds[SOCK_ID_IPV4_LISTEN].fd, 1);
190+
ret = tcp_bind_listen_connection(
191+
&fds[SOCK_ID_IPV4_LISTEN],
192+
&sock_addr[SOCK_ID_IPV4_LISTEN]);
159193
if (ret < 0) {
160-
NET_ERR("Cannot listen IPv4 TCP (%d)", errno);
161194
goto error;
162195
}
163-
164-
fds[SOCK_ID_IPV4_LISTEN].events = ZSOCK_POLLIN;
165196
}
166197

167198
if (IS_ENABLED(CONFIG_NET_IPV6)) {
@@ -189,7 +220,7 @@ static void tcp_server_session(void)
189220
const struct in6_addr *addr =
190221
zperf_get_default_if_in6_addr();
191222
if (!addr) {
192-
NET_ERR("Unable to get IPv6 by default\n");
223+
NET_ERR("Unable to get IPv6 by default");
193224
goto error;
194225
}
195226
memcpy(&in6_addr->sin6_addr, addr,
@@ -201,29 +232,20 @@ static void tcp_server_session(void)
201232
NET_INFO("Binding to %s",
202233
net_sprint_ipv6_addr(&in6_addr->sin6_addr));
203234

204-
ret = zsock_bind(fds[SOCK_ID_IPV6_LISTEN].fd,
205-
(struct sockaddr *)in6_addr,
206-
sizeof(struct sockaddr_in6));
207-
if (ret < 0) {
208-
NET_ERR("Cannot bind IPv6 TCP port %d (%d)",
209-
ntohs(in6_addr->sin6_port), errno);
210-
goto error;
211-
}
235+
memcpy(net_sin6(&sock_addr[SOCK_ID_IPV6_LISTEN]), in6_addr,
236+
sizeof(struct sockaddr_in6));
212237

213-
ret = zsock_listen(fds[SOCK_ID_IPV6_LISTEN].fd, 1);
238+
ret = tcp_bind_listen_connection(
239+
&fds[SOCK_ID_IPV6_LISTEN],
240+
&sock_addr[SOCK_ID_IPV6_LISTEN]);
214241
if (ret < 0) {
215-
NET_ERR("Cannot listen IPv6 TCP (%d)", errno);
216242
goto error;
217243
}
218-
219-
fds[SOCK_ID_IPV6_LISTEN].events = ZSOCK_POLLIN;
220244
}
221245

222246
NET_INFO("Listening on port %d", tcp_server_port);
223247

224248
while (true) {
225-
struct sockaddr addr_ipv4, addr_ipv6;
226-
227249
ret = zsock_poll(fds, ARRAY_SIZE(fds), POLL_TIMEOUT_MS);
228250
if (ret < 0) {
229251
NET_ERR("TCP receiver poll error (%d)", errno);
@@ -239,84 +261,84 @@ static void tcp_server_session(void)
239261
}
240262

241263
for (int i = 0; i < ARRAY_SIZE(fds); i++) {
242-
struct sockaddr *addr = &addr_ipv6;
243-
socklen_t addrlen = sizeof(struct sockaddr);
244-
245264
if ((fds[i].revents & ZSOCK_POLLERR) ||
246265
(fds[i].revents & ZSOCK_POLLNVAL)) {
247266
NET_ERR("TCP receiver IPv%d socket error",
248-
(i <= SOCK_ID_IPV4_DATA) ? 4 : 6);
267+
(sock_addr[i].sa_family == AF_INET
268+
? 4 : 6));
249269
goto error;
250270
}
251271

252272
if (!(fds[i].revents & ZSOCK_POLLIN)) {
253273
continue;
254274
}
255275

256-
switch (i) {
257-
case SOCK_ID_IPV4_LISTEN:
258-
addr = &addr_ipv4;
259-
__fallthrough;
260-
case SOCK_ID_IPV6_LISTEN:{
261-
int sock = zsock_accept(fds[i].fd, addr, &addrlen);
276+
if ((i >= SOCK_ID_IPV4_LISTEN) && (i <= SOCK_ID_IPV6_LISTEN)) {
277+
int j = SOCK_ID_IPV6_LISTEN + 1;
278+
struct sockaddr addr_incoming_conn;
279+
socklen_t addrlen = sizeof(struct sockaddr);
280+
int sock = zsock_accept(fds[i].fd,
281+
&addr_incoming_conn,
282+
&addrlen);
262283

263284
if (sock < 0) {
264285
NET_ERR("TCP receiver IPv%d accept error",
265-
(i <= SOCK_ID_IPV4_DATA) ? 4 : 6);
286+
(sock_addr[i].sa_family == AF_INET
287+
? 4 : 6));
266288
goto error;
267289
}
268290

269-
if (i == SOCK_ID_IPV4_LISTEN &&
270-
fds[SOCK_ID_IPV4_DATA].fd < 0) {
271-
fds[SOCK_ID_IPV4_DATA].fd = sock;
272-
fds[SOCK_ID_IPV4_DATA].events = ZSOCK_POLLIN;
273-
} else if (i == SOCK_ID_IPV6_LISTEN &&
274-
fds[SOCK_ID_IPV6_DATA].fd < 0) {
275-
fds[SOCK_ID_IPV6_DATA].fd = sock;
276-
fds[SOCK_ID_IPV6_DATA].events = ZSOCK_POLLIN;
277-
} else {
291+
for (; j < SOCK_ID_MAX; j++) {
292+
if (fds[j].fd < 0) {
293+
break;
294+
}
295+
}
296+
297+
if (j == SOCK_ID_MAX) {
278298
/* Too many connections. */
299+
NET_ERR("Dropping TCP connection, reached maximum limit.");
279300
zsock_close(sock);
280-
break;
301+
} else {
302+
fds[j].fd = sock;
303+
fds[j].events = ZSOCK_POLLIN;
304+
memcpy(&sock_addr[j],
305+
&addr_incoming_conn,
306+
addrlen);
281307
}
282-
283-
break;
284-
}
285-
286-
case SOCK_ID_IPV4_DATA:
287-
addr = &addr_ipv4;
288-
__fallthrough;
289-
case SOCK_ID_IPV6_DATA:
308+
} else if ((i > SOCK_ID_IPV6_LISTEN) && (i < SOCK_ID_MAX)) {
290309
ret = zsock_recv(fds[i].fd, buf, sizeof(buf), 0);
291310
if (ret < 0) {
292311
NET_ERR("recv failed on IPv%d socket (%d)",
293-
(i <= SOCK_ID_IPV4_DATA) ? 4 : 6,
312+
(sock_addr[i].sa_family == AF_INET
313+
? 4 : 6),
294314
errno);
295-
goto error;
315+
tcp_session_error_report();
316+
/* This will close the zperf session */
317+
ret = 0;
296318
}
297319

298-
tcp_received(addr, ret);
320+
tcp_received(&sock_addr[i], ret);
299321

300322
if (ret == 0) {
301323
zsock_close(fds[i].fd);
302324
fds[i].fd = -1;
325+
memset(&sock_addr[i], 0,
326+
sizeof(struct sockaddr));
303327
}
304-
305-
break;
328+
} else {
329+
goto error;
306330
}
307331
}
308332
}
309333

310334
error:
311-
if (tcp_session_cb != NULL) {
312-
tcp_session_cb(ZPERF_SESSION_ERROR, NULL,
313-
tcp_user_data);
314-
}
335+
tcp_session_error_report();
315336

316337
cleanup:
317338
for (int i = 0; i < ARRAY_SIZE(fds); i++) {
318339
if (fds[i].fd >= 0) {
319340
zsock_close(fds[i].fd);
341+
memset(&sock_addr[i], 0, sizeof(struct sockaddr));
320342
}
321343
}
322344
}

0 commit comments

Comments
 (0)