Beef up tests to the extended header functions
[ric-plt/lib/rmr.git] / test / app_test / test_support.c
1 // :vim ts=4 sw=4 noet:
2 /*
3 ==================================================================================
4         Copyright (c) 2019 Nokia
5         Copyright (c) 2018-2019 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         Mnemonic:       test_support.c
23         Abstract:       Support functions for app test programmes.
24
25                                         sum() compute a simple checksum over a buffer
26                                         split() split an ascii buffer at the first |
27                                         generate_payload() build a header and data buffer generate
28                                                 a random data buffer with a header containing
29                                                 the checksum, and lengths.
30                                         validate_msg() given a message of <hdr><data> validate
31                                                 that the message is the correct length and chk sum.
32
33         Date:           28 October 2019
34         Author:         E. Scott Daniels
35 */
36
37 #include <ctype.h>
38
39 #ifndef _supp_tools_c
40 #define _supp_tools_c
41
42 #ifndef DEBUG
43 #define DEBUG 0
44 #endif
45
46 // defaults if the test app doesn't set these
47 #ifndef HDRSIZE
48 #define HDR_SIZE 64                                                     // the size of the header we place into the message
49 #endif 
50
51 #ifndef MSG_SIZE
52 #define MSG_SIZE 1024                                           // the size of the message that will be sent (hdr+payload)
53 #endif
54
55 #ifndef DATA_SIZE
56 #define DATA_SIZE (HDR_SIZE-HDR_SIZE)           // the actual 'data' length returned in the ack msg
57 #endif
58
59 void spew( char* buf, int len ) {
60         int i;
61         char wbuf[1024];                                // slower, but buffer so that mult writers to the tty don't jumble (too much)
62         char bbuf[10];
63
64         wbuf[0] = 0;
65         for( i = 0; i < len; i++ ) {
66                 if( i % 16 == 0 ) {
67                         fprintf( stderr, "%s\n", wbuf );
68                         wbuf[0] = 0;
69                 }
70                 sprintf( bbuf, "%02x ", (unsigned char) *(buf+i) );
71                 strcat( wbuf, bbuf );
72         }
73
74         fprintf( stderr, "%s\n", wbuf );
75 }
76
77 /*
78         Parse n bytes and generate a very simplistic checksum. 
79         Returns the checksum.
80 */
81 static int sum( char* bytes, int len ) {
82         int sum = 0;
83         int     i = 0;
84
85         while( i < len ) {
86                 sum += *(bytes++) + i;
87                 i++;
88         }
89
90         return sum % 255;
91 }
92
93 /*
94         Split the message at the first sep and return a pointer to the first
95         character after.
96 */
97 static char* split( char* str, char sep ) {
98         char*   s;
99
100         s = strchr( str, sep );
101
102         if( s ) {
103                 return s+1;
104         }
105
106         fprintf( stderr, "<RCVR> no pipe in message: (%s)\n", str );
107         return NULL;
108 }
109
110 /*
111         Generate all buffers that will be combined into a single message
112         payload. This is a random set of bytes into payload and then populate
113         the header with the payload length and chksum. The header generated is
114         placed into a fixed length buffer and consists of three values:
115                 checksum result of payload
116                 header size (the fixed size, though info is a string)
117                 payload size
118
119         The message can be validated by computing the checksum of the
120         message after the HDR_SIZE, and comparing that with the value
121         passed.  The values in the header are all ASCII so they can
122         easily be printed on receipt as a debugging step if needed.
123
124         hs_over and ds_over allow the caller to override the header and data
125         size constants if set to a positive number
126
127         The return value is the size of the message payload needed to
128         hold both the header and the payload.
129 */
130 int generate_payload( char* hdr, char* data, int hs_over, int ds_over ) {
131         int i;
132         long r;
133         int sv;
134         int     hsize;
135         int dsize;
136
137         hsize = hs_over <= 0 ? HDR_SIZE : hs_over;              // set values from overrides or defaults
138         dsize = ds_over <= 0 ? DATA_SIZE : ds_over;
139
140         memset( hdr, 0, sizeof( char ) * hsize );
141         for( i = 0; i < dsize; i++ ) {
142                 r = random();
143                 data[i] = r & 0xff;
144         }
145
146         sv = sum( data, dsize ); 
147         snprintf( hdr, sizeof( char ) * hsize, "%d %d %d |", sv, hsize, dsize );
148
149         return hsize + dsize;
150 }
151
152 /*
153         Generate a header for a given payload buffer. THe header size and data size
154         override values default to the HDR_SIZE and DATA_SIZE constants if a value
155         is <= 0; The data is checksummed and  the header buffer is populated
156         (see generate_payload() for detailed description.
157
158         The return is the number of bytes required for the full payload of both
159         header and data.
160 */
161 int generate_header( char* hdr, char* data, int hs_over, int ds_over ) {
162         int sv;
163         int     hsize;
164         int dsize;
165         int     wrote;
166
167         hsize = hs_over <= 0 ? HDR_SIZE : hs_over;              // set values from overrides or defaults
168         dsize = ds_over <= 0 ? DATA_SIZE : ds_over;
169
170         memset( hdr, 0, sizeof( char ) * hsize );
171         sv = sum( data, dsize ); 
172         wrote = snprintf( hdr, sizeof( char ) * hsize, "%d %d %d |", sv, hsize, dsize );
173         if( wrote >= hsize ) {
174                 fprintf( stderr, "<ERR>  header overflow\n" );
175                 hdr[hsize-1] = 0;
176         }
177
178         return hsize + dsize;
179 }
180
181 /*
182         Convenience function to push a header/data into an RMR mbuf. It is assumed that the
183         mbuf is large enough; no checks are made. If either length is <= 0, then the 
184         default (constant value) is used.
185 */
186 void fill_payload( rmr_mbuf_t* msg, char* hdr, int hdr_len, char *data, int data_len ) {
187         char*   payload;
188
189         if( msg == NULL ) {
190                 fprintf( stderr, "<TEST> fill payload: msg passed in was nil\n" );
191                 return;
192         }
193
194         hdr_len = hdr_len <= 0 ? HDR_SIZE : hdr_len;            // set values from input; else use defaults
195         data_len = data_len <= 0 ? DATA_SIZE : data_len;
196
197         if( hdr_len <= 0 || data_len <= 0 ) {
198                 fprintf( stderr, "<TEST> fill payload: header or date len invalid: hdr=%d data=%d\n", hdr_len, data_len );
199                 return;
200         }
201
202         payload = msg->payload;
203
204         memcpy( payload, hdr, hdr_len > 0 ? hdr_len : HDR_SIZE );
205         payload += hdr_len;
206         memcpy( payload, data, data_len > 0 ? data_len : DATA_SIZE );
207 }
208
209 /*
210         This function accepts an RMR message payload assumed to be header and user data,  in the 
211         format: <hdr><data> where <hdr> consists of a string with three space separated values:
212                 checksum
213                 hdr size
214                 data size
215
216         Validation is:
217                 ensure that the rmr_len matches the header size and data size which are parsed from
218                 the message.  If sizes match, a checksum is performed on the data and the result
219                 compared to the checksum value in the header.
220 */
221 int validate_msg( char* buf, int rmr_len ) {
222         char*   tok;
223         char*   tok_mark = NULL;
224         char*   search_start;
225         char*   ohdr = NULL;    // original header as we trash the header parsing it
226         int             ex_sv;                  // expected checksum value (pulled from received header)
227         int             sv;                             // computed checksum value
228         int             ex_mlen = 0;    // expected msg_len (computed from the header, compared with rmr_len)
229         int             hdr_len;                // length of header to skip
230         int             data_len;               // length of data received
231         int             i;
232         int             good = 0;
233
234         if( buf == 0 && rmr_len <= 0 ) {
235                 fprintf( stderr, "<TEST> validate msg: nil buffer or no len: %p len=%d\n", buf, rmr_len );
236                 return 0;
237         }
238
239         for( i = 0; i < HDR_SIZE; i++ ) {               // for what we consider the dfault header, we must see ALL ascci and a trail zero before end
240                 if( *(buf+i) == 0 ) {
241                         good = 1;
242                         break;
243                 }
244
245                 if( ! isprint( *buf ) ) {  // we expect the header to be a zero terminated string
246                         fprintf( stderr, "<TEST> validate msg: header is not completely ASCII i=%d\n", i );
247                         spew( buf, rmr_len > 64 ? 64 : rmr_len );
248                         return 0;
249                 }
250         }
251
252         if( ! good ) {
253                 fprintf( stderr, "<TEST> validate msg: didn't find an acceptable header (not nil terminated)\n" );
254                 return 0;
255         }
256
257         ohdr = strdup( buf );           // must copy so we can trash
258
259         search_start = ohdr;
260         for( i = 0; i < 3; i++ ) {
261                 tok = strtok_r( search_start, " ", &tok_mark );
262                 search_start = NULL;
263                 if( tok ) {
264                         switch( i ) {
265                                 case 0:
266                                         ex_sv = atoi( tok );
267                                         break;
268
269                                 case 1:
270                                         hdr_len = atoi( tok );          // capture header length        
271                                         ex_mlen = hdr_len;                      // start to compute total msg len
272                 
273                                         break;
274
275                                 case 2:
276                                         data_len = atoi( tok );         // add data length      
277                                         ex_mlen += data_len;
278                                         break;
279                         }
280                 }
281         }
282
283         if( ex_mlen != rmr_len ) {
284                 fprintf( stderr, "[FAIL] received message length did not match hdr+data lengths, rmr_len=%d data follows:\n", rmr_len );
285                 if( ! isprint( *ohdr ) ) {
286                         fprintf( stderr, "<TEST> validate msg: header isn't printable\n" );
287                         spew( ohdr, rmr_len > 64 ? 64 : rmr_len );
288                 } else {
289                         fprintf( stderr, "<TEST> validate msg: header: (%s)\n", ohdr );
290                         fprintf( stderr, "<TEST> validate msg: computed length: %d (expected)\n", ex_mlen );
291                 }
292                 free( ohdr );
293                 return 0;
294         }
295
296         if( DEBUG ) {
297                 fprintf( stderr, "[OK]  message lengths are good\n" );
298         }
299                 
300         tok = buf + hdr_len;
301         //fprintf( stderr, ">>>> computing chksum starting at %d for %d bytes\n", hdr_len, data_len );
302         sv = sum( tok, data_len );                      // compute checksum of data portion
303
304         if( sv != ex_sv ) {
305                 fprintf( stderr, "<TEST> validate msg:  data checksum mismatch, got %d, expected %d. header: %s\n", sv, ex_sv, ohdr );
306                 free( ohdr );
307                 return 0;
308         }
309         
310         free( ohdr );
311         return 1;       
312 }
313
314
315 #endif