]> begriffs open source - cmsis-driver-validation/blob - Tools/SockServer/Source/SockServer.c
- Minor spelling corrections in Abstract.txt file of example for STMicroelectronics...
[cmsis-driver-validation] / Tools / SockServer / 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  *----------------------------------------------------------------------------*/
11  
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include "rl_net.h"
16 #include "cmsis_os2.h"
17 #include "SockServer.h"
18
19 // Global status variables
20 SOCKADDR_IN remote_addr;        // Remote IP address and port
21 uint32_t rx_cnt;                // Receive count
22 uint32_t tx_cnt;                // Transmit count
23
24 // Local functions
25 static void EchoThread (void *argument);
26 static void ChargenThread (void *argument);
27 static void DiscardThread (void *argument);
28 static char gen_char (char *buf, char setchar, uint32_t len);
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 // Datagram server thread
48 // (runs ECHO and CHARGEN services)
49 void DgramServer (void *argument) {
50   SOCKADDR_IN sa;
51   int32_t sock_echo,sock_chargen;
52   int32_t nfds,rc,sa_len;
53   char *buff,setchar;
54   struct timeval tv;
55   fd_set fds;
56
57   // Allocate sockets
58   sock_echo    = socket (PF_INET, SOCK_DGRAM, 0);
59   sock_chargen = socket (PF_INET, SOCK_DGRAM, 0);
60
61   // Bind sockets
62   sa.sin_family      = AF_INET;
63   sa.sin_addr.s_addr = INADDR_ANY;
64
65   sa.sin_port        = htons (ECHO_PORT);
66   bind (sock_echo, (SOCKADDR *)&sa, sizeof(sa));
67
68   sa.sin_port        = htons (CHARGEN_PORT);
69   bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
70
71   setchar = '@';
72   buff = malloc (BUFF_SIZE);
73
74   // Receive data
75   for (;;) {
76     FD_ZERO(&fds);
77     FD_SET(sock_echo, &fds);
78     FD_SET(sock_chargen, &fds);
79     nfds = (sock_echo > sock_chargen) ? sock_echo : sock_chargen;
80     tv.tv_sec  = 120;
81     tv.tv_usec = 0;
82
83     // Wait for the packet
84     select (nfds+1, &fds, 0, 0, &tv);
85
86     if (FD_ISSET(sock_echo, &fds)) {
87       // Data ready, recvfrom will not block
88       sa_len = sizeof (sa);
89       rc = recvfrom (sock_echo, buff, BUFF_SIZE, 0, (SOCKADDR *)&sa, &sa_len);
90       if (rc > 0) {
91         rx_cnt += rc;
92         memcpy (&remote_addr, &sa, sizeof(sa));
93         rc = sendto (sock_echo, buff, rc, 0, (SOCKADDR *)&sa, sa_len);
94         if (rc > 0) tx_cnt += rc;
95       }
96       if (rc < 0) {
97         break;
98       }
99     }
100     if (FD_ISSET(sock_chargen, &fds)) {
101       // Data ready, recvfrom will not block
102       sa_len = sizeof (sa);
103       rc = recvfrom (sock_chargen, buff, BUFF_SIZE, 0, (SOCKADDR *)&sa, &sa_len);
104       if (rc > 0) {
105         rx_cnt += rc;
106         memcpy (&remote_addr, &sa, sizeof(sa));
107         int32_t len = rand() >> 22;
108         if (len < 2)         len = 2;
109         if (len > BUFF_SIZE) len = BUFF_SIZE;
110         setchar = gen_char (buff, setchar, len);
111         rc = sendto (sock_chargen, buff, len, 0, (SOCKADDR *)&sa, sa_len);
112         if (rc > 0) tx_cnt += rc;
113       }
114       if (rc < 0) {
115         break;
116       }
117     }
118   }
119   free (buff);
120 }
121
122 // Stream socket handler (2 instances)
123 static void EchoThread (void *argument) {
124   int32_t sock = (int32_t)argument;
125   int32_t rc;
126
127   char *buff = malloc (BUFF_SIZE);
128   for (; buff;) {
129     rc = recv (sock, buff, BUFF_SIZE, 0);
130     if (rc > 0) {
131       rx_cnt += rc;
132       rc = send (sock, buff, rc, 0);
133       if (rc > 0) tx_cnt += rc;
134       // ESC terminates the thread
135       if (buff[0] == ESC) break;
136     }
137     if (rc < 0) break;
138   }
139   closesocket (sock);
140   free (buff);
141 }
142
143 // Stream socket handler (2 instances)
144 static void ChargenThread (void *argument) {
145   int32_t rc,sock = (int32_t)argument;
146   char buff[82],setchar = '@';
147
148   for (;;) {
149     rc = recv (sock, buff, sizeof(buff), MSG_DONTWAIT);
150     if (rc > 0) rx_cnt += rc;
151     // ESC terminates the thread
152     if ((rc > 0) && (buff[0] == ESC)) break;
153     setchar = gen_char (buff, setchar, 81);
154     rc = send (sock, buff, 81, 0);
155     if (rc < 0) break;
156     else tx_cnt += rc;
157     osDelay (100);
158   }
159   closesocket (sock);
160 }
161
162 // Stream socket handler (1 instance)
163 static void DiscardThread (void *argument) {
164   int32_t rc,sock = (int32_t)argument;
165   char buff[40];
166
167   for (;;) {
168     rc = recv (sock, buff, sizeof(buff), 0);
169     if (rc > 0) rx_cnt += rc;
170     // ESC terminates the thread
171     if ((rc > 0) && (buff[0] == ESC)) break;
172     if (rc < 0) break;
173   }
174   closesocket (sock);
175 }
176
177 // Stream server thread
178 // (runs ECHO, CHARGEN and DISCARD services)
179 void StreamServer (void *argument) {
180   SOCKADDR_IN sa;
181   int32_t sock_echo,sock_chargen,sock_discard;
182   int32_t sock,nfds,sa_len;
183   struct timeval tv;
184   fd_set fds;
185
186   // Allocate sockets
187   sock_echo    = socket (PF_INET, SOCK_STREAM, 0);
188   sock_chargen = socket (PF_INET, SOCK_STREAM, 0);
189   sock_discard = socket (PF_INET, SOCK_STREAM, 0);
190
191   // Bind sockets
192   sa.sin_family      = AF_INET;
193   sa.sin_addr.s_addr = INADDR_ANY;
194
195   sa.sin_port = htons (ECHO_PORT);
196   bind (sock_echo,    (SOCKADDR *)&sa, sizeof(sa));
197
198   sa.sin_port = htons (CHARGEN_PORT);
199   bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
200
201   sa.sin_port = htons (DISCARD_PORT);
202   bind (sock_discard, (SOCKADDR *)&sa, sizeof(sa));
203
204   // Start listening
205   listen (sock_echo, 2);
206   listen (sock_chargen, 2);
207   listen (sock_discard, 1);
208
209   for (;;) {
210     FD_ZERO(&fds);
211     FD_SET(sock_echo, &fds);
212     FD_SET(sock_chargen, &fds);
213     FD_SET(sock_discard, &fds);
214     nfds = sock_echo;
215     if (sock_chargen > nfds) nfds = sock_chargen;
216     if (sock_discard > nfds) nfds = sock_discard;
217     tv.tv_sec  = 120;
218     tv.tv_usec = 0;
219
220     // Wait for the client to connect
221     select (nfds+1, &fds, 0, 0, &tv);
222     if (FD_ISSET(sock_echo, &fds)) {
223       // Connect is pending, accept will not block
224       sa_len = sizeof(sa);
225       sock   = accept (sock_echo, (SOCKADDR *)&sa, &sa_len);
226       if (sock >= 0) {
227         memcpy (&remote_addr, &sa, sa_len);
228         // Create spawn thread (max.2)
229         osThreadNew(EchoThread, (void *)sock, NULL);
230       }
231     }
232     if (FD_ISSET(sock_chargen, &fds)) {
233       // Connect is pending, accept will not block
234       sa_len = sizeof(sa);
235       sock   = accept (sock_chargen, (SOCKADDR *)&sa, &sa_len);
236       if (sock >= 0) {
237         memcpy (&remote_addr, &sa, sa_len);
238         // Create spawn thread (max.2)
239         osThreadNew(ChargenThread, (void *)sock, NULL);
240       }
241     }
242     if (FD_ISSET(sock_discard, &fds)) {
243       // Connect is pending, accept will not block
244       sa_len = sizeof(sa);
245       sock   = accept (sock_discard, (SOCKADDR *)&sa, &sa_len);
246       if (sock >= 0) {
247         memcpy (&remote_addr, &sa, sa_len);
248         // Create spawn thread (max.1)
249         osThreadNew(DiscardThread, (void *)sock, NULL);
250       }
251     }
252     osDelay (10);
253   }
254 }
255
256 // Test assistant thread
257 // - Creates a stream server socket
258 // - Waits for the WiFi driver to connect and send the command
259 // - Scans the command for <proto>, <ip_addr>, <port> and <delay_ms>
260 // - Closes connection and waits for <delay_ms>
261 // - Connects to <ip_addr:port> (stream or datagram type)
262 // - Sends small text and disconnects
263 void TestAssistant (void *argument) {
264   SOCKADDR_IN sa;
265   IN_ADDR da;
266   int32_t sock,sd,rc,sa_len,type;
267   uint16_t tout,port;
268   char buff[80];
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         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         closesocket (sd);
292         if (rc > 0) {
293           buff[rc] = 0;
294           if (strncmp (buff, "CONNECT TCP", 11) == 0) {
295             type = SOCK_STREAM;
296             break;
297           }
298           if (strncmp (buff, "CONNECT UDP", 11) == 0) {
299             type = SOCK_DGRAM;
300             break;
301           }
302         }
303       }
304     }
305     closesocket (sock);
306
307     /* Syntax:  CONNECT <proto>,<ip_addr>,<port>,<delay_ms>
308        Param:   <proto>    = protocol (TCP, UDP)
309                 <ip_addr>  = IP address (0.0.0.0 = sender address)
310                 <port>     = port number
311                 <delay_ms> = startup delay
312
313        Example: CONNECT TCP,192.168.1.200,80,600
314        (wait 600ms then connect to 192.168.1.200, port 80)
315     */
316     da.s_addr = INADDR_ANY;
317     sscanf (buff+11,",%hhu.%hhu.%hhu.%hhu,%hu,%hu",
318                      &da.s_b1, &da.s_b2, &da.s_b3, &da.s_b4, &port, &tout);
319     if (da.s_addr != INADDR_ANY) {
320       // Supplied address not 0.0.0.0 use it
321       sa.sin_addr.s_addr = da.s_addr;
322     }
323     sa.sin_port = htons (port);
324
325     // Limit the timeout
326     if (tout > 5000-10) tout = 5000-10;
327     osDelay (10 + tout);
328
329     // Create stream or datagram socket
330     sock = socket (PF_INET, type, 0);
331
332     // Connect to requested address
333     rc = connect (sock, (SOCKADDR *)&sa, sa_len);
334     if (rc == 0) {
335       // Send some text, wait and close
336       send (sock, "SockServer", 10, 0);
337       osDelay (500);
338     }
339     closesocket (sock);
340     osDelay (10);
341   }
342 }