diff --git a/CHANGES b/CHANGES index a305c95..0ad2239 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ Changes ======= +v3.1.12.2 +- Always call subscribe with TCP_AND_UDP subscription type +- Support for NUL (U+0000) code point within strings v3.1.12.1 - Adapt to vSomeIP 2.8.0: Don't call subscription status handler on SubscribeEventGroupNACK for non selective subscriptions diff --git a/CMakeLists.txt b/CMakeLists.txt index d5a82ed..ebbac41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,7 +132,7 @@ message(STATUS "CommonAPI Version: ${CommonAPI_VERSION}") find_package( Boost 1.54 COMPONENTS system thread log REQUIRED ) include_directories( ${Boost_INCLUDE_DIR} ) -find_package (vsomeip 2.7.0 REQUIRED) +find_package (vsomeip 2.9.0 REQUIRED) message(STATUS "vsomeip version: ${vsomeip_VERSION}") include_directories ( diff --git a/include/CommonAPI/SomeIP/Connection.hpp b/include/CommonAPI/SomeIP/Connection.hpp index 477e63d..57439f6 100644 --- a/include/CommonAPI/SomeIP/Connection.hpp +++ b/include/CommonAPI/SomeIP/Connection.hpp @@ -196,9 +196,9 @@ class Connection: virtual void processMsgQueueEntry(MsgQueueEntry &_msgQueueEntry); virtual void processAvblQueueEntry(AvblQueueEntry &_avblQueueEntry); - virtual void processErrQueueEntry(ErrQueueEntry &_errQueueEntry); + virtual void processErrQueueEntry(ErrQueueEntry &_errQueueEntry); - template + template void processFunctionQueueEntry(FunctionQueueEntry &_functionQueueEntry); virtual const ConnectionId_t& getConnectionId(); diff --git a/include/CommonAPI/SomeIP/ProxyHelper.hpp b/include/CommonAPI/SomeIP/ProxyHelper.hpp index 375dcb9..31a4348 100644 --- a/include/CommonAPI/SomeIP/ProxyHelper.hpp +++ b/include/CommonAPI/SomeIP/ProxyHelper.hpp @@ -35,18 +35,18 @@ template < template class Out_, class... OutArgs_> struct ProxyHelper, Out_> { - template - static void callMethod( - Proxy_ &_proxy, - const method_id_t _methodId, - const bool _isReliable, - const bool _isLittleEndian, - const InArgs_ &... _inArgs, - CommonAPI::CallStatus &_callStatus) { + template + static void callMethod( + Proxy_ &_proxy, + const method_id_t _methodId, + const bool _isReliable, + const bool _isLittleEndian, + const InArgs_ &... _inArgs, + CommonAPI::CallStatus &_callStatus) { - Message methodCall = _proxy.createMethodCall(_methodId, _isReliable); - callMethod(_proxy, methodCall, _isLittleEndian, _inArgs..., _callStatus); - } + Message methodCall = _proxy.createMethodCall(_methodId, _isReliable); + callMethod(_proxy, methodCall, _isLittleEndian, _inArgs..., _callStatus); + } template static void callMethod( diff --git a/src/CommonAPI/SomeIP/Connection.cpp b/src/CommonAPI/SomeIP/Connection.cpp index a8dc562..f0d95a8 100644 --- a/src/CommonAPI/SomeIP/Connection.cpp +++ b/src/CommonAPI/SomeIP/Connection.cpp @@ -36,31 +36,31 @@ void ErrQueueEntry::process(std::shared_ptr _connection) { } void Connection::receive(const std::shared_ptr &_message) { - commDirectionType itsDirection = - (_message->get_message_type() < vsomeip::message_type_e::MT_NOTIFICATION ? - commDirectionType::STUBRECEIVE : commDirectionType::PROXYRECEIVE); - - // avoid blocking the mainloop - bool isSendAndBlockAnswer = false; - { - std::lock_guard itsLock(sendReceiveMutex_); - if(_message->get_message_type() != vsomeip::message_type_e::MT_NOTIFICATION && - sendAndBlockAnswers_.find(_message->get_session()) != sendAndBlockAnswers_.end()) { - isSendAndBlockAnswer = true; - } - } + commDirectionType itsDirection = + (_message->get_message_type() < vsomeip::message_type_e::MT_NOTIFICATION ? + commDirectionType::STUBRECEIVE : commDirectionType::PROXYRECEIVE); + + // avoid blocking the mainloop + bool isSendAndBlockAnswer = false; + { + std::lock_guard itsLock(sendReceiveMutex_); + if(_message->get_message_type() != vsomeip::message_type_e::MT_NOTIFICATION && + sendAndBlockAnswers_.find(_message->get_session()) != sendAndBlockAnswers_.end()) { + isSendAndBlockAnswer = true; + } + } if (auto lockedContext = mainLoopContext_.lock() && !isSendAndBlockAnswer) { (void)lockedContext; std::shared_ptr msg_queue_entry - = std::make_shared(_message, itsDirection); + = std::make_shared(_message, itsDirection); watch_->pushQueue(msg_queue_entry); } else { - if (itsDirection == commDirectionType::PROXYRECEIVE) { - handleProxyReceive(_message); - } else { - handleStubReceive(_message); - } + if (itsDirection == commDirectionType::PROXYRECEIVE) { + handleProxyReceive(_message); + } else { + handleStubReceive(_message); + } } } @@ -127,7 +127,11 @@ void Connection::handleProxyReceive(const std::shared_ptr &_me callStatus = CallStatus::REMOTE_ERROR; } - itsHandler->onMessageReply(callStatus, Message(_message)); + try { + itsHandler->onMessageReply(callStatus, Message(_message)); + } catch (const std::exception& e) { + COMMONAPI_ERROR("Message reply failed(", e.what(), ")"); + } return; } @@ -139,7 +143,11 @@ void Connection::handleProxyReceive(const std::shared_ptr &_me asyncTimeouts_.erase(sessionId); sendReceiveMutex_.unlock(); - itsHandler->onMessageReply(CallStatus::REMOTE_ERROR, Message(_message)); + try { + itsHandler->onMessageReply(CallStatus::REMOTE_ERROR, Message(_message)); + } catch (const std::exception& e) { + COMMONAPI_ERROR("Message reply failed on timeout(", e.what(), ")"); + } } else { sendReceiveMutex_.unlock(); } @@ -207,8 +215,12 @@ void Connection::handleAvailabilityChange(const service_id_t _service, watch_->pushQueue(msg_queue_entry); asyncTimeouts_[it->first] = std::move(it->second); } else { - std::get<2>(it->second)->onMessageReply( - CallStatus::REMOTE_ERROR, Message(itsResponse)); + try { + std::get<2>(it->second)->onMessageReply( + CallStatus::REMOTE_ERROR, Message(itsResponse)); + } catch (const std::exception& e) { + COMMONAPI_ERROR("Message reply failed when service became unavailable(", e.what(), ")"); + } } it = asyncAnswers_.erase(it); } else { @@ -273,7 +285,11 @@ void Connection::cleanup() { watch_->pushQueue(msg_queue_entry); asyncTimeouts_[it->first] = std::move(it->second); } else { - std::get<2>(it->second)->onMessageReply(CallStatus::REMOTE_ERROR, Message(response)); + try { + std::get<2>(it->second)->onMessageReply(CallStatus::REMOTE_ERROR, Message(response)); + } catch (const std::exception& e) { + COMMONAPI_ERROR("Message reply failed on cleanup(", e.what(), ")"); + } } it = asyncAnswers_.erase(it); } else { @@ -349,7 +365,7 @@ bool Connection::attachMainLoopContext(std::weak_ptr mainLoopCo bool Connection::connect(bool) { if (!application_->init()) - return false; + return false; std::function connectionHandler = std::bind(&Connection::onConnectionEvent, shared_from_this(), @@ -466,12 +482,12 @@ Message Connection::sendMessageWithReplyAndBlock( const Message& message, const CommonAPI::CallInfo *_info) const { - if (!isConnected()) + if (!isConnected()) return Message(); std::unique_lock lock(sendReceiveMutex_); - std::pair::iterator, bool> itsAnswer; + std::pair::iterator, bool> itsAnswer; application_->send(message.message_, true); if (_info->sender_ != 0) { COMMONAPI_DEBUG("Message sent: SenderID: ", _info->sender_, @@ -601,7 +617,7 @@ void Connection::subscribe(service_id_t serviceId, instance_id_t instanceId, eventHandler, _tag); application_->subscribe(serviceId, instanceId, eventGroupId, major, - vsomeip::subscription_type_e::SU_PREFER_RELIABLE, eventId); + vsomeip::subscription_type_e::SU_RELIABLE_AND_UNRELIABLE, eventId); } void Connection::addSubscriptionStatusListener(service_id_t serviceId, diff --git a/src/CommonAPI/SomeIP/Factory.cpp b/src/CommonAPI/SomeIP/Factory.cpp index 65fc6f2..7b7ce29 100644 --- a/src/CommonAPI/SomeIP/Factory.cpp +++ b/src/CommonAPI/SomeIP/Factory.cpp @@ -43,27 +43,27 @@ Factory::~Factory() { void Factory::init() { #ifndef _WIN32 - std::lock_guard itsLock(initializerMutex_); + std::lock_guard itsLock(initializerMutex_); #endif - if (!isInitialized_) { - for (auto i : initializers_) i(); - initializers_.clear(); // Not needed anymore - isInitialized_ = true; - } + if (!isInitialized_) { + for (auto i : initializers_) i(); + initializers_.clear(); // Not needed anymore + isInitialized_ = true; + } } void Factory::registerInterface(InterfaceInitFunction _function) { #ifndef _WIN32 - std::lock_guard itsLock(initializerMutex_); + std::lock_guard itsLock(initializerMutex_); #endif - if (isInitialized_) { - // We are already running --> initialize the interface library! - _function(); - } else { - // We are not initialized --> save the initializer - initializers_.push_back(_function); - } + if (isInitialized_) { + // We are already running --> initialize the interface library! + _function(); + } else { + // We are not initialized --> save the initializer + initializers_.push_back(_function); + } } void @@ -198,17 +198,17 @@ Factory::registerStub( CommonAPI::Address address(_domain, _interface, _instance); Address someipAddress; if (AddressTranslator::get()->translate(address, someipAddress)) { - std::shared_ptr itsConnection = getConnection(_context); - if (itsConnection) { - std::shared_ptr adapter - = stubAdapterCreateFunctionsIterator->second( - someipAddress, itsConnection, _stub); - if (adapter) { - adapter->init(adapter); - if (registerStubAdapter(adapter)) - return true; - } - } + std::shared_ptr itsConnection = getConnection(_context); + if (itsConnection) { + std::shared_ptr adapter + = stubAdapterCreateFunctionsIterator->second( + someipAddress, itsConnection, _stub); + if (adapter) { + adapter->init(adapter); + if (registerStubAdapter(adapter)) + return true; + } + } } } @@ -351,10 +351,10 @@ Factory::getConnection(const ConnectionId_t &_connectionId) { = std::make_shared(_connectionId); if (itsConnection) { if (!itsConnection->connect(true)) { - COMMONAPI_ERROR("Failed to create connection ", _connectionId); - itsConnection.reset(); + COMMONAPI_ERROR("Failed to create connection ", _connectionId); + itsConnection.reset(); } else { - connections_.insert({ _connectionId, itsConnection } ); + connections_.insert({ _connectionId, itsConnection } ); } } @@ -380,18 +380,18 @@ Factory::getConnection(std::shared_ptr _context) { itsConnection = std::make_shared(_context->getName()); if (itsConnection) { if (!itsConnection->connect(false)) { - COMMONAPI_ERROR("Failed to create connection ", - _context->getName()); - itsConnection.reset(); + COMMONAPI_ERROR("Failed to create connection ", + _context->getName()); + itsConnection.reset(); } else { - connections_.insert({ _context->getName(), itsConnection } ); + connections_.insert({ _context->getName(), itsConnection } ); } } } if (itsConnection) { incrementConnection(itsConnection); - itsConnection->attachMainLoopContext(_context); + itsConnection->attachMainLoopContext(_context); } return itsConnection; diff --git a/src/CommonAPI/SomeIP/InputStream.cpp b/src/CommonAPI/SomeIP/InputStream.cpp index 257121d..f652b67 100644 --- a/src/CommonAPI/SomeIP/InputStream.cpp +++ b/src/CommonAPI/SomeIP/InputStream.cpp @@ -248,26 +248,30 @@ InputStream& InputStream::readValue(std::string &_value, const StringDeployment { case StringEncoding::UTF16BE: while (itsSize > 1 && (data[itsSize - 1] != 0x00 || data[itsSize - 2] != 0x00)) - itsSize--; + itsSize--; if (itsSize % 2 != 0) { - errorOccurred_ = true; + errorOccurred_ = true; } - if(!hasError()) + if(!hasError()) { encoder->utf16To8((byte_t *) data, BIG_ENDIAN, itsSize - 2, status, &bytes, length); + itsSize = static_cast(length); + } break; case StringEncoding::UTF16LE: while (itsSize > 1 && (data[itsSize - 1] != 0x00 || data[itsSize - 2] != 0x00)) - itsSize--; + itsSize--; if (itsSize % 2 != 0) { - errorOccurred_ = true; + errorOccurred_ = true; } - if(!hasError()) + if(!hasError()) { encoder->utf16To8((byte_t *) data, LITTLE_ENDIAN, itsSize - 2, status, &bytes, length); + itsSize = static_cast(length); + } break; default: @@ -301,14 +305,15 @@ InputStream& InputStream::readValue(std::string &_value, const StringDeployment errorOccurred_ = true; } if (bytes == NULL) { - _value = ""; - } else { - _value = (char*)bytes; - //only delete bytes if not allocated in this function (this is the case for deployed fixed length UTF8 strings) - if( bytes != (byte_t *) data) - delete[] bytes; - bytes = NULL; - } + _value = ""; + } else { + // explicitly assign to support NUL (U+0000 code point) in UTF-8 strings + _value.assign(std::string((const char*)bytes, itsSize - 1u)); + //only delete bytes if not allocated in this function (this is the case for deployed fixed length UTF8 strings) + if( bytes != (byte_t *) data) + delete[] bytes; + bytes = NULL; + } } return *this;