/src/open62541_15/src/client/ua_client_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 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) |
6 | | * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB |
7 | | * Copyright 2017 (c) Stefan Profanter, fortiss GmbH |
8 | | */ |
9 | | |
10 | | #include "ua_client_internal.h" |
11 | | |
12 | | /* Helper method for additional warnings */ |
13 | | void |
14 | | Client_warnEndpointsResult(UA_Client *client, |
15 | | const UA_GetEndpointsResponse *response, |
16 | 0 | const UA_String *endpointUrl) { |
17 | 0 | if(response->endpointsSize == 0) { |
18 | 0 | UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT, |
19 | 0 | "The server did not return any endpoints. " |
20 | 0 | "Did you use the correct endpointUrl?"); |
21 | 0 | return; |
22 | 0 | } |
23 | | |
24 | 0 | if(!UA_String_equal(endpointUrl, &response->endpoints[0].endpointUrl) || |
25 | 0 | (response->endpoints[0].server.discoveryUrlsSize > 0 && |
26 | 0 | !UA_String_equal(endpointUrl, &response->endpoints[0].server.discoveryUrls[0]))) { |
27 | 0 | UA_String *betterUrl = &response->endpoints[0].endpointUrl; |
28 | 0 | if(response->endpoints[0].server.discoveryUrlsSize > 0) |
29 | 0 | betterUrl = &response->endpoints[0].server.discoveryUrls[0]; |
30 | 0 | UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT, |
31 | 0 | "The server returned Endpoints with a different EndpointUrl %S than was " |
32 | 0 | "used to initialize the connection: %S. Some servers require a complete " |
33 | 0 | "match of the EndpointUrl/DiscoveryUrl (including the path) " |
34 | 0 | "to return all endpoints.", *betterUrl, *endpointUrl); |
35 | 0 | } |
36 | 0 | } |
37 | | |
38 | | /* Gets a list of endpoints. Memory is allocated for endpointDescription array */ |
39 | | static UA_StatusCode |
40 | | getEndpointsInternal(UA_Client *client, const UA_String endpointUrl, |
41 | | size_t *endpointDescriptionsSize, |
42 | 0 | UA_EndpointDescription **endpointDescriptions) { |
43 | 0 | UA_LOCK_ASSERT(&client->clientMutex); |
44 | |
|
45 | 0 | UA_GetEndpointsRequest request; |
46 | 0 | UA_GetEndpointsRequest_init(&request); |
47 | 0 | request.requestHeader.timeoutHint = 10000; |
48 | | // assume the endpointurl outlives the service call |
49 | 0 | request.endpointUrl = endpointUrl; |
50 | |
|
51 | 0 | UA_GetEndpointsResponse response; |
52 | 0 | __Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST], |
53 | 0 | &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]); |
54 | |
|
55 | 0 | if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) { |
56 | 0 | UA_StatusCode retval = response.responseHeader.serviceResult; |
57 | 0 | UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT, |
58 | 0 | "GetEndpointRequest failed with error code %s", |
59 | 0 | UA_StatusCode_name(retval)); |
60 | 0 | UA_GetEndpointsResponse_clear(&response); |
61 | 0 | return retval; |
62 | 0 | } |
63 | | |
64 | 0 | *endpointDescriptions = response.endpoints; |
65 | 0 | *endpointDescriptionsSize = response.endpointsSize; |
66 | 0 | response.endpoints = NULL; |
67 | 0 | response.endpointsSize = 0; |
68 | 0 | UA_GetEndpointsResponse_clear(&response); |
69 | 0 | return UA_STATUSCODE_GOOD; |
70 | 0 | } |
71 | | |
72 | | UA_StatusCode |
73 | | UA_Client_getEndpoints(UA_Client *client, const char *serverUrl, |
74 | | size_t *endpointDescriptionsSize, |
75 | 0 | UA_EndpointDescription** endpointDescriptions) { |
76 | 0 | lockClient(client); |
77 | |
|
78 | 0 | UA_Boolean connected = (client->channel.state == UA_SECURECHANNELSTATE_OPEN); |
79 | | /* Client is already connected to a different server */ |
80 | 0 | if(connected && strncmp((const char*)client->config.endpoint.endpointUrl.data, serverUrl, |
81 | 0 | client->config.endpoint.endpointUrl.length) != 0) { |
82 | 0 | unlockClient(client); |
83 | 0 | return UA_STATUSCODE_BADINVALIDARGUMENT; |
84 | 0 | } |
85 | | |
86 | 0 | UA_StatusCode retval; |
87 | 0 | const UA_String url = UA_STRING((char*)(uintptr_t)serverUrl); |
88 | 0 | if(!connected) { |
89 | 0 | retval = connectSecureChannel(client, serverUrl); |
90 | 0 | if(retval != UA_STATUSCODE_GOOD) { |
91 | 0 | unlockClient(client); |
92 | 0 | return retval; |
93 | 0 | } |
94 | 0 | } |
95 | 0 | retval = getEndpointsInternal(client, url, endpointDescriptionsSize, |
96 | 0 | endpointDescriptions); |
97 | 0 | unlockClient(client); |
98 | |
|
99 | 0 | if(!connected) |
100 | 0 | UA_Client_disconnect(client); |
101 | 0 | return retval; |
102 | 0 | } |
103 | | |
104 | | UA_StatusCode |
105 | | UA_Client_findServers(UA_Client *client, const char *serverUrl, |
106 | | size_t serverUrisSize, UA_String *serverUris, |
107 | | size_t localeIdsSize, UA_String *localeIds, |
108 | | size_t *registeredServersSize, |
109 | 0 | UA_ApplicationDescription **registeredServers) { |
110 | 0 | lockClient(client); |
111 | 0 | UA_Boolean connected = (client->channel.state == UA_SECURECHANNELSTATE_OPEN); |
112 | | /* Client is already connected to a different server */ |
113 | 0 | if(connected && strncmp((const char*)client->config.endpoint.endpointUrl.data, serverUrl, |
114 | 0 | client->config.endpoint.endpointUrl.length) != 0) { |
115 | 0 | unlockClient(client); |
116 | 0 | return UA_STATUSCODE_BADINVALIDARGUMENT; |
117 | 0 | } |
118 | | |
119 | 0 | UA_StatusCode retval; |
120 | 0 | if(!connected) { |
121 | 0 | retval = connectSecureChannel(client, serverUrl); |
122 | 0 | if(retval != UA_STATUSCODE_GOOD) { |
123 | 0 | unlockClient(client); |
124 | 0 | return retval; |
125 | 0 | } |
126 | 0 | } |
127 | | |
128 | | /* Prepare the request */ |
129 | 0 | UA_FindServersRequest request; |
130 | 0 | UA_FindServersRequest_init(&request); |
131 | 0 | request.serverUrisSize = serverUrisSize; |
132 | 0 | request.serverUris = serverUris; |
133 | 0 | request.localeIdsSize = localeIdsSize; |
134 | 0 | request.localeIds = localeIds; |
135 | | |
136 | | /* Send the request */ |
137 | 0 | UA_FindServersResponse response; |
138 | 0 | __Client_Service(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST], |
139 | 0 | &response, &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]); |
140 | |
|
141 | 0 | unlockClient(client); |
142 | | |
143 | | /* Process the response */ |
144 | 0 | retval = response.responseHeader.serviceResult; |
145 | 0 | if(retval == UA_STATUSCODE_GOOD) { |
146 | 0 | *registeredServersSize = response.serversSize; |
147 | 0 | *registeredServers = response.servers; |
148 | 0 | response.serversSize = 0; |
149 | 0 | response.servers = NULL; |
150 | 0 | } else { |
151 | 0 | *registeredServersSize = 0; |
152 | 0 | *registeredServers = NULL; |
153 | 0 | } |
154 | | |
155 | | /* Clean up */ |
156 | 0 | UA_FindServersResponse_clear(&response); |
157 | 0 | if(!connected) |
158 | 0 | UA_Client_disconnect(client); |
159 | 0 | return retval; |
160 | 0 | } |
161 | | |
162 | | UA_StatusCode |
163 | | UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl, |
164 | | UA_UInt32 startingRecordId, UA_UInt32 maxRecordsToReturn, |
165 | | size_t serverCapabilityFilterSize, UA_String *serverCapabilityFilter, |
166 | 0 | size_t *serverOnNetworkSize, UA_ServerOnNetwork **serverOnNetwork) { |
167 | 0 | lockClient(client); |
168 | |
|
169 | 0 | UA_Boolean connected = (client->channel.state == UA_SECURECHANNELSTATE_OPEN); |
170 | | /* Client is already connected to a different server */ |
171 | 0 | if(connected && strncmp((const char*)client->config.endpoint.endpointUrl.data, serverUrl, |
172 | 0 | client->config.endpoint.endpointUrl.length) != 0) { |
173 | 0 | unlockClient(client); |
174 | 0 | return UA_STATUSCODE_BADINVALIDARGUMENT; |
175 | 0 | } |
176 | | |
177 | 0 | UA_StatusCode retval; |
178 | 0 | if(!connected) { |
179 | 0 | retval = connectSecureChannel(client, serverUrl); |
180 | 0 | if(retval != UA_STATUSCODE_GOOD) { |
181 | 0 | unlockClient(client); |
182 | 0 | return retval; |
183 | 0 | } |
184 | 0 | } |
185 | | |
186 | | /* Prepare the request */ |
187 | 0 | UA_FindServersOnNetworkRequest request; |
188 | 0 | UA_FindServersOnNetworkRequest_init(&request); |
189 | 0 | request.startingRecordId = startingRecordId; |
190 | 0 | request.maxRecordsToReturn = maxRecordsToReturn; |
191 | 0 | request.serverCapabilityFilterSize = serverCapabilityFilterSize; |
192 | 0 | request.serverCapabilityFilter = serverCapabilityFilter; |
193 | | |
194 | | /* Send the request */ |
195 | 0 | UA_FindServersOnNetworkResponse response; |
196 | 0 | __Client_Service(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST], |
197 | 0 | &response, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKRESPONSE]); |
198 | |
|
199 | 0 | unlockClient(client); |
200 | | |
201 | | /* Process the response */ |
202 | 0 | retval = response.responseHeader.serviceResult; |
203 | 0 | if(retval == UA_STATUSCODE_GOOD) { |
204 | 0 | *serverOnNetworkSize = response.serversSize; |
205 | 0 | *serverOnNetwork = response.servers; |
206 | 0 | response.serversSize = 0; |
207 | 0 | response.servers = NULL; |
208 | 0 | } else { |
209 | 0 | *serverOnNetworkSize = 0; |
210 | 0 | *serverOnNetwork = NULL; |
211 | 0 | } |
212 | | |
213 | | /* Clean up */ |
214 | 0 | UA_FindServersOnNetworkResponse_clear(&response); |
215 | 0 | if(!connected) |
216 | 0 | UA_Client_disconnect(client); |
217 | 0 | return retval; |
218 | 0 | } |