mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-04-30 10:47:48 +02:00
Server, Client: Fix thread-safety violations related to NBTConnectionReceiveBuffer
This commit is contained in:
parent
1a8c94ba94
commit
ac403baf41
5 changed files with 180 additions and 165 deletions
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (C) 2014-2023 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
/* Copyright (C) 2014-2024 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||||
*
|
*
|
||||||
* You can redistribute this program and/or modify it under the terms of
|
* You can redistribute this program and/or modify it under the terms of
|
||||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||||
|
@ -172,7 +172,10 @@ namespace SMBLibrary.Client
|
||||||
{
|
{
|
||||||
m_clientSocket.Disconnect(false);
|
m_clientSocket.Disconnect(false);
|
||||||
m_clientSocket.Close();
|
m_clientSocket.Close();
|
||||||
m_connectionState.ReceiveBuffer.Dispose();
|
lock (m_connectionState.ReceiveBuffer)
|
||||||
|
{
|
||||||
|
m_connectionState.ReceiveBuffer.Dispose();
|
||||||
|
}
|
||||||
m_isConnected = false;
|
m_isConnected = false;
|
||||||
m_userID = 0;
|
m_userID = 0;
|
||||||
}
|
}
|
||||||
|
@ -424,63 +427,66 @@ namespace SMBLibrary.Client
|
||||||
ConnectionState state = (ConnectionState)ar.AsyncState;
|
ConnectionState state = (ConnectionState)ar.AsyncState;
|
||||||
Socket clientSocket = state.ClientSocket;
|
Socket clientSocket = state.ClientSocket;
|
||||||
|
|
||||||
if (!clientSocket.Connected)
|
lock (state.ReceiveBuffer)
|
||||||
{
|
{
|
||||||
state.ReceiveBuffer.Dispose();
|
if (!clientSocket.Connected)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int numberOfBytesReceived = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
numberOfBytesReceived = clientSocket.EndReceive(ar);
|
|
||||||
}
|
|
||||||
catch (ArgumentException) // The IAsyncResult object was not returned from the corresponding synchronous method on this class.
|
|
||||||
{
|
|
||||||
state.ReceiveBuffer.Dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (ObjectDisposedException)
|
|
||||||
{
|
|
||||||
Log("[ReceiveCallback] EndReceive ObjectDisposedException");
|
|
||||||
state.ReceiveBuffer.Dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (SocketException ex)
|
|
||||||
{
|
|
||||||
Log("[ReceiveCallback] EndReceive SocketException: " + ex.Message);
|
|
||||||
state.ReceiveBuffer.Dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numberOfBytesReceived == 0)
|
|
||||||
{
|
|
||||||
m_isConnected = false;
|
|
||||||
state.ReceiveBuffer.Dispose();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
|
|
||||||
buffer.SetNumberOfBytesReceived(numberOfBytesReceived);
|
|
||||||
ProcessConnectionBuffer(state);
|
|
||||||
|
|
||||||
if (clientSocket.Connected)
|
|
||||||
{
|
{
|
||||||
try
|
state.ReceiveBuffer.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numberOfBytesReceived = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
numberOfBytesReceived = clientSocket.EndReceive(ar);
|
||||||
|
}
|
||||||
|
catch (ArgumentException) // The IAsyncResult object was not returned from the corresponding synchronous method on this class.
|
||||||
|
{
|
||||||
|
state.ReceiveBuffer.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
Log("[ReceiveCallback] EndReceive ObjectDisposedException");
|
||||||
|
state.ReceiveBuffer.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (SocketException ex)
|
||||||
|
{
|
||||||
|
Log("[ReceiveCallback] EndReceive SocketException: " + ex.Message);
|
||||||
|
state.ReceiveBuffer.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numberOfBytesReceived == 0)
|
||||||
|
{
|
||||||
|
m_isConnected = false;
|
||||||
|
state.ReceiveBuffer.Dispose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
|
||||||
|
buffer.SetNumberOfBytesReceived(numberOfBytesReceived);
|
||||||
|
ProcessConnectionBuffer(state);
|
||||||
|
|
||||||
|
if (clientSocket.Connected)
|
||||||
{
|
{
|
||||||
clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state);
|
try
|
||||||
}
|
{
|
||||||
catch (ObjectDisposedException)
|
clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state);
|
||||||
{
|
}
|
||||||
m_isConnected = false;
|
catch (ObjectDisposedException)
|
||||||
buffer.Dispose();
|
{
|
||||||
Log("[ReceiveCallback] BeginReceive ObjectDisposedException");
|
m_isConnected = false;
|
||||||
}
|
buffer.Dispose();
|
||||||
catch (SocketException ex)
|
Log("[ReceiveCallback] BeginReceive ObjectDisposedException");
|
||||||
{
|
}
|
||||||
m_isConnected = false;
|
catch (SocketException ex)
|
||||||
buffer.Dispose();
|
{
|
||||||
Log("[ReceiveCallback] BeginReceive SocketException: " + ex.Message);
|
m_isConnected = false;
|
||||||
|
buffer.Dispose();
|
||||||
|
Log("[ReceiveCallback] BeginReceive SocketException: " + ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,10 @@ namespace SMBLibrary.Client
|
||||||
{
|
{
|
||||||
m_clientSocket.Disconnect(false);
|
m_clientSocket.Disconnect(false);
|
||||||
m_clientSocket.Close();
|
m_clientSocket.Close();
|
||||||
m_connectionState.ReceiveBuffer.Dispose();
|
lock (m_connectionState.ReceiveBuffer)
|
||||||
|
{
|
||||||
|
m_connectionState.ReceiveBuffer.Dispose();
|
||||||
|
}
|
||||||
m_isConnected = false;
|
m_isConnected = false;
|
||||||
m_messageID = 0;
|
m_messageID = 0;
|
||||||
m_sessionID = 0;
|
m_sessionID = 0;
|
||||||
|
@ -357,63 +360,66 @@ namespace SMBLibrary.Client
|
||||||
ConnectionState state = (ConnectionState)ar.AsyncState;
|
ConnectionState state = (ConnectionState)ar.AsyncState;
|
||||||
Socket clientSocket = state.ClientSocket;
|
Socket clientSocket = state.ClientSocket;
|
||||||
|
|
||||||
if (!clientSocket.Connected)
|
lock (state.ReceiveBuffer)
|
||||||
{
|
{
|
||||||
state.ReceiveBuffer.Dispose();
|
if (!clientSocket.Connected)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int numberOfBytesReceived = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
numberOfBytesReceived = clientSocket.EndReceive(ar);
|
|
||||||
}
|
|
||||||
catch (ArgumentException) // The IAsyncResult object was not returned from the corresponding synchronous method on this class.
|
|
||||||
{
|
|
||||||
state.ReceiveBuffer.Dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (ObjectDisposedException)
|
|
||||||
{
|
|
||||||
Log("[ReceiveCallback] EndReceive ObjectDisposedException");
|
|
||||||
state.ReceiveBuffer.Dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (SocketException ex)
|
|
||||||
{
|
|
||||||
Log("[ReceiveCallback] EndReceive SocketException: " + ex.Message);
|
|
||||||
state.ReceiveBuffer.Dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numberOfBytesReceived == 0)
|
|
||||||
{
|
|
||||||
m_isConnected = false;
|
|
||||||
state.ReceiveBuffer.Dispose();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
|
|
||||||
buffer.SetNumberOfBytesReceived(numberOfBytesReceived);
|
|
||||||
ProcessConnectionBuffer(state);
|
|
||||||
|
|
||||||
if (clientSocket.Connected)
|
|
||||||
{
|
{
|
||||||
try
|
state.ReceiveBuffer.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numberOfBytesReceived = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
numberOfBytesReceived = clientSocket.EndReceive(ar);
|
||||||
|
}
|
||||||
|
catch (ArgumentException) // The IAsyncResult object was not returned from the corresponding synchronous method on this class.
|
||||||
|
{
|
||||||
|
state.ReceiveBuffer.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
Log("[ReceiveCallback] EndReceive ObjectDisposedException");
|
||||||
|
state.ReceiveBuffer.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (SocketException ex)
|
||||||
|
{
|
||||||
|
Log("[ReceiveCallback] EndReceive SocketException: " + ex.Message);
|
||||||
|
state.ReceiveBuffer.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numberOfBytesReceived == 0)
|
||||||
|
{
|
||||||
|
m_isConnected = false;
|
||||||
|
state.ReceiveBuffer.Dispose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
|
||||||
|
buffer.SetNumberOfBytesReceived(numberOfBytesReceived);
|
||||||
|
ProcessConnectionBuffer(state);
|
||||||
|
|
||||||
|
if (clientSocket.Connected)
|
||||||
{
|
{
|
||||||
clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state);
|
try
|
||||||
}
|
{
|
||||||
catch (ObjectDisposedException)
|
clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state);
|
||||||
{
|
}
|
||||||
m_isConnected = false;
|
catch (ObjectDisposedException)
|
||||||
Log("[ReceiveCallback] BeginReceive ObjectDisposedException");
|
{
|
||||||
buffer.Dispose();
|
m_isConnected = false;
|
||||||
}
|
Log("[ReceiveCallback] BeginReceive ObjectDisposedException");
|
||||||
catch (SocketException ex)
|
buffer.Dispose();
|
||||||
{
|
}
|
||||||
m_isConnected = false;
|
catch (SocketException ex)
|
||||||
Log("[ReceiveCallback] BeginReceive SocketException: " + ex.Message);
|
{
|
||||||
buffer.Dispose();
|
m_isConnected = false;
|
||||||
|
Log("[ReceiveCallback] BeginReceive SocketException: " + ex.Message);
|
||||||
|
buffer.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,11 @@ using Utilities;
|
||||||
|
|
||||||
namespace SMBLibrary.NetBios
|
namespace SMBLibrary.NetBios
|
||||||
{
|
{
|
||||||
|
/// <remarks>
|
||||||
|
/// NBTConnectionReceiveBuffer is not thread-safe.
|
||||||
|
/// </remarks>
|
||||||
public class NBTConnectionReceiveBuffer : IDisposable
|
public class NBTConnectionReceiveBuffer : IDisposable
|
||||||
{
|
{
|
||||||
#if NETSTANDARD2_0
|
|
||||||
private object m_bufferSyncLock = new object();
|
|
||||||
#endif
|
|
||||||
private byte[] m_buffer;
|
private byte[] m_buffer;
|
||||||
private int m_readOffset = 0;
|
private int m_readOffset = 0;
|
||||||
private int m_bytesInBuffer = 0;
|
private int m_bytesInBuffer = 0;
|
||||||
|
@ -131,13 +131,10 @@ namespace SMBLibrary.NetBios
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
#if NETSTANDARD2_0
|
#if NETSTANDARD2_0
|
||||||
lock (m_bufferSyncLock)
|
if (m_buffer != null)
|
||||||
{
|
{
|
||||||
if (m_buffer != null)
|
ArrayPool<byte>.Shared.Return(m_buffer);
|
||||||
{
|
m_buffer = null;
|
||||||
ArrayPool<byte>.Shared.Return(m_buffer);
|
|
||||||
m_buffer = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
m_buffer = null;
|
m_buffer = null;
|
||||||
|
|
|
@ -42,7 +42,10 @@ namespace SMBLibrary.Server
|
||||||
connection.SendQueue.Stop();
|
connection.SendQueue.Stop();
|
||||||
SocketUtils.ReleaseSocket(connection.ClientSocket);
|
SocketUtils.ReleaseSocket(connection.ClientSocket);
|
||||||
connection.CloseSessions();
|
connection.CloseSessions();
|
||||||
connection.ReceiveBuffer.Dispose();
|
lock (connection.ReceiveBuffer)
|
||||||
|
{
|
||||||
|
connection.ReceiveBuffer.Dispose();
|
||||||
|
}
|
||||||
RemoveConnection(connection);
|
RemoveConnection(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -230,63 +230,66 @@ namespace SMBLibrary.Server
|
||||||
ConnectionState state = (ConnectionState)result.AsyncState;
|
ConnectionState state = (ConnectionState)result.AsyncState;
|
||||||
Socket clientSocket = state.ClientSocket;
|
Socket clientSocket = state.ClientSocket;
|
||||||
|
|
||||||
if (!m_listening)
|
lock (state.ReceiveBuffer)
|
||||||
{
|
{
|
||||||
clientSocket.Close();
|
if (!m_listening)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int numberOfBytesReceived;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
numberOfBytesReceived = clientSocket.EndReceive(result);
|
|
||||||
}
|
|
||||||
catch (ObjectDisposedException)
|
|
||||||
{
|
|
||||||
state.LogToServer(Severity.Debug, "The connection was terminated");
|
|
||||||
m_connectionManager.ReleaseConnection(state);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (SocketException ex)
|
|
||||||
{
|
|
||||||
const int WSAECONNRESET = 10054;
|
|
||||||
if (ex.ErrorCode == WSAECONNRESET)
|
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Debug, "The connection was forcibly closed by the remote host");
|
clientSocket.Close();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
state.LogToServer(Severity.Debug, "The connection was terminated, Socket error code: {0}", ex.ErrorCode);
|
|
||||||
}
|
|
||||||
m_connectionManager.ReleaseConnection(state);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numberOfBytesReceived == 0)
|
int numberOfBytesReceived;
|
||||||
{
|
|
||||||
state.LogToServer(Severity.Debug, "The client closed the connection");
|
|
||||||
m_connectionManager.ReleaseConnection(state);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.UpdateLastReceiveDT();
|
|
||||||
NBTConnectionReceiveBuffer receiveBuffer = state.ReceiveBuffer;
|
|
||||||
receiveBuffer.SetNumberOfBytesReceived(numberOfBytesReceived);
|
|
||||||
ProcessConnectionBuffer(ref state);
|
|
||||||
|
|
||||||
if (clientSocket.Connected)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
clientSocket.BeginReceive(state.ReceiveBuffer.Buffer, state.ReceiveBuffer.WriteOffset, state.ReceiveBuffer.AvailableLength, 0, ReceiveCallback, state);
|
numberOfBytesReceived = clientSocket.EndReceive(result);
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException)
|
catch (ObjectDisposedException)
|
||||||
{
|
{
|
||||||
|
state.LogToServer(Severity.Debug, "The connection was terminated");
|
||||||
m_connectionManager.ReleaseConnection(state);
|
m_connectionManager.ReleaseConnection(state);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (SocketException)
|
catch (SocketException ex)
|
||||||
{
|
{
|
||||||
|
const int WSAECONNRESET = 10054;
|
||||||
|
if (ex.ErrorCode == WSAECONNRESET)
|
||||||
|
{
|
||||||
|
state.LogToServer(Severity.Debug, "The connection was forcibly closed by the remote host");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.LogToServer(Severity.Debug, "The connection was terminated, Socket error code: {0}", ex.ErrorCode);
|
||||||
|
}
|
||||||
m_connectionManager.ReleaseConnection(state);
|
m_connectionManager.ReleaseConnection(state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numberOfBytesReceived == 0)
|
||||||
|
{
|
||||||
|
state.LogToServer(Severity.Debug, "The client closed the connection");
|
||||||
|
m_connectionManager.ReleaseConnection(state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.UpdateLastReceiveDT();
|
||||||
|
NBTConnectionReceiveBuffer receiveBuffer = state.ReceiveBuffer;
|
||||||
|
receiveBuffer.SetNumberOfBytesReceived(numberOfBytesReceived);
|
||||||
|
ProcessConnectionBuffer(ref state);
|
||||||
|
|
||||||
|
if (clientSocket.Connected)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
clientSocket.BeginReceive(state.ReceiveBuffer.Buffer, state.ReceiveBuffer.WriteOffset, state.ReceiveBuffer.AvailableLength, 0, ReceiveCallback, state);
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
m_connectionManager.ReleaseConnection(state);
|
||||||
|
}
|
||||||
|
catch (SocketException)
|
||||||
|
{
|
||||||
|
m_connectionManager.ReleaseConnection(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue