Coverage Report

Created: 2026-05-30 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/src/server/ua_discovery.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, 2019 (c) Sten GrĂ¼ner
8
 *    Copyright 2015 (c) Chris Iatrou
9
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
10
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
11
 *    Copyright 2017 (c) Julian Grothoff
12
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
13
 *    Copyright 2017 (c) HMS Industrial Networks AB (Author: Jonas Green)
14
 */
15
16
#include <open62541/client.h>
17
#include <open62541/client_highlevel_async.h>
18
#include "ua_discovery.h"
19
#include "ua_server_internal.h"
20
21
#ifdef UA_ENABLE_DISCOVERY
22
23
void
24
UA_DiscoveryManager_setState(UA_DiscoveryManager *dm,
25
1.08k
                             UA_LifecycleState state) {
26
    /* Check if open connections remain */
27
1.08k
    if(state == UA_LIFECYCLESTATE_STOPPING ||
28
813
       state == UA_LIFECYCLESTATE_STOPPED) {
29
813
        state = UA_LIFECYCLESTATE_STOPPED;
30
813
#ifdef UA_ENABLE_DISCOVERY_MULTICAST_MDNSD 
31
813
        if(UA_DiscoveryManager_getMdnsConnectionCount() > 0)
32
542
            state = UA_LIFECYCLESTATE_STOPPING;
33
813
#endif
34
35
4.06k
        for(size_t i = 0; i < UA_MAXREGISTERREQUESTS; i++) {
36
3.25k
            if(dm->registerRequests[i].client != NULL)
37
0
                state = UA_LIFECYCLESTATE_STOPPING;
38
3.25k
        }
39
813
    }
40
41
    /* No change */
42
1.08k
    if(state == dm->sc.state)
43
542
        return;
44
45
    /* Set the new state and notify */
46
542
    dm->sc.state = state;
47
542
    if(dm->sc.notifyState)
48
0
        dm->sc.notifyState(&dm->sc, state);
49
542
}
50
51
static UA_StatusCode
52
3.30k
UA_DiscoveryManager_clear(struct UA_ServerComponent *sc) {
53
3.30k
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)sc;
54
55
3.30k
    if(sc->state != UA_LIFECYCLESTATE_STOPPED) {
56
0
        UA_LOG_ERROR(sc->server->config.logging, UA_LOGCATEGORY_SERVER,
57
0
                     "Cannot delete the DiscoveryManager because "
58
0
                     "it is not stopped");
59
0
        return UA_STATUSCODE_BADINTERNALERROR;
60
0
    }
61
62
3.30k
    registeredServer *rs, *rs_tmp;
63
3.30k
    LIST_FOREACH_SAFE(rs, &dm->registeredServers, pointers, rs_tmp) {
64
0
        LIST_REMOVE(rs, pointers);
65
0
        UA_RegisteredServer_clear(&rs->registeredServer);
66
0
        UA_free(rs);
67
0
    }
68
69
3.30k
# ifdef UA_ENABLE_DISCOVERY_MULTICAST
70
3.30k
    UA_DiscoveryManager_clearMdns(dm);
71
3.30k
# endif /* UA_ENABLE_DISCOVERY_MULTICAST */
72
73
3.30k
    return UA_STATUSCODE_GOOD;
74
3.30k
}
75
76
/* Cleanup server registration: If the semaphore file path is set, then it just
77
 * checks the existence of the file. When it is deleted, the registration is
78
 * removed. If there is no semaphore file, then the registration will be removed
79
 * if it is older than 60 minutes. */
80
static void
81
0
UA_DiscoveryManager_cleanupTimedOut(UA_Server *server, void *data) {
82
0
    UA_EventLoop *el = server->config.eventLoop;
83
0
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)data;
84
85
    /* TimedOut gives the last DateTime at which we must have seen the
86
     * registered server. Otherwise it is timed out. */
87
0
    UA_DateTime timedOut = el->dateTime_nowMonotonic(el);
88
0
    if(server->config.discoveryCleanupTimeout)
