Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fixes for Windows and the OPC UA server #312

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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 \
Expand Down
43 changes: 43 additions & 0 deletions include/opc/ua/protocol/input_from_stream_buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/******************************************************************************
* Copyright (C) 2013-2014 by Alexander Rykovanov *
* [email protected] *
* *
* 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 <opc/ua/protocol/channel.h>
#include <boost/asio/streambuf.hpp>

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

}
9 changes: 9 additions & 0 deletions include/opc/ua/protocol/status_codes.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#pragma once

#include <stdint.h>
#include <stdexcept>

namespace OpcUa
{
Expand Down Expand Up @@ -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;
};

}

4 changes: 2 additions & 2 deletions python/src/py_opcua_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ static void Node_SetValue(Node & self, const object & obj, VariantType vtype)
// UaClient helpers
//--------------------------------------------------------------------------

static std::shared_ptr<Subscription> UaClient_CreateSubscription(UaClient & self, uint period, PySubscriptionHandler & callback)
static std::shared_ptr<Subscription> UaClient_CreateSubscription(UaClient & self, uint32_t period, PySubscriptionHandler & callback)
{
return self.CreateSubscription(period, callback);
}
Expand All @@ -256,7 +256,7 @@ static Node UaClient_GetNode(UaClient & self, ObjectId objectid)
// UaServer helpers
//--------------------------------------------------------------------------

static std::shared_ptr<Subscription> UaServer_CreateSubscription(UaServer & self, uint period, PySubscriptionHandler & callback)
static std::shared_ptr<Subscription> UaServer_CreateSubscription(UaServer & self, uint32_t period, PySubscriptionHandler & callback)
{
return self.CreateSubscription(period, callback);
}
Expand Down
46 changes: 1 addition & 45 deletions src/core/common/uri_facade_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,4 @@
/// (See accompanying file LICENSE or copy at
/// http://www.gnu.org/licenses/lgpl.html)
///


#include <windows.h>
#include <wininet.h>

#include <opc/common/uri_facade.h>
#include <opc/common/exception.h>


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"
46 changes: 46 additions & 0 deletions src/protocol/input_from_stream_buffer.cpp
Original file line number Diff line number Diff line change
@@ -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 <opc/ua/protocol/input_from_stream_buffer.h>

#include <algorithm>

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

}
8 changes: 7 additions & 1 deletion src/protocol/status_codes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
4 changes: 2 additions & 2 deletions src/server/address_space_internal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,15 +283,15 @@ 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);

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;
Expand Down
15 changes: 10 additions & 5 deletions src/server/internal_subscription.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 9 additions & 9 deletions src/server/opc_tcp_async.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <opc/ua/protocol/binary/stream.h>
#include <opc/ua/protocol/channel.h>
#include <opc/ua/protocol/secure_channel.h>
#include <opc/ua/protocol/input_from_buffer.h>
#include <opc/ua/protocol/input_from_stream_buffer.h>

#include <array>
#include <boost/asio.hpp>
Expand Down Expand Up @@ -129,16 +129,16 @@ class OpcTcpConnection : public std::enable_shared_from_this<OpcTcpConnection>,
Server::OpcTcpMessages::SharedPtr MessageProcessor;
OStreamBinary OStream;
Common::Logger::SharedPtr Logger;
std::vector<char> Buffer;
boost::asio::streambuf StreamBuffer;
};

OpcTcpConnection::OpcTcpConnection(tcp::socket socket, OpcTcpServer & tcpServer, const Common::Logger::SharedPtr & logger)
: Socket(std::move(socket))
, 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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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<const char*>(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;
Expand All @@ -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)
Expand Down
Loading