diff --git a/CMakeLists.txt b/CMakeLists.txt index de03564e..28068e19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,22 +21,22 @@ IF (NOT DEFINED CMAKE_INSTALL_LIBDIR) ENDIF () SET (CMAKE_LIBRARY_OUTPUT_DIRECTORY - ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR} - CACHE PATH - "" - ) + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR} + CACHE PATH + "" + ) SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY - ${PROJECT_BINARY_DIR}/bin - CACHE PATH - "" - ) + ${PROJECT_BINARY_DIR}/bin + CACHE PATH + "" + ) SET (CMAKE_ARCHIVE_OUTPUT_DIRECTORY - ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR} - CACHE PATH - "" - ) + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR} + CACHE PATH + "" + ) # Helper function to generate a pkg-config file for a single library # Takes the filename of the .pc file as a parameter and replaces all @@ -65,6 +65,11 @@ if(MSVC) SET(DYNAMIC_LIBRARY_CXX_FLAGS /MDd CACHE STRING "") SET(D /D) + IF (BUILD_SHARED_LIBS) + SET(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_PROGRAM_OPTIONS_DYN_LINK=1) + ENDIF () + add_definitions(/D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32 /D_WINDOWS /FS /D_WIN32_WINNT=0x0600) add_compile_options(/Zi /Od /EHsc /W4) else(MSVC) @@ -155,7 +160,6 @@ ADD_CUSTOM_COMMAND( #DEPENDS ${PROJECT_SOURCE_DIR}/NodeIds.csv ) - add_library(opcuaprotocol src/protocol/rawsize_auto.cpp src/protocol/serialize_auto.cpp @@ -174,6 +178,7 @@ add_library(opcuaprotocol src/protocol/binary_variant.cpp src/protocol/binary_view.cpp src/protocol/input_from_buffer.cpp + src/protocol/input_from_stream_buffer.cpp src/protocol/monitored_items.cpp src/protocol/nodeid.cpp src/protocol/session.cpp diff --git a/Makefile.am b/Makefile.am index 1a27eff4..55b54834 100644 --- a/Makefile.am +++ b/Makefile.am @@ -245,6 +245,7 @@ protocolinclude_HEADERS = \ include/opc/ua/protocol/extension_identifiers.h \ include/opc/ua/protocol/guid.h \ include/opc/ua/protocol/input_from_buffer.h \ + include/opc/ua/protocol/input_from_stream_buffer.h \ include/opc/ua/protocol/message_identifiers.h \ include/opc/ua/protocol/monitored_items.h \ include/opc/ua/protocol/node_management.h \ @@ -281,6 +282,7 @@ libopcuaprotocol_la_SOURCES = \ src/protocol/binary_session.cpp \ src/protocol/binary_view.cpp \ src/protocol/input_from_buffer.cpp \ + src/protocol/input_from_stream_buffer.cpp \ src/protocol/monitored_items.cpp \ src/protocol/nodeid.cpp \ src/protocol/session.cpp \ diff --git a/include/opc/ua/protocol/input_from_stream_buffer.h b/include/opc/ua/protocol/input_from_stream_buffer.h new file mode 100644 index 00000000..2879fe08 --- /dev/null +++ b/include/opc/ua/protocol/input_from_stream_buffer.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (C) 2013-2014 by Alexander Rykovanov * + * rykovanov.as@gmail.com * + * * + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation; version 3 of the License. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this library; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ******************************************************************************/ + +#pragma once + +#include +#include + +namespace OpcUa +{ + +class InputFromStreamBuffer : public OpcUa::InputChannel +{ +public: + InputFromStreamBuffer(boost::asio::streambuf & buf); + + virtual std::size_t Receive(char * data, std::size_t size) override; + + size_t GetRemainSize() const; + + virtual void Stop() override {} + +private: + boost::asio::streambuf & Buffer; +}; + +} diff --git a/include/opc/ua/protocol/status_codes.h b/include/opc/ua/protocol/status_codes.h index 88c23d4a..946c02e3 100644 --- a/include/opc/ua/protocol/status_codes.h +++ b/include/opc/ua/protocol/status_codes.h @@ -6,6 +6,7 @@ #pragma once #include +#include namespace OpcUa { @@ -233,5 +234,13 @@ enum class StatusCode : uint32_t //raise appropriate exception if StatusCode is not Good void CheckStatusCode(StatusCode code); +class StatusCodeException : public std::runtime_error { +public: + explicit StatusCodeException(StatusCode value); + StatusCode GetValue() const; +private: + StatusCode Value; +}; + } diff --git a/python/src/py_opcua_module.cpp b/python/src/py_opcua_module.cpp index 5b13f4ed..9d139a9a 100644 --- a/python/src/py_opcua_module.cpp +++ b/python/src/py_opcua_module.cpp @@ -242,7 +242,7 @@ static void Node_SetValue(Node & self, const object & obj, VariantType vtype) // UaClient helpers //-------------------------------------------------------------------------- -static std::shared_ptr UaClient_CreateSubscription(UaClient & self, uint period, PySubscriptionHandler & callback) +static std::shared_ptr UaClient_CreateSubscription(UaClient & self, uint32_t period, PySubscriptionHandler & callback) { return self.CreateSubscription(period, callback); } @@ -256,7 +256,7 @@ static Node UaClient_GetNode(UaClient & self, ObjectId objectid) // UaServer helpers //-------------------------------------------------------------------------- -static std::shared_ptr UaServer_CreateSubscription(UaServer & self, uint period, PySubscriptionHandler & callback) +static std::shared_ptr UaServer_CreateSubscription(UaServer & self, uint32_t period, PySubscriptionHandler & callback) { return self.CreateSubscription(period, callback); } diff --git a/src/core/common/uri_facade_win.cpp b/src/core/common/uri_facade_win.cpp index 1a807fb8..aaca564d 100644 --- a/src/core/common/uri_facade_win.cpp +++ b/src/core/common/uri_facade_win.cpp @@ -7,48 +7,4 @@ /// (See accompanying file LICENSE or copy at /// http://www.gnu.org/licenses/lgpl.html) /// - - -#include -#include - -#include -#include - - -namespace Common -{ - -void Uri::Initialize(const char * uriString, std::size_t size) -{ - URL_COMPONENTS url = {0}; - url.dwStructSize = sizeof(url); - url.dwSchemeLength = 1; - url.dwUserNameLength = 1; - url.dwPasswordLength = 1; - url.dwHostNameLength = 1; - DWORD options = 0; - - // TODO msdn says do not use this function in services and in server patforms. :( - // TODO http://msdn.microsoft.com/en-us/library/windows/desktop/aa384376(v=vs.85).aspx - if (!InternetCrackUrl(uriString, size, options, &url)) - { - THROW_ERROR1(CannotParseUri, uriString); - } - - - SchemeStr = std::string(url.lpszScheme, url.lpszScheme + url.dwSchemeLength); - UserStr = std::string(url.lpszUserName, url.lpszUserName + url.dwUserNameLength); - PasswordStr = std::string(url.lpszPassword, url.lpszPassword + url.dwPasswordLength); - HostStr = std::string(url.lpszHostName, url.lpszHostName + url.dwHostNameLength); - PortNum = url.nPort; - - if (SchemeStr.empty() || HostStr.empty()) - { - THROW_ERROR1(CannotParseUri, uriString); - } -} - -} // namespace Common - - +#include "uri_facade_lin.cpp" \ No newline at end of file diff --git a/src/protocol/input_from_stream_buffer.cpp b/src/protocol/input_from_stream_buffer.cpp new file mode 100644 index 00000000..288e36bc --- /dev/null +++ b/src/protocol/input_from_stream_buffer.cpp @@ -0,0 +1,46 @@ +/****************************************************************************** + * This library is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation; version 3 of the License. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this library; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ******************************************************************************/ + +#include + +#include + +namespace OpcUa +{ + +InputFromStreamBuffer::InputFromStreamBuffer(boost::asio::streambuf & buf) : Buffer(buf) +{ + +} + +std::size_t InputFromStreamBuffer::Receive(char * data, std::size_t size) +{ + size_t bufferSize = GetRemainSize(); + if (bufferSize == 0) + { + return 0; + } + + const std::size_t sizeToRead = std::min(bufferSize, size); + Buffer.sgetn(data, sizeToRead); + return sizeToRead; +} + +size_t InputFromStreamBuffer::GetRemainSize() const { + return Buffer.size(); +} + +} diff --git a/src/protocol/status_codes.cpp b/src/protocol/status_codes.cpp index 30eb1fd0..de5881f5 100644 --- a/src/protocol/status_codes.cpp +++ b/src/protocol/status_codes.cpp @@ -19,7 +19,13 @@ void OpcUa::CheckStatusCode(StatusCode code) if (code == StatusCode::Good) { return; } - throw std::runtime_error(OpcUa::ToString(code)); + throw StatusCodeException(code); } +OpcUa::StatusCodeException::StatusCodeException(StatusCode value) : runtime_error(OpcUa::ToString(value)), Value(value) { +} + +OpcUa::StatusCode OpcUa::StatusCodeException::GetValue() const { + return Value; +} diff --git a/src/server/address_space_internal.cpp b/src/server/address_space_internal.cpp index 161ba980..934ab7b8 100644 --- a/src/server/address_space_internal.cpp +++ b/src/server/address_space_internal.cpp @@ -283,7 +283,7 @@ uint32_t AddressSpaceInMemory::AddDataChangeCallback(const NodeId & node, Attrib if (it == Nodes.end()) { LOG_ERROR(Logger, "address_space_internal| Node: '{}' not found", node); - throw std::runtime_error("address_space_internal| NodeId not found"); + throw StatusCodeException(StatusCode::BadNodeIdUnknown); } AttributesMap::iterator ait = it->second.Attributes.find(attribute); @@ -291,7 +291,7 @@ uint32_t AddressSpaceInMemory::AddDataChangeCallback(const NodeId & node, Attrib if (ait == it->second.Attributes.end()) { LOG_ERROR(Logger, "address_space_internal| Attribute: {} of node: ‘{}‘ not found", (unsigned)attribute, node); - throw std::runtime_error("Attribute not found"); + throw StatusCodeException(StatusCode::BadAttributeIdInvalid); } uint32_t handle = ++DataChangeCallbackHandle; diff --git a/src/server/internal_subscription.cpp b/src/server/internal_subscription.cpp index edf4715b..8b06a40e 100644 --- a/src/server/internal_subscription.cpp +++ b/src/server/internal_subscription.cpp @@ -303,12 +303,17 @@ MonitoredItemCreateResult InternalSubscription::CreateMonitoredItem(const Monito if (request.ItemToMonitor.AttributeId != AttributeId::EventNotifier) { LOG_DEBUG(Logger, "internal_subscription | id: {}, subscribe to data changes", Data.SubscriptionId); - + uint32_t id = result.MonitoredItemId; - callbackHandle = AddressSpace.AddDataChangeCallback(request.ItemToMonitor.NodeId, request.ItemToMonitor.AttributeId, [this, id](const OpcUa::NodeId & nodeId, OpcUa::AttributeId attr, const DataValue & value) - { - this->DataChangeCallback(id, value); - }); + try { + callbackHandle = AddressSpace.AddDataChangeCallback(request.ItemToMonitor.NodeId, request.ItemToMonitor.AttributeId, [this, id](const OpcUa::NodeId & nodeId, OpcUa::AttributeId attr, const DataValue & value) + { + this->DataChangeCallback(id, value); + }); + } catch (StatusCodeException e){ + result.Status = e.GetValue(); + return result; + } } MonitoredDataChange mdata; diff --git a/src/server/opc_tcp_async.cpp b/src/server/opc_tcp_async.cpp index dc700c2b..1e09f314 100644 --- a/src/server/opc_tcp_async.cpp +++ b/src/server/opc_tcp_async.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -129,7 +129,7 @@ class OpcTcpConnection : public std::enable_shared_from_this, Server::OpcTcpMessages::SharedPtr MessageProcessor; OStreamBinary OStream; Common::Logger::SharedPtr Logger; - std::vector Buffer; + boost::asio::streambuf StreamBuffer; }; OpcTcpConnection::OpcTcpConnection(tcp::socket socket, OpcTcpServer & tcpServer, const Common::Logger::SharedPtr & logger) @@ -137,8 +137,8 @@ OpcTcpConnection::OpcTcpConnection(tcp::socket socket, OpcTcpServer & tcpServer, , TcpServer(tcpServer) , OStream(*this) , Logger(logger) - , Buffer(8192) { + StreamBuffer.prepare(8192); } OpcTcpConnection::SharedPtr OpcTcpConnection::create(tcp::socket socket, OpcTcpServer & tcpServer, Services::SharedPtr uaServer, const Common::Logger::SharedPtr & logger) @@ -166,7 +166,7 @@ void OpcTcpConnection::ReadNextData() // do not lose reference to shared instance even if another // async operation decides to call GoodBye() OpcTcpConnection::SharedPtr self = shared_from_this(); - async_read(Socket, buffer(Buffer), transfer_exactly(GetHeaderSize()), + async_read(Socket, StreamBuffer, transfer_exactly(GetHeaderSize()), [self](const boost::system::error_code & error, std::size_t bytes_transferred) { try @@ -198,7 +198,7 @@ void OpcTcpConnection::ProcessHeader(const boost::system::error_code & error, st LOG_DEBUG(Logger, "opc_tcp_async | received message header with size: {}", bytes_transferred); - OpcUa::InputFromBuffer messageChannel(&Buffer[0], bytes_transferred); + OpcUa::InputFromStreamBuffer messageChannel(StreamBuffer); IStreamBinary messageStream(messageChannel); OpcUa::Binary::Header header; messageStream >> header; @@ -210,7 +210,7 @@ void OpcTcpConnection::ProcessHeader(const boost::system::error_code & error, st // do not lose reference to shared instance even if another // async operation decides to call GoodBye() OpcTcpConnection::SharedPtr self = shared_from_this(); - async_read(Socket, buffer(Buffer), transfer_exactly(messageSize), + async_read(Socket, StreamBuffer, transfer_exactly(messageSize), [self, header](const boost::system::error_code & error, std::size_t bytesTransferred) { self->ProcessMessage(header.Type, error, bytesTransferred); @@ -228,10 +228,10 @@ void OpcTcpConnection::ProcessMessage(OpcUa::Binary::MessageType type, const boo return; } - LOG_TRACE(Logger, "opc_tcp_async | received message: {}", ToHexDump(Buffer, bytesTransferred)); + LOG_TRACE(Logger, "opc_tcp_async | received message: {}", ToHexDump(boost::asio::buffer_cast(StreamBuffer.data()), bytesTransferred)); // restrict server size code only with current message. - OpcUa::InputFromBuffer messageChannel(&Buffer[0], bytesTransferred); + OpcUa::InputFromStreamBuffer messageChannel(StreamBuffer); IStreamBinary messageStream(messageChannel); bool cont = true; @@ -250,7 +250,7 @@ void OpcTcpConnection::ProcessMessage(OpcUa::Binary::MessageType type, const boo if (messageChannel.GetRemainSize()) { - std::cerr << "opc_tcp_async | ERROR!!! Message from client has been processed partially." << std::endl; + LOG_ERROR(Logger, "opc_tcp_async | ERROR!!! Message from client has been processed partially."); } if (!cont) diff --git a/src/server/server_object.cpp b/src/server/server_object.cpp index f35b168b..f94a8c3a 100644 --- a/src/server/server_object.cpp +++ b/src/server/server_object.cpp @@ -25,7 +25,7 @@ #include #include -#ifdef WIN32 +#ifdef _WIN32 #undef GetObject #endif diff --git a/src/server/tcp_server.cpp b/src/server/tcp_server.cpp index b4f20005..ada46992 100644 --- a/src/server/tcp_server.cpp +++ b/src/server/tcp_server.cpp @@ -9,7 +9,10 @@ /// #ifdef _WIN32 +#define NOMINMAX +#include #include +#define SHUT_RDWR SD_BOTH #endif #include "tcp_server.h"