89
0
        timedOut -= server->config.discoveryCleanupTimeout * UA_DATETIME_SEC;
90
91
0
    registeredServer *current, *temp;
92
0
    LIST_FOREACH_SAFE(current, &dm->registeredServers, pointers, temp) {
93
0
        UA_Boolean semaphoreDeleted = false;
94
95
0
#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE
96
0
        if(current->registeredServer.semaphoreFilePath.length) {
97
0
            size_t fpSize = current->registeredServer.semaphoreFilePath.length+1;
98
0
            char* filePath = (char *)UA_malloc(fpSize);
99
0
            if(filePath) {
100
0
                memcpy(filePath, current->registeredServer.semaphoreFilePath.data,
101
0
                       current->registeredServer.semaphoreFilePath.length );
102
0
                filePath[current->registeredServer.semaphoreFilePath.length] = '\0';
103
0
                semaphoreDeleted = UA_fileExists(filePath) == false;
104
0
                UA_free(filePath);
105
0
            } else {
106
0
                UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
107
0
                             "Cannot check registration semaphore. Out of memory");
108
0
            }
109
0
        }
110
0
#endif
111
112
0
        if(semaphoreDeleted ||
113
0
           (server->config.discoveryCleanupTimeout &&
114
0
            current->lastSeen < timedOut)) {
115
0
            if(semaphoreDeleted) {
116
0
                UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
117
0
                            "Registration of server with URI %S is removed because "
118
0
                            "the semaphore file '%S' was deleted",
119
0
                            current->registeredServer.serverUri,
120
0
                            current->registeredServer.semaphoreFilePath);
121
0
            } else {
122
                // cppcheck-suppress unreadVariable
123
0
                UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
124
0
                            "Registration of server with URI %S has timed out "
125
0
                            "and is removed", current->registeredServer.serverUri);
126
0
            }
127
0
            LIST_REMOVE(current, pointers);
128
0
            UA_RegisteredServer_clear(&current->registeredServer);
129
0
            UA_free(current);
130
0
            dm->registeredServersSize--;
131
0
        }
132
0
    }
133
0
}
134
135
static void
136
0
UA_DiscoveryManager_cyclicTimer(UA_Server *server, void *data) {
137
0
    UA_DiscoveryManager_cleanupTimedOut(server, data);
138
0
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
139
0
    UA_DiscoveryManager_mdnsCyclicTimer(server, data);
140
0
#endif
141
0
}
142
143
static UA_StatusCode
144
UA_DiscoveryManager_start(struct UA_ServerComponent *sc,
145
271
                          UA_Server *server) {
146
271
    if(sc->state != UA_LIFECYCLESTATE_STOPPED)
147
0
        return UA_STATUSCODE_BADINTERNALERROR;
148
149
271
    sc->server = server; /* Set the backpointer */
150
151
271
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)sc;
152
153
271
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
154
271
    UA_DiscoveryManager_resetServerOnNetworkRecordCounter(dm);
155
271
#endif /* UA_ENABLE_DISCOVERY_MULTICAST */
156
157
271
    UA_StatusCode res =
158
271
        addRepeatedCallback(server, UA_DiscoveryManager_cyclicTimer,
159
271
                            dm, 1000.0, &dm->discoveryCallbackId);
160
271
    if(res != UA_STATUSCODE_GOOD)
161
0
        return res;
162
163
271
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
164
271
    if(server->config.mdnsEnabled)
165
271
        UA_DiscoveryManager_startMulticast(dm);
166
271
#endif
167
168
271
    UA_DiscoveryManager_setState(dm, UA_LIFECYCLESTATE_STARTED);
169
271
    return UA_STATUSCODE_GOOD;
170
271
}
171
172
static void
173
536
UA_DiscoveryManager_stop(struct UA_ServerComponent *sc) {
174
536
    if(sc->state != UA_LIFECYCLESTATE_STARTED)
175
0
        return;
176
177
536
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)sc;
178
179
    /* Set STOPPING early so that CLOSING callbacks (fired by stopMulticast
180
     * below) do not trigger UA_DiscoveryManager_startMulticast and re-open
181
     * connections that would prevent the DM from reaching STOPPED. */
