websocket-server – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | using System; |
2 | using System.Collections.Generic; |
||
3 | using System.Linq; |
||
4 | using System.Security.Cryptography; |
||
5 | using System.Text; |
||
6 | using System.Net.Sockets; |
||
7 | using System.Text.RegularExpressions; |
||
8 | using System.Diagnostics; |
||
9 | using System.Threading; |
||
10 | using WebSockets.Common; |
||
11 | using WebSockets.Exceptions; |
||
12 | using WebSockets.Server.Http; |
||
13 | using System.IO; |
||
14 | using WebSockets.Events; |
||
15 | |||
16 | namespace WebSockets.Server.WebSocket |
||
17 | { |
||
18 | public class WebSocketService : WebSocketBase, IService |
||
19 | { |
||
20 | private readonly Stream _stream; |
||
21 | private readonly string _header; |
||
22 | private readonly IWebSocketLogger _logger; |
||
23 | private readonly TcpClient _tcpClient; |
||
24 | private bool _isDisposed = false; |
||
25 | |||
26 | public WebSocketService(Stream stream, TcpClient tcpClient, string header, bool noDelay, IWebSocketLogger logger) |
||
27 | : base(logger) |
||
28 | { |
||
29 | _stream = stream; |
||
30 | _header = header; |
||
31 | _logger = logger; |
||
32 | _tcpClient = tcpClient; |
||
33 | |||
34 | // send requests immediately if true (needed for small low latency packets but not a long stream). |
||
35 | // Basically, dont wait for the buffer to be full before before sending the packet |
||
36 | tcpClient.NoDelay = noDelay; |
||
37 | } |
||
38 | |||
39 | public void Respond() |
||
40 | { |
||
41 | base.OpenBlocking(_stream, _tcpClient.Client); |
||
42 | } |
||
43 | |||
44 | protected override void PerformHandshake(Stream stream) |
||
45 | { |
||
46 | string header = _header; |
||
47 | |||
48 | try |
||
49 | { |
||
50 | Regex webSocketKeyRegex = new Regex("Sec-WebSocket-Key: (.*)"); |
||
51 | Regex webSocketVersionRegex = new Regex("Sec-WebSocket-Version: (.*)"); |
||
52 | |||
53 | // check the version. Support version 13 and above |
||
54 | const int WebSocketVersion = 13; |
||
55 | int secWebSocketVersion = Convert.ToInt32(webSocketVersionRegex.Match(header).Groups[1].Value.Trim()); |
||
56 | if (secWebSocketVersion < WebSocketVersion) |
||
57 | { |
||
58 | throw new WebSocketVersionNotSupportedException(string.Format("WebSocket Version {0} not suported. Must be {1} or above", secWebSocketVersion, WebSocketVersion)); |
||
59 | } |
||
60 | |||
61 | string secWebSocketKey = webSocketKeyRegex.Match(header).Groups[1].Value.Trim(); |
||
62 | string setWebSocketAccept = base.ComputeSocketAcceptString(secWebSocketKey); |
||
63 | string response = ("HTTP/1.1 101 Switching Protocols" + Environment.NewLine |
||
64 | + "Connection: Upgrade" + Environment.NewLine |
||
65 | + "Upgrade: websocket" + Environment.NewLine |
||
66 | + "Sec-WebSocket-Accept: " + setWebSocketAccept); |
||
67 | |||
68 | HttpHelper.WriteHttpHeader(response, stream); |
||
69 | _logger.Information(this.GetType(), "Web Socket handshake sent"); |
||
70 | } |
||
71 | catch (WebSocketVersionNotSupportedException ex) |
||
72 | { |
||
73 | string response = "HTTP/1.1 426 Upgrade Required" + Environment.NewLine + "Sec-WebSocket-Version: 13"; |
||
74 | HttpHelper.WriteHttpHeader(response, stream); |
||
75 | throw; |
||
76 | } |
||
77 | catch (Exception ex) |
||
78 | { |
||
79 | HttpHelper.WriteHttpHeader("HTTP/1.1 400 Bad Request", stream); |
||
80 | throw; |
||
81 | } |
||
82 | } |
||
83 | |||
84 | private static void CloseConnection(Socket socket) |
||
85 | { |
||
86 | socket.Shutdown(SocketShutdown.Both); |
||
87 | socket.Close(); |
||
88 | } |
||
89 | |||
90 | public virtual void Dispose() |
||
91 | { |
||
92 | // send special web socket close message. Don't close the network stream, it will be disposed later |
||
93 | if (_stream.CanWrite && !_isDisposed) |
||
94 | { |
||
95 | using (MemoryStream stream = new MemoryStream()) |
||
96 | { |
||
97 | // set the close reason to Normal |
||
98 | BinaryReaderWriter.WriteUShort((ushort) WebSocketCloseCode.Normal, stream, false); |
||
99 | |||
100 | // send close message to client to begin the close handshake |
||
101 | Send(WebSocketOpCode.ConnectionClose, stream.ToArray()); |
||
102 | } |
||
103 | |||
104 | _isDisposed = true; |
||
105 | _logger.Information(this.GetType(), "Sent web socket close message to client"); |
||
106 | CloseConnection(_tcpClient.Client); |
||
107 | } |
||
108 | } |
||
109 | |||
110 | protected override void OnConnectionClose(byte[] payload) |
||
111 | { |
||
112 | Send(WebSocketOpCode.ConnectionClose, payload); |
||
113 | _logger.Information(this.GetType(), "Sent response close message to client"); |
||
114 | _isDisposed = true; |
||
115 | |||
116 | base.OnConnectionClose(payload); |
||
117 | } |
||
118 | } |
||
119 | } |