fix(rtable): Prevent direct send hairpins
If the current node is listed as an endpoint for a message type
that this process would add to the route table a hair-pin loop
back to the node can happen. This isn't desireable and this
change will prevent the current node from being added as a
recipient endpoint to any route table entry.
Signed-off-by: E. Scott Daniels <daniels@research.att.com>
Change-Id: I5a1b2bdaad2eab499ae5a1c7430238c1da2f3256
Add latency call/receive test support
Signed-off-by: E. Scott Daniels <daniels@research.att.com>
Change-Id: I70be670d063adfdf6505431a4a2ce72e846df0a4
Actual mods to implement hairpin loop avodiance
Signed-off-by: E. Scott Daniels <daniels@research.att.com>
Change-Id: Ieead4fbf69ade58db1f37d1949cf0f03683c64de
Signed-off-by: E. Scott Daniels <daniels@research.att.com>
diff --git a/test/app_test/lreceiver.c b/test/app_test/lreceiver.c
new file mode 100644
index 0000000..161abc7
--- /dev/null
+++ b/test/app_test/lreceiver.c
@@ -0,0 +1,178 @@
+// :vim ts=4 sw=4 noet:
+/*
+==================================================================================
+ Copyright (c) 2019 Nokia
+ Copyright (c) 2018-2019 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.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+*/
+
+/*
+ Mnemonic: rmr_rcvr.c
+ Abstract: This is a very simple receiver that listens for messages and
+ returns each to the sender after adding a timestamp to the
+ payload. The payload is expected to be lc_msg_t (see lcaller.c)
+ and this will update the 'turn' timestamp on receipt.
+
+ Define these environment variables to have some control:
+ RMR_SEED_RT -- path to the static routing table
+ RMR_RTG_SVC -- port to listen for RTG connections
+
+ Date: 18 April 2019
+ Author: E. Scott Daniels
+*/
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+
+#include <rmr/rmr.h>
+
+/*
+ The message type placed into the payload.
+*/
+typedef struct lc_msg {
+ struct timespec out_ts; // time just before call executed
+ struct timespec turn_ts; // time at the receiver, on receipt
+ struct timespec in_ts; // time received back by the caller
+ int out_retries; // number of retries required to send
+ int turn_retries; // number of retries required to send
+} lc_msg_t;
+
+// ----------------------------------------------------------------------------------
+
+static int sum( char* str ) {
+ int sum = 0;
+ int i = 0;
+
+ while( *str ) {
+ sum += *(str++) + i++;
+ }
+
+ return sum % 255;
+}
+
+/*
+ Split the message at the first sep and return a pointer to the first
+ character after.
+*/
+static char* split( char* str, char sep ) {
+ char* s;
+
+ s = strchr( str, sep );
+
+ if( s ) {
+ return s+1;
+ }
+
+ fprintf( stderr, "<RCVR> no pipe in message: (%s)\n", str );
+ return NULL;
+}
+
+int main( int argc, char** argv ) {
+ void* mrc; // msg router context
+ lc_msg_t* lmc; // latency message type from caller
+ rmr_mbuf_t* msg = NULL; // message received
+ int i;
+ int errors = 0;
+ char* listen_port = "4560";
+ long count = 0; // total received
+ long timeout = 0;
+ char* data;
+ int nmsgs = 10; // number of messages to stop after (argv[1] overrides)
+ int rt_count = 0; // retry count
+ time_t now;
+ int active;
+
+ data = getenv( "RMR_RTG_SVC" );
+ if( data == NULL ) {
+ setenv( "RMR_RTG_SVC", "19289", 1 ); // set one that won't collide with the sender if on same host
+ }
+
+ if( argc > 1 ) {
+ nmsgs = atoi( argv[1] );
+ }
+ if( argc > 2 ) {
+ listen_port = argv[2];
+ }
+
+
+ fprintf( stderr, "<RCVR> listening on port: %s for a max of %d messages\n", listen_port, nmsgs );
+
+ mrc = rmr_init( listen_port, RMR_MAX_RCV_BYTES, RMRFL_MTCALL ); // start your engines!
+ //mrc = rmr_init( listen_port, RMR_MAX_RCV_BYTES, 0 ); // start your engines!
+ if( mrc == NULL ) {
+ fprintf( stderr, "<RCVR> ABORT: unable to initialise RMr\n" );
+ exit( 1 );
+ }
+
+ timeout = time( NULL ) + 20;
+ while( ! rmr_ready( mrc ) ) { // wait for RMr to load a route table
+ fprintf( stderr, "<RCVR> waiting for RMr to show ready\n" );
+ sleep( 1 );
+
+ if( time( NULL ) > timeout ) {
+ fprintf( stderr, "<RCVR> giving up\n" );
+ exit( 1 );
+ }
+ }
+ fprintf( stderr, "<RCVR> rmr now shows ready, listening begins\n" );
+
+ timeout = time( NULL ) + 2; // once we start, we assume if we go 2s w/o a message that we're done
+ //while( count < nmsgs ) {
+ while( 1 ) {
+ active = 0;
+ msg = rmr_torcv_msg( mrc, msg, 1000 ); // pop every second or so to timeout if needed
+
+ if( msg ) {
+ active = 1;
+ if( msg->state == RMR_OK ) {
+ lmc = (lc_msg_t *) msg->payload;
+ clock_gettime( CLOCK_REALTIME, &lmc->turn_ts ); // mark time that we received it.
+ count++;
+
+ msg = rmr_rts_msg( mrc, msg );
+ rt_count = 1000;
+ while( rt_count > 0 && msg != NULL && msg->state == RMR_ERR_RETRY ) { // to work right in nano we need this :(
+ lmc->turn_retries++;
+ if( count < 1 ) { // 1st msg, so we need to connect, and we'll wait for that
+ sleep( 1 );
+ }
+ rt_count--;
+ msg = rmr_rts_msg( mrc, msg ); // we don't try to resend if this returns retry
+ }
+ }
+ }
+
+ now = time( NULL );
+ if( now > timeout ) {
+ break;
+ }
+
+ if( active ) {
+ timeout = now + 2;
+ }
+ }
+
+ fprintf( stderr, "<RCVR> %ld is finished got %ld messages\n", (long) getpid(), count );
+
+
+ sleep( 3 );
+ rmr_close( mrc );
+ return 0;
+}
+