182
536
    sc->state = UA_LIFECYCLESTATE_STOPPING;
183
184
536
    removeCallback(dm->sc.server, dm->discoveryCallbackId);
185
186
    /* Cancel all outstanding register requests */
187
2.68k
    for(size_t i = 0; i < UA_MAXREGISTERREQUESTS; i++) {
188
2.14k
        if(dm->registerRequests[i].client == NULL)
189
2.14k
            continue;
190
0
        UA_Client_disconnectSecureChannelAsync(dm->registerRequests[i].client);
191
0
    }
192
193
536
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
194
536
    if(sc->server->config.mdnsEnabled)
195
536
        UA_DiscoveryManager_stopMulticast(dm);
196
536
#endif
197
198
536
    UA_DiscoveryManager_setState(dm, UA_LIFECYCLESTATE_STOPPED);
199
536
}
200
201
UA_ServerComponent *
202
7.29k
UA_DiscoveryManager_new(void) {
203
7.29k
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
204
7.29k
        UA_calloc(1, sizeof(UA_DiscoveryManager));
205
7.29k
    if(!dm)
206
0
        return NULL;
207
208
7.29k
    dm->sc.name = UA_STRING("discovery");
209
7.29k
    dm->sc.start = UA_DiscoveryManager_start;
210
7.29k
    dm->sc.stop = UA_DiscoveryManager_stop;
211
7.29k
    dm->sc.clear = UA_DiscoveryManager_clear;
212
7.29k
    return &dm->sc;
213
7.29k
}
214
215
/********************************/
216
/* Register at Discovery Server */
217
/********************************/
218
219
static void
220
0
asyncRegisterRequest_clear(void *_, void *context) {
221
0
    asyncRegisterRequest *ar = (asyncRegisterRequest*)context;
222
0
    UA_DiscoveryManager *dm = ar->dm;
223
224
0
    UA_String_clear(&ar->semaphoreFilePath);
225
0
    if(ar->client)
226
0
        UA_Client_delete(ar->client);
227
0
    memset(ar, 0, sizeof(asyncRegisterRequest));
228
229
    /* The Discovery manager is fully stopped? */
230
0
    UA_DiscoveryManager_setState(dm, dm->sc.state);
231
0
}
232
233
static void
234
0
asyncRegisterRequest_clearAsync(asyncRegisterRequest *ar) {
235
0
    UA_Server *server = ar->server;
236
0
    UA_ServerConfig *sc = &server->config;
237
0
    UA_EventLoop *el = sc->eventLoop;
238
239
0
    ar->cleanupCallback.callback = asyncRegisterRequest_clear;
240
0
    ar->cleanupCallback.application = server;
241
0
    ar->cleanupCallback.context = ar;
242
0
    el->addDelayedCallback(el, &ar->cleanupCallback);
243
0
}
244
245
static void
246
setupRegisterRequest(asyncRegisterRequest *ar, UA_RequestHeader *rh,
247
0
                     UA_RegisteredServer *rs) {
248
0
    UA_ServerConfig *sc = &ar->dm->sc.server->config;
249
250
0
    rh->timeoutHint = 10000;
251
252
0
    rs->isOnline = !ar->unregister;
253
0
    rs->serverUri = sc->applicationDescription.applicationUri;
254
0
    rs->productUri = sc->applicationDescription.productUri;
255
0
    rs->serverType = sc->applicationDescription.applicationType;
256
0
    rs->gatewayServerUri = sc->applicationDescription.gatewayServerUri;
257
0
    rs->semaphoreFilePath = ar->semaphoreFilePath;
258
259
0
    rs->serverNames = &sc->applicationDescription.applicationName;
260
0
    rs->serverNamesSize = 1;
261
262
    /* Mirror the discovery URLs from the server config (includes hostnames from
263
     * the network layers) */
264
0
    rs->discoveryUrls = sc->applicationDescription.discoveryUrls;
265
0
    rs->discoveryUrlsSize = sc->applicationDescription.discoveryUrlsSize;
266
0
}
267
268
static void
269
registerAsyncResponse(UA_Client *client, void *userdata,
270
0
                      UA_UInt32 requestId, void *resp) {
271
0
    asyncRegisterRequest *ar = (asyncRegisterRequest*)userdata;
272
0
    const UA_ServerConfig *sc = &ar->dm->sc.server->config;
273
0
    UA_Response *response = (UA_Response*)resp;
274
0
    const char *regtype = (ar->register2) ? "RegisterServer2" : "RegisterServer";
275
276
    /* Success registering? */
277
0
    if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD) {
278
0
        UA_LOG_INFO(sc->logging, UA_LOGCATEGORY_SERVER, "%s succeeded", regtype);
279
0
        goto done;
280
0
    }
