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]
10 *----------------------------------------------------------------------------*/
16 #include "cmsis_os2.h"
17 #include "SockServer.h"
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
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);
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;
47 // Datagram server thread
48 // (runs ECHO and CHARGEN services)
49 void DgramServer (void *argument) {
51 int32_t sock_echo,sock_chargen;
52 int32_t nfds,rc,sa_len;
58 sock_echo = socket (PF_INET, SOCK_DGRAM, 0);
59 sock_chargen = socket (PF_INET, SOCK_DGRAM, 0);
62 sa.sin_family = AF_INET;
63 sa.sin_addr.s_addr = INADDR_ANY;
65 sa.sin_port = htons (ECHO_PORT);
66 bind (sock_echo, (SOCKADDR *)&sa, sizeof(sa));
68 sa.sin_port = htons (CHARGEN_PORT);
69 bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
72 buff = malloc (BUFF_SIZE);
77 FD_SET(sock_echo, &fds);
78 FD_SET(sock_chargen, &fds);
79 nfds = (sock_echo > sock_chargen) ? sock_echo : sock_chargen;
83 // Wait for the packet
84 select (nfds+1, &fds, 0, 0, &tv);
86 if (FD_ISSET(sock_echo, &fds)) {
87 // Data ready, recvfrom will not block
89 rc = recvfrom (sock_echo, buff, BUFF_SIZE, 0, (SOCKADDR *)&sa, &sa_len);
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;
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);
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;
122 // Stream socket handler (2 instances)
123 static void EchoThread (void *argument) {
124 int32_t sock = (int32_t)argument;
127 char *buff = malloc (BUFF_SIZE);
129 rc = recv (sock, buff, BUFF_SIZE, 0);
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;
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 = '@';
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);
162 // Stream socket handler (1 instance)
163 static void DiscardThread (void *argument) {
164 int32_t rc,sock = (int32_t)argument;
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;
177 // Stream server thread
178 // (runs ECHO, CHARGEN and DISCARD services)
179 void StreamServer (void *argument) {
181 int32_t sock_echo,sock_chargen,sock_discard;
182 int32_t sock,nfds,sa_len;
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);
192 sa.sin_family = AF_INET;
193 sa.sin_addr.s_addr = INADDR_ANY;
195 sa.sin_port = htons (ECHO_PORT);
196 bind (sock_echo, (SOCKADDR *)&sa, sizeof(sa));
198 sa.sin_port = htons (CHARGEN_PORT);
199 bind (sock_chargen, (SOCKADDR *)&sa, sizeof(sa));
201 sa.sin_port = htons (DISCARD_PORT);
202 bind (sock_discard, (SOCKADDR *)&sa, sizeof(sa));
205 listen (sock_echo, 2);
206 listen (sock_chargen, 2);
207 listen (sock_discard, 1);
211 FD_SET(sock_echo, &fds);
212 FD_SET(sock_chargen, &fds);
213 FD_SET(sock_discard, &fds);
215 if (sock_chargen > nfds) nfds = sock_chargen;
216 if (sock_discard > nfds) nfds = sock_discard;
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
225 sock = accept (sock_echo, (SOCKADDR *)&sa, &sa_len);
227 memcpy (&remote_addr, &sa, sa_len);
228 // Create spawn thread (max.2)
229 osThreadNew(EchoThread, (void *)sock, NULL);
232 if (FD_ISSET(sock_chargen, &fds)) {
233 // Connect is pending, accept will not block
235 sock = accept (sock_chargen, (SOCKADDR *)&sa, &sa_len);
237 memcpy (&remote_addr, &sa, sa_len);
238 // Create spawn thread (max.2)
239 osThreadNew(ChargenThread, (void *)sock, NULL);
242 if (FD_ISSET(sock_discard, &fds)) {
243 // Connect is pending, accept will not block
245 sock = accept (sock_discard, (SOCKADDR *)&sa, &sa_len);
247 memcpy (&remote_addr, &sa, sa_len);
248 // Create spawn thread (max.1)
249 osThreadNew(DiscardThread, (void *)sock, NULL);
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) {
266 int32_t sock,sd,rc,sa_len,type;
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
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);
294 if (strncmp (buff, "CONNECT TCP", 11) == 0) {
298 if (strncmp (buff, "CONNECT UDP", 11) == 0) {
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)
311 <delay_ms> = startup delay
313 Example: CONNECT TCP,192.168.1.200,80,600
314 (wait 600ms then connect to 192.168.1.200, port 80)
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;
323 sa.sin_port = htons (port);
326 if (tout > 5000-10) tout = 5000-10;
329 // Create stream or datagram socket
330 sock = socket (PF_INET, type, 0);
332 // Connect to requested address
333 rc = connect (sock, (SOCKADDR *)&sa, sa_len);
335 // Send some text, wait and close
336 send (sock, "SockServer", 10, 0);