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(); } }
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); } } } }
private void Braodcast(EngineIOPacket Packet, Action Callback) { foreach (EngineIOSocket Socket in _Clients.Values) { Socket.Send(Packet); } Callback?.Invoke(); }
public EngineIOServer Broadcast(string Data, Action Callback = null) { if (!string.IsNullOrEmpty(Data)) { Braodcast(EngineIOPacket.CreateMessagePacket(Data), Callback); } return(this); }
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); }); }
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(); } }
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); } }
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); } }
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(); }
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; } } }
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(); }
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); }
protected void OnPacket(EngineIOPacket Packet) { OnPacket(SocketIOPacket.Decode(Packet)); }
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);
public EngineIOClient Send(byte[] RawData, Action Callback = null) { Send(EngineIOPacket.CreateMessagePacket(RawData ?? new byte[0]), Callback); return(this); }
public EngineIOClient Send(string Data, Action Callback = null) { Send(EngineIOPacket.CreateMessagePacket(Data ?? string.Empty), Callback); return(this); }