Supports RFC 6455
This commit is contained in:
parent
fc6ee2db12
commit
118e0015d5
@ -4,12 +4,12 @@ using System.Runtime.CompilerServices;
|
|||||||
// Information about this assembly is defined by the following attributes.
|
// Information about this assembly is defined by the following attributes.
|
||||||
// Change them to the values specific to your project.
|
// Change them to the values specific to your project.
|
||||||
|
|
||||||
[assembly: AssemblyTitle("wsclient1")]
|
[assembly: AssemblyTitle("Example")]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription("")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("")]
|
[assembly: AssemblyProduct("")]
|
||||||
[assembly: AssemblyCopyright("")]
|
[assembly: AssemblyCopyright("sta")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
127
Example/Program.cs
Normal file
127
Example/Program.cs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
#if NOTIFY
|
||||||
|
using Notifications;
|
||||||
|
#endif
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Threading;
|
||||||
|
using WebSocketSharp;
|
||||||
|
|
||||||
|
namespace Example
|
||||||
|
{
|
||||||
|
public struct NfMessage
|
||||||
|
{
|
||||||
|
public string Summary;
|
||||||
|
public string Body;
|
||||||
|
public string Icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ThreadState
|
||||||
|
{
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public AutoResetEvent Notification { get; private set; }
|
||||||
|
|
||||||
|
public ThreadState()
|
||||||
|
{
|
||||||
|
Enabled = true;
|
||||||
|
Notification = new AutoResetEvent(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
private static Queue _msgQ = Queue.Synchronized(new Queue());
|
||||||
|
|
||||||
|
private static void enNfMessage(string summary, string body, string icon)
|
||||||
|
{
|
||||||
|
var msg = new NfMessage
|
||||||
|
{
|
||||||
|
Summary = summary,
|
||||||
|
Body = body,
|
||||||
|
Icon = icon
|
||||||
|
};
|
||||||
|
|
||||||
|
_msgQ.Enqueue(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
ThreadState ts = new ThreadState();
|
||||||
|
|
||||||
|
WaitCallback notifyMsg = state =>
|
||||||
|
{
|
||||||
|
while (ts.Enabled)
|
||||||
|
{
|
||||||
|
Thread.Sleep(500);
|
||||||
|
|
||||||
|
if (_msgQ.Count > 0)
|
||||||
|
{
|
||||||
|
NfMessage msg = (NfMessage)_msgQ.Dequeue();
|
||||||
|
#if NOTIFY
|
||||||
|
Notification nf = new Notification(msg.Summary,
|
||||||
|
msg.Body,
|
||||||
|
msg.Icon);
|
||||||
|
nf.AddHint("append", "allowed");
|
||||||
|
nf.Show();
|
||||||
|
#else
|
||||||
|
Console.WriteLine("{0}: {1}", msg.Summary, msg.Body);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.Notification.Set();
|
||||||
|
};
|
||||||
|
|
||||||
|
ThreadPool.QueueUserWorkItem(notifyMsg);
|
||||||
|
|
||||||
|
using (WebSocket ws = new WebSocket("ws://echo.websocket.org", "echo"))
|
||||||
|
//using (WebSocket ws = new WebSocket("wss://echo.websocket.org", "echo"))
|
||||||
|
{
|
||||||
|
ws.OnOpen += (sender, e) =>
|
||||||
|
{
|
||||||
|
ws.Send("Hi, all!");
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.OnMessage += (sender, e) =>
|
||||||
|
{
|
||||||
|
enNfMessage("[WebSocket] Message", e.Data, "notification-message-im");
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.OnError += (sender, e) =>
|
||||||
|
{
|
||||||
|
enNfMessage("[WebSocket] Error", e.Data, "notification-message-im");
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.OnClose += (sender, e) =>
|
||||||
|
{
|
||||||
|
enNfMessage(
|
||||||
|
String.Format("[WebSocket] Close({0}:{1})", (ushort)e.Code, e.Code),
|
||||||
|
e.Reason,
|
||||||
|
"notification-message-im");
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.Connect();
|
||||||
|
|
||||||
|
Thread.Sleep(500);
|
||||||
|
Console.WriteLine("\nType \"exit\" to exit.\n");
|
||||||
|
|
||||||
|
string data;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Thread.Sleep(500);
|
||||||
|
|
||||||
|
Console.Write("> ");
|
||||||
|
data = Console.ReadLine();
|
||||||
|
if (data == "exit")
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.Send(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.Enabled = false;
|
||||||
|
ts.Notification.WaitOne();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,12 +4,12 @@ using System.Runtime.CompilerServices;
|
|||||||
// Information about this assembly is defined by the following attributes.
|
// Information about this assembly is defined by the following attributes.
|
||||||
// Change them to the values specific to your project.
|
// Change them to the values specific to your project.
|
||||||
|
|
||||||
[assembly: AssemblyTitle("wsclient")]
|
[assembly: AssemblyTitle("Example1")]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription("")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("")]
|
||||||
[assembly: AssemblyProduct("")]
|
[assembly: AssemblyProduct("")]
|
||||||
[assembly: AssemblyCopyright("")]
|
[assembly: AssemblyCopyright("sta")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
318
Example1/AudioStreamer.cs
Normal file
318
Example1/AudioStreamer.cs
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
#if NOTIFY
|
||||||
|
using Notifications;
|
||||||
|
#endif
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using WebSocketSharp;
|
||||||
|
using WebSocketSharp.Frame;
|
||||||
|
|
||||||
|
namespace Example
|
||||||
|
{
|
||||||
|
public struct NfMessage
|
||||||
|
{
|
||||||
|
public string Summary;
|
||||||
|
public string Body;
|
||||||
|
public string Icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AudioMessage
|
||||||
|
{
|
||||||
|
public uint user_id;
|
||||||
|
public byte ch_num;
|
||||||
|
public uint buffer_length;
|
||||||
|
public float[,] buffer_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TextMessage
|
||||||
|
{
|
||||||
|
public uint? user_id;
|
||||||
|
public string name;
|
||||||
|
public string type;
|
||||||
|
public string message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ThreadState
|
||||||
|
{
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public AutoResetEvent Notification { get; private set; }
|
||||||
|
|
||||||
|
public ThreadState()
|
||||||
|
{
|
||||||
|
Enabled = true;
|
||||||
|
Notification = new AutoResetEvent(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AudioStreamer : IDisposable
|
||||||
|
{
|
||||||
|
private Dictionary<uint, Queue> _audioBox;
|
||||||
|
private Queue _msgQ;
|
||||||
|
private string _name;
|
||||||
|
private WaitCallback _notifyMsg;
|
||||||
|
private ThreadState _notifyMsgState;
|
||||||
|
private TimerCallback _sendHeartbeat;
|
||||||
|
private Timer _heartbeatTimer;
|
||||||
|
private uint? _user_id;
|
||||||
|
private WebSocket _ws;
|
||||||
|
|
||||||
|
public AudioStreamer(string url)
|
||||||
|
{
|
||||||
|
_ws = new WebSocket(url);
|
||||||
|
_msgQ = Queue.Synchronized(new Queue());
|
||||||
|
_audioBox = new Dictionary<uint, Queue>();
|
||||||
|
_user_id = null;
|
||||||
|
|
||||||
|
configure();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configure()
|
||||||
|
{
|
||||||
|
_ws.OnOpen += (sender, e) =>
|
||||||
|
{
|
||||||
|
var msg = createTextMessage("connection", String.Empty);
|
||||||
|
_ws.Send(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
_ws.OnMessage += (sender, e) =>
|
||||||
|
{
|
||||||
|
switch (e.Type)
|
||||||
|
{
|
||||||
|
case Opcode.TEXT:
|
||||||
|
var msg = parseTextMessage(e.Data);
|
||||||
|
_msgQ.Enqueue(msg);
|
||||||
|
break;
|
||||||
|
case Opcode.BINARY:
|
||||||
|
var audioMsg = parseAudioMessage(e.RawData);
|
||||||
|
if (audioMsg.user_id == _user_id) goto default;
|
||||||
|
if (_audioBox.ContainsKey(audioMsg.user_id))
|
||||||
|
{
|
||||||
|
_audioBox[audioMsg.user_id].Enqueue(audioMsg.buffer_array);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var q = Queue.Synchronized(new Queue());
|
||||||
|
q.Enqueue(audioMsg.buffer_array);
|
||||||
|
_audioBox.Add(audioMsg.user_id, q);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_ws.OnError += (sender, e) =>
|
||||||
|
{
|
||||||
|
enNfMessage("[AudioStreamer] error", "WS Error: " + e.Data, "notification-message-im");
|
||||||
|
};
|
||||||
|
|
||||||
|
_ws.OnClose += (sender, e) =>
|
||||||
|
{
|
||||||
|
enNfMessage
|
||||||
|
(
|
||||||
|
"[AudioStreamer] disconnect",
|
||||||
|
String.Format("WS Close({0}:{1}): {2}", (ushort)e.Code, e.Code, e.Reason),
|
||||||
|
"notification-message-im"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
_notifyMsgState = new ThreadState();
|
||||||
|
_notifyMsg = (state) =>
|
||||||
|
{
|
||||||
|
while (_notifyMsgState.Enabled)
|
||||||
|
{
|
||||||
|
Thread.Sleep(500);
|
||||||
|
|
||||||
|
if (_msgQ.Count > 0)
|
||||||
|
{
|
||||||
|
NfMessage msg = (NfMessage)_msgQ.Dequeue();
|
||||||
|
#if NOTIFY
|
||||||
|
Notification nf = new Notification(msg.Summary,
|
||||||
|
msg.Body,
|
||||||
|
msg.Icon);
|
||||||
|
nf.AddHint("append", "allowed");
|
||||||
|
nf.Show();
|
||||||
|
#else
|
||||||
|
Console.WriteLine("{0}: {1}", msg.Summary, msg.Body);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_notifyMsgState.Notification.Set();
|
||||||
|
};
|
||||||
|
|
||||||
|
_sendHeartbeat = (state) =>
|
||||||
|
{
|
||||||
|
var msg = createTextMessage("heartbeat", String.Empty);
|
||||||
|
_ws.Send(msg);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] createAudioMessage(float[,] buffer_array)
|
||||||
|
{
|
||||||
|
List<byte> msg = new List<byte>();
|
||||||
|
|
||||||
|
uint user_id = (uint)_user_id;
|
||||||
|
int ch_num = buffer_array.GetLength(0);
|
||||||
|
int buffer_length = buffer_array.GetLength(1);
|
||||||
|
|
||||||
|
msg.AddRange(user_id.ToBytes(ByteOrder.BIG));
|
||||||
|
msg.Add((byte)ch_num);
|
||||||
|
msg.AddRange(((uint)buffer_length).ToBytes(ByteOrder.BIG));
|
||||||
|
|
||||||
|
ch_num.Times(i =>
|
||||||
|
{
|
||||||
|
buffer_length.Times(j =>
|
||||||
|
{
|
||||||
|
msg.AddRange(buffer_array[i, j].ToBytes(ByteOrder.BIG));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return msg.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string createTextMessage(string type, string message)
|
||||||
|
{
|
||||||
|
var msg = new TextMessage
|
||||||
|
{
|
||||||
|
user_id = _user_id,
|
||||||
|
name = _name,
|
||||||
|
type = type,
|
||||||
|
message = message
|
||||||
|
};
|
||||||
|
|
||||||
|
return JsonConvert.SerializeObject(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AudioMessage parseAudioMessage(byte[] data)
|
||||||
|
{
|
||||||
|
uint user_id = data.SubArray(0, 4).To<uint>(ByteOrder.BIG);
|
||||||
|
byte ch_num = data.SubArray(4, 1)[0];
|
||||||
|
uint buffer_length = data.SubArray(5, 4).To<uint>(ByteOrder.BIG);
|
||||||
|
float[,] buffer_array = new float[ch_num, buffer_length];
|
||||||
|
|
||||||
|
int offset = 9;
|
||||||
|
ch_num.Times(i =>
|
||||||
|
{
|
||||||
|
buffer_length.Times(j =>
|
||||||
|
{
|
||||||
|
buffer_array[i, j] = data.SubArray(offset, 4).To<float>(ByteOrder.BIG);
|
||||||
|
offset += 4;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return new AudioMessage
|
||||||
|
{
|
||||||
|
user_id = user_id,
|
||||||
|
ch_num = ch_num,
|
||||||
|
buffer_length = buffer_length,
|
||||||
|
buffer_array = buffer_array
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private NfMessage parseTextMessage(string data)
|
||||||
|
{
|
||||||
|
JObject msg = JObject.Parse(data);
|
||||||
|
uint user_id = (uint)msg["user_id"];
|
||||||
|
string name = (string)msg["name"];
|
||||||
|
string type = (string)msg["type"];
|
||||||
|
|
||||||
|
string message;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "connection":
|
||||||
|
JArray users = (JArray)msg["message"];
|
||||||
|
StringBuilder sb = new StringBuilder("Now keeping connection\n");
|
||||||
|
foreach (JToken user in users)
|
||||||
|
{
|
||||||
|
sb.AppendFormat("user_id: {0} name: {1}\n", (uint)user["user_id"], (string)user["name"]);
|
||||||
|
}
|
||||||
|
message = sb.ToString().TrimEnd('\n');
|
||||||
|
break;
|
||||||
|
case "connected":
|
||||||
|
_user_id = user_id;
|
||||||
|
message = String.Format("user_id: {0} name: {1}", user_id, name);
|
||||||
|
break;
|
||||||
|
case "message":
|
||||||
|
message = String.Format("{0}: {1}", name, (string)msg["message"]);
|
||||||
|
break;
|
||||||
|
case "start_music":
|
||||||
|
message = String.Format("{0}: Started playing music!", name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message = "Received unknown type message: " + type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NfMessage
|
||||||
|
{
|
||||||
|
Summary = String.Format("[AudioStreamer] {0}", type),
|
||||||
|
Body = message,
|
||||||
|
Icon = "notification-message-im"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enNfMessage(string summary, string body, string icon)
|
||||||
|
{
|
||||||
|
var msg = new NfMessage
|
||||||
|
{
|
||||||
|
Summary = summary,
|
||||||
|
Body = body,
|
||||||
|
Icon = icon
|
||||||
|
};
|
||||||
|
|
||||||
|
_msgQ.Enqueue(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Connect()
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Console.Write("Your name > ");
|
||||||
|
name = Console.ReadLine();
|
||||||
|
}
|
||||||
|
while (name == String.Empty);
|
||||||
|
|
||||||
|
_name = name;
|
||||||
|
|
||||||
|
_ws.Connect();
|
||||||
|
|
||||||
|
ThreadPool.QueueUserWorkItem(_notifyMsg);
|
||||||
|
_heartbeatTimer = new Timer(_sendHeartbeat, null, 30 * 1000, 30 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disconnect()
|
||||||
|
{
|
||||||
|
var wait = new AutoResetEvent(false);
|
||||||
|
_heartbeatTimer.Dispose(wait);
|
||||||
|
wait.WaitOne();
|
||||||
|
|
||||||
|
_ws.Close();
|
||||||
|
|
||||||
|
_notifyMsgState.Enabled = false;
|
||||||
|
_notifyMsgState.Notification.WaitOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(string data)
|
||||||
|
{
|
||||||
|
var msg = createTextMessage("message", data);
|
||||||
|
_ws.Send(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(FileInfo file)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,10 +5,10 @@
|
|||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
<ProductVersion>9.0.21022</ProductVersion>
|
<ProductVersion>9.0.21022</ProductVersion>
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
<ProjectGuid>{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}</ProjectGuid>
|
<ProjectGuid>{390E2568-57B7-4D17-91E5-C29336368CCF}</ProjectGuid>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RootNamespace>WsClient</RootNamespace>
|
<RootNamespace>Example</RootNamespace>
|
||||||
<AssemblyName>wsclient</AssemblyName>
|
<AssemblyName>example1</AssemblyName>
|
||||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
@ -16,7 +16,7 @@
|
|||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>bin\Debug</OutputPath>
|
<OutputPath>bin\Debug</OutputPath>
|
||||||
<DefineConstants>DEBUG</DefineConstants>
|
<DefineConstants>DEBUG;</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<Externalconsole>true</Externalconsole>
|
<Externalconsole>true</Externalconsole>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>bin\Debug_Ubuntu</OutputPath>
|
<OutputPath>bin\Debug_Ubuntu</OutputPath>
|
||||||
<DefineConstants>DEBUG,NOTIFY</DefineConstants>
|
<DefineConstants>DEBUG;NOTIFY</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<Externalconsole>true</Externalconsole>
|
<Externalconsole>true</Externalconsole>
|
||||||
@ -43,26 +43,31 @@
|
|||||||
<DebugType>none</DebugType>
|
<DebugType>none</DebugType>
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>bin\Release_Ubuntu</OutputPath>
|
<OutputPath>bin\Release_Ubuntu</OutputPath>
|
||||||
<DefineConstants>NOTIFY</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<Externalconsole>true</Externalconsole>
|
<Externalconsole>true</Externalconsole>
|
||||||
|
<DefineConstants>NOTIFY</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="notify-sharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=2df29c54e245917a">
|
<Reference Include="notify-sharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=2df29c54e245917a">
|
||||||
|
<Private>False</Private>
|
||||||
<Package>notify-sharp</Package>
|
<Package>notify-sharp</Package>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=3.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AssemblyInfo.cs" />
|
<Compile Include="AssemblyInfo.cs" />
|
||||||
<Compile Include="wsclient.cs" />
|
<Compile Include="AudioStreamer.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
|
<ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
|
||||||
<Project>{B357BAC7-529E-4D81-A0D2-71041B19C8DE}</Project>
|
<Project>{B357BAC7-529E-4D81-A0D2-71041B19C8DE}</Project>
|
||||||
<Name>websocket-sharp</Name>
|
<Name>websocket-sharp</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
|
||||||
</Project>
|
</Project>
|
35
Example1/Program.cs
Normal file
35
Example1/Program.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Example
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
//using (AudioStreamer streamer = new AudioStreamer("ws://localhost:3000/socket"))
|
||||||
|
using (AudioStreamer streamer = new AudioStreamer("ws://agektmr.node-ninja.com:3000/socket"))
|
||||||
|
{
|
||||||
|
streamer.Connect();
|
||||||
|
|
||||||
|
Thread.Sleep(500);
|
||||||
|
Console.WriteLine("\nType \"exit\" to exit.\n");
|
||||||
|
|
||||||
|
string data;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Thread.Sleep(500);
|
||||||
|
|
||||||
|
Console.Write("> ");
|
||||||
|
data = Console.ReadLine();
|
||||||
|
if (data == "exit")
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
streamer.Write(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
167
README.md
167
README.md
@ -1,8 +1,171 @@
|
|||||||
# websocket-sharp #
|
# websocket-sharp #
|
||||||
|
|
||||||
A C# implementation of a WebSocket protocol client.
|
**websocket-sharp** is a C# implementation of a WebSocket protocol client.
|
||||||
|
|
||||||
## Usage ##
|
## Usage ##
|
||||||
|
|
||||||
Please refer to wsclient/wsclient.cs.
|
### Step 1 ###
|
||||||
|
|
||||||
|
Required namespaces.
|
||||||
|
|
||||||
|
using WebSocketSharp;
|
||||||
|
using WebSocketSharp.Frame;
|
||||||
|
|
||||||
|
In `WebSocketSharp` namespace `WebSocket` class exists, in `WebSocketSharp.Frame` namespace WebSocket data frame resources (e.g. `WsFrame` class) exist.
|
||||||
|
|
||||||
|
### Step 2 ###
|
||||||
|
|
||||||
|
Creating instance of `WebSocket` class.
|
||||||
|
|
||||||
|
using (WebSocket ws = new WebSocket("ws://example.com"))
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
So `WebSocket` class inherits `IDisposable` interface, you can use `using` statement.
|
||||||
|
|
||||||
|
### Step 3 ###
|
||||||
|
|
||||||
|
Setting of `WebSocket` event handlers.
|
||||||
|
|
||||||
|
#### WebSocket.OnOpen event ####
|
||||||
|
|
||||||
|
`WebSocket.OnOpen` event is emitted immediately after WebSocket connection has been established.
|
||||||
|
|
||||||
|
ws.OnOpen += (sender, e) =>
|
||||||
|
{
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
So `e` has come across as `EventArgs.Empty`, there is no operation on `e`.
|
||||||
|
|
||||||
|
#### WebSocket.OnMessage event ####
|
||||||
|
|
||||||
|
`WebSocket.OnMessage` event is emitted each time WebSocket data frame is received.
|
||||||
|
|
||||||
|
ws.OnMessage += (sender, e) =>
|
||||||
|
{
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
So **type** of received WebSocket data frame is stored in `e.Type` (`WebSocketSharp.MessageEventArgs.Type`, its type is `WebSocketSharp.Frame.Opcode`), you check it out and you determine which item you should operate.
|
||||||
|
|
||||||
|
switch (e.Type)
|
||||||
|
{
|
||||||
|
case Opcode.TEXT:
|
||||||
|
...
|
||||||
|
break;
|
||||||
|
case Opcode.BINARY:
|
||||||
|
...
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
If `e.Type` is `Opcode.TEXT`, you operate `e.Data` (`WebSocketSharp.MessageEventArgs.Data`, its type is `string`).
|
||||||
|
|
||||||
|
if `e.Type` is `Opcode.BINARY`, you operate `e.RawData` (`WebSocketSharp.MessageEventArgs.RawData`, its type is `byte[]`).
|
||||||
|
|
||||||
|
#### WebSocket.OnError event ####
|
||||||
|
|
||||||
|
`WebSocket.OnError` event is emitted when some error is occurred.
|
||||||
|
|
||||||
|
ws.OnError += (sender, e) =>
|
||||||
|
{
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
So error message is stored in `e.Data` (`WebSocketSharp.MessageEventArgs.Data`, its type is `string`) , you operate it.
|
||||||
|
|
||||||
|
#### WebSocket.OnClose event ####
|
||||||
|
|
||||||
|
`WebSocket.OnClose` event is emitted when WebSocket connection is closed.
|
||||||
|
|
||||||
|
ws.OnClose += (sender, e) =>
|
||||||
|
{
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
So close status code is stored in `e.Code` (`WebSocketSharp.CloseEventArgs.Code`, its type is `WebSocketSharp.Frame.CloseStatusCode`) and reason of close is stored in `e.Reason` (`WebSocketSharp.CloseEventArgs.Reason`, its type is `string`), you operate them.
|
||||||
|
|
||||||
|
### Step 4 ###
|
||||||
|
|
||||||
|
Connecting to server using WebSocket.
|
||||||
|
|
||||||
|
ws.Connect();
|
||||||
|
|
||||||
|
### Step 5 ###
|
||||||
|
|
||||||
|
Sending data.
|
||||||
|
|
||||||
|
ws.Send(data);
|
||||||
|
|
||||||
|
`WebSocket.Send` method is overloaded.
|
||||||
|
|
||||||
|
data types are `string`, `byte[]` and `FileInfo` class.
|
||||||
|
|
||||||
|
### Step 6 ###
|
||||||
|
|
||||||
|
Closing WebSocket connection.
|
||||||
|
|
||||||
|
ws.Close(code, reason);
|
||||||
|
|
||||||
|
If you want to close WebSocket connection explicitly, you can use `Close` method.
|
||||||
|
|
||||||
|
Type of `code` is `WebSocketSharp.Frame.CloseStatusCode`, type of `reason` is `string`.
|
||||||
|
|
||||||
|
`WebSocket.Close` method is overloaded (In addition `Close()` and `Close(code)` exist).
|
||||||
|
|
||||||
|
## Examples ##
|
||||||
|
|
||||||
|
Examples of using **websocket-sharp**.
|
||||||
|
|
||||||
|
### Example ###
|
||||||
|
|
||||||
|
[Example] connects to the [Echo server] using the WebSocket.
|
||||||
|
|
||||||
|
### Example1 ###
|
||||||
|
|
||||||
|
[Example1] connects to the [Audio Data delivery server] using the WebSocket ([Example1] is only implemented a chat feature, still unfinished).
|
||||||
|
|
||||||
|
[Example1] uses [Json.NET].
|
||||||
|
|
||||||
|
## Supported WebSocket Protocol ##
|
||||||
|
|
||||||
|
**websocket-sharp** supports **[RFC 6455]**.
|
||||||
|
|
||||||
|
- @**[branch: hybi-00]** supports older draft-ietf-hybi-thewebsocketprotocol-00 (**[hybi-00]**).
|
||||||
|
- @**[branch: draft75]** supports even more old draft-hixie-thewebsocketprotocol-75 (**[hixie-75]**).
|
||||||
|
|
||||||
|
## Reference ##
|
||||||
|
|
||||||
|
- **[The WebSocket Protocol]**
|
||||||
|
- **[The WebSocket API]**
|
||||||
|
|
||||||
|
Thx for translating to japanese.
|
||||||
|
|
||||||
|
- **[The WebSocket Protocol 日本語訳]**
|
||||||
|
- **[The WebSocket API 日本語訳]**
|
||||||
|
|
||||||
|
## License ##
|
||||||
|
|
||||||
|
Copyright © 2010 - 2012 sta.blockhead
|
||||||
|
|
||||||
|
Licensed under the **[MIT License]**.
|
||||||
|
|
||||||
|
|
||||||
|
[Audio Data delivery server]: http://agektmr.node-ninja.com:3000/
|
||||||
|
[branch: draft75]: https://github.com/sta/websocket-sharp/tree/draft75
|
||||||
|
[branch: hybi-00]: https://github.com/sta/websocket-sharp/tree/hybi-00
|
||||||
|
[Echo server]: http://www.websocket.org/echo.html
|
||||||
|
[Example]: https://github.com/sta/websocket-sharp/tree/master/Example
|
||||||
|
[Example1]: https://github.com/sta/websocket-sharp/tree/master/Example1
|
||||||
|
[hixie-75]: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
|
||||||
|
[hybi-00]: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
|
||||||
|
[Json.NET]: http://james.newtonking.com/projects/json-net.aspx
|
||||||
|
[MIT License]: http://www.opensource.org/licenses/mit-license.php
|
||||||
|
[RFC 6455]: http://tools.ietf.org/html/rfc6455
|
||||||
|
[The WebSocket API]: http://dev.w3.org/html5/websockets
|
||||||
|
[The WebSocket API 日本語訳]: http://www.hcn.zaq.ne.jp/___/WEB/WebSocket-ja.html
|
||||||
|
[The WebSocket Protocol]: http://tools.ietf.org/html/rfc6455
|
||||||
|
[The WebSocket Protocol 日本語訳]: http://www.hcn.zaq.ne.jp/___/WEB/RFC6455-ja.html
|
||||||
|
@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 10.00
|
|||||||
# Visual Studio 2008
|
# Visual Studio 2008
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp", "websocket-sharp\websocket-sharp.csproj", "{B357BAC7-529E-4D81-A0D2-71041B19C8DE}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp", "websocket-sharp\websocket-sharp.csproj", "{B357BAC7-529E-4D81-A0D2-71041B19C8DE}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wsclient", "wsclient\wsclient.csproj", "{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wsclient1", "wsclient1\wsclient1.csproj", "{B0B609B7-A81C-46B0-A9B8-82E9716D355B}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example1", "Example1\Example1.csproj", "{390E2568-57B7-4D17-91E5-C29336368CCF}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -15,6 +15,14 @@ Global
|
|||||||
Release_Ubuntu|Any CPU = Release_Ubuntu|Any CPU
|
Release_Ubuntu|Any CPU = Release_Ubuntu|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
|
||||||
|
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
|
||||||
|
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release_Ubuntu|Any CPU.ActiveCfg = Release_Ubuntu|Any CPU
|
||||||
|
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
|
||||||
|
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
|
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
|
||||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
|
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
|
||||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
@ -23,14 +31,6 @@ Global
|
|||||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
|
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
|
||||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release|Any CPU.Build.0 = Release|Any CPU
|
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
|
|
||||||
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
|
|
||||||
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Release_Ubuntu|Any CPU.ActiveCfg = Release_Ubuntu|Any CPU
|
|
||||||
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
|
|
||||||
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
|
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
|
||||||
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
|
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
|
||||||
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<Properties>
|
<Properties>
|
||||||
<MonoDevelop.Ide.Workspace ActiveConfiguration="Release" ctype="Workspace" />
|
<MonoDevelop.Ide.Workspace ActiveConfiguration="Release_Ubuntu" />
|
||||||
<MonoDevelop.Ide.Workbench ActiveDocument="websocket-sharp/WebSocket.cs" ctype="Workbench">
|
<MonoDevelop.Ide.Workbench ActiveDocument="websocket-sharp/WebSocket.cs">
|
||||||
<Files>
|
<Files>
|
||||||
<File FileName="websocket-sharp/WebSocket.cs" Line="80" Column="19" />
|
<File FileName="websocket-sharp/WebSocket.cs" Line="217" Column="41" />
|
||||||
</Files>
|
</Files>
|
||||||
</MonoDevelop.Ide.Workbench>
|
</MonoDevelop.Ide.Workbench>
|
||||||
<MonoDevelop.Ide.DebuggingService.Breakpoints>
|
<MonoDevelop.Ide.DebuggingService.Breakpoints>
|
||||||
<BreakpointStore />
|
<BreakpointStore />
|
||||||
</MonoDevelop.Ide.DebuggingService.Breakpoints>
|
</MonoDevelop.Ide.DebuggingService.Breakpoints>
|
||||||
<MonoDevelop.Ide.DebuggingService.PinnedWatches ctype="PinnedWatchStore" />
|
<MonoDevelop.Ide.DebuggingService.PinnedWatches />
|
||||||
</Properties>
|
</Properties>
|
@ -17,7 +17,7 @@ using System.Runtime.CompilerServices;
|
|||||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||||
// and "{Major}.{Minor}.{Build}.*" will update just the 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,
|
// The following attributes are used to specify the signing key for the assembly,
|
||||||
// if desired. See the Mono documentation for more information about signing.
|
// 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
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -28,19 +28,59 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace WebSocketSharp
|
namespace WebSocketSharp
|
||||||
{
|
{
|
||||||
public static class Ext
|
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,
|
this string expected,
|
||||||
string actual,
|
string actual,
|
||||||
Func<string, string, string> func,
|
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);
|
ret = func(expected, actual);
|
||||||
return true;
|
return true;
|
||||||
@ -50,106 +90,226 @@ namespace WebSocketSharp
|
|||||||
return false;
|
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;
|
List<byte> readData = new List<byte>();
|
||||||
dist.Add(b);
|
|
||||||
return b == Convert.ToByte(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint GenerateKey(this Random rand, int space)
|
ulong count = length / (ulong)bufferLength;
|
||||||
|
int remainder = (int)(length % (ulong)bufferLength);
|
||||||
|
|
||||||
|
byte[] buffer1 = new byte[bufferLength];
|
||||||
|
|
||||||
|
count.Times(() =>
|
||||||
{
|
{
|
||||||
uint max = (uint)(0xffffffff / space);
|
stream.Read(buffer1, 0, bufferLength);
|
||||||
|
readData.AddRange(buffer1);
|
||||||
int upper16 = (int)((max & 0xffff0000) >> 16);
|
|
||||||
int lower16 = (int)(max & 0x0000ffff);
|
|
||||||
|
|
||||||
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( () =>
|
|
||||||
{
|
|
||||||
i = rand.Next(secKey.Count + 1);
|
|
||||||
secKey.Insert(i, rand.GeneratePrintableASCIIwithoutSPandNum());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
space.Times( () =>
|
if (remainder > 0)
|
||||||
{
|
{
|
||||||
i = rand.Next(1, secKey.Count);
|
byte[] buffer2 = new byte[remainder];
|
||||||
secKey.Insert(i, ' ');
|
stream.Read(buffer2, 0, remainder);
|
||||||
} );
|
readData.AddRange(buffer2);
|
||||||
|
|
||||||
return new String(secKey.ToArray());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] InitializeWithPrintableASCII(this byte[] bytes, Random rand)
|
return readData.ToArray();
|
||||||
{
|
|
||||||
for (int i = 0; i < bytes.Length; i++)
|
|
||||||
{
|
|
||||||
bytes[i] = (byte)rand.Next(32, 127);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes;
|
public static T[] SubArray<T>(this T[] array, int startIndex, int length)
|
||||||
|
{
|
||||||
|
if (startIndex == 0 && array.Length == length)
|
||||||
|
{
|
||||||
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsValid(this string[] response, byte[] expectedCR, byte[] actualCR, out string message)
|
T[] subArray = new T[length];
|
||||||
{
|
Array.Copy(array, startIndex, subArray, 0, length);
|
||||||
string expectedCRtoHexStr = BitConverter.ToString(expectedCR);
|
return subArray;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message = String.Empty;
|
public static void Times<T>(this T n, Action act)
|
||||||
return true;
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Times(this int n, Action act)
|
ulong m = (ulong)(object)n;
|
||||||
{
|
|
||||||
for (int i = 0; i < n; i++)
|
for (ulong i = 0; i < m; i++)
|
||||||
{
|
{
|
||||||
act();
|
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
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -27,15 +27,18 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using WebSocketSharp.Frame;
|
||||||
|
|
||||||
namespace WebSocketSharp
|
namespace WebSocketSharp.Stream
|
||||||
{
|
{
|
||||||
public interface IWsStream : IDisposable
|
public interface IWsStream : IDisposable
|
||||||
{
|
{
|
||||||
void Close();
|
void Close();
|
||||||
int Read(byte[] buffer, int offset, int size);
|
int Read(byte[] buffer, int offset, int size);
|
||||||
int ReadByte();
|
int ReadByte();
|
||||||
|
WsFrame ReadFrame();
|
||||||
void Write(byte[] buffer, int offset, int count);
|
void Write(byte[] buffer, int offset, int count);
|
||||||
void WriteByte(byte value);
|
void WriteByte(byte value);
|
||||||
|
void WriteFrame(WsFrame frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* The MIT License
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* 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.Security;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using WebSocketSharp.Frame;
|
||||||
|
|
||||||
namespace WebSocketSharp
|
namespace WebSocketSharp.Stream
|
||||||
{
|
{
|
||||||
public class WsStream<T> : IWsStream
|
public class WsStream<TStream> : IWsStream
|
||||||
where T : Stream
|
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) &&
|
if (streamType != typeof(NetworkStream) &&
|
||||||
streamType != typeof(SslStream))
|
streamType != typeof(SslStream))
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Unsupported Stream type: " + streamType.ToString());
|
throw new NotSupportedException("Not supported Stream type: " + streamType.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (innerStream == null)
|
if (innerStream == null)
|
||||||
@ -54,37 +57,56 @@ namespace WebSocketSharp
|
|||||||
throw new ArgumentNullException("innerStream");
|
throw new ArgumentNullException("innerStream");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.innerStream = innerStream;
|
_innerStream = innerStream;
|
||||||
|
_forRead = new object();
|
||||||
|
_forWrite = new object();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
innerStream.Close();
|
_innerStream.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
innerStream.Dispose();
|
_innerStream.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Read(byte[] buffer, int offset, int size)
|
public int Read(byte[] buffer, int offset, int size)
|
||||||
{
|
{
|
||||||
return innerStream.Read(buffer, offset, size);
|
return _innerStream.Read(buffer, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReadByte()
|
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)
|
public void Write(byte[] buffer, int offset, int count)
|
||||||
{
|
{
|
||||||
innerStream.Write(buffer, offset, count);
|
_innerStream.Write(buffer, offset, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteByte(byte value)
|
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
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* 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>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="notify-sharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=2df29c54e245917a">
|
<Reference Include="System.ServiceModel" />
|
||||||
<Package>notify-sharp</Package>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AssemblyInfo.cs" />
|
<Compile Include="AssemblyInfo.cs" />
|
||||||
<Compile Include="Ext.cs" />
|
<Compile Include="Ext.cs" />
|
||||||
<Compile Include="WebSocket.cs" />
|
<Compile Include="WebSocket.cs" />
|
||||||
<Compile Include="WsState.cs" />
|
<Compile Include="WsState.cs" />
|
||||||
<Compile Include="IWsStream.cs" />
|
<Compile Include="MessageEventArgs.cs" />
|
||||||
<Compile Include="WsStream.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>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Stream\" />
|
||||||
|
<Folder Include="Frame\" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,67 +0,0 @@
|
|||||||
#if NOTIFY
|
|
||||||
using Notifications;
|
|
||||||
#endif
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using WebSocketSharp;
|
|
||||||
|
|
||||||
namespace Example
|
|
||||||
{
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
//using (WebSocket ws = new WebSocket("ws://localhost:8000/"))
|
|
||||||
using (WebSocket ws = new WebSocket("ws://localhost:8000/", "chat"))
|
|
||||||
{
|
|
||||||
ws.OnOpen += (o, e) =>
|
|
||||||
{
|
|
||||||
ws.Send("Hi, all!");
|
|
||||||
};
|
|
||||||
|
|
||||||
ws.OnMessage += (o, s) =>
|
|
||||||
{
|
|
||||||
#if NOTIFY
|
|
||||||
Notification nf = new Notification("[WebSocket] Message",
|
|
||||||
s,
|
|
||||||
"notification-message-im");
|
|
||||||
nf.AddHint("append", "allowed");
|
|
||||||
nf.Show();
|
|
||||||
#else
|
|
||||||
Console.WriteLine("[WebSocket] Message: {0}", s);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
ws.OnError += (o, s) =>
|
|
||||||
{
|
|
||||||
Console.WriteLine("[WebSocket] Error : {0}", s);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*ws.OnClose += (o, e) =>
|
|
||||||
{
|
|
||||||
//Do something.
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
ws.Connect();
|
|
||||||
|
|
||||||
Thread.Sleep(500);
|
|
||||||
Console.WriteLine("\nType \"exit\" to exit.\n");
|
|
||||||
|
|
||||||
string data;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
Thread.Sleep(500);
|
|
||||||
|
|
||||||
Console.Write("> ");
|
|
||||||
data = Console.ReadLine();
|
|
||||||
if (data == "exit")
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ws.Send(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,65 +0,0 @@
|
|||||||
#if NOTIFY
|
|
||||||
using Notifications;
|
|
||||||
#endif
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using WebSocketSharp;
|
|
||||||
|
|
||||||
namespace Example
|
|
||||||
{
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
EventHandler onOpen = (o, e) =>
|
|
||||||
{
|
|
||||||
Console.WriteLine("[WebSocket] Opened.");
|
|
||||||
};
|
|
||||||
|
|
||||||
MessageEventHandler onMessage = (o, s) =>
|
|
||||||
{
|
|
||||||
#if NOTIFY
|
|
||||||
Notification nf = new Notification("[WebSocket] Message",
|
|
||||||
s,
|
|
||||||
"notification-message-im");
|
|
||||||
nf.AddHint("append", "allowed");
|
|
||||||
nf.Show();
|
|
||||||
#else
|
|
||||||
Console.WriteLine("[WebSocket] Message: {0}", s);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
MessageEventHandler onError = (o, s) =>
|
|
||||||
{
|
|
||||||
Console.WriteLine("[WebSocket] Error : {0}", s);
|
|
||||||
};
|
|
||||||
|
|
||||||
EventHandler onClose = (o, e) =>
|
|
||||||
{
|
|
||||||
Console.WriteLine("[WebSocket] Closed.");
|
|
||||||
};
|
|
||||||
|
|
||||||
//using (WebSocket ws = new WebSocket("ws://localhost:8000/", onOpen, onMessage, onError, onClose))
|
|
||||||
using (WebSocket ws = new WebSocket("ws://localhost:8000/", "chat", onOpen, onMessage, onError, onClose))
|
|
||||||
{
|
|
||||||
Thread.Sleep(500);
|
|
||||||
Console.WriteLine("\nType \"exit\" to exit.\n");
|
|
||||||
|
|
||||||
string data;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
Thread.Sleep(500);
|
|
||||||
|
|
||||||
Console.Write("> ");
|
|
||||||
data = Console.ReadLine();
|
|
||||||
if (data == "exit")
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ws.Send(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProductVersion>9.0.21022</ProductVersion>
|
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
|
||||||
<ProjectGuid>{B0B609B7-A81C-46B0-A9B8-82E9716D355B}</ProjectGuid>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<RootNamespace>wsclient1</RootNamespace>
|
|
||||||
<AssemblyName>wsclient1</AssemblyName>
|
|
||||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug</OutputPath>
|
|
||||||
<DefineConstants>DEBUG</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<Externalconsole>true</Externalconsole>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>none</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Release</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<Externalconsole>true</Externalconsole>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_Ubuntu|AnyCPU' ">
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug_Ubuntu</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<Externalconsole>true</Externalconsole>
|
|
||||||
<DefineConstants>DEBUG,NOTIFY</DefineConstants>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_Ubuntu|AnyCPU' ">
|
|
||||||
<DebugType>none</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Release_Ubuntu</OutputPath>
|
|
||||||
<DefineConstants>NOTIFY</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<Externalconsole>true</Externalconsole>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="notify-sharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=2df29c54e245917a">
|
|
||||||
<Package>notify-sharp</Package>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="wsclient1.cs" />
|
|
||||||
<Compile Include="AssemblyInfo.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
|
|
||||||
<Project>{B357BAC7-529E-4D81-A0D2-71041B19C8DE}</Project>
|
|
||||||
<Name>websocket-sharp</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
|
||||||
</Project>
|
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user