Coverage Report

Created: 2026-08-14 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/src/server/ua_server.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
 *
5
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
6
 *    Copyright 2014-2017 (c) Florian Palm
7
 *    Copyright 2015-2016 (c) Sten Grüner
8
 *    Copyright 2015-2016 (c) Chris Iatrou
9
 *    Copyright 2015 (c) LEvertz
10
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
11
 *    Copyright 2016 (c) Julian Grothoff
12
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
13
 *    Copyright 2016 (c) Lorenz Haas
14
 *    Copyright 2017 (c) frax2222
15
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
16
 *    Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang)
17
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
18
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
19
 *    Copyright 2022-2025 (c) Fraunhofer IOSB (Author: Andreas Ebner)
20
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
21
 */
22
23
#include "ua_server_internal.h"
24
25
#ifdef UA_ENABLE_SUBSCRIPTIONS
26
#include "ua_subscription.h"
27
#endif
28
29
#ifdef UA_ENABLE_NODESET_INJECTOR
30
#include "open62541/nodesetinjector.h"
31
#endif
32
33
#ifdef UA_ENABLE_ENCRYPTION
34
#include "open62541/plugin/certificategroup_default.h"
35
#endif
36
37
5.91k
#define STARTCHANNELID 1
38
5.91k
#define STARTTOKENID 1
39
40
/**********************/
41
/* Namespace Handling */
42
/**********************/
43
44
/* The NS1 Uri can be changed by the user to some custom string. This method is
45
 * called to initialize the NS1 Uri if it is not set before to the default
46
 * Application URI.
47
 *
48
 * This is done as soon as the Namespace Array is read or written via node value
49
 * read / write services, or UA_Server_addNamespace, or UA_Server_getNamespaceByIndex
50
 * UA_Server_getNamespaceByName or UA_Server_run_startup is called.
51
 *
52
 * Therefore one has to set the custom NS1 URI before one of the previously
53
 * mentioned steps. */
54
55
void
56
17.0k
setupNs1Uri(UA_Server *server) {
57
17.0k
    if(!server->namespaces[1].data) {
58
17.0k
        UA_String_copy(&server->config.applicationDescription.applicationUri,
59
17.0k
                       &server->namespaces[1]);
60
17.0k
    }
61
17.0k
}
62
63
16.4k
UA_UInt16 addNamespace(UA_Server *server, const UA_String name) {
64
    /* ensure that the uri for ns1 is set up from the app description */
65
16.4k
    setupNs1Uri(server);
66
67
    /* Check if the namespace already exists in the server's namespace array */
68
16.4k
    for(size_t i = 0; i < server->namespacesSize; ++i) {
69
16.4k
        if(UA_String_equal(&name, &server->namespaces[i]))
70
16.4k
            return (UA_UInt16) i;
71
16.4k
    }
72
73
    /* Make the array bigger */
74
0
    UA_String *newNS = (UA_String*)UA_realloc(server->namespaces,
75
0
                                              sizeof(UA_String) * (server->namespacesSize + 1));
76
0
    UA_CHECK_MEM(newNS, return 0);
77
78
0
    server->namespaces = newNS;
79
80
    /* Copy the namespace string */
81
0
    UA_StatusCode retval = UA_String_copy(&name, &server->namespaces[server->namespacesSize]);
82
0
    UA_CHECK_STATUS(retval, return 0);
83
84
    /* Announce the change (otherwise, the array appears unchanged) */
85
0
    ++server->namespacesSize;
86
0
    return (UA_UInt16)(server->namespacesSize - 1);
87
0
}
88
89
16.4k
UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
90
    /* Override const attribute to get string (dirty hack) */
91
16.4k
    UA_String nameString;
92
16.4k
    nameString.length = strlen(name);
93
16.4k
    nameString.data = (UA_Byte*)(uintptr_t)name;
94
16.4k
    lockServer(server);
95
16.4k
    UA_UInt16 retVal = addNamespace(server, nameString);
96
16.4k
    unlockServer(server);
97
16.4k
    return retVal;
