Esempio n. 1
0
 /// <summary>
 /// Initializes a secure channel with the endpoint identified by the connection.
 /// </summary>
 /// <param name="connection">The connection to use.</param>
 /// <param name="settings">The settings to use when creating the channel.</param>
 /// <exception cref="ServiceResultException">Thrown if any communication error occurs.</exception>
 public void Initialize(
     ITransportWaitingConnection connection,
     TransportChannelSettings settings)
 {
     SaveSettings(connection.EndpointUrl, settings);
     CreateChannel(connection);
 }
Esempio n. 2
0
        /// <summary>
        /// Initializes a secure channel with the endpoint identified by the connection.
        /// </summary>
        /// <param name="connection">The connection to use.</param>
        /// <param name="settings">The settings to use when creating the channel.</param>
        /// <exception cref="ServiceResultException">Thrown if any communication error occurs.</exception>
        public void Initialize(
            ITransportWaitingConnection connection,
            TransportChannelSettings settings)
        {
            SaveSettings(connection.EndpointUrl, settings);

            var socket = connection.Handle as IMessageSocket;

            if (socket == null)
            {
                throw new ArgumentException("Connection Handle is not of type IMessageSocket.");
            }

            m_channel = new UaSCUaBinaryClientChannel(
                Guid.NewGuid().ToString(),
                m_bufferManager,
                m_messageSocketFactory,
                m_quotas,
                m_settings.ClientCertificate,
                m_settings.ClientCertificateChain,
                m_settings.ServerCertificate,
                m_settings.Description);

            m_channel.Socket = socket;
            m_channel.Socket.ChangeSink(m_channel);
        }
Esempio n. 3
0
        /// <summary>
        /// Opens the channel before sending the request.
        /// </summary>
        /// <param name="connection">A reverse connection, null otherwise.</param>
        private void CreateChannel(ITransportWaitingConnection connection = null)
        {
            IMessageSocket socket = null;

            if (connection != null)
            {
                socket = connection.Handle as IMessageSocket;
                if (socket == null)
                {
                    throw new ArgumentException("Connection Handle is not of type IMessageSocket.");
                }
            }

            // create the channel.
            m_channel = new UaSCUaBinaryClientChannel(
                Guid.NewGuid().ToString(),
                m_bufferManager,
                m_messageSocketFactory,
                m_quotas,
                m_settings.ClientCertificate,
                m_settings.ClientCertificateChain,
                m_settings.ServerCertificate,
                m_settings.Description);

            // use socket for reverse connections, ignore otherwise
            if (socket != null)
            {
                m_channel.Socket = socket;
                m_channel.Socket.ChangeSink(m_channel);
                m_channel.ReverseSocket = true;
            }
        }
        /// <summary>
        /// Creates a new transport channel that supports the ITransportWaitingConnection service contract.
        /// </summary>
        public static ITransportChannel Create(
            ApplicationConfiguration configuration,
            ITransportWaitingConnection connection,
            EndpointConfiguration endpointConfiguration,
            ServiceMessageContext messageContext,
            X509Certificate2 clientCertificate = null)
        {
            // create a default description.
            var endpoint = new EndpointDescription {
                EndpointUrl       = connection.EndpointUrl.ToString(),
                SecurityMode      = MessageSecurityMode.None,
                SecurityPolicyUri = SecurityPolicies.None
            };

            endpoint.Server.ApplicationUri  = endpoint.EndpointUrl;
            endpoint.Server.ApplicationType = ApplicationType.DiscoveryServer;

            ITransportChannel channel = CreateUaBinaryChannel(
                configuration,
                connection,
                endpoint,
                endpointConfiguration,
                clientCertificate,
                (X509Certificate2Collection)null,
                messageContext);

            return(channel);
        }
