1 /*------------------------------------------------------------------------------
2 * CMSIS-Driver_Validation - Tools
3 * Copyright (c) 2019 ARM Germany GmbH. All rights reserved.
4 *------------------------------------------------------------------------------
6 * Purpose: Implements ECHO, DISCARD and CHARGEN standard services
7 * - Echo Protocol service [RFC 862]
8 * - Discard Protocol service [RFC 863]
9 * - Character Generator Protocol service [RFC 864]
10 *----------------------------------------------------------------------------*/
12 #define VERSION "v1.1"
20 #include "SockServer.h"
22 // Link with ws2_32.lib
23 #pragma comment(lib, "Ws2_32.lib")
25 // Global status variables
26 SOCKADDR_IN remote_addr; // Remote IP address and port
27 uint32_t rx_cnt; // Receive count
28 uint32_t tx_cnt; // Transmit count
30 // Generate character array for transmit
31 static char gen_char (char *buf, char setchar, uint32_t len) {
35 if ((++setchar < 0x21) || (setchar == 0x7f)) {
38 for (i = 0, ch = setchar; i < (len-2); i++) {
40 if (++ch == 0x7f) ch = 0x21;
48 static void print_status (void) {
49 printf("\rAddr=%s, rx_cnt=%d, tx_cnt=%d",inet_ntoa(remote_addr.sin_addr),rx_cnt,tx_cnt);
52 // Datagram server thread
53 // (runs ECHO and CHARGEN services)
54 DWORD WINAPI DgramServer (void *argument) {
56 int32_t sock_echo,sock_chargen;
57 int32_t nfds,rc,sa_len;
63 sock_echo = socket (PF_INET, SOCK_DGRAM, 0);
64 sock_chargen = socket (PF_INET, SOCK_DGRAM, 0);
67 sa.sin_family = AF_INET;
68 sa.sin_addr.s_addr = INADDR_ANY;
70 sa.sin_port = htons (ECHO_PORT);
71 bind (sock_echo, (SOCKADDR *)&sa, sizeof(sa));
73 sa.sin_port = htons (CHARGEN_PORT);
74 bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
77 buff = malloc (BUFF_SIZE);
82 FD_SET(sock_echo, &fds);
83 FD_SET(sock_chargen, &fds);
86 if (sock_chargen > nfds) nfds = sock_chargen;
91 // Wait for the packet
92 select (nfds+1, &fds, 0, 0, &tv);
94 if (FD_ISSET(sock_echo, &fds)) {
95 // Data ready, recvfrom will not block
97 rc = recvfrom (sock_echo, buff, BUFF_SIZE, 0, (SOCKADDR *)&sa, &sa_len);
100 memcpy (&remote_addr, &sa, sizeof(sa));
101 rc = sendto (sock_echo, buff, rc, 0, (SOCKADDR *)&sa, sa_len);
102 if (rc > 0) tx_cnt += rc;
110 if (FD_ISSET(sock_chargen, &fds)) {
111 // Data ready, recvfrom will not block
112 sa_len = sizeof (sa);
113 rc = recvfrom (sock_chargen, buff, BUFF_SIZE, 0, (SOCKADDR *)&sa, &sa_len);
116 memcpy (&remote_addr, &sa, sizeof(sa));
117 int32_t len = rand() >> 22;
118 if (len < 2) len = 2;
119 if (len > BUFF_SIZE) len = BUFF_SIZE;
120 setchar = gen_char (buff, setchar, len);
121 rc = sendto (sock_chargen, buff, len, 0, (SOCKADDR *)&sa, sa_len);
122 if (rc > 0) tx_cnt += rc;
134 // ECHO stream socket handler
135 DWORD WINAPI EchoThread (void *argument) {
136 int32_t sock = (int32_t)argument;
139 char *buff = malloc (BUFF_SIZE);
141 rc = recv (sock, buff, BUFF_SIZE, 0);
144 rc = send (sock, buff, rc, 0);
147 // ESC terminates the thread
148 if (buff[0] == ESC) break;
156 // CHARGEN stream socket handler
157 DWORD WINAPI ChargenThread (void *argument) {
158 int32_t rc,sock = (int32_t)argument;
159 char buff[82],setchar = '@';
160 unsigned long enable = 1;
162 // Set non-blocking mode
163 ioctlsocket (sock, FIONBIO, &enable);
165 rc = recv (sock, buff, sizeof(buff), 0);
168 // ESC terminates the thread
169 if (buff[0] == ESC) break;
172 // Non-blocking mode, check error code
173 if (WSAGetLastError() != WSAEWOULDBLOCK) break;
175 setchar = gen_char (buff, setchar, 81);
176 rc = send (sock, buff, 81, 0);
186 // DISCARD stream socket handler
187 DWORD WINAPI DiscardThread (void *argument) {
188 int32_t rc,sock = (int32_t)argument;
192 rc = recv (sock, buff, sizeof(buff), 0);
195 // ESC terminates the thread
196 if (buff[0] == ESC) break;
203 // Test assistant thread
204 DWORD WINAPI AssistantThread (void *argument) {
205 int32_t rc,sock = (int32_t)argument;
210 // Set blocking receive timeout
211 uint32_t tout = 2000;
212 setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tout, sizeof(tout));
214 // Get remote peer address
215 sa_len = sizeof (sa);
216 getpeername (sock, (SOCKADDR *)&sa, &sa_len);
218 // Receive the command (tout = 2s)
219 rc = recv (sock, buff, sizeof(buff), 0);
228 /* Syntax: CONNECT <proto>,<ip_addr>,<port>,<delay_ms>
229 Param: <proto> = protocol (TCP, UDP)
230 <ip_addr> = IP address (0.0.0.0 = sender address)
232 <delay_ms> = startup delay
234 Example: CONNECT TCP,192.168.1.200,80,600
235 (wait 600ms then connect to 192.168.1.200, port 80)
237 if ((strncmp (buff, "CONNECT TCP", 11) == 0) ||
238 (strncmp (buff, "CONNECT UDP", 11) == 0)) {
246 // Parse command parameters
247 da.s_addr = INADDR_ANY;
248 sscanf (buff+11,",%hhu.%hhu.%hhu.%hhu,%hu,%u",
249 &da.s_b1,&da.s_b2,&da.s_b3,&da.s_b4,&port,&delay);
251 sa.sin_family = AF_INET;
252 sa.sin_port = htons (port);
253 if (da.s_addr != INADDR_ANY) {
254 // Supplied address not 0.0.0.0 use it
255 sa.sin_addr.s_addr = da.s_addr;
259 if (delay < 10) delay = 10;
260 if (delay > 5000) delay = 5000;
263 // Create stream or datagram socket
264 sock = socket (PF_INET, (buff[8] == 'T') ? SOCK_STREAM : SOCK_DGRAM, 0);
266 // Connect to requested address
267 rc = connect (sock, (SOCKADDR *)&sa, sizeof(sa));
269 // Send some text, wait and close
270 send (sock, "SockServer", 10, 0);
277 /* Syntax: SEND <proto>,<bsize>,<time_ms>
278 Param: <proto> = protocol (TCP, UDP)
279 <bsize> = size of data block in bytes
280 <time_ms> = test duration in ms
282 if (strncmp (buff, "SEND TCP", 8) == 0) {
285 int32_t i,n,cnt,ch = 'a';
287 // Parse command parameters
288 sscanf (buff+8,",%u,%u",&bsize,&time);
291 if (bsize < 32) bsize = 32;
292 if (bsize > 1460) bsize = 1460;
293 if (time < 500) time = 500;
294 if (time > 60000) time = 60000;
296 // Adjust Winsock2 send buffering
298 setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *)&n, sizeof(n));
304 n = sprintf (buff,"Block[%d] ",++i);
305 memset (buff+n, ch, bsize-n);
307 if (++ch > '~') ch = ' ';
308 n = send (sock, buff, bsize, 0);
310 } while (clock () - ticks < time);
312 // Inform the client of the number of bytes received
313 n = sprintf (buff,"STAT %d bytes.",cnt);
314 send (sock, buff, n, 0);
316 // let the client close the connection
317 while (recv (sock, buff, sizeof(buff), 0) > 0);
323 /* Syntax: RECV <proto>,<bsize>
324 Param: <proto> = protocol (TCP, UDP)
325 <bsize> = size of data block in bytes
327 if (strncmp (buff, "RECV TCP", 8) == 0) {
331 // Parse command parameters
332 sscanf (buff+8,",%u",&bsize);
335 if (bsize < 32) bsize = 32;
336 if (bsize > 1460) bsize = 1460;
340 for (cnt = 0; ; cnt += n) {
341 n = recv (sock, buff, bsize, 0);
342 if (strncmp(buff, "STOP", 4) == 0) {
343 // Client terminated upload
349 // Inform the client of the number of bytes received
350 n = sprintf (buff, "STAT %d bytes.",cnt);
351 send (sock, buff, n, 0);
353 // let the client close the connection
354 while (recv (sock, buff, sizeof(buff), 0) > 0);
364 // Conditional accept filtering (Winsock2)
365 int32_t CALLBACK ConditionAcceptFunc(
367 LPWSABUF lpCallerData,
371 LPWSABUF lpCalleeData,
373 DWORD_PTR dwCallbackData) {
377 // Stream server thread
378 // (runs ECHO, CHARGEN, DISCARD and ASSISTANT services)
379 DWORD WINAPI StreamServer (void *argument) {
380 int32_t sock_echo,sock_chargen,sock_discard,sock_assistant,sock_rejected;
382 int32_t sock,nfds,sa_len;
389 sock_echo = socket (PF_INET, SOCK_STREAM, 0);
390 sock_chargen = socket (PF_INET, SOCK_STREAM, 0);
391 sock_discard = socket (PF_INET, SOCK_STREAM, 0);
392 sock_assistant = socket (PF_INET, SOCK_STREAM, 0);
393 sock_rejected = socket (PF_INET, SOCK_STREAM, 0);
395 // Enable conditional accept (Winsock2)
397 retv = setsockopt (sock_rejected, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, (char *)&en, sizeof(en));
398 if (retv != NO_ERROR) {
399 printf ("Failed to set SO_CONDITIONAL_ACCEPT\n");
403 sa.sin_family = AF_INET;
404 sa.sin_addr.s_addr = INADDR_ANY;
406 sa.sin_port = htons (ECHO_PORT);
407 bind (sock_echo, (SOCKADDR *)&sa, sizeof(sa));
409 sa.sin_port = htons (CHARGEN_PORT);
410 bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
412 sa.sin_port = htons (DISCARD_PORT);
413 bind (sock_discard, (SOCKADDR *)&sa, sizeof(sa));
415 sa.sin_port = htons (ASSISTANT_PORT);
416 bind (sock_assistant,(SOCKADDR *)&sa, sizeof(sa));
418 sa.sin_port = htons (TCP_REJECTED_PORT);
419 bind (sock_rejected, (SOCKADDR *)&sa, sizeof(sa));
422 listen (sock_echo, 2);
423 listen (sock_chargen, 2);
424 listen (sock_discard, 2);
425 listen (sock_assistant, 2);
426 listen (sock_rejected, 2);
430 FD_SET(sock_echo, &fds);
431 FD_SET(sock_chargen, &fds);
432 FD_SET(sock_discard, &fds);
433 FD_SET(sock_assistant, &fds);
434 FD_SET(sock_rejected, &fds);
437 if (sock_chargen > nfds) nfds = sock_chargen;
438 if (sock_discard > nfds) nfds = sock_discard;
439 if (sock_assistant > nfds) nfds = sock_assistant;
440 if (sock_rejected > nfds) nfds = sock_rejected;
445 // Wait for the client to connect
446 select (nfds+1, &fds, 0, 0, &tv);
448 if (FD_ISSET(sock_echo, &fds)) {
449 // Connect is pending, accept will not block
451 sock = accept (sock_echo, (SOCKADDR *)&sa, &sa_len);
453 memcpy (&remote_addr, &sa, sa_len);
454 // Create spawn thread
455 CreateThread(NULL, 0, EchoThread, (void *)sock, 0, NULL);
459 if (FD_ISSET(sock_chargen, &fds)) {
460 // Connect is pending, accept will not block
462 sock = accept (sock_chargen, (SOCKADDR *)&sa, &sa_len);
464 memcpy (&remote_addr, &sa, sa_len);
465 // Create spawn thread
466 CreateThread(NULL, 0, ChargenThread, (void *)sock, 0, NULL);
470 if (FD_ISSET(sock_discard, &fds)) {
471 // Connect is pending, accept will not block
473 sock = accept (sock_discard, (SOCKADDR *)&sa, &sa_len);
475 memcpy (&remote_addr, &sa, sa_len);
476 // Create spawn thread
477 CreateThread(NULL, 0, DiscardThread, (void *)sock, 0, NULL);
481 if (FD_ISSET(sock_assistant, &fds)) {
482 // Connect is pending, accept will not block
484 sock = accept (sock_assistant, (SOCKADDR *)&sa, &sa_len);
486 memcpy (&remote_addr, &sa, sa_len);
487 // Create spawn thread
488 CreateThread(NULL, 0, AssistantThread, (void *)sock, 0, NULL);
492 if (FD_ISSET(sock_rejected, &fds)) {
493 // Connect is pending, reject it
494 sock = WSAAccept (sock_rejected, NULL, NULL, &ConditionAcceptFunc, 0);
511 printf("\nSockServer %s\n", VERSION);
513 // Initialize Winsock2
514 iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
515 if (iResult != NO_ERROR) {
516 printf("WSAStartup failed with error: %d\n", iResult);
520 thread = CreateThread(NULL, 0, DgramServer, NULL, 0, NULL);
521 if (thread == NULL) {
522 printf("Failed to create thread: DgramServer\n");
527 thread = CreateThread(NULL, 0, StreamServer, NULL, 0, NULL);
528 if (thread == NULL) {
529 printf("Failed to create thread: StreamServer\n");
534 // Print info about local host
535 if (gethostname (ac, sizeof(ac)) != SOCKET_ERROR) {
536 printf ("\nServer name: %s\n",ac);
537 phe = gethostbyname (ac);
539 for (int i = 0; phe->h_addr_list[i] != 0; i++) {
541 memcpy (&addr, phe->h_addr_list[i], sizeof (struct in_addr));
542 printf ("Address: %s\n", inet_ntoa(addr));
547 printf("\nPress any key to stop...\n");
550 // Terminate use of Winsock2