Beispiel #1
0
        private void OnPollRequest(HttpListenerRequest Request, HttpListenerResponse Response)
        {
            try
            {
                if (PollRequest == null)
                {
                    PollRequest  = Request;
                    PollResponse = Response;

                    Semaphore.Release();
                    Writable = true;
                    Emit(Event.DRAIN);

                    if (Writable && ShouldClose != null)
                    {
                        Send(EngineIOPacket.CreateNoopPacket().Encode(EngineIOTransportType.polling, ForceBase64), OnPollRequestClose);
                    }
                }
                else
                {
                    throw new EngineIOException("Overlap from client");
                }
            }
            catch (Exception Exception)
            {
                CloseResponse(Response);
                OnPollRequestClose(Exception);
            }
        }
 internal static SocketIOPacket Decode(EngineIOPacket EngineIOPacket)
 {
     if ((EngineIOPacket?.Type ?? EngineIOPacketType.UNKNOWN) == EngineIOPacketType.MESSAGE)
     {
         try
         {
             if (EngineIOPacket.IsText)
             {
                 return(Decode(EngineIOPacket.Data));
             }
             else
             {
                 return(Decode(EngineIOPacket.RawData));
             }
         }
         catch (Exception Exception)
         {
             throw new SocketIOException("Packet decoding failed. " + EngineIOPacket, Exception);
         }
     }
     else
     {
         throw new SocketIOException("Type of Engine.IO packet is not message.");
     }
 }
 protected override void SendInternal(EngineIOPacket Packet)
 {
     if (Packet != null)
     {
         Request(EngineIOHttpMethod.POST, Packet.Encode(EngineIOTransportType.polling, Option.ForceBase64), (Exception) => OnError("Post error", Exception));
     }
 }
        private void OnWebSocketMessage(object sender, MessageEventArgs e)
        {
            if (e.IsText || e.IsBinary)
            {
                EngineIOPacket Packet;

                if (e.IsText)
                {
                    Packet = EngineIOPacket.Decode(e.Data);
                }
                else
                {
                    Packet = EngineIOPacket.Decode(e.RawData);
                }

                if (Packet.Type != EngineIOPacketType.CLOSE)
                {
                    OnPacket(Packet);

                    if (Packet.Type == EngineIOPacketType.OPEN)
                    {
                        Writable = true;
                    }
                }
                else
                {
                    Close();
                }
            }
        }
        private void OnWebSocketMessage(object sender, MessageEventArgs e)
        {
            NameValueCollection Headers = new NameValueCollection();

            Emit(Event.HEADERS, Headers);

            if (Headers.Count > 0)
            {
                Dictionary <string, string> CustomHeaders = new Dictionary <string, string>();

                foreach (string Key in Headers.AllKeys)
                {
                    CustomHeaders[Key] = Headers[Key];
                }

                Client.CustomHeaders = CustomHeaders;
            }

            EngineIOPacket Packet = EngineIOPacket.Decode(e);

            if (Packet.Type != EngineIOPacketType.CLOSE)
            {
                OnPacket(Packet);
            }
            else
            {
                Close();
            }
        }
