This commit is contained in:
jsaey 2023-11-17 09:43:03 +01:00
parent cbfb1a9407
commit bcc9a6d44c
69 changed files with 1149 additions and 1461 deletions

View File

@ -8,7 +8,7 @@ using System.Security.Cryptography.X509Certificates;
internal class Program internal class Program
{ {
private static WebSocket _client; private static WSClient _client;
private static WSServer _server; private static WSServer _server;
private static async Task Main(string[] args) private static async Task Main(string[] args)
@ -66,8 +66,8 @@ internal class Program
StartServer(serverUri, certificatePath, certificatePassword, requiredPassword); StartServer(serverUri, certificatePath, certificatePassword, requiredPassword);
// Start the client in the main thread // Start the client in the main thread
_client = new WebSocket(clientUri); _client = new WSClient(clientUri);
_client.SslConfiguration.Certificates.Add(new X509Certificate(certificatePath, certificatePassword)); _client.SSL.Certificates.Add(new X509Certificate(certificatePath, certificatePassword));
_client.OnConnect += (sender, e) => Console.WriteLine($"Connected to server"); _client.OnConnect += (sender, e) => Console.WriteLine($"Connected to server");
_client.OnMessageReceived += (sender, e) => Console.WriteLine($"Received message from server: {e.Data}"); _client.OnMessageReceived += (sender, e) => Console.WriteLine($"Received message from server: {e.Data}");
_client.OnDisconnect += (sender, e) => Console.WriteLine($"Disconnected from server: {e.Code} : {e.Reason}"); _client.OnDisconnect += (sender, e) => Console.WriteLine($"Disconnected from server: {e.Code} : {e.Reason}");

View File

@ -7,13 +7,13 @@ namespace EonaCat.BlockChain
{ {
public class P2PClient public class P2PClient
{ {
private readonly IDictionary<string, WebSocket> wsDict = new Dictionary<string, WebSocket>(); private readonly IDictionary<string, WSClient> wsDict = new Dictionary<string, WSClient>();
public void Connect(string url) public void Connect(string url)
{ {
if (!wsDict.ContainsKey(url)) if (!wsDict.ContainsKey(url))
{ {
WebSocket webSocket = new WebSocket(url); WSClient webSocket = new WSClient(url);
webSocket.OnMessageReceived += (sender, e) => webSocket.OnMessageReceived += (sender, e) =>
{ {
if (e.Data == "Hi Client") if (e.Data == "Hi Client")

View File

@ -211,24 +211,6 @@ namespace EonaCat.Quic.Connections
TerminateConnection(); TerminateConnection();
} }
private void OnStreamDataBlockedFrame(Frame frame)
{
StreamDataBlockedFrame sdbf = (StreamDataBlockedFrame)frame;
StreamId streamId = sdbf.StreamId;
if (_streams.ContainsKey(streamId.Id) == false)
{
return;
}
QuicStream stream = _streams[streamId.Id];
stream.ProcessStreamDataBlocked(sdbf);
// Remove the stream from the connection
_streams.Remove(streamId.Id);
}
internal QuicConnection(ConnectionData connection) internal QuicConnection(ConnectionData connection)
{ {
_currentTransferRate = 0; _currentTransferRate = 0;

View File

@ -146,10 +146,7 @@ namespace EonaCat.Quic.Infrastructure
break; break;
} }
if (result != null) result?.Decode(_array);
{
result.Decode(_array);
}
return result; return result;
} }

View File

@ -60,8 +60,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
public override byte[] Encode() public override byte[] Encode()
{ {
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
result.Add(ActualType); {
ActualType
};
result.AddRange(ErrorCode.ToByteArray()); result.AddRange(ErrorCode.ToByteArray());
if (ActualType == 0x1c) if (ActualType == 0x1c)
{ {

View File

@ -28,8 +28,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
public override byte[] Encode() public override byte[] Encode()
{ {
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
result.Add(Type); {
Type
};
result.AddRange(MaximumData.ToByteArray()); result.AddRange(MaximumData.ToByteArray());
return result.ToArray(); return result.ToArray();

View File

@ -20,9 +20,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
public override byte[] Encode() public override byte[] Encode()
{ {
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
{
result.Add(Type); Type
};
result.AddRange(MaximumData.ToByteArray()); result.AddRange(MaximumData.ToByteArray());
return result.ToArray(); return result.ToArray();

View File

@ -34,9 +34,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
public override byte[] Encode() public override byte[] Encode()
{ {
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
{
result.Add(Type); Type
};
result.AddRange(StreamId.ToByteArray()); result.AddRange(StreamId.ToByteArray());
result.AddRange(MaximumStreamData.ToByteArray()); result.AddRange(MaximumStreamData.ToByteArray());

View File

@ -28,9 +28,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
public override byte[] Encode() public override byte[] Encode()
{ {
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
{
result.Add(Type); Type
};
result.AddRange(MaximumStreams.ToByteArray()); result.AddRange(MaximumStreams.ToByteArray());
return result.ToArray(); return result.ToArray();

View File

@ -17,8 +17,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
public override byte[] Encode() public override byte[] Encode()
{ {
List<byte> data = new List<byte>(); List<byte> data = new List<byte>
data.Add(Type); {
Type
};
return data.ToArray(); return data.ToArray();
} }

View File

@ -17,8 +17,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
public override byte[] Encode() public override byte[] Encode()
{ {
List<byte> data = new List<byte>(); List<byte> data = new List<byte>
data.Add(Type); {
Type
};
return data.ToArray(); return data.ToArray();
} }

View File

@ -23,9 +23,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
public override byte[] Encode() public override byte[] Encode()
{ {
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
{
result.Add(Type); Type
};
result.AddRange(StreamId.ToByteArray()); result.AddRange(StreamId.ToByteArray());
result.AddRange(ApplicationProtocolErrorCode.ToByteArray()); result.AddRange(ApplicationProtocolErrorCode.ToByteArray());
result.AddRange(FinalSize.ToByteArray()); result.AddRange(FinalSize.ToByteArray());

View File

@ -32,9 +32,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
public override byte[] Encode() public override byte[] Encode()
{ {
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
{
result.Add(Type); Type
};
result.AddRange(StreamId.ToByteArray()); result.AddRange(StreamId.ToByteArray());
result.AddRange(MaximumStreamData.ToByteArray()); result.AddRange(MaximumStreamData.ToByteArray());

View File

@ -79,8 +79,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
byte LEN_BIT = (byte)(ActualType & 0x02); byte LEN_BIT = (byte)(ActualType & 0x02);
byte FIN_BIT = (byte)(ActualType & 0x01); byte FIN_BIT = (byte)(ActualType & 0x01);
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
result.Add(ActualType); {
ActualType
};
byte[] streamId = StreamId; byte[] streamId = StreamId;
result.AddRange(streamId); result.AddRange(streamId);

View File

@ -72,8 +72,10 @@ namespace EonaCat.Quic.Infrastructure.Packets
{ {
byte[] frames = EncodeFrames(); byte[] frames = EncodeFrames();
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
result.Add((byte)(Type | (PacketNumber.Size - 1))); {
(byte)(Type | (PacketNumber.Size - 1))
};
result.AddRange(ByteHelpers.GetBytes(Version)); result.AddRange(ByteHelpers.GetBytes(Version));
result.Add(DestinationConnectionId.Size); result.Add(DestinationConnectionId.Size);

View File

@ -59,9 +59,10 @@ namespace EonaCat.Quic.Infrastructure.Packets
{ {
byte[] frames = EncodeFrames(); byte[] frames = EncodeFrames();
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
{
result.Add(EncodeTypeField()); EncodeTypeField()
};
result.AddRange(ByteHelpers.GetBytes(Version)); result.AddRange(ByteHelpers.GetBytes(Version));
result.Add(DestinationConnectionId.Size); result.Add(DestinationConnectionId.Size);

View File

@ -38,8 +38,10 @@ namespace EonaCat.Quic.Infrastructure.Packets
{ {
byte[] frames = EncodeFrames(); byte[] frames = EncodeFrames();
List<byte> result = new List<byte>(); List<byte> result = new List<byte>
result.Add((byte)(Type | (PacketNumber.Size - 1))); {
(byte)(Type | (PacketNumber.Size - 1))
};
result.AddRange(DestinationConnectionId.ToByteArray()); result.AddRange(DestinationConnectionId.ToByteArray());
byte[] pnBytes = PacketNumber; byte[] pnBytes = PacketNumber;

View File

@ -107,7 +107,6 @@ namespace EonaCat.Quic
private QuicConnection ProcessInitialPacket(Packet packet, IPEndPoint endPoint) private QuicConnection ProcessInitialPacket(Packet packet, IPEndPoint endPoint)
{ {
QuicConnection result = null; QuicConnection result = null;
ulong availableConnectionId;
byte[] data; byte[] data;
// Unsupported version. Version negotiation packet is sent only on initial connection. All other packets are dropped. (5.2.2 / 16th draft) // Unsupported version. Version negotiation packet is sent only on initial connection. All other packets are dropped. (5.2.2 / 16th draft)
if (packet.Version != QuicVersion.CurrentVersion || !QuicVersion.SupportedVersions.Contains(packet.Version)) if (packet.Version != QuicVersion.CurrentVersion || !QuicVersion.SupportedVersions.Contains(packet.Version))
@ -127,7 +126,7 @@ namespace EonaCat.Quic
{ {
ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.PROTOCOL_VIOLATION, 0x00, ErrorConstants.PMTUNotReached)); ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.PROTOCOL_VIOLATION, 0x00, ErrorConstants.PMTUNotReached));
} }
else if (ConnectionPool.AddConnection(new ConnectionData(new PacketWireTransfer(_client, endPoint), cast.SourceConnectionId, 0), out availableConnectionId) == true) else if (ConnectionPool.AddConnection(new ConnectionData(new PacketWireTransfer(_client, endPoint), cast.SourceConnectionId, 0), out ulong availableConnectionId) == true)
{ {
// Tell the peer the available connection id // Tell the peer the available connection id
ip.SourceConnectionId = (byte)availableConnectionId; ip.SourceConnectionId = (byte)availableConnectionId;

View File

@ -291,9 +291,11 @@ namespace EonaCat.Network
user = user.Substring(i + 1); user = user.Substring(i + 1);
} }
var res = new NameValueCollection(); var res = new NameValueCollection
res["username"] = user; {
res["password"] = pass; ["username"] = user,
["password"] = pass
};
return res; return res;
} }

View File

@ -281,8 +281,7 @@ namespace EonaCat.Network
private static string Convert(string key) private static string Convert(string key)
{ {
HttpHeaderInfo info; return _headers.TryGetValue(key, out HttpHeaderInfo info) ? info.Name : string.Empty;
return _headers.TryGetValue(key, out info) ? info.Name : string.Empty;
} }
private void DoWithCheckingState( private void DoWithCheckingState(

View File

@ -16,21 +16,21 @@ namespace EonaCat.Network
/// This class provides access to various properties and methods for interacting with the WebSocket connection /// This class provides access to various properties and methods for interacting with the WebSocket connection
/// within the context of an HTTP request handled by an <see cref="HttpListener"/>. /// within the context of an HTTP request handled by an <see cref="HttpListener"/>.
/// </remarks> /// </remarks>
/// <seealso cref="WebSocketContext"/> /// <seealso cref="WSContext"/>
public class HttpListenerWebSocketContext : WebSocketContext public class HttpListenerWSContext : WSContext
{ {
private readonly HttpListenerContext _context; private readonly HttpListenerContext _context;
private readonly WebSocket _websocket; private readonly WSClient _websocket;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HttpListenerWebSocketContext"/> class. /// Initializes a new instance of the <see cref="HttpListenerWSContext"/> class.
/// </summary> /// </summary>
/// <param name="context">The <see cref="HttpListenerContext"/> associated with the WebSocket connection.</param> /// <param name="context">The <see cref="HttpListenerContext"/> associated with the WebSocket connection.</param>
/// <param name="protocol">The WebSocket protocol negotiated during the connection.</param> /// <param name="protocol">The WebSocket protocol negotiated during the connection.</param>
internal HttpListenerWebSocketContext(HttpListenerContext context, string protocol) internal HttpListenerWSContext(HttpListenerContext context, string protocol)
{ {
_context = context; _context = context;
_websocket = new WebSocket(this, protocol); _websocket = new WSClient(this, protocol);
} }
/// <summary> /// <summary>
@ -83,7 +83,7 @@ namespace EonaCat.Network
public override System.Net.IPEndPoint UserEndPoint => _context.Connection.RemoteEndPoint; public override System.Net.IPEndPoint UserEndPoint => _context.Connection.RemoteEndPoint;
public override WebSocket WebSocket => _websocket; public override WSClient WebSocket => _websocket;
/// <summary> /// <summary>
/// Closes the WebSocket connection. /// Closes the WebSocket connection.

View File

@ -19,7 +19,7 @@ namespace EonaCat.Network
/// This internal class provides access to various properties and methods for interacting with the WebSocket connection /// This internal class provides access to various properties and methods for interacting with the WebSocket connection
/// within the context of a TCP listener. /// within the context of a TCP listener.
/// </remarks> /// </remarks>
internal class TcpListenerWebSocketContext : WebSocketContext internal class TcpListenerWSContext : WSContext
{ {
private CookieCollection _cookies; private CookieCollection _cookies;
private NameValueCollection _queryString; private NameValueCollection _queryString;
@ -28,21 +28,21 @@ namespace EonaCat.Network
private readonly TcpClient _tcpClient; private readonly TcpClient _tcpClient;
private readonly Uri _uri; private readonly Uri _uri;
private IPrincipal _user; private IPrincipal _user;
private readonly WebSocket _websocket; private readonly WSClient _websocket;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TcpListenerWebSocketContext"/> class. /// Initializes a new instance of the <see cref="TcpListenerWSContext"/> class.
/// </summary> /// </summary>
/// <param name="tcpClient">The <see cref="TcpClient"/> associated with the WebSocket connection.</param> /// <param name="tcpClient">The <see cref="TcpClient"/> associated with the WebSocket connection.</param>
/// <param name="protocol">The WebSocket protocol negotiated during the connection.</param> /// <param name="protocol">The WebSocket protocol negotiated during the connection.</param>
/// <param name="secure">A boolean indicating whether the connection is secure.</param> /// <param name="secure">A boolean indicating whether the connection is secure.</param>
/// <param name="sslConfig">The SSL configuration for secure connections.</param> /// <param name="sslConfig">The SSL configuration for secure connections.</param>
/// <param name="logger">The logger for logging.</param> /// <param name="logger">The logger for logging.</param>
internal TcpListenerWebSocketContext( internal TcpListenerWSContext(
TcpClient tcpClient, TcpClient tcpClient,
string protocol, string protocol,
bool secure, bool secure,
SSLConfigurationServer sslConfig SSLConfigServer sslConfig
) )
{ {
_tcpClient = tcpClient; _tcpClient = tcpClient;
@ -74,7 +74,7 @@ namespace EonaCat.Network
_request.RequestUri, _request.Headers["Host"], _request.IsWebSocketRequest, secure _request.RequestUri, _request.Headers["Host"], _request.IsWebSocketRequest, secure
); );
_websocket = new WebSocket(this, protocol); _websocket = new WSClient(this, protocol);
} }
/// <summary> /// <summary>
@ -100,7 +100,7 @@ namespace EonaCat.Network
public override NameValueCollection QueryString => _queryString ??= public override NameValueCollection QueryString => _queryString ??=
HttpUtility.InternalParseQueryString( HttpUtility.InternalParseQueryString(
_uri != null ? _uri.Query : null, Encoding.UTF8 _uri?.Query, Encoding.UTF8
) )
; ;
@ -131,7 +131,7 @@ namespace EonaCat.Network
public override System.Net.IPEndPoint UserEndPoint => (System.Net.IPEndPoint)_tcpClient.Client.RemoteEndPoint; public override System.Net.IPEndPoint UserEndPoint => (System.Net.IPEndPoint)_tcpClient.Client.RemoteEndPoint;
public override WebSocket WebSocket => _websocket; public override WSClient WebSocket => _websocket;
/// <summary> /// <summary>
/// Authenticates the WebSocket connection based on the specified authentication scheme. /// Authenticates the WebSocket connection based on the specified authentication scheme.

View File

@ -15,12 +15,12 @@ namespace EonaCat.Network
/// This abstract class defines properties and methods for accessing information related to a WebSocket connection, /// This abstract class defines properties and methods for accessing information related to a WebSocket connection,
/// such as headers, cookies, authentication status, and more. /// such as headers, cookies, authentication status, and more.
/// </remarks> /// </remarks>
public abstract class WebSocketContext public abstract class WSContext
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WebSocketContext"/> class. /// Initializes a new instance of the <see cref="WSContext"/> class.
/// </summary> /// </summary>
protected WebSocketContext() protected WSContext()
{ {
} }
@ -107,6 +107,6 @@ namespace EonaCat.Network
/// <summary> /// <summary>
/// Gets the WebSocket instance associated with the context. /// Gets the WebSocket instance associated with the context.
/// </summary> /// </summary>
public abstract WebSocket WebSocket { get; } public abstract WSClient WebSocket { get; }
} }
} }

View File

@ -226,10 +226,9 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!canSetName(value, out string message))
if (!canSetName(value, out msg))
{ {
throw new CookieException(msg); throw new CookieException(message);
} }
_name = value; _name = value;
@ -272,8 +271,7 @@ namespace EonaCat.Network
"The value specified for the Port attribute isn't enclosed in double quotes."); "The value specified for the Port attribute isn't enclosed in double quotes.");
} }
string err; if (!tryCreatePorts(value, out _ports, out string err))
if (!tryCreatePorts(value, out _ports, out err))
{ {
throw new CookieException( throw new CookieException(
string.Format( string.Format(
@ -308,10 +306,9 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!canSetValue(value, out string message))
if (!canSetValue(value, out msg))
{ {
throw new CookieException(msg); throw new CookieException(message);
} }
_value = value.Length > 0 ? value : "\"\""; _value = value.Length > 0 ? value : "\"\"";

View File

@ -236,13 +236,12 @@ namespace EonaCat.Network
buff.AppendFormat(", {0}", pairs[++i].Trim()); buff.AppendFormat(", {0}", pairs[++i].Trim());
} }
DateTime expires;
if (!DateTime.TryParseExact( if (!DateTime.TryParseExact(
buff.ToString(), buff.ToString(),
new[] { "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'", "r" }, new[] { "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'", "r" },
CultureInfo.CreateSpecificCulture("en-US"), CultureInfo.CreateSpecificCulture("en-US"),
DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal,
out expires)) out DateTime expires))
{ {
expires = DateTime.Now; expires = DateTime.Now;
} }

View File

@ -37,7 +37,7 @@ namespace EonaCat.Network
IPEndPoint endpoint, IPEndPoint endpoint,
bool secure, bool secure,
string certificateFolderPath, string certificateFolderPath,
SSLConfigurationServer sslConfig, SSLConfigServer sslConfig,
bool reuseAddress bool reuseAddress
) )
{ {
@ -52,8 +52,8 @@ namespace EonaCat.Network
} }
IsSecure = true; IsSecure = true;
SslConfiguration = new SSLConfigurationServer(sslConfig); SSL = new SSLConfigServer(sslConfig);
SslConfiguration.Certificate = cert; SSL.Certificate = cert;
} }
_endpoint = endpoint; _endpoint = endpoint;
@ -91,7 +91,7 @@ namespace EonaCat.Network
/// <summary> /// <summary>
/// Gets the SSL configuration for the secure endpoint. /// Gets the SSL configuration for the secure endpoint.
/// </summary> /// </summary>
public SSLConfigurationServer SslConfiguration { get; } public SSLConfigServer SSL { get; }
private static void addSpecial(List<HttpListenerPrefix> prefixes, HttpListenerPrefix prefix) private static void addSpecial(List<HttpListenerPrefix> prefixes, HttpListenerPrefix prefix)
{ {
@ -183,7 +183,7 @@ namespace EonaCat.Network
} }
catch (SocketException) catch (SocketException)
{ {
// TODO: Should log the error code when this class has a logging. // Do nothing
} }
catch (ObjectDisposedException) catch (ObjectDisposedException)
{ {
@ -196,10 +196,7 @@ namespace EonaCat.Network
} }
catch catch
{ {
if (sock != null) sock?.Close();
{
sock.Close();
}
return; return;
} }
@ -436,8 +433,10 @@ namespace EonaCat.Network
return; return;
} }
prefs2 = new Dictionary<HttpListenerPrefix, HttpListener>(prefs); prefs2 = new Dictionary<HttpListenerPrefix, HttpListener>(prefs)
prefs2[prefix] = listener; {
[prefix] = listener
};
} }
while (Interlocked.CompareExchange(ref _prefixes, prefs2, prefs) != prefs); while (Interlocked.CompareExchange(ref _prefixes, prefs2, prefs) != prefs);
} }

View File

@ -40,8 +40,7 @@ namespace EonaCat.Network
throw new HttpListenerException(87, "Includes an invalid host."); throw new HttpListenerException(87, "Includes an invalid host.");
} }
int port; if (!int.TryParse(pref.Port, out int port))
if (!int.TryParse(pref.Port, out port))
{ {
throw new HttpListenerException(87, "Includes an invalid port."); throw new HttpListenerException(87, "Includes an invalid port.");
} }
@ -64,8 +63,7 @@ namespace EonaCat.Network
var endpoint = new IPEndPoint(addr, port); var endpoint = new IPEndPoint(addr, port);
EndPointListener lsnr; if (_endpoints.TryGetValue(endpoint, out EndPointListener lsnr))
if (_endpoints.TryGetValue(endpoint, out lsnr))
{ {
if (lsnr.IsSecure ^ pref.IsSecure) if (lsnr.IsSecure ^ pref.IsSecure)
{ {
@ -104,8 +102,7 @@ namespace EonaCat.Network
return; return;
} }
int port; if (!int.TryParse(pref.Port, out int port))
if (!int.TryParse(pref.Port, out port))
{ {
return; return;
} }
@ -128,8 +125,7 @@ namespace EonaCat.Network
var endpoint = new IPEndPoint(addr, port); var endpoint = new IPEndPoint(addr, port);
EndPointListener lsnr; if (!_endpoints.TryGetValue(endpoint, out EndPointListener lsnr))
if (!_endpoints.TryGetValue(endpoint, out lsnr))
{ {
return; return;
} }
@ -151,8 +147,7 @@ namespace EonaCat.Network
{ {
lock (((ICollection)_endpoints).SyncRoot) lock (((ICollection)_endpoints).SyncRoot)
{ {
EndPointListener lsnr; if (!_endpoints.TryGetValue(endpoint, out EndPointListener lsnr))
if (!_endpoints.TryGetValue(endpoint, out lsnr))
{ {
return false; return false;
} }

View File

@ -19,6 +19,8 @@ namespace EonaCat.Network
{ {
private byte[] _buffer; private byte[] _buffer;
private const int _bufferLength = 8192; private const int _bufferLength = 8192;
private const int TIMEOUT_CONTINUE = 15000;
private const int TIMEOUT_INITIAL = 90000;
private HttpListenerContext _context; private HttpListenerContext _context;
private bool _contextRegistered; private bool _contextRegistered;
private StringBuilder _currentLine; private StringBuilder _currentLine;
@ -31,7 +33,7 @@ namespace EonaCat.Network
private int _position; private int _position;
private MemoryStream _requestBuffer; private MemoryStream _requestBuffer;
private Socket _socket; private Socket _socket;
private readonly object _sync; private readonly object _lock;
private int _timeout; private int _timeout;
private readonly Dictionary<int, bool> _timeoutCanceled; private readonly Dictionary<int, bool> _timeoutCanceled;
private Timer _timer; private Timer _timer;
@ -47,11 +49,11 @@ namespace EonaCat.Network
_listener = listener; _listener = listener;
IsSecure = listener.IsSecure; IsSecure = listener.IsSecure;
var netStream = new NetworkStream(socket, false); var networkStream = new NetworkStream(socket, false);
if (IsSecure) if (IsSecure)
{ {
var conf = listener.SslConfiguration; var conf = listener.SSL;
var sslStream = new SslStream(netStream, false, conf.ClientCertificateValidationCallback); var sslStream = new SslStream(networkStream, false, conf.ClientCertificateValidationCallback);
sslStream.AuthenticateAsServer( sslStream.AuthenticateAsServer(
conf.Certificate, conf.Certificate,
conf.IsClientCertificateRequired, conf.IsClientCertificateRequired,
@ -63,15 +65,15 @@ namespace EonaCat.Network
} }
else else
{ {
Stream = netStream; Stream = networkStream;
} }
_sync = new object(); _lock = new object();
_timeout = 90000; // 90k ms for first request, 15k ms from then on. _timeout = TIMEOUT_INITIAL;
_timeoutCanceled = new Dictionary<int, bool>(); _timeoutCanceled = new Dictionary<int, bool>();
_timer = new Timer(onTimeout, this, Timeout.Infinite, Timeout.Infinite); _timer = new Timer(OnTimeout, this, Timeout.Infinite, Timeout.Infinite);
init(); Setup();
} }
/// <summary> /// <summary>
@ -106,24 +108,24 @@ namespace EonaCat.Network
private void close() private void close()
{ {
lock (_sync) lock (_lock)
{ {
if (_socket == null) if (_socket == null)
{ {
return; return;
} }
disposeTimer(); DisposeTimer();
disposeRequestBuffer(); DisposeRequestBuffer();
disposeStream(); DisposeStream();
closeSocket(); CloseSocket();
} }
unregisterContext(); UnregisterContext();
removeConnection(); RemoveConnection();
} }
private void closeSocket() private void CloseSocket()
{ {
try try
{ {
@ -137,7 +139,7 @@ namespace EonaCat.Network
_socket = null; _socket = null;
} }
private void disposeRequestBuffer() private void DisposeRequestBuffer()
{ {
if (_requestBuffer == null) if (_requestBuffer == null)
{ {
@ -148,7 +150,7 @@ namespace EonaCat.Network
_requestBuffer = null; _requestBuffer = null;
} }
private void disposeStream() private void DisposeStream()
{ {
if (Stream == null) if (Stream == null)
{ {
@ -162,7 +164,7 @@ namespace EonaCat.Network
Stream = null; Stream = null;
} }
private void disposeTimer() private void DisposeTimer()
{ {
if (_timer == null) if (_timer == null)
{ {
@ -181,7 +183,7 @@ namespace EonaCat.Network
_timer = null; _timer = null;
} }
private void init() private void Setup()
{ {
_context = new HttpListenerContext(this); _context = new HttpListenerContext(this);
_inputState = InputState.RequestLine; _inputState = InputState.RequestLine;
@ -192,17 +194,17 @@ namespace EonaCat.Network
_requestBuffer = new MemoryStream(); _requestBuffer = new MemoryStream();
} }
private static void onRead(IAsyncResult asyncResult) private static void OnRead(IAsyncResult asyncResult)
{ {
var conn = (HttpConnection)asyncResult.AsyncState; var httpConnection = (HttpConnection)asyncResult.AsyncState;
if (conn._socket == null) if (httpConnection._socket == null)
{ {
return; return;
} }
lock (conn._sync) lock (httpConnection._lock)
{ {
if (conn._socket == null) if (httpConnection._socket == null)
{ {
return; return;
} }
@ -211,111 +213,110 @@ namespace EonaCat.Network
var len = 0; var len = 0;
try try
{ {
var current = conn.Reuses; var current = httpConnection.Reuses;
if (!conn._timeoutCanceled[current]) if (!httpConnection._timeoutCanceled[current])
{ {
conn._timer.Change(Timeout.Infinite, Timeout.Infinite); httpConnection._timer.Change(Timeout.Infinite, Timeout.Infinite);
conn._timeoutCanceled[current] = true; httpConnection._timeoutCanceled[current] = true;
} }
nread = conn.Stream.EndRead(asyncResult); nread = httpConnection.Stream.EndRead(asyncResult);
conn._requestBuffer.Write(conn._buffer, 0, nread); httpConnection._requestBuffer.Write(httpConnection._buffer, 0, nread);
len = (int)conn._requestBuffer.Length; len = (int)httpConnection._requestBuffer.Length;
} }
catch (Exception ex) catch (Exception exception)
{ {
if (conn._requestBuffer != null && conn._requestBuffer.Length > 0) if (httpConnection._requestBuffer != null && httpConnection._requestBuffer.Length > 0)
{ {
conn.SendError(ex.Message, 400); httpConnection.SendError(exception.Message, 400);
return; return;
} }
conn.close(); httpConnection.close();
return; return;
} }
if (nread <= 0) if (nread <= 0)
{ {
conn.close(); httpConnection.close();
return; return;
} }
if (conn.processInput(conn._requestBuffer.GetBuffer(), len)) if (httpConnection.ProcessInput(httpConnection._requestBuffer.GetBuffer(), len))
{ {
if (!conn._context.HasError) if (!httpConnection._context.HasError)
{ {
conn._context.Request.FinishInitialization(); httpConnection._context.Request.FinishInitialization();
} }
if (conn._context.HasError) if (httpConnection._context.HasError)
{ {
conn.SendError(); httpConnection.SendError();
return; return;
} }
HttpListener lsnr; if (!httpConnection._listener.TrySearchHttpListener(httpConnection._context.Request.Url, out HttpListener httpListener))
if (!conn._listener.TrySearchHttpListener(conn._context.Request.Url, out lsnr))
{ {
conn.SendError(null, 404); httpConnection.SendError(null, 404);
return; return;
} }
if (conn._lastListener != lsnr) if (httpConnection._lastListener != httpListener)
{ {
conn.removeConnection(); httpConnection.RemoveConnection();
if (!lsnr.AddConnection(conn)) if (!httpListener.AddConnection(httpConnection))
{ {
conn.close(); httpConnection.close();
return; return;
} }
conn._lastListener = lsnr; httpConnection._lastListener = httpListener;
} }
conn._context.Listener = lsnr; httpConnection._context.Listener = httpListener;
if (!conn._context.Authenticate()) if (!httpConnection._context.Authenticate())
{ {
return; return;
} }
if (conn._context.Register()) if (httpConnection._context.Register())
{ {
conn._contextRegistered = true; httpConnection._contextRegistered = true;
} }
return; return;
} }
conn.Stream.BeginRead(conn._buffer, 0, _bufferLength, onRead, conn); httpConnection.Stream.BeginRead(httpConnection._buffer, 0, _bufferLength, OnRead, httpConnection);
} }
} }
private static void onTimeout(object state) private static void OnTimeout(object state)
{ {
var conn = (HttpConnection)state; var httpConnection = (HttpConnection)state;
var current = conn.Reuses; var current = httpConnection.Reuses;
if (conn._socket == null) if (httpConnection._socket == null)
{ {
return; return;
} }
lock (conn._sync) lock (httpConnection._lock)
{ {
if (conn._socket == null) if (httpConnection._socket == null)
{ {
return; return;
} }
if (conn._timeoutCanceled[current]) if (httpConnection._timeoutCanceled[current])
{ {
return; return;
} }
conn.SendError(null, 408); httpConnection.SendError(null, 408);
} }
} }
private bool processInput(byte[] data, int length) private bool ProcessInput(byte[] data, int length)
{ {
_currentLine ??= new StringBuilder(64); _currentLine ??= new StringBuilder(64);
@ -323,7 +324,7 @@ namespace EonaCat.Network
try try
{ {
string line; string line;
while ((line = readLineFrom(data, _position, length, out nread)) != null) while ((line = ReadLineFrom(data, _position, length, out nread)) != null)
{ {
_position += nread; _position += nread;
if (line.Length == 0) if (line.Length == 0)
@ -358,9 +359,9 @@ namespace EonaCat.Network
} }
} }
} }
catch (Exception ex) catch (Exception exception)
{ {
_context.ErrorMessage = ex.Message; _context.ErrorMessage = exception.Message;
return true; return true;
} }
@ -374,22 +375,22 @@ namespace EonaCat.Network
return false; return false;
} }
private string readLineFrom(byte[] buffer, int offset, int length, out int read) private string ReadLineFrom(byte[] buffer, int offset, int length, out int read)
{ {
read = 0; read = 0;
for (var i = offset; i < length && _lineState != LineState.Lf; i++) for (var i = offset; i < length && _lineState != LineState.LineFeed; i++)
{ {
read++; read++;
var b = buffer[i]; var b = buffer[i];
if (b == 13) if (b == 13)
{ {
_lineState = LineState.Cr; _lineState = LineState.CarriageReturn;
} }
else if (b == 10) else if (b == 10)
{ {
_lineState = LineState.Lf; _lineState = LineState.LineFeed;
} }
else else
{ {
@ -397,7 +398,7 @@ namespace EonaCat.Network
} }
} }
if (_lineState != LineState.Lf) if (_lineState != LineState.LineFeed)
{ {
return null; return null;
} }
@ -410,7 +411,7 @@ namespace EonaCat.Network
return line; return line;
} }
private void removeConnection() private void RemoveConnection()
{ {
if (_lastListener != null) if (_lastListener != null)
{ {
@ -422,7 +423,7 @@ namespace EonaCat.Network
} }
} }
private void unregisterContext() private void UnregisterContext()
{ {
if (!_contextRegistered) if (!_contextRegistered)
{ {
@ -444,7 +445,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_lock)
{ {
if (_socket == null) if (_socket == null)
{ {
@ -458,17 +459,16 @@ namespace EonaCat.Network
{ {
// Don't close. Keep working. // Don't close. Keep working.
Reuses++; Reuses++;
disposeRequestBuffer(); DisposeRequestBuffer();
unregisterContext(); UnregisterContext();
init(); Setup();
BeginReadRequest(); BeginReadRequest();
return; return;
} }
} }
else if (_outputStream != null) else
{ {
_outputStream.Close(true); _outputStream?.Close(true);
} }
close(); close();
@ -484,14 +484,14 @@ namespace EonaCat.Network
if (Reuses == 1) if (Reuses == 1)
{ {
_timeout = 15000; _timeout = TIMEOUT_CONTINUE;
} }
try try
{ {
_timeoutCanceled.Add(Reuses, false); _timeoutCanceled.Add(Reuses, false);
_timer.Change(_timeout, Timeout.Infinite); _timer.Change(_timeout, Timeout.Infinite);
Stream.BeginRead(_buffer, 0, _bufferLength, onRead, this); Stream.BeginRead(_buffer, 0, _bufferLength, OnRead, this);
} }
catch catch
{ {
@ -520,7 +520,7 @@ namespace EonaCat.Network
return _inputStream; return _inputStream;
} }
lock (_sync) lock (_lock)
{ {
if (_socket == null) if (_socket == null)
{ {
@ -529,7 +529,7 @@ namespace EonaCat.Network
var buff = _requestBuffer.GetBuffer(); var buff = _requestBuffer.GetBuffer();
var len = (int)_requestBuffer.Length; var len = (int)_requestBuffer.Length;
disposeRequestBuffer(); DisposeRequestBuffer();
if (chunked) if (chunked)
{ {
_context.Response.SendInChunks = true; _context.Response.SendInChunks = true;
@ -557,7 +557,7 @@ namespace EonaCat.Network
return _outputStream; return _outputStream;
} }
lock (_sync) lock (_lock)
{ {
if (_socket == null) if (_socket == null)
{ {
@ -592,7 +592,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_lock)
{ {
if (_socket == null) if (_socket == null)
{ {
@ -601,12 +601,12 @@ namespace EonaCat.Network
try try
{ {
var res = _context.Response; var httpResponse = _context.Response;
res.StatusCode = status; httpResponse.StatusCode = status;
res.ContentType = "text/html"; httpResponse.ContentType = "text/html";
var content = new StringBuilder(64); var content = new StringBuilder(64);
content.AppendFormat("<html><head><title>EonaCat.Network Error</title></head><body><h1>{0} {1}", status, res.StatusDescription); content.AppendFormat("<html><head><title>EonaCat.Network Error</title></head><body><h1>{0} {1}", status, httpResponse.StatusDescription);
if (message != null && message.Length > 0) if (message != null && message.Length > 0)
{ {
content.AppendFormat(" ({0})</h1></body></html>", message); content.AppendFormat(" ({0})</h1></body></html>", message);
@ -616,12 +616,12 @@ namespace EonaCat.Network
content.Append("</h1></body></html>"); content.Append("</h1></body></html>");
} }
var enc = Encoding.UTF8; var encoding = Encoding.UTF8;
var entity = enc.GetBytes(content.ToString()); var entity = encoding.GetBytes(content.ToString());
res.ContentEncoding = enc; httpResponse.ContentEncoding = encoding;
res.ContentLength64 = entity.LongLength; httpResponse.ContentLength64 = entity.LongLength;
res.Close(entity, true); httpResponse.Close(entity, true);
} }
catch catch
{ {

View File

@ -80,11 +80,13 @@ namespace EonaCat.Network
string password, string realm, string method, string entity string password, string realm, string method, string entity
) )
{ {
var copied = new NameValueCollection(_parameters); var copied = new NameValueCollection(_parameters)
copied["password"] = password; {
copied["realm"] = realm; ["password"] = password,
copied["method"] = method; ["realm"] = realm,
copied["entity"] = entity; ["method"] = method,
["entity"] = entity
};
var expected = AuthenticationResponse.CreateRequestDigest(copied); var expected = AuthenticationResponse.CreateRequestDigest(copied);
return _parameters["response"] == expected; return _parameters["response"] == expected;

View File

@ -68,8 +68,7 @@ namespace EonaCat.Network
/// <returns>True if the header is restricted, false otherwise.</returns> /// <returns>True if the header is restricted, false otherwise.</returns>
public bool IsRestricted(bool response) public bool IsRestricted(bool response)
{ {
return (Type & HttpHeaderType.Restricted) == HttpHeaderType.Restricted return (Type & HttpHeaderType.Restricted) == HttpHeaderType.Restricted && (response ? IsResponse : IsRequest);
&& (response ? IsResponse : IsRequest);
} }
} }
} }

View File

@ -18,19 +18,19 @@ namespace EonaCat.Network
private string _certFolderPath; private string _certFolderPath;
private readonly Dictionary<HttpConnection, HttpConnection> _connections; private readonly Dictionary<HttpConnection, HttpConnection> _connections;
private readonly object _connectionsSync; private readonly object _connectionsSync;
private readonly List<HttpListenerContext> _ctxQueue; private readonly List<HttpListenerContext> contextQueue;
private readonly object _ctxQueueSync; private readonly object _contextQueueLock;
private readonly Dictionary<HttpListenerContext, HttpListenerContext> _ctxRegistry; private readonly Dictionary<HttpListenerContext, HttpListenerContext> _contextRegistry;
private readonly object _ctxRegistrySync; private readonly object _contextRegistryLock;
private static readonly string _defaultRealm; private static readonly string _defaultRealm;
private bool _ignoreWriteExceptions; private bool _ignoreWriteExceptions;
private volatile bool _listening; private volatile bool _listening;
private readonly HttpListenerPrefixCollection _prefixes; private readonly HttpListenerPrefixCollection _prefixes;
private string _realm; private string _realm;
private SSLConfigurationServer _sslConfig; private SSLConfigServer _sslConfig;
private Func<IIdentity, NetworkCredential> _userCredFinder; private Func<IIdentity, NetworkCredential> _userCredFinder;
private readonly List<HttpListenerAsyncResult> _waitQueue; private readonly List<HttpListenerAsyncResult> _waitQueue;
private readonly object _waitQueueSync; private readonly object _waitQueueLock;
static HttpListener() static HttpListener()
{ {
@ -47,16 +47,16 @@ namespace EonaCat.Network
_connections = new Dictionary<HttpConnection, HttpConnection>(); _connections = new Dictionary<HttpConnection, HttpConnection>();
_connectionsSync = ((ICollection)_connections).SyncRoot; _connectionsSync = ((ICollection)_connections).SyncRoot;
_ctxQueue = new List<HttpListenerContext>(); contextQueue = new List<HttpListenerContext>();
_ctxQueueSync = ((ICollection)_ctxQueue).SyncRoot; _contextQueueLock = ((ICollection)contextQueue).SyncRoot;
_ctxRegistry = new Dictionary<HttpListenerContext, HttpListenerContext>(); _contextRegistry = new Dictionary<HttpListenerContext, HttpListenerContext>();
_ctxRegistrySync = ((ICollection)_ctxRegistry).SyncRoot; _contextRegistryLock = ((ICollection)_contextRegistry).SyncRoot;
_prefixes = new HttpListenerPrefixCollection(this); _prefixes = new HttpListenerPrefixCollection(this);
_waitQueue = new List<HttpListenerAsyncResult>(); _waitQueue = new List<HttpListenerAsyncResult>();
_waitQueueSync = ((ICollection)_waitQueue).SyncRoot; _waitQueueLock = ((ICollection)_waitQueue).SyncRoot;
} }
internal bool IsDisposed { get; private set; } internal bool IsDisposed { get; private set; }
@ -154,12 +154,12 @@ namespace EonaCat.Network
} }
} }
public SSLConfigurationServer SslConfiguration public SSLConfigServer SslConfiguration
{ {
get get
{ {
CheckDisposed(); CheckDisposed();
return _sslConfig ??= new SSLConfigurationServer(); return _sslConfig ??= new SSLConfigServer();
} }
set set
@ -197,9 +197,9 @@ namespace EonaCat.Network
} }
} }
private void cleanupConnections() private void CleanupConnections()
{ {
HttpConnection[] conns = null; HttpConnection[] httpConnections = null;
lock (_connectionsSync) lock (_connectionsSync)
{ {
if (_connections.Count == 0) if (_connections.Count == 0)
@ -209,29 +209,29 @@ namespace EonaCat.Network
// Need to copy this since closing will call the RemoveConnection method. // Need to copy this since closing will call the RemoveConnection method.
var keys = _connections.Keys; var keys = _connections.Keys;
conns = new HttpConnection[keys.Count]; httpConnections = new HttpConnection[keys.Count];
keys.CopyTo(conns, 0); keys.CopyTo(httpConnections, 0);
_connections.Clear(); _connections.Clear();
} }
for (var i = conns.Length - 1; i >= 0; i--) for (var i = httpConnections.Length - 1; i >= 0; i--)
{ {
conns[i].Close(true); httpConnections[i].Close(true);
} }
} }
private void cleanupContextQueue(bool sendServiceUnavailable) private void CleanupContextQueue(bool sendServiceUnavailable)
{ {
HttpListenerContext[] ctxs = null; HttpListenerContext[] httpContextQueues = null;
lock (_ctxQueueSync) lock (_contextQueueLock)
{ {
if (_ctxQueue.Count == 0) if (contextQueue.Count == 0)
{ {
return; return;
} }
ctxs = _ctxQueue.ToArray(); httpContextQueues = contextQueue.ToArray();
_ctxQueue.Clear(); contextQueue.Clear();
} }
if (!sendServiceUnavailable) if (!sendServiceUnavailable)
@ -239,54 +239,54 @@ namespace EonaCat.Network
return; return;
} }
foreach (var ctx in ctxs) foreach (var currentContext in httpContextQueues)
{ {
var res = ctx.Response; var response = currentContext.Response;
res.StatusCode = (int)HttpStatusCode.ServiceUnavailable; response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
res.Close(); response.Close();
} }
} }
private void cleanupContextRegistry() private void CleanupContextRegistry()
{ {
HttpListenerContext[] ctxs = null; HttpListenerContext[] contexts = null;
lock (_ctxRegistrySync) lock (_contextRegistryLock)
{ {
if (_ctxRegistry.Count == 0) if (_contextRegistry.Count == 0)
{ {
return; return;
} }
// Need to copy this since closing will call the UnregisterContext method. // Need to copy this since closing will call the UnregisterContext method.
var keys = _ctxRegistry.Keys; var keys = _contextRegistry.Keys;
ctxs = new HttpListenerContext[keys.Count]; contexts = new HttpListenerContext[keys.Count];
keys.CopyTo(ctxs, 0); keys.CopyTo(contexts, 0);
_ctxRegistry.Clear(); _contextRegistry.Clear();
} }
for (var i = ctxs.Length - 1; i >= 0; i--) for (var i = contexts.Length - 1; i >= 0; i--)
{ {
ctxs[i].Connection.Close(true); contexts[i].Connection.Close(true);
} }
} }
private void cleanupWaitQueue(Exception exception) private void CleanupWaitQueue(Exception exception)
{ {
HttpListenerAsyncResult[] aress = null; HttpListenerAsyncResult[] results = null;
lock (_waitQueueSync) lock (_waitQueueLock)
{ {
if (_waitQueue.Count == 0) if (_waitQueue.Count == 0)
{ {
return; return;
} }
aress = _waitQueue.ToArray(); results = _waitQueue.ToArray();
_waitQueue.Clear(); _waitQueue.Clear();
} }
foreach (var ares in aress) foreach (var currentResult in results)
{ {
ares.Complete(exception); currentResult.Complete(exception);
} }
} }
@ -298,19 +298,19 @@ namespace EonaCat.Network
EndPointManager.RemoveListener(this); EndPointManager.RemoveListener(this);
} }
lock (_ctxRegistrySync) lock (_contextRegistryLock)
{ {
cleanupContextQueue(!force); CleanupContextQueue(!force);
} }
cleanupContextRegistry(); CleanupContextRegistry();
cleanupConnections(); CleanupConnections();
cleanupWaitQueue(new ObjectDisposedException(GetType().ToString())); CleanupWaitQueue(new ObjectDisposedException(GetType().ToString()));
IsDisposed = true; IsDisposed = true;
} }
private HttpListenerAsyncResult getAsyncResultFromQueue() private HttpListenerAsyncResult GetAsyncResultFromQueue()
{ {
if (_waitQueue.Count == 0) if (_waitQueue.Count == 0)
{ {
@ -323,15 +323,15 @@ namespace EonaCat.Network
return ares; return ares;
} }
private HttpListenerContext getContextFromQueue() private HttpListenerContext GetContextFromQueue()
{ {
if (_ctxQueue.Count == 0) if (contextQueue.Count == 0)
{ {
return null; return null;
} }
var ctx = _ctxQueue[0]; var ctx = contextQueue[0];
_ctxQueue.RemoveAt(0); contextQueue.RemoveAt(0);
return ctx; return ctx;
} }
@ -357,14 +357,14 @@ namespace EonaCat.Network
internal HttpListenerAsyncResult BeginGetContext(HttpListenerAsyncResult asyncResult) internal HttpListenerAsyncResult BeginGetContext(HttpListenerAsyncResult asyncResult)
{ {
lock (_ctxRegistrySync) lock (_contextRegistryLock)
{ {
if (!_listening) if (!_listening)
{ {
throw new HttpListenerException(995); throw new HttpListenerException(995);
} }
var ctx = getContextFromQueue(); var ctx = GetContextFromQueue();
if (ctx == null) if (ctx == null)
{ {
_waitQueue.Add(asyncResult); _waitQueue.Add(asyncResult);
@ -404,23 +404,23 @@ namespace EonaCat.Network
return false; return false;
} }
lock (_ctxRegistrySync) lock (_contextRegistryLock)
{ {
if (!_listening) if (!_listening)
{ {
return false; return false;
} }
_ctxRegistry[context] = context; _contextRegistry[context] = context;
var ares = getAsyncResultFromQueue(); var result = GetAsyncResultFromQueue();
if (ares == null) if (result == null)
{ {
_ctxQueue.Add(context); contextQueue.Add(context);
} }
else else
{ {
ares.Complete(context); result.Complete(context);
} }
return true; return true;
@ -455,9 +455,9 @@ namespace EonaCat.Network
internal void UnregisterContext(HttpListenerContext context) internal void UnregisterContext(HttpListenerContext context)
{ {
lock (_ctxRegistrySync) lock (_contextRegistryLock)
{ {
_ctxRegistry.Remove(context); _contextRegistry.Remove(context);
} }
} }
@ -522,23 +522,23 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(asyncResult)); throw new ArgumentNullException(nameof(asyncResult));
} }
if (asyncResult is not HttpListenerAsyncResult ares) if (asyncResult is not HttpListenerAsyncResult result)
{ {
throw new ArgumentException("A wrong IAsyncResult.", nameof(asyncResult)); throw new ArgumentException("A wrong IAsyncResult.", nameof(asyncResult));
} }
if (ares.EndCalled) if (result.EndCalled)
{ {
throw new InvalidOperationException("This IAsyncResult cannot be reused."); throw new InvalidOperationException("This IAsyncResult cannot be reused.");
} }
ares.EndCalled = true; result.EndCalled = true;
if (!ares.IsCompleted) if (!result.IsCompleted)
{ {
ares.AsyncWaitHandle.WaitOne(); result.AsyncWaitHandle.WaitOne();
} }
return ares.GetContext(); // This may throw an exception. return result.GetContext();
} }
/// <summary> /// <summary>
@ -558,10 +558,10 @@ namespace EonaCat.Network
throw new InvalidOperationException("The listener hasn't been started."); throw new InvalidOperationException("The listener hasn't been started.");
} }
var ares = BeginGetContext(new HttpListenerAsyncResult(null, null)); var result = BeginGetContext(new HttpListenerAsyncResult(null, null));
ares.InGet = true; result.InGet = true;
return EndGetContext(ares); return EndGetContext(result);
} }
/// <summary> /// <summary>
@ -593,14 +593,14 @@ namespace EonaCat.Network
_listening = false; _listening = false;
EndPointManager.RemoveListener(this); EndPointManager.RemoveListener(this);
lock (_ctxRegistrySync) lock (_contextRegistryLock)
{ {
cleanupContextQueue(true); CleanupContextQueue(true);
} }
cleanupContextRegistry(); CleanupContextRegistry();
cleanupConnections(); CleanupConnections();
cleanupWaitQueue(new HttpListenerException(995, "The listener is closed.")); CleanupWaitQueue(new HttpListenerException(995, "The listener is closed."));
} }
/// <summary> /// <summary>

View File

@ -86,10 +86,7 @@ namespace EonaCat.Network
asyncResult._completed = true; asyncResult._completed = true;
var waitHandle = asyncResult._waitHandle; var waitHandle = asyncResult._waitHandle;
if (waitHandle != null) waitHandle?.Set();
{
waitHandle.Set();
}
} }
var callback = asyncResult._callback; var callback = asyncResult._callback;

View File

@ -11,7 +11,7 @@ namespace EonaCat.Network
/// </summary> /// </summary>
public sealed class HttpListenerContext public sealed class HttpListenerContext
{ {
private HttpListenerWebSocketContext _websocketContext; private HttpListenerWSContext _websocketContext;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HttpListenerContext"/> class. /// Initializes a new instance of the <see cref="HttpListenerContext"/> class.
@ -124,8 +124,8 @@ namespace EonaCat.Network
/// Accepts a WebSocket connection with the specified protocol. /// Accepts a WebSocket connection with the specified protocol.
/// </summary> /// </summary>
/// <param name="protocol">The WebSocket subprotocol to negotiate.</param> /// <param name="protocol">The WebSocket subprotocol to negotiate.</param>
/// <returns>The <see cref="HttpListenerWebSocketContext"/> for the WebSocket connection.</returns> /// <returns>The <see cref="HttpListenerWSContext"/> for the WebSocket connection.</returns>
public HttpListenerWebSocketContext AcceptWebSocket(string protocol) public HttpListenerWSContext AcceptWebSocket(string protocol)
{ {
if (_websocketContext != null) if (_websocketContext != null)
{ {
@ -145,7 +145,7 @@ namespace EonaCat.Network
} }
} }
_websocketContext = new HttpListenerWebSocketContext(this, protocol); _websocketContext = new HttpListenerWSContext(this, protocol);
return _websocketContext; return _websocketContext;
} }
} }

View File

@ -251,8 +251,7 @@ namespace EonaCat.Network
if (lower == "content-length") if (lower == "content-length")
{ {
long len; if (long.TryParse(val, out long len) && len >= 0)
if (long.TryParse(val, out len) && len >= 0)
{ {
ContentLength64 = len; ContentLength64 = len;
_contentLengthSet = true; _contentLengthSet = true;
@ -359,13 +358,13 @@ namespace EonaCat.Network
{ {
try try
{ {
var ares = InputStream.BeginRead(buff, 0, len, null, null); var result = InputStream.BeginRead(buff, 0, len, null, null);
if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne(100)) if (!result.IsCompleted && !result.AsyncWaitHandle.WaitOne(100))
{ {
return false; return false;
} }
if (InputStream.EndRead(ares) <= 0) if (InputStream.EndRead(result) <= 0)
{ {
return true; return true;
} }

View File

@ -218,8 +218,7 @@ namespace EonaCat.Network
return; return;
} }
Uri uri = null; if (!value.MaybeUri() || !Uri.TryCreate(value, UriKind.Absolute, out Uri uri))
if (!value.MaybeUri() || !Uri.TryCreate(value, UriKind.Absolute, out uri))
{ {
throw new ArgumentException("Not an absolute URL.", nameof(value)); throw new ArgumentException("Not an absolute URL.", nameof(value));
} }
@ -405,10 +404,7 @@ namespace EonaCat.Network
if (templateResponse._headers != null) if (templateResponse._headers != null)
{ {
if (_headers != null) _headers?.Clear();
{
_headers.Clear();
}
Headers.Add(templateResponse._headers); Headers.Add(templateResponse._headers);
} }
@ -447,8 +443,7 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(url)); throw new ArgumentNullException(nameof(url));
} }
Uri uri = null; if (!url.MaybeUri() || !Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
if (!url.MaybeUri() || !Uri.TryCreate(url, UriKind.Absolute, out uri))
{ {
throw new ArgumentException("Not an absolute URL.", nameof(url)); throw new ArgumentException("Not an absolute URL.", nameof(url));
} }

View File

@ -9,7 +9,7 @@ namespace EonaCat.Network
internal class HttpStreamAsyncResult : IAsyncResult internal class HttpStreamAsyncResult : IAsyncResult
{ {
private readonly AsyncCallback _callback; private readonly AsyncCallback _callback;
private bool _completed; private bool _isCompleted;
private readonly object _sync; private readonly object _sync;
private ManualResetEvent _waitHandle; private ManualResetEvent _waitHandle;
@ -40,7 +40,7 @@ namespace EonaCat.Network
{ {
lock (_sync) lock (_sync)
{ {
return _waitHandle ??= new ManualResetEvent(_completed); return _waitHandle ??= new ManualResetEvent(_isCompleted);
} }
} }
} }
@ -53,7 +53,7 @@ namespace EonaCat.Network
{ {
lock (_sync) lock (_sync)
{ {
return _completed; return _isCompleted;
} }
} }
} }
@ -62,17 +62,14 @@ namespace EonaCat.Network
{ {
lock (_sync) lock (_sync)
{ {
if (_completed) if (_isCompleted)
{ {
return; return;
} }
_completed = true; _isCompleted = true;
if (_waitHandle != null) _waitHandle?.Set();
{
_waitHandle.Set();
}
_callback?.Invoke(this); _callback?.Invoke(this);
} }

View File

@ -71,7 +71,7 @@ namespace EonaCat.Network
{ {
if (_entities == null) if (_entities == null)
{ {
initEntities(); GenerateHtmlEntityRefrencesDictionary();
} }
return _entities; return _entities;
@ -90,10 +90,9 @@ namespace EonaCat.Network
: -1; : -1;
} }
private static void initEntities() private static void GenerateHtmlEntityRefrencesDictionary()
{ {
// Build the dictionary of HTML entity references. // Build the dictionary of HTML entity references.
// This list comes from the HTML 4.01 W3C recommendation.
_entities = new Dictionary<string, char> _entities = new Dictionary<string, char>
{ {
{ "nbsp", '\u00A0' }, { "nbsp", '\u00A0' },
@ -491,8 +490,7 @@ namespace EonaCat.Network
} }
else if (requestUri.MaybeUri()) else if (requestUri.MaybeUri())
{ {
Uri uri; var valid = Uri.TryCreate(requestUri, UriKind.Absolute, out Uri uri) &&
var valid = Uri.TryCreate(requestUri, UriKind.Absolute, out uri) &&
(((schm = uri.Scheme).StartsWith("http") && !websocketRequest) || (((schm = uri.Scheme).StartsWith("http") && !websocketRequest) ||
(schm.StartsWith("ws") && websocketRequest)); (schm.StartsWith("ws") && websocketRequest));
@ -523,8 +521,7 @@ namespace EonaCat.Network
var url = string.Format("{0}://{1}{2}", schm, host, path); var url = string.Format("{0}://{1}{2}", schm, host, path);
Uri res; if (!Uri.TryCreate(url, UriKind.Absolute, out Uri res))
if (!Uri.TryCreate(url, UriKind.Absolute, out res))
{ {
return null; return null;
} }

View File

@ -5,12 +5,24 @@ using System;
namespace EonaCat.Network namespace EonaCat.Network
{ {
/// <summary>
/// Represents HTTP versions.
/// </summary>
public class HttpVersion public class HttpVersion
{ {
/// <summary>
/// Gets the HTTP version 1.0.
/// </summary>
public static readonly Version Version10 = new Version(1, 0); public static readonly Version Version10 = new Version(1, 0);
/// <summary>
/// Gets the HTTP version 1.1.
/// </summary>
public static readonly Version Version11 = new Version(1, 1); public static readonly Version Version11 = new Version(1, 1);
/// <summary>
/// Initializes a new instance of the <see cref="HttpVersion"/> class.
/// </summary>
public HttpVersion() public HttpVersion()
{ {
} }

View File

@ -6,7 +6,15 @@ namespace EonaCat.Network
internal enum LineState internal enum LineState
{ {
None, None,
Cr,
Lf /// <summary>
/// Moves the cursor to the beginning of the current line
/// </summary>
CarriageReturn,
/// <summary>
/// Moves the cursor down to the next line and then to the beginning of the line
/// </summary>
LineFeed
} }
} }

View File

@ -8,24 +8,24 @@ using System.Security.Cryptography.X509Certificates;
namespace EonaCat.Network namespace EonaCat.Network
{ {
public class SSLConfigurationClient public class SSLConfigClient
{ {
private LocalCertificateSelectionCallback _clientCertSelectionCallback; private LocalCertificateSelectionCallback _clientCertSelectionCallback;
private X509CertificateCollection _clientCertificates; private X509CertificateCollection _clientCertificates;
private RemoteCertificateValidationCallback _serverCertValidationCallback; private RemoteCertificateValidationCallback _serverCertValidationCallback;
public SSLConfigurationClient() public SSLConfigClient()
{ {
SslProtocols = SslProtocols.Tls12; SslProtocols = SslProtocols.Tls12;
} }
public SSLConfigurationClient(string targetHost) public SSLConfigClient(string targetHost)
{ {
TargetHost = targetHost; TargetHost = targetHost;
SslProtocols = SslProtocols.Tls12; SslProtocols = SslProtocols.Tls12;
} }
public SSLConfigurationClient(SSLConfigurationClient configuration) public SSLConfigClient(SSLConfigClient configuration)
{ {
if (configuration == null) if (configuration == null)
{ {

View File

@ -8,22 +8,22 @@ using System.Security.Cryptography.X509Certificates;
namespace EonaCat.Network namespace EonaCat.Network
{ {
public class SSLConfigurationServer public class SSLConfigServer
{ {
private RemoteCertificateValidationCallback _clientCertValidationCallback; private RemoteCertificateValidationCallback _clientCertificationValidationCallback;
public SSLConfigurationServer() public SSLConfigServer()
{ {
SslProtocols = SslProtocols.Tls12; SslProtocols = SslProtocols.Tls12;
} }
public SSLConfigurationServer(X509Certificate2 certificate) public SSLConfigServer(X509Certificate2 certificate)
{ {
Certificate = certificate; Certificate = certificate;
SslProtocols = SslProtocols.Tls12; SslProtocols = SslProtocols.Tls12;
} }
public SSLConfigurationServer(SSLConfigurationServer configuration) public SSLConfigServer(SSLConfigServer configuration)
{ {
if (configuration == null) if (configuration == null)
{ {
@ -32,7 +32,7 @@ namespace EonaCat.Network
CheckForCertificateRevocation = configuration.CheckForCertificateRevocation; CheckForCertificateRevocation = configuration.CheckForCertificateRevocation;
IsClientCertificateRequired = configuration.IsClientCertificateRequired; IsClientCertificateRequired = configuration.IsClientCertificateRequired;
_clientCertValidationCallback = configuration._clientCertValidationCallback; _clientCertificationValidationCallback = configuration._clientCertificationValidationCallback;
SslProtocols = configuration.SslProtocols; SslProtocols = configuration.SslProtocols;
Certificate = configuration.Certificate; Certificate = configuration.Certificate;
} }
@ -45,14 +45,14 @@ namespace EonaCat.Network
{ {
get get
{ {
_clientCertValidationCallback ??= ValidateClientCertificate; _clientCertificationValidationCallback ??= ValidateClientCertificate;
return _clientCertValidationCallback; return _clientCertificationValidationCallback;
} }
set set
{ {
_clientCertValidationCallback = value; _clientCertificationValidationCallback = value;
} }
} }

View File

@ -54,7 +54,7 @@ namespace EonaCat.Network
// Returns 0 if we can keep reading from the base stream, // Returns 0 if we can keep reading from the base stream,
// > 0 if we read something from the buffer, // > 0 if we read something from the buffer,
// -1 if we had a content length set and we finished reading that many bytes. // -1 if we had a content length set and we finished reading that many bytes.
private int fillFromBuffer(byte[] buffer, int offset, int count) private int FillFromBuffer(byte[] buffer, int offset, int count)
{ {
if (buffer == null) if (buffer == null)
{ {
@ -71,8 +71,8 @@ namespace EonaCat.Network
throw new ArgumentOutOfRangeException(nameof(count), "A negative value."); throw new ArgumentOutOfRangeException(nameof(count), "A negative value.");
} }
var len = buffer.Length; var bufferLength = buffer.Length;
if (offset + count > len) if (offset + count > bufferLength)
{ {
throw new ArgumentException( throw new ArgumentException(
"The sum of 'offset' and 'count' is greater than 'buffer' length."); "The sum of 'offset' and 'count' is greater than 'buffer' length.");
@ -117,17 +117,16 @@ namespace EonaCat.Network
throw new ObjectDisposedException(GetType().ToString()); throw new ObjectDisposedException(GetType().ToString());
} }
var nread = fillFromBuffer(buffer, offset, count); var nread = FillFromBuffer(buffer, offset, count);
if (nread > 0 || nread == -1) if (nread > 0 || nread == -1)
{ {
var ares = new HttpStreamAsyncResult(callback, state); var result = new HttpStreamAsyncResult(callback, state);
ares.Buffer = buffer; result.Buffer = buffer;
ares.Offset = offset; result.Offset = offset;
ares.Count = count; result.Count = count;
ares.SyncRead = nread > 0 ? nread : 0; result.SyncRead = nread > 0 ? nread : 0;
ares.Complete(); result.Complete();
return result;
return ares;
} }
// Avoid reading past the end of the request to allow for HTTP pipelining. // Avoid reading past the end of the request to allow for HTTP pipelining.
@ -164,13 +163,13 @@ namespace EonaCat.Network
if (asyncResult is HttpStreamAsyncResult) if (asyncResult is HttpStreamAsyncResult)
{ {
var ares = (HttpStreamAsyncResult)asyncResult; var result = (HttpStreamAsyncResult)asyncResult;
if (!ares.IsCompleted) if (!result.IsCompleted)
{ {
ares.AsyncWaitHandle.WaitOne(); result.AsyncWaitHandle.WaitOne();
} }
return ares.SyncRead; return result.SyncRead;
} }
// Close on exception? // Close on exception?
@ -200,7 +199,7 @@ namespace EonaCat.Network
} }
// Call the fillFromBuffer method to check for buffer boundaries even when _bodyLeft is 0. // Call the fillFromBuffer method to check for buffer boundaries even when _bodyLeft is 0.
var nread = fillFromBuffer(buffer, offset, count); var nread = FillFromBuffer(buffer, offset, count);
if (nread == -1) // No more bytes available (Content-Length). if (nread == -1) // No more bytes available (Content-Length).
{ {
return 0; return 0;

View File

@ -11,24 +11,24 @@ namespace EonaCat.Network
private bool _dataSet; private bool _dataSet;
private readonly byte[] _rawData; private readonly byte[] _rawData;
internal MessageEventArgs(WebSocketFrame frame) internal MessageEventArgs(WSFrame frame)
{ {
Opcode = frame.Opcode; Opcode = frame.Opcode;
_rawData = frame.PayloadData.ApplicationData; _rawData = frame.PayloadData.ApplicationData;
} }
internal MessageEventArgs(Opcode opcode, byte[] rawData) internal MessageEventArgs(OperationCode opcode, byte[] rawData)
{ {
if ((ulong)rawData.LongLength > PayloadData.MaxLength) if ((ulong)rawData.LongLength > PayloadData.MaxLength)
{ {
throw new WebSocketException(CloseStatusCode.TooBig); throw new WSException(CloseStatusCode.TooBig);
} }
Opcode = opcode; Opcode = opcode;
_rawData = rawData; _rawData = rawData;
} }
internal Opcode Opcode { get; } internal OperationCode Opcode { get; }
public string Data public string Data
{ {
@ -39,11 +39,11 @@ namespace EonaCat.Network
} }
} }
public bool IsBinary => Opcode == Opcode.Binary; public bool IsBinary => Opcode == OperationCode.Binary;
public bool IsPing => Opcode == Opcode.Ping; public bool IsPing => Opcode == OperationCode.Ping;
public bool IsText => Opcode == Opcode.Text; public bool IsText => Opcode == OperationCode.Text;
public byte[] RawData public byte[] RawData
{ {
@ -61,7 +61,7 @@ namespace EonaCat.Network
return; return;
} }
if (Opcode == Opcode.Binary) if (Opcode == OperationCode.Binary)
{ {
_dataSet = true; _dataSet = true;
return; return;

View File

@ -406,9 +406,9 @@ namespace EonaCat.Network
return opcode > 0x7 && opcode < 0x10; return opcode > 0x7 && opcode < 0x10;
} }
internal static bool IsControl(this Opcode opcode) internal static bool IsControl(this OperationCode opcode)
{ {
return opcode >= Opcode.Close; return opcode >= OperationCode.Close;
} }
internal static bool IsData(this byte opcode) internal static bool IsData(this byte opcode)
@ -416,9 +416,9 @@ namespace EonaCat.Network
return opcode == 0x1 || opcode == 0x2; return opcode == 0x1 || opcode == 0x2;
} }
internal static bool IsData(this Opcode opcode) internal static bool IsData(this OperationCode opcode)
{ {
return opcode == Opcode.Text || opcode == Opcode.Binary; return opcode == OperationCode.Text || opcode == OperationCode.Binary;
} }
internal static bool IsPortNumber(this int value) internal static bool IsPortNumber(this int value)
@ -428,10 +428,10 @@ namespace EonaCat.Network
internal static bool IsReserved(this ushort code) internal static bool IsReserved(this ushort code)
{ {
return code == 1004 return code == (ushort)CloseStatusCode.Undefined
|| code == 1005 || code == (ushort)CloseStatusCode.NoStatus
|| code == 1006 || code == (ushort)CloseStatusCode.Abnormal
|| code == 1015; || code == (ushort)CloseStatusCode.TlsHandshakeFailure;
} }
internal static bool IsReserved(this CloseStatusCode code) internal static bool IsReserved(this CloseStatusCode code)
@ -444,7 +444,7 @@ namespace EonaCat.Network
internal static bool IsSupported(this byte opcode) internal static bool IsSupported(this byte opcode)
{ {
return Enum.IsDefined(typeof(Opcode), opcode); return Enum.IsDefined(typeof(OperationCode), opcode);
} }
internal static bool IsText(this string value) internal static bool IsText(this string value)
@ -855,8 +855,7 @@ namespace EonaCat.Network
return null; return null;
} }
System.Net.IPAddress addr; if (System.Net.IPAddress.TryParse(value, out System.Net.IPAddress addr))
if (System.Net.IPAddress.TryParse(value, out addr))
{ {
return addr; return addr;
} }
@ -1542,7 +1541,7 @@ namespace EonaCat.Network
? BitConverter.GetBytes((uint)(object)value) ? BitConverter.GetBytes((uint)(object)value)
: type == typeof(ulong) : type == typeof(ulong)
? BitConverter.GetBytes((ulong)(object)value) ? BitConverter.GetBytes((ulong)(object)value)
: WebSocket.EmptyBytes; : WSClient.EmptyBytes;
if (bytes.Length > 1 && !order.IsHostOrder()) if (bytes.Length > 1 && !order.IsHostOrder())
{ {
@ -1586,9 +1585,8 @@ namespace EonaCat.Network
public static Uri ToUri(this string value) public static Uri ToUri(this string value)
{ {
Uri ret;
Uri.TryCreate( Uri.TryCreate(
value, value.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out ret value, value.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out Uri ret
); );
return ret; return ret;

View File

@ -3,7 +3,7 @@
namespace EonaCat.Network namespace EonaCat.Network
{ {
internal enum Opcode : byte internal enum OperationCode : byte
{ {
Cont = 0x0, Cont = 0x0,

View File

@ -28,10 +28,10 @@ namespace EonaCat.Network
internal PayloadData() internal PayloadData()
{ {
_code = 1005; _code = (ushort)CloseStatusCode.NoStatus;
_reason = string.Empty; _reason = string.Empty;
_data = WebSocket.EmptyBytes; _data = WSClient.EmptyBytes;
_codeSet = true; _codeSet = true;
_reasonSet = true; _reasonSet = true;
@ -68,7 +68,7 @@ namespace EonaCat.Network
{ {
_code = _length > 1 _code = _length > 1
? _data.SubArray(0, 2).ToUInt16(ByteOrder.Big) ? _data.SubArray(0, 2).ToUInt16(ByteOrder.Big)
: (ushort)1005; : (ushort)CloseStatusCode.NoStatus;
_codeSet = true; _codeSet = true;
} }
@ -104,7 +104,7 @@ namespace EonaCat.Network
public byte[] ExtensionData => ExtensionDataLength > 0 public byte[] ExtensionData => ExtensionDataLength > 0
? _data.SubArray(0, ExtensionDataLength) ? _data.SubArray(0, ExtensionDataLength)
: WebSocket.EmptyBytes; : WSClient.EmptyBytes;
public ulong Length => (ulong)_length; public ulong Length => (ulong)_length;

View File

@ -74,8 +74,7 @@ namespace EonaCat.Network
throw new ArgumentException("It contains '..'.", nameof(path)); throw new ArgumentException("It contains '..'.", nameof(path));
} }
byte[] contents; tryReadFile(createFilePath(path), out byte[] contents);
tryReadFile(createFilePath(path), out contents);
return contents; return contents;
} }

View File

@ -40,11 +40,9 @@ namespace EonaCat.Network
throw new ArgumentException("An empty string.", nameof(url)); throw new ArgumentException("An empty string.", nameof(url));
} }
Uri uri; if (!tryCreateUri(url, out Uri uri, out string message))
string msg;
if (!tryCreateUri(url, out uri, out msg))
{ {
throw new ArgumentException(msg, nameof(url)); throw new ArgumentException(message, nameof(url));
} }
var host = uri.GetDnsSafeHost(true); var host = uri.GetDnsSafeHost(true);
@ -52,14 +50,14 @@ namespace EonaCat.Network
var addr = host.ToIPAddress(); var addr = host.ToIPAddress();
if (addr == null) if (addr == null)
{ {
msg = "The host part could not be converted to an IP address."; message = "The host part could not be converted to an IP address.";
throw new ArgumentException(msg, nameof(url)); throw new ArgumentException(message, nameof(url));
} }
if (!addr.IsLocal()) if (!addr.IsLocal())
{ {
msg = "The IP address of the host is not a local IP address."; message = "The IP address of the host is not a local IP address.";
throw new ArgumentException(msg, nameof(url)); throw new ArgumentException(message, nameof(url));
} }
init(host, addr, uri.Port, uri.Scheme == "https"); init(host, addr, uri.Port, uri.Scheme == "https");
@ -69,8 +67,8 @@ namespace EonaCat.Network
{ {
if (!port.IsPortNumber()) if (!port.IsPortNumber())
{ {
var msg = "Less than 1 or greater than 65535."; var message = "Less than 1 or greater than 65535.";
throw new ArgumentOutOfRangeException(nameof(port), msg); throw new ArgumentOutOfRangeException(nameof(port), message);
} }
init("*", System.Net.IPAddress.Any, port, secure); init("*", System.Net.IPAddress.Any, port, secure);
@ -95,8 +93,8 @@ namespace EonaCat.Network
if (!port.IsPortNumber()) if (!port.IsPortNumber())
{ {
var msg = "Less than 1 or greater than 65535."; var message = "Less than 1 or greater than 65535.";
throw new ArgumentOutOfRangeException(nameof(port), msg); throw new ArgumentOutOfRangeException(nameof(port), message);
} }
init(address.ToString(true), address, port, secure); init(address.ToString(true), address, port, secure);
@ -113,18 +111,17 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!canSet(out string message))
if (!canSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!canSet(out msg)) if (!canSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -190,18 +187,17 @@ namespace EonaCat.Network
throw new ArgumentException("An absolute root.", nameof(value)); throw new ArgumentException("An absolute root.", nameof(value));
} }
string msg; if (!canSet(out string message))
if (!canSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!canSet(out msg)) if (!canSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -240,18 +236,17 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!canSet(out string message))
if (!canSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!canSet(out msg)) if (!canSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -269,18 +264,17 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!canSet(out string message))
if (!canSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!canSet(out msg)) if (!canSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -289,14 +283,14 @@ namespace EonaCat.Network
} }
} }
public SSLConfigurationServer SslConfiguration public SSLConfigServer SslConfiguration
{ {
get get
{ {
if (!IsSecure) if (!IsSecure)
{ {
var msg = "This instance does not provide secure connections."; var message = "This instance does not provide secure connections.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
return _listener.SslConfiguration; return _listener.SslConfiguration;
@ -312,18 +306,17 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!canSet(out string message))
if (!canSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!canSet(out msg)) if (!canSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -381,7 +374,7 @@ namespace EonaCat.Network
{ {
try try
{ {
WebSocketServices.Stop(1006, string.Empty); WebSocketServices.Stop((ushort)CloseStatusCode.Abnormal, string.Empty);
} }
finally finally
{ {
@ -440,15 +433,6 @@ namespace EonaCat.Network
return true; return true;
} }
private string createFilePath(string childPath)
{
childPath = childPath.TrimStart('/', '\\');
return new StringBuilder(_docRootPath, 32)
.AppendFormat("/{0}", childPath)
.ToString()
.Replace('\\', '/');
}
private static HttpListener createListener( private static HttpListener createListener(
string hostname, int port, bool secure string hostname, int port, bool secure
) )
@ -512,12 +496,11 @@ namespace EonaCat.Network
context.Response.Close(); context.Response.Close();
} }
private void processRequest(HttpListenerWebSocketContext context) private void processRequest(HttpListenerWSContext context)
{ {
var path = context.RequestUri.AbsolutePath; var path = context.RequestUri.AbsolutePath;
WSEndpointHost host; if (!WebSocketServices.InternalTryGetServiceHost(path, out WSEndpointHost host))
if (!WebSocketServices.InternalTryGetServiceHost(path, out host))
{ {
context.Close(HttpStatusCode.NotImplemented); context.Close(HttpStatusCode.NotImplemented);
return; return;
@ -572,10 +555,7 @@ namespace EonaCat.Network
Logger.Error(ex.Message); Logger.Error(ex.Message);
Logger.Debug(ex.ToString()); Logger.Debug(ex.ToString());
if (ctx != null) ctx?.Connection.Close(true);
{
ctx.Connection.Close(true);
}
break; break;
} }
@ -623,7 +603,7 @@ namespace EonaCat.Network
} }
catch catch
{ {
WebSocketServices.Stop(1011, string.Empty); WebSocketServices.Stop((ushort)CloseStatusCode.ServerError, string.Empty);
throw; throw;
} }
@ -637,10 +617,10 @@ namespace EonaCat.Network
{ {
_listener.Start(); _listener.Start();
} }
catch (Exception ex) catch (Exception exception)
{ {
var msg = "The underlying listener has failed to start."; var message = "The underlying listener has failed to start.";
throw new InvalidOperationException(msg, ex); throw new InvalidOperationException(message, exception);
} }
_receiveThread = new Thread(new ThreadStart(receiveRequest)); _receiveThread = new Thread(new ThreadStart(receiveRequest));
@ -650,7 +630,7 @@ namespace EonaCat.Network
private void stop(ushort code, string reason) private void stop(ushort code, string reason)
{ {
if (_state == ServerState.Ready) if (_state == ServerState.Started)
{ {
Logger.Info("The server is not started."); Logger.Info("The server is not started.");
return; return;
@ -796,10 +776,9 @@ namespace EonaCat.Network
{ {
if (IsSecure) if (IsSecure)
{ {
string msg; if (!checkCertificate(out string message))
if (!checkCertificate(out msg))
{ {
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
} }
@ -808,42 +787,41 @@ namespace EonaCat.Network
public void Stop() public void Stop()
{ {
stop(1005, string.Empty); stop((ushort)CloseStatusCode.NoStatus, string.Empty);
} }
public void Stop(ushort code, string reason) public void Stop(ushort code, string reason)
{ {
if (!code.IsCloseStatusCode()) if (!code.IsCloseStatusCode())
{ {
var msg = "Less than 1000 or greater than 4999."; var message = "Less than 1000 or greater than 4999.";
throw new ArgumentOutOfRangeException(nameof(code), msg); throw new ArgumentOutOfRangeException(nameof(code), message);
} }
if (code == 1010) if (code == (ushort)CloseStatusCode.MandatoryExtension)
{ {
var msg = "1010 cannot be used."; var message = $"{(ushort)CloseStatusCode.MandatoryExtension} cannot be used.";
throw new ArgumentException(msg, nameof(code)); throw new ArgumentException(message, nameof(code));
} }
if (!reason.IsNullOrEmpty()) if (!reason.IsNullOrEmpty())
{ {
if (code == 1005) if (code == (ushort)CloseStatusCode.NoStatus)
{ {
var msg = "1005 cannot be used."; var message = $"{(ushort)CloseStatusCode.NoStatus} cannot be used.";
throw new ArgumentException(msg, nameof(code)); throw new ArgumentException(message, nameof(code));
} }
byte[] bytes; if (!reason.TryGetUTF8EncodedBytes(out byte[] bytes))
if (!reason.TryGetUTF8EncodedBytes(out bytes))
{ {
var msg = "It could not be UTF-8-encoded."; var message = "It could not be UTF-8-encoded.";
throw new ArgumentException(msg, nameof(reason)); throw new ArgumentException(message, nameof(reason));
} }
if (bytes.Length > 123) if (bytes.Length > 123)
{ {
var msg = "Its size is greater than 123 bytes."; var message = "Its size is greater than 123 bytes.";
throw new ArgumentOutOfRangeException(nameof(reason), msg); throw new ArgumentOutOfRangeException(nameof(reason), message);
} }
} }
@ -854,29 +832,28 @@ namespace EonaCat.Network
{ {
if (code == CloseStatusCode.MandatoryExtension) if (code == CloseStatusCode.MandatoryExtension)
{ {
var msg = "MandatoryExtension cannot be used."; var message = "MandatoryExtension cannot be used.";
throw new ArgumentException(msg, nameof(code)); throw new ArgumentException(message, nameof(code));
} }
if (!reason.IsNullOrEmpty()) if (!reason.IsNullOrEmpty())
{ {
if (code == CloseStatusCode.NoStatus) if (code == CloseStatusCode.NoStatus)
{ {
var msg = "NoStatus cannot be used."; var message = "NoStatus cannot be used.";
throw new ArgumentException(msg, nameof(code)); throw new ArgumentException(message, nameof(code));
} }
byte[] bytes; if (!reason.TryGetUTF8EncodedBytes(out byte[] bytes))
if (!reason.TryGetUTF8EncodedBytes(out bytes))
{ {
var msg = "It could not be UTF-8-encoded."; var message = "It could not be UTF-8-encoded.";
throw new ArgumentException(msg, nameof(reason)); throw new ArgumentException(message, nameof(reason));
} }
if (bytes.Length > 123) if (bytes.Length > 123)
{ {
var msg = "Its size is greater than 123 bytes."; var message = "Its size is greater than 123 bytes.";
throw new ArgumentOutOfRangeException(nameof(reason), msg); throw new ArgumentOutOfRangeException(nameof(reason), message);
} }
} }

View File

@ -7,7 +7,7 @@ namespace EonaCat.Network
{ {
public interface IWSSession public interface IWSSession
{ {
WebSocketContext Context { get; } WSContext Context { get; }
string ID { get; } string ID { get; }
@ -15,6 +15,6 @@ namespace EonaCat.Network
DateTime StartTime { get; } DateTime StartTime { get; }
WebSocketState State { get; } WSState State { get; }
} }
} }

View File

@ -5,7 +5,7 @@ namespace EonaCat.Network
{ {
internal enum ServerState internal enum ServerState
{ {
Ready, Started,
Start, Start,
ShuttingDown, ShuttingDown,
Stop Stop

View File

@ -10,7 +10,7 @@ namespace EonaCat.Network
{ {
private bool _emitOnPing; private bool _emitOnPing;
private string _protocol; private string _protocol;
private WebSocket _websocket; private WSClient _websocket;
protected WSEndpoint() protected WSEndpoint()
{ {
@ -19,7 +19,7 @@ namespace EonaCat.Network
protected WSSessionManager Sessions { get; private set; } protected WSSessionManager Sessions { get; private set; }
public WebSocketContext Context { get; private set; } public WSContext Context { get; private set; }
public Func<CookieCollection, CookieCollection, bool> CookiesValidator { get; set; } public Func<CookieCollection, CookieCollection, bool> CookiesValidator { get; set; }
@ -57,7 +57,7 @@ namespace EonaCat.Network
set set
{ {
if (State != WebSocketState.Connecting) if (State != WSState.Connecting)
{ {
return; return;
} }
@ -73,9 +73,9 @@ namespace EonaCat.Network
public DateTime StartTime { get; private set; } public DateTime StartTime { get; private set; }
public WebSocketState State => _websocket != null ? _websocket.ReadyState : WebSocketState.Connecting; public WSState State => _websocket != null ? _websocket.ReadyState : WSState.Connecting;
private string checkHandshakeRequest(WebSocketContext context) private string checkHandshakeRequest(WSContext context)
{ {
return OriginValidator != null && !OriginValidator(context.Origin) return OriginValidator != null && !OriginValidator(context.Origin)
? "Includes no Origin header, or it has an invalid value." ? "Includes no Origin header, or it has an invalid value."
@ -119,7 +119,7 @@ namespace EonaCat.Network
OnOpen(); OnOpen();
} }
internal void Start(WebSocketContext context, WSSessionManager sessions) internal void Start(WSContext context, WSSessionManager sessions)
{ {
if (_websocket != null) if (_websocket != null)
{ {
@ -178,58 +178,37 @@ namespace EonaCat.Network
protected void Send(byte[] data) protected void Send(byte[] data)
{ {
if (_websocket != null) _websocket?.Send(data);
{
_websocket.Send(data);
}
} }
protected void Send(FileInfo file) protected void Send(FileInfo file)
{ {
if (_websocket != null) _websocket?.Send(file);
{
_websocket.Send(file);
}
} }
protected void Send(string data) protected void Send(string data)
{ {
if (_websocket != null) _websocket?.Send(data);
{
_websocket.Send(data);
}
} }
protected void SendAsync(byte[] data, Action<bool> completed) protected void SendAsync(byte[] data, Action<bool> completed)
{ {
if (_websocket != null) _websocket?.SendAsync(data, completed);
{
_websocket.SendAsync(data, completed);
}
} }
protected void SendAsync(FileInfo file, Action<bool> completed) protected void SendAsync(FileInfo file, Action<bool> completed)
{ {
if (_websocket != null) _websocket?.SendAsync(file, completed);
{
_websocket.SendAsync(file, completed);
}
} }
protected void SendAsync(string data, Action<bool> completed) protected void SendAsync(string data, Action<bool> completed)
{ {
if (_websocket != null) _websocket?.SendAsync(data, completed);
{
_websocket.SendAsync(data, completed);
}
} }
protected void SendAsync(Stream stream, int length, Action<bool> completed) protected void SendAsync(Stream stream, int length, Action<bool> completed)
{ {
if (_websocket != null) _websocket?.SendAsync(stream, length, completed);
{
_websocket.SendAsync(stream, length, completed);
}
} }
} }
} }

View File

@ -52,7 +52,7 @@ namespace EonaCat.Network
Sessions.Start(); Sessions.Start();
} }
internal void StartSession(WebSocketContext context) internal void StartSession(WSContext context)
{ {
CreateSession().Start(context, Sessions); CreateSession().Start(context, Sessions);
} }

View File

@ -21,7 +21,7 @@ namespace EonaCat.Network
{ {
_clean = true; _clean = true;
_hosts = new Dictionary<string, WSEndpointHost>(); _hosts = new Dictionary<string, WSEndpointHost>();
_state = ServerState.Ready; _state = ServerState.Started;
_sync = ((ICollection)_hosts).SyncRoot; _sync = ((ICollection)_hosts).SyncRoot;
_waitTime = TimeSpan.FromSeconds(1); _waitTime = TimeSpan.FromSeconds(1);
} }
@ -69,12 +69,11 @@ namespace EonaCat.Network
if (path.IndexOfAny(new[] { '?', '#' }) > -1) if (path.IndexOfAny(new[] { '?', '#' }) > -1)
{ {
var msg = "It includes either or both query and fragment components."; var message = "It includes either or both query and fragment components.";
throw new ArgumentException(msg, nameof(path)); throw new ArgumentException(message, nameof(path));
} }
WSEndpointHost host; InternalTryGetServiceHost(path, out WSEndpointHost host);
InternalTryGetServiceHost(path, out host);
return host; return host;
} }
@ -89,18 +88,17 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!canSet(out string message))
if (!canSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!canSet(out msg)) if (!canSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -139,18 +137,17 @@ namespace EonaCat.Network
throw new ArgumentOutOfRangeException(nameof(value), "Zero or less."); throw new ArgumentOutOfRangeException(nameof(value), "Zero or less.");
} }
string msg; if (!canSet(out string message))
if (!canSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!canSet(out msg)) if (!canSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -164,7 +161,7 @@ namespace EonaCat.Network
} }
} }
private void broadcast(Opcode opcode, byte[] data, Action completed) private void broadcast(OperationCode opcode, byte[] data, Action completed)
{ {
var cache = new Dictionary<CompressionMethod, byte[]>(); var cache = new Dictionary<CompressionMethod, byte[]>();
@ -196,7 +193,7 @@ namespace EonaCat.Network
} }
} }
private void broadcast(Opcode opcode, Stream stream, Action completed) private void broadcast(OperationCode opcode, Stream stream, Action completed)
{ {
var cache = new Dictionary<CompressionMethod, Stream>(); var cache = new Dictionary<CompressionMethod, Stream>();
@ -233,41 +230,6 @@ namespace EonaCat.Network
} }
} }
private void broadcastAsync(Opcode opcode, byte[] data, Action completed)
{
ThreadPool.QueueUserWorkItem(
state => broadcast(opcode, data, completed)
);
}
private void broadcastAsync(Opcode opcode, Stream stream, Action completed)
{
ThreadPool.QueueUserWorkItem(
state => broadcast(opcode, stream, completed)
);
}
private Dictionary<string, Dictionary<string, bool>> broadping(
byte[] frameAsBytes, TimeSpan timeout
)
{
var ret = new Dictionary<string, Dictionary<string, bool>>();
foreach (var host in Hosts)
{
if (_state != ServerState.Start)
{
Logger.Error("The server is shutting down.");
break;
}
var res = host.Sessions.Broadping(frameAsBytes, timeout);
ret.Add(host.Path, res);
}
return ret;
}
private bool canSet(out string message) private bool canSet(out string message)
{ {
message = null; message = null;
@ -294,8 +256,7 @@ namespace EonaCat.Network
lock (_sync) lock (_sync)
{ {
WSEndpointHost host; if (_hosts.TryGetValue(path, out WSEndpointHost host))
if (_hosts.TryGetValue(path, out host))
{ {
throw new ArgumentException("Already in use.", nameof(path)); throw new ArgumentException("Already in use.", nameof(path));
} }
@ -385,16 +346,15 @@ namespace EonaCat.Network
if (path.IndexOfAny(new[] { '?', '#' }) > -1) if (path.IndexOfAny(new[] { '?', '#' }) > -1)
{ {
var msg = "It includes either or both query and fragment components."; var message = "It includes either or both query and fragment components.";
throw new ArgumentException(msg, nameof(path)); throw new ArgumentException(message, nameof(path));
} }
path = HttpUtility.UrlDecode(path).TrimSlashFromEnd(); path = HttpUtility.UrlDecode(path).TrimSlashFromEnd();
lock (_sync) lock (_sync)
{ {
WSEndpointHost host; if (_hosts.TryGetValue(path, out WSEndpointHost host))
if (_hosts.TryGetValue(path, out host))
{ {
throw new ArgumentException("Already in use.", nameof(path)); throw new ArgumentException("Already in use.", nameof(path));
} }
@ -436,7 +396,7 @@ namespace EonaCat.Network
{ {
if (host.State == ServerState.Start) if (host.State == ServerState.Start)
{ {
host.Stop(1001, string.Empty); host.Stop((ushort)CloseStatusCode.Away, string.Empty);
} }
} }
} }
@ -460,8 +420,8 @@ namespace EonaCat.Network
if (path.IndexOfAny(new[] { '?', '#' }) > -1) if (path.IndexOfAny(new[] { '?', '#' }) > -1)
{ {
var msg = "It includes either or both query and fragment components."; var message = "It includes either or both query and fragment components.";
throw new ArgumentException(msg, nameof(path)); throw new ArgumentException(message, nameof(path));
} }
path = HttpUtility.UrlDecode(path).TrimSlashFromEnd(); path = HttpUtility.UrlDecode(path).TrimSlashFromEnd();
@ -479,7 +439,7 @@ namespace EonaCat.Network
if (host.State == ServerState.Start) if (host.State == ServerState.Start)
{ {
host.Stop(1001, string.Empty); host.Stop((ushort)CloseStatusCode.Away, string.Empty);
} }
return true; return true;
@ -504,8 +464,8 @@ namespace EonaCat.Network
if (path.IndexOfAny(new[] { '?', '#' }) > -1) if (path.IndexOfAny(new[] { '?', '#' }) > -1)
{ {
var msg = "It includes either or both query and fragment components."; var message = "It includes either or both query and fragment components.";
throw new ArgumentException(msg, nameof(path)); throw new ArgumentException(message, nameof(path));
} }
return InternalTryGetServiceHost(path, out host); return InternalTryGetServiceHost(path, out host);

View File

@ -22,8 +22,8 @@ namespace EonaCat.Network
private string _realmInUse; private string _realmInUse;
private Thread _receiveThread; private Thread _receiveThread;
private bool _reuseAddress; private bool _reuseAddress;
private SSLConfigurationServer _sslConfig; private SSLConfigServer _sslConfig;
private SSLConfigurationServer _sslConfigInUse; private SSLConfigServer _sslConfigInUse;
private volatile ServerState _state; private volatile ServerState _state;
private object _sync; private object _sync;
private Func<IIdentity, NetworkCredential> _userCredentialsFinder; private Func<IIdentity, NetworkCredential> _userCredentialsFinder;
@ -56,11 +56,9 @@ namespace EonaCat.Network
throw new ArgumentException("An empty string.", nameof(url)); throw new ArgumentException("An empty string.", nameof(url));
} }
Uri uri; if (!tryCreateUri(url, out Uri uri, out string message))
string msg;
if (!tryCreateUri(url, out uri, out msg))
{ {
throw new ArgumentException(msg, nameof(url)); throw new ArgumentException(message, nameof(url));
} }
var host = uri.DnsSafeHost; var host = uri.DnsSafeHost;
@ -68,14 +66,14 @@ namespace EonaCat.Network
var addr = host.ToIPAddress(); var addr = host.ToIPAddress();
if (addr == null) if (addr == null)
{ {
msg = "The host part could not be converted to an IP address."; message = "The host part could not be converted to an IP address.";
throw new ArgumentException(msg, nameof(url)); throw new ArgumentException(message, nameof(url));
} }
if (!addr.IsLocal()) if (!addr.IsLocal())
{ {
msg = "The IP address of the host is not a local IP address."; message = "The IP address of the host is not a local IP address.";
throw new ArgumentException(msg, nameof(url)); throw new ArgumentException(message, nameof(url));
} }
init(host, addr, uri.Port, uri.Scheme == "wss"); init(host, addr, uri.Port, uri.Scheme == "wss");
@ -85,8 +83,8 @@ namespace EonaCat.Network
{ {
if (!port.IsPortNumber()) if (!port.IsPortNumber())
{ {
var msg = "Less than 1 or greater than 65535."; var message = "Less than 1 or greater than 65535.";
throw new ArgumentOutOfRangeException(nameof(port), msg); throw new ArgumentOutOfRangeException(nameof(port), message);
} }
var addr = System.Net.IPAddress.Any; var addr = System.Net.IPAddress.Any;
@ -112,8 +110,8 @@ namespace EonaCat.Network
if (!port.IsPortNumber()) if (!port.IsPortNumber())
{ {
var msg = "Less than 1 or greater than 65535."; var message = "Less than 1 or greater than 65535.";
throw new ArgumentOutOfRangeException(nameof(port), msg); throw new ArgumentOutOfRangeException(nameof(port), message);
} }
init(address.ToString(), address, port, secure); init(address.ToString(), address, port, secure);
@ -130,18 +128,17 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!CanSet(out string message))
if (!CanSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!CanSet(out msg)) if (!CanSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -159,18 +156,17 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!CanSet(out string message))
if (!CanSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!CanSet(out msg)) if (!CanSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -210,18 +206,17 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!CanSet(out string message))
if (!CanSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!CanSet(out msg)) if (!CanSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -239,18 +234,17 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!CanSet(out string message))
if (!CanSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!CanSet(out msg)) if (!CanSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -259,14 +253,14 @@ namespace EonaCat.Network
} }
} }
public SSLConfigurationServer SslConfiguration public SSLConfigServer SslConfiguration
{ {
get get
{ {
if (!IsSecure) if (!IsSecure)
{ {
var msg = "This instance does not provide secure connections."; var message = "This instance does not provide secure connections.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
return GetSslConfiguration(); return GetSslConfiguration();
@ -282,8 +276,7 @@ namespace EonaCat.Network
set set
{ {
string message; if (!CanSet(out string message))
if (!CanSet(out message))
{ {
Logger.Warning(message); Logger.Warning(message);
return; return;
@ -337,7 +330,7 @@ namespace EonaCat.Network
} }
finally finally
{ {
Endpoints.Stop(1006, string.Empty); Endpoints.Stop((ushort)CloseStatusCode.Abnormal, string.Empty);
} }
} }
catch catch
@ -374,7 +367,7 @@ namespace EonaCat.Network
} }
private static bool CheckSslConfiguration( private static bool CheckSslConfiguration(
SSLConfigurationServer configuration, out string message SSLConfigServer configuration, out string message
) )
{ {
message = null; message = null;
@ -394,9 +387,9 @@ namespace EonaCat.Network
return realm != null && realm.Length > 0 ? realm : _defaultRealm; return realm != null && realm.Length > 0 ? realm : _defaultRealm;
} }
private SSLConfigurationServer GetSslConfiguration() private SSLConfigServer GetSslConfiguration()
{ {
_sslConfig ??= new SSLConfigurationServer(); _sslConfig ??= new SSLConfigServer();
return _sslConfig; return _sslConfig;
} }
@ -417,7 +410,7 @@ namespace EonaCat.Network
_sync = new object(); _sync = new object();
} }
private void processRequest(TcpListenerWebSocketContext context) private void processRequest(TcpListenerWSContext context)
{ {
var uri = context.RequestUri; var uri = context.RequestUri;
if (uri == null) if (uri == null)
@ -441,8 +434,7 @@ namespace EonaCat.Network
} }
} }
WSEndpointHost host; if (!Endpoints.InternalTryGetServiceHost(uri.AbsolutePath, out WSEndpointHost host))
if (!Endpoints.InternalTryGetServiceHost(uri.AbsolutePath, out host))
{ {
context.Close(HttpStatusCode.NotImplemented); context.Close(HttpStatusCode.NotImplemented);
return; return;
@ -464,7 +456,7 @@ namespace EonaCat.Network
{ {
try try
{ {
var ctx = new TcpListenerWebSocketContext( var ctx = new TcpListenerWSContext(
cl, null, IsSecure, _sslConfigInUse); cl, null, IsSecure, _sslConfigInUse);
if (!ctx.Authenticate(_authSchemes, _realmInUse, _userCredentialsFinder)) if (!ctx.Authenticate(_authSchemes, _realmInUse, _userCredentialsFinder))
@ -502,10 +494,7 @@ namespace EonaCat.Network
Logger.Error(ex.Message); Logger.Error(ex.Message);
Logger.Debug(ex.ToString()); Logger.Debug(ex.ToString());
if (cl != null) cl?.Close();
{
cl.Close();
}
break; break;
} }
@ -517,7 +506,7 @@ namespace EonaCat.Network
} }
} }
private void start(SSLConfigurationServer sslConfig) private void start(SSLConfigServer sslConfig)
{ {
Logger.IsLoggingEnabled = IsLoggingEnabled; Logger.IsLoggingEnabled = IsLoggingEnabled;
Logger.DisableConsole = !IsConsoleLoggingEnabled; Logger.DisableConsole = !IsConsoleLoggingEnabled;
@ -558,7 +547,7 @@ namespace EonaCat.Network
} }
catch catch
{ {
Endpoints.Stop(1011, string.Empty); Endpoints.Stop((ushort)CloseStatusCode.ServerError, string.Empty);
throw; throw;
} }
@ -581,8 +570,8 @@ namespace EonaCat.Network
} }
catch (Exception ex) catch (Exception ex)
{ {
var msg = "The underlying listener has failed to start."; var message = "The underlying listener has failed to start.";
throw new InvalidOperationException(msg, ex); throw new InvalidOperationException(message, ex);
} }
_receiveThread = new Thread(new ThreadStart(receiveRequest)); _receiveThread = new Thread(new ThreadStart(receiveRequest));
@ -592,7 +581,7 @@ namespace EonaCat.Network
private void stop(ushort code, string reason) private void stop(ushort code, string reason)
{ {
if (_state == ServerState.Ready) if (_state == ServerState.Started)
{ {
Logger.Info("The server is not started."); Logger.Info("The server is not started.");
return; return;
@ -668,8 +657,8 @@ namespace EonaCat.Network
} }
catch (Exception ex) catch (Exception ex)
{ {
var msg = "The underlying listener has failed to stop."; var message = "The underlying listener has failed to stop.";
throw new InvalidOperationException(msg, ex); throw new InvalidOperationException(message, ex);
} }
_receiveThread.Join(millisecondsTimeout); _receiveThread.Join(millisecondsTimeout);
@ -712,14 +701,13 @@ namespace EonaCat.Network
public void Start() public void Start()
{ {
SSLConfigurationServer sslConfig = null; SSLConfigServer sslConfig = null;
if (IsSecure) if (IsSecure)
{ {
sslConfig = new SSLConfigurationServer(GetSslConfiguration()); sslConfig = new SSLConfigServer(GetSslConfiguration());
string message; if (!CheckSslConfiguration(sslConfig, out string message))
if (!CheckSslConfiguration(sslConfig, out message))
{ {
throw new InvalidOperationException(message); throw new InvalidOperationException(message);
} }
@ -730,42 +718,41 @@ namespace EonaCat.Network
public void Stop() public void Stop()
{ {
stop(1005, string.Empty); stop((ushort)CloseStatusCode.NoStatus, string.Empty);
} }
public void Stop(ushort code, string reason) public void Stop(ushort code, string reason)
{ {
if (!code.IsCloseStatusCode()) if (!code.IsCloseStatusCode())
{ {
var msg = "Less than 1000 or greater than 4999."; var message = "Less than 1000 or greater than 4999.";
throw new ArgumentOutOfRangeException(nameof(code), msg); throw new ArgumentOutOfRangeException(nameof(code), message);
} }
if (code == 1010) if (code == (ushort)CloseStatusCode.MandatoryExtension)
{ {
var msg = "1010 cannot be used."; var message = $"{(ushort)CloseStatusCode.MandatoryExtension} cannot be used.";
throw new ArgumentException(msg, nameof(code)); throw new ArgumentException(message, nameof(code));
} }
if (!reason.IsNullOrEmpty()) if (!reason.IsNullOrEmpty())
{ {
if (code == 1005) if (code == (ushort)CloseStatusCode.NoStatus)
{ {
var msg = "1005 cannot be used."; var message = $"{(ushort)CloseStatusCode.NoStatus} cannot be used.";
throw new ArgumentException(msg, nameof(code)); throw new ArgumentException(message, nameof(code));
} }
byte[] bytes; if (!reason.TryGetUTF8EncodedBytes(out byte[] bytes))
if (!reason.TryGetUTF8EncodedBytes(out bytes))
{ {
var msg = "It could not be UTF-8-encoded."; var message = "It could not be UTF-8-encoded.";
throw new ArgumentException(msg, nameof(reason)); throw new ArgumentException(message, nameof(reason));
} }
if (bytes.Length > 123) if (bytes.Length > 123)
{ {
var msg = "Its size is greater than 123 bytes."; var message = "Its size is greater than 123 bytes.";
throw new ArgumentOutOfRangeException(nameof(reason), msg); throw new ArgumentOutOfRangeException(nameof(reason), message);
} }
} }
@ -776,29 +763,28 @@ namespace EonaCat.Network
{ {
if (code == CloseStatusCode.MandatoryExtension) if (code == CloseStatusCode.MandatoryExtension)
{ {
var msg = "MandatoryExtension cannot be used."; var message = "MandatoryExtension cannot be used.";
throw new ArgumentException(msg, nameof(code)); throw new ArgumentException(message, nameof(code));
} }
if (!reason.IsNullOrEmpty()) if (!reason.IsNullOrEmpty())
{ {
if (code == CloseStatusCode.NoStatus) if (code == CloseStatusCode.NoStatus)
{ {
var msg = "NoStatus cannot be used."; var message = "NoStatus cannot be used.";
throw new ArgumentException(msg, nameof(code)); throw new ArgumentException(message, nameof(code));
} }
byte[] bytes; if (!reason.TryGetUTF8EncodedBytes(out byte[] bytes))
if (!reason.TryGetUTF8EncodedBytes(out bytes))
{ {
var msg = "It could not be UTF-8-encoded."; var message = "It could not be UTF-8-encoded.";
throw new ArgumentException(msg, nameof(reason)); throw new ArgumentException(message, nameof(reason));
} }
if (bytes.Length > 123) if (bytes.Length > 123)
{ {
var msg = "Its size is greater than 123 bytes."; var message = "Its size is greater than 123 bytes.";
throw new ArgumentOutOfRangeException(nameof(reason), msg); throw new ArgumentOutOfRangeException(nameof(reason), message);
} }
} }

View File

@ -26,7 +26,7 @@ namespace EonaCat.Network
_clean = true; _clean = true;
_forSweep = new object(); _forSweep = new object();
_sessions = new Dictionary<string, IWSSession>(); _sessions = new Dictionary<string, IWSSession>();
_state = ServerState.Ready; _state = ServerState.Started;
_sync = ((ICollection)_sessions).SyncRoot; _sync = ((ICollection)_sessions).SyncRoot;
_waitTime = TimeSpan.FromSeconds(1); _waitTime = TimeSpan.FromSeconds(1);
@ -39,7 +39,7 @@ namespace EonaCat.Network
{ {
get get
{ {
foreach (var res in broadping(WebSocketFrame.EmptyPingBytes)) foreach (var res in broadping(WSFrame.EmptyPingBytes))
{ {
if (res.Value) if (res.Value)
{ {
@ -85,7 +85,7 @@ namespace EonaCat.Network
{ {
get get
{ {
foreach (var res in broadping(WebSocketFrame.EmptyPingBytes)) foreach (var res in broadping(WSFrame.EmptyPingBytes))
{ {
if (!res.Value) if (!res.Value)
{ {
@ -109,8 +109,7 @@ namespace EonaCat.Network
throw new ArgumentException("An empty string.", nameof(id)); throw new ArgumentException("An empty string.", nameof(id));
} }
IWSSession session; tryGetSession(id, out IWSSession session);
tryGetSession(id, out session);
return session; return session;
} }
@ -125,18 +124,17 @@ namespace EonaCat.Network
set set
{ {
string msg; if (!canSet(out string message))
if (!canSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!canSet(out msg)) if (!canSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -180,18 +178,17 @@ namespace EonaCat.Network
throw new ArgumentOutOfRangeException(nameof(value), "Zero or less."); throw new ArgumentOutOfRangeException(nameof(value), "Zero or less.");
} }
string msg; if (!canSet(out string message))
if (!canSet(out msg))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
lock (_sync) lock (_sync)
{ {
if (!canSet(out msg)) if (!canSet(out message))
{ {
Logger.Warning(msg); Logger.Warning(message);
return; return;
} }
@ -200,7 +197,7 @@ namespace EonaCat.Network
} }
} }
private void broadcast(Opcode opcode, byte[] data, Action completed) private void broadcast(OperationCode opcode, byte[] data, Action completed)
{ {
var cache = new Dictionary<CompressionMethod, byte[]>(); var cache = new Dictionary<CompressionMethod, byte[]>();
@ -233,7 +230,7 @@ namespace EonaCat.Network
} }
} }
private void broadcast(Opcode opcode, Stream stream, Action completed) private void broadcast(OperationCode opcode, Stream stream, Action completed)
{ {
var cache = new Dictionary<CompressionMethod, Stream>(); var cache = new Dictionary<CompressionMethod, Stream>();
@ -271,14 +268,14 @@ namespace EonaCat.Network
} }
} }
private void broadcastAsync(Opcode opcode, byte[] data, Action completed) private void broadcastAsync(OperationCode opcode, byte[] data, Action completed)
{ {
ThreadPool.QueueUserWorkItem( ThreadPool.QueueUserWorkItem(
state => broadcast(opcode, data, completed) state => broadcast(opcode, data, completed)
); );
} }
private void broadcastAsync(Opcode opcode, Stream stream, Action completed) private void broadcastAsync(OperationCode opcode, Stream stream, Action completed)
{ {
ThreadPool.QueueUserWorkItem( ThreadPool.QueueUserWorkItem(
state => broadcast(opcode, stream, completed) state => broadcast(opcode, stream, completed)
@ -337,7 +334,7 @@ namespace EonaCat.Network
private void stop(PayloadData payloadData, bool send) private void stop(PayloadData payloadData, bool send)
{ {
var bytes = send var bytes = send
? WebSocketFrame.CreateCloseFrame(payloadData, false).ToArray() ? WSFrame.CreateCloseFrame(payloadData, false).ToArray()
: null; : null;
lock (_sync) lock (_sync)
@ -391,7 +388,7 @@ namespace EonaCat.Network
} }
internal void Broadcast( internal void Broadcast(
Opcode opcode, byte[] data, Dictionary<CompressionMethod, byte[]> cache OperationCode opcode, byte[] data, Dictionary<CompressionMethod, byte[]> cache
) )
{ {
foreach (var session in Sessions) foreach (var session in Sessions)
@ -407,7 +404,7 @@ namespace EonaCat.Network
} }
internal void Broadcast( internal void Broadcast(
Opcode opcode, Stream stream, Dictionary<CompressionMethod, Stream> cache OperationCode opcode, Stream stream, Dictionary<CompressionMethod, Stream> cache
) )
{ {
foreach (var session in Sessions) foreach (var session in Sessions)
@ -462,7 +459,7 @@ namespace EonaCat.Network
internal void Stop(ushort code, string reason) internal void Stop(ushort code, string reason)
{ {
if (code == 1005) if (code == (ushort)CloseStatusCode.NoStatus)
{ // == no status { // == no status
stop(PayloadData.Empty, true); stop(PayloadData.Empty, true);
return; return;
@ -475,8 +472,8 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
var msg = "The current state of the manager is not Start."; var message = "The current state of the manager is not Start.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
if (data == null) if (data == null)
@ -484,13 +481,13 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(data)); throw new ArgumentNullException(nameof(data));
} }
if (data.LongLength <= WebSocket.FragmentLength) if (data.LongLength <= WSClient.FragmentLength)
{ {
broadcast(Opcode.Binary, data, null); broadcast(OperationCode.Binary, data, null);
} }
else else
{ {
broadcast(Opcode.Binary, new MemoryStream(data), null); broadcast(OperationCode.Binary, new MemoryStream(data), null);
} }
} }
@ -498,8 +495,8 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
var msg = "The current state of the manager is not Start."; var message = "The current state of the manager is not Start.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
if (data == null) if (data == null)
@ -507,20 +504,19 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(data)); throw new ArgumentNullException(nameof(data));
} }
byte[] bytes; if (!data.TryGetUTF8EncodedBytes(out byte[] bytes))
if (!data.TryGetUTF8EncodedBytes(out bytes))
{ {
var msg = "It could not be UTF-8-encoded."; var message = "It could not be UTF-8-encoded.";
throw new ArgumentException(msg, nameof(data)); throw new ArgumentException(message, nameof(data));
} }
if (bytes.LongLength <= WebSocket.FragmentLength) if (bytes.LongLength <= WSClient.FragmentLength)
{ {
broadcast(Opcode.Text, bytes, null); broadcast(OperationCode.Text, bytes, null);
} }
else else
{ {
broadcast(Opcode.Text, new MemoryStream(bytes), null); broadcast(OperationCode.Text, new MemoryStream(bytes), null);
} }
} }
@ -528,8 +524,8 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
var msg = "The current state of the manager is not Start."; var message = "The current state of the manager is not Start.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
if (stream == null) if (stream == null)
@ -539,14 +535,14 @@ namespace EonaCat.Network
if (!stream.CanRead) if (!stream.CanRead)
{ {
var msg = "It cannot be read."; var message = "It cannot be read.";
throw new ArgumentException(msg, nameof(stream)); throw new ArgumentException(message, nameof(stream));
} }
if (length < 1) if (length < 1)
{ {
var msg = "Less than 1."; var message = "Less than 1.";
throw new ArgumentException(msg, nameof(length)); throw new ArgumentException(message, nameof(length));
} }
var bytes = stream.ReadBytes(length); var bytes = stream.ReadBytes(length);
@ -554,8 +550,8 @@ namespace EonaCat.Network
var len = bytes.Length; var len = bytes.Length;
if (len == 0) if (len == 0)
{ {
var msg = "No data could be read from it."; var message = "No data could be read from it.";
throw new ArgumentException(msg, nameof(stream)); throw new ArgumentException(message, nameof(stream));
} }
if (len < length) if (len < length)
@ -568,13 +564,13 @@ namespace EonaCat.Network
); );
} }
if (len <= WebSocket.FragmentLength) if (len <= WSClient.FragmentLength)
{ {
broadcast(Opcode.Binary, bytes, null); broadcast(OperationCode.Binary, bytes, null);
} }
else else
{ {
broadcast(Opcode.Binary, new MemoryStream(bytes), null); broadcast(OperationCode.Binary, new MemoryStream(bytes), null);
} }
} }
@ -582,8 +578,8 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
var msg = "The current state of the manager is not Start."; var message = "The current state of the manager is not Start.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
if (data == null) if (data == null)
@ -591,13 +587,13 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(data)); throw new ArgumentNullException(nameof(data));
} }
if (data.LongLength <= WebSocket.FragmentLength) if (data.LongLength <= WSClient.FragmentLength)
{ {
broadcastAsync(Opcode.Binary, data, completed); broadcastAsync(OperationCode.Binary, data, completed);
} }
else else
{ {
broadcastAsync(Opcode.Binary, new MemoryStream(data), completed); broadcastAsync(OperationCode.Binary, new MemoryStream(data), completed);
} }
} }
@ -605,8 +601,8 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
var msg = "The current state of the manager is not Start."; var message = "The current state of the manager is not Start.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
if (data == null) if (data == null)
@ -614,20 +610,19 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(data)); throw new ArgumentNullException(nameof(data));
} }
byte[] bytes; if (!data.TryGetUTF8EncodedBytes(out byte[] bytes))
if (!data.TryGetUTF8EncodedBytes(out bytes))
{ {
var msg = "It could not be UTF-8-encoded."; var message = "It could not be UTF-8-encoded.";
throw new ArgumentException(msg, nameof(data)); throw new ArgumentException(message, nameof(data));
} }
if (bytes.LongLength <= WebSocket.FragmentLength) if (bytes.LongLength <= WSClient.FragmentLength)
{ {
broadcastAsync(Opcode.Text, bytes, completed); broadcastAsync(OperationCode.Text, bytes, completed);
} }
else else
{ {
broadcastAsync(Opcode.Text, new MemoryStream(bytes), completed); broadcastAsync(OperationCode.Text, new MemoryStream(bytes), completed);
} }
} }
@ -635,8 +630,8 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
var msg = "The current state of the manager is not Start."; var message = "The current state of the manager is not Start.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
if (stream == null) if (stream == null)
@ -646,14 +641,14 @@ namespace EonaCat.Network
if (!stream.CanRead) if (!stream.CanRead)
{ {
var msg = "It cannot be read."; var message = "It cannot be read.";
throw new ArgumentException(msg, nameof(stream)); throw new ArgumentException(message, nameof(stream));
} }
if (length < 1) if (length < 1)
{ {
var msg = "Less than 1."; var message = "Less than 1.";
throw new ArgumentException(msg, nameof(length)); throw new ArgumentException(message, nameof(length));
} }
var bytes = stream.ReadBytes(length); var bytes = stream.ReadBytes(length);
@ -661,8 +656,8 @@ namespace EonaCat.Network
var len = bytes.Length; var len = bytes.Length;
if (len == 0) if (len == 0)
{ {
var msg = "No data could be read from it."; var message = "No data could be read from it.";
throw new ArgumentException(msg, nameof(stream)); throw new ArgumentException(message, nameof(stream));
} }
if (len < length) if (len < length)
@ -675,23 +670,22 @@ namespace EonaCat.Network
); );
} }
if (len <= WebSocket.FragmentLength) if (len <= WSClient.FragmentLength)
{ {
broadcastAsync(Opcode.Binary, bytes, completed); broadcastAsync(OperationCode.Binary, bytes, completed);
} }
else else
{ {
broadcastAsync(Opcode.Binary, new MemoryStream(bytes), completed); broadcastAsync(OperationCode.Binary, new MemoryStream(bytes), completed);
} }
} }
public void CloseSession(string id) public void CloseSession(string id)
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var message = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
session.Context.WebSocket.Close(); session.Context.WebSocket.Close();
@ -699,11 +693,10 @@ namespace EonaCat.Network
public void CloseSession(string id, ushort code, string reason) public void CloseSession(string id, ushort code, string reason)
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var message = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
session.Context.WebSocket.Close(code, reason); session.Context.WebSocket.Close(code, reason);
@ -711,11 +704,10 @@ namespace EonaCat.Network
public void CloseSession(string id, CloseStatusCode code, string reason) public void CloseSession(string id, CloseStatusCode code, string reason)
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var message = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
session.Context.WebSocket.Close(code, reason); session.Context.WebSocket.Close(code, reason);
@ -723,11 +715,10 @@ namespace EonaCat.Network
public bool PingTo(string id) public bool PingTo(string id)
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var message = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
return session.Context.WebSocket.Ping(); return session.Context.WebSocket.Ping();
@ -735,11 +726,10 @@ namespace EonaCat.Network
public bool PingTo(string message, string id) public bool PingTo(string message, string id)
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var pingMessage = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(pingMessage);
} }
return session.Context.WebSocket.Ping(message); return session.Context.WebSocket.Ping(message);
@ -747,11 +737,10 @@ namespace EonaCat.Network
public void SendTo(byte[] data, string id) public void SendTo(byte[] data, string id)
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var message = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
session.Context.WebSocket.Send(data); session.Context.WebSocket.Send(data);
@ -759,11 +748,10 @@ namespace EonaCat.Network
public void SendTo(string data, string id) public void SendTo(string data, string id)
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var message = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
session.Context.WebSocket.Send(data); session.Context.WebSocket.Send(data);
@ -771,11 +759,10 @@ namespace EonaCat.Network
public void SendTo(Stream stream, int length, string id) public void SendTo(Stream stream, int length, string id)
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var message = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
session.Context.WebSocket.Send(stream, length); session.Context.WebSocket.Send(stream, length);
@ -783,11 +770,10 @@ namespace EonaCat.Network
public void SendToAsync(byte[] data, string id, Action<bool> completed) public void SendToAsync(byte[] data, string id, Action<bool> completed)
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var message = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
session.Context.WebSocket.SendAsync(data, completed); session.Context.WebSocket.SendAsync(data, completed);
@ -795,11 +781,10 @@ namespace EonaCat.Network
public void SendToAsync(string data, string id, Action<bool> completed) public void SendToAsync(string data, string id, Action<bool> completed)
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var message = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
session.Context.WebSocket.SendAsync(data, completed); session.Context.WebSocket.SendAsync(data, completed);
@ -809,11 +794,10 @@ namespace EonaCat.Network
Stream stream, int length, string id, Action<bool> completed Stream stream, int length, string id, Action<bool> completed
) )
{ {
IWSSession session; if (!TryGetSession(id, out IWSSession session))
if (!TryGetSession(id, out session))
{ {
var msg = "The session could not be found."; var message = "The session could not be found.";
throw new InvalidOperationException(msg); throw new InvalidOperationException(message);
} }
session.Context.WebSocket.SendAsync(stream, length, completed); session.Context.WebSocket.SendAsync(stream, length, completed);
@ -852,15 +836,14 @@ namespace EonaCat.Network
break; break;
} }
IWSSession session; if (_sessions.TryGetValue(id, out IWSSession session))
if (_sessions.TryGetValue(id, out session))
{ {
var state = session.State; var state = session.State;
if (state == WebSocketState.Open) if (state == WSState.Open)
{ {
session.Context.WebSocket.Close(CloseStatusCode.Abnormal); session.Context.WebSocket.Close(CloseStatusCode.Abnormal);
} }
else if (state == WebSocketState.Closing) else if (state == WSState.Closing)
{ {
continue; continue;
} }

View File

@ -5,44 +5,44 @@ using System;
namespace EonaCat.Network namespace EonaCat.Network
{ {
public class WebSocketException : Exception public class WSException : Exception
{ {
internal WebSocketException() internal WSException()
: this(CloseStatusCode.Abnormal, null, null) : this(CloseStatusCode.Abnormal, null, null)
{ {
} }
internal WebSocketException(Exception innerException) internal WSException(Exception innerException)
: this(CloseStatusCode.Abnormal, null, innerException) : this(CloseStatusCode.Abnormal, null, innerException)
{ {
} }
internal WebSocketException(string message) internal WSException(string message)
: this(CloseStatusCode.Abnormal, message, null) : this(CloseStatusCode.Abnormal, message, null)
{ {
} }
internal WebSocketException(CloseStatusCode code) internal WSException(CloseStatusCode code)
: this(code, null, null) : this(code, null, null)
{ {
} }
internal WebSocketException(string message, Exception innerException) internal WSException(string message, Exception innerException)
: this(CloseStatusCode.Abnormal, message, innerException) : this(CloseStatusCode.Abnormal, message, innerException)
{ {
} }
internal WebSocketException(CloseStatusCode code, Exception innerException) internal WSException(CloseStatusCode code, Exception innerException)
: this(code, null, innerException) : this(code, null, innerException)
{ {
} }
internal WebSocketException(CloseStatusCode code, string message) internal WSException(CloseStatusCode code, string message)
: this(code, message, null) : this(code, message, null)
{ {
} }
internal WebSocketException( internal WSException(
CloseStatusCode code, string message, Exception innerException CloseStatusCode code, string message, Exception innerException
) )
: base("EonaCat Network: " + (message ?? code.GetMessage()), innerException) : base("EonaCat Network: " + (message ?? code.GetMessage()), innerException)

View File

@ -9,33 +9,33 @@ using System.Text;
namespace EonaCat.Network namespace EonaCat.Network
{ {
internal class WebSocketFrame : IEnumerable<byte> internal class WSFrame : IEnumerable<byte>
{ {
private const int BUFFER_SIZE = 1024; private const int BUFFER_SIZE = 1024;
internal static readonly byte[] EmptyPingBytes; internal static readonly byte[] EmptyPingBytes;
static WebSocketFrame() static WSFrame()
{ {
EmptyPingBytes = CreatePingFrame(false).ToArray(); EmptyPingBytes = CreatePingFrame(false).ToArray();
} }
private WebSocketFrame() private WSFrame()
{ {
} }
internal WebSocketFrame(Opcode opcode, PayloadData payloadData, bool mask) internal WSFrame(OperationCode opcode, PayloadData payloadData, bool mask)
: this(FinalFrame.Final, opcode, payloadData, false, mask) : this(FinalFrame.Final, opcode, payloadData, false, mask)
{ {
} }
internal WebSocketFrame(FinalFrame finalFrame, Opcode opcode, byte[] data, bool compressed, bool mask) internal WSFrame(FinalFrame finalFrame, OperationCode opcode, byte[] data, bool compressed, bool mask)
: this(finalFrame, opcode, new PayloadData(data), compressed, mask) : this(finalFrame, opcode, new PayloadData(data), compressed, mask)
{ {
} }
internal WebSocketFrame( internal WSFrame(
FinalFrame fin, Opcode opcode, PayloadData payloadData, bool compressed, bool mask) FinalFrame fin, OperationCode opcode, PayloadData payloadData, bool compressed, bool mask)
{ {
Fin = fin; Fin = fin;
Rsv1 = opcode.IsData() && compressed ? Rsv.On : Rsv.Off; Rsv1 = opcode.IsData() && compressed ? Rsv.On : Rsv.Off;
@ -47,7 +47,7 @@ namespace EonaCat.Network
if (len < 126) if (len < 126)
{ {
PayloadLength = (byte)len; PayloadLength = (byte)len;
ExtendedPayloadLength = WebSocket.EmptyBytes; ExtendedPayloadLength = WSClient.EmptyBytes;
} }
else if (len < 0x010000) else if (len < 0x010000)
{ {
@ -69,7 +69,7 @@ namespace EonaCat.Network
else else
{ {
Mask = Mask.Off; Mask = Mask.Off;
MaskingKey = WebSocket.EmptyBytes; MaskingKey = WSClient.EmptyBytes;
} }
PayloadData = payloadData; PayloadData = payloadData;
@ -87,29 +87,29 @@ namespace EonaCat.Network
public FinalFrame Fin { get; private set; } public FinalFrame Fin { get; private set; }
public bool IsBinary => Opcode == Opcode.Binary; public bool IsBinary => Opcode == OperationCode.Binary;
public bool IsClose => Opcode == Opcode.Close; public bool IsClose => Opcode == OperationCode.Close;
public bool IsCompressed => Rsv1 == Rsv.On; public bool IsCompressed => Rsv1 == Rsv.On;
public bool IsContinuation => Opcode == Opcode.Cont; public bool IsContinuation => Opcode == OperationCode.Cont;
public bool IsControl => Opcode >= Opcode.Close; public bool IsControl => Opcode >= OperationCode.Close;
public bool IsData => Opcode == Opcode.Text || Opcode == Opcode.Binary; public bool IsData => Opcode == OperationCode.Text || Opcode == OperationCode.Binary;
public bool IsFinal => Fin == FinalFrame.Final; public bool IsFinal => Fin == FinalFrame.Final;
public bool IsFragment => Fin == FinalFrame.More || Opcode == Opcode.Cont; public bool IsFragment => Fin == FinalFrame.More || Opcode == OperationCode.Cont;
public bool IsMasked => Mask == Mask.On; public bool IsMasked => Mask == Mask.On;
public bool IsPing => Opcode == Opcode.Ping; public bool IsPing => Opcode == OperationCode.Ping;
public bool IsPong => Opcode == Opcode.Pong; public bool IsPong => Opcode == OperationCode.Pong;
public bool IsText => Opcode == Opcode.Text; public bool IsText => Opcode == OperationCode.Text;
public ulong Length => 2 + (ulong)(ExtendedPayloadLength.Length + MaskingKey.Length) + PayloadData.Length; public ulong Length => 2 + (ulong)(ExtendedPayloadLength.Length + MaskingKey.Length) + PayloadData.Length;
@ -117,7 +117,7 @@ namespace EonaCat.Network
public byte[] MaskingKey { get; private set; } public byte[] MaskingKey { get; private set; }
public Opcode Opcode { get; private set; } public OperationCode Opcode { get; private set; }
public PayloadData PayloadData { get; private set; } public PayloadData PayloadData { get; private set; }
@ -132,12 +132,12 @@ namespace EonaCat.Network
private static byte[] createMaskingKey() private static byte[] createMaskingKey()
{ {
var key = new byte[4]; var key = new byte[4];
WebSocket.RandomNumber.GetBytes(key); WSClient.RandomNumber.GetBytes(key);
return key; return key;
} }
private static string dump(WebSocketFrame frame) private static string dump(WSFrame frame)
{ {
var len = frame.Length; var len = frame.Length;
var cnt = (long)(len / 4); var cnt = (long)(len / 4);
@ -213,7 +213,7 @@ namespace EonaCat.Network
return output.ToString(); return output.ToString();
} }
private static string print(WebSocketFrame frame) private static string print(WSFrame frame)
{ {
// Payload Length // Payload Length
var payloadLen = frame.PayloadLength; var payloadLen = frame.PayloadLength;
@ -259,11 +259,11 @@ Extended Payload Length: {7}
payload); payload);
} }
private static WebSocketFrame processHeader(byte[] header) private static WSFrame processHeader(byte[] header)
{ {
if (header.Length != 2) if (header.Length != 2)
{ {
throw new WebSocketException("The header of a frame cannot be read from the stream."); throw new WSException("The header of a frame cannot be read from the stream.");
} }
// FIN // FIN
@ -299,34 +299,34 @@ Extended Payload Length: {7}
if (err != null) if (err != null)
{ {
throw new WebSocketException(CloseStatusCode.ProtocolError, err); throw new WSException(CloseStatusCode.ProtocolError, err);
} }
var frame = new WebSocketFrame(); var frame = new WSFrame();
frame.Fin = fin; frame.Fin = fin;
frame.Rsv1 = rsv1; frame.Rsv1 = rsv1;
frame.Rsv2 = rsv2; frame.Rsv2 = rsv2;
frame.Rsv3 = rsv3; frame.Rsv3 = rsv3;
frame.Opcode = (Opcode)opcode; frame.Opcode = (OperationCode)opcode;
frame.Mask = mask; frame.Mask = mask;
frame.PayloadLength = payloadLen; frame.PayloadLength = payloadLen;
return frame; return frame;
} }
private static WebSocketFrame readExtendedPayloadLength(Stream stream, WebSocketFrame frame) private static WSFrame readExtendedPayloadLength(Stream stream, WSFrame frame)
{ {
var len = frame.ExtendedPayloadLengthCount; var len = frame.ExtendedPayloadLengthCount;
if (len == 0) if (len == 0)
{ {
frame.ExtendedPayloadLength = WebSocket.EmptyBytes; frame.ExtendedPayloadLength = WSClient.EmptyBytes;
return frame; return frame;
} }
var bytes = stream.ReadBytes(len); var bytes = stream.ReadBytes(len);
if (bytes.Length != len) if (bytes.Length != len)
{ {
throw new WebSocketException( throw new WSException(
"The extended payload length of a frame cannot be read from the stream."); "The extended payload length of a frame cannot be read from the stream.");
} }
@ -336,14 +336,14 @@ Extended Payload Length: {7}
private static void readExtendedPayloadLengthAsync( private static void readExtendedPayloadLengthAsync(
Stream stream, Stream stream,
WebSocketFrame frame, WSFrame frame,
Action<WebSocketFrame> completed, Action<WSFrame> completed,
Action<Exception> error) Action<Exception> error)
{ {
var len = frame.ExtendedPayloadLengthCount; var len = frame.ExtendedPayloadLengthCount;
if (len == 0) if (len == 0)
{ {
frame.ExtendedPayloadLength = WebSocket.EmptyBytes; frame.ExtendedPayloadLength = WSClient.EmptyBytes;
completed(frame); completed(frame);
return; return;
@ -355,7 +355,7 @@ Extended Payload Length: {7}
{ {
if (bytes.Length != len) if (bytes.Length != len)
{ {
throw new WebSocketException( throw new WSException(
"The extended payload length of a frame cannot be read from the stream."); "The extended payload length of a frame cannot be read from the stream.");
} }
@ -365,30 +365,30 @@ Extended Payload Length: {7}
error); error);
} }
private static WebSocketFrame readHeader(Stream stream) private static WSFrame readHeader(Stream stream)
{ {
return processHeader(stream.ReadBytes(2)); return processHeader(stream.ReadBytes(2));
} }
private static void readHeaderAsync( private static void readHeaderAsync(
Stream stream, Action<WebSocketFrame> completed, Action<Exception> error) Stream stream, Action<WSFrame> completed, Action<Exception> error)
{ {
stream.ReadBytesAsync(2, bytes => completed(processHeader(bytes)), error); stream.ReadBytesAsync(2, bytes => completed(processHeader(bytes)), error);
} }
private static WebSocketFrame readMaskingKey(Stream stream, WebSocketFrame frame) private static WSFrame readMaskingKey(Stream stream, WSFrame frame)
{ {
var len = frame.IsMasked ? 4 : 0; var len = frame.IsMasked ? 4 : 0;
if (len == 0) if (len == 0)
{ {
frame.MaskingKey = WebSocket.EmptyBytes; frame.MaskingKey = WSClient.EmptyBytes;
return frame; return frame;
} }
var bytes = stream.ReadBytes(len); var bytes = stream.ReadBytes(len);
if (bytes.Length != len) if (bytes.Length != len)
{ {
throw new WebSocketException("The masking key of a frame cannot be read from the stream."); throw new WSException("The masking key of a frame cannot be read from the stream.");
} }
frame.MaskingKey = bytes; frame.MaskingKey = bytes;
@ -397,14 +397,14 @@ Extended Payload Length: {7}
private static void readMaskingKeyAsync( private static void readMaskingKeyAsync(
Stream stream, Stream stream,
WebSocketFrame frame, WSFrame frame,
Action<WebSocketFrame> completed, Action<WSFrame> completed,
Action<Exception> error) Action<Exception> error)
{ {
var len = frame.IsMasked ? 4 : 0; var len = frame.IsMasked ? 4 : 0;
if (len == 0) if (len == 0)
{ {
frame.MaskingKey = WebSocket.EmptyBytes; frame.MaskingKey = WSClient.EmptyBytes;
completed(frame); completed(frame);
return; return;
@ -416,7 +416,7 @@ Extended Payload Length: {7}
{ {
if (bytes.Length != len) if (bytes.Length != len)
{ {
throw new WebSocketException( throw new WSException(
"The masking key of a frame cannot be read from the stream."); "The masking key of a frame cannot be read from the stream.");
} }
@ -426,7 +426,7 @@ Extended Payload Length: {7}
error); error);
} }
private static WebSocketFrame readPayloadData(Stream stream, WebSocketFrame frame) private static WSFrame readPayloadData(Stream stream, WSFrame frame)
{ {
var len = frame.FullPayloadLength; var len = frame.FullPayloadLength;
if (len == 0) if (len == 0)
@ -437,7 +437,7 @@ Extended Payload Length: {7}
if (len > PayloadData.MaxLength) if (len > PayloadData.MaxLength)
{ {
throw new WebSocketException(CloseStatusCode.TooBig, "A frame has a long payload length."); throw new WSException(CloseStatusCode.TooBig, "A frame has a long payload length.");
} }
var llen = (long)len; var llen = (long)len;
@ -447,7 +447,7 @@ Extended Payload Length: {7}
if (bytes.LongLength != llen) if (bytes.LongLength != llen)
{ {
throw new WebSocketException( throw new WSException(
"The payload data of a frame cannot be read from the stream."); "The payload data of a frame cannot be read from the stream.");
} }
@ -457,8 +457,8 @@ Extended Payload Length: {7}
private static void readPayloadDataAsync( private static void readPayloadDataAsync(
Stream stream, Stream stream,
WebSocketFrame frame, WSFrame frame,
Action<WebSocketFrame> completed, Action<WSFrame> completed,
Action<Exception> error) Action<Exception> error)
{ {
var len = frame.FullPayloadLength; var len = frame.FullPayloadLength;
@ -472,7 +472,7 @@ Extended Payload Length: {7}
if (len > PayloadData.MaxLength) if (len > PayloadData.MaxLength)
{ {
throw new WebSocketException(CloseStatusCode.TooBig, "A frame has a long payload length."); throw new WSException(CloseStatusCode.TooBig, "A frame has a long payload length.");
} }
var llen = (long)len; var llen = (long)len;
@ -480,7 +480,7 @@ Extended Payload Length: {7}
{ {
if (bytes.LongLength != llen) if (bytes.LongLength != llen)
{ {
throw new WebSocketException( throw new WSException(
"The payload data of a frame cannot be read from the stream."); "The payload data of a frame cannot be read from the stream.");
} }
@ -497,39 +497,39 @@ Extended Payload Length: {7}
stream.ReadBytesAsync(llen, BUFFER_SIZE, compl, error); stream.ReadBytesAsync(llen, BUFFER_SIZE, compl, error);
} }
internal static WebSocketFrame CreateCloseFrame( internal static WSFrame CreateCloseFrame(
PayloadData payloadData, bool mask PayloadData payloadData, bool mask
) )
{ {
return new WebSocketFrame( return new WSFrame(
FinalFrame.Final, Opcode.Close, payloadData, false, mask FinalFrame.Final, OperationCode.Close, payloadData, false, mask
); );
} }
internal static WebSocketFrame CreatePingFrame(bool mask) internal static WSFrame CreatePingFrame(bool mask)
{ {
return new WebSocketFrame( return new WSFrame(
FinalFrame.Final, Opcode.Ping, PayloadData.Empty, false, mask FinalFrame.Final, OperationCode.Ping, PayloadData.Empty, false, mask
); );
} }
internal static WebSocketFrame CreatePingFrame(byte[] data, bool mask) internal static WSFrame CreatePingFrame(byte[] data, bool mask)
{ {
return new WebSocketFrame( return new WSFrame(
FinalFrame.Final, Opcode.Ping, new PayloadData(data), false, mask FinalFrame.Final, OperationCode.Ping, new PayloadData(data), false, mask
); );
} }
internal static WebSocketFrame CreatePongFrame( internal static WSFrame CreatePongFrame(
PayloadData payloadData, bool mask PayloadData payloadData, bool mask
) )
{ {
return new WebSocketFrame( return new WSFrame(
FinalFrame.Final, Opcode.Pong, payloadData, false, mask FinalFrame.Final, OperationCode.Pong, payloadData, false, mask
); );
} }
internal static WebSocketFrame ReadFrame(Stream stream, bool unmask) internal static WSFrame ReadFrame(Stream stream, bool unmask)
{ {
var frame = readHeader(stream); var frame = readHeader(stream);
readExtendedPayloadLength(stream, frame); readExtendedPayloadLength(stream, frame);
@ -547,7 +547,7 @@ Extended Payload Length: {7}
internal static void ReadFrameAsync( internal static void ReadFrameAsync(
Stream stream, Stream stream,
bool unmask, bool unmask,
Action<WebSocketFrame> completed, Action<WSFrame> completed,
Action<Exception> error Action<Exception> error
) )
{ {
@ -593,7 +593,7 @@ Extended Payload Length: {7}
Mask = Mask.Off; Mask = Mask.Off;
PayloadData.Mask(MaskingKey); PayloadData.Mask(MaskingKey);
MaskingKey = WebSocket.EmptyBytes; MaskingKey = WSClient.EmptyBytes;
} }
public IEnumerator<byte> GetEnumerator() public IEnumerator<byte> GetEnumerator()

View File

@ -3,7 +3,7 @@
namespace EonaCat.Network namespace EonaCat.Network
{ {
public enum WebSocketState : ushort public enum WSState : ushort
{ {
Connecting = 0, Connecting = 0,

View File

@ -50,8 +50,7 @@ namespace EonaCat.Network
private static byte[] readEntityBody(Stream stream, string length) private static byte[] readEntityBody(Stream stream, string length)
{ {
long len; if (!long.TryParse(length, out long len))
if (!long.TryParse(length, out len))
{ {
throw new ArgumentException("Cannot be parsed.", nameof(length)); throw new ArgumentException("Cannot be parsed.", nameof(length));
} }
@ -98,7 +97,7 @@ namespace EonaCat.Network
if (!read) if (!read)
{ {
throw new WebSocketException("The length of header part is greater than the max length."); throw new WSException("The length of header part is greater than the max length.");
} }
return Encoding.UTF8.GetString(buff.ToArray()) return Encoding.UTF8.GetString(buff.ToArray())
@ -142,15 +141,15 @@ namespace EonaCat.Network
timer.Dispose(); timer.Dispose();
} }
var msg = timeout var message = timeout
? "A timeout has occurred while reading an HTTP request/response." ? "A timeout has occurred while reading an HTTP request/response."
: exception != null : exception != null
? "An exception has occurred while reading an HTTP request/response." ? "An exception has occurred while reading an HTTP request/response."
: null; : null;
if (msg != null) if (message != null)
{ {
throw new WebSocketException(msg, exception); throw new WSException(message, exception);
} }
return http; return http;

View File

@ -114,7 +114,7 @@ namespace EonaCat.Network
} }
catch (Exception e) catch (Exception e)
{ {
NetworkHelper.Logger.Error(string.Format(" {0}: at {1} is close ,error msg :{2}", para.ip, para.port, e.Message)); NetworkHelper.Logger.Error(string.Format(" {0}: at {1} is close ,error message :{2}", para.ip, para.port, e.Message));
} }
finally finally
{ {

View File

@ -256,20 +256,5 @@ namespace EonaCat.Network
_Routes.Add(route); _Routes.Add(route);
} }
} }
private void Remove(ContentRoute route)
{
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
lock (_Lock)
{
_Routes.Remove(route);
}
return;
}
} }
} }

View File

@ -137,12 +137,6 @@ namespace EonaCat.Network
return "application/octet-stream"; return "application/octet-stream";
} }
private void Set204Response(HttpContext ctx)
{
ctx.Response.StatusCode = 204;
ctx.Response.ContentLength = 0;
}
private void Set404Response(HttpContext ctx) private void Set404Response(HttpContext ctx)
{ {
ctx.Response.StatusCode = 404; ctx.Response.StatusCode = 404;

View File

@ -129,11 +129,10 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(rawUrl)); throw new ArgumentNullException(nameof(rawUrl));
} }
object val = null;
if (Matcher.Match( if (Matcher.Match(
BuildConsolidatedRegex(method, rawUrl), BuildConsolidatedRegex(method, rawUrl),
out val)) out object val))
{ {
if (val == null) if (val == null)
{ {

View File

@ -451,8 +451,7 @@ namespace EonaCat.Network
if (ctx.Request.Method == HttpMethod.GET || ctx.Request.Method == HttpMethod.HEAD) if (ctx.Request.Method == HttpMethod.GET || ctx.Request.Method == HttpMethod.HEAD)
{ {
ContentRoute cr = null; if (_Routes.Content.Match(ctx.Request.Url.RawWithoutQuery, out ContentRoute cr))
if (_Routes.Content.Match(ctx.Request.Url.RawWithoutQuery, out cr))
{ {
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)
{ {
@ -468,8 +467,7 @@ namespace EonaCat.Network
} }
} }
StaticRoute sr = null; Func<HttpContext, Task> handler = _Routes.Static.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out StaticRoute sr);
Func<HttpContext, Task> handler = _Routes.Static.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out sr);
if (handler != null) if (handler != null)
{ {
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)
@ -485,9 +483,7 @@ namespace EonaCat.Network
return; return;
} }
ParameterRoute pr = null; handler = _Routes.Parameter.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out Dictionary<string, string> parameters, out ParameterRoute pr);
Dictionary<string, string> parameters = null;
handler = _Routes.Parameter.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out parameters, out pr);
if (handler != null) if (handler != null)
{ {
ctx.Request.Url.Parameters = new Dictionary<string, string>(parameters); ctx.Request.Url.Parameters = new Dictionary<string, string>(parameters);
@ -505,8 +501,7 @@ namespace EonaCat.Network
return; return;
} }
DynamicRoute dr = null; handler = _Routes.Dynamic.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out DynamicRoute dr);
handler = _Routes.Dynamic.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out dr);
if (handler != null) if (handler != null)
{ {
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)

View File

@ -577,43 +577,6 @@ namespace EonaCat.Network
} }
} }
private void ReadStreamFully()
{
if (Data == null)
{
return;
}
if (!Data.CanRead)
{
return;
}
if (_DataAsBytes == null)
{
if (!ChunkedTransfer)
{
_DataAsBytes = StreamToBytes(Data);
}
else
{
while (true)
{
Chunk chunk = ReadChunk().Result;
if (chunk.Data != null && chunk.Data.Length > 0)
{
_DataAsBytes = AppendBytes(_DataAsBytes, chunk.Data);
}
if (chunk.IsFinalChunk)
{
break;
}
}
}
}
}
private byte[] ReadStreamFully(Stream input) private byte[] ReadStreamFully(Stream input)
{ {
if (input == null) if (input == null)

View File

@ -125,7 +125,7 @@ namespace EonaCat.Network
private readonly HttpRequest _Request = null; private readonly HttpRequest _Request = null;
private readonly System.Net.HttpListenerContext _Context = null; private readonly System.Net.HttpListenerContext _Context = null;
private readonly System.Net.HttpListenerResponse _Response = null; private readonly System.Net.HttpListenerResponse _Response = null;
private readonly Stream _OutputStream = null; private readonly Stream _outputStream = null;
private bool _HeadersSent = false; private bool _HeadersSent = false;
private readonly EonaCatWebserverSettings _Settings = new EonaCatWebserverSettings(); private readonly EonaCatWebserverSettings _Settings = new EonaCatWebserverSettings();
private readonly EonaCatWebserverEvents _Events = new EonaCatWebserverEvents(); private readonly EonaCatWebserverEvents _Events = new EonaCatWebserverEvents();
@ -168,7 +168,7 @@ namespace EonaCat.Network
_Settings = settings; _Settings = settings;
_Events = events; _Events = events;
_OutputStream = _Response.OutputStream; _outputStream = _Response.OutputStream;
} }
/// <summary> /// <summary>
@ -190,13 +190,10 @@ namespace EonaCat.Network
SendHeaders(); SendHeaders();
} }
await _OutputStream.FlushAsync(token).ConfigureAwait(false); await _outputStream.FlushAsync(token).ConfigureAwait(false);
_OutputStream.Close(); _outputStream.Close();
if (_Response != null) _Response?.Close();
{
_Response.Close();
}
ResponseSent = true; ResponseSent = true;
return true; return true;
@ -229,13 +226,10 @@ namespace EonaCat.Network
SendHeaders(); SendHeaders();
} }
await _OutputStream.FlushAsync(token).ConfigureAwait(false); await _outputStream.FlushAsync(token).ConfigureAwait(false);
_OutputStream.Close(); _outputStream.Close();
if (_Response != null) _Response?.Close();
{
_Response.Close();
}
ResponseSent = true; ResponseSent = true;
return true; return true;
@ -288,17 +282,14 @@ namespace EonaCat.Network
{ {
if (bytes != null && bytes.Length > 0) if (bytes != null && bytes.Length > 0)
{ {
await _OutputStream.WriteAsync(bytes, 0, bytes.Length, token).ConfigureAwait(false); await _outputStream.WriteAsync(bytes, 0, bytes.Length, token).ConfigureAwait(false);
} }
} }
await _OutputStream.FlushAsync(token).ConfigureAwait(false); await _outputStream.FlushAsync(token).ConfigureAwait(false);
_OutputStream.Close(); _outputStream.Close();
if (_Response != null) _Response?.Close();
{
_Response.Close();
}
ResponseSent = true; ResponseSent = true;
return true; return true;
@ -347,17 +338,14 @@ namespace EonaCat.Network
{ {
if (data != null && data.Length > 0) if (data != null && data.Length > 0)
{ {
await _OutputStream.WriteAsync(data, 0, data.Length, token).ConfigureAwait(false); await _outputStream.WriteAsync(data, 0, data.Length, token).ConfigureAwait(false);
} }
} }
await _OutputStream.FlushAsync(token).ConfigureAwait(false); await _outputStream.FlushAsync(token).ConfigureAwait(false);
_OutputStream.Close(); _outputStream.Close();
if (_Response != null) _Response?.Close();
{
_Response.Close();
}
ResponseSent = true; ResponseSent = true;
return true; return true;
@ -406,7 +394,7 @@ namespace EonaCat.Network
if (bytesRead > 0) if (bytesRead > 0)
{ {
await Data.WriteAsync(buffer, 0, bytesRead, token).ConfigureAwait(false); await Data.WriteAsync(buffer, 0, bytesRead, token).ConfigureAwait(false);
await _OutputStream.WriteAsync(buffer, 0, bytesRead, token).ConfigureAwait(false); await _outputStream.WriteAsync(buffer, 0, bytesRead, token).ConfigureAwait(false);
bytesRemaining -= bytesRead; bytesRemaining -= bytesRead;
} }
} }
@ -418,13 +406,10 @@ namespace EonaCat.Network
} }
} }
await _OutputStream.FlushAsync(token).ConfigureAwait(false); await _outputStream.FlushAsync(token).ConfigureAwait(false);
_OutputStream.Close(); _outputStream.Close();
if (_Response != null) _Response?.Close();
{
_Response.Close();
}
ResponseSent = true; ResponseSent = true;
return true; return true;
@ -466,8 +451,8 @@ namespace EonaCat.Network
chunk = new byte[0]; chunk = new byte[0];
} }
await _OutputStream.WriteAsync(chunk, 0, numBytes, token).ConfigureAwait(false); await _outputStream.WriteAsync(chunk, 0, numBytes, token).ConfigureAwait(false);
await _OutputStream.FlushAsync(token).ConfigureAwait(false); await _outputStream.FlushAsync(token).ConfigureAwait(false);
} }
catch (Exception) catch (Exception)
{ {
@ -504,19 +489,16 @@ namespace EonaCat.Network
{ {
if (chunk != null && chunk.Length > 0) if (chunk != null && chunk.Length > 0)
{ {
await _OutputStream.WriteAsync(chunk, 0, numBytes, token).ConfigureAwait(false); await _outputStream.WriteAsync(chunk, 0, numBytes, token).ConfigureAwait(false);
} }
byte[] endChunk = new byte[0]; byte[] endChunk = new byte[0];
await _OutputStream.WriteAsync(endChunk, 0, endChunk.Length, token).ConfigureAwait(false); await _outputStream.WriteAsync(endChunk, 0, endChunk.Length, token).ConfigureAwait(false);
await _OutputStream.FlushAsync(token).ConfigureAwait(false); await _outputStream.FlushAsync(token).ConfigureAwait(false);
_OutputStream.Close(); _outputStream.Close();
if (_Response != null) _Response?.Close();
{
_Response.Close();
}
ResponseSent = true; ResponseSent = true;
return true; return true;
@ -647,32 +629,6 @@ namespace EonaCat.Network
} }
} }
private byte[] PackageChunk(byte[] chunk)
{
if (chunk == null || chunk.Length < 1)
{
return Encoding.UTF8.GetBytes("0\r\n\r\n");
}
MemoryStream ms = new MemoryStream();
string newlineStr = "\r\n";
byte[] newline = Encoding.UTF8.GetBytes(newlineStr);
string chunkLenHex = chunk.Length.ToString("X");
byte[] chunkLen = Encoding.UTF8.GetBytes(chunkLenHex);
ms.Write(chunkLen, 0, chunkLen.Length);
ms.Write(newline, 0, newline.Length);
ms.Write(chunk, 0, chunk.Length);
ms.Write(newline, 0, newline.Length);
ms.Seek(0, SeekOrigin.Begin);
byte[] ret = ms.ToArray();
return ret;
}
private byte[] ReadStreamFully(Stream input) private byte[] ReadStreamFully(Stream input)
{ {
if (input == null) if (input == null)

View File

@ -613,8 +613,7 @@ namespace EonaCat.Network
extension = "." + extension; extension = "." + extension;
} }
string mime; return data.TryGetValue(extension.ToLower(), out string mime) ? mime : "application/octet-stream";
return data.TryGetValue(extension.ToLower(), out mime) ? mime : "application/octet-stream";
} }
} }
} }

View File

@ -218,20 +218,5 @@ namespace EonaCat.Network
_Routes.Add(route); _Routes.Add(route);
} }
} }
private void Remove(StaticRoute route)
{
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
lock (_Lock)
{
_Routes.Remove(route);
}
return;
}
} }
} }