281
282
0
    UA_LOG_WARNING(sc->logging, UA_LOGCATEGORY_SERVER,
283
0
                   "%s failed with statuscode %s", regtype,
284
0
                   UA_StatusCode_name(response->responseHeader.serviceResult));
285
286
    /* RegisterServer already failed. Do not retry indefinitely. */
287
0
    if(!ar->register2)
288
0
        goto done;
289
290
    /* Try RegisterServer next */
291
0
    ar->register2 = false;
292
293
    /* Try RegisterServer immediately if we can.
294
     * Otherwise wait for the next state callback. */
295
0
    UA_SecureChannelState ss;
296
0
    UA_Client_getState(client, &ss, NULL, NULL);
297
0
    if(!ar->shutdown && ss == UA_SECURECHANNELSTATE_OPEN) {
298
0
        UA_RegisterServerRequest request;
299
0
        UA_RegisterServerRequest_init(&request);
300
0
        setupRegisterRequest(ar, &request.requestHeader, &request.server);
301
0
        UA_StatusCode res =
302
0
            __UA_Client_AsyncService(client, &request,
303
0
                                     &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST],
304
0
                                     registerAsyncResponse,
305
0
                                     &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE], ar, NULL);
306
0
        if(res != UA_STATUSCODE_GOOD) {
307
0
            UA_LOG_ERROR((const UA_Logger *)&sc->logging, UA_LOGCATEGORY_CLIENT,
308
0
                         "RegisterServer failed with statuscode %s",
309
0
                         UA_StatusCode_name(res));
310
0
            goto done;
311
0
        }
312
0
    }
313
314
0
    return;
315
316
0
 done:
317
    /* Close the client connection, will be cleaned up in the client state
318
     * callback when closing is complete */
319
0
    ar->shutdown = true;
320
0
    UA_Client_disconnectSecureChannelAsync(ar->client);
321
0
}
322
323
static void
324
discoveryClientStateCallback(UA_Client *client,
325
                             UA_SecureChannelState channelState,
326
                             UA_SessionState sessionState,
327
0
                             UA_StatusCode connectStatus) {
328
0
    asyncRegisterRequest *ar = (asyncRegisterRequest*)
329
0
        UA_Client_getContext(client);
330
0
    UA_ServerConfig *sc = &ar->dm->sc.server->config;
331
332
    /* Connection failed */
333
0
    if(connectStatus != UA_STATUSCODE_GOOD) {
334
0
        if(connectStatus != UA_STATUSCODE_BADCONNECTIONCLOSED) {
335
0
            UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_SERVER,
336
0
                         "Could not connect to the Discovery server with error %s",
337
0
                         UA_StatusCode_name(connectStatus));
338
0
        }
339
340
        /* Connection fully closed */
341
0
        if(channelState == UA_SECURECHANNELSTATE_CLOSED) {
342
0
            if(!ar->connectSuccess || ar->shutdown) {
343
0
                asyncRegisterRequest_clearAsync(ar); /* Clean up */
344
0
            } else {
345
0
                ar->connectSuccess = false;
346
0
                UA_Client_connectAsync(client, NULL);   /* Reconnect */
347
0
            }
348
0
        }
349
0
        return;
350
0
    }
