Correct bug identified in static analysis
[ric-plt/lib/rmr.git] / test / test_nng_em.c
index 76fe72b..c2c1e80 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
 
-static int em_send_failures = 0;       // test programme can set this to emulate eagain send failures
-
-// ----------- epoll emulation ---------------------------------------------
-
-// CAUTION: sys/epoll.h must be included before this define and function will properly compile. 
-#define epoll_wait em_wait
-/*
-       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. 
-*/
-static int em_wait( int fd, void* events, int n, int to ) {
-       static int ready = 0;
-
-       ready = !ready;
-       return ready;
-}
-
-
+#include <pthread.h>
+#include "test_common_em.c"                    // things common to all emulation code
 
 //--------------------------------------------------------------------------
 #ifdef EMULATE_NNG
 
 //--------------------------------------------------------------------------
 #ifdef EMULATE_NNG
@@ -62,96 +48,76 @@ struct nn_msghdr {
        int boo;
 };
 
        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;
-}
-
-
-
-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
-       so that we can fill in length, type and xaction id things.
-#define MSG_VER 1
-struct em_msg {
-       int32_t mtype;                                          // message type  ("long" network integer)
-       int32_t plen;                                           // payload length
-       int32_t rmr_ver;                                        // our internal message version number
-       unsigned char xid[32];                          // space for user transaction id or somesuch
-       unsigned char sid[32];                          // sender ID for return to sender needs
-       unsigned char src[16];                          // name of the sender (source)
-       unsigned char meid[32];                         // managed element id.
-       struct timespec ts;                                     // timestamp ???
-};
-*/
-
-/*
-       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
-struct em_msg {
-       int32_t mtype;                                          // message type  ("long" network integer)
-       int32_t plen;                                           // payload length
-       int32_t rmr_ver;                                        // our internal message version number
-       unsigned char xid[32];                          // space for user transaction id or somesuch
-       unsigned char sid[32];                          // sender ID for return to sender needs
-       unsigned char src[64];                          // name of the sender (source)
-       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)
-
-};
+#define SOCKET_TYPE            nng_socket              // socket representation is different in each transport
 
 /*
        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;
 }
 
@@ -200,12 +166,13 @@ 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 ) {
+       free( m );                                      // we must ditch the message as nng does (or reuses)
        return return_value;
 }
 
 /*
        Emulate sending a message. If the global em_send_failures is set,
        return return_value;
 }
 
 /*
        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 ) {
@@ -241,13 +208,11 @@ static int em_nng_msg_alloc( nng_msg** mp, size_t l ) {
 */
 static void em_nng_free( void* p, size_t l ) {
        if( p ) {
 */
 static void em_nng_free( void* p, size_t l ) {
        if( p ) {
-               //fprintf( stderr, ">>>>> not freed: %p\n", p );
                free( p );
        }
 }
 static void em_nng_msg_free( void* p ) {
        if( p ) {
                free( p );
        }
 }
 static void em_nng_msg_free( void* p ) {
        if( p ) {
-               //fprintf( stderr, ">>>>> not freed: %p\n", p );
                free( p );
        }
 }
                free( p );
        }
 }
@@ -277,20 +242,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
@@ -321,6 +286,8 @@ static int em_nng_getopt_int( nng_socket s, void* con, int* target ) {
 
 #else
 
 
 #else
 
+#define SOCKET_TYPE            int             // socket representation is different in each transport
+
 
 // ----------------------- emulated nano functions --------------------------
 struct em_nn_msghdr {
 
 // ----------------------- emulated nano functions --------------------------
 struct em_nn_msghdr {
@@ -337,16 +304,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 +329,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 +384,25 @@ 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 ) {
+       free( 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 +411,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