Initial source commit
[ric-plt/xapp-frame-cpp.git] / src / messaging / message.cpp
diff --git a/src/messaging/message.cpp b/src/messaging/message.cpp
new file mode 100644 (file)
index 0000000..0c6b262
--- /dev/null
@@ -0,0 +1,320 @@
+// vi: ts=4 sw=4 noet:
+/*
+==================================================================================
+       Copyright (c) 2020 Nokia
+       Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       message.cpp
+       Abstract:       A message wrapper. This should completely hide the
+                               underlying transport (RMR) message structure from
+                               the user application. For the most part, the getters
+                               are used by the framwork; it is unlikely that other
+                               than adding/extracting the MEID, the user app will
+                               be completely unaware of information that is not
+                               presented in the callback parms.
+
+       Date:           12 March 2020
+       Author:         E. Scott Daniels
+*/
+
+#include <string.h>
+#include <unistd.h>
+
+#include <rmr/rmr.h>
+
+#include <iostream>
+
+#include "message.hpp"
+
+// --------------- private ------------------------------------------------
+
+// --------------- builders -----------------------------------------------
+
+/*
+       Create a new message wrapper for an existing RMR msg buffer.
+*/
+Message::Message( rmr_mbuf_t* mbuf, void* mrc ) {
+       this->mrc = mrc;                        // the message router context for sends
+       this->mbuf = mbuf;
+}
+
+Message::Message( void* mrc, int payload_len ) {
+       this->mrc = mrc;
+       this->mbuf = rmr_alloc_msg( mrc, payload_len );
+}
+
+/*
+       Destroyer.
+*/
+Message::~Message() {
+       if( mbuf != NULL ) {
+               rmr_free_msg( mbuf );
+       }
+
+       mbuf = NULL;
+}
+
+
+// --- getters/setters -----------------------------------------------------
+/*
+       Copy the payload bytes, and return a smart pointer (unique) to it.
+       If the application needs to update the payload in place for a return
+       to sender call, or just to access the payload in a more efficent manner
+       (without the copy), the Get_payload() function should be considered.
+
+       This function will return a NULL pointer if malloc fails.
+*/
+//char* Message::Copy_payload( ){
+std::unique_ptr<unsigned char> Message::Copy_payload( ){
+       unsigned char*  new_payload = NULL;
+
+       if( mbuf != NULL ) {
+               new_payload = (unsigned char *) malloc( sizeof( unsigned char ) * mbuf->len );
+               memcpy( new_payload, mbuf->payload, mbuf->len );
+       }
+
+       return std::unique_ptr<unsigned char>( new_payload );
+}
+
+/*
+       Makes a copy of the MEID and returns a smart pointer to it.
+*/
+std::unique_ptr<unsigned char> Message::Get_meid(){
+       unsigned char* m = NULL;
+
+       if( m != NULL ) {
+               m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_MEID );
+               rmr_get_meid( mbuf, m );
+       }
+
+       return std::unique_ptr<unsigned char>( m );
+}
+
+int Message::Get_available_size(){
+       if( mbuf != NULL ) {
+               return rmr_payload_size( mbuf );
+       }
+
+       return 0;
+}
+
+int    Message::Get_mtype(){
+       if( mbuf != NULL ) {
+               return mbuf->mtype;
+       }
+
+       return INVALID_MTYPE;
+}
+
+/*
+       Makes a copy of the source field and returns a smart pointer to it.
+*/
+std::unique_ptr<unsigned char> Message::Get_src(){
+       unsigned char* m = NULL;
+
+       m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_SRC );
+       if( m != NULL ) {
+               rmr_get_src( mbuf, m );
+       }
+
+       return std::unique_ptr<unsigned char>( m );
+}
+
+int    Message::Get_state( ){
+       if( mbuf != NULL ) {
+               return mbuf->state;
+       }
+
+       return INVALID_STATUS;
+}
+
+int    Message::Get_subid(){
+       if( mbuf != NULL ) {
+               return mbuf->sub_id;
+       }
+
+       return INVALID_SUBID;
+}
+
+int    Message::Get_len(){
+       if( mbuf != NULL ) {
+               return mbuf->len;
+       }
+
+       return 0;
+}
+
+/*
+       This returns a smart (unique) pointer to the payload portion of the
+       message. This provides the user application with the means to
+       update the payload in place to avoid multiple copies.  The
+       user programme is responsible to determing the usable payload
+       length by calling Message:Get_available_size(), and ensuring that
+       writing beyond the indicated size does not happen.
+*/
+Msg_component Message::Get_payload(){
+       if( mbuf != NULL ) {
+               return std::unique_ptr<unsigned char, unfreeable>( mbuf->payload );
+       }
+
+       return NULL;
+}
+
+void Message::Set_meid( std::unique_ptr<unsigned char> new_meid ) {
+       if( mbuf != NULL ) {
+               rmr_str2meid( mbuf, (unsigned char *) new_meid.get() );
+       }
+}
+
+void Message::Set_mtype( int new_type ){
+       if( mbuf != NULL ) {
+               mbuf->mtype = new_type;
+       }
+}
+
+void Message::Set_subid( int new_subid ){
+       if( mbuf != NULL ) {
+               mbuf->sub_id = new_subid;
+       }
+}
+
+
+// -------------- send functions ---------------------------------
+
+/*
+       This assumes that the contents of the mbuf were set by either a send attempt that
+       failed with a retry and thus is ready to be processed by RMR.
+       Exposed to the user, but not expected to be frequently used.
+*/
+bool Message::Send( ) {
+       if( mbuf == NULL ) {
+               return false;
+       }
+
+       mbuf =  rmr_send_msg( mrc, mbuf );
+       return mbuf->state == RMR_OK;
+}
+
+/*
+       Similar to Send(), this assumes that the message is already set up and this is a retry.
+       Exposed to the user, but not expected to be frequently used.
+*/
+bool Message::Reply( ) {
+       if( mbuf == NULL ) {
+               return false;
+       }
+
+       mbuf =  rmr_rts_msg( mrc, mbuf );
+       return mbuf->state == RMR_OK;
+}
+
+/*
+       Send workhorse.
+       This will setup the message (type etc.) ensure the message payload space is
+       large enough and copy in the payload (if a new payload is given), then will
+       either send or rts the message based on the stype parm.
+
+       If payload is nil, then we assume the user updated the payload in place and
+       no copy is needed.
+
+       This is public, but most users should use Send_msg or Send_response functions.
+*/
+bool Message::Send( int mtype, int subid, int payload_len, unsigned char* payload, int stype ) {
+
+       if( mbuf == NULL ) {
+               return false;
+       }
+
+       mbuf->mtype = mtype;
+       mbuf->sub_id = subid;
+       mbuf->len = payload_len;
+
+       if( payload != NULL ) {                 // if we have a payload, ensure msg has room, realloc if needed, then copy
+               mbuf = rmr_realloc_payload( mbuf, payload_len, RMR_NO_COPY, RMR_NO_CLONE );             // ensure message is large enough
+               if( mbuf == NULL ) {
+                       return false;
+               }
+
+               memcpy( mbuf->payload, payload, mbuf->len );
+       }
+
+       if( stype == RESPONSE ) {
+               mbuf = rmr_rts_msg( mrc, mbuf );
+       } else {
+               mbuf = rmr_send_msg( mrc, mbuf );
+       }
+
+       return mbuf->state == RMR_OK;
+}
+
+/*
+       Send a response to the endpoint that sent the original message.
+
+       Response can be null and the assumption will be that the message payload
+       was updated in place and no additional copy is needed before sending the message.
+
+       The second form of the call allows for a stack allocated buffer (e.g. char foo[120]) to
+       be passed as the payload.
+*/
+bool Message::Send_response(  int mtype, int subid, int response_len, std::unique_ptr<unsigned char> response ) {
+       return Send( mtype, subid, response_len, response.get(), RESPONSE );
+}
+
+bool Message::Send_response(  int mtype, int subid, int response_len, unsigned char* response ) {
+       return Send( mtype, subid, response_len, response, RESPONSE );
+}
+
+/*
+       These allow a response message to be sent without changing the mtype/subid.
+*/
+bool Message::Send_response(  int response_len, std::unique_ptr<unsigned char> response ) {
+       return Send( NOCHANGE, NOCHANGE, response_len, response.get(), RESPONSE );
+}
+
+bool Message::Send_response(  int response_len, unsigned char* response ) {
+       return Send( NOCHANGE, NOCHANGE, response_len, response, RESPONSE );
+}
+
+
+/*
+       Send a message based on message type routing.
+
+       Payload can be null and the assumption will be that the message payload
+       was updated in place and no additional copy is needed before sending the message.
+
+       Return is a new mbuf suitable for sending another message, or the original buffer with
+       a bad state sent if there was a failure.
+*/
+bool Message::Send_msg(  int mtype, int subid, int payload_len, std::unique_ptr<unsigned char> payload ) {
+       return Send( mtype, subid, payload_len, payload.get(), MESSAGE );
+}
+
+bool Message::Send_msg(  int mtype, int subid, int payload_len, unsigned char* payload ) {
+       return Send( mtype, subid, payload_len, payload, MESSAGE );
+}
+
+/*
+       Similar send functions that allow the message type/subid to remain unchanged
+*/
+bool Message::Send_msg(  int payload_len, std::unique_ptr<unsigned char> payload ) {
+       return Send( NOCHANGE, NOCHANGE, payload_len, payload.get(), MESSAGE );
+}
+
+bool Message::Send_msg(  int payload_len, unsigned char* payload ) {
+       return Send( NOCHANGE, NOCHANGE, payload_len, payload, MESSAGE );
+}