Add better support for manual app testing
[ric-plt/lib/rmr.git] / src / rmr / common / src / tools_static.c
index 67adc85..2d2cc22 100644 (file)
@@ -1,8 +1,8 @@
 // :vi sw=4 ts=4 noet:
 /*
 ==================================================================================
 // :vi sw=4 ts=4 noet:
 /*
 ==================================================================================
-       Copyright (c) 2019 Nokia
-       Copyright (c) 2018-2019 AT&T Intellectual Property.
+       Copyright (c) 2019-2021 Nokia
+       Copyright (c) 2018-2021 AT&T Intellectual Property.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
        Mnemonic:       tools_static.c
        Abstract:       A small set of very simple tools to support Uta == RMR.
                                        uta_tokenise -- simple string tokeniser
        Mnemonic:       tools_static.c
        Abstract:       A small set of very simple tools to support Uta == RMR.
                                        uta_tokenise -- simple string tokeniser
+                                       uta_rmip_tokenise -- tokenise and remove ip addresses from the list
                                        uta_h2ip        -- look up host name and return an ip address
                                        uta_lookup_rtg  -- looks in env for rtg host:port
                                        uta_has_str     -- searches buffer of tokens for a string
 
                                        uta_link2       -- establish a nanomsg connection to a host
 
                                        uta_h2ip        -- look up host name and return an ip address
                                        uta_lookup_rtg  -- looks in env for rtg host:port
                                        uta_has_str     -- searches buffer of tokens for a string
 
                                        uta_link2       -- establish a nanomsg connection to a host
 
+                                       uta_dump_env -- dump the environment variables to stdout that are
+                                                               of importance to RMR.
+
        Author:         E. Scott Daniels
        Date:           30 November 2018
 */
        Author:         E. Scott Daniels
        Date:           30 November 2018
 */
 #include <sys/socket.h>
 #include <netdb.h>
 
 #include <sys/socket.h>
 #include <netdb.h>
 
