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