2 ==================================================================================
3 Copyright (c) 2019 Nokia
4 Copyright (c) 2018-2019 AT&T Intellectual Property.
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================================
21 Mnemonic: test_nng_em.c
22 Abstract: A nano/NNG message emulator for testing without needing to
23 actually have nanomsg, nng, or external processes.
24 We also emulate the epoll_wait() function for controlled
27 This module must be directly included to be used.
28 Date: 11 February 2019
29 Author: E. Scott Daniels
32 // ---------------------- emulated nng functions ---------------------------
38 static int em_send_failures = 0; // test programme can set this to emulate eagain send failures
39 static int em_timeout = -1; // set by set socket option
41 // ----------- epoll emulation ---------------------------------------------
43 // CAUTION: sys/epoll.h must be included before this define and function will properly compile.
44 #define epoll_wait em_wait
46 Every other call returns 1 ready; alternate calls return 0 ready.
47 Mostly for testing the timeout receive call. First call should return
48 something ready and the second should return nothing ready so we can
51 static int em_wait( int fd, void* events, int n, int to ) {
61 Simulated v1 message for receive to return. This needs to match the RMr header
62 so that we can fill in length, type and xaction id things.
65 int32_t mtype; // message type ("long" network integer)
66 int32_t plen; // payload length
67 int32_t rmr_ver; // our internal message version number
68 unsigned char xid[32]; // space for user transaction id or somesuch
69 unsigned char sid[32]; // sender ID for return to sender needs
70 unsigned char src[16]; // name of the sender (source)
71 unsigned char meid[32]; // managed element id.
72 struct timespec ts; // timestamp ???
77 v2 message; should be able to use it for everything that is set up here as
78 we don't add a payload even if setting a v1 type.
80 #define ALT_MSG_VER 1 // alternate every so often
81 #define MSG_VER 2 // default version to insert
83 int32_t mtype; // message type ("long" network integer)
84 int32_t plen; // payload length
85 int32_t rmr_ver; // our internal message version number
86 unsigned char xid[32]; // space for user transaction id or somesuch
87 unsigned char sid[32]; // sender ID for return to sender needs
88 unsigned char src[64]; // name of the sender (source)
89 unsigned char meid[32]; // managed element id.
90 struct timespec ts; // timestamp ???
93 int32_t flags; // HFL_* constants
94 int32_t len0; // length of the RMr header data
95 int32_t len1; // length of the tracing data
96 int32_t len2; // length of data 1 (d1)
97 int32_t len3; // length of data 2 (d2)
101 static int return_value = 0;
103 //--------------------------------------------------------------------------
111 Test app can call this to have all emulated functions return failure instead
114 static void en_set_return( int rv ) {
120 static int em_nng_foo() {
121 fprintf( stderr, "emulated functions in play" );
126 Receive message must allocate a new buffer and return the pointer into *m.
127 Every 9 messages or so we'll simulate an old version message
129 static int em_nng_recvmsg( nng_socket s, nng_msg ** m, int i ) {
132 static int count = 0; // we'll simulate a message going in by dropping an rmr-ish msg with transaction id only
137 b = (void *) malloc( 2048 );
139 memset( b, 0, 2048 );
141 msg = (struct em_msg *) b;
142 if( count % 10 == 9 ) {
143 //msg->rmr_ver = htonl( MSG_VER );
144 msg->rmr_ver = ALT_MSG_VER; // emulate the bug in RMr v1
146 msg->rmr_ver = htonl( MSG_VER );
148 msg->mtype = htonl( 1 );
149 msg->plen = htonl( 220 );
150 msg->len0 = htonl( sizeof( struct em_msg ) );
151 msg->len1 = htonl( trace_size );
152 snprintf( msg->xid, 32, "%015d", count++ ); // simple transaction id so we can test receive specific and ring stuff
153 snprintf( msg->src, 16, "localhost:4562" ); // set src id (unrealistic) so that rts() can be tested
156 //fprintf( stderr, ">>> simulated received message: %s\n", msg->xid );
160 static void* em_msg_body( nng_msg* msg ) {
161 return (void *) msg; // we don't manage a real msg, so body is just the buffer we allocated
164 static size_t em_msg_len( const nng_msg* msg ) {
173 static int em_nng_pull_open(nng_socket * s ) {
176 static int em_nng_pull0_open(nng_socket * s ) {
179 static int em_nng_listen(nng_socket s, const char * c, nng_listener * l, int i ) {
182 static int em_nng_close(nng_socket s ) {
185 static int em_nng_push0_open(nng_socket * s ) {
188 static int em_nng_dial(nng_socket s, const char * c, nng_dialer * d, int i ) {
189 //fprintf( stderr, "<info> === simulated dialing: %s\n", c );
192 static int em_nng_setopt(nng_socket s, const char * c, const void * p, size_t t ) {
195 static int em_nng_sub_open(nng_socket * s ) {
198 static int em_nng_sub0_open(nng_socket * s ) {
201 static int em_nng_recv(nng_socket s, void * v, size_t * t, int i ) {
205 static int em_nng_send( nng_socket s, void* m, int l, int f ) {
210 Emulate sending a message. If the global em_send_failures is set,
211 then every so often we fail with an EAGAIN to drive that part
214 static int em_sendmsg( nng_socket s, nng_msg* m, int i ) {
215 static int count = 0;
217 if( em_send_failures && (count++ % 15 == 14) ) {
218 //fprintf( stderr, ">>>> failing send\n\n" );
225 static void* em_nng_alloc( size_t len ) {
226 return malloc( len );
229 static int em_nng_msg_alloc( nng_msg** mp, size_t l ) {
232 if( !mp || return_value != 0 ) {
236 p = (void *) malloc( sizeof( char ) * l );
243 We just free the buffer here as it was a simple malloc.
245 static void em_nng_free( void* p, size_t l ) {
247 //fprintf( stderr, ">>>>> not freed: %p\n", p );
251 static void em_nng_msg_free( void* p ) {
253 //fprintf( stderr, ">>>>> not freed: %p\n", p );
258 static int em_dialer_create( void* d, nng_socket s, char* stuff ) {
259 //fprintf( stderr, ">>>> emulated dialer create\n\n" );
263 static int em_dialer_start( nng_dialer d, int i ) {
264 //fprintf( stderr, ">>>> emulated dialer start\n\n" );
269 static int em_dialer_setopt_ms( nng_dialer dialer, void* option, int ms ) {
273 static int em_nng_getopt_int( nng_socket s, void* con, int* target ) {
282 // nng redefines some of these to point directly to various 'versions' of the function (ugg, function versions, really?)
286 #undef nng_pull0_open
289 #undef nng_getopt_int
290 #undef nng_push0_open
298 #define nng_msg_alloc em_nng_msg_alloc
299 #define nng_recvmsg em_nng_recvmsg
300 #define nng_free em_nng_free
301 #define nng_free em_nng_free
302 #define nng_msg_free em_nng_msg_free
303 #define nng_pull_open em_nng_pull_open
304 #define nng_pull0_open em_nng_pull0_open
305 #define nng_listen em_nng_listen
306 #define nng_close em_nng_close
307 #define nng_getopt_int em_nng_getopt_int
308 #define nng_push0_open em_nng_push0_open
309 #define nng_dial em_nng_dial
310 #define nng_setopt em_nng_setopt
311 #define nng_sub_open em_nng_sub_open
312 #define nng_sub0_open em_nng_sub0_open
313 #define nng_recv em_nng_recv
314 #define nng_send em_nng_send
315 #define nng_sendmsg em_sendmsg
316 #define nng_alloc em_nng_alloc
317 #define nng_free em_nng_free
318 #define nng_dialer_setopt_ms em_dialer_setopt_ms
319 #define nng_dialer_start em_dialer_start
320 #define nng_dialer_create em_dialer_create
321 #define nng_msg_body em_msg_body
322 #define nng_msg_len em_msg_len
328 // ----------------------- emulated nano functions --------------------------
329 struct em_nn_msghdr {
333 static int em_nn_socket (int domain, int protocol ) {
339 static int em_nn_close (int s ) {
343 //static int em_nn_setsockopt (int s, int level, int option, const void *optval, size_t optvallen ) {
347 static int em_nn_getsockopt (int s, int level, int option, void *optval, size_t *optvallen ) {
351 static int em_nn_bind (int s, const char *addr ) {
352 // fprintf( stderr, ">>> ===== emulated bind called ====\n" );
356 static int em_nn_connect (int s, const char *addr ) {
360 static int em_nn_shutdown (int s, int how ) {
364 static int em_nn_send (int s, const void *buf, size_t len, int flags ) {
368 static int em_nn_recv (int s, void *m, size_t len, int flags ) {
371 static int count = 0; // we'll simulate a message going in by dropping an rmr-ish msg with transaction id only
373 static int counter = 0; // if timeout value is set; we return timeout (eagain) every 3 calls
375 if( em_timeout > 0 ) {
377 if( counter % 3 == 0 ) {
382 b = (void *) malloc( 2048 );
383 if( m != NULL ) { // blindly we assume this is 2k or bigger
384 memset( m, 0, 2048 );
385 msg = (struct em_msg *) m;
386 if( count % 10 == 9 ) {
387 //msg->rmr_ver = htonl( MSG_VER );
388 msg->rmr_ver = ALT_MSG_VER; // emulate the bug in RMr v1
390 msg->rmr_ver = htonl( MSG_VER );
392 msg->mtype = htonl( 1 );
393 msg->plen = htonl( 220 );
394 msg->len0 = htonl( sizeof( struct em_msg ) );
395 msg->len1 = htonl( trace_size );
396 snprintf( msg->xid, 32, "%015d", count++ ); // simple transaction id so we can test receive specific and ring stuff
397 snprintf( msg->src, 16, "localhost:4562" ); // set src id (unrealistic) so that rts() can be tested
398 //fprintf( stderr, "<EM> returning message len=%d\n\n", ntohl( msg->plen ) );
400 fprintf( stderr, "<EM> message was nil\n\n" );
403 //fprintf( stderr, ">>> simulated received message: %s len=%d\n", msg->xid, msg->plen );
407 static int em_sendmsg (int s, const struct em_nn_msghdr *msghdr, int flags ) {
411 static int em_nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags ) {
415 static void em_nn_freemsg( void* ptr ) {
420 Hacky implementation of set sock opt. We assume value is a pointer to int and ignore size.
422 static int em_setsockopt( int sock, int foo, int action, int* value, int size ) {
423 if( action == NN_RCVTIMEO ) {
430 #define nn_socket em_nn_socket
431 #define nn_close em_nn_close
432 //#define nn_setsockopt em_nn_setsockopt
433 #define nn_getsockopt em_nn_getsockopt
434 #define nn_bind em_nn_bind
435 #define nn_connect em_nn_connect
436 #define nn_shutdown em_nn_shutdown
437 #define nn_send em_nn_send
438 #define nn_recv em_nn_recv
439 #define nn_sendmsg em_nn_sendmsg
440 #define nn_recvmsg em_nn_recvmsg
441 #define nn_setsockopt em_setsockopt
442 #define nn_freemsg em_nn_freemsg