/**
         * <summary>
         * Creates a client facade, tries to connect to remote server, in case
         * of success starts reader thread.</summary>
         *
         * <param name="clientId">Client identifier.</param>
         * <param name="srvAddr">Server to connect to.</param>
         * <param name="sslCtx">SSL context to use if SSL is enabled, <c>null</c> otherwise.</param>
         * <param name="connectTimeout">Connect timeout.</param>
         * <param name="marshaller">Marshaller to use in communication.</param>
         * <param name="credentials">Client credentials.</param>
         * <param name="top">Topology instance.</param>
         * <exception cref="IOException">If connection could not be established.</exception>
         */
        public GridClientTcpConnection(Guid clientId, IPEndPoint srvAddr, IGridClientSslContext sslCtx, int connectTimeout,
                                       IGridClientMarshaller marshaller, Object credentials, GridClientTopology top)
            : base(clientId, srvAddr, sslCtx, credentials, top)
        {
            this.marshaller = marshaller;

            if (connectTimeout <= 0)
            {
                connectTimeout = (int)SOCK_READ_TIMEOUT.TotalMilliseconds;
            }

            Dbg.Assert(connectTimeout > 0, "connectTimeout > 0");

            int       retries    = 3;
            Exception firstCause = null;

            do
            {
                if (retries-- <= 0)
                {
                    throw new IOException("Cannot open socket for address: " + srvAddr, firstCause);
                }

                if (tcp != null)
                {
                    Dbg.WriteLine("Connection to address {0} failed, try re-connect", srvAddr);
                }

                try {
                    // Create a TCP/IP client socket.
                    tcp = new TcpClient();

                    tcp.ReceiveTimeout = connectTimeout;
                    tcp.SendTimeout    = connectTimeout;

                    // Open connection.
                    tcp.Connect(srvAddr);
                }
                catch (Exception x) {
                    if (firstCause == null)
                    {
                        firstCause = x;
                    }

                    if (tcp != null && tcp.Connected)
                    {
                        tcp.Close();
                    }

                    continue;
                }
            } while (!tcp.Connected);

            if (sslCtx == null)
            {
                stream = tcp.GetStream();
            }
            else
            {
                stream = sslCtx.CreateStream(tcp);

                lock (stream) {
                    // Flush client authentication packets (if any).
                    stream.Flush();
                }
            }

            // Avoid immediate attempt to close by idle.
            lastPacketSndTime = lastPacketRcvTime = lastPingSndTime = lastPingRcvTime = U.Now;

            rdr = new Thread(readPackets);

            rdr.Name = "grid-tcp-connection--client#" + clientId + "--addr#" + srvAddr;

            //Dbg.WriteLine("Start thread: " + rdr.Name);

            rdr.Start();
        }