Supports RFC 6455
This commit is contained in:
@@ -17,7 +17,7 @@ using System.Runtime.CompilerServices;
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("1.0.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.1.*")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
38
websocket-sharp/ByteOrder.cs
Normal file
38
websocket-sharp/ByteOrder.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* ByteOrder.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
public enum ByteOrder : byte
|
||||
{
|
||||
LITTLE = 0x0,
|
||||
BIG = 0x1
|
||||
}
|
||||
}
|
87
websocket-sharp/CloseEventArgs.cs
Normal file
87
websocket-sharp/CloseEventArgs.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* CloseEventArgs.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using WebSocketSharp.Frame;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
public class CloseEventArgs : MessageEventArgs
|
||||
{
|
||||
private ushort _code;
|
||||
private string _reason;
|
||||
private bool _wasClean;
|
||||
|
||||
public CloseStatusCode Code
|
||||
{
|
||||
get
|
||||
{
|
||||
return (CloseStatusCode)_code;
|
||||
}
|
||||
}
|
||||
|
||||
public string Reason
|
||||
{
|
||||
get
|
||||
{
|
||||
return _reason;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WasClean
|
||||
{
|
||||
get
|
||||
{
|
||||
return _wasClean;
|
||||
}
|
||||
set
|
||||
{
|
||||
_wasClean = value;
|
||||
}
|
||||
}
|
||||
|
||||
public CloseEventArgs(PayloadData data)
|
||||
: base(Opcode.CLOSE, data)
|
||||
{
|
||||
_code = data.ToBytes().SubArray(0, 2).To<ushort>(ByteOrder.BIG);
|
||||
|
||||
if (data.Length > 2)
|
||||
{
|
||||
var buffer = data.ToBytes().SubArray(2, (int)(data.Length - 2));
|
||||
_reason = Encoding.UTF8.GetString(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
_reason = String.Empty;
|
||||
}
|
||||
|
||||
_wasClean = false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 sta.blockhead
|
||||
* Copyright (c) 2010-2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -28,19 +28,59 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
public static class Ext
|
||||
{
|
||||
public static bool AreNotEqualDo(
|
||||
public static bool EqualsAndSaveTo(this int value, char c, List<byte> dest)
|
||||
{
|
||||
byte b = (byte)value;
|
||||
dest.Add(b);
|
||||
return b == Convert.ToByte(c);
|
||||
}
|
||||
|
||||
public static string GetHeaderValue(this string src, string separater)
|
||||
{
|
||||
int i = src.IndexOf(separater);
|
||||
return src.Substring(i + 1).Trim();
|
||||
}
|
||||
|
||||
public static bool IsHostOrder(this ByteOrder order)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian ^ (order == ByteOrder.LITTLE))
|
||||
{// true ^ false or false ^ true
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{// true ^ true or false ^ false
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsNullDo<T>(this T value, Action act)
|
||||
where T : class
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
act();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool NotEqualsDo(
|
||||
this string expected,
|
||||
string actual,
|
||||
Func<string, string, string> func,
|
||||
out string ret)
|
||||
out string ret,
|
||||
bool ignoreCase)
|
||||
{
|
||||
if (expected != actual)
|
||||
if (String.Compare(expected, actual, ignoreCase) != 0)
|
||||
{
|
||||
ret = func(expected, actual);
|
||||
return true;
|
||||
@@ -50,106 +90,226 @@ namespace WebSocketSharp
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool EqualsWithSaveTo(this int asByte, char c, List<byte> dist)
|
||||
public static byte[] ReadBytes<TStream>(this TStream stream, ulong length, int bufferLength)
|
||||
where TStream : System.IO.Stream
|
||||
{
|
||||
byte b = (byte)asByte;
|
||||
dist.Add(b);
|
||||
return b == Convert.ToByte(c);
|
||||
}
|
||||
List<byte> readData = new List<byte>();
|
||||
|
||||
public static uint GenerateKey(this Random rand, int space)
|
||||
{
|
||||
uint max = (uint)(0xffffffff / space);
|
||||
ulong count = length / (ulong)bufferLength;
|
||||
int remainder = (int)(length % (ulong)bufferLength);
|
||||
|
||||
int upper16 = (int)((max & 0xffff0000) >> 16);
|
||||
int lower16 = (int)(max & 0x0000ffff);
|
||||
byte[] buffer1 = new byte[bufferLength];
|
||||
|
||||
return ((uint)rand.Next(upper16 + 1) << 16) + (uint)rand.Next(lower16 + 1);
|
||||
}
|
||||
|
||||
public static char GeneratePrintableASCIIwithoutSPandNum(this Random rand)
|
||||
{
|
||||
int ascii = rand.Next(2) == 0 ? rand.Next(33, 48) : rand.Next(58, 127);
|
||||
return Convert.ToChar(ascii);
|
||||
}
|
||||
|
||||
public static string GenerateSecKey(this Random rand, out uint key)
|
||||
{
|
||||
int space = rand.Next(1, 13);
|
||||
int ascii = rand.Next(1, 13);
|
||||
|
||||
key = rand.GenerateKey(space);
|
||||
|
||||
long mKey = key * space;
|
||||
List<char> secKey = new List<char>(mKey.ToString().ToCharArray());
|
||||
|
||||
int i;
|
||||
ascii.Times( () =>
|
||||
count.Times(() =>
|
||||
{
|
||||
i = rand.Next(secKey.Count + 1);
|
||||
secKey.Insert(i, rand.GeneratePrintableASCIIwithoutSPandNum());
|
||||
} );
|
||||
stream.Read(buffer1, 0, bufferLength);
|
||||
readData.AddRange(buffer1);
|
||||
});
|
||||
|
||||
space.Times( () =>
|
||||
if (remainder > 0)
|
||||
{
|
||||
i = rand.Next(1, secKey.Count);
|
||||
secKey.Insert(i, ' ');
|
||||
} );
|
||||
|
||||
return new String(secKey.ToArray());
|
||||
}
|
||||
|
||||
public static byte[] InitializeWithPrintableASCII(this byte[] bytes, Random rand)
|
||||
{
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
bytes[i] = (byte)rand.Next(32, 127);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static bool IsValid(this string[] response, byte[] expectedCR, byte[] actualCR, out string message)
|
||||
{
|
||||
string expectedCRtoHexStr = BitConverter.ToString(expectedCR);
|
||||
string actualCRtoHexStr = BitConverter.ToString(actualCR);
|
||||
|
||||
Func<string, Func<string, string, string>> func = s =>
|
||||
{
|
||||
return (e, a) =>
|
||||
{
|
||||
#if DEBUG
|
||||
Console.WriteLine("WS: Error @IsValid: Invalid {0} response.", s);
|
||||
Console.WriteLine(" expected: {0}", e);
|
||||
Console.WriteLine(" actual : {0}", a);
|
||||
#endif
|
||||
return String.Format("Invalid {0} response: {1}", s, a);
|
||||
};
|
||||
};
|
||||
|
||||
Func<string, string, string> func1 = func("handshake");
|
||||
Func<string, string, string> func2 = func("challenge");
|
||||
|
||||
string msg;
|
||||
if ("HTTP/1.1 101 WebSocket Protocol Handshake".AreNotEqualDo(response[0], func1, out msg) ||
|
||||
"Upgrade: WebSocket".AreNotEqualDo(response[1], func1, out msg) ||
|
||||
"Connection: Upgrade".AreNotEqualDo(response[2], func1, out msg) ||
|
||||
expectedCRtoHexStr.AreNotEqualDo(actualCRtoHexStr, func2, out msg))
|
||||
{
|
||||
message = msg;
|
||||
return false;
|
||||
byte[] buffer2 = new byte[remainder];
|
||||
stream.Read(buffer2, 0, remainder);
|
||||
readData.AddRange(buffer2);
|
||||
}
|
||||
|
||||
message = String.Empty;
|
||||
return true;
|
||||
return readData.ToArray();
|
||||
}
|
||||
|
||||
public static void Times(this int n, Action act)
|
||||
public static T[] SubArray<T>(this T[] array, int startIndex, int length)
|
||||
{
|
||||
for (int i = 0; i < n; i++)
|
||||
if (startIndex == 0 && array.Length == length)
|
||||
{
|
||||
return array;
|
||||
}
|
||||
|
||||
T[] subArray = new T[length];
|
||||
Array.Copy(array, startIndex, subArray, 0, length);
|
||||
return subArray;
|
||||
}
|
||||
|
||||
public static void Times<T>(this T n, Action act)
|
||||
where T : struct
|
||||
{
|
||||
if (typeof(T) != typeof(byte) &&
|
||||
typeof(T) != typeof(Int16) &&
|
||||
typeof(T) != typeof(Int32) &&
|
||||
typeof(T) != typeof(Int64) &&
|
||||
typeof(T) != typeof(UInt16) &&
|
||||
typeof(T) != typeof(UInt32) &&
|
||||
typeof(T) != typeof(UInt64))
|
||||
{
|
||||
throw new NotSupportedException("Not supported Struct type: " + typeof(T).ToString());
|
||||
}
|
||||
|
||||
ulong m = (ulong)(object)n;
|
||||
|
||||
for (ulong i = 0; i < m; i++)
|
||||
{
|
||||
act();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Times<T>(this T n, Action<ulong> act)
|
||||
where T : struct
|
||||
{
|
||||
if (typeof(T) != typeof(byte) &&
|
||||
typeof(T) != typeof(Int16) &&
|
||||
typeof(T) != typeof(Int32) &&
|
||||
typeof(T) != typeof(Int64) &&
|
||||
typeof(T) != typeof(UInt16) &&
|
||||
typeof(T) != typeof(UInt32) &&
|
||||
typeof(T) != typeof(UInt64))
|
||||
{
|
||||
throw new NotSupportedException("Not supported Struct type: " + typeof(T).ToString());
|
||||
}
|
||||
|
||||
ulong m = (ulong)(object)n;
|
||||
|
||||
for (ulong i = 0; i < m; i++)
|
||||
{
|
||||
act(i);
|
||||
}
|
||||
}
|
||||
|
||||
public static T To<T>(this byte[] src, ByteOrder srcOrder)
|
||||
where T : struct
|
||||
{
|
||||
T dest;
|
||||
byte[] buffer = src.ToHostOrder(srcOrder);
|
||||
|
||||
if (typeof(T) == typeof(Boolean))
|
||||
{
|
||||
dest = (T)(object)BitConverter.ToBoolean(buffer, 0);
|
||||
}
|
||||
else if (typeof(T) == typeof(Char))
|
||||
{
|
||||
dest = (T)(object)BitConverter.ToChar(buffer, 0);
|
||||
}
|
||||
else if (typeof(T) == typeof(Double))
|
||||
{
|
||||
dest = (T)(object)BitConverter.ToDouble(buffer, 0);
|
||||
}
|
||||
else if (typeof(T) == typeof(Int16))
|
||||
{
|
||||
dest = (T)(object)BitConverter.ToInt16(buffer, 0);
|
||||
}
|
||||
else if (typeof(T) == typeof(Int32))
|
||||
{
|
||||
dest = (T)(object)BitConverter.ToInt32(buffer, 0);
|
||||
}
|
||||
else if (typeof(T) == typeof(Int64))
|
||||
{
|
||||
dest = (T)(object)BitConverter.ToInt64(buffer, 0);
|
||||
}
|
||||
else if (typeof(T) == typeof(Single))
|
||||
{
|
||||
dest = (T)(object)BitConverter.ToSingle(buffer, 0);
|
||||
}
|
||||
else if (typeof(T) == typeof(UInt16))
|
||||
{
|
||||
dest = (T)(object)BitConverter.ToUInt16(buffer, 0);
|
||||
}
|
||||
else if (typeof(T) == typeof(UInt32))
|
||||
{
|
||||
dest = (T)(object)BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
else if (typeof(T) == typeof(UInt64))
|
||||
{
|
||||
dest = (T)(object)BitConverter.ToUInt64(buffer, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
dest = default(T);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public static byte[] ToBytes<T>(this T value, ByteOrder order)
|
||||
where T : struct
|
||||
{
|
||||
byte[] buffer;
|
||||
|
||||
if (typeof(T) == typeof(Boolean))
|
||||
{
|
||||
buffer = BitConverter.GetBytes((Boolean)(object)value);
|
||||
}
|
||||
else if (typeof(T) == typeof(Char))
|
||||
{
|
||||
buffer = BitConverter.GetBytes((Char)(object)value);
|
||||
}
|
||||
else if (typeof(T) == typeof(Double))
|
||||
{
|
||||
buffer = BitConverter.GetBytes((Double)(object)value);
|
||||
}
|
||||
else if (typeof(T) == typeof(Int16))
|
||||
{
|
||||
buffer = BitConverter.GetBytes((Int16)(object)value);
|
||||
}
|
||||
else if (typeof(T) == typeof(Int32))
|
||||
{
|
||||
buffer = BitConverter.GetBytes((Int32)(object)value);
|
||||
}
|
||||
else if (typeof(T) == typeof(Int64))
|
||||
{
|
||||
buffer = BitConverter.GetBytes((Int64)(object)value);
|
||||
}
|
||||
else if (typeof(T) == typeof(Single))
|
||||
{
|
||||
buffer = BitConverter.GetBytes((Single)(object)value);
|
||||
}
|
||||
else if (typeof(T) == typeof(UInt16))
|
||||
{
|
||||
buffer = BitConverter.GetBytes((UInt16)(object)value);
|
||||
}
|
||||
else if (typeof(T) == typeof(UInt32))
|
||||
{
|
||||
buffer = BitConverter.GetBytes((UInt32)(object)value);
|
||||
}
|
||||
else if (typeof(T) == typeof(UInt64))
|
||||
{
|
||||
buffer = BitConverter.GetBytes((UInt64)(object)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = new byte[]{};
|
||||
}
|
||||
|
||||
return order.IsHostOrder()
|
||||
? buffer
|
||||
: buffer.Reverse().ToArray();
|
||||
}
|
||||
|
||||
public static byte[] ToHostOrder(this byte[] src, ByteOrder srcOrder)
|
||||
{
|
||||
byte[] buffer = new byte[src.Length];
|
||||
src.CopyTo(buffer, 0);
|
||||
|
||||
return srcOrder.IsHostOrder()
|
||||
? buffer
|
||||
: buffer.Reverse().ToArray();
|
||||
}
|
||||
|
||||
public static string ToString<T>(this T[] array, string separater)
|
||||
{
|
||||
int len;
|
||||
StringBuilder sb;
|
||||
|
||||
len = array.Length;
|
||||
if (len == 0)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
sb = new StringBuilder();
|
||||
for (int i = 0; i < len - 1; i++)
|
||||
{
|
||||
sb.AppendFormat("{0}{1}", array[i].ToString(), separater);
|
||||
}
|
||||
sb.Append(array[len - 1].ToString());
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
59
websocket-sharp/Frame/CloseStatusCode.cs
Normal file
59
websocket-sharp/Frame/CloseStatusCode.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* CloseStatusCode.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp.Frame
|
||||
{
|
||||
public enum CloseStatusCode : ushort
|
||||
{
|
||||
/*
|
||||
* Close Status Code
|
||||
*
|
||||
* Defined Status Codes: http://tools.ietf.org/html/rfc6455#section-7.4.1
|
||||
*
|
||||
* "Reserved value" MUST NOT be set as a status code in a Close control frame by an endpoint.
|
||||
* It is designated for use in applications expecting a status code to indicate that connection
|
||||
* was closed due to a system grounds.
|
||||
*
|
||||
*/
|
||||
NORMAL = 1000, // Normal closure.
|
||||
AWAY = 1001, // A Server going down or a browser having navigated away from a page.
|
||||
PROTOCOL_ERROR = 1002, // Terminating the connection due to a protocol error.
|
||||
INCORRECT_DATA = 1003, // Received a type of data it cannot accept.
|
||||
UNDEFINED = 1004, // Reserved value. Still undefined.
|
||||
NO_STATUS_CODE = 1005, // Reserved value.
|
||||
ABNORMAL = 1006, // Reserved value. Connection was closed abnormally.
|
||||
INCONSISTENT_DATA = 1007, // Received data within a message that was not consistent with the type of the message.
|
||||
POLICY_VIOLATION = 1008, // Received a message that violates its policy.
|
||||
TOO_BIG = 1009, // Received a message that is too big.
|
||||
IGNORE_EXTENSION = 1010, // Server ignored negotiated extensions.
|
||||
SERVER_ERROR = 1011, // Server encountered an unexpected condition.
|
||||
HANDSHAKE_FAILURE = 1015 // Reserved value. Failure to establish a connection.
|
||||
}
|
||||
}
|
38
websocket-sharp/Frame/Fin.cs
Normal file
38
websocket-sharp/Frame/Fin.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* Fin.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp.Frame
|
||||
{
|
||||
public enum Fin : byte
|
||||
{
|
||||
MORE = 0x0,
|
||||
FINAL = 0x1
|
||||
}
|
||||
}
|
38
websocket-sharp/Frame/Mask.cs
Normal file
38
websocket-sharp/Frame/Mask.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* Mask.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp.Frame
|
||||
{
|
||||
public enum Mask : byte
|
||||
{
|
||||
UNMASK = 0x0,
|
||||
MASK = 0x1
|
||||
}
|
||||
}
|
43
websocket-sharp/Frame/Opcode.cs
Normal file
43
websocket-sharp/Frame/Opcode.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* Opcode.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp.Frame
|
||||
{
|
||||
[Flags]
|
||||
public enum Opcode : byte
|
||||
{
|
||||
CONT = 0x0,
|
||||
TEXT = 0x1,
|
||||
BINARY = 0x2,
|
||||
CLOSE = 0x8,
|
||||
PING = 0x9,
|
||||
PONG = 0xa
|
||||
}
|
||||
}
|
184
websocket-sharp/Frame/PayloadData.cs
Normal file
184
websocket-sharp/Frame/PayloadData.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* PayloadData.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace WebSocketSharp.Frame
|
||||
{
|
||||
public class PayloadData : IEnumerable<byte>
|
||||
{
|
||||
|
||||
#region Public Static Fields
|
||||
|
||||
public static readonly ulong MaxLength;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public byte[] ExtensionData { get; private set; }
|
||||
public byte[] ApplicationData { get; private set; }
|
||||
public bool IsMasked { get; private set; }
|
||||
|
||||
public ulong Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return (ulong)(ExtensionData.LongLength + ApplicationData.LongLength);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Constructor
|
||||
|
||||
static PayloadData()
|
||||
{
|
||||
MaxLength = long.MaxValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
public PayloadData(string appData)
|
||||
: this(Encoding.UTF8.GetBytes(appData))
|
||||
{
|
||||
}
|
||||
|
||||
public PayloadData(byte[] appData)
|
||||
: this(new byte[]{}, appData)
|
||||
{
|
||||
}
|
||||
|
||||
public PayloadData(byte[] appData, bool masked)
|
||||
: this(new byte[]{}, appData, masked)
|
||||
{
|
||||
}
|
||||
|
||||
public PayloadData(byte[] extData, byte[] appData)
|
||||
: this(extData, appData, false)
|
||||
{
|
||||
}
|
||||
|
||||
public PayloadData(byte[] extData, byte[] appData, bool masked)
|
||||
{
|
||||
Func<string, Action> func = s => () =>
|
||||
{
|
||||
string message = String.Format("{0} must not be null.", s);
|
||||
throw new ArgumentNullException(message);
|
||||
};
|
||||
extData.IsNullDo(func("extData"));
|
||||
appData.IsNullDo(func("appData"));
|
||||
|
||||
if ((ulong)extData.LongLength + (ulong)appData.LongLength > MaxLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Plus extData length and appData lenght must be less than MaxLength.");
|
||||
}
|
||||
|
||||
ExtensionData = extData;
|
||||
ApplicationData = appData;
|
||||
IsMasked = masked;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void mask(byte[] src, byte[] key)
|
||||
{
|
||||
if (key.Length != 4)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("key length must be 4.");
|
||||
}
|
||||
|
||||
for (long i = 0; i < src.LongLength; i++)
|
||||
{
|
||||
src[i] = (byte)(src[i] ^ key[i % 4]);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public IEnumerator<byte> GetEnumerator()
|
||||
{
|
||||
foreach (byte b in ExtensionData)
|
||||
{
|
||||
yield return b;
|
||||
}
|
||||
foreach (byte b in ApplicationData)
|
||||
{
|
||||
yield return b;
|
||||
}
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Mask(byte[] maskingKey)
|
||||
{
|
||||
if (ExtensionData.LongLength > 0)
|
||||
{
|
||||
mask(ExtensionData, maskingKey);
|
||||
}
|
||||
if (ApplicationData.LongLength > 0)
|
||||
{
|
||||
mask(ApplicationData, maskingKey);
|
||||
}
|
||||
|
||||
IsMasked = !IsMasked;
|
||||
}
|
||||
|
||||
public byte[] ToBytes()
|
||||
{
|
||||
if (ExtensionData.LongLength > 0)
|
||||
{
|
||||
return ExtensionData.Concat(ApplicationData).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
return ApplicationData;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return BitConverter.ToString(ToBytes());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
38
websocket-sharp/Frame/Rsv.cs
Normal file
38
websocket-sharp/Frame/Rsv.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* Rsv.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace WebSocketSharp.Frame
|
||||
{
|
||||
public enum Rsv : byte
|
||||
{
|
||||
OFF = 0x0,
|
||||
ON = 0x1
|
||||
}
|
||||
}
|
461
websocket-sharp/Frame/WsFrame.cs
Normal file
461
websocket-sharp/Frame/WsFrame.cs
Normal file
@@ -0,0 +1,461 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* WsFrame.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebSocketSharp.Frame
|
||||
{
|
||||
public class WsFrame : IEnumerable<byte>
|
||||
{
|
||||
#region Private Static Fields
|
||||
|
||||
private static readonly int _readBufferLen;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public Fin Fin { get; private set; }
|
||||
public Rsv Rsv1 { get; private set; }
|
||||
public Rsv Rsv2 { get; private set; }
|
||||
public Rsv Rsv3 { get; private set; }
|
||||
public Opcode Opcode { get; private set; }
|
||||
public Mask Masked { get; private set; }
|
||||
public byte PayloadLen { get; private set; }
|
||||
public byte[] ExtPayloadLen { get; private set; }
|
||||
public byte[] MaskingKey { get; private set; }
|
||||
public PayloadData PayloadData { get; private set; }
|
||||
|
||||
public ulong Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return 2 + (ulong)(ExtPayloadLen.Length + MaskingKey.Length) + PayloadLength;
|
||||
}
|
||||
}
|
||||
|
||||
public ulong PayloadLength
|
||||
{
|
||||
get
|
||||
{
|
||||
return PayloadData.Length;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Constructor
|
||||
|
||||
static WsFrame()
|
||||
{
|
||||
_readBufferLen = 1024;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Constructors
|
||||
|
||||
private WsFrame()
|
||||
{
|
||||
Rsv1 = Rsv.OFF;
|
||||
Rsv2 = Rsv.OFF;
|
||||
Rsv3 = Rsv.OFF;
|
||||
ExtPayloadLen = new byte[]{};
|
||||
MaskingKey = new byte[]{};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
public WsFrame(Opcode opcode, PayloadData payloadData)
|
||||
: this(Fin.FINAL, opcode, payloadData)
|
||||
{
|
||||
}
|
||||
|
||||
public WsFrame(Fin fin, Opcode opcode, PayloadData payloadData)
|
||||
: this(fin, opcode, Mask.MASK, payloadData)
|
||||
{
|
||||
}
|
||||
|
||||
public WsFrame(Fin fin, Opcode opcode, Mask mask, PayloadData payloadData)
|
||||
: this()
|
||||
{
|
||||
Fin = fin;
|
||||
Opcode = opcode;
|
||||
Masked = mask;
|
||||
|
||||
ulong dataLength = payloadData.Length;
|
||||
if (dataLength < 126)
|
||||
{
|
||||
PayloadLen = (byte)dataLength;
|
||||
}
|
||||
else if (dataLength < 0x010000)
|
||||
{
|
||||
PayloadLen = (byte)126;
|
||||
ExtPayloadLen = ((ushort)dataLength).ToBytes(ByteOrder.BIG);
|
||||
}
|
||||
else
|
||||
{
|
||||
PayloadLen = (byte)127;
|
||||
ExtPayloadLen = dataLength.ToBytes(ByteOrder.BIG);
|
||||
}
|
||||
|
||||
PayloadData = payloadData;
|
||||
if (Masked == Mask.MASK)
|
||||
{
|
||||
MaskingKey = new byte[4];
|
||||
var rand = new Random();
|
||||
rand.NextBytes(MaskingKey);
|
||||
PayloadData.Mask(MaskingKey);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Static Methods
|
||||
|
||||
public static WsFrame Parse(byte[] src)
|
||||
{
|
||||
return Parse(src, true);
|
||||
}
|
||||
|
||||
public static WsFrame Parse(byte[] src, bool unmask)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream(src))
|
||||
{
|
||||
return Parse(ms, unmask);
|
||||
}
|
||||
}
|
||||
|
||||
public static WsFrame Parse<TStream>(TStream stream)
|
||||
where TStream : System.IO.Stream
|
||||
{
|
||||
return Parse(stream, true);
|
||||
}
|
||||
|
||||
public static WsFrame Parse<TStream>(TStream stream, bool unmask)
|
||||
where TStream : System.IO.Stream
|
||||
{
|
||||
Fin fin;
|
||||
Rsv rsv1, rsv2, rsv3;
|
||||
Opcode opcode;
|
||||
Mask masked;
|
||||
byte payloadLen;
|
||||
byte[] extPayloadLen = new byte[]{};
|
||||
byte[] maskingKey = new byte[]{};
|
||||
PayloadData payloadData;
|
||||
|
||||
byte[] buffer1, buffer2, buffer3;
|
||||
int buffer1Len = 2;
|
||||
int buffer2Len = 0;
|
||||
ulong buffer3Len = 0;
|
||||
int maskingKeyLen = 4;
|
||||
|
||||
buffer1 = new byte[buffer1Len];
|
||||
stream.Read(buffer1, 0, buffer1Len);
|
||||
|
||||
// FIN
|
||||
fin = (buffer1[0] & 0x80) == 0x80
|
||||
? Fin.FINAL
|
||||
: Fin.MORE;
|
||||
// RSV1
|
||||
rsv1 = (buffer1[0] & 0x40) == 0x40
|
||||
? Rsv.ON
|
||||
: Rsv.OFF;
|
||||
// RSV2
|
||||
rsv2 = (buffer1[0] & 0x20) == 0x20
|
||||
? Rsv.ON
|
||||
: Rsv.OFF;
|
||||
// RSV3
|
||||
rsv3 = (buffer1[0] & 0x10) == 0x10
|
||||
? Rsv.ON
|
||||
: Rsv.OFF;
|
||||
// opcode
|
||||
opcode = (Opcode)(buffer1[0] & 0x0f);
|
||||
// MASK
|
||||
masked = (buffer1[1] & 0x80) == 0x80
|
||||
? Mask.MASK
|
||||
: Mask.UNMASK;
|
||||
// Payload len
|
||||
payloadLen = (byte)(buffer1[1] & 0x7f);
|
||||
// Extended payload length
|
||||
if (payloadLen <= 125)
|
||||
{
|
||||
buffer3Len = payloadLen;
|
||||
}
|
||||
else if (payloadLen == 126)
|
||||
{
|
||||
buffer2Len = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer2Len = 8;
|
||||
}
|
||||
|
||||
if (buffer2Len > 0)
|
||||
{
|
||||
buffer2 = new byte[buffer2Len];
|
||||
stream.Read(buffer2, 0, buffer2Len);
|
||||
extPayloadLen = buffer2;
|
||||
switch (buffer2Len)
|
||||
{
|
||||
case 2:
|
||||
buffer3Len = extPayloadLen.To<ushort>(ByteOrder.BIG);
|
||||
break;
|
||||
case 8:
|
||||
buffer3Len = extPayloadLen.To<ulong>(ByteOrder.BIG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer3Len > PayloadData.MaxLength)
|
||||
{
|
||||
throw new WsReceivedTooBigMessageException();
|
||||
}
|
||||
// Masking-key
|
||||
if (masked == Mask.MASK)
|
||||
{
|
||||
maskingKey = new byte[maskingKeyLen];
|
||||
stream.Read(maskingKey, 0, maskingKeyLen);
|
||||
}
|
||||
// Payload Data
|
||||
if (buffer3Len <= (ulong)_readBufferLen)
|
||||
{
|
||||
buffer3 = new byte[buffer3Len];
|
||||
stream.Read(buffer3, 0, (int)buffer3Len);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer3 = stream.ReadBytes(buffer3Len, _readBufferLen);
|
||||
}
|
||||
|
||||
if (masked == Mask.MASK)
|
||||
{
|
||||
payloadData = new PayloadData(buffer3, true);
|
||||
if (unmask == true)
|
||||
{
|
||||
payloadData.Mask(maskingKey);
|
||||
masked = Mask.UNMASK;
|
||||
maskingKey = new byte[]{};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
payloadData = new PayloadData(buffer3);
|
||||
}
|
||||
|
||||
return new WsFrame
|
||||
{
|
||||
Fin = fin,
|
||||
Rsv1 = rsv1,
|
||||
Rsv2 = rsv2,
|
||||
Rsv3 = rsv3,
|
||||
Opcode = opcode,
|
||||
Masked = masked,
|
||||
PayloadLen = payloadLen,
|
||||
ExtPayloadLen = extPayloadLen,
|
||||
MaskingKey = maskingKey,
|
||||
PayloadData = payloadData
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public IEnumerator<byte> GetEnumerator()
|
||||
{
|
||||
foreach (byte b in ToBytes())
|
||||
{
|
||||
yield return b;
|
||||
}
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void Print()
|
||||
{
|
||||
byte[] buffer;
|
||||
long count, i, j;
|
||||
int countDigit, remainder;
|
||||
string countFmt, extPayloadLen, headerFmt, topLineFmt, bottomLineFmt, payloadData, spFmt;
|
||||
|
||||
switch (ExtPayloadLen.Length)
|
||||
{
|
||||
case 2:
|
||||
extPayloadLen = ExtPayloadLen.To<ushort>(ByteOrder.BIG).ToString();
|
||||
break;
|
||||
case 8:
|
||||
extPayloadLen = ExtPayloadLen.To<ulong>(ByteOrder.BIG).ToString();
|
||||
break;
|
||||
default:
|
||||
extPayloadLen = String.Empty;
|
||||
break;
|
||||
}
|
||||
|
||||
if (((Opcode.TEXT | Opcode.PING | Opcode.PONG) & Opcode) == Opcode &&
|
||||
Masked == Mask.UNMASK &&
|
||||
PayloadLength > 0)
|
||||
{
|
||||
payloadData = Encoding.UTF8.GetString(PayloadData.ToBytes());
|
||||
}
|
||||
else
|
||||
{
|
||||
payloadData = BitConverter.ToString(PayloadData.ToBytes());
|
||||
}
|
||||
|
||||
headerFmt = @"
|
||||
WsFrame:
|
||||
|
||||
FIN={0}, RSV1={1}, RSV2={2}, RSV3={3}, Opcode={4},
|
||||
MASK={5}, Payload Len={6}, Extended Payload Len={7},
|
||||
Masking Key ={8},
|
||||
Payload Data={9}";
|
||||
|
||||
buffer = ToBytes();
|
||||
count = (long)(Length / 4);
|
||||
remainder = (int)(Length % 4);
|
||||
|
||||
if (count < 10000)
|
||||
{
|
||||
countDigit = 4;
|
||||
countFmt = "{0,4}";
|
||||
}
|
||||
else if (count < 0x010000)
|
||||
{
|
||||
countDigit = 4;
|
||||
countFmt = "{0,4:X}";
|
||||
}
|
||||
else if (count < 0x0100000000)
|
||||
{
|
||||
countDigit = 8;
|
||||
countFmt = "{0,8:X}";
|
||||
}
|
||||
else
|
||||
{
|
||||
countDigit = 16;
|
||||
countFmt = "{0,16:X}";
|
||||
}
|
||||
|
||||
spFmt = String.Format("{{0,{0}}}", countDigit);
|
||||
|
||||
topLineFmt = String.Format(@"
|
||||
{0} 01234567 89ABCDEF 01234567 89ABCDEF
|
||||
{0}+--------+--------+--------+--------+", spFmt);
|
||||
|
||||
Func<string, Action<string, string, string, string>> func = s =>
|
||||
{
|
||||
long lineCount = 0;
|
||||
string lineFmt = String.Format(" {0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|", s);
|
||||
return (arg1, arg2, arg3, arg4) =>
|
||||
{
|
||||
Console.WriteLine(lineFmt, ++lineCount, arg1, arg2, arg3, arg4);
|
||||
};
|
||||
};
|
||||
var printLine = func(countFmt);
|
||||
|
||||
bottomLineFmt = String.Format(" {0}+--------+--------+--------+--------+", spFmt);
|
||||
|
||||
Console.WriteLine(headerFmt,
|
||||
Fin, Rsv1, Rsv2, Rsv3, Opcode,
|
||||
Masked, PayloadLen, extPayloadLen,
|
||||
BitConverter.ToString(MaskingKey),
|
||||
payloadData);
|
||||
|
||||
Console.WriteLine(topLineFmt, String.Empty);
|
||||
|
||||
for (i = 0; i <= count; i++)
|
||||
{
|
||||
j = i * 4;
|
||||
if (i < count)
|
||||
{
|
||||
printLine(
|
||||
Convert.ToString(buffer[j], 2).PadLeft(8, '0'),
|
||||
Convert.ToString(buffer[j + 1], 2).PadLeft(8, '0'),
|
||||
Convert.ToString(buffer[j + 2], 2).PadLeft(8, '0'),
|
||||
Convert.ToString(buffer[j + 3], 2).PadLeft(8, '0'));
|
||||
}
|
||||
else if (i == count && remainder > 0)
|
||||
{
|
||||
printLine(
|
||||
Convert.ToString(buffer[j], 2).PadLeft(8, '0'),
|
||||
remainder >= 2 ? Convert.ToString(buffer[j + 1], 2).PadLeft(8, '0') : String.Empty,
|
||||
remainder == 3 ? Convert.ToString(buffer[j + 2], 2).PadLeft(8, '0') : String.Empty,
|
||||
String.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine(bottomLineFmt, String.Empty);
|
||||
}
|
||||
|
||||
public byte[] ToBytes()
|
||||
{
|
||||
var bytes = new List<byte>();
|
||||
|
||||
int first16 = (int)Fin;
|
||||
first16 = (first16 << 1) + (int)Rsv1;
|
||||
first16 = (first16 << 1) + (int)Rsv2;
|
||||
first16 = (first16 << 1) + (int)Rsv3;
|
||||
first16 = (first16 << 4) + (int)Opcode;
|
||||
first16 = (first16 << 1) + (int)Masked;
|
||||
first16 = (first16 << 7) + (int)PayloadLen;
|
||||
bytes.AddRange(((ushort)first16).ToBytes(ByteOrder.BIG));
|
||||
|
||||
if (PayloadLen >= 126)
|
||||
{
|
||||
bytes.AddRange(ExtPayloadLen);
|
||||
}
|
||||
|
||||
if (Masked == Mask.MASK)
|
||||
{
|
||||
bytes.AddRange(MaskingKey);
|
||||
}
|
||||
|
||||
if (PayloadLen > 0)
|
||||
{
|
||||
bytes.AddRange(PayloadData.ToBytes());
|
||||
}
|
||||
|
||||
return bytes.ToArray();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return BitConverter.ToString(ToBytes());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
87
websocket-sharp/MessageEventArgs.cs
Normal file
87
websocket-sharp/MessageEventArgs.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* MessageEventArgs.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using WebSocketSharp.Frame;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
public class MessageEventArgs : EventArgs
|
||||
{
|
||||
private Opcode _type;
|
||||
private PayloadData _data;
|
||||
|
||||
public Opcode Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
}
|
||||
|
||||
public string Data
|
||||
{
|
||||
get
|
||||
{
|
||||
if (((Opcode.TEXT | Opcode.PING | Opcode.PONG) & _type) == _type)
|
||||
{
|
||||
if (_data.Length > 0)
|
||||
{
|
||||
return Encoding.UTF8.GetString(_data.ToBytes());
|
||||
}
|
||||
else
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
return _type.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] RawData
|
||||
{
|
||||
get
|
||||
{
|
||||
return _data.ToBytes();
|
||||
}
|
||||
}
|
||||
|
||||
public MessageEventArgs(string data)
|
||||
: this(Opcode.TEXT, new PayloadData(data))
|
||||
{
|
||||
}
|
||||
|
||||
public MessageEventArgs(Opcode type, PayloadData data)
|
||||
{
|
||||
_type = type;
|
||||
_data = data;
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 sta.blockhead
|
||||
* Copyright (c) 2010-2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -27,15 +27,18 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using WebSocketSharp.Frame;
|
||||
|
||||
namespace WebSocketSharp
|
||||
namespace WebSocketSharp.Stream
|
||||
{
|
||||
public interface IWsStream : IDisposable
|
||||
{
|
||||
void Close();
|
||||
int Read(byte[] buffer, int offset, int size);
|
||||
int ReadByte();
|
||||
void Write(byte[] buffer, int offset, int count);
|
||||
void WriteByte(byte value);
|
||||
void Close();
|
||||
int Read(byte[] buffer, int offset, int size);
|
||||
int ReadByte();
|
||||
WsFrame ReadFrame();
|
||||
void Write(byte[] buffer, int offset, int count);
|
||||
void WriteByte(byte value);
|
||||
void WriteFrame(WsFrame frame);
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 sta.blockhead
|
||||
* Copyright (c) 2010-2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -32,21 +32,24 @@ using System.IO;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using WebSocketSharp.Frame;
|
||||
|
||||
namespace WebSocketSharp
|
||||
namespace WebSocketSharp.Stream
|
||||
{
|
||||
public class WsStream<T> : IWsStream
|
||||
where T : Stream
|
||||
public class WsStream<TStream> : IWsStream
|
||||
where TStream : System.IO.Stream
|
||||
{
|
||||
private T innerStream;
|
||||
private TStream _innerStream;
|
||||
private Object _forRead;
|
||||
private Object _forWrite;
|
||||
|
||||
public WsStream(T innerStream)
|
||||
public WsStream(TStream innerStream)
|
||||
{
|
||||
Type streamType = typeof(T);
|
||||
Type streamType = typeof(TStream);
|
||||
if (streamType != typeof(NetworkStream) &&
|
||||
streamType != typeof(SslStream))
|
||||
{
|
||||
throw new NotSupportedException("Unsupported Stream type: " + streamType.ToString());
|
||||
throw new NotSupportedException("Not supported Stream type: " + streamType.ToString());
|
||||
}
|
||||
|
||||
if (innerStream == null)
|
||||
@@ -54,37 +57,56 @@ namespace WebSocketSharp
|
||||
throw new ArgumentNullException("innerStream");
|
||||
}
|
||||
|
||||
this.innerStream = innerStream;
|
||||
_innerStream = innerStream;
|
||||
_forRead = new object();
|
||||
_forWrite = new object();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
innerStream.Close();
|
||||
_innerStream.Close();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
innerStream.Dispose();
|
||||
_innerStream.Dispose();
|
||||
}
|
||||
|
||||
public int Read(byte[] buffer, int offset, int size)
|
||||
{
|
||||
return innerStream.Read(buffer, offset, size);
|
||||
return _innerStream.Read(buffer, offset, size);
|
||||
}
|
||||
|
||||
public int ReadByte()
|
||||
{
|
||||
return innerStream.ReadByte();
|
||||
return _innerStream.ReadByte();
|
||||
}
|
||||
|
||||
public WsFrame ReadFrame()
|
||||
{
|
||||
lock (_forRead)
|
||||
{
|
||||
return WsFrame.Parse(_innerStream);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
innerStream.Write(buffer, offset, count);
|
||||
_innerStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public void WriteByte(byte value)
|
||||
{
|
||||
innerStream.WriteByte(value);
|
||||
_innerStream.WriteByte(value);
|
||||
}
|
||||
|
||||
public void WriteFrame(WsFrame frame)
|
||||
{
|
||||
lock (_forWrite)
|
||||
{
|
||||
var buffer = frame.ToBytes();
|
||||
_innerStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
54
websocket-sharp/WsReceivedTooBigMessageException.cs
Normal file
54
websocket-sharp/WsReceivedTooBigMessageException.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
#region MIT License
|
||||
/**
|
||||
* WsReceivedTooBigMessageException.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using WebSocketSharp.Frame;
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
public class WsReceivedTooBigMessageException : Exception
|
||||
{
|
||||
private static readonly string _defaultMessage;
|
||||
|
||||
static WsReceivedTooBigMessageException()
|
||||
{
|
||||
_defaultMessage = String.Format(
|
||||
"Client received a payload data bigger than the allowable value({0} bytes).", PayloadData.MaxLength);
|
||||
}
|
||||
|
||||
public WsReceivedTooBigMessageException()
|
||||
: this(_defaultMessage)
|
||||
{
|
||||
}
|
||||
|
||||
public WsReceivedTooBigMessageException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 sta.blockhead
|
||||
* Copyright (c) 2010-2012 sta.blockhead
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -52,17 +52,30 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="notify-sharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=2df29c54e245917a">
|
||||
<Package>notify-sharp</Package>
|
||||
</Reference>
|
||||
<Reference Include="System.ServiceModel" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AssemblyInfo.cs" />
|
||||
<Compile Include="Ext.cs" />
|
||||
<Compile Include="WebSocket.cs" />
|
||||
<Compile Include="WsState.cs" />
|
||||
<Compile Include="IWsStream.cs" />
|
||||
<Compile Include="WsStream.cs" />
|
||||
<Compile Include="MessageEventArgs.cs" />
|
||||
<Compile Include="CloseEventArgs.cs" />
|
||||
<Compile Include="WsReceivedTooBigMessageException.cs" />
|
||||
<Compile Include="ByteOrder.cs" />
|
||||
<Compile Include="Stream\IWsStream.cs" />
|
||||
<Compile Include="Stream\WsStream.cs" />
|
||||
<Compile Include="Frame\WsFrame.cs" />
|
||||
<Compile Include="Frame\CloseStatusCode.cs" />
|
||||
<Compile Include="Frame\Fin.cs" />
|
||||
<Compile Include="Frame\Mask.cs" />
|
||||
<Compile Include="Frame\Opcode.cs" />
|
||||
<Compile Include="Frame\PayloadData.cs" />
|
||||
<Compile Include="Frame\Rsv.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
<Folder Include="Stream\" />
|
||||
<Folder Include="Frame\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Binary file not shown.
Reference in New Issue
Block a user