Beispiel #6
0
        private void OnPacket(EngineIOPacket Packet)
        {
            if (ReadyState == EngineIOReadyState.OPEN)
            {
                Emit(Event.PACKET, Packet);

                ResetPongTimer(Server.Option.PingInterval + Server.Option.PingTimeout);
                ResetPingTimer();

                switch (Packet.Type)
                {
                case EngineIOPacketType.PING:
                    Send(EngineIOPacket.CreatePongPacket(Packet.Data));
                    Emit(Event.HEARTBEAT);
                    break;

                case EngineIOPacketType.PONG:
                    SimpleMutex.Lock(PongMutex, () => Pong++);
                    Emit(Event.HEARTBEAT);
                    break;

                case EngineIOPacketType.MESSAGE:
                    Emit(Event.MESSAGE, Packet);
                    break;

                case EngineIOPacketType.UNKNOWN:
                    OnClose(string.Format("Parse error : {0}", Packet.Data));
                    break;
                }
            }
        }
        private void HandleResponse(EngineIOHttpMethod Method, HttpWebResponse Response)
        {
            using (Response)
            {
                if (Response.StatusCode == HttpStatusCode.OK)
                {
                    if (Option.WithCredentials)
                    {
                        Cookies.Add(Response.Cookies);
                    }

                    if (Method == EngineIOHttpMethod.GET)
                    {
                        EngineIOPacket[] Packets = EngineIOPacket.Decode(Response);

                        if ((Packets?.Length ?? 0) > 0)
                        {
                            foreach (EngineIOPacket Packet in Packets)
                            {
                                if (Packet.Type != EngineIOPacketType.CLOSE)
                                {
                                    if (ReadyState == EngineIOReadyState.OPENING)
                                    {
                                        OnOpen();
                                    }

                                    OnPacket(Packet);

                                    if (Packet.Type == EngineIOPacketType.OPEN)
                                    {
                                        Writable = true;
                                    }
                                }
                                else
                                {
                                    OnClose();
                                }
                            }

                            if (ReadyState != EngineIOReadyState.CLOSED)
                            {
                                Polling = false;
                                Emit(Event.POLL_COMPLETE);

                                if (ReadyState == EngineIOReadyState.OPEN)
                                {
                                    ThreadPool.QueueUserWorkItem((_) => Poll());
                                }
                            }
                        }
                    }
                    else if (Method == EngineIOHttpMethod.POST)
                    {
                        Writable = true;
                        Emit(Event.DRAIN);
                    }
                }
            }
        }
Beispiel #8
0
        private void Braodcast(EngineIOPacket Packet, Action Callback)
        {
            foreach (EngineIOSocket Socket in _Clients.Values)
            {
                Socket.Send(Packet);
            }

            Callback?.Invoke();
        }
Beispiel #9
0
        public EngineIOServer Broadcast(string Data, Action Callback = null)
        {
            if (!string.IsNullOrEmpty(Data))
            {
                Braodcast(EngineIOPacket.CreateMessagePacket(Data), Callback);
            }

            return(this);
        }
Beispiel #10
0
        public EngineIOServer Broadcast(byte[] RawData, Action Callback = null)
        {
            if ((RawData?.Length ?? 0) > 0)
            {
                Braodcast(EngineIOPacket.CreateMessagePacket(RawData), Callback);
            }

            return(this);
        }
 private void StartPingTimer()
 {
     SimpleMutex.Lock(PingMutex, () =>
     {
         PingTimer = new EngineIOTimeout(() =>
         {
             Send(EngineIOPacket.CreatePingPacket());
             ResetPongTimer(Server.Option.PingTimeout);
         }, Server.Option.PingInterval * 1.1);
     });
 }
Beispiel #12
0
        internal void Send(EngineIOPacket Packet, Action Callback = null)
        {
            if (ReadyState == EngineIOReadyState.OPENING || ReadyState == EngineIOReadyState.OPEN)
            {
                Emit(Event.PACKET_CREATE, Packet);
                SimpleMutex.Lock(BufferMutex, () => PacketBuffer.Enqueue(Packet));

                Once(Event.FLUSH, Callback);
                Flush();
            }
        }
