DraftHybi00Processor.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Security.Cryptography;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. using SuperSocket.Common;
  8. using SuperSocket.SocketBase.Protocol;
  9. namespace SuperWebSocket.Protocol
  10. {
  11. /// <summary>
  12. /// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
  13. /// </summary>
  14. class DraftHybi00Processor : ProtocolProcessorBase
  15. {
  16. private static readonly byte[] m_ZeroKeyBytes = new byte[0];
  17. public DraftHybi00Processor()
  18. : base(0, new CloseStatusCodeHybi10())
  19. {
  20. }
  21. public override bool Handshake(IWebSocketSession session, WebSocketReceiveFilterBase previousFilter, out IReceiveFilter<IWebSocketFragment> dataFrameReader)
  22. {
  23. var secKey1 = session.Items.GetValue<string>(WebSocketConstant.SecWebSocketKey1, string.Empty);
  24. var secKey2 = session.Items.GetValue<string>(WebSocketConstant.SecWebSocketKey2, string.Empty);
  25. dataFrameReader = null;
  26. if (string.IsNullOrEmpty(secKey1) && string.IsNullOrEmpty(secKey2) && NextProcessor != null)
  27. {
  28. return NextProcessor.Handshake(session, previousFilter, out dataFrameReader);
  29. }
  30. session.ProtocolProcessor = this;
  31. if (!session.AppServer.ValidateHandshake(session, session.Items.GetValue<string>(WebSocketConstant.Origin, string.Empty)))
  32. return false;
  33. var secKey3 = session.Items.GetValue<byte[]>(WebSocketConstant.SecWebSocketKey3, m_ZeroKeyBytes);
  34. var responseBuilder = new StringBuilder();
  35. responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseHeadLine00);
  36. responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseUpgradeLine);
  37. responseBuilder.AppendWithCrCf(WebSocketConstant.ResponseConnectionLine);
  38. if (!string.IsNullOrEmpty(session.Origin))
  39. responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseOriginLine, session.Origin);
  40. responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseLocationLine, session.UriScheme, session.Host, session.Path);
  41. var subProtocol = session.GetAvailableSubProtocol(session.Items.GetValue<string>(WebSocketConstant.SecWebSocketProtocol, string.Empty));
  42. if (!string.IsNullOrEmpty(subProtocol))
  43. responseBuilder.AppendFormatWithCrCf(WebSocketConstant.ResponseProtocolLine, subProtocol);
  44. responseBuilder.AppendWithCrCf();
  45. byte[] data = Encoding.UTF8.GetBytes(responseBuilder.ToString());
  46. session.SendRawData(data, 0, data.Length);
  47. //Encrypt message
  48. byte[] secret = GetResponseSecurityKey(secKey1, secKey2, secKey3);
  49. session.SendRawData(secret, 0, secret.Length);
  50. dataFrameReader = new WebSocketDataReceiveFilter(previousFilter);
  51. return true;
  52. }
  53. private const string m_SecurityKeyRegex = "[^0-9]";
  54. private byte[] GetResponseSecurityKey(string secKey1, string secKey2, byte[] secKey3)
  55. {
  56. //Remove all symbols that are not numbers
  57. string k1 = Regex.Replace(secKey1, m_SecurityKeyRegex, String.Empty);
  58. string k2 = Regex.Replace(secKey2, m_SecurityKeyRegex, String.Empty);
  59. //Convert received string to 64 bit integer.
  60. Int64 intK1 = Int64.Parse(k1);
  61. Int64 intK2 = Int64.Parse(k2);
  62. //Dividing on number of spaces
  63. int k1Spaces = secKey1.Count(c => c == ' ');
  64. int k2Spaces = secKey2.Count(c => c == ' ');
  65. int k1FinalNum = (int)(intK1 / k1Spaces);
  66. int k2FinalNum = (int)(intK2 / k2Spaces);
  67. //Getting byte parts
  68. byte[] b1 = BitConverter.GetBytes(k1FinalNum).Reverse().ToArray();
  69. byte[] b2 = BitConverter.GetBytes(k2FinalNum).Reverse().ToArray();
  70. //byte[] b3 = Encoding.UTF8.GetBytes(secKey3);
  71. byte[] b3 = secKey3;
  72. //Concatenating everything into 1 byte array for hashing.
  73. byte[] bChallenge = new byte[b1.Length + b2.Length + b3.Length];
  74. Array.Copy(b1, 0, bChallenge, 0, b1.Length);
  75. Array.Copy(b2, 0, bChallenge, b1.Length, b2.Length);
  76. Array.Copy(b3, 0, bChallenge, b1.Length + b2.Length, b3.Length);
  77. //Hash and return
  78. byte[] hash = MD5.Create().ComputeHash(bChallenge);
  79. return hash;
  80. }
  81. public override IList<ArraySegment<byte>> GetEncodedPackage(int opCode, byte[] data, int offset, int length)
  82. {
  83. throw new NotSupportedException();
  84. }
  85. public override IList<ArraySegment<byte>> GetEncodedPackage(int opCode, string message)
  86. {
  87. return new ArraySegment<byte>[] { GetPackageData(message) };
  88. }
  89. private ArraySegment<byte> GetPackageData(string message)
  90. {
  91. var maxByteCount = Encoding.UTF8.GetMaxByteCount(message.Length) + 2;
  92. var sendBuffer = new byte[maxByteCount];
  93. sendBuffer[0] = WebSocketConstant.StartByte;
  94. int bytesCount = Encoding.UTF8.GetBytes(message, 0, message.Length, sendBuffer, 1);
  95. sendBuffer[1 + bytesCount] = WebSocketConstant.EndByte;
  96. return new ArraySegment<byte>(sendBuffer, 0, bytesCount + 2);
  97. }
  98. public override void SendMessage(IWebSocketSession session, string message)
  99. {
  100. var packageData = GetPackageData(message);
  101. session.SendRawData(packageData.Array, packageData.Offset, packageData.Count);
  102. }
  103. public override void SendCloseHandshake(IWebSocketSession session, int statusCode, string closeReason)
  104. {
  105. session.SendRawData(WebSocketConstant.ClosingHandshake, 0, WebSocketConstant.ClosingHandshake.Length);
  106. }
  107. public override void SendPong(IWebSocketSession session, byte[] pong)
  108. {
  109. }
  110. public override void SendPing(IWebSocketSession session, byte[] ping)
  111. {
  112. }
  113. public override bool CanSendBinaryData
  114. {
  115. get { return false; }
  116. }
  117. public override void SendData(IWebSocketSession session, byte[] data, int offset, int length)
  118. {
  119. throw new NotSupportedException();
  120. }
  121. public override bool IsValidCloseCode(int code)
  122. {
  123. throw new NotSupportedException();
  124. }
  125. public override bool TrySendMessage(IWebSocketSession session, string message)
  126. {
  127. var packageData = GetPackageData(message);
  128. return session.TrySendRawData(packageData.Array, packageData.Offset, packageData.Count);
  129. }
  130. public override bool TrySendData(IWebSocketSession session, byte[] data, int offset, int length)
  131. {
  132. throw new NotImplementedException();
  133. }
  134. }
  135. }