blob: 44c4e0f6da74e7efab0abc82d94cef71b382f05f [file] [log] [blame]
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -05001/*
2==================================================================================
3 Copyright (c) 2020 Nokia
4 Copyright (c) 2020 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_si95_em.c
22 Abstract: This supplies a bunch of dummy SI95 functions which emulate
23 the sending/receiving of data such that modules can be tested
24 without the acutal backing of a network.
25
26 This module must be directly included to be used.
27 Date: 20 February 2020
28 Author: E. Scott Daniels
29*/
30
31
32#include "rmr.h" // we use some of rmr defs in building dummy messages, so we need these
33#include "rmr_agnostic.h"
34
E. Scott Danielse15b1382020-04-14 15:55:13 -040035// ---------------------- emulated SI95 functions ---------------------------
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -050036
37
38#ifndef _em_si // this is the same define as the nng emulation code uses to give warning if both included
39#define _em_si
40
41#include <arpa/inet.h>
42#include <pthread.h>
43
44#include "test_common_em.c" // common emulation needed for all (epoll, gethostname...)
45
E. Scott Danielse15b1382020-04-14 15:55:13 -040046// --- some globals --------------------------------------------------------
47int em_reset_call_flag = 0; // allows a send to turn off the call flag (see em_disable_call_flg())
48
49// ------------- emulated message header -----------------------------------
50
51/*
52 This is a copy from agnostic.h. we need to reset flags in some situations
53 so we have to have this, under a different name to avoid disaster.
54*/
55typedef struct {
56 int32_t mtype; // message type ("long" network integer)
57 int32_t plen; // payload length (sender data length in payload)
58 int32_t rmr_ver; // our internal message version number
59 unsigned char xid[RMR_MAX_XID]; // space for user transaction id or somesuch
60 unsigned char sid[RMR_MAX_SID]; // sender ID for return to sender needs
61 unsigned char src[RMR_MAX_SRC]; // name:port of the sender (source)
62 unsigned char meid[RMR_MAX_MEID]; // managed element id.
63 struct timespec ts; // timestamp ???
64
65 // V2 extension
66 int32_t flags; // HFL_* constants
67 int32_t len0; // length of the RMr header data
68 int32_t len1; // length of the tracing data
69 int32_t len2; // length of data 1 (d1)
70 int32_t len3; // length of data 2 (d2)
71 int32_t sub_id; // subscription id (-1 invalid)
72
73 // v3 extension
74 unsigned char srcip[RMR_MAX_SRC]; // ip address and port of the source
75} em_mhdr_t;
76
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -050077//--------------------------------------------------------------------------
78/*
79 These are the current references in the RMR code; all others are internal
80 to the SI portion of the library
81
82 SIcbreg( ctx->si_ctx,
83 SIwait( ctx->si_ctx );
84 SIinitialise( SI_OPT_FG ); // FIX ME: si needs to streamline and drop fork/bg stuff
85 SIlistener( ctx->si_ctx, TCP_DEVICE, bind_info )) < 0 ) {
86 SItp_stats( ctx->si_ctx ); // dump some interesting stats
87 SIclose( ctx->nn_sock );
88 SIset_tflags( ctx->si_ctx, SI_TF_FASTACK );
89 SIconnect( si_ctx, conn_info )) < 0 ) {
90 SIsendt( ctx->si_ctx, nn_sock, msg->tp_buf, tot_len )) != SI_OK ) {
91*/
92
93#define SIEM_BLOCKED 18
94#define SIEM_ERROR (-1)
95#define SIEM_OK 0
96
97#define SOCKET_TYPE int // socket representation is different in each transport
98
99struct ginfo_blk; // defined in SI things, but must exist here
100
101#include "si95/socket_if.h" // need to have the si context more than anything else
102
103
104static void *em_sinew( int type ) {
105 return NULL;
106}
107
108static char *em_sigetname( int sid ) {
109 return "somename";
110}
111
112static int em_siaddress( void *src, void **dest, int type ) {
113 return 0;
114}
115
116static void em_sibldpoll( struct ginfo_blk* gptr ) {
117 return;
118}
119
120static struct tp_blk *em_siconn_prep( struct ginfo_blk *gptr, int type, char *abuf, int family ) {
121 return NULL;
122}
123
124/*
125 Caller passing a callback funciton for SI to drive; nothing to do.
126*/
127void *em_cb_data = NULL;
128static void em_sicbreg( struct ginfo_blk *gptr, int type, int ((*fptr)()), void * dptr ) {
129 if( em_cb_data == NULL ) {
E. Scott Danielsc113b082020-04-08 15:44:40 -0400130 fprintf( stderr, "<SIEM> calldback dptr %p saved for type %d\n", dptr, type );
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -0500131 em_cb_data = dptr;
132 }
133 return;
134}
135
136static void em_sicbstat( struct ginfo_blk *gptr, int status, int type ) {
137 return;
138}
139
140static int em_siclose( struct ginfo_blk *gptr, int fd ) {
141 return 0;
142}
143
144/*
145 If em_send_failures is true, this will fail a small part of the time
146 to simualte connection failures.
E. Scott Daniels26864552021-02-22 14:42:21 -0500147
148 If the port number is < 1000 it will fail -- allowing for specific,single
149 failure cases.
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -0500150*/
151static int em_next_fd = 0;
152static int em_siconnect( struct ginfo_blk *gptr, char *abuf ) {
153 static int count = 0;
E. Scott Daniels26864552021-02-22 14:42:21 -0500154 char* tok;
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -0500155
156 if( em_send_failures && (count++ % 15 == 14) ) {
157 //fprintf( stderr, "<SIEM> siem is failing connect attempt\n\n" );
158 return -1;
159 }
160
E. Scott Daniels26864552021-02-22 14:42:21 -0500161 if( (tok = strchr( abuf, ':' )) != NULL && atoi( tok+1 ) < 1000 ) {
162 fprintf( stderr, "<SIEM> siem is emulating connect to (%s) with a failure; port <1000\n", abuf );
163 return -1;
164 }
165
E. Scott Danielse15b1382020-04-14 15:55:13 -0400166 fprintf( stderr, "<SIEM> siem is emulating connect to (%s) attempt return fd=%d\n", abuf, em_next_fd );
167 if( em_next_fd < 50 ) {
168 em_next_fd++;
169 }
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -0500170 return em_next_fd-1;
171}
172
173static struct tp_blk *em_siestablish( int type, char *abuf, int family ) {
174 return NULL;
175}
176
177static int em_sigenaddr( char *target, int proto, int family, int socktype, struct sockaddr **rap ) {
178 return 0;
179}
180
181static int em_sigetaddr( struct ginfo_blk *gptr, char *buf ) {
182 return 0;
183}
184
E. Scott Daniels05850e02020-11-11 15:57:22 -0500185static struct tp_blk *em_silisten_prep( int type, char* abuf, int family ) {
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -0500186 return NULL;
187}
188
189/*
190 Called to open a listen port; returns the port fd or -1 on error.
191*/
192static int em_silistener( struct ginfo_blk *gptr, int type, char *abuf ) {
193 return 100;
194}
195
196static void em_simap_fd( struct ginfo_blk *gptr, int fd, struct tp_blk* tpptr ) {
197 return;
198}
199
200static int em_sinewsession( struct ginfo_blk *gptr, struct tp_blk *tpptr ) {
201 return 0;
202}
203
204static int em_sipoll( struct ginfo_blk *gptr, int msdelay ) {
205 return 0;
206}
207
208static int em_sircv( struct ginfo_blk *gptr, int sid, char *buf, int buflen, char *abuf, int delay ) {
209 return 0;
210}
211
212static void em_sisend( struct ginfo_blk *gptr, struct tp_blk *tpptr ) {
213 return;
214}
215
E. Scott Danielse15b1382020-04-14 15:55:13 -0400216/*
217 Calling this function causes the send emulation to turn off the call
218 flag in the RMR header. Turning that flag off makes the arriving message
219 look as though it might be a response to a call rather than a call itself.
220 This is needed since we loop back messages.
221*/
222static void em_disable_call_flg() {
223 em_reset_call_flag = 1;
224 fprintf( stderr, "<SIEM> reset call flag setting is: %d\n", em_reset_call_flag );
225}
226
227/*
228 Opposite of disable_call_flg; the flag is not touched.
229*/
230static void em_allow_call_flg() {
231 em_reset_call_flag = 0;
232 fprintf( stderr, "<SIEM> reset call flag setting is: %d\n", em_reset_call_flag );
233}
234
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -0500235// callback prototype to drive to simulate 'receive'
236static int mt_data_cb( void* datap, int fd, char* buf, int buflen );
E. Scott Danielse15b1382020-04-14 15:55:13 -0400237
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -0500238/*
239 Emulate sending a message. If the global em_send_failures is set,
240 then every so often we fail with an EAGAIN to drive that part
241 of the code in RMr.
242
243 "Send a message" by passing it to the callback if we have a non-nil cb data pointer.
244 We'll divide the data into two to test the concatination of the receiver.
245*/
246static int em_sisendt( struct ginfo_blk *gptr, int fd, char *ubuf, int ulen ) {
247 static int count = 0;
248 static int uss = -1; // ultra short send done
249
250 if( em_send_failures && ((count++ % 15) == 14) ) {
251 //fprintf( stderr, "<SIEM> sendt is failing send with blocked/again\n\n" );
252 errno = EAGAIN;
253 return SIEM_BLOCKED;
254 }
255
E. Scott Danielse15b1382020-04-14 15:55:13 -0400256 if( em_reset_call_flag ) { // for call testing we need to flip the flag off to see it "return"
257 em_mhdr_t* hdr;
258
259 hdr = (em_mhdr_t *) (ubuf+50); // past the transport header bytes
260 hdr->flags &= ~HFL_CALL_MSG; // flip off the call flag
261 }
262
E. Scott Danielsfc5c77b2020-02-21 13:24:29 -0500263 uss++;
264
265 if( em_cb_data != NULL ) {
266 if( uss == 1 ) { // drive the reconstruction where a split in the msg length happens
267 fprintf( stderr, "<SIEM> sendt is queuing ultra short first packet of a two packet sendh len=%d\n", ulen );
268 mt_data_cb( em_cb_data, 0, ubuf, 3 );
269 mt_data_cb( em_cb_data, 0, ubuf+3, ulen - 3 );
270 } else {
271 if( ulen > 100 ) {
272 fprintf( stderr, "<SIEM> sendt is queuing two packets with the callback len=%d\n", ulen );
273 mt_data_cb( em_cb_data, 0, ubuf, 100 );
274 mt_data_cb( em_cb_data, 0, ubuf+100, ulen - 100 );
275 } else {
276 fprintf( stderr, "<SIEM> sendt is queuing one packet with the callback len=%d\n", ulen );
277 mt_data_cb( em_cb_data, 0, ubuf, ulen );
278 }
279 }
280 }
281
282 errno = 0;
283 //fprintf( stderr, "<SIEM> sendt is returning default reeturn status: %d\n", return_value );
284 return return_value;
285}
286
287/*
288 Sets flags; ignore.
289*/
290static void em_siset_tflags( struct ginfo_blk *gp, int flags ) {
291 return;
292}
293
294static int em_sishow_version( ) {
295 return 0;
296}
297
298static void em_sishutdown( struct ginfo_blk *gptr ) {
299 return;
300}
301
302/*
303 This prints some SI stats -- ignore.
304*/
305static void em_sitp_stats( void *vgp ) {
306 return;
307}
308
309static void em_siterm( struct ginfo_blk* gptr, struct tp_blk *tpptr ) {
310 return;
311}
312
313static void em_sitrash( int type, void *bp ) {
314 return;
315}
316
317/*
318 This will be tricky. Wait receives raw packets from the network
319 and drives the callback(s) which are registered. We'll need to
320 simulate driving the callback with data that spans multiple FDs
321 and has messages split across buffers, but does not block foreaver
322 so the test can continue.
323 It won't be pretty.
324
325 For now We'll hard code the RMR callback functions and not
326 try to use what it passes via the register function lest we
327 need to implement all of SI just to run unit tests.
328
329
330 Thinking: use rmr's alloc function to alloc a message buffer
331 which we fill in. We can cheat and add the length as RMR does
332 on send, and then split the buffer as we feed it back to the
333 callback function.
334*/
335static int em_siwait( struct ginfo_blk *gptr ) {
336 return 0;
337}
338
339/*
340 The emulation doesn't use the global info stuff, so alloc something
341 to generate a pointer.
342*/
343static struct ginfo_blk *em_siinitialise( int opts ) {
344 void *p;
345
346 p = malloc( 1024 );
347 return p;
348}
349
350
351// redefine all SI calls to reference functions here.
352#define SInew em_sinew
353#define sigetname em_sigetname
354#define SIaddress em_siaddress
355#define SIbldpoll em_sibldpoll
356#define SIconn_prep em_siconn_prep
357#define SIcbreg em_sicbreg
358#define SIcbstat em_sicbstat
359//#define SIclose em_siclose
360#define SIconnect em_siconnect
361#define SIestablish em_siestablish
362#define SIgenaddr em_sigenaddr
363#define SIgetaddr em_sigetaddr
364#define SIlisten_prep em_silisten_prep
365#define SIlistener em_silistener
366#define SImap_fd em_simap_fd
367#define SInewsession em_sinewsession
368#define SIpoll em_sipoll
369#define SIrcv em_sircv
370#define SIsend em_sisend
371#define SIsendt em_sisendt
372#define SIset_tflags em_siset_tflags
373#define SIshow_version em_sishow_version
374#define SIshutdown em_sishutdown
375#define SItp_stats em_sitp_stats
376#define SIterm em_siterm
377#define SItrash em_sitrash
378#define SIwait em_siwait
379#define SIinitialise em_siinitialise
380
381
382#endif