/// <summary>
            /// The <see cref="Connection.Close()"/> implementation method.
            /// </summary>
            /// <remarks>
            /// This method is called on the service thread.
            /// </remarks>
            /// <param name="notify">
            /// if <b>true</b>, notify the peer that the Connection is being
            /// closed.
            /// </param>
            /// <param name="e">
            /// The optional reason why the Connection is being closed.
            /// </param>
            /// <param name="millis">
            /// The number of milliseconds to wait for the Connection to close;
            /// pass 0 to perform a non-blocking close or -1 to wait forever.
            /// </param>
            /// <returns>
            /// <b>true</b> if the invocation of this method closed the
            /// Connection.
            /// </returns>
            public override bool CloseInternal(bool notify, Exception e,
                                               int millis)
            {
                if (base.CloseInternal(notify, e, millis))
                {
                    var reader = Reader;
                    if (reader != null)
                    {
                        reader.Stop();
                        Reader = null;
                    }

                    var stream = Stream;
                    if (stream != null)
                    {
                        stream.Close();
                    }

                    NetworkUtils.Close(Client);

                    return(true);
                }

                return(false);
            }
        /// <summary>
        /// Open and return a new Connection.
        /// </summary>
        /// <returns>
        /// A newly opened Connection.
        /// </returns>
        protected override Connection OpenConnection()
        {
            IAddressProvider provider = RemoteAddressProvider;

            Debug.Assert(provider != null);

            // Default value for Coherence is 0, which is an infinite timeout.
            // Default value for .NET IAsyncResult.WaitOne infinite timeout is -1.
            // So, convert the Coherence infinite value to .NET Timeout.Infinite.
            Int32 cMillis = (Int32)ConnectTimeout;

            cMillis = cMillis <= 0 ? Timeout.Infinite : cMillis;

            // open a new connection
            var         addresses    = new StringBuilder().Append('[');
            IEnumerator enmrRedirect = null;
            IEnumerator enmrSubport  = null;
            IPEndPoint  addrNext     = null;
            Int32       subportNext  = -1;
            Exception   cause        = null;

            for ( ; ;)
            {
                var connection = (TcpConnection)InstantiateConnection();

                IPEndPoint addr;
                Int32      subport;
                if (enmrRedirect == null || addrNext == null)
                {
                    addr    = provider.NextAddress;
                    subport = Subport;

                    // reset redirection information
                    enmrRedirect = null;
                    enmrSubport  = null;
                }
                else
                {
                    addr     = addrNext;
                    addrNext = enmrRedirect.MoveNext() ?
                               (IPEndPoint)enmrRedirect.Current : null;

                    subport     = subportNext;
                    subportNext = enmrSubport.MoveNext() ?
                                  (Int32)enmrSubport.Current : -1;

                    // update redirection information
                    connection.IsRedirect = true;
                }

                if (addr == null)
                {
                    break;
                }

                string address = NetworkUtils.ToString(addr, subport);
                if (RemoteAddressProvider is ConfigurableAddressProvider)
                {
                    StreamProvider.RemoteAddress = ((ConfigurableAddressProvider)RemoteAddressProvider).RemoteHostAddress;
                }

                if (addresses.Length > 1)
                {
                    addresses.Append(", ");
                }
                addresses.Append(address);

                // create and configure a new client
                TcpClient client = InstantiateClient();
                try
                {
                    if (enmrRedirect == null)
                    {
                        CacheFactory.Log("Connecting Socket to " + address,
                                         CacheFactory.LogLevel.Debug);
                    }
                    else
                    {
                        CacheFactory.Log("Redirecting Socket to " + address,
                                         CacheFactory.LogLevel.Debug);
                    }

                    IAsyncResult result = client.BeginConnect(addr.Address, addr.Port, null, null);
                    result.AsyncWaitHandle.WaitOne(cMillis);
                    if (!client.Connected)
                    {
                        CacheFactory.Log("Error connecting TcpClient to "
                                         + address + ": connection timeout", CacheFactory.LogLevel.Info);
                        NetworkUtils.Close(client);
                        continue;
                    }

                    CacheFactory.Log("Connected TcpClient to " + address,
                                     CacheFactory.LogLevel.Info);
                    connection.Client = client;
                }
                catch (Exception e)
                {
                    cause = e;
                    CacheFactory.Log("Error connecting TcpClient to "
                                     + address + ": " + e, CacheFactory.LogLevel.Info);

                    NetworkUtils.Close(client);

                    // if we aren't current redirecting, or we've tried the last redirect
                    // address, reject the last address supplied by the address provider
                    if (enmrRedirect == null || addrNext == null)
                    {
                        provider.Reject(e);
                    }
                    continue;
                }

                // write out subport info
                if (subport != -1)
                {
                    bool   secure = connection.IsSecure;
                    Stream stream = connection.Stream = StreamProvider.GetStream(client);
                    if (secure)
                    {
                        Monitor.Enter(stream);
                    }

                    try
                    {
                        NetworkUtils.WriteSubport(stream, subport);
                    }
                    catch (Exception e)
                    {
                        CacheFactory.Log("Error connecting TcpClient to "
                                         + address + ": " + e, CacheFactory.LogLevel.Info);
                        throw new ConnectionException(e);
                    }
                    finally
                    {
                        if (secure)
                        {
                            Monitor.Exit(stream);
                        }
                    }
                }

                try
                {
                    connection.Open();
                }
                catch (Exception e)
                {
                    if (enmrRedirect == null && connection.IsRedirect)
                    {
                        IList list = connection.RedirectList;

                        // create an IPEndPoint list from from the redirect list
                        var listRedirect = new ArrayList(list.Count);
                        var listSubport  = new ArrayList(list.Count);
                        foreach (var o in list)
                        {
                            var ao     = (Object[])o;
                            var s      = (String)ao[0];
                            var port32 = new Port32((Int32)ao[1]);
                            try
                            {
                                listRedirect.Add(new IPEndPoint(NetworkUtils.GetHostAddress(s, ConnectTimeout),
                                                                port32.Baseport));
                                listSubport.Add(port32.Subport);
                            }
                            catch (Exception)
                            {
                                // invalid or unresolvable address
                                CacheFactory.Log("Skipping unresolvable address \"" + s + "\".",
                                                 CacheFactory.LogLevel.Info);
                            }
                        }
                        enmrRedirect = listRedirect.GetEnumerator();
                        enmrSubport  = listSubport.GetEnumerator();
                        if (enmrRedirect.MoveNext() && enmrSubport.MoveNext())
                        {
                            addrNext    = (IPEndPoint)enmrRedirect.Current;
                            subportNext = (Int32)enmrSubport.Current;
                        }
                        else
                        {
                            addrNext    = null;
                            subportNext = -1;
                        }
                    }
                    else
                    {
                        CacheFactory.Log("Error establishing a connection with " + address + ": " + e,
                                         CacheFactory.LogLevel.Info);

                        // if we aren't current redirecting, or we've tried the last redirect
                        // address, reject the last address supplied by the address provider
                        if (enmrRedirect == null || addrNext == null)
                        {
                            provider.Reject(e);
                        }
                    }
                    continue;
                }

                provider.Accept();
                return(connection);
            }
            addresses.Append(']');

            String message = "could not establish a connection "
                             + "to one of the following addresses: " + addresses
                             + "; make sure the \"remote-addresses\" configuration "
                             + "element contains an address and port of a running "
                             + "TcpAcceptor";

            throw cause == null ? new ConnectionException(message)
                    : new ConnectionException(message, cause);
        }