Remove nanomsg support from app test scripts
[ric-plt/lib/rmr.git] / test / test_nng_em.c
1 /*
2 ==================================================================================
3         Copyright (c) 2019 Nokia
4         Copyright (c) 2018-2019 AT&T Intellectual Property.
5
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
9
10            http://www.apache.org/licenses/LICENSE-2.0
11
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 ==================================================================================
18 */
19
20 /*
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
25                                 poll related testing.
26
27                                 This module must be directly included to be used.
28         Date:           11 February 2019
29         Author:         E. Scott Daniels
30 */
31
32
33 #include "rmr.h"                                // we use some of rmr defs in building dummy messages, so we need these
34 #include "rmr_agnostic.h"
35
36 // ---------------------- emulated nng functions ---------------------------
37
38
39 #ifndef _em_nn
40 #define _em_nn
41
42 #include <pthread.h>
43
44 static int em_send_failures = 0;        // test programme can set this to emulate eagain send failures
45 static int em_timeout = -1;                     // set by set socket option
46 static int em_mtc_msgs = 0;                     // set to generate 'received' messages with mt-call header data
47 static int return_value = 0;            // functions should return this value
48 static int rcv_count = 0;                       // receive counter for transaction id to allow test to rest
49 static int rcv_delay = 0;                       // forced delay before call to rcvmsg starts to work
50
51 static int gates_ok = 0;
52 static pthread_mutex_t rcv_gate;
53 static int em_gen_long_hostname = 0;            // if set the emulated hostname generates a longer name (>40 char)
54
55
56 // ----------- gethostname emulation ---------------------------------------
57 #define gethostname  em_gethostname
58 static int em_gethostname( char* buf, size_t len ) {
59         if( len < 1 ) {
60                 errno = EINVAL;
61                 return 1;
62         }
63
64         if( em_gen_long_hostname ) {
65                 snprintf( buf, len, "hostname-which-is-long-a860430b890219-dfw82" );
66         } else {
67                 snprintf( buf, len, "em-hostname" );
68         }
69
70         return 0;
71 }
72
73 static int em_set_long_hostname( int v ) {
74         em_gen_long_hostname = !!v;
75 }
76
77 // ----------- epoll emulation ---------------------------------------------
78
79 // CAUTION: sys/epoll.h must be included before these define and function will properly compile.
80 #define epoll_wait em_wait
81 #define epoll_ctl  em_ep_ctl
82 #define epoll_create  em_ep_create
83
84 /*
85         Every other call returns 1 ready; alternate calls return 0 ready.
86         Mostly for testing the timeout receive call. First call should return
87         something ready and the second should return nothing ready so we can
88         drive both cases.
89 */
90 static int em_wait( int fd, void* events, int n, int to ) {
91         static int ready = 0;
92
93         ready = !ready;
94         return ready;
95 }
96
97 int em_ep_ctl( int epfd, int op, int fd, struct epoll_event *event ) {
98         return 0;
99 }
100
101 int em_ep_create( int size ) {
102         return 0;
103 }
104
105
106
107 /*
108         Simulated v1 message for receive to return. This needs to match the RMr header
109         so that we can fill in length, type and xaction id things.
110 #define MSG_VER 1
111 struct em_msg {
112         int32_t mtype;                                          // message type  ("long" network integer)
113         int32_t plen;                                           // payload length
114         int32_t rmr_ver;                                        // our internal message version number
115         unsigned char xid[32];                          // space for user transaction id or somesuch
116         unsigned char sid[32];                          // sender ID for return to sender needs
117         unsigned char src[16];                          // name of the sender (source)
118         unsigned char meid[32];                         // managed element id.
119         struct timespec ts;                                     // timestamp ???
120 };
121 */
122
123 /*
124         v2 message; should be able to use it for everything that is set up here as
125         we don't add a payload even if setting a v1 type.
126 */
127 #define ALT_MSG_VER 1   // alternate every so often
128 #define MSG_VER 3               // default version to insert
129 struct em_msg {
130         int32_t mtype;                                          // message type  ("long" network integer)
131         int32_t plen;                                           // payload length
132         int32_t rmr_ver;                                        // our internal message version number
133         unsigned char xid[32];                          // space for user transaction id or somesuch
134         unsigned char sid[32];                          // sender ID for return to sender needs
135         unsigned char src[64];                          // name of the sender (source)
136         unsigned char meid[32];                         // managed element id.
137         struct timespec ts;                                     // timestamp ???
138
139                                             // V2 extension
140         int32_t flags;                      // HFL_* constants
141         int32_t len0;                       // length of the RMr header data
142         int32_t len1;                       // length of the tracing data
143         int32_t len2;                       // length of data 1 (d1)
144         int32_t len3;                       // length of data 2 (d2)
145         int32_t sub_id;                                         // subscription id (-1 invalid)
146
147                                                                                 // V3 stuff
148         unsigned char srcip[64];                                // sender ID for return to sender needs
149 };
150
151
152
153 // --  emulation control functions ------------------------------------------------------
154
155 /*
156         Test app can call this to have all emulated functions return failure instead
157         of success.
158 */
159 static void en_set_return( int rv ) {
160         return_value = rv;
161 }
162
163
164
165 static int em_nng_foo() {
166         fprintf( stderr, "emulated functions in play" );
167 }
168
169
170 /*
171         Turns on/off the generation of multi-threaded call messages
172 */
173 static int em_set_mtc_msgs( int state ) {
174         em_mtc_msgs = state;
175 }
176
177 /*
178         Returns the size of the header we inserted
179 */
180 static int em_hdr_size() {
181         if( em_mtc_msgs ) {
182                 return (int) sizeof( struct em_msg ) + 4;
183         }
184
185         return (int) sizeof( struct em_msg );
186 }
187
188 static void em_set_rcvcount( int v ) {
189         rcv_count = v;
190 }
191
192 static void em_set_rcvdelay( int v ) {
193         rcv_delay = v;
194 }
195
196 static void em_start() {
197         if( ! gates_ok ) {
198                 pthread_mutex_init( &rcv_gate, NULL );
199                 gates_ok = 1;
200         }
201 }
202
203 //--------------------------------------------------------------------------
204 #ifdef EMULATE_NNG
205 struct nn_msghdr {
206         int boo;
207 };
208
209
210 /*
211         Receive message must allocate a new buffer and return the pointer into *m.
212         Every 9 messages or so we'll simulate an old version message
213
214         If em_mtc_msgs is set, then we add a non-zero d1 field with
215         the call-id set to 2, and alternate the call flag
216 */
217 static int em_nng_recvmsg( nng_socket s, nng_msg ** m, int i ) {
218         static int call_flag = 0;
219
220         void* b;
221         struct em_msg* msg;
222         int trace_size = 0;
223         int d1_size = 0;
224         unsigned char* d1;
225
226         if( rcv_delay > 0 ) {
227                 sleep( rcv_delay );
228         }
229
230         if( em_mtc_msgs ) {
231                 d1_size = 4;
232         }
233
234         if( m != NULL ) {
235                 b = (void *) malloc( 2048 );
236                 memset( b, 0, 2048 );
237
238                 *m = (nng_msg *) b;
239                 msg = (struct em_msg *) b;
240                 if( ! em_mtc_msgs  &&  (rcv_count % 10) == 9 ) {
241                         msg->rmr_ver = ALT_MSG_VER;                                                     // allow emulation the bug in RMr v1
242                 } else {
243                         msg->rmr_ver = htonl( MSG_VER );
244                 }
245
246                 msg->mtype = htonl( 1 );
247                 msg->plen = htonl( 220 );
248                 msg->len0 = htonl( sizeof( struct em_msg ) );
249                 msg->len1 = htonl( trace_size );
250                 msg->len2 = htonl( d1_size );
251                 msg->len3 = htonl( 0 );
252
253                 pthread_mutex_lock( &rcv_gate );        // hold lock to update counter/flag
254                 if( em_mtc_msgs ) {
255                         d1 = DATA1_ADDR( msg );
256                         d1[0] = 2;                                                                      // simulated msgs always on chute 2
257                         if( call_flag ) {
258                                 rcv_count++;
259                                 msg->flags |= HFL_CALL_MSG;
260                         }
261                         if( rcv_delay > 0 ) {
262                                 fprintf( stderr, "<EM>    count=%d flag=%d %02x \n", rcv_count, call_flag, msg->flags );
263                         }
264                         call_flag = !call_flag;
265                 } else {
266                         rcv_count++;
267                 }
268                 pthread_mutex_unlock( &rcv_gate );
269                 snprintf( msg->xid, 32, "%015d", rcv_count );           // simple transaction id so we can test receive specific and ring stuff
270                 snprintf( msg->src, 64, "localhost:4562" );             // set src id (unrealistic) so that rts() can be tested
271                 snprintf( msg->srcip, 64, "89.2.19.19:4562" );          // set src ip for rts testing
272
273                 //fprintf( stderr, ">>> simulated received message: %s %s p=%p len0=%d\n", msg->src, msg->srcip, msg, (int) ntohl( msg->len0 ) );
274         } else {
275                 fprintf( stderr, "<WARN> em: simulated receive no msg pointer provided\n" );
276         }
277
278         return return_value;
279 }
280
281 static void* em_msg_body( nng_msg* msg ) {
282         return (void *) msg;                                                            // we don't manage a real msg, so body is just the buffer we allocated
283 }
284
285 static size_t em_msg_len( const nng_msg* msg ) {
286         if( msg ) {
287                 return  2048;
288         }
289
290         return 0;
291 }
292
293
294 static int em_nng_pull_open(nng_socket * s ) {
295         return return_value;
296 }
297 static int em_nng_pull0_open(nng_socket * s ) {
298         return return_value;
299 }
300 static int em_nng_listen(nng_socket s, const char * c, nng_listener * l, int i ) {
301         return return_value;
302 }
303 static int em_nng_close(nng_socket s ) {
304         return return_value;
305 }
306 static int em_nng_push0_open(nng_socket * s ) {
307         return return_value;
308 }
309 static int em_nng_dial(nng_socket s, const char * c, nng_dialer * d, int i ) {
310         //fprintf( stderr, "<info> === simulated dialing: %s\n", c );
311         return return_value;
312 }
313 static int em_nng_setopt(nng_socket s, const char * c, const void * p, size_t t ) {
314         return return_value;
315 }
316 static int em_nng_sub_open(nng_socket * s ) {
317         return return_value;
318 }
319 static int em_nng_sub0_open(nng_socket * s ) {
320         return return_value;
321 }
322 static int em_nng_recv(nng_socket s, void * v, size_t * t, int i ) {
323         return return_value;
324 }
325 static int em_nng_send( nng_socket s, void* m, int l, int f ) {
326         free( m );                                      // we must ditch the message as nng does (or reuses)
327         return return_value;
328 }
329
330 /*
331         Emulate sending a message. If the global em_send_failures is set,
332         then every so often we fail with an EAGAIN to drive that part
333         of the code in RMr.
334 */
335 static int em_sendmsg( nng_socket s, nng_msg* m, int i ) {
336         static int count = 0;
337
338         if( em_send_failures && (count++ % 15 == 14) ) {
339                 //fprintf( stderr, ">>>> failing send\n\n" );
340                 return NNG_EAGAIN;
341         }
342
343         return return_value;
344 }
345
346 static void* em_nng_alloc( size_t len ) {
347         return malloc( len );
348 }
349
350 static int em_nng_msg_alloc( nng_msg** mp, size_t l ) {
351         void*   p;
352
353         if( !mp || return_value != 0  ) {
354                 return -1;
355         }
356
357         p = (void *) malloc( sizeof( char ) * l );
358         *mp = (nng_msg *) p;
359
360         return return_value;
361 }
362
363 /*
364         We just free the buffer here as it was a simple malloc.
365 */
366 static void em_nng_free( void* p, size_t l ) {
367         if( p ) {
368                 free( p );
369         }
370 }
371 static void em_nng_msg_free( void* p ) {
372         if( p ) {
373                 free( p );
374         }
375 }
376
377 static int em_dialer_create( void* d, nng_socket s, char* stuff ) {
378         //fprintf( stderr, ">>>> emulated dialer create\n\n" );
379         return 0;
380 }
381
382 static int em_dialer_start( nng_dialer d, int i ) {
383         //fprintf( stderr, ">>>> emulated dialer start\n\n" );
384         return return_value;
385 }
386
387
388 static int em_dialer_setopt_ms( nng_dialer dialer, void* option, int ms ) {
389         return return_value;
390 }
391
392 static int em_nng_getopt_int( nng_socket s, void* con, int* target ) {
393         if( target ) {
394                 *target = 0;
395         }
396         return return_value;
397 }
398
399
400
401 // nng redefines some of these to point directly to various 'versions' of the function (ugg, function versions, really?)
402 #undef nng_recvmsg
403 #undef nng_free
404 #undef nng_pull_open
405 #undef nng_pull0_open
406 #undef nng_listen
407 #undef nng_close
408 #undef nng_getopt_int
409 #undef nng_push0_open
410 #undef nng_dial
411 #undef nng_setopt
412 #undef nng_sub_open
413 #undef nng_sub0_open
414 #undef nng_recv
415 #undef nng_alloc
416
417 #define nng_msg_alloc em_nng_msg_alloc
418 #define nng_recvmsg em_nng_recvmsg
419 #define nng_free em_nng_free
420 #define nng_free em_nng_free
421 #define nng_msg_free em_nng_msg_free
422 #define nng_pull_open em_nng_pull_open
423 #define nng_pull0_open em_nng_pull0_open
424 #define nng_listen em_nng_listen
425 #define nng_close em_nng_close
426 #define nng_getopt_int em_nng_getopt_int
427 #define nng_push0_open em_nng_push0_open
428 #define nng_dial em_nng_dial
429 #define nng_setopt em_nng_setopt
430 #define nng_sub_open em_nng_sub_open
431 #define nng_sub0_open em_nng_sub0_open
432 #define nng_recv em_nng_recv
433 #define nng_send em_nng_send
434 #define nng_sendmsg em_sendmsg
435 #define nng_alloc em_nng_alloc
436 #define nng_free em_nng_free
437 #define nng_dialer_setopt_ms em_dialer_setopt_ms
438 #define nng_dialer_start em_dialer_start
439 #define nng_dialer_create em_dialer_create
440 #define nng_msg_body em_msg_body
441 #define nng_msg_len em_msg_len
442
443
444 #else
445
446
447 // ----------------------- emulated nano functions --------------------------
448 struct em_nn_msghdr {
449         int dummy;
450 };
451
452 static int em_nn_socket (int domain, int protocol ) {
453         static int s = 1;
454
455         return ++s;
456 }
457
458 static int em_nn_close (int s ) {
459         return 1;
460 }
461
462 //static int em_nn_setsockopt (int s, int level, int option, const void *optval, size_t optvallen ) {
463         //return 1;
464 //}
465
466 static int em_nn_getsockopt (int s, int level, int option, void *optval, size_t *optvallen ) {
467         return 1;
468 }
469
470 static int em_nn_bind (int s, const char *addr ) {
471         //      fprintf( stderr, ">>> ===== emulated bind called ====\n" );
472         return 1;
473 }
474
475 static int em_nn_connect (int s, const char *addr ) {
476         return 1;
477 }
478
479 static int em_nn_shutdown (int s, int how ) {
480         return 1;
481 }
482
483 static int em_nn_send (int s, const void *buf, size_t len, int flags ) {
484         return 1;
485 }
486
487 static int em_nn_recv (int s, void *m, size_t len, int flags ) {
488         void* b;
489         struct em_msg* msg;
490         static int count = 0;                   // we'll simulate a message going in by dropping an rmr-ish msg with transaction id only
491         int trace_size = 0;
492         static int counter = 0;                         // if timeout value is set; we return timeout (eagain) every 3 calls
493         int d1_size = 0;
494
495         if( em_timeout > 0 ) {
496                 counter++;
497                 if( counter % 3 == 0 ) {
498                         return EAGAIN;
499                 }
500         }
501
502         if( em_mtc_msgs ) {
503                 d1_size = 4;
504         }
505
506         b = (void *) malloc( 2048 );
507         if( m != NULL ) {                                               // blindly we assume this is 2k or bigger
508                 memset( m, 0, 2048 );
509                 msg = (struct em_msg *) m;
510                 if( count % 10  == 9 ) {
511                         //msg->rmr_ver = htonl( MSG_VER );
512                         msg->rmr_ver = ALT_MSG_VER;             // emulate the bug in RMr v1
513                 } else {
514                         msg->rmr_ver = htonl( MSG_VER );
515                 }
516                 msg->mtype = htonl( 1 );
517                 msg->plen = htonl( 220 );
518                 msg->len0 = htonl( sizeof( struct em_msg ) );
519                 msg->len1 = htonl( trace_size );
520                 msg->len2 = htonl( d1_size );
521                 msg->len3 = htonl( 0 );
522                 snprintf( msg->xid, 32, "%015d", count++ );             // simple transaction id so we can test receive specific and ring stuff
523                 snprintf( msg->src, 64, "localhost:4562" );             // set src id (unrealistic) so that rts() can be tested
524                 snprintf( msg->srcip, 64, "89.2.19.19:4562" );          // set src ip for rts testing
525                 //fprintf( stderr, "<EM>   returning message len=%d\n\n", ntohl( msg->plen ) );
526         } else {
527                 fprintf( stderr, "<EM>   message was nil\n\n" );
528         }
529
530         //fprintf( stderr, ">>> simulated received message: %s %s len=%d p=%p\n", msg->src, msg->srcip, ntohl( msg->plen ), m );
531         return 2048;
532 }
533
534 static int em_sendmsg (int s, const struct em_nn_msghdr *msghdr, int flags ) {
535         return 1;
536 }
537
538 static int em_nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags ) {
539         return 1;
540 }
541
542 static void em_nn_freemsg( void* ptr ) {
543         free( ptr );
544         return;
545 }
546
547 /*
548         Hacky implementation of set sock opt. We assume value is a pointer to int and ignore size.
549 */
550 static int em_setsockopt( int sock, int foo, int action, int* value, int size ) {
551         if( action ==  NN_RCVTIMEO ) {
552                 em_timeout = *value;
553         }
554 }
555
556
557 // nanomsg
558 #define nn_socket  em_nn_socket
559 #define nn_close  em_nn_close
560 //#define nn_setsockopt  em_nn_setsockopt
561 #define nn_getsockopt  em_nn_getsockopt
562 #define nn_bind  em_nn_bind
563 #define nn_connect  em_nn_connect
564 #define nn_shutdown  em_nn_shutdown
565 #define nn_send  em_nn_send
566 #define nn_recv  em_nn_recv
567 #define nn_sendmsg  em_nn_sendmsg
568 #define nn_recvmsg  em_nn_recvmsg
569 #define nn_setsockopt  em_setsockopt
570 #define nn_freemsg  em_nn_freemsg
571
572 #endif
573
574
575 #endif