WsStream.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #region MIT License
  2. /**
  3. * WsStream.cs
  4. *
  5. * The MIT License
  6. *
  7. * Copyright (c) 2010-2012 sta.blockhead
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. */
  27. #endregion
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Configuration;
  31. using System.IO;
  32. using System.Net;
  33. using System.Net.Sockets;
  34. using System.Security.Cryptography.X509Certificates;
  35. using System.Text;
  36. using WebSocketSharp.Frame;
  37. using WebSocketSharp.Net.Security;
  38. namespace WebSocketSharp
  39. {
  40. internal class WsStream : IDisposable
  41. {
  42. #region Fields
  43. private Stream _innerStream;
  44. private bool _isSecure;
  45. private Object _forRead;
  46. private Object _forWrite;
  47. #endregion
  48. #region Private Constructor
  49. private WsStream()
  50. {
  51. _forRead = new object();
  52. _forWrite = new object();
  53. }
  54. #endregion
  55. #region Public Constructors
  56. public WsStream(NetworkStream innerStream)
  57. : this()
  58. {
  59. if (innerStream == null)
  60. throw new ArgumentNullException("innerStream");
  61. _innerStream = innerStream;
  62. _isSecure = false;
  63. }
  64. public WsStream(SslStream innerStream)
  65. : this()
  66. {
  67. if (innerStream == null)
  68. throw new ArgumentNullException("innerStream");
  69. _innerStream = innerStream;
  70. _isSecure = true;
  71. }
  72. #endregion
  73. #region Properties
  74. public bool DataAvailable
  75. {
  76. get
  77. {
  78. return _isSecure
  79. ? ((SslStream)_innerStream).DataAvailable
  80. : ((NetworkStream)_innerStream).DataAvailable;
  81. }
  82. }
  83. public bool IsSecure
  84. {
  85. get
  86. {
  87. return _isSecure;
  88. }
  89. }
  90. #endregion
  91. #region Private Methods
  92. private int read(byte[] buffer, int offset, int size)
  93. {
  94. var readLen = _innerStream.Read(buffer, offset, size);
  95. if (readLen < size)
  96. {
  97. var msg = String.Format("Data can not be read from {0}.", _innerStream.GetType().Name);
  98. throw new IOException(msg);
  99. }
  100. return readLen;
  101. }
  102. private int readByte()
  103. {
  104. return _innerStream.ReadByte();
  105. }
  106. private string[] readHandshake()
  107. {
  108. var buffer = new List<byte>();
  109. while (true)
  110. {
  111. if (Ext.EqualsAndSaveTo(readByte(), '\r', buffer) &&
  112. Ext.EqualsAndSaveTo(readByte(), '\n', buffer) &&
  113. Ext.EqualsAndSaveTo(readByte(), '\r', buffer) &&
  114. Ext.EqualsAndSaveTo(readByte(), '\n', buffer))
  115. break;
  116. }
  117. return Encoding.UTF8.GetString(buffer.ToArray())
  118. .Replace("\r\n", "\n").Replace("\n\n", "\n").TrimEnd('\n')
  119. .Split('\n');
  120. }
  121. private void write(byte[] buffer, int offset, int count)
  122. {
  123. _innerStream.Write(buffer, offset, count);
  124. }
  125. private void writeByte(byte value)
  126. {
  127. _innerStream.WriteByte(value);
  128. }
  129. #endregion
  130. #region Internal Methods
  131. internal static WsStream CreateClientStream(TcpClient client, string host, bool secure)
  132. {
  133. var netStream = client.GetStream();
  134. if (secure)
  135. {
  136. System.Net.Security.RemoteCertificateValidationCallback validationCb = (sender, certificate, chain, sslPolicyErrors) =>
  137. {
  138. // FIXME: Always returns true
  139. return true;
  140. };
  141. var sslStream = new SslStream(netStream, false, validationCb);
  142. sslStream.AuthenticateAsClient(host);
  143. return new WsStream(sslStream);
  144. }
  145. return new WsStream(netStream);
  146. }
  147. internal static WsStream CreateServerStream(TcpClient client, bool secure)
  148. {
  149. var netStream = client.GetStream();
  150. if (secure)
  151. {
  152. var sslStream = new SslStream(netStream, false);
  153. var certPath = ConfigurationManager.AppSettings["ServerCertPath"];
  154. sslStream.AuthenticateAsServer(new X509Certificate2(certPath));
  155. return new WsStream(sslStream);
  156. }
  157. return new WsStream(netStream);
  158. }
  159. internal static WsStream CreateServerStream(WebSocketSharp.Net.HttpListenerContext context)
  160. {
  161. var conn = context.Connection;
  162. var stream = conn.Stream;
  163. return conn.IsSecure
  164. ? new WsStream((SslStream)stream)
  165. : new WsStream((NetworkStream)stream);
  166. }
  167. #endregion
  168. #region Public Methods
  169. public void Close()
  170. {
  171. _innerStream.Close();
  172. }
  173. public void Dispose()
  174. {
  175. _innerStream.Dispose();
  176. }
  177. public WsFrame ReadFrame()
  178. {
  179. lock (_forRead)
  180. {
  181. try
  182. {
  183. return WsFrame.Parse(_innerStream);
  184. }
  185. catch
  186. {
  187. return null;
  188. }
  189. }
  190. }
  191. public void ReadFrameAsync(Action<WsFrame> completed)
  192. {
  193. WsFrame.ParseAsync(_innerStream, completed);
  194. }
  195. public string[] ReadHandshake()
  196. {
  197. lock (_forRead)
  198. {
  199. try
  200. {
  201. return readHandshake();
  202. }
  203. catch
  204. {
  205. return null;
  206. }
  207. }
  208. }
  209. public bool WriteFrame(WsFrame frame)
  210. {
  211. lock (_forWrite)
  212. {
  213. try
  214. {
  215. var buffer = frame.ToBytes();
  216. write(buffer, 0, buffer.Length);
  217. return true;
  218. }
  219. catch
  220. {
  221. return false;
  222. }
  223. }
  224. }
  225. public bool WriteHandshake(Handshake handshake)
  226. {
  227. lock (_forWrite)
  228. {
  229. try
  230. {
  231. var buffer = handshake.ToBytes();
  232. write(buffer, 0, buffer.Length);
  233. return true;
  234. }
  235. catch
  236. {
  237. return false;
  238. }
  239. }
  240. }
  241. #endregion
  242. }
  243. }