Correct inability to extend payload for rts msg
[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
60 void spew( char* buf, int len ) {
61         int i;
62         char wbuf[1024];                                // slower, but buffer so that mult writers to the tty don't jumble (too much)
63         char bbuf[10];
64
65         wbuf[0] = 0;
66         for( i = 0; i < len; i++ ) {
67                 if( i % 16 == 0 ) {
68                         fprintf( stderr, "%s\n", wbuf );
69                         wbuf[0] = 0;
70                 }
71                 sprintf( bbuf, "%02x ", (unsigned char) *(buf+i) );
72                 strcat( wbuf, bbuf );
73         }
74
75         fprintf( stderr, "%s\n", wbuf );
76 }
77
78 /*
79         Parse n bytes and generate a very simplistic checksum. 
80         Returns the checksum.
81 */
82 static int sum( char* bytes, int len ) {
83         int sum = 0;
84         int     i = 0;
85
86         while( i < len ) {
87                 sum += *(bytes++) + i;
88                 i++;
89         }
90
91         return sum % 255;
92 }
93
94 /*
95         Split the message at the first sep and return a pointer to the first
96         character after.
97 */
98 static char* split( char* str, char sep ) {
99         char*   s;
100
101         s = strchr( str, sep );
102
103         if( s ) {
104                 return s+1;
105         }
106
107         fprintf( stderr, "<RCVR> no pipe in message: (%s)\n", str );
108         return NULL;
109 }
110
111 /*
112         Generate all buffers that will be combined into a single message
113         payload. This is a random set of bytes into payload and then populate
114         the header with the payload length and chksum. The header generated is
115         placed into a fixed length buffer and consists of three values:
116                 checksum result of payload
117                 header size (the fixed size, though info is a string)
118                 payload size
119
120         The message can be validated by computing the checksum of the
121         message after the HDR_SIZE, and comparing that with the value
122         passed.  The values in the header are all ASCII so they can
123         easily be printed on receipt as a debugging step if needed.
124
125         hs_over and ds_over allow the caller to override the header and data
126         size constants if set to a positive number
127
128         The return value is the size of the message payload needed to
129         hold both the header and the payload.
130 */
131 int generate_payload( char* hdr, char* data, int hs_over, int ds_over ) {
132         int i;
133         long r;
134         int sv;
135         int     hsize;
136         int dsize;
137
138         hsize = hs_over <= 0 ? HDR_SIZE : hs_over;              // set values from overrides or defaults
139         dsize = ds_over <= 0 ? DATA_SIZE : ds_over;
140
141         memset( hdr, 0, sizeof( char ) * hsize );
142         for( i = 0; i < dsize; i++ ) {
143                 r = random();
144                 data[i] = r & 0xff;
145         }
146
147         sv = sum( data, dsize ); 
148         snprintf( hdr, sizeof( char ) * hsize, "%d %d %d |", sv, hsize, dsize );
149
150         return hsize + dsize;
151 }
152
153 /*
154         Generate a header for a given payload buffer. THe header size and data size
155         override values default to the HDR_SIZE and DATA_SIZE constants if a value
156         is <= 0; The data is checksummed and  the header buffer is populated
157         (see generate_payload() for detailed description.
158
159         The return is the number of bytes required for the full payload of both
160         header and data.
161 */
162 int generate_header( char* hdr, char* data, int hs_over, int ds_over ) {
163         int sv;
164         int     hsize;
165         int dsize;
166         int     wrote;
167
168         hsize = hs_over <= 0 ? HDR_SIZE : hs_over;              // set values from overrides or defaults
169         dsize = ds_over <= 0 ? DATA_SIZE : ds_over;
170
171         memset( hdr, 0, sizeof( char ) * hsize );
172         sv = sum( data, dsize ); 
173         wrote = snprintf( hdr, sizeof( char ) * hsize, "%d %d %d |", sv, hsize, dsize );
174         if( wrote >= hsize ) {
175                 fprintf( stderr, "<ERR>  header overflow\n" );
176                 hdr[hsize-1] = 0;
177         }
178
179         return hsize + dsize;
180 }
181
182 /*
183         Convenience function to push a header/data into an RMR mbuf. It is assumed that the
184         mbuf is large enough; no checks are made. If either length is <= 0, then the 
185         default (constant value) is used.
186 */
187 void fill_payload( rmr_mbuf_t* msg, char* hdr, int hdr_len, char *data, int data_len ) {
188         char*   payload;
189
190         if( msg == NULL ) {
191                 fprintf( stderr, "<TEST> fill payload: msg passed in was nil\n" );
192                 return;
193         }
194
195         hdr_len = hdr_len <= 0 ? HDR_SIZE : hdr_len;            // set values from input; else use defaults
196         data_len = data_len <= 0 ? DATA_SIZE : data_len;
197
198         if( hdr_len <= 0 || data_len <= 0 ) {
199                 fprintf( stderr, "<TEST> fill payload: header or date len invalid: hdr=%d data=%d\n", hdr_len, data_len );
200                 return;
201         }
202
203         payload = msg->payload;
204
205         memcpy( payload, hdr, hdr_len > 0 ? hdr_len : HDR_SIZE );
206         payload += hdr_len;
207         memcpy( payload, data, data_len > 0 ? data_len : DATA_SIZE );
208 }
209
210 /*
211         This function accepts an RMR message payload assumed to be header and user data,  in the 
212         format: <hdr><data> where <hdr> consists of a string with three space separated values:
213                 checksum
214                 hdr size
215                 data size
216
217         Validation is:
218                 ensure that the rmr_len matches the header size and data size which are parsed from
219                 the message.  If sizes match, a checksum is performed on the data and the result
220                 compared to the checksum value in the header.
221 */
222 int validate_msg( char* buf, int rmr_len ) {
223         char*   tok;
224         char*   tok_mark = NULL;
225         char*   search_start;
226         char*   ohdr = NULL;    // original header as we trash the header parsing it
227         int             ex_sv;                  // expected checksum value (pulled from received header)
228         int             sv;                             // computed checksum value
229         int             ex_mlen = 0;    // expected msg_len (computed from the header, compared with rmr_len)
230         int             hdr_len;                // length of header to skip
231         int             data_len;               // length of data received
232         int             i;
233         int             good = 0;
234
235         if( buf == 0 && rmr_len <= 0 ) {
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, 64 );
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 = buf;
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, "[CONT] header isn't printable\n" );
287                         spew( ohdr, 64 );
288                 } else {
289                         fprintf( stderr, "[CONT] header: (%s)\n", ohdr );
290                         fprintf( stderr, "[CONT] 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, "[FAIL] 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