Add API allowing xAPPs to send alarm messages
[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         unsigned char*  new_payload = NULL;
156
157         if( mbuf != NULL ) {
158                 new_payload = (unsigned char *) malloc( sizeof( unsigned char ) * mbuf->len );
159                 memcpy( new_payload, mbuf->payload, mbuf->len );
160         }
161
162         return std::unique_ptr<unsigned char>( new_payload );
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 = NULL;
202
203         m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_SRC );
204         memset( m, 0, sizeof( unsigned char ) * RMR_MAX_SRC );
205
206         if( m != NULL ) {
207                 rmr_get_src( mbuf, m );
208         }
209
210         return std::unique_ptr<unsigned char>( m );
211 }
212
213 int     xapp::Message::Get_state( ){
214         int state = INVALID_STATUS;
215
216         if( mbuf != NULL ) {
217                 state =  mbuf->state;
218         }
219
220         return state;
221 }
222
223 int     xapp::Message::Get_subid(){
224         int     rval = INVALID_SUBID;
225
226         if( mbuf != NULL ) {
227                 rval =mbuf->sub_id;
228         }
229
230         return rval;
231 }
232
233 /*
234         Return the amount of the payload (bytes) which is used. See
235         Get_available_size() to get the total usable space in the payload.
236 */
237 int     xapp::Message::Get_len(){
238         int rval = 0;
239
240         if( mbuf != NULL ) {
241                 rval = mbuf->len;
242         }
243
244         return rval;
245 }
246
247 /*
248         This returns a smart (unique) pointer to the payload portion of the
249         message. This provides the user application with the means to
250         update the payload in place to avoid multiple copies.  The
251         user programme is responsible to determing the usable payload
252         length by calling Message:Get_available_size(), and ensuring that
253         writing beyond the indicated size does not happen.
254 */
255 Msg_component xapp::Message::Get_payload(){
256         if( mbuf != NULL ) {
257                 return std::unique_ptr<unsigned char, unfreeable>( mbuf->payload );
258         }
259
260         return NULL;
261 }
262
263 void xapp::Message::Set_meid( std::shared_ptr<unsigned char> new_meid ) {
264         if( mbuf != NULL ) {
265                 rmr_str2meid( mbuf, (unsigned char *) new_meid.get() );
266         }
267 }
268
269 void xapp::Message::Set_mtype( int new_type ){
270         if( mbuf != NULL ) {
271                 mbuf->mtype = new_type;
272         }
273 }
274
275 void xapp::Message::Set_len( int new_len ){
276         if( mbuf != NULL  && new_len >= 0 ) {
277                 mbuf->len = new_len;
278         }
279 }
280
281 void xapp::Message::Set_subid( int new_subid ){
282         if( mbuf != NULL ) {
283                 mbuf->sub_id = new_subid;
284         }
285 }
286
287
288 // -------------- send functions ---------------------------------
289
290 /*
291         This assumes that the contents of the mbuf were set by either a send attempt that
292         failed with a retry and thus is ready to be processed by RMR.
293         Exposed to the user, but not expected to be frequently used.
294 */
295 bool xapp::Message::Send( ) {
296         bool state = false;
297
298         if( mbuf != NULL ) {
299                 mbuf =  rmr_send_msg( mrc, mbuf );      // send and pick up new mbuf
300                 state = mbuf->state == RMR_OK;          // overall state for caller
301         }
302
303         return state;
304 }
305
306 /*
307         Similar to Send(), this assumes that the message is already set up and this is a retry.
308         Exposed to the user, but not expected to be frequently used.
309 */
310 bool xapp::Message::Reply( ) {
311         bool state = false;
312
313         if( mbuf != NULL ) {
314                 mbuf =  rmr_rts_msg( mrc, mbuf );               // send and pick up new mbuf
315                 state = mbuf->state == RMR_OK;                  // state for caller based on send
316         }
317
318         return state;
319 }
320
321 /*
322         Send workhorse.
323         This will setup the message (type etc.) ensure the message payload space is
324         large enough and copy in the payload (if a new payload is given), then will
325         either send or rts the message based on the stype parm.
326
327         If payload is nil, then we assume the user updated the payload in place and
328         no copy is needed.
329
330         This is public, but most users should use Send_msg or Send_response functions.
331 */
332 bool xapp::Message::Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype, rmr_whid_t whid ) {
333         bool state = false;
334
335         if( mbuf != NULL ) {
336                 if( mtype != NO_CHANGE ) {
337                         mbuf->mtype = mtype;
338                 }
339                 if( subid != NO_CHANGE ) {
340                         mbuf->sub_id = subid;
341                 }
342
343                 if( payload_len != NO_CHANGE ) {
344                         mbuf->len = payload_len;
345                 }
346
347                 if( payload != NULL ) {                 // if we have a payload, ensure msg has room, realloc if needed, then copy
348                         mbuf = rmr_realloc_payload( mbuf, payload_len, RMR_NO_COPY, RMR_NO_CLONE );             // ensure message is large enough
349                         if( mbuf == NULL ) {
350                                 return false;
351                         }
352
353                         memcpy( mbuf->payload, payload, mbuf->len );
354                 }
355
356                 switch( stype ) {
357                         case RESPONSE:
358                                 mbuf = rmr_rts_msg( mrc, mbuf );
359                                 break;
360
361                         case MESSAGE:
362                                 mbuf = rmr_send_msg( mrc, mbuf );
363                                 break;
364
365                         case WORMHOLE_MSG:
366                                 mbuf = rmr_wh_send_msg( mrc, whid,  mbuf );
367                                 break;
368                 }
369
370                 state = mbuf->state == RMR_OK;
371         }
372
373         return state;
374 }
375
376 /*
377         Send a response to the endpoint that sent the original message.
378
379         Response can be null and the assumption will be that the message payload
380         was updated in place and no additional copy is needed before sending the message.
381
382         The second form of the call allows for a stack allocated buffer (e.g. char foo[120]) to
383         be passed as the payload.
384 */
385 bool xapp::Message::Send_response(  int mtype, int subid, int response_len, std::shared_ptr<unsigned char> response ) {
386         return Send( mtype, subid, response_len, response.get(), RESPONSE, NO_WHID );
387 }
388
389 bool xapp::Message::Send_response(  int mtype, int subid, int response_len, unsigned char* response ) {
390         return Send( mtype, subid, response_len, response, RESPONSE, NO_WHID );
391 }
392
393 /*
394         These allow a response message to be sent without changing the mtype/subid.
395 */
396 bool xapp::Message::Send_response(  int response_len, std::shared_ptr<unsigned char> response ) {
397         return Send( NO_CHANGE, NO_CHANGE, response_len, response.get(), RESPONSE, NO_WHID );
398 }
399
400 bool xapp::Message::Send_response(  int response_len, unsigned char* response ) {
401         return Send( NO_CHANGE, NO_CHANGE, response_len, response, RESPONSE, NO_WHID );
402 }
403
404
405 /*
406         Send a message based on message type routing.
407
408         Payload can be null and the assumption will be that the message payload
409         was updated in place and no additional copy is needed before sending the message.
410
411         Return is a new mbuf suitable for sending another message, or the original buffer with
412         a bad state sent if there was a failure.
413 */
414 bool xapp::Message::Send_msg(  int mtype, int subid, int payload_len, std::shared_ptr<unsigned char> payload ) {
415         return Send( mtype, subid, payload_len, payload.get(), MESSAGE, NO_WHID );
416 }
417
418 bool xapp::Message::Send_msg(  int mtype, int subid, int payload_len, unsigned char* payload ) {
419         return Send( mtype, subid, payload_len, payload, MESSAGE, NO_WHID );
420 }
421
422 /*
423         Similar send functions that allow the message type/subid to remain unchanged
424 */
425 bool xapp::Message::Send_msg(  int payload_len, std::shared_ptr<unsigned char> payload ) {
426         return Send( NO_CHANGE, NO_CHANGE, payload_len, payload.get(), MESSAGE, NO_WHID );
427 }
428
429 bool xapp::Message::Send_msg(  int payload_len, unsigned char* payload ) {
430         return Send( NO_CHANGE, NO_CHANGE, payload_len, payload, MESSAGE, NO_WHID );
431 }
432
433
434 /*
435         Wormhole send allows an xAPP to send a message directly based on an existing
436         wormhole ID (use xapp::Wormhole_open() to get one). Wormholes should NOT be
437         used for reponse messages, but are intended for things like route tables and
438         alarm messages where routing doesn't exist/apply.
439 */
440 bool xapp::Message::Wormhole_send( int whid, int mtype, int subid, int payload_len, std::shared_ptr<unsigned char> payload ) {
441         return Send( mtype, subid, payload_len, payload.get(), WORMHOLE_MSG, whid );
442 }
443
444
445 } // namespace