58225c457e54fc419fa38312b3f14f4877d6dcc4
[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         Regardless of action taken (actual realloc or not) the caller's reference to mbuf
289         is still valid follwing the call and will point to the correct spot (same tp
290         buffer if no realloc needed, or the new one if there was).
291 */
292 extern int rmr_set_trace( rmr_mbuf_t* msg, unsigned const char* data, int size ) {
293         uta_mhdr_t*     hdr;
294         rmr_mbuf_t* nm;                 // new message if larger is needed
295         int             len;
296         void*   old_tp_buf;             // if we need to realloc, must hold old to free
297         void*   old_hdr;
298
299         if( msg == NULL ) {
300                 errno = EINVAL;
301                 return 0;
302         }
303
304         errno = 0;
305         if( size <= 0 ) {
306                 return 0;
307         }
308
309         hdr = (uta_mhdr_t *) msg->header;
310         if( !hdr ) {
311                 errno = EINVAL;
312                 return 0;
313         }
314
315         len = RMR_TR_LEN( hdr );
316
317         if( len != size ) {                                                     // different sized trace data, must realloc the buffer
318                 nm = rmr_realloc_msg( msg, size );              // realloc with changed trace size
319                 old_tp_buf = msg->tp_buf;                               // hold to repoint new mbuf at small buffer
320                 old_hdr = msg->header;
321
322                 msg->tp_buf = nm->tp_buf;                               // reference the reallocated buffer
323                 msg->header = nm->header;
324                 msg->id = NULL;                                                 // currently unused
325                 msg->xaction = nm->xaction;
326                 msg->payload = nm->payload;
327
328                 nm->tp_buf = old_tp_buf;                                // set to free; point to the small buffer
329                 nm->header = old_hdr;                                   // nano frees on hdr, so must set both
330                 rmr_free_msg( nm );
331
332                 hdr = (uta_mhdr_t *) msg->header;               // header WILL be different
333                 len = RMR_TR_LEN( hdr );
334         }
335
336         memcpy( TRACE_ADDR( hdr ), data, size );
337
338         return size;
339 }
340
341
342 /*
343         Returns a pointer (reference) to the trace data in the message. If sizeptr
344         is supplied, then the trace data size is assigned to the referenced
345         integer so that the caller doesn't need to make a second call to get the
346         value.
347
348         CAUTION:  user programmes should avoid writing to the referenced trace
349                         area (use rmr_set_trace() to avoid possible data overruns. This
350                         function is a convenience, and it is expected that users will
351                         use the trace data as read-only so as a copy is not necessary.
352 */
353 extern void* rmr_trace_ref( rmr_mbuf_t* msg, int* sizeptr ) {
354         uta_mhdr_t*     hdr = NULL;
355         int size = 0;
356
357         if( sizeptr != NULL ) {
358                 *sizeptr = 0;                                   // ensure reset if we bail
359         }
360
361         if( msg == NULL ) {
362                 return NULL;
363         }
364
365         hdr = msg->header;
366         if( (size = RMR_TR_LEN( hdr )) <= 0 ) {
367                 return NULL;
368         }
369
370         if( sizeptr != NULL ) {
371                 *sizeptr = size;
372         }
373
374         return (void *) TRACE_ADDR( hdr );
375 }
376
377 /*
378         Copies the trace bytes from the message header into the buffer provided by
379         the user. If the trace data in the header is less than size, then only
380         that number of bytes are copied, else exactly size bytes are copied. The
381         number actually copied is returned.
382 */
383 extern int rmr_get_trace( rmr_mbuf_t* msg, unsigned char* dest, int size ) {
384         uta_mhdr_t*     hdr = NULL;
385         int n2copy = 0;
386
387         if( msg == NULL ) {
388                 return 0;
389         }
390
391         if( size <= 0 || dest == NULL ) {
392                 return 0;
393         }
394
395         hdr = msg->header;
396         if( (n2copy = size < RMR_TR_LEN( hdr ) ? size : RMR_TR_LEN( hdr )) <= 0  ) {
397                 return 0;
398         }
399
400         memcpy( dest, TRACE_ADDR( hdr ), n2copy );
401
402         return n2copy;
403 }
404
405 /*
406         Returns the number of bytes currently allocated for trace data in the message
407         buffer.
408 */
409 extern int rmr_get_trlen( rmr_mbuf_t* msg ) {
410         uta_mhdr_t*     hdr;
411
412         if( msg == NULL ) {
413                 return 0;
414         }
415
416         hdr = msg->header;
417
418         return RMR_TR_LEN( hdr );
419 }
420
421 /*
422         Returns the string in the source portion of the header. This is assumed to be
423         something that can be used for direct sends (hostname:port). Regardless, it
424         will be a nil terminated, ascii string with max of 64 characters including
425         the final nil. So, the user must ensure that dest is at least 64 bytes.
426
427         As a convenience, the pointer to dest is returned on success; nil on failure
428         with errno set.
429 */
430 extern unsigned char* rmr_get_src( rmr_mbuf_t* msg, unsigned char* dest ) {
431         uta_mhdr_t*     hdr = NULL;
432
433         if( msg == NULL ) {
434                 errno = EINVAL;
435                 return NULL;
436         }
437
438         if( dest != NULL ) {
439                 hdr = msg->header;
440                 zt_buf_fill( dest, hdr->src, RMR_MAX_SRC );
441         }
442
443         return dest;
444 }
445
446 /*
447         Returns the string with the IP address as reported by the sender. This is
448         the IP address that the sender has sussed off of one of the interfaces
449         and cannot be guarenteed to be the acutal IP address which was used to
450         establish the connection.   The caller must provide a buffer of at least
451         64 bytes; the string will be nil terminated. A pointer to the user's buffer
452         is returned on success, nil on failure.
453 */
454 extern unsigned char* rmr_get_srcip( rmr_mbuf_t* msg, unsigned char* dest ) {
455         uta_mhdr_t*     hdr = NULL;
456         char*   rstr = NULL;
457
458         errno = EINVAL;
459
460         if( dest != NULL && msg != NULL ) {
461                 hdr = msg->header;
462                 if( HDR_VERSION( msg->header ) > 2 ) {          // src ip was not present in hdr until ver 3
463                         errno = 0;
464                         zt_buf_fill( dest, hdr->srcip, RMR_MAX_SRC );
465                         rstr = dest;
466                 } else  {
467                         errno = 0;
468                         zt_buf_fill( dest, hdr->src, RMR_MAX_SRC );                             // reutrn the name:port for old messages
469                         rstr = dest;
470                 }
471         }
472
473         return rstr;
474 }
475