// :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.
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_dump_env -- dump the environment variables to stdout that are
+ of importance to RMR.
+
Author: E. Scott Daniels
Date: 30 November 2018
*/
#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
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
*(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 ) {
- //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;
}
}
+#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
return ctx->rtg_addr != NULL;
}
+#endif
/*
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).
*/
-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];
- 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;
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;
}
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->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 );
}
}
}
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;
}
+ if( addr == NULL ) {
+ return 0;
+ }
+
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 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