Add lsender test programme
[ric-plt/lib/rmr.git] / test / test_nng_em.c
index 76fe72b..88f5966 100644 (file)
@@ -1,13 +1,13 @@
 /*
 ==================================================================================
-       Copyright (c) 2019 Nokia 
+       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
+          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,
@@ -19,7 +19,7 @@
 
 /*
        Mnemonic:       test_nng_em.c
-       Abstract:       A nano/NNG message emulator for testing without needing to 
+       Abstract:       A nano/NNG message emulator for testing without needing to
                                actually have nanomsg, nng, or external processes.
                                We also emulate the epoll_wait() function for controlled
                                poll related testing.
        Author:         E. Scott Daniels
 */
 
+
+#include "rmr.h"                               // we use some of rmr defs in building dummy messages, so we need these
+#include "rmr_agnostic.h"
+
 // ---------------------- emulated nng functions ---------------------------
 
 
 #ifndef _em_nn
 #define _em_nn
 
+#include <pthread.h>
+
 static int em_send_failures = 0;       // test programme can set this to emulate eagain send failures
+static int em_timeout = -1;                    // set by set socket option
+static int em_mtc_msgs = 0;                    // set to generate 'received' messages with mt-call header data
+static int return_value = 0;           // functions should return this value
+static int rcv_count = 0;                      // receive counter for transaction id to allow test to rest
+static int rcv_delay = 0;                      // forced delay before call to rcvmsg starts to work
+
+static int gates_ok = 0;
+static pthread_mutex_t rcv_gate;
+static int em_gen_long_hostname = 0;           // if set the emulated hostname generates a longer name (>40 char)
+
+
+// ----------- gethostname emulation ---------------------------------------
+#define gethostname  em_gethostname
+static int em_gethostname( char* buf, size_t len ) {
+       if( len < 1 ) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       if( em_gen_long_hostname ) {
+               snprintf( buf, len, "hostname-which-is-long-a860430b890219-dfw82" );
+       } else {
+               snprintf( buf, len, "em-hostname" );
+       }
+
+       return 0;
+}
+
+static int em_set_long_hostname( int v ) {
+       em_gen_long_hostname = !!v;
+}
 
 // ----------- epoll emulation ---------------------------------------------
 
-// CAUTION: sys/epoll.h must be included before this define and function will properly compile. 
+// CAUTION: sys/epoll.h must be included before these define and function will properly compile.
 #define epoll_wait em_wait
