public override void OnConnect(Session session) { WebMessage.GetSessionBuffer(session, true); WebMessage.GetSessionData(session, true); if (IsOrderlyProcess) { WebMessage.GetSingleTaskFactory(session, true); } base.OnConnect(session); }
// please know that function Decode() should be called in single thread public bool Decode(Session session, MemoryStream stream, List <Object> output) { bool isNew = false; WebMessage netMsg = null; bool hasKey = false; Stack <Object> stack = WebMessage.GetSessionBuffer(session); if (stack.Count > 0) { hasKey = true; netMsg = (WebMessage)stack.Peek(); } if (netMsg == null) { isNew = true; netMsg = new WebMessage(); if (hasKey) { stack.Pop(); } stack.Push(netMsg); } if (isNew) { if (netMsg != null) { netMsg.ReceivingState = WebMessage.STATE_WAIT_FOR_BODY; netMsg.MessageType = WebMessage.MSG_TYPE_HANDSHAKE; } } int total = 0; if (netMsg.ReceivingState == WebMessage.STATE_WAIT_FOR_BODY) { if (netMsg.MessageType == WebMessage.MSG_TYPE_HANDSHAKE) { long orgpos = stream.Position; long msglen = stream.Length - stream.Position; Byte[] bytes = new Byte[msglen]; stream.Read(bytes, 0, bytes.Length); bool found = false; int curpos = 0; int maxpos = bytes.Length - 1; int checkedlen = 0; while (curpos <= maxpos && !found) { if (bytes[curpos] == '\r') { if (curpos + 1 <= maxpos && bytes[curpos + 1] == '\n') { if (curpos + 2 <= maxpos && bytes[curpos + 2] == '\r') { if (curpos + 3 <= maxpos && bytes[curpos + 3] == '\n') { found = true; checkedlen = curpos + 3 + 1; } } } } curpos++; } if (found) { Encoding encode = Encoding.UTF8; string headerContent = encode.GetString(bytes, 0, checkedlen); string[] rawClientHandshakeLines = headerContent.Split(new string[] { "\r\n" }, System.StringSplitOptions.RemoveEmptyEntries); string acceptKey = ""; bool foundKey = false; bool foundUrl = false; bool foundServerSign = false; string handshakeMsg = ""; foreach (string oneline in rawClientHandshakeLines) { if (!foundUrl && oneline.Contains(HTTP_HEADER_SIGN)) { if (oneline.Contains(HTTP_SERVER_HEADER_SIGN)) { foundServerSign = true; } else { string reqline = oneline.Trim(); int beginPos = reqline.IndexOf(' ') + 1; int endPos = reqline.LastIndexOf(' '); if (beginPos > 0 && endPos > beginPos) { WebMessage.SetSessionData(session, "Path", reqline.Substring(beginPos, endPos - beginPos).Trim()); } } foundUrl = true; } if (!foundKey && !foundServerSign && oneline.Contains(WEBSOCK_CLIENT_HEADER_SIGN + ":")) { acceptKey = ComputeWebSocketHandshakeSecurityHash09(oneline.Substring(oneline.IndexOf(":") + 2)); foundKey = true; } } if (acceptKey != null && acceptKey.Length > 0) { handshakeMsg = String.Format(WEBSOCK_HANDSHAKE_REPLY_MSG, acceptKey); } stream.Position = orgpos + checkedlen; netMsg.ReceivingState = WebMessage.STATE_READY; if (stack.Count > 0) { stack.Pop(); } netMsg.MessageContent = headerContent; netMsg.MessageType = WebMessage.MSG_TYPE_HANDSHAKE; output.Add(netMsg); total++; netMsg = new WebMessage(); netMsg.VirtualHeaderSize = 2; stack.Push(netMsg); if (handshakeMsg != null && handshakeMsg.Length > 0) { session.Send(handshakeMsg); } } else { if (curpos > m_MaxMsgSize) { session.Close(); } else { stream.Position = orgpos; } return(false); } } if (netMsg.ReceivingState == WebMessage.STATE_WAIT_FOR_BODY && stream.Length - stream.Position >= netMsg.ContentSize) { Byte[] bytes = new Byte[netMsg.ContentSize]; stream.Read(bytes, 0, netMsg.ContentSize); if (netMsg.MaskFlag > 0 && netMsg.MaskBytes != null) { int masklen = netMsg.MaskBytes.Length; for (int i = 0; i < bytes.Length; i++) { bytes[i] = (byte)(bytes[i] ^ netMsg.MaskBytes[i % masklen]); } } if (netMsg.MessageType == WebMessage.MSG_TYPE_STRING) { netMsg.MessageContent = Encoding.UTF8.GetString(bytes, 0, bytes.Length); } if (netMsg.MessageType == WebMessage.MSG_TYPE_BINARY || netMsg.MessageType == WebMessage.MSG_TYPE_PING || netMsg.MessageType == WebMessage.MSG_TYPE_PONG) { netMsg.RawContent = bytes; netMsg.ContentSize = bytes.Length; } output.Add(netMsg); total++; netMsg.ReceivingState = WebMessage.STATE_READY; if (stack.Count > 0) { stack.Pop(); } netMsg = new WebMessage(); netMsg.VirtualHeaderSize = 2; stack.Push(netMsg); } } while (netMsg.ReceivingState == WebMessage.STATE_WAIT_FOR_HEADER && stream.Length - stream.Position >= netMsg.VirtualHeaderSize) { if (netMsg.ReceivingState == WebMessage.STATE_WAIT_FOR_HEADER) { if (stream.Length - stream.Position >= netMsg.VirtualHeaderSize) { Byte[] bytes = new Byte[netMsg.VirtualHeaderSize]; stream.Read(bytes, 0, netMsg.VirtualHeaderSize); if (netMsg.VirtualHeaderSize == 2) { // first byte ... sbyte opcode = (sbyte)(bytes[0] & 0x0f); switch (opcode) // not support 0x00 for now ... { case 0x08: session.Close(); return(false); case 0x09: netMsg.MessageType = WebMessage.MSG_TYPE_PING; break; case 0x0A: netMsg.MessageType = WebMessage.MSG_TYPE_PONG; break; case 0x01: netMsg.MessageType = WebMessage.MSG_TYPE_STRING; break; case 0x02: netMsg.MessageType = WebMessage.MSG_TYPE_BINARY; break; default: session.Close(); // just close it if undefined op code found return(false); } bool needmask = (bytes[1] & 0x80) == 0x80; if (needmask) { netMsg.VirtualHeaderSize += 4; netMsg.MaskFlag = 1; } else { netMsg.MaskFlag = 0; } sbyte payloadlen = (sbyte)(bytes[1] & 0x7f); if (payloadlen == 126) { netMsg.VirtualHeaderSize += 2; netMsg.HeaderFlag = 1; } else if (payloadlen == 127) { netMsg.VirtualHeaderSize += 8; netMsg.HeaderFlag = 2; } else { netMsg.HeaderFlag = 0; } } if (netMsg.VirtualHeaderSize > bytes.Length) { stream.Position = stream.Position - bytes.Length; continue; } if (netMsg.MaskFlag > 0) { netMsg.MaskBytes = new byte[4]; Buffer.BlockCopy(bytes, netMsg.VirtualHeaderSize - 4, netMsg.MaskBytes, 0, 4); } if (netMsg.HeaderFlag == 1) { netMsg.ContentSize = (int)bytes[2] * 256 + (int)bytes[3]; } else if (netMsg.HeaderFlag == 2) { long len = 0; int n = 1; for (int i = 7; i >= 0; i--) { len += (int)bytes[i + 2] * n; n *= 256; } netMsg.ContentSize = (int)len; } else { netMsg.ContentSize = (sbyte)(bytes[1] & 0x7f); } if (netMsg.ContentSize > m_MaxMsgSize) { netMsg.ContentSize = 0; } if (netMsg.ContentSize < 0) { netMsg.ContentSize = 0; } if (netMsg.ContentSize > 0) { netMsg.ReceivingState = WebMessage.STATE_WAIT_FOR_BODY; } else { netMsg.ReceivingState = WebMessage.STATE_READY; if (stack.Count > 0) { stack.Pop(); } netMsg = new WebMessage(); netMsg.VirtualHeaderSize = 2; stack.Push(netMsg); continue; } } } if (netMsg.ReceivingState == WebMessage.STATE_WAIT_FOR_BODY) { if (stream.Length - stream.Position >= netMsg.ContentSize) { Byte[] bytes = new Byte[netMsg.ContentSize]; stream.Read(bytes, 0, netMsg.ContentSize); if (netMsg.MaskFlag > 0 && netMsg.MaskBytes != null) { int masklen = netMsg.MaskBytes.Length; for (int i = 0; i < bytes.Length; i++) { bytes[i] = (byte)(bytes[i] ^ netMsg.MaskBytes[i % masklen]); } } if (netMsg.MessageType == WebMessage.MSG_TYPE_STRING) { netMsg.MessageContent = Encoding.UTF8.GetString(bytes, 0, bytes.Length); } if (netMsg.MessageType == WebMessage.MSG_TYPE_BINARY || netMsg.MessageType == WebMessage.MSG_TYPE_PING || netMsg.MessageType == WebMessage.MSG_TYPE_PONG) { netMsg.RawContent = bytes; netMsg.ContentSize = bytes.Length; } output.Add(netMsg); total++; netMsg.ReceivingState = WebMessage.STATE_READY; if (stack.Count > 0) { stack.Pop(); } netMsg = new WebMessage(); netMsg.VirtualHeaderSize = 2; stack.Push(netMsg); } } } if (total > 0 && stream.Length - stream.Position <= 0) { return(true); } if (netMsg.ReceivingState != WebMessage.STATE_WAIT_FOR_HEADER && netMsg.ReceivingState != WebMessage.STATE_WAIT_FOR_BODY && netMsg.ReceivingState != WebMessage.STATE_READY) { session.Close(); } return(false); }