Add ability to control route table req frequency
[ric-plt/lib/rmr.git] / src / rmr / common / src / tools_static.c
index 8e615af..b4245cd 100644 (file)
@@ -22,6 +22,7 @@
        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_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
 #include <sys/socket.h>
 #include <netdb.h>
 
 #include <sys/socket.h>
 #include <netdb.h>
 
+// --- some protos needed for better organisation --------
+int is_this_myip( if_addrs_t* l, char* addr );
+
+
+// ----------------------------------------------------------------------------------
 
 /*
        Simple tokeniser. Split a null terminated string into tokens recording the
 
 /*
        Simple tokeniser. Split a null terminated string into tokens recording the
@@ -77,6 +83,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
@@ -107,7 +150,7 @@ static char* uta_h2ip( char const* hname ) {
 
        hent = gethostbyname( dname );
        if( hent == NULL || hent->h_addr_list == NULL ) {
 
        hent = gethostbyname( dname );
        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;
        }
@@ -237,9 +280,12 @@ static int uta_has_str( char const* buf, char const* str, char sep, int max ) {
        that could be in the route table.
 
        If the environment variable which limits the binding of our listen port
        that could be in the route table.
 
        If the environment variable which limits the binding of our listen port
-       to a single interface (ENV_BIND_IF) then ONLY that address is added to
-       the list so that we don't pick up entries from the rtable that are for other
+       to a single interface (ENV_BIND_IF) then ONLY that interface/address is added
+       to the list so that we don't pick up entries from the rtable that are for other
        processes listening on different interfaces.
        processes listening on different interfaces.
+
+       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).
 */
 if_addrs_t*  mk_ip_list( char* port ) {
        if_addrs_t* l;
 */
 if_addrs_t*  mk_ip_list( char* port ) {
        if_addrs_t* l;
@@ -249,7 +295,8 @@ if_addrs_t*  mk_ip_list( char* port ) {
        char    wbuf[NI_MAXHOST+128];
        char*   fmt;
        char*   envp;                           // at the environment var if there
        char    wbuf[NI_MAXHOST+128];
        char*   fmt;
        char*   envp;                           // at the environment var if there
-
+       char*   target_if = NULL;       // target interface supplied by ENV_BIND_IF
+       char*   tok;
 
 
        if( (l = (if_addrs_t *) malloc( sizeof( if_addrs_t ) )) == NULL ) {
 
 
        if( (l = (if_addrs_t *) malloc( sizeof( if_addrs_t ) )) == NULL ) {
@@ -263,30 +310,42 @@ if_addrs_t*  mk_ip_list( char* port ) {
        }
 
        if( (envp = getenv( ENV_BIND_IF )) != NULL ) {
        }
 
        if( (envp = getenv( ENV_BIND_IF )) != NULL ) {
-               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 );
-               return l;
+               if( isdigit( *envp ) || *envp == '[' ) {                                        // ip address given and not device name
+                       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 ) rmr_vlog( RMR_VL_INFO, "rmr: using only specific bind interface when searching specific RT entries: %s\n", wbuf );
+                       return l;
+               }
+
+               target_if = envp;               // device name given, suss it out below
        }
 
        getifaddrs( &ifs );
        for( ele = ifs; ele; ele = ele->ifa_next ) {
        }
 
        getifaddrs( &ifs );
        for( ele = ifs; ele; ele = ele->ifa_next ) {
-               *octs = 0;
-
-               if( ele && strcmp( ele->ifa_name, "lo" )  ) {
-                       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";
+               memset( octs, 0, sizeof( octs ) );
+               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 != 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";
+                                       }
                                }
                        }
 
                        if( *octs ) {
                                }
                        }
 
                        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( 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++;
                                        snprintf( wbuf, sizeof( wbuf ), fmt, octs, port );              // smash port onto the addr
                                        l->addrs[l->naddrs] = strdup( wbuf );
                                        l->naddrs++;
@@ -316,8 +375,12 @@ int is_this_myip( if_addrs_t* l, char* addr ) {
                return 0;
        }
 
                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;
                }
        }
@@ -380,4 +443,21 @@ static int has_myip( char const* buf, if_addrs_t* list, char sep, int max ) {
        return rc;
 }
 
        return rc;
 }
 
+/*
+       Given a list manager block, return the default IP address.
+       For now, that is just the first address on the list which
+       easily could be non-deterministic and change with each restart
+       of the application if a specific interface is not provided via
+       the environment variable (ENV_BIND_IF) and if there is more than
+       one device available on the container/physical host.
+*/
+static char* get_default_ip( if_addrs_t* iplist ) {
+
+       if( iplist != NULL  &&  iplist->naddrs > 0  &&  iplist->addrs != NULL ) {
+               return strdup( iplist->addrs[0] );
+       }
+
+       return NULL;
+}
+
 #endif
 #endif