Hello,
I'm having an unusual problem with Rebex.Tls sockets.
The code:
private async Task StartServer() // Starts server
{
try
{
var address = IPAddress.Parse("127.0.0.1");
var port = Int32.Parse("5678");
_server = new AbcSocketServer(new SocketSettings(), _logger, _tlsLogConfiguration, _context.ServerCertificate);
_server.OnConnection += OnConnectionA; // add new connection
_server.StartListen(new IPEndPoint(address, port), 100);
_logger.Info($"Server started. Listening on {address}:{port} ...");
}
catch (Exception ex)
{
_logger.ErrorFormat("The application failed to start correctly. {0}", ex);
}
}
private void OnConnectionA(object sender, SecureConnectionArgs e)
{
Task.Run(async () =>
{
LogNewConnection(e.Ssl.Socket);
SecureConnectionArgs client = e;
try
{
while (e.Ssl.Connected)
{
ReceivedData received = await PullData(2048, e); // Exception
if (received.BytesCount == 0)
{
await e.Ssl.DisposeAsync();
break;
}
string req = Encoding.UTF8.GetString(received.MessageData).TrimEnd('\0');
if (!string.IsNullOrEmpty(req))
{
_logger.Info("Received: " + req);
}
}
}
catch (Exception ex)
{
_logger.Error($"Received unexpected error: {ex.Message} \n{ex.StackTrace}");
}
finally
{
LogDisconect(client.Ssl.Socket);
client.Ssl.Dispose();
var socketId = _manager.GetAllSockets().FirstOrDefault(s => s.Value == client).Key;
_logger.Warn($"Disconnected {socketId}");
}
});
}
private async Task<ReceivedData> PullData(int chunkSize, SecureConnectionArgs e)
{
byte[] messageData = new byte[0];
byte[] dataChunk;
int bytesReceived = 0;
int available = int.MaxValue;
while (available > 0)
{
dataChunk = new byte[chunkSize];
bytesReceived += await e.Ssl.ReceiveAsync(dataChunk);
messageData = messageData.Concat(dataChunk).ToArray();
available = e.Ssl.Available;
}
return new ReceivedData(messageData, bytesReceived);
}
public ExampleResponse ExampleMethod(string socketId, string id)
{
var client = _manager.GetAllSockets().FirstOrDefault(s => s.Key == socketId); // Get socket from KeyValuePair<string, SecureConnectionArgs>
try
{
if(client.Value == null || IsSocketAlive(client.Value)) // Check if socket is not null or is still connected
{
_log.Info("Offline");
return new ExampleResponse
{
ErrorCode = ErrorCodes.Offline,
ErrorMessage = $"Socket {socketId} is offline"
};
}
else
{
var message = new ExampleMessage
{
text = "Sending a message"
};
_log.Info("Sending...");
var xmlMsg = message.SerializeMessage(); // Serialize message to XML
client.Value.Ssl.SendAsync(Encoding.UTF8.GetBytes(xmlMsg)); // Sends message to socket
}
}
catch(Exception ex)
{
_log.Error($"Exception with socket {socketId}: {ex}");
return new ExampleResponse
{
ErrorCode = ErrorCodes.InternalError,
ErrorMessage = $"Internal error has occured with socket {socketId}"
};
}
// If we came this far the message has been sent
return new ExampleResponse
{
ErrorCode = ErrorCodes.Success,
ErrorMessage = "None"
};
}
private bool IsSocketAlive(SecureConnectionArgs client) // Checks if socket is still online
{
return (client.Ssl.Poll(1, SocketSelectMode.SelectRead) && client.Ssl.Available == 0)
}
Now the problem with this code is that when the ethernet cable gets unplugged it does not fail to send a message to the socket and it returns that the message has been sent.
But after a couple of seconds we do get an Exeption OnConnectionA (See // Exception)
Received unexpected error: Connection was closed by the remote connection end.
at gcrvw.qwujb.xslib()
at gcrvw.nduus.mmyho(Task p0, Func`1 p1)
at gcrvw.qwujb.xulmm()
at gcrvw.qwujb.gmkrt(Byte[] p0, Int32 p1, Int32 p2, Boolean p3)
at gcrvw.nduus.uapvn[TR](Task`1 p0, Func`1 p1)
at gcrvw.qwujb.ofafp(Byte[] p0, Int32 p1, Int32 p2, Boolean p3)
at gcrvw.npgii.iurrr(ArraySegment`1 p0)
at Rebex.Net.TlsSocket.ReceiveAsync(ArraySegment`1 buffer)
How can we make sure that the socket is alive and receives the message from ExampleMethod?
Because it sends the message and returns that everything is ok.
How can we make sure that the socket before sending the message is still alive if it disconnects ungracefully (ethernet cable unplugged)?
When we disable the network adapter all statuses change and we are able to identify that the socket was disconnected only when disconnecting ungracefully (ethernet cable unplugged) we dont know because statuses do not change.
Scenario:
1. Socket connects and is added to _manager list
2. Unplug ethernet cable from computer
3. Initiate ExampleMethod() - Send to socket
4. client.Value.Ssl.SendAsync(Encoding.UTF8.GetBytes(xmlMsg)); - this line passes without errors even with disconnected ethernet cable
5. After ~10 seconds we get Exception in bytesReceived += await e.Ssl.ReceiveAsync(dataChunk);
We dont understand why 4. Did not throw exception? We need to know here if the message was sent successfully.
- .NET Core 3.1
- Rebex.Tls (5.0.7579)