Address code analysis issues
[ric-plt/lib/rmr.git] / src / rmr / common / src / mbuf_api.c
1 // : vi 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:       mbuf_api.c
23         Abstract:       These are common functions which work only on the mbuf and
24                                 thus (because they do not touch an endpoint or context)
25                                 can be agnostic to the underlying transport, or the transport
26                                 layer provides a transport specific function (e.g. payload
27                                 reallocation).
28
29         Author:         E. Scott Daniels
30         Date:           8 February 2019
31 */
32
33 #include <stdlib.h>
34 #include <netdb.h>                      // uint* types
35 #include <errno.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <stdio.h>
39 #include <semaphore.h>
40
41 #include "rmr.h"                                // things the users see
42 #include "rmr_agnostic.h"               // agnostic things (must be included before private)
43 #include "rmr_logging.h"
44
45 //#define BUF_TOOLS_ONLY 1
46 #include "tools_static.c"
47
48
49 // ---------- some wrappers need explicit copy-in functions, also header field setters -----
50
51 /*
52         Allow the user programme to set the meid in the header.  The meid is a fixed
53         length buffer in the header and thus we must ensure it is not overrun. If
54         the  user gives a source buffer that is too large, we truncate. The return
55         value is the number of bytes copied, or -1 for absolute failure (bad pointer
56         etc.).  Errno is set:
57                 EINVAL id poitner, buf or buf header are bad.
58                 EOVERFLOW if the bytes given would have overrun
59
60         We have been told that the meid will be a string, so we enforce that even if
61         the user is copying in bytes.  We will add a 0 byte at len+1 when len is less
62         than the field size, or as the last byte (doing damage to their string) if
63         the caller didn't play by the rules. If they pass a non-nil terminated set
64         of bytes which are the field length, we'll indicate truncation.
65
66 */
67 extern int rmr_bytes2meid( rmr_mbuf_t* mbuf, unsigned char const* src, int len ) {
68         uta_mhdr_t* hdr;
69
70         if( src == NULL  ||  mbuf == NULL || mbuf->header == NULL ) {
71                 errno = EINVAL;
72                 return -1;
73         }
74
75         errno = 0;
76         if( len > RMR_MAX_MEID ) {
77                 len = RMR_MAX_MEID;
78                 errno = EOVERFLOW;
79         }
80
81         hdr = (uta_mhdr_t *) mbuf->header;
82         memcpy( hdr->meid, src, len );
83
84         if( len == RMR_MAX_MEID ) {
85                 if( *(hdr->meid+len-1) != 0 ) {
86                         *(hdr->meid+len-1) = 0;
87                         errno = EOVERFLOW;
88                 }
89         } else {
90                 *(hdr->meid+len) = 0;
91         }
92
93         return len;
94 }
95
96 /*
97         Allows the user programme to set the meid from a string. The end of string
98         (nil) will be included UNLESS the total length including the end of string
99         would exceed the size of the space in the header for the meid.  The return
100         value is RMR_OK for success and !RMR_OK on failure. Errno will be set
101         on error.
102 */
103 extern int rmr_str2meid( rmr_mbuf_t* mbuf, unsigned char const* str ) {
104         int len;                // len moved -- we do validate
105
106         if( str == NULL  ||  mbuf == NULL || mbuf->header == NULL ) {
107                 errno = EINVAL;
108                 return RMR_ERR_BADARG;
109         }
110
111         errno = 0;
112         if( (len = strlen( (char *) str )) > RMR_MAX_MEID-1 ) {
113                 errno = EOVERFLOW;
114                 return RMR_ERR_OVERFLOW;
115         }
116
117         rmr_bytes2meid( mbuf, str, len+1 );
118         return RMR_OK;
119 }
120
121
122
123 /*
124         This will copy n bytes from source into the payload. If len is larger than
125         the payload only the bytes which will fit are copied, The user should
126         check errno on return to determine success or failure.
127 */
128 extern void rmr_bytes2payload( rmr_mbuf_t* mbuf, unsigned char const* src, int len ) {
129         if( src == NULL  ||  mbuf == NULL || mbuf->payload == NULL ) {
130                 errno = EINVAL;
131                 return;
132         }
133
134         errno = 0;
135         mbuf->state = RMR_OK;
136         if( len > mbuf->alloc_len - sizeof( uta_mhdr_t ) ) {
137                 mbuf->state = RMR_ERR_OVERFLOW;
138                 errno = EMSGSIZE;
139                 len = mbuf->alloc_len - sizeof( uta_mhdr_t );
140         }
141
142         mbuf->len = len;
143         memcpy( mbuf->payload, src, len );
144 }
145
146 /*
147         This will copy a nil terminated string to the mbuf payload. The buffer length
148         is set to the string length.
149 */
150 extern void rmr_str2payload( rmr_mbuf_t* mbuf, unsigned char const* str ) {
151         rmr_bytes2payload( mbuf, str, strlen( (char *) str ) + 1 );
152 }
153
154
155 /*
156         Allow the user programme to set the xaction field in the header.  The xaction
157         is a fixed length buffer in the header and thus we must ensure it is not overrun.
158         If the  user gives a source buffer that is too large, we truncate. The return
159         value is the number of bytes copied, or -1 for absolute failure (bad pointer
160         etc.).  Errno is set:
161                 EINVAL id poitner, buf or buf header are bad.
162                 EOVERFLOW if the bytes given would have overrun
163
164 */
165 extern int rmr_bytes2xact( rmr_mbuf_t* mbuf, unsigned char const* src, int len ) {
166         uta_mhdr_t* hdr;
167
168         if( src == NULL  ||  mbuf == NULL || mbuf->header == NULL ) {
169                 errno = EINVAL;
170                 return -1;
171         }
172
173         errno = 0;
174         if( len > RMR_MAX_XID ) {
175                 len = RMR_MAX_XID;
176                 errno = EOVERFLOW;
177         }
178
179         hdr = (uta_mhdr_t *) mbuf->header;
180         memcpy( hdr->xid, src, len );
181
182         return len;
183 }
184
185
186
187 /*
188         Allows the user programme to set the xaction (xid) field from a string. The end
189         of string (nil) will be included UNLESS the total length including the end of string
190         would exceed the size of the space in the header for the xaction.  The return
191         value is RMR_OK for success and !RMR_OK on failure. Errno will be set
192         on error.
193 */
194 extern int rmr_str2xact( rmr_mbuf_t* mbuf, unsigned char const* str ) {
195         int len;                // len moved -- we do validate
196
197         if( str == NULL  ||  mbuf == NULL || mbuf->header == NULL ) {
198                 errno = EINVAL;
199                 return RMR_ERR_BADARG;
200         }
201
202         errno = 0;
203         if( (len = strlen( (char *) str )) > RMR_MAX_XID-1 ) {
204                 errno = EOVERFLOW;
205                 return RMR_ERR_OVERFLOW;
206         }
207
208         rmr_bytes2xact( mbuf, str, len+1 );
209         return RMR_OK;
210 }
211
212 /*
213         Extracts the transaction bytes from the header and places into a
214         user supplied buffer (dest). The buffer must be at least RMR_MAX_XID
215         bytes in length as this function will copy the entire field (even if
216         the sender saved a shorter "string." If the user supplies a nil poniter
217         as the destination, a buffer is allocated; the caller must free when
218         finished.  The buffer will be exactly RMR_MAX_XID bytes long.
219
220         The return value is a pointer to the buffer that was filled (to
221         the dest buffer provided, or the buffer we allocated). If there is an
222         error, a nil pointer is returned, and errno should suggest the root
223         cause of the issue (invalid message or no memory).
224 */
225 extern unsigned char*  rmr_get_xact( rmr_mbuf_t* mbuf, unsigned char* dest ) {
226         errno = 0;
227
228         if( mbuf == NULL || mbuf->xaction == NULL ) {
229                 errno = EINVAL;
230                 return NULL;
231         }
232
233         if( ! dest ) {
234                 if( (dest = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_XID )) == NULL ) {
235                         errno = ENOMEM;
236                         return NULL;
237                 }
238         }
239
240         memcpy( dest, mbuf->xaction, RMR_MAX_XID );
241
242         return dest;
243 }
244
245 /*
246         Extracts the meid (managed entity) from the header and copies the bytes
247         to the user supplied area. If the user supplied pointer is nil, then
248         a buffer will be allocated and it is the user's responsibilty to free.
249         A pointer is returned to the destination memory (allocated or not)
250         for consistency. If the user programme supplies a destination it is
251         the responsibility of the programme to ensure that the space is large
252         enough.
253 */
254 extern unsigned char*  rmr_get_meid( rmr_mbuf_t* mbuf, unsigned char* dest ) {
255         uta_mhdr_t* hdr;
256
257         errno = 0;
258
259         if( mbuf == NULL || mbuf->header == NULL ) {
260                 errno = EINVAL;
261                 return NULL;
262         }
263
264         if( ! dest ) {
265                 if( (dest = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_MEID )) == NULL ) {
266                         errno = ENOMEM;
267                         return NULL;
268                 }
269         }
270
271         hdr = (uta_mhdr_t *) mbuf->header;
272         memcpy( dest, hdr->meid, RMR_MAX_MEID );
273
274         return dest;
275 }
276
277 // ------------------- trace related access functions --------------------------------------
278 /*
279         The set_trace function will copy the supplied data for size bytes into the
280         header.  If the header trace area is not large enough, a new one will be allocated
281         which will cause a payload copy based on the msg->len value (if 0 no payload
282         data is copied).
283
284         The return value is the number of bytes actually coppied. If 0 bytes are coppied
285         errno should indicate the reason. If 0 is returned and errno is 0, then size
286         passed was 0.  The state in the message is left UNCHANGED.
287 */
288 extern int rmr_set_trace( rmr_mbuf_t* msg, unsigned const char* data, int size ) {
289         uta_mhdr_t*     hdr;
290         rmr_mbuf_t* nm;                 // new message if larger is needed
291         int             len;
292         void*   old_tp_buf;             // if we need to realloc, must hold old to free
293         void*   old_hdr;
294
295         if( msg == NULL ) {
296                 errno = EINVAL;
297                 return 0;
298         }
299
300         errno = 0;
301         if( size <= 0 ) {
302                 return 0;
303         }
304
305         hdr = (uta_mhdr_t *) msg->header;
306         if( !hdr ) {
307                 errno = EINVAL;
308                 return 0;
309         }
310
311         len = RMR_TR_LEN( hdr );
312
313         if( len != size ) {                                                     // different sized trace data, must realloc the buffer
314                 nm = rmr_realloc_msg( msg, size );              // realloc with changed trace size
315                 old_tp_buf = msg->tp_buf;
316                 old_hdr = msg->header;
317
318                 msg->tp_buf = nm->tp_buf;                               // reference the reallocated buffer
319                 msg->header = nm->header;
320                 msg->id = NULL;                                                 // currently unused
321                 msg->xaction = nm->xaction;
322                 msg->payload = nm->payload;
323
324                 nm->tp_buf = old_tp_buf;                                // set to free
325                 nm->header = old_hdr;                                   // nano frees on hdr, so must set both
326                 rmr_free_msg( nm );
327
328                 hdr = (uta_mhdr_t *) msg->header;               // header WILL be different
329                 len = RMR_TR_LEN( hdr );
330         }
331
332         memcpy( TRACE_ADDR( hdr ), data, size );
333
334         return size;
335 }
336
337
338 /*
339         Returns a pointer (reference) to the trace data in the message. If sizeptr
340         is supplied, then the trace data size is assigned to the referenced
341         integer so that the caller doesn't need to make a second call to get the
342         value.
343
344         CAUTION:  user programmes should avoid writing to the referenced trace
345                         area (use rmr_set_trace() to avoid possible data overruns. This
346                         function is a convenience, and it is expected that users will
347                         use the trace data as read-only so as a copy is not necessary.
348 */
349 extern void* rmr_trace_ref( rmr_mbuf_t* msg, int* sizeptr ) {
350         uta_mhdr_t*     hdr = NULL;
351         int size = 0;
352
353         if( sizeptr != NULL ) {
354                 *sizeptr = 0;                                   // ensure reset if we bail
355         }
356
357         if( msg == NULL ) {
358                 return NULL;
359         }
360
361         hdr = msg->header;
362         if( (size = RMR_TR_LEN( hdr )) <= 0 ) {
363                 return NULL;
364         }
365
366         if( sizeptr != NULL ) {
367                 *sizeptr = size;
368         }
369
370         return (void *) TRACE_ADDR( hdr );
371 }
372
373 /*
374         Copies the trace bytes from the message header into the buffer provided by
375         the user. If the trace data in the header is less than size, then only
376         that number of bytes are copied, else exactly size bytes are copied. The
377         number actually copied is returned.
378 */
379 extern int rmr_get_trace( rmr_mbuf_t* msg, unsigned char* dest, int size ) {
380         uta_mhdr_t*     hdr = NULL;
381         int n2copy = 0;
382
383         if( msg == NULL ) {
384                 return 0;
385         }
386
387         if( size <= 0 || dest == NULL ) {
388                 return 0;
389         }
390
391         hdr = msg->header;
392         if( (n2copy = size < RMR_TR_LEN( hdr ) ? size : RMR_TR_LEN( hdr )) <= 0  ) {
393                 return 0;
394         }
395
396         memcpy( dest, TRACE_ADDR( hdr ), n2copy );
397
398         return n2copy;
399 }
400
401 /*
402         Returns the number of bytes currently allocated for trace data in the message
403         buffer.
404 */
405 extern int rmr_get_trlen( rmr_mbuf_t* msg ) {
406         uta_mhdr_t*     hdr;
407
408         if( msg == NULL ) {
409                 return 0;
410         }
411
412         hdr = msg->header;
413
414         return RMR_TR_LEN( hdr );
415 }
416
417 /*
418         Returns the string in the source portion of the header. This is assumed to be
419         something that can be used for direct sends (hostname:port). Regardless, it
420         will be a nil terminated, ascii string with max of 64 characters including
421         the final nil. So, the user must ensure that dest is at least 64 bytes.
422
423         As a convenience, the pointer to dest is returned on success; nil on failure
424         with errno set.
425 */
426 extern unsigned char* rmr_get_src( rmr_mbuf_t* msg, unsigned char* dest ) {
427         uta_mhdr_t*     hdr = NULL;
428
429         if( msg == NULL ) {
430                 errno = EINVAL;
431                 return NULL;
432         }
433
434         if( dest != NULL ) {
435                 hdr = msg->header;
436                 zt_buf_fill( dest, hdr->src, RMR_MAX_SRC );
437         }
438
439         return dest;
440 }
441
442 /*
443         Returns the string with the IP address as reported by the sender. This is
444         the IP address that the sender has sussed off of one of the interfaces
445         and cannot be guarenteed to be the acutal IP address which was used to
446         establish the connection.   The caller must provide a buffer of at least
447         64 bytes; the string will be nil terminated. A pointer to the user's buffer
448         is returned on success, nil on failure.
449 */
450 extern unsigned char* rmr_get_srcip( rmr_mbuf_t* msg, unsigned char* dest ) {
451         uta_mhdr_t*     hdr = NULL;
452         char*   rstr = NULL;
453
454         errno = EINVAL;
455
456         if( dest != NULL && msg != NULL ) {
457                 hdr = msg->header;
458                 if( HDR_VERSION( msg->header ) > 2 ) {          // src ip was not present in hdr until ver 3
459                         errno = 0;
460                         zt_buf_fill( dest, hdr->srcip, RMR_MAX_SRC );
461                         rstr = dest;
462                 } else  {
463                         errno = 0;
464                         zt_buf_fill( dest, hdr->src, RMR_MAX_SRC );                             // reutrn the name:port for old messages
465                         rstr = dest;
466                 }
467         }
468
469         return rstr;
470 }
471