Mercurial > hg > ucis.core
annotate Net/WebSocketPacketStream.cs @ 111:df53bdd49507 default tip
Merge
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Fri, 07 Nov 2014 18:37:39 +0100 |
parents | 6be3c9bdb480 |
children |
rev | line source |
---|---|
12 | 1 ???using System; |
2 using System.IO; | |
3 using System.Security.Cryptography; | |
4 using System.Text; | |
5 using System.Threading; | |
6 using UCIS.Util; | |
7 | |
8 namespace UCIS.Net.HTTP { | |
9 public class WebSocketPacketStream : PacketStream { | |
10 Stream baseStream; | |
11 Boolean negotiationDone = false; | |
12 Boolean closed = false; | |
13 ManualResetEvent negotiationEvent = new ManualResetEvent(false); | |
14 Boolean binaryProtocol = false; | |
15 int wsProtocol = -1; | |
16 | |
17 public WebSocketPacketStream(HTTPContext context) { | |
18 try { | |
19 String ConnectionHeader = context.GetRequestHeader("Connection"); //can be comma-separated list | |
20 Boolean ConnectionUpgrade = ConnectionHeader != null && ConnectionHeader.Contains("Upgrade"); | |
21 Boolean UpgradeWebsocket = "WebSocket".Equals(context.GetRequestHeader("Upgrade"), StringComparison.OrdinalIgnoreCase); | |
22 String SecWebSocketKey = context.GetRequestHeader("Sec-WebSocket-Key"); | |
23 String SecWebSocketKey1 = context.GetRequestHeader("Sec-WebSocket-Key1"); | |
24 String SecWebSocketKey2 = context.GetRequestHeader("Sec-WebSocket-Key2"); | |
25 String SecWebSocketProtocol = context.GetRequestHeader("Sec-WebSocket-Protocol"); | |
26 String[] SecWebSocketProtocols = SecWebSocketProtocol == null ? null : SecWebSocketProtocol.Split(new String[] { ", " }, StringSplitOptions.None); | |
27 if (!ConnectionUpgrade || !UpgradeWebsocket || SecWebSocketProtocols == null || SecWebSocketProtocols.Length == 0) goto Failure; | |
28 binaryProtocol = SecWebSocketProtocol != null && Array.IndexOf(SecWebSocketProtocols, "binary") != -1; | |
29 if (SecWebSocketKey != null) { | |
30 wsProtocol = 13; | |
31 String hashedKey; | |
32 using (SHA1 sha1 = new SHA1Managed()) { | |
33 Byte[] hashable = Encoding.ASCII.GetBytes(SecWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); | |
34 Byte[] hash = sha1.ComputeHash(hashable); | |
35 hashedKey = Convert.ToBase64String(hash, Base64FormattingOptions.None); | |
36 } | |
37 context.SuppressStandardHeaders = true; | |
38 context.SendStatus(101); | |
39 context.SendHeader("Connection", "Upgrade"); | |
40 context.SendHeader("Upgrade", "websocket"); | |
41 context.SendHeader("Sec-WebSocket-Accept", hashedKey); | |
42 context.SendHeader("Sec-WebSocket-Protocol", binaryProtocol ? "binary" : "base64"); | |
75 | 43 baseStream = context.GetDirectStream(); |
12 | 44 } else if (SecWebSocketKey1 != null && SecWebSocketKey2 != null) { |
45 wsProtocol = 100; | |
46 Byte[] key = new Byte[4 + 4 + 8]; | |
47 CalculateHybi00MagicNumber(SecWebSocketKey1, key, 0); | |
48 CalculateHybi00MagicNumber(SecWebSocketKey2, key, 4); | |
49 context.SuppressStandardHeaders = true; | |
50 context.SendStatus(101); | |
51 context.SendHeader("Connection", "Upgrade"); | |
52 context.SendHeader("Upgrade", "websocket"); | |
53 context.SendHeader("Sec-WebSocket-Protocol", binaryProtocol ? "binary" : "base64"); | |
54 context.SendHeader("Sec-WebSocket-Origin", context.GetRequestHeader("Origin")); | |
55 context.SendHeader("Sec-WebSocket-Location", "ws://" + context.GetRequestHeader("Host") + context.RequestPath); | |
75 | 56 baseStream = context.GetDirectStream(); |
12 | 57 ReadAllBytes(key, 8, 8); |
58 using (MD5 md5 = new MD5CryptoServiceProvider()) key = md5.ComputeHash(key); | |
59 baseStream.Write(key, 0, key.Length); | |
60 } else { | |
61 goto Failure; | |
62 } | |
63 if (closed) baseStream.Close(); | |
37 | 64 } catch (Exception) { |
12 | 65 closed = true; |
75 | 66 if (baseStream != null) baseStream.Close(); |
12 | 67 } finally { |
68 negotiationDone = true; | |
69 negotiationEvent.Set(); | |
70 } | |
71 return; | |
72 Failure: | |
73 closed = true; | |
75 | 74 context.SendErrorResponse(400); |
12 | 75 return; |
76 } | |
77 | |
78 private void CalculateHybi00MagicNumber(String s, Byte[] obuf, int opos) { | |
79 long number = 0; | |
80 long spaces = 0; | |
81 foreach (Char c in s) { | |
82 if (c == ' ') { | |
83 spaces++; | |
84 } else if (c >= '0' && c <= '9') { | |
85 number = number * 10 + (c - '0'); | |
86 } | |
87 } | |
88 number /= spaces; | |
89 obuf[opos++] = (Byte)(number >> 24); | |
90 obuf[opos++] = (Byte)(number >> 16); | |
91 obuf[opos++] = (Byte)(number >> 8); | |
92 obuf[opos++] = (Byte)(number >> 0); | |
93 } | |
94 | |
95 public override bool CanRead { get { return negotiationDone && !closed; } } | |
96 public override bool CanSeek { get { return false; } } | |
97 public override bool CanWrite { get { return negotiationDone && !closed; } } | |
98 public override void Flush() { } | |
99 | |
100 public override void Close() { | |
101 closed = true; | |
102 base.Close(); | |
103 if (baseStream != null) baseStream.Close(); | |
104 } | |
105 public override bool CanTimeout { get { return baseStream.CanTimeout; } } | |
106 public override int ReadTimeout { | |
107 get { return baseStream.ReadTimeout; } | |
108 set { baseStream.ReadTimeout = value; } | |
109 } | |
110 public override int WriteTimeout { | |
111 get { return baseStream.WriteTimeout; } | |
112 set { baseStream.WriteTimeout = value; } | |
113 } | |
114 | |
115 public override long Length { get { throw new NotSupportedException(); } } | |
116 public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } | |
117 public override void SetLength(long value) { throw new NotSupportedException(); } | |
118 public override long Position { | |
119 get { throw new NotSupportedException(); } | |
120 set { throw new NotSupportedException(); } | |
121 } | |
122 | |
123 private void ReadAllBytes(Byte[] buffer, int offset, int count) { | |
124 while (count > 0) { | |
125 int l = baseStream.Read(buffer, offset, count); | |
126 if (l <= 0) throw new EndOfStreamException(); | |
127 offset += l; | |
128 count -= l; | |
129 } | |
130 } | |
131 | |
132 Byte[] leftOver = null; | |
133 public override int Read(byte[] buffer, int offset, int count) { | |
134 Byte[] packet = leftOver; | |
135 leftOver = null; | |
136 if (packet == null) packet = ReadPacket(); | |
137 if (packet == null) return 0; | |
138 if (count > packet.Length) count = packet.Length; | |
139 Buffer.BlockCopy(packet, 0, buffer, offset, count); | |
140 if (packet.Length > count) leftOver = ArrayUtil.Slice(packet, count); | |
141 return count; | |
142 } | |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
143 private int ReadRawMessage(out Byte[] payloadret) { |
12 | 144 if (leftOver != null) throw new InvalidOperationException("There is remaining data from a partial read"); |
145 negotiationEvent.WaitOne(); | |
146 if (closed) throw new ObjectDisposedException("WebSocketPacketStream"); | |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
147 if (wsProtocol == 13) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
148 Byte[] multipartbuffer = null; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
149 int multipartopcode = -1; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
150 while (true) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
151 int flags = baseStream.ReadByte(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
152 if (flags == -1) throw new EndOfStreamException(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
153 UInt64 pllen = (byte)baseStream.ReadByte(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
154 Boolean masked = (pllen & 128) != 0; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
155 pllen &= 127; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
156 if (pllen == 126) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
157 pllen = (uint)baseStream.ReadByte() << 8; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
158 pllen |= (uint)baseStream.ReadByte(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
159 } else if (pllen == 127) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
160 pllen = (ulong)baseStream.ReadByte() << 56; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
161 pllen |= (ulong)baseStream.ReadByte() << 48; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
162 pllen |= (ulong)baseStream.ReadByte() << 40; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
163 pllen |= (ulong)baseStream.ReadByte() << 32; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
164 pllen |= (uint)baseStream.ReadByte() << 24; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
165 pllen |= (uint)baseStream.ReadByte() << 16; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
166 pllen |= (uint)baseStream.ReadByte() << 8; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
167 pllen |= (uint)baseStream.ReadByte(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
168 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
169 Byte[] mask = new Byte[4]; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
170 if (masked) ReadAllBytes(mask, 0, mask.Length); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
171 //Console.WriteLine("Read flags={0} masked={1} mask={2} len={3}", flags, masked, mask, pllen); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
172 Byte[] payload = new Byte[pllen]; // + (4 - (pllen % 4))]; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
173 ReadAllBytes(payload, 0, (int)pllen); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
174 if (masked) for (int i = 0; i < (int)pllen; i++) payload[i] ^= mask[i % 4]; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
175 int opcode = flags & 0x0f; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
176 Boolean fin = (flags & 0x80) != 0; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
177 if (opcode == 0) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
178 //Console.WriteLine("WebSocket received continuation frame type {0}!", multipartopcode); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
179 Array.Resize(ref multipartbuffer, multipartbuffer.Length + payload.Length); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
180 payload.CopyTo(multipartbuffer, multipartbuffer.Length - payload.Length); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
181 opcode = -1; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
182 if (fin) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
183 payload = multipartbuffer; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
184 opcode = multipartopcode; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
185 multipartbuffer = null; |
12 | 186 } |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
187 } else if (!fin) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
188 //Console.WriteLine("WebSocket received non-fin frame type {0}!", opcode); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
189 multipartbuffer = payload; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
190 multipartopcode = opcode; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
191 opcode = -1; |
12 | 192 } |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
193 if (opcode == -1) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
194 } else if (opcode == 0) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
195 throw new NotSupportedException("WebSocket opcode 0 is not supported"); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
196 } else if (opcode == 1) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
197 payloadret = payload; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
198 return 1; //text frame |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
199 } else if (opcode == 2) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
200 payloadret = payload; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
201 return 2; //binary frame |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
202 } else if (opcode == 8) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
203 payloadret = null; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
204 return 0; //end of stream |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
205 } else if (opcode == 9) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
206 //Console.WriteLine("WebSocket PING"); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
207 WriteProtocol13Frame(10, payload, 0, (int)pllen); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
208 } else if (opcode == 10) { //PONG |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
209 } else { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
210 //Console.WriteLine("WebSocket UNKNOWN OPCODE {0}", opcode); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
211 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
212 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
213 } else if (wsProtocol == 100) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
214 int frameType = baseStream.ReadByte(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
215 if (frameType == -1) throw new EndOfStreamException(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
216 if ((frameType & 0x80) != 0) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
217 int length = 0; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
218 while (true) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
219 int b = baseStream.ReadByte(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
220 if (b == -1) throw new EndOfStreamException(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
221 length = (length << 7) | (b & 0x7f); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
222 if ((b & 0x80) == 0) break; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
223 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
224 Byte[] buffer = new Byte[length]; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
225 ReadAllBytes(buffer, 0, length); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
226 if (frameType == 0xff && length == 0) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
227 payloadret = null; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
228 return 0; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
229 } else { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
230 throw new InvalidOperationException(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
231 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
232 } else { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
233 using (MemoryStream ms = new MemoryStream()) { |
12 | 234 while (true) { |
235 int b = baseStream.ReadByte(); | |
236 if (b == -1) throw new EndOfStreamException(); | |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
237 if (b == 0xff) break; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
238 ms.WriteByte((Byte)b); |
12 | 239 } |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
240 if (frameType == 0x00) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
241 ms.Seek(0, SeekOrigin.Begin); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
242 payloadret = ms.ToArray(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
243 return 1; //text frame |
12 | 244 } else { |
245 throw new InvalidOperationException(); | |
246 } | |
247 } | |
248 } | |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
249 } else { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
250 throw new InvalidOperationException(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
251 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
252 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
253 public override byte[] ReadPacket() { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
254 Byte[] payload; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
255 int opcode = ReadRawMessage(out payload); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
256 switch (opcode) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
257 case 0: return null; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
258 case 1: return Convert.FromBase64String(Encoding.UTF8.GetString(payload)); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
259 case 2: return payload; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
260 default: throw new InvalidOperationException("Internal error: unexpected frame type"); |
12 | 261 } |
262 } | |
263 private delegate Byte[] ReadPacketDelegate(); | |
264 ReadPacketDelegate readPacketDelegate; | |
265 public override IAsyncResult BeginReadPacket(AsyncCallback callback, object state) { | |
266 if (readPacketDelegate == null) readPacketDelegate = ReadPacket; | |
267 return readPacketDelegate.BeginInvoke(callback, state); | |
268 } | |
269 public override byte[] EndReadPacket(IAsyncResult asyncResult) { | |
270 return readPacketDelegate.EndInvoke(asyncResult); | |
271 } | |
272 public override void Write(byte[] buffer, int offset, int count) { | |
273 negotiationEvent.WaitOne(); | |
274 if (!binaryProtocol) { | |
275 String encoded = Convert.ToBase64String(buffer, offset, count, Base64FormattingOptions.None); | |
276 buffer = Encoding.ASCII.GetBytes(encoded); | |
277 offset = 0; | |
278 count = buffer.Length; | |
279 } | |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
280 WriteRawMessage(buffer, offset, count, binaryProtocol); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
281 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
282 private void WriteRawMessage(Byte[] buffer, int offset, int count, Boolean binary) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
283 negotiationEvent.WaitOne(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
284 if (closed) throw new ObjectDisposedException("WebSocketPacketStream"); |
12 | 285 if (wsProtocol == 13) { |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
286 WriteProtocol13Frame(binary ? (Byte)0x2 : (Byte)0x1, buffer, offset, count); |
12 | 287 } else if (wsProtocol == 100) { |
288 Byte[] bytes = new Byte[2 + count]; | |
289 bytes[0] = 0x00; | |
290 Buffer.BlockCopy(buffer, offset, bytes, 1, count); | |
291 bytes[1 + count] = 0xff; | |
292 baseStream.Write(bytes, 0, bytes.Length); | |
293 } else { | |
294 throw new InvalidOperationException(); | |
295 } | |
296 } | |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
297 private void WriteProtocol13Frame(Byte opcode, Byte[] buffer, int offset, int count) { |
12 | 298 int pllen = count; |
299 int hlen = 2; | |
300 if (pllen > 0xffff) hlen += 8; | |
301 else if (pllen > 125) hlen += 2; | |
302 Byte[] wbuf = new Byte[count + hlen]; | |
303 wbuf[0] = (Byte)(opcode | 0x80); | |
304 if (pllen > 0xffff) { | |
305 wbuf[1] = 127; | |
306 wbuf[2] = 0; | |
307 wbuf[3] = 0; | |
308 wbuf[4] = 0; | |
309 wbuf[5] = 0; | |
310 wbuf[6] = (Byte)(pllen >> 24); | |
311 wbuf[7] = (Byte)(pllen >> 16); | |
312 wbuf[8] = (Byte)(pllen >> 8); | |
313 wbuf[9] = (Byte)(pllen >> 0); | |
314 } else if (pllen > 125) { | |
315 wbuf[1] = 126; | |
316 wbuf[2] = (Byte)(pllen >> 8); | |
317 wbuf[3] = (Byte)(pllen >> 0); | |
318 } else { | |
319 wbuf[1] = (Byte)pllen; | |
320 } | |
321 Buffer.BlockCopy(buffer, offset, wbuf, hlen, count); | |
322 baseStream.Write(wbuf, 0, wbuf.Length); | |
323 } | |
107
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
324 |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
325 public String ReadTextMessage() { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
326 Byte[] payload; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
327 int opcode = ReadRawMessage(out payload); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
328 switch (opcode) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
329 case 0: return null; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
330 case 1: |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
331 case 2: return Encoding.UTF8.GetString(payload); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
332 default: throw new InvalidOperationException("Internal error: unexpected frame type"); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
333 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
334 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
335 private delegate String ReadTextMessageDelegate(); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
336 ReadTextMessageDelegate readTextMessageDelegate; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
337 public IAsyncResult BeginReadTextMessage(AsyncCallback callback, object state) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
338 if (readTextMessageDelegate == null) readTextMessageDelegate = ReadTextMessage; |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
339 return readTextMessageDelegate.BeginInvoke(callback, state); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
340 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
341 public String EndReadTextMessage(IAsyncResult asyncResult) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
342 return readTextMessageDelegate.EndInvoke(asyncResult); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
343 } |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
344 public void WriteTextMessage(String message) { |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
345 Byte[] packet = Encoding.UTF8.GetBytes(message); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
346 WriteRawMessage(packet, 0, packet.Length, false); |
6be3c9bdb480
HTTP: Added text frame support in WebSocket server
Ivo Smits <Ivo@UCIS.nl>
parents:
75
diff
changeset
|
347 } |
12 | 348 } |
349 } |