98
16.4k
}
99
100
UA_ServerConfig*
101
1.15M
UA_Server_getConfig(UA_Server *server) {
102
1.15M
    UA_CHECK_MEM(server, return NULL);
103
1.15M
    return &server->config;
104
1.15M
}
105
106
UA_StatusCode
107
getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
108
0
                   size_t *foundIndex) {
109
    /* ensure that the uri for ns1 is set up from the app description */
110
0
    setupNs1Uri(server);
111
0
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
112
0
    for(size_t idx = 0; idx < server->namespacesSize; idx++) {
113
0
        if(UA_String_equal(&server->namespaces[idx], &namespaceUri)) {
114
0
            (*foundIndex) = idx;
115
0
            res = UA_STATUSCODE_GOOD;
116
0
            break;
117
0
        }
118
0
    }
119
0
    return res;
120
0
}
121
122
UA_StatusCode
123
getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex,
124
0
                   UA_String *foundUri) {
125
    /* ensure that the uri for ns1 is set up from the app description */
126
0
    setupNs1Uri(server);
127
0
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
128
0
    if(namespaceIndex >= server->namespacesSize)
129
0
        return res;
130
0
    res = UA_String_copy(&server->namespaces[namespaceIndex], foundUri);
131
0
    return res;
132
0
}
133
134
UA_StatusCode
135
UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
136
0
                             size_t *foundIndex) {
137
0
    lockServer(server);
138
0
    UA_StatusCode res = getNamespaceByName(server, namespaceUri, foundIndex);
139
0
    unlockServer(server);
140
0
    return res;
141
0
}
142
143
UA_StatusCode
144
UA_Server_getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex,
145
0
                              UA_String *foundUri) {
146
0
    lockServer(server);
147
0
    UA_StatusCode res = getNamespaceByIndex(server, namespaceIndex, foundUri);
148
0
    unlockServer(server);
149
0
    return res;
150
0
}
151
152
UA_StatusCode
153
UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
154
0
                               UA_NodeIteratorCallback callback, void *handle) {
155
0
    UA_BrowseDescription bd;
156
0
    UA_BrowseDescription_init(&bd);
157
0
    bd.nodeId = parentNodeId;
158
0
    bd.browseDirection = UA_BROWSEDIRECTION_BOTH;
159
0
    bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_ISFORWARD;
160
161
0
    UA_BrowseResult br = UA_Server_browse(server, 0, &bd);
162
0
    UA_StatusCode res = br.statusCode;
163
0
    UA_CHECK_STATUS(res, goto cleanup);
164
165
0
    for(size_t i = 0; i < br.referencesSize; i++) {
166
0
        if(!UA_ExpandedNodeId_isLocal(&br.references[i].nodeId))
167
0
            continue;
168
0
        res = callback(br.references[i].nodeId.nodeId, !br.references[i].isForward,
169
0
                       br.references[i].referenceTypeId, handle);
170
0
        UA_CHECK_STATUS(res, goto cleanup);
171
0
    }
172
0
cleanup:
173
0
    UA_BrowseResult_clear(&br);
174
0
    return res;
175
0
}
176
177
/********************/
178
/* GDS Transaction  */
179
/********************/
180
181
UA_StatusCode
182
0
UA_GDSTransaction_init(UA_GDSTransaction *transaction, UA_Server *server, const UA_NodeId sessionId) {
183
0
    if(!transaction || !server)
184
0
        return UA_STATUSCODE_BADINTERNALERROR;
185
186
0
    UA_ByteString csr = UA_BYTESTRING_NULL;
187
0
    if(transaction->localCsrCertificate.length > 0)
188
0
        csr = transaction->localCsrCertificate;
189
190
0
    memset(transaction, 0, sizeof(UA_GDSTransaction));
191
192
0
    transaction->state = UA_GDSTRANSACTIONSTATE_PENDING;
193
0
    UA_NodeId_copy(&sessionId, &transaction->sessionId);
194
0
    transaction->server = server;
195
0
    transaction->localCsrCertificate = csr;
196
197
0
    return UA_STATUSCODE_GOOD;
198
0
}
199
200
UA_CertificateGroup*
201
UA_GDSTransaction_getCertificateGroup(UA_GDSTransaction *transaction,
202
0
                                      const UA_CertificateGroup *certGroup) {
203
0
#ifdef UA_ENABLE_ENCRYPTION
204
0
    if(!transaction || !certGroup)
205
0
        return NULL;
206
207
    /* Check if transaction was initialized */
208
0
    if(transaction->state != UA_GDSTRANSACTIONSTATE_PENDING)
209
0
        return NULL;
210
211
0
    for(size_t i = 0; i < transaction->certGroupSize; i++) {
212
0
        UA_CertificateGroup *group = &transaction->certGroups[i];
213
0
        if(UA_NodeId_equal(&group->certificateGroupId, &certGroup->certificateGroupId))
214
0
            return group;
215
0
    }
216
217
    /* If the certGroup does not exist, create a new one */
218
0
    transaction->certGroups = (UA_CertificateGroup*)UA_realloc(transaction->certGroups, (transaction->certGroupSize + 1) * sizeof(UA_CertificateGroup));
219
0
    if(!transaction->certGroups)
220
0
        return NULL;
221
222
0
    transaction->certGroupSize++;
223
224
0
    memset(&transaction->certGroups[transaction->certGroupSize-1], 0, sizeof(UA_CertificateGroup));
225
226
0
    UA_TrustListDataType trustList;
227
0
    UA_TrustListDataType_init(&trustList);
228
0
    trustList.specifiedLists = UA_TRUSTLISTMASKS_ALL;
229
0
    certGroup->getTrustList((UA_CertificateGroup*)(uintptr_t)certGroup, &trustList);
230
231
    /* Set up the parameters */
232
0
    static UA_THREAD_LOCAL UA_KeyValuePair params[1] = {
233
0
        {{0, UA_STRING_STATIC("max-trust-listsize")}, {0}}
234
0
    };
235
0
    UA_KeyValueMap paramsMap = {1, params};
236
237
0
    UA_ServerConfig *config = UA_Server_getConfig(transaction->server);
238
0
    UA_Variant_setScalar(&params[0].value, &config->maxTrustListSize,
239
0
                         &UA_TYPES[UA_TYPES_UINT32]);
240
241
0
    UA_CertificateGroup_Memorystore(&transaction->certGroups[transaction->certGroupSize-1],
242
0
        (UA_NodeId*)(uintptr_t)&certGroup->certificateGroupId, &trustList, certGroup->logging, &paramsMap);
243
244
0
    UA_TrustListDataType_clear(&trustList);
245
246
0
    return &transaction->certGroups[transaction->certGroupSize-1];
247
#else
248
    return NULL;
249
#endif
250
0
}
251
252
UA_StatusCode
253
UA_GDSTransaction_addCertificateInfo(UA_GDSTransaction *transaction,
254
                                     const UA_NodeId certificateGroupId,
255
                                     const UA_NodeId certificateTypeId,
256
                                     const UA_ByteString *certificate,
257
0
                                     const UA_ByteString *privateKey) {
258
0
    if(!transaction || !certificate)
259
0
        return UA_STATUSCODE_BADINTERNALERROR;
260
261
    /* Check if transaction was initialized */
262
0
    if(transaction->state != UA_GDSTRANSACTIONSTATE_PENDING)
263
0
        return UA_STATUSCODE_BADINVALIDSTATE;
264
265
    /* Check if an entry with certificateGroupId and certificateTypeId already exists */
266
0
    for(size_t i = 0; i < transaction->certificateInfosSize; i++) {
267
0
        UA_GDSCertificateInfo *certInfo = &transaction->certificateInfos[i];
268
269
0
        if(!UA_NodeId_equal(&certInfo->certificateGroup, &certificateGroupId) ||
270
0
           !UA_NodeId_equal(&certInfo->certificateType, &certificateTypeId))
271
0
            continue;
272
273
0
        UA_ByteString_clear(&certInfo->certificate);
274
0
        UA_ByteString_clear(&certInfo->privateKey);
275
276
0
        UA_ByteString_copy(certificate, &certInfo->certificate);
277
0
        certInfo->privateKey = UA_BYTESTRING_NULL;
278
0
        if(privateKey)
279
0
            UA_ByteString_copy(privateKey, &certInfo->privateKey);
280
281
0
        return UA_STATUSCODE_GOOD;
282
0
    }
283
284
0
    UA_GDSCertificateInfo *newCertInfos = (UA_GDSCertificateInfo *)UA_realloc(transaction->certificateInfos,
285
0
        (transaction->certificateInfosSize + 1) * sizeof(UA_GDSCertificateInfo));
286
0
    if(!newCertInfos)
287
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
288
289
0
    transaction->certificateInfos = newCertInfos;
290
291
0
    UA_GDSCertificateInfo *newCertInfo = &transaction->certificateInfos[transaction->certificateInfosSize];
292
0
    UA_ByteString_copy(certificate, &newCertInfo->certificate);
293
0
    UA_NodeId_copy(&certificateGroupId, &newCertInfo->certificateGroup);
294
0
    UA_NodeId_copy(&certificateTypeId, &newCertInfo->certificateType);
295
0
    newCertInfo->privateKey = UA_BYTESTRING_NULL;
296
0
    if(privateKey)
297
0
        UA_ByteString_copy(privateKey, &newCertInfo->privateKey);
298
299
0
    transaction->certificateInfosSize++;
300
301
0
    return UA_STATUSCODE_GOOD;
302
0
}
303
304
5.91k
void UA_GDSTransaction_clear(UA_GDSTransaction *transaction) {
305
5.91k
    if(!transaction)
306
0
        return;
307
308
5.91k
    transaction->state = UA_GDSTRANSACTIONSTATE_FRESH;
309
5.91k
    transaction->server = NULL;
310
5.91k
    UA_NodeId_clear(&transaction->sessionId);
311
5.91k
    UA_ByteString_clear(&transaction->localCsrCertificate);
312
313
5.91k
    if(transaction->certGroups) {
314
0
        for(size_t i = 0; i < transaction->certGroupSize; i++) {
315
0
            transaction->certGroups[i].clear(&transaction->certGroups[i]);
316
0
        }
317
0
        UA_free(transaction->certGroups);
318
0
        transaction->certGroupSize = 0;
319
0
        transaction->certGroups = NULL;
320
0
    }
321
322
5.91k
    if(transaction->certificateInfos) {
323
0
        for(size_t i = 0; i < transaction->certificateInfosSize; i++) {
324
0
            UA_ByteString_clear(&transaction->certificateInfos[i].certificate);
325
0
            UA_ByteString_clear(&transaction->certificateInfos[i].privateKey);
326
0
            UA_NodeId_clear(&transaction->certificateInfos[i].certificateGroup);
327
0
            UA_NodeId_clear(&transaction->certificateInfos[i].certificateType);
328
0
        }
329
0
        UA_free(transaction->certificateInfos);
330
0
        transaction->certificateInfosSize = 0;
331
0
        transaction->certificateInfos = NULL;
332
0
    }
333
5.91k
}
334
335
0
void UA_GDSTransaction_delete(UA_GDSTransaction *transaction) {
336
0
    UA_GDSTransaction_clear(transaction);
337
0
    UA_free(transaction);
338
0
}
339
340
#ifndef UA_ENABLE_GDS_PUSHMANAGEMENT
341
/* Minimal stub: when GDS push management is not compiled in,
342
 * only the embedded transaction needs to be cleared. */
343
void
344
5.91k
UA_GDSManager_clear(UA_GDSManager *gdsManager) {
345
5.91k
    if(!gdsManager)
346
0
        return;
347
5.91k
    gdsManager->checkSessionCallbackId = 0;
348
5.91k
    UA_GDSTransaction_clear(&gdsManager->transaction);
349
5.91k
}
350
#endif
351
352
/*********************/
353
/* Server Components */
354
/*********************/
355
356
enum ZIP_CMP
357
14.4k
cmpServerComponent(const UA_UInt64 *a, const UA_UInt64 *b) {
358
14.4k
    if(*a == *b)
359
0
        return ZIP_CMP_EQ;
360
14.4k
    return (*a < *b) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
361
14.4k
}
362
363
void
364
addServerComponent(UA_Server *server, UA_ServerComponent *sc,
365
17.9k
                   UA_UInt64 *identifier) {
366
17.9k
    if(!sc)
367
0
        return;
368
369
17.9k
    sc->identifier = ++server->serverComponentIds;
370
17.9k
    ZIP_INSERT(UA_ServerComponentTree, &server->serverComponents, sc);
371
372
    /* Start the component if the server is started */
373
17.9k
    if(server->state == UA_LIFECYCLESTATE_STARTED && sc->start)
374
0
        sc->start(sc, server);
375
376
17.9k
    if(identifier)
377
0
        *identifier = sc->identifier;
378
17.9k
}
379
380
static void *
381
705
findServerComponent(void *context, UA_ServerComponent *sc) {
382
705
    UA_String *name = (UA_String*)context;
383
705
    return (UA_String_equal(&sc->name, name)) ? sc : NULL;
384
705
}
385
386
UA_ServerComponent *
387
492
getServerComponentByName(UA_Server *server, UA_String name) {
388
492
    return (UA_ServerComponent*)
389
492
        ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
390
492
                 findServerComponent, &name);
