Simplify continuous-integration build
[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
 
        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,
 
    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
 
 /*
        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.
                                actually have nanomsg, nng, or external processes.
                                We also emulate the epoll_wait() function for controlled
                                poll related testing.
        Author:         E. Scott Daniels
 */
 
        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
 
 // ---------------------- 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_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 ---------------------------------------------
 
 
 // ----------- 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_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
        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;
 */
 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;
 }
 
        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
 
 /*
        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
        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
 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 ???
 
        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
 /*
        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 em_nng_recvmsg( nng_socket s, nng_msg ** m, int i ) {
+       static int call_flag = 0;
+
        void* b;
        struct em_msg* msg;
        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 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 ) {
        if( m != NULL ) {
+               b = (void *) malloc( 2048 );
                memset( b, 0, 2048 );
                memset( b, 0, 2048 );
+
                *m = (nng_msg *) b;
                msg = (struct em_msg *) b;
                *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 );
                }
                } else {
                        msg->rmr_ver = htonl( MSG_VER );
                }
+
                msg->mtype = htonl( 1 );
                msg->mtype = htonl( 1 );
-               msg->plen = htonl( 129 );
+               msg->plen = htonl( 220 );
                msg->len0 = htonl( sizeof( struct em_msg ) );
                msg->len1 = htonl( trace_size );
                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;
 }
 
        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_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 ) {
        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,
 
 /*
        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 ) {
        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?)
 
 
 // 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
 
 #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;
 }
 
        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 ) {
 
 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;
 }
 
        return 1;
 }
 
@@ -362,8 +486,51 @@ static int em_nn_send (int s, const void *buf, size_t len, int flags ) {
        return 1;
 }
 
        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 ) {
 }
 
 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;
 }
 
        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_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
 #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_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
 
 
 #endif