diff --git a/Example/Example.pidb b/Example/Example.pidb
index bd18f672..e8af61bf 100644
Binary files a/Example/Example.pidb and b/Example/Example.pidb differ
diff --git a/Example/Program.cs b/Example/Program.cs
index 74c26cd7..a67428cd 100644
--- a/Example/Program.cs
+++ b/Example/Program.cs
@@ -73,8 +73,9 @@ namespace Example
ThreadPool.QueueUserWorkItem(notifyMsg);
- using (WebSocket ws = new WebSocket("ws://echo.websocket.org", "echo"))
+ //using (WebSocket ws = new WebSocket("ws://echo.websocket.org", "echo"))
//using (WebSocket ws = new WebSocket("wss://echo.websocket.org", "echo"))
+ using (WebSocket ws = new WebSocket("ws://localhost:4649"))
{
ws.OnOpen += (sender, e) =>
{
@@ -88,7 +89,7 @@ namespace Example
ws.OnError += (sender, e) =>
{
- enNfMessage("[WebSocket] Error", e.Data, "notification-message-im");
+ enNfMessage("[WebSocket] Error", e.Message, "notification-message-im");
};
ws.OnClose += (sender, e) =>
diff --git a/Example/bin/Debug/example.exe b/Example/bin/Debug/example.exe
index 075e308f..3c76bb23 100755
Binary files a/Example/bin/Debug/example.exe and b/Example/bin/Debug/example.exe differ
diff --git a/Example/bin/Debug/example.exe.mdb b/Example/bin/Debug/example.exe.mdb
index 8c77fe71..80eaa185 100644
Binary files a/Example/bin/Debug/example.exe.mdb and b/Example/bin/Debug/example.exe.mdb differ
diff --git a/Example/bin/Debug/websocket-sharp.dll b/Example/bin/Debug/websocket-sharp.dll
index 6fd6c13b..a3c86269 100755
Binary files a/Example/bin/Debug/websocket-sharp.dll and b/Example/bin/Debug/websocket-sharp.dll differ
diff --git a/Example/bin/Debug/websocket-sharp.dll.mdb b/Example/bin/Debug/websocket-sharp.dll.mdb
index 695ceb15..83a06f05 100644
Binary files a/Example/bin/Debug/websocket-sharp.dll.mdb and b/Example/bin/Debug/websocket-sharp.dll.mdb differ
diff --git a/Example/bin/Debug_Ubuntu/example.exe b/Example/bin/Debug_Ubuntu/example.exe
index 4328cab3..31b552f0 100755
Binary files a/Example/bin/Debug_Ubuntu/example.exe and b/Example/bin/Debug_Ubuntu/example.exe differ
diff --git a/Example/bin/Debug_Ubuntu/example.exe.mdb b/Example/bin/Debug_Ubuntu/example.exe.mdb
index 7203875e..8fb49fe8 100644
Binary files a/Example/bin/Debug_Ubuntu/example.exe.mdb and b/Example/bin/Debug_Ubuntu/example.exe.mdb differ
diff --git a/Example/bin/Debug_Ubuntu/websocket-sharp.dll b/Example/bin/Debug_Ubuntu/websocket-sharp.dll
index 4b8d81cb..e318f2b9 100755
Binary files a/Example/bin/Debug_Ubuntu/websocket-sharp.dll and b/Example/bin/Debug_Ubuntu/websocket-sharp.dll differ
diff --git a/Example/bin/Debug_Ubuntu/websocket-sharp.dll.mdb b/Example/bin/Debug_Ubuntu/websocket-sharp.dll.mdb
index f26ae797..8e296ffa 100644
Binary files a/Example/bin/Debug_Ubuntu/websocket-sharp.dll.mdb and b/Example/bin/Debug_Ubuntu/websocket-sharp.dll.mdb differ
diff --git a/Example/bin/Release/example.exe b/Example/bin/Release/example.exe
index 05a56e8d..2612eac0 100755
Binary files a/Example/bin/Release/example.exe and b/Example/bin/Release/example.exe differ
diff --git a/Example/bin/Release/websocket-sharp.dll b/Example/bin/Release/websocket-sharp.dll
index 0096e74e..c41cbdc8 100755
Binary files a/Example/bin/Release/websocket-sharp.dll and b/Example/bin/Release/websocket-sharp.dll differ
diff --git a/Example/bin/Release_Ubuntu/example.exe b/Example/bin/Release_Ubuntu/example.exe
index 4bfd5bea..cdbf41c8 100755
Binary files a/Example/bin/Release_Ubuntu/example.exe and b/Example/bin/Release_Ubuntu/example.exe differ
diff --git a/Example/bin/Release_Ubuntu/websocket-sharp.dll b/Example/bin/Release_Ubuntu/websocket-sharp.dll
index eed7a63f..9541e270 100755
Binary files a/Example/bin/Release_Ubuntu/websocket-sharp.dll and b/Example/bin/Release_Ubuntu/websocket-sharp.dll differ
diff --git a/Example1/AudioStreamer.cs b/Example1/AudioStreamer.cs
index bbfbf691..3a0a6cc7 100644
--- a/Example1/AudioStreamer.cs
+++ b/Example1/AudioStreamer.cs
@@ -108,7 +108,7 @@ namespace Example
_ws.OnError += (sender, e) =>
{
- enNfMessage("[AudioStreamer] error", "WS: Error: " + e.Data, "notification-message-im");
+ enNfMessage("[AudioStreamer] error", "WS: Error: " + e.Message, "notification-message-im");
};
_ws.OnClose += (sender, e) =>
diff --git a/Example1/Example1.pidb b/Example1/Example1.pidb
index b5082acb..02ab1ea4 100644
Binary files a/Example1/Example1.pidb and b/Example1/Example1.pidb differ
diff --git a/Example1/bin/Debug/example1.exe b/Example1/bin/Debug/example1.exe
index f37ceb2b..2cfd924f 100755
Binary files a/Example1/bin/Debug/example1.exe and b/Example1/bin/Debug/example1.exe differ
diff --git a/Example1/bin/Debug/example1.exe.mdb b/Example1/bin/Debug/example1.exe.mdb
index 9f23f439..87d20e00 100644
Binary files a/Example1/bin/Debug/example1.exe.mdb and b/Example1/bin/Debug/example1.exe.mdb differ
diff --git a/Example1/bin/Debug/websocket-sharp.dll b/Example1/bin/Debug/websocket-sharp.dll
index 6fd6c13b..a3c86269 100755
Binary files a/Example1/bin/Debug/websocket-sharp.dll and b/Example1/bin/Debug/websocket-sharp.dll differ
diff --git a/Example1/bin/Debug/websocket-sharp.dll.mdb b/Example1/bin/Debug/websocket-sharp.dll.mdb
index 695ceb15..83a06f05 100644
Binary files a/Example1/bin/Debug/websocket-sharp.dll.mdb and b/Example1/bin/Debug/websocket-sharp.dll.mdb differ
diff --git a/Example1/bin/Debug_Ubuntu/example1.exe b/Example1/bin/Debug_Ubuntu/example1.exe
index 3c365f20..747660a6 100755
Binary files a/Example1/bin/Debug_Ubuntu/example1.exe and b/Example1/bin/Debug_Ubuntu/example1.exe differ
diff --git a/Example1/bin/Debug_Ubuntu/example1.exe.mdb b/Example1/bin/Debug_Ubuntu/example1.exe.mdb
index 45364548..55757034 100644
Binary files a/Example1/bin/Debug_Ubuntu/example1.exe.mdb and b/Example1/bin/Debug_Ubuntu/example1.exe.mdb differ
diff --git a/Example1/bin/Debug_Ubuntu/websocket-sharp.dll b/Example1/bin/Debug_Ubuntu/websocket-sharp.dll
index 4b8d81cb..e318f2b9 100755
Binary files a/Example1/bin/Debug_Ubuntu/websocket-sharp.dll and b/Example1/bin/Debug_Ubuntu/websocket-sharp.dll differ
diff --git a/Example1/bin/Debug_Ubuntu/websocket-sharp.dll.mdb b/Example1/bin/Debug_Ubuntu/websocket-sharp.dll.mdb
index f26ae797..8e296ffa 100644
Binary files a/Example1/bin/Debug_Ubuntu/websocket-sharp.dll.mdb and b/Example1/bin/Debug_Ubuntu/websocket-sharp.dll.mdb differ
diff --git a/Example1/bin/Release/example1.exe b/Example1/bin/Release/example1.exe
index 137862de..cefdb422 100755
Binary files a/Example1/bin/Release/example1.exe and b/Example1/bin/Release/example1.exe differ
diff --git a/Example1/bin/Release/websocket-sharp.dll b/Example1/bin/Release/websocket-sharp.dll
index 0096e74e..c41cbdc8 100755
Binary files a/Example1/bin/Release/websocket-sharp.dll and b/Example1/bin/Release/websocket-sharp.dll differ
diff --git a/Example1/bin/Release_Ubuntu/example1.exe b/Example1/bin/Release_Ubuntu/example1.exe
index 0d09b87c..70d334fa 100755
Binary files a/Example1/bin/Release_Ubuntu/example1.exe and b/Example1/bin/Release_Ubuntu/example1.exe differ
diff --git a/Example1/bin/Release_Ubuntu/websocket-sharp.dll b/Example1/bin/Release_Ubuntu/websocket-sharp.dll
index eed7a63f..9541e270 100755
Binary files a/Example1/bin/Release_Ubuntu/websocket-sharp.dll and b/Example1/bin/Release_Ubuntu/websocket-sharp.dll differ
diff --git a/Example2/App.config b/Example2/App.config
new file mode 100644
index 00000000..84bc00fa
--- /dev/null
+++ b/Example2/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/Example2/AssemblyInfo.cs b/Example2/AssemblyInfo.cs
new file mode 100644
index 00000000..6335efbf
--- /dev/null
+++ b/Example2/AssemblyInfo.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("Example2")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("sta")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/Example2/Example2.csproj b/Example2/Example2.csproj
new file mode 100644
index 00000000..aee5e9bf
--- /dev/null
+++ b/Example2/Example2.csproj
@@ -0,0 +1,67 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.21022
+ 2.0
+ {B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}
+ Exe
+ Example2
+ example2
+ v3.5
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ true
+
+
+ none
+ false
+ bin\Release
+ prompt
+ 4
+ true
+
+
+ true
+ full
+ false
+ bin\Debug_Ubuntu
+ DEBUG;
+ prompt
+ 4
+ true
+
+
+ none
+ false
+ bin\Release_Ubuntu
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+
+
+
+
+ {B357BAC7-529E-4D81-A0D2-71041B19C8DE}
+ websocket-sharp
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Example2/Example2.pidb b/Example2/Example2.pidb
new file mode 100644
index 00000000..9dd560e7
Binary files /dev/null and b/Example2/Example2.pidb differ
diff --git a/Example2/Program.cs b/Example2/Program.cs
new file mode 100644
index 00000000..9a59dcc4
--- /dev/null
+++ b/Example2/Program.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Threading;
+using WebSocketSharp;
+
+namespace Example
+{
+ public class Program
+ {
+ public static void Main (string[] args)
+ {
+ //WebSocketServer wssv = new WebSocketServer("ws://localhost");
+ WebSocketServer wssv = new WebSocketServer("ws://localhost:4649");
+
+ wssv.OnConnection += (sender, e) =>
+ {
+ WebSocket ws = e.Socket;
+ ws.OnMessage += (sender_, e_) =>
+ {
+ // Echo
+ ws.Send(e_.Data);
+ // Chat
+ //wssv.Send(e_.Data);
+ };
+ };
+
+ wssv.Start();
+ Console.WriteLine(
+ "WebSocket Server ({0}) listening on address: {1} port: {2}\n", wssv.Url, wssv.Address, wssv.Port);
+
+ Console.WriteLine("Press any key to stop server...");
+ Console.ReadLine();
+
+ wssv.Stop();
+ }
+ }
+}
diff --git a/Example2/bin/Debug/example2.exe b/Example2/bin/Debug/example2.exe
new file mode 100755
index 00000000..ff910fb1
Binary files /dev/null and b/Example2/bin/Debug/example2.exe differ
diff --git a/Example2/bin/Debug/example2.exe.config b/Example2/bin/Debug/example2.exe.config
new file mode 100644
index 00000000..84bc00fa
--- /dev/null
+++ b/Example2/bin/Debug/example2.exe.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/Example2/bin/Debug/example2.exe.mdb b/Example2/bin/Debug/example2.exe.mdb
new file mode 100644
index 00000000..657a1457
Binary files /dev/null and b/Example2/bin/Debug/example2.exe.mdb differ
diff --git a/Example2/bin/Debug/websocket-sharp.dll b/Example2/bin/Debug/websocket-sharp.dll
new file mode 100755
index 00000000..a3c86269
Binary files /dev/null and b/Example2/bin/Debug/websocket-sharp.dll differ
diff --git a/Example2/bin/Debug/websocket-sharp.dll.mdb b/Example2/bin/Debug/websocket-sharp.dll.mdb
new file mode 100644
index 00000000..83a06f05
Binary files /dev/null and b/Example2/bin/Debug/websocket-sharp.dll.mdb differ
diff --git a/Example2/bin/Debug_Ubuntu/example2.exe b/Example2/bin/Debug_Ubuntu/example2.exe
new file mode 100755
index 00000000..53a99ad6
Binary files /dev/null and b/Example2/bin/Debug_Ubuntu/example2.exe differ
diff --git a/Example2/bin/Debug_Ubuntu/example2.exe.config b/Example2/bin/Debug_Ubuntu/example2.exe.config
new file mode 100644
index 00000000..84bc00fa
--- /dev/null
+++ b/Example2/bin/Debug_Ubuntu/example2.exe.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/Example2/bin/Debug_Ubuntu/example2.exe.mdb b/Example2/bin/Debug_Ubuntu/example2.exe.mdb
new file mode 100644
index 00000000..f535430b
Binary files /dev/null and b/Example2/bin/Debug_Ubuntu/example2.exe.mdb differ
diff --git a/Example2/bin/Debug_Ubuntu/websocket-sharp.dll b/Example2/bin/Debug_Ubuntu/websocket-sharp.dll
new file mode 100755
index 00000000..e318f2b9
Binary files /dev/null and b/Example2/bin/Debug_Ubuntu/websocket-sharp.dll differ
diff --git a/Example2/bin/Debug_Ubuntu/websocket-sharp.dll.mdb b/Example2/bin/Debug_Ubuntu/websocket-sharp.dll.mdb
new file mode 100644
index 00000000..8e296ffa
Binary files /dev/null and b/Example2/bin/Debug_Ubuntu/websocket-sharp.dll.mdb differ
diff --git a/Example2/bin/Release/example2.exe b/Example2/bin/Release/example2.exe
new file mode 100755
index 00000000..9c802bce
Binary files /dev/null and b/Example2/bin/Release/example2.exe differ
diff --git a/Example2/bin/Release/example2.exe.config b/Example2/bin/Release/example2.exe.config
new file mode 100644
index 00000000..84bc00fa
--- /dev/null
+++ b/Example2/bin/Release/example2.exe.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/Example2/bin/Release/websocket-sharp.dll b/Example2/bin/Release/websocket-sharp.dll
new file mode 100755
index 00000000..c41cbdc8
Binary files /dev/null and b/Example2/bin/Release/websocket-sharp.dll differ
diff --git a/Example2/bin/Release_Ubuntu/example2.exe b/Example2/bin/Release_Ubuntu/example2.exe
new file mode 100755
index 00000000..febb55f2
Binary files /dev/null and b/Example2/bin/Release_Ubuntu/example2.exe differ
diff --git a/Example2/bin/Release_Ubuntu/example2.exe.config b/Example2/bin/Release_Ubuntu/example2.exe.config
new file mode 100644
index 00000000..84bc00fa
--- /dev/null
+++ b/Example2/bin/Release_Ubuntu/example2.exe.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/Example2/bin/Release_Ubuntu/websocket-sharp.dll b/Example2/bin/Release_Ubuntu/websocket-sharp.dll
new file mode 100755
index 00000000..9541e270
Binary files /dev/null and b/Example2/bin/Release_Ubuntu/websocket-sharp.dll differ
diff --git a/README.md b/README.md
index 01fc1e6d..eebd208a 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,12 @@
# websocket-sharp #
-**websocket-sharp** is a C# implementation of a WebSocket protocol client.
+**websocket-sharp** is a C# implementation of a WebSocket protocol client & server.
## Usage ##
-### Step 1 ###
+### WebSocket Client ###
+
+#### Step 1 ####
Required namespaces.
@@ -13,7 +15,7 @@ Required namespaces.
In `WebSocketSharp` namespace `WebSocket` class exists, in `WebSocketSharp.Frame` namespace WebSocket data frame resources (e.g. `WsFrame` class) exist.
-### Step 2 ###
+#### Step 2 ####
Creating instance of `WebSocket` class.
@@ -22,13 +24,13 @@ Creating instance of `WebSocket` class.
...
}
-So `WebSocket` class inherits `IDisposable` interface, you can use `using` statement.
+`WebSocket` class inherits `IDisposable` interface, so you can use `using` statement.
-### Step 3 ###
+#### Step 3 ####
Setting `WebSocket` event handlers.
-#### WebSocket.OnOpen event ####
+##### WebSocket.OnOpen event #####
`WebSocket.OnOpen` event is emitted immediately after WebSocket connection has been established.
@@ -37,9 +39,9 @@ Setting `WebSocket` event handlers.
...
};
-So `e` has come across as `EventArgs.Empty`, there is no operation on `e`.
+`e` has come across as `EventArgs.Empty`, so there is no operation on `e`.
-#### WebSocket.OnMessage event ####
+##### WebSocket.OnMessage event #####
`WebSocket.OnMessage` event is emitted each time WebSocket data frame is received.
@@ -48,7 +50,7 @@ So `e` has come across as `EventArgs.Empty`, there is no operation on `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.
+**type** of received WebSocket data frame is stored in `e.Type` (`WebSocketSharp.MessageEventArgs.Type`, its type is `WebSocketSharp.Frame.Opcode`), so you check it out and you determine which item you should operate.
switch (e.Type)
{
@@ -66,7 +68,7 @@ If `e.Type` is `Opcode.TEXT`, you operate `e.Data` (`WebSocketSharp.MessageEvent
If `e.Type` is `Opcode.BINARY`, you operate `e.RawData` (`WebSocketSharp.MessageEventArgs.RawData`, its type is `byte[]`).
-#### WebSocket.OnError event ####
+##### WebSocket.OnError event #####
`WebSocket.OnError` event is emitted when some error is occurred.
@@ -75,9 +77,9 @@ If `e.Type` is `Opcode.BINARY`, you operate `e.RawData` (`WebSocketSharp.Message
...
};
-So error message is stored in `e.Data` (`WebSocketSharp.MessageEventArgs.Data`, its type is `string`), you operate it.
+Error message is stored in `e.Message` (`WebSocketSharp.ErrorEventArgs.Message`, its type is `string`), so you operate it.
-#### WebSocket.OnClose event ####
+##### WebSocket.OnClose event #####
`WebSocket.OnClose` event is emitted when WebSocket connection is closed.
@@ -86,15 +88,15 @@ So error message is stored in `e.Data` (`WebSocketSharp.MessageEventArgs.Data`,
...
};
-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.
+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`), so you operate them.
-### Step 4 ###
+#### Step 4 ####
Connecting to server using WebSocket.
ws.Connect();
-### Step 5 ###
+#### Step 5 ####
Sending data.
@@ -104,7 +106,7 @@ Sending data.
`data` types are `string`, `byte[]` and `FileInfo` class.
-### Step 6 ###
+#### Step 6 ####
Closing WebSocket connection.
@@ -116,6 +118,96 @@ Type of `code` is `WebSocketSharp.Frame.CloseStatusCode`, type of `reason` is `s
`WebSocket.Close` method is overloaded (In addition `Close()` and `Close(code)` exist).
+### WebSocket Server ###
+
+#### Step 1 ####
+
+Required namespaces.
+
+ using WebSocketSharp;
+ using WebSocketSharp.Frame;
+
+Same as **WebSocket Client**.
+
+#### Step 2 ####
+
+Creating instance of `WebSocketServer` class.
+
+ WebSocketServer wssv = new WebSocketServer("ws://example.com:4649");
+
+If you set WebSocket url without port number, `WebSocketServer` set 80 or 443 to port number automatically.
+So it is necessary to run with root permission.
+
+ $ sudo mono example2.exe
+
+#### Step 3 ####
+
+Setting WebSocketServer event handlers.
+
+##### WebSocketServer.OnConnection event #####
+
+`WebSocketServer.OnConnection` event is emitted each time client makes a connection request.
+
+ wssv.OnConnection += (sender, e) =>
+ {
+ ...
+ };
+
+`WebSocket` to communicate with client is stored in `e.Socket` (`WebSocketSharp.ConnectionEventArgs.Socket`, its type is `WebSocketSharp.WebSocket`), so you operate it.
+
+ WebSocket ws = e.Socket;
+ ws.OnMessage += (sender_, e_) =>
+ {
+ ...
+ };
+
+Same settings of `WebSocket` event handlers as **WebSocket Client**.
+
+This WebSocket is server-side, so data is sent from server to client.
+
+If you want to function as echo server that returns a data to client as it is received,
+
+ // Echo
+ ws.Send(e_.Data);
+
+If you want to function as chat server that returns a data to all clients,
+
+ // Chat
+ wssv.Send(e_.Data);
+
+##### WebSocketServer.OnError event #####
+
+`WebSocketServer.OnError` event is emitted when some error is occurred.
+
+ wssv.OnError += (sender, e) =>
+ {
+ ...
+ };
+
+Error message is stored in `e.Message` (`WebSocketSharp.ErrorEventArgs.Message`, its type is `string`), so you operate it.
+
+#### Step 4 ####
+
+Starting server.
+
+ wssv.Start();
+
+#### Step 5 ####
+
+Sending data to all clients.
+
+ wssv.Send(data);
+
+`WebSocketServer.Send` method is overloaded.
+
+`data` types are `string` and `byte[]`.
+
+#### Step 6 ####
+
+Stopping server.
+
+ wssv.Stop();
+
## Examples ##
Examples of using **websocket-sharp**.
@@ -130,6 +222,10 @@ Examples of using **websocket-sharp**.
[Example1] uses [Json.NET].
+### Example2 ###
+
+[Example2] starts WebSocket server.
+
## Supported WebSocket Protocol ##
**websocket-sharp** supports **[RFC 6455]**.
@@ -160,6 +256,7 @@ Licensed under the **[MIT License]**.
[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
+[Example2]: https://github.com/sta/websocket-sharp/tree/master/Example2
[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
diff --git a/websocket-sharp.sln b/websocket-sharp.sln
index a7c94077..ef2da1cf 100644
--- a/websocket-sharp.sln
+++ b/websocket-sharp.sln
@@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example1", "Example1\Example1.csproj", "{390E2568-57B7-4D17-91E5-C29336368CCF}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example2", "Example2\Example2.csproj", "{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -39,6 +41,14 @@ Global
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
+ {B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
+ {B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Release_Ubuntu|Any CPU.ActiveCfg = Release_Ubuntu|Any CPU
+ {B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
+ {B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = websocket-sharp\websocket-sharp.csproj
diff --git a/websocket-sharp.userprefs b/websocket-sharp.userprefs
index cb5cca4b..8d2074ef 100644
--- a/websocket-sharp.userprefs
+++ b/websocket-sharp.userprefs
@@ -2,7 +2,7 @@
-
+
diff --git a/websocket-sharp/ConnectionEventArgs.cs b/websocket-sharp/ConnectionEventArgs.cs
new file mode 100644
index 00000000..9b2c3615
--- /dev/null
+++ b/websocket-sharp/ConnectionEventArgs.cs
@@ -0,0 +1,42 @@
+#region MIT License
+/**
+ * ConnectionEventArgs.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 class ConnectionEventArgs : EventArgs
+ {
+ public WebSocket Socket { get; private set; }
+
+ public ConnectionEventArgs(WebSocket webSocket)
+ {
+ Socket = webSocket;
+ }
+ }
+}
diff --git a/websocket-sharp/ErrorEventArgs.cs b/websocket-sharp/ErrorEventArgs.cs
new file mode 100644
index 00000000..0f7c8d5c
--- /dev/null
+++ b/websocket-sharp/ErrorEventArgs.cs
@@ -0,0 +1,42 @@
+#region MIT License
+/**
+ * ErrorEventArgs.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 class ErrorEventArgs : EventArgs
+ {
+ public string Message { get; private set; }
+
+ public ErrorEventArgs(string message)
+ {
+ Message = message;
+ }
+ }
+}
diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs
index 8f47db3f..8bc6157a 100644
--- a/websocket-sharp/WebSocket.cs
+++ b/websocket-sharp/WebSocket.cs
@@ -32,6 +32,7 @@
using System;
using System.Collections.Generic;
+using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -60,12 +61,14 @@ namespace WebSocketSharp
#region Private Fields
+ private AutoResetEvent _autoEvent;
private string _base64key;
private string _binaryType;
private string _extensions;
private Object _forClose;
private Object _forSend;
private int _fragmentLen;
+ private bool _isClient;
private Thread _msgThread;
private NetworkStream _netStream;
private string _protocol;
@@ -125,7 +128,7 @@ namespace WebSocketSharp
switch (value)
{
case WsState.OPEN:
- messageThreadStart();
+ startMessageThread();
OnOpen.Emit(this, EventArgs.Empty);
break;
case WsState.CLOSING:
@@ -153,7 +156,7 @@ namespace WebSocketSharp
public event EventHandler OnOpen;
public event EventHandler OnMessage;
- public event EventHandler OnError;
+ public event EventHandler OnError;
public event EventHandler OnClose;
#endregion
@@ -174,27 +177,43 @@ namespace WebSocketSharp
#endregion
+ #region Internal Constructors
+
+ internal WebSocket(string url, TcpClient tcpClient)
+ : this()
+ {
+ _uri = new Uri(url);
+ if (!isValidScheme(_uri))
+ {
+ throw new ArgumentException("Unsupported WebSocket URI scheme: " + _uri.Scheme);
+ }
+
+ _tcpClient = tcpClient;
+ _isClient = false;
+ }
+
+ #endregion
+
#region Public Constructors
public WebSocket(string url, params string[] protocols)
- : this()
+ : this()
{
- _uri = new Uri(url);
- string scheme = _uri.Scheme;
-
- if (scheme != "ws" && scheme != "wss")
+ _uri = new Uri(url);
+ if (!isValidScheme(_uri))
{
- throw new ArgumentException("Unsupported WebSocket URI scheme: " + scheme);
+ throw new ArgumentException("Unsupported WebSocket URI scheme: " + _uri.Scheme);
}
- _protocols = protocols.ToString(", ");
+ _protocols = protocols.ToString(", ");
+ _isClient = true;
}
public WebSocket(
string url,
EventHandler onOpen,
EventHandler onMessage,
- EventHandler onError,
+ EventHandler onError,
EventHandler onClose,
params string[] protocols)
: this(url, protocols)
@@ -211,10 +230,37 @@ namespace WebSocketSharp
#region Private Methods
+ private void acceptHandshake()
+ {
+ string msg, response;
+ string[] request;
+
+ request = receiveOpeningHandshake();
+ #if DEBUG
+ Console.WriteLine("\nWS: Info@acceptHandshake: Opening handshake from client:\n");
+ foreach (string s in request)
+ {
+ Console.WriteLine("{0}", s);
+ }
+ #endif
+ if (!isValidRequest(request, out msg))
+ {
+ throw new InvalidOperationException(msg);
+ }
+
+ response = createResponseHandshake();
+ #if DEBUG
+ Console.WriteLine("\nWS: Info@acceptHandshake: Opening handshake from server:\n{0}", response);
+ #endif
+ sendResponseHandshake(response);
+
+ ReadyState = WsState.OPEN;
+ }
+
private void close(PayloadData data)
{
#if DEBUG
- Console.WriteLine("WS: Info@close: Current thread IsBackground?: {0}", Thread.CurrentThread.IsBackground);
+ Console.WriteLine("\nWS: Info@close: Current thread IsBackground?: {0}", Thread.CurrentThread.IsBackground);
#endif
lock(_forClose)
{
@@ -291,13 +337,20 @@ namespace WebSocketSharp
if (!Thread.CurrentThread.IsBackground)
{
- _msgThread.Join(5000);
+ if (_isClient)
+ {
+ _msgThread.Join(5000);
+ }
+ else
+ {
+ _autoEvent.WaitOne();
+ }
}
ReadyState = WsState.CLOSED;
}
- private void createConnection()
+ private void createClientStream()
{
string scheme = _uri.Scheme;
string host = _uri.DnsSafeHost;
@@ -400,6 +453,45 @@ namespace WebSocketSharp
crlf;
}
+ private string createResponseHandshake()
+ {
+ string crlf = "\r\n";
+
+ string resStatus = "HTTP/1.1 101 Switching Protocols" + crlf;
+ string resUpgrade = "Upgrade: websocket" + crlf;
+ string resConnection = "Connection: Upgrade" + crlf;
+ string secWsAccept = String.Format("Sec-WebSocket-Accept: {0}{1}", createExpectedKey(), crlf);
+ //string secWsProtocol = "Sec-WebSocket-Protocol: chat" + crlf;
+ string secWsVersion = String.Format("Sec-WebSocket-Version: {0}{1}", _version, crlf);
+
+ return resStatus +
+ resUpgrade +
+ resConnection +
+ secWsAccept +
+ //secWsProtocol +
+ secWsVersion +
+ crlf;
+ }
+
+ private void createServerStream()
+ {
+ _netStream = _tcpClient.GetStream();
+
+ if (_uri.Scheme == "wss")
+ {
+ _sslStream = new SslStream(_netStream);
+
+ string certPath = ConfigurationManager.AppSettings["ServerCertPath"];
+ _sslStream.AuthenticateAsServer(new X509Certificate(certPath));
+
+ _wsStream = new WsStream(_sslStream);
+ }
+ else
+ {
+ _wsStream = new WsStream(_netStream);
+ }
+ }
+
private void doHandshake()
{
string msg, request;
@@ -407,11 +499,11 @@ namespace WebSocketSharp
request = createOpeningHandshake();
#if DEBUG
- Console.WriteLine("WS: Info@doHandshake: Opening handshake from client:\n{0}", request);
+ Console.WriteLine("\nWS: Info@doHandshake: Opening handshake from client:\n{0}", request);
#endif
response = sendOpeningHandshake(request);
#if DEBUG
- Console.WriteLine("WS: Info@doHandshake: Opening handshake from server:");
+ Console.WriteLine("\nWS: Info@doHandshake: Opening handshake from server:\n");
foreach (string s in response)
{
Console.WriteLine("{0}", s);
@@ -432,18 +524,123 @@ namespace WebSocketSharp
var caller = callerFrame.GetMethod();
Console.WriteLine("WS: Error@{0}: {1}", caller.Name, message);
#endif
- OnError.Emit(this, new MessageEventArgs(message));
+ OnError.Emit(this, new ErrorEventArgs(message));
+ }
+
+ private bool isValidRequest(string[] request, out string message)
+ {
+ string reqConnection, reqHost, reqUpgrade, secWsVersion;
+ string[] reqRequest;
+
+ List extensionList = new List();
+
+ Func> func = s =>
+ {
+ return (e, a) =>
+ {
+ return String.Format("Invalid request {0} value: {1}(expected: {2})", s, a, e);
+ };
+ };
+
+ string expectedHost = _uri.DnsSafeHost;
+ int port = ((IPEndPoint)_tcpClient.Client.LocalEndPoint).Port;
+ if (port != 80)
+ {
+ expectedHost += ":" + port;
+ }
+
+ reqRequest = request[0].Split(' ');
+ if ("GET".NotEqualsDo(reqRequest[0], func("HTTP Method"), out message, false))
+ {
+ return false;
+ }
+ if ("HTTP/1.1".NotEqualsDo(reqRequest[2], func("HTTP Version"), out message, false))
+ {
+ return false;
+ }
+
+ for (int i = 1; i < request.Length; i++)
+ {
+ if (request[i].Contains("Connection:"))
+ {
+ reqConnection = request[i].GetHeaderValue(":");
+ if ("Upgrade".NotEqualsDo(reqConnection, func("Connection"), out message, true))
+ {
+ return false;
+ }
+ }
+ else if (request[i].Contains("Host:"))
+ {
+ reqHost = request[i].GetHeaderValue(":");
+ if (expectedHost.NotEqualsDo(reqHost, func("Host"), out message, true))
+ {
+ return false;
+ }
+ }
+ else if (request[i].Contains("Origin:"))
+ {
+ continue;
+ }
+ else if (request[i].Contains("Upgrade:"))
+ {
+ reqUpgrade = request[i].GetHeaderValue(":");
+ if ("websocket".NotEqualsDo(reqUpgrade, func("Upgrade"), out message, true))
+ {
+ return false;
+ }
+ }
+ else if (request[i].Contains("Sec-WebSocket-Extensions:"))
+ {
+ extensionList.Add(request[i].GetHeaderValue(":"));
+ }
+ else if (request[i].Contains("Sec-WebSocket-Key:"))
+ {
+ _base64key = request[i].GetHeaderValue(":");
+ }
+ else if (request[i].Contains("Sec-WebSocket-Protocol:"))
+ {
+ _protocols = request[i].GetHeaderValue(":");
+ #if DEBUG
+ Console.WriteLine("WS: Info@isValidRequest: Sub protocol: {0}", _protocols);
+ #endif
+ }
+ else if (request[i].Contains("Sec-WebSocket-Version:"))
+ {
+ secWsVersion = request[i].GetHeaderValue(":");
+ if (_version.NotEqualsDo(secWsVersion, func("Sec-WebSocket-Version"), out message, true))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ Console.WriteLine("WS: Info@isValidRequest: Unsupported request header line: {0}", request[i]);
+ }
+ }
+
+ if (String.IsNullOrEmpty(_base64key))
+ {
+ message = "Sec-WebSocket-Key header field does not exist or the value isn't set.";
+ return false;
+ }
+ #if DEBUG
+ foreach (string s in extensionList)
+ {
+ Console.WriteLine("WS: Info@isValidRequest: Extensions: {0}", s);
+ }
+ #endif
+ message = String.Empty;
+ return true;
}
private bool isValidResponse(string[] response, out string message)
{
- Func> func;
- string resUpgrade, resConnection;
- string secWsAccept, secWsVersion;
+ string resUpgrade, resConnection, secWsAccept, secWsVersion;
string[] resStatus;
+
List extensionList = new List();
- func = s =>
+ Func> func = s =>
{
return (e, a) =>
{
@@ -501,9 +698,10 @@ namespace WebSocketSharp
else if (response[i].Contains("Sec-WebSocket-Version:"))
{
secWsVersion = response[i].GetHeaderValue(":");
- #if DEBUG
- Console.WriteLine("WS: Info@isValidResponse: Version: {0}", secWsVersion);
- #endif
+ if (_version.NotEqualsDo(secWsVersion, func("Sec-WebSocket-Version"), out message, true))
+ {
+ return false;
+ }
}
else
{
@@ -520,38 +718,81 @@ namespace WebSocketSharp
return true;
}
+ private bool isValidScheme(Uri uri)
+ {
+ string scheme = uri.Scheme;
+ if (scheme == "ws" || scheme == "wss")
+ {
+ return true;
+ }
+
+ return false;
+ }
+
private void message()
{
- #if DEBUG
- Console.WriteLine("WS: Info@message: Current thread IsBackground?: {0}", Thread.CurrentThread.IsBackground);
- #endif
- MessageEventArgs eventArgs;
- while (_readyState == WsState.OPEN)
+ try
{
- try
- {
- eventArgs = receive();
+ MessageEventArgs eventArgs = receive();
- if (eventArgs != null)
- {
- OnMessage.Emit(this, eventArgs);
- }
- }
- catch (WsReceivedTooBigMessageException ex)
+ if (eventArgs != null)
{
- close(CloseStatusCode.TOO_BIG, ex.Message);
+ OnMessage.Emit(this, eventArgs);
}
}
+ catch (WsReceivedTooBigMessageException ex)
+ {
+ close(CloseStatusCode.TOO_BIG, ex.Message);
+ }
+ }
+
+ private void messageLoop()
+ {
+ #if DEBUG
+ Console.WriteLine("\nWS: Info@messageLoop: Current thread IsBackground?: {0}", Thread.CurrentThread.IsBackground);
+ #endif
+ while (_readyState == WsState.OPEN)
+ {
+ message();
+ }
#if DEBUG
- Console.WriteLine("WS: Info@message: Exit message method.");
+ Console.WriteLine("WS: Info@messageLoop: Exit messageLoop method.");
#endif
}
- private void messageThreadStart()
+ private void startMessageThread()
{
- _msgThread = new Thread(new ThreadStart(message));
- _msgThread.IsBackground = true;
- _msgThread.Start();
+ if (_isClient)
+ {
+ _msgThread = new Thread(new ThreadStart(messageLoop));
+ _msgThread.IsBackground = true;
+ _msgThread.Start();
+ }
+ else
+ {
+ _autoEvent = new AutoResetEvent(false);
+ Action act = () =>
+ {
+ if (_readyState == WsState.OPEN)
+ {
+ message();
+ }
+ };
+ AsyncCallback callback = (ar) =>
+ {
+ act.EndInvoke(ar);
+
+ if (_readyState == WsState.OPEN)
+ {
+ act.BeginInvoke(callback, null);
+ }
+ else
+ {
+ _autoEvent.Set();
+ }
+ };
+ act.BeginInvoke(callback, null);
+ }
}
private MessageEventArgs receive()
@@ -671,6 +912,26 @@ namespace WebSocketSharp
pong(payloadData);
}
+ private string[] receiveOpeningHandshake()
+ {
+ var readData = new List();
+
+ while (true)
+ {
+ if (_wsStream.ReadByte().EqualsAndSaveTo('\r', readData) &&
+ _wsStream.ReadByte().EqualsAndSaveTo('\n', readData) &&
+ _wsStream.ReadByte().EqualsAndSaveTo('\r', readData) &&
+ _wsStream.ReadByte().EqualsAndSaveTo('\n', readData))
+ {
+ break;
+ }
+ }
+
+ return Encoding.UTF8.GetString(readData.ToArray())
+ .Replace("\r\n", "\n").Replace("\n\n", "\n").TrimEnd('\n')
+ .Split('\n');
+ }
+
private bool send(WsFrame frame)
{
if (_readyState != WsState.OPEN)
@@ -832,6 +1093,12 @@ namespace WebSocketSharp
.Split('\n');
}
+ private void sendResponseHandshake(string value)
+ {
+ var buffer = Encoding.UTF8.GetBytes(value);
+ _wsStream.Write(buffer, 0, buffer.Length);
+ }
+
#endregion
#region Public Methods
@@ -840,14 +1107,22 @@ namespace WebSocketSharp
{
if (_readyState == WsState.OPEN)
{
- Console.WriteLine("WS: Info@Connect: Connection is already established.");
+ Console.WriteLine("\nWS: Info@Connect: Connection is already established.");
return;
}
try
- {
- createConnection();
- doHandshake();
+ {
+ if (_isClient)
+ {
+ createClientStream();
+ doHandshake();
+ }
+ else
+ {
+ createServerStream();
+ acceptHandshake();
+ }
}
catch (Exception ex)
{
diff --git a/websocket-sharp/WebSocketServer.cs b/websocket-sharp/WebSocketServer.cs
new file mode 100644
index 00000000..1d1677e5
--- /dev/null
+++ b/websocket-sharp/WebSocketServer.cs
@@ -0,0 +1,237 @@
+#region MIT License
+/**
+ * WebSocketServer.cs
+ *
+ * A C# implementation of a WebSocket protocol server.
+ *
+ * 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.Generic;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using WebSocketSharp.Frame;
+
+namespace WebSocketSharp
+{
+ public class WebSocketServer
+ {
+ #region Private Fields
+
+ private TcpListener _tcpListener;
+ private Uri _uri;
+ private SynchronizedCollection _webSockets;
+
+ #endregion
+
+ #region Properties
+
+ public IPAddress Address
+ {
+ get { return Endpoint.Address; }
+ }
+
+ public IPEndPoint Endpoint
+ {
+ get { return (IPEndPoint)_tcpListener.LocalEndpoint; }
+ }
+
+ public int Port
+ {
+ get { return Endpoint.Port; }
+ }
+
+ public string Url
+ {
+ get { return _uri.ToString(); }
+ }
+
+ #endregion
+
+ #region Events
+
+ public event EventHandler OnConnection;
+ public event EventHandler OnError;
+
+ #endregion
+
+ #region Public Constructor
+
+ public WebSocketServer(string url)
+ {
+ _uri = new Uri(url);
+ if (!isValidScheme(_uri))
+ {
+ throw new ArgumentException("Unsupported WebSocket URI scheme: " + _uri.Scheme);
+ }
+
+ string scheme = _uri.Scheme;
+ int port = _uri.Port;
+
+ if (port <= 0)
+ {
+ if (scheme == "wss")
+ {
+ port = 443;
+ }
+ else
+ {
+ port = 80;
+ }
+ }
+
+ _tcpListener = new TcpListener(IPAddress.Any, port);
+ _webSockets = new SynchronizedCollection();
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private void acceptClient(IAsyncResult ar)
+ {
+ TcpListener listener = (TcpListener)ar.AsyncState;
+
+ if (listener.Server == null || !listener.Server.IsBound)
+ {
+ return;
+ }
+
+ try
+ {
+ TcpClient client = listener.EndAcceptTcpClient(ar);
+
+ WebSocket ws = new WebSocket(_uri.ToString(), client);
+ OnConnection.Emit(this, new ConnectionEventArgs(ws));
+ _webSockets.Add(ws);
+
+ ws.Connect();
+ }
+ catch (ObjectDisposedException)
+ {
+ // TcpListener has been stopped.
+ return;
+ }
+ catch (Exception ex)
+ {
+ error(ex.Message);
+ }
+
+ listener.BeginAcceptTcpClient(acceptClient, listener);
+ }
+
+ private void error(string message)
+ {
+ #if DEBUG
+ var callerFrame = new StackFrame(1);
+ var caller = callerFrame.GetMethod();
+ Console.WriteLine("WSSV: Error@{0}: {1}", caller.Name, message);
+ #endif
+ OnError.Emit(this, new ErrorEventArgs(message));
+ }
+
+ private bool isValidScheme(Uri uri)
+ {
+ string scheme = uri.Scheme;
+ if (scheme == "ws" || scheme == "wss")
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public void Close(CloseStatusCode code, string reason)
+ {
+ lock (_webSockets.SyncRoot)
+ {
+ foreach (WebSocket ws in _webSockets)
+ {
+ if (ws.ReadyState == WsState.OPEN)
+ {
+ ws.Close(code, reason);
+ }
+ }
+ }
+ }
+
+ public void Send(byte[] data)
+ {
+ WaitCallback broadcast = (state) =>
+ {
+ lock (_webSockets.SyncRoot)
+ {
+ foreach (WebSocket ws in _webSockets)
+ {
+ if (ws.ReadyState == WsState.OPEN)
+ {
+ ws.Send(data);
+ }
+ }
+ }
+ };
+ ThreadPool.QueueUserWorkItem(broadcast);
+ }
+
+ public void Send(string data)
+ {
+ WaitCallback broadcast = (state) =>
+ {
+ lock (_webSockets.SyncRoot)
+ {
+ foreach (WebSocket ws in _webSockets)
+ {
+ if (ws.ReadyState == WsState.OPEN)
+ {
+ ws.Send(data);
+ }
+ }
+ }
+ };
+ ThreadPool.QueueUserWorkItem(broadcast);
+ }
+
+ public void Start()
+ {
+ _tcpListener.Start();
+ _tcpListener.BeginAcceptTcpClient(acceptClient, _tcpListener);
+ }
+
+ public void Stop()
+ {
+ _tcpListener.Stop();
+ Close(CloseStatusCode.NORMAL, String.Empty);
+ }
+
+ #endregion
+ }
+}
diff --git a/websocket-sharp/bin/Debug/websocket-sharp.dll b/websocket-sharp/bin/Debug/websocket-sharp.dll
index 6fd6c13b..a3c86269 100755
Binary files a/websocket-sharp/bin/Debug/websocket-sharp.dll and b/websocket-sharp/bin/Debug/websocket-sharp.dll differ
diff --git a/websocket-sharp/bin/Debug/websocket-sharp.dll.mdb b/websocket-sharp/bin/Debug/websocket-sharp.dll.mdb
index 695ceb15..83a06f05 100644
Binary files a/websocket-sharp/bin/Debug/websocket-sharp.dll.mdb and b/websocket-sharp/bin/Debug/websocket-sharp.dll.mdb differ
diff --git a/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll b/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll
index 4b8d81cb..e318f2b9 100755
Binary files a/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll and b/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll differ
diff --git a/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll.mdb b/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll.mdb
index f26ae797..8e296ffa 100644
Binary files a/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll.mdb and b/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll.mdb differ
diff --git a/websocket-sharp/bin/Release/websocket-sharp.dll b/websocket-sharp/bin/Release/websocket-sharp.dll
index 0096e74e..c41cbdc8 100755
Binary files a/websocket-sharp/bin/Release/websocket-sharp.dll and b/websocket-sharp/bin/Release/websocket-sharp.dll differ
diff --git a/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.dll b/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.dll
index eed7a63f..9541e270 100755
Binary files a/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.dll and b/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.dll differ
diff --git a/websocket-sharp/websocket-sharp.csproj b/websocket-sharp/websocket-sharp.csproj
index 6dfbe2f3..f55abe96 100644
--- a/websocket-sharp/websocket-sharp.csproj
+++ b/websocket-sharp/websocket-sharp.csproj
@@ -53,11 +53,11 @@
+
-
@@ -72,6 +72,10 @@
+
+
+
+
diff --git a/websocket-sharp/websocket-sharp.pidb b/websocket-sharp/websocket-sharp.pidb
index ba958474..b0b7ab54 100644
Binary files a/websocket-sharp/websocket-sharp.pidb and b/websocket-sharp/websocket-sharp.pidb differ