diff --git a/README.md b/README.md
index 862b829..1d7ca38 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ A spinoff library of Dache that provides highly efficient, scalable, simple sock
**NUGET:** http://www.nuget.org/packages/SimplSockets
-**WEB:** http://www.getdache.net
+**WEB:** http://www.getdache.net
**EMAIL:** info@getdache.net
@@ -15,6 +15,23 @@ VERSION HISTORY
============================================
+1.1.0
+------------------
+
+
+- Fixed multiple bugs in how SimplSocket class handled communication errors.
+
+- Fixed bugs that could cause infinite client hang in the case that the server stopped responding.
+
+- Fixed semaphore calculation bugs.
+
+- Errors are now handled gracefully and correctly, with atomic exception raising via the passed in error handler event delegate.
+
+- Slight performance improvements enabled by smoother connection error handling.
+
+- Special thanks to Ruslan (https://github.com/ruzhovt) for discovering and documenting the source of these errors.
+
+
1.0.1
------------------
diff --git a/SimplSockets/ISimplSocketClient.cs b/SimplSockets/ISimplSocketClient.cs
index 1fa83e8..8770863 100644
--- a/SimplSockets/ISimplSocketClient.cs
+++ b/SimplSockets/ISimplSocketClient.cs
@@ -9,13 +9,11 @@ namespace SimplSockets
public interface ISimplSocketClient : IDisposable
{
///
- /// Connects to an endpoint. Once this is called, you must call Close before calling Connect or Listen again. The errorHandler method
- /// will not be called if the connection fails. Instead this method will return false.
+ /// Connects to an endpoint. Once this is called, you must call Close before calling Connect or Listen again. This method will not raise an error.
///
/// The endpoint.
- /// The error handler.
/// true if connection is successful, false otherwise.
- bool Connect(EndPoint endPoint, EventHandler errorHandler);
+ bool Connect(EndPoint endPoint);
///
/// Sends a message to the server without waiting for a response (one-way communication).
diff --git a/SimplSockets/ISimplSocketServer.cs b/SimplSockets/ISimplSocketServer.cs
index deab448..3ceab59 100644
--- a/SimplSockets/ISimplSocketServer.cs
+++ b/SimplSockets/ISimplSocketServer.cs
@@ -12,8 +12,7 @@ public interface ISimplSocketServer : IDisposable
/// Begin listening for incoming connections. Once this is called, you must call Close before calling Connect or Listen again.
///
/// The local endpoint to listen on.
- /// The error handler.
- void Listen(EndPoint localEndpoint, EventHandler errorHandler);
+ void Listen(EndPoint localEndpoint);
///
/// Sends a message back to the client.
diff --git a/SimplSockets/SimplSocket.cs b/SimplSockets/SimplSocket.cs
index 6d8a9bf..2421adc 100644
--- a/SimplSockets/SimplSocket.cs
+++ b/SimplSockets/SimplSocket.cs
@@ -58,40 +58,57 @@ public class SimplSocket : ISimplSocketClient, ISimplSocketServer, IDisposable
/// Create a client.
///
/// The function that creates a new socket. Use this to specify your socket constructor and initialize settings.
+ /// The error handler that is raised when a Socket error occurs.
/// The message buffer size to use for send/receive.
/// The maximum connections to allow to use the socket simultaneously.
/// Whether or not to use the Nagle algorithm.
- public static ISimplSocketClient CreateClient(Func socketFunc, int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
+ public static ISimplSocketClient CreateClient(Func socketFunc, EventHandler errorHandler, int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
{
- return new SimplSocket(socketFunc, messageBufferSize, maximumConnections, useNagleAlgorithm);
+ return new SimplSocket(socketFunc, errorHandler, messageBufferSize, maximumConnections, useNagleAlgorithm);
}
///
/// Create a server.
///
/// The function that creates a new socket. Use this to specify your socket constructor and initialize settings.
+ /// The error handler that is raised when a Socket error occurs.
+ /// The message handler that handles incoming messages.
/// The message buffer size to use for send/receive.
/// The maximum connections to allow to use the socket simultaneously.
/// Whether or not to use the Nagle algorithm.
- public static ISimplSocketServer CreateServer(Func socketFunc, int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
+ public static ISimplSocketServer CreateServer(Func socketFunc, EventHandler errorHandler, EventHandler messageHandler,
+ int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
{
- return new SimplSocket(socketFunc, messageBufferSize, maximumConnections, useNagleAlgorithm);
+ // Sanitize
+ if (messageHandler == null)
+ {
+ throw new ArgumentNullException("messageHandler");
+ }
+
+ var simplSocket = new SimplSocket(socketFunc, errorHandler, messageBufferSize, maximumConnections, useNagleAlgorithm);
+ simplSocket.MessageReceived += messageHandler;
+ return simplSocket;
}
///
/// The private constructor - used to enforce factor-style instantiation.
///
/// The function that creates a new socket. Use this to specify your socket constructor and initialize settings.
+ /// The error handler that is raised when a Socket error occurs.
/// The message buffer size to use for send/receive.
/// The maximum connections to allow to use the socket simultaneously.
/// Whether or not to use the Nagle algorithm.
- private SimplSocket(Func socketFunc, int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
+ private SimplSocket(Func socketFunc, EventHandler errorHandler, int messageBufferSize, int maximumConnections, bool useNagleAlgorithm)
{
// Sanitize
if (socketFunc == null)
{
throw new ArgumentNullException("socketFunc");
}
+ if (errorHandler == null)
+ {
+ throw new ArgumentNullException("errorHandler");
+ }
if (messageBufferSize < 128)
{
throw new ArgumentException("must be >= 128", "messageBufferSize");
@@ -102,6 +119,7 @@ private SimplSocket(Func socketFunc, int messageBufferSize, int maximumC
}
_socketFunc = socketFunc;
+ Error += errorHandler;
_messageBufferSize = messageBufferSize;
_maximumConnections = maximumConnections;
_maxConnectionsSemaphore = new Semaphore(maximumConnections, maximumConnections);
@@ -158,9 +176,8 @@ public int CurrentlyConnectedClients
/// will not be called if the connection fails. Instead this method will return false.
///
/// The endpoint.
- /// The error handler.
/// true if connection is successful, false otherwise.
- public bool Connect(EndPoint endPoint, EventHandler errorHandler)
+ public bool Connect(EndPoint endPoint)
{
// Sanitize
if (_isDoingSomething)
@@ -171,10 +188,6 @@ public bool Connect(EndPoint endPoint, EventHandler errorHandle
{
throw new ArgumentNullException("endPoint");
}
- if (errorHandler == null)
- {
- throw new ArgumentNullException("errorHandler");
- }
_isDoingSomething = true;
_useClientMultiplexer = true;
@@ -196,12 +209,10 @@ public bool Connect(EndPoint endPoint, EventHandler errorHandle
}
catch (SocketException ex)
{
+ _isDoingSomething = false;
return false;
}
- // Register error handler
- Error += errorHandler;
-
// Get a message state from the pool
var messageState = _messageStatePool.Pop();
messageState.Data = new MemoryStream();
@@ -233,8 +244,7 @@ public bool Connect(EndPoint endPoint, EventHandler errorHandle
/// Begin listening for incoming connections. Once this is called, you must call Close before calling Connect or Listen again.
///
/// The local endpoint to listen on.
- /// The error handler.
- public void Listen(EndPoint localEndpoint, EventHandler errorHandler)
+ public void Listen(EndPoint localEndpoint)
{
// Sanitize
if (_isDoingSomething)
@@ -245,16 +255,9 @@ public void Listen(EndPoint localEndpoint, EventHandler errorHa
{
throw new ArgumentNullException("localEndpoint");
}
- if (errorHandler == null)
- {
- throw new ArgumentNullException("errorHandler");
- }
_isDoingSomething = true;
- // Register error handler
- Error += errorHandler;
-
// Create socket
_socket = _socketFunc();