Fix due to the added SessionManager.cs

This commit is contained in:
sta
2012-10-09 12:14:55 +09:00
parent 94385ea2bc
commit c560d4fba9
66 changed files with 345 additions and 245 deletions

View File

@@ -32,8 +32,8 @@ using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace WebSocketSharp.Frame
{
namespace WebSocketSharp.Frame {
public class WsFrame : IEnumerable<byte>
{
#region Field
@@ -42,37 +42,6 @@ namespace WebSocketSharp.Frame
#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()
@@ -120,6 +89,37 @@ namespace WebSocketSharp.Frame
#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 Private Methods
IEnumerator IEnumerable.GetEnumerator()

View File

@@ -1,6 +1,6 @@
//
// EndPointManager.cs
// Copied from System.Net.EndPointManager
// Copied from System.Net.EndPointManager.cs
//
// Author:
// Gonzalo Paniagua Javier (gonzalo@ximian.com)

View File

@@ -39,12 +39,12 @@ namespace WebSocketSharp.Server {
#region Fields
private Thread _acceptRequestThread;
private bool _isWindows;
private HttpListener _listener;
private int _port;
private string _rootPath;
private Dictionary<string, IWebSocketServer> _wsServers;
private Thread _acceptRequestThread;
private bool _isWindows;
private HttpListener _listener;
private int _port;
private string _rootPath;
private Dictionary<string, IServiceHost> _services;
#endregion
@@ -119,7 +119,7 @@ namespace WebSocketSharp.Server {
{
_isWindows = false;
_listener = new HttpListener();
_wsServers = new Dictionary<string, IWebSocketServer>();
_services = new Dictionary<string, IServiceHost>();
var os = Environment.OSVersion;
if (os.Platform != PlatformID.Unix && os.Platform != PlatformID.MacOSX)
@@ -248,7 +248,7 @@ namespace WebSocketSharp.Server {
var res = context.Response;
var path = req.RawUrl;
if (!_wsServers.ContainsKey(path))
if (!_services.ContainsKey(path))
{
res.StatusCode = (int)HttpStatusCode.NotImplemented;
return false;
@@ -256,8 +256,8 @@ namespace WebSocketSharp.Server {
var wsContext = context.AcceptWebSocket(path);
var socket = wsContext.WebSocket;
var wsServer = _wsServers[path];
wsServer.BindWebSocket(socket);
var service = _services[path];
service.BindWebSocket(socket);
return true;
}
@@ -269,8 +269,8 @@ namespace WebSocketSharp.Server {
public void AddService<T>(string path)
where T : WebSocketService, new()
{
var server = new WebSocketServer<T>();
_wsServers.Add(path, server);
var service = new WebSocketServer<T>();
_services.Add(path, service);
}
public byte[] GetFile(string path)
@@ -295,9 +295,9 @@ namespace WebSocketSharp.Server {
{
_listener.Close();
_acceptRequestThread.Join(5 * 1000);
foreach (var server in _wsServers.Values)
server.Stop();
_wsServers.Clear();
foreach (var service in _services.Values)
service.Stop();
_services.Clear();
}
#endregion

View File

@@ -1,6 +1,6 @@
#region MIT License
/**
* IWebSocketServer.cs
* IServiceHost.cs
*
* The MIT License
*
@@ -30,11 +30,10 @@ using System;
namespace WebSocketSharp.Server {
public interface IWebSocketServer {
public interface IServiceHost {
void BindWebSocket(WebSocket socket);
void Start();
void Stop();
void StopServices();
}
}

View File

@@ -0,0 +1,184 @@
#region MIT License
/**
* SessionManager.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.Generic;
using WebSocketSharp.Frame;
namespace WebSocketSharp.Server {
public class SessionManager {
#region Private Fields
private bool _isStopped;
private Dictionary<string, WebSocketService> _sessions;
private object _syncRoot;
#endregion
#region Public Constructor
public SessionManager()
{
_isStopped = false;
_sessions = new Dictionary<string, WebSocketService>();
_syncRoot = new object();
}
#endregion
#region Properties
public int Count {
get {
lock (_syncRoot)
{
return _sessions.Count;
}
}
}
public object SyncRoot {
get {
return _syncRoot;
}
}
#endregion
#region Private Method
private Dictionary<string, WebSocketService> copySessions()
{
lock (_syncRoot)
{
return new Dictionary<string, WebSocketService>(_sessions);
}
}
private string getNewID()
{
return Guid.NewGuid().ToString("N");
}
#endregion
#region Public Methods
public string Add(WebSocketService service)
{
lock (_syncRoot)
{
if (_isStopped)
return null;
var id = getNewID();
_sessions.Add(id, service);
return id;
}
}
public void Broadcast(byte[] data)
{
lock (_syncRoot)
{
foreach (var service in _sessions.Values)
service.SendAsync(data);
}
}
public void Broadcast(string data)
{
lock (_syncRoot)
{
foreach (var service in _sessions.Values)
service.SendAsync(data);
}
}
public Dictionary<string, bool> Broadping(string data)
{
var result = new Dictionary<string, bool>();
foreach (var session in copySessions())
result.Add(session.Key, session.Value.Ping(data));
return result;
}
public IEnumerable<string> GetIDs()
{
lock (_syncRoot)
{
return _sessions.Keys;
}
}
public bool Remove(string id)
{
lock (_syncRoot)
{
if (_isStopped)
return false;
return _sessions.Remove(id);
}
}
public bool TryGetByID(string id, out WebSocketService service)
{
lock (_syncRoot)
{
return _sessions.TryGetValue(id, out service);
}
}
public void Stop()
{
Stop(CloseStatusCode.NORMAL, String.Empty);
}
public void Stop(CloseStatusCode code, string reason)
{
lock (_syncRoot)
{
if (_isStopped)
return;
_isStopped = true;
foreach (var service in _sessions.Values)
service.Stop(code, reason);
_sessions.Clear();
}
}
#endregion
}
}

View File

@@ -29,10 +29,8 @@
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using WebSocketSharp.Frame;
using WebSocketSharp.Net;
using WebSocketSharp.Net.Sockets;
@@ -42,7 +40,7 @@ namespace WebSocketSharp.Server {
{
#region Field
private Dictionary<string, IWebSocketServer> _servers;
private Dictionary<string, IServiceHost> _services;
#endregion
@@ -56,7 +54,7 @@ namespace WebSocketSharp.Server {
public WebSocketServer(int port)
: base(System.Net.IPAddress.Any, port)
{
_servers = new Dictionary<string, IWebSocketServer>();
_services = new Dictionary<string, IServiceHost>();
}
#endregion
@@ -68,14 +66,14 @@ namespace WebSocketSharp.Server {
var context = client.AcceptWebSocket();
var socket = context.WebSocket;
var path = context.RequestUri.ToString();
if (!_servers.ContainsKey(path))
if (!_services.ContainsKey(path))
{
socket.Close(HttpStatusCode.NotImplemented);
return;
}
var server = _servers[path];
server.BindWebSocket(socket);
var service = _services[path];
service.BindWebSocket(socket);
}
#endregion
@@ -85,28 +83,28 @@ namespace WebSocketSharp.Server {
public void AddService<T>(string path)
where T : WebSocketService, new()
{
var server = new WebSocketServer<T>();
_servers.Add(path, server);
var service = new WebSocketServer<T>();
_services.Add(path, service);
}
public override void Stop()
{
base.Stop();
foreach (var server in _servers.Values)
server.Stop();
_servers.Clear();
foreach (var service in _services.Values)
service.Stop();
_services.Clear();
}
#endregion
}
public class WebSocketServer<T> : WebSocketServerBase, IWebSocketServer
public class WebSocketServer<T> : WebSocketServerBase, IServiceHost
where T : WebSocketService, new()
{
#region Fields
private Dictionary<string, WebSocketService> _services;
private Uri _uri;
private SessionManager _sessions;
private Uri _uri;
#endregion
@@ -162,7 +160,7 @@ namespace WebSocketSharp.Server {
private void init()
{
_services = new Dictionary<string, WebSocketService>();
_sessions = new SessionManager();
}
#endregion
@@ -182,29 +180,14 @@ namespace WebSocketSharp.Server {
public void BindWebSocket(WebSocket socket)
{
T service = new T();
service.Bind(socket, _services);
service.Bind(socket, _sessions);
service.Start();
}
public override void Stop()
{
base.Stop();
StopServices();
}
public void StopServices()
{
StopServices(CloseStatusCode.NORMAL, String.Empty);
}
public void StopServices(CloseStatusCode code, string reason)
{
lock (((ICollection)_services).SyncRoot)
{
foreach (WebSocketService service in _services.Values)
service.Stop(code, reason);
_services.Clear();
}
_sessions.Stop();
}
#endregion

View File

@@ -27,7 +27,6 @@
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using WebSocketSharp.Frame;
@@ -38,16 +37,8 @@ namespace WebSocketSharp.Server
{
#region Private Fields
private Dictionary<string, WebSocketService> _services;
private WebSocket _socket;
#endregion
#region Properties
public string ID { get; private set; }
public bool IsBound { get; private set; }
public bool IsStop { get; private set; }
private SessionManager _sessions;
private WebSocket _socket;
#endregion
@@ -55,53 +46,37 @@ namespace WebSocketSharp.Server
public WebSocketService()
{
ID = String.Empty;
IsBound = false;
IsStop = false;
ID = String.Empty;
IsBound = false;
IsStopped = false;
}
#endregion
#region Properties
public string ID { get; private set; }
public bool IsBound { get; private set; }
public bool IsStopped { get; private set; }
#endregion
#region Private Method
private void addService(string id, WebSocketService service)
{
lock (((ICollection)_services).SyncRoot)
{
_services.Add(id, service);
}
}
private string getNewID()
{
return Guid.NewGuid().ToString("N");
}
private void defaultBind()
{
_socket.OnOpen += (sender, e) =>
{
ID = getNewID();
addService(ID, this);
ID = _sessions.Add(this);
};
_socket.OnClose += (sender, e) =>
{
if (!IsStop)
{
removeService(ID);
}
if (!IsStopped)
_sessions.Remove(ID);
};
}
private void removeService(string id)
{
lock (((ICollection)_services).SyncRoot)
{
_services.Remove(id);
}
}
#endregion
#region Protected Methods
@@ -126,10 +101,10 @@ namespace WebSocketSharp.Server
#region Public Methods
public void Bind(WebSocket socket, Dictionary<string, WebSocketService> services)
public void Bind(WebSocket socket, SessionManager sessions)
{
_socket = socket;
_services = services;
_sessions = sessions;
defaultBind();
_socket.OnOpen += onOpen;
@@ -159,12 +134,9 @@ namespace WebSocketSharp.Server
public Dictionary<string, bool> PingAround(string data)
{
if (!IsBound) return null;
lock (((ICollection)_services).SyncRoot)
{
return PingTo(_services.Keys, data);
}
return IsBound
? _sessions.Broadping(data)
: null;
}
public bool PingTo(string id)
@@ -172,120 +144,83 @@ namespace WebSocketSharp.Server
return PingTo(id, String.Empty);
}
public Dictionary<string, bool> PingTo(IEnumerable<string> group)
{
return PingTo(group, String.Empty);
}
public bool PingTo(string id, string data)
{
if (!IsBound) return false;
if (!IsBound)
return false;
lock (((ICollection)_services).SyncRoot)
{
WebSocketService service;
return _services.TryGetValue(id, out service)
? service.Ping(data)
: false;
}
WebSocketService service;
return _sessions.TryGetByID(id, out service)
? service.Ping(data)
: false;
}
public Dictionary<string, bool> PingTo(IEnumerable<string> group, string data)
public void Publish(byte[] data)
{
if (!IsBound) return null;
var result = new Dictionary<string, bool>();
lock (((ICollection)_services).SyncRoot)
{
foreach (string id in group)
{
result.Add(id, PingTo(id, data));
}
}
return result;
if (IsBound)
_sessions.Broadcast(data);
}
public void Publish<TData>(TData data)
public void Publish(string data)
{
if (!IsBound) return;
WaitCallback broadcast = (state) =>
{
lock (((ICollection)_services).SyncRoot)
{
SendTo(_services.Keys, data);
}
};
ThreadPool.QueueUserWorkItem(broadcast);
if (IsBound)
_sessions.Broadcast(data);
}
public void Send(byte[] data)
{
if (IsBound) _socket.Send(data);
if (IsBound)
_socket.Send(data);
}
public void Send(string data)
{
if (IsBound) _socket.Send(data);
if (IsBound)
_socket.Send(data);
}
public void SendTo<TData>(string id, TData data)
public void SendAsync(byte[] data)
{
if (!IsBound) return;
if (typeof(TData) != typeof(string) &&
typeof(TData) != typeof(byte[]))
WaitCallback sendCb = (state) =>
{
var msg = "Type of data must be string or byte[].";
throw new ArgumentException(msg);
}
lock (((ICollection)_services).SyncRoot)
{
WebSocketService service;
if (_services.TryGetValue(id, out service))
{
if (typeof(TData) == typeof(string))
{
string data_ = (string)(object)data;
service.Send(data_);
}
else if (typeof(TData) == typeof(byte[]))
{
byte[] data_ = (byte[])(object)data;
service.Send(data_);
}
}
}
Send(data);
};
ThreadPool.QueueUserWorkItem(sendCb);
}
public void SendTo<TData>(IEnumerable<string> group, TData data)
public void SendAsync(string data)
{
if (!IsBound) return;
if (typeof(TData) != typeof(string) &&
typeof(TData) != typeof(byte[]))
WaitCallback sendCb = (state) =>
{
var msg = "Type of data must be string or byte[].";
throw new ArgumentException(msg);
}
Send(data);
};
ThreadPool.QueueUserWorkItem(sendCb);
}
lock (((ICollection)_services).SyncRoot)
{
foreach (string id in group)
{
SendTo(id, data);
}
}
public void SendTo(string id, byte[] data)
{
if (!IsBound)
return;
WebSocketService service;
if (_sessions.TryGetByID(id, out service))
service.Send(data);
}
public void SendTo(string id, string data)
{
if (!IsBound)
return;
WebSocketService service;
if (_sessions.TryGetByID(id, out service))
service.Send(data);
}
public void Start()
{
if (IsBound) _socket.Connect();
if (IsBound)
_socket.Connect();
}
public void Stop()
@@ -295,9 +230,10 @@ namespace WebSocketSharp.Server
public void Stop(CloseStatusCode code, string reason)
{
if (!IsBound || IsStop) return;
if (!IsBound || IsStopped)
return;
IsStop = true;
IsStopped = true;
_socket.Close(code, reason);
}

View File

@@ -32,11 +32,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Threading;
@@ -588,12 +586,9 @@ namespace WebSocketSharp {
{
try
{
MessageEventArgs eventArgs = receive();
var eventArgs = receive();
if (eventArgs != null)
{
OnMessage.Emit(this, eventArgs);
}
}
catch (WsReceivedTooBigMessageException ex)
{
@@ -609,7 +604,6 @@ namespace WebSocketSharp {
{
Action messageInvoker = (Action)ar.AsyncState;
messageInvoker.EndInvoke(ar);
if (_readyState == WsState.OPEN)
{
messageInvoker.BeginInvoke(messageLoopCallback, messageInvoker);
@@ -619,6 +613,22 @@ namespace WebSocketSharp {
_exitMessageLoop.Set();
}
private bool ping(string data, int millisecondsTimeout)
{
var buffer = Encoding.UTF8.GetBytes(data);
if (buffer.Length > 125)
{
var msg = "Ping frame must have a payload length of 125 bytes or less.";
error(msg);
return false;
}
if (!send(Fin.FINAL, Opcode.PING, buffer))
return false;
return _receivePong.WaitOne(millisecondsTimeout);
}
private void pong(PayloadData data)
{
var frame = createFrame(Fin.FINAL, Opcode.PONG, data);
@@ -643,12 +653,11 @@ namespace WebSocketSharp {
return frame;
}
private WsFrame readFrameWithTimeout()
private WsFrame readFrameWithTimeout(int millisecondsTimeout)
{
if (!_wsStream.DataAvailable)
{
var timeout = 1 * 100;
Thread.Sleep(timeout);
Thread.Sleep(millisecondsTimeout);
if (!_wsStream.DataAvailable)
return null;
}
@@ -663,7 +672,7 @@ namespace WebSocketSharp {
private MessageEventArgs receive()
{
var frame = _isClient ? readFrame() : readFrameWithTimeout();
var frame = _isClient ? readFrame() : readFrameWithTimeout(1 * 100);
if (frame == null)
return null;
@@ -939,7 +948,6 @@ namespace WebSocketSharp {
private void startMessageThread()
{
_exitMessageLoop = new AutoResetEvent(false);
Action messageInvoker = () =>
{
if (_readyState == WsState.OPEN)
@@ -1022,18 +1030,7 @@ namespace WebSocketSharp {
public bool Ping(string data)
{
var buffer = Encoding.UTF8.GetBytes(data);
if (buffer.Length > 125)
{
var msg = "Ping frame must have a payload length of 125 bytes or less.";
error(msg);
return false;
}
if (!send(Fin.FINAL, Opcode.PING, buffer))
return false;
return _receivePong.WaitOne(5 * 1000);
return ping(data, 5 * 1000);
}
public void Send(string data)

View File

@@ -107,10 +107,11 @@
<Compile Include="Server\ResponseEventArgs.cs" />
<Compile Include="Net\HttpVersion.cs" />
<Compile Include="Net\HttpStatusCode.cs" />
<Compile Include="Server\IWebSocketServer.cs" />
<Compile Include="Net\Sockets\TcpListenerWebSocketContext.cs" />
<Compile Include="Server\WebSocketServerBase.cs" />
<Compile Include="Net\Security\SslStream.cs" />
<Compile Include="Server\IServiceHost.cs" />
<Compile Include="Server\SessionManager.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

Binary file not shown.