]> begriffs open source - cmsis-driver-validation/blob - Tools/SockServer/Embedded/MDK/Source/SockServer.c
Changes:
[cmsis-driver-validation] / Tools / SockServer / Embedded / MDK / Source / SockServer.c
1 /*------------------------------------------------------------------------------
2  * MDK Middleware - Component ::Network
3  * Copyright (c) 2019 ARM Germany GmbH. All rights reserved.
4  *------------------------------------------------------------------------------
5  * Name:    SockServer.c
6  * Purpose: Implements ECHO, DISCARD and CHARGEN services
7  *          - Echo Protocol service                [RFC 862]
8  *          - Discard Protocol service             [RFC 863]
9  *          - Character Generator Protocol service [RFC 864]
10  * Rev.:    V1.1
11  *----------------------------------------------------------------------------*/
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include "rl_net.h"
17 #include "cmsis_os2.h"
18 #include "SockServer.h"
19
20 // Global status variables
21 SOCKADDR_IN remote_addr;        // Remote IP address and port
22 uint32_t rx_cnt;                // Receive count
23 uint32_t tx_cnt;                // Transmit count
24
25 // Local functions
26 static void EchoThread (void *argument);
27 static void ChargenThread (void *argument);
28 static void DiscardThread (void *argument);
29 static char gen_char (char *buf, char setchar, uint32_t len);
30
31 // Generate character array for transmit
32 static char gen_char (char *buf, char setchar, uint32_t len) {
33   uint32_t i;
34   char ch;
35
36   if ((++setchar < 0x21) || (setchar == 0x7f)) {
37     setchar = 0x21;
38   }
39   for (i = 0, ch = setchar; i < (len-2); i++) {
40     buf[i] = ch;
41     if (++ch == 0x7f) ch = 0x21;
42   }
43   buf[i]   = '\n';
44   buf[i+1] = '\r';
45   return (setchar);
46 }
47
48 // Datagram server thread
49 // (runs ECHO and CHARGEN services)
50 void DgramServer (void *argument) {
51   SOCKADDR_IN sa;
52   int32_t sock_echo,sock_chargen;
53   int32_t nfds,rc,sa_len;
54   char *buff,setchar;
55   struct timeval tv;
56   fd_set fds;
57
58   // Allocate sockets
59   sock_echo    = socket (PF_INET, SOCK_DGRAM, 0);
60   sock_chargen = socket (PF_INET, SOCK_DGRAM, 0);
61
62   // Bind sockets
63   sa.sin_family      = AF_INET;
64   sa.sin_addr.s_addr = INADDR_ANY;
65
66   sa.sin_port        = htons (ECHO_PORT);
67   bind (sock_echo, (SOCKADDR *)&sa, sizeof(sa));
68
69   sa.sin_port        = htons (CHARGEN_PORT);
70   bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
71
72   setchar = '@';
73   buff = malloc (BUFF_SIZE);
74
75   // Receive data
76   for (;;) {
77     FD_ZERO(&fds);
78     FD_SET(sock_echo, &fds);
79     FD_SET(sock_chargen, &fds);
80     nfds = (sock_echo > sock_chargen) ? sock_echo : sock_chargen;
81     tv.tv_sec  = 120;
82     tv.tv_usec = 0;
83
84     // Wait for the packet
85     select (nfds+1, &fds, 0, 0, &tv);
86
87     if (FD_ISSET(sock_echo, &fds)) {
88       // Data ready, recvfrom will not block
89       sa_len = sizeof (sa);
90       rc = recvfrom (sock_echo, buff, BUFF_SIZE, 0, (SOCKADDR *)&sa, &sa_len);
91       if (rc > 0) {
92         rx_cnt += rc;
93         memcpy (&remote_addr, &sa, sizeof(sa));
94         rc = sendto (sock_echo, buff, rc, 0, (SOCKADDR *)&sa, sa_len);
95         if (rc > 0) tx_cnt += rc;
96       }
97       if (rc < 0) {
98         break;
99       }
100     }
101     if (FD_ISSET(sock_chargen, &fds)) {
102       // Data ready, recvfrom will not block
103       sa_len = sizeof (sa);
104       rc = recvfrom (sock_chargen, buff, BUFF_SIZE, 0, (SOCKADDR *)&sa, &sa_len);
105       if (rc > 0) {
106         rx_cnt += rc;
107         memcpy (&remote_addr, &sa, sizeof(sa));
108         int32_t len = rand() >> 22;
109         if (len < 2)         len = 2;
110         if (len > BUFF_SIZE) len = BUFF_SIZE;
111         setchar = gen_char (buff, setchar, len);
112         rc = sendto (sock_chargen, buff, len, 0, (SOCKADDR *)&sa, sa_len);
113         if (rc > 0) tx_cnt += rc;
114       }
115       if (rc < 0) {
116         break;
117       }
118     }
119   }
120   free (buff);
121 }
122
123 // ECHO stream socket handler (2 instances)
124 static void EchoThread (void *argument) {
125   int32_t sock = (int32_t)argument;
126   int32_t rc;
127
128   char *buff = malloc (BUFF_SIZE);
129   for (; buff;) {
130     rc = recv (sock, buff, BUFF_SIZE, 0);
131     if (rc > 0) {
132       rx_cnt += rc;
133       rc = send (sock, buff, rc, 0);
134       if (rc > 0) tx_cnt += rc;
135       // ESC terminates the thread
136       if (buff[0] == ESC) break;
137     }
138     if (rc < 0) break;
139   }
140   closesocket (sock);
141   free (buff);
142 }
143
144 // CHARGEN stream socket handler (2 instances)
145 static void ChargenThread (void *argument) {
146   int32_t rc,sock = (int32_t)argument;
147   char buff[82],setchar = '@';
148
149   for (;;) {
150     rc = recv (sock, buff, sizeof(buff), MSG_DONTWAIT);
151     if (rc > 0) rx_cnt += rc;
152     // ESC terminates the thread
153     if ((rc > 0) && (buff[0] == ESC)) break;
154     setchar = gen_char (buff, setchar, 81);
155     rc = send (sock, buff, 81, 0);
156     if (rc < 0) break;
157     else tx_cnt += rc;
158     osDelay (100);
159   }
160   closesocket (sock);
161 }
162
163 // DISCARD stream socket handler (1 instance)
164 static void DiscardThread (void *argument) {
165   int32_t rc,sock = (int32_t)argument;
166   char buff[40];
167
168   for (;;) {
169     rc = recv (sock, buff, sizeof(buff), 0);
170     if (rc > 0) rx_cnt += rc;
171     // ESC terminates the thread
172     if ((rc > 0) && (buff[0] == ESC)) break;
173     if (rc < 0) break;
174   }
175   closesocket (sock);
176 }
177
178 // Stream server thread
179 // (runs ECHO, CHARGEN and DISCARD services)
180 void StreamServer (void *argument) {
181   SOCKADDR_IN sa;
182   int32_t sock_echo,sock_chargen,sock_discard,sock_timeout;
183   int32_t sock,nfds,sa_len;
184   struct timeval tv;
185   fd_set fds;
186
187   // Allocate sockets
188   sock_echo    = socket (PF_INET, SOCK_STREAM, 0);
189   sock_chargen = socket (PF_INET, SOCK_STREAM, 0);
190   sock_discard = socket (PF_INET, SOCK_STREAM, 0);
191   sock_timeout = socket (PF_INET, SOCK_STREAM, 0);
192
193   // Bind sockets
194   sa.sin_family      = AF_INET;
195   sa.sin_addr.s_addr = INADDR_ANY;
196
197   sa.sin_port = htons (ECHO_PORT);
198   bind (sock_echo,    (SOCKADDR *)&sa, sizeof(sa));
199
200   sa.sin_port = htons (CHARGEN_PORT);
201   bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
202
203   sa.sin_port = htons (DISCARD_PORT);
204   bind (sock_discard, (SOCKADDR *)&sa, sizeof(sa));
205
206   sa.sin_port = htons (TCP_TIMEOUT_PORT);
207   bind (sock_timeout, (SOCKADDR *)&sa, sizeof(sa));
208
209   // Start listening
210   listen (sock_echo, 2);
211   listen (sock_chargen, 2);
212   listen (sock_discard, 1);
213   listen (sock_timeout, 1);
214
215   for (;;) {
216     FD_ZERO(&fds);
217     FD_SET(sock_echo, &fds);
218     FD_SET(sock_chargen, &fds);
219     FD_SET(sock_discard, &fds);
220
221     nfds = sock_echo;
222     if (sock_chargen > nfds) nfds = sock_chargen;
223     if (sock_discard > nfds) nfds = sock_discard;
224
225     tv.tv_sec  = 120;
226     tv.tv_usec = 0;
227
228     // Wait for the client to connect
229     select (nfds+1, &fds, 0, 0, &tv);
230     if (FD_ISSET(sock_echo, &fds)) {
231       // Connect is pending, accept will not block
232       sa_len = sizeof(sa);
233       sock   = accept (sock_echo, (SOCKADDR *)&sa, &sa_len);
234       if (sock >= 0) {
235         memcpy (&remote_addr, &sa, sa_len);
236         // Create spawn thread (max.2)
237         osThreadNew(EchoThread, (void *)sock, NULL);
238       }
239     }
240     if (FD_ISSET(sock_chargen, &fds)) {
241       // Connect is pending, accept will not block
242       sa_len = sizeof(sa);
243       sock   = accept (sock_chargen, (SOCKADDR *)&sa, &sa_len);
244       if (sock >= 0) {
245         memcpy (&remote_addr, &sa, sa_len);
246         // Create spawn thread (max.2)
247         osThreadNew(ChargenThread, (void *)sock, NULL);
248       }
249     }
250     if (FD_ISSET(sock_discard, &fds)) {
251       // Connect is pending, accept will not block
252       sa_len = sizeof(sa);
253       sock   = accept (sock_discard, (SOCKADDR *)&sa, &sa_len);
254       if (sock >= 0) {
255         memcpy (&remote_addr, &sa, sa_len);
256         // Create spawn thread (max.1)
257         osThreadNew(DiscardThread, (void *)sock, NULL);
258       }
259     }
260     osDelay (10);
261   }
262 }
263
264 // Test assistant thread
265 void TestAssistant (void *argument) {
266   SOCKADDR_IN sa;
267   int32_t sock,sd,rc,sa_len;
268   static char buff[1500];
269
270   while (1) {
271     // Create socket
272     sock = socket (PF_INET, SOCK_STREAM, 0);
273
274     // Server mode first
275     sa.sin_family      = AF_INET;
276     sa.sin_addr.s_addr = INADDR_ANY;
277     sa.sin_port        = htons (ASSISTANT_PORT);
278     bind (sock, (SOCKADDR *)&sa, sizeof(sa));
279     listen (sock, 1);
280
281     while (1) {
282       // Wait for the client to connect
283       sa_len = sizeof (sa);
284       sd = accept (sock, (SOCKADDR *)&sa, &sa_len);
285       if (sd >= 0) {
286         // Set blocking receive timeout
287         uint32_t tout = 2000;
288         setsockopt (sd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tout, sizeof(tout));
289         // Receive the command (tout = 2s)
290         rc = recv (sd, buff, sizeof(buff), 0);
291         if (rc > 0) {
292           buff[rc] = 0;
293           if ((strncmp (buff, "CONNECT TCP", 11) == 0) ||
294               (strncmp (buff, "CONNECT UDP", 11) == 0) ||
295               (strncmp (buff, "SEND TCP", 8) == 0)     ||
296               (strncmp (buff, "RECV TCP", 8) == 0)) {
297             break;
298           }
299         }
300         closesocket (sd);
301         osDelay (10);
302       }
303     }
304     closesocket (sock);
305
306     /* Syntax:  CONNECT <proto>,<ip_addr>,<port>,<delay_ms>
307        Param:   <proto>    = protocol (TCP, UDP)
308                 <ip_addr>  = IP address (0.0.0.0 = sender address)
309                 <port>     = port number
310                 <delay_ms> = startup delay
311
312        Example: CONNECT TCP,192.168.1.200,80,600
313        (wait 600ms then connect to 192.168.1.200, port 80)
314     */
315     if (buff[0] == 'C') { // CONNECT
316       uint16_t delay,port;
317       IN_ADDR  da;
318
319       closesocket (sd);
320
321       da.s_addr = INADDR_ANY;
322       sscanf (buff+11,",%hhu.%hhu.%hhu.%hhu,%hu,%hu",
323                        &da.s_b1, &da.s_b2, &da.s_b3, &da.s_b4, &port, &delay);
324       if (da.s_addr != INADDR_ANY) {
325         // Supplied address not 0.0.0.0 use it
326         sa.sin_addr.s_addr = da.s_addr;
327       }
328       sa.sin_port = htons (port);
329
330       // Limit the timeout
331       if (delay < 10)   delay = 10;
332       if (delay > 5000) delay = 6000;
333       osDelay (delay);
334
335       // Create stream or datagram socket
336       sock = socket (PF_INET, (buff[8] == 'T') ? SOCK_STREAM : SOCK_DGRAM, 0);
337
338       // Connect to requested address
339       rc = connect (sock, (SOCKADDR *)&sa, sa_len);
340       if (rc == 0) {
341         // Send some text, wait and close
342         send (sock, "SockServer", 10, 0);
343         osDelay (500);
344       }
345       closesocket (sock);
346       osDelay (10);
347       continue;
348     }
349
350     /* Syntax:  SEND <proto>,<blocksz>,<time_ms>
351        Param:   <proto>   = protocol (TCP, UDP)
352                 <bsize>   = size of data block in bytes 
353                 <time_ms> = test duration in ms
354     */
355     if (buff[0] == 'S') { // SEND
356       uint32_t bsize,time,ticks;
357       int32_t  i,n,cnt,ch = 'a';
358     
359       // Parse command parameters
360       sscanf (buff+8,",%u,%u",&bsize,&time);
361     
362       // Check limits
363       if (bsize < 32)   bsize = 32;
364       if (bsize > 1460) bsize = 1460;
365       if (time < 500)   time  = 500;
366       if (time > 60000) time  = 60000;
367
368       osDelay (10);
369
370       time  = SYSTICK_MSEC(time);
371       ticks = GET_SYSTICK();
372       i = cnt = 0;
373       do {
374         n = sprintf (buff,"Block[%d] ",++i);
375         memset (buff+n, ch, bsize-n);
376         buff[bsize] = 0;
377         if (++ch > '~') ch = ' ';
378         n = send (sd, buff, bsize, 0);
379         if (n > 0) cnt += n; 
380       } while (GET_SYSTICK() - ticks < time);
381
382       // Inform the client of the number of bytes received
383       n = sprintf (buff,"STAT %d bytes.",cnt);
384       send (sd, buff, n, 0);
385
386       // Let the client close the connection
387       while (recv (sd, buff, sizeof(buff), 0) > 0);
388
389       closesocket (sd);
390       continue;
391     }
392
393     /* Syntax:  RECV <proto>,<blocksz>
394        Param:   <proto> = protocol (TCP, UDP)
395                 <bsize> = size of data block in bytes 
396     */
397     if (buff[0] == 'R') { // RECV
398       uint32_t bsize;
399       int32_t  n,cnt;
400     
401       // Parse command parameters
402       sscanf (buff+8,",%u",&bsize);
403     
404       // Check limits
405       if (bsize < 32)   bsize = 32;
406       if (bsize > 1460) bsize = 1460;
407
408       osDelay (10);
409
410       for (cnt = 0;  ; cnt += n) {
411         n = recv (sd, buff, bsize, 0);
412         if (strncmp(buff, "STOP", 4) == 0) {
413           // Client terminated upload
414           break;
415         }
416         if (n <= 0) break; 
417       }
418
419       // Inform the client of the number of bytes received
420       n = sprintf (buff, "STAT %d bytes.",cnt);
421       send (sd, buff, n, 0);
422  
423       // Let the client close the connection
424       while (recv (sd, buff, sizeof(buff), 0) > 0);
425
426       closesocket (sd);
427       continue;
428     }
429   }
430 }