UA Server SDK C++ Bundle  1.3.3.206
 All Data Structures Namespaces Functions Variables Typedefs Enumerations Enumerator Groups Pages
Lesson 1: Setting up a basic OPC UA Server console application

This lesson will guide you through the process of setting up a basic OPC UA Server console application.

Content:

Utilities Used in this Lesson

The lesson uses servermain.cpp from examples.

In addition the following utility files are used from examples/utilities:

  • opcserver.h/opcserver.cpp
  • serverconfigxml.h / serverconfigxml.cpp
  • shutdown.h/shutdown.cpp

Linux specific: Signal handlers

On Linux you SHOULD install a signal handler to handle SIGPIPE. SIGPIPE is sent when writing on a closed socket which can happen when a connection is broken. The default handler terminates the application which is the desired behaviour when using pipes for inter-process communication, but not for networking applications like OPC UA. You can ignore this signal by calling signal(SIGPIPE, SIG_IGN) or by installing a signal handler.

You should also handle the signals SIGINT and SIGTERM like shown in the following example. SIGINT is sent when a user wants to interrupt a process by pressing CTRL-C on controlling terminal. SIGTERM is sent when a process is requested to terminate. SIGTERM is the default signal sent to a process by the kill or killall command. Unlike the SIGKILL signal, it can be caught by an application so that it can properly terminate. SIGTERM is also sent by the init process during system shutdown, it then waits a few seconds and then sends SIGKILL to all remaining processes to forcibly terminate them.

For more information on signals please see man signal(2) , man sigaction(2) , or the book UNIX Network Programming from Richard Stevens, Addison Wesley.

In our examples we setup signal handlers in the utility function RegisterSignalHandler() in shutdown.cpp. You can either use this utility function or set up your own signal handlers like shown in the following example.

