From b66bf162769b94fa04d6c4e72cffdb6480bfdb96 Mon Sep 17 00:00:00 2001 From: Mazet Laurent Date: Thu, 22 May 2025 15:17:28 +0200 Subject: [PATCH] clean udp socket --- sap.c | 238 +++++++++++++++++++++-------------------------------- sap.h | 73 ++-------------- sap_test.c | 44 +++++----- 3 files changed, 122 insertions(+), 233 deletions(-) diff --git a/sap.c b/sap.c index 3c6e743..7006764 100644 --- a/sap.c +++ b/sap.c @@ -32,34 +32,42 @@ DECLARE_VERBOSE_LEVEL (sap, INFO); +/** + SAP type +*/ +typedef enum { + SAP_error_e = 0, + SAP_udp_e +} SAP_type_t; + /** SAP address structure */ typedef struct { - enum { SAP_error, SAP_udp } type; - struct sockaddr_in sockaddr; + SAP_type_t type; + struct sockaddr_in addrin; + struct sockaddr_in addrout; } SAP_addr_t; #define MAX_SAP_NUMBER 4096 -/** - Type of private descriptor associated to each connected SAP. -*/ -typedef struct { - int is_blocking; -} SAP_descriptor_t ; - /** List of private descriptor associated to each connected SAP. */ -SAP_descriptor_t *SAP_list[MAX_SAP_NUMBER] = { 0 }; +SAP_addr_t *SAP_list[MAX_SAP_NUMBER] = { 0 }; -/** - Init flag -*/ -static int __init = 1; +SAP_addr_t *sapdup (SAP_addr_t *sap) +{ + + VERBOSE (sap, TRACE, PRINTF ("sapdup\n")); + + SAP_addr_t *newsap = (SAP_addr_t *) calloc (1, sizeof (SAP_addr_t)); + memcpy (newsap, sap, sizeof (SAP_addr_t)); + + return newsap; +} -void free_saps (void) +void free_all_saps (void) { VERBOSE (sap, TRACE, PRINTF ("free_saps\n")); @@ -70,32 +78,56 @@ void free_saps (void) } } -static inline int parse_url (const char *ascii_url, SAP_addr_t *addr) +void __attribute__ ((constructor)) _init_morep_ (void) { + atexit (free_all_saps); +} - VERBOSE (sap, TRACE, PRINTF ("parse_url\n")); +int parse_protocol (SAP_addr_t *addr, char *url) +{ - struct in_addr **addr_list; - char url_to_parse[256] = { 0 }; + VERBOSE (sap, TRACE, PRINTF ("parse_protocol\n")); - strncpy (url_to_parse, ascii_url, sizeof (url_to_parse) - 1); - if (strncmp (url_to_parse, "udp://", 6) == 0) { - addr->type = SAP_udp; - } else { + int rc = -1; + SAP_type_t type = SAP_error_e; + if (strncmp (url, "udp://", 6) == 0) { + type = SAP_udp_e; + rc = 6; + } + if (addr->type == SAP_error_e) { + addr->type = type; + } else if (addr->type != type) { + rc = -1; + } + + return rc; +} + + +int parse_address (struct sockaddr_in *addr, char *url) +{ + + VERBOSE (sap, TRACE, PRINTF ("parse_addr\n")); + + char *pt = strchr (url, ':'); + if (pt == NULL) { + VERBOSE (sap, WARNING, PRINTF ("can't parse address '%s'\n", url)); return -1; } - char *hostname = strtok (url_to_parse + 6, ":"); - char *port = strtok (NULL, ":"); - if ((hostname == NULL) || (port == NULL)) { + char *hostname = (char *) calloc (pt - url + 1, 1); + memcpy (hostname, url, pt - url); + char *port = pt + 1; + if ((*hostname == '\0') || (*port == '\0')) { errno = EINVAL; + free (hostname); return -1; } - addr->sockaddr.sin_family = AF_INET; - addr->sockaddr.sin_port = htons (atoi (port)); + addr->sin_family = AF_INET; + addr->sin_port = htons (atoi (port)); - VERBOSE (sap, INFO, PRINTF ("parse URL %s %s\n", hostname, port)); + VERBOSE (sap, INFO, PRINTF ("parse URL -> %s %s\n", hostname, port)); if (hostname[0] != '*') { struct hostent *he = gethostbyname (hostname); @@ -104,151 +136,69 @@ static inline int parse_url (const char *ascii_url, SAP_addr_t *addr) return -1; } - addr_list = (struct in_addr **) he->h_addr_list; - addr->sockaddr.sin_addr.s_addr = addr_list[0]->s_addr; + struct in_addr **addr_list = (struct in_addr **) he->h_addr_list; + addr->sin_addr.s_addr = addr_list[0]->s_addr; } else { - addr->sockaddr.sin_addr.s_addr = INADDR_ANY; + addr->sin_addr.s_addr = INADDR_ANY; } + free (hostname); return 0; } -static inline int sap_create_and_listen (char *local_address) +int SAP_Connect (char *local_address, char * remote_address) { - VERBOSE (sap, TRACE, PRINTF ("sap_create_and_listen\n")); + VERBOSE (sap, TRACE, PRINTF ("SAP_Connect\n")); - SAP_addr_t addr; - int sap = 0; + SAP_addr_t sap = { 0 }; + int rc; + /* parse local url */ VERBOSE (sap, DEBUG, PRINTF ("SAP local addr %s\n", local_address)); - if (parse_url (local_address, &addr) < 0) { - VERBOSE (sap, ERROR, PRINTF ("can't parse url\n")); - errno = EINVAL; - return -1; - } - - VERBOSE (sap, DEBUG, PRINTF ("local port: %d\n", ntohs (addr.sockaddr.sin_port))); - - switch (addr.type) { - case SAP_udp: - sap = socket (PF_INET, SOCK_DGRAM, 0); - if (sap >= 0) { - int val = 1; - setsockopt (sap, SOL_SOCKET, SO_REUSEADDR, (OPT_TYPE *)&val, sizeof (val)); - if (bind (sap, (struct sockaddr *)&addr.sockaddr, sizeof (addr.sockaddr)) < 0) { - VERBOSE (sap, ERROR, PRINTF ("cant bind on SAP %d\n", sap)); - } - } - break; - default: + rc = parse_protocol (&sap, local_address); + if ((rc <= 0) || (parse_address (&sap.addrin, local_address + rc) < 0)) { + VERBOSE (sap, ERROR, PRINTF ("can't parse local url\n")); errno = EINVAL; return -1; - break; } + VERBOSE (sap, DEBUG, PRINTF ("local port -> %d\n", ntohs (sap.addrin.sin_port))); - return sap; -} - -int SAP_Create (char *local_address) -{ - - VERBOSE (sap, TRACE, PRINTF ("SAP_Create\n")); - - return sap_create_and_listen (local_address); -} - -int SAP_Connect (char *local_address, char * remote_address) -{ - - VERBOSE (sap, TRACE, PRINTF ("SAP_Connect\n")); - - SAP_addr_t addr; - int sap; - + /* parse remote url */ VERBOSE (sap, DEBUG, PRINTF ("SAP remote addr %s\n", remote_address)); - if (parse_url (remote_address, &addr) < 0) { - VERBOSE (sap, ERROR, PRINTF ("can't parse url\n")); + rc = parse_protocol (&sap, remote_address); + if ((rc <= 0) || (parse_address (&sap.addrout, remote_address + rc) < 0)) { + VERBOSE (sap, ERROR, PRINTF ("can't parse remote url\n")); errno = EINVAL; return -1; } + VERBOSE (sap, DEBUG, PRINTF ("remote port -> %d\n", ntohs (sap.addrout.sin_port))); - VERBOSE (sap, DEBUG, PRINTF ("remote port: %d\n", ntohs (addr.sockaddr.sin_port))); - - if (local_address) { - VERBOSE (sap, DEBUG, PRINTF ("SAP local addr %s\n", local_address)); - sap = sap_create_and_listen (local_address); - } else { - VERBOSE (sap, DEBUG, PRINTF ("SAP local addr '*'\n")); - switch (addr.type) { - case SAP_udp: - sap = socket (PF_INET, SOCK_DGRAM, 0); - break; - default: - VERBOSE (sap, ERROR, PRINTF ("unkown protocol\n")); - errno = EINVAL; - return -1; - } - } - - if (sap < 0) { - VERBOSE (sap, ERROR, PRINTF ("can't accept any SAP\n")); - return sap; - } - if (sap >= MAX_SAP_NUMBER) { - VERBOSE (sap, ERROR, PRINTF ("no more SAP avaliable\n")); + /* create socket */ + int sock = socket (PF_INET, SOCK_DGRAM, 0); + if ((sock < 0) || (sock >= MAX_SAP_NUMBER) || (SAP_list[sock] != NULL)) { + VERBOSE (sap, ERROR, PRINTF ("can't accept socket %d\n", sock)); errno = ENOMEM; return -1; } - if (connect (sap, (struct sockaddr *)&addr.sockaddr, sizeof (addr.sockaddr)) < 0) { - VERBOSE (sap, ERROR, PRINTF ("can't connect on soket %d\n", sap)); + /* bind on local */ + int val = 1; + setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (OPT_TYPE *)&val, sizeof (val)); + if (bind (sock, (struct sockaddr *)&sap.addrin, sizeof (sap.addrin)) < 0) { + VERBOSE (sap, ERROR, PRINTF ("can't bind socket %d\n", sock)); return -1; } - - assert (SAP_list[sap] == NULL); - SAP_list[sap] = (SAP_descriptor_t *) calloc (1, sizeof (SAP_descriptor_t)); - assert (SAP_list[sap]); - - if (__sync_bool_compare_and_swap (&__init, 1, 0)) { - atexit (free_saps); - } - - return sap; -} - -int SAP_IsConnected (int sap) -{ - - VERBOSE (sap, TRACE, PRINTF ("SAP_IsConnected\n")); - int sockerr; - socklen_t rlen = sizeof (sockerr); - - if (getsockopt (sap, SOL_SOCKET, SO_ERROR, (OPT_TYPE *)&sockerr, &rlen) < 0) { - VERBOSE (sap, ERROR, PRINTF ("error on getsockopt\n")); + /* connect on remote */ + if (connect (sock, (struct sockaddr *)&sap.addrout, sizeof (sap.addrout)) < 0) { + VERBOSE (sap, ERROR, PRINTF ("can't connect socket %d\n", sock)); return -1; } + + SAP_list[sock] = sapdup (&sap); - switch (sockerr) { - case 0: - return 1; - break; - case EINPROGRESS: - return 0; - break; - } - - return -1; -} - -void SAP_Reject (int sap) -{ - - VERBOSE (sap, TRACE, PRINTF ("SAP_Reject\n")); - - int newsap = accept (sap, NULL, 0); - close (newsap); + return sock; } void SAP_Close (int sap) diff --git a/sap.h b/sap.h index ef43c10..a4b810f 100644 --- a/sap.h +++ b/sap.h @@ -21,30 +21,10 @@ __BEGIN_DECLS however, the abstraction level provided by this library will permit future implementations on other communication networks (shared memory for example). - - sap values returned by SAP_Create(), SAP_Connect and - SAP_Accept() are standard Linux file descriptors that can be used - in select()/poll() system calls. -*/ - -/** - @ingroup SAP - - Create a new SAP (Service Access Point) that will be used later for - outgoing or incoming connection - @param local_address local address of the SAP with the following - syntax: 'udp://hostname:port' or 'tcp://hostname:port', hostname - can be '*' to listen on any address handled by the host - - @return a new file descriptor associated with this SAP - - @see SAP_Connect() - @see SAP_Accept() - @see SAP_Reject() - @see SAP_Close() + sap values returned by SAP_Connect is a standard Linux file + descriptors that can be used in select()/poll() system calls. */ -int SAP_Create (char *local_address); /** @ingroup SAP @@ -53,60 +33,24 @@ int SAP_Create (char *local_address); until connection is established or refused. @param local_address local address of the SAP with the following - syntax: 'udp://hostname:port' or 'tcp://hostname:port'. Can be - NULL if local address dot not need to be specified + syntax: 'udp://hostname:port'. @param remote_address same format as for local_address @return a new file descriptor associated with this connection - @see SAP_Create() - @see SAP_Accept() - @see SAP_Reject() @see SAP_Close() @see SAP_Send() @see SAP_Receive() */ int SAP_Connect (char *local_address, char *remote_address); -/** - @ingroup SAP - - Check if connection is established, typ. called after - SAP_Connect() - - @param sap sap retuned by SAP_Connect - - @return -1=error, 0=not yet connected, 1=connected - - @see SAP_Connect() -*/ -int SAP_Is_Connected (int sap); - -/** - @ingroup SAP - - Reject an incoming connection. Returns immediately. - - @param sap the file descriptor retuned by SAP_Create() - - @see SAP_Create() - @see SAP_Accept() - @see SAP_Close() - @see SAP_Send() - @see SAP_Receive() -*/ -void SAP_Reject (int sap); - /** @ingroup SAP Destroy a SAP. - @param sap the file descriptor retuned by SAP_Create() or - SAP_Connect() or SAP_Accept() + @param sap the file descriptor retuned by SAP_Connect() - @see SAP_Create() - @see SAP_Accept() @see SAP_Connect() */ void SAP_Close (int sap); @@ -123,7 +67,6 @@ void SAP_Close (int sap); transmitted @param len length of the message - @see SAP_Accept() @see SAP_Connect() */ int SAP_Send (int sap, unsigned char *data, int len); @@ -134,14 +77,12 @@ int SAP_Send (int sap, unsigned char *data, int len); Received a message over an existing SAP connection. Returns immediately if SAP not set to blocking mode - @param sap the file descriptor retuned by SAP_Connect() or - SAP_Accept() + @param sap the file descriptor retuned by SAP_Connect() @param buffer a pointer to the reception buffer @param maxlen max length of the reception buffer @return length of the message or 0 if no message was pending - @see SAP_Accept() @see SAP_Connect() */ int SAP_Receive (int sap, unsigned char *buffer, int maxlen); @@ -151,15 +92,13 @@ int SAP_Receive (int sap, unsigned char *buffer, int maxlen); Received a message over an existing SAP connection with a timeout - @param sap the file descriptor retuned by SAP_Connect() or - SAP_Accept() + @param sap the file descriptor retuned by SAP_Connect() @param buffer a pointer to the reception buffer @param maxlen max length of the reception buffer @param ms Exit after microseconds if now data is received @return length of the message or 0 if no message was pending - @see SAP_Accept() @see SAP_Connect() */ int SAP_Receive_timeout (int sap, unsigned char *buffer, int maxlen, int ms); diff --git a/sap_test.c b/sap_test.c index f8b6881..45a59a8 100644 --- a/sap_test.c +++ b/sap_test.c @@ -49,35 +49,34 @@ void *udp_client (UNUSED void *dummy) for (count = 0; count < nb_messages; count++) { - tx_len[count] = rand () % sizeof (tx_data[count]); - for (int i = 0; i < tx_len[count]; i++) - tx_data[count][i] = rand () % 256; - - int rc = SAP_Send (sap, tx_data[count], tx_len[count]); - if (rc < 0) { - VERBOSE (sap, WARNING, PRINTF ("client SAP_Send tx error (%d/%d-%d)\n", rc, tx_len[count], errno)); - SAP_Echo_UDP_OK = 0; - return NULL; - } + tx_len[count] = rand () % sizeof (tx_data[count]); + for (int i = 0; i < tx_len[count]; i++) + tx_data[count][i] = rand () % 256; - if (tx_len[count] != rc) { - VERBOSE (sap, WARNING, PRINTF ("client SAP_Send tx len error tx=%d rc=%d\n", tx_len[count], rc)); - SAP_Echo_UDP_OK = 0; - return NULL; - } - VERBOSE (sap, DEBUG, PRINTF ("client SAP_Send ok (%d)\n", tx_len[count])); - } + int rc = SAP_Send (sap, tx_data[count], tx_len[count]); + if (rc < 0) { + VERBOSE (sap, WARNING, PRINTF ("client SAP_Send tx error (%d/%d-%d)\n", rc, tx_len[count], errno)); + SAP_Echo_UDP_OK = 0; + return NULL; + } + + if (tx_len[count] != rc) { + VERBOSE (sap, WARNING, PRINTF ("client SAP_Send tx len error tx=%d rc=%d\n", tx_len[count], rc)); + SAP_Echo_UDP_OK = 0; + return NULL; + } + VERBOSE (sap, DEBUG, PRINTF ("client SAP_Send ok (%d)\n", tx_len[count])); + + usleep (1e4); - for (count = 0; count < 10; count++) { int rx_len; unsigned char rx_data[32768]; - do { rx_len = SAP_Receive (sap, rx_data, sizeof (rx_data)); if (rx_len == 0) { VERBOSE (sap, DEBUG, PRINTF ("client's sleeping...\n")); - sleep (1); + usleep (1e3); } } while (rx_len == 0); @@ -122,7 +121,7 @@ void *udp_server (UNUSED void *dummy) int rx_len = SAP_Receive (sap, data, sizeof (data)); if (rx_len == 0) { VERBOSE (sap, DEBUG, PRINTF ("server's sleeping...\n")); - sleep (1); + usleep (1e3); continue; } if (rx_len < 0) { @@ -132,6 +131,7 @@ void *udp_server (UNUSED void *dummy) } VERBOSE (sap, INFO, PRINTF ("udp_server receive data len=%d, sending echo\n", rx_len)); + usleep (1e4); int tx_len = SAP_Send (sap, data, rx_len); if (tx_len == rx_len) { @@ -172,7 +172,7 @@ int main (int argc, char **argv) pthread_create (&udp_thread, NULL, udp_server, NULL); /* Give some delay to server to setup there SAP */ - sleep (1); + usleep (1e6); printf ("*** STARTING TEST SEQUENCE ***\n"); -- 2.30.2