Add metrics to the framework
[ric-plt/xapp-frame-cpp.git] / src / messaging / message.cpp
1 // vi: ts=4 sw=4 noet:
2 /*
3 ==================================================================================
4         Copyright (c) 2020 Nokia
5         Copyright (c) 2020 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:       message.cpp
23         Abstract:       A message wrapper. This should completely hide the
24                                 underlying transport (RMR) message structure from
25                                 the user application. For the most part, the getters
26                                 are used by the framwork; it is unlikely that other
27                                 than adding/extracting the MEID, the user app will
28                                 be completely unaware of information that is not
29                                 presented in the callback parms.
30
31         Date:           12 March 2020
32         Author:         E. Scott Daniels
33 */
34
35 #include <string.h>
36 #include <unistd.h>
37
38 #include <rmr/rmr.h>
39
40 #include <iostream>
41
42 #include "message.hpp"
43
44 namespace xapp {
45
46
47
48 // --------------- private ------------------------------------------------
49
50 // --------------- builders/operators  -------------------------------------
51
52 /*
53         Create a new message wrapper for an existing RMR msg buffer.
54 */
55 xapp::Message::Message( rmr_mbuf_t* mbuf, void* mrc ) {
56         this->mrc = mrc;                        // the message router context for sends
57         this->mbuf = mbuf;
58 }
59
60 xapp::Message::Message( void* mrc, int payload_len ) {
61         this->mrc = mrc;
62         this->mbuf = rmr_alloc_msg( mrc, payload_len );
63 }
64
65 /*
66         Copy builder.  Given a source object instance (soi), create a copy.
67         Creating a copy should be avoided as it can be SLOW!
68 */
69 xapp::Message::Message( const Message& soi ) {
70         int payload_size;
71
72         mrc = soi.mrc;
73         payload_size = rmr_payload_size( soi.mbuf );            // rmr can handle a nil pointer
74         mbuf = rmr_realloc_payload( soi.mbuf, payload_size, RMR_COPY, RMR_CLONE );
75 }
76
77 /*
78         Assignment operator. Simiolar to the copycat, but "this" object exists and
79         may have data that needs to be released prior to making a copy of the soi.
80 */
81 Message& xapp::Message::operator=( const Message& soi ) {
82         int     payload_size;
83
84         if( this != &soi ) {                            // cannot do self assignment
85                 if( mbuf != NULL ) {
86                         rmr_free_msg( mbuf );           // release the old one so we don't leak
87                 }
88
89                 payload_size = rmr_payload_size( soi.mbuf );            // rmr can handle a nil pointer
90                 mrc = soi.mrc;
91                 mbuf = rmr_realloc_payload( soi.mbuf, payload_size, RMR_COPY, RMR_CLONE );
92         }
93
94         return *this;
95 }
96
97 /*
98         Move builder.  Given a source object instance (soi), move the information from
99         the soi ensuring that the destriction of the soi doesn't trash things from
100         under us.
101 */
102 xapp::Message::Message( Message&& soi ) {
103         mrc = soi.mrc;
104         mbuf = soi.mbuf;
105
106         soi.mrc = NULL;         // prevent closing of RMR stuff on soi destroy
107         soi.mbuf = NULL;
108 }
109
110 /*
111         Move Assignment operator. Move the message data to the existing object
112         ensure the object reference is cleaned up, and ensuring that the source
113         object references are removed.
114 */
115 Message& xapp::Message::operator=( Message&& soi ) {
116         if( this != &soi ) {                            // cannot do self assignment
117                 if( mbuf != NULL ) {
118                         rmr_free_msg( mbuf );           // release the old one so we don't leak
119                 }
120
121                 mrc = soi.mrc;
122                 mbuf = soi.mbuf;
123
124                 soi.mrc = NULL;
125                 soi.mbuf = NULL;
126         }
127
128         return *this;
129 }
130
131
132 /*
133         Destroyer.
134 */
135 xapp::Message::~Message() {
136         if( mbuf != NULL ) {
137                 rmr_free_msg( mbuf );
138         }
139
140         mbuf = NULL;
141 }
142
143
144 // --- getters/setters -----------------------------------------------------
145 /*
146         Copy the payload bytes, and return a smart pointer (unique) to it.
147         If the application needs to update the payload in place for a return
148         to sender call, or just to access the payload in a more efficent manner
149         (without the copy), the Get_payload() function should be considered.
150
151         This function will return a NULL pointer if malloc fails.
152 */
153 //char* Message::Copy_payload( ){
154 std::unique_ptr<unsigned char> xapp::Message::Copy_payload( ){
155
156         if( mbuf != NULL ) {
157                 unsigned char*  new_payload = new unsigned char[mbuf->len];
158                 memcpy( new_payload, mbuf->payload, mbuf->len );
159                 return std::unique_ptr<unsigned char>( new_payload );
160         }
161
162         return NULL;
163 }
164
165 /*
166         Makes a copy of the MEID and returns a smart pointer to it.
167 */
168 std::unique_ptr<unsigned char> xapp::Message::Get_meid(){
169         unsigned char* m = NULL;
170
171         m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_MEID );
172         rmr_get_meid( mbuf, m );
173
174         return std::unique_ptr<unsigned char>( m );
175 }
176
177 /*
178         Return the total size of the payload (the amount that can be written to
179         as opposed to the portion of the payload which is currently in use.
180         If mbuf isn't valid (nil, or message has a broken header) the return
181         will be -1.
182 */
183 int xapp::Message::Get_available_size(){
184         return rmr_payload_size( mbuf );                // rmr can handle a nil pointer
185 }
186
187 int     xapp::Message::Get_mtype(){
188         int rval = INVALID_MTYPE;
189
190         if( mbuf != NULL ) {
191                 rval = mbuf->mtype;
192         }
193
194         return rval;
195 }
196
197 /*
198         Makes a copy of the source field and returns a smart pointer to it.
199 */
200 std::unique_ptr<unsigned char> xapp::Message::Get_src(){
201         unsigned char* m = new unsigned char[RMR_MAX_SRC]; 
202
203         if( m != NULL ) {
204                 rmr_get_src( mbuf, m );
205         }
206
207         return std::unique_ptr<unsigned char>( m );
208 }
209
210 int     xapp::Message::Get_state( ){
211         int state = INVALID_STATUS;
212
213         if( mbuf != NULL ) {
214                 state =  mbuf->state;
215         }
216
217         return state;
218 }
219
220 int     xapp::Message::Get_subid(){
221         int     rval = INVALID_SUBID;
222
223         if( mbuf != NULL ) {
224                 rval =mbuf->sub_id;
225         }
226
227         return rval;
228 }
229
230 /*
231         Return the amount of the payload (bytes) which is used. See
232         Get_available_size() to get the total usable space in the payload.
233 */
234 int     xapp::Message::Get_len(){
235         int rval = 0;
236
237         if( mbuf != NULL ) {
238                 rval = mbuf->len;
239         }
240
241         return rval;
242 }
243
244 /*
245         This returns a smart (unique) pointer to the payload portion of the
246         message. This provides the user application with the means to
247         update the payload in place to avoid multiple copies.  The
248         user programme is responsible to determing the usable payload
249         length by calling Message:Get_available_size(), and ensuring that
250         writing beyond the indicated size does not happen.
251 */
252 Msg_component xapp::Message::Get_payload(){
253         if( mbuf != NULL ) {
254                 return std::unique_ptr<unsigned char, unfreeable>( mbuf->payload );
255         }
256
257         return NULL;
258 }
259
260 void xapp::Message::Set_meid( std::shared_ptr<unsigned char> new_meid ) {
261         if( mbuf != NULL ) {
262                 rmr_str2meid( mbuf, (unsigned char *) new_meid.get() );
263         }
264 }
265
266 void xapp::Message::Set_mtype( int new_type ){
267         if( mbuf != NULL ) {
268                 mbuf->mtype = new_type;
269         }
270 }
271
272 void xapp::Message::Set_len( int new_len ){
273         if( mbuf != NULL  && new_len >= 0 ) {
274                 mbuf->len = new_len;
275         }
276 }
277
278 void xapp::Message::Set_subid( int new_subid ){
279         if( mbuf != NULL ) {
280                 mbuf->sub_id = new_subid;
281         }
282 }
283
284
285 // -------------- send functions ---------------------------------
286
287 /*
288         This assumes that the contents of the mbuf were set by either a send attempt that
289         failed with a retry and thus is ready to be processed by RMR.
290         Exposed to the user, but not expected to be frequently used.
291 */
292 bool xapp::Message::Send( ) {
293         bool state = false;
294
295         if( mbuf != NULL ) {
296                 mbuf =  rmr_send_msg( mrc, mbuf );      // send and pick up new mbuf
297                 state = mbuf->state == RMR_OK;          // overall state for caller
298         }
299
300         return state;
301 }
302
303 /*
304         Similar to Send(), this assumes that the message is already set up and this is a retry.
305         Exposed to the user, but not expected to be frequently used.
306 */
307 bool xapp::Message::Reply( ) {
308         bool state = false;
309
310         if( mbuf != NULL ) {
311                 mbuf =  rmr_rts_msg( mrc, mbuf );               // send and pick up new mbuf
312                 state = mbuf->state == RMR_OK;                  // state for caller based on send
313         }
314
315         return state;
316 }
317
318 /*
319         Send workhorse.
320         This will setup the message (type etc.) ensure the message payload space is
321         large enough and copy in the payload (if a new payload is given), then will
322         either send or rts the message based on the stype parm.
323
324         If payload is nil, then we assume the user updated the payload in place and
325         no copy is needed.
326
327         This is public, but most users should use Send_msg or Send_response functions.
328 */
329 bool xapp::Message::Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype, rmr_whid_t whid ) {
330         bool state = false;
331
332         if( mbuf != NULL ) {
333                 if( mtype != NO_CHANGE ) {
334                         mbuf->mtype = mtype;
335                 }
336                 if( subid != NO_CHANGE ) {
337                         mbuf->sub_id = subid;
338                 }
339
340                 if( payload_len != NO_CHANGE ) {
341                         mbuf->len = payload_len;
342                 }
343
344                 if( payload != NULL ) {                 // if we have a payload, ensure msg has room, realloc if needed, then copy
345                         mbuf = rmr_realloc_payload( mbuf, payload_len, RMR_NO_COPY, RMR_NO_CLONE );             // ensure message is large enough
346                         if( mbuf == NULL ) {
347                                 return false;
348                         }
349
350                         memcpy( mbuf->payload, payload, mbuf->len );
351                 }
352
353                 switch( stype ) {
354                         case RESPONSE:
355                                 mbuf = rmr_rts_msg( mrc, mbuf );
356                                 break;
357
358                         case MESSAGE:
359                                 mbuf = rmr_send_msg( mrc, mbuf );
360                                 break;
361
362                         case WORMHOLE_MSG:
363                                 mbuf = rmr_wh_send_msg( mrc, whid,  mbuf );
364                                 break;
365                 }
366
367                 state = mbuf->state == RMR_OK;
368         }
369
370         return state;
371 }
372
373 /*
374         Send a response to the endpoint that sent the original message.
375
376         Response can be null and the assumption will be that the message payload
377         was updated in place and no additional copy is needed before sending the message.
378
379         The second form of the call allows for a stack allocated buffer (e.g. char foo[120]) to
380         be passed as the payload.
381 */
382 bool xapp::Message::Send_response(  int mtype, int subid, int response_len, std::shared_ptr<unsigned char> response ) {
383         return Send( mtype, subid, response_len, response.get(), RESPONSE, NO_WHID );
384 }
385
386 bool xapp::Message::Send_response(  int mtype, int subid, int response_len, unsigned char* response ) {
387         return Send( mtype, subid, response_len, response, RESPONSE, NO_WHID );
388 }
389
390 /*
391         These allow a response message to be sent without changing the mtype/subid.
392 */
393 bool xapp::Message::Send_response(  int response_len, std::shared_ptr<unsigned char> response ) {
394         return Send( NO_CHANGE, NO_CHANGE, response_len, response.get(), RESPONSE, NO_WHID );
395 }
396
397 bool xapp::Message::Send_response(  int response_len, unsigned char* response ) {
398         return Send( NO_CHANGE, NO_CHANGE, response_len, response, RESPONSE, NO_WHID );
399 }
400
401
402 /*
403         Send a message based on message type routing.
404
405         Payload can be null and the assumption will be that the message payload
406         was updated in place and no additional copy is needed before sending the message.
407
408         Return is a new mbuf suitable for sending another message, or the original buffer with
409         a bad state sent if there was a failure.
410 */
411 bool xapp::Message::Send_msg(  int mtype, int subid, int payload_len, std::shared_ptr<unsigned char> payload ) {
412         return Send( mtype, subid, payload_len, payload.get(), MESSAGE, NO_WHID );
413 }
414
415 bool xapp::Message::Send_msg(  int mtype, int subid, int payload_len, unsigned char* payload ) {
416         return Send( mtype, subid, payload_len, payload, MESSAGE, NO_WHID );
417 }
418
419 /*
420         Similar send functions that allow the message type/subid to remain unchanged
421 */
422 bool xapp::Message::Send_msg(  int payload_len, std::shared_ptr<unsigned char> payload ) {
423         return Send( NO_CHANGE, NO_CHANGE, payload_len, payload.get(), MESSAGE, NO_WHID );
424 }
425
426 bool xapp::Message::Send_msg(  int payload_len, unsigned char* payload ) {
427         return Send( NO_CHANGE, NO_CHANGE, payload_len, payload, MESSAGE, NO_WHID );
428 }
429
430
431 /*
432         Wormhole send allows an xAPP to send a message directly based on an existing
433         wormhole ID (use xapp::Wormhole_open() to get one). Wormholes should NOT be
434         used for reponse messages, but are intended for things like route tables and
435         alarm messages where routing doesn't exist/apply.
436 */
437 bool xapp::Message::Wormhole_send( int whid, int mtype, int subid, int payload_len, std::shared_ptr<unsigned char> payload ) {
438         return Send( mtype, subid, payload_len, payload.get(), WORMHOLE_MSG, whid );
439 }
440
441
442 } // namespace