From d3138aa97cb0556f9db947cfdd6e5118d5c94d44 Mon Sep 17 00:00:00 2001 From: KoenPlasmans Date: Thu, 24 Mar 2022 18:46:39 +0100 Subject: [PATCH] Add connect asynchronous --- Lansweeper.SMBLibrary.nuspec | 6 +- SMBLibrary.Tests/SMBLibrary.Tests.csproj | 2 +- SMBLibrary/Client/ISMBClient.cs | 4 +- SMBLibrary/Client/SMB1Client.cs | 281 +++++++++++++++++++++- SMBLibrary/Client/SMB2Client.cs | 294 +++++++++++++++++++++++ SMBLibrary/SMBLibrary.csproj | 4 +- 6 files changed, 583 insertions(+), 8 deletions(-) diff --git a/Lansweeper.SMBLibrary.nuspec b/Lansweeper.SMBLibrary.nuspec index b7c04d9..bf52e29 100644 --- a/Lansweeper.SMBLibrary.nuspec +++ b/Lansweeper.SMBLibrary.nuspec @@ -3,7 +3,7 @@ Lansweeper.SMBLibrary - 1.5.0 + 1.6.0 Lansweeper.SMBLibrary TalAloni/Lansweeper SMBLibrary is an open-source C# SMB 1.0/CIFS, SMB 2.0, SMB 2.1 and SMB 3.0 server and client implementation. @@ -20,7 +20,7 @@ - + @@ -32,7 +32,7 @@ - + diff --git a/SMBLibrary.Tests/SMBLibrary.Tests.csproj b/SMBLibrary.Tests/SMBLibrary.Tests.csproj index 9d7f95d..26a343e 100644 --- a/SMBLibrary.Tests/SMBLibrary.Tests.csproj +++ b/SMBLibrary.Tests/SMBLibrary.Tests.csproj @@ -1,7 +1,7 @@  - net40 + net48 false SMBLibrary.Tests SMBLibrary.Tests diff --git a/SMBLibrary/Client/ISMBClient.cs b/SMBLibrary/Client/ISMBClient.cs index e4b66e0..abf503f 100644 --- a/SMBLibrary/Client/ISMBClient.cs +++ b/SMBLibrary/Client/ISMBClient.cs @@ -4,9 +4,9 @@ * the GNU Lesser Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. */ -using System; using System.Collections.Generic; using System.Net; +using System.Threading.Tasks; namespace SMBLibrary.Client { @@ -14,6 +14,8 @@ namespace SMBLibrary.Client { bool Connect(IPAddress serverAddress, SMBTransportType transport, string serverName = null); + Task ConnectAsync(IPAddress serverAddress, SMBTransportType transport, string serverName = null); + void Disconnect(); NTStatus Login(string domainName, string userName, string password); diff --git a/SMBLibrary/Client/SMB1Client.cs b/SMBLibrary/Client/SMB1Client.cs index 2a1a84e..cad06e1 100644 --- a/SMBLibrary/Client/SMB1Client.cs +++ b/SMBLibrary/Client/SMB1Client.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; +using System.Threading.Tasks; using SMBLibrary.Authentication.NTLM; using SMBLibrary.NetBios; using SMBLibrary.Services; @@ -69,6 +70,79 @@ namespace SMBLibrary.Client return Connect(serverAddress, transport, false, serverName); } + public Task ConnectAsync(IPAddress serverAddress, SMBTransportType transport, string serverName = null) + { + return ConnectAsync(serverAddress, transport, false, serverName); + } + + public async Task ConnectAsync(IPAddress serverAddress, SMBTransportType transport, bool forceExtendedSecurity, string serverName = null) + { + m_transport = transport; + if (!m_isConnected) + { + m_forceExtendedSecurity = forceExtendedSecurity; + int port; + port = transport == SMBTransportType.NetBiosOverTCP ? NetBiosOverTCPPort : DirectTCPPort; + + if (!await ConnectSocketAsync(serverAddress, port)) + { + return false; + } + + if (transport == SMBTransportType.NetBiosOverTCP) + { + SessionRequestPacket sessionRequest = new SessionRequestPacket(); + sessionRequest.CalledName = NetBiosUtils.GetMSNetBiosName(serverName ?? "*SMBSERVER", NetBiosSuffix.FileServiceService); + sessionRequest.CallingName = NetBiosUtils.GetMSNetBiosName(Environment.MachineName, NetBiosSuffix.WorkstationService); + await TrySendPacketAsync(m_clientSocket, sessionRequest); + + SessionPacket sessionResponsePacket = await WaitForSessionResponsePacketAsync(); + if (!(sessionResponsePacket is PositiveSessionResponsePacket)) + { + var socketAsyncEventArgs = new SocketAsyncEventArgs + { + DisconnectReuseSocket = false + }; + var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Disconnect); + m_clientSocket.DisconnectAsync(socketAsyncEventArgs); + await task; + + if (!await ConnectSocketAsync(serverAddress, port)) + { + return false; + } + + NameServiceClient nameServiceClient = new NameServiceClient(serverAddress); + serverName = nameServiceClient.GetServerName(); + if (serverName == null) + { + return false; + } + + sessionRequest.CalledName = serverName; + await TrySendPacketAsync(m_clientSocket, sessionRequest); + + sessionResponsePacket = await WaitForSessionResponsePacketAsync(); + if (!(sessionResponsePacket is PositiveSessionResponsePacket)) + { + return false; + } + } + } + + bool supportsDialect = await NegotiateDialectAsync(m_forceExtendedSecurity); + if (!supportsDialect) + { + m_clientSocket.Close(); + } + else + { + m_isConnected = true; + } + } + return m_isConnected; + } + public bool Connect(IPAddress serverAddress, SMBTransportType transport, bool forceExtendedSecurity, string serverName = null) { m_transport = transport; @@ -149,6 +223,31 @@ namespace SMBLibrary.Client return true; } + private async Task ConnectSocketAsync(IPAddress serverAddress, int port) + { + m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + + try + { + var socketAsyncEventArgs = new SocketAsyncEventArgs + { + RemoteEndPoint = new IPEndPoint(serverAddress, port) + }; + var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Connect); + m_clientSocket.ConnectAsync(socketAsyncEventArgs); + await task; + } + catch (SocketException) + { + return false; + } + + ConnectionState state = new ConnectionState(m_clientSocket); + NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer; + m_clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state); + return true; + } + public void Disconnect() { if (m_isConnected) @@ -158,6 +257,21 @@ namespace SMBLibrary.Client } } + public async Task DisconnectAsync() + { + if (m_isConnected) + { + var socketAsyncEventArgs = new SocketAsyncEventArgs + { + DisconnectReuseSocket = false + }; + var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Disconnect); + m_clientSocket.DisconnectAsync(socketAsyncEventArgs); + await task; + m_isConnected = false; + } + } + private bool NegotiateDialect(bool forceExtendedSecurity) { NegotiateRequest request = new NegotiateRequest(); @@ -211,6 +325,59 @@ namespace SMBLibrary.Client } } + private async Task NegotiateDialectAsync(bool forceExtendedSecurity) + { + NegotiateRequest request = new NegotiateRequest(); + request.Dialects.Add(NTLanManagerDialect); + + await TrySendMessageAsync(request); + SMB1Message reply = await WaitForMessageAsync(CommandName.SMB_COM_NEGOTIATE); + if (reply == null) + { + return false; + } + + if (reply.Commands[0] is NegotiateResponse && !forceExtendedSecurity) + { + NegotiateResponse response = (NegotiateResponse)reply.Commands[0]; + Domainname = response.DomainName; + Hostname = response.ServerName; + + m_unicode = ((response.Capabilities & Capabilities.Unicode) > 0); + m_largeFiles = ((response.Capabilities & Capabilities.LargeFiles) > 0); + bool ntSMB = ((response.Capabilities & Capabilities.NTSMB) > 0); + bool rpc = ((response.Capabilities & Capabilities.RpcRemoteApi) > 0); + bool ntStatusCode = ((response.Capabilities & Capabilities.NTStatusCode) > 0); + m_infoLevelPassthrough = ((response.Capabilities & Capabilities.InfoLevelPassthrough) > 0); + m_largeRead = ((response.Capabilities & Capabilities.LargeRead) > 0); + m_largeWrite = ((response.Capabilities & Capabilities.LargeWrite) > 0); + m_serverMaxBufferSize = response.MaxBufferSize; + m_maxMpxCount = Math.Min(response.MaxMpxCount, ClientMaxMpxCount); + m_serverChallenge = response.Challenge; + return ntSMB && rpc && ntStatusCode; + } + else if (reply.Commands[0] is NegotiateResponseExtended) + { + NegotiateResponseExtended response = (NegotiateResponseExtended)reply.Commands[0]; + m_unicode = ((response.Capabilities & Capabilities.Unicode) > 0); + m_largeFiles = ((response.Capabilities & Capabilities.LargeFiles) > 0); + bool ntSMB = ((response.Capabilities & Capabilities.NTSMB) > 0); + bool rpc = ((response.Capabilities & Capabilities.RpcRemoteApi) > 0); + bool ntStatusCode = ((response.Capabilities & Capabilities.NTStatusCode) > 0); + m_infoLevelPassthrough = ((response.Capabilities & Capabilities.InfoLevelPassthrough) > 0); + m_largeRead = ((response.Capabilities & Capabilities.LargeRead) > 0); + m_largeWrite = ((response.Capabilities & Capabilities.LargeWrite) > 0); + m_serverMaxBufferSize = response.MaxBufferSize; + m_maxMpxCount = Math.Min(response.MaxMpxCount, ClientMaxMpxCount); + m_securityBlob = response.SecurityBlob; + return ntSMB && rpc && ntStatusCode; + } + else + { + return false; + } + } + public NTStatus Login(string domainName, string userName, string password) { return Login(domainName, userName, password, AuthenticationMethod.NTLMv2); @@ -554,6 +721,32 @@ namespace SMBLibrary.Client } } + internal async Task WaitForMessageAsync(CommandName commandName) + { + const int TimeOut = 5000; + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + while (stopwatch.ElapsedMilliseconds < TimeOut) + { + lock (m_incomingQueueLock) + { + for (int index = 0; index < m_incomingQueue.Count; index++) + { + SMB1Message message = m_incomingQueue[index]; + + if (message.Commands[0].CommandName == commandName) + { + m_incomingQueue.RemoveAt(index); + return message; + } + } + } + await Task.Delay(99); + m_incomingQueueEventHandle.WaitOne(1); + } + return null; + } + internal SMB1Message WaitForMessage(CommandName commandName) { const int TimeOut = 5000; @@ -599,6 +792,27 @@ namespace SMBLibrary.Client return null; } + internal async Task WaitForSessionResponsePacketAsync() + { + const int TimeOut = 5000; + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + while (stopwatch.ElapsedMilliseconds < TimeOut) + { + if (m_sessionResponsePacket != null) + { + SessionPacket result = m_sessionResponsePacket; + m_sessionResponsePacket = null; + return result; + } + + await Task.Delay(99); + m_sessionResponseEventHandle.WaitOne(1); + } + + return null; + } + private void Log(string message) { System.Diagnostics.Debug.Print(message); @@ -621,6 +835,23 @@ namespace SMBLibrary.Client TrySendMessage(m_clientSocket, message); } + internal Task TrySendMessageAsync(SMB1Command request) + { + return TrySendMessageAsync(request, 0); + } + + internal Task TrySendMessageAsync(SMB1Command request, ushort treeID) + { + SMB1Message message = new SMB1Message(); + message.Header.UnicodeFlag = m_unicode; + message.Header.ExtendedSecurityFlag = m_forceExtendedSecurity; + message.Header.Flags2 |= HeaderFlags2.LongNamesAllowed | HeaderFlags2.LongNameUsed | HeaderFlags2.NTStatusCode; + message.Header.UID = m_userID; + message.Header.TID = treeID; + message.Commands.Add(request); + return TrySendMessageAsync(m_clientSocket, message); + } + public bool Unicode { get @@ -705,6 +936,15 @@ namespace SMBLibrary.Client TrySendPacket(socket, packet); } + public static Task TrySendMessageAsync(Socket socket, SMB1Message message) + { + SessionMessagePacket packet = new SessionMessagePacket + { + Trailer = message.GetBytes() + }; + return TrySendPacketAsync(socket, packet); + } + public static void TrySendPacket(Socket socket, SessionPacket packet) { try @@ -719,5 +959,44 @@ namespace SMBLibrary.Client { } } + + public static async Task TrySendPacketAsync(Socket socket, SessionPacket packet) + { + try + { + byte[] packetBytes = packet.GetBytes(); + var socketAsyncEventArgs = new SocketAsyncEventArgs(); + socketAsyncEventArgs.SetBuffer(packetBytes, 0, packetBytes.Length); + var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Send); + socket.SendAsync(socketAsyncEventArgs); + await task; + } + catch (SocketException) + { + } + catch (ObjectDisposedException) + { + } + } + + private static Task CreateTaskFromCompletionHandler(SocketAsyncEventArgs socketAsyncEventArgs, SocketAsyncOperation socketAsyncOperation) + { + TaskCompletionSource completionSource = new TaskCompletionSource(); + socketAsyncEventArgs.Completed += new EventHandler((o, eventArgs) => + { + if (eventArgs.LastOperation == socketAsyncOperation) + { + if (eventArgs.SocketError == SocketError.Success) + { + completionSource.SetResult(""); + } + else + { + completionSource.SetException(new SocketException((int)eventArgs.SocketError)); + } + } + }); + return completionSource.Task; + } } -} +} \ No newline at end of file diff --git a/SMBLibrary/Client/SMB2Client.cs b/SMBLibrary/Client/SMB2Client.cs index 0cf9794..c89dabf 100644 --- a/SMBLibrary/Client/SMB2Client.cs +++ b/SMBLibrary/Client/SMB2Client.cs @@ -11,6 +11,7 @@ using System.Net; using System.Net.Sockets; using System.Security.Cryptography; using System.Threading; +using System.Threading.Tasks; using SMBLibrary.Authentication.NTLM; using SMBLibrary.NetBios; using SMBLibrary.Services; @@ -120,6 +121,73 @@ namespace SMBLibrary.Client return m_isConnected; } + public async Task ConnectAsync(IPAddress serverAddress, SMBTransportType transport, string serverName = null) + { + m_transport = transport; + if (!m_isConnected) + { + int port; + port = transport == SMBTransportType.NetBiosOverTCP ? NetBiosOverTCPPort : DirectTCPPort; + + if (!await ConnectSocketAsync(serverAddress, port)) + { + return false; + } + + if (transport == SMBTransportType.NetBiosOverTCP) + { + SessionRequestPacket sessionRequest = new SessionRequestPacket(); + sessionRequest.CalledName = NetBiosUtils.GetMSNetBiosName(serverName ?? "*SMBSERVER", NetBiosSuffix.FileServiceService); + sessionRequest.CallingName = NetBiosUtils.GetMSNetBiosName(Environment.MachineName, NetBiosSuffix.WorkstationService); + TrySendPacket(m_clientSocket, sessionRequest); + + SessionPacket sessionResponsePacket = await WaitForSessionResponsePacketAsync(); + if (!(sessionResponsePacket is PositiveSessionResponsePacket)) + { + var socketAsyncEventArgs = new SocketAsyncEventArgs + { + DisconnectReuseSocket = false + }; + var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Disconnect); + m_clientSocket.DisconnectAsync(socketAsyncEventArgs); + await task; + + if (!await ConnectSocketAsync(serverAddress, port)) + { + return false; + } + + NameServiceClient nameServiceClient = new NameServiceClient(serverAddress); + serverName = nameServiceClient.GetServerName(); + if (serverName == null) + { + return false; + } + + sessionRequest.CalledName = serverName; + await TrySendPacketAsync(m_clientSocket, sessionRequest); + + sessionResponsePacket = await WaitForSessionResponsePacketAsync(); + if (!(sessionResponsePacket is PositiveSessionResponsePacket)) + { + return false; + } + } + } + + bool supportsDialect = await NegotiateDialectAsync(); + if (!supportsDialect) + { + m_clientSocket.Close(); + } + else + { + m_isConnected = true; + } + } + return m_isConnected; + } + private bool ConnectSocket(IPAddress serverAddress, int port) { m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); @@ -139,6 +207,31 @@ namespace SMBLibrary.Client return true; } + private async Task ConnectSocketAsync(IPAddress serverAddress, int port) + { + m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + + try + { + var socketAsyncEventArgs = new SocketAsyncEventArgs + { + RemoteEndPoint = new IPEndPoint(serverAddress, port) + }; + var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Connect); + m_clientSocket.ConnectAsync(socketAsyncEventArgs); + await task; + } + catch (SocketException) + { + return false; + } + + ConnectionState state = new ConnectionState(m_clientSocket); + NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer; + m_clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state); + return true; + } + public void Disconnect() { if (m_isConnected) @@ -148,6 +241,47 @@ namespace SMBLibrary.Client } } + public async Task DisconnectAsync() + { + if (m_isConnected) + { + var socketAsyncEventArgs = new SocketAsyncEventArgs + { + DisconnectReuseSocket = false + }; + var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Disconnect); + m_clientSocket.DisconnectAsync(socketAsyncEventArgs); + await task; + m_isConnected = false; + } + } + + private async Task NegotiateDialectAsync() + { + NegotiateRequest request = new NegotiateRequest(); + request.SecurityMode = SecurityMode.SigningEnabled; + request.Capabilities = Capabilities.Encryption; + request.ClientGuid = Guid.NewGuid(); + request.ClientStartTime = DateTime.Now; + request.Dialects.Add(SMB2Dialect.SMB202); + request.Dialects.Add(SMB2Dialect.SMB210); + request.Dialects.Add(SMB2Dialect.SMB300); + + await TrySendCommandAsync(request); + NegotiateResponse response = await WaitForCommandAsync(SMB2CommandName.Negotiate) as NegotiateResponse; + if (response != null && response.Header.Status == NTStatus.STATUS_SUCCESS) + { + m_dialect = response.DialectRevision; + m_signingRequired = (response.SecurityMode & SecurityMode.SigningRequired) > 0; + m_maxTransactSize = Math.Min(response.MaxTransactSize, ClientMaxTransactSize); + m_maxReadSize = Math.Min(response.MaxReadSize, ClientMaxReadSize); + m_maxWriteSize = Math.Min(response.MaxWriteSize, ClientMaxWriteSize); + m_securityBlob = response.SecurityBuffer; + return true; + } + return false; + } + private bool NegotiateDialect() { NegotiateRequest request = new NegotiateRequest(); @@ -512,6 +646,52 @@ namespace SMBLibrary.Client return null; } + internal async Task WaitForCommandAsync(SMB2CommandName commandName) + { + const int TimeOut = 5000; + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + while (stopwatch.ElapsedMilliseconds < TimeOut) + { + lock (m_incomingQueueLock) + { + for (int index = 0; index < m_incomingQueue.Count; index++) + { + SMB2Command command = m_incomingQueue[index]; + + if (command.CommandName == commandName) + { + m_incomingQueue.RemoveAt(index); + return command; + } + } + } + await Task.Delay(99); + m_incomingQueueEventHandle.WaitOne(1); + } + return null; + } + + internal async Task WaitForSessionResponsePacketAsync() + { + const int TimeOut = 5000; + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + while (stopwatch.ElapsedMilliseconds < TimeOut) + { + if (m_sessionResponsePacket != null) + { + SessionPacket result = m_sessionResponsePacket; + m_sessionResponsePacket = null; + return result; + } + await Task.Delay(99); + m_sessionResponseEventHandle.WaitOne(1); + } + + return null; + } + internal SessionPacket WaitForSessionResponsePacket() { const int TimeOut = 5000; @@ -597,6 +777,66 @@ namespace SMBLibrary.Client } } + internal Task TrySendCommandAsync(SMB2Command request) + { + return TrySendCommandAsync(request, m_encryptSessionData); + } + + internal async Task TrySendCommandAsync(SMB2Command request, bool encryptData) + { + if (m_dialect == SMB2Dialect.SMB202 || m_transport == SMBTransportType.NetBiosOverTCP) + { + request.Header.CreditCharge = 0; + request.Header.Credits = 1; + m_availableCredits -= 1; + } + else + { + if (request.Header.CreditCharge == 0) + { + request.Header.CreditCharge = 1; + } + + if (m_availableCredits < request.Header.CreditCharge) + { + throw new Exception("Not enough credits"); + } + + m_availableCredits -= request.Header.CreditCharge; + + if (m_availableCredits < DesiredCredits) + { + request.Header.Credits += (ushort)(DesiredCredits - m_availableCredits); + } + } + + request.Header.MessageID = m_messageID; + request.Header.SessionID = m_sessionID; + // [MS-SMB2] If the client encrypts the message [..] then the client MUST set the Signature field of the SMB2 header to zero + if (m_signingRequired && !encryptData) + { + request.Header.IsSigned = (m_sessionID != 0 && ((request.CommandName == SMB2CommandName.TreeConnect || request.Header.TreeID != 0) || + (m_dialect == SMB2Dialect.SMB300 && request.CommandName == SMB2CommandName.Logoff))); + if (request.Header.IsSigned) + { + request.Header.Signature = new byte[16]; // Request could be reused + byte[] buffer = request.GetBytes(); + byte[] signature = SMB2Cryptography.CalculateSignature(m_signingKey, m_dialect, buffer, 0, buffer.Length); + // [MS-SMB2] The first 16 bytes of the hash MUST be copied into the 16-byte signature field of the SMB2 Header. + request.Header.Signature = ByteReader.ReadBytes(signature, 0, 16); + } + } + await TrySendCommandAsync(m_clientSocket, request, encryptData ? m_encryptionKey : null); + if (m_dialect == SMB2Dialect.SMB202 || m_transport == SMBTransportType.NetBiosOverTCP) + { + m_messageID++; + } + else + { + m_messageID += request.Header.CreditCharge; + } + } + public uint MaxTransactSize { get @@ -636,6 +876,21 @@ namespace SMBLibrary.Client TrySendPacket(socket, packet); } + public static Task TrySendCommandAsync(Socket socket, SMB2Command request, byte[] encryptionKey) + { + SessionMessagePacket packet = new SessionMessagePacket(); + if (encryptionKey != null) + { + byte[] requestBytes = request.GetBytes(); + packet.Trailer = SMB2Cryptography.TransformMessage(encryptionKey, requestBytes, request.Header.SessionID); + } + else + { + packet.Trailer = request.GetBytes(); + } + return TrySendPacketAsync(socket, packet); + } + public static void TrySendPacket(Socket socket, SessionPacket packet) { try @@ -650,5 +905,44 @@ namespace SMBLibrary.Client { } } + + public static async Task TrySendPacketAsync(Socket socket, SessionPacket packet) + { + try + { + byte[] packetBytes = packet.GetBytes(); + var socketAsyncEventArgs = new SocketAsyncEventArgs(); + socketAsyncEventArgs.SetBuffer(packetBytes, 0, packetBytes.Length); + var task = CreateTaskFromCompletionHandler(socketAsyncEventArgs, SocketAsyncOperation.Send); + socket.SendAsync(socketAsyncEventArgs); + await task; + } + catch (SocketException) + { + } + catch (ObjectDisposedException) + { + } + } + + private static Task CreateTaskFromCompletionHandler(SocketAsyncEventArgs socketAsyncEventArgs, SocketAsyncOperation socketAsyncOperation) + { + TaskCompletionSource completionSource = new TaskCompletionSource(); + socketAsyncEventArgs.Completed += new EventHandler((o, eventArgs) => + { + if (eventArgs.LastOperation == socketAsyncOperation) + { + if (eventArgs.SocketError == SocketError.Success) + { + completionSource.SetResult(""); + } + else + { + completionSource.SetException(new SocketException((int)eventArgs.SocketError)); + } + } + }); + return completionSource.Task; + } } } diff --git a/SMBLibrary/SMBLibrary.csproj b/SMBLibrary/SMBLibrary.csproj index 417b158..9c971f2 100644 --- a/SMBLibrary/SMBLibrary.csproj +++ b/SMBLibrary/SMBLibrary.csproj @@ -2,10 +2,10 @@ Lansweeper.SMBLibrary - net40;net48;netstandard2.0 + net48;netstandard2.0 false SMBLibrary - 1.5.0 + 1.6.0 1573;1591 SMBLibrary false