echo_server.c
Go to the documentation of this file.
1 /**
2  * @file echo_server.c
3  * @brief Echo server
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * The Echo service simply sends back to the originating source
30  * any data it receives. Refer to RFC 862 for complete details
31  *
32  * @author Oryx Embedded SARL (www.oryx-embedded.com)
33  * @version 2.6.0
34  **/
35 
36 //Switch to the appropriate trace level
37 #define TRACE_LEVEL ECHO_TRACE_LEVEL
38 
39 //Dependencies
40 #include "core/net.h"
41 #include "echo/echo_server.h"
42 #include "echo/echo_server_misc.h"
43 #include "debug.h"
44 
45 //Check TCP/IP stack configuration
46 #if (ECHO_SERVER_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief Initialize settings with default values
51  * @param[out] settings Structure that contains Echo server settings
52  **/
53 
55 {
56  //Default task parameters
57  settings->task = OS_TASK_DEFAULT_PARAMS;
60 
61  //TCP/IP stack context
62  settings->netContext = NULL;
63  //The Echo server is not bound to any interface
64  settings->interface = NULL;
65 
66  //Echo service port number
67  settings->port = ECHO_PORT;
68 }
69 
70 
71 /**
72  * @brief Initialize Echo server context
73  * @param[in] context Pointer to the Echo server context
74  * @param[in] settings Echo server specific settings
75  * @return Error code
76  **/
77 
79  const EchoServerSettings *settings)
80 {
81  error_t error;
82 
83  //Debug message
84  TRACE_INFO("Initializing Echo server...\r\n");
85 
86  //Ensure the parameters are valid
87  if(context == NULL || settings == NULL)
89 
90  //Initialize status code
91  error = NO_ERROR;
92 
93  //Clear Echo server context
94  osMemset(context, 0, sizeof(EchoServerContext));
95 
96  //Initialize task parameters
97  context->taskParams = settings->task;
98  context->taskId = OS_INVALID_TASK_ID;
99 
100  //Attach TCP/IP stack context
101  if(settings->netContext != NULL)
102  {
103  context->netContext = settings->netContext;
104  }
105  else if(settings->interface != NULL)
106  {
107  context->netContext = settings->interface->netContext;
108  }
109  else
110  {
111  context->netContext = netGetDefaultContext();
112  }
113 
114  //Save user settings
115  context->interface = settings->interface;
116  context->port = settings->port;
117 
118  //Create an event object to poll the state of sockets
119  if(!osCreateEvent(&context->event))
120  {
121  //Failed to create event
122  error = ERROR_OUT_OF_RESOURCES;
123  }
124 
125  //Any error to report?
126  if(error)
127  {
128  //Clean up side effects
129  echoServerDeinit(context);
130  }
131 
132  //Return status code
133  return error;
134 }
135 
136 
137 /**
138  * @brief Start Echo server
139  * @param[in] context Pointer to the Echo server context
140  * @return Error code
141  **/
142 
144 {
145  error_t error;
146 
147  //Make sure the Echo server context is valid
148  if(context == NULL)
150 
151  //Debug message
152  TRACE_INFO("Starting Echo server...\r\n");
153 
154  //Make sure the Echo server is not already running
155  if(context->running)
156  return ERROR_ALREADY_RUNNING;
157 
158  //Start of exception handling block
159  do
160  {
161 #if (ECHO_SERVER_TCP_SUPPORT == ENABLED)
162  //Open a TCP socket
165  //Failed to open socket?
166  if(context->tcpSocket == NULL)
167  {
168  //Report an error
169  error = ERROR_OPEN_FAILED;
170  break;
171  }
172 
173  //Force the socket to operate in non-blocking mode
174  error = socketSetTimeout(context->tcpSocket, 0);
175  //Any error to report?
176  if(error)
177  break;
178 
179  //Associate the socket with the relevant interface
180  error = socketBindToInterface(context->tcpSocket, context->interface);
181  //Any error to report?
182  if(error)
183  break;
184 
185  //The Echo server listens for TCP connection requests on port 7
186  error = socketBind(context->tcpSocket, &IP_ADDR_ANY, context->port);
187  //Any error to report?
188  if(error)
189  break;
190 
191  //Place socket in listening state
192  error = socketListen(context->tcpSocket, 0);
193  //Any error to report?
194  if(error)
195  break;
196 #endif
197 
198 #if (ECHO_SERVER_UDP_SUPPORT == ENABLED)
199  //Open a UDP socket
200  context->udpSocket = socketOpenEx(context->netContext, SOCKET_TYPE_DGRAM,
202  //Failed to open socket?
203  if(context->udpSocket == NULL)
204  {
205  //Report an error
206  error = ERROR_OPEN_FAILED;
207  break;
208  }
209 
210  //Force the socket to operate in non-blocking mode
211  error = socketSetTimeout(context->udpSocket, 0);
212  //Any error to report?
213  if(error)
214  break;
215 
216  //Associate the socket with the relevant interface
217  error = socketBindToInterface(context->udpSocket, context->interface);
218  //Any error to report?
219  if(error)
220  break;
221 
222  //The Echo server listens for UDP datagrams on port 7
223  error = socketBind(context->udpSocket, &IP_ADDR_ANY, context->port);
224  //Any error to report?
225  if(error)
226  break;
227 #endif
228 
229  //Start the Echo server
230  context->stop = FALSE;
231  context->running = TRUE;
232 
233  //Create a task
234  context->taskId = osCreateTask("Echo Server", (OsTaskCode) echoServerTask,
235  context, &context->taskParams);
236 
237  //Failed to create task?
238  if(context->taskId == OS_INVALID_TASK_ID)
239  {
240  //Report an error
241  error = ERROR_OUT_OF_RESOURCES;
242  break;
243  }
244 
245  //End of exception handling block
246  } while(0);
247 
248  //Any error to report?
249  if(error)
250  {
251  //Clean up side effects
252  context->running = FALSE;
253 
254 #if (ECHO_SERVER_TCP_SUPPORT == ENABLED)
255  //Close listening TCP socket
256  socketClose(context->tcpSocket);
257  context->tcpSocket = NULL;
258 #endif
259 
260 #if (ECHO_SERVER_UDP_SUPPORT == ENABLED)
261  //Close UDP socket
262  socketClose(context->udpSocket);
263  context->udpSocket = NULL;
264 #endif
265  }
266 
267  //Return status code
268  return error;
269 }
270 
271 
272 /**
273  * @brief Stop Echo server
274  * @param[in] context Pointer to the Echo server context
275  * @return Error code
276  **/
277 
279 {
280 #if (ECHO_SERVER_TCP_SUPPORT == ENABLED)
281  uint_t i;
282 #endif
283 
284  //Make sure the Echo server context is valid
285  if(context == NULL)
287 
288  //Debug message
289  TRACE_INFO("Stopping Echo server...\r\n");
290 
291  //Check whether the Echo server is running
292  if(context->running)
293  {
294 #if (NET_RTOS_SUPPORT == ENABLED)
295  //Stop the Echo server
296  context->stop = TRUE;
297  //Send a signal to the task to abort any blocking operation
298  osSetEvent(&context->event);
299 
300  //Wait for the task to terminate
301  while(context->running)
302  {
303  osDelayTask(1);
304  }
305 #endif
306 
307 #if (ECHO_SERVER_TCP_SUPPORT == ENABLED)
308  //Loop through the TCP connection table
309  for(i = 0; i < ECHO_SERVER_MAX_TCP_CONNECTIONS; i++)
310  {
311  //Close TCP connection
313  }
314 
315  //Close listening TCP socket
316  socketClose(context->tcpSocket);
317  context->tcpSocket = NULL;
318 #endif
319 
320 #if (ECHO_SERVER_UDP_SUPPORT == ENABLED)
321  //Close UDP socket
322  socketClose(context->udpSocket);
323  context->udpSocket = NULL;
324 #endif
325  }
326 
327  //Successful processing
328  return NO_ERROR;
329 }
330 
331 
332 /**
333  * @brief Echo server task
334  * @param[in] context Pointer to the Echo server context
335  **/
336 
338 {
339  error_t error;
340  uint_t i;
341  systime_t timeout;
343 
344 #if (NET_RTOS_SUPPORT == ENABLED)
345  //Task prologue
346  osEnterTask();
347 
348  //Process events
349  while(1)
350  {
351 #endif
352  //Set polling timeout
353  timeout = ECHO_SERVER_TICK_INTERVAL;
354 
355  //Clear event descriptor set
356  osMemset(eventDesc, 0, sizeof(eventDesc));
357 
358 #if (ECHO_SERVER_TCP_SUPPORT == ENABLED)
359  //Specify the events the application is interested in
360  for(i = 0; i < ECHO_SERVER_MAX_TCP_CONNECTIONS; i++)
361  {
362  EchoTcpConnection *connection;
363 
364  //Point to the structure describing the current TCP connection
365  connection = &context->tcpConnection[i];
366 
367  //Loop through active connections only
368  if(connection->state != ECHO_TCP_CONNECTION_STATE_CLOSED)
369  {
370  //Register connection events
371  echoServerRegisterTcpConnectionEvents(connection, &eventDesc[i]);
372 
373  //Check whether the socket is ready for I/O operation
374  if(eventDesc[i].eventFlags != 0)
375  {
376  //No need to poll the underlying socket for incoming traffic
377  timeout = 0;
378  }
379  }
380  }
381 
382  //The Echo server listens for TCP connection requests on port 7
383  eventDesc[i].socket = context->tcpSocket;
384  eventDesc[i++].eventMask = SOCKET_EVENT_RX_READY;
385 #else
386  //TCP Echo service is not supported
387  i = 0;
388 #endif
389 
390 #if (ECHO_SERVER_UDP_SUPPORT == ENABLED)
391  //The Echo server listens for UDP datagrams on port 7
392  eventDesc[i].socket = context->udpSocket;
393  eventDesc[i++].eventMask = SOCKET_EVENT_RX_READY;
394 #endif
395 
396  //Wait for one of the set of sockets to become ready to perform I/O
397  error = socketPoll(eventDesc, i, &context->event, timeout);
398 
399  //Check status code
400  if(error == NO_ERROR || error == ERROR_TIMEOUT ||
401  error == ERROR_WAIT_CANCELED)
402  {
403  //Stop request?
404  if(context->stop)
405  {
406  //Stop Echo server operation
407  context->running = FALSE;
408  //Task epilogue
409  osExitTask();
410  //Kill ourselves
412  }
413 
414 #if (ECHO_SERVER_TCP_SUPPORT == ENABLED)
415  //Event-driven processing
416  for(i = 0; i < ECHO_SERVER_MAX_TCP_CONNECTIONS; i++)
417  {
418  EchoTcpConnection *connection;
419 
420  //Point to the structure describing the current TCP connection
421  connection = &context->tcpConnection[i];
422 
423  //Loop through active connections only
424  if(connection->state != ECHO_TCP_CONNECTION_STATE_CLOSED)
425  {
426  //Check whether the socket is ready to perform I/O
427  if(eventDesc[i].eventFlags != 0)
428  {
429  //Connection event handler
431  }
432  }
433  }
434 
435  //Any TCP connection request received on port 7?
436  if(eventDesc[i++].eventFlags != 0)
437  {
438  //Accept TCP connection request
440  }
441 #else
442  //TCP Echo service is not supported
443  i = 0;
444 #endif
445 
446 #if (ECHO_SERVER_UDP_SUPPORT == ENABLED)
447  //Any UDP datagram received on port 7?
448  if(eventDesc[i].eventFlags != 0)
449  {
450  //Process incoming UDP datagram
452  }
453 #endif
454  }
455 
456  //Handle periodic operations
457  echoServerTick(context);
458 
459 #if (NET_RTOS_SUPPORT == ENABLED)
460  }
461 #endif
462 }
463 
464 
465 /**
466  * @brief Release Echo server context
467  * @param[in] context Pointer to the Echo server context
468  **/
469 
471 {
472  //Make sure the Echo server context is valid
473  if(context != NULL)
474  {
475  //Free previously allocated resources
476  osDeleteEvent(&context->event);
477 
478  //Clear Echo server context
479  osMemset(context, 0, sizeof(EchoServerContext));
480  }
481 }
482 
483 #endif
void echoServerDeinit(EchoServerContext *context)
Release Echo server context.
Definition: echo_server.c:470
OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg, const OsTaskParameters *params)
Create a task.
@ SOCKET_IP_PROTO_UDP
Definition: socket.h:108
NetInterface * interface
Underlying network interface.
Definition: echo_server.h:166
error_t socketBind(Socket *socket, const IpAddr *localIpAddr, uint16_t localPort)
Associate a local address with a socket.
Definition: socket.c:1344
#define ECHO_SERVER_TICK_INTERVAL
Definition: echo_server.h:101
#define osExitTask()
#define ECHO_SERVER_PRIORITY
Definition: echo_server.h:54
OsTaskParameters task
Task parameters.
Definition: echo_server.h:137
#define TRUE
Definition: os_port.h:50
#define OS_INVALID_TASK_ID
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:2094
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
@ SOCKET_TYPE_DGRAM
Definition: socket.h:93
#define ECHO_PORT
Definition: echo_server.h:112
uint16_t port
Echo server port number.
Definition: echo_server.h:167
@ SOCKET_TYPE_STREAM
Definition: socket.h:92
#define OS_SELF_TASK_ID
Structure describing socket events.
Definition: socket.h:433
Echo TCP connection.
Definition: echo_server.h:149
@ ERROR_OPEN_FAILED
Definition: error.h:75
@ ECHO_TCP_CONNECTION_STATE_CLOSED
Definition: echo_server.h:126
void echoServerGetDefaultSettings(EchoServerSettings *settings)
Initialize settings with default values.
Definition: echo_server.c:54
const IpAddr IP_ADDR_ANY
Definition: ip.c:53
void osDeleteTask(OsTaskId taskId)
Delete a task.
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
void echoServerProcessTcpConnectionEvents(EchoTcpConnection *connection)
Connection event handler.
void echoServerAcceptTcpConnection(EchoServerContext *context)
Accept connection request.
error_t
Error codes.
Definition: error.h:43
Echo server.
Echo server settings.
Definition: echo_server.h:136
void(* OsTaskCode)(void *arg)
Task routine.
NetInterface * interface
Underlying network interface.
Definition: echo_server.h:139
void osDeleteEvent(OsEvent *event)
Delete an event object.
error_t echoServerStop(EchoServerContext *context)
Stop Echo server.
Definition: echo_server.c:278
Socket * tcpSocket
Listening TCP socket.
Definition: echo_server.h:174
NetContext * netGetDefaultContext(void)
Get default TCP/IP stack context.
Definition: net.c:527
const OsTaskParameters OS_TASK_DEFAULT_PARAMS
#define ECHO_SERVER_STACK_SIZE
Definition: echo_server.h:47
#define ECHO_SERVER_MAX_TCP_CONNECTIONS
Definition: echo_server.h:66
#define TRACE_INFO(...)
Definition: debug.h:105
NetContext * netContext
TCP/IP stack context.
Definition: echo_server.h:165
void echoServerTick(EchoServerContext *context)
Handle periodic operations.
EchoTcpConnection tcpConnection[ECHO_SERVER_MAX_TCP_CONNECTIONS]
TCP connections.
Definition: echo_server.h:175
bool_t running
Operational state of the Echo server.
Definition: echo_server.h:168
#define osEnterTask()
uint16_t port
Echo server port number.
Definition: echo_server.h:140
error_t socketPoll(SocketEventDesc *eventDesc, uint_t size, OsEvent *extEvent, systime_t timeout)
Wait for one of a set of sockets to become ready to perform I/O.
Definition: socket.c:2182
NetContext * netContext
TCP/IP stack context.
Definition: echo_server.h:138
#define socketBindToInterface
Definition: net_legacy.h:193
uint32_t systime_t
System time.
@ ERROR_TIMEOUT
Definition: error.h:95
void echoServerTask(EchoServerContext *context)
Echo server task.
Definition: echo_server.c:337
Socket * udpSocket
UDP socket.
Definition: echo_server.h:178
error_t echoServerInit(EchoServerContext *context, const EchoServerSettings *settings)
Initialize Echo server context.
Definition: echo_server.c:78
Echo server context.
Definition: echo_server.h:164
@ SOCKET_EVENT_RX_READY
Definition: socket.h:179
OsTaskId taskId
Task identifier.
Definition: echo_server.h:172
Socket * socketOpenEx(NetContext *context, uint_t type, uint_t protocol)
Create a socket.
Definition: socket.c:146
@ ERROR_WAIT_CANCELED
Definition: error.h:73
bool_t osCreateEvent(OsEvent *event)
Create an event object.
Helper functions for Echo server.
void echoServerRegisterTcpConnectionEvents(EchoTcpConnection *connection, SocketEventDesc *eventDesc)
Register TCP connection events.
error_t echoServerStart(EchoServerContext *context)
Start Echo server.
Definition: echo_server.c:143
OsEvent event
Event object used to poll the sockets.
Definition: echo_server.h:170
void osDelayTask(systime_t delay)
Delay routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
void echoServerCloseTcpConnection(EchoTcpConnection *connection)
Close TCP connection.
Socket * socket
Handle to a socket to monitor.
Definition: socket.h:434
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
void echoServerProcessUdpDatagram(EchoServerContext *context)
Process incoming UDP datagram.
TCP/IP stack core.
EchoTcpConnectionState state
Connection state.
Definition: echo_server.h:150
bool_t stop
Stop request.
Definition: echo_server.h:169
@ SOCKET_IP_PROTO_TCP
Definition: socket.h:107
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:169
uint_t eventMask
Requested events.
Definition: socket.h:435
@ ERROR_ALREADY_RUNNING
Definition: error.h:294
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
OsTaskParameters taskParams
Task parameters.
Definition: echo_server.h:171
error_t socketListen(Socket *socket, uint_t backlog)
Place a socket in the listening state.
Definition: socket.c:1441