Fix rmr_call() parameter checking bug 64/3264/3 3.7.3
authorE. Scott Daniels <daniels@research.att.com>
Tue, 14 Apr 2020 19:55:13 +0000 (15:55 -0400)
committerE. Scott Daniels <daniels@research.att.com>
Tue, 14 Apr 2020 20:17:56 +0000 (16:17 -0400)
When RMR was extended to add wormhole support for
a rmr_wh_call() function, the main call code was broken
into an inward facing funciton.  A parameter check which
applies only to the outward facing rmr_call() API function
was accidentally moved to the internal funciton.  This change
moves the check back into the rmr_call() funciton.

Issue-ID: RIC-333

Signed-off-by: E. Scott Daniels <daniels@research.att.com>
Change-Id: Iab0c8cc33e8a9970c53b9248021a1273559f82f8

12 files changed:
CHANGES_CORE.txt
CMakeLists.txt
src/rmr/si/src/rmr_si.c
src/rmr/si/src/sr_si_static.c
test/lg_buf_static_test.c
test/rmr_si_api_static_test.c
test/rmr_si_rcv_static_test.c [new file with mode: 0644]
test/rmr_si_rcv_test.c [new file with mode: 0644]
test/rmr_si_test.c
test/test_msg_support.c [new file with mode: 0644]
test/test_si95_em.c
test/test_support.c

index 3abf384..9500781 100644 (file)
@@ -5,6 +5,9 @@
 # API and build change  and fix summaries. Doc correctsions
 # and/or changes are not mentioned here; see the commit messages.
 
+2020 April 14; version 3.7.3
+       Fix bug in rmr_call() when using SI95  (RIC-333)
+
 2020 April 10; version 3.7.2
        Fix bug related to static route table only mode (RIC-331)
 
index 8fcc274..a08762a 100644 (file)
@@ -40,7 +40,7 @@ cmake_minimum_required( VERSION 3.5 )
 
 set( major_version "3" )               # should be automatically populated from git tag later, but until CI process sets a tag we use this
 set( minor_version "7" )
-set( patch_level "2" )
+set( patch_level "3" )
 
 set( install_root "${CMAKE_INSTALL_PREFIX}" )
 set( install_inc "include/rmr" )
index 7d7449f..4aefe4a 100644 (file)
@@ -370,7 +370,7 @@ extern rmr_mbuf_t* rmr_call( void* vctx, rmr_mbuf_t* msg ) {
                return msg;
        }
 
-       return rmr_mt_call( vctx, msg, 1, 1000 );               // use the reserved call-id of 1 and wait up to 1 sec
+    return mt_call( vctx, msg, 1, 1000, NULL );                // use the reserved call-id of 1 and wait up to 1 sec
 }
 
 /*
@@ -874,6 +874,7 @@ extern rmr_mbuf_t* rmr_mt_rcv( void* vctx, rmr_mbuf_t* mbuf, int max_wait ) {
                if( mbuf != NULL ) {
                        mbuf->flags |= MFL_ADDSRC;               // turn on so if user app tries to send this buffer we reset src
                }
+
                return mbuf;
        }
 
@@ -974,12 +975,6 @@ static rmr_mbuf_t* mt_call( void* vctx, rmr_mbuf_t* mbuf, int call_id, int max_w
                return mbuf;
        }
 
-       if( call_id > MAX_CALL_ID || call_id < 2 ) {                                    // 0 and 1 are reserved; user app cannot supply them
-               mbuf->state = RMR_ERR_BADARG;
-               mbuf->tp_state = errno;
-               return mbuf;
-       }
-
        ombuf = mbuf;                                                                                                   // save to return timeout status with
 
        chute = &ctx->chutes[call_id];
@@ -1081,6 +1076,14 @@ static rmr_mbuf_t* mt_call( void* vctx, rmr_mbuf_t* mbuf, int call_id, int max_w
        This is now just an outward facing wrapper so we can support wormhole calls.
 */
 extern rmr_mbuf_t* rmr_mt_call( void* vctx, rmr_mbuf_t* mbuf, int call_id, int max_wait ) {
+
+       // must vet call_id here, all others vetted by workhorse mt_call() function
+       if( call_id > MAX_CALL_ID || call_id < 2 ) {            // 0 and 1 are reserved; user app cannot supply them
+               mbuf->state = RMR_ERR_BADARG;
+               mbuf->tp_state = EINVAL;
+               return mbuf;
+       }
+
        return mt_call( vctx, mbuf, call_id, max_wait, NULL );
 }
 