Beispiel #13
0
        private void StartHeartbeat()
        {
            SimpleMutex.Lock(PingMutex, () =>
            {
                if (PingTimer == null && Handshake != null)
                {
                    ulong PingInterval = Handshake.PingInterval;

                    PingTimer          = new Timer(PingInterval / 2.0);
                    PingTimer.Elapsed += (_, __) =>
                    {
                        SimpleMutex.Lock(PingMutex, () =>
                        {
                            PingTimer.Interval = PingInterval;
                            Send(EngineIOPacket.CreatePingPacket());

                            SimpleMutex.Lock(PongMutex, () =>
                            {
                                if (PongTimer == null && Handshake != null)
                                {
                                    PongTimer          = new Timer(Handshake.PingTimeout);
                                    PongTimer.Elapsed += (___, ____) =>
                                    {
                                        SimpleMutex.Lock(PongMutex, () =>
                                        {
                                            if (Pong > 0)
                                            {
                                                Pong = 0;
                                            }
                                            else
                                            {
                                                OnClose("Heartbeat timeout");
                                            }
                                        });
                                    };

                                    PongTimer.AutoReset = false;
                                }

                                if (!PongTimer.Enabled)
                                {
                                    PongTimer.Start();
                                }
                            });
                        });
                    };

                    PingTimer.AutoReset = true;
                    PingTimer.Start();
                }
            });
        }
        protected override void CloseInternal()
        {
            void OnClose() => Send(EngineIOPacket.CreateClosePacket());

            if (ReadyState == EngineIOReadyState.OPEN)
            {
                OnClose();
            }
            else
            {
                Once(Event.OPEN, OnClose);
            }
        }
Beispiel #15
0
        private void OnDataRequest(HttpListenerRequest Request, HttpListenerResponse Response)
        {
            using (Response)
            {
                try
                {
                    if (DataRequest == null)
                    {
                        EngineIOPacket[] Packets = EngineIOPacket.Decode(Request);
                        Response.Headers = SetHeaders(Response.Headers);

                        using (Response.OutputStream)
                        {
                            Response.KeepAlive = false;

                            Response.ContentType     = "text/html";
                            Response.ContentEncoding = Encoding.UTF8;
                            Response.ContentLength64 = 2;

                            Response.OutputStream.Write(Encoding.UTF8.GetBytes("ok"), 0, 2);
                        }

                        foreach (EngineIOPacket Packet in Packets)
                        {
                            if (Packet.Type != EngineIOPacketType.CLOSE)
                            {
                                OnPacket(Packet);
                            }
                            else
                            {
                                OnClose();
                            }
                        }

                        CleanupDataRequest();
                    }
                    else
                    {
                        throw new EngineIOException("Data request overlap from client");
                    }
                }
                catch (Exception Exception)
                {
                    CloseResponse(Response);
                    OnDataRequestClose(Exception);
                }
            }
        }
        private void StartCheckTimer()
        {
            SimpleMutex.Lock(CheckMutex, () =>
            {
                CheckTimer          = new Timer(100);
                CheckTimer.Elapsed += (_, __) =>
                {
                    if (Transport is EngineIOPolling && Transport.Writable)
                    {
                        Transport.Send(EngineIOPacket.CreateNoopPacket());
                    }
                };

                CheckTimer.AutoReset = true;
                CheckTimer.Start();
            });
        }
        protected override void SendInternal(EngineIOPacket Packet)
        {
            if (Packet != null)
            {
                object EncodedPacket = Packet.Encode(EngineIOTransportType.websocket, Option.ForceBase64);

                if (EncodedPacket is string)
                {
                    WebSocket.Send(EncodedPacket as string);
                }
                else if (EncodedPacket is byte[])
                {
                    WebSocket.Send(EncodedPacket as byte[]);
                }

                Emit(Event.FLUSH);
                Emit(Event.DRAIN);
            }
        }
Beispiel #18
0
        protected override void CloseInternal(Action Callback)
        {
            void OnClose()
            {
                CloseTimer?.Stop();
                Callback?.Invoke();
                this.OnClose();
            }

            if (DataResponse != null)
            {
                try
                {
                    DataResponse.Headers = SetHeaders(DataResponse.Headers);
                    DataResponse.Close();
                }
                catch
                {
                }
            }

            DataRequest  = null;
            DataResponse = null;

            if (Writable)
            {
                Send(EngineIOPacket.CreateClosePacket().Encode(EngineIOTransportType.polling, ForceBase64));
                OnClose();
            }
            else if (Discarded)
            {
                OnClose();
            }
            else
            {
                ShouldClose = OnClose;
                CloseTimer  = new EngineIOTimeout(OnClose, 30 * 1000);
            }

            ConnectionTimer.Stop();
        }
