File: C:/Redmine-4.x/redmine-4.2.9/files/190114181004_Main.cpp
/*****************************************************************************
Author
©. Michel Condemine, 4CE Industry (2010-2012)
Contributors
This software is a computer program whose purpose is to
implement behavior describe in the OPC UA specification.
see wwww.opcfoundation.org for more details about OPC.
This software is governed by the CeCILL-C license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL-C
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL-C license and that you accept its terms.
*****************************************************************************/
#include "stdafx.h"
#include "UAVariable.h"
#include "UAMethod.h"
#ifdef _GNUC_
#include <dlfcn.h>
// below header file for the new keyboard control mode (q or Q without hiting 'Enter')
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#endif
#include "VpiFuncCaller.h"
#include "VpiTag.h"
#include "VpiWriteObject.h"
#include "RefCountedNodeId.h"
#include "SubscribedTagDetail.h"
#include "VpiDevice.h"
#include "UAReferenceType.h"
#include "UAObjectType.h"
#include "Field.h"
#include "Definition.h"
#include "UADataType.h"
#include "UAVariableType.h"
#include "UAView.h"
#include "UAObject.h"
#include "Alias.h"
#include "SimulatedNode.h"
#include "SimulatedGroup.h"
#include "BuildInfo.h"
#include "ServerStatus.h"
#include "VpiWriteObject.h"
#include "VPIScheduler.h"
#include "NamespaceUri.h"
#include "StatusCodeException.h"
#include "ContinuationPoint.h"
#include "SessionSecurityDiagnosticsDataType.h"
#include "SessionDiagnosticsDataType.h"
#include "luainc.h"
#include "LuaVirtualMachine.h"
#include "LuaScript.h"
#include "OpenOpcUaScript.h"
using namespace UAScript;
//#include "MonitoredItemServer.h"
#include "UAMonitoredItemNotification.h"
#include "UADataChangeNotification.h"
#include "EventDefinition.h"
#include "EventsEngine.h"
using namespace UAEvents;
#include "VpiDispatchedTag.h"
#include "UAInformationModel.h"
#include "MonitoredItemServer.h"
#include "UAEventNotificationList.h"
#include "QueuedPublishRequest.h"
#include "UAStatusChangeNotification.h"
#include "SubscriptionServer.h"
#include "QueuedCallRequest.h"
#include "QueuedReadRequest.h"
#include "QueuedHistoryReadRequest.h"
#include "QueuedQueryFirstRequest.h"
#include "QueuedQueryNextRequest.h"
#include "SessionServer.h"
#include "UABinding.h"
#include "VfiDataValue.h"
#include "UAHistorianVariable.h"
#include "HaEngine.h"
using namespace UAHistoricalAccess;
#include "ServerApplication.h"
#include "ServiceModule.h" // Implement the server as a Windows Service. So this class/header is a Windows Only class/header
#if defined(WIN32) || defined(WIN64)
#include <conio.h>
//#include "resource.h"
#endif
#include "opcua_base64.h"
using namespace OpenOpcUa;
using namespace UASimulation;
using namespace UASubSystem;
using namespace UAAddressSpace;
using namespace UACoreServer;
// Set of parameter passed to the thread used to load a Vpi
typedef struct _SubSystemParam
{
OpcUa_CharA* pszProjectFolder;
OpcUa_CharA* chFileName;
} SubSystemParam;
void LoadSubsystemsThread(LPVOID arg);
//
CUAInformationModel* CServerApplication::m_pTheAddressSpace=NULL;
OpcUa_Semaphore g_ShutdownServerSem;
OpcUa_Boolean g_bRun;
//CServerApplication m_theApplication;
CServerApplication* g_pTheApplication = OpcUa_Null;
OpcUa_Thread hInvertingReferenceThread=OpcUa_Null;
#if defined(WIN32) || defined(WIN64)
//CServiceModule _Module;
#endif
//
/// <summary>
/// Shutdowns the server.
/// Sequence of de-initialization for a proper stop of the server
/// </summary>
void ShutdownServer(OpcUa_Int32 iSecondsTillShutdown,OpcUa_CharA* ShutdownReason)
{
CUAInformationModel* pInformationModel=CServerApplication::m_pTheAddressSpace;
if (pInformationModel)
{
// First we stop the thread in charge of updated the mandatory nodes
//pInformationModel->StopUpdateMandatoryNodesThread();
// Now let's update the server status
CServerStatus* pServerStatus = pInformationModel->GetInternalServerStatus();
if (pServerStatus)
{
pServerStatus->SetServerState(OpcUa_ServerState_Shutdown);
OpcUa_NodeId aTmpNodeId00;
OpcUa_NodeId_Initialize(&aTmpNodeId00);
CUAVariable* pUATmpVariable00 = OpcUa_Null;
aTmpNodeId00.IdentifierType = OpcUa_IdentifierType_Numeric;
OpcUa_Variant varVal00;
OpcUa_Variant_Initialize(&varVal00);
varVal00.Datatype = OpcUaType_Int32;
aTmpNodeId00.Identifier.Numeric = OpcUaId_Server_ServerStatus_State; // 2259
OpcUa_StatusCode uStatus = pInformationModel->GetNodeIdFromVariableList(aTmpNodeId00, &pUATmpVariable00);
if (uStatus == OpcUa_Good)
{
varVal00.Datatype = OpcUaType_UInt32;
varVal00.Value.Int32 = pServerStatus->GetServerState();
CDataValue* pDataValue = pUATmpVariable00->GetValue();
if (pDataValue)
pDataValue->SetValue(varVal00);
}
// SecondsTillShutdown
pServerStatus->SetSecondsTillShutdown(iSecondsTillShutdown);
aTmpNodeId00.Identifier.Numeric = 2992; // SecondsTillShutdown
uStatus = pInformationModel->GetNodeIdFromVariableList(aTmpNodeId00, &pUATmpVariable00);
if (uStatus == OpcUa_Good)
{
varVal00.Datatype = OpcUaType_UInt32;
varVal00.Value.Int32 = pServerStatus->GetSecondsTillShutdown();
CDataValue* pDataValue = pUATmpVariable00->GetValue();
if (pDataValue)
pDataValue->SetValue(varVal00);
}
// ShutdownReason
OpcUa_LocalizedText aShutdownReason;
OpcUa_LocalizedText_Initialize(&aShutdownReason);
OpcUa_String_AttachCopy(&(aShutdownReason.Locale), "en-US");
OpcUa_String_AttachCopy(&(aShutdownReason.Text), ShutdownReason);
pServerStatus->SetShutdownReason(aShutdownReason);
OpcUa_LocalizedText_Clear(&aShutdownReason);
OpcUa_NodeId_Clear(&aTmpNodeId00);
///////////////////////////////////////////
//
// ServerStatus
//
//////////////////////////////////////////
CUAVariable* pUAVariable = NULL;
OpcUa_NodeId aNodeId;
OpcUa_NodeId_Initialize(&aNodeId);
aNodeId.Identifier.Numeric = 2256; // ServerStatus UpdateMandatoryNodesThread
aNodeId.IdentifierType = OpcUa_IdentifierType_Numeric;
aNodeId.NamespaceIndex = 0; // opc foundation namespace
pInformationModel->LockServerCacheMutex();
uStatus = pInformationModel->GetNodeIdFromVariableList(aNodeId, &pUAVariable);
if (uStatus == OpcUa_Good)
{
///////////////////////////////////////////////////////////////////////
CDataValue* pDataValue = pUAVariable->GetValue();
OpcUa_Variant aVariant = pDataValue->GetValue();
if (aVariant.Value.ExtensionObject)
{
if (pDataValue)
{
if (pDataValue->GetValue().Value.ExtensionObject)
{
{
//
// mise a jour des nodes encapsulées 2258,2259,2992, 2993
OpcUa_NodeId aTmpNodeId;
OpcUa_NodeId_Initialize(&aTmpNodeId);
CUAVariable* pUATmpVariable = OpcUa_Null;
aTmpNodeId.IdentifierType = OpcUa_IdentifierType_Numeric;
OpcUa_Variant varVal;
OpcUa_Variant_Initialize(&varVal);
aTmpNodeId.Identifier.Numeric = 2258; // CurrentTime
uStatus = pInformationModel->GetNodeIdFromVariableList(aTmpNodeId, &pUATmpVariable);
if (uStatus == OpcUa_Good)
{
varVal.Datatype = OpcUaType_DateTime;
varVal.Value.DateTime = pServerStatus->GetInternalCurrentTime();
CDataValue* pDataValue00 = pUATmpVariable->GetValue();
if (pDataValue00)
{
pDataValue00->SetValue(varVal);
pDataValue00->SetStatusCode(OpcUa_Good);
pDataValue00->SetServerTimestamp(OpcUa_DateTime_UtcNow());
}
}
OpcUa_Variant_Initialize(&varVal);
aTmpNodeId.Identifier.Numeric = OpcUaId_Server_ServerStatus_State; ; //2259
uStatus = pInformationModel->GetNodeIdFromVariableList(aTmpNodeId, &pUATmpVariable);
if (uStatus == OpcUa_Good)
{
varVal.Datatype = OpcUaType_Int32;
varVal.Value.Int32 = pServerStatus->GetServerState();
CDataValue* pDataValue00 = pUATmpVariable->GetValue();
if (pDataValue00)
{
pDataValue00->SetValue(varVal);
pDataValue00->SetStatusCode(OpcUa_Good);
pDataValue00->SetServerTimestamp(OpcUa_DateTime_UtcNow());
}
}
OpcUa_Variant_Clear(&varVal);
// SecondsTillShutdown
OpcUa_Variant_Initialize(&varVal);
aTmpNodeId.Identifier.Numeric = 2992; // SecondsTillShutdown
uStatus = pInformationModel->GetNodeIdFromVariableList(aTmpNodeId, &pUATmpVariable);
if (uStatus == OpcUa_Good)
{
varVal.Datatype = OpcUaType_Int32;
varVal.Value.Int32 = pServerStatus->GetSecondsTillShutdown();
CDataValue* pDataValue00 = pUATmpVariable->GetValue();
if (pDataValue00)
{
pDataValue00->SetValue(varVal);
pDataValue00->SetStatusCode(OpcUa_Good);
pDataValue00->SetServerTimestamp(OpcUa_DateTime_UtcNow());
}
}
OpcUa_Variant_Clear(&varVal);
// ShutdownReason
OpcUa_Variant_Initialize(&varVal);
aTmpNodeId.Identifier.Numeric = 2993; // ShutdownReason
uStatus = pInformationModel->GetNodeIdFromVariableList(aTmpNodeId, &pUATmpVariable);
if (uStatus == OpcUa_Good)
{
varVal.Value.LocalizedText = (OpcUa_LocalizedText*)OpcUa_Alloc(sizeof(OpcUa_LocalizedText));
if (varVal.Value.LocalizedText)
{
OpcUa_LocalizedText_Initialize(varVal.Value.LocalizedText);
varVal.Datatype = OpcUaType_LocalizedText;
OpcUa_LocalizedText ltVal = pServerStatus->GetShutdownReason();
OpcUa_LocalizedText_CopyTo(<Val, varVal.Value.LocalizedText);
CDataValue* pDataValue00 = pUATmpVariable->GetValue();
if (pDataValue00)
{
pDataValue00->SetValue(varVal);
pDataValue00->SetStatusCode(OpcUa_Good);
pDataValue00->SetServerTimestamp(OpcUa_DateTime_UtcNow());
}
}
}
OpcUa_Variant_Clear(&varVal);
OpcUa_NodeId_Clear(&aTmpNodeId);
}
}
}
}
}
pInformationModel->UnlockServerCacheMutex();
}
}
// fin informations de Shutdown
}
// Play a small animation while stoping the server
OpcUa_StatusCode StopAnimation(OpcUa_Int32 iSecond)
{
OpcUa_StatusCode uStatus = OpcUa_Good;
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
if (pInformationModel)
{
CServerStatus* pServerStatus = pInformationModel->GetInternalServerStatus();
OpcUa_Variant varVal;
OpcUa_NodeId aTmpNodeId;
OpcUa_NodeId_Initialize(&aTmpNodeId);
aTmpNodeId.IdentifierType = OpcUa_IdentifierType_Numeric;
aTmpNodeId.Identifier.Numeric = 2992; // SecondsTillShutdown
CUAVariable* pUATmpVariable = OpcUa_Null;
uStatus = pInformationModel->GetNodeIdFromVariableList(aTmpNodeId, &pUATmpVariable);
if (uStatus == OpcUa_Good)
{
for (OpcUa_Int32 ii = 0; ii < iSecond*10; ii++)
{
if ((ii % 10) == 0)
{
printf(".");
// SecondsTillShutdown
OpcUa_Variant_Initialize(&varVal);
CDataValue* pDataValue = pUATmpVariable->GetValue();
varVal.Datatype = OpcUaType_Int32;
varVal.Value.Int32 = pServerStatus->GetSecondsTillShutdown() - 1;
pServerStatus->SetSecondsTillShutdown(varVal.Value.Int32);
pDataValue->SetValue(varVal);
}
OpcUa_Thread_Sleep(100);
}
}
printf("\n");
}
return uStatus;
}
OpcUa_Boolean IsService(char* szCommand)
{
OpcUa_Boolean bResult = OpcUa_False;
#ifdef _GNUC_
bResult = OpcUa_False;
#endif
#if defined(WIN32) || defined(WIN64)
if (strcmp(szCommand, "Install") == 0)
bResult = OpcUa_True;
if (strcmp(szCommand, "Uninstall") == 0)
bResult = OpcUa_True;
if (strcmp(szCommand, "Service") == 0)
bResult = OpcUa_True;
#endif
return bResult;
}
OpcUa_StatusCode RunAsApplication(STARTUP_COMMAND eCommand)
{
////////////////////////////////////////////////
//
// Run as a Shell or Linux server
OpcUa_StatusCode uStatus = OpcUa_Good;
OpcUa_CharA* path = g_pTheApplication->GetConfigPath();
OpcUa_CharA* fileName = g_pTheApplication->GetConfigFileName();
if ((path) && (fileName) && (eCommand==RUN_SERVER) )
{
OpcUa_ProxyStubConfiguration* pTraceConfiguration= g_pTheApplication->GetTraceConfiguration();
CServerApplication::m_pTheAddressSpace = new CUAInformationModel();
///////////////////////////////////////////////////
//
// Sempahore to remotly stop the server
OpcUa_Semaphore_Create(&g_ShutdownServerSem, 0, 0x100);
// Parsing du fichier de configuration du serveur
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_LEVEL_ALWAYS, "Loading %s %s\n", path, fileName);
uStatus = g_pTheApplication->LoadUaServerConfiguration(path, fileName);
if (uStatus == OpcUa_Good)
{
// Fin chargement du fichier de configuration
// Mise en place de L'application Description et des informations sur les ports d'écoute
CApplicationDescription* pApplicationDescription = g_pTheApplication->GetApplicationDescription();
uStatus = SetServerDescriptionTransportPortListener(&pApplicationDescription);
if (uStatus == OpcUa_Good)
{
g_pTheApplication->SetApplicationDescription(pApplicationDescription);
// Update the server Uri
OpcUa_CharA* pszApplicationUri = OpcUa_Null;
CServerApplication::m_pTheAddressSpace->BuildApplicationUri(&pszApplicationUri);
CNamespaceUri* pNamespaceUri=CServerApplication::m_pTheAddressSpace->GetNamespaceUri(1);
OpcUa_String szApplicationUri;
OpcUa_String_Initialize(&szApplicationUri);
OpcUa_String_AttachCopy(&szApplicationUri, pszApplicationUri);
pNamespaceUri->SetUriName(&szApplicationUri);
OpcUa_String_Clear(&szApplicationUri);
//////////////////////////////////////////
//
// Definition du niveau de trace
//
//////////////////////////////////////////
// OPCUA_TRACE_OUTPUT_LEVEL_DEBUG
// OPCUA_TRACE_OUTPUT_LEVEL_INFO
// OPCUA_TRACE_OUTPUT_LEVEL_WARNING
// OPCUA_TRACE_OUTPUT_LEVEL_NONE
// OPCUA_TRACE_OUTPUT_LEVEL_SYSTEM
// OPCUA_TRACE_OUTPUT_LEVEL_ERROR
OpcUa_UInt32 uiTraceLevel = g_pTheApplication->GetTraceLevel();
OpcUa_Trace_ChangeTraceLevel(pTraceConfiguration,uiTraceLevel);
OpcUa_UInt32 iOutput = g_pTheApplication->GetTraceOutput();
if (iOutput == OPCUA_TRACE_OUTPUT_FILE)
{
// Mise en place du nom du fichier de sortie
OpcUa_String szLogFolder;
OpcUa_String_Initialize(&szLogFolder);
OpcUa_String strFileName;
OpcUa_String_Initialize(&strFileName);
OpcUa_String strBakFileName;
OpcUa_String_Initialize(&strBakFileName);
// extension du fichier
OpcUa_String strExtension;
OpcUa_String_Initialize(&strExtension);
OpcUa_String_AttachCopy(&strExtension, ".log");
#if defined(WIN32) || defined(WIN64)
OpcUa_String_AttachCopy(&szLogFolder, "Logs\\");
#endif
#ifdef _GNUC_
OpcUa_String_AttachCopy(&szLogFolder, "Logs/");
#endif
// extension de la sauvegarde
OpcUa_String strBakExtension;
OpcUa_String_Initialize(&strBakExtension);
OpcUa_String_AttachCopy(&strBakExtension, ".bak");
// create the output filename base on the name of the server EndPoint
pApplicationDescription = g_pTheApplication->GetApplicationDescription();
if (pApplicationDescription)
{
// Get the first ServerName
OpcUa_LocalizedText aLocalizedText = pApplicationDescription->GetApplicationName();
// Log folder name
OpcUa_String szLogFolderName = g_pTheApplication->GetLogFolder();
if (OpcUa_String_StrLen(&szLogFolderName) > 0)
{
OpcUa_String_CopyTo(&(szLogFolderName), &strFileName);
OpcUa_String_CopyTo(&(szLogFolderName), &strBakFileName);
// Check that the last caracter of the ProjectFolderName is a \ or not
OpcUa_CharA* pszLogFolder = OpcUa_String_GetRawString(&szLogFolderName);
OpcUa_UInt32 iLen = OpcUa_String_StrLen(&szLogFolderName);
#if defined(WIN32) || defined(WIN64)
if (pszLogFolder[iLen - 1] != '\\')
{
OpcUa_String sep;
OpcUa_String_Initialize(&sep);
OpcUa_String_AttachCopy(&sep, "\\");
OpcUa_String_StrnCat(&strFileName, &sep, OpcUa_String_StrLen(&sep));
OpcUa_String_StrnCat(&strBakFileName, &sep, OpcUa_String_StrLen(&sep));
OpcUa_String_Clear(&sep);
}
#endif
#ifdef _GNUC_
if (pszLogFolder[iLen - 1] != '/')
{
OpcUa_String sep;
OpcUa_String_Initialize(&sep);
OpcUa_String_AttachCopy(&sep, "/");
OpcUa_String_StrnCat(&strFileName, &sep, OpcUa_String_StrLen(&sep));
OpcUa_String_StrnCat(&strBakFileName, &sep, OpcUa_String_StrLen(&sep));
OpcUa_String_Clear(&sep);
}
#endif
// Add Log folder
// Add the filename extracted from the ServerName
OpcUa_String_StrnCat(&strFileName, &aLocalizedText.Text, OpcUa_String_StrLen(&aLocalizedText.Text));
OpcUa_String_StrnCat(&strBakFileName, &aLocalizedText.Text, OpcUa_String_StrLen(&aLocalizedText.Text));
}
else
{
OpcUa_String_CopyTo(&(aLocalizedText.Text), &strFileName);
OpcUa_String_CopyTo(&(aLocalizedText.Text), &strBakFileName);
}
// creation du nom du fichier de log
OpcUa_String_StrnCat(&strFileName, &strExtension, OpcUa_String_StrLen(&strExtension));
// creation du nom du fichier de sauvegarde
OpcUa_String_StrnCat(&strBakFileName, &strBakExtension, OpcUa_String_StrLen(&strBakExtension));
OpcUa_Trace_SetTraceFile(pTraceConfiguration,strFileName);
// On sauvegarde une eventuelle trace existante
FILE* hFile = OpcUa_Null;
hFile = fopen(OpcUa_String_GetRawString(&strFileName), "r");
if (hFile)
{
// Ouverture du fichier de sauvegarde
FILE* hFileBak = OpcUa_Null;
OpcUa_CharA* szBakFileName = OpcUa_String_GetRawString(&strBakFileName);
hFileBak = fopen(szBakFileName, "w");
if (hFileBak)
{
char bakBuffer;
// On lit l'ensemble du fichier dans le buffer
// On copie dans la sauvegarde
while (fread(&bakBuffer, sizeof(char), 1, hFile) == 1)
fwrite(&bakBuffer, sizeof(char), 1, hFileBak);
// On ferme l'ancien fichier
fclose(hFile);
fflush(hFileBak);
if (fclose(hFileBak) == EOF)
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Cannot close the bak log file\n");
}
// On supprime l'ancien fichier
hFile = fopen(OpcUa_String_GetRawString(&strFileName), "w");
if (hFile)
fclose(hFile);
}
}
OpcUa_String_Clear(&strExtension);
OpcUa_String_Clear(&strFileName);
OpcUa_String_Clear(&strBakExtension);
OpcUa_String_Clear(&strBakFileName);
OpcUa_String_Clear(&szLogFolder);
}
// Load nodeset files to create the server AddressSpace
uStatus = LoadNodeSetFiles();
if (uStatus == OpcUa_Good)
{
uStatus = LoadSimulationFiles();
if (uStatus == OpcUa_Good)
{
//
// Load subsystem configuration file
uStatus = LoadSubSystemFiles();
if (uStatus == OpcUa_Good)
{
CEventsEngine* pEventsEngine = g_pTheApplication->GetEventsEngine();
if (!pEventsEngine)
pEventsEngine = new CEventsEngine(pTraceConfiguration);
if (pEventsEngine)
g_pTheApplication->SetEventsEngine(pEventsEngine);
/////////////////////////////////////////////////////////
// PostProcessing
//
uStatus = PostProcessing();
if (uStatus != OpcUa_Good)
{
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Failed);
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Post Processing failed 0x%05x\n", uStatus);
}
else
{
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
// Déblocage de la thread de mise à jour des MandatoryNodes
OpcUa_Semaphore_Post(pInformationModel->m_UpdateMandatoryNodesThreadSem, 1);
// Si besoin demarrage du moteur d'archivage
CHaEngine* pHaEngine = g_pTheApplication->GetHaEngine();
if (pHaEngine)
{
if (pHaEngine->LoadVfi() == OpcUa_Good)
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Your Vfi was correctly loaded\n");
pHaEngine->InitHaEngine(); // Call GlobalStart
OpcUa_Vfi_Handle hVfiHandle = OpcUa_Null;
OpcUa_String szArchiveId = g_pTheApplication->GetArchiveId();
OpcUa_NodeId aNodeId;
OpcUa_NodeId_Initialize(&aNodeId);
if (ParseNodeId(OpcUa_String_GetRawString(&szArchiveId), &aNodeId) == OpcUa_Good)
{
// Warning the Vfi is suppose to copy the aNodeId
uStatus = pHaEngine->VfiGlobalStart(g_pTheApplication->GetArchiveName(),
aNodeId,
&hVfiHandle);
if (uStatus == OpcUa_Good)
{
pHaEngine->SetVfiHandle(hVfiHandle);
// VfiSetNotifyCallback
uStatus=pHaEngine->VfiSetNotifyCallback(hVfiHandle, (PFUNCVFINOTIFYCALLBACK)(VfiNotifyCallback));
if (uStatus == OpcUa_Good)
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "VfiSetNotifyCallback succeeded\n");
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "VfiSetNotifyCallback failed 0x%05x\n", uStatus);
// VfiColdStart
uStatus = pHaEngine->VfiColdStart(hVfiHandle);
if (uStatus != OpcUa_Good)
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "VfiColdStart failed 0x%05x\n", uStatus);
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "VfiColdStart succeeded\n");
}
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "VfiGlobalStart failed 0x%05x\n", uStatus);
}
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "ParseNodeId failed when preparing the call to VfiGlobalStart\n");
OpcUa_NodeId_Clear(&aNodeId);
}
else
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Failed);
}
// initialize security by specifying the client certificate and the location of the trusted certificates.
OpcUa_String szProjectFolder = g_pTheApplication->GetProjectFolder();
OpcUa_CharA* pszCertificateStore = (OpcUa_CharA*)OpcUa_Alloc(512);
ZeroMemory(pszCertificateStore, 512);
if (OpcUa_String_StrLen(&szProjectFolder) > 0)
{
OpcUa_CharA* pszProjectFolder = OpcUa_String_GetRawString(&szProjectFolder);
#if defined(WIN32) || defined(WIN64)
if (pszProjectFolder[OpcUa_String_StrLen(&szProjectFolder) - 1] == '\\')
pszProjectFolder[OpcUa_String_StrLen(&szProjectFolder) - 1] = 0;
sprintf(pszCertificateStore, "%s\\CertificateStore", OpcUa_String_GetRawString(&szProjectFolder));
#endif
#ifdef _GNUC_
if (pszProjectFolder[OpcUa_String_StrLen(&szProjectFolder) - 1] == '/')
pszProjectFolder[OpcUa_String_StrLen(&szProjectFolder) - 1] = 0;
sprintf(pszCertificateStore, "%s/CertificateStore", OpcUa_String_GetRawString(&szProjectFolder));
#endif
}
OpcUa_String aCertificateStore;
OpcUa_String_Initialize(&aCertificateStore);
OpcUa_String_AttachCopy(&aCertificateStore, pszCertificateStore);
// Set up all path for the certificate Store
g_pTheApplication->SetCertificateStorePath(aCertificateStore);
OpcUa_Free(pszCertificateStore);
uStatus = g_pTheApplication->LoadPFXCertificate();
if (uStatus == OpcUa_Good)
{
// on va tenter de lire le fichier DER afin de vérifier qu'il s'agit du bon DER
// a savoir :
// 1- il existe
// 2- sa clé correpsond acelle du pfx
uStatus = g_pTheApplication->LoadDERCertificate();
if (uStatus != OpcUa_Good)
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Your certificate in DER file not fit the private key. Will create a new one\n");
uStatus = g_pTheApplication->CreateCertificate();
}
}
else
uStatus = g_pTheApplication->CreateCertificate();
// on va vérifier que le certificat du serveur est encore valide
OpcUa_CharA* sThumbprint = OpcUa_Null;
OpcUa_CharA* lApplicationUri = OpcUa_Null;
OpcUa_CharA* psCommonName = OpcUa_Null;
OpcUa_StringA* pNameEntries = OpcUa_Null; // (OpcUa_StringA*)OpcUa_Alloc(sizeof(OpcUa_String));
OpcUa_UInt32 uiNoOfNameEntries = 0;
OpcUa_ByteString* pServerCertificate = g_pTheApplication->GetCertificate();
if (pServerCertificate)
{
uStatus = OpcUa_Certificate_GetInfo(
(OpcUa_ByteString*)pServerCertificate,
&pNameEntries,
&uiNoOfNameEntries,
&psCommonName,
&sThumbprint,
&lApplicationUri,
OpcUa_Null,
OpcUa_Null);
if (uiNoOfNameEntries > 0)
{
// Search for CRLDP in the entries
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Extension found in the server certificate are :\n");
for (OpcUa_UInt32 i = 0; i < uiNoOfNameEntries; i++)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "%s:\n", pNameEntries[i]);
if (strcmp(pNameEntries[i], "CRL Distribution Points") == 0)
{
}
}
}
if (pNameEntries)
free(pNameEntries);
if (lApplicationUri)
{
OpcUa_Free(lApplicationUri);
lApplicationUri = OpcUa_Null;
}
if (sThumbprint)
{
OpcUa_Free(sThumbprint);
sThumbprint = OpcUa_Null;
}
if (psCommonName)
{
OpcUa_Free(psCommonName);
psCommonName = OpcUa_Null;
}
OpcUa_DateTime ValidFrom, ValidTo;
OpcUa_DateTime_Initialize(&ValidFrom);
OpcUa_DateTime_Initialize(&ValidTo);
uStatus = OpcUa_Certificate_GetDateBound(
(OpcUa_ByteString*)pServerCertificate,
&ValidFrom, &ValidTo);
if (uStatus == OpcUa_Good)
{
// Verification de la validitée du certificat;
OpcUa_String* strFrom = OpcUa_Null; // (OpcUa_String*)OpcUa_Alloc(sizeof(OpcUa_String));
OpcUa_String* strTo = OpcUa_Null; //OpcUa_String*)OpcUa_Alloc(sizeof(OpcUa_String));
Utils::OpcUaDateTimeToString(ValidFrom, &strFrom);
Utils::OpcUaDateTimeToString(ValidTo, &strTo);
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Your certificate validate your server \nfrom: %s \nto: %s\n",
OpcUa_String_GetRawString(strFrom),
OpcUa_String_GetRawString(strTo));
if (strTo)
{
OpcUa_String_Clear(strTo);
OpcUa_Free(strTo);
}
if (strFrom)
{
OpcUa_String_Clear(strFrom);
OpcUa_Free(strFrom);
}
// Est ce que la date de fin est dépassée
OpcUa_DateTime utcNow = OpcUa_DateTime_UtcNow();
OpcUa_UInt32 uDiff = 0;
uStatus = OpcUa_P_GetDateTimeDiffInSeconds32(utcNow, ValidTo, &uDiff);
if ((uStatus != OpcUa_BadOutOfRange) && (uStatus != OpcUa_BadInvalidArgument))
{
// Il n'est peut etre pas encore valide
uStatus = OpcUa_P_GetDateTimeDiffInSeconds32(ValidFrom, utcNow, &uDiff);
if ((uStatus != OpcUa_BadOutOfRange) && (uStatus != OpcUa_BadInvalidArgument))
{
// Il est peut être mal formé
uStatus = OpcUa_P_GetDateTimeDiffInSeconds32(ValidFrom, ValidTo, &uDiff);
if ((uStatus == OpcUa_BadOutOfRange) || (uStatus == OpcUa_BadInvalidArgument))
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS, "Your certificate is corrupted. Server is stopping\n");
ShutdownServer(5, (OpcUa_CharA*)"Server shutdown: Your certificate is corrupted");
uStatus = OpcUa_BadCertificateInvalid;
}
}
else
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS, "Your certificate is not yet valid. Server is stopping\n");
ShutdownServer(5, (OpcUa_CharA*)"Server shutdown: Your certificate is not yet valid.");
uStatus = OpcUa_BadCertificateInvalid;
}
}
else
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS, "Your certificate is expired. Server is stopping\n");
ShutdownServer(5, (OpcUa_CharA*)"Server shutdown: Your certificate is expired.");
uStatus = OpcUa_BadCertificateInvalid;
}
}
if (uStatus == OpcUa_Good)
{
uStatus = g_pTheApplication->InitializeSecurity();
if (uStatus != OpcUa_Good)
{
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Failed);
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "InitializeSecurity failed StatusCode=0x%05x\n", uStatus);
}
else
{
// make sure the discovery server knows about the server.
// note: it may take time for the discovery server to recognize a new certificate.
//g_pTheApplication->AddServerToDiscoveryServerTrustList(OpcUa_False);
// start the server.
g_pTheApplication->StartLDSRegistrationThread();
CApplicationDescription* pAppDescription = g_pTheApplication->GetApplicationDescription(); // pApplicationDescriptionList->at(ii);
if (pAppDescription)
{
/////////////////////////////////////////////////////////////////////////////////////////////
OpcUa_String* pListener = (OpcUa_String*)OpcUa_Alloc(sizeof(OpcUa_String));
OpcUa_String_Initialize(pListener);
if (pAppDescription->GetDiscoveryUrls())
{
OpcUa_String* pUrl = pAppDescription->GetDiscoveryUrls();
if (pUrl)
OpcUa_String_CopyTo(pUrl, pListener);
OpcUa_LocalizedText aAppName = pAppDescription->GetApplicationName();
OpcUa_String_StrnCat(pListener, &(aAppName.Text), OpcUa_String_StrLen(&(aAppName.Text)));
}
else
{
OpcUa_String* pUri = pAppDescription->GetApplicationUri();
if (pUri)
OpcUa_String_CopyTo(pUri, pListener);
}
if (pListener)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_DEBUG, "%s\n", OPCUA_P_CONFIGSTRING);
#if OPCUA_P_LISTEN_INET6 == OPCUA_CONFIG_YES
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS,
"Server listening on IPV6 at :\n\t%s.\r\n", OpcUa_String_GetRawString(pListener));
#endif
#if OPCUA_P_LISTEN_INET6 == OPCUA_CONFIG_NO
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS,
"Server listening on IPV4 at :\n\t%s.\r\n", OpcUa_String_GetRawString(pListener));
#endif
OpcUa_String_Clear(pListener);
OpcUa_Free(pListener);
}
else
{
OpcUa_String* pUri = pAppDescription->GetApplicationUri();
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_LEVEL_ALWAYS,
"CRITICAL ERROR>Server is not listening on :\n\t%s.\r\n", OpcUa_String_GetRawString(pUri));
}
///////////////////////////////////////////////////////////////////////////////////////////////
//OpcUa_String* aString=pAppDescription->GetApplicationUri();
//OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS,"Server listening at %s.\r\n", OpcUa_String_GetRawString(aString));
// démarrage de la thread de surveillance des timeout de l'ensemble des sessions
g_pTheApplication->StartSessionsTimeoutThread();
}
else
{
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Failed);
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_LEVEL_ALWAYS, "Critical error. OpenOpcUaServer cannot start.\r\n");
}
}
// show the summary of nodes
g_pTheApplication->m_pTheAddressSpace->TraceAddressSpace();
// Let's start/unlock the EventsEngine thread if needed
if (pEventsEngine)
{
if (pEventsEngine->GetEventDefinitionListSize() > 0)
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Will start the EventEngine...\n");
OpcUa_Semaphore_Post(pEventsEngine->m_EventsThreadSem, 1);
}
}
// Let's start/unlock the simulation thread if needed
pInformationModel->UnlockSimulationGroups();
// Let's start/unlock the HA Engine in case it's require
if (pHaEngine)
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Will start the HA engine...\n");
OpcUa_Semaphore_Post(pHaEngine->m_StorageThreadSem, 1);
}
// Set the state of the server after its initialization
if (g_pTheApplication->GetVpiDeviceList()->size() == 0)
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Test);
//else
//{
// CServerStatus* pServerStatus = pInformationModel->GetInternalServerStatus();
// //if ((pServerStatus->GetServerState() != OpcUa_ServerState_CommunicationFault) && (pServerStatus->GetServerState() != OpcUa_ServerState_Failed) )
// // pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Running);
//}
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS, "Press Q or q to exit.\r\n");
getQChar();
// stop the server.
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Shutdown);
// We have to enter the full stop process mecanism
ShutdownServer(15, (OpcUa_CharA*)"Server shutdown by operator");
// Will now play an basic animation and update the value of SecondsTillShutdown
StopAnimation(15);
}
else
{
// Let's unlock the simulation threadOpcUa_Semaphore_Post(pInformationModel->GetSimulationEvent(), 1);
pInformationModel->UnlockSimulationGroups();
OpcUa_String certificateStore = g_pTheApplication->GetCertificateStorePath();
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS, "Cleanup your certificate Store \n in: .\\%s \n and restart the server\n", OpcUa_String_GetRawString(&certificateStore));
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS, "Press Q or q to exit.\r\n");
getQChar();
// stop the server.
// We have to enter the full stop process mecanism
if (uStatus != OpcUa_BadCertificateInvalid)
ShutdownServer(10, (OpcUa_CharA*)"Server shutdown Configuration error");
// Will now play an basic animation and update the value of SecondsTillShutdown
StopAnimation(10);
}
}
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error> Server certificate is not correct\n");
OpcUa_String_Clear(&aCertificateStore);
}
}
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error> Error in SubSystem Files\n");
}
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error> Error in Simulation Files\n");
}
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error> when loading UANodeSet: 0x%05x\n",uStatus);
}
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error> Information in server Configuration file are not consistant\n");
}
else
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error> Cannot load ServerConfiguration file. Probably a parsing error: 0x%05x\n", uStatus);
for (OpcUa_Int32 ii = 0; ii < 100; ii++)
{
if ((ii % 10) == 0)
printf(".");
OpcUa_Thread_Sleep(100);
}
printf("\n");
}
if (g_pTheApplication)
{
g_pTheApplication->RemoveAllVpiDevice();
g_pTheApplication->StopHaEngine();
}
// Cleanup the InvertingThread. Here this thread is suppose to be finish a long time ago
if (hInvertingReferenceThread)
OpcUa_Thread_Delete(hInvertingReferenceThread);
//
if (CServerApplication::m_pTheAddressSpace)
{
delete CServerApplication::m_pTheAddressSpace;
CServerApplication::m_pTheAddressSpace = OpcUa_Null;
}
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "OpenOpcUaCoreServer is stopped.\n");
if (g_pTheApplication)
{
delete g_pTheApplication;
g_pTheApplication = OpcUa_Null;
}
///////////////////////////////////////////////////
//
// Sempahore to remotly stop the server
OpcUa_Semaphore_Delete(&g_ShutdownServerSem);
}
else
uStatus = OpcUa_BadInvalidArgument;
printf("OpenOpcUaCoreServer RunAsApplication terminated 0x%05x.\n",uStatus);
return uStatus;
}
OpcUa_StatusCode RunAsWindowsService(STARTUP_COMMAND eCommand) // char* szCommand, char* path, char* fileName)
{
OpcUa_StatusCode uStatus=OpcUa_Good;
#if !defined(WIN32_WCE)
#if defined(WIN32) || defined(WIN64)
OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
HRESULT hr = S_OK;
OpcUa_CharA* path = g_pTheApplication->GetConfigPath();
OpcUa_CharA* fileName = g_pTheApplication->GetConfigFileName();
OpcUa_CharA* serviceName=OpcUa_Null;
if (eCommand==STARTUP_COMMAND::INSTALL_SERVICE)
{
hr = g_pTheApplication->m_ServiceModule.InstallService(path, fileName);
if (hr == S_OK)
uStatus = OpcUa_Good;
else
uStatus = OpcUa_BadInternalError;
hr = S_FALSE; // force to false in order to stop the server startup
}
else
{
if (eCommand == STARTUP_COMMAND::UNINSTALL_SERVICE)
{
hr = g_pTheApplication->m_ServiceModule.UninstallService();
if (hr == S_OK)
{
uStatus = OpcUa_Good;
hr = S_FALSE; // Force to false in order to stop the server startup
}
else
uStatus = OpcUa_BadInternalError;
}
}
if (eCommand == STARTUP_COMMAND::RUN_SERVER)
{
uStatus = OpcUa_BadInvalidArgument;
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_ERROR, "RunAsWindowsService>You cannot run the server as an application when it was installed as a service.\n");
}
else
{
if (eCommand == STARTUP_COMMAND::RUN_SERVICE)
{
HKEY hk;
char szSubKey[256];
ZeroMemory(szSubKey, 256);
strcpy(&szSubKey[0], "AppID\\{CB85A975-BAD5-4A1E-A142-FF98330EB221}");
if (RegOpenKey(HKEY_CLASSES_ROOT,
szSubKey, &hk) != ERROR_SUCCESS)
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>cannot open the registry key.\n");
}
else
RegCloseKey(hk);
CServerApplication::m_pTheAddressSpace = new CUAInformationModel();
// Extract configuration parameter from the registry
g_pTheApplication->m_ServiceModule.ExtractConfigurationParams(&path, &fileName, &serviceName);
///////////////////////////////////////////////////////////////
//
//
///////////////////////////////////////////////////
//
// Sempahore to remotly stop the server
OpcUa_Semaphore_Create(&g_ShutdownServerSem, 0, 0x100);
// Parsing du fichier de configuration du serveur
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Loading %s %s\n", path, fileName);
uStatus = g_pTheApplication->LoadUaServerConfiguration(path, fileName);
if (uStatus == OpcUa_Good)
{
// Fin chargement du fichier de configuration
// Mise en place de L'application Description et des informations sur les ports d'écoute
CApplicationDescription* pApplicationDescription = g_pTheApplication->GetApplicationDescription();
uStatus = SetServerDescriptionTransportPortListener(&pApplicationDescription);
if (uStatus == OpcUa_Good)
{
g_pTheApplication->SetApplicationDescription(pApplicationDescription);
//////////////////////////////////////////
//
// Definition du niveau de trace
//
//////////////////////////////////////////
// OPCUA_TRACE_OUTPUT_LEVEL_DEBUG
// OPCUA_TRACE_OUTPUT_LEVEL_INFO
// OPCUA_TRACE_OUTPUT_LEVEL_WARNING
// OPCUA_TRACE_OUTPUT_LEVEL_NONE
// OPCUA_TRACE_OUTPUT_LEVEL_SYSTEM
// OPCUA_TRACE_OUTPUT_LEVEL_ERROR
OpcUa_UInt32 uiTraceLevel = g_pTheApplication->GetTraceLevel();
OpcUa_Trace_ChangeTraceLevel(pTraceConfiguration, uiTraceLevel);
OpcUa_UInt32 iOutput = g_pTheApplication->GetTraceOutput();
if (iOutput == OPCUA_TRACE_OUTPUT_FILE)
{
// Mise en place du nom du fichier de sortie
OpcUa_String szLogFolder;
OpcUa_String_Initialize(&szLogFolder);
OpcUa_String strFileName;
OpcUa_String_Initialize(&strFileName);
OpcUa_String strBakFileName;
OpcUa_String_Initialize(&strBakFileName);
// extension du fichier
OpcUa_String strExtension;
OpcUa_String_Initialize(&strExtension);
OpcUa_String_AttachCopy(&strExtension, ".log");
#if defined(WIN32) || defined(WIN64)
OpcUa_String_AttachCopy(&szLogFolder, "Logs\\");
#endif
#ifdef _GNUC_
OpcUa_String_AttachCopy(&szLogFolder, "Logs/");
#endif
// extension de la sauvegarde
OpcUa_String strBakExtension;
OpcUa_String_Initialize(&strBakExtension);
OpcUa_String_AttachCopy(&strBakExtension, ".bak");
// create the output filename base on the name of the server EndPoint
pApplicationDescription = g_pTheApplication->GetApplicationDescription();
if (pApplicationDescription)
{
// Get the first ServerName
OpcUa_LocalizedText aLocalizedText = pApplicationDescription->GetApplicationName();
// Project folder name
OpcUa_String szLogFolderName = g_pTheApplication->GetLogFolder();
if (OpcUa_String_StrLen(&szLogFolderName) > 0)
{
OpcUa_String_CopyTo(&(szLogFolderName), &strFileName);
OpcUa_String_CopyTo(&(szLogFolderName), &strBakFileName);
// Check that the last caracter of the ProjectFolderName is a \ or not
OpcUa_CharA* pszLogFolder = OpcUa_String_GetRawString(&szLogFolderName);
OpcUa_UInt32 iLen = OpcUa_String_StrLen(&szLogFolderName);
if (pszLogFolder[iLen - 1] != '\\')
{
OpcUa_String sep;
OpcUa_String_Initialize(&sep);
OpcUa_String_AttachCopy(&sep, "\\");
OpcUa_String_StrnCat(&strFileName, &sep, OpcUa_String_StrLen(&sep));
OpcUa_String_StrnCat(&strBakFileName, &sep, OpcUa_String_StrLen(&sep));
OpcUa_String_Clear(&sep);
}
// Add Log folder
// Add the filename extracted from the ServerName
OpcUa_String_StrnCat(&strFileName, &aLocalizedText.Text, OpcUa_String_StrLen(&aLocalizedText.Text));
OpcUa_String_StrnCat(&strBakFileName, &aLocalizedText.Text, OpcUa_String_StrLen(&aLocalizedText.Text));
}
else
{
OpcUa_String_CopyTo(&(aLocalizedText.Text), &strFileName);
OpcUa_String_CopyTo(&(aLocalizedText.Text), &strBakFileName);
}
// creation du nom du fichier de log
OpcUa_String_StrnCat(&strFileName, &strExtension, OpcUa_String_StrLen(&strExtension));
// creation du nom du fichier de sauvegarde
OpcUa_String_StrnCat(&strBakFileName, &strBakExtension, OpcUa_String_StrLen(&strBakExtension));
OpcUa_Trace_SetTraceFile(pTraceConfiguration, strFileName);
// On sauvegarde une eventuelle trace existante
FILE* hFile = OpcUa_Null;
hFile = fopen(OpcUa_String_GetRawString(&strFileName), "r");
if (hFile)
{
// Ouverture du fichier de sauvegarde
FILE* hFileBak = OpcUa_Null;
OpcUa_CharA* szBakFileName = OpcUa_String_GetRawString(&strBakFileName);
hFileBak = fopen(szBakFileName, "w");
char bakBuffer;
// On lit l'ensemble du fichier dans le buffer
// On copie dans la sauvegarde
while (fread(&bakBuffer, sizeof(char), 1, hFile) == 1)
fwrite(&bakBuffer, sizeof(char), 1, hFileBak);
// On ferme l'ancien fichier
fclose(hFile);
fflush(hFileBak);
if (fclose(hFileBak) == EOF)
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Cannot close the bak log file\n");
// On supprime l'ancien fichier
hFile = fopen(OpcUa_String_GetRawString(&strFileName), "w");
if (hFile)
fclose(hFile);
}
}
OpcUa_String_Clear(&strExtension);
OpcUa_String_Clear(&strFileName);
OpcUa_String_Clear(&strBakExtension);
OpcUa_String_Clear(&strBakFileName);
OpcUa_String_Clear(&szLogFolder);
}
// Chargement des fichiers NodeSet qui constitueront l'espace d'adressage
uStatus = LoadNodeSetFiles();
if (uStatus == OpcUa_Good)
{
uStatus = LoadSimulationFiles();
if (uStatus == OpcUa_Good)
{
// Chargement de la configuration des subsystems
uStatus = LoadSubSystemFiles();
if (uStatus == OpcUa_Good)
{
CEventsEngine* pEventsEngine = g_pTheApplication->GetEventsEngine();
pEventsEngine = new CEventsEngine(pTraceConfiguration);
if (pEventsEngine)
g_pTheApplication->SetEventsEngine(pEventsEngine);
/////////////////////////////////////////////////////////
// PostProcessing
//
uStatus = PostProcessing();
if (uStatus != OpcUa_Good)
{
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Failed);
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>Post Processing failed 0x%05x\n", uStatus);
}
else
{
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
// Déblocage de la thread de mise à jour des MandatoryNodes
OpcUa_Semaphore_Post(pInformationModel->m_UpdateMandatoryNodesThreadSem, 1);
// démarrage du mecanisme de dialogue avec les sous-systèmes
//g_pTheApplication->WakeupAllVpi();
// Si besoin demarrage du moteur d'archivage
CHaEngine* pHaEngine = g_pTheApplication->GetHaEngine();
if (pHaEngine)
{
if (pHaEngine->LoadVfi() == OpcUa_Good)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>Your Vfi was correctly loaded\n");
pHaEngine->InitHaEngine(); // Call GlobalStart
OpcUa_Vfi_Handle hVfiHandle = OpcUa_Null;
OpcUa_String szArchiveId = g_pTheApplication->GetArchiveId();
OpcUa_NodeId aNodeId;
OpcUa_NodeId_Initialize(&aNodeId);
if (ParseNodeId(OpcUa_String_GetRawString(&szArchiveId), &aNodeId) == OpcUa_Good)
{
// Warning the Vfi is suppose to copy the aNodeId
uStatus = pHaEngine->VfiGlobalStart(g_pTheApplication->GetArchiveName(),
aNodeId,
&hVfiHandle);
if (uStatus == OpcUa_Good)
{
pHaEngine->SetVfiHandle(hVfiHandle);
uStatus = pHaEngine->VfiColdStart(hVfiHandle);
if (uStatus != OpcUa_Good)
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>VfiColdStart failed 0x%05x\n", uStatus);
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>VfiGlobalStart failed 0x%05x\n", uStatus);
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>ParseNodeId failed when preparing the call to VfiGlobalStart\n");
OpcUa_NodeId_Clear(&aNodeId);
}
else
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Failed);
}
// initialize security by specifying the client certificate and the location of the trusted certificates.
OpcUa_String szProjectFolder = g_pTheApplication->GetProjectFolder();
OpcUa_CharA* pszCertificateStore = (OpcUa_CharA*)OpcUa_Alloc(512);
ZeroMemory(pszCertificateStore, 512);
sprintf(pszCertificateStore, "%s\\CertificateStore", OpcUa_String_GetRawString(&szProjectFolder));
OpcUa_String aCertificateStore;
OpcUa_String_Initialize(&aCertificateStore);
OpcUa_String_AttachCopy(&aCertificateStore, pszCertificateStore);
g_pTheApplication->SetCertificateStorePath(aCertificateStore);
OpcUa_Free(pszCertificateStore);
uStatus = g_pTheApplication->LoadPFXCertificate();
if (uStatus == OpcUa_Good)
{
// on va tenter de lire le fichier DER afin de vérifier qu'il s'agit du bon DER
// a savoir :
// 1- il existe
// 2- sa clé correpsond acelle du pfx
uStatus = g_pTheApplication->LoadDERCertificate();
if (uStatus != OpcUa_Good)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>Your certificate in DER file not fit the private key. Will create a new one\n");
uStatus = g_pTheApplication->CreateCertificate();
}
}
else
uStatus = g_pTheApplication->CreateCertificate();
// on va vérifier que le certificat du serveur est encore valide
OpcUa_CharA* sThumbprint = OpcUa_Null;
OpcUa_CharA* lApplicationUri = OpcUa_Null;
OpcUa_CharA* psCommonName = OpcUa_Null;
OpcUa_ByteString* pServerCertificate = g_pTheApplication->GetCertificate();
if (pServerCertificate)
{
uStatus = OpcUa_Certificate_GetInfo(
(OpcUa_ByteString*)pServerCertificate,
OpcUa_Null,
OpcUa_Null,
&psCommonName,
&sThumbprint,
&lApplicationUri,
OpcUa_Null,
OpcUa_Null);
OpcUa_DateTime ValidFrom, ValidTo;
OpcUa_DateTime_Initialize(&ValidFrom);
OpcUa_DateTime_Initialize(&ValidTo);
uStatus = OpcUa_Certificate_GetDateBound(
(OpcUa_ByteString*)pServerCertificate,
&ValidFrom, &ValidTo);
if (uStatus == OpcUa_Good)
{
// Verification de la validitée du certificat;
OpcUa_String* strFrom = OpcUa_Null;// (OpcUa_String*)OpcUa_Alloc(sizeof(OpcUa_String));
OpcUa_String* strTo = OpcUa_Null; // (OpcUa_String*)OpcUa_Alloc(sizeof(OpcUa_String));
Utils::OpcUaDateTimeToString(ValidFrom, &strFrom);
Utils::OpcUaDateTimeToString(ValidTo, &strTo);
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>Your certificate validate your server \nfrom: %s \nto: %s\n",
OpcUa_String_GetRawString(strFrom),
OpcUa_String_GetRawString(strTo));
if (strTo)
{
OpcUa_String_Clear(strTo);
OpcUa_Free(strTo);
}
if (strFrom)
{
OpcUa_String_Clear(strFrom);
OpcUa_Free(strFrom);
}
// Est ce que la date de fin est dépassée
OpcUa_DateTime utcNow = OpcUa_DateTime_UtcNow();
OpcUa_UInt32 uDiff = 0;
uStatus = OpcUa_P_GetDateTimeDiffInSeconds32(utcNow, ValidTo, &uDiff);
if ((uStatus != OpcUa_BadOutOfRange) && (uStatus != OpcUa_BadInvalidArgument))
{
// Il n'est peut etre pas encore valide
uStatus = OpcUa_P_GetDateTimeDiffInSeconds32(ValidFrom, utcNow, &uDiff);
if ((uStatus != OpcUa_BadOutOfRange) && (uStatus != OpcUa_BadInvalidArgument))
{
// Il est peut être mal formé
uStatus = OpcUa_P_GetDateTimeDiffInSeconds32(ValidFrom, ValidTo, &uDiff);
if ((uStatus == OpcUa_BadOutOfRange) || (uStatus == OpcUa_BadInvalidArgument))
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_LEVEL_ALWAYS, "RunAsWindowsService>Your certificate is corrupted. Server is stopping\n");
ShutdownServer(5, (OpcUa_CharA*)"Server shutdown: Your certificate is corrupted");
uStatus = OpcUa_BadCertificateInvalid;
}
}
else
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_LEVEL_ALWAYS, "RunAsWindowsService>Your certificate is not yet valid. Server is stopping\n");
ShutdownServer(5, (OpcUa_CharA*)"Server shutdown: Your certificate is not yet valid.");
uStatus = OpcUa_BadCertificateInvalid;
}
}
else
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_LEVEL_ALWAYS, "Your certificate is expired. Server is stopping\n");
ShutdownServer(5, (OpcUa_CharA*)"Server shutdown: Your certificate is expired.");
uStatus = OpcUa_BadCertificateInvalid;
}
}
if (uStatus == OpcUa_Good)
{
uStatus = g_pTheApplication->InitializeSecurity();
if (uStatus != OpcUa_Good)
{
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Failed);
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>InitializeSecurity failed StatusCode=0x%05x\n", uStatus);
}
else
{
// make sure the discovery server knows about the server.
// note: it may take time for the discovery server to recognize a new certificate.
//g_pTheApplication->AddServerToDiscoveryServerTrustList(OpcUa_False);
// start the server.
g_pTheApplication->StartLDSRegistrationThread();
CApplicationDescription* pAppDescription = g_pTheApplication->GetApplicationDescription(); // pApplicationDescriptionList->at(ii);
if (pAppDescription)
{
/////////////////////////////////////////////////////////////////////////////////////////////
OpcUa_String* pListener = (OpcUa_String*)OpcUa_Alloc(sizeof(OpcUa_String));
OpcUa_String_Initialize(pListener);
if (pAppDescription->GetDiscoveryUrls())
{
OpcUa_String* pUrl = pAppDescription->GetDiscoveryUrls();
if (pUrl)
OpcUa_String_CopyTo(pUrl, pListener);
OpcUa_LocalizedText aAppName = pAppDescription->GetApplicationName();
OpcUa_String_StrnCat(pListener, &(aAppName.Text), OpcUa_String_StrLen(&(aAppName.Text)));
}
else
{
OpcUa_String* pUri = pAppDescription->GetApplicationUri();
if (pUri)
OpcUa_String_CopyTo(pUri, pListener);
}
if (pListener)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_LEVEL_ALWAYS, "Server listening at :\n\t%s.\r\n", OpcUa_String_GetRawString(pListener));
OpcUa_String_Clear(pListener);
OpcUa_Free(pListener);
}
///////////////////////////////////////////////////////////////////////////////////////////////
//OpcUa_String* aString=pAppDescription->GetApplicationUri();
//OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS,"Server listening at %s.\r\n", OpcUa_String_GetRawString(aString));
// démarrage de la thread de surveillance des timeout de l'ensemble des sessions
g_pTheApplication->StartSessionsTimeoutThread();
}
else
{
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Failed);
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_LEVEL_ALWAYS, "RunAsWindowsService>Critical error. OpenOpcUaServer cannot start.\r\n");
}
}
g_pTheApplication->m_pTheAddressSpace->TraceAddressSpace();
// Let's start/unlock the EventsEngine thread if needed
if (pEventsEngine)
{
if (pEventsEngine->GetEventDefinitionListSize() > 0)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>Will start the EventEngine...\n");
OpcUa_Semaphore_Post(pEventsEngine->m_EventsThreadSem, 1);
}
}
// Let's start/unlock the simulation thread if needed
pInformationModel->UnlockSimulationGroups();
// Let's start/unlock the HA Engine in case it's require
if (pHaEngine)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>Will start the HA engine...\n");
OpcUa_Semaphore_Post(pHaEngine->m_StorageThreadSem, 1);
}
g_bRun = OpcUa_True;
// Set the state of the server after its initialization
if (g_pTheApplication->GetVpiDeviceList()->size()==0)
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Test);
else
{
CServerStatus* pServerStatus = pInformationModel->GetInternalServerStatus();
//if (pServerStatus->GetServerState()!=OpcUa_ServerState_CommunicationFault)
// pInformationModel->ChangeServerStatusState(OpcUa_ServerState_Running);
}
g_pTheApplication->m_ServiceModule.Start();
g_bRun = OpcUa_False;
// When we get here, the service has been stopped
//
// stop the server.
// We have to enter the full stop process mecanism
ShutdownServer(15, (OpcUa_CharA*)"Server shutdown by operator");
// Will now play an basic animation and update the value of SecondsTillShutdown
StopAnimation(15);
}
else
{
// Let's unlock the simulation thread
pInformationModel->UnlockSimulationGroups();
OpcUa_String certificateStore = g_pTheApplication->GetCertificateStorePath();
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_LEVEL_ALWAYS, "RunAsWindowsService>Cleanup your certificate Store \n in: .\\%s \n and restart the server\n", OpcUa_String_GetRawString(&certificateStore));
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_LEVEL_ALWAYS, "RunAsWindowsService>Press Q or q to exit.\r\n");
getQChar();
// stop the server.
// We have to enter the full stop process mecanism
if (uStatus != OpcUa_BadCertificateInvalid)
ShutdownServer(10, (OpcUa_CharA*)"Server shutdown Configuration error");
// Will now play an basic animation and update the value of SecondsTillShutdown
StopAnimation(10);
}
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService:Critical error> Server certificate is not correct\n");
OpcUa_String_Clear(&aCertificateStore);
}
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService:Critical error> Error in SubSystem Files\n");
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService:Critical error> Error in Simulation Files\n");
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService:Critical error> Error in fileNodeSet\n");
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService:Critical error> Information in server Configuration file are not consistant\n");
}
else
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService:Critical error> Cannot load ServerConfiguration file. Probably a parsing error\n");
for (OpcUa_Int32 ii = 0; ii < 100; ii++)
{
if ((ii % 10) == 0)
printf(".");
OpcUa_Thread_Sleep(100);
}
printf("\n");
}
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>Remove Vpis.\n");
if (g_pTheApplication)
{
g_pTheApplication->RemoveAllVpiDevice();
g_pTheApplication->StopHaEngine();
}
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>Clean up some server resources.\n");
// Cleanup the InvertingThread. Here this thread is suppose to be finish a long time ago
if (hInvertingReferenceThread)
OpcUa_Thread_Delete(hInvertingReferenceThread);
//
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>Will try to delete AddressSpace.\n");
if (CServerApplication::m_pTheAddressSpace)
{
delete CServerApplication::m_pTheAddressSpace;
CServerApplication::m_pTheAddressSpace = OpcUa_Null;
}
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>AddressSpace deleted.\n");
if (fileName)
OpcUa_Free(fileName);
if (path)
OpcUa_Free(path);
if (g_pTheApplication)
{
#if defined(WIN32) || defined(WIN64)
SERVICE_STATUS uServiceStatus = g_pTheApplication->m_ServiceModule.GetServiceStatus();
uStatus = uServiceStatus.dwWin32ExitCode;
#endif
delete g_pTheApplication;
g_pTheApplication = OpcUa_Null;
}
OpcUa_Trace(OpcUa_Null, OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>File ressource deleted.\n");
///////////////////////////////////////////////////
//
// Sempahore to remotly stop the server
OpcUa_Semaphore_Delete(&g_ShutdownServerSem);
//OpcUa_Trace(OpcUa_Null,OPCUA_TRACE_SERVER_LEVEL_ERROR, "RunAsWindowsService>OpenOpcUaCore server is stopped.\n");//pTraceConfiguration
}
}
#endif
#endif
return uStatus;
}
// This application needs to have the uastack and OpenSSL DLLs in its path to run.
//
// Open the Project Properties | Debugging page
// Add this string to the Environment setting:
//
// PATH=%PATH%;
//
// Le fichier de configuration sera passé en ligne de commande
//
//
#if defined(WIN32_WCE)
int main(int argc, char* argv[])
{
#endif
#if !defined(WIN32_WCE)
#if defined(WIN32) || defined(WIN64)
int _tmain(int argc, _TCHAR* argv[])
{
//#if defined(WIN32) || !defined(WIN32_WCE)
// #ifdef _DEBUG
// _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
// #endif
//#endif
#endif
#endif
#ifdef _GNUC_
int main(int argc, char* argv[])
{
#endif
OpcUa_ReferenceParameter(argc);
OpcUa_ReferenceParameter(argv);
OpcUa_String aString;
OpcUa_String_Initialize(&aString);
try
{
//////////////////////////////////////////////////////////
//
// initialize the application and the stack.
g_pTheApplication = new CServerApplication();
if (g_pTheApplication)
g_pTheApplication->Initialize();
//OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
STARTUP_COMMAND eCommand = COMMAND_UNKNOWN;
switch (argc)
{
case 1: // no parameter is an incorrect call
printf("The server cannot start. Please use the correct syntax\n");
printf("The syntax is : OpenOpcUaCoreServer_[VERSION] <fullpath\\configfile.oouaprj>\n");
break;
case 2: // One parameter is the correct syntax to start the server for both as app or as a service
// Parse the file parameter or Service name if started as a service
g_pTheApplication->ParseFirstParameter(argv[1],&eCommand);
if (eCommand == COMMAND_UNKNOWN)
{
printf("The server cannot start. Please use the correct syntax\n");
printf("The syntax is : OpenOpcUaCoreServer_[VERSION] <fullpath\\configfile.oouaprj>\n");
}
#if defined(WIN32) || defined(WIN64)
else
{
if (eCommand == RUN_SERVICE)
{
// Extract the serviceName from the registry
OpcUa_CharA* path = OpcUa_Null;
OpcUa_CharA* fileName = OpcUa_Null;
OpcUa_CharA* serviceName = OpcUa_Null;
g_pTheApplication->m_ServiceModule.ExtractConfigurationParams(&path, &fileName, &serviceName);
g_pTheApplication->m_ServiceModule.SetServiceName(serviceName);
}
}
#endif
break;
case 3: // Two parameters is correct for server registration as a Windows service
#ifdef _GNUC_
printf("The server cannot start. Please use the correct syntax\n");
printf("The syntax is : OpenOpcUaCoreServer_[VERSION] <fullpath\\configfile.oouaprj>\n");
#endif
#if defined(WIN32) || defined(WIN64)
// Parse the file parameter
g_pTheApplication->ParseFirstParameter(argv[1], &eCommand);
// Parse the service registration/unregistration info
g_pTheApplication->ParseSecondParameter(argv[2],&eCommand);
#endif
break;
default:
printf("The server cannot start. Please use the correct syntax\n");
printf("The syntax is : OpenOpcUaCoreServer_[VERSION] <fullpath\\configfile.oouaprj>\n");
break;
}
#if !defined(WIN32_WCE)
#if defined(WIN32) || defined(WIN64)
if (!g_pTheApplication->m_ServiceModule.IsInstalled())
{
{
if (eCommand == STARTUP_COMMAND::INSTALL_SERVICE)
{
RunAsWindowsService(eCommand);
}
else
{
if (eCommand == STARTUP_COMMAND::RUN_SERVER)
RunAsApplication(eCommand);
else
{
if (eCommand == STARTUP_COMMAND::UNINSTALL_SERVICE)
{
// This one in case of a corrupted situation
RunAsWindowsService(eCommand);
}
else
{
printf("The server cannot start. Please use the correct syntax\n");
printf("The syntax is : OpenOpcUaCoreServer_[VERSION] <fullpath\\configfile.oouaprj>\n");
}
}
}
}
}
else
{
// If the server is installed as a service. and no parameter was on the command line let's start as a service
if ((g_pTheApplication->m_ServiceModule.IsInstalled()) && (g_pTheApplication->m_ServiceModule.IsService()))
RunAsWindowsService(eCommand);
else
RunAsApplication(eCommand);
}
#endif
#endif
#if defined(_GNUC_) || defined(WIN32_WCE)
if (eCommand == RUN_SERVER)
RunAsApplication(eCommand);
else
{
printf("The server cannot start. Please use the correct syntax\n");
printf("The syntax is : OpenOpcUaCoreServer_[VERSION] <fullpath\\configfile.oouaprj>\n");
}
#endif
}
catch (CStatusCodeException* e)
{
OpcUa_ProxyStubConfiguration* pTraceConfiguration = OpcUa_Null;
if (g_pTheApplication)
pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
if (e)
{
OpcUa_String aString=e->GetMessage();
OpcUa_CharA* pMessage=OpcUa_String_GetRawString(&aString);
if (pMessage)
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR,"ERROR [0x%08X]: %s\r\n", e->GetCode(), *pMessage);
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR,"ERROR [0x%08X]: \r\n", e->GetCode());
}
else
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR,"Critical error> in Main.cpp\n");
return 0;
}
catch (std::exception e)
{
OpcUa_ProxyStubConfiguration* pTraceConfiguration = OpcUa_Null;
if (g_pTheApplication)
pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR,"ERROR> %s\n",e.what());
return 0;
}
return 0;
}
#ifdef _GNUC_
// strips off all characters entered on a line except for the first one.
int _kbhit(void)
{
struct termios oldt, newt;
int ch; int oldf;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
if (ch != EOF)
{
ungetc(ch, stdin);
return 1;
}
return 0;
}
#endif
// strips off all characters entered on a line except for the first one.
int getQChar()
{
int Choice=0;
g_bRun = OpcUa_True;
while (g_bRun)
{
if (_kbhit())
{
#ifdef _GNUC_
Choice = getchar();
#endif
#if !defined(WIN32_WCE)
#if defined(WIN32) || defined(WIN64)
Choice = _getch();
#endif
#endif
#if defined(WIN32_WCE)
Choice =getchar(); //_getch();
#endif
switch (Choice)
{
case 0x51:
case 0x71:
g_bRun = OpcUa_False;
break;
default:
break;
}
}
OpcUa_Semaphore_TimedWait(g_ShutdownServerSem, 1);
}
return Choice;
}
OpcUa_StatusCode AddLoggerMessage(wchar_t* szMessage, DWORD dwLevel)
{
OpcUa_StatusCode hr = OpcUa_Good;
OpcUa_ReferenceParameter(dwLevel);
OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR,"%ls\n",szMessage);
return hr;
}
/// <summary>
/// Finds the type definition for the aNodeId passed in.
/// </summary>
/// <param name="aNodeId">A node identifier.</param>
/// <param name="pDefinition">The p definition.</param>
/// <returns>OpcUa_StatusCode OpcUa_Good if CDefintion properly found</returns>
OpcUa_StatusCode FindTypeDefinition(OpcUa_NodeId aNodeId, CDefinition** pDefinition)
{
OpcUa_StatusCode uStatus = OpcUa_Good;
CUADataType* pUADataType=NULL;
CUAInformationModel* pInformationModel=CServerApplication::m_pTheAddressSpace;
uStatus = pInformationModel->GetNodeIdFromDataTypeList(aNodeId, &pUADataType);
if (uStatus==OpcUa_Good)
*pDefinition=pUADataType->GetDefinition();
return uStatus;
}
// Function name : CUAInformationModel::FindBuiltinType
// Description : This function is Looking for the builtin type for a type specify in a NodeId
// Return type : OpcUa_StatusCode OpcUa_Good if the function succeed, OpcUa_BadNotFound is not
// Argument : OpcUa_NodeId aNodeId = DataType declare in the NodeId
// Argument : OpcUa_Byte* pBuiltInType [out] related BuiltInType
OpcUa_StatusCode FindBuiltinType(OpcUa_NodeId aNodeId, OpcUa_Byte* pBuiltInType)
{
OpcUa_StatusCode uStatus=OpcUa_Good;
CUADataType* pUADataType=NULL;
CUAInformationModel* pInformationModel=CServerApplication::m_pTheAddressSpace;
// Afin de prendre en compte la désorganisation du fichier Opc.Ua.NodeSet2.xml
// Je vais traiter quelques types particuliers manuellement
if ( (aNodeId.NamespaceIndex==0) && (aNodeId.Identifier.Numeric==0)) // Probablement une erreur dans le fichier XML. Je vais considérer que le type par défaut est BaseDataType ns=0;i=24
*pBuiltInType=24; //BaseDataType
else
{
if ( (aNodeId.NamespaceIndex==0) && (aNodeId.Identifier.Numeric==29)) //Enumeration
*pBuiltInType=6; // une enumeration sera traité comme un Int32
else
{
// 338 = BuildInfo, 862 = ServerStatusDataType, 296 = Argument, 859 = ServerDiagnosticsSummaryDataType, 874 = SubscriptionDiagnosticsDataType
// 871 = ServiceCounterDataType, 865 = SessionDiagnosticsDataType, 868 = SessionSecurityDiagnosticsDataType, 853 = RedundantServerDataType,
// 856 = SamplingIntervalDiagnosticsDataType, 877 = ModelChangeStructureDataType, 884 = Range, 887 = EUInformation, 897 = SemanticChangeStructureDataType
// 891 = Annotation, 11944 = NetworkGroupDataType, 12079 = AxisInformation, 8912 = TimeZoneDataType
// This default answer accelerate the look up and fix issues in the OPC FOundation Part 5 nodeset sequential declaration
if ((
(aNodeId.Identifier.Numeric == 338) ||
(aNodeId.Identifier.Numeric == 853) ||
(aNodeId.Identifier.Numeric == 856) ||
(aNodeId.Identifier.Numeric == 859) ||
(aNodeId.Identifier.Numeric == 865) ||
(aNodeId.Identifier.Numeric == 868) ||
(aNodeId.Identifier.Numeric == 871) ||
(aNodeId.Identifier.Numeric == 874) ||
(aNodeId.Identifier.Numeric == 877) ||
(aNodeId.Identifier.Numeric == 884) ||
(aNodeId.Identifier.Numeric == 887) ||
(aNodeId.Identifier.Numeric == 891) ||
(aNodeId.Identifier.Numeric == 897) ||
(aNodeId.Identifier.Numeric == 338) ||
(aNodeId.Identifier.Numeric == 862) ||
(aNodeId.Identifier.Numeric == 8912) ||
(aNodeId.Identifier.Numeric == 11944) ||
(aNodeId.Identifier.Numeric == 12079) ||
(aNodeId.Identifier.Numeric == 296) ) &&
(aNodeId.NamespaceIndex == 0) )
*pBuiltInType=22;
else
{
// 852 = ServerState, 851 = RedundancySupport, 12077 = AxisScaleEnumeration, 890 = ExceptionDeviationFormat,
if ((
(aNodeId.Identifier.Numeric == 851) ||
(aNodeId.Identifier.Numeric == 852) ||
(aNodeId.Identifier.Numeric == 890) ||
(aNodeId.Identifier.Numeric == 12077)) &&
(aNodeId.NamespaceIndex == 0) )
{
*pBuiltInType=29; // Enumeration
}
else
{
// check the consistency of param
// Si on recoit un builtInType on retourne directement ce type
if ((aNodeId.NamespaceIndex == 0) && (aNodeId.Identifier.Numeric <= 25) && (aNodeId.Identifier.Numeric > 0))
*pBuiltInType = (OpcUa_Byte)aNodeId.Identifier.Numeric; // cast to byte
else
{
uStatus = pInformationModel->GetNodeIdFromDataTypeList(aNodeId, &pUADataType);
if (uStatus == OpcUa_Good)
{
// on recupère la reference HasSubType
OpcUa_NodeId NodeIdHasSubType;
OpcUa_NodeId_Initialize(&NodeIdHasSubType);
NodeIdHasSubType.Identifier.Numeric = 45;
NodeIdHasSubType.NamespaceIndex = 0;
NodeIdHasSubType.IdentifierType = OpcUa_IdentifierType_Numeric;
//OpcUa_ReferenceNodeList* pRefNodeList= pUADataType->GetReferenceNodeList();
CUAReferenceList* pRefNodeList = pUADataType->GetReferenceNodeList();
for (OpcUa_UInt32 ii = 0; ii < pRefNodeList->size(); ii++)
{
//OpcUa_ReferenceNode* pRefNode=pRefNodeList->at(ii);
CUAReference* pRefNode = pRefNodeList->at(ii);
OpcUa_NodeId aRefNodeId = pRefNode->GetReferenceTypeId();
if (Utils::IsEqual(&aRefNodeId, &NodeIdHasSubType))
{
OpcUa_NodeId aTargetId = pRefNode->GetTargetId().NodeId;
uStatus = FindBuiltinType(aTargetId, pBuiltInType);
break;
}
}
}
else
uStatus = OpcUa_BadNotFound;
}
}
}
}
}
return uStatus;
}
// analyse un nodeid afin de déterminer s'il est syntaxiquement correct ou nom
//un node in correcte syntaxiquement est "ns=2;s="
// ns>3
OpcUa_StatusCode IsNodeIdValid(const OpcUa_NodeId aNodeId)
{
OpcUa_StatusCode uStatus=OpcUa_Good;
switch (aNodeId.IdentifierType)
{
case OpcUa_IdentifierType_Numeric:
break;
case OpcUa_IdentifierType_String:
//if (OpcUa_String_StrLen(&(aNodeId.Identifier.String))==0)
// uStatus=OpcUa_BadNodeIdInvalid;
break;
case OpcUa_IdentifierType_Guid:
break;
case OpcUa_IdentifierType_Opaque:
//if (aNodeId.Identifier.ByteString.Data==OpcUa_Null)
// uStatus=OpcUa_BadNodeIdInvalid;
break;
default:
uStatus=OpcUa_BadNodeIdInvalid;
break;
}
return uStatus;
}
/// <summary>
/// Parses the node identifier The parsed char* should be in for define by the specification ie: ns=1;i=256 or ns=1;s=myNode .
/// </summary>
/// <param name="atts">The input string to parse.</param>
/// <param name="pNodeId">The pNode identifier this outpout parameter should be allocated and release by the caller.</param>
/// <returns></returns>
OpcUa_StatusCode ParseNodeId(const char* atts,OpcUa_NodeId* pNodeId)
{
OpcUa_String szNodeId;
OpcUa_String_Initialize(&szNodeId);
OpcUa_StatusCode uStatus=OpcUa_Good;
if (atts)
{
OpcUa_String_AttachCopy(&szNodeId,atts);
OpcUa_UInt32 szNodeIdSize = OpcUa_String_StrLen(&szNodeId);
OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
//OpcUa_StatusCode uStatus=OpcUa_Bad;
OpcUa_UInt16 iNamespace;
OpcUa_UInt32 iNodeId;
if (!pNodeId)
uStatus = OpcUa_BadInvalidArgument;
else
{
//CUAInformationModel* pInformationModel=CServerApplication::m_pTheAddressSpace;
// Format isbg
// i = numeric
// s = string
// b = opaque
// g = guid
// On verifie la cohérence syntaxique de atts
int iRes=-1;
OpcUa_CharA* pszNodeId = OpcUa_String_GetRawString(&szNodeId);
OpcUa_CharA* pszPrefix = (OpcUa_CharA*)OpcUa_Alloc(4);
ZeroMemory(pszPrefix, 4);
OpcUa_MemCpy(pszPrefix, 3, &pszNodeId[0], 3);
if (OpcUa_StrCmpA(pszPrefix, "ns=")==0)
//std::string str(atts);
//std::string szprefix=str.substr(0,3);
//if (szprefix=="ns=")
{
OpcUa_CharA* pch = OpcUa_StrChrA(pszNodeId, ';');
if (pch)
//OpcUa_UInt32 iPos=str.find(";");
//if (iPos!=string::npos)
{
OpcUa_UInt32 iPos = (OpcUa_UInt32) (pch - pszNodeId);
switch (pszNodeId[iPos+1])
//switch (str.at(iPos+1))
{
case 105: // i
{
iRes = sscanf_s(atts, "ns=%hu;i=%u", &iNamespace, &iNodeId);
if (iRes == 2)
{
//// Recherche du namespace réel
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
// il faut recherche le CNamespaceUri ou m_indexReference==iNamespace
OpcUa_Int32 iIndexNS = -1; //
uStatus = pInformationModel->OnLoadNamespaceUriToAbsoluteNamespaceUri(iNamespace, &iIndexNS);
if (uStatus == OpcUa_Good)
{
CNamespaceUri* pNamespaceUri = pInformationModel->GetNamespaceUri(iIndexNS);
if (!pNamespaceUri)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error this namespace was not define. Check your NodeSet file\n");
uStatus = OpcUa_BadInternalError;
}
else
{
// affection des informations dans le nodeid qui sera renvoyé
pNodeId->IdentifierType = OpcUa_IdentifierType_Numeric;
pNodeId->NamespaceIndex = (OpcUa_UInt16)pNamespaceUri->GetAbsoluteIndex();
pNodeId->Identifier.Numeric = iNodeId;
}
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error. Cannot retrieve the Absolute namespace Uri Index. Relative was %u Check your NodeSet file. uStatus=0x%05x\n", iNamespace, uStatus);
}
else
uStatus = OpcUa_BadInvalidArgument;
}
break;
case 115: //s
{
OpcUa_CharA* strId = (OpcUa_CharA*)OpcUa_Alloc(256);
if (strId)
{
ZeroMemory(strId, 256);
int iRes115 = sscanf(atts, "ns=%hu;s=%s", &iNamespace, strId);
if (iRes115 == 2)
{
OpcUa_CharA* pszIdentifier = (OpcUa_CharA*)OpcUa_Alloc((szNodeIdSize - (iPos + 3))+1);
if (pszIdentifier)
{
ZeroMemory(pszIdentifier, (szNodeIdSize - (iPos + 3)) + 1);
OpcUa_MemCpy(pszIdentifier, szNodeIdSize - (iPos + 3), &pszNodeId[iPos + 3], szNodeIdSize - (iPos + 3));
//std::string szIdentifier = str.substr(iPos + 3, str.size() - (iPos + 3));
//// Recherche du namespace réel
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
// il faut recherche le CNamespaceUri ou m_indexReference==iNamespace
OpcUa_Int32 iIndexNS = -1;
uStatus = pInformationModel->OnLoadNamespaceUriToAbsoluteNamespaceUri(iNamespace, &iIndexNS);
if (uStatus == OpcUa_Good)
{
CNamespaceUri* pNamespaceUri = pInformationModel->GetNamespaceUri(iIndexNS);
if (!pNamespaceUri)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error this namespace was not define. Check your NodeSet file\n");
uStatus = OpcUa_BadInvalidArgument;
}
else
{
// affection des informations dans le nodeid qui sera renvoyé
pNodeId->IdentifierType = OpcUa_IdentifierType_String;
pNodeId->NamespaceIndex = (OpcUa_UInt16)pNamespaceUri->GetAbsoluteIndex();
OpcUa_String_AttachCopy(&(pNodeId->Identifier.String), (OpcUa_CharA*)pszIdentifier);
//OpcUa_String_AttachCopy(&(pNodeId->Identifier.String), (OpcUa_CharA*)szIdentifier.c_str());
}
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error. Cannot retrieve the Absolute namespace Uri Index. Check your NodeSet file\n");
}
else
uStatus = OpcUa_BadInternalError;
}
else
uStatus = OpcUa_BadInvalidArgument;
OpcUa_Free(strId);
}
}
break;
case 98: //b
{
OpcUa_CharA* bstrId = (OpcUa_CharA*)OpcUa_Alloc(1024);
if (bstrId)
{
ZeroMemory(bstrId, 1024);
iRes = sscanf(atts, "ns=%hu;b=%1023s",&iNamespace, bstrId);
if (iRes == 2)
{
//OpcUa_CharA* pszIdentifier = (OpcUa_CharA*)OpcUa_Alloc(szNodeIdSize - (iPos + 3));
//ZeroMemory(pszIdentifier, szNodeIdSize - (iPos + 3));
//OpcUa_MemCpy(pszIdentifier, szNodeIdSize - (iPos + 3), &pszNodeId[iPos + 3], szNodeIdSize - (iPos + 3));
//std::string szIdentifier = str.substr(iPos + 3, str.size() - (iPos + 3));
//// Recherche du namespace réel
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
// il faut recherche le CNamespaceUri ou m_indexReference==iNamespace
OpcUa_Int32 iIndexNS = -1;
uStatus = pInformationModel->OnLoadNamespaceUriToAbsoluteNamespaceUri(iNamespace, &iIndexNS);
if (uStatus == OpcUa_Good)
{
CNamespaceUri* pNamespaceUri = pInformationModel->GetNamespaceUri(iIndexNS);
if (!pNamespaceUri)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error this namespace was not define. Check your NodeSet file\n");
uStatus = OpcUa_BadInvalidArgument;
}
else
{
//pNodeId->Identifier.ByteString= (OpcUa_ByteString*)OpcUa_Alloc(sizeof(OpcUa_ByteString));
OpcUa_ByteString_Initialize(&pNodeId->Identifier.ByteString);
if (pNodeId->Identifier.Guid)
{
// affection des informations dans le nodeid qui sera renvoyé
pNodeId->IdentifierType = OpcUa_IdentifierType_Opaque;
pNodeId->NamespaceIndex = (OpcUa_UInt16)pNamespaceUri->GetAbsoluteIndex();
uStatus = OpcUa_Base64_Decode(bstrId, &pNodeId->Identifier.ByteString.Length, &pNodeId->Identifier.ByteString.Data);
}
}
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error. Cannot retrieve the Absolute namespace Uri Index. Check your NodeSet file\n");
}
else
uStatus = OpcUa_BadInvalidArgument;
OpcUa_Free(bstrId);
}
}
break;
case 103: //g
{
OpcUa_CharA* strId = (OpcUa_CharA*)OpcUa_Alloc(256);
if (strId)
{
ZeroMemory(strId, 256);
iRes = sscanf(atts, "ns=%hu;g=%255s", &iNamespace, strId);
if (iRes == 2)
{
//std::string szIdentifier = str.substr(iPos + 3, str.size() - (iPos + 3));
//// Recherche du namespace réel
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
// il faut recherche le CNamespaceUri ou m_indexReference==iNamespace
OpcUa_Int32 iIndexNS = -1;
uStatus = pInformationModel->OnLoadNamespaceUriToAbsoluteNamespaceUri(iNamespace, &iIndexNS);
if (uStatus == OpcUa_Good)
{
CNamespaceUri* pNamespaceUri = pInformationModel->GetNamespaceUri(iIndexNS);
if (!pNamespaceUri)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error this namespace was not define. Check your NodeSet file\n");
uStatus = OpcUa_BadInvalidArgument;
}
else
{
pNodeId->Identifier.Guid = (OpcUa_Guid*)OpcUa_Alloc(sizeof(OpcUa_Guid));
if (pNodeId->Identifier.Guid)
{// affection des informations dans le nodeid qui sera renvoyé
pNodeId->IdentifierType = OpcUa_IdentifierType_Guid;
pNodeId->NamespaceIndex = (OpcUa_UInt16)pNamespaceUri->GetAbsoluteIndex();
uStatus = OpcUa_Guid_FromString(strId, pNodeId->Identifier.Guid);
}
}
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error. Cannot retrieve the Absolute namespace Uri Index. Check your NodeSet file\n");
}
else
uStatus = OpcUa_BadInvalidArgument;
OpcUa_Free(strId);
}
}
break;
default:
uStatus=OpcUa_BadNotSupported;
break;
}
}
}
else
{
switch (pszNodeId[0])
//switch (str.at(0))
{
case 105: // i
iRes=sscanf_s(atts,"i=%u",&iNodeId);
if (iRes==1)
{
pNodeId->IdentifierType=OpcUa_IdentifierType_Numeric;
pNodeId->NamespaceIndex=0;
pNodeId->Identifier.Numeric=iNodeId;
}
else
uStatus=OpcUa_BadInvalidArgument;
break;
case 115: //s
uStatus=OpcUa_BadNotImplemented;
break;
case 98: //b
uStatus=OpcUa_BadNotImplemented;
break;
case 103: //g
uStatus=OpcUa_BadNotImplemented;
break;
default:
uStatus=OpcUa_BadInvalidArgument;
break;
}
}
// traitement des alias
if (uStatus !=OpcUa_Good)
{
CUAInformationModel* pInformationModel=CServerApplication::m_pTheAddressSpace;
CAliasList* pAliasList=pInformationModel->GetAliasList();
if (pAliasList)
{
for (OpcUa_UInt16 ii=0;ii<pAliasList->size();ii++)
{
CAlias* pAlias=pAliasList->at(ii);
OpcUa_String aString=pAlias->GetAliasName();
if (OpcUa_StrCmpA(atts,OpcUa_String_GetRawString(&aString))==0)
{
*pNodeId=pAlias->GetNodeId();
uStatus=OpcUa_Good;
break;
}
}
}
}
}
}
else
uStatus=OpcUa_BadInvalidArgument;
OpcUa_String_Clear(&szNodeId);
return uStatus;
}
///-------------------------------------------------------------------------------------------------
/// <summary> Creates node identifier. </summary>
///
/// <remarks> Michel, 23/09/2016. </remarks>
///
/// <param name="IdentifierType"> Type of the identifier. </param>
/// <param name="namespaceIndex"> Zero-based index of the namespace. </param>
/// <param name="pNodeId"> [in,out] If non-null, identifier for the node. </param>
///
/// <returns> The new node identifier. </returns>
///-------------------------------------------------------------------------------------------------
OpcUa_StatusCode CreateNodeId(OpcUa_UInt16 IdentifierType, OpcUa_UInt16 namespaceIndex, OpcUa_UInt32 InitialValue, OpcUa_NodeId* pNodeId)
{
OpcUa_StatusCode uStatus=OpcUa_Good;
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
if (pNodeId)
{
OpcUa_NodeId_Initialize(pNodeId);
pNodeId->IdentifierType = IdentifierType;
pNodeId->NamespaceIndex = namespaceIndex;
pNodeId->Identifier.Numeric = InitialValue;
CUABase* pUABase = OpcUa_Null;
while (pInformationModel->GetNodeIdFromDictionnary(*pNodeId, &pUABase) == OpcUa_Good)
{
pNodeId->Identifier.Numeric++;
}
}
else
uStatus = OpcUa_BadInvalidArgument;
return uStatus;
}
// Il s'agit de préparer le code d'etat en fonction de attente de la specification UA
// Ce OpcUa_StatusCode servira de base pour la selection du code a retourner lors des lectures
// Plus loin dans le code le resultat sera traité de cette manière
// if (uStatusPreChecked==OpcUa_BadIndexRangeInvalid)
// pResponse->Results[ii].StatusCode=uStatusPreChecked;
// else
// pResponse->Results[ii].StatusCode=OpcUa_Good;
OpcUa_StatusCode PreCheckedStatusCode(OpcUa_ReadValueId* pNodeToRead, CUABase* pUABase)
{
OpcUa_StatusCode uStatus=OpcUa_Good;
if (OpcUa_String_StrLen(&(pNodeToRead->IndexRange))>0)
{
uStatus = OpcUa_BadOutOfRange;
if ( (pNodeToRead->AttributeId == OpcUa_Attributes_Value)
&& ((pUABase->GetNodeClass()==OpcUa_NodeClass_Variable) || ( pUABase->GetNodeClass()==OpcUa_NodeClass_VariableType) )
&& ( ( ((CUAVariable*)pUABase)->GetBuiltInType()==OpcUaType_Variant) || ( ((CUAVariable*)pUABase)->GetBuiltInType()==OpcUaType_ByteString) || (((CUAVariable*)pUABase)->GetBuiltInType()==OpcUaType_String) ) )
uStatus=OpcUa_Good;
}
else
{
uStatus=OpcUa_BadAttributeIdInvalid;
}
return uStatus;
}
// Pour un nodeId donnée recherche le nodeId inverse associé
OpcUa_StatusCode FindConsistentInverseNodeId(OpcUa_NodeId aReferenceNodeId,OpcUa_NodeId* pConsistentInverseNodeId)
{
OpcUa_StatusCode uStatus=OpcUa_Good;
if (pConsistentInverseNodeId)
{
OpcUa_NodeId_Initialize(pConsistentInverseNodeId);
pConsistentInverseNodeId->IdentifierType=OpcUa_IdentifierType_Numeric;
if (aReferenceNodeId.IdentifierType==OpcUa_IdentifierType_Numeric)
{
if (aReferenceNodeId.Identifier.Numeric==45) // HasSubtype
pConsistentInverseNodeId->Identifier.Numeric=40; // HasTypeDefinition
if (aReferenceNodeId.Identifier.Numeric==40) // HasTypeDefinition
pConsistentInverseNodeId->Identifier.Numeric=45; // HasSubtype
}
}
else
uStatus=OpcUa_BadInvalidArgument;
return uStatus;
}
void InvertingReferenceThread(void* /*arg*/)
{
OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
CUAInformationModel* pInformationModel = CServerApplication::m_pTheAddressSpace;
if (!pInformationModel)
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical Error>CUAInformationModel null. Contact Michel Condemine\n");
return;
}
OpcUa_StatusCode uStatus = pInformationModel->InvertInverseReferences();
if ((uStatus != OpcUa_Good) && (uStatus != OpcUa_BadNothingToDo))
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Configuration inconsistency. Error during inverting of inverse references. Please check you XMLs files\n");
// We will add an iverse reference for all forward reference declared in the nodeset
// Those references are require for theinverse browsing of the AddressSpace
// il s'agit des references indispensable pour le browsing inverse de l'espace d'addressage
uStatus = pInformationModel->InvertForwardReferences();
if ((uStatus != OpcUa_Good) && (uStatus != OpcUa_BadNothingToDo))
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Configuration inconsistency. Error during inverting of forware references.. Please check you XMLs files\n");
// We tell pending thread that part of the postParsing threatment is finished
//OpcUa_Semaphore_Post(pInformationModel->m_PostThreatmentSem, 1);
pInformationModel->SearchEventsDefinition();
//
CEventsEngine* pEventsEngine = g_pTheApplication->GetEventsEngine();
if (pEventsEngine)
{
if (pEventsEngine->GetEventDefinitionListSize() > 0)
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Will start the EventEngine...\n");
OpcUa_Semaphore_Post(pEventsEngine->m_EventsThreadSem, 1);
}
}
// Update Method
uStatus = pInformationModel->UpdateMethods();
//// Update All CUADataType Encoding value (typeId Binary and Xml)
//uStatus = pInformationModel->UpdataDataTypesEncodingType();
// Mise à jour des EncodeableType de chaque extensionObject
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Start Updating UAVariables EncodeableObject\n");
uStatus = pInformationModel->UpdateUAVariablesEncodeableObject();
if (uStatus != OpcUa_Good)
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Update of EncodeableType failed. Please contact OpenOpcUa team\n");
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "UAVariables EncodeableObject has been updated properly\n");
// Update All CUADataType Encoding value (typeId Binary and Xml)
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Start Updating DataTypes EncodingType\n");
uStatus = pInformationModel->UpdateDataTypesEncodingType();
if ( (uStatus != OpcUa_Good) && (uStatus != OpcUa_GoodOverload))
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Update of DataTypesEncodingType failed. Please contact OpenOpcUa Team. 0x%05x\n",uStatus);
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "DataTypes EncodingType has been updated properly\n");
//uStatus = pInformationModel->UpdateUAVariablesEncodeableObject();
//if (uStatus != OpcUa_Good)
// OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Update of EncodeableType failed. Please contact OpenOpcUa team\n");
// Mise à jour des DataTypes pour chaque UAVariableType.
// A l'initialisation le dataType de chaque UAVariable doit être ns=0;i=0
// les dataType initialisé au travers du fichier XML ne seront pas traité
uStatus = pInformationModel->UpdateUAVariableTypeDataType();
// mise jour de tous les types de données pending <=> celle qui n'ont pas été initialisé lors du chargement du fichier XML
uStatus = pInformationModel->UpdatePendingVariableDatatype();
//
pInformationModel->Autorun();
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "End Post-Parsing initialization\n");
hInvertingReferenceThread = OpcUa_Null;
}
///-------------------------------------------------------------------------------------------------
/// <summary> Posts the processing. </summary>
///
/// <remarks> Michel, 29/07/2016. </remarks>
///
/// <returns> An OpcUa_StatusCode. </returns>
///-------------------------------------------------------------------------------------------------
OpcUa_StatusCode PostProcessing()
{
OpcUa_StatusCode uStatus=OpcUa_Good;
OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
//////////////////////////////////////////
//
// Begining Post Treatment
//
//////////////////////////////////////////
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR,"Start Post-Parsing initialization\n");
// This all the action made on the server before it runs
// Some action are made synchronously others asynchronously
CUAInformationModel* pInformationModel=CServerApplication::m_pTheAddressSpace;
if (!pInformationModel)
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR,"Critical Error>CUAInformationModel null. Contact Michel Condemine\n");
return 3;
}
// State 2259. Il s'agit d'une enumération qui contient l'etat du serveur
pInformationModel->ChangeServerStatusState(OpcUa_ServerState_NoConfiguration);
// Update NamespaceArray
uStatus=pInformationModel->UpdateNamespaceArray();
//
// Let's update builtIn types for all UAVariables
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR,"Start Updating UAVariablesBuiltinType\n");
uStatus=pInformationModel->UpdateUAVariablesBuiltinType();
if (uStatus!=OpcUa_Good)
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR,"Configuration inconsistency.Error during Built-In type update Please check you XMLs files\n");
// Update fastAccessList (m_UAInformationModelFastAccessList) for all nodeid declare in namespace index 0
uStatus=pInformationModel->UpdateInformationModelFastAccessList();
// We will forward all the inverse reference detected during the xml file parsing
// This means that we will create a new forward reference
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Start Updating inverse references\n");
// Create the thread for inversing reference
uStatus = OpcUa_Thread_Create(&hInvertingReferenceThread, InvertingReferenceThread, OpcUa_Null);
if (uStatus == OpcUa_Good)
OpcUa_Thread_Start(hInvertingReferenceThread);
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "End Post-Parsing. Threads running...\n");
//////////////////////////////////////////
//
// End Post Treatment
//
//////////////////////////////////////////
return uStatus;
}
///////////////////////////////////////////////////////////////////////////////////////
//
// Chargement de tous les fichiers nodeset declarés dasn le fichier XML de configuration
//
OpcUa_StatusCode LoadNodeSetFiles()
{
OpcUa_StatusCode uStatus=OpcUa_Good;
OpcUa_CharA* localPath=OpcUa_Null;
OpcUa_CharA* fileName=OpcUa_Null;
OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
OpcUa_String szProjectFolder=g_pTheApplication->GetProjectFolder();
// Load nodeset file in order to create the serveur addressSpace
for (OpcUa_UInt32 ii=0;ii<g_pTheApplication->m_FilesNodeSet.size();ii++)
{
OpcUa_String* pFullFileName=(OpcUa_String*)g_pTheApplication->m_FilesNodeSet.at(ii);
if (pFullFileName)
{
OpcUa_CharA* chFileName = OpcUa_String_GetRawString(pFullFileName);
// Search if the fileName contains a Path separator.
basic_string<char> myString(chFileName);
basic_string<char>::size_type index = 0;
#ifdef _GNUC_
index=myString.rfind("/");
#else
#if defined(WIN32) || defined(WIN64)
index = myString.rfind("\\");
#endif
#endif
if (index == basic_string<char>::npos)
{
localPath = OpcUa_String_GetRawString(&szProjectFolder);
fileName = OpcUa_String_GetRawString(pFullFileName);
// Parsing des fichiers de configuration de l'espace d'adressage
uStatus = g_pTheApplication->LoadUaServerNodeSet(localPath, fileName);
if (uStatus != OpcUa_Good)
{
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error>Cannot load NodeSet file uStatus=0x%05x\n", uStatus);
if (uStatus == OpcUa_BadFileNotFound)
break;
}
}
else
{
uStatus = OpcUa_BadFileNotFound;
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_LEVEL_ALWAYS, "Critical error>Full NodeSet filename is corrupted. The FileName cannot contains path informations\n");
}
}
else
{
uStatus = OpcUa_BadInvalidArgument;
break;
}
}
// fin Chargement des fichiers NodeSet qui constitueront l'espace d'adressage
return uStatus;
}
// Mise en place de L'application Description et des informations sur les ports d'écoute
OpcUa_StatusCode SetServerDescriptionTransportPortListener(CApplicationDescription** pAppDescription)
{
OpcUa_StatusCode uStatus=OpcUa_BadInvalidArgument;
OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
CUABindings aUABindings=g_pTheApplication->GetServerBindings();
for (OpcUa_UInt16 iii=0;iii<aUABindings.size();iii++)
{
CUABinding* pBinding=aUABindings.at(iii);
if (pBinding)
{
uStatus=OpcUa_Good;
OpcUa_ApplicationDescription* pUaApplicationDescription=(OpcUa_ApplicationDescription*)OpcUa_Alloc(sizeof(OpcUa_ApplicationDescription));
OpcUa_ApplicationDescription_Initialize(pUaApplicationDescription);
OpcUa_LocalizedText* pAppName= g_pTheApplication->GetApplicationName();
if (pAppName)
{
OpcUa_LocalizedText_Initialize(&(pUaApplicationDescription->ApplicationName));
OpcUa_LocalizedText_CopyTo(pAppName,&(pUaApplicationDescription->ApplicationName));
}
pUaApplicationDescription->ApplicationType=OpcUa_ApplicationType_Server;
// ApplicationUri
// creation de l'applicationURI a partir du nom de l'application
std::string applicationUri;
if (pAppName)
uStatus=OpcUa_CreateApplication_Uri(OpcUa_String_GetRawString(&(pAppName->Text)),&applicationUri);
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_WARNING, "ApplicationUri=%s\n", applicationUri.c_str());
OpcUa_String_AttachCopy(&(pUaApplicationDescription->ApplicationUri),applicationUri.c_str());
// ProductUri
OpcUa_String strBinding=pBinding->AsString();
OpcUa_String_AttachCopy(&(pUaApplicationDescription->ProductUri),applicationUri.c_str());
pUaApplicationDescription->NoOfDiscoveryUrls=1;
pUaApplicationDescription->DiscoveryUrls=(OpcUa_String*)OpcUa_Alloc(sizeof(OpcUa_String));
OpcUa_String_Initialize(&(pUaApplicationDescription->DiscoveryUrls[0]));
OpcUa_String_StrnCpy(&(pUaApplicationDescription->DiscoveryUrls[0]),
&strBinding,
OpcUa_String_StrLen(&strBinding));
OpcUa_String_Initialize(&(pUaApplicationDescription->DiscoveryProfileUri));
OpcUa_String_Initialize(&(pUaApplicationDescription->GatewayServerUri));
(*pAppDescription)=new CApplicationDescription(pUaApplicationDescription);
OpcUa_ApplicationDescription_Clear(pUaApplicationDescription);
OpcUa_Free(pUaApplicationDescription);
}
}
return uStatus;
}
OpcUa_StatusCode LoadSimulationFiles()
{
OpcUa_StatusCode uStatus=OpcUa_Good;
OpcUa_CharA* localPath=OpcUa_Null;
OpcUa_CharA* fileName=OpcUa_Null;
OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
OpcUa_String szProjectFolder = g_pTheApplication->GetProjectFolder();
// Chargement des paramètres de simulation
for (OpcUa_UInt16 iii=0;iii<g_pTheApplication->m_FilesSimulation.size();iii++)
{
OpcUa_String* pFullFileName=g_pTheApplication->m_FilesSimulation.at(iii);
if (pFullFileName)
{
// séparation du path et du nom de fichier
OpcUa_CharA* chFileName = OpcUa_String_GetRawString(pFullFileName);
basic_string<char> myString(chFileName);
basic_string<char>::size_type index = 0;
#ifdef _GNUC_
index=myString.rfind("/");
#else
#if defined(WIN32) || defined(WIN64)
index = myString.rfind("\\");
#endif
#endif
if (index == basic_string<char>::npos)
{
localPath = OpcUa_String_GetRawString(&szProjectFolder);
fileName = OpcUa_String_GetRawString(pFullFileName);
uStatus = g_pTheApplication->LoadUaServerSimulation(localPath, fileName);
if (uStatus != OpcUa_Good)
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error>Cannot load Simulation file %s uStatus=0x%05x\n", fileName,uStatus);
}
else
{
uStatus = OpcUa_BadFileNotFound;
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error>Simulation filename is corrupted. The FileName cannot contains path informations\n");
}
}
else
{
uStatus = OpcUa_BadInvalidArgument;
break;
}
}
// fin Chargement des paramètres de simulation
return uStatus;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary> Loads sub system files. </summary>
///
/// <remarks> Michel, 26/12/2018. </remarks>
///
/// <returns> The sub system files. </returns>
////////////////////////////////////////////////////////////////////////////////////////////////////
OpcUa_StatusCode LoadSubSystemFiles()
{
OpcUa_StatusCode uStatus=OpcUa_Good;
OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
// Add System nodes.Those nodes are not loaded through nodeset files.
CUAInformationModel* pInformationModel=g_pTheApplication->m_pTheAddressSpace;
uStatus = pInformationModel->AddinternalOpenOpcUaSystemNodes();
if (uStatus != OpcUa_Good)
{
OpcUa_Trace(pTraceConfiguration,OPCUA_TRACE_SERVER_LEVEL_ERROR, "Critical error>Cannot create InternalSystemNodes uStatus=0x%05x\n",uStatus);
}
OpcUa_String szProjectFolder = g_pTheApplication->GetProjectFolder();
//SubSystemParam* pSubSystemParam = (SubSystemParam*)OpcUa_Alloc(sizeof(SubSystemParam));
//if (pSubSystemParam)
//{
for (OpcUa_UInt16 iii = 0; iii < g_pTheApplication->m_FilesSubsystem.size(); iii++)
{
SubSystemParam* pSubSystemParam = (SubSystemParam*)OpcUa_Alloc(sizeof(SubSystemParam));
if (pSubSystemParam)
{
ZeroMemory(pSubSystemParam, sizeof(SubSystemParam));
pSubSystemParam->pszProjectFolder = OpcUa_String_GetRawString(&szProjectFolder);
OpcUa_String* pFullFileName = g_pTheApplication->m_FilesSubsystem.at(iii);
if (pFullFileName)
{
pSubSystemParam->chFileName = OpcUa_String_GetRawString(pFullFileName);
OpcUa_Thread hThread;
if (OpcUa_Thread_Create(&hThread, LoadSubsystemsThread, pSubSystemParam) == OpcUa_Good)
OpcUa_Thread_Start(hThread);
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "LoadSubSystemFiles>Cannot load Server Subsystem file: %s %s\n", OpcUa_String_GetRawString(pFullFileName));
}
}
}
// Fin Chargement de la configuration des subsystems
//OpcUa_Free(pSubSystemParam);
//}
//else
// uStatus = OpcUa_BadOutOfMemory;
return uStatus;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary> Loads subsystems thread. </summary>
///
/// <remarks> Michel, 26/12/2018. </remarks>
///
/// <param name="arg"> The argument. </param>
////////////////////////////////////////////////////////////////////////////////////////////////////
void LoadSubsystemsThread(LPVOID arg)
{
OpcUa_StatusCode uStatus = OpcUa_Good;
OpcUa_ProxyStubConfiguration* pTraceConfiguration = g_pTheApplication->GetTraceConfiguration();
SubSystemParam* pSubSystemParam;
pSubSystemParam = (SubSystemParam*)arg;
if (pSubSystemParam->pszProjectFolder)
{
OpcUa_CharA* pszSeparator = (OpcUa_CharA*)OpcUa_Alloc(4);
ZeroMemory(pszSeparator, 4);
//
// Ensure that the file name doesn't contains a PathFile separator
#ifdef _GNUC_
memcpy(pszSeparator, "/", 1);
#endif
#if defined(WIN32) || defined(WIN64)
memcpy(pszSeparator, "\\", 2);
#endif
if (strcmp(pSubSystemParam->chFileName, pszSeparator) != 0)
{
g_pTheApplication->m_pTheAddressSpace->LockServerCacheMutex();
// Parsing des fichiers de configuration de l'espace d'adressage
uStatus = g_pTheApplication->LoadUaServerSubsystems(pSubSystemParam->pszProjectFolder, pSubSystemParam->chFileName);
if (uStatus != OpcUa_Good)
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "LoadSubsystemsThread>Cannot load Server Subsystem file%s %s\n", pSubSystemParam->pszProjectFolder, pSubSystemParam->chFileName);
// démarrage du mecanisme de dialogue avec les sous-systèmes
g_pTheApplication->WakeupAllVpi();
g_pTheApplication->m_pTheAddressSpace->UnlockServerCacheMutex();
}
else
{
uStatus = OpcUa_BadFileNotFound;
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "LoadSubsystemsThread>Subsystem filename is corrupted\n");
}
OpcUa_Free(pszSeparator);
}
else
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Subsystems was not properly loaded. You specified a empty or null ProjectFolder\n");
if (pSubSystemParam)
OpcUa_Free(pSubSystemParam);
OpcUa_Trace(pTraceConfiguration, OPCUA_TRACE_SERVER_LEVEL_ERROR, "Subsystems were properly loaded\n");
}
// Extract the OpcData_Value from pDataValue1 and send in the pDataValue2 based on the pRange
OpcUa_StatusCode AdjustArrayToRange(OpcUa_DataValue* pDataValue1, CNumericRange* pNumericRange, OpcUa_DataValue** pDataValue2)
{
OpcUa_StatusCode uStatus=OpcUa_Good;
if (pDataValue1)
{
if (pDataValue1->Value.ArrayType==OpcUa_VariantArrayType_Array)
{
if (pNumericRange)
{
// Allocate output
(*pDataValue2)=(OpcUa_DataValue*)OpcUa_Alloc(sizeof(OpcUa_DataValue));
if ((*pDataValue2))
OpcUa_DataValue_Initialize((*pDataValue2));
//OpcUa_DataValue* pValue1=pDataValue1;
if (pNumericRange->IsMultiDimensional())
{
OpcUa_UInt32 iNoOfSubRanges =pNumericRange->GetNoOfSubRanges() ;
if (iNoOfSubRanges<=2)
{
if (iNoOfSubRanges==2)
{
CDataValue* pTmpDataValue2=new CDataValue();
if (pTmpDataValue2)
{
// it can be only ByteString and String
// SubRange pour la première dimension
CNumericRange* pSubRange00=pNumericRange->GetRangeAt(0);
// SubRange pour la deuxième dimension
CNumericRange* pSubRange01=pNumericRange->GetRangeAt(1);
if (pSubRange00&&pSubRange01)
{
OpcUa_Int32 iFirstDimLen=pSubRange00->GetEndIndex()-pSubRange00->GetBeginIndex()+1;
uStatus=pTmpDataValue2->InitializeArray(pDataValue1->Value.Datatype,iFirstDimLen);
if (uStatus==OpcUa_Good)
{
OpcUa_DataValue* pValue2=pTmpDataValue2->GetInternalDataValue();
switch (pDataValue1->Value.Datatype)
{
case OpcUaType_ByteString:
{
OpcUa_UInt32 j=0;
// Extraction pour la première dimension (Ligne)
for (OpcUa_Int32 i=pSubRange00->GetBeginIndex();i<=pSubRange00->GetEndIndex();i++)
{
// On extrait le byteString pour la première dimension
OpcUa_ByteString aByteString=pDataValue1->Value.Value.Array.Value.ByteStringArray[i];
if (aByteString.Data)
{
// On applique les second subRange sur le byteString Extrait
OpcUa_ByteString aSubByteString;
OpcUa_ByteString_Initialize(&aSubByteString);
OpcUa_Int32 iOffset = pSubRange01->GetEndIndex() - pSubRange01->GetBeginIndex() + 1;
aSubByteString.Data = (OpcUa_Byte*)OpcUa_Alloc(sizeof(OpcUa_Byte)*iOffset);
// Mise en form d'un byteString Resultat
OpcUa_Int32 ii = 0;
for (OpcUa_Int32 iSubIndex = pSubRange01->GetBeginIndex(); iSubIndex <= pSubRange01->GetEndIndex(); iSubIndex++)
aSubByteString.Data[ii++] = aByteString.Data[iSubIndex];
aSubByteString.Length = iOffset;
// Transfert du resultat dans la byteString
pValue2->Value.ArrayType = OpcUa_VariantArrayType_Array;
pValue2->Value.Datatype = OpcUaType_ByteString;
OpcUa_ByteString_CopyTo(&aSubByteString, &(pValue2->Value.Value.Array.Value.ByteStringArray[j++]));
OpcUa_ByteString_Clear(&aSubByteString);
}
}
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
delete pTmpDataValue2;
pTmpDataValue2 = OpcUa_Null;
//(*pDataValue2)=pValue2;
}
break;
case OpcUaType_String:
{
OpcUa_UInt32 j=0;
// Extraction pour la première dimension (Ligne)
for (OpcUa_Int32 i=pSubRange00->GetBeginIndex();i<=pSubRange00->GetEndIndex();i++)
{
// On extrait le byteString pour la première dimension
OpcUa_String aString=pDataValue1->Value.Value.Array.Value.StringArray[i];
// On applique les second subRange sur le byteString Extrait
OpcUa_String aSubString;
OpcUa_String_Initialize(&aSubString);
OpcUa_Int32 iOffset=pSubRange01->GetEndIndex()-pSubRange01->GetBeginIndex()+1;
OpcUa_CharA* pBuf=(OpcUa_CharA*)OpcUa_Alloc(sizeof(OpcUa_Byte)*iOffset+1);
OpcUa_CharA* aRawString=OpcUa_String_GetRawString(&aString);
ZeroMemory(pBuf,iOffset+1);
// Mise en form d'un byteString Resultat
OpcUa_Int32 ii=0;
for (OpcUa_Int32 iSubIndex=pSubRange01->GetBeginIndex();iSubIndex<=pSubRange01->GetEndIndex();iSubIndex++)
pBuf[ii++]=aRawString[iSubIndex];
// Transfert du resultat dans la byteString
pValue2->Value.ArrayType=OpcUa_VariantArrayType_Array;
pValue2->Value.Datatype=OpcUaType_String;
OpcUa_String_AttachCopy(&aSubString,pBuf);
OpcUa_String_CopyTo(&aSubString,&(pValue2->Value.Value.Array.Value.StringArray[j++]));
OpcUa_Free(pBuf);
OpcUa_String_Clear(&aSubString);
}
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
delete pTmpDataValue2;
pTmpDataValue2 = OpcUa_Null;
//(*pDataValue2)=pValue2;
}
break;
default:
uStatus = OpcUa_BadIndexRangeNoData; // OpcUa_BadInvalidArgument; 1.0.4.0
delete pTmpDataValue2;
pTmpDataValue2 = OpcUa_Null;
break;
}
}
}
else
{
delete pTmpDataValue2;
pTmpDataValue2 = OpcUa_Null;
uStatus = OpcUa_BadInvalidArgument;
}
}
else
uStatus=OpcUa_BadOutOfMemory;
}
else
uStatus=OpcUa_BadInvalidArgument;
}
else
uStatus=OpcUa_BadNotSupported;
}
else
{
if (pNumericRange->IsUnique())
{
CDataValue* pTmpDataValue2=new CDataValue();
if (pTmpDataValue2)
{
uStatus=pTmpDataValue2->InitializeArray(pDataValue1->Value.Datatype,1);
if (uStatus==OpcUa_Good)
{
OpcUa_UInt32 uniqueIndex = pNumericRange->GetEndIndex();
OpcUa_DataValue* pValue2=pTmpDataValue2->GetInternalDataValue();
switch (pDataValue1->Value.Datatype)
{
case OpcUaType_Boolean:
pValue2->Value.Value.Array.Value.BooleanArray[0] = pDataValue1->Value.Value.Array.Value.BooleanArray[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_Byte:
pValue2->Value.Value.Array.Value.ByteArray[0] = pDataValue1->Value.Value.Array.Value.ByteArray[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_SByte:
pValue2->Value.Value.Array.Value.SByteArray[0] = pDataValue1->Value.Value.Array.Value.SByteArray[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_DateTime:
pValue2->Value.Value.Array.Value.DateTimeArray[0] = pDataValue1->Value.Value.Array.Value.DateTimeArray[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_Double:
pValue2->Value.Value.Array.Value.DoubleArray[0] = pDataValue1->Value.Value.Array.Value.DoubleArray[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_Float:
pValue2->Value.Value.Array.Value.FloatArray[0] = pDataValue1->Value.Value.Array.Value.FloatArray[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_Int16:
pValue2->Value.Value.Array.Value.Int16Array[0] = pDataValue1->Value.Value.Array.Value.Int16Array[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_Int32:
pValue2->Value.Value.Array.Value.Int32Array[0] = pDataValue1->Value.Value.Array.Value.Int32Array[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_Int64:
pValue2->Value.Value.Array.Value.Int64Array[0] = pDataValue1->Value.Value.Array.Value.Int64Array[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_UInt16:
pValue2->Value.Value.Array.Value.UInt16Array[0] = pDataValue1->Value.Value.Array.Value.UInt16Array[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_UInt32:
pValue2->Value.Value.Array.Value.UInt32Array[0] = pDataValue1->Value.Value.Array.Value.UInt32Array[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_UInt64:
pValue2->Value.Value.Array.Value.UInt64Array[0] = pDataValue1->Value.Value.Array.Value.UInt64Array[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_StatusCode:
pValue2->Value.Value.Array.Value.StatusCodeArray[0] = pDataValue1->Value.Value.Array.Value.StatusCodeArray[uniqueIndex];
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_Guid:
OpcUa_Guid_CopyTo(&(pDataValue1->Value.Value.Array.Value.GuidArray[uniqueIndex]), &(pValue2->Value.Value.Array.Value.GuidArray[0]));
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_QualifiedName:
OpcUa_QualifiedName_CopyTo(&(pDataValue1->Value.Value.Array.Value.QualifiedNameArray[uniqueIndex]), &(pValue2->Value.Value.Array.Value.QualifiedNameArray[0]));
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_LocalizedText:
OpcUa_LocalizedText_CopyTo(&(pDataValue1->Value.Value.Array.Value.LocalizedTextArray[uniqueIndex]), &(pValue2->Value.Value.Array.Value.LocalizedTextArray[0]));
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
case OpcUaType_String:
OpcUa_String_CopyTo(&(pDataValue1->Value.Value.Array.Value.StringArray[uniqueIndex]), &(pValue2->Value.Value.Array.Value.StringArray[0]));
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
break;
default:
uStatus = OpcUa_BadNotSupported;
if (*pDataValue2)
{
OpcUa_DataValue_Initialize((*pDataValue2));
OpcUa_Free((*pDataValue2));
(*pDataValue2) = OpcUa_Null;
}
break;
}
}
else
{
if (*pDataValue2)
{
OpcUa_DataValue_Initialize((*pDataValue2));
OpcUa_Free((*pDataValue2));
(*pDataValue2) = OpcUa_Null;
}
}
// release resources
delete pTmpDataValue2;
pTmpDataValue2 = OpcUa_Null;
}
else
{
if (*pDataValue2)
{
OpcUa_DataValue_Initialize((*pDataValue2));
OpcUa_Free((*pDataValue2));
(*pDataValue2) = OpcUa_Null;
}
}
}
else
{
OpcUa_Int32 iArrayLen=(pNumericRange->GetEndIndex()-pNumericRange->GetBeginIndex())+1;
CDataValue* pTmpDataValue2=new CDataValue();
if (pTmpDataValue2)
{
uStatus=pTmpDataValue2->InitializeArray(pDataValue1->Value.Datatype,iArrayLen);
if (uStatus==OpcUa_Good)
{
OpcUa_DataValue* pValue1=pDataValue1;
OpcUa_DataValue* pValue2=pTmpDataValue2->GetInternalDataValue();
OpcUa_Int32 ii=0;
for (OpcUa_Int32 i=pNumericRange->GetBeginIndex();i<=pNumericRange->GetEndIndex();i++)
{
if (pNumericRange->GetBeginIndex()<=pValue1->Value.Value.Array.Length)
{
switch (pValue1->Value.Datatype)
{
case OpcUaType_Boolean:
pValue2->Value.Value.Array.Value.BooleanArray[ii] = pValue1->Value.Value.Array.Value.BooleanArray[i];
break;
case OpcUaType_Byte:
pValue2->Value.Value.Array.Value.ByteArray[ii] = pValue1->Value.Value.Array.Value.ByteArray[i];
break;
case OpcUaType_ByteString:
OpcUa_ByteString_Initialize(&(pValue2->Value.Value.Array.Value.ByteStringArray[ii]));
OpcUa_ByteString_CopyTo(&(pValue1->Value.Value.Array.Value.ByteStringArray[i]),&(pValue2->Value.Value.Array.Value.ByteStringArray[ii]));
break;
case OpcUaType_DateTime:
pValue2->Value.Value.Array.Value.DateTimeArray[ii].dwHighDateTime =pValue1->Value.Value.Array.Value.DateTimeArray[i].dwHighDateTime;
pValue2->Value.Value.Array.Value.DateTimeArray[ii].dwLowDateTime =pValue1->Value.Value.Array.Value.DateTimeArray[i].dwLowDateTime;
break;
case OpcUaType_Double:
pValue2->Value.Value.Array.Value.DoubleArray[ii] = pValue1->Value.Value.Array.Value.DoubleArray[i];
break;
case OpcUaType_Float:
pValue2->Value.Value.Array.Value.FloatArray[ii] = pValue1->Value.Value.Array.Value.FloatArray[i];
break;
case OpcUaType_Guid:
OpcUa_Guid_CopyTo(&(pValue1->Value.Value.Array.Value.GuidArray[i]),&(pValue2->Value.Value.Array.Value.GuidArray[ii]));
break;
case OpcUaType_Int16:
pValue2->Value.Value.Array.Value.Int16Array[ii] = pValue1->Value.Value.Array.Value.Int16Array[i];
break;
case OpcUaType_Int32:
pValue2->Value.Value.Array.Value.Int32Array[ii] = pValue1->Value.Value.Array.Value.Int32Array[i];
break;
case OpcUaType_Int64:
pValue2->Value.Value.Array.Value.Int64Array[ii] = pValue1->Value.Value.Array.Value.Int64Array[i];
break;
case OpcUaType_LocalizedText:
OpcUa_LocalizedText_CopyTo(&(pValue1->Value.Value.Array.Value.LocalizedTextArray[i]),&(pValue2->Value.Value.Array.Value.LocalizedTextArray[ii]));
break;
case OpcUaType_NodeId:
OpcUa_NodeId_CopyTo(&(pValue1->Value.Value.Array.Value.NodeIdArray[i]),&(pValue2->Value.Value.Array.Value.NodeIdArray[ii]));
break;
case OpcUaType_QualifiedName:
OpcUa_QualifiedName_CopyTo(&(pValue1->Value.Value.Array.Value.QualifiedNameArray[i]),&(pValue2->Value.Value.Array.Value.QualifiedNameArray[ii]));
break;
case OpcUaType_SByte:
pValue2->Value.Value.Array.Value.SByteArray[ii] = pValue1->Value.Value.Array.Value.SByteArray[i];
break;
case OpcUaType_StatusCode:
pValue2->Value.Value.Array.Value.StatusCodeArray[ii] = pValue1->Value.Value.Array.Value.StatusCodeArray[i];
break;
case OpcUaType_String:
OpcUa_String_Initialize(&(pValue2->Value.Value.Array.Value.StringArray[ii]));
OpcUa_String_CopyTo(&(pValue1->Value.Value.Array.Value.StringArray[i]),&(pValue2->Value.Value.Array.Value.StringArray[ii]));
break;
case OpcUaType_UInt16:
pValue2->Value.Value.Array.Value.UInt16Array[ii] = pValue1->Value.Value.Array.Value.UInt16Array[i];
break;
case OpcUaType_UInt32:
pValue2->Value.Value.Array.Value.UInt32Array[ii] = pValue1->Value.Value.Array.Value.UInt32Array[i];
break;
case OpcUaType_UInt64:
pValue2->Value.Value.Array.Value.UInt64Array[ii] = pValue1->Value.Value.Array.Value.UInt64Array[i];
break;
default:
break;
}
}
ii++;
}
OpcUa_DataValue_CopyTo(pValue2, (*pDataValue2));
}
else
{
if (*pDataValue2)
{
OpcUa_DataValue_Initialize((*pDataValue2));
OpcUa_Free((*pDataValue2));
(*pDataValue2) = OpcUa_Null;
}
}
// release resources
delete pTmpDataValue2;
pTmpDataValue2 = OpcUa_Null;
}
else
{
if (*pDataValue2)
{
OpcUa_DataValue_Initialize((*pDataValue2));
OpcUa_Free((*pDataValue2));
(*pDataValue2) = OpcUa_Null;
}
}
}
}
}
else
uStatus=OpcUa_BadInvalidArgument;
}
else
uStatus=OpcUa_BadInvalidArgument;
}
else
uStatus=OpcUa_BadInvalidArgument;
return uStatus;
}
// Generic Extension object copy function
OpcUa_StatusCode Copy(OpcUa_ExtensionObject** pTargetExtensionObject,OpcUa_ExtensionObject* pSourceExtensionObject)
{
OpcUa_StatusCode uStatus=OpcUa_Good;
if (pSourceExtensionObject)
{
switch (pSourceExtensionObject->Encoding)
{
case OpcUa_ExtensionObjectEncoding_None:
break;
case OpcUa_ExtensionObjectEncoding_Binary:
case OpcUa_ExtensionObjectEncoding_Xml:
OpcUa_ExtensionObject_Initialize(*pTargetExtensionObject);
OpcUa_ExtensionObject_CopyTo(pSourceExtensionObject,*pTargetExtensionObject);
break;
case OpcUa_ExtensionObjectEncoding_EncodeableObject:
{
CUAInformationModel* pInformationModel=CServerApplication::m_pTheAddressSpace;
OpcUa_Int32 iNamespaceIndex=0;
OpcUa_NodeId aNodeId;
OpcUa_NodeId_Initialize(&aNodeId);
aNodeId.IdentifierType=OpcUa_IdentifierType_Numeric;
OpcUa_String aString;
OpcUa_String_Initialize(&aString);
if (pSourceExtensionObject)
{
if (pSourceExtensionObject->Body.EncodeableObject.Type)
{
if (pSourceExtensionObject->Body.EncodeableObject.Type->NamespaceUri)
{
OpcUa_String_AttachCopy(&aString, pSourceExtensionObject->Body.EncodeableObject.Type->NamespaceUri);
if (pInformationModel->GetNamespaceUri(aString, &iNamespaceIndex) != OpcUa_Good)
iNamespaceIndex = 0;
}
aNodeId.NamespaceIndex = (OpcUa_UInt16)iNamespaceIndex;
aNodeId.Identifier.Numeric = pSourceExtensionObject->Body.EncodeableObject.Type->TypeId;
CUADataType* pUADataType=OpcUa_Null;
// Look for the dataType
uStatus=pInformationModel->GetNodeIdFromDataTypeList(aNodeId,&pUADataType);
if (uStatus==OpcUa_Good)
{
// Get the definition for this DataType
CDefinition* pDefinition=pUADataType->GetDefinition();
if (pDefinition)
{
OpcUa_Int32 iInstanceComputedSize = -1;
uStatus = pDefinition->GetInstanceSize(&iInstanceComputedSize);
OpcUa_UInt32 uiTotalSize = 0;
uStatus = pDefinition->DuplicateExtensionObject(pSourceExtensionObject, pTargetExtensionObject, &uiTotalSize);
}
}
}
else
uStatus = OpcUa_BadInvalidArgument;
}
else
uStatus = OpcUa_BadInvalidArgument;
}
break;
}
}
else
uStatus=OpcUa_BadInvalidArgument;
return uStatus;
}
/// <summary>
/// Copy from pVoidBufSource to pVoidBufTarget considering that pVoidBufSource contains a "builtInType" with a size of "ifieldSize".
/// ifieldSize is used only for "NormalType". "SpecialType" are type that contains a sting (something dynamic)
/// </summary>
/// <param name="ifieldSize">Size of the ifield.</param>
/// <param name="builtInType">Type of the built in.</param>
/// <param name="pVoidBufSource">The p void buf source.</param>
/// <param name="pVoidBufTarget">The p void buf target.</param>
/// <returns>OpcUa_StatusCode OpcUa_Good when no error are detected</returns>
OpcUa_StatusCode CopyBuiltInType(const OpcUa_Int32 ifieldSize, const OpcUa_Byte builtInType, void** pVoidBufSource, void** pVoidBufTarget)
{
OpcUa_StatusCode uStatus = OpcUa_Good;
switch (builtInType)
{
case OpcUaType_ExtensionObject:
{
}
break;
case OpcUaType_ByteString:
{
// Initialize the byteString
OpcUa_ByteString* pByteString = (OpcUa_ByteString*)OpcUa_Alloc(sizeof(OpcUa_ByteString));
OpcUa_ByteString_Initialize(pByteString);
//
// Let's get the size of the byteString
OpcUa_MemCpy(&(pByteString->Length), 4, *pVoidBufSource, 4);
((OpcUa_Byte*&)*pVoidBufTarget) += 4;
((OpcUa_Byte*&)*pVoidBufSource) += 4;
// Let's now trnsfert the content
pByteString->Data = (OpcUa_Byte*)OpcUa_Alloc(pByteString->Length);
ZeroMemory(pByteString->Data, pByteString->Length);
OpcUa_MemCpy(&(pByteString->Data), pByteString->Length, *pVoidBufSource, pByteString->Length);
// Ajust pointers
((OpcUa_Byte*&)*pVoidBufTarget) += pByteString->Length; //
((OpcUa_Byte*&)*pVoidBufSource) += pByteString->Length;
}
break;
case OpcUaType_DataValue:
break;
case OpcUaType_LocalizedText:
{
CopyBuiltInType(0, OpcUaType_String, pVoidBufSource, pVoidBufTarget);
CopyBuiltInType(0, OpcUaType_String, pVoidBufSource, pVoidBufTarget);
// OpcUa_LocalizedText* pLocalizedText = (OpcUa_LocalizedText*)OpcUa_Alloc(sizeof(OpcUa_LocalizedText));
// OpcUa_LocalizedText_Initialize(pLocalizedText);
//#ifdef _DEBUG
// ///////////////////////////////////////////////
// // Copy Locale pLocalizedText->Locale
// // copy flag
// OpcUa_MemCpy(pVoidBufTarget, 4, *pVoidBufSource, 4);
// ((OpcUa_Byte*&)pVoidBufTarget) += 4; //
// OpcUa_MemCpy(&(pLocalizedText->Locale.flags), 2, *pVoidBufSource, 2);
// ((OpcUa_Byte*&)*pVoidBufSource) += 4; // The real size is 4 because a OpcUa_String is in fact an OpcUa_StringInternal
// // copy Length
// OpcUa_MemCpy(pVoidBufTarget, 4, *pVoidBufSource, 4);
// ((OpcUa_Byte*&)pVoidBufTarget) += 4; //
// OpcUa_MemCpy(&(pLocalizedText->Locale.uLength), 4, *pVoidBufSource, 4);
// pLocalizedText->Locale.strContent = (OpcUa_CharA*)OpcUa_Alloc(pLocalizedText->Locale.uLength + 1);
// ZeroMemory(pLocalizedText->Locale.strContent, pLocalizedText->Locale.uLength + 1);
// // Copy the content
// ((OpcUa_Byte*&)*pVoidBufSource) += 4;
// void* apVoid = OpcUa_Alloc(4);
// memcpy(&apVoid, *pVoidBufSource, 4);
// OpcUa_MemCpy((pLocalizedText->Locale.strContent), pLocalizedText->Locale.uLength, ((void*)(apVoid)), pLocalizedText->Locale.uLength);
// OpcUa_MemCpy(pVoidBufTarget, 4, &(pLocalizedText->Locale.strContent), 4);
// // Update the pointer
// ((OpcUa_Byte*&)pVoidBufTarget) += 4; //
// ((OpcUa_Byte*&)*pVoidBufSource) += 4;
// ///////////////////////////////////////////////
// // Copy Locale pLocalizedText->Text
// // copy flag
// OpcUa_MemCpy(pVoidBufTarget, 4, *pVoidBufSource, 4);
// ((OpcUa_Byte*&)pVoidBufTarget) += 4; //
// OpcUa_MemCpy(&(pLocalizedText->Text.flags), 2, *pVoidBufSource, 2);
// ((OpcUa_Byte*&)*pVoidBufSource) += 4; // The real size is 4 because a OpcUa_String is in fact an OpcUa_StringInternal
// // copy Length
// OpcUa_MemCpy(pVoidBufTarget, 4, *pVoidBufSource, 4);
// ((OpcUa_Byte*&)pVoidBufTarget) += 4; //
// OpcUa_MemCpy(&(pLocalizedText->Text.uLength), 4, *pVoidBufSource, 4);
// pLocalizedText->Text.strContent = (OpcUa_CharA*)OpcUa_Alloc(pLocalizedText->Text.uLength + 1);
// ZeroMemory(pLocalizedText->Text.strContent, pLocalizedText->Text.uLength + 1);
// // Copy the content
// ((OpcUa_Byte*&)*pVoidBufSource) += 4;
// void* apVoid1 = OpcUa_Alloc(4);
// memcpy(&apVoid1, *pVoidBufSource, 4);
// OpcUa_MemCpy((pLocalizedText->Text.strContent), pLocalizedText->Text.uLength, ((void*)(apVoid1)), pLocalizedText->Text.uLength);
// OpcUa_MemCpy(pVoidBufTarget, 4, &(pLocalizedText->Text.strContent), 4);
// // Update the pointer
// ((OpcUa_Byte*&)pVoidBufTarget) += 4; //
// ((OpcUa_Byte*&)*pVoidBufSource) += 4;
//#endif
}
break;
case OpcUaType_QualifiedName:
{
CopyBuiltInType(2, OpcUaType_UInt16, pVoidBufSource, pVoidBufTarget);
CopyBuiltInType(2, OpcUaType_UInt16, pVoidBufSource, pVoidBufTarget);
CopyBuiltInType(0, OpcUaType_String, pVoidBufSource, pVoidBufTarget);
//iSize = 12; // string
//iSize += 6; // uLength + flag
//iSize += 4; // NamespaceIndex + Reserved
}
break;
case OpcUaType_String:
{
#ifdef _DEBUG
OpcUa_String* pString = (OpcUa_String*)OpcUa_Alloc(sizeof(OpcUa_String));
OpcUa_String_Initialize(pString);
// copy flag
OpcUa_MemCpy(*pVoidBufTarget, 4, *pVoidBufSource, 4);
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
OpcUa_MemCpy(&(pString->flags), 2, *pVoidBufSource, 2);
((OpcUa_Byte*&)*pVoidBufSource) += 4; // The real size is 4 because a OpcUa_String is in fact an OpcUa_StringInternal
// copy Length
OpcUa_MemCpy(*pVoidBufTarget, 4, *pVoidBufSource, 4);
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
OpcUa_MemCpy(&(pString->uLength), 4, *pVoidBufSource, 4);
pString->strContent = (OpcUa_CharA*)OpcUa_Alloc(pString->uLength + 1);
ZeroMemory(pString->strContent, pString->uLength + 1);
((OpcUa_Byte*&)*pVoidBufSource) += 4;
// Copy the content
void* apVoid = OpcUa_Alloc(4);
memcpy(&apVoid, *pVoidBufSource, 4);
OpcUa_MemCpy((pString->strContent), pString->uLength, ((void*)(apVoid)), pString->uLength);
OpcUa_MemCpy(*pVoidBufTarget, 4, &(pString->strContent), 4);
// Update the pointer
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
((OpcUa_Byte*&)*pVoidBufSource) += 4;
#else
OpcUa_String* pString = (OpcUa_String*)OpcUa_Alloc(sizeof(OpcUa_String));
OpcUa_String_Initialize(pString);
// copy flag
OpcUa_MemCpy(*pVoidBufTarget, 4, *pVoidBufSource, 4);
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
OpcUa_MemCpy(&(pString->uReserved1), 2, *pVoidBufSource, 2);
((OpcUa_Byte*&)*pVoidBufSource) += 4; // The real size is 4 because a OpcUa_String is in fact an OpcUa_StringInternal
// copy Length
OpcUa_MemCpy(*pVoidBufTarget, 4, *pVoidBufSource, 4);
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
OpcUa_MemCpy(&(pString->uReserved2), 4, *pVoidBufSource, 4);
pString->uReserved4 = (OpcUa_CharA*)OpcUa_Alloc(pString->uReserved2 + 1);
ZeroMemory(pString->uReserved4, pString->uReserved2 + 1);
((OpcUa_Byte*&)*pVoidBufSource) += 4;
// Copy the content
void* apVoid = OpcUa_Alloc(4);
memcpy(&apVoid, *pVoidBufSource, 4);
OpcUa_MemCpy((pString->uReserved4), pString->uReserved2, ((void*)(apVoid)), pString->uReserved2);
OpcUa_MemCpy(*pVoidBufTarget, 4, &(pString->uReserved4), 4);
// Update the pointer
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
((OpcUa_Byte*&)*pVoidBufSource) += 4;
#endif
}
break;
case OpcUaType_Variant:
printf("OpcUaType_Variant... arrggghhh Encapsulated Variant special case\n");
break;
case OpcUaType_NodeId:
{
OpcUa_NodeId aNodeId;
// IdentifierType OpcUa_UInt16
OpcUa_MemCpy(*pVoidBufTarget, 2, *pVoidBufSource, 2);
OpcUa_MemCpy(&(aNodeId.IdentifierType), 2, *pVoidBufSource, 2);
((OpcUa_Byte*&)*pVoidBufTarget) += 2; //
((OpcUa_Byte*&)*pVoidBufSource) += 2; //
// NamespaceIndex OpcUa_UInt16
OpcUa_MemCpy(*pVoidBufTarget, 2, *pVoidBufSource, 2);
OpcUa_MemCpy(&(aNodeId.NamespaceIndex), 2, *pVoidBufSource, 2);
((OpcUa_Byte*&)*pVoidBufTarget) += 2; //
((OpcUa_Byte*&)*pVoidBufSource) += 2; //
// Now the content of the NodeId
switch (aNodeId.IdentifierType)
{
case OpcUa_IdentifierType_Numeric:
{
OpcUa_MemCpy(*pVoidBufTarget, 4, *pVoidBufSource, 4);
OpcUa_MemCpy(&(aNodeId.Identifier.Numeric), 4, *pVoidBufSource, 4);
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
((OpcUa_Byte*&)*pVoidBufSource) += 4; //
}
break;
case OpcUa_IdentifierType_String:
{
#ifdef _DEBUG
OpcUa_String_Initialize(&(aNodeId.Identifier.String));
// copy flag
OpcUa_MemCpy(*pVoidBufTarget, 4, *pVoidBufSource, 4);
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
OpcUa_MemCpy(&(aNodeId.Identifier.String.flags), 2, *pVoidBufSource, 2);
((OpcUa_Byte*&)*pVoidBufSource) += 4; // The real size is 4 because a OpcUa_String is in fact an OpcUa_StringInternal
// copy Length
OpcUa_MemCpy(*pVoidBufTarget, 4, *pVoidBufSource, 4);
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
OpcUa_MemCpy(&(aNodeId.Identifier.String.uLength), 4, *pVoidBufSource, 4);
aNodeId.Identifier.String.strContent = (OpcUa_CharA*)OpcUa_Alloc(aNodeId.Identifier.String.uLength + 1);
ZeroMemory(aNodeId.Identifier.String.strContent, aNodeId.Identifier.String.uLength + 1);
// Copy the content
((OpcUa_Byte*&)*pVoidBufSource) += 4;
void* apVoid = OpcUa_Alloc(4);
memcpy(&apVoid, *pVoidBufSource, 4);
OpcUa_MemCpy((aNodeId.Identifier.String.strContent), aNodeId.Identifier.String.uLength, ((void*)(apVoid)), aNodeId.Identifier.String.uLength);
OpcUa_MemCpy(*pVoidBufTarget, 4, &(aNodeId.Identifier.String.strContent), 4);
// Update the pointer
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
((OpcUa_Byte*&)*pVoidBufSource) += 4;
#else
OpcUa_String* pString = (OpcUa_String*)OpcUa_Alloc(sizeof(OpcUa_String));
OpcUa_String_Initialize(pString);
// copy flag
OpcUa_MemCpy(*pVoidBufTarget, 4, *pVoidBufSource, 4);
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
OpcUa_MemCpy(&(pString->uReserved1), 2, *pVoidBufSource, 2);
((OpcUa_Byte*&)*pVoidBufSource) += 4; // The real size is 4 because a OpcUa_String is in fact an OpcUa_StringInternal
// copy Length
OpcUa_MemCpy(*pVoidBufTarget, 4, *pVoidBufSource, 4);
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
OpcUa_MemCpy(&(pString->uReserved2), 4, *pVoidBufSource, 4);
pString->uReserved4 = (OpcUa_CharA*)OpcUa_Alloc(pString->uReserved2 + 1);
ZeroMemory(pString->uReserved4, pString->uReserved2 + 1);
// Copy the content
((OpcUa_Byte*&)*pVoidBufSource) += 4;
void* apVoid = OpcUa_Alloc(4);
memcpy(&apVoid, *pVoidBufSource, 4);
OpcUa_MemCpy((pString->uReserved4), pString->uReserved2, ((void*)(apVoid)), pString->uReserved2);
OpcUa_MemCpy(*pVoidBufTarget, 4, &(pString->uReserved4), 4);
// Update the pointer
((OpcUa_Byte*&)*pVoidBufTarget) += 4; //
((OpcUa_Byte*&)*pVoidBufSource) += 4;
#endif
}
break;
case OpcUa_IdentifierType_Guid:
{
; // TODO
}
break;
case OpcUa_IdentifierType_Opaque:
{
; // TODO
}
break;
default:
uStatus = OpcUa_BadNodeIdInvalid;
break;
}
}
break;
default:
OpcUa_MemCpy(*pVoidBufTarget, ifieldSize, *pVoidBufSource, ifieldSize);
// move the calculation pointer
((OpcUa_Byte*&)*pVoidBufSource) += ifieldSize;
// move the result pointer
((OpcUa_Byte*&)*pVoidBufTarget) += ifieldSize;
break;
}
return uStatus;
}