351
352
    /* Wait until the SecureChannel is open */
353
0
    if(channelState != UA_SECURECHANNELSTATE_OPEN)
354
0
        return;
355
356
    /* We have at least succeeded to connect */
357
0
    ar->connectSuccess = true;
358
359
    /* Is this the encrypted SecureChannel already? (We might have to wait for
360
     * the second connection after the FindServers handshake */
361
0
    UA_MessageSecurityMode msm = UA_MESSAGESECURITYMODE_INVALID;
362
0
    UA_Client_getConnectionAttribute_scalar(client, UA_QUALIFIEDNAME(0, "securityMode"),
363
0
                                            &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE],
364
0
                                            &msm);
365
0
#ifdef UA_ENABLE_ENCRYPTION
366
0
    UA_ClientConfig *cc = UA_Client_getConfig(client);
367
0
    if(cc->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT &&
368
0
       msm != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
369
0
        return;
370
0
#endif
371
372
0
    const UA_DataType *reqType;
373
0
    const UA_DataType *respType;
374
0
    UA_RegisterServerRequest reg1;
375
0
    UA_RegisterServer2Request reg2;
376
0
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
377
0
    UA_ExtensionObject mdnsConfig;
378
0
#endif
379
0
    void *request;
380
381
    /* Prepare the request. This does not allocate memory */
382
0
    if(ar->register2) {
383
0
        UA_RegisterServer2Request_init(&reg2);
384
0
        setupRegisterRequest(ar, &reg2.requestHeader, &reg2.server);
385
0
        reqType = &UA_TYPES[UA_TYPES_REGISTERSERVER2REQUEST];
386
0
        respType = &UA_TYPES[UA_TYPES_REGISTERSERVER2RESPONSE];
387
0
        request = &reg2;
388
389
0
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
390
        /* Set the configuration that is only available for
391
         * UA_RegisterServer2Request */
392
0
        UA_ExtensionObject_setValueNoDelete(&mdnsConfig, &sc->mdnsConfig,
393
0
                                            &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION]);
394
0
        reg2.discoveryConfigurationSize = 1;
395
0
        reg2.discoveryConfiguration = &mdnsConfig;
396
0
#endif
397
0
    } else {
398
0
        UA_RegisterServerRequest_init(&reg1);
399
0
        setupRegisterRequest(ar, &reg1.requestHeader, &reg1.server);
400
0
        reqType = &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST];
401
0
        respType = &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE];
402
0
        request = &reg1;
403
0
    }
404
405
    /* Try to call RegisterServer2 */
406
0
    UA_StatusCode res =
407
0
        __UA_Client_AsyncService(client, request, reqType, registerAsyncResponse,
408
0
                                 respType, ar, NULL);
409
0
    if(res != UA_STATUSCODE_GOOD) {
410
        /* Close the client connection, will be cleaned up in the client state
411
         * callback when closing is complete */
412
0
        UA_Client_disconnectSecureChannelAsync(ar->client);
413
0
        UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_CLIENT,
414
0
                     "RegisterServer2 failed with statuscode %s",
415
0
                     UA_StatusCode_name(res));
416
0
    }
417
0
}
418
419
static UA_StatusCode
420
UA_Server_register(UA_Server *server, UA_ClientConfig *cc, UA_Boolean unregister,
421
                   const UA_String discoveryServerUrl,
422
0
                   const UA_String semaphoreFilePath) {
423
    /* Get the discovery manager */
424
0
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
425
0
        getServerComponentByName(server, UA_STRING("discovery"));
426
0
    if(!dm) {
427
0
        UA_ClientConfig_clear(cc);
428
0
        return UA_STATUSCODE_BADINTERNALERROR;
429
0
    }
430
431
    /* Check that the discovery manager is running */
432
0
    UA_ServerConfig *sc = &server->config;
433
0
    if(dm->sc.state != UA_LIFECYCLESTATE_STARTED) {
434
0
        UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_SERVER,
435
0
                     "The server must be started for registering");
436
0
        UA_ClientConfig_clear(cc);
437
0
        return UA_STATUSCODE_BADINTERNALERROR;
438
0
    }
