public WebSocketChannel(TcpChannel source) : this() { if (source == null) throw new ArgumentNullException("source"); this.messageSource = source; this.initSource = new HttpChannel(source); this.State = WebChannelState.Initializing; }
private void Process() { // wait for clients and process channels and changes var resourceListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 9242); //var liveListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 9234); var liveWire = new LiveWire.LiveWireServer(); liveWire.Start(); resourceListener.Start(); //liveListener.Start(); Console.WriteLine("Started server on port 9242"); while (!stopSignal.WaitOne(16)) { liveWire.Process(); // accept new clients if (resourceListener.Pending()) { var client = resourceListener.AcceptTcpClient(); //client.NoDelay = true; //client.ReceiveTimeout = 1; //client.SendTimeout = 1; var baseChannel = new TcpChannel(client); var channel = new HttpChannel(baseChannel); //var channel = new WebSocketChannel(baseChannel); AddChannelPrototype(channel); } // if (liveListener.Pending()) { // var client = liveListener.AcceptTcpClient(); // var baseChannel = new TcpChannel(client); // var channel = new WebSocketChannel(baseChannel); // AddChannelPrototype(channel); // } List <IWebChannel> toClose = new List <IWebChannel>(); foreach (var c in channels) { c.Process(); if (c.State == WebChannelState.InitFailed || c.State == WebChannelState.Closed) { toClose.Add(c); continue; } if (c.AvailableMessageNo > 0) { var wc = c as WebSocketChannel; if (wc != null) { WebSocketMessage message = wc.EmitMessage(); string text = message.Text; Console.WriteLine("received: " + text); //string updateMsg = "{ 'type': 'request', Console.WriteLine("circling that"); //string updateMsg = "{ 'sender': 'minority', 'type': 'config', 'update', 'content': 'sent to update division' }"; //Console.WriteLine("sending update: " + updateMsg); //Thread.Sleep(1000); JsonString str = JsonString.Parse(text); str.AddTerminal("text", "tentacles"); wc.SendMessage(new WebSocketMessage(str.ToJsonString())); wc.SendMessage(new WebSocketMessage("{\"type\":\"update\", \"subject\":\"content\" }")); } var hc = c as HttpChannel; if (hc != null) { HttpMessage message = hc.EmitMessage(); //Console.WriteLine("message: "); //Console.WriteLine(message.Header.ToString()); //Console.WriteLine(Encoding.UTF8.GetString(message.Content)); string resource = message.Header.Resource; byte[] responseContent = new Services.ResourceWireServer().ProvideResource(resource); HttpHeader responseHeader; if (responseContent.Length > 0) { responseHeader = new HttpHeader(HttpMethod.Response, resource, message.Header.Version, HttpStatusCode.OK); if (resource.EndsWith(".js")) { responseHeader.Fields.Add("Content-Type", "text/javascript; charset=UTF-8"); } else if (resource.EndsWith(".html") || resource.Equals("/")) { responseHeader.Fields.Add("Content-Type", "text/html; charset=UTF-8"); } else if (resource.EndsWith(".css")) { responseHeader.Fields.Add("Content-Type", "text/css; charset=UTF-8"); } else if (resource.EndsWith(".ico")) { responseHeader.Fields.Add("Content-Type", "image/vnd.microsoft.icon"); } else if (resource.EndsWith(".svg")) { responseHeader.Fields.Add("Content-Type", "image/svg+xml"); } else { responseHeader.Fields.Add("Content-Type", "text/plain; charset=UTF-8"); } responseHeader.Fields.Add("Content-Encoding", "identity"); responseHeader.Fields.Add("Content-Length", string.Format("{0}", responseContent.Length)); //responseHeader.Fields.Add("Transfer-Encoding", "identity"); responseHeader.Fields.Add("Connection", "close"); } else { responseHeader = new HttpHeader(HttpMethod.Response, resource, message.Header.Version, HttpStatusCode.NotFound); responseHeader.Fields.Add("Content-Length", "0"); //responseHeader.Fields.Add("Transfer-Encoding", "identity"); responseHeader.Fields.Add("Connection", "close"); } responseHeader.Fields.Add("Server", "Irseny"); responseHeader.Fields.Add("Date", DateTime.UtcNow.ToString()); var response = new HttpMessage(responseHeader, responseContent); hc.SendMessage(response); hc.Close(); } } } foreach (IWebChannel c in toClose) { c.Close(); Console.WriteLine("closed client " + channels.IndexOf(c)); channels.Remove(c); } } foreach (var c in channels) { c.Close(); } resourceListener.Stop(); }
private void ProcessInit() { // continue initializing through the html channel initSource.Process(); // stop processing if something went wrong if (initSource.State == WebChannelState.Closed || initSource.State == WebChannelState.InitFailed) { State = WebChannelState.InitFailed; initSource = null; } // wait for the first header to arrive if (initSource.AvailableMessageNo > 0) { HttpHeader header = initSource.EmitMessage().Header; string headerKey = string.Empty; bool headerValid = false; bool canRecover = false; bool denySubprotocol = false; bool denyExtension = false; do { // check the header for errors if (header.Method != HttpMethod.Get) { break; } // TODO optional origin string connection; if (!header.Fields.TryGetValue("Connection", out connection)) { break; } if (!connection.ToLower().Contains("upgrade")) { break; } string upgrade; if (!header.Fields.TryGetValue("Upgrade", out upgrade)) { break; } if (!upgrade.ToLower().Contains("websocket")) { break; } if (!header.Fields.TryGetValue("Sec-WebSocket-Key", out headerKey)) { break; } string sVersion; if (header.Fields.TryGetValue("Sec-WebSocket-Version", out sVersion)) { // TODO improve detection bool acceptVersion = false; if (sVersion.Contains("13")) { acceptVersion = true; } if (!acceptVersion) { headerValid = false; canRecover = true; HttpHeader response = new HttpHeader(header.Version, HttpStatusCode.UpgradeRequired); response.Fields.Add("Sec-WebSocket-Version", "13"); initSource.SendMessage(new HttpMessage(response)); break; } } // this implementation does not support subprotocols or extensions // send null fields if these exist in the request if (header.Fields.ContainsKey("Subprotocol")) { denySubprotocol = true; } if (header.Fields.ContainsKey("Extension")) { denyExtension = true; } // TODO optional handle resource or send 404 not found headerValid = true; } while (false); if (!headerValid) { if (!canRecover) { // set the connection on ice if the setup failed State = WebChannelState.InitFailed; initSource.Close(false); initSource = null; } } else { // send an appropriate response header HttpHeader response = new HttpHeader(HttpVersion.Version11, HttpStatusCode.SwitchingProtocols); response.Fields.Add("Upgrade", "websocket"); response.Fields.Add("Connection", "Upgrade"); byte[] byteKey = Encoding.UTF8.GetBytes(headerKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); byte[] sha1Key = System.Security.Cryptography.SHA1.Create().ComputeHash(byteKey); string base64Key = Convert.ToBase64String(sha1Key); response.Fields.Add("Sec-WebSocket-Accept", base64Key); if (denySubprotocol) { response.Fields.Add("Subprotocol", "null"); } if (denyExtension) { response.Fields.Add("Extension", "null"); } initSource.SendMessage(new HttpMessage(response)); // since the upgrade is done no more http communication is necessary // ACK has to be sent first so initSource can not contain any websocket messages at this point initSource.Flush(); initSource.Close(false); initSource = null; // the handshake has been completed // messages can now be sent State = WebChannelState.Open; // continue with sending all pending messages foreach (WebSocketMessage send in toSend) { byte[] encoded = EncodeMessage(send); messageSource.SendMessage(encoded); } toSend.Clear(); } } }