ANSI C Based OPC UA Client/Server/PubSub SDK  1.9.1.442
clientmain.c
/*****************************************************************************
* *
* Copyright (c) 2006-2019 Unified Automation GmbH. All rights reserved. *
* *
* Software License Agreement ("SLA") Version 2.7 *
* *
* Unless explicitly acquired and licensed from Licensor under another *
* license, the contents of this file are subject to the Software License *
* Agreement ("SLA") Version 2.7, or subsequent versions as allowed by the *
* SLA, and You may not copy or use this file in either source code or *
* executable form, except in compliance with the terms and conditions of *
* the SLA. *
* *
* All software distributed under the SLA is provided strictly on an "AS *
* IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, *
* AND LICENSOR HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT *
* LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR *
* PURPOSE, QUIET ENJOYMENT, OR NON-INFRINGEMENT. See the SLA for specific *
* language governing rights and limitations under the SLA. *
* *
* The complete license agreement can be found here: *
* http://unifiedautomation.com/License/SLA/2.7/ *
* *
* Project: UA ANSI C SDK based Sample Client *
* *
*****************************************************************************/
/*============================================================================
* Includes
*===========================================================================*/
#include <stdio.h>
#include <stdlib.h>
#if defined(WIN32)
#include <windows.h>
#endif
#include <uabase_settings.h>
#include <uabase_utilities.h>
#include <uabase_trace.h>
#include <uabase_module.h>
#include <opcua_memory.h>
#include <opcua_datetime.h>
#include <opcua_string.h>
#include <opcua_proxystub.h>
#include <opcua_trace.h>
#include <opcua_pkifactory.h>
#include <uaclient_module.h>
#include <uaclient_discovery.h>
#include <uaclient_session.h>
#include <uaclient_subscription.h>
#include <uaclient_config.h>
#if OPCUA_SUPPORT_PKI && UABASE_USE_FILESYSTEM
# include <uabase_p_filesystem.h>
# include <uabase_pki.h>
#endif /* OPCUA_SUPPORT_PKI && UABASE_USE_FILESYSTEM */
/*============================================================================
* Defines
*===========================================================================*/
#define UACLIENT_APPLICATION_NAME "UaSdkC - Client - Lesson04@[gethostname]"
#define UACLIENT_APPLICATION_URI "urn:[gethostname]:UnifiedAutomation:UaSdkC:Client:Lesson04"
#define UACLIENT_PRODUCT_NAME "UA ANSI C SDK based Sample Client"
#define UACLIENT_PRODUCT_URI "urn:UnifiedAutomation:UaSdkC:Client:Lesson04"
/* Server configuration used by this client */
#define SERVER_ENDPOINT_URL "opc.tcp://localhost:48020"
/*============================================================================
* Client Structures
*===========================================================================*/
typedef enum _SampleStateMachine
{
State_Idle,
State_FindServers,
State_FindServersDone,
State_GetEndpoints,
State_GetEndpointsDone,
State_Connect,
State_Connected,
State_Disconnect,
State_Disconnected,
State_Error
} SampleStateMachine;
typedef struct _SampleClientContext
{
SampleStateMachine State;
} SampleClientContext;
typedef struct _Sample_Discovery
{
OpcUa_String InitialDiscoveryUrl;
OpcUa_String DiscoveryUrl;
UaClient_Discovery *pDiscovery;
OpcUa_List lstDiscoveryUrls;
OpcUa_List lstEndpoints;
OpcUa_Void *pUserData;
} Sample_Discovery;
/*============================================================================
* Main helper functions
*===========================================================================*/
#if defined(WIN32) && !defined(_WIN32_WCE)
#include <conio.h>
#elif !defined(EUROS_VERSION) && !defined(_WIN32_WCE) && !defined(__VXWORKS__)
#include <unistd.h> /* for read() */
#include <netdb.h>
static int peek_character = -1;
int _getch(void)
{
char ch = 0;
ssize_t ret;
if (peek_character != -1)
{
ch = peek_character;
peek_character = -1;
return ch;
}
ret = read(0, &ch, 1);
OpcUa_ReferenceParameter(ret);
return ch;
}
#else
int _getch()
{
return 0;
}
#endif
int GetFQHostname(char *a_szHostname, int a_len)
{
struct hostent* pEnt = 0;
int ret = gethostname(a_szHostname, a_len);
if (ret != 0) return ret;
pEnt = gethostbyname(a_szHostname);
if (pEnt == 0) return -1;
OpcUa_StrlCpyA(a_szHostname, pEnt->h_name, a_len);
a_szHostname[a_len - 1] = 0;
return 0;
}
/* 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_Client, "InitializeOpcUaStack");
/* Initialize Stack */
printf("UA Client: 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_WARNING;
uStatus = UaBase_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_Client, "CleanupOpcUaStack");
/* Clean Up UA Stack */
uStatus = UaBase_Module_ClearUaStack(a_phProxyStubPlatformLayer);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
#if OPCUA_SUPPORT_PKI && UABASE_USE_FILESYSTEM
OpcUa_StatusCode SetupPKIStore(UaBase_Settings* a_pSettings,
const char* a_szHostname,
const char* a_szApplicationUri,
const char* a_szApplicationName,
OpcUa_Boolean a_bIsClient)
{
OpcUa_Boolean bGenerateCertificate = OpcUa_False;
OpcUa_CharA szString[UABASE_PATH_MAX];
OpcUa_CharA szCertificateFile[UABASE_PATH_MAX];
OpcUa_CharA szCertificateKeyFile[UABASE_PATH_MAX];
UaBase_File *pFile = OpcUa_Null;
OpcUa_Boolean bCertAvailable = OpcUa_True;
OpcUa_Int iRet;
OpcUa_InitializeStatus(OpcUa_Module_Utilities, "SetupPKIStore");
UaBase_Settings_ReadBool(a_pSettings, "GenerateCertificate", &bGenerateCertificate, OpcUa_False);
UaBase_Settings_ReadString(a_pSettings, "CertificateFile", szCertificateFile, sizeof(szCertificateFile), "");
UaBase_Settings_ReadString(a_pSettings, "CertificateKeyFile", szCertificateKeyFile, sizeof(szCertificateKeyFile), "");
UaBase_Settings_ReadString(a_pSettings, "TrustListPath", szString, sizeof(szString), "");
iRet = UaBase_MkPath(szString);
if (iRet != UABASE_SUCCESS) { OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "Could not create trust list path (ret=%i)\n", iRet); OpcUa_GotoErrorWithStatus(OpcUa_BadInternalError); }
UaBase_Settings_ReadString(a_pSettings, "CRLPath", szString, sizeof(szString), "");
iRet = UaBase_MkPath(szString);
if (iRet != UABASE_SUCCESS) { OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "Could not create CRL path (ret=%i)\n", iRet); OpcUa_GotoErrorWithStatus(OpcUa_BadInternalError); }
UaBase_Settings_ReadString(a_pSettings, "IssuerTrustListPath", szString, sizeof(szString), "");
iRet = UaBase_MkPath(szString);
if (iRet != UABASE_SUCCESS) { OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "Could not create issuer trust list path (ret=%i)\n", iRet); OpcUa_GotoErrorWithStatus(OpcUa_BadInternalError); }
UaBase_Settings_ReadString(a_pSettings, "IssuerCRLPath", szString, sizeof(szString), "");
iRet = UaBase_MkPath(szString);
if (iRet != UABASE_SUCCESS) { OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "Could not create issuer CRL path (ret=%i)\n", iRet); OpcUa_GotoErrorWithStatus(OpcUa_BadInternalError); }
if (bGenerateCertificate == OpcUa_False)
{
OpcUa_ReturnStatusCode;
}
/* check if certificate and private key exist and create new ones if not */
pFile = UaBase_Fopen(szCertificateFile, "r");
if (pFile != NULL)
{
UaBase_Fclose(pFile);
}
else
{
bCertAvailable = OpcUa_False;
}
pFile = UaBase_Fopen(szCertificateKeyFile, "r");
if (pFile != NULL)
{
UaBase_Fclose(pFile);
}
else
{
bCertAvailable = OpcUa_False;
}
pFile = NULL;
if (bCertAvailable == OpcUa_False)
{
OpcUa_PkiCertificate *pCertificate = OpcUa_Null;
OpcUa_PkiRsaKeyPair *pSubjectKeyPair = OpcUa_Null;
OpcUa_PkiCertificateInfo certificateInfo = OPCUA_PKICERTIFICATEINFO_STATICINITIALIZER;
OpcUa_CharA szCommonName[64];
OpcUa_CharA szOrganization[64];
OpcUa_CharA szOrganizationUnit[64];
OpcUa_CharA szLocality[64];
OpcUa_CharA szState[64];
OpcUa_CharA szCountry[3];
OpcUa_CharA szDNSNames[64];
OpcUa_CharA szIPAddresses[64];
OpcUa_CharA szApplicationUri[128];
OpcUa_UInt iYearsValidFor = 0;
OpcUa_UInt iKeyLength = 0;
OpcUa_CharA szSignatureAlgorithm[8] = "";
OpcUa_X509SignatureAlgorithm signatureAlgorithm = OpcUa_X509SignatureAlgorithm_Sha256;
OpcUa_StringA_snprintf(szString, sizeof(szString), "%s", a_szApplicationName);
UaBase_Settings_ReplaceString(szString, sizeof(szString), "[gethostname]", a_szHostname);
UaBase_Settings_ReadString(a_pSettings, "CommonName", szCommonName, sizeof(szCommonName), "");
UaBase_Settings_ReplaceString(szCommonName, sizeof(szCommonName), "[ApplicationName]", szString);
subject.sCommonName = szCommonName;
UaBase_Settings_ReadString(a_pSettings, "Organization", szOrganization, sizeof(szOrganization), "");
subject.sOrganization = szOrganization;
UaBase_Settings_ReadString(a_pSettings, "OrganizationUnit", szOrganizationUnit, sizeof(szOrganizationUnit), "");
subject.sOrganizationUnit = szOrganizationUnit;
UaBase_Settings_ReadString(a_pSettings, "Locality", szLocality, sizeof(szLocality), "");
subject.sLocality = szLocality;
UaBase_Settings_ReadString(a_pSettings, "State", szState, sizeof(szState), "");
subject.sState = szState;
UaBase_Settings_ReadString(a_pSettings, "Country", szCountry, sizeof(szCountry), "");
subject.sCountry = szCountry;
subject.sDomainComponent = "";
OpcUa_StrlCpyA(szApplicationUri, a_szApplicationUri, sizeof(szApplicationUri));
UaBase_Settings_ReplaceString(szApplicationUri, sizeof(szApplicationUri), "[gethostname]", a_szHostname);
certificateInfo.sURI = szApplicationUri;
UaBase_Settings_ReadString(a_pSettings, "IPAddresses", szIPAddresses, sizeof(szIPAddresses), "");
certificateInfo.sIP = szIPAddresses;
UaBase_Settings_ReadString(a_pSettings, "DNSNames", szDNSNames, sizeof(szDNSNames), "");
UaBase_Settings_ReplaceString(szDNSNames, sizeof(szDNSNames), "[gethostname]", a_szHostname);
certificateInfo.sDNS = OpcUa_StrLenA(szDNSNames) > 0 ? szDNSNames : a_szHostname;
certificateInfo.sEMail = "";
UaBase_Settings_ReadUInt(a_pSettings, "YearsValidFor", &iYearsValidFor, 5);
certificateInfo.validTime = 3600 * 24 * 365 * iYearsValidFor;
certificateInfo.extendedKeyUsage = a_bIsClient == OpcUa_False ? OpcUa_ExtendedKeyUsage_ServerAuth : OpcUa_ExtendedKeyUsage_ClientAuth;
UaBase_Settings_ReadUInt(a_pSettings, "KeyLength", &iKeyLength, 2048);
UaBase_Settings_ReadString(a_pSettings, "SignatureAlgorithm", szSignatureAlgorithm, sizeof(szSignatureAlgorithm), "Sha256");
uStatus = UaBase_PkiRsaKeyPair_Create(&pSubjectKeyPair, iKeyLength);
if (OpcUa_IsNotGood(uStatus)) { OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "UaBase_PkiRsaKeyPair_Create failed (ret=0x%08x)\n", uStatus); OpcUa_GotoError; }
if (szSignatureAlgorithm[0] != '\0')
{
if (OpcUa_StrCmpA(szSignatureAlgorithm, "Sha1") == 0) signatureAlgorithm = OpcUa_X509SignatureAlgorithm_Sha1;
else if (OpcUa_StrCmpA(szSignatureAlgorithm, "Sha224") == 0) signatureAlgorithm = OpcUa_X509SignatureAlgorithm_Sha224;
else if (OpcUa_StrCmpA(szSignatureAlgorithm, "Sha256") == 0) signatureAlgorithm = OpcUa_X509SignatureAlgorithm_Sha256;
else if (OpcUa_StrCmpA(szSignatureAlgorithm, "Sha384") == 0) signatureAlgorithm = OpcUa_X509SignatureAlgorithm_Sha384;
else if (OpcUa_StrCmpA(szSignatureAlgorithm, "Sha512") == 0) signatureAlgorithm = OpcUa_X509SignatureAlgorithm_Sha512;
}
&pCertificate,
certificateInfo,
subject,
*pSubjectKeyPair,
subject,
*pSubjectKeyPair,
signatureAlgorithm);
if (OpcUa_IsNotGood(uStatus)) { OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "UaBase_PkiCertificate_Create failed (ret=0x%08x)\n", uStatus); OpcUa_GotoError; }
/* create path for certificate */
OpcUa_StrlCpyA(szString, szCertificateFile, sizeof(szString));
UaBase_DirName(szString);
iRet = UaBase_MkPath(szString);
if (iRet != UABASE_SUCCESS) { OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "Could not create certificate path (ret=%i)\n", iRet); OpcUa_GotoErrorWithStatus(OpcUa_BadInternalError);; }
/* create certificate */
uStatus = UaBase_PkiCertificate_ToDERFile(pCertificate, szCertificateFile);
if (OpcUa_IsNotGood(uStatus)) { OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "UaBase_PkiCertificate_ToDERFile failed (ret=0x%08x)\n", uStatus); OpcUa_GotoError; }
/* create path for key */
OpcUa_StrlCpyA(szString, szCertificateKeyFile, sizeof(szString));
UaBase_DirName(szString);
iRet = UaBase_MkPath(szString);
if (iRet != UABASE_SUCCESS) { OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "Could not create private key path (ret=%i)\n", iRet); OpcUa_GotoErrorWithStatus(OpcUa_BadInternalError);; }
/* create key */
uStatus = UaBase_PkiRsaKeyPair_ToPEMFile(pSubjectKeyPair, szCertificateKeyFile);
if (OpcUa_IsNotGood(uStatus)) { OpcUa_Trace(OPCUA_TRACE_LEVEL_ERROR, "UaBase_PkiRsaKeyPair_ToPEMFile failed (ret=0x%08x)\n", uStatus); OpcUa_GotoError; }
UaBase_PkiRsaKeyPair_Delete(&pSubjectKeyPair);
}
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
OpcUa_StatusCode SetupClientPKIInfrastructure(UaBase_Settings *a_pSettings,
const char *a_szHostname,
const char *a_szApplicationUri,
const char *a_szApplicationName)
{
OpcUa_InitializeStatus(OpcUa_Module_Client, "SetupClientPKIInfrastructure");
UaBase_Settings_BeginGroup(a_pSettings, "PKIStore");
uStatus = SetupPKIStore(a_pSettings,
a_szHostname,
a_szApplicationUri,
a_szApplicationName,
OpcUa_True);
OpcUa_GotoErrorIfBad(uStatus);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
#endif /* OPCUA_SUPPORT_PKI && UABASE_USE_FILESYSTEM */
OpcUa_Void Sample_ConnectionStatusChanged_CB(UaClient_Session *a_pSession,
{
SampleClientContext *pClientContext = a_pSession->pUserData;
const char *pStatus = "INVALID";
switch (a_status)
{
pStatus = "Disconnected";
if (pClientContext->State == State_Connect)
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UA Client: failed to connect to server!\n");
}
if (pClientContext->State == State_Disconnect)
{
pClientContext->State = State_Disconnected;
}
else
{
pClientContext->State = State_Error;
}
break;
pStatus = "Connected";
if (pClientContext->State == State_Connect)
{
pClientContext->State = State_Connected;
}
else
{
pClientContext->State = State_Error;
}
break;
pStatus = "Connecting";
break;
pStatus = "ConnectionWarningWatchdogTimeout";
break;
pStatus = "ConnectionErrorClientReconnect";
break;
pStatus = "SessionAutomaticallyRecreated";
break;
default: break;
}
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "\n--> Sample_ConnectionStatusChanged_CB: %s\n\n", pStatus);
}
OpcUa_Boolean Sample_ConnectError_CB(UaClient_Session *a_pSession,
OpcUa_Boolean a_overridable)
{
SampleClientContext *pClientContext = a_pSession->pUserData;
const char *pServiceType = "INVALID";
switch (a_serviceType)
{
case UaClient_ConnectServiceType_CertificateValidation: pServiceType = "CertificateValidation"; break;
case UaClient_ConnectServiceType_OpenSecureChannel: pServiceType = "OpenSecureChannel"; break;
case UaClient_ConnectServiceType_CreateSession: pServiceType = "CreateSession"; break;
case UaClient_ConnectServiceType_UserIdentityToken: pServiceType = "UserIdentityToken"; break;
case UaClient_ConnectServiceType_ActivateSession: pServiceType = "ActivateSession"; break;
default: break;
}
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_ConnectError_CB:\n");
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " ServiceType: %s\n", pServiceType);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Error: 0x%08x\n", a_error);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Overridable: %s\n", a_overridable == OpcUa_False ? "false" : "true");
pClientContext->State = State_Error;
return OpcUa_False;
}
OpcUa_Void Sample_FindServers_CB(const UaClient_Discovery *a_pDiscovery,
OpcUa_ResponseHeader *a_pResponseHeader,
OpcUa_Int32 a_NoOfServers,
OpcUa_Void *a_pUserData)
{
Sample_Discovery *pSampleDiscovery = (Sample_Discovery*)a_pUserData;
SampleClientContext *pClientContext = pSampleDiscovery->pUserData;
OpcUa_ReferenceParameter(a_pDiscovery);
if (OpcUa_IsGood(a_pResponseHeader->ServiceResult))
{
OpcUa_Int32 i, j;
printf("Sample_FindServers_CB result (0x%08x):\n", a_pResponseHeader->ServiceResult);
for (i = 0; i < a_NoOfServers; i++)
{
printf("[%i] %s:\n", i, OpcUa_String_GetRawString(&a_pServers[i].ApplicationName.Text));
for (j = 0; j < a_pServers[i].NoOfDiscoveryUrls; j++)
{
OpcUa_String* pCopy = OpcUa_Alloc(sizeof(OpcUa_String));
if (!pCopy)
{
printf(" OUT OF MEMORY\n");
break;
}
*pCopy = a_pServers[i].DiscoveryUrls[j];
OpcUa_String_Initialize(&a_pServers[i].DiscoveryUrls[j]);
OpcUa_List_AddElementToEnd(&pSampleDiscovery->lstDiscoveryUrls, pCopy);
printf(" %s\n", OpcUa_String_GetRawString(pCopy));
}
}
}
else
{
printf("Sample_FindServers_CB: bad status (0x%08x)\n", a_pResponseHeader->ServiceResult);
}
if (pClientContext->State == State_FindServers)
{
pClientContext->State = State_FindServersDone;
}
else
{
pClientContext->State = State_Error;
}
}
OpcUa_Void Sample_GetEndpoints_CB(const UaClient_Discovery *a_pDiscovery,
OpcUa_ResponseHeader *a_pResponseHeader,
OpcUa_Int32 a_NoOfEndpoints,
OpcUa_Void *a_pUserData)
{
Sample_Discovery *pSampleDiscovery = (Sample_Discovery*)a_pUserData;
SampleClientContext *pClientContext = pSampleDiscovery->pUserData;
OpcUa_ReferenceParameter(a_pDiscovery);
if (OpcUa_IsGood(a_pResponseHeader->ServiceResult))
{
OpcUa_Int32 i;
printf("Sample_GetEndpoints_CB result (0x%08x):\n", a_pResponseHeader->ServiceResult);
for (i = 0; i < a_NoOfEndpoints; i++)
{
if (!pCopy)
{
printf(" OUT OF MEMORY\n");
break;
}
*pCopy = a_pEndpoints[i];
OpcUa_EndpointDescription_Initialize(&a_pEndpoints[i]);
OpcUa_List_AddElementToEnd(&pSampleDiscovery->lstEndpoints, pCopy);
printf("[%i]: %s\n", i, OpcUa_String_GetRawString(&pCopy->EndpointUrl));
}
if (pClientContext->State == State_GetEndpoints)
{
pClientContext->State = State_GetEndpointsDone;
}
else
{
pClientContext->State = State_Error;
}
}
else
{
printf("Sample_GetEndpoints_CB: bad status (0x%08x)\n", a_pResponseHeader->ServiceResult);
pClientContext->State = State_Error;
}
}
/* Main OPC UA Client Loop. */
OpcUa_StatusCode ClientMain(UaBase_Settings* a_pSettings, const char* a_szHostname, const char* a_szUrl)
{
UaClient uaClient;
OpcUa_Boolean bClientInitialized = OpcUa_False;
UaClient_Configuration *pClientConfiguration = OpcUa_Null;
UaClient_Session *pSession = OpcUa_Null;
UaClient_Session_Callback sessionCallback;
OpcUa_Boolean bComplete = OpcUa_False;
SampleClientContext clientContext;
Sample_Discovery sampleDiscovery;
char szValue[UABASE_PATH_MAX] = { 0 };
OpcUa_String *pDiscoveryUrl;
OpcUa_UInt32 uNoOfDiscoveryUrls = 0, uNoOfEndpoints = 0;
OpcUa_InitializeStatus(OpcUa_Module_Client, "ClientMain");
OpcUa_DeclareErrorTraceModule(OpcUa_Module_Client);
clientContext.State = State_Idle;
#if OPCUA_SUPPORT_PKI && UABASE_USE_FILESYSTEM
uStatus = SetupClientPKIInfrastructure(a_pSettings,
a_szHostname,
UACLIENT_APPLICATION_URI,
UACLIENT_APPLICATION_NAME);
OpcUa_GotoErrorIfBad(uStatus);
#endif /* OPCUA_SUPPORT_PKI && UABASE_USE_FILESYSTEM */
/* Initialize our helper structure sampleDiscovery */
OpcUa_String_Initialize(&sampleDiscovery.InitialDiscoveryUrl);
OpcUa_String_Initialize(&sampleDiscovery.DiscoveryUrl);
sampleDiscovery.pDiscovery = OpcUa_Null;
OpcUa_List_Initialize(&sampleDiscovery.lstDiscoveryUrls);
OpcUa_List_Initialize(&sampleDiscovery.lstEndpoints);
/* Initialize the Client SDK */
uStatus = UaClient_Initialize(&uaClient);
OpcUa_GotoErrorIfBad(uStatus);
bClientInitialized = OpcUa_True;
pClientConfiguration = UaClient_GetConfiguration();
#if OPCUA_TRACE_ENABLE && UABASE_USE_FILESYSTEM
uStatus = UaBase_FileTrace_SetApplicationName(OpcUa_String_FromCString(UACLIENT_APPLICATION_NAME));
OpcUa_GotoErrorIfBad(uStatus);
uStatus = UaBase_FileTrace_SetApplicationVersion(OpcUa_String_FromCString(UASDK_VERSION));
OpcUa_GotoErrorIfBad(uStatus);
#endif /* OPCUA_TRACE_ENABLE && UABASE_USE_FILESYSTEM */
uStatus = UaClient_Settings_GetConfigurationFromSettings(a_pSettings, pClientConfiguration);
OpcUa_GotoErrorIfBad(uStatus);
/* ApplicationDescription */
OpcUa_String_AttachReadOnly(&pClientConfiguration->ApplicationDescription.ApplicationUri, UACLIENT_APPLICATION_URI);
OpcUa_String_AttachReadOnly(&pClientConfiguration->ApplicationDescription.ProductUri, UACLIENT_PRODUCT_URI);
OpcUa_String_AttachReadOnly(&pClientConfiguration->ApplicationDescription.ApplicationName.Text, UACLIENT_APPLICATION_NAME);
/* Replace [gethostname] in ApplicationName and ApplicationUri */
UaBase_Settings_ReplaceUaString(&pClientConfiguration->ApplicationDescription.ApplicationName.Text, "[gethostname]", a_szHostname);
UaBase_Settings_ReplaceUaString(&pClientConfiguration->ApplicationDescription.ApplicationUri, "[gethostname]", a_szHostname);
/* Configure discovery and session for using in loop */
uStatus = UaClient_Discovery_Create(&sampleDiscovery.pDiscovery);
OpcUa_GotoErrorIfBad(uStatus);
/* Create an OPC UA Session which handles the connection */
OpcUa_MemSet(&sessionCallback, 0, sizeof(sessionCallback));
sessionCallback.pfConnectionStatusChanged_CB = Sample_ConnectionStatusChanged_CB;
sessionCallback.pfConnectError_CB = Sample_ConnectError_CB;
uStatus = UaClient_Session_Create(&sessionCallback, &pSession);
OpcUa_GotoErrorIfBad(uStatus);
uStatus = UaBase_Settings_BeginGroup(a_pSettings, "SampleClient");
OpcUa_GotoErrorIfBad(uStatus);
if (a_szUrl == OpcUa_Null || OpcUa_StrLenA(a_szUrl) <= 0)
{
uStatus = UaBase_Settings_ReadUaString(a_pSettings, "DiscoveryURL", &sampleDiscovery.InitialDiscoveryUrl, "opc.tcp://localhost:48020");
OpcUa_GotoErrorIfBad(uStatus);
uStatus = UaBase_Settings_ReadUaString(a_pSettings, "EndpointURL", &pSession->EndpointDescription.EndpointUrl, "");
OpcUa_GotoErrorIfBad(uStatus);
if (uStatus == OpcUa_UncertainSubstituteValue)
{
uStatus = UaBase_Settings_ReadUaString(a_pSettings, "DiscoveryURL", &pSession->EndpointDescription.EndpointUrl, "opc.tcp://localhost:48020");
OpcUa_GotoErrorIfBad(uStatus);
}
}
else
{
uStatus = OpcUa_String_AttachCopy(&sampleDiscovery.InitialDiscoveryUrl, a_szUrl);
OpcUa_GotoErrorIfBad(uStatus);
uStatus = OpcUa_String_AttachCopy(&pSession->EndpointDescription.EndpointUrl, a_szUrl);
OpcUa_GotoErrorIfBad(uStatus);
}
uStatus = OpcUa_String_CopyTo(&sampleDiscovery.InitialDiscoveryUrl, &sampleDiscovery.DiscoveryUrl);
OpcUa_GotoErrorIfBad(uStatus);
uStatus = UaBase_Settings_ReadString(a_pSettings, "UserTokenType", szValue, sizeof(szValue), "Anonymous");
OpcUa_GotoErrorIfBad(uStatus);
if (OpcUa_StrCmpA(szValue, "Anonymous") == 0)
{
pSession->UserToken.TokenType = OpcUa_UserTokenType_Anonymous;
}
else if (OpcUa_StrCmpA(szValue, "UserName") == 0)
{
pSession->UserToken.TokenType = OpcUa_UserTokenType_UserName;
OpcUa_String_Initialize(&pSession->UserToken.Token.UserName.User);
OpcUa_String_Initialize(&pSession->UserToken.Token.UserName.Password);
uStatus = UaBase_Settings_ReadUaString(a_pSettings, "User", &pSession->UserToken.Token.UserName.User, "");
OpcUa_GotoErrorIfBad(uStatus);
uStatus = UaBase_Settings_ReadUaString(a_pSettings, "Password", &pSession->UserToken.Token.UserName.Password, "");
OpcUa_GotoErrorIfBad(uStatus);
}
else if (OpcUa_StrCmpA(szValue, "Certificate") == 0)
{
#if defined(OPCUA_P_PKI_TYPE_OPENSSL)
OpcUa_PKIProvider PKIProvider;
OpcUa_CertificateStoreConfiguration PKIConfig;
OpcUa_Handle hCertificateStore = OpcUa_Null;
OpcUa_MemSet(&PKIProvider, 0, sizeof(PKIProvider));
OpcUa_CertificateStoreConfiguration_Initialize(&PKIConfig);
pSession->UserToken.TokenType = OpcUa_UserTokenType_Certificate;
OpcUa_ByteString_Initialize(&pSession->UserToken.Token.X509.UserCertificate);
OpcUa_Key_Initialize(&pSession->UserToken.Token.X509.UserPrivateKey);
PKIConfig.strPkiType = (char*)OPCUA_P_PKI_TYPE_OPENSSL;
uStatus = UaBase_Settings_ReadString(a_pSettings, "UserCertificateLocation", szValue, sizeof(szValue), "");
OpcUa_GotoErrorIfBad(uStatus);
PKIConfig.strTrustedCertificateListLocation = szValue;
uStatus = OpcUa_PKIProvider_Create(&PKIConfig, &PKIProvider);
OpcUa_GotoErrorIfBad(uStatus);
uStatus = PKIProvider.OpenCertificateStore(&PKIProvider,
&hCertificateStore);
OpcUa_GotoErrorIfBad(uStatus);
uStatus = PKIProvider.LoadCertificate(&PKIProvider,
szValue,
hCertificateStore,
&pSession->UserToken.Token.X509.UserCertificate);
OpcUa_GotoErrorIfBad(uStatus);
uStatus = UaBase_Settings_ReadString(a_pSettings, "UserPrivateKeyLocation", szValue, sizeof(szValue), "");
OpcUa_GotoErrorIfBad(uStatus);
uStatus = PKIProvider.LoadPrivateKey(szValue,
OpcUa_Crypto_Encoding_PEM,
OpcUa_Null,
&pSession->UserToken.Token.X509.UserPrivateKey);
OpcUa_GotoErrorIfBad(uStatus);
uStatus = PKIProvider.CloseCertificateStore(&PKIProvider, &hCertificateStore);
OpcUa_GotoErrorIfBad(uStatus);
#else /* defined(OPCUA_P_PKI_TYPE_OPENSSL) */
printf("Cannot use certificate tokens without OpenSSL\n");
OpcUa_GotoErrorWithStatus(OpcUa_BadConfigurationError);
#endif /* defined(OPCUA_P_PKI_TYPE_OPENSSL) */
}
/* Set EndpointUrl */
OpcUa_String_AttachReadOnly(&pSession->EndpointDescription.EndpointUrl, SERVER_ENDPOINT_URL);
/* Disable automatic reconnect */
pSession->AutomaticReconnect = OpcUa_False;
/* Set user data */
pSession->pUserData = &clientContext;
/* StartUp Client */
uStatus = UaClient_StartUp(&uaClient);
OpcUa_GotoErrorIfBad(uStatus);
while (!(bComplete && pSession->ConnectionStatus == UaClient_ConnectionStatus_Disconnected))
{
/* process sample state machine */
switch (clientContext.State)
{
case State_Idle:
sampleDiscovery.pUserData = &clientContext;
uStatus = UaClient_Discovery_BeginFindServers(sampleDiscovery.pDiscovery,
OpcUa_Null,
&sampleDiscovery.DiscoveryUrl,
0,
OpcUa_Null,
0,
OpcUa_Null,
Sample_FindServers_CB,
&sampleDiscovery);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_FindServers;
break;
case State_FindServersDone:
/* Call GetEndpoints for each server returned by FindServers */
uNoOfDiscoveryUrls = 0;
uNoOfEndpoints = 0;
OpcUa_List_GetNumberOfElements(&sampleDiscovery.lstDiscoveryUrls, &uNoOfDiscoveryUrls);
OpcUa_List_GetNumberOfElements(&sampleDiscovery.lstEndpoints, &uNoOfEndpoints);
if (uNoOfDiscoveryUrls > 0 && sampleDiscovery.pDiscovery->Connected == OpcUa_False)
{
pDiscoveryUrl = OpcUa_List_RemoveFirstElement(&sampleDiscovery.lstDiscoveryUrls);
OpcUa_String_Clear(&sampleDiscovery.DiscoveryUrl);
sampleDiscovery.DiscoveryUrl = *pDiscoveryUrl;
OpcUa_Free(pDiscoveryUrl);
uStatus = UaClient_Discovery_BeginGetEndpoints(sampleDiscovery.pDiscovery,
OpcUa_Null,
&sampleDiscovery.DiscoveryUrl,
0,
OpcUa_Null,
0,
OpcUa_Null,
Sample_GetEndpoints_CB,
&sampleDiscovery);
OpcUa_GotoErrorIfBad(uStatus);
}
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_GetEndpoints;
break;
case State_GetEndpointsDone:
uNoOfDiscoveryUrls = 0;
uNoOfEndpoints = 0;
OpcUa_List_GetNumberOfElements(&sampleDiscovery.lstDiscoveryUrls, &uNoOfDiscoveryUrls);
OpcUa_List_GetNumberOfElements(&sampleDiscovery.lstEndpoints, &uNoOfEndpoints);
/* Let user choose an endpoint */
if (uNoOfDiscoveryUrls == 0 && uNoOfEndpoints > 0 && sampleDiscovery.pDiscovery->Connected == OpcUa_False)
{
OpcUa_UInt32 i = 0;
int iChosen = -1;
/* restore original DiscoveryUrl set at application start */
OpcUa_String_CopyTo(&sampleDiscovery.InitialDiscoveryUrl, &sampleDiscovery.DiscoveryUrl);
printf("Select one of the following endpoints by pressing the according key:\n");
OpcUa_List_ResetCurrent(&sampleDiscovery.lstEndpoints);
pEndpoint = OpcUa_List_GetCurrentElement(&sampleDiscovery.lstEndpoints);
while (pEndpoint)
{
const char* szSecurityMode = pEndpoint->SecurityMode == OpcUa_MessageSecurityMode_None ? "None" :
pEndpoint->SecurityMode == OpcUa_MessageSecurityMode_SignAndEncrypt ? "SignAndEncrypt" : "Invalid";
printf("[%u]:\n", i);
printf(" EndpointUrl: %s\n", OpcUa_String_GetRawString(&pEndpoint->EndpointUrl));
printf(" SecurityMode: %s\n", szSecurityMode);
printf(" SecurityMode: %s\n", OpcUa_String_GetRawString(&pEndpoint->SecurityPolicyUri));
pEndpoint = OpcUa_List_GetNextElement(&sampleDiscovery.lstEndpoints);
i++;
}
while (iChosen == -1)
{
iChosen = _getch() - '0';
if (iChosen >= 0 && iChosen < (int)uNoOfEndpoints)
{
i = 0;
OpcUa_List_ResetCurrent(&sampleDiscovery.lstEndpoints);
pEndpoint = OpcUa_List_GetCurrentElement(&sampleDiscovery.lstEndpoints);
while (pEndpoint)
{
if (i == (OpcUa_UInt32)iChosen)
{
printf("Using endpoint #%i\n", i);
/* Set session connect info */
OpcUa_EndpointDescription_Clear(&pSession->EndpointDescription);
pSession->EndpointDescription = *pEndpoint;
OpcUa_EndpointDescription_Initialize(pEndpoint);
#if OPCUA_SUPPORT_PKI
if (OpcUa_String_StrnCmp(&pSession->EndpointDescription.SecurityPolicyUri,
OpcUa_String_FromCString(OpcUa_SecurityPolicy_None),
OPCUA_STRING_LENDONTCARE,
OpcUa_False) != 0)
{
/* Check if certificate is trusted */
if (OpcUa_IsBad(uStatus))
{
UaClient_TrustCertificate(&pClientConfiguration->PkiConfig,
printf("\n");
printf("Stored server certificate in the client trust list\n");
printf("Make sure the client certificate is in server trust list\n\n");
}
}
#endif
if (a_szUrl != OpcUa_Null && OpcUa_StrLenA(a_szUrl) > 0)
{
/* If EndpointURL was passed with -u, use it instead of the returned one. */
uStatus = OpcUa_String_AttachCopy(&pSession->EndpointDescription.EndpointUrl, a_szUrl);
OpcUa_GotoErrorIfBad(uStatus);
}
}
else
{
OpcUa_EndpointDescription_Clear(pEndpoint);
}
OpcUa_Free(pEndpoint);
pEndpoint = OpcUa_List_GetNextElement(&sampleDiscovery.lstEndpoints);
i++;
}
OpcUa_List_Clear(&sampleDiscovery.lstEndpoints);
}
else
{
printf("Invalid choice, please try again\n");
iChosen = -1;
}
}
}
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UA Client: Connecting to %s ...\n", SERVER_ENDPOINT_URL);
uStatus = UaClient_Session_BeginConnect(pSession);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Connect;
break;
case State_Connected:
uStatus = UaClient_Session_BeginDisconnect(pSession, OpcUa_False);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Disconnect;
break;
case State_Disconnected:
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample successfully completed. Terminating now.\n");
bComplete = OpcUa_True;
break;
case State_Error:
uStatus = UaClient_Session_BeginDisconnect(pSession, OpcUa_True);
if (OpcUa_IsBad(uStatus) && uStatus != OpcUa_BadInvalidState) { OpcUa_GotoError; }
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "An error occured. Terminating now.\n");
bComplete = OpcUa_True;
break;
default:
break;
}
/* Process Ua Client events */
uStatus = UaBase_DoCom();
if (OpcUa_IsBad(uStatus))
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UaBase_DoCom failed (0x%08x)\n", uStatus);
bComplete = OpcUa_True;
}
}
UaClient_Discovery_Delete(&sampleDiscovery.pDiscovery);
OpcUa_List_Clear(&sampleDiscovery.lstDiscoveryUrls);
OpcUa_List_Clear(&sampleDiscovery.lstEndpoints);
OpcUa_String_Clear(&sampleDiscovery.InitialDiscoveryUrl);
OpcUa_String_Clear(&sampleDiscovery.DiscoveryUrl);
pSession->pUserData = OpcUa_Null;
/* Clean Up Client */
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UA Client: Main stopped\n");
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
if (pSession)
pSession->pUserData = OpcUa_Null;
if (bClientInitialized != OpcUa_False)
{
UaClient_Discovery_Delete(&sampleDiscovery.pDiscovery);
OpcUa_List_Clear(&sampleDiscovery.lstDiscoveryUrls);
OpcUa_List_Clear(&sampleDiscovery.lstEndpoints);
OpcUa_String_Clear(&sampleDiscovery.InitialDiscoveryUrl);
OpcUa_String_Clear(&sampleDiscovery.DiscoveryUrl);
/* Clean up Base */
}
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UA Client: Main stopped due ERROR! (0x%08x)\n", uStatus);
OpcUa_FinishErrorHandling;
}
/*============================================================================
* Main entry point for the application
*===========================================================================*/
int main(void)
{
int ret = EXIT_SUCCESS;
OpcUa_StatusCode uStatus = OpcUa_Good;
OpcUa_Handle hProxyStubPlatformLayer = OpcUa_Null;
OpcUa_ProxyStubConfiguration proxyStubConfiguration;
UaBase_Settings g_settings;
#if defined(WIN32)
char szConfigurationFile[UABASE_PATH_MAX] = "client_settings.ini";
#else
char szConfigurationFile[UABASE_PATH_MAX] = "client_settings.conf";
#endif
char szHostname[256] = "";
char szUrl[256] = "";
/* Set up OPC UA */
uStatus = InitializeOpcUaStack(&hProxyStubPlatformLayer, &proxyStubConfiguration);
if ( OpcUa_IsNotGood(uStatus) )
{
return EXIT_FAILURE;
}
uStatus = UaBase_Settings_Initialize(&g_settings, szConfigurationFile);
if (OpcUa_IsNotGood(uStatus))
{
printf("Could not open configuration file '%s'\n", szConfigurationFile);
CleanupOpcUaStack(&hProxyStubPlatformLayer);
exit(EXIT_FAILURE);
}
GetFQHostname(szHostname, sizeof(szHostname));
uStatus = ClientMain(&g_settings, szHostname, szUrl);
if (OpcUa_IsNotGood(uStatus))
{
ret = EXIT_FAILURE;
}
UaBase_Settings_Clear(&g_settings);
/* Clean up OPC UA */
uStatus = CleanupOpcUaStack(&hProxyStubPlatformLayer);
if ( OpcUa_IsNotGood(uStatus) )
{
ret = EXIT_FAILURE;
}
return ret;
}