UA ANSI C Server Professional  1.4.2.297
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Modules Pages
servermain.c
/******************************************************************************
**
** Copyright (C) 2011-2014 Unified Automation GmbH. All Rights Reserved.
** Web: http://www.unifiedautomation.com
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** Project: OPC Ansi C OPC Server Examples
**
******************************************************************************/
/*============================================================================
* Includes
*===========================================================================*/
#include <uaserver_config.h>
#if defined(_WIN32) || defined(_WIN32_WCE)
# include <winsock2.h>
#else
# include <unistd.h>
# include <stdlib.h>
# include <netdb.h>
# ifdef VXWORKS
# include <hostLib.h>
# endif /* VXWORKS */
#endif
#include <uaserver_module.h>
#include <uaserver_utilities.h>
#include <uaserver_p_filesystem.h>
#include <uaserver_p_pki.h>
/*============================================================================
* Application Defines
*===========================================================================*/
/* Server/application URLs, URIs and names */
#define UASERVER_PORT 48020
#define UASERVER_APPLICATIONNAME "UaSdkC - LessonSecurity01"
#define UASERVER_APPLICATIONURI "UnifiedAutomation:UaSdkC:LessonSecurity01"
#define UASERVER_PRODUCTNAME "UaSdkC - LessonSecurity01"
#define UASERVER_PRODUCTURI "http://www.unifiedautomation.com/server-sdk.htm"
#define UASERVER_MANUFACTURERNAME UASDK_VENDOR_INFO
#define UASERVER_SOFTWAREVERSION UASDK_VERSION
#define UASERVER_BUILDNUMBER chSTR2(UASDK_BUILD_VERSION)
/* PKI configuration */
#define UASERVER_PKI_CONFIGNAME OPCUA_P_PKI_TYPE_OPENSSL
#define UASERVER_PKI_SERVERCERT "pki/own/uaservercert.der"
#define UASERVER_PKI_PRIVATEKEY "pki/own/uaserverkey.nopass.pem"
#define UASERVER_PKI_CERTDIR "pki/trusted/certs/"
#define UASERVER_PKI_CRLDIR "pki/trusted/crl/"
#define UASERVER_PKI_REJECTED "pki/rejected/"
/*============================================================================
* Helper function for creating the PKI infrastructure
*===========================================================================*/
OpcUa_StatusCode CreateCertificates(OpcUa_CharA *szApplicationUri, OpcUa_CharA *szHostname)
{
OpcUa_StatusCode uStatus = OpcUa_Good;
UaServer_File *pFile = OpcUa_Null;
OpcUa_Boolean bCertAvailable = OpcUa_True;
OpcUa_Int iRet;
/* Check if certificate and private key exist */
pFile = UaServer_Fopen(UASERVER_PKI_SERVERCERT, "r");
if (pFile != OpcUa_Null)
{
UaServer_Fclose(pFile);
}
else
{
bCertAvailable = OpcUa_False;
}
pFile = UaServer_Fopen(UASERVER_PKI_PRIVATEKEY, "r");
if (pFile != OpcUa_Null)
{
UaServer_Fclose(pFile);
}
else
{
bCertAvailable = OpcUa_False;
}
/* Create PKI folder structure */
if (bCertAvailable == OpcUa_False)
{
iRet = UaServer_MkPath("pki/own");
if (iRet != UASERVER_SUCCESS) {printf("Could not create certificate path (ret=%i)\n", iRet);}
iRet = UaServer_MkPath(UASERVER_PKI_CERTDIR);
if (iRet != UASERVER_SUCCESS) {printf("Could not create trust list path (ret=%i)\n", iRet);}
iRet = UaServer_MkPath(UASERVER_PKI_CRLDIR);
if (iRet != UASERVER_SUCCESS) {printf("Could not create CRL path (ret=%i)\n", iRet);}
iRet = UaServer_MkPath(UASERVER_PKI_REJECTED);
if (iRet != UASERVER_SUCCESS) {printf("Could not create rejected certificate path (ret=%i)\n", iRet);}
}
/* Create certificate and private key if needed */
if (bCertAvailable == OpcUa_False)
{
OpcUa_StatusCode ret = OpcUa_Good;
OpcUa_PkiCertificate* pCertificate = OpcUa_Null;
OpcUa_PkiRsaKeyPair* pSubjectKeyPair = OpcUa_Null;
OpcUa_PkiCertificateInfo certificateInfo;
ret = UaServer_PkiRsaKeyPair_Create(&pSubjectKeyPair, 2048);
if (OpcUa_IsNotGood(ret)) {printf("UaServer_PkiRsaKeyPair_Create failed (ret=0x%08x)\n", ret);}
certificateInfo.sURI = szApplicationUri;
certificateInfo.sIP = "";
certificateInfo.sDNS = (OpcUa_StringA)szHostname;
certificateInfo.sEMail = "";
certificateInfo.validTime = 3600*24*365*5;
subject.sCommonName = UASERVER_APPLICATIONNAME;
subject.sOrganization = UASERVER_MANUFACTURERNAME;
subject.sOrganizationUnit = "";
subject.sLocality = "Nuremberg";
subject.sState = "Bavaria";
subject.sCountry = "DE";
subject.sDomainComponent = "";
&pCertificate,
certificateInfo,
subject,
*pSubjectKeyPair,
subject,
*pSubjectKeyPair);
if (OpcUa_IsNotGood(ret)) {printf("UaServer_PkiCertificate_Create failed (ret=0x%08x)\n", ret);}
ret = UaServer_PkiCertificate_ToDERFile(pCertificate, UASERVER_PKI_SERVERCERT);
if (OpcUa_IsNotGood(ret)) {printf("UaServer_PkiCertificate_ToDERFile failed (ret=0x%08x)\n", ret);}
ret = UaServer_PkiRsaKeyPair_ToPEMFile(pSubjectKeyPair, UASERVER_PKI_PRIVATEKEY);
if (OpcUa_IsNotGood(ret)) {printf("UaServer_PkiRsaKeyPair_ToPEMFile failed (ret=0x%08x)\n", ret);}
UaServer_PkiRsaKeyPair_Delete(&pSubjectKeyPair);
}
return uStatus;
}
/*============================================================================
* Main helper functions
*===========================================================================*/
/* Initializes OPC UA Stack.
* Here you can configure trace settings and other stack configuration options.
*/
OpcUa_StatusCode InitializeOpcUaStack(OpcUa_Handle *a_phProxyStubPlatformLayer,
OpcUa_ProxyStubConfiguration *a_pProxyStubConfiguration)
{
OpcUa_InitializeStatus(OpcUa_Module_Server, "InitializeOpcUaStack");
/* Initialize Stack */
printf("UA Server: Initializing Stack...\n");
/* Default values can be changed here */
a_pProxyStubConfiguration->bProxyStub_Trace_Enabled = OpcUa_True;
a_pProxyStubConfiguration->uProxyStub_Trace_Level = OPCUA_TRACE_OUTPUT_LEVEL_ERROR;
uStatus = UaServer_Module_InitializeUaStack(a_phProxyStubPlatformLayer, a_pProxyStubConfiguration);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
/* Cleanup counterpart to InitializeOpcUaStack. */
OpcUa_StatusCode CleanupOpcUaStack(OpcUa_Handle *a_phProxyStubPlatformLayer)
{
OpcUa_InitializeStatus(OpcUa_Module_Server, "CleanupOpcUaStack");
/* Clean Up UA Stack */
uStatus = UaServer_Module_ClearUaStack(a_phProxyStubPlatformLayer);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
int GetFQHostname( char *szHostname, int len )
{
struct hostent *pEnt = 0;
int ret = gethostname( szHostname, len );
if ( ret != 0 ) return ret;
pEnt = gethostbyname( szHostname );
if ( pEnt == 0 ) return -1;
strlcpy( szHostname, pEnt->h_name, len );
szHostname[len - 1] = 0;
return 0;
}
/* Main OPC UA Server Loop. */
OpcUa_StatusCode ServerMain()
{
UaServer uaServer;
UaServer_Configuration *pServerConfig = OpcUa_Null;
OpcUa_CharA szHostname[256];
OpcUa_CharA szEndpointURL[300];
OpcUa_CharA szApplicationUri[300];
UaServer_Endpoint *pEndpoint = OpcUa_Null;
OpcUa_InitializeStatus(OpcUa_Module_Server, "ServerMain");
OpcUa_MemSet(szEndpointURL, 0, sizeof(szEndpointURL));
OpcUa_MemSet(szApplicationUri, 0, sizeof(szApplicationUri));
/* Create EndpointURL and ApplicationURI strings */
GetFQHostname(szHostname, sizeof(szHostname));
OpcUa_SnPrintfA(szEndpointURL, sizeof(szEndpointURL)-1, "opc.tcp://%s:%u", szHostname, UASERVER_PORT);
OpcUa_SnPrintfA(szApplicationUri, sizeof(szApplicationUri)-1, "urn:%s:%s", szHostname, UASERVER_APPLICATIONURI);
uStatus = CreateCertificates(szApplicationUri, szHostname);
OpcUa_GotoErrorIfBad(uStatus);
/* Initialize Server */
uStatus = UaServer_Initialize(&uaServer);
OpcUa_GotoErrorIfBad(uStatus);
/* Get configuration structure of the server */
pServerConfig = UaServer_GetConfiguration(&uaServer);
/* Configure ApplicationDescription of the server */
OpcUa_String_AttachReadOnly(&pServerConfig->ApplicationDescription.ApplicationUri, szApplicationUri);
OpcUa_String_AttachReadOnly(&pServerConfig->ApplicationDescription.ProductUri, UASERVER_PRODUCTURI);
OpcUa_String_AttachReadOnly(&pServerConfig->ApplicationDescription.ApplicationName.Text, UASERVER_APPLICATIONNAME);
pServerConfig->ApplicationDescription.ApplicationType = OpcUa_ApplicationType_Server;
pServerConfig->ApplicationDescription.NoOfDiscoveryUrls = 1;
pServerConfig->ApplicationDescription.DiscoveryUrls = OpcUa_Alloc(sizeof(OpcUa_String));
OpcUa_String_Initialize(&pServerConfig->ApplicationDescription.DiscoveryUrls[0]);
OpcUa_String_AttachReadOnly(&pServerConfig->ApplicationDescription.DiscoveryUrls[0], szEndpointURL);
/* Configure BuildInfo of the server */
OpcUa_String_AttachReadOnly(&pServerConfig->BuildInfo.ManufacturerName, UASERVER_MANUFACTURERNAME);
OpcUa_String_AttachReadOnly(&pServerConfig->BuildInfo.ProductName, UASERVER_PRODUCTNAME);
OpcUa_String_AttachReadOnly(&pServerConfig->BuildInfo.SoftwareVersion, UASERVER_SOFTWAREVERSION);
OpcUa_String_AttachReadOnly(&pServerConfig->BuildInfo.BuildNumber, UASERVER_BUILDNUMBER);
OpcUa_String_AttachReadOnly(&pServerConfig->BuildInfo.ProductUri, UASERVER_APPLICATIONURI);
pServerConfig->BuildInfo.BuildDate = UaServer_GetBuildDate();
/* Set the folder where to store rejected client certificates */
OpcUa_String_AttachReadOnly(&pServerConfig->RejectedCertificateLocation, UASERVER_PKI_REJECTED);
/* Create one endpoint */
pServerConfig->uNoOfEndpoints = 1;
pServerConfig->pEndpoints = OpcUa_Alloc(sizeof(UaServer_Endpoint));
UaServer_Endpoint_Initialize(&pServerConfig->pEndpoints[0]);
pEndpoint = &pServerConfig->pEndpoints[0];
/* Set the endpoint URL */
OpcUa_String_AttachReadOnly(&pEndpoint->sEndpointUrl, szEndpointURL);
/* enable OpenSSL PKI */
pEndpoint->PkiConfig.strPkiType = UASERVER_PKI_CONFIGNAME;
pEndpoint->PkiConfig.strTrustedCertificateListLocation = UASERVER_PKI_CERTDIR;
pEndpoint->PkiConfig.strRevokedCertificateListLocation = UASERVER_PKI_CRLDIR;
OpcUa_String_AttachReadOnly(&pEndpoint->ServerCertificateLocation, UASERVER_PKI_SERVERCERT);
OpcUa_String_AttachReadOnly(&pEndpoint->ServerPrivateKeyLocation, UASERVER_PKI_PRIVATEKEY);
/* Set the endpoint configuration to use Basic256 / SIGNANDENCRYPT */
pEndpoint->pSecurityPolicyConfigurations = OpcUa_Alloc(sizeof(OpcUa_Endpoint_SecurityPolicyConfiguration));
OpcUa_MemSet(pEndpoint->pSecurityPolicyConfigurations, 0, sizeof(OpcUa_Endpoint_SecurityPolicyConfiguration));
OpcUa_String_AttachReadOnly(&pEndpoint->pSecurityPolicyConfigurations[0].sSecurityPolicy, OpcUa_SecurityPolicy_Basic256);
pEndpoint->pSecurityPolicyConfigurations[0].uMessageSecurityModes = OPCUA_ENDPOINT_MESSAGESECURITYMODE_SIGNANDENCRYPT;
/* Set the endpoint configuration to use anonymous logon */
pEndpoint->uNoOfUserTokenPolicy = 1;
pEndpoint->pUserTokenPolicy = OpcUa_Alloc(pEndpoint->uNoOfUserTokenPolicy * sizeof(OpcUa_UserTokenPolicy));
OpcUa_UserTokenPolicy_Initialize(&pEndpoint->pUserTokenPolicy[0]);
pEndpoint->pUserTokenPolicy[0].TokenType = OpcUa_UserTokenType_Anonymous;
OpcUa_String_AttachReadOnly(&pEndpoint->pUserTokenPolicy[0].PolicyId, "Anonymous");
/* Initialize the provider list, the server provider is added automatically */
printf("UA Server: Building Provider List...\n");
uStatus = UaServer_ProviderList_Create(&uaServer);
OpcUa_GotoErrorIfBad(uStatus);
/* Load providers */
printf("UA Server: Loading Provider Modules...\n");
uStatus = UaServer_Providers_Initialize(&uaServer);
OpcUa_GotoErrorIfBad(uStatus);
/* Start up server */
uStatus = UaServer_StartUp(&uaServer);
OpcUa_GotoErrorIfBad(uStatus);
printf("\n#############################################");
printf("\n# Server started! Press %s to stop!", UASERVER_P_SHUTDOWN_SEQUENCE);
printf("\n#############################################\n\n");
printf("Endpoint URL: %s\n", szEndpointURL);
/* Initialize the check for shutdown keystrokes. On Linux, default signal handlers
are added in UaServer_P_InitShutdownFlag. */
/******************************************************************************/
/* Serve! */
while (UaServer_P_IsShutdownFlagSet() == OpcUa_False && OpcUa_IsGood(uStatus))
{
uStatus = UaServer_DoCom();
}
OpcUa_GotoErrorIfBad(uStatus);
/******************************************************************************/
/* Clean up the check for shutdown keystrokes */
/* UaServer_Clear clears the PkiConfig of the endpoint and attempts to free the strings
set there. As we have set literal string constants, we don't want those to be freed, so
we set them to NULL by initializing the structure. */
OpcUa_CertificateStoreConfiguration_Initialize(&pEndpoint->PkiConfig);
/* Clean up server */
UaServer_Clear(&uaServer);
printf("UA Server: Main stopped successfully.\n");
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
/* Clean up the check for shutdown keystrokes */
/* UaServer_Clear clears the PkiConfig of the endpoint and attempts to free the strings
set there. As we have set literal string constants, we don't want those to be freed, so
we set them to NULL by initializing the structure. */
if (pEndpoint != OpcUa_Null)
{
OpcUa_CertificateStoreConfiguration_Initialize(&pEndpoint->PkiConfig);
}
/* Clean up server */
UaServer_Clear(&uaServer);
printf("UA Server: Main stopped due to ERROR! (0x%08X)\nPress Enter to close Window!\n", uStatus);
getchar();
OpcUa_FinishErrorHandling;
}
/*============================================================================
* Main entry point for the application
*===========================================================================*/
int main(int argc, char *argv[])
{
int ret = EXIT_SUCCESS;
OpcUa_StatusCode uStatus = OpcUa_Good;
OpcUa_Handle hProxyStubPlatformLayer = OpcUa_Null;
OpcUa_ProxyStubConfiguration proxyStubConfiguration;
/* The main method parameters are unused */
OpcUa_ReferenceParameter(argc);
OpcUa_ReferenceParameter(argv);
/* Set up OPC UA */
uStatus = InitializeOpcUaStack(&hProxyStubPlatformLayer, &proxyStubConfiguration);
if ( OpcUa_IsNotGood(uStatus) )
{
return EXIT_FAILURE;
}
/* Start the main server loop */
uStatus = ServerMain();
if ( OpcUa_IsNotGood(uStatus) )
{
ret = EXIT_FAILURE;
}
/* Clean up OPC UA */
uStatus = CleanupOpcUaStack(&hProxyStubPlatformLayer);
if ( OpcUa_IsNotGood(uStatus) )
{
ret = EXIT_FAILURE;
}
return ret;
}
#ifdef _WIN32_WCE
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nShowCmd)
{
OpcUa_ReferenceParameter(hInstance);
OpcUa_ReferenceParameter(hPrevInstance);
OpcUa_ReferenceParameter(lpCmdLine);
OpcUa_ReferenceParameter(nShowCmd);
return main(0, OpcUa_Null);
}
#endif