2 Commits

Author SHA1 Message Date
sta
9029714f17 fix WebSocket.cs 2010-10-28 16:28:08 +09:00
sta
fb0485faec branched to draft75 2010-10-28 16:20:17 +09:00
42 changed files with 47 additions and 395 deletions

View File

@@ -5,8 +5,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp", "websocke
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wsclient", "wsclient\wsclient.csproj", "{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wsclient", "wsclient\wsclient.csproj", "{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wsclient1", "wsclient1\wsclient1.csproj", "{B0B609B7-A81C-46B0-A9B8-82E9716D355B}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -23,14 +21,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

View File

@@ -1,8 +1,8 @@
<Properties> <Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Release" ctype="Workspace" /> <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug_Ubuntu" ctype="Workspace" />
<MonoDevelop.Ide.Workbench ActiveDocument="websocket-sharp/WebSocket.cs" ctype="Workbench"> <MonoDevelop.Ide.Workbench ActiveDocument="websocket-sharp/WebSocket.cs" ctype="Workbench">
<Files> <Files>
<File FileName="websocket-sharp/WebSocket.cs" Line="80" Column="19" /> <File FileName="websocket-sharp/WebSocket.cs" Line="247" Column="31" />
</Files> </Files>
</MonoDevelop.Ide.Workbench> </MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.DebuggingService.Breakpoints> <MonoDevelop.Ide.DebuggingService.Breakpoints>

View File

@@ -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("0.9.9.*")]
// 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.

View File

@@ -28,28 +28,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace WebSocketSharp namespace WebSocketSharp
{ {
public static class Ext public static class Ext
{ {
public static bool AreNotEqualDo(
this string expected,
string actual,
Func<string, string, string> func,
out string ret)
{
if (expected != actual)
{
ret = func(expected, actual);
return true;
}
ret = String.Empty;
return false;
}
public static bool EqualsWithSaveTo(this int asByte, char c, List<byte> dist) public static bool EqualsWithSaveTo(this int asByte, char c, List<byte> dist)
{ {
byte b = (byte)asByte; byte b = (byte)asByte;
@@ -57,98 +40,11 @@ namespace WebSocketSharp
return b == Convert.ToByte(c); return b == Convert.ToByte(c);
} }
public static uint GenerateKey(this Random rand, int space) public static void NotEqualsDo(this string expected, string actual, Action<string, string> act)
{ {
uint max = (uint)(0xffffffff / space); if (expected != actual)
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); act(expected, actual);
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( () =>
{
i = rand.Next(1, secKey.Count);
secKey.Insert(i, ' ');
} );
return new String(secKey.ToArray());
}
public static byte[] InitializeWithPrintableASCII(this byte[] bytes, Random rand)
{
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = (byte)rand.Next(32, 127);
}
return bytes;
}
public static bool IsValid(this string[] response, byte[] expectedCR, byte[] actualCR, out string message)
{
string expectedCRtoHexStr = BitConverter.ToString(expectedCR);
string actualCRtoHexStr = BitConverter.ToString(actualCR);
Func<string, Func<string, string, string>> func = s =>
{
return (e, a) =>
{
#if DEBUG
Console.WriteLine("WS: Error @IsValid: Invalid {0} response.", s);
Console.WriteLine(" expected: {0}", e);
Console.WriteLine(" actual : {0}", a);
#endif
return String.Format("Invalid {0} response: {1}", s, a);
};
};
Func<string, string, string> func1 = func("handshake");
Func<string, string, string> func2 = func("challenge");
string msg;
if ("HTTP/1.1 101 WebSocket Protocol Handshake".AreNotEqualDo(response[0], func1, out msg) ||
"Upgrade: WebSocket".AreNotEqualDo(response[1], func1, out msg) ||
"Connection: Upgrade".AreNotEqualDo(response[2], func1, out msg) ||
expectedCRtoHexStr.AreNotEqualDo(actualCRtoHexStr, func2, out msg))
{
message = msg;
return false;
}
message = String.Empty;
return true;
}
public static void Times(this int n, Action act)
{
for (int i = 0; i < n; i++)
{
act();
} }
} }
} }

View File