+#define epoll_ctl  em_ep_ctl
+#define epoll_create  em_ep_create
+
 /*
-       Every other call returns 1 ready; alternate calls return 0 ready. 
-       Mostly for testing the timeout receive call. First call should return 
+       Every other call returns 1 ready; alternate calls return 0 ready.
+       Mostly for testing the timeout receive call. First call should return
        something ready and the second should return nothing ready so we can
-       drive both cases. 
+       drive both cases.
 */
 static int em_wait( int fd, void* events, int n, int to ) {
        static int ready = 0;
@@ -54,30 +94,15 @@ static int em_wait( int fd, void* events, int n, int to ) {
        return ready;
 }
 
-
-
-//--------------------------------------------------------------------------
-#ifdef EMULATE_NNG
-struct nn_msghdr {
-       int boo;
-};
-
-static int return_value = 0;
-
-/*
-       Test app can call this to have all emulated functions return failure instead
-       of success.
-*/
-static void en_set_retur( int rv ) {
-       return_value = rv;
+int em_ep_ctl( int epfd, int op, int fd, struct epoll_event *event ) {
+       return 0;
 }
 
+int em_ep_create( int size ) {
+       return 0;
+}
 
 
-static int em_nng_foo() {
-       fprintf( stderr, "emulated functions in play" );
-}                              
-
 
 /*
        Simulated v1 message for receive to return. This needs to match the RMr header
@@ -96,11 +121,11 @@ struct em_msg {
 */
 
 /*
-       v2 message; should be able to use it for everything that is set up here as 
+       v2 message; should be able to use it for everything that is set up here as
        we don't add a payload even if setting a v1 type.
 */
 #define ALT_MSG_VER 1  // alternate every so often
-#define MSG_VER 2              // default version to insert
+#define MSG_VER 3              // default version to insert
 struct em_msg {
        int32_t mtype;                                          // message type  ("long" network integer)
        int32_t plen;                                           // payload length
@@ -111,47 +136,145 @@ struct em_msg {
        unsigned char meid[32];                         // 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)
+                                           // 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 stuff
+       unsigned char srcip[64];                                // sender ID for return to sender needs
+};
+
+
+
+// --  emulation control functions ------------------------------------------------------
+
+/*
+       Test app can call this to have all emulated functions return failure instead
+       of success.
+*/
+static void en_set_return( int rv ) {
+       return_value = rv;
+}
+
+
+
+static int em_nng_foo() {
+       fprintf( stderr, "emulated functions in play" );
+}
+
+
+/*
+       Turns on/off the generation of multi-threaded call messages
+*/
+static int em_set_mtc_msgs( int state ) {
+       em_mtc_msgs = state;
+}
+
+/*
+       Returns the size of the header we inserted
+*/
+static int em_hdr_size() {
+       if( em_mtc_msgs ) {
+               return (int) sizeof( struct em_msg ) + 4;
+       }
+
+       return (int) sizeof( struct em_msg );
+}
+
+static void em_set_rcvcount( int v ) {
+       rcv_count = v;
+}
+
+static void em_set_rcvdelay( int v ) {
+       rcv_delay = v;
+}
+
+static void em_start() {
+       if( ! gates_ok ) {
+               pthread_mutex_init( &rcv_gate, NULL );
+               gates_ok = 1;
+       }
+}
 
+//--------------------------------------------------------------------------
+#ifdef EMULATE_NNG
+struct nn_msghdr {
+       int boo;
 };
 
+
 /*
        Receive message must allocate a new buffer and return the pointer into *m.
        Every 9 messages or so we'll simulate an old version message
+
+       If em_mtc_msgs is set, then we add a non-zero d1 field with
+       the call-id set to 2, and alternate the call flag
 */
 static int em_nng_recvmsg( nng_socket s, nng_msg ** m, int i ) {
+       static int call_flag = 0;
+
        void* b;
        struct em_msg* msg;
-       static int count = 0;                   // we'll simulate a message going in by dropping an rmr-ish msg with transaction id only
        int trace_size = 0;
+       int d1_size = 0;
+       unsigned char* d1;
 
-       //sleep( 1 );
+       if( rcv_delay > 0 ) {
+               sleep( rcv_delay );
+       }
+
+       if( em_mtc_msgs ) {
+               d1_size = 4;
+       }
 
-       b = (void *) malloc( 2048 );
        if( m != NULL ) {
+               b = (void *) malloc( 2048 );
                memset( b, 0, 2048 );
+
                *m = (nng_msg *) b;
                msg = (struct em_msg *) b;
-               if( count % 10  == 9 ) {
-                       //msg->rmr_ver = htonl( MSG_VER );
-                       msg->rmr_ver = ALT_MSG_VER;             // emulate the bug in RMr v1
+               if( ! em_mtc_msgs  &&  (rcv_count % 10) == 9 ) {
+                       msg->rmr_ver = ALT_MSG_VER;                                                     // allow emulation the bug in RMr v1
                } else {
                        msg->rmr_ver = htonl( MSG_VER );
                }
+
                msg->mtype = htonl( 1 );
-               msg->plen = htonl( 129 );
+               msg->plen = htonl( 220 );
                msg->len0 = htonl( sizeof( struct em_msg ) );
                msg->len1 = htonl( trace_size );
-               snprintf( msg->xid, 32, "%015d", count++ );             // simple transaction id so we can test receive specific and ring stuff
-               snprintf( msg->src, 16, "localhost:4562" );             // set src id (unrealistic) so that rts() can be tested
+               msg->len2 = htonl( d1_size );
+               msg->len3 = htonl( 0 );
+
+               pthread_mutex_lock( &rcv_gate );        // hold lock to update counter/flag
+               if( em_mtc_msgs ) {
+                       d1 = DATA1_ADDR( msg );
+                       d1[0] = 2;                                                                      // simulated msgs always on chute 2
+                       if( call_flag ) {
+                               rcv_count++;
+                               msg->flags |= HFL_CALL_MSG;
+                       }
+                       if( rcv_delay > 0 ) {
+                               fprintf( stderr, "<EM>    count=%d flag=%d %02x \n", rcv_count, call_flag, msg->flags );
+                       }
+                       call_flag = !call_flag;
+               } else {
+                       rcv_count++;
+               }
+               pthread_mutex_unlock( &rcv_gate );
+               snprintf( msg->xid, 32, "%015d", rcv_count );           // simple transaction id so we can test receive specific and ring stuff
+               snprintf( msg->src, 64, "localhost:4562" );             // set src id (unrealistic) so that rts() can be tested
+               snprintf( msg->srcip, 64, "89.2.19.19:4562" );          // set src ip for rts testing
+
+               //fprintf( stderr, ">>> simulated received message: %s %s p=%p len0=%d\n", msg->src, msg->srcip, msg, (int) ntohl( msg->len0 ) );
+       } else {
+               fprintf( stderr, "<WARN> em: simulated receive no msg pointer provided\n" );
        }
 
-       //fprintf( stderr, ">>> simulated received message: %s\n", msg->xid );
        return return_value;
 }
 
@@ -197,6 +320,7 @@ static int em_nng_sub0_open(nng_socket * s ) {
        return return_value;
 }
 static int em_nng_recv(nng_socket s, void * v, size_t * t, int i ) {
+
        return return_value;
 }
 static int em_nng_send( nng_socket s, void* m, int l, int f ) {
@@ -205,7 +329,7 @@ static int em_nng_send( nng_socket s, void* m, int l, int f ) {
 
 /*
        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 
+       then every so often we fail with an EAGAIN to drive that part
        of the code in RMr.
 */
 static int em_sendmsg( nng_socket s, nng_msg* m, int i ) {
@@ -277,20 +401,20 @@ static int em_nng_getopt_int( nng_socket s, void* con, int* target ) {
 
 
 // nng redefines some of these to point directly to various 'versions' of the function (ugg, function versions, really?)
-#undef nng_recvmsg 
-#undef nng_free 
-#undef nng_pull_open 
-#undef nng_pull0_open 
-#undef nng_listen 
-#undef nng_close 
-#undef nng_getopt_int 
-#undef nng_push0_open 
-#undef nng_dial 
-#undef nng_setopt 
-#undef nng_sub_open 
-#undef nng_sub0_open 
-#undef nng_recv 
-#undef nng_alloc 
+#undef nng_recvmsg
+#undef nng_free
+#undef nng_pull_open
+#undef nng_pull0_open
+#undef nng_listen
+#undef nng_close
+#undef nng_getopt_int
+#undef nng_push0_open
+#undef nng_dial
+#undef nng_setopt
+#undef nng_sub_open
+#undef nng_sub0_open
+#undef nng_recv
+#undef nng_alloc
 
 #define nng_msg_alloc em_nng_msg_alloc
 #define nng_recvmsg em_nng_recvmsg
@@ -337,16 +461,16 @@ static int em_nn_close (int s ) {
        return 1;
 }
 
-static int em_nn_setsockopt (int s, int level, int option, const void *optval, size_t optvallen ) {
-       return 1;
-}
+//static int em_nn_setsockopt (int s, int level, int option, const void *optval, size_t optvallen ) {
+       //return 1;
+//}
 
 static int em_nn_getsockopt (int s, int level, int option, void *optval, size_t *optvallen ) {
        return 1;
 }
 
 static int em_nn_bind (int s, const char *addr ) {
-fprintf( stderr, ">>> ===== emulated bind called ====\n" );
+       //      fprintf( stderr, ">>> ===== emulated bind called ====\n" );
        return 1;
 }
 
@@ -362,8 +486,51 @@ static int em_nn_send (int s, const void *buf, size_t len, int flags ) {
        return 1;
 }
 
-static int em_nn_recv (int s, void *buf, size_t len, int flags ) {
-       return 1;
+static int em_nn_recv (int s, void *m, size_t len, int flags ) {
+       void* b;
+       struct em_msg* msg;
+       static int count = 0;                   // we'll simulate a message going in by dropping an rmr-ish msg with transaction id only
+       int trace_size = 0;
+       static int counter = 0;                         // if timeout value is set; we return timeout (eagain) every 3 calls
+       int d1_size = 0;
+
+       if( em_timeout > 0 ) {
+               counter++;
+               if( counter % 3 == 0 ) {
+                       return EAGAIN;
+               }
+       }
+
+       if( em_mtc_msgs ) {
+               d1_size = 4;
+       }
+
+       b = (void *) malloc( 2048 );
+       if( m != NULL ) {                                               // blindly we assume this is 2k or bigger
+               memset( m, 0, 2048 );
+               msg = (struct em_msg *) m;
+               if( count % 10  == 9 ) {
+                       //msg->rmr_ver = htonl( MSG_VER );
+                       msg->rmr_ver = ALT_MSG_VER;             // emulate the bug in RMr v1
+               } else {
+                       msg->rmr_ver = htonl( MSG_VER );
+               }
+               msg->mtype = htonl( 1 );
+               msg->plen = htonl( 220 );
+               msg->len0 = htonl( sizeof( struct em_msg ) );
+               msg->len1 = htonl( trace_size );
+               msg->len2 = htonl( d1_size );
+               msg->len3 = htonl( 0 );
+               snprintf( msg->xid, 32, "%015d", count++ );             // simple transaction id so we can test receive specific and ring stuff
+               snprintf( msg->src, 64, "localhost:4562" );             // set src id (unrealistic) so that rts() can be tested
+               snprintf( msg->srcip, 64, "89.2.19.19:4562" );          // set src ip for rts testing
+               //fprintf( stderr, "<EM>   returning message len=%d\n\n", ntohl( msg->plen ) );
+       } else {
+               fprintf( stderr, "<EM>   message was nil\n\n" );
+       }
+
+       //fprintf( stderr, ">>> simulated received message: %s %s len=%d p=%p\n", msg->src, msg->srcip, ntohl( msg->plen ), m );
+       return 2048;
 }
 
 static int em_sendmsg (int s, const struct em_nn_msghdr *msghdr, int flags ) {
@@ -374,10 +541,24 @@ static int em_nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags ) {
        return 1;
 }
 
-// nanomsg 
+static void em_nn_freemsg( void* ptr ) {
+       return;
+}
+
+/*
+       Hacky implementation of set sock opt. We assume value is a pointer to int and ignore size.
+*/
+static int em_setsockopt( int sock, int foo, int action, int* value, int size ) {
+       if( action ==  NN_RCVTIMEO ) {
+               em_timeout = *value;
+       }
+}
+
+
+// nanomsg
 #define nn_socket  em_nn_socket
 #define nn_close  em_nn_close
-#define nn_setsockopt  em_nn_setsockopt
+//#define nn_setsockopt  em_nn_setsockopt
 #define nn_getsockopt  em_nn_getsockopt
 #define nn_bind  em_nn_bind
 #define nn_connect  em_nn_connect
@@ -386,8 +567,10 @@ static int em_nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags ) {
 #define nn_recv  em_nn_recv
 #define nn_sendmsg  em_nn_sendmsg
 #define nn_recvmsg  em_nn_recvmsg
+#define nn_setsockopt  em_setsockopt
+#define nn_freemsg  em_nn_freemsg
 
-#endif 
+#endif
 
 
 #endif