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