]> begriffs open source - cmsis-driver-validation/blob - Tools/SockServer/PC/Win/Source/SockServer.c
Minor comment correction in SockServer.c module
[cmsis-driver-validation] / Tools / SockServer / PC / Win / Source / SockServer.c
1 /*------------------------------------------------------------------------------
2  * CMSIS-Driver_Validation - Tools
3  * Copyright (c) 2019 ARM Germany GmbH. All rights reserved.
4  *------------------------------------------------------------------------------
5  * Name:    SockServer.c
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  *----------------------------------------------------------------------------*/
11
12 #define VERSION     "v1.1"
13
14 #include <stdio.h>
15 #include <stdint.h>
16 #include <conio.h>
17 #include <time.h>
18 #include <windows.h>
19 #include <winsock2.h>
20 #include "SockServer.h"
21
22 // Link with ws2_32.lib
23 #pragma comment(lib, "Ws2_32.lib")
24
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
29
30 // Generate character array for transmit
31 static char gen_char (char *buf, char setchar, uint32_t len) {
32   uint32_t i;
33   char ch;
34
35   if ((++setchar < 0x21) || (setchar == 0x7f)) {
36     setchar = 0x21;
37   }
38   for (i = 0, ch = setchar; i < (len-2); i++) {
39     buf[i] = ch;
40     if (++ch == 0x7f) ch = 0x21;
41   }
42   buf[i]   = '\n';
43   buf[i+1] = '\r';
44   return (setchar);
45 }
46
47 // Debug print status
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);
50 }
51
52 // Datagram server thread
53 // (runs ECHO and CHARGEN services)
54 DWORD WINAPI DgramServer (void *argument) {
55   SOCKADDR_IN sa;
56   int32_t sock_echo,sock_chargen;
57   int32_t nfds,rc,sa_len;
58   char *buff,setchar;
59   struct timeval tv;
60   fd_set fds;
61
62   // Allocate sockets
63   sock_echo    = socket (PF_INET, SOCK_DGRAM, 0);
64   sock_chargen = socket (PF_INET, SOCK_DGRAM, 0);
65
66   // Bind sockets
67   sa.sin_family      = AF_INET;
68   sa.sin_addr.s_addr = INADDR_ANY;
69
70   sa.sin_port        = htons (ECHO_PORT);
71   bind (sock_echo, (SOCKADDR *)&sa, sizeof(sa));
72
73   sa.sin_port        = htons (CHARGEN_PORT);
74   bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
75
76   setchar = '@';
77   buff = malloc (BUFF_SIZE);
78
79   // Receive data
80   for (;;) {
81     FD_ZERO(&fds);
82     FD_SET(sock_echo, &fds);
83     FD_SET(sock_chargen, &fds);
84
85     nfds = sock_echo;
86     if (sock_chargen > nfds) nfds = sock_chargen;
87
88     tv.tv_sec  = 120;
89     tv.tv_usec = 0;
90
91     // Wait for the packet
92     select (nfds+1, &fds, 0, 0, &tv);
93
94     if (FD_ISSET(sock_echo, &fds)) {
95       // Data ready, recvfrom will not block
96       sa_len = sizeof (sa);
97       rc = recvfrom (sock_echo, buff, BUFF_SIZE, 0, (SOCKADDR *)&sa, &sa_len);
98       if (rc > 0) {
99         rx_cnt += rc;
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;
103         print_status ();
104       }
105       if (rc < 0) {
106         break;
107       }
108     }
109
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);
114       if (rc > 0) {
115         rx_cnt += rc;
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;
123         print_status ();
124       }
125       if (rc < 0) {
126         break;
127       }
128     }
129   }
130   free (buff);
131   return (0);
132 }
133
134 // ECHO stream socket handler
135 DWORD WINAPI EchoThread (void *argument) {
136   int32_t sock = (int32_t)argument;
137   int32_t rc;
138
139   char *buff = malloc (BUFF_SIZE);
140   for (; buff;) {
141     rc = recv (sock, buff, BUFF_SIZE, 0);
142     if (rc <= 0) break;
143     rx_cnt += rc;
144     rc = send (sock, buff, rc, 0);
145     if (rc < 0) break;
146     tx_cnt += rc;
147     // ESC terminates the thread
148     if (buff[0] == ESC) break;
149     print_status ();
150   }
151   closesocket (sock);
152   free (buff);
153   return (0);
154 }
155
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;  
161
162   // Set non-blocking mode
163   ioctlsocket (sock, FIONBIO, &enable);
164   for (;;) {
165     rc = recv (sock, buff, sizeof(buff), 0);
166     if (rc > 0) {
167       rx_cnt += rc;
168       // ESC terminates the thread
169       if (buff[0] == ESC) break;
170     }
171     else {
172       // Non-blocking mode, check error code
173       if (WSAGetLastError() != WSAEWOULDBLOCK) break;
174     }
175     setchar = gen_char (buff, setchar, 81);
176     rc = send (sock, buff, 81, 0);
177     if (rc < 0) break;
178     tx_cnt += rc;
179     print_status ();
180     Sleep (100);
181   }
182   closesocket (sock);
183   return (0);
184 }
185
186 // DISCARD stream socket handler
187 DWORD WINAPI DiscardThread (void *argument) {
188   int32_t rc,sock = (int32_t)argument;
189   char buff[40];
190   
191   for (;;) {
192     rc = recv (sock, buff, sizeof(buff), 0);
193     if (rc <= 0) break;
194     rx_cnt += rc;
195     // ESC terminates the thread
196     if (buff[0] == ESC) break;
197     print_status ();
198   }
199   closesocket (sock);
200   return (0);
201 }
202
203 // Test assistant thread
204 DWORD WINAPI AssistantThread (void *argument) {
205   int32_t rc,sock = (int32_t)argument;
206   SOCKADDR_IN sa;
207   int32_t sa_len;
208   char buff[1500];
209    
210   // Set blocking receive timeout
211   uint32_t tout = 2000;
212   setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tout, sizeof(tout));
213
214   // Get remote peer address
215   sa_len = sizeof (sa);
216   getpeername (sock, (SOCKADDR *)&sa, &sa_len);
217
218   // Receive the command (tout = 2s)
219   rc = recv (sock, buff, sizeof(buff), 0);
220   if (rc <= 0) {
221     closesocket (sock);
222     return (0);
223   }
224
225   // Parse the command
226   buff[rc] = 0;
227
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)
231               <port>     = port number
232               <delay_ms> = startup delay
233
234      Example: CONNECT TCP,192.168.1.200,80,600
235      (wait 600ms then connect to 192.168.1.200, port 80)
236   */
237   if ((strncmp (buff, "CONNECT TCP", 11) == 0) || 
238       (strncmp (buff, "CONNECT UDP", 11) == 0)) {
239     uint16_t port;
240     uint32_t delay;
241     IN_ADDR da;
242
243     Sleep (10);
244     closesocket (sock);
245     
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);
250  
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;
256     }
257  
258     // Limit the timeout
259     if (delay < 10)   delay = 10;
260     if (delay > 5000) delay = 5000;
261     Sleep (delay);
262
263     // Create stream or datagram socket
264     sock = socket (PF_INET,  (buff[8] == 'T') ? SOCK_STREAM : SOCK_DGRAM, 0);
265
266     // Connect to requested address
267     rc = connect (sock, (SOCKADDR *)&sa, sizeof(sa));
268     if (rc == 0) {
269       // Send some text, wait and close
270       send (sock, "SockServer", 10, 0);
271       Sleep (500);
272     }
273     closesocket (sock);
274     return (0);
275   }
276
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
281   */
282   if (strncmp (buff, "SEND TCP", 8) == 0) { 
283     uint32_t bsize,time;
284     clock_t ticks,tout;
285     int32_t i,n,cnt,ch = 'a';
286     
287     // Parse command parameters
288     sscanf (buff+8,",%u,%u",&bsize,&time);
289     
290     // Check limits
291     if (bsize < 32)    bsize = 32;
292     if (bsize > 1460)  bsize = 1460;
293     if (time < 500)    time  = 500;
294     if (time > 60000)  time  = 60000;
295
296     // Adjust Winsock2 send buffering
297     n = bsize * 2;
298     setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *)&n, sizeof(n));
299     Sleep (10);
300
301     i = cnt = 0;
302     ticks = clock ();
303     do {
304       n = sprintf (buff,"Block[%d] ",++i);
305       memset (buff+n, ch, bsize-n);
306       buff[bsize] = 0;
307       if (++ch > '~') ch = ' ';
308       n = send (sock, buff, bsize, 0);
309       if (n > 0) cnt += n; 
310     } while (clock () - ticks < time);
311
312     // Inform the client of the number of bytes received
313     n = sprintf (buff,"STAT %d bytes.",cnt);       
314     send (sock, buff, n, 0);
315
316     // let the client close the connection
317     while (recv (sock, buff, sizeof(buff), 0) > 0);
318
319     closesocket (sock);
320     return (0);
321   }
322
323   /* Syntax:  RECV <proto>,<bsize>
324      Param:   <proto> = protocol (TCP, UDP)
325               <bsize> = size of data block in bytes 
326   */
327   if (strncmp (buff, "RECV TCP", 8) == 0) { 
328     uint32_t bsize;
329     int32_t i,n,cnt;
330     
331     // Parse command parameters
332     sscanf (buff+8,",%u",&bsize);
333     
334     // Check limits
335     if (bsize < 32)    bsize = 32;
336     if (bsize > 1460)  bsize = 1460;
337
338     Sleep (10);
339
340     for (cnt = 0;  ; cnt += n) {
341       n = recv (sock, buff, bsize, 0);
342       if (strncmp(buff, "STOP", 4) == 0) {
343         // Client terminated upload
344         break;
345       }
346       if (n <= 0) break; 
347     }
348
349     // Inform the client of the number of bytes received
350     n = sprintf (buff, "STAT %d bytes.",cnt);
351     send (sock, buff, n, 0);
352  
353     // let the client close the connection
354     while (recv (sock, buff, sizeof(buff), 0) > 0);
355
356     closesocket (sock);
357     return (0);
358   }
359
360   closesocket (sock);
361   return (0);
362 }
363
364 // Conditional accept filtering (Winsock2)
365 int32_t CALLBACK ConditionAcceptFunc(
366     LPWSABUF lpCallerId,
367     LPWSABUF lpCallerData,
368     LPQOS pQos,
369     LPQOS lpGQOS,
370     LPWSABUF lpCalleeId,
371     LPWSABUF lpCalleeData,
372     GROUP FAR * g,
373     DWORD_PTR dwCallbackData) {
374   return (CF_REJECT);
375 }
376
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;
381   SOCKADDR_IN sa;
382   int32_t sock,nfds,sa_len;
383   struct timeval tv;
384   fd_set fds;
385   uint32_t en;
386   int32_t retv;
387
388   // Allocate sockets
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);
394   
395   // Enable conditional accept (Winsock2)
396   en = 1;
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");
400   }
401   
402   // Bind sockets
403   sa.sin_family      = AF_INET;
404   sa.sin_addr.s_addr = INADDR_ANY;
405
406   sa.sin_port = htons (ECHO_PORT);
407   bind (sock_echo,    (SOCKADDR *)&sa, sizeof(sa));
408
409   sa.sin_port = htons (CHARGEN_PORT);
410   bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
411
412   sa.sin_port = htons (DISCARD_PORT);
413   bind (sock_discard, (SOCKADDR *)&sa, sizeof(sa));
414
415   sa.sin_port = htons  (ASSISTANT_PORT);
416   bind (sock_assistant,(SOCKADDR *)&sa, sizeof(sa));
417
418   sa.sin_port = htons  (TCP_REJECTED_PORT);
419   bind (sock_rejected, (SOCKADDR *)&sa, sizeof(sa));
420   
421   // Start listening
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);
427   
428   for (;;) {
429     FD_ZERO(&fds);
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);
435     
436     nfds = sock_echo;
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;
441     
442     tv.tv_sec  = 120;
443     tv.tv_usec = 0;
444
445     // Wait for the client to connect
446     select (nfds+1, &fds, 0, 0, &tv);
447
448     if (FD_ISSET(sock_echo, &fds)) {
449       // Connect is pending, accept will not block
450       sa_len = sizeof(sa);
451       sock   = accept (sock_echo, (SOCKADDR *)&sa, &sa_len);
452       if (sock >= 0) {
453         memcpy (&remote_addr, &sa, sa_len);
454         // Create spawn thread
455         CreateThread(NULL, 0, EchoThread, (void *)sock, 0, NULL);
456       }
457     }
458
459     if (FD_ISSET(sock_chargen, &fds)) {
460       // Connect is pending, accept will not block
461       sa_len = sizeof(sa);
462       sock   = accept (sock_chargen, (SOCKADDR *)&sa, &sa_len);
463       if (sock >= 0) {
464         memcpy (&remote_addr, &sa, sa_len);
465         // Create spawn thread
466         CreateThread(NULL, 0, ChargenThread, (void *)sock, 0, NULL);
467       }
468     }
469
470     if (FD_ISSET(sock_discard, &fds)) {
471       // Connect is pending, accept will not block
472       sa_len = sizeof(sa);
473       sock   = accept (sock_discard, (SOCKADDR *)&sa, &sa_len);
474       if (sock >= 0) {
475         memcpy (&remote_addr, &sa, sa_len);
476         // Create spawn thread
477         CreateThread(NULL, 0, DiscardThread, (void *)sock, 0, NULL);
478       }
479     }
480
481     if (FD_ISSET(sock_assistant, &fds)) {
482       // Connect is pending, accept will not block
483       sa_len = sizeof(sa);
484       sock   = accept (sock_assistant, (SOCKADDR *)&sa, &sa_len);
485       if (sock >= 0) {
486         memcpy (&remote_addr, &sa, sa_len);
487         // Create spawn thread
488         CreateThread(NULL, 0, AssistantThread, (void *)sock, 0, NULL);
489       }
490     }
491
492     if (FD_ISSET(sock_rejected, &fds)) {
493       // Connect is pending, reject it
494       sock = WSAAccept (sock_rejected, NULL, NULL, &ConditionAcceptFunc, 0);
495       if (sock >= 0) {
496         closesocket (sock);
497       }
498     }
499     Sleep (10);
500   }
501 }
502
503 // Main program
504 int main() {
505   WSADATA wsaData;
506   HANDLE thread;
507   int iResult;
508   char ac[80];
509   struct hostent *phe;
510     
511   printf("\nSockServer %s\n", VERSION);
512
513   // Initialize Winsock2 
514   iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
515   if (iResult != NO_ERROR) {
516     printf("WSAStartup failed with error: %d\n", iResult);
517     return (1);
518   }
519
520   thread = CreateThread(NULL, 0, DgramServer, NULL, 0, NULL);
521   if (thread == NULL) {
522     printf("Failed to create thread: DgramServer\n");
523     WSACleanup();
524     return (1);
525   }
526
527   thread = CreateThread(NULL, 0, StreamServer, NULL, 0, NULL);
528   if (thread == NULL) {
529     printf("Failed to create thread: StreamServer\n");
530     WSACleanup();
531     return (1);
532   }
533
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);
538     if (phe != NULL) {
539       for (int i = 0; phe->h_addr_list[i] != 0; i++) {
540         struct in_addr addr;
541         memcpy (&addr, phe->h_addr_list[i], sizeof (struct in_addr));
542         printf ("Address: %s\n", inet_ntoa(addr));
543       }
544     }
545   }
546
547   printf("\nPress any key to stop...\n");
548   _getch ();
549   
550   // Terminate use of Winsock2
551   WSACleanup();
552   printf ("\nOk\n");
553   return 0;
554 }