Beispiel #19
0
        private void OnPacket(EngineIOPacket Packet)
        {
            if (ReadyState != EngineIOReadyState.CLOSED)
            {
                Emit(Event.PACKET, Packet);

                switch (Packet.Type)
                {
                case EngineIOPacketType.OPEN:
                    Emit(Event.HANDSHAKE);

                    Handshake = new EngineIOHandshake(Packet.Data);
                    Option.Query.Add("sid", Handshake.SID);

                    OnOpen();

                    if (ReadyState != EngineIOReadyState.CLOSED)
                    {
                        StartHeartbeat();
                    }
                    break;

                case EngineIOPacketType.PING:
                    Send(EngineIOPacket.CreatePongPacket(Packet.Data));
                    break;

                case EngineIOPacketType.PONG:
                    SimpleMutex.Lock(PongMutex, () => Pong++);
                    break;

                case EngineIOPacketType.MESSAGE:
                    Emit(Event.MESSAGE, Packet);
                    break;

                case EngineIOPacketType.UNKNOWN:
                    OnError(new EngineIOException(string.Format("Parse error : {0}", Packet.Data)));
                    break;
                }
            }
        }
Beispiel #20
0
        private void OnOpen()
        {
            ReadyState = EngineIOReadyState.OPEN;
            EngineIOServerOption Option = Server.Option;

            Transport.SID = SID;
            Send(EngineIOPacket.CreateOpenPacket(SID, Option.PingInterval, Option.PingTimeout, Option.WebSocket && Option.AllowUpgrade));

            object InitialData = Option.InitialData;

            if (InitialData is string)
            {
                Send(InitialData as string);
            }
            else if (InitialData is byte[])
            {
                Send(InitialData as byte[]);
            }

            Emit(Event.OPEN);
            ResetPingTimer();
        }
Beispiel #21
0
        internal void UpgradeTransport(EngineIOWebSocket Transport)
        {
            void OnTransportPacket(object Argument)
            {
                EngineIOPacket Packet = Argument as EngineIOPacket;

                if (Packet.Type == EngineIOPacketType.PING)
                {
                    Transport.Send(EngineIOPacket.CreatePongPacket(Packet.Data));
                    Emit(Event.UPGRADING);

                    ResetCheckTimer();
                }
                else
                {
                    Cleanup();

                    if (Packet.Type == EngineIOPacketType.UPGRADE && ReadyState != EngineIOReadyState.CLOSED)
                    {
                        this.Transport.Discard();
                        Upgraded = true;

                        ClearTransport();
                        SetTransport(Transport);

                        Emit(Event.UPGRADE);

                        ResetPingTimer();
                        Flush();

                        if (ReadyState == EngineIOReadyState.CLOSING)
                        {
                            this.Transport.Close(() =>
                            {
                                this.OnClose("Forced close.");
                            });
                        }
                    }
                    else
                    {
                        Transport.Close();
                    }
                }
            }

            void Cleanup()
            {
                Upgrading = false;

                StopCheckTimer();
                StopUpgradeTimer();

                Transport.Off(EngineIOTransport.Event.PACKET, OnTransportPacket);
                Transport.Off(EngineIOTransport.Event.CLOSE, OnTransportClose);
                Transport.Off(EngineIOTransport.Event.ERROR, OnTransportError);
            }

            void OnTransportError(object Exception)
            {
                EngineIOLogger.Error(this, Exception as Exception);

                Cleanup();
                Transport.Close();
            }

            void OnTransportClose()
            {
                OnTransportError(new EngineIOException("Transport closed."));
            }

            void OnClose()
            {
                OnTransportError(new EngineIOException("Socket closed."));
            }

            Upgrading = true;
            StartUpgradeTimer(() =>
            {
                Cleanup();

                if (Transport.ReadyState == EngineIOReadyState.OPEN)
                {
                    Transport.Close();
                }
            });

            Transport.On(EngineIOTransport.Event.PACKET, OnTransportPacket);
            Transport.Once(EngineIOTransport.Event.CLOSE, OnTransportClose);
            Transport.Once(EngineIOTransport.Event.ERROR, OnTransportError);

            Once(Event.CLOSE, OnClose);
        }
