public static PoolConnection CreatePoolConnection(Client client, string url, int port, string login, string password)
        {
            string credential = url + port.ToString() + login + password;

            PoolConnection lpc, mypc = null;

            int batchCounter = 0;

            while (Connections.TryGetValue(credential + batchCounter.ToString(), out lpc))
            {
                if (lpc.WebClients.Count > MainClass.BatchSize)
                {
                    batchCounter++;
                }
                else
                {
                    mypc = lpc; break;
                }
            }

            credential += batchCounter.ToString();


            if (mypc == null)
            {
                CConsole.ColorInfo(() =>
                {
                    Console.WriteLine("{0}: initiated new pool connection", client.WebSocket.ConnectionInfo.Id);
                    Console.WriteLine("{0} {1} {2}", login, password, url);
                });


                mypc             = new PoolConnection();
                mypc.Credentials = credential;
                mypc.LastSender  = client;

                mypc.TcpClient = new TcpClient();

                Fleck.SocketExtensions.SetKeepAlive(mypc.TcpClient.Client, 60000, 1000);
                mypc.TcpClient.Client.ReceiveBufferSize = 4096 * 2;

                mypc.Login    = login;
                mypc.Password = password;
                mypc.Port     = port;
                mypc.Url      = url;

                mypc.WebClients.TryAdd(client);

                Connections.TryAdd(credential, mypc);

                try { mypc.TcpClient.Client.BeginConnect(url, port, new AsyncCallback(ConnectCallback), mypc); } catch { }
            }
            else
            {
                Console.WriteLine("{0}: reusing pool connection", client.WebSocket.ConnectionInfo.Id);

                mypc.WebClients.TryAdd(client);

                if (mypc.LastJob != null)
                {
                    ReceiveJob(client, mypc.LastJob, mypc.LastSolved);
                }
                else
                {
                    Console.WriteLine("{0} no job yet.", client.WebSocket.ConnectionInfo.Id);
                }
            }

            client.PoolConnection = mypc;

            return(mypc);
        }
        private static void ReceiveCallback(IAsyncResult result)
        {
            PoolConnection mypc   = result.AsyncState as PoolConnection;
            TcpClient      client = mypc.TcpClient;

            if (mypc.Closed || !client.Connected)
            {
                return;
            }

            NetworkStream networkStream;

            try { networkStream = client.GetStream(); } catch { return; }

            int bytesread = 0;

            try { bytesread = networkStream.EndRead(result); } catch { return; }

            string json = string.Empty;

            try
            {
                if (bytesread == 0) // disconnected
                {
                    // slow that down a bit to avoid negative feedback loop

                    Task.Run(async delegate
                    {
                        await Task.Delay(TimeSpan.FromSeconds(4));

                        List <Client> cllist = new List <Client>(mypc.WebClients.Values);
                        foreach (Client ev in cllist)
                        {
                            Disconnect(ev, "lost pool connection.");
                        }
                    });

                    return;
                }

                json = Encoding.ASCII.GetString(mypc.ReceiveBuffer, 0, bytesread);

                networkStream.BeginRead(mypc.ReceiveBuffer, 0, mypc.ReceiveBuffer.Length, new AsyncCallback(ReceiveCallback), mypc);
            }
            catch { return; }

            if (bytesread == 0 || string.IsNullOrEmpty(json))
            {
                return;                                               //?!
            }
            var msg = json.FromJson <JsonData>();

            if (msg == null)
            {
                return;
            }

            if (string.IsNullOrEmpty(mypc.PoolId))
            {
                // this "protocol" is strange
                if (!msg.ContainsKey("result"))
                {
                    string additionalInfo = "none";

                    // try to get the error
                    if (msg.ContainsKey("error"))
                    {
                        msg = msg["error"] as JsonData;

                        if (msg != null && msg.ContainsKey("message"))
                        {
                            additionalInfo = msg["message"].GetString();
                        }
                    }

                    List <Client> cllist = new List <Client>(mypc.WebClients.Values);
                    foreach (Client ev in cllist)
                    {
                        Disconnect(ev, "can not connect. additional information: " + additionalInfo);
                    }

                    return;
                }

                msg = msg["result"] as JsonData;

                if (msg == null)
                {
                    return;
                }
                if (!msg.ContainsKey("id"))
                {
                    return;
                }
                if (!msg.ContainsKey("job"))
                {
                    return;
                }

                mypc.PoolId = msg["id"].GetString();

                var lastjob = msg["job"] as JsonData;

                if (!VerifyJob(lastjob))
                {
                    CConsole.ColorWarning(() =>
                                          Console.WriteLine("Failed to verify job: {0}", json));
                    return;
                }

                // extended stratum
                if (!lastjob.ContainsKey("variant"))
                {
                    lastjob.Add("variant", mypc.DefaultVariant);
                }
                if (!lastjob.ContainsKey("algo"))
                {
                    lastjob.Add("algo", mypc.DefaultAlgorithm);
                }
                AlgorithmHelper.NormalizeAlgorithmAndVariant(lastjob);

                mypc.LastJob         = lastjob;
                mypc.LastInteraction = DateTime.Now;

                mypc.LastSolved = new CcHashset <string>();

                List <Client> cllist2 = new List <Client>(mypc.WebClients.Values);
                foreach (Client ev in cllist2)
                {
                    ReceiveJob(ev, mypc.LastJob, mypc.LastSolved);
                }
            }
            else if (msg.ContainsKey("method") && msg["method"].GetString() == "job")
            {
                if (!msg.ContainsKey("params"))
                {
                    return;
                }

                var lastjob = msg["params"] as JsonData;

                if (!VerifyJob(lastjob))
                {
                    CConsole.ColorWarning(() =>
                                          Console.WriteLine("Failed to verify job: {0}", json));
                    return;
                }

                // extended stratum
                if (!lastjob.ContainsKey("variant"))
                {
                    lastjob.Add("variant", mypc.DefaultVariant);
                }
                if (!lastjob.ContainsKey("algo"))
                {
                    lastjob.Add("algo", mypc.DefaultAlgorithm);
                }
                AlgorithmHelper.NormalizeAlgorithmAndVariant(lastjob);

                mypc.LastJob         = lastjob;
                mypc.LastInteraction = DateTime.Now;
                mypc.LastSolved      = new CcHashset <string>();

                List <Client> cllist2 = new List <Client>(mypc.WebClients.Values);

                Console.WriteLine("Sending job to {0} client(s)!", cllist2.Count);

                foreach (Client ev in cllist2)
                {
                    ReceiveJob(ev, mypc.LastJob, mypc.LastSolved);
                }
            }
            else
            {
                if (msg.ContainsKey("error"))
                {
                    // who knows?
                    ReceiveError(mypc.LastSender, msg);
                }
                else
                {
                    CConsole.ColorWarning(() =>
                                          Console.WriteLine("Pool is sending nonsense."));
                }
            }
        }