blob: 41f5a78bf15546a8b8d49853b0f79b7841f4a4cc [file] [log] [blame]
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -04001// 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
E. Scott Daniels6ef23e12020-07-15 08:03:22 -040044namespace xapp {
45
46
47
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -040048// --------------- private ------------------------------------------------
49
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -040050// --------------- builders/operators -------------------------------------
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -040051
52/*
53 Create a new message wrapper for an existing RMR msg buffer.
54*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -040055xapp::Message::Message( rmr_mbuf_t* mbuf, void* mrc ) {
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -040056 this->mrc = mrc; // the message router context for sends
57 this->mbuf = mbuf;
58}
59
E. Scott Daniels6ef23e12020-07-15 08:03:22 -040060xapp::Message::Message( void* mrc, int payload_len ) {
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -040061 this->mrc = mrc;
62 this->mbuf = rmr_alloc_msg( mrc, payload_len );
63}
64
65/*
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -040066 Copy builder. Given a source object instance (soi), create a copy.
67 Creating a copy should be avoided as it can be SLOW!
68*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -040069xapp::Message::Message( const Message& soi ) {
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -040070 int payload_size;
71
72 mrc = soi.mrc;
73 payload_size = rmr_payload_size( soi.mbuf ); // rmr can handle a nil pointer
E. Scott Daniels6ef23e12020-07-15 08:03:22 -040074 mbuf = rmr_realloc_payload( soi.mbuf, payload_size, RMR_COPY, RMR_CLONE );
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -040075}
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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -040081Message& xapp::Message::operator=( const Message& soi ) {
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -040082 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 }
E. Scott Daniels6ef23e12020-07-15 08:03:22 -040088
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -040089 payload_size = rmr_payload_size( soi.mbuf ); // rmr can handle a nil pointer
90 mrc = soi.mrc;
E. Scott Daniels6ef23e12020-07-15 08:03:22 -040091 mbuf = rmr_realloc_payload( soi.mbuf, payload_size, RMR_COPY, RMR_CLONE );
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -040092 }
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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400102xapp::Message::Message( Message&& soi ) {
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400103 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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400115Message& xapp::Message::operator=( Message&& soi ) {
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400116 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 }
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400120
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400121 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/*
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400133 Destroyer.
134*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400135xapp::Message::~Message() {
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400136 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( ){
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400154std::unique_ptr<unsigned char> xapp::Message::Copy_payload( ){
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400155 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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400168std::unique_ptr<unsigned char> xapp::Message::Get_meid(){
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400169 unsigned char* m = NULL;
170
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400171 m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_MEID );
172 rmr_get_meid( mbuf, m );
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400173
174 return std::unique_ptr<unsigned char>( m );
175}
176
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400177/*
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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400183int xapp::Message::Get_available_size(){
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400184 return rmr_payload_size( mbuf ); // rmr can handle a nil pointer
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400185}
186
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400187int xapp::Message::Get_mtype(){
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400188 int rval = INVALID_MTYPE;
189
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400190 if( mbuf != NULL ) {
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400191 rval = mbuf->mtype;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400192 }
193
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400194 return rval;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400195}
196
197/*
198 Makes a copy of the source field and returns a smart pointer to it.
199*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400200std::unique_ptr<unsigned char> xapp::Message::Get_src(){
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400201 unsigned char* m = NULL;
202
203 m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_SRC );
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400204 memset( m, 0, sizeof( unsigned char ) * RMR_MAX_SRC );
205
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400206 if( m != NULL ) {
207 rmr_get_src( mbuf, m );
208 }
209
210 return std::unique_ptr<unsigned char>( m );
211}
212
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400213int xapp::Message::Get_state( ){
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400214 int state = INVALID_STATUS;
215
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400216 if( mbuf != NULL ) {
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400217 state = mbuf->state;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400218 }
219
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400220 return state;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400221}
222
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400223int xapp::Message::Get_subid(){
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400224 int rval = INVALID_SUBID;
225
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400226 if( mbuf != NULL ) {
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400227 rval =mbuf->sub_id;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400228 }
229
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400230 return rval;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400231}
232
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400233/*
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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400237int xapp::Message::Get_len(){
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400238 int rval = 0;
239
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400240 if( mbuf != NULL ) {
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400241 rval = mbuf->len;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400242 }
243
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400244 return rval;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400245}
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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400255Msg_component xapp::Message::Get_payload(){
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400256 if( mbuf != NULL ) {
257 return std::unique_ptr<unsigned char, unfreeable>( mbuf->payload );
258 }
259
260 return NULL;
261}
262
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400263void xapp::Message::Set_meid( std::shared_ptr<unsigned char> new_meid ) {
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400264 if( mbuf != NULL ) {
265 rmr_str2meid( mbuf, (unsigned char *) new_meid.get() );
266 }
267}
268
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400269void xapp::Message::Set_mtype( int new_type ){
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400270 if( mbuf != NULL ) {
271 mbuf->mtype = new_type;
272 }
273}
274
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400275void xapp::Message::Set_len( int new_len ){
E. Scott Daniels4e4fb502020-03-24 12:28:06 -0400276 if( mbuf != NULL && new_len >= 0 ) {
277 mbuf->len = new_len;
278 }
279}
280
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400281void xapp::Message::Set_subid( int new_subid ){
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400282 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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400295bool xapp::Message::Send( ) {
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400296 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
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400301 }
302
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400303 return state;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400304}
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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400310bool xapp::Message::Reply( ) {
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400311 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
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400316 }
317
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400318 return state;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400319}
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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400332bool xapp::Message::Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype, rmr_whid_t whid ) {
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400333 bool state = false;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400334
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400335 if( mbuf != NULL ) {
336 if( mtype != NO_CHANGE ) {
337 mbuf->mtype = mtype;
338 }
339 if( subid != NO_CHANGE ) {
340 mbuf->sub_id = subid;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400341 }
342
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400343 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
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400356 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;
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400368 }
369
370 state = mbuf->state == RMR_OK;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400371 }
372
E. Scott Daniels0b08d9d2020-03-27 10:18:37 -0400373 return state;
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400374}
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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400385bool 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 );
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400387}
388
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400389bool 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 );
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400391}
392
393/*
394 These allow a response message to be sent without changing the mtype/subid.
395*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400396bool 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 );
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400398}
399
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400400bool xapp::Message::Send_response( int response_len, unsigned char* response ) {
401 return Send( NO_CHANGE, NO_CHANGE, response_len, response, RESPONSE, NO_WHID );
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400402}
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*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400414bool 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 );
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400416}
417
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400418bool 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 );
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400420}
421
422/*
423 Similar send functions that allow the message type/subid to remain unchanged
424*/
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400425bool 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 );
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400427}
428
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400429bool xapp::Message::Send_msg( int payload_len, unsigned char* payload ) {
430 return Send( NO_CHANGE, NO_CHANGE, payload_len, payload, MESSAGE, NO_WHID );
E. Scott Daniels8cb3c6f2020-03-19 11:36:37 -0400431}
E. Scott Daniels6ef23e12020-07-15 08:03:22 -0400432
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*/
440bool 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