Beispiel #22
0
 protected void OnPacket(EngineIOPacket Packet)
 {
     OnPacket(SocketIOPacket.Decode(Packet));
 }
Beispiel #23
0
        private void Probe()
        {
            EngineIOWebSocket Transport = new EngineIOWebSocket(Option);
            bool Failed = PriorWebsocketSuccess = false;

            void OnTransportOpen()
            {
                string Message = "probe";

                Transport.Send(EngineIOPacket.CreatePingPacket(Message));
                Transport.Once(EngineIOTransport.Event.PACKET, (Packet) =>
                {
                    if (!Failed)
                    {
                        EngineIOPacket Temp = Packet is EngineIOPacket ? Packet as EngineIOPacket : EngineIOPacket.CreateClosePacket();

                        if (Temp.Type == EngineIOPacketType.PONG && Temp.Data.Equals(Message))
                        {
                            Upgrading = true;
                            Emit(Event.UPGRADING, Transport);

                            PriorWebsocketSuccess = true;

                            (this.Transport as EngineIOPolling).Pause(() =>
                            {
                                if (!Failed && ReadyState != EngineIOReadyState.CLOSED)
                                {
                                    CleanUp();

                                    SetTransport(Transport);
                                    Transport.Send(EngineIOPacket.CreateUpgradePacket());

                                    Emit(Event.UPGRADE, Transport);
                                    Upgrading = false;

                                    Flush();
                                }
                            });
                        }
                        else
                        {
                            Emit(Event.UPGRADE_ERROR, new EngineIOException("Probe error"));
                        }
                    }
                });
            }

            void OnTransportClose()
            {
                OnTransportError(new EngineIOException("Transport closed"));
            }

            void OnTransportError(object Exception)
            {
                string Message = "Probe error";

                Exception = Exception is Exception ? new EngineIOException(Message, Exception as Exception) : new EngineIOException(Message);

                FreezeTransport();
                Emit(Event.UPGRADE_ERROR, Exception as Exception);
            }

            void FreezeTransport()
            {
                if (!Failed)
                {
                    Failed = true;
                    CleanUp();

                    Transport.Close();
                    Transport = null;
                }
            }

            void OnClose()
            {
                OnError(new EngineIOException("Client closed"));
            }

            void OnUpgrade()
            {
                if (!(Transport is EngineIOWebSocket))
                {
                    FreezeTransport();
                }
            }

            void CleanUp()
            {
                Transport.Off(EngineIOTransport.Event.OPEN, OnTransportOpen);
                Transport.Off(EngineIOTransport.Event.ERROR, OnTransportError);
                Transport.Off(EngineIOTransport.Event.CLOSE, OnTransportClose);

                Off(Event.CLOSE, OnClose);
                Off(Event.UPGRADING, OnUpgrade);
            }

            Transport.Once(EngineIOTransport.Event.OPEN, OnTransportOpen);
            Transport.Once(EngineIOTransport.Event.ERROR, OnTransportError);
            Transport.Once(EngineIOTransport.Event.CLOSE, OnTransportClose);

            Once(Event.CLOSE, OnClose);
            Once(Event.UPGRADING, OnUpgrade);

            Transport.Open();
        }
        protected EngineIOTransport OnPacket(EngineIOPacket Packet)
        {
            Emit(Event.PACKET, Packet);

            return(this);
        }
 protected abstract void SendInternal(EngineIOPacket Packet);
Beispiel #26
0
        public EngineIOClient Send(byte[] RawData, Action Callback = null)
        {
            Send(EngineIOPacket.CreateMessagePacket(RawData ?? new byte[0]), Callback);

            return(this);
        }
Beispiel #27
0
        public EngineIOClient Send(string Data, Action Callback = null)
        {
            Send(EngineIOPacket.CreateMessagePacket(Data ?? string.Empty), Callback);

            return(this);
        }