Files
Mapo-IOB-WIN/IOB-OPC-UA/Libraries/Opc.Ua.Client/CoreClientUtils.cs
T
2021-03-25 18:25:25 +01:00

321 lines
13 KiB
C#

/* ========================================================================
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* The complete license agreement can be found here:
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
using System;
using System.Collections.Generic;
namespace Opc.Ua.Client
{
/// <summary>
/// Defines numerous re-useable utility functions for clients.
/// </summary>
public static class CoreClientUtils
{
/// <summary>
/// The default discover operation timeout.
/// </summary>
public static readonly int DefaultDiscoverTimeout = 15000;
#region Discovery
/// <summary>
/// Discovers the servers on the local machine.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <returns>A list of server urls.</returns>
public static IList<string> DiscoverServers(ApplicationConfiguration configuration)
{
return DiscoverServers(configuration, DefaultDiscoverTimeout);
}
/// <summary>
/// Discovers the servers on the local machine.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="discoverTimeout">Operation timeout in milliseconds.</param>
/// <returns>A list of server urls.</returns>
public static IList<string> DiscoverServers(
ApplicationConfiguration configuration,
int discoverTimeout
)
{
List<string> serverUrls = new List<string>();
// set a short timeout because this is happening in the drop down event.
var endpointConfiguration = EndpointConfiguration.Create(configuration);
endpointConfiguration.OperationTimeout = discoverTimeout;
// Connect to the local discovery server and find the available servers.
using (DiscoveryClient client = DiscoveryClient.Create(new Uri(String.Format(Utils.DiscoveryUrls[0], "localhost")), endpointConfiguration))
{
ApplicationDescriptionCollection servers = client.FindServers(null);
// populate the drop down list with the discovery URLs for the available servers.
for (int ii = 0; ii < servers.Count; ii++)
{
if (servers[ii].ApplicationType == ApplicationType.DiscoveryServer)
{
continue;
}
for (int jj = 0; jj < servers[ii].DiscoveryUrls.Count; jj++)
{
string discoveryUrl = servers[ii].DiscoveryUrls[jj];
// Many servers will use the '/discovery' suffix for the discovery endpoint.
// The URL without this prefix should be the base URL for the server.
if (discoveryUrl.EndsWith("/discovery"))
{
discoveryUrl = discoveryUrl.Substring(0, discoveryUrl.Length - "/discovery".Length);
}
// ensure duplicates do not get added.
if (!serverUrls.Contains(discoveryUrl))
{
serverUrls.Add(discoveryUrl);
}
}
}
}
return serverUrls;
}
/// <summary>
/// Finds the endpoint that best matches the current settings.
/// </summary>
/// <param name="discoveryUrl">The discovery URL.</param>
/// <param name="useSecurity">if set to <c>true</c> select an endpoint that uses security.</param>
/// <returns>The best available endpoint.</returns>
public static EndpointDescription SelectEndpoint(string discoveryUrl, bool useSecurity)
{
return SelectEndpoint(discoveryUrl, useSecurity, DefaultDiscoverTimeout);
}
/// <summary>
/// Finds the endpoint that best matches the current settings.
/// </summary>
/// <param name="discoveryUrl">The discovery URL.</param>
/// <param name="useSecurity">if set to <c>true</c> select an endpoint that uses security.</param>
/// <param name="discoverTimeout">Operation timeout in milliseconds.</param>
/// <returns>The best available endpoint.</returns>
public static EndpointDescription SelectEndpoint(
string discoveryUrl,
bool useSecurity,
int discoverTimeout
)
{
var url = GetDiscoveryUrl(discoveryUrl);
var endpointConfiguration = EndpointConfiguration.Create();
endpointConfiguration.OperationTimeout = discoverTimeout;
// Connect to the server's discovery endpoint and find the available configuration.
using (var client = DiscoveryClient.Create(url, endpointConfiguration))
{
var endpoints = client.GetEndpoints(null);
return SelectEndpoint(url, endpoints, useSecurity);
}
}
/// <summary>
/// Finds the endpoint that best matches the current settings.
/// </summary>
public static EndpointDescription SelectEndpoint(
ApplicationConfiguration application,
ITransportWaitingConnection connection,
bool useSecurity
)
{
return SelectEndpoint(application, connection, useSecurity, DefaultDiscoverTimeout);
}
/// <summary>
/// Finds the endpoint that best matches the current settings.
/// </summary>
public static EndpointDescription SelectEndpoint(
ApplicationConfiguration application,
ITransportWaitingConnection connection,
bool useSecurity,
int discoverTimeout
)
{
var endpointConfiguration = EndpointConfiguration.Create();
endpointConfiguration.OperationTimeout = discoverTimeout > 0 ? discoverTimeout : DefaultDiscoverTimeout;
using (DiscoveryClient client = DiscoveryClient.Create(application, connection, endpointConfiguration))
{
var url = new Uri(client.Endpoint.EndpointUrl);
var endpoints = client.GetEndpoints(null);
return SelectEndpoint(url, endpoints, useSecurity);
}
}
/// <summary>
/// Finds the endpoint that best matches the current settings.
/// </summary>
/// <param name="application">The application configuration.</param>
/// <param name="discoveryUrl">The discovery URL.</param>
/// <param name="useSecurity">if set to <c>true</c> select an endpoint that uses security.</param>
/// <returns>The best available endpoint.</returns>
public static EndpointDescription SelectEndpoint(
ApplicationConfiguration application,
string discoveryUrl,
bool useSecurity)
{
return SelectEndpoint(application, discoveryUrl, useSecurity, DefaultDiscoverTimeout);
}
/// <summary>
/// Finds the endpoint that best matches the current settings.
/// </summary>
/// <param name="application">The application configuration.</param>
/// <param name="discoveryUrl">The discovery URL.</param>
/// <param name="useSecurity">if set to <c>true</c> select an endpoint that uses security.</param>
/// <param name="discoverTimeout">The timeout for the discover operation.</param>
/// <returns>The best available endpoint.</returns>
public static EndpointDescription SelectEndpoint(
ApplicationConfiguration application,
string discoveryUrl,
bool useSecurity,
int discoverTimeout
)
{
var uri = GetDiscoveryUrl(discoveryUrl);
var endpointConfiguration = EndpointConfiguration.Create();
endpointConfiguration.OperationTimeout = discoverTimeout;
using (var client = DiscoveryClient.Create(application, uri, endpointConfiguration))
{
// Connect to the server's discovery endpoint and find the available configuration.
Uri url = new Uri(client.Endpoint.EndpointUrl);
var endpoints = client.GetEndpoints(null);
var selectedEndpoint = SelectEndpoint(url, endpoints, useSecurity);
Uri endpointUrl = Utils.ParseUri(selectedEndpoint.EndpointUrl);
if (endpointUrl != null && endpointUrl.Scheme == uri.Scheme)
{
UriBuilder builder = new UriBuilder(endpointUrl);
builder.Host = uri.DnsSafeHost;
builder.Port = uri.Port;
selectedEndpoint.EndpointUrl = builder.ToString();
}
return selectedEndpoint;
}
}
/// <summary>
/// Select the best supported endpoint from an
/// EndpointDescriptionCollection, with or without security.
/// </summary>
/// <param name="url"></param>
/// <param name="endpoints"></param>
/// <param name="useSecurity"></param>
public static EndpointDescription SelectEndpoint(
Uri url,
EndpointDescriptionCollection endpoints,
bool useSecurity)
{
EndpointDescription selectedEndpoint = null;
// select the best endpoint to use based on the selected URL and the UseSecurity checkbox.
for (int ii = 0; ii < endpoints.Count; ii++)
{
EndpointDescription endpoint = endpoints[ii];
// check for a match on the URL scheme.
if (endpoint.EndpointUrl.StartsWith(url.Scheme))
{
// check if security was requested.
if (useSecurity)
{
if (endpoint.SecurityMode == MessageSecurityMode.None)
{
continue;
}
// skip unsupported security policies
if (SecurityPolicies.GetDisplayName(endpoint.SecurityPolicyUri) == null)
{
continue;
}
}
else
{
if (endpoint.SecurityMode != MessageSecurityMode.None)
{
continue;
}
}
// pick the first available endpoint by default.
if (selectedEndpoint == null)
{
selectedEndpoint = endpoint;
}
// The security level is a relative measure assigned by the server to the
// endpoints that it returns. Clients should always pick the highest level
// unless they have a reason not too.
if (endpoint.SecurityLevel > selectedEndpoint.SecurityLevel)
{
selectedEndpoint = endpoint;
}
}
}
// pick the first available endpoint by default.
if (selectedEndpoint == null && endpoints.Count > 0)
{
selectedEndpoint = endpoints[0];
}
// return the selected endpoint.
return selectedEndpoint;
}
#endregion
#region Private Methods
private static Uri GetDiscoveryUrl(string discoveryUrl)
{
// needs to add the '/discovery' back onto non-UA TCP URLs.
if (discoveryUrl.StartsWith(Utils.UriSchemeHttp))
{
if (!discoveryUrl.EndsWith("/discovery"))
{
discoveryUrl += "/discovery";
}
}
// parse the selected URL.
return new Uri(discoveryUrl);
}
#endregion
}
}