391
492
}
392
393
static void *
394
837
startServerComponent(void *server, UA_ServerComponent *sc) {
395
837
    sc->start(sc, (UA_Server*)server);
396
837
    return NULL;
397
837
}
398
399
static void *
400
837
stopServerComponent(void *_, UA_ServerComponent *sc) {
401
837
    sc->stop(sc);
402
837
    return NULL;
403
837
}
404
405
/* ZIP_ITER returns NULL only if all components are stopped */
406
static void *
407
1.11k
checkServerComponent(void *_, UA_ServerComponent *sc) {
408
1.11k
    return (sc->state == UA_LIFECYCLESTATE_STOPPED) ? NULL : (void*)0x01;
409
1.11k
}
410
411
/********************/
412
/* Server Lifecycle */
413
/********************/
414
415
/* The server needs to be stopped before it can be deleted */
416
UA_StatusCode
417
5.91k
UA_Server_delete(UA_Server *server) {
418
5.91k
    if(!server)
419
0
        return UA_STATUSCODE_BADINTERNALERROR;
420
421
5.91k
    if(server->state != UA_LIFECYCLESTATE_STOPPED) {
422
0
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
423
0
                     "The server must be fully stopped before it can be deleted");
424
0
        return UA_STATUSCODE_BADINTERNALERROR;
425
0
    }
426
427
5.91k
    lockServer(server);
428
429
5.91k
    session_list_entry *current, *temp;
430
5.91k
    LIST_FOREACH_SAFE(current, &server->sessions, pointers, temp) {
431
4.16k
        UA_Session_remove(server, &current->session, UA_SHUTDOWNREASON_CLOSE);
432
4.16k
    }
433
5.91k
    UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
434
435
5.91k
#ifdef UA_ENABLE_SUBSCRIPTIONS
436
    /* Remove subscriptions without a session */
437
5.91k
    UA_Subscription *sub, *sub_tmp;
438
5.91k
    LIST_FOREACH_SAFE(sub, &server->subscriptions, serverListEntry, sub_tmp) {
439
0
        UA_Subscription_delete(server, sub);
440
0
    }
441
442
#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
443
    UA_ConditionList_delete(server);
444
#endif
445
446
5.91k
#endif
447
448
5.91k
#if UA_MULTITHREADING >= 100
449
5.91k
    UA_AsyncManager_clear(&server->asyncManager, server);
450
5.91k
#endif
451
452
    /* Clean up the Admin Session */
453
5.91k
    UA_Session_clear(&server->adminSession, server);
454
5.91k
#ifdef UA_ENABLE_SUBSCRIPTIONS
455
5.91k
    server->adminSubscription = NULL;
456
5.91k
    UA_assert(server->monitoredItemsSize == 0);
457
5.91k
    UA_assert(server->subscriptionsSize == 0);
458
5.91k
#endif
459
460
    /* Remove all server components (all stopped by now) */
461
5.91k
    UA_ServerComponent *top;
462
23.1k
    while((top = ZIP_ROOT(&server->serverComponents))) {
463
17.2k
        UA_assert(top->state == UA_LIFECYCLESTATE_STOPPED);
464
17.2k
        top->clear(top);
465
17.2k
        ZIP_REMOVE(UA_ServerComponentTree, &server->serverComponents, top);
466
17.2k
        UA_free(top);
467
17.2k
    }
468
469
5.91k
    unlockServer(server); /* The timer has its own mutex */
470
471
    /* Clean up the config */
472
5.91k
    UA_ServerConfig_clear(&server->config);
473
474
5.91k
#if UA_MULTITHREADING >= 100
475
5.91k
    UA_LOCK_DESTROY(&server->serviceMutex);
476
5.91k
#endif
477
478
5.91k
    UA_GDSManager_clear(&server->gdsManager);
479
480
    /* Clean up the custom datatypes */
481
5.91k
    if(server->customTypes_internal != NULL) {
482
0
        for(size_t i = 0; i < server->customTypes_internalSize; i++) {
483
0
            UA_DataTypeArray *curr = &server->customTypes_internal[i];
484
0
            for(size_t j = 0; j < curr->typesSize; j++)
485
0
                UA_DataType_clear(&curr->types[j]);
486
0
            UA_free(curr->types);
487
0
        }
488
0
        UA_free(server->customTypes_internal);
489
0
    }
490
491
    /* Delete the server itself and return */
492
5.91k
    UA_free(server);
493
5.91k
    return UA_STATUSCODE_GOOD;
494
5.91k
}
495
496
/* Regular house-keeping tasks. Removing unused and timed-out channels and
497
 * sessions. */
498
static void
499
0
serverHouseKeeping(UA_Server *server, void *_) {
500
0
    lockServer(server);
501
0
    UA_EventLoop *el = server->config.eventLoop;
502
0
    cleanupSessions(server, el->dateTime_nowMonotonic(el));
503
0
    unlockServer(server);
504
0
}
505
506
/********************/
507
/* Server Lifecycle */
508
/********************/
509
510
static
511
UA_INLINE
512
16.4k
UA_Boolean UA_Server_NodestoreIsConfigured(UA_Server *server) {
513
16.4k
    return (server->config.nodestore && server->config.nodestore->getNode);
514
16.4k
}
515
516
static UA_Server *
517
5.91k
UA_Server_init(UA_Server *server) {
518
5.91k
    UA_StatusCode res = UA_STATUSCODE_GOOD;
519
5.91k
    UA_CHECK_FATAL(UA_Server_NodestoreIsConfigured(server), goto cleanup,
520
5.91k
                   server->config.logging, UA_LOGCATEGORY_SERVER,
521
5.91k
                   "No Nodestore configured in the server");
522
523
    /* Init start time to zero, the actual start time will be sampled in
524
     * UA_Server_run_startup() */
525
5.91k
    server->startTime = 0;
526
527
    /* Set a seed for non-cyptographic randomness */
528
5.91k
#ifndef UA_ENABLE_DETERMINISTIC_RNG
529
5.91k
    UA_random_seed((UA_UInt64)UA_DateTime_now());
530
5.91k
#endif
531
532
5.91k
    UA_LOCK_INIT(&server->serviceMutex);
533
5.91k
    lockServer(server);
534
535
    /* Initialize the adminSession */
536
5.91k
    UA_Session_init(&server->adminSession);
537
5.91k
    server->adminSession.sessionId.identifierType = UA_NODEIDTYPE_GUID;
538
5.91k
    server->adminSession.sessionId.identifier.guid.data1 = 1;
539
5.91k
    server->adminSession.validTill = UA_INT64_MAX;
540
5.91k
    server->adminSession.sessionName = UA_STRING_ALLOC("Administrator");
541
542
5.91k
#ifdef UA_ENABLE_SUBSCRIPTIONS
543
    /* Initialize the adminSubscription */
544
5.91k
    server->adminSubscription = UA_Subscription_new();
545
5.91k
    UA_CHECK_MEM(server->adminSubscription, goto cleanup);
546
5.91k
    UA_Session_attachSubscription(&server->adminSession, server->adminSubscription);
547
5.91k
#endif
548
549
    /* Create Namespaces 0 and 1
550
     * Ns1 will be filled later with the uri from the app description */
551
5.91k
    server->namespaces = (UA_String *)UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
552
5.91k
    UA_CHECK_MEM(server->namespaces, goto cleanup);
553
554
5.91k
    server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
555
5.91k
    server->namespaces[1] = UA_STRING_NULL;
556
5.91k
    server->namespacesSize = 2;
557
558
    /* Initialize Session Management */
559
5.91k
    LIST_INIT(&server->sessions);
560
5.91k
    server->sessionCount = 0;
561
562
    /* Initialize SecureChannel */
563
5.91k
    TAILQ_INIT(&server->channels);
564
    /* TODO: use an ID that is likely to be unique after a restart */
565
5.91k
    server->lastChannelId = STARTCHANNELID;
566
5.91k
    server->lastTokenId = STARTTOKENID;
567
568
5.91k
#if UA_MULTITHREADING >= 100
569
5.91k
    UA_AsyncManager_init(&server->asyncManager, server);
570
5.91k
#endif
571
572
    /* Initialize namespace 0 */
573
5.91k
#if defined(UA_GENERATED_NAMESPACE_ZERO) || defined(UA_NAMESPACE_ZERO_MINIMAL)
574
    /* Generate NS0 nodes at runtime or create the minimal NS0 */
575
5.91k
    res = initNS0(server);
576
#else
577
    /* NONE configuration: NS0 pre-loaded by external nodestore (e.g., ROM).
578
     * Only connect data sources for dynamic values like ServerTime, ServerStatus, etc. */
579
    res = initNS0_dataSources(server);
580
#endif
581
5.91k
    UA_CHECK_STATUS(res, goto cleanup);
582
583
#ifdef UA_ENABLE_GDS_PUSHMANAGEMENT
584
    res = initNS0PushManagement(server);
585
    UA_CHECK_STATUS(res, goto cleanup);
586
#endif
587
588
#ifdef UA_ENABLE_NODESET_INJECTOR
589
    res = UA_Server_injectNodesets(server);
590
    UA_CHECK_STATUS(res, goto cleanup);
591
#endif
592
593
    /* Initialize the binay protocol support */
594
5.91k
    addServerComponent(server, UA_BinaryProtocolManager_new(server), NULL);
595
596
    /* Initialized Discovery */
597
5.91k
#ifdef UA_ENABLE_DISCOVERY
598
5.91k
    addServerComponent(server, UA_DiscoveryManager_new(), NULL);
599
5.91k
#endif
600
601
    /* Initialize PubSub */
602
5.91k
#ifdef UA_ENABLE_PUBSUB
603
5.91k
    if(server->config.pubsubEnabled)
604
5.91k
        addServerComponent(server, UA_PubSubManager_new(server), NULL);
605
5.91k
#endif
606
607
    /* For all custom datatypes, check if they are represented in the
608
     * information model. If not, add them. */
609
5.91k
#ifdef UA_ENABLE_TYPEDESCRIPTION
610
5.91k
    for(const UA_DataTypeArray *custom = server->config.customDataTypes;
611
5.91k
        custom != NULL; custom = custom->next) {
612
0
        for(size_t i = 0; i < custom->typesSize; i++) {
613
0
            const UA_DataType *type = &custom->types[i];
614
0
            if(type->typeKind != UA_DATATYPEKIND_STRUCTURE &&
615
0
               type->typeKind != UA_DATATYPEKIND_OPTSTRUCT &&
616
0
               type->typeKind != UA_DATATYPEKIND_UNION)
617
0
                continue;
618
0
            const UA_Node *node =
619
0
                UA_NODESTORE_GET_SELECTIVE(server, &type->typeId, 0,
620
0
                                           UA_REFERENCETYPESET_NONE,
621
0
                                           UA_BROWSEDIRECTION_INVALID);
622
0
            if(node) {
623
0
                UA_NODESTORE_RELEASE(server, node);
624
0
                continue;
625
0
            }
626
627
0
            UA_QualifiedName dataTypeBrowseName =
628
0
                {type->typeId.namespaceIndex, UA_STRING_STATIC((char*)(uintptr_t)type->typeName)};
629
0
            UA_DataTypeAttributes dta = UA_DataTypeAttributes_default;
630
0
            dta.displayName.text = UA_STRING((char*)(uintptr_t)type->typeName);
631
0
            res = UA_Server_addDataTypeNode(server, type->typeId, UA_NS0ID(STRUCTURE),
632
0
                                            UA_NS0ID(HASSUBTYPE), dataTypeBrowseName,
633
0
                                            dta, NULL, NULL);
634
0
            if(res != UA_STATUSCODE_GOOD) {
635
0
                UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
636
0
                               "Could not add DataTypeNode for %s (%N)",
637
0
                               type->typeName, type->typeId);
638
0
            }
639
0
        }
640
0
    }
