socket_misc.c
Go to the documentation of this file.
1 /**
2  * @file socket_misc.c
3  * @brief Helper functions for sockets
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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SOCKET_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "core/socket.h"
37 #include "core/socket_misc.h"
38 #include "core/raw_socket.h"
39 #include "core/udp.h"
40 #include "core/tcp.h"
41 #include "core/tcp_misc.h"
42 #include "debug.h"
43 
44 
45 /**
46  * @brief Allocate a socket
47  * @param[in] context Pointer to the TCP/IP stack context
48  * @param[in] type Type specification for the new socket
49  * @param[in] protocol Protocol to be used
50  * @return Handle referencing the new socket
51  **/
52 
54 {
55  error_t error;
56  uint_t i;
57  uint16_t port;
58  Socket *socket;
59 
60  //Initialize socket handle
61  socket = NULL;
62 
63 #if (TCP_SUPPORT == ENABLED)
64  //Connection-oriented socket?
66  {
67  //Always use TCP as underlying transport protocol
69  //Get an ephemeral port number
70  port = tcpGetDynamicPort(context);
71  //Continue processing
72  error = NO_ERROR;
73  }
74  else
75 #endif
76 #if (UDP_SUPPORT == ENABLED)
77  //Connectionless socket?
78  if(type == SOCKET_TYPE_DGRAM)
79  {
80  //Always use UDP as underlying transport protocol
82  //Get an ephemeral port number
83  port = udpGetDynamicPort(context);
84  //Continue processing
85  error = NO_ERROR;
86  }
87  else
88 #endif
89 #if (RAW_SOCKET_SUPPORT == ENABLED)
90  //Raw socket?
92  {
93  //Port numbers are not relevant for raw sockets
94  port = 0;
95  //Continue processing
96  error = NO_ERROR;
97  }
98  else
99 #endif
100  {
101  //The socket type is not supported
102  error = ERROR_INVALID_PARAMETER;
103  }
104 
105  //Check status code
106  if(!error)
107  {
108  //Loop through socket descriptors
109  for(i = 0; i < SOCKET_MAX_COUNT; i++)
110  {
111  //Unused socket found?
113  {
114  //Save socket handle
115  socket = &socketTable[i];
116  //We are done
117  break;
118  }
119  }
120 
121 #if (TCP_SUPPORT == ENABLED)
122  //No more sockets available?
123  if(socket == NULL)
124  {
125  //Kill the oldest connection in the TIME-WAIT state whenever the
126  //socket table runs out of space
128  }
129 #endif
130 
131  //Check whether the current entry is free
132  if(socket != NULL)
133  {
134  //Save socket descriptor
135  i = socket->descriptor;
136 
137  //Clear the structure keeping the event field untouched
138  osMemset(socket, 0, offsetof(Socket, event));
139 
140  osMemset((uint8_t *) socket + offsetof(Socket, event) + sizeof(OsEvent),
141  0, sizeof(Socket) - offsetof(Socket, event) - sizeof(OsEvent));
142 
143  //Save parameters
144  socket->netContext = context;
145  socket->descriptor = i;
146  socket->type = type;
147  socket->protocol = protocol;
148  socket->localPort = port;
149  socket->timeout = INFINITE_DELAY;
150 
151 #if (ETH_VLAN_SUPPORT == ENABLED)
152  //Default VLAN PCP and DEI fields
153  socket->vlanPcp = -1;
154  socket->vlanDei = -1;
155 #endif
156 
157 #if (ETH_VMAN_SUPPORT == ENABLED)
158  //Default VMAN PCP and DEI fields
159  socket->vmanPcp = -1;
160  socket->vmanDei = -1;
161 #endif
162 
163 #if (TCP_SUPPORT == ENABLED && TCP_KEEP_ALIVE_SUPPORT == ENABLED)
164  //TCP keep-alive mechanism must be disabled by default (refer to
165  //RFC 1122, section 4.2.3.6)
166  socket->keepAliveEnabled = FALSE;
167 
168  //Default TCP keep-alive parameters
169  socket->keepAliveIdle = TCP_DEFAULT_KEEP_ALIVE_IDLE;
170  socket->keepAliveInterval = TCP_DEFAULT_KEEP_ALIVE_INTERVAL;
171  socket->keepAliveMaxProbes = TCP_DEFAULT_KEEP_ALIVE_PROBES;
172 #endif
173 
174 #if (TCP_SUPPORT == ENABLED)
175  //Default MSS value
176  socket->mss = TCP_MAX_MSS;
177 
178  //Default TX and RX buffer size
181 
182  //Compute the window scale factor to use for the receive window
184 #endif
185  }
186  }
187 
188  //Return a handle to the freshly created socket
189  return socket;
190 }
191 
192 
193 /**
194  * @brief Subscribe to the specified socket events
195  * @param[in] socket Handle that identifies a socket
196  * @param[in] event Event object used to receive notifications
197  * @param[in] eventMask Logic OR of the requested socket events
198  **/
199 
201 {
202  //Valid socket handle?
203  if(socket != NULL)
204  {
205  //Get exclusive access
206  netLock(socket->netContext);
207 
208  //An user event may have been previously registered...
209  if(socket->userEvent != NULL)
210  {
211  socket->eventMask |= eventMask;
212  }
213  else
214  {
215  socket->eventMask = eventMask;
216  }
217 
218  //Suscribe to get notified of events
219  socket->userEvent = event;
220 
221 #if (TCP_SUPPORT == ENABLED)
222  //Handle TCP specific events
223  if(socket->type == SOCKET_TYPE_STREAM)
224  {
226  }
227 #endif
228 #if (UDP_SUPPORT == ENABLED)
229  //Handle UDP specific events
230  if(socket->type == SOCKET_TYPE_DGRAM)
231  {
233  }
234 #endif
235 #if (RAW_SOCKET_SUPPORT == ENABLED)
236  //Handle events that are specific to raw sockets
237  if(socket->type == SOCKET_TYPE_RAW_IP ||
238  socket->type == SOCKET_TYPE_RAW_ETH)
239  {
241  }
242 #endif
243 
244  //Release exclusive access
245  netUnlock(socket->netContext);
246  }
247 }
248 
249 
250 /**
251  * @brief Unsubscribe previously registered events
252  * @param[in] socket Handle that identifies a socket
253  **/
254 
256 {
257  //Valid socket handle?
258  if(socket != NULL)
259  {
260  //Get exclusive access
261  netLock(socket->netContext);
262 
263  //Unsuscribe socket events
264  socket->userEvent = NULL;
265 
266  //Release exclusive access
267  netUnlock(socket->netContext);
268  }
269 }
270 
271 
272 /**
273  * @brief Retrieve event flags for a specified socket
274  * @param[in] socket Handle that identifies a socket
275  * @return Logic OR of events in the signaled state
276  **/
277 
279 {
280  uint_t eventFlags;
281 
282  //Valid socket handle?
283  if(socket != NULL)
284  {
285  //Get exclusive access
286  netLock(socket->netContext);
287 
288  //Read event flags for the specified socket
289  eventFlags = socket->eventFlags;
290 
291  //Release exclusive access
292  netUnlock(socket->netContext);
293  }
294  else
295  {
296  //The socket handle is not valid
297  eventFlags = 0;
298  }
299 
300  //Return the events in the signaled state
301  return eventFlags;
302 }
303 
304 
305 /**
306  * @brief Filter out incoming multicast traffic
307  * @param[in] socket Handle that identifies a socket
308  * @param[in] destAddr Destination IP address of the received packet
309  * @param[in] srcAddr Source IP address of the received packet
310  * @return Return TRUE if the multicast packet should be accepted, else FALSE
311  **/
312 
314  const IpAddr *srcAddr)
315 {
316 #if (SOCKET_MAX_MULTICAST_GROUPS > 0)
317  uint_t i;
318  bool_t acceptable;
319  SocketMulticastGroup *group;
320 
321  //Initialize flag
322  acceptable = FALSE;
323 
324  //Loop through multicast groups
325  for(i = 0; i < SOCKET_MAX_MULTICAST_GROUPS; i++)
326  {
327  //Point to the current multicast group
328  group = &socket->multicastGroups[i];
329 
330  //Matching multicast address?
331  if(ipCompAddr(&group->addr, destAddr))
332  {
333 #if (SOCKET_MAX_MULTICAST_SOURCES > 0)
334  uint_t j;
335 
336  //Check filter mode
337  if(group->filterMode == IP_FILTER_MODE_INCLUDE)
338  {
339  //In INCLUDE mode, reception of packets sent to the specified
340  //multicast address is requested only from those IP source
341  //addresses listed in the source list
342  for(j = 0; j < SOCKET_MAX_MULTICAST_SOURCES && !acceptable; j++)
343  {
344  //Compare source addresses
345  if(ipCompAddr(&group->sources[j], srcAddr))
346  {
347  acceptable = TRUE;
348  }
349  }
350  }
351  else
352  {
353  //In EXCLUDE mode, reception of packets sent to the given multicast
354  //address is requested from all IP source addresses except those
355  //listed in the source list
356  acceptable = TRUE;
357 
358  //Loop through the list of excluded source addresses
359  for(j = 0; j < group->numSources && acceptable; j++)
360  {
361  //Compare source addresses
362  if(ipCompAddr(&group->sources[j], srcAddr))
363  {
364  acceptable = FALSE;
365  }
366  }
367  }
368 #else
369  //The multicast address is acceptable
370  acceptable = TRUE;
371 #endif
372  }
373  }
374 
375  //Return TRUE if the multicast packet should be accepted
376  return acceptable;
377 #else
378  //Not implemented
379  return FALSE;
380 #endif
381 }
382 
383 
384 /**
385  * @brief Create a new multicast group
386  * @param[in] socket Handle to a socket
387  * @param[in] groupAddr IP address identifying a multicast group
388  * @return Pointer to the newly created multicast group
389  **/
390 
392  const IpAddr *groupAddr)
393 {
394 #if (SOCKET_MAX_MULTICAST_GROUPS > 0)
395  uint_t i;
396  SocketMulticastGroup *group;
397 
398  //Initialize pointer
399  group = NULL;
400 
401  //Loop through multicast groups
402  for(i = 0; i < SOCKET_MAX_MULTICAST_GROUPS; i++)
403  {
404  //Check whether the current entry is available for use
405  if(socket->multicastGroups[i].addr.length == 0)
406  {
407  //Point to the current group
408  group = &socket->multicastGroups[i];
409 
410  //Save multicast group address
411  group->addr = *groupAddr;
412 
413 #if (SOCKET_MAX_MULTICAST_SOURCES > 0)
414  //By default, all sources are accepted
415  group->filterMode = IP_FILTER_MODE_EXCLUDE;
416  group->numSources = 0;
417 #endif
418  //We are done
419  break;
420  }
421  }
422 
423  //Return a pointer to the newly created multicast group
424  return group;
425 #else
426  //Not implemented
427  return NULL;
428 #endif
429 }
430 
431 
432 /**
433  * @brief Search the list of multicast groups for a given group address
434  * @param[in] socket Handle to a socket
435  * @param[in] groupAddr IP address identifying a multicast group
436  * @return A pointer to the matching multicast group is returned. NULL is
437  * returned if the specified group address cannot be found
438  **/
439 
441  const IpAddr *groupAddr)
442 {
443 #if (SOCKET_MAX_MULTICAST_GROUPS > 0)
444  uint_t i;
445  SocketMulticastGroup *group;
446 
447  //Initialize pointer
448  group = NULL;
449 
450  //Loop through multicast groups
451  for(i = 0; i < SOCKET_MAX_MULTICAST_GROUPS; i++)
452  {
453  //Compare group addresses
454  if(ipCompAddr(&socket->multicastGroups[i].addr, groupAddr))
455  {
456  //Point to the current group
457  group = &socket->multicastGroups[i];
458  break;
459  }
460  }
461 
462  //Return a pointer to the matching multicast group
463  return group;
464 #else
465  //Not implemented
466  return NULL;
467 #endif
468 }
469 
470 
471 /**
472  * @brief Delete a multicast group
473  * @param[in] group Pointer to the multicast group
474  **/
475 
477 {
478  //Delete the specified entry
479  group->addr = IP_ADDR_UNSPECIFIED;
480 }
481 
482 
483 /**
484  * @brief Add an address to the multicast source filter
485  * @param[in] group Pointer to the multicast group
486  * @param[in] srcAddr IP address to be added to the list
487  * @return Error code
488  **/
489 
491  const IpAddr *srcAddr)
492 {
493 #if (SOCKET_MAX_MULTICAST_SOURCES > 0)
494  error_t error;
495 
496  //Initialize status code
497  error = NO_ERROR;
498 
499  //Make sure that the source address is not a duplicate
500  if(socketFindMulticastSrcAddr(group, srcAddr) < 0)
501  {
502  //Check the length of the list
503  if(group->numSources < SOCKET_MAX_MULTICAST_SOURCES)
504  {
505  //Append the source address to the list
506  group->sources[group->numSources] = *srcAddr;
507  group->numSources++;
508  }
509  else
510  {
511  //The implementation limits the number of source addresses
512  error = ERROR_OUT_OF_RESOURCES;
513  }
514  }
515 
516  //Return status code
517  return error;
518 #else
519  //Not implemented
520  return ERROR_NOT_IMPLEMENTED;
521 #endif
522 }
523 
524 
525 /**
526  * @brief Remove an address from the multicast source filter
527  * @param[in] group Pointer to the multicast group
528  * @param[in] srcAddr IP address to be removed from the list
529  **/
530 
532  const IpAddr *srcAddr)
533 {
534 #if (SOCKET_MAX_MULTICAST_SOURCES > 0)
535  uint_t i;
536  uint_t j;
537 
538  //Loop through the list of source addresses
539  for(i = 0; i < group->numSources; i++)
540  {
541  //Matching IP address?
542  if(ipCompAddr(&group->sources[i], srcAddr))
543  {
544  //Remove the source address from the list
545  for(j = i + 1; j < group->numSources; j++)
546  {
547  group->sources[j - 1] = group->sources[j];
548  }
549 
550  //Update the length of the list
551  group->numSources--;
552 
553  //We are done
554  break;
555  }
556  }
557 #endif
558 }
559 
560 
561 /**
562  * @brief Search the list of multicast sources for a given IP address
563  * @param[in] group Pointer to the multicast group
564  * @param[in] srcAddr Source IP address
565  * @return Index of the matching IP address is returned. -1 is
566  * returned if the specified IP address cannot be found
567  **/
568 
570  const IpAddr *srcAddr)
571 {
572 #if (SOCKET_MAX_MULTICAST_SOURCES > 0)
573  int_t i;
574  int_t index;
575 
576  //Initialize index
577  index = -1;
578 
579  //Loop through the list of source addresses
580  for(i = 0; i < group->numSources; i++)
581  {
582  //Matching IP address?
583  if(ipCompAddr(&group->sources[i], srcAddr))
584  {
585  index = i;
586  break;
587  }
588  }
589 
590  //Return the index of the matching IP address, if any
591  return index;
592 #else
593  //Not implemented
594  return -1;
595 #endif
596 }
@ SOCKET_IP_PROTO_UDP
Definition: socket.h:108
void netUnlock(NetContext *context)
Release exclusive access to the core of the TCP/IP stack.
Definition: net.c:319
#define NetContext
Definition: net.h:36
Multicast group.
Definition: socket.h:273
void tcpComputeWindowScaleFactor(Socket *socket)
Compute the window scale factor to use for the receive window.
Definition: tcp_misc.c:1583
uint16_t tcpGetDynamicPort(NetContext *context)
Get an ephemeral port number.
Definition: tcp.c:102
int bool_t
Definition: compiler_port.h:63
Ipv4Addr destAddr
Definition: ipv4.h:354
uint8_t protocol
Definition: ipv4.h:351
signed int int_t
Definition: compiler_port.h:56
void udpUpdateEvents(Socket *socket)
Update UDP related events.
Definition: udp.c:971
IP network address.
Definition: ip.h:90
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
const IpAddr IP_ADDR_UNSPECIFIED
Definition: ip.c:54
#define TRUE
Definition: os_port.h:50
#define SOCKET_MAX_MULTICAST_GROUPS
Definition: socket.h:53
Event object.
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
@ SOCKET_TYPE_DGRAM
Definition: socket.h:93
@ IP_FILTER_MODE_EXCLUDE
Definition: ip.h:68
uint8_t type
Definition: coap_common.h:176
SocketMulticastGroup * socketCreateMulticastGroupEntry(Socket *socket, const IpAddr *groupAddr)
Create a new multicast group.
Definition: socket_misc.c:391
#define TCP_MAX_MSS
Definition: tcp.h:54
@ SOCKET_TYPE_STREAM
Definition: socket.h:92
#define TCP_DEFAULT_KEEP_ALIVE_INTERVAL
Definition: tcp.h:222
#define TCP_DEFAULT_TX_BUFFER_SIZE
Definition: tcp.h:68
IpAddr addr
Multicast address.
Definition: socket.h:274
#define FALSE
Definition: os_port.h:46
void socketRemoveMulticastSrcAddr(SocketMulticastGroup *group, const IpAddr *srcAddr)
Remove an address from the multicast source filter.
Definition: socket_misc.c:531
Helper functions for TCP.
void socketDeleteMulticastGroupEntry(SocketMulticastGroup *group)
Delete a multicast group.
Definition: socket_misc.c:476
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t
Error codes.
Definition: error.h:43
Socket * tcpKillOldestConnection(void)
Kill the oldest socket in the TIME-WAIT state.
Definition: tcp.c:1057
bool_t ipCompAddr(const IpAddr *ipAddr1, const IpAddr *ipAddr2)
Compare IP addresses.
Definition: ip.c:318
#define TCP_MAX_RX_BUFFER_SIZE
Definition: tcp.h:89
Socket * socketAllocate(NetContext *context, uint_t type, uint_t protocol)
Allocate a socket.
Definition: socket_misc.c:53
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:65
@ SOCKET_TYPE_RAW_IP
Definition: socket.h:94
void tcpUpdateEvents(Socket *socket)
Update TCP related events.
Definition: tcp_misc.c:2171
#define MIN(a, b)
Definition: os_port.h:63
Socket socketTable[SOCKET_MAX_COUNT]
Definition: socket.c:49
void rawSocketUpdateEvents(Socket *socket)
Update event state for raw sockets.
Definition: raw_socket.c:1020
#define TCP_MAX_TX_BUFFER_SIZE
Definition: tcp.h:75
TCP/IP raw sockets.
uint16_t udpGetDynamicPort(NetContext *context)
Get an ephemeral port number.
Definition: udp.c:80
uint16_t port
Definition: dns_common.h:270
#define TCP_DEFAULT_KEEP_ALIVE_PROBES
Definition: tcp.h:229
error_t socketAddMulticastSrcAddr(SocketMulticastGroup *group, const IpAddr *srcAddr)
Add an address to the multicast source filter.
Definition: socket_misc.c:490
void socketRegisterEvents(Socket *socket, OsEvent *event, uint_t eventMask)
Subscribe to the specified socket events.
Definition: socket_misc.c:200
Helper functions for sockets.
TCP (Transmission Control Protocol)
@ SOCKET_TYPE_UNUSED
Definition: socket.h:91
Ipv4Addr groupAddr
Definition: igmp_common.h:214
UDP (User Datagram Protocol)
#define Socket
Definition: socket.h:36
@ IP_FILTER_MODE_INCLUDE
Definition: ip.h:69
#define SOCKET_MAX_MULTICAST_SOURCES
Definition: socket.h:60
MacAddr srcAddr
Definition: ethernet.h:222
Socket API.
@ SOCKET_TYPE_RAW_ETH
Definition: socket.h:95
void netLock(NetContext *context)
Get exclusive access to the core of the TCP/IP stack.
Definition: net.c:307
#define TCP_DEFAULT_KEEP_ALIVE_IDLE
Definition: tcp.h:215
bool_t socketMulticastFilter(Socket *socket, const IpAddr *destAddr, const IpAddr *srcAddr)
Filter out incoming multicast traffic.
Definition: socket_misc.c:313
#define TCP_DEFAULT_RX_BUFFER_SIZE
Definition: tcp.h:82
unsigned int uint_t
Definition: compiler_port.h:57
void socketUnregisterEvents(Socket *socket)
Unsubscribe previously registered events.
Definition: socket_misc.c:255
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
#define SOCKET_MAX_COUNT
Definition: socket.h:46
SocketMulticastGroup * socketFindMulticastGroupEntry(Socket *socket, const IpAddr *groupAddr)
Search the list of multicast groups for a given group address.
Definition: socket_misc.c:440
@ SOCKET_IP_PROTO_TCP
Definition: socket.h:107
uint_t socketGetEvents(Socket *socket)
Retrieve event flags for a specified socket.
Definition: socket_misc.c:278
int_t socketFindMulticastSrcAddr(SocketMulticastGroup *group, const IpAddr *srcAddr)
Search the list of multicast sources for a given IP address.
Definition: socket_misc.c:569
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define INFINITE_DELAY
Definition: os_port.h:75