Example #1
0
        private async void ProcessWebsocketRequest(TcpClient client, HttpRequestHeader req)
        {
            try
            {
                int REPO_IDLE_TIMEOUT = req.Repository.WebSocketIdelTimeout;
                int CHANCES           = req.Repository.WebSocketIdelChances;
                if (CHANCES == -1)
                {
                    CHANCES = int.MinValue;
                }

                NetworkStream stream                = client.GetStream();
                const string  WEBSOCKET_GUID        = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
                int           SEC_WEBSOCKET_VERSION = int.Parse(req.HeaderKeys["Sec-WebSocket-Version"]);
                string        SEC_WEBSOCKET_KEY     = req.HeaderKeys["Sec-WebSocket-Key"];

                IronPythonObject ipy = PythonRunner.InitializeForWebsocket(req);

                // فقط لهذا الإصدار
                if (SEC_WEBSOCKET_VERSION == 13)
                {
                    #region Handshake
                    byte[] SWKA          = System.Security.Cryptography.SHA1.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(SEC_WEBSOCKET_KEY + WEBSOCKET_GUID));
                    string Base64Sha1Key = Convert.ToBase64String(SWKA);

                    HttpRespondHeader resh = new HttpRespondHeader();
                    resh.SetState(req.HttpVersion, HttpRespondState.SWITCHING_PROTOCOLS);
                    resh.AddHeader("Server", HttpRespondHeader.CurrentServerVersion.ToString());
                    resh.AddHeader("Connection", "Upgrade");
                    resh.AddHeader("Upgrade", "websocket");
                    resh.AddHeader("Sec-WebSocket-Accept", Base64Sha1Key + "\r\n");
                    await stream.WriteAsync(resh.GetHeaderBytes());

                    await stream.FlushAsync();

                    #endregion

                    List <byte[]> Buffer      = new List <byte[]>();
                    string        LastMessage = string.Empty;

                    while (!IsSuspended && Active && client.Connected)
                    {
                        #region Idle section
                        if (!stream.DataAvailable)
                        {
                            if (!client.Connected)
                            {
                                return;
                            }
                            else
                            {
SPIN_STATE:
                                if (!System.Threading.SpinWait.SpinUntil(() => stream.DataAvailable && client.Available != 0, REPO_IDLE_TIMEOUT))
                                {
                                    if (CHANCES == int.MinValue)
                                    {
                                        goto SPIN_STATE;
                                    }
                                    else if (CHANCES == 0)
                                    {
                                        await CloseConnection(stream, client);

                                        client.Close();
                                        return;
                                    }
                                    else
                                    {
                                        CHANCES--;
                                    }
                                }
                            }
                        }
                        #endregion

                        byte[] buffer = new byte[client.Available];

                        if (await stream.ReadAsync(buffer, 0, buffer.Length) == 0)
                        {
                            continue;
                        }

LOOP:

                        if (buffer.Length == 0)
                        {
                            continue;
                        }

                        #region IF CLIENT WANTS TO CLOSE THE CONNECION
                        if (buffer[0] == 0b10001000)
                        {
                            await CloseConnection(stream, client);

                            client.Close();
                            return;
                        }
                        #endregion


                        bool FIN  = (buffer[0] & 0b10000000) != 0; //(buffer[0] & 0b10000000) != 0;
                        bool MASK = (buffer[1] & 0b10000000) != 0;

                        int OPCODE      = buffer[0] & 0b00001111;
                        int MESSAGE_LEN = buffer[1] & 0b01111111; // - 128
                        int OFFSET      = 2;

                        if (MESSAGE_LEN == 0)
                        {
                            continue;
                        }
                        else if (MESSAGE_LEN == 126)
                        {
                            MESSAGE_LEN = BitConverter.ToUInt16(new byte[] { buffer[3], buffer[2] }, 0);
                            OFFSET      = 4;
                        }
                        else if (MESSAGE_LEN == 127)
                        {
                            MESSAGE_LEN = (int)BitConverter.ToUInt64(new byte[] { buffer[9], buffer[8], buffer[7], buffer[6], buffer[5], buffer[4], buffer[3], buffer[2] }, 0);
                            OFFSET      = 10;
                        }


                        if (!MASK)
                        {
                            await CloseConnection(stream, client); return;
                        }
                        else if (MASK)
                        {
                            byte[] decoded = new byte[MESSAGE_LEN];
                            byte[] masks   = new byte[4] {
                                buffer[OFFSET], buffer[OFFSET + 1], buffer[OFFSET + 2], buffer[OFFSET + 3]
                            };
                            OFFSET += 4;

                            for (int i = 0; i < MESSAGE_LEN; ++i)
                            {
                                decoded[i] = (byte)(buffer[OFFSET + i] ^ masks[i % 4]);
                            }

                            buffer = buffer[(MESSAGE_LEN + OFFSET)..];