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