private bool processFrame(WsFrame frame) { return frame.IsCompressed && _compression == CompressionMethod.NONE ? processUnsupportedFrame ( frame, CloseStatusCode.INCORRECT_DATA, "A compressed data has been received without available decompression method.") : frame.IsFragmented ? processFragmentedFrame (frame) : frame.IsData ? processDataFrame (frame) : frame.IsPing ? processPingFrame (frame) : frame.IsPong ? processPongFrame () : frame.IsClose ? processCloseFrame (frame) : processUnsupportedFrame (frame, CloseStatusCode.POLICY_VIOLATION, null); }
private bool processUnsupportedFrame(WsFrame frame, CloseStatusCode code, string reason) { _logger.Debug ("Unsupported frame:\n" + frame.PrintToString (false)); processException (new WebSocketException (code, reason), null); return false; }
private bool processCloseFrame(WsFrame frame) { var payload = frame.PayloadData; close (payload, !payload.ContainsReservedCloseStatusCode, false); return false; }
private bool processFragmentedFrame(WsFrame frame) { return frame.IsContinuation // Not first fragment ? true : processFragments (frame); }
private bool acceptFrame(WsFrame frame) { return frame.IsCompressed && _compression == CompressionMethod.None ? acceptUnsupportedFrame ( frame, CloseStatusCode.IncorrectData, "A compressed data has been received without available decompression method.") : frame.IsFragmented ? acceptFragmentedFrame (frame) : frame.IsData ? acceptDataFrame (frame) : frame.IsPing ? acceptPingFrame (frame) : frame.IsPong ? acceptPongFrame (frame) : frame.IsClose ? acceptCloseFrame (frame) : acceptUnsupportedFrame (frame, CloseStatusCode.PolicyViolation, null); }
private bool acceptPongFrame(WsFrame frame) { _receivePong.Set (); _logger.Trace ("Received a Pong."); return true; }
private bool processData(WsFrame frame) { if (!frame.IsData) return false; if (frame.IsCompressed && _compression == CompressionMethod.NONE) return false; var args = frame.IsCompressed ? new MessageEventArgs ( frame.Opcode, frame.PayloadData.ApplicationData.Decompress (_compression)) : new MessageEventArgs (frame.Opcode, frame.PayloadData); OnMessage.Emit (this, args); return true; }
private bool acceptDataFrame(WsFrame frame) { var args = frame.IsCompressed ? new MessageEventArgs ( frame.Opcode, frame.PayloadData.ApplicationData.Decompress (_compression)) : new MessageEventArgs (frame.Opcode, frame.PayloadData); if (_readyState == WebSocketState.Open) OnMessage.Emit (this, args); return true; }
private bool processAbnormal(WsFrame frame) { if (frame != null) return false; _logger.Trace ("Start closing handshake."); var code = CloseStatusCode.ABNORMAL; Close (code, code.GetMessage ()); return true; }
private bool processClose(WsFrame frame) { if (!frame.IsClose) return false; _logger.Trace ("Start closing handshake."); close (frame.PayloadData); return true; }
private bool processPong(WsFrame frame) { if (!frame.IsPong) return false; #if DEBUG Console.WriteLine("WS: Info@processPong: Receive Pong."); #endif _receivePong.Set(); return true; }
private bool processPing(WsFrame frame) { if (!frame.IsPing) return false; #if DEBUG Console.WriteLine("WS: Info@processPing: Return Pong."); #endif pong(frame.PayloadData); return true; }
private bool processClose(WsFrame frame) { if (!frame.IsClose) return false; #if DEBUG Console.WriteLine("WS: Info@processClose: Start closing handshake."); #endif close(frame.PayloadData); return true; }
private bool processAbnormal(WsFrame frame) { if (frame != null) return false; #if DEBUG Console.WriteLine("WS: Info@processAbnormal: Start closing handshake."); #endif var code = CloseStatusCode.ABNORMAL; Close(code, code.GetMessage()); return true; }
private bool processFragmented(WsFrame frame) { // Not first fragment if (frame.IsContinuation) return true; // Not fragmented if (frame.IsFinal) return false; bool incorrect = !frame.IsData || (frame.IsCompressed && _compression == CompressionMethod.NONE); if (!incorrect) processFragments (frame); else processIncorrectFrame (); return true; }
public bool WriteFrame(WsFrame frame) { lock (_forWrite) { try { var buffer = frame.ToBytes(); write(buffer, 0, buffer.Length); return true; } catch { return false; } } }
private void processFrame(WsFrame frame) { bool processed = processAbnormal (frame) || processFragmented (frame) || processData (frame) || processPing (frame) || processPong (frame) || processClose (frame); if (!processed) processIncorrectFrame (); }
private bool acceptFragmentedFrame(WsFrame frame) { return frame.IsContinuation // Not first fragment ? true : acceptFragments (frame); }
private bool processPing(WsFrame frame) { if (!frame.IsPing) return false; _logger.Trace ("Return Pong."); pong (frame.PayloadData); return true; }
private bool acceptPingFrame(WsFrame frame) { var mask = _client ? Mask.Mask : Mask.Unmask; if (send (WsFrame.CreatePongFrame (mask, frame.PayloadData))) _logger.Trace ("Returned a Pong."); return true; }
private bool processPong(WsFrame frame) { if (!frame.IsPong) return false; _logger.Trace ("Receive Pong."); _receivePong.Set (); return true; }
private bool send(WsFrame frame) { lock (_forConn) { if (_readyState != WebSocketState.Open) { _logger.Warn ("Sending has been interrupted."); return false; } return _stream.Write (frame.ToByteArray ()); } }
private bool send(WsFrame frame) { lock (_forFrame) { var ready = _stream == null ? false : _readyState == WebSocketState.OPEN ? true : _readyState == WebSocketState.CLOSING ? frame.IsClose : false; if (!ready) { var msg = "The WebSocket connection isn't established or has been closed."; _logger.Error (msg); error (msg); return false; } return _stream.WriteFrame (frame); } }
private bool processDataFrame(WsFrame frame) { var args = frame.IsCompressed ? new MessageEventArgs ( frame.Opcode, frame.PayloadData.ApplicationData.Decompress (_compression)) : new MessageEventArgs (frame.Opcode, frame.PayloadData); OnMessage.Emit (this, args); return true; }
private static WsFrame createControlFrame(Opcode opcode, PayloadData payloadData, bool client) { var mask = client ? Mask.MASK : Mask.UNMASK; var frame = new WsFrame (Fin.FINAL, opcode, mask, payloadData); return frame; }
private bool processFragments(WsFrame first) { using (var concatenated = new MemoryStream ()) { concatenated.WriteBytes (first.PayloadData.ApplicationData); if (!concatenateFragmentsInto (concatenated)) return false; byte [] data; if (_compression != CompressionMethod.NONE) { data = concatenated.DecompressToArray (_compression); } else { concatenated.Close (); data = concatenated.ToArray (); } OnMessage.Emit (this, new MessageEventArgs (first.Opcode, data)); return true; } }
private static WsFrame createFrame( Fin fin, Opcode opcode, PayloadData payloadData, bool compressed, bool client) { var mask = client ? Mask.MASK : Mask.UNMASK; var frame = new WsFrame (fin, opcode, mask, payloadData, compressed); return frame; }
private bool processPingFrame(WsFrame frame) { if (send (WsFrame.CreatePongFrame (_client ? Mask.MASK : Mask.UNMASK, frame.PayloadData))) _logger.Trace ("Returned Pong."); return true; }
public bool WriteFrame(WsFrame frame) { return Write (frame.ToByteArray ()); }
private bool send(WsFrame frame) { if (_readyState != WebSocketState.OPEN) { var msg = "A WebSocket connection isn't established or has been closed."; _logger.Error (msg); error (msg); return false; } return _stream.Write (frame.ToByteArray ()); }
private void ForwardStreamNew(Stream source, Stream destination, byte[] buffer, CommPacketDirection direction) { var rawVerbs = new string[] { "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT" }; byte[][] verbs = rawVerbs.Select(cur => Encoding.UTF8.GetBytes(cur).Take(2).ToArray()).ToArray(); Regex requestLinePattern = new Regex($"^({string.Join("|", rawVerbs)}) [^ ]+ HTTP/1.1$"); Regex contentLengthPattern = new Regex($"^Content-Length: ([0-9]+)$"); Regex chunkedPattern = new Regex($"^Transfer-Encoding: chunked$"); Regex statusLinePattern = new Regex($"^HTTP/1.1 ([0-9]+) (.*)$"); Regex websocketPlanet = new Regex("GET /([0-9]+)/websocket/game HTTP/1.1"); Regex udpPortPattern = new Regex("\"udpPort\"\\:([0-9]+)\\,"); try { destination = new BufferedStream(destination); } catch (Exception ex) { Log.Error(ex, "Error creating buffered stream"); return; } new Thread(() => { MemoryStream ms = null; try { bool isWebSocket = false; while (true) { try { destination.Flush(); } catch (Exception ex) { Log.Error(ex, "Error Flushing stream"); Kill(direction == CommPacketDirection.ServerToClient); } if (!m_connectionInstance.IsConnectionOpen) { break; } //if (ms != null) //{ // ms.Position = 0; // messagecache[direction].Enqueue(ms); //} //while (messagecache[direction].Count > 10) //{ // messagecache[direction].Dequeue(); //} ms = new MemoryStream(); StreamWriter sw = null; bool ReadBytes(int count) { int offset = 0; while (offset < count) { int bytesRead = 0; try { bytesRead = source.Read(buffer, offset, count - offset); } catch (Exception ex) { Log.Error(ex, "Error Reading stream"); Kill(direction == CommPacketDirection.ClientToServer); } if (bytesRead == 0) { return(false); } offset += bytesRead; } return(true); } string ReadLine() { List <byte> result = new List <byte>(); byte?prevByte = null; while (true) { byte[] readBuffer = new byte[1]; if (source.Read(readBuffer, 0, 1) != 1) { return(null); } result.Add(readBuffer[0]); if (prevByte == '\r' && readBuffer[0] == '\n') { break; } prevByte = readBuffer[0]; } return(Encoding.UTF8.GetString(result.ToArray()).TrimEnd('\r', '\n')); } void DoHttpHeadersContentAndForward() { List <string> headers = new List <string>(); ulong contentLength = 0; bool chunked = false; string curLine = null; while ((curLine = ReadLine()) != null && curLine != string.Empty) { sw.WriteLine(curLine); curLine = curLine.Trim(); Match m = contentLengthPattern.Match(curLine); if (m.Success) { contentLength = Convert.ToUInt64(m.Groups[1].Value); } m = chunkedPattern.Match(curLine); if (m.Success) { chunked = true; } headers.Add(curLine.ToLower()); } sw.WriteLine(); sw.Flush(); if (curLine == null) { throw new Exception("HTTP unexpected end of stream while reading headers"); } if (chunked && contentLength > 0) { throw new Exception("Chunked content with length not supported"); } void DoReadLength(ulong curLength) { while (curLength > 0) { int bytesRead = 0; try { bytesRead = source.Read(buffer, 0, Math.Min(buffer.Length, (int)Math.Min(int.MaxValue, curLength))); } catch (Exception ex) { Log.Error(ex, "Error reading bytes"); Kill(direction == CommPacketDirection.ClientToServer); } if (bytesRead == 0) { throw new Exception("HTTP unexpected end of stream while reading content"); } ms.Write(buffer, 0, bytesRead); curLength -= (ulong)bytesRead; } } DoReadLength(contentLength); if (chunked) { bool lastChunk = false; while (!lastChunk && (curLine = ReadLine()) != null && curLine != string.Empty) { sw.WriteLine(curLine); sw.Flush(); var length = ulong.Parse(curLine.Trim()); if (length > 0) { DoReadLength(length); } else { lastChunk = true; } curLine = ReadLine(); if (curLine == null || curLine.Length != 0) { throw new Exception("HTTP protocol failure"); } sw.WriteLine(); sw.Flush(); } } ms.Position = 0; if (!headers.Contains("content-type: application/json".ToLower())) { DestinationWrite(destination, ms.ToArray(), (int)ms.Length, direction); } else { var orgLength = ms.Length; string entireMessage = new StreamReader(ms).ReadToEnd(); ForwardHttpData(destination, entireMessage, direction); } } void forwardWebsocketFrame() { WsFrame frame = null; try { frame = new WsFrame(buffer, 2, source); } catch (Exception ex) { Log.Error(ex, "Error creating WsFrame"); } var worldData = frame?.Messages.FirstOrDefault(cur => cur.ApiId.HasValue && cur.ApiId.Value == 0); if (worldData != null) { string theJson = Encoding.UTF8.GetString(worldData.Buffer, 0, worldData.Buffer.Length); Match m = udpPortPattern.Match(theJson); if (m.Success && planetStringName != null) { int serverPort = Convert.ToInt32(m.Groups[1].Value); if (serverPort.ToString().Length != 4) { throw new Exception("Length change of udpPort"); } if (!planetPorts.ContainsKey(planetStringName)) { //throw new Exception($"Planet dictionary does not contain {planetStringName}"); } else { planetPorts[planetStringName].RemotePort = serverPort; theJson = udpPortPattern.Replace(theJson, $"\"udpPort\":{planetPorts[planetStringName].LocalPort},"); byte[] sendData = Encoding.UTF8.GetBytes(theJson); if (sendData.Length != worldData.Buffer.Length) { throw new Exception("JSON length error"); } worldData.Buffer = sendData; } } } if (planetStringName != null) { frame?.Messages.AddRange(GetOutgoingMessages(planetStringName, direction)); } try { frame?.Send(destination); } catch (Exception ex) { Log.Error(ex, "Error sending frame"); Kill(direction == CommPacketDirection.ServerToClient); } //if (frame.readStream.Length != frame.writeStream.Length) //{ // throw new Exception("frame length mismatch."); //} //if (!frame.readStream.ToArray().SequenceEqual(frame.writeStream.ToArray())) //{ // throw new Exception("frame data mismatch."); //} if (frame == null) { frame = new WsFrame() { Messages = new List <WsMessage> { new WsMessage(24, null, Encoding.UTF8.GetBytes("Frame decoding failure!")), }, }; } try { websocketDataQueue[direction].Add(frame); } catch (Exception ex) { Log.Error(ex, "Error adding frame to queue"); } Application.Current.Dispatcher.Invoke(() => { ProxyUiWindow.AddFrame(frame, direction, m_connectionInstance); }); } if (!ReadBytes(2)) { // Connection terminated waiting for new message. This is fine. break; } if (direction == CommPacketDirection.ClientToServer) { if (!verbs.Any(cur => cur[0] == buffer[0] && cur[1] == buffer[1]) && !isWebSocket) { isWebSocket = true; ProxyManagerWindow.Instance.Dispatcher.BeginInvoke(new Action(() => { m_connectionInstance.Parent.Instances.Remove(m_connectionInstance); var wsg = ComponentEngine.Instance.GetComponent <TcpComponent>().websocketGroup; m_connectionInstance.Parent = wsg; wsg.Instances.Add(m_connectionInstance); })); } if (!isWebSocket) { // GET /index.html HTTP/1.1 sw = new StreamWriter(ms); string requestLine = (Encoding.UTF8.GetString(buffer, 0, 2) + ReadLine()).Trim(); sw.WriteLine(requestLine); if (!requestLinePattern.IsMatch(requestLine)) { throw new Exception("HTTP request line invalid"); } Match m = websocketPlanet.Match(requestLine); if (m.Success) { var newVal = Convert.ToInt32(m.Groups[1].Value); if (planetId != -1) { if (planetId != newVal) { throw new Exception("Multiple planets detected on a single stream"); } } else { planetId = newVal; planetStringName = planetLookup.Where(cur => cur.Value.Value == newVal).FirstOrDefault().Key; planetDisplayName = planetLookup[planetStringName].Key; } } DoHttpHeadersContentAndForward(); } else { forwardWebsocketFrame(); } } else { if ((buffer[0] != 'H' || buffer[1] != 'T') && !isWebSocket) { isWebSocket = true; ProxyManagerWindow.Instance.Dispatcher.BeginInvoke(new Action(() => { m_connectionInstance.Parent.Instances.Remove(m_connectionInstance); var wsg = ComponentEngine.Instance.GetComponent <TcpComponent>().websocketGroup; m_connectionInstance.Parent = wsg; wsg.Instances.Add(m_connectionInstance); })); } if (!isWebSocket) { // HTTP/1.1 200 OK sw = new StreamWriter(ms); string statusLine = (Encoding.UTF8.GetString(buffer, 0, 2) + ReadLine()).Trim(); sw.WriteLine(statusLine); if (!statusLinePattern.IsMatch(statusLine)) { throw new Exception("HTTP status line invalid"); } DoHttpHeadersContentAndForward(); } else { forwardWebsocketFrame(); } } } Log.Information("Killing connection"); Kill(direction == CommPacketDirection.ClientToServer); } catch (Exception ex) { Log.Error(ex, "Forward Stream error"); Kill(direction == CommPacketDirection.ClientToServer); } }).Start(); }