Correct bug identified in static analysis
[ric-plt/lib/rmr.git] / test / si95_test.c
1 // :vi sw=4 ts=4 noet:
2 /*
3 ==================================================================================
4         Copyright (c) 2020 Nokia
5         Copyright (c) 2020 AT&T Intellectual Property.
6
7    Licensed under the Apache License, Version 2.0 (the "License");
8    you may not use this file except in compliance with the License.
9    You may obtain a copy of the License at
10
11            http://www.apache.org/licenses/LICENSE-2.0
12
13    Unless required by applicable law or agreed to in writing, software
14    distributed under the License is distributed on an "AS IS" BASIS,
15    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16    See the License for the specific language governing permissions and
17    limitations under the License.
18 ==================================================================================
19 */
20
21 /*
22         Mmemonic:       si95_test.c
23         Abstract:       This is the main driver to test the si95 core functions
24                                 (within rmr/src/si/src/si95).
25
26         Author:         E. Scott Daniels
27         Date:           6 March 2018
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <netdb.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <pthread.h>
37 #include <ctype.h>
38
39 #include <netdb.h>              // these four needed for si address tests
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <netinet/in.h>
43
44
45
46 #include <unistd.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <strings.h>
50 #include <errno.h>
51 #include <string.h>
52 #include <stdint.h>
53 #include <ctype.h>
54 #include <sys/epoll.h>
55 #include <pthread.h>
56 #include <semaphore.h>
57
58 #define DEBUG 1
59
60                                                                                         // specific test tools in this directory
61 #undef NNG_UNDER_TEST                                           // NNG is NOT under test so undefine if set
62 #define NO_EMULATION 1                                          // no emulation of transport functions
63 #define NO_PRIVATE_HEADERS 1                            // no rmr_si or rmr_nng headers
64 #define NO_DUMMY_RMR 1                                          // no msg things
65
66 #include "test_support.c"                                       // things like fail_if()
67 #include "test_transport_em.c"                          // system/transport emulation (open, close, connect, etc)
68
69 /*
70 #include "rmr.h"                                        // things the users see
71 #include "rmr_symtab.h"
72 #include "rmr_agnostic.h"                       // transport agnostic header
73 */
74 #include <rmr_logging.h>
75 #include <logging.c>
76
77 #include <si95/siaddress.c>
78 //#include <si95/sialloc.c>
79 #include <si95/sibldpoll.c>
80 #include <si95/sicbreg.c>
81 #include <si95/sicbstat.c>
82 #include <si95/siclose.c>
83 #include <si95/siconnect.c>
84 #include <si95/siestablish.c>
85 #include <si95/sigetadd.c>
86 #include <si95/sigetname.c>
87 #include <si95/siinit.c>
88 #include <si95/silisten.c>
89 #include <si95/sinew.c>
90 #include <si95/sinewses.c>
91 #include <si95/sipoll.c>
92 //#include <si95/sircv.c>
93 #include <si95/sisend.c>
94 #include <si95/sisendt.c>
95 #include <si95/sishutdown.c>
96 #include <si95/siterm.c>
97 #include <si95/sitrash.c>
98 //#include <si95/siwait.c>
99
100 // ---------------------------------------------------------------------
101
102 void*   si_ctx = NULL;                  // a global context might be useful
103
104 // ---------------------------------------------------------------------
105
106 /*
107         Fake callback to register.
108 */
109 static int test_cb( void* data ) {
110         return 0;
111 }
112
113 /*
114         Returns error for coverage testing of CB calls
115 */
116 static int test_cb_err( void* data ) {
117         return -1;
118 }
119
120 /*
121         Memory allocation/free related tests
122 */
123 static int memory( ) {
124         int             errors = 0;
125         void*   ptr;
126         void*   iptr;
127
128         // ---- SInew ----------------
129         ptr = SInew( 100 );                             // invalid block type should return nil
130         errors += fail_not_nil( ptr, "memory: sinew did not return nil when given a valid struct type" );
131         SItrash( 100, NULL );                           // drive trash for coverage
132
133         iptr = SInew( IOQ_BLK );
134         errors += fail_if_nil( iptr, "memory: sinew returned nil when given ioq request" );
135         SItrash(  IOQ_BLK, iptr );
136
137         ptr = SInew( TP_BLK );
138         errors += fail_if_nil( ptr, "memory: sinew returned nil when given tpblk request" );
139         if( ptr ) {
140                 iptr = SInew( IOQ_BLK );
141                 ((struct tp_blk *)ptr)->squeue = iptr;
142                 SItrash(  TP_BLK, ptr );
143         }
144
145         ptr = SInew( GI_BLK );
146         errors += fail_if_nil( ptr, "memory: sinew returned nil when given giblk request" );
147         SItrash(  GI_BLK, ptr );                // GI block cannot be trashed, ensure this (valgind will complain about a leak)
148
149         fprintf( stderr, "<INFO> memory module finished with %d errors\n", errors );
150         return errors;
151 }
152
153 /*
154         Test initialisation related things
155 */
156 static int init() {
157         int             errors = 0;
158
159         si_ctx = SIinitialise( 0 );
160         errors += fail_if_nil( si_ctx, "init: siinit returned a nil pointer" );
161
162         SIclr_tflags( si_ctx, 0x00 );           // drive for coverage; no return value from these
163         SIset_tflags( si_ctx, 0x03 );
164
165         fprintf( stderr, "<INFO> init  module finished with %d errors\n", errors );
166         return errors;
167 }
168
169 static int cleanup() {
170         int errors = 0;
171
172         if( ! si_ctx ) {
173                 fprintf( stderr, "<INFO> cleanup has no context to use\n" );
174                 return 0;
175         }
176
177         fprintf( stderr, "<INFO> cleanup running\n" );
178         SIcbstat( si_ctx, SI_RET_UNREG, SI_CB_SECURITY );
179         SIcbstat( si_ctx, SI_RET_QUIT, SI_CB_SECURITY );
180
181         SItp_stats( si_ctx );           // drive for coverage only
182         SItp_stats( NULL );
183
184         SIconnect( si_ctx, "127.0.0.1:43086" ); // ensure context has a tp block to free on shutdown
185         SIshutdown( NULL );
186         SIabort( si_ctx );
187
188
189         fprintf( stderr, "<INFO> cleanup  module finished with %d errors\n", errors );
190         return errors;
191 }
192
193 /*
194         Address related tests.
195 */
196 static int addr() {
197         int errors = 0;
198         int l;
199         struct sockaddr* addr;
200         char buf1[4096];                        // space to build buffers for xlation
201         char*   hr_addr;                        // human readable address returned
202         void* net_addr;                         // a network address block of some type
203
204         addr = (struct sockaddr *) malloc( sizeof( struct sockaddr ) );
205 /*
206         l = SIgenaddr( "    [ff02::4]:4567", PF_INET6, IPPROTO_TCP, SOCK_STREAM, &addr );
207
208         SIgenaddr( "    [ff02::4]:4567", PF_INET6, IPPROTO_TCP, SOCK_STREAM, &addr );
209 */
210
211         l = SIaddress( NULL, NULL, 0 );
212         errors += fail_if_true( l != 0, "SIaddress given two null pointers didn't return 0 len" );
213         l = SIaddress( buf1, NULL, 0 );
214         errors += fail_if_true( l != 0, "SIaddress given null dest pointer didn't return 0 len" );
215         l = SIaddress( NULL, (void *) &buf1, 0 );
216         errors += fail_if_true( l != 0, "SIaddress given null src pointer didn't return 0 len" );
217
218         net_addr = NULL;
219         snprintf( buf1, sizeof( buf1 ), "   [ff02::5:4001" );           // invalid address, drive leading space eater too
220         l = SIaddress( buf1, (void **)  &net_addr, AC_TOADDR6 );
221         errors += fail_if_true( l > 0, "to addr6 with bad addr convdersion returned valid len" );
222         free( net_addr );
223
224         snprintf( buf1, sizeof( buf1 ), "[ff02::5]:4002" );             // v6 might not be supported so failure is OK here; driving for coverage
225         l = SIaddress( buf1, &net_addr, AC_TOADDR6 );
226         if( l > 0 ) {
227                 l = SIaddress( net_addr, (void *) &hr_addr, AC_TODOT );                                         // convert the address back to hr string
228                 errors += fail_if_true( l < 1, "v6 to dot conversion failed" );
229                 errors += fail_if_nil( hr_addr, "v6 to dot conversion yields a nil pointer" );
230                 free( net_addr );
231         }
232
233         snprintf( buf1, sizeof( buf1 ), "localhost:43086" );
234         l = SIaddress( buf1, (void **) &net_addr, AC_TOADDR );
235         errors += fail_if_true( l < 1, "v4 to addr conversion failed" );
236
237         l = SIaddress( net_addr, (void *) &hr_addr, AC_TODOT );                                         // convert the address back to hr string
238         errors += fail_if_true( l < 1, "to dot convdersion failed" );
239         errors += fail_if_nil( hr_addr, "v4 to dot conversion yields a nil pointer" );
240         free( net_addr );
241
242         fprintf( stderr, "<INFO> addr module finished with %d errors\n", errors );
243         return errors;
244 }
245
246 /*
247         Prep related tests. These mostly drive cases that aren't driven by "normal"
248         connect, send, receive tests (e.g. UDP branches).
249 */
250 static int prep() {
251         int             errors = 0;
252         void*   thing;                                  // the thing that should be returned
253
254         thing = SIlisten_prep( UDP_DEVICE, "localhost:1234", AF_INET );
255         errors += fail_if_nil( thing, "listen prep udp returned nil block" );
256
257         thing = SIlisten_prep( UDP_DEVICE, "localhost:1234", 84306 );           // this should fail
258         errors += fail_not_nil( thing, "listen prep udp returned valid block ptr for bogus family" );
259
260         thing = SIconn_prep( si_ctx, UDP_DEVICE, "localhost:1234", 84306 );             // again, expect to fail; bogus family
261         errors += fail_not_nil( thing, "conn prep udp returned valid block ptr for bogus family" );
262
263         return errors;
264 }
265
266 /*
267         Polling/waiting tests.  These are difficult at best because of the blocking
268         nature of things, not to mention needing to have real ports open etc.
269 */
270 static int poll() {
271         int errors  = 0;
272         int status;
273
274         status = SIpoll( si_ctx, 1 );
275         errors += fail_if_true( status != 0, "poll failed" );
276
277         return errors;
278 }
279
280
281 /*
282         Connection oriented tests.
283 */
284 static int conn( ) {
285         int errors = 0;
286         int state;
287         int cfd = 3;                                    // fd for close
288         char*   buf;
289
290         state = SIconnect( si_ctx, "localhost:4567" );          // driver regular connect
291         errors += fail_if_true( state < 0, "connect to low port failed" );
292
293         state = SIconnect( si_ctx, "localhost:43086" );         // drive save connect with good return code
294         errors += fail_if_true( state < 0, "connect to high port failed" );
295
296         tpem_set_addr_dup_state( 1 );                                           // force get sockket name emulation to return a duplicate address
297         state = SIconnect( si_ctx, "localhost:43086" );         // drive save connect with good return code
298         errors += fail_if_true( state >= 0, "forced dup connect did not return error" );
299
300         tpem_set_addr_dup_state( 0 );                                           // back to normal
301         tpem_set_conn_state( -1 );
302         state = SIconnect( si_ctx, "localhost:4567" );          // driver regular connect
303         errors += fail_if_true( state >= 0, "connect to low port successful when failure expected" );
304         tpem_set_conn_state( 3 );
305
306         tpem_set_sock_state( 1 );                                                       // make scoket calls fail
307         state = SIconnect( si_ctx, "localhost:4567" );          // driver regular connect
308         errors += fail_if_true( state >= 0, "connect to low port successful when socket based failure expected" );
309
310         tpem_set_sock_state( 0 );
311
312         state = SIlistener( si_ctx, TCP_DEVICE, "0.0.0.0:4567" );
313         errors += fail_if_true( state < 0, "listen failed" );
314
315         tpem_set_bind_state( 1 );
316         state = SIlistener( si_ctx, TCP_DEVICE, "0.0.0.0:4567" );
317         errors += fail_if_true( state >= 0, "listen successful when bind error set" );
318         tpem_set_bind_state( 0 );
319
320         SIbldpoll( si_ctx );            // for coverage. no return value and nothing we can check
321
322         state = SIclose( NULL, 0 );                     //coverage
323         errors += fail_if_true( state != SI_ERROR, "close given nil context returned success" );
324
325         state = SIclose( si_ctx, cfd );
326         errors += fail_if_true( state == SI_ERROR, "close given good context and good fd returned error" );
327
328         state = SIclose( si_ctx, 5000 );                                                // out of range fd
329         errors += fail_if_true( state != SI_ERROR, "close given good context and bad fd returned success" );
330
331         state = SIclose( si_ctx, TCP_LISTEN_PORT );                             // close listener
332         errors += fail_if_true( state == SI_ERROR, "close given good context and listener fd returned error" );
333
334         state = SIclose( si_ctx, UDP_PORT );                                    // close first open udp port (should not be there)
335         errors += fail_if_true( state != SI_ERROR, "close given good context and udp generic fd returned error" );
336
337         buf = SIgetname( 3 );
338         if( fail_if_true( buf == NULL, "get name failed to return a buffer" ) ) {
339                 errors++;
340         } else {
341                 errors += fail_if_true( buf[0] == 0, "get name returned buf with emtpy string" );
342                 free( buf );
343         }
344
345         buf = SIgetname( -1 );                  // invalid fd
346         errors += fail_not_nil( buf, "get name returned buf with non-emtpy string when given bad fd" );
347
348         fprintf( stderr, "<INFO> conn module finished with %d errors\n", errors );
349         return errors;
350 }
351
352 /*
353         Misc tests that just don't fit in another bucket.
354 */
355 static int misc( ) {
356         int errors = 0;
357         char    buf[1024];
358
359         SIcbreg( NULL, SI_CB_SECURITY, test_cb, NULL );         // coverage only, no return value no verification
360         SIcbreg( si_ctx, SI_CB_SECURITY, test_cb, NULL );
361
362         buf[0] = 0;
363         SIgetaddr( si_ctx, buf );
364         errors += fail_if_true( buf[0] == 0, "get address failed" );
365         fprintf( stderr, "<INFO> get address returns (%s)\n", buf );
366
367         fprintf( stderr, "<INFO> misc module finished with %d errors\n", errors );
368         return errors;
369 }
370
371
372 /*
373         New session (accept) testing.
374 */
375 static int new_sess( ) {
376         int errors = 0;
377         char    buf[1024];
378         struct tp_blk *tpptr;
379         int             status;
380
381         tpptr = SInew( TP_BLK );
382         tpptr->fd = 3;
383         tpptr->flags |= TPF_LISTENFD;
384
385         tpem_set_accept_fd( -1 );                                                                       // accept will "fail" for coverage
386         status = SInewsession( si_ctx, tpptr );
387         errors += fail_if_true( status != SI_ERROR, "newsession did not fail when accept fails" );
388
389         tpem_set_accept_fd( 5 );                                                                        // accept will return a good fd
390         SIcbreg( si_ctx, SI_CB_SECURITY, test_cb_err, NULL );           // register error and drive new session for error coverage
391         status = SInewsession( si_ctx, tpptr );
392         errors += fail_if_true( status >= 0, "newsession did failed when accept was good" );
393
394         tpem_set_accept_fd( 6 );                                                                        // accept will return a good fd
395         SIset_tflags( si_ctx, SI_TF_NODELAY | SI_TF_FASTACK );          // flip options for coverage in new sess
396         SIcbreg( si_ctx, SI_CB_CONN, test_cb, NULL );                           // drive connection for coverage
397         SIcbreg( si_ctx, SI_CB_SECURITY, test_cb, NULL );
398         status = SInewsession( si_ctx, tpptr );
399         errors += fail_if_true( status < 0, "newsession did failed when accept was good" );
400
401         fprintf( stderr, "<INFO> new_sess module finished with %d errors\n", errors );
402         return errors;
403 }
404
405 /*
406         Send tests
407 */
408 static int send_tests( ) {
409         int             errors = 0;
410         char    buf[1024];
411         int             len;
412         int             state;
413
414         len = snprintf( buf, 100, "Heaven knows I'm miserable now!" );
415
416         state = SIsendt( si_ctx, 9999, buf, len );
417         errors += fail_if_true( state >= 0, "send given fd out of range did not fail" );
418
419         state = SIsendt( si_ctx, -1, buf, len );
420         errors += fail_if_true( state >= 0, "send given neg fd did not fail" );
421
422         SIsendt( si_ctx, 6, buf, len );
423
424         tpem_set_send_err( 99 );
425         SIsendt( si_ctx, 6, buf, len );
426
427         tpem_set_send_err( 0 );
428         tpem_set_sel_blk( 1 );
429         SIsendt( si_ctx, 6, buf, len );
430
431         tpem_set_sel_blk( 0 );
432         tpem_set_selef_fd( 6 );                                         // will cause send to fail and fd6 to close
433         SIsendt( si_ctx, 6, buf, len );
434
435         return errors;
436 }
437
438
439 // ----------------------------------------------------------------------------------------
440
441 /*
442         Drive tests...
443 */
444 int main() {
445         int errors = 0;
446
447         rmr_set_vlevel( 5 );                    // enable all debugging
448
449         fprintf( stderr, "\n<INFO> starting SI95 tests\n" );
450
451         errors += init();
452         errors += memory();
453         errors += addr();
454         errors += prep();
455         errors += conn();
456         errors += misc();
457
458         errors += new_sess();           // should leave a "connected" session at fd == 6
459         errors += send_tests();
460
461         errors += poll();
462
463         errors += cleanup();
464
465         test_summary( errors, "SI95 tests" );
466         if( errors == 0 ) {
467                 fprintf( stderr, "<PASS> all tests were OK\n\n" );
468         } else {
469                 fprintf( stderr, "<FAIL> %d errors in SI95 core code\n\n", errors );
470         }
471
472         return !!errors;
473 }