clean udp socket
authorMazet Laurent <laurent.mazet@thalesgroup.com>
Thu, 22 May 2025 13:17:28 +0000 (15:17 +0200)
committerMazet Laurent <laurent.mazet@thalesgroup.com>
Thu, 22 May 2025 13:17:28 +0000 (15:17 +0200)
sap.c
sap.h
sap_test.c

diff --git a/sap.c b/sap.c
index 3c6e74377f9c723e11a7a02c2198022f831ca529..700676452d1e3f77ec7d757776c6e7159ad42d25 100644 (file)
--- a/sap.c
+++ b/sap.c
 
 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 ef43c10e608e3dda7a3034fddf15d718e5e8de2a..a4b810fea49128b6e35451d1127b9ea33f782a7c 100644 (file)
--- 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);
index f8b688157b5452dd191143a3da88993720122cb8..45a59a8ce78df96b4c5331de625eada67bef7c15 100644 (file)
@@ -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");