/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(¤t->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(®2); |
384 | 0 | setupRegisterRequest(ar, ®2.requestHeader, ®2.server); |
385 | 0 | reqType = &UA_TYPES[UA_TYPES_REGISTERSERVER2REQUEST]; |
386 | 0 | respType = &UA_TYPES[UA_TYPES_REGISTERSERVER2RESPONSE]; |
387 | 0 | request = ®2; |
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(®1); |
399 | 0 | setupRegisterRequest(ar, ®1.requestHeader, ®1.server); |
400 | 0 | reqType = &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST]; |
401 | 0 | respType = &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE]; |
402 | 0 | request = ®1; |
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 */ |