#include "ua_server_internal.h"
#include "ua_discovery.h"
#include "ua_services.h"
#ifdef UA_ENABLE_DISCOVERY
#include <open62541/client.h>
static UA_StatusCode
setApplicationDescriptionFromRegisteredServer(const UA_FindServersRequest *request,
UA_ApplicationDescription *target,
const UA_RegisteredServer *rs) {
UA_StatusCode retval = UA_STATUSCODE_GOOD;
target->applicationType = rs->serverType;
retval |= UA_String_copy(&rs->serverUri, &target->applicationUri);
retval |= UA_String_copy(&rs->productUri, &target->productUri);
retval |= UA_String_copy(&rs->gatewayServerUri, &target->gatewayServerUri);
if(retval != UA_STATUSCODE_GOOD)
return retval;
if(request->localeIdsSize) {
UA_Boolean appNameFound = false;
for(size_t i = 0; i < request->localeIdsSize && !appNameFound; i++) {
for(size_t j =0; j < rs->serverNamesSize; j++) {
if(UA_String_equal(&request->localeIds[i],
&rs->serverNames[j].locale)) {
retval = UA_LocalizedText_copy(&rs->serverNames[j],
&target->applicationName);
if(retval != UA_STATUSCODE_GOOD)
return retval;
appNameFound = true;
break;
}
}
}
if(!appNameFound && rs->serverNamesSize) {
retval = UA_LocalizedText_copy(&rs->serverNames[0],
&target->applicationName);
if(retval != UA_STATUSCODE_GOOD)
return retval;
}
} else if(rs->serverNamesSize) {
retval = UA_LocalizedText_copy(&rs->serverNames[0],
&target->applicationName);
if(retval != UA_STATUSCODE_GOOD)
return retval;
}
if(rs->discoveryUrlsSize > 0) {
target->discoveryUrls = (UA_String *)
UA_calloc(rs->discoveryUrlsSize, sizeof(UA_String));
if(!target->discoveryUrls)
return UA_STATUSCODE_BADOUTOFMEMORY;
target->discoveryUrlsSize = rs->discoveryUrlsSize;
for(size_t i = 0; i < rs->discoveryUrlsSize; i++)
retval |= UA_String_copy(&rs->discoveryUrls[i],
&target->discoveryUrls[i]);
}
return retval;
}
#endif
UA_Boolean
Service_FindServers(UA_Server *server, UA_Session *session,
const UA_FindServersRequest *request,
UA_FindServersResponse *response) {
UA_ServerConfig *sc = &server->config;
UA_LOG_DEBUG_SESSION(sc->logging, session, "Processing FindServersRequest");
UA_LOCK_ASSERT(&server->serviceMutex);
UA_Boolean foundSelf = false;
if(request->serverUrisSize) {
for(size_t i = 0; i < request->serverUrisSize; i++) {
if(UA_String_equal(&request->serverUris[i],
&sc->applicationDescription.applicationUri)) {
foundSelf = true;
break;
}
}
} else {
foundSelf = true;
}
#ifndef UA_ENABLE_DISCOVERY
if(!foundSelf)
return true;
response->responseHeader.serviceResult =
UA_Array_copy(&sc->applicationDescription, 1, (void**)&response->servers,
&UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
return true;
response->serversSize = 1;
#else
UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
getServerComponentByName(server, UA_STRING("discovery"));
if(!dm) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
return true;
}
size_t maxResults = dm->registeredServersSize + 1;
response->servers = (UA_ApplicationDescription*)
UA_Array_new(maxResults, &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
if(!response->servers) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
return true;
}
size_t pos = 0;
registeredServer *current;
if(foundSelf) {
response->responseHeader.serviceResult =
UA_ApplicationDescription_copy(&sc->applicationDescription,
&response->servers[pos]);
pos++;
if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
goto cleanup;
}
LIST_FOREACH(current, &dm->registeredServers, pointers) {
UA_Boolean usable = (request->serverUrisSize == 0);
if(!usable) {
for(size_t i = 0; i < request->serverUrisSize; i++) {
if(UA_String_equal(¤t->registeredServer.serverUri,
&request->serverUris[i])) {
usable = true;
break;
}
}
}
if(!usable)
continue;
response->responseHeader.serviceResult |=
setApplicationDescriptionFromRegisteredServer(request,
&response->servers[pos],
¤t->registeredServer);
pos++;
}
cleanup:
if(pos == 0) {
UA_free(response->servers);
response->servers = NULL;
}
response->serversSize = pos;
#endif
if(request->endpointUrl.length > 0) {
for(size_t i = 0; i < response->serversSize; i++) {
UA_ApplicationDescription *ad = &response->servers[i];
UA_Array_delete(ad->discoveryUrls, ad->discoveryUrlsSize,
&UA_TYPES[UA_TYPES_STRING]);
ad->discoveryUrls = NULL;
ad->discoveryUrlsSize = 0;
response->responseHeader.serviceResult =
UA_Array_copy(&request->endpointUrl, 1,
(void**)&ad->discoveryUrls,
&UA_TYPES[UA_TYPES_STRING]);
if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
break;
ad->discoveryUrlsSize = 1;
}
}
return true;
}
#if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST)
static UA_Boolean
entryMatchesCapabilityFilter(size_t serverCapabilityFilterSize,
UA_String *serverCapabilityFilter,
UA_ServerOnNetwork *current) {
if(serverCapabilityFilterSize > current->serverCapabilitiesSize)
return false;
for(size_t i = 0; i < serverCapabilityFilterSize; i++) {
UA_Boolean capabilityFound = false;
for(size_t j = 0; j < current->serverCapabilitiesSize; j++) {
if(UA_String_equal_ignorecase(&serverCapabilityFilter[i],
¤t->serverCapabilities[j])) {
capabilityFound = true;
break;
}
}
if(!capabilityFound)
return false;
}
return true;
}
UA_Boolean
Service_FindServersOnNetwork(UA_Server *server, UA_Session *session,
const UA_FindServersOnNetworkRequest *request,
UA_FindServersOnNetworkResponse *response) {
UA_LOCK_ASSERT(&server->serviceMutex);
UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
getServerComponentByName(server, UA_STRING("discovery"));
if(!dm) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
return true;
}
if(!server->config.mdnsEnabled) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTIMPLEMENTED;
return true;
}
response->lastCounterResetTime =
UA_DiscoveryManager_getServerOnNetworkCounterResetTime(dm);
UA_UInt32 recordCount = 0;
UA_UInt32 serverOnNetworkRecordIdCounter =
UA_DiscoveryManager_getServerOnNetworkRecordIdCounter(dm);
if(request->startingRecordId < serverOnNetworkRecordIdCounter)
recordCount = serverOnNetworkRecordIdCounter - request->startingRecordId;
if(request->maxRecordsToReturn && recordCount > request->maxRecordsToReturn)
recordCount = UA_MIN(recordCount, request->maxRecordsToReturn);
if(recordCount == 0) {
response->serversSize = 0;
return true;
}
UA_UInt32 filteredCount = 0;
UA_STACKARRAY(UA_ServerOnNetwork*, filtered, recordCount);
UA_ServerOnNetwork *current = UA_DiscoveryManager_getServerOnNetworkList(dm);
if(!current) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
return true;
}
for(size_t i = 0; i < recordCount; i++) {
if(filteredCount >= recordCount)
break;
if(current->recordId < request->startingRecordId)
continue;
if(!entryMatchesCapabilityFilter(request->serverCapabilityFilterSize,
request->serverCapabilityFilter, current))
continue;
filtered[filteredCount++] = current;
current = UA_DiscoveryManager_getNextServerOnNetworkRecord(dm, current);
if(!current)
break;
}
if(filteredCount == 0)
return true;
response->servers = (UA_ServerOnNetwork*)
UA_malloc(sizeof(UA_ServerOnNetwork)*filteredCount);
if(!response->servers) {
response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
return true;
}
response->serversSize = filteredCount;
for(size_t i = 0; i < filteredCount; i++) {
UA_ServerOnNetwork_copy(filtered[i], &response->servers[filteredCount-i-1]);
}
return true;
}
#endif
static UA_String basic256Sha256Uri = UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
UA_SecurityPolicy *
getDefaultEncryptedSecurityPolicy(UA_Server *server,
UA_SecurityPolicyType type) {
UA_SecurityPolicy *best = NULL;
UA_Byte securityLevel = 0;
(void)type;
for(size_t i = 0; i < server->config.securityPoliciesSize; i++) {
UA_SecurityPolicy *sp = &server->config.securityPolicies[i];
if(sp->policyType == UA_SECURITYPOLICYTYPE_NONE)
continue;
if(UA_SecurityPolicy_isEcc(sp) || UA_SecurityPolicy_isEnhancedSecurity(sp))
continue;
if(UA_String_equal(&basic256Sha256Uri, &sp->policyUri))
return sp;
if(sp->securityLevel >= securityLevel) {
best = sp;
securityLevel = sp->securityLevel;
}
}
return best;
}
static const char *securityModeStrs[4] = {"-invalid", "-none", "-sign", "-sign+encrypt"};
UA_String
securityPolicyUriPostfix(const UA_String uri) {
if(uri.length == 0) return uri;
for(UA_Byte *b = uri.data + uri.length - 1; b >= uri.data; b--) {
if(*b != '#')
continue;
UA_String postfix = {uri.length - (size_t)(b - uri.data), b};
return postfix;
}
return uri;
}
static UA_StatusCode
updateEndpointUserIdentityToken(UA_Server *server,
UA_SecurityPolicyType policyType,
UA_EndpointDescription *ed) {
if(ed->userIdentityTokensSize > 0)
return UA_STATUSCODE_GOOD;
UA_StatusCode res = UA_STATUSCODE_GOOD;
UA_ServerConfig *sc = &server->config;
for(size_t i = 0; i < sc->accessControl.userTokenPoliciesSize; i++) {
UA_UserTokenPolicy *utp = &sc->accessControl.userTokenPolicies[i];
res = UA_Array_appendCopy((void**)&ed->userIdentityTokens,
&ed->userIdentityTokensSize, utp,
&UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
if(res != UA_STATUSCODE_GOOD)
return res;
utp = &ed->userIdentityTokens[ed->userIdentityTokensSize - 1];
UA_String_clear(&utp->securityPolicyUri);
#ifdef UA_ENABLE_ENCRYPTION
if(utp->tokenType != UA_USERTOKENTYPE_ANONYMOUS &&
UA_String_equal(&ed->securityPolicyUri, &UA_SECURITY_POLICY_NONE_URI) &&
(!sc->allowNonePolicyPassword || utp->tokenType != UA_USERTOKENTYPE_USERNAME)) {
UA_SecurityPolicy *encSP;
if(ed->securityMode == UA_MESSAGESECURITYMODE_NONE)
encSP = getDefaultEncryptedSecurityPolicy(server, policyType);
else
encSP = getSecurityPolicyByUri(server, &ed->securityPolicyUri);
if(!encSP) {
UA_LOG_WARNING(sc->logging, UA_LOGCATEGORY_CLIENT,
"Removing a UserTokenPolicy that would allow the "
"password to be transmitted without encryption "
"(Can be enabled via config->allowNonePolicyPassword)");
UA_StatusCode res2 =
UA_Array_resize((void **)&ed->userIdentityTokens,
&ed->userIdentityTokensSize,
ed->userIdentityTokensSize - 1,
&UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
(void)res2;
continue;
}
res |= UA_String_copy(&encSP->policyUri, &utp->securityPolicyUri);
}
#endif
UA_String postfix;
if(utp->securityPolicyUri.length > 0)
postfix = securityPolicyUriPostfix(utp->securityPolicyUri);
else
postfix = securityPolicyUriPostfix(ed->securityPolicyUri);
size_t newLen = utp->policyId.length + postfix.length +
strlen(securityModeStrs[ed->securityMode]);
UA_Byte *newString = (UA_Byte*)UA_realloc(utp->policyId.data, newLen);
if(!newString)
continue;
size_t pos = utp->policyId.length;
memcpy(&newString[pos], securityModeStrs[ed->securityMode],
strlen(securityModeStrs[ed->securityMode]));
pos += strlen(securityModeStrs[ed->securityMode]);
memcpy(&newString[pos], postfix.data, postfix.length);
utp->policyId.data = newString;
utp->policyId.length = newLen;
}
return res;
}
UA_StatusCode
setCurrentEndpointsArray(UA_Server *server, const UA_String endpointUrl,
UA_String *profileUris, size_t profileUrisSize,
UA_EndpointDescription **arr, size_t *arrSize) {
UA_ServerConfig *sc = &server->config;
size_t clone_times = 1;
if(endpointUrl.length == 0)
clone_times = sc->applicationDescription.discoveryUrlsSize;
*arr = (UA_EndpointDescription*)
UA_Array_new(sc->endpointsSize * clone_times,
&UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
if(!*arr)
return UA_STATUSCODE_BADOUTOFMEMORY;
size_t pos = 0;
UA_StatusCode retval = UA_STATUSCODE_GOOD;
for(size_t j = 0; j < sc->endpointsSize; ++j) {
const UA_EndpointDescription *ep = &sc->endpoints[j];
UA_Boolean usable = (profileUrisSize == 0);
if(!usable) {
for(size_t i = 0; i < profileUrisSize; ++i) {
if(!UA_String_equal(&profileUris[i], &ep->transportProfileUri))
continue;
usable = true;
break;
}
}
if(!usable)
continue;
UA_SecurityPolicy *sp =
getSecurityPolicyByUri(server, &ep->securityPolicyUri);
if(!sp) {
UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
"GetEndpoints: Endpoint defines SecurityPolicy "
"%S which is not available", ep->securityPolicyUri);
continue;
}
for(size_t i = 0; i < clone_times; ++i) {
UA_EndpointDescription *ed = &(*arr)[pos];
retval |= UA_EndpointDescription_copy(&sc->endpoints[j], ed);
UA_ApplicationDescription_clear(&ed->server);
retval |= UA_ApplicationDescription_copy(&sc->applicationDescription,
&ed->server);
UA_ByteString_clear(&ed->serverCertificate);
retval |= UA_ByteString_copy(&sp->localCertificate,
&ed->serverCertificate);
retval |= updateEndpointUserIdentityToken(server, sp->policyType, ed);
if(ed->serverCertificate.length == 0) {
for(size_t ti = 0; ti < ed->userIdentityTokensSize; ti++) {
UA_UserTokenPolicy *utp = &ed->userIdentityTokens[ti];
if(utp->securityPolicyUri.length == 0)
continue;
UA_SecurityPolicy *encSP =
getSecurityPolicyByUri(server, &utp->securityPolicyUri);
if(!encSP || encSP->localCertificate.length == 0)
continue;
retval |= UA_ByteString_copy(&encSP->localCertificate,
&ed->serverCertificate);
break;
}
}
UA_String_clear(&ed->endpointUrl);
if(endpointUrl.length == 0) {
retval |= UA_String_copy(&sc->applicationDescription.discoveryUrls[i],
&ed->endpointUrl);
} else {
retval |= UA_String_copy(&endpointUrl, &ed->endpointUrl);
size_t k = 0;
for(; k < ed->server.discoveryUrlsSize; k++) {
if(UA_String_equal(&ed->endpointUrl, &ed->server.discoveryUrls[k]))
break;
}
if(k == ed->server.discoveryUrlsSize) {
retval |= UA_Array_appendCopy((void **)&ed->server.discoveryUrls,
&ed->server.discoveryUrlsSize,
&endpointUrl,
&UA_TYPES[UA_TYPES_STRING]);
}
}
if(retval != UA_STATUSCODE_GOOD)
goto error;
pos++;
}
}
*arrSize = pos;
return UA_STATUSCODE_GOOD;
error:
UA_Array_delete(*arr, sc->endpointsSize * clone_times,
&UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
*arr = NULL;
return retval;
}
UA_Boolean
Service_GetEndpoints(UA_Server *server, UA_Session *session,
const UA_GetEndpointsRequest *request,
UA_GetEndpointsResponse *response) {
UA_LOCK_ASSERT(&server->serviceMutex);
UA_LOG_DEBUG_SESSION(server->config.logging, session,
"Processing GetEndpointsRequest with endpointUrl %S",
request->endpointUrl);
response->responseHeader.serviceResult =
setCurrentEndpointsArray(server, request->endpointUrl,
request->profileUris, request->profileUrisSize,
&response->endpoints, &response->endpointsSize);
return true;
}
#ifdef UA_ENABLE_DISCOVERY
static void
process_RegisterServer(UA_Server *server, UA_Session *session,
const UA_RequestHeader* requestHeader,
const UA_RegisteredServer *requestServer,
const size_t requestDiscoveryConfigurationSize,
const UA_ExtensionObject *requestDiscoveryConfiguration,
UA_ResponseHeader* responseHeader,
size_t *responseConfigurationResultsSize,
UA_StatusCode **responseConfigurationResults,
size_t *responseDiagnosticInfosSize,
UA_DiagnosticInfo *responseDiagnosticInfos) {
UA_LOCK_ASSERT(&server->serviceMutex);
UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
getServerComponentByName(server, UA_STRING("discovery"));
if(!dm)
return;
UA_ServerConfig *sc = &server->config;
if(sc->applicationDescription.applicationType != UA_APPLICATIONTYPE_DISCOVERYSERVER) {
responseHeader->serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
return;
}
registeredServer *rs = NULL;
LIST_FOREACH(rs, &dm->registeredServers, pointers) {
if(UA_String_equal(&rs->registeredServer.serverUri, &requestServer->serverUri))
break;
}
UA_MdnsDiscoveryConfiguration *mdnsConfig = NULL;
const UA_String* mdnsServerName = NULL;
if(requestDiscoveryConfigurationSize) {
*responseConfigurationResults =
(UA_StatusCode *)UA_Array_new(requestDiscoveryConfigurationSize,
&UA_TYPES[UA_TYPES_STATUSCODE]);
if(!(*responseConfigurationResults)) {
responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
return;
}
*responseConfigurationResultsSize = requestDiscoveryConfigurationSize;
for(size_t i = 0; i < requestDiscoveryConfigurationSize; i++) {
const UA_ExtensionObject *object = &requestDiscoveryConfiguration[i];
if(!mdnsConfig && (object->encoding == UA_EXTENSIONOBJECT_DECODED ||
object->encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
(object->content.decoded.type == &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION])) {
mdnsConfig = (UA_MdnsDiscoveryConfiguration *)object->content.decoded.data;
mdnsServerName = &mdnsConfig->mdnsServerName;
(*responseConfigurationResults)[i] = UA_STATUSCODE_GOOD;
} else {
(*responseConfigurationResults)[i] = UA_STATUSCODE_BADNOTSUPPORTED;
}
}
}
if(!mdnsServerName && requestServer->serverNamesSize)
mdnsServerName = &requestServer->serverNames[0].text;
if(!mdnsServerName) {
responseHeader->serviceResult = UA_STATUSCODE_BADSERVERNAMEMISSING;
return;
}
if(requestServer->discoveryUrlsSize == 0) {
responseHeader->serviceResult = UA_STATUSCODE_BADDISCOVERYURLMISSING;
return;
}
if(requestServer->semaphoreFilePath.length) {
#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE
char* filePath = (char*)
UA_malloc(sizeof(char)*requestServer->semaphoreFilePath.length+1);
if(!filePath) {
UA_LOG_ERROR_SESSION(sc->logging, session,
"Cannot allocate memory for semaphore path. "
"Out of memory.");
responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
return;
}
memcpy(filePath, requestServer->semaphoreFilePath.data,
requestServer->semaphoreFilePath.length );
filePath[requestServer->semaphoreFilePath.length] = '\0';
if(!UA_fileExists( filePath )) {
responseHeader->serviceResult = UA_STATUSCODE_BADSEMAPHOREFILEMISSING;
UA_free(filePath);
return;
}
UA_free(filePath);
#else
UA_LOG_WARNING(sc->logging, UA_LOGCATEGORY_CLIENT,
"Ignoring semaphore file path. open62541 not compiled "
"with UA_ENABLE_DISCOVERY_SEMAPHORE=ON");
#endif
}
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
if(sc->mdnsEnabled) {
for(size_t i = 0; i < requestServer->discoveryUrlsSize; i++) {
UA_Boolean updateTxt = (requestServer->isOnline && i==0) ||
(!requestServer->isOnline && i==requestServer->discoveryUrlsSize);
UA_Discovery_updateMdnsForDiscoveryUrl(dm, *mdnsServerName, mdnsConfig,
requestServer->discoveryUrls[i],
requestServer->isOnline, updateTxt);
}
}
#endif
if(!requestServer->isOnline) {
if(!rs) {
UA_LOG_WARNING_SESSION(sc->logging, session,
"Could not unregister server %S. Not registered.",
requestServer->serverUri);
responseHeader->serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
return;
}
if(dm->registerServerCallback)
dm->registerServerCallback(requestServer, dm->registerServerCallbackData);
LIST_REMOVE(rs, pointers);
UA_RegisteredServer_clear(&rs->registeredServer);
UA_free(rs);
dm->registeredServersSize--;
responseHeader->serviceResult = UA_STATUSCODE_GOOD;
return;
}
UA_StatusCode retval = UA_STATUSCODE_GOOD;
if(!rs) {
UA_LOG_DEBUG_SESSION(sc->logging, session,
"Registering new server: %S",
requestServer->serverUri);
rs = (registeredServer*)UA_malloc(sizeof(registeredServer));
if(!rs) {
responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
return;
}
LIST_INSERT_HEAD(&dm->registeredServers, rs, pointers);
dm->registeredServersSize++;
} else {
UA_RegisteredServer_clear(&rs->registeredServer);
}
if(dm->registerServerCallback)
dm->registerServerCallback(requestServer,
dm->registerServerCallbackData);
UA_EventLoop *el = sc->eventLoop;
UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
UA_RegisteredServer_copy(requestServer, &rs->registeredServer);
rs->lastSeen = nowMonotonic;
responseHeader->serviceResult = retval;
}
UA_Boolean
Service_RegisterServer(UA_Server *server, UA_Session *session,
const UA_RegisterServerRequest *request,
UA_RegisterServerResponse *response) {
UA_LOG_DEBUG_SESSION(server->config.logging, session,
"Processing RegisterServerRequest");
UA_LOCK_ASSERT(&server->serviceMutex);
process_RegisterServer(server, session, &request->requestHeader,
&request->server, 0, NULL, &response->responseHeader,
0, NULL, 0, NULL);
return true;
}
UA_Boolean
Service_RegisterServer2(UA_Server *server, UA_Session *session,
const UA_RegisterServer2Request *request,
UA_RegisterServer2Response *response) {
UA_LOG_DEBUG_SESSION(server->config.logging, session,
"Processing RegisterServer2Request");
UA_LOCK_ASSERT(&server->serviceMutex);
process_RegisterServer(server, session, &request->requestHeader,
&request->server,
request->discoveryConfigurationSize,
request->discoveryConfiguration,
&response->responseHeader,
&response->configurationResultsSize,
&response->configurationResults,
&response->diagnosticInfosSize,
response->diagnosticInfos);
return true;
}
#endif