Esempio n. 5
0
        /// <summary>
        /// Creates a new UA-binary transport channel if requested. Null otherwise.
        /// </summary>
        public static ITransportChannel CreateUaBinaryChannel(
            ApplicationConfiguration configuration,
            ITransportWaitingConnection connection,
            EndpointDescription description,
            EndpointConfiguration endpointConfiguration,
            X509Certificate2 clientCertificate,
            X509Certificate2Collection clientCertificateChain,
            ServiceMessageContext messageContext)
        {
            bool useUaTcp = description.EndpointUrl.StartsWith(Utils.UriSchemeOpcTcp);
            bool useHttps = description.EndpointUrl.StartsWith(Utils.UriSchemeHttps);

            // initialize the channel which will be created with the server.
            ITransportChannel channel = null;

            if (useUaTcp)
            {
                channel = new TcpTransportChannel();
            }
#if !NO_HTTPS
            else if (useHttps)
            {
                channel = new HttpsTransportChannel();
            }
#endif

            if (channel == null)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadProtocolVersionUnsupported,
                          "Unsupported transport profile\r\n");
            }

            // create a UA channel.
            var settings = new TransportChannelSettings {
                Description            = description,
                Configuration          = endpointConfiguration,
                ClientCertificate      = clientCertificate,
                ClientCertificateChain = clientCertificateChain
            };

            if (description.ServerCertificate != null && description.ServerCertificate.Length > 0)
            {
                settings.ServerCertificate = Utils.ParseCertificateBlob(description.ServerCertificate);
            }

            if (configuration != null)
            {
                settings.CertificateValidator = configuration.CertificateValidator.GetChannelValidator();
            }

            settings.NamespaceUris = messageContext.NamespaceUris;
            settings.Factory       = messageContext.Factory;

            channel.Initialize(connection, settings);
            channel.Open();

            return(channel);
        }
Esempio n. 6
0
 /// <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));
 }
Esempio n. 7
0
        private Task <Session> CreateSession(
            ApplicationConfiguration config,
            ITransportWaitingConnection connection,
            EndpointDescription selectedEndpoint,
            IUserIdentity userIdentity)
        {
            var endpointConfiguration = EndpointConfiguration.Create(config);
            var endpoint = new ConfiguredEndpoint(null, selectedEndpoint, endpointConfiguration);

            return(Session.Create(config, connection, endpoint, false, false, "OPC UA Complex Types Client", 60000, userIdentity, null));
        }
Esempio n. 8
0
        /// <summary>
        /// Creates a binding for to use for discovering servers.
        /// </summary>
        public static DiscoveryClient Create(
            ITransportWaitingConnection connection,
            EndpointConfiguration configuration)
        {
            if (configuration == null)
            {
                configuration = EndpointConfiguration.Create();
            }

            ITransportChannel channel = DiscoveryChannel.Create(null, connection, configuration, new ServiceMessageContext());
            return new DiscoveryClient(channel);
        }
        /// <summary>
        /// Creates a binding for to use for discovering servers.
        /// </summary>
        public static DiscoveryClient Create(
            ApplicationConfiguration application,
            ITransportWaitingConnection connection,
            EndpointConfiguration configuration)
        {
            if (configuration == null)
            {
                configuration = EndpointConfiguration.Create();
            }

            ITransportChannel channel = DiscoveryChannel.Create(application, connection, configuration, application.CreateMessageContext());

            return(new DiscoveryClient(channel));
        }
