3 ==================================================================================
4 Copyright (c) 2019 Nokia
5 Copyright (c) 2018-2019 AT&T Intellectual Property.
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
11 http://www.apache.org/licenses/LICENSE-2.0
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18 ==================================================================================
22 Mnemonic: tools_static.c
23 Abstract: A small set of very simple tools to support Uta == RMR.
24 uta_tokenise -- simple string tokeniser
25 uta_h2ip -- look up host name and return an ip address
26 uta_lookup_rtg -- looks in env for rtg host:port
27 uta_has_str -- searches buffer of tokens for a string
29 uta_link2 -- establish a nanomsg connection to a host
31 Author: E. Scott Daniels
32 Date: 30 November 2018
35 #ifndef _tools_static_c
36 #define _tools_static_c
47 #include <sys/types.h> // these are needed to suss out ip addresses from interfaces
49 #include <arpa/inet.h>
50 #include <sys/socket.h>
55 Simple tokeniser. Split a null terminated string into tokens recording the
56 pointers in the tokens array provided. Tokens MUST be large enough. Max is
57 the max number of tokens to split into. Returns the actual number of tokens
58 recorded in the pointer array.
60 CAUTION: this modifies the string passed in!!
62 static int uta_tokenise( char* buf, char** tokens, int max, char sep ) {
63 char* end; // end of token
66 if( !buf || ! tokens || !(*buf) ) {
72 while( n < max && *end && (end = strchr( end, sep )) != NULL ) {
81 Xlate hostname (expected to be name:port) to an IP address that nano will tolerate.
82 We'll use the first address from the list to keep it simple. If the first character
83 of the name is a digit, we assume it's really an IP address and just return that.
85 Return is a string which the caller must free. Even if the string passed in is already
86 an IP address, a duplicate will be returend so that it can always be freed.
87 On error a nil pointer is returned.
89 static char* uta_h2ip( char const* hname ) {
96 char* dname; // duplicated name for distruction
98 dname = strdup( hname );
100 if( isdigit( *dname ) || *dname == '[' ) { // hostnames can't start with digit, or ipv6 [; assume ip address
104 if( (tok = strchr( dname, ':' )) != NULL ) {
108 hent = gethostbyname( dname );
109 if( hent == NULL || hent->h_addr_list == NULL ) {
110 //fprintf( stderr, "[WARN] h2ip: dns lookup failed for: %s\n", dname );
115 a = ntohl( *((unsigned int *)hent->h_addr_list[0]) );
116 for( i = 3; i >= 0; i-- ) {
121 if( tok ) { // if :port was given, smash it back on
122 snprintf( buf, sizeof( buf ), "%d.%d.%d.%d:%s", octs[0], octs[1], octs[2], octs[3], tok );
124 snprintf( buf, sizeof( buf ), "%d.%d.%d.%d", octs[0], octs[1], octs[2], octs[3] );
128 return strdup( buf );
133 Looks for the environment variable RMR_RTG_SVC which we assume to be name[:port], and
134 does a dns lookup on the name. If the env does not have such a variable, we default to
135 "rtg" and a port of 5656.
137 Returns true (1) if lookup found something;
139 CAUTION: this is ONLY used if the RTG is a pub and we are using pub/sub to get updates.
140 There are issues with some underlying transport pub/sub implementations so this
141 is likley NOT needed/used.
143 static int uta_lookup_rtg( uta_ctx_t* ctx ) {
144 char* ev; // pointer to the env value
145 char* def_port = "5656";
154 if( ctx->rtg_addr ) {
155 free( ctx->rtg_addr );
158 if( (ev = getenv( "RMR_RTG_SVC" )) == NULL ) {
162 dstr = strdup( ev ); // copy so we can trash it
163 if( (port = strchr( dstr, ':' )) == NULL ) {
167 port++; // point at the first digit
169 ev = dstr; // all references below assume ev
172 ctx->rtg_addr = uta_h2ip( ev ); // convert name to IP addr
173 ctx->rtg_port = atoi( port );
178 return ctx->rtg_addr != NULL;
183 Expects a buffer of 'sep' separated tokens and looks to see if
184 the given string is one of those tokens. Returns the token
185 index (0 - n-1) if the string is found; -1 otherwise. The max
186 parameter supplies the maximum number of tokens to search in
189 On failure (-1) errno will be set in cases where memory cannot
190 be alocated (is this even possible any more?). If errno is 0
191 and failure is returned, then the caller should assume that
192 the token isn't in the list, or the list had no elements.
194 static int uta_has_str( char const* buf, char const* str, char sep, int max ) {
195 char* dbuf; // duplicated buf so we can trash
196 char** tokens; // pointer to tokens from the string
197 int ntokens; // number of tokens buf split into
199 int rc; // return code
205 dbuf = strdup( buf );
211 if( (tokens = (char **) malloc( sizeof( char * ) * max )) == NULL ) {
217 ntokens = uta_tokenise( dbuf, tokens, max, sep );
220 for( i = 0; rc < 0 && i < ntokens; i++ ) {
222 if( strcmp( tokens[i], str ) == 0 ) {
234 Generate a list of all IP address associated with the interfaces available.
235 For now we capture them all, but we may need to limit. The port is smashed
236 onto each IP we find so that we can do a direct compare against the addr
237 that could be in the route table.
239 If the environment variable which limits the binding of our listen port
240 to a single interface (ENV_BIND_IF) then ONLY that address is added to
241 the list so that we don't pick up entries from the rtable that are for other
242 processes listening on different interfaces.
244 if_addrs_t* mk_ip_list( char* port ) {
246 struct ifaddrs *ifs; // pointer to head
247 struct ifaddrs *ele; // pointer into the list
248 char octs[NI_MAXHOST+1];
249 char wbuf[NI_MAXHOST+128];
251 char* envp; // at the environment var if there
255 if( (l = (if_addrs_t *) malloc( sizeof( if_addrs_t ) )) == NULL ) {
258 memset( l, 0, sizeof( if_addrs_t ) );
259 l->addrs = (char **) malloc( sizeof( char* ) * 128 );
260 if( l->addrs == NULL ) {
265 if( (envp = getenv( ENV_BIND_IF )) != NULL ) {
266 snprintf( wbuf, sizeof( wbuf ), "%s:%s", envp, port ); // smash port onto the addr as is
267 l->addrs[l->naddrs] = strdup( wbuf );
269 if( DEBUG ) fprintf( stderr, "[INFO] rmr: using only specific bind interface when searching specific RT entries: %s\n", wbuf );
274 for( ele = ifs; ele; ele = ele->ifa_next ) {
277 if( ele && strcmp( ele->ifa_name, "lo" ) ) {
278 if( ele->ifa_addr->sa_family == AF_INET ) {
279 getnameinfo( ele->ifa_addr, sizeof( struct sockaddr_in ), octs, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
282 if( ele->ifa_addr->sa_family == AF_INET6 ) {
283 getnameinfo( ele->ifa_addr, sizeof( struct sockaddr_in6 ), octs, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
289 if( l->naddrs < 128 ) {
290 snprintf( wbuf, sizeof( wbuf ), fmt, octs, port ); // smash port onto the addr
291 l->addrs[l->naddrs] = strdup( wbuf );
306 Check the address:port passed in and return true if it matches
307 one of the addresses we saw when we built the list. Right now
308 this isn't a speed intensive part of our processing, so we just
309 do a straight search through the list. We don't expect this to
310 ever be a higly driven functions so not bothering to optimise.
312 int is_this_myip( if_addrs_t* l, char* addr ) {
319 for( i = 0; i < l->naddrs; i++ ) {
320 if( strcmp( addr, l->addrs[i] ) == 0 ) {
329 Expects a buffer containing "sep" separated tokens, and a list of
330 IP addresses anchored by ip_list. Searches the tokens to see if
331 any are an ip address:port which is in the ip list. Returns true
332 (1) if a token is in the list, false otherwise.
334 static int has_myip( char const* buf, if_addrs_t* list, char sep, int max ) {
335 char* dbuf; // duplicated buf so we can trash
336 char** tokens; // pointer to tokens from the string
337 int ntokens; // number of tokens buf split into
339 int rc = 0; // return code
354 dbuf = strdup( buf ); // get a copy we can mess with
360 if( (tokens = (char **) malloc( sizeof( char * ) * max )) == NULL ) {
366 ntokens = uta_tokenise( dbuf, tokens, max, sep );
369 for( i = 0; ! rc && i < ntokens; i++ ) {
371 if( is_this_myip( list, tokens[i] ) ) {