641
5.91k
#endif
642
643
5.91k
    unlockServer(server);
644
5.91k
    return server;
645
646
0
 cleanup:
647
0
    unlockServer(server);
648
0
    UA_Server_delete(server);
649
0
    return NULL;
650
5.91k
}
651
652
UA_Server *
653
16.4k
UA_Server_newWithConfig(UA_ServerConfig *config) {
654
16.4k
    UA_CHECK_MEM(config, return NULL);
655
656
16.4k
    UA_CHECK_LOG(config->eventLoop != NULL, return NULL, ERROR,
657
16.4k
                 config->logging, UA_LOGCATEGORY_SERVER, "No EventLoop configured");
658
659
16.4k
    UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server));
660
16.4k
    UA_CHECK_MEM(server, UA_ServerConfig_clear(config); return NULL);
661
662
16.4k
    server->config = *config;
663
664
    /* If not defined, set logging to what the server has */
665
16.4k
    if(!server->config.secureChannelPKI.logging)
666
0
        server->config.secureChannelPKI.logging = server->config.logging;
667
16.4k
    if(!server->config.sessionPKI.logging)
668
0
        server->config.sessionPKI.logging = server->config.logging;
669
670
    /* Reset the old config */
671
16.4k
    memset(config, 0, sizeof(UA_ServerConfig));
672
16.4k
    return UA_Server_init(server);
673
16.4k
}
674
675
/* Returns if the server should be shut down immediately */
676
static UA_Boolean
677
0
setServerShutdown(UA_Server *server) {
678
0
    if(server->endTime != 0)
679
0
        return false;
680
0
    if(server->config.shutdownDelay == 0)
681
0
        return true;
682
683
0
    UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
684
0
                   "Shutting down the server with a delay of %i ms",
685
0
                   (int)server->config.shutdownDelay);
686
687
0
    UA_EventLoop *el = server->config.eventLoop;
688
0
    server->endTime = el->dateTime_now(el) + (UA_DateTime)(server->config.shutdownDelay * UA_DATETIME_MSEC);
689
690
    /* Call the application notification callback */
691
0
    UA_ServerConfig *config = &server->config;
692
0
    if(config->lifecycleNotificationCallback)
693
0
        config->lifecycleNotificationCallback(server, UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_SHUTDOWN,
694
0
                                              UA_KEYVALUEMAP_NULL);
695
0
    if(config->globalNotificationCallback)
696
0
        config->globalNotificationCallback(server, UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_SHUTDOWN,
697
0
                                           UA_KEYVALUEMAP_NULL);
698
699
0
    return false;
700
0
}
701
702
/*******************/
703
/* Timed Callbacks */
704
/*******************/
705
706
UA_StatusCode
707
UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback,
708
0
                           void *data, UA_DateTime date, UA_UInt64 *callbackId) {
709
0
    lockServer(server);
710
0
    UA_EventLoop *el = server->config.eventLoop;
711
0
    UA_StatusCode retval = el->addTimer(el, (UA_Callback)callback, server, data,
712
0
                                        0.0, &date, UA_TIMERPOLICY_ONCE, callbackId);
713
0
    unlockServer(server);
714
0
    return retval;
715
0
}
716
717
UA_StatusCode
718
addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
719
2.76k
                    void *data, UA_Double interval_ms, UA_UInt64 *callbackId) {
720
2.76k
    UA_LOCK_ASSERT(&server->serviceMutex);
721
2.76k
    UA_EventLoop *el = server->config.eventLoop;
722
2.76k
    return el->addTimer(el, (UA_Callback)callback, server, data, interval_ms, NULL,
723
2.76k
                        UA_TIMERPOLICY_CURRENTTIME, callbackId);
724
2.76k
}
725
726
UA_StatusCode
727
UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
728
                              void *data, UA_Double interval_ms,
729
0
                              UA_UInt64 *callbackId) {
730
0
    lockServer(server);
731
0
    UA_StatusCode res = addRepeatedCallback(server, callback, data, interval_ms, callbackId);
732
0
    unlockServer(server);
733
0
    return res;
734
0
}
735
736
UA_StatusCode
737
changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
738
0
                               UA_Double interval_ms) {
739
0
    UA_LOCK_ASSERT(&server->serviceMutex);
740
0
    UA_EventLoop *el = server->config.eventLoop;
741
0
    return el->modifyTimer(el, callbackId, interval_ms, NULL, UA_TIMERPOLICY_CURRENTTIME);
742
0
}
743
744
UA_StatusCode
745
UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
746
0
                                         UA_Double interval_ms) {
747
0
    lockServer(server);
748
0
    UA_StatusCode retval = changeRepeatedCallbackInterval(server, callbackId, interval_ms);
749
0
    unlockServer(server);
750
0
    return retval;
751
0
}
752
753
void
754
2.76k
removeCallback(UA_Server *server, UA_UInt64 callbackId) {
755
2.76k
    UA_LOCK_ASSERT(&server->serviceMutex);
756
2.76k
    UA_EventLoop *el = server->config.eventLoop;
757
2.76k
    el->removeTimer(el, callbackId);
758
2.76k
}
759
760
void
761
0
UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId) {
762
0
    lockServer(server);
763
0
    removeCallback(server, callbackId);
764
0
    unlockServer(server);
765
0
}
766
767
/* When the trustlist changes, re-check the certificates of all
768
 * SecureChannels */