@@ -33,13 +33,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Security.Cryptography;
namespace WebSocketSharp namespace WebSocketSharp
{ {
@@ -53,8 +51,6 @@ namespace WebSocketSharp
get { return uri.ToString(); } get { return uri.ToString(); }
} }
private Object sync = new Object();
private volatile WsState readyState; private volatile WsState readyState;
public WsState ReadyState public WsState ReadyState
{ {
@@ -65,18 +61,17 @@ namespace WebSocketSharp
switch (value) switch (value)
{ {
case WsState.OPEN: case WsState.OPEN:
readyState = value;
if (OnOpen != null) if (OnOpen != null)
{ {
OnOpen(this, EventArgs.Empty); OnOpen(this, EventArgs.Empty);
} }
break; goto default;
case WsState.CLOSING: case WsState.CLOSING:
case WsState.CLOSED: case WsState.CLOSED:
lock(sync)
{
close(value); close(value);
} break;
default:
readyState = value;
break; break;
} }
} }
@@ -132,41 +127,8 @@ namespace WebSocketSharp
this.protocol = protocol; this.protocol = protocol;
} }
public WebSocket(
string url,
EventHandler onOpen,
MessageEventHandler onMessage,
MessageEventHandler onError,
EventHandler onClose)
: this(url, String.Empty, onOpen, onMessage, onError, onClose)
{
}
public WebSocket(
string url,
string protocol,
EventHandler onOpen,
MessageEventHandler onMessage,
MessageEventHandler onError,
EventHandler onClose)
: this(url, protocol)
{
this.OnOpen += onOpen;
this.OnMessage += onMessage;
this.OnError += onError;
this.OnClose += onClose;
Connect();
}
public void Connect() public void Connect()
{ {
if (readyState == WsState.OPEN)
{
Console.WriteLine("WS: Info @Connect: Connection is already established.");
return;
}
createConnection(); createConnection();
doHandshake(); doHandshake();
@@ -284,12 +246,30 @@ namespace WebSocketSharp
private void doHandshake() private void doHandshake()
{ {
byte[] expectedCR, actualCR; string request = createOpeningHandshake();
string request = createOpeningHandshake(out expectedCR);
#if DEBUG #if DEBUG
Console.WriteLine("WS: Info @doHandshake: Handshake from client: \n{0}", request); Console.WriteLine("WS: Info @doHandshake: Handshake from client: \n{0}", request);
#endif #endif
string[] response = sendOpeningHandshake(request, out actualCR); byte[] sendBuffer = Encoding.UTF8.GetBytes(request);
wsStream.Write(sendBuffer, 0, sendBuffer.Length);
string[] response;
List<byte> rawdata = new List<byte>();
while (true)
{
if (wsStream.ReadByte().EqualsWithSaveTo('\r', rawdata) &&
wsStream.ReadByte().EqualsWithSaveTo('\n', rawdata) &&
wsStream.ReadByte().EqualsWithSaveTo('\r', rawdata) &&
wsStream.ReadByte().EqualsWithSaveTo('\n', rawdata))
{
break;
}
}
response = Encoding.UTF8.GetString(rawdata.ToArray())
.Replace("\r\n", "\n").Replace("\n\n", "\n")
.Split('\n');
#if DEBUG #if DEBUG
Console.WriteLine("WS: Info @doHandshake: Handshake from server:"); Console.WriteLine("WS: Info @doHandshake: Handshake from server:");
foreach (string s in response) foreach (string s in response)
@@ -297,15 +277,18 @@ namespace WebSocketSharp
Console.WriteLine("{0}", s); Console.WriteLine("{0}", s);
} }
#endif #endif
string msg; Action<string, string> act = (e, a) =>
if (!(response.IsValid(expectedCR, actualCR, out msg)))
{ {
throw new IOException(msg); throw new IOException("Invalid handshake response: " + a);
} };
"HTTP/1.1 101 Web Socket Protocol Handshake".NotEqualsDo(response[0], act);
"Upgrade: WebSocket".NotEqualsDo(response[1], act);
"Connection: Upgrade".NotEqualsDo(response[2], act);
for (int i = 3; i < response.Length; i++) for (int i = 3; i < response.Length; i++)
{ {
if (response[i].Contains("Sec-WebSocket-Protocol:")) if (response[i].Contains("WebSocket-Protocol:"))
{ {
int j = response[i].IndexOf(":"); int j = response[i].IndexOf(":");
protocol = response[i].Substring(j + 1).Trim(); protocol = response[i].Substring(j + 1).Trim();
@@ -318,7 +301,7 @@ namespace WebSocketSharp
ReadyState = WsState.OPEN; ReadyState = WsState.OPEN;
} }
private string createOpeningHandshake(out byte[] expectedCR) private string createOpeningHandshake()
{ {
string path = uri.PathAndQuery; string path = uri.PathAndQuery;
string host = uri.DnsSafeHost; string host = uri.DnsSafeHost;
@@ -331,73 +314,16 @@ namespace WebSocketSharp
} }
string subProtocol = protocol != String.Empty string subProtocol = protocol != String.Empty
? String.Format("Sec-WebSocket-Protocol: {0}\r\n", protocol) ? String.Format("WebSocket-Protocol: {0}\r\n", protocol)
: protocol; : protocol;
Random rand = new Random();
uint key1, key2;
string secKey1 = rand.GenerateSecKey(out key1);
string secKey2 = rand.GenerateSecKey(out key2);
byte[] key3 = new byte[8].InitializeWithPrintableASCII(rand);
string secKeys = "Sec-WebSocket-Key1: {0}\r\n" +
"Sec-WebSocket-Key2: {1}\r\n";
secKeys = String.Format(secKeys, secKey1, secKey2);
string key3ToAscii = Encoding.ASCII.GetString(key3);
expectedCR = createExpectedCR(key1, key2, key3);
return "GET " + path + " HTTP/1.1\r\n" + return "GET " + path + " HTTP/1.1\r\n" +
"Upgrade: WebSocket\r\n" + "Upgrade: WebSocket\r\n" +
"Connection: Upgrade\r\n" + "Connection: Upgrade\r\n" +
subProtocol + subProtocol +
"Host: " + host + "\r\n" + "Host: " + host + "\r\n" +
"Origin: " + origin + "\r\n" + "Origin: " + origin + "\r\n" +
secKeys + "\r\n";
"\r\n" +
key3ToAscii;
}
private byte[] createExpectedCR(uint key1, uint key2, byte[] key3)
{
byte[] key1Bytes = BitConverter.GetBytes(key1);
byte[] key2Bytes = BitConverter.GetBytes(key2);
Array.Reverse(key1Bytes);
Array.Reverse(key2Bytes);
byte[] concatKeys = key1Bytes.Concat(key2Bytes).Concat(key3).ToArray();
MD5 md5 = MD5.Create();
return md5.ComputeHash(concatKeys);
}
private string[] sendOpeningHandshake(string openingHandshake, out byte[] challengeResponse)
{
challengeResponse = new byte[16];
List<byte> rawdata = new List<byte>();
byte[] sendBuffer = Encoding.UTF8.GetBytes(openingHandshake);
wsStream.Write(sendBuffer, 0, sendBuffer.Length);
while (true)
{
if (wsStream.ReadByte().EqualsWithSaveTo('\r', rawdata) &&
wsStream.ReadByte().EqualsWithSaveTo('\n', rawdata) &&
wsStream.ReadByte().EqualsWithSaveTo('\r', rawdata) &&
wsStream.ReadByte().EqualsWithSaveTo('\n', rawdata))
{
wsStream.Read(challengeResponse, 0, challengeResponse.Length);
break;
}
}
return Encoding.UTF8.GetString(rawdata.ToArray())
.Replace("\r\n", "\n").Replace("\n\n", "\n")
.Split('\n');
} }
private void message() private void message()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -14,11 +14,11 @@ namespace Example
//using (WebSocket ws = new WebSocket("ws://localhost:8000/")) //using (WebSocket ws = new WebSocket("ws://localhost:8000/"))
using (WebSocket ws = new WebSocket("ws://localhost:8000/", "chat")) using (WebSocket ws = new WebSocket("ws://localhost:8000/", "chat"))
{ {
ws.OnOpen += (o, e) => /*ws.OnOpen += (o, e) =>
{ {
ws.Send("Hi, all!"); //Do something.
}; };
*/
ws.OnMessage += (o, s) => ws.OnMessage += (o, s) =>
{ {
#if NOTIFY #if NOTIFY

Binary file not shown.

View File

@@ -1,27 +0,0 @@
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("wsclient1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[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("")]

Binary file not shown.

Binary file not shown.

View File

@@ -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);
}
}
}
}
}

View File

@@ -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.