#include <signal.h>
/* Shutdown flag: Note that this must be defined volatile, because it gets set by a signal handler. */
static volatile unsigned int g_ShutDown = 0;
/* Signal handler for SIG_INT. */
void sig_int(int signo)
{
SHUTDOWN_TRACE("Received SIG_INT(%i) signal.\n", signo);
g_ShutDown = 1;
}
void RegisterSignalHandler()
{
struct sigaction new_action, old_action;
/* Set up the structure to specify the new action. */
new_action.sa_handler = sig_int;
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0;
/* install new signal handler for SIGINT */
sigaction(SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
{
sigaction(SIGINT, &new_action, NULL);
}
/* install new signal handler for SIGTERM */
sigaction(SIGTERM, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
{
sigaction(SIGTERM, &new_action, NULL);
}
/* Set up the structure to prevent program termination on interrupted connections. */
new_action.sa_handler = SIG_IGN;
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0;
/* install new signal handler for SIGPIPE */
sigaction(SIGPIPE, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
{
sigaction(SIGPIPE, &new_action, NULL);
}
}
OpcUa_StatusCode install_signal_handler()

Step 1: Create a New Project

Set up a console application.

Windows:

Create a new project. Use the following settings:

  • Win32 Console Application
  • No precompiled headers
  • Empty project.

Step 2: Add Files to the Project

Add the files listed below to your application:

  • [SDK Installation Directory]/examples/utilities/opcserver.h
  • [SDK Installation Directory]/examples/utilities/opcserver.cpp
  • [SDK Installation Directory]/examples/utilities/serverconfigxml.h
  • [SDK Installation Directory]/examples/utilities/serverconfigxml.cpp
  • [SDK Installation Directory]/examples/utilities/shutdown.h
  • [SDK Installation Directory]/examples/utilities/shutdown.cpp

Create the main function in servermain.cpp

The example is using a console application.

The following code provides a generic main function without OPC UA code that extracts the application path from the input arguments and calls the function OpcServerMain where we will add the OPC UA specific code. The function in the following code contains only the waiting loop for a user shutdown command.

#include "uaplatformlayer.h"
#include "shutdown.h"
int OpcServerMain(const char* szAppPath)
{
printf(" Press %s to shutdown server\n", SHUTDOWN_SEQUENCE);
while(ShutDownFlag() == 0)
{
}
return 0;
}
int main(int, char*[])
{
int ret = 0;
RegisterSignalHandler();
// Extract application path
char* pszAppPath = getAppPath();
//-------------------------------------------
// Call the OPC server main method
ret = OpcServerMain(pszAppPath);
//-------------------------------------------
if ( pszAppPath ) delete [] pszAppPath;
return ret;
}

Initializing UA Stack and XML Parser

The UA Stack and the XML Parser modules are ANSI C based modules and do require a global initialization before any of their functionality is used.

The initialization of the XML Parser is only needed if the XML configuration file is used through the class ServerConfigXml.

Warning
None of the SDK functionality can be used before the UA stack initialization is done.
This requirement includes static members or global variables using UA SDK or UA Stack classes and functions.
If UA SDK or UA Stack classes and functions are used before UaPlatformLayer::init is called, the server will crash since the platform layer of the UA stack is not loaded.

Add the marked line and replace the code in OpcServerMain() as shown below.

#include "uaplatformlayer.h"
#include "shutdown.h"
#include "xmldocument.h" // Add this line
int OpcServerMain(const char* szAppPath)
{
int ret = 0;
// Initialize the XML Parser
// Initialize the UA Stack platform layer
if ( ret == 0 )
{
// SDK can be used now
}
// Cleanup the UA Stack platform layer
// Cleanup the XML Parser
return ret;
}

If the UaPlatformLayer::init call succeeds, the UA SDK and UA Stack classes and functions can be used.

Create OPC UA Server

The following code is used to initialize and start the server object. OPC UA clients can connect to the server after this code is executed.

#include "uaplatformlayer.h"
#include "shutdown.h"
#include "xmldocument.h"
#include "opcserver.h" // Add this line
...
if ( ret == 0 )
{
// New code begins
// Create configuration file name
UaString sConfigFileName(szAppPath);
sConfigFileName += "/ServerConfig.xml";
//- Start up OPC server ---------------------
// Create and initialize server object
OpcServer* pServer = new OpcServer;
pServer->setServerConfig(sConfigFileName, szAppPath);
// Start server object
ret = pServer->start();
if ( ret != 0 )
{
delete pServer;
pServer = 0;
}
// New code ends
}
Create configuration file name
This code uses the class UaString to create the configuration file name including the path. The configuration file in the example can be found in the bin directory that contains also the server executable file.
Start up OPC server
This code can be integrated into a start up sequence of the application where the OPC server should be integrated.
Create and initialize server object
This code creates an instance of the class OpcServer used to manage all OPC UA SDK modules. In a second step the configuraiton file and application path is set to allow the server object to find its configuration and PKI folder.
Start server object
After the start function of the OpcServer object has been called successfully, OPC UA clients can connect to the server.

Shut Down OPC UA Server

The following code is used to wait for a user shut down command and to shut down the OPC UA server.

#include "uaplatformlayer.h"
#include "shutdown.h"
#include "xmldocument.h"
#include "opcserver.h"
#include "uathread.h" // Add this line
...
// Start server object
ret = pServer->start();
if ( ret != 0 )
{
delete pServer;
pServer = 0;
}
// New code begins
if(ret == 0)
{
printf("***************************************************\n");
printf(" Press %s to shutdown server\n", SHUTDOWN_SEQUENCE);
printf("***************************************************\n");
// Wait for user command to terminate the server thread.
while(ShutDownFlag() == 0)
{
}
printf("***************************************************\n");
printf(" Shutting down server\n");
printf("***************************************************\n");
//- Stop OPC server -------------------------
// Stop the server and wait three seconds if clients are connected
// to allow them to disconnect after they received the shutdown signal
pServer->stop(3, UaLocalizedText("", "User shut down"));
delete pServer;
pServer = NULL;
//-------------------------------------------
}
// New code ends
Wait for user command
The loop checks for a user shut down command and sleeps between the checks. The platform independent UaThread::msleep function is used.
Stop OPC server
This code can be integrated into a shut down sequence of the application where the OPC server should be integrated. It stops the server and provides information that is sent to the clients connected to the server to allow them to disconnect from the server.

Step 3: Add Include Directories

Add the following include paths to your application:

[SDK Installation Directory]\examples\utilities
[SDK Installation Directory]\include\uastack
[SDK Installation Directory]\include\uabase
[SDK Installation Directory]\include\uapki
[SDK Installation Directory]\include\xmlparser
[SDK Installation Directory]\include\uaserver
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\openssl\inc32
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\libxml2\include

The following include path is only needed for this example:
[SDK Installation Directory]/examples/simulation_buildingautiomation

For more information see LibraryOverview.

Step 4: Add Linker Settings

Windows:
For Additional Library Directories enter the following values:
[SDK Installation Directory]\lib
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\openssl\out32dll.dbg (Debug)
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\libxml2\out32dll.dbg (Debug)
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\openssl\out32dll (Release)
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\libxml2\out32dll (Release)

For Additional Dependencies (Debug) enter:
uastackd.lib
uabased.lib
uapkid.lib
uamoduled.lib
coremoduled.lib
xmlparserd.lib
libeay32d.lib
libxml2d.lib
ws2_32.lib
rpcrt4.lib
crypt32.lib

For Additional Dependencies (Release) enter:
uastack.lib
uabase.lib
uapki.lib
uamodule.lib
coremodule.lib
xmlparser.lib
libeay32.lib
libxml2.lib
ws2_32.lib
rpcrt4.lib
crypt32.lib

Linux:
For Additional Library Directories enter the following values:
-L[SDK Installation Directory]/lib

For Additional Dependencies (Debug) enter:
-luastackd -luabased -luapkid -luamoduled -lcoremoduled -lxmlparserd -lssl -lxml2

For Additional Dependencies (Release) enter:
-luastack -luabase -luapki -luamodule -lcoremodule -lxmlparser -lssl -lxml2

For more information see LibraryOverview.

Step 5: Add Preprocessor Defines

Add

OPCUA_SUPPORT_SECURITYPOLICY_BASIC128RSA15=1
OPCUA_SUPPORT_SECURITYPOLICY_BASIC256=1
OPCUA_SUPPORT_SECURITYPOLICY_NONE=1
OPCUA_SUPPORT_PKI=1
LIBXML_STATIC
SUPPORT_XML_CONFIG
_UA_STACK_USE_DLL

Additional defines for Windows:

UNICODE
_UNICODE
_CRT_SECURE_NO_WARNINGS
_CRT_SECURE_NO_DEPRECATE

Step 6: Set Output Path

Set the output path to “bin” where the config file “ServerConfig.xml” can be found.

Windows:

Enter these values:

Output Directory
[SDK Installation Directory]\bin
Intermediate Directory
obj\$(ConfigurationName)

Step 7: Run Application

Compile and run the server application.

Try to connect to the server with an OPC UA Client, e.g. UaExpert. Figure 1-1 shows how to add the server. For more information, refer to the documentation of UaExpert.

Figure 1-1 Add server to UaExpert

Edit the server properties as shown in Figure 1-2.

Figure 1-2 Edit server properties.