769
static void
770
0
secureChannel_delayedCloseTrustList(void *application, void *context) {
771
0
    UA_DelayedCallback *dc = (UA_DelayedCallback*)context;
772
0
    UA_Server *server = (UA_Server*)application;
773
774
0
    UA_CertificateGroup *certGroup = &server->config.secureChannelPKI;
775
0
    UA_SecureChannel *channel;
776
0
    TAILQ_FOREACH(channel, &server->channels, serverEntry) {
777
0
        if(channel->state != UA_SECURECHANNELSTATE_CLOSED &&
778
0
           channel->state != UA_SECURECHANNELSTATE_CLOSING)
779
0
            continue;
780
0
        if(channel->remoteCertificate.length == 0)
781
0
            continue; /* SecureChannels w/o security */
782
0
        UA_StatusCode res =
783
0
            validateCertificate(server, certGroup, channel, channel->sessions,
784
0
                                "RenewTrustList", NULL, channel->remoteCertificate);
785
0
        if(res != UA_STATUSCODE_GOOD)
786
0
            UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_CLOSE);
787
0
    }
788
0
    UA_free(dc);
789
0
}
790
791
static UA_CertificateGroup*
792
0
getCertificateGroup(UA_Server *server, const UA_NodeId certificateGroupId) {
793
0
    UA_NodeId defaultApplicationGroup =
794
0
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
795
0
    UA_NodeId defaultUserTokenGroup =
796
0
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
797
0
    if(UA_NodeId_equal(&certificateGroupId, &defaultApplicationGroup)) {
798
0
        return &server->config.secureChannelPKI;
799
0
    }
800
0
    if(UA_NodeId_equal(&certificateGroupId, &defaultUserTokenGroup)) {
801
0
        return &server->config.sessionPKI;
802
0
    }
803
0
    return NULL;
804
0
}
805
806
UA_StatusCode
807
UA_Server_addCertificates(UA_Server *server,
808
                          const UA_NodeId certificateGroupId,
809
                          UA_ByteString *certificates,
810
                          size_t certificatesSize,
811
                          UA_ByteString *crls,
812
                          size_t crlsSize,
813
                          const UA_Boolean isTrusted,
814
0
                          const UA_Boolean appendCertificates) {
815
0
    UA_CertificateGroup *certGroup = getCertificateGroup(server, certificateGroupId);
816
0
    if(!certGroup)
817
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
818
819
0
    UA_TrustListDataType trustList;
820
0
    UA_TrustListDataType_init(&trustList);
821
822
0
    if(isTrusted) {
823
0
        trustList.specifiedLists = UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES | UA_TRUSTLISTMASKS_TRUSTEDCRLS;
824
0
        trustList.trustedCertificates = certificates;
825
0
        trustList.trustedCertificatesSize = certificatesSize;
826
0
        trustList.trustedCrls = crls;
827
0
        trustList.trustedCrlsSize = crlsSize;
828
0
    } else {
829
0
        trustList.specifiedLists = UA_TRUSTLISTMASKS_ISSUERCERTIFICATES | UA_TRUSTLISTMASKS_ISSUERCRLS;
830
0
        trustList.issuerCertificates = certificates;
831
0
        trustList.issuerCertificatesSize = certificatesSize;
832
0
        trustList.issuerCrls = crls;
833
0
        trustList.issuerCrlsSize = crlsSize;
834
0
    }
835
836
    /* When adding certificate files to the TrustList,
837
     * it is not necessary to check the trust status of the existing SecureChannels. */
838
0
    if(appendCertificates)
839
0
        return certGroup->addToTrustList(certGroup, &trustList);
840
841
0
    UA_StatusCode retval = certGroup->setTrustList(certGroup, &trustList);
842
0
    if(retval != UA_STATUSCODE_GOOD)
843
0
        return retval;
844
845
0
    UA_DelayedCallback *dc = (UA_DelayedCallback*)UA_calloc(1, sizeof(UA_DelayedCallback));
846
0
    if(!dc)
847
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
848
849
0
    dc->callback = secureChannel_delayedCloseTrustList;
850
0
    dc->application = server;
851
0
    dc->context = dc;
852
853
0
    UA_EventLoop *el = server->config.eventLoop;
854
0
    el->addDelayedCallback(el, dc);
855
856
0
    return UA_STATUSCODE_GOOD;
857
0
}
858
859
UA_StatusCode
860
UA_Server_removeCertificates(UA_Server *server,
861
                             const UA_NodeId certificateGroupId,
862
                             UA_ByteString *certificates,
863
                             size_t certificatesSize,
864
0
                             const UA_Boolean isTrusted) {
865
0
    UA_CertificateGroup *certGroup = getCertificateGroup(server, certificateGroupId);
866
0
    if(!certGroup)
867
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
868
869
0
    UA_ByteString *crls = NULL;
870
0
    size_t crlsSize = 0;
871
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
872
0
    for(size_t i = 0; i < certificatesSize; i++) {
873
0
        retval = certGroup->getCertificateCrls(certGroup, &certificates[i], isTrusted, &crls, &crlsSize);
874
        /* Tolerate "Bad_NoMatch" to support removing CA certificates that do
875
         * not have an associated CRL. */
876
0
        if((retval != UA_STATUSCODE_GOOD) && (retval != UA_STATUSCODE_BADNOMATCH)) {
877
0
            UA_Array_delete(crls, crlsSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
878
0
            return retval;
879
0
        }
880
0
    }
881
882
0
    UA_TrustListDataType trustList;
883
0
    UA_TrustListDataType_init(&trustList);
884
0
    if(isTrusted) {
885
0
        trustList.specifiedLists = UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES | UA_TRUSTLISTMASKS_TRUSTEDCRLS;
886
0
        trustList.trustedCertificates = certificates;
887
0
        trustList.trustedCertificatesSize = certificatesSize;
888
0
        trustList.trustedCrls = crls;
889
0
        trustList.trustedCrlsSize = crlsSize;
890
0
    } else {
891
0
        trustList.specifiedLists = UA_TRUSTLISTMASKS_ISSUERCERTIFICATES | UA_TRUSTLISTMASKS_ISSUERCRLS;
892
0
        trustList.issuerCertificates = certificates;
893
0
        trustList.issuerCertificatesSize = certificatesSize;
894
0
        trustList.issuerCrls = crls;
895
0
        trustList.issuerCrlsSize = crlsSize;
896
0
    }
897
898
0
    retval = certGroup->removeFromTrustList(certGroup, &trustList);
899
0
    UA_Array_delete(crls, crlsSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
900
0
    if(retval != UA_STATUSCODE_GOOD)
901
0
        return retval;
902
903
0
    UA_DelayedCallback *dc = (UA_DelayedCallback*)UA_calloc(1, sizeof(UA_DelayedCallback));
904
0
    if(!dc)
905
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
906
907
0
    dc->callback = secureChannel_delayedCloseTrustList;
908
0
    dc->application = server;
909
0
    dc->context = dc;
910
911
0
    UA_EventLoop *el = server->config.eventLoop;
912
0
    el->addDelayedCallback(el, dc);
913
914
0
    return UA_STATUSCODE_GOOD;
915
0
}
916
917
typedef struct UpdateCertInfo {
918
    UA_Server *server;
919
    UA_NodeId certificateTypeId;
920
} UpdateCertInfo;
921
922
static void
923
0
secureChannel_delayedClose(void *application, void *context) {
924
0
    UA_DelayedCallback *dc = (UA_DelayedCallback*)context;
925
0
    UpdateCertInfo *info = (UpdateCertInfo*)application;
926
927
0
    UA_SecureChannel *channel;
928
0
    TAILQ_FOREACH(channel, &info->server->channels, serverEntry) {
929
0
        const UA_SecurityPolicy *policy = channel->securityPolicy;
930
0
        if(UA_NodeId_equal(&policy->certificateTypeId, &(info->certificateTypeId)))
931
0
            UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_CLOSE);
932
0
    }
933
0
    UA_NodeId_clear(&(info->certificateTypeId));
934
0
    UA_free(info);
935
0
    UA_free(dc);
936
0
}
937
938
UA_StatusCode
939
UA_Server_updateCertificate(UA_Server *server,
940
                            const UA_NodeId certificateGroupId,
941
                            const UA_NodeId certificateTypeId,
942
                            const UA_ByteString certificate,
943
0
                            const UA_ByteString *privateKey) {
944
0
    if(!server)
945
0
        return UA_STATUSCODE_BADINTERNALERROR;
946
947
0
    lockServer(server);
948
949
0
    if(server->gdsManager.transaction.state == UA_GDSTRANSACTIONSTATE_PENDING) {
950
0
        unlockServer(server);
951
0
        return UA_STATUSCODE_BADTRANSACTIONPENDING;
952
0
    }
953
954
0
    UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
955
0
    UA_NodeId certGroupId = certificateGroupId;
956
0
    if(UA_NodeId_isNull(&certGroupId)) {
957
        /* Use default value if argument is empty */
958
0
        certGroupId = defaultApplicationGroup;
959
0
    }
960
    /* The server currently only supports the DefaultApplicationGroup */
961
0
    if(!UA_NodeId_equal(&certGroupId, &defaultApplicationGroup)) {
962
0
        unlockServer(server);
963
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
964
0
    }
965
966
    /* The server currently only supports the following certificate type */
967
    /* UA_NodeId certTypRsaMin = UA_NODEID_NUMERIC(0, UA_NS0ID_RSAMINAPPLICATIONCERTIFICATETYPE); */
968
0
    UA_NodeId certTypRsaSha256 = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
969
0
    if(!UA_NodeId_equal(&certificateTypeId, &certTypRsaSha256)) {
970
0
        unlockServer(server);
971
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
972
0
    }
973
974
0
    UA_ByteString newPrivateKey = UA_BYTESTRING_NULL;
975
0
    if(privateKey) {
976
0
        if(UA_CertificateUtils_checkKeyPair(&certificate, privateKey) != UA_STATUSCODE_GOOD) {
977
0
            unlockServer(server);
978
0
            return UA_STATUSCODE_BADNOTSUPPORTED;
979
0
        }
980
0
        newPrivateKey = *privateKey;
981
0
    }
982
983
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
984
0
    for(size_t i = 0; i < server->config.endpointsSize; i++) {
985
0
        UA_EndpointDescription *ed = &server->config.endpoints[i];
986
0
        UA_SecurityPolicy *sp = getSecurityPolicyByUri(server,
987
0
                            &server->config.endpoints[i].securityPolicyUri);
988
0
        UA_CHECK_MEM(sp, unlockServer(server); return UA_STATUSCODE_BADINTERNALERROR);
989
990
0
        if(!UA_NodeId_equal(&sp->certificateTypeId, &certificateTypeId))
991
0
            continue;
992
993
0
        retval = sp->updateCertificate(sp, certificate, newPrivateKey);
994
0
        if(retval != UA_STATUSCODE_GOOD) {
995
0
            unlockServer(server);
996
0
            return retval;
997
0
        }
998
999
0
        UA_ByteString_clear(&ed->serverCertificate);
1000
0
        UA_ByteString_copy(&certificate, &ed->serverCertificate);
1001
0
    }
1002
1003
0
    UA_DelayedCallback *dc = (UA_DelayedCallback*)UA_calloc(1, sizeof(UA_DelayedCallback));
1004
0
    if(!dc) {
1005
0
        unlockServer(server);
1006
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1007
0
    }
1008
1009
0
    UpdateCertInfo *certInfo = (UpdateCertInfo*)UA_calloc(1, sizeof(UpdateCertInfo));
1010
0
    certInfo->server = server;
1011
0
    UA_NodeId_copy(&certificateTypeId, &(certInfo->certificateTypeId));
1012
1013
0
    dc->callback = secureChannel_delayedClose;
1014
0
    dc->application = certInfo;
1015
0
    dc->context = dc;
1016
1017
0
    UA_EventLoop *el = server->config.eventLoop;
1018
0
    el->addDelayedCallback(el, dc);
1019
1020
0
    unlockServer(server);
1021
0
    return UA_STATUSCODE_GOOD;
1022
0
}
1023
1024
UA_StatusCode
1025
UA_Server_createSigningRequest(UA_Server *server,
1026
                               const UA_NodeId certificateGroupId,
1027
                               const UA_NodeId certificateTypeId,
1028
                               const UA_String *subjectName,
1029
                               const UA_Boolean *regenerateKey,
1030
                               const UA_ByteString *nonce,
1031
0
                               UA_ByteString *csr) {
1032
0
    if(!server || !csr)
1033
0
        return UA_STATUSCODE_BADINTERNALERROR;
1034
1035
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1036
0
    UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
1037
0
    UA_NodeId certGroupId = certificateGroupId;
1038
0
    if(UA_NodeId_isNull(&certGroupId)) {
1039
        /* Use default value if argument is empty */
1040
0
        certGroupId = defaultApplicationGroup;
1041
0
    }
1042
    /* The server currently only supports the DefaultApplicationGroup */
1043
0
    if(!UA_NodeId_equal(&certGroupId, &defaultApplicationGroup))
1044
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1045
1046
    /* The server currently only supports RSA CertificateType */
1047
0
    UA_NodeId rsaShaCertificateType = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
1048
0
    UA_NodeId rsaMinCertificateType = UA_NODEID_NUMERIC(0,UA_NS0ID_RSAMINAPPLICATIONCERTIFICATETYPE);
1049
0
    if(!UA_NodeId_equal(&certificateTypeId, &rsaShaCertificateType) &&
1050
0
       !UA_NodeId_equal(&certificateTypeId, &rsaMinCertificateType))
1051
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1052
1053
0
    UA_CertificateGroup certGroup = server->config.secureChannelPKI;
1054
1055
0
    if(!UA_NodeId_equal(&certGroup.certificateGroupId, &defaultApplicationGroup))
1056
0
        return UA_STATUSCODE_BADINTERNALERROR;
1057
1058
0
    UA_ByteString *newPrivateKey = NULL;
1059
0
    if(regenerateKey && *regenerateKey == true)
1060
0
        newPrivateKey = UA_ByteString_new();
1061
1062
0
    for(size_t i = 0; i < server->config.endpointsSize; i++) {
1063
0
        UA_SecurityPolicy *sp =
1064
0
            getSecurityPolicyByUri(server, &server->config.endpoints[i].securityPolicyUri);
1065
0
        if(!sp) {
1066
0
            retval = UA_STATUSCODE_BADINTERNALERROR;
1067
0
            goto cleanup;
1068
0
        }
1069
1070
0
        if(sp->policyType == UA_SECURITYPOLICYTYPE_NONE)
1071
0
            continue;
1072
1073
0
        if(UA_NodeId_equal(&certificateTypeId, &sp->certificateTypeId) &&
1074
0
           UA_NodeId_equal(&certGroupId, &sp->certificateGroupId)) {
1075
0
            retval = sp->createSigningRequest(sp, subjectName, nonce,
1076
0
                                              &UA_KEYVALUEMAP_NULL, csr, newPrivateKey);
1077
0
            if(retval != UA_STATUSCODE_GOOD)
1078
0
                goto cleanup;
1079
0
        }
1080
0
    }
1081
1082
0
    UA_ByteString_clear(&server->gdsManager.transaction.localCsrCertificate);
1083
0
    UA_ByteString_copy(csr, &server->gdsManager.transaction.localCsrCertificate);
1084
1085
0
cleanup:
1086
0
    if(newPrivateKey)
1087
0
    {
1088
        /* wipe private key before freeing its memory */
1089
0
        UA_ByteString_memZero(newPrivateKey);
1090
0
        UA_ByteString_delete(newPrivateKey);
1091
0
    }
1092
1093
0
    return retval;
1094
0
}
1095
1096
/***************************/
1097
/* Server lookup functions */
1098
/***************************/
1099
1100
UA_SecurityPolicy *
1101
8.01k
getSecurityPolicyByUri(const UA_Server *server, const UA_String *securityPolicyUri) {
1102
8.01k
    for(size_t i = 0; i < server->config.securityPoliciesSize; i++) {
1103
8.01k
        UA_SecurityPolicy *sp = &server->config.securityPolicies[i];
1104
8.01k
        if(UA_String_equal(securityPolicyUri, &sp->policyUri))
1105
8.01k
            return sp;
1106
8.01k
    }
1107
0
    return NULL;
1108
8.01k
}
1109
1110
UA_SecurityPolicy *
1111
0
getSecurityPolicyByPostfix(const UA_Server *server, const UA_String uriPostfix) {
1112
0
    for(size_t i = 0; i < server->config.securityPoliciesSize; i++) {
1113
0
        UA_SecurityPolicy *sp = &server->config.securityPolicies[i];
1114
0
        UA_String spPostfix = securityPolicyUriPostfix(sp->policyUri);
1115
0
        if(UA_String_equal(&uriPostfix, &spPostfix))
1116
0
            return sp;
1117
0
    }
1118
0
    return NULL;
1119
0
}
1120
1121
/* The local ApplicationUri has to match the certificates of the
1122
 * SecurityPolicies */
1123
static void
1124
557
verifyServerApplicationUri(const UA_Server *server) {
1125
#if UA_LOGLEVEL <= 400
1126
    const UA_ServerConfig *sc = &server->config;
1127
    for(size_t i = 0; i < sc->securityPoliciesSize; i++) {
1128
        UA_SecurityPolicy *sp = &sc->securityPolicies[i];
1129
        if(sp->policyType == UA_SECURITYPOLICYTYPE_NONE &&
1130
           sp->localCertificate.length == 0)
1131
            continue;
1132
        UA_StatusCode retval =
1133
            UA_CertificateUtils_verifyApplicationUri(&sp->localCertificate,
1134
                                &sc->applicationDescription.applicationUri);
1135
        if(retval != UA_STATUSCODE_GOOD) {
1136
            UA_LOG_WARNING(sc->logging, UA_LOGCATEGORY_SERVER,
1137
                           "The ApplicationUri %S in the server's ApplicationDescription "
1138
                           "does not match the URI specified in the certificate "
1139
                           "for the SecurityPolicy %S",
1140
                           server->config.applicationDescription.applicationUri,
1141
                           sp->policyUri);
1142
        }
1143
    }
1144
#endif
1145
557
}
1146
1147
UA_ServerStatistics
1148
0
UA_Server_getStatistics(UA_Server *server) {
1149
0
    UA_ServerStatistics stat;
1150
0
    lockServer(server);
1151
0
    stat.scs = server->secureChannelStatistics;
1152
0
    UA_ServerDiagnosticsSummaryDataType *sds = &server->serverDiagnosticsSummary;
1153
0
    stat.ss.currentSessionCount = server->activeSessionCount;
1154
0
    stat.ss.cumulatedSessionCount = sds->cumulatedSessionCount;
1155
0
    stat.ss.securityRejectedSessionCount = sds->securityRejectedSessionCount;
1156
0
    stat.ss.rejectedSessionCount = sds->rejectedSessionCount;
1157
0
    stat.ss.sessionTimeoutCount = sds->sessionTimeoutCount;
1158
0
    stat.ss.sessionAbortCount = sds->sessionAbortCount;
1159
0
    unlockServer(server);
1160
0
    return stat;
1161
0
}
1162
1163
/********************/
1164
/* Main Server Loop */
1165
/********************/
1166
1167
785
#define UA_MAXTIMEOUT 500 /* Max timeout in ms between main-loop iterations */
1168
1169
void
1170
837
setServerLifecycleState(UA_Server *server, UA_LifecycleState state) {
1171
837
    UA_LOCK_ASSERT(&server->serviceMutex);
1172
1173
    /* Not state change, nothing to do */
1174
837
    if(server->state == state)
1175
0
        return;
1176
1177
837
    server->state = state; /* Apply the state change */
1178
1179
    /* Call the application notification callback */
1180
837
    UA_ServerConfig *config = &server->config;
1181
837
    if(config->globalNotificationCallback || config->lifecycleNotificationCallback) {
1182
0
        UA_ApplicationNotificationType nt = UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_STARTED;
1183
0
        switch(state) {
1184
0
        case UA_LIFECYCLESTATE_STOPPED: nt = UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_STOPPING; break;
1185
0
        case UA_LIFECYCLESTATE_STOPPING: nt = UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_STOPPING; break;
1186
0
        default: break;
1187
0
        }
1188
0
        if(config->lifecycleNotificationCallback)
1189
0
            config->lifecycleNotificationCallback(server, nt, UA_KEYVALUEMAP_NULL);
1190
0
        if(config->globalNotificationCallback)
1191
0
            config->globalNotificationCallback(server, nt, UA_KEYVALUEMAP_NULL);
1192
0
    }
1193
1194
    /* Call the (legacy) notification callback */
1195
837
    if(server->config.notifyLifecycleState)
1196
0
        server->config.notifyLifecycleState(server, state);
1197
837
}
1198
1199
UA_LifecycleState
1200
0
UA_Server_getLifecycleState(UA_Server *server) {
1201
0
    return server->state;
1202
0
}
1203
1204
/* Start: Spin up the workers and the network layer and sample the server's
1205
 *        start time.
1206
 * Iterate: Process repeated callbacks and events in the network layer. This
1207
 *          part can be driven from an external main-loop in an event-driven
1208
 *          single-threaded architecture.
1209
 * Stop: Stop workers, finish all callbacks, stop the network layer, clean up */
1210
1211
UA_StatusCode
1212
279
UA_Server_run_startup(UA_Server *server) {
1213
279
    if(server == NULL) {
1214
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1215
0
    }
1216
279
    UA_ServerConfig *config = &server->config;
1217
1218
279
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1219
    /* Prominently warn user that fuzzing build is enabled. This will tamper
1220
     * with authentication tokens and other important variables E.g. if fuzzing
1221
     * is enabled, and two clients are connected, subscriptions do not work
1222
     * properly, since the tokens will be overridden to allow easier fuzzing. */
1223
279
    UA_LOG_FATAL(server->config.logging, UA_LOGCATEGORY_SERVER,
1224
279
                 "Server was built with unsafe fuzzing mode. "
1225
279
                 "This should only be used for specific fuzzing builds.");
1226
279
#endif
1227
1228
279
    if(server->state != UA_LIFECYCLESTATE_STOPPED) {
1229
0
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
1230
0
                       "The server has already been started");
1231
0
        return UA_STATUSCODE_BADINTERNALERROR;
1232
0
    }
1233
1234
    /* Check if UserIdentityTokens are defined */
1235
279
    bool hasUserIdentityTokens = false;
1236
558
    for(size_t i = 0; i < config->endpointsSize; i++) {
1237
279
        if(config->endpoints[i].userIdentityTokensSize > 0) {
1238
0
            hasUserIdentityTokens = true;
1239
0
            break;
1240
0
        }
1241
279
    }
1242
279
    if(config->accessControl.userTokenPoliciesSize == 0 && hasUserIdentityTokens == false) {
1243
0
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
1244
0
                     "The server has no userIdentificationPolicies defined.");
1245
0
        return UA_STATUSCODE_BADINTERNALERROR;
1246
0
    }
