Coverage Report

Created: 2026-08-13 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}