+// --- some protos needed for better organisation --------
+static int is_this_myip( if_addrs_t* l, char* addr );
+
+
+// ----------------------------------------------------------------------------------
+
+
+/*
+       A strncpy() replacement that ensures the resulting dest buffer has
+       a zero (nil) terminator even if the source is longer than the dest
+       length.
+       A max of len-1 bytes are copied from src to dest. The copy stops when
+       a zero (nil) is encountered in the src, or len-1 bytes are copied.
+       The string is always nil terminated.
+       The string length is returned.
+
+       It is the responsiblity of the caller to ensure that dest is at
+       least len bytes in length.
+
+       If either src/dest is invalid (nil) a value of -1 is returned.
+*/
+static inline int zt_buf_fill( char* dest, char const* src, int len ) {
+       char*           dp;
+       char const*     sp;
+       int                     n;              // num moved
+
+       if( dest == NULL || src == NULL ) {
+               return -1;
+       }
+
+       dp = dest;
+       sp = src;
+       n = 0;
+       while(  *sp && n < len-1 ) {
+               *(dp++) = *(sp++);
+               n++;
+       }
+
+       *dp = 0;
+       return n;
+}
 
 /*
        Simple tokeniser. Split a null terminated string into tokens recording the
 
 /*
        Simple tokeniser. Split a null terminated string into tokens recording the
@@ -77,6 +122,43 @@ static int uta_tokenise( char* buf, char** tokens, int max, char sep ) {
        return n;
 }
 
        return n;
 }
 
+/*
+       Tokenise and remove matches.
+       Given a buffer of 'sep' separated tokens, and a list of things,
+       return up to max tokens with any tokens that matched things in
+       the list. Toks is the user supplied array of char* which we will
+       fill in (up to max) with pointers to tokens from buf.  This
+       damages buf, so the caller must dup the string if it must be
+       preserved for later, original, use.  The pointers returned in
+       toks will reference portions of bufs.
+
+       Returns the number of tokens referenced by toks.
+*/
+static int uta_rmip_tokenise( char* buf, if_addrs_t* iplist, char** toks, int max, char sep ) {
+       int     ntoks = 0;                      // total toks in the original buffer
+       int             pcount = 0;                     // count after prune
+       char**  all_toks;
+       int i;
+       int j;
+
+
+       all_toks = malloc( sizeof( char * ) * max );                                    // refernce to all tokens; we'll prune
+       pcount = ntoks = uta_tokenise( buf, all_toks, max, sep );               // split them up
+       j = 0;
+       if( ntoks > 0 ) {
+               for( i = 0; i < ntoks; i++ ) {
+                       if( is_this_myip( iplist, all_toks[i] ) ) {
+                               pcount--;                                                                       // ours, prune
+                       } else {
+                               toks[j++] = all_toks[i];                                        // not one of ours, keep it
+                       }
+               }
+       }
+
+       free( all_toks );
+       return pcount;
+}
+
 /*
        Xlate hostname (expected to be name:port) to an IP address that nano will tolerate.
        We'll use the first address from the list to keep it simple. If the first character
 /*
        Xlate hostname (expected to be name:port) to an IP address that nano will tolerate.
        We'll use the first address from the list to keep it simple. If the first character
@@ -105,9 +187,9 @@ static char* uta_h2ip( char const* hname ) {
                *(tok++) = 0;
        }
 
                *(tok++) = 0;
        }
 
-       hent = gethostbyname( dname );
+       hent = gethostbyname( dname );                  // valgrind will complain that this leaks, but we cannot free it!
        if( hent == NULL || hent->h_addr_list == NULL ) {
        if( hent == NULL || hent->h_addr_list == NULL ) {
-               //fprintf( stderr, "[WARN] h2ip: dns lookup failed for: %s\n", dname );
+               //rmr_vlog( RMR_VL_WARN, "h2ip: dns lookup failed for: %s\n", dname );
                free( dname );
                return NULL;
        }
                free( dname );
                return NULL;
        }
@@ -129,6 +211,7 @@ static char* uta_h2ip( char const* hname ) {
 }
 
 
 }
 
 
+#ifdef RTG_PUB
 /*
        Looks for the environment variable RMR_RTG_SVC which we assume to be name[:port], and
        does a dns lookup on the name. If the env does not have such a variable, we default to
 /*
        Looks for the environment variable RMR_RTG_SVC which we assume to be name[:port], and
        does a dns lookup on the name. If the env does not have such a variable, we default to
@@ -177,6 +260,7 @@ static int uta_lookup_rtg( uta_ctx_t* ctx ) {
 
        return ctx->rtg_addr != NULL;
 }
 
        return ctx->rtg_addr != NULL;
 }
+#endif
 
 
 /*
 
 
 /*
@@ -241,16 +325,16 @@ static int uta_has_str( char const* buf, char const* str, char sep, int max ) {
        to the list so that we don't pick up entries from the rtable that are for other
        processes listening on different interfaces.
 
        to the list so that we don't pick up entries from the rtable that are for other
        processes listening on different interfaces.
 
-       The ENV_BIN_IF environment variable may be either an IP address (v6 must be in 
+       The ENV_BIN_IF environment variable may be either an IP address (v6 must be in
        square braces), or an interface name (e.g. eth0).
 */
        square braces), or an interface name (e.g. eth0).
 */