439
440
    /* Find a free slot for storing the async request information */
441
0
    asyncRegisterRequest *ar = NULL;
442
0
    for(size_t i = 0; i < UA_MAXREGISTERREQUESTS; i++) {
443
0
        if(dm->registerRequests[i].client == NULL) {
444
0
            ar = &dm->registerRequests[i];
445
0
            break;
446
0
        }
447
0
    }
448
0
    if(!ar) {
449
0
        UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_SERVER,
450
0
                     "Too many outstanding register requests. Cannot proceed.");
451
0
        UA_ClientConfig_clear(cc);
452
0
        return UA_STATUSCODE_BADINTERNALERROR;
453
0
    }
454
455
    /* Use the EventLoop from the server for the client */
456
0
    if(cc->eventLoop && !cc->externalEventLoop)
457
0
        cc->eventLoop->free(cc->eventLoop);
458
0
    cc->eventLoop = sc->eventLoop;
459
0
    cc->externalEventLoop = true;
460
461
    /* Set the state callback method and context */
462
0
    cc->stateCallback = discoveryClientStateCallback;
463
0
    cc->clientContext = ar;
464
465
    /* If it's not already set, use encryption by default */
466
0
    if(cc->securityMode == UA_MESSAGESECURITYMODE_INVALID) {
467
0
#ifdef UA_ENABLE_ENCRYPTION
468
0
        cc->securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
469
#else
470
        cc->securityMode = UA_MESSAGESECURITYMODE_NONE;
471
#endif
472
0
    }
473
474
    /* Open only a SecureChannel */
475
0
    cc->noSession = true;
476
477
    /* Move the endpoint url */
478
0
    UA_String_clear(&cc->endpointUrl);
479
0
    UA_String_copy(&discoveryServerUrl, &cc->endpointUrl);
480
481
    /* Instantiate the client */
482
0
    ar->client = UA_Client_newWithConfig(cc);
483
0
    if(!ar->client) {
484
0
        UA_ClientConfig_clear(cc);
485
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
486
0
    }
487
488
    /* Zero out the supplied config */
489
0
    memset(cc, 0, sizeof(UA_ClientConfig));
490
491
    /* Finish setting up the context */
492
0
    ar->server = server;
493
0
    ar->dm = dm;
494
0
    ar->unregister = unregister;
495
0
    ar->register2 = true; /* Try register2 first */
496
0
    UA_String_copy(&semaphoreFilePath, &ar->semaphoreFilePath);
497
498
    /* Connect asynchronously. The register service is called once the
499
     * connection is open. */
500
0
    ar->connectSuccess = false;
501
0
    return UA_Client_connectAsync(ar->client, NULL);
502
0
}
503
504
UA_StatusCode
505
UA_Server_registerDiscovery(UA_Server *server, UA_ClientConfig *cc,
506
                            const UA_String discoveryServerUrl,
507
0
                            const UA_String semaphoreFilePath) {
508
0
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
509
0
                "Registering at the DiscoveryServer: %S", discoveryServerUrl);
510
0
    lockServer(server);
511
0
    UA_StatusCode res =
512
0
        UA_Server_register(server, cc, false, discoveryServerUrl, semaphoreFilePath);
513
0
    unlockServer(server);
514
0
    return res;
515
0
}
516
517
UA_StatusCode
518
UA_Server_deregisterDiscovery(UA_Server *server, UA_ClientConfig *cc,
519
0
                              const UA_String discoveryServerUrl) {
520
0
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
521
0
                "Deregistering at the DiscoveryServer: %S", discoveryServerUrl);
522
0
    lockServer(server);
523
0
    UA_StatusCode res =
524
        UA_Server_register(server, cc, true, discoveryServerUrl, UA_STRING_NULL);
525
0
    unlockServer(server);
526
0
    return res;
527
0
}
528
529
#endif /* UA_ENABLE_DISCOVERY */