1247
1248
    /* Start the EventLoop if not already started */
1249
279
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
1250
279
    UA_EventLoop *el = config->eventLoop;
1251
279
    UA_CHECK_MEM_ERROR(el, return UA_STATUSCODE_BADINTERNALERROR,
1252
279
                       config->logging, UA_LOGCATEGORY_SERVER,
1253
279
                       "An EventLoop must be configured");
1254
1255
279
    if(el->state != UA_EVENTLOOPSTATE_STARTED) {
1256
0
        retVal = el->start(el);
1257
0
        UA_CHECK_STATUS(retVal, return retVal); /* Errors are logged internally */
1258
0
    }
1259
1260
    /* Take the server lock */
1261
279
    lockServer(server);
1262
1263
    /* Does the ApplicationUri match the local certificates? */
1264
279
    verifyServerApplicationUri(server);
1265
1266
279
#if UA_MULTITHREADING >= 100
1267
    /* Add regulare callback for async operation processing */
1268
279
    UA_AsyncManager_start(&server->asyncManager, server);
1269
279
#endif
1270
1271
    /* Are there enough SecureChannels possible for the max number of sessions? */
1272
279
    if(config->maxSecureChannels != 0 &&
1273
279
       (config->maxSessions == 0 || config->maxSessions > config->maxSecureChannels)) {
1274
0
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
1275
0
                       "Maximum SecureChannels count not enough for the "
1276
0
                       "maximum Sessions count");