Esempio n. 10
0
        /// <summary>
        /// Creates a new UA-binary transport channel if requested. Null otherwise.
        /// </summary>
        public static ITransportChannel CreateUaBinaryChannel(
            ApplicationConfiguration configuration,
            ITransportWaitingConnection connection,
            EndpointDescription description,
            EndpointConfiguration endpointConfiguration,
            X509Certificate2 clientCertificate,
            X509Certificate2Collection clientCertificateChain,
            IServiceMessageContext messageContext)
        {
            // initialize the channel which will be created with the server.
            string            uriScheme = new Uri(description.EndpointUrl).Scheme;
            ITransportChannel channel   = TransportBindings.Channels.GetChannel(uriScheme);

            if (channel == null)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadProtocolVersionUnsupported,
                          "Unsupported transport profile for scheme {0}.", uriScheme);
            }

            // create a UA channel.
            var settings = new TransportChannelSettings {
                Description            = description,
                Configuration          = endpointConfiguration,
                ClientCertificate      = clientCertificate,
                ClientCertificateChain = clientCertificateChain
            };

            if (description.ServerCertificate != null && description.ServerCertificate.Length > 0)
            {
                settings.ServerCertificate = Utils.ParseCertificateBlob(description.ServerCertificate);
            }

            if (configuration != null)
            {
                settings.CertificateValidator = configuration.CertificateValidator.GetChannelValidator();
            }

            settings.NamespaceUris = messageContext.NamespaceUris;
            settings.Factory       = messageContext.Factory;

            channel.Initialize(connection, settings);
            channel.Open();

            return(channel);
        }
Esempio n. 11
0
        /// <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));
            }
        }
Esempio n. 12
0
        /// <summary>
        /// Closes any existing secure channel and opens a new one.
        /// </summary>
        /// <param name="connection">A reverse connection, null otherwise.</param>
        /// <exception cref="ServiceResultException">Thrown if any communication error occurs.</exception>
        /// <remarks>
        /// Calling this method will cause outstanding requests over the current secure channel to fail.
        /// </remarks>
        public void Reconnect(ITransportWaitingConnection connection)
        {
            Utils.Trace("TransportChannel RECONNECT: Reconnecting to {0}.", m_url);

            lock (m_lock)
            {
                // the new channel must be created first because WinSock will reuse sockets and this
                // can result in messages sent over the old socket arriving as messages on the new socket.
                // if this happens the new channel is shutdown because of a security violation.
                UaSCUaBinaryClientChannel channel = m_channel;
                m_channel = null;

                try
                {
                    // reconnect.
                    CreateChannel(connection);

                    // begin connect operation.
                    IAsyncResult result = m_channel.BeginConnect(m_url, m_operationTimeout, null, null);
                    m_channel.EndConnect(result);
                }
                finally
                {
                    // close existing channel.
                    if (channel != null)
                    {
                        try
                        {
                            channel.Close(1000);
                        }
                        catch (Exception e)
                        {
                            // do nothing.
                            Utils.Trace(e, "Ignoring exception while closing transport channel during Reconnect.");
                        }
                        finally
                        {
                            channel.Dispose();
                        }
                    }
                }
            }
        }
Esempio n. 13
0
        /// <summary>
        /// Creates a new transport channel that supports the ISessionChannel service contract.
        /// </summary>
        /// <param name="configuration">The application configuration.</param>
        /// <param name="connection"></param>
        /// <param name="description">The description for the endpoint.</param>
        /// <param name="endpointConfiguration">The configuration to use with the endpoint.</param>
        /// <param name="clientCertificate">The client certificate.</param>
        /// <param name="clientCertificateChain">The client certificate chain.</param>
        /// <param name="messageContext">The message context to use when serializing the messages.</param>
        /// <returns></returns>
        public static ITransportChannel Create(
            ApplicationConfiguration configuration,
            ITransportWaitingConnection connection,
            EndpointDescription description,
            EndpointConfiguration endpointConfiguration,
            X509Certificate2 clientCertificate,
            X509Certificate2Collection clientCertificateChain,
            IServiceMessageContext messageContext)
        {
            // create a UA binary channel.
            ITransportChannel channel = CreateUaBinaryChannel(
                configuration,
                connection,
                description,
                endpointConfiguration,
                clientCertificate,
                clientCertificateChain,
                messageContext);

            return(channel);
        }
Esempio n. 14
0
 /// <inheritdoc/>
 public override void Reconnect(ITransportWaitingConnection connection)
 {
     throw new NotImplementedException("Reconnect for waiting connections is not supported for this channel");
 }
