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