1277
0
    }
1278
1279
    /* Add a regular callback for housekeeping tasks. With a 1s interval. */
1280
279
    retVal = addRepeatedCallback(server, serverHouseKeeping,
1281
279
                                 NULL, 1000.0, &server->houseKeepingCallbackId);
1282
279
    UA_CHECK_STATUS_ERROR(retVal, unlockServer(server); return retVal,
1283
279
                          config->logging, UA_LOGCATEGORY_SERVER,
1284
279
                          "Could not create the server housekeeping task");
1285
1286
    /* Ensure that the uri for ns1 is set up from the app description */
1287
279
    UA_String_clear(&server->namespaces[1]);
1288
279
    setupNs1Uri(server);
1289
1290
    /* At least one endpoint has to be configured */
1291
279
    if(config->endpointsSize == 0) {
1292
0
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
1293
0
                       "There has to be at least one endpoint.");
1294
0
    }
1295
1296
    /* Update Endpoint description */
1297
558
    for(size_t i = 0; i < config->endpointsSize; ++i) {
1298
279
        UA_ApplicationDescription_clear(&config->endpoints[i].server);
1299
279
        UA_ApplicationDescription_copy(&config->applicationDescription,
1300
279
                                       &config->endpoints[i].server);
1301
279
    }
1302
1303
    /* Write ServerArray with same ApplicationUri value as NamespaceArray */
