| // 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 ); |
| } |