-if_addrs_t*  mk_ip_list( char* port ) {
+static if_addrs_t*  mk_ip_list( char* port ) {
        if_addrs_t* l;
        struct  ifaddrs *ifs;           // pointer to head
        struct  ifaddrs *ele;           // pointer into the list
        char    octs[NI_MAXHOST+1];
        char    wbuf[NI_MAXHOST+128];
        if_addrs_t* l;
        struct  ifaddrs *ifs;           // pointer to head
        struct  ifaddrs *ele;           // pointer into the list
        char    octs[NI_MAXHOST+1];
        char    wbuf[NI_MAXHOST+128];
-       char*   fmt;
+       char*   fmt = NULL;                     // address format (v4 or v6)
        char*   envp;                           // at the environment var if there
        char*   target_if = NULL;       // target interface supplied by ENV_BIND_IF
        char*   tok;
        char*   envp;                           // at the environment var if there
        char*   target_if = NULL;       // target interface supplied by ENV_BIND_IF
        char*   tok;
@@ -271,7 +355,7 @@ if_addrs_t*  mk_ip_list( char* port ) {
                        snprintf( wbuf, sizeof( wbuf ), "%s:%s", envp, port );          // smash port onto the addr as is
                        l->addrs[l->naddrs] = strdup( wbuf );
                        l->naddrs++;
                        snprintf( wbuf, sizeof( wbuf ), "%s:%s", envp, port );          // smash port onto the addr as is
                        l->addrs[l->naddrs] = strdup( wbuf );
                        l->naddrs++;
-                       if( DEBUG ) fprintf( stderr, "[INFO] rmr: using only specific bind interface when searching specific RT entries: %s\n", wbuf );
+                       if( DEBUG ) rmr_vlog( RMR_VL_INFO, "rmr: using only specific bind interface when searching specific RT entries: %s\n", wbuf );
                        return l;
                }
 
                        return l;
                }
 
@@ -281,30 +365,40 @@ if_addrs_t*  mk_ip_list( char* port ) {
        getifaddrs( &ifs );
        for( ele = ifs; ele; ele = ele->ifa_next ) {
                memset( octs, 0, sizeof( octs ) );
        getifaddrs( &ifs );
        for( ele = ifs; ele; ele = ele->ifa_next ) {
                memset( octs, 0, sizeof( octs ) );
+               if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "checking interface: %s\n", ele->ifa_name );
                if( ele && strcmp( ele->ifa_name, "lo" ) &&                                                                     // do NOT capture the loopback interface address
                        (target_if == NULL || strcmp( ele->ifa_name, target_if ) == 0 ) ) {             // no target, or matches ENV_BIND_IF target
 
                if( ele && strcmp( ele->ifa_name, "lo" ) &&                                                                     // do NOT capture the loopback interface address
                        (target_if == NULL || strcmp( ele->ifa_name, target_if ) == 0 ) ) {             // no target, or matches ENV_BIND_IF target
 
-                       if( ele->ifa_addr->sa_family == AF_INET ) {
-                               getnameinfo( ele->ifa_addr, sizeof( struct sockaddr_in ),  octs, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
-                               fmt = "%s:%s";
-                       } else {
-                               if( ele->ifa_addr->sa_family == AF_INET6 ) {
-                                       getnameinfo( ele->ifa_addr, sizeof( struct sockaddr_in6 ),  octs, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
-                                       fmt = "[%s]:%s";
+                       if( ele->ifa_addr != NULL ) {                                           // possible for some interfaces to not have an address
+                               if( ele->ifa_addr->sa_family == AF_INET ) {
+                                       getnameinfo( ele->ifa_addr, sizeof( struct sockaddr_in ),  octs, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
+                                       fmt = "%s:%s";
+                               } else {
+                                       if( ele->ifa_addr->sa_family == AF_INET6 ) {
+                                               getnameinfo( ele->ifa_addr, sizeof( struct sockaddr_in6 ),  octs, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
+                                               fmt = "[%s]:%s";
+                                       } else {
+                                               if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "unrecognised IF family (not v4 or v6)\n" );
+                                               continue;
+                                       }
                                }
                                }
-                       }
-
-                       if( *octs ) {
-                               if( (tok = strchr( octs, '%' )) != NULL ) {                     // for unknown reasons some ip6 addrs have %if-name appended; truncate
-                                       *tok = 0;
-                               }
-                               if( l->naddrs < 128 ) {
-                                       if( DEBUG ) fprintf( stderr, "[DBUG] capture address: %s: %s\n", ele->ifa_name, octs );
 
 
-                                       snprintf( wbuf, sizeof( wbuf ), fmt, octs, port );              // smash port onto the addr
-                                       l->addrs[l->naddrs] = strdup( wbuf );
-                                       l->naddrs++;
+                               if( *octs  && fmt != NULL ) {                           // possible that we didn't recognise the format (v4 or v6), don't try if we didn't
+                                       if( (tok = strchr( octs, '%' )) != NULL ) {                     // for unknown reasons some ip6 addrs have %if-name appended; truncate
+                                               *tok = 0;
+                                       }
+                                       if( l->naddrs < 128 ) {
+                                               if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "capture address: %s: %s\n", ele->ifa_name, octs );
+
+                                               snprintf( wbuf, sizeof( wbuf ), fmt, octs, port );              // smash port onto the addr
+                                               l->addrs[l->naddrs] = strdup( wbuf );
+                                               l->naddrs++;
+                                       }
+                               } else {
+                                       if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "unrecognised or no octets octs=%x fmt=%p\n", *octs, fmt );
                                }
                                }
+                       } else {
+                               if( DEBUG ) rmr_vlog( RMR_VL_DEBUG, "no ip address for interface: %s\n", ele->ifa_name );
                        }
                }
        }
                        }
                }
        }
@@ -323,15 +417,19 @@ if_addrs_t*  mk_ip_list( char* port ) {
        do a straight search through the list. We don't expect this to
        ever be a higly driven functions so not bothering to optimise.
 */
        do a straight search through the list. We don't expect this to
        ever be a higly driven functions so not bothering to optimise.
 */
-int is_this_myip( if_addrs_t* l, char* addr ) {
+static int is_this_myip( if_addrs_t* l, char* addr ) {
        int i;
 
        if( l == NULL ) {
                return 0;
        }
 
        int i;
 
        if( l == NULL ) {
                return 0;
        }
 
+       if( addr == NULL ) {
+               return 0;
+       }
+
        for( i = 0; i < l->naddrs; i++ ) {
        for( i = 0; i < l->naddrs; i++ ) {
-               if( strcmp( addr, l->addrs[i] ) == 0 ) {
+               if( l->addrs[i] != NULL  &&  strcmp( addr, l->addrs[i] ) == 0 ) {
                        return 1;
                }
        }
                        return 1;
                }
        }
@@ -411,4 +509,37 @@ static char* get_default_ip( if_addrs_t* iplist ) {
        return NULL;
 }
 
        return NULL;
 }
 
+/*
+       Write all environment variables that we consider to be important to stderr.
+*/
+static void uta_dump_env( ) {
+       char* token;
+       char* elist[] = {
+                       ENV_BIND_IF,
+                       ENV_RTG_PORT,
+                       ENV_RTG_ADDR,
+                       ENV_SEED_RT,
+                       ENV_SEED_MEMAP,
+                       ENV_RTG_RAW,
+                       ENV_VERBOSE_FILE,
+                       ENV_NAME_ONLY,
+                       ENV_WARNINGS,
+                       ENV_SRC_ID,
+                       ENV_LOG_HR,
+                       ENV_LOG_VLEVEL,
+                       ENV_CTL_PORT,
+                       ENV_RTREQ_FREA
+       };
+       int i;
+
+       for( i = 0; i < sizeof( elist ) / sizeof( char *); i ++ ) {
+               token = getenv( elist[i] );
+               if( token != NULL ) {
+                       rmr_vlog( RMR_VL_INFO, "dump_env: %s = '%s'\n", elist[i], token );
+               } else {
+                       rmr_vlog( RMR_VL_INFO, "dump_env: %s = <unset>\n", elist[i] );
+               }
+       }
+}
+
 #endif
 #endif