1304
279
    UA_Variant var;
1305
279
    UA_Variant_init(&var);
1306
279
    UA_Variant_setArray(&var, &config->applicationDescription.applicationUri,
1307
279
                        1, &UA_TYPES[UA_TYPES_STRING]);
1308
279
    UA_NodeId serverArray = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY);
1309
279
    writeValueAttribute(server, serverArray, &var);
1310
1311
    /* Sample the start time and set it to the Server object */
1312
279
    server->startTime = el->dateTime_now(el);
1313
279
    UA_Variant_init(&var);
1314
279
    UA_Variant_setScalar(&var, &server->startTime, &UA_TYPES[UA_TYPES_DATETIME]);
1315
279
    UA_NodeId startTime =
1316
279
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME);
1317
279
    writeValueAttribute(server, startTime, &var);
1318
1319
    /* Start all ServerComponents */
1320
279
    ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
1321
279
             startServerComponent, server);
1322
1323
    /* Check that the binary protocol support component have been started */
1324
279
    UA_ServerComponent *binaryProtocolManager =
1325
279
        getServerComponentByName(server, UA_STRING("binary"));
1326
279
    if(!binaryProtocolManager) {
1327
0
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
1328
0
                     "Binary protocol support component not found.");
1329
        /* Stop all server components that have already been started */
1330
0
        ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
1331
0
                 stopServerComponent, server);
1332
0
        unlockServer(server);
1333
0
        return UA_STATUSCODE_BADINTERNALERROR;
1334
0
    }
1335
279
    if(binaryProtocolManager->state != UA_LIFECYCLESTATE_STARTED) {
1336
0
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
1337
0
                       "The binary protocol support component could not been started.");
1338
        /* Stop all server components that have already been started */
1339
0
        ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
1340
0
                 stopServerComponent, NULL);
1341
0
        unlockServer(server);
1342
0
        return UA_STATUSCODE_BADINTERNALERROR;
1343
0
    }
1344
1345
    /* Set the server to STARTED. From here on, only use
1346
     * UA_Server_run_shutdown(server) to stop the server. */
1347
279
    setServerLifecycleState(server, UA_LIFECYCLESTATE_STARTED);
1348
1349
279
    unlockServer(server);
1350
279
    return UA_STATUSCODE_GOOD;
1351
279
}
1352
1353
UA_UInt16
1354
2.01k
UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal) {
1355
    /* Make sure an EventLoop is configured */
1356
2.01k
    UA_EventLoop *el = server->config.eventLoop;
1357
2.01k
    if(!el)
1358
0
        return 0;
1359
1360
    /* Process timed and network events in the EventLoop */
1361
2.01k
    UA_UInt32 timeout = (waitInternal) ? UA_MAXTIMEOUT : 0;
1362
2.01k
    el->run(el, timeout);
1363
1364
    /* Return the time until the next scheduled callback */
1365
2.01k
    UA_DateTime now = el->dateTime_nowMonotonic(el);
1366
2.01k
    UA_DateTime nextTimeout = (el->nextTimer(el) - now) / UA_DATETIME_MSEC;
1367
2.01k
    if(nextTimeout < 0)
1368
0
        nextTimeout = 0;
1369
2.01k
    if(nextTimeout > UA_UINT16_MAX)
1370
557
        nextTimeout = UA_UINT16_MAX;
1371
2.01k
    return (UA_UInt16)nextTimeout;
1372
2.01k
}
1373
1374
static UA_Boolean
1375
0
testShutdownCondition(UA_Server *server) {
1376
    /* Was there a wait time until the shutdown configured? */
1377
0
    if(server->endTime == 0)
1378
0
        return false;
1379
0
    UA_EventLoop *el = server->config.eventLoop;
1380
0
    return (el->dateTime_now(el) > server->endTime);
1381
0
}
1382
1383
static UA_Boolean
1384
558
testStoppedCondition(UA_Server *server) {
1385
    /* Check if there are remaining server components that did not fully stop */
1386
558
    if(ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
1387
558
                checkServerComponent, NULL) != NULL)
1388
279
        return false;
1389
279
    return true;
1390
558
}
1391
1392
UA_StatusCode
1393
557
UA_Server_run_shutdown(UA_Server *server) {
1394
557
    if(server == NULL)
1395
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1396
1397
557
    lockServer(server);
1398
1399
557
    if(server->state != UA_LIFECYCLESTATE_STARTED) {
1400
0
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
1401
0
                     "The server is not started, cannot be shut down");
1402
0
        unlockServer(server);
1403
0
        return UA_STATUSCODE_BADINTERNALERROR;
1404
0
    }
1405
1406
    /* Set to stopping and notify the application */
1407
557
    setServerLifecycleState(server, UA_LIFECYCLESTATE_STOPPING);
1408
1409
557
#if UA_MULTITHREADING >= 100
1410
    /* Stop regular callback for async operation processing */
1411
557
    UA_AsyncManager_stop(&server->asyncManager, server);
1412
557
#endif
1413
1414
    /* Stop the regular housekeeping tasks */
1415
557
    if(server->houseKeepingCallbackId != 0) {
1416
557
        removeCallback(server, server->houseKeepingCallbackId);
1417
557
        server->houseKeepingCallbackId = 0;
1418
557
    }
1419
1420
    /* Stop all ServerComponents */
1421
557
    ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
1422
557
             stopServerComponent, NULL);
1423
1424
    /* Are we already stopped? */
1425
557
    if(testStoppedCondition(server)) {
1426
0
        setServerLifecycleState(server, UA_LIFECYCLESTATE_STOPPED);
1427
0
    }
1428
1429
    /* Only stop the EventLoop if it is coupled to the server lifecycle  */
1430
557
    if(server->config.externalEventLoop) {
1431
0
        unlockServer(server);
1432
0
        return UA_STATUSCODE_GOOD;
1433
0
    }
1434
1435
    /* Unlock and do one "normal" iteration. This allows threads waiting for the
1436
     * server lock to proceed before the server lock is destroyed. */
1437
557
    unlockServer(server);
1438
557
    UA_Server_run_iterate(server, true);
1439
557
    lockServer(server);
1440
1441
    /* Iterate the EventLoop until the server is stopped */
1442
557
    UA_StatusCode res = UA_STATUSCODE_GOOD;
1443
557
    UA_EventLoop *el = server->config.eventLoop;
1444
557
    while(!testStoppedCondition(server) &&
1445
0
          res == UA_STATUSCODE_GOOD) {
1446
0
        res = el->run(el, 100);
1447
0
    }
1448
1449
    /* Stop the EventLoop. Iterate until stopped. */
1450
557
    el->stop(el);
1451
557
    while(el->state != UA_EVENTLOOPSTATE_STOPPED &&
1452
0
          el->state != UA_EVENTLOOPSTATE_FRESH &&
1453
0
          res == UA_STATUSCODE_GOOD) {
1454
0
        res = el->run(el, 100);
1455
0
    }
1456
1457
    /* Set server lifecycle state to stopped if not already the case */
1458
557
    setServerLifecycleState(server, UA_LIFECYCLESTATE_STOPPED);
1459
1460
557
    unlockServer(server);
1461
557
    return res;
1462
557
}
1463
1464
UA_StatusCode
1465
0
UA_Server_run(UA_Server *server, const volatile UA_Boolean *running) {
1466
0
    UA_StatusCode retval = UA_Server_run_startup(server);
1467
0
    UA_CHECK_STATUS(retval, return retval);
1468
1469
0
    while(!testShutdownCondition(server)) {
1470
0
        UA_Server_run_iterate(server, true);
1471
0
        if(!*running) {
1472
0
            if(setServerShutdown(server))
1473
0
                break;
1474
0
        }
1475
0
    }
1476
0
    return UA_Server_run_shutdown(server);
1477
0
}
1478
1479
37.0M
void lockServer(UA_Server *server) {
1480
37.0M
    if(UA_LIKELY(server->config.eventLoop && server->config.eventLoop->lock))
1481
37.0M
        server->config.eventLoop->lock(server->config.eventLoop);
1482
37.0M
    UA_LOCK(&server->serviceMutex);
1483
37.0M
}
1484
1485
37.0M
void unlockServer(UA_Server *server) {
1486
37.0M
    if(UA_LIKELY(server->config.eventLoop && server->config.eventLoop->unlock))
1487
37.0M
        server->config.eventLoop->unlock(server->config.eventLoop);
1488
37.0M
    UA_UNLOCK(&server->serviceMutex);
1489
37.0M
}