d149cc00602b647c471eb636beb53721d2908712
[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 -----------------------------------------------
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         Destroyer.
63 */
64 Message::~Message() {
65         if( mbuf != NULL ) {
66                 rmr_free_msg( mbuf );
67         }
68
69         mbuf = NULL;
70 }
71
72
73 // --- getters/setters -----------------------------------------------------
74 /*
75         Copy the payload bytes, and return a smart pointer (unique) to it.
76         If the application needs to update the payload in place for a return
77         to sender call, or just to access the payload in a more efficent manner
78         (without the copy), the Get_payload() function should be considered.
79
80         This function will return a NULL pointer if malloc fails.
81 */
82 //char* Message::Copy_payload( ){
83 std::unique_ptr<unsigned char> Message::Copy_payload( ){
84         unsigned char*  new_payload = NULL;
85
86         if( mbuf != NULL ) {
87                 new_payload = (unsigned char *) malloc( sizeof( unsigned char ) * mbuf->len );
88                 memcpy( new_payload, mbuf->payload, mbuf->len );
89         }
90
91         return std::unique_ptr<unsigned char>( new_payload );
92 }
93
94 /*
95         Makes a copy of the MEID and returns a smart pointer to it.
96 */
97 std::unique_ptr<unsigned char> Message::Get_meid(){
98         unsigned char* m = NULL;
99
100         m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_MEID );
101         rmr_get_meid( mbuf, m );
102
103         return std::unique_ptr<unsigned char>( m );
104 }
105
106 /*
107         Return the total size of the payload (the amount that can be written to
108         as opposed to the portion of the payload which is currently in use.
109         If mbuf isn't valid (nil, or message has a broken header) the return
110         will be -1.
111 */
112 int Message::Get_available_size(){
113         return rmr_payload_size( mbuf );                // rmr can handle a nil pointer
114 }
115
116 int     Message::Get_mtype(){
117         int rval = INVALID_MTYPE;
118
119         if( mbuf != NULL ) {
120                 rval = mbuf->mtype;
121         }
122
123         return rval;
124 }
125
126 /*
127         Makes a copy of the source field and returns a smart pointer to it.
128 */
129 std::unique_ptr<unsigned char> Message::Get_src(){
130         unsigned char* m = NULL;
131
132         m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_SRC );
133         memset( m, 0, sizeof( unsigned char ) * RMR_MAX_SRC );
134
135         if( m != NULL ) {
136                 rmr_get_src( mbuf, m );
137         }
138
139         return std::unique_ptr<unsigned char>( m );
140 }
141
142 int     Message::Get_state( ){
143         if( mbuf != NULL ) {
144                 return mbuf->state;
145         }
146
147         return INVALID_STATUS;
148 }
149
150 int     Message::Get_subid(){
151         int     rval = INVALID_SUBID;
152
153         if( mbuf != NULL ) {
154                 rval =mbuf->sub_id;
155         }
156
157         return rval;
158 }
159
160 /*
161         Return the amount of the payload (bytes) which is used. See
162         Get_available_size() to get the total usable space in the payload.
163 */
164 int     Message::Get_len(){
165         int rval = 0;
166
167         if( mbuf != NULL ) {
168                 rval = mbuf->len;
169         }
170
171         return rval;
172 }
173
174 /*
175         This returns a smart (unique) pointer to the payload portion of the
176         message. This provides the user application with the means to
177         update the payload in place to avoid multiple copies.  The
178         user programme is responsible to determing the usable payload
179         length by calling Message:Get_available_size(), and ensuring that
180         writing beyond the indicated size does not happen.
181 */
182 Msg_component Message::Get_payload(){
183         if( mbuf != NULL ) {
184                 return std::unique_ptr<unsigned char, unfreeable>( mbuf->payload );
185         }
186
187         return NULL;
188 }
189
190 void Message::Set_meid( std::shared_ptr<unsigned char> new_meid ) {
191         if( mbuf != NULL ) {
192                 rmr_str2meid( mbuf, (unsigned char *) new_meid.get() );
193         }
194 }
195
196 void Message::Set_mtype( int new_type ){
197         if( mbuf != NULL ) {
198                 mbuf->mtype = new_type;
199         }
200 }
201
202 void Message::Set_len( int new_len ){
203         if( mbuf != NULL  && new_len >= 0 ) {
204                 mbuf->len = new_len;
205         }
206 }
207
208 void Message::Set_subid( int new_subid ){
209         if( mbuf != NULL ) {
210                 mbuf->sub_id = new_subid;
211         }
212 }
213
214
215 // -------------- send functions ---------------------------------
216
217 /*
218         This assumes that the contents of the mbuf were set by either a send attempt that
219         failed with a retry and thus is ready to be processed by RMR.
220         Exposed to the user, but not expected to be frequently used.
221 */
222 bool Message::Send( ) {
223         if( mbuf == NULL ) {
224                 return false;
225         }
226
227         mbuf =  rmr_send_msg( mrc, mbuf );
228         return mbuf->state == RMR_OK;
229 }
230
231 /*
232         Similar to Send(), this assumes that the message is already set up and this is a retry.
233         Exposed to the user, but not expected to be frequently used.
234 */
235 bool Message::Reply( ) {
236         if( mbuf == NULL ) {
237                 return false;
238         }
239
240         mbuf =  rmr_rts_msg( mrc, mbuf );
241         return mbuf->state == RMR_OK;
242 }
243
244 /*
245         Send workhorse.
246         This will setup the message (type etc.) ensure the message payload space is
247         large enough and copy in the payload (if a new payload is given), then will
248         either send or rts the message based on the stype parm.
249
250         If payload is nil, then we assume the user updated the payload in place and
251         no copy is needed.
252
253         This is public, but most users should use Send_msg or Send_response functions.
254 */
255 bool Message::Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype ) {
256
257         if( mbuf == NULL ) {
258                 return false;
259         }
260
261         if( mtype != NO_CHANGE ) {
262                 mbuf->mtype = mtype;
263         }
264         if( subid != NO_CHANGE ) {
265                 mbuf->sub_id = subid;
266         }
267
268         if( payload_len != NO_CHANGE ) {
269                 mbuf->len = payload_len;
270         }
271
272         if( payload != NULL ) {                 // if we have a payload, ensure msg has room, realloc if needed, then copy
273                 mbuf = rmr_realloc_payload( mbuf, payload_len, RMR_NO_COPY, RMR_NO_CLONE );             // ensure message is large enough
274                 if( mbuf == NULL ) {
275                         return false;
276                 }
277
278                 memcpy( mbuf->payload, payload, mbuf->len );
279         }
280
281         if( stype == RESPONSE ) {
282                 mbuf = rmr_rts_msg( mrc, mbuf );
283         } else {
284                 mbuf = rmr_send_msg( mrc, mbuf );
285         }
286
287         return mbuf->state == RMR_OK;
288 }
289
290 /*
291         Send a response to the endpoint that sent the original message.
292
293         Response can be null and the assumption will be that the message payload
294         was updated in place and no additional copy is needed before sending the message.
295
296         The second form of the call allows for a stack allocated buffer (e.g. char foo[120]) to
297         be passed as the payload.
298 */
299 bool Message::Send_response(  int mtype, int subid, int response_len, std::shared_ptr<unsigned char> response ) {
300         return Send( mtype, subid, response_len, response.get(), RESPONSE );
301 }
302
303 bool Message::Send_response(  int mtype, int subid, int response_len, unsigned char* response ) {
304         return Send( mtype, subid, response_len, response, RESPONSE );
305 }
306
307 /*
308         These allow a response message to be sent without changing the mtype/subid.
309 */
310 bool Message::Send_response(  int response_len, std::shared_ptr<unsigned char> response ) {
311         return Send( NO_CHANGE, NO_CHANGE, response_len, response.get(), RESPONSE );
312 }
313
314 bool Message::Send_response(  int response_len, unsigned char* response ) {
315         return Send( NO_CHANGE, NO_CHANGE, response_len, response, RESPONSE );
316 }
317
318
319 /*
320         Send a message based on message type routing.
321
322         Payload can be null and the assumption will be that the message payload
323         was updated in place and no additional copy is needed before sending the message.
324
325         Return is a new mbuf suitable for sending another message, or the original buffer with
326         a bad state sent if there was a failure.
327 */
328 bool Message::Send_msg(  int mtype, int subid, int payload_len, std::shared_ptr<unsigned char> payload ) {
329         return Send( mtype, subid, payload_len, payload.get(), MESSAGE );
330 }
331
332 bool Message::Send_msg(  int mtype, int subid, int payload_len, unsigned char* payload ) {
333         return Send( mtype, subid, payload_len, payload, MESSAGE );
334 }
335
336 /*
337         Similar send functions that allow the message type/subid to remain unchanged
338 */
339 bool Message::Send_msg(  int payload_len, std::shared_ptr<unsigned char> payload ) {
340         return Send( NO_CHANGE, NO_CHANGE, payload_len, payload.get(), MESSAGE );
341 }
342
343 bool Message::Send_msg(  int payload_len, unsigned char* payload ) {
344         return Send( NO_CHANGE, NO_CHANGE, payload_len, payload, MESSAGE );
345 }