1 /*------------------------------------------------------------------------------
2 * MDK Middleware - Component ::Network
3 * Copyright (c) 2019 ARM Germany GmbH. All rights reserved.
4 *------------------------------------------------------------------------------
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]
11 *----------------------------------------------------------------------------*/
17 #include "cmsis_os2.h"
18 #include "SockServer.h"
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
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);
31 // Generate character array for transmit
32 static char gen_char (char *buf, char setchar, uint32_t len) {
36 if ((++setchar < 0x21) || (setchar == 0x7f)) {
39 for (i = 0, ch = setchar; i < (len-2); i++) {
41 if (++ch == 0x7f) ch = 0x21;
48 // Datagram server thread
49 // (runs ECHO and CHARGEN services)
50 void DgramServer (void *argument) {
52 int32_t sock_echo,sock_chargen;
53 int32_t nfds,rc,sa_len;
59 sock_echo = socket (PF_INET, SOCK_DGRAM, 0);
60 sock_chargen = socket (PF_INET, SOCK_DGRAM, 0);
63 sa.sin_family = AF_INET;
64 sa.sin_addr.s_addr = INADDR_ANY;
66 sa.sin_port = htons (ECHO_PORT);
67 bind (sock_echo, (SOCKADDR *)&sa, sizeof(sa));
69 sa.sin_port = htons (CHARGEN_PORT);
70 bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
73 buff = malloc (BUFF_SIZE);
78 FD_SET(sock_echo, &fds);
79 FD_SET(sock_chargen, &fds);
80 nfds = (sock_echo > sock_chargen) ? sock_echo : sock_chargen;
84 // Wait for the packet
85 select (nfds+1, &fds, 0, 0, &tv);
87 if (FD_ISSET(sock_echo, &fds)) {
88 // Data ready, recvfrom will not block
90 rc = recvfrom (sock_echo, buff, BUFF_SIZE, 0, (SOCKADDR *)&sa, &sa_len);
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;
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);
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;
123 // ECHO stream socket handler (2 instances)
124 static void EchoThread (void *argument) {
125 int32_t sock = (int32_t)argument;
128 char *buff = malloc (BUFF_SIZE);
130 rc = recv (sock, buff, BUFF_SIZE, 0);
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;
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 = '@';
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);
163 // DISCARD stream socket handler (1 instance)
164 static void DiscardThread (void *argument) {
165 int32_t rc,sock = (int32_t)argument;
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;
178 // Stream server thread
179 // (runs ECHO, CHARGEN and DISCARD services)
180 void StreamServer (void *argument) {
182 int32_t sock_echo,sock_chargen,sock_discard,sock_timeout;
183 int32_t sock,nfds,sa_len;
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);
194 sa.sin_family = AF_INET;
195 sa.sin_addr.s_addr = INADDR_ANY;
197 sa.sin_port = htons (ECHO_PORT);
198 bind (sock_echo, (SOCKADDR *)&sa, sizeof(sa));
200 sa.sin_port = htons (CHARGEN_PORT);
201 bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
203 sa.sin_port = htons (DISCARD_PORT);
204 bind (sock_discard, (SOCKADDR *)&sa, sizeof(sa));
206 sa.sin_port = htons (TCP_TIMEOUT_PORT);
207 bind (sock_timeout, (SOCKADDR *)&sa, sizeof(sa));
210 listen (sock_echo, 2);
211 listen (sock_chargen, 2);
212 listen (sock_discard, 1);
213 listen (sock_timeout, 1);
217 FD_SET(sock_echo, &fds);
218 FD_SET(sock_chargen, &fds);
219 FD_SET(sock_discard, &fds);
222 if (sock_chargen > nfds) nfds = sock_chargen;
223 if (sock_discard > nfds) nfds = sock_discard;
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
233 sock = accept (sock_echo, (SOCKADDR *)&sa, &sa_len);
235 memcpy (&remote_addr, &sa, sa_len);
236 // Create spawn thread (max.2)
237 osThreadNew(EchoThread, (void *)sock, NULL);
240 if (FD_ISSET(sock_chargen, &fds)) {
241 // Connect is pending, accept will not block
243 sock = accept (sock_chargen, (SOCKADDR *)&sa, &sa_len);
245 memcpy (&remote_addr, &sa, sa_len);
246 // Create spawn thread (max.2)
247 osThreadNew(ChargenThread, (void *)sock, NULL);
250 if (FD_ISSET(sock_discard, &fds)) {
251 // Connect is pending, accept will not block
253 sock = accept (sock_discard, (SOCKADDR *)&sa, &sa_len);
255 memcpy (&remote_addr, &sa, sa_len);
256 // Create spawn thread (max.1)
257 osThreadNew(DiscardThread, (void *)sock, NULL);
264 // Test assistant thread
265 void TestAssistant (void *argument) {
267 int32_t sock,sd,rc,sa_len;
268 static char buff[1500];
272 sock = socket (PF_INET, SOCK_STREAM, 0);
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));
282 // Wait for the client to connect
283 sa_len = sizeof (sa);
284 sd = accept (sock, (SOCKADDR *)&sa, &sa_len);
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);
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)) {
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)
310 <delay_ms> = startup delay
312 Example: CONNECT TCP,192.168.1.200,80,600
313 (wait 600ms then connect to 192.168.1.200, port 80)
315 if (buff[0] == 'C') { // CONNECT
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;
328 sa.sin_port = htons (port);
331 if (delay < 10) delay = 10;
332 if (delay > 5000) delay = 6000;
335 // Create stream or datagram socket
336 sock = socket (PF_INET, (buff[8] == 'T') ? SOCK_STREAM : SOCK_DGRAM, 0);
338 // Connect to requested address
339 rc = connect (sock, (SOCKADDR *)&sa, sa_len);
341 // Send some text, wait and close
342 send (sock, "SockServer", 10, 0);
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
355 if (buff[0] == 'S') { // SEND
356 uint32_t bsize,time,ticks;
357 int32_t i,n,cnt,ch = 'a';
359 // Parse command parameters
360 sscanf (buff+8,",%u,%u",&bsize,&time);
363 if (bsize < 32) bsize = 32;
364 if (bsize > 1460) bsize = 1460;
365 if (time < 500) time = 500;
366 if (time > 60000) time = 60000;
370 time = SYSTICK_MSEC(time);
371 ticks = GET_SYSTICK();
374 n = sprintf (buff,"Block[%d] ",++i);
375 memset (buff+n, ch, bsize-n);
377 if (++ch > '~') ch = ' ';
378 n = send (sd, buff, bsize, 0);
380 } while (GET_SYSTICK() - ticks < time);
382 // Inform the client of the number of bytes received
383 n = sprintf (buff,"STAT %d bytes.",cnt);
384 send (sd, buff, n, 0);
386 // Let the client close the connection
387 while (recv (sd, buff, sizeof(buff), 0) > 0);
393 /* Syntax: RECV <proto>,<blocksz>
394 Param: <proto> = protocol (TCP, UDP)
395 <bsize> = size of data block in bytes
397 if (buff[0] == 'R') { // RECV
401 // Parse command parameters
402 sscanf (buff+8,",%u",&bsize);
405 if (bsize < 32) bsize = 32;
406 if (bsize > 1460) bsize = 1460;
410 for (cnt = 0; ; cnt += n) {
411 n = recv (sd, buff, bsize, 0);
412 if (strncmp(buff, "STOP", 4) == 0) {
413 // Client terminated upload
419 // Inform the client of the number of bytes received
420 n = sprintf (buff, "STAT %d bytes.",cnt);
421 send (sd, buff, n, 0);
423 // Let the client close the connection
424 while (recv (sd, buff, sizeof(buff), 0) > 0);