index dac0cb5..798fe26 100644 (file)
@@ -789,6 +789,7 @@ static  rmr_mbuf_t* mtosend_msg( void* vctx, rmr_mbuf_t* msg, int max_to ) {
                                } else {
                                        ok_sends++;
                                        msg = clone_m;                                                                          // clone will be the next to send
+                                       msg->state = RMR_OK;
                                }
                        } else {
                                msg = send_msg( ctx, msg, nn_sock, max_to );                    // send the last, and allocate a new buffer; drops the clone if it was
index a74e080..35c3be8 100644 (file)
@@ -59,7 +59,7 @@ static int rmr_lgbuf_test( ) {
        snprintf( msg->payload, msg->len, "Rambling Wreck from Georgia Tech!\n\n" );
        msg = rmr_send_msg( rmc, msg );
        if( msg && msg->state != RMR_OK ) {
-               printf( stderr, "[ERR] lg buf test: send failed? %d\n", msg->state );
+               fprintf( stderr, "<FAIL> lg buf test: send failed? %d\n", msg->state );
        }
        rmr_free_msg( msg );
 
index e50a987..528e9cc 100644 (file)
                                         rmr_mtosend_msg
                                         rmr_free_msg
 
+                               Not all message/call functions can be tested here because of the
+                               callback nature of SI.  There is a specific rcv test static module
+                               for those tests.
+
        Author:         E. Scott Daniels
        Date:           5 April 2019
 */
 #include "rmr.h"
 #include "rmr_agnostic.h"
 
-/*
-       Send a 'burst' of messages to drive some send retry failures to increase RMr coverage
-       by handling the retry caee.
-*/
-static void send_n_msgs( void* ctx, int n ) {
-       rmr_mbuf_t*     msg;                    // message buffers
-       int i;
-
-       msg = rmr_alloc_msg( ctx,  1024 );
-       if( ! msg ) {
-               return;
-       }
-
-       for( i = 0; i < n; i++ ) {
-               //fprintf( stderr, "mass send\n" );
-               msg->len = 100;
-               msg->mtype = 1;
-               msg->state = 999;
-               errno = 999;
-               msg = rmr_send_msg( ctx, msg );
-       }
-}
-
-/*
-       Refresh or allocate a message with some default values
-*/
-static rmr_mbuf_t* fresh_msg( void* ctx, rmr_mbuf_t* msg ) {
-       if( ! msg )  {
-               msg = rmr_alloc_msg( ctx, 2048 );
-       }
-
-       msg->mtype = 0;
-       msg->sub_id = -1;
-       msg->state = 0;
-       msg->len = 100;
-
-       return msg;
-}
-
 static int rmr_api_test( ) {
        int             errors = 0;
        void*   rmc;                            // route manager context
@@ -265,109 +230,6 @@ static int rmr_api_test( ) {
        mt_disc_cb( rmc, 0 );                   // disconnect callback for coverage
        mt_disc_cb( rmc, 100 );                 // with a fd that doesn't exist
 
-return errors;
-
-       msg2 = rmr_rcv_msg( NULL, NULL );
-       errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg "  );
-
-       msg2 = rmr_rcv_msg( rmc, NULL );
-       errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg "  );
-       if( msg2 ) {
-               if( msg2->state != RMR_ERR_EMPTY ) {
-                       errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state (not empty) "  );
-               }
-       }
-
-
-       msg = rmr_rcv_msg( rmc, msg );
-       if( msg ) {
-               errors += fail_not_equal( msg->state, RMR_OK, "rmr_rcv_msg did not return an ok state "  );
-               errors += fail_not_equal( msg->len, 220, "rmr_rcv_msg returned message with invalid len "  );
-       } else {
-               errors += fail_if_nil( msg, "rmr_rcv_msg returned a nil pointer "  );
-       }
-
-       rmr_rts_msg( NULL, NULL );                      // drive for coverage
-       rmr_rts_msg( rmc, NULL );
-       errors += fail_if( errno == 0, "rmr_rts_msg did not set errno when given a nil message "  );
-
-       msg->state = 0;
-       msg = rmr_rts_msg( NULL, msg );                 // should set state in msg
-       if( msg ) {
-               errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context "  );
-       } else {
-               errors += fail_if_nil( msg,  "rmr_rts_msg returned a nil msg when given a good one" );
-       }
-
-
-       msg = rmr_rts_msg( rmc, msg );                  // return the buffer to the sender
-       errors += fail_if_nil( msg, "rmr_rts_msg did not return a message pointer "  );
-       errors += fail_not_equal( msg->state, 0, "rts_msg did not return a good state (a) when expected" );
-       errors += fail_not_equal( errno, 0, "rmr_rts_msg did not reset errno (a) expected (b)"  );
-
-       msg->state = 0;
-       msg = rmr_call( NULL, msg );
-       errors += fail_if( msg->state == 0, "rmr_call did not set message state when given message with nil context "  );
-
-       snprintf( msg->xaction, 17, "%015d", 16 );              // dummy transaction id (emulation generates, this should arrive after a few calls to recv)
-       msg->mtype = 0;
-       msg->sub_id = -1;
-       em_set_rcvcount( 0 );                                                   // reset message counter
-       em_set_rcvdelay( 1 );                                                   // force slow msg rate during mt testing
-       msg = rmr_call( rmc, msg );                                             // dummy nng/nano function will sequentually add xactions and should match or '16'
-       errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to succeed "  );
-       if( msg ) {
-               errors += fail_not_equal( msg->state, RMR_OK, "rmr_call did not properly set state on successful return "  );
-               errors += fail_not_equal( errno, 0, "rmr_call did not properly set errno (a) on successful return "  );
-       }
-
-       snprintf( wbuf, 17, "%015d", 14 );                              // while waiting, the queued messages should have #14, so issue a few receives looking for it
-       for( i = 0; i < 16; i++ ) {                                             // it should be in the first 15
-               msg = rmr_rcv_msg( rmc, msg );
-               if( msg ) {
-                       if( strcmp( wbuf, msg->xaction ) == 0 ) {               // found the queued message
-                               break;
-                       }
-                       fprintf( stderr, "<INFO> msg: %s\n", msg->xaction );
-               } else {
-                       errors += fail_if_nil( msg, "receive returnd nil msg while looking for queued message "  );
-               }
-       }
-
-       errors += fail_if( i >= 16, "did not find expected message on queue "  );
-
-       if( ! msg ) {
-               msg = rmr_alloc_msg( rmc, 2048 );                               // something buggered above; get a new one
-       }
-       msg->mtype = 0;
-       msg->sub_id = -1;
-       msg = rmr_call( rmc, msg );                                                     // make a call that we never expect a response on (nil pointer back)
-       errors += fail_not_nil( msg, "rmr_call returned a nil message on call expected not to receive a response "  );
-       errors += fail_if( errno == 0, "rmr_call did not set errno on failure "  );
-
-       rmr_free_msg( NULL );                   // drive for coverage; nothing to check
-       rmr_free_msg( msg2 );
-
-
-       msg2 = rmr_torcv_msg( NULL, NULL, 10 );
-       errors += fail_not_nil( msg2, "rmr_torcv_msg returned a pointer when given nil information "  );
-       msg2 = rmr_torcv_msg( rmc, NULL, 10 );
-       errors += fail_if_nil( msg2, "rmr_torcv_msg did not return a message pointer when given a nil old msg "  );
-
-       // ---  test timeout receive; our dummy epoll function will return 1 ready on first call and 0 ready (timeout emulation) on second
-       //              however we must drain the swamp (queue) first, so run until we get a timeout error, or 20 and report error if we get to 20.
-       msg = NULL;
-       for( i = 0; i < 40; i++ ) {
-               msg = rmr_torcv_msg( rmc, msg, 10 );
-               errors += fail_if_nil( msg, "torcv_msg returned nil msg when message expected "  );
-               if( msg ) {
-                       if( msg->state == RMR_ERR_TIMEOUT || msg->state == RMR_ERR_EMPTY ) {            // queue drained and we've seen both states from poll if we get a timeout
-                               break;
-                       }
-               }
-       }
-       errors += fail_if( i >= 40, "torcv_msg never returned a timeout "  );
-
 
        // ---- trace things that are not a part of the mbuf_api functions and thus must be tested here -------
        state = rmr_init_trace( NULL, 37 );                                             // coverage test nil context
diff --git a/test/rmr_si_rcv_static_test.c b/test/rmr_si_rcv_static_test.c
new file mode 100644 (file)
index 0000000..ad543a0
--- /dev/null
@@ -0,0 +1,237 @@
+// : vi ts=4 sw=4 noet :
+/*
+==================================================================================
+           Copyright (c) 2019-2020 Nokia
+           Copyright (c) 2018-2020 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.
+==================================================================================
+*/
+
+/*
+       Mmemonic:       rmr_si_api_static_test.c
+       Abstract:       Specific tests related to the API functions in rmr_si.c.
+                               This should be included by a driver which invokes the 'main'
+                               test function here: rmr_api_test.
+
+                               This test set applies only to the outward facting API functions
+                               in the rmr_si.c module (mostly because the context for SI is
+                               different).
+
+                               The message buffer specific API tests are in a different static
+                               module.  API functions tested here are:
+                                        rmr_close
+                                        rmr_get_rcvfd
+                                        rmr_ready
+                                        rmr_init
+                                        rmr_set_rtimeout
+                                        rmr_set_stimeout
+                                        rmr_rcv_specific
+                                        rmr_torcv_msg
+                                        rmr_rcv_msg
+                                        rmr_call
+                                        rmr_rts_msg
+                                        rmr_send_msg
+                                        rmr_mtosend_msg
+                                        rmr_free_msg
+
+       Author:         E. Scott Daniels
+       Date:           14 April 2020   (AKD)
+*/
+
+#define DEBUG 2
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include "rmr.h"
+#include "rmr_agnostic.h"
+
+static int rmr_rcv_test( ) {
+       int             errors = 0;
+       void*   rmc;                            // route manager context
+       void*   rmc2;                           // second context for non-listener init
+       rmr_mbuf_t*     msg;                    // message buffers
+       rmr_mbuf_t*     msg2;
+       int             v = 0;                                  // some value
+       char    wbuf[128];
+       int             i;
+       int             state;
+       int             max_tries;                      // prevent a sticking in any loop
+
+       v = rmr_ready( NULL );
+       errors += fail_if( v != 0, "rmr_ready returned true before initialisation "  );
+
+       em_set_long_hostname( 1 );
+       if( (rmc = rmr_init( "4560", 1024, FL_NOTHREAD )) == NULL ) {
+               fail_if_nil( rmc, "rmr_init returned a nil pointer "  );
+               return 1;
+       }
+
+       msg = rmr_alloc_msg( NULL,  1024 );                                                                     // should return nil pointer
+       errors += fail_not_nil( msg, "rmr_alloc_msg didn't return nil when given nil context "  );
+       gen_rt( rmc );                          // gen dummy route table
+
+       if( ! rmr_ready( rmc ) ) {
+               fprintf( stderr, "\nPANIC!  rmr isn't showing ready after loading a rt table\n\n" );
+               return errors+1;
+       }
+
+       msg = rmr_alloc_msg( rmc, 2048 );                               // get a buffer with a transport header
+       msg->len = 500;
+       msg->mtype = 1;
+       msg->state = 999;
+       msg->tp_state = 999;
+       errno = 999;
+       snprintf( msg->payload, 500, "Stand up and cheer from OU to Oh yea! (5)" );
+
+       msg = rmr_send_msg( rmc, msg );
+       errors += fail_if_nil( msg, "send_msg_ did not return a message on send "  );
+       if( msg ) {
+               errors += fail_not_equal( msg->state, RMR_OK, "send_msg returned bad status for send that should work "  );
+               errors += fail_if( errno != 0, "send_msg set errno for send that should work "  );
+               v = rmr_payload_size( msg );
+               errors += fail_if( v != 2048, "send_msg did not allocate new buffer with correct size "  );
+               errors += fail_if( msg->tp_state == 999, "send_msg did not set tp_state (2)" );
+       }
+
+       rmr_set_stimeout( NULL, 0 );            // not supported, but funciton exists, so drive away
+       rmr_set_stimeout( rmc, 20 );
+       rmr_set_stimeout( rmc, -1 );
+       rmr_set_rtimeout( NULL, 0 );
+       rmr_set_rtimeout( rmc, 20 );
+       rmr_set_rtimeout( rmc, -1 );
+
+       max_tries = 10;                                         // there shouldn't be more than 10 queued at this point
+       while( (msg2 = rmr_torcv_msg( rmc, msg2, 200 )) != NULL ) {
+               if( msg2->state != RMR_OK || max_tries <= 0 ) {
+                       break;
+               }
+
+               max_tries--;
+       }
+
+       msg2 = rmr_rcv_msg( NULL, NULL );
+       errors += fail_if( msg2 != NULL, "rmr_rcv_msg returned msg when given nil context and msg "  );
+
+       send_n_msgs( rmc, 1 );                  // ensure there is a message to read
+       msg2 = rmr_rcv_msg( rmc, NULL );
+       errors += fail_if( msg2 == NULL, "rmr_rcv_msg returned nil msg when given nil msg "  );
+       if( msg2 ) {
+               if( msg2->state != RMR_ERR_EMPTY ) {
+                       errors += fail_not_equal( msg2->state, RMR_OK, "receive given nil message did not return msg with good state (not empty) "  );
+               }
+       }
+
+       send_n_msgs( rmc, 1 );                  // ensure there is a message to read (len is set to 100)
+       msg = rmr_rcv_msg( rmc, msg );
+       if( msg ) {
+               errors += fail_not_equal( msg->state, RMR_OK, "rmr_rcv_msg did not return an ok state "  );
+               errors += fail_not_equal( msg->len, 100, "rmr_rcv_msg returned message with invalid len "  );
+       } else {
+               errors += fail_if_nil( msg, "rmr_rcv_msg returned a nil pointer "  );
+       }
+
+       rmr_rts_msg( NULL, NULL );                      // drive for coverage
+       rmr_rts_msg( rmc, NULL );
+       errors += fail_if( errno == 0, "rmr_rts_msg did not set errno when given a nil message "  );
+
+       msg->state = 0;
+       msg = rmr_rts_msg( NULL, msg );                 // should set state in msg
+       if( msg ) {
+               errors += fail_if_equal( msg->state, 0, "rmr_rts_msg did not set state when given valid message but no context "  );
+       } else {
+               errors += fail_if_nil( msg,  "rmr_rts_msg returned a nil msg when given a good one" );
+       }
+
+       msg = rmr_rts_msg( rmc, msg );                  // return the buffer to the sender
+       errors += fail_if_nil( msg, "rmr_rts_msg did not return a message pointer "  );
+       errors += fail_not_equal( msg->state, 0, "rts_msg did not return a good state (a) when expected" );
+       errors += fail_not_equal( errno, 0, "rmr_rts_msg did not reset errno (a) expected (b)"  );
+
+       msg->state = 0;
+       msg = rmr_call( NULL, msg );
+       errors += fail_if( msg->state == 0, "rmr_call did not set message state when given message with nil context "  );
+
+       em_set_rcvcount( 0 );                                                   // reset message counter
+       em_set_rcvdelay( 1 );                                                   // force slow msg rate during mt testing
+       em_disable_call_flg();                                                  // cause reflected message to appear to be a response
+
+       snprintf( msg->xaction, 17, "%015d", 16 );
+       msg->mtype = 0;
+       msg->sub_id = -1;
+       msg->len = 234;
+       msg = rmr_call( rmc, msg );
+       errors += fail_if_nil( msg, "rmr_call returned a nil message on call expected to succeed "  );
+       if( msg ) {
+               errors += fail_not_equal( msg->state, RMR_OK, "rmr_call did not properly set state on successful return "  );
+               errors += fail_not_equal( errno, 0, "rmr_call did not properly set errno (a) on successful return "  );
+       }
+
+       if( ! msg ) {
+               msg = rmr_alloc_msg( rmc, 2048 );                               // something buggered above; get a new one
+       }
+
+       em_allow_call_flg();                                                            // cause reflected message to appear to be a call
+       snprintf( msg->xaction, 17, "%015d", 16 );                      // ensure there is an xaction id
+       msg->mtype = 0;
+       msg->sub_id = -1;
+       msg->len = 345;
+       msg = rmr_call( rmc, msg );                                                     // make a call that we never expect a response on (nil pointer back)
+       errors += fail_not_nil( msg, "rmr_call returned message on call expected not to receive a response "  );
+       errors += fail_if( errno == 0, "rmr_call did not set errno on failure "  );
+
+       rmr_free_msg( NULL );                   // drive for coverage; nothing to check
+       rmr_free_msg( msg2 );
+
+       msg2 = rmr_torcv_msg( NULL, NULL, 10 );
+       errors += fail_not_nil( msg2, "rmr_torcv_msg returned a pointer when given nil information "  );
+       msg2 = rmr_torcv_msg( rmc, NULL, 10 );
+       errors += fail_if_nil( msg2, "rmr_torcv_msg did not return a message pointer when given a nil old msg "  );
+
+       // ---  test timeout receive; our dummy epoll function will return 1 ready on first call and 0 ready (timeout emulation) on second
+       //              however we must drain the swamp (queue) first, so run until we get a timeout error, or 20 and report error if we get to 20.
+       msg = NULL;
+       for( i = 0; i < 40; i++ ) {
+               msg = rmr_torcv_msg( rmc, msg, 10 );
+               errors += fail_if_nil( msg, "torcv_msg returned nil msg when message expected "  );
+               if( msg ) {
+                       if( msg->state == RMR_ERR_TIMEOUT || msg->state == RMR_ERR_EMPTY ) {            // queue drained and we've seen both states from poll if we get a timeout
+                               break;
+                       }
+               }
+       }
+       errors += fail_if( i >= 40, "torcv_msg never returned a timeout "  );
+
+       ((uta_ctx_t *)rmc)->shutdown = 1;
+       rmr_close( NULL );                      // drive for coverage
+       rmr_close( rmc );                       // no return to check; drive for coverage
+
+
+       // --------------- phew, done ------------------------------------------------------------------------------
+
+       if( ! errors ) {
+               fprintf( stderr, "<INFO> all RMR receive tests pass\n" );
+       } else {
+               fprintf( stderr, "<INFO> receive tests failures noticed \n" );
+       }
+
+       return !!errors;
+}
diff --git a/test/rmr_si_rcv_test.c b/test/rmr_si_rcv_test.c
new file mode 100644 (file)
index 0000000..fdd1f33
--- /dev/null
@@ -0,0 +1,101 @@
+// :vi sw=4 ts=4 noet:
+/*
+==================================================================================
+       Copyright (c) 2020 Nokia
+       Copyright (c) 2020 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.
+==================================================================================
+*/
+
+/*
+       Mmemonic:       rmr_si_rcv_test.c
+       Abstract:       This drives only the receive tests for the SI API. Because
+                               of the threaded nature of SI receives it is not possible to
+                               mix these tests with the other coverage tests which allocate
+                               various contexes.
+
+       Author:         E. Scott Daniels
+       Date:           14 April 2020           (AKD)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <errno.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <ctype.h>
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <sys/epoll.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#define DEBUG 1
+#define PARANOID_CHECKS        1                                       // must have parinoid testing on to not fail on nil pointer tests
+
+                                                                                       // specific test tools in this directory
+#undef NNG_UNDER_TEST 
+#include "test_support.c"                                      // things like fail_if()
+#include "test_ctx_support.c"                          // dummy context support
+#include "test_msg_support.c"
+#include "test_gen_rt.c"
+
+
+#include "rmr.h"                                       // things the users see
+#include "rmr_symtab.h"
+#include "rmr_logging.h"
+#include "rmr_agnostic.h"                      // transport agnostic header
+
+#include "symtab.c"
+#include "logging.c"
+#include "rmr_si.c"
+#include "mbuf_api.c"
+
+
+static void gen_rt( uta_ctx_t* ctx );          // defined in sr_si_static_test, but used by a few others (eliminate order requirement below)
+
+                                                                                       // and finally....
+#include "rmr_si_rcv_static_test.c"                    // the only test driver
+
+
+/*
+       Drive each of the separate tests and report.
+*/
+int main() {
+       int errors = 0;
+
+       rmr_set_vlevel( 5 );                    // enable all debugging
+
+       fprintf( stderr, "\n<INFO> starting receive tests (%d)\n", errors );
+       errors += rmr_rcv_test();
+       fprintf( stderr, "<INFO> error count: %d\n", errors );
+
+       if( errors == 0 ) {
+               fprintf( stderr, "<PASS> all tests were OK\n\n" );
+       } else {
+               fprintf( stderr, "<FAIL> %d modules reported errors\n\n", errors );
+       }
+
+       return !!errors;
+}
index aa1b6ab..c3eb09b 100644 (file)
@@ -61,6 +61,7 @@
 #undef NNG_UNDER_TEST 
 #include "test_support.c"                                      // things like fail_if()
 #include "test_ctx_support.c"                          // dummy context support
+#include "test_msg_support.c"
 #include "test_gen_rt.c"
 
 
@@ -86,6 +87,7 @@ static void gen_rt( uta_ctx_t* ctx );         // defined in sr_si_static_test, but used
 #include "mbuf_api_static_test.c"
 #include "sr_si_static_test.c"
 #include "lg_buf_static_test.c"
+// do NOT include the receive test static must be stand alone
 
 #include "rmr_si_api_static_test.c"
 
diff --git a/test/test_msg_support.c b/test/test_msg_support.c
new file mode 100644 (file)
index 0000000..1e52c83
--- /dev/null
@@ -0,0 +1,94 @@
+// vi: ts=4 sw=4 noet :
+/*
+==================================================================================
+           Copyright (c) 2019-2020 Nokia
+           Copyright (c) 2018-2020 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:       test_msg_support.c
+       Abstract:       Support for testing with messages; requires RMR defs, so not
+                               to be included for things like ring tests etc.
+       Author:         E. Scott Daniels
+       Date:           14 April 2020   (AKD)
+*/
+
+#ifndef _test_msg_support_c
+#define _test_msg_support_c
+
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int test_support_xact_count = 0;
+/*
+       Send a 'burst' of messages to drive some send retry failures to increase RMr coverage
+       by handling the retry caee.
+*/
+static void send_n_msgs( void* ctx, int n ) {
+       rmr_mbuf_t*     msg;                    // message buffers
+       int i;
+
+       msg = rmr_alloc_msg( ctx,  1024 );
+       if( ! msg ) {
+               fprintf( stderr, "<FAIL> mass send of %d messages couldn't allocate message!\n", n );
+               return;
+       }
+
+       fprintf( stderr, "<INFO> mass send of %d messages\n", n );
+       for( i = 0; i < n; i++ ) {
+               msg->len = 100;
+               msg->mtype = 1;
+               msg->state = 999;
+
+               snprintf( msg->xaction, 32, "%015d", test_support_xact_count++ );               // simple transaction id so we can test receive specific and ring stuff
+
+               errno = 999;
+               msg = rmr_send_msg( ctx, msg );
+               if( msg && msg->state != 0 ) {
+                       fprintf( stderr, "<WARN> mass send failed: state=%d type=%d\n", msg->state, msg->mtype );
+               }
+       }
+}
+
+
+/*
+       Allow test to reset the transaction id counter.
+*/
+static void reset_xact_count() {
+       test_support_xact_count = 0;
+}
+
+/*
+       Refresh or allocate a message with some default values
+*/
+static rmr_mbuf_t* fresh_msg( void* ctx, rmr_mbuf_t* msg ) {
+       if( ! msg )  {
+               msg = rmr_alloc_msg( ctx, 2048 );
+       }
+
+       msg->mtype = 0;
+       msg->sub_id = -1;
+       msg->state = 0;
+       msg->len = 100;
+
+       return msg;
+}
+
+#endif
index c2cf4cb..9eb7d94 100644 (file)
@@ -32,7 +32,7 @@
 #include "rmr.h"                               // we use some of rmr defs in building dummy messages, so we need these
 #include "rmr_agnostic.h"
 
-// ---------------------- emulated nng functions ---------------------------
+// ---------------------- emulated SI95 functions ---------------------------
 
 
 #ifndef _em_si         // this is the same define as the nng emulation code uses to give warning if both included
 
 #include "test_common_em.c"                    // common emulation needed for all (epoll, gethostname...)
 
+// --- some globals --------------------------------------------------------
+int em_reset_call_flag = 0;                    // allows a send to turn off the call flag (see em_disable_call_flg())
+
+// ------------- emulated message header -----------------------------------
+
+/*
+       This is a copy from agnostic.h. we need to reset flags in some situations
+       so we have to have this, under a different name to avoid disaster.
+*/
+typedef struct {
+    int32_t mtype;                      // message type  ("long" network integer)
+    int32_t plen;                       // payload length (sender data length in payload)
+    int32_t rmr_ver;                    // our internal message version number
+    unsigned char xid[RMR_MAX_XID];     // space for user transaction id or somesuch
+    unsigned char sid[RMR_MAX_SID];     // sender ID for return to sender needs
+    unsigned char src[RMR_MAX_SRC];     // name:port of the sender (source)
+    unsigned char meid[RMR_MAX_MEID];   // managed element id.
+    struct timespec ts;                 // timestamp ???
+
+                                        // V2 extension
+    int32_t flags;                      // HFL_* constants
+    int32_t len0;                       // length of the RMr header data
+    int32_t len1;                       // length of the tracing data
+    int32_t len2;                       // length of data 1 (d1)
+    int32_t len3;                       // length of data 2 (d2)
+    int32_t sub_id;                     // subscription id (-1 invalid)
+
+                                        // v3 extension
+    unsigned char srcip[RMR_MAX_SRC];   // ip address and port of the source
+} em_mhdr_t;
+
 //--------------------------------------------------------------------------
 /*
        These are the current references in the RMR code; all others are internal
@@ -123,8 +154,10 @@ static int em_siconnect( struct ginfo_blk *gptr, char *abuf ) {
                return -1;
        }
 
-       fprintf( stderr, "<SIEM> siem is emulating connect attempt return fd=%d\n", em_next_fd );
-       em_next_fd++;
+       fprintf( stderr, "<SIEM> siem is emulating connect to (%s) attempt return fd=%d\n", abuf, em_next_fd );
+       if( em_next_fd < 50 ) {
+               em_next_fd++;
+       }
        return em_next_fd-1;
 }
 
@@ -171,8 +204,28 @@ static void em_sisend( struct ginfo_blk *gptr, struct tp_blk *tpptr ) {
        return;
 }
 
+/*
+       Calling this function causes the send emulation to turn off the call
+       flag in the RMR header. Turning that flag off makes the arriving message
+       look as though it might be a response to a call rather than a call itself.
+       This is needed since we loop back messages.
+*/
+static void em_disable_call_flg() {
+       em_reset_call_flag = 1;
+       fprintf( stderr, "<SIEM> reset call flag setting is: %d\n", em_reset_call_flag );
+}
+
+/*
+       Opposite of disable_call_flg; the flag is not touched.
+*/
+static void em_allow_call_flg() {
+       em_reset_call_flag = 0;
+       fprintf( stderr, "<SIEM> reset call flag setting is: %d\n", em_reset_call_flag );
+}
+
 //  callback prototype to drive to simulate 'receive'
 static int mt_data_cb( void* datap, int fd, char* buf, int buflen );
+
 /*
        Emulate sending a message. If the global em_send_failures is set,
        then every so often we fail with an EAGAIN to drive that part
@@ -191,6 +244,13 @@ static int em_sisendt( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen ) {
                return SIEM_BLOCKED;
        }
 
+       if( em_reset_call_flag ) {              // for call testing we need to flip the flag off to see it "return"
+               em_mhdr_t*      hdr;
+
+               hdr = (em_mhdr_t *) (ubuf+50);          // past the transport header bytes
+               hdr->flags &= ~HFL_CALL_MSG;            // flip off the call flag
+       }
+
        uss++;
 
        if( em_cb_data != NULL ) {
index 8429e50..9f8f00f 100644 (file)
@@ -1,4 +1,4 @@
-// : vi ts=4 sw=4 noet :
+// vi: ts=4 sw=4 noet :
 /*
 ==================================================================================
            Copyright (c) 2019-2020 Nokia