Esempio n. 15
0
 /// <inheritdoc/>
 /// <remarks>Not implemented here.</remarks>
 void ITransportChannel.Reconnect(ITransportWaitingConnection connection)
 {
     throw new NotImplementedException();
 }
Esempio n. 16
0
        private async Task <Session> ConsoleSampleClient()
        {
            Console.WriteLine("1 - Create an Application Configuration.");
            ExitCode = ExitCode.ErrorCreateApplication;

            ApplicationInstance application = new ApplicationInstance {
                ApplicationName   = "UA Core Complex Client",
                ApplicationType   = ApplicationType.Client,
                ConfigSectionName = "Opc.Ua.ComplexClient"
            };

            // load the application configuration.
            ApplicationConfiguration config = await application.LoadApplicationConfiguration(false).ConfigureAwait(false);

            // check the application certificate.
            bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0).ConfigureAwait(false);

            if (!haveAppCertificate)
            {
                throw new Exception("Application instance certificate invalid!");
            }

            ReverseConnectManager reverseConnectManager = null;

            if (ReverseConnectUri != null)
            {
                // start the reverse connection manager
                reverseConnectManager = new ReverseConnectManager();
                reverseConnectManager.AddEndpoint(ReverseConnectUri);
                reverseConnectManager.StartService(config);
            }

            if (haveAppCertificate)
            {
                config.ApplicationUri = Utils.GetApplicationUriFromCertificate(config.SecurityConfiguration.ApplicationCertificate.Certificate);
                if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates)
                {
                    m_autoAccept = true;
                }
                config.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation);
            }
            else
            {
                Console.WriteLine("    WARN: missing application certificate, using unsecure connection.");
            }

            Console.WriteLine("2 - Discover endpoints of {0}.", m_endpointURL);
            ExitCode = ExitCode.ErrorDiscoverEndpoints;
            EndpointDescription selectedEndpoint;

            if (reverseConnectManager == null)
            {
                selectedEndpoint = CoreClientUtils.SelectEndpoint(m_endpointURL, haveAppCertificate, 15000);
            }
            else
            {
                Console.WriteLine("   Waiting for reverse connection.");
                ITransportWaitingConnection connection = await reverseConnectManager.WaitForConnection(
                    new Uri(m_endpointURL), null, new CancellationTokenSource(60000).Token);

                if (connection == null)
                {
                    throw new ServiceResultException(StatusCodes.BadTimeout, "Waiting for a reverse connection timed out.");
                }
                selectedEndpoint = CoreClientUtils.SelectEndpoint(config, connection, haveAppCertificate, 15000);
            }

            Console.WriteLine("    Selected endpoint uses: {0}",
                              selectedEndpoint.SecurityPolicyUri.Substring(selectedEndpoint.SecurityPolicyUri.LastIndexOf('#') + 1));

            Console.WriteLine("3 - Create a session with OPC UA server.");
            ExitCode = ExitCode.ErrorCreateSession;

            // create the user identity
            UserIdentity userIdentity;

            if (String.IsNullOrEmpty(Username) && String.IsNullOrEmpty(Password))
            {
                userIdentity = new UserIdentity(new AnonymousIdentityToken());
            }
            else
            {
                userIdentity = new UserIdentity(Username, Password);
            }

            // create worker session
            if (reverseConnectManager == null)
            {
                m_session = await CreateSession(config, selectedEndpoint, userIdentity).ConfigureAwait(false);
            }
            else
            {
                Console.WriteLine("   Waiting for reverse connection.");
                ITransportWaitingConnection connection = await reverseConnectManager.WaitForConnection(
                    new Uri(m_endpointURL), null, new CancellationTokenSource(60000).Token);

                if (connection == null)
                {
                    throw new ServiceResultException(StatusCodes.BadTimeout, "Waiting for a reverse connection timed out.");
                }
                m_session = await CreateSession(config, connection, selectedEndpoint, userIdentity).ConfigureAwait(false);
            }

            // register keep alive handler
            m_session.KeepAlive += Client_KeepAlive;

            Console.WriteLine("4 - Browse for all custom type variables.");
            ExitCode = ExitCode.ErrorReadComplexTypes;

            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();
            var allVariableNodes       = BrowseAdddressSpace ? BrowseAllVariables() : new List <INode>();
            var allCustomTypeVariables = allVariableNodes.Where(n => ((VariableNode)n).DataType.NamespaceIndex != 0).ToList();

            stopWatch.Stop();

            Console.WriteLine($" -- Browse all nodes took {stopWatch.ElapsedMilliseconds}ms.");
            Console.WriteLine($" -- Browsed {allVariableNodes.Count} nodes, from which {allCustomTypeVariables.Count} are custom type variables.");

            stopWatch.Reset();
            // for testing clear the nodecache
            m_session.NodeCache.Clear();
            stopWatch.Start();

            if (LoadTypeSystem)
            {
                Console.WriteLine("5 - Load the server type dictionary.");
                ExitCode = ExitCode.ErrorLoadTypeDictionary;

                stopWatch.Reset();
                stopWatch.Start();

                var complexTypeSystem = new ComplexTypeSystem(m_session);
                await complexTypeSystem.Load().ConfigureAwait(false);

                stopWatch.Stop();

                Console.WriteLine($"Load type system took {stopWatch.ElapsedMilliseconds}ms.");

                Console.WriteLine($"Custom types defined for this session:");
                foreach (var type in complexTypeSystem.GetDefinedTypes())
                {
                    Console.WriteLine($"{type.Namespace}.{type.Name}");
                }

                Console.WriteLine($"Loaded {m_session.DataTypeSystem.Count} dictionaries:");
                foreach (var dictionary in m_session.DataTypeSystem)
                {
                    Console.WriteLine($" + {dictionary.Value.Name}");
                    foreach (var type in dictionary.Value.DataTypes)
                    {
                        Console.WriteLine($" -- {type.Key}:{type.Value}");
                    }
                }
            }
            else
            {
                Console.WriteLine("4 - Not loading the server type dictionary.");
            }

            foreach (VariableNode variableNode in allCustomTypeVariables)
            {
                try
                {
                    var value = m_session.ReadValue(variableNode.NodeId);

                    CastInt32ToEnum(variableNode, value);
                    Console.WriteLine($" -- {variableNode}:{value}");

                    if (value.Value is ExtensionObject extensionObject)
                    {
                        if (extensionObject.Body is BaseComplexType complexType)
                        {
                            foreach (var item in complexType.GetPropertyEnumerator())
                            {
                                if (Verbose)
                                {
                                    Console.WriteLine($" -- -- {item.Name}:{complexType[item.Name]}");
                                }
                                if (WriteComplexInt && item.PropertyType == typeof(Int32))
                                {
                                    var data = complexType[item.Name];
                                    if (data != null)
                                    {
                                        complexType[item.Name] = (Int32)data + 1;
                                    }
                                    Console.WriteLine($" -- -- Increment: {item.Name}, {complexType[item.Name]}");
                                    WriteValue(m_session, variableNode.NodeId, value);
                                }
                            }
                        }
                    }

                    if (PrintAsJson)
                    {
                        PrintValueAsJson(variableNode.BrowseName.Name, value);
                    }
                }
                catch (ServiceResultException sre)
                {
                    if (sre.StatusCode == StatusCodes.BadUserAccessDenied)
                    {
                        Console.WriteLine($" -- {variableNode}: Access denied!");
                    }
                }
            }

            Console.WriteLine("6 - Create test sessions which load only single types as needed.");
            if (LoadTypeSystem)
            {
                foreach (VariableNode variableNode in allCustomTypeVariables)
                {
                    Session testSession = null;
                    try
                    {
                        Console.WriteLine($"Open session for {variableNode}:");
                        testSession = await CreateSession(config, selectedEndpoint, userIdentity).ConfigureAwait(false);

                        var    complexTypeSystem = new ComplexTypeSystem(testSession);
                        NodeId dataType          = variableNode.DataType;
                        Type   nullType          = testSession.Factory.GetSystemType(dataType);
                        var    valueBefore       = testSession.ReadValue(variableNode.NodeId);
                        Console.WriteLine($" -- {valueBefore}");
                        Type systemType = await complexTypeSystem.LoadType(dataType).ConfigureAwait(false);

                        var valueAfter = testSession.ReadValue(variableNode.NodeId);
                        Console.WriteLine($" -- {variableNode}: {systemType} {dataType}");
                        Console.WriteLine($" -- {valueAfter}");
                        Console.WriteLine($"Custom types defined for {variableNode}:");
                        foreach (var type in complexTypeSystem.GetDefinedTypes())
                        {
                            Console.WriteLine($" -- {type.Namespace}.{type.Name}");
                        }
                    }
                    catch (ServiceResultException sre)
                    {
                        if (sre.StatusCode == StatusCodes.BadUserAccessDenied)
                        {
                            Console.WriteLine($" -- {variableNode}: Access denied!");
                        }
                    }
                    finally
                    {
                        testSession?.Close();
                    }
                }
            }
            else
            {
                Console.WriteLine("6 - Not testing to load individual types.");
            }

            Console.WriteLine("7 - Create a subscription with publishing interval of 1 second.");
            ExitCode = ExitCode.ErrorCreateSubscription;
            var subscription = new Subscription(m_session.DefaultSubscription)
            {
                PublishingInterval = 1000
            };

            Console.WriteLine("8 - Add all custom values and the server time to the subscription.");
            ExitCode = ExitCode.ErrorMonitoredItem;
            var list = new List <MonitoredItem> {
                new MonitoredItem(subscription.DefaultItem)
                {
                    DisplayName = "ServerStatusCurrentTime", StartNodeId = "i=" + Variables.Server_ServerStatus_CurrentTime.ToString()
                }
            };

            list.ForEach(i => i.Notification += OnNotification);

            foreach (var customVariable in allCustomTypeVariables)
            {
                var newItem = new MonitoredItem(subscription.DefaultItem)
                {
                    DisplayName = customVariable.DisplayName.Text,
                    StartNodeId = ExpandedNodeId.ToNodeId(customVariable.NodeId, m_session.NamespaceUris)
                };
                newItem.Notification += OnComplexTypeNotification;
                list.Add(newItem);
            }

            subscription.AddItems(list);

            Console.WriteLine("9 - Add the subscription to the session.");
            ExitCode = ExitCode.ErrorAddSubscription;
            m_session.AddSubscription(subscription);
            subscription.Create();

            Console.WriteLine("10 - Running...Press Ctrl-C to exit...");
            ExitCode = ExitCode.ErrorRunning;

            return(m_session);
        }
Esempio n. 17
0
 /// <summary>
 /// Initializes a secure channel with the endpoint identified by the URL.
 /// </summary>
 /// <param name="connection">The connection to use.</param>
 /// <param name="settings">The settings to use when creating the channel.</param>
 /// <exception cref="ServiceResultException">Thrown if any communication error occurs.</exception>
 public void Initialize(
     ITransportWaitingConnection connection,
     TransportChannelSettings settings)
 {
     throw new NotSupportedException("WCF channels must be configured when they are constructed.");
 }
Esempio n. 18
0
 /// <summary>
 /// Closes any existing secure channel and opens a new one using an existing channel.
 /// </summary>
 /// <param name="connection">The reverse transport connection for the Reconnect.</param>
 /// <exception cref="ServiceResultException">Thrown if any communication error occurs.</exception>
 /// <remarks>
 /// Calling this method will cause outstanding requests over the current secure channel to fail.
 /// </remarks>
 public abstract void Reconnect(ITransportWaitingConnection connection);
        /// <summary>
        /// Updates an endpoint with information from the server's discovery endpoint.
        /// </summary>
        public void UpdateFromServer(
            Uri endpointUrl,
            ITransportWaitingConnection connection,
            MessageSecurityMode securityMode,
            string securityPolicyUri)
        {
            // get the a discovery url.
            Uri discoveryUrl = GetDiscoveryUrl(endpointUrl);

            // create the discovery client.
            DiscoveryClient client;

            if (connection != null)
            {
                client = DiscoveryClient.Create(connection, m_configuration);
            }
            else
            {
                client = DiscoveryClient.Create(discoveryUrl, m_configuration);
            }

            try
            {
                // get the endpoints.
                EndpointDescriptionCollection collection = client.GetEndpoints(null);

                if (collection == null || collection.Count == 0)
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadUnknownResponse,
                              "Server does not have any endpoints defined.");
                }

                // find list of matching endpoints.
                EndpointDescriptionCollection matches = new EndpointDescriptionCollection();

                // first pass - match on the requested security parameters.
                foreach (EndpointDescription description in collection)
                {
                    // check for match on security policy.
                    if (!String.IsNullOrEmpty(securityPolicyUri))
                    {
                        if (securityPolicyUri != description.SecurityPolicyUri)
                        {
                            continue;
                        }
                    }

                    // check for match on security mode.
                    if (securityMode != MessageSecurityMode.Invalid)
                    {
                        if (securityMode != description.SecurityMode)
                        {
                            continue;
                        }
                    }

                    // add to list of matches.
                    matches.Add(description);
                }

                // no matches (security parameters may have changed).
                if (matches.Count == 0)
                {
                    matches = collection;
                }

                // check if list has to be narrowed down further.
                if (matches.Count > 1)
                {
                    collection = matches;
                    matches    = new EndpointDescriptionCollection();

                    // second pass - match on the url scheme.
                    foreach (EndpointDescription description in collection)
                    {
                        // parse the endpoint url.
                        Uri sessionUrl = Utils.ParseUri(description.EndpointUrl);

                        if (sessionUrl == null)
                        {
                            continue;
                        }

                        // check for matching protocol.
                        if (sessionUrl.Scheme != endpointUrl.Scheme)
                        {
                            continue;
                        }

                        matches.Add(description);
                    }
                }

                // no matches (protocol may not be supported).
                if (matches.Count == 0)
                {
                    matches = collection;
                }

                // choose first in list by default.
                EndpointDescription match = matches[0];

                // check if list has to be narrowed down further.
                if (matches.Count > 1)
                {
                    // third pass - match based on security level.
                    foreach (EndpointDescription description in matches)
                    {
                        if (description.SecurityLevel > match.SecurityLevel)
                        {
                            match = description;
                        }
                    }
                }

                // check if the endpoint url matches the endpoint used in the request.
                if (discoveryUrl != null)
                {
                    Uri matchUrl = Utils.ParseUri(match.EndpointUrl);
                    if (matchUrl == null || String.Compare(discoveryUrl.DnsSafeHost, matchUrl.DnsSafeHost, StringComparison.OrdinalIgnoreCase) != 0)
                    {
                        UriBuilder uri = new UriBuilder(matchUrl);
                        uri.Host          = discoveryUrl.DnsSafeHost;
                        uri.Port          = discoveryUrl.Port;
                        match.EndpointUrl = uri.ToString();

                        // need to update the discovery urls.
                        match.Server.DiscoveryUrls.Clear();
                        match.Server.DiscoveryUrls.Add(discoveryUrl.ToString());
                    }
                }

                // update the endpoint.
                Update(match);
            }
            finally
            {
                client.Close();
            }
        }