Add connect asynchronous

This commit is contained in:
KoenPlasmans 2022-03-24 18:46:39 +01:00
parent ab35a19a2b
commit d3138aa97c
6 changed files with 583 additions and 8 deletions

View file

@ -3,7 +3,7 @@
<metadata minClientVersion="3.3">
<id>Lansweeper.SMBLibrary</id>
<version>1.5.0</version>
<version>1.6.0</version>
<title>Lansweeper.SMBLibrary</title>
<authors>TalAloni/Lansweeper</authors>
<description>SMBLibrary is an open-source C# SMB 1.0/CIFS, SMB 2.0, SMB 2.1 and SMB 3.0 server and client implementation.</description>
@ -20,7 +20,7 @@
<!--Needed to restore references when client installs package-->
<references>
<group targetFramework="net40">
<group targetFramework="net48">
<reference file="SMBLibrary.dll" />
</group>
<group targetFramework="netstandard2.0">
@ -32,7 +32,7 @@
<!--Needed for package-->
<files>
<file src="SMBLibrary\bin\Release\netstandard2.0\SMBLibrary.dll" target="lib\netstandard2.0" />
<file src="SMBLibrary\bin\Release\net40\SMBLibrary.dll" target="lib\net40" />
<file src="SMBLibrary\bin\Release\net48\SMBLibrary.dll" target="lib\net48" />
</files>
</package>

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net40</TargetFrameworks>
<TargetFrameworks>net48</TargetFrameworks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AssemblyName>SMBLibrary.Tests</AssemblyName>
<RootNamespace>SMBLibrary.Tests</RootNamespace>

View file

@ -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<bool> ConnectAsync(IPAddress serverAddress, SMBTransportType transport, string serverName = null);
void Disconnect();
NTStatus Login(string domainName, string userName, string password);

View file

@ -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<bool> ConnectAsync(IPAddress serverAddress, SMBTransportType transport, string serverName = null)
{
return ConnectAsync(serverAddress, transport, false, serverName);
}
public async Task<bool> 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<bool> 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<bool> 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<SMB1Message> 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<SessionPacket> 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<string> completionSource = new TaskCompletionSource<string>();
socketAsyncEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>((o, eventArgs) =>
{
if (eventArgs.LastOperation == socketAsyncOperation)
{
if (eventArgs.SocketError == SocketError.Success)
{
completionSource.SetResult("");
}
else
{
completionSource.SetException(new SocketException((int)eventArgs.SocketError));
}
}
});
return completionSource.Task;
}
}
}
}

View file

@ -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<bool> 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<bool> 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<bool> 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<SMB2Command> 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<SessionPacket> 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<string> completionSource = new TaskCompletionSource<string>();
socketAsyncEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>((o, eventArgs) =>
{
if (eventArgs.LastOperation == socketAsyncOperation)
{
if (eventArgs.SocketError == SocketError.Success)
{
completionSource.SetResult("");
}
else
{
completionSource.SetException(new SocketException((int)eventArgs.SocketError));
}
}
});
return completionSource.Task;
}
}
}

View file

@ -2,10 +2,10 @@
<PropertyGroup>
<PackageId>Lansweeper.SMBLibrary</PackageId>
<TargetFrameworks>net40;net48;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net48;netstandard2.0</TargetFrameworks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AssemblyName>SMBLibrary</AssemblyName>
<Version>1.5.0</Version>
<Version>1.6.0</Version>
<NoWarn>1573;1591</NoWarn>
<RootNamespace>SMBLibrary</RootNamespace>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>