public static SocketError Set(SafeSocketHandle handle, SocketOptionName optionName, int optionValueSeconds) { IOControlKeepAlive ioControlKeepAlive = s_socketKeepAliveTable.GetOrCreateValue(handle); if (optionName == SocketOptionName.TcpKeepAliveTime) { ioControlKeepAlive._timeMs = SecondsToMilliseconds(optionValueSeconds); } else { ioControlKeepAlive._intervalMs = SecondsToMilliseconds(optionValueSeconds); } byte[] buffer = s_keepAliveValuesBuffer ?? (s_keepAliveValuesBuffer = new byte[3 * sizeof(uint)]); ioControlKeepAlive.Fill(buffer); int realOptionLength = 0; return(SocketPal.WindowsIoctl(handle, unchecked ((int)IOControlCode.KeepAliveValues), buffer, null, out realOptionLength)); }
internal SocketError DoOperationDisconnect(Socket socket, SafeCloseSocket handle) { SocketError socketError = SocketPal.Disconnect(socket, handle, _disconnectReuseSocket); FinishOperationSync(socketError, 0, SocketFlags.None); return(socketError); }
// Check the result of the overlapped operation. // Handle synchronous success by completing the asyncResult here. // Handle synchronous failure by cleaning up and returning a SocketError. internal SocketError ProcessOverlappedResult(bool success, int bytesTransferred) { if (success) { // Synchronous success. Socket socket = (Socket)AsyncObject; if (socket.SafeHandle.SkipCompletionPortOnSuccess) { // The socket handle is configured to skip completion on success, // so we can complete this asyncResult right now. CompletionCallback(bytesTransferred, SocketError.Success); return(SocketError.Success); } // Socket handle is going to post a completion to the completion port (may have done so already). // Return pending and we will continue in the completion port callback. return(SocketError.IOPending); } // Get the socket error (which may be IOPending) SocketError errorCode = SocketPal.GetLastSocketError(); if (errorCode == SocketError.IOPending) { // Operation is pending. // We will continue when the completion arrives (may have already at this point). return(SocketError.IOPending); } // Synchronous failure. // Release overlapped and pinned structures. ReleaseUnmanagedStructures(); return(errorCode); }
private IAsyncResult BeginSendFileInternal(string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state) { FileStream fileStream = OpenFile(fileName); TransmitFileAsyncResult asyncResult = new TransmitFileAsyncResult(this, state, callback); asyncResult.StartPostingAsyncOp(false); SocketError errorCode = SocketPal.SendFileAsync(_handle, fileStream, preBuffer, postBuffer, flags, asyncResult); // Check for synchronous exception if (errorCode != SocketError.Success) { SocketException socketException = new SocketException((int)errorCode); UpdateStatusAfterSocketError(socketException); if (NetEventSource.IsEnabled) { NetEventSource.Error(this, socketException); } throw socketException; } asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache); return(asyncResult); }
private void SendFileInternal(string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags) { // Open the file, if any FileStream fileStream = OpenFile(fileName); SocketError errorCode; using (fileStream) { SafeFileHandle fileHandle = fileStream?.SafeFileHandle; // This can throw ObjectDisposedException. errorCode = SocketPal.SendFile(_handle, fileHandle, preBuffer, postBuffer, flags); } if (errorCode != SocketError.Success) { SocketException socketException = new SocketException((int)errorCode); UpdateStatusAfterSocketError(socketException); if (NetEventSource.IsEnabled) { NetEventSource.Error(this, socketException); } throw socketException; } // If the user passed the Disconnect and/or ReuseSocket flags, then TransmitFile disconnected the socket. // Update our state to reflect this. if ((flags & (TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket)) != 0) { SetToDisconnected(); _remoteEndPoint = null; } }
public static unsafe InnerSafeCloseSocket CreateSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) { int af = SocketPal.GetPlatformAddressFamily(addressFamily); int sock = SocketPal.GetPlatformSocketType(socketType); int pt = (int)protocolType; int fd = Interop.libc.socket(af, sock, pt); if (fd != -1) { // The socket was created successfully; make it non-blocking and enable // IPV6_V6ONLY by default for AF_INET6 sockets. int err = Interop.Sys.Fcntl.SetIsNonBlocking(fd, 1); if (err != 0) { Interop.Sys.Close(fd); fd = -1; } else if (addressFamily == AddressFamily.InterNetworkV6) { int on = 1; err = Interop.libc.setsockopt(fd, Interop.libc.IPPROTO_IPV6, Interop.libc.IPV6_V6ONLY, &on, (uint)sizeof(int)); if (err != 0) { Interop.Sys.Close(fd); fd = -1; } } } var res = new InnerSafeCloseSocket(); res.SetHandle((IntPtr)fd); return(res); }
private Interop.Error CloseHandle(IntPtr handle) { Interop.Error errorCode = Interop.Error.SUCCESS; bool remappedError = false; if (Interop.Sys.Close(handle) != 0) { errorCode = Interop.Sys.GetLastError(); if (errorCode == Interop.Error.ECONNRESET) { // Some Unix platforms (e.g. FreeBSD) non-compliantly return ECONNRESET from close(). // For our purposes, we want to ignore such a "failure" and treat it as success. // In such a case, the file descriptor was still closed and there's no corrective // action to take. errorCode = Interop.Error.SUCCESS; remappedError = true; } } if (NetEventSource.IsEnabled) { NetEventSource.Info(this, remappedError ? $"handle:{handle}, close():ECONNRESET, but treating it as SUCCESS" : $"handle:{handle}, close():{errorCode}"); } #if DEBUG _closeSocketHandle = handle; _closeSocketResult = SocketPal.GetSocketErrorForErrorCode(errorCode); #endif return(errorCode); }
private void TransferCompletionCallback(int bytesTransferred, byte[] socketAddress, int socketAddressSize, int receivedFlags, SocketError socketError) { Debug.Assert(socketAddress == null || socketAddress == _socketAddress.Buffer); _socketAddressSize = socketAddressSize; _receivedFlags = SocketPal.GetSocketFlags(receivedFlags); CompletionCallback(bytesTransferred, socketError); }
internal SocketError DoOperationSendPackets(Socket socket, SafeCloseSocket handle) { Debug.Assert(_sendPacketsElements != null); SendPacketsElement[] elements = (SendPacketsElement[])_sendPacketsElements.Clone(); FileStream[] files = new FileStream[elements.Length]; // Open all files synchronously ahead of time so that any exceptions are propagated // to the caller, to match Windows behavior. try { for (int i = 0; i < elements.Length; i++) { string path = elements[i]?.FilePath; if (path != null) { files[i] = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x1000, useAsync: true); } } } catch (Exception exc) { // Clean up any files that were already opened. foreach (FileStream s in files) { s?.Dispose(); } // Windows differentiates the directory not being found from the file not being found. // Approximate this by checking to see if the directory exists; this is only best-effort, // as there are various things that could affect this, e.g. directory creation racing with // this check, but it's good enough for most situations. if (exc is FileNotFoundException fnfe) { string dirname = Path.GetDirectoryName(fnfe.FileName); if (!string.IsNullOrEmpty(dirname) && !Directory.Exists(dirname)) { throw new DirectoryNotFoundException(fnfe.Message); } } // Otherwise propagate the original error. throw; } SocketPal.SendPacketsAsync(socket, SendPacketsFlags, elements, files, (bytesTransferred, error) => { if (error == SocketError.Success) { FinishOperationAsyncSuccess((int)bytesTransferred, SocketFlags.None); } else { FinishOperationAsyncFailure(error, (int)bytesTransferred, SocketFlags.None); } }); return(SocketError.IOPending); }
public static unsafe SocketError SendFile(SafeCloseSocket handle, SafeFileHandle fileHandle, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags) { fixed(byte *prePinnedBuffer = preBuffer) fixed(byte *postPinnedBuffer = postBuffer) { bool success = TransmitFileHelper(handle, fileHandle, SafeNativeOverlapped.Zero, preBuffer, postBuffer, flags); return(success ? SocketError.Success : SocketPal.GetLastSocketError()); } }
private void ReceiveMessageFromCompletionCallback(int bytesTransferred, byte[] socketAddress, int socketAddressSize, int receivedFlags, IPPacketInformation ipPacketInformation, SocketError errorCode) { Debug.Assert(_socketAddress != null); Debug.Assert(socketAddress == null || _socketAddress.Buffer == socketAddress); _socketAddressSize = socketAddressSize; _receivedFlags = SocketPal.GetSocketFlags(receivedFlags); _receiveMessageFromPacketInfo = ipPacketInformation; CompletionCallback(bytesTransferred, errorCode); }
internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeCloseSocket handle, out int bytesTransferred) { int platformFlags = SocketPal.GetPlatformSocketFlags(_socketFlags); bool isIPv4, isIPv6; Socket.GetIPProtocolInformation(socket.AddressFamily, _socketAddress, out isIPv4, out isIPv6); bytesTransferred = 0; return(handle.AsyncContext.ReceiveMessageFromAsync(_buffer, _offset, _count, platformFlags, _socketAddress.Buffer, _socketAddress.Size, isIPv4, isIPv6, ReceiveMessageFromCompletionCallback)); }
public void CompletionCallback(int numBytes, byte[] socketAddress, int socketAddressSize, int receivedFlags, IPPacketInformation ipPacketInformation, SocketError errorCode) { Debug.Assert(_socketAddress != null); Debug.Assert(socketAddress == null || _socketAddress.Buffer == socketAddress); _socketAddressSize = socketAddressSize; _socketFlags = SocketPal.GetSocketFlags(receivedFlags); _ipPacketInformation = ipPacketInformation; base.CompletionCallback(numBytes, errorCode); }
public void CompletionCallback(IntPtr acceptedFileDescriptor, byte[] socketAddress, int socketAddressLen, SocketError errorCode) { _buffer = null; _numBytes = 0; if (errorCode == SocketError.Success) { Internals.SocketAddress remoteSocketAddress = IPEndPointExtensions.Serialize(_listenSocket._rightEndPoint); System.Buffer.BlockCopy(socketAddress, 0, remoteSocketAddress.Buffer, 0, socketAddressLen); _acceptedSocket = _listenSocket.CreateAcceptSocket( SocketPal.CreateSocket(acceptedFileDescriptor), _listenSocket._rightEndPoint.Create(remoteSocketAddress)); } base.CompletionCallback(0, errorCode); }
private void SendFileInternal(string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags) { CheckTransmitFileOptions(flags); // Open the file, if any // Open it before we send the preBuffer so that any exception happens first FileStream fileStream = OpenFile(fileName); SocketError errorCode = SocketError.Success; using (fileStream) { // Send the preBuffer, if any // This will throw on error if (preBuffer != null && preBuffer.Length > 0) { Send(preBuffer); } // Send the file, if any if (fileStream != null) { // This can throw ObjectDisposedException. errorCode = SocketPal.SendFile(_handle, fileStream); } } if (errorCode != SocketError.Success) { SocketException socketException = new SocketException((int)errorCode); UpdateStatusAfterSocketError(socketException); if (NetEventSource.IsEnabled) { NetEventSource.Error(this, socketException); } throw socketException; } // Send the postBuffer, if any // This will throw on error if (postBuffer != null && postBuffer.Length > 0) { Send(postBuffer); } }
internal SocketError DoOperationSendTo(SafeCloseSocket handle, out int bytesTransferred) { int platformFlags = SocketPal.GetPlatformSocketFlags(_socketFlags); SocketError errorCode; if (_buffer != null) { errorCode = handle.AsyncContext.SendToAsync(_buffer, _offset, _count, platformFlags, _socketAddress.Buffer, _socketAddress.Size, TransferCompletionCallback); } else { errorCode = handle.AsyncContext.SendToAsync(_bufferList, platformFlags, _socketAddress.Buffer, _socketAddress.Size, TransferCompletionCallback); } bytesTransferred = 0; return(errorCode); }
private unsafe void InitIPPacketInformation() { if (_controlBuffer.Length == s_controlDataSize) { // IPv4 _ipPacketInformation = SocketPal.GetIPPacketInformation((Interop.Winsock.ControlData *)_message->controlBuffer.Pointer); } else if (_controlBuffer.Length == s_controlDataIPv6Size) { // IPv6 _ipPacketInformation = SocketPal.GetIPPacketInformation((Interop.Winsock.ControlDataIPv6 *)_message->controlBuffer.Pointer); } else { // Other _ipPacketInformation = new IPPacketInformation(); } }
public static unsafe InnerSafeCloseSocket Accept(SafeCloseSocket socketHandle, byte[] socketAddress, ref int socketAddressLen, out SocketError errorCode) { int acceptedFd; if (!socketHandle.IsNonBlocking) { errorCode = socketHandle.AsyncContext.Accept(socketAddress, ref socketAddressLen, -1, out acceptedFd); } else { SocketPal.TryCompleteAccept(socketHandle, socketAddress, ref socketAddressLen, out acceptedFd, out errorCode); } var res = new InnerSafeCloseSocket(); res.SetHandle((IntPtr)acceptedFd); return(res); }
public static unsafe InnerSafeCloseSocket CreateSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, out SocketError errorCode) { int fd; Interop.Error error = Interop.Sys.Socket(addressFamily, socketType, protocolType, &fd); if (error == Interop.Error.SUCCESS) { Debug.Assert(fd != -1); errorCode = SocketError.Success; // The socket was created successfully; make it non-blocking and enable // IPV6_V6ONLY by default for AF_INET6 sockets. int err = Interop.Sys.Fcntl.SetIsNonBlocking((IntPtr)fd, 1); if (err != 0) { Interop.Sys.Close((IntPtr)fd); fd = -1; errorCode = SocketError.SocketError; } else if (addressFamily == AddressFamily.InterNetworkV6) { int on = 1; error = Interop.Sys.SetSockOpt(fd, SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, (byte *)&on, sizeof(int)); if (error != Interop.Error.SUCCESS) { Interop.Sys.Close((IntPtr)fd); fd = -1; errorCode = SocketPal.GetSocketErrorForErrorCode(error); } } } else { Debug.Assert(fd == -1); errorCode = SocketPal.GetSocketErrorForErrorCode(error); } var res = new InnerSafeCloseSocket(); res.SetHandle((IntPtr)fd); return(res); }
internal unsafe SocketError DoOperationReceive(SafeCloseSocket handle, out SocketFlags flags, out int bytesTransferred) { int platformFlags = SocketPal.GetPlatformSocketFlags(_socketFlags); SocketError errorCode; if (_buffer != null) { errorCode = handle.AsyncContext.ReceiveAsync(_buffer, _offset, _count, platformFlags, TransferCompletionCallback); } else { errorCode = handle.AsyncContext.ReceiveAsync(_bufferList, platformFlags, TransferCompletionCallback); } flags = _socketFlags; bytesTransferred = 0; return(errorCode); }
private IAsyncResult BeginSendFileInternal(string fileName, byte[] preBuffer, byte[] postBuffer, TransmitFileOptions flags, AsyncCallback callback, object state) { FileStream fileStream = OpenFile(fileName); TransmitFileAsyncResult asyncResult = new TransmitFileAsyncResult(this, state, callback); asyncResult.StartPostingAsyncOp(false); SocketError errorCode = SocketPal.SendFileAsync(_handle, fileStream, preBuffer, postBuffer, flags, asyncResult); // Check for synchronous exception if (!CheckErrorAndUpdateStatus(errorCode)) { throw new SocketException((int)errorCode); } asyncResult.FinishPostingAsyncOp(ref Caches.SendClosureCache); return(asyncResult); }
private unsafe void InitIPPacketInformation() { int?controlBufferLength = _controlBuffer?.Length; if (controlBufferLength == sizeof(Interop.Winsock.ControlData)) { // IPv4 _ipPacketInformation = SocketPal.GetIPPacketInformation((Interop.Winsock.ControlData *)_message->controlBuffer.Pointer); } else if (controlBufferLength == sizeof(Interop.Winsock.ControlDataIPv6)) { // IPv6 _ipPacketInformation = SocketPal.GetIPPacketInformation((Interop.Winsock.ControlDataIPv6 *)_message->controlBuffer.Pointer); } else { // Other _ipPacketInformation = default; } }
private void SendFileInternal(string?fileName, byte[]?preBuffer, byte[]?postBuffer, TransmitFileOptions flags) { CheckTransmitFileOptions(flags); // Open the file, if any // Open it before we send the preBuffer so that any exception happens first FileStream?fileStream = OpenFile(fileName); SocketError errorCode = SocketError.Success; using (fileStream) { // Send the preBuffer, if any // This will throw on error if (preBuffer != null && preBuffer.Length > 0) { Send(preBuffer); } // Send the file, if any if (fileStream != null) { // This can throw ObjectDisposedException. errorCode = SocketPal.SendFile(_handle, fileStream); } } if (errorCode != SocketError.Success) { UpdateSendSocketErrorForDisposed(ref errorCode); UpdateStatusAfterSocketErrorAndThrowException(errorCode); } // Send the postBuffer, if any // This will throw on error if (postBuffer != null && postBuffer.Length > 0) { Send(postBuffer); } }
private async Task SendFileInternalAsync(FileStream?fileStream, byte[]?preBuffer, byte[]?postBuffer) { SocketError errorCode = SocketError.Success; using (fileStream) { // Send the preBuffer, if any // This will throw on error if (preBuffer != null && preBuffer.Length > 0) { // Using "this." makes the extension method kick in await this.SendAsync(new ArraySegment <byte>(preBuffer), SocketFlags.None).ConfigureAwait(false); } // Send the file, if any if (fileStream != null) { var tcs = new TaskCompletionSource <SocketError>(); errorCode = SocketPal.SendFileAsync(_handle, fileStream, (_, socketError) => tcs.SetResult(socketError)); if (errorCode == SocketError.IOPending) { errorCode = await tcs.Task.ConfigureAwait(false); } } } if (errorCode != SocketError.Success) { UpdateSendSocketErrorForDisposed(ref errorCode); UpdateStatusAfterSocketErrorAndThrowException(errorCode); } // Send the postBuffer, if any // This will throw on error if (postBuffer != null && postBuffer.Length > 0) { // Using "this." makes the extension method kick in await this.SendAsync(new ArraySegment <byte>(postBuffer), SocketFlags.None).ConfigureAwait(false); } }
internal static unsafe InnerSafeCloseSocket Accept(SafeSocketHandle socketHandle, byte[] socketAddress, ref int socketAddressLen, out SocketError errorCode) { IntPtr acceptedFd; if (!socketHandle.IsNonBlocking) { errorCode = socketHandle.AsyncContext.Accept(socketAddress, ref socketAddressLen, out acceptedFd); } else { bool completed = SocketPal.TryCompleteAccept(socketHandle, socketAddress, ref socketAddressLen, out acceptedFd, out errorCode); if (!completed) { errorCode = SocketError.WouldBlock; } } var res = new InnerSafeCloseSocket(); res.SetHandle(acceptedFd); return(res); }
internal static unsafe InnerSafeCloseSocket CreateSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, out SocketError errorCode) { IntPtr fd; Interop.Error error = Interop.Sys.Socket(addressFamily, socketType, protocolType, &fd); if (error == Interop.Error.SUCCESS) { Debug.Assert(fd != (IntPtr)(-1), "fd should not be -1"); errorCode = SocketError.Success; // The socket was created successfully; enable IPV6_V6ONLY by default for normal AF_INET6 sockets. // This fails on raw sockets so we just let them be in default state. if (addressFamily == AddressFamily.InterNetworkV6 && socketType != SocketType.Raw) { int on = 1; error = Interop.Sys.SetSockOpt(fd, SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, (byte *)&on, sizeof(int)); if (error != Interop.Error.SUCCESS) { Interop.Sys.Close(fd); fd = (IntPtr)(-1); errorCode = SocketPal.GetSocketErrorForErrorCode(error); } } } else { Debug.Assert(fd == (IntPtr)(-1), $"Unexpected fd: {fd}"); errorCode = SocketPal.GetSocketErrorForErrorCode(error); } var res = new InnerSafeCloseSocket(); res.SetHandle(fd); return(res); }
// This method is called by base.CompletionPortCallback base.OverlappedCallback as part of IO completion internal override object PostCompletion(int numBytes) { SocketError errorCode = (SocketError)ErrorCode; Socket socket = (Socket)AsyncObject; if (errorCode == SocketError.Success) { // Set the socket context. try { errorCode = Interop.Winsock.setsockopt( socket.SafeHandle, SocketOptionLevel.Socket, SocketOptionName.UpdateConnectContext, null, 0); if (errorCode == SocketError.SocketError) { errorCode = SocketPal.GetLastSocketError(); } } catch (ObjectDisposedException) { errorCode = SocketError.OperationAborted; } ErrorCode = (int)errorCode; } if (errorCode == SocketError.Success) { socket.SetToConnected(); return(socket); } return(null); }
public static unsafe InnerSafeCloseSocket CreateSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, out SocketError errorCode) { int fd; Interop.Error error = Interop.Sys.Socket(addressFamily, socketType, protocolType, &fd); if (error == Interop.Error.SUCCESS) { Debug.Assert(fd != -1, "fd should not be -1"); errorCode = SocketError.Success; // The socket was created successfully; enable IPV6_V6ONLY by default for AF_INET6 sockets. if (addressFamily == AddressFamily.InterNetworkV6) { int on = 1; error = Interop.Sys.DangerousSetSockOpt(fd, SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, (byte *)&on, sizeof(int)); if (error != Interop.Error.SUCCESS) { Interop.Sys.Close((IntPtr)fd); fd = -1; errorCode = SocketPal.GetSocketErrorForErrorCode(error); } } } else { Debug.Assert(fd == -1, $"Unexpected fd: {fd}"); errorCode = SocketPal.GetSocketErrorForErrorCode(error); } var res = new InnerSafeCloseSocket(); res.SetHandle((IntPtr)fd); return(res); }
private unsafe SocketError InnerReleaseHandle() { Interop.Error errorCode = Interop.Error.SUCCESS; // If _abortive was set to false in Close, it's safe to block here, which means // we can honor the linger options set on the socket. It also means closesocket() might return WSAEWOULDBLOCK, in which // case we need to do some recovery. if (!_abortive) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"handle:{handle} Following 'non-abortive' branch."); } // Close, and if its errno is other than EWOULDBLOCK, there's nothing more to do - we either succeeded or failed. errorCode = CloseHandle(handle); if (errorCode != Interop.Error.EWOULDBLOCK) { return(SocketPal.GetSocketErrorForErrorCode(errorCode)); } // The socket must be non-blocking with a linger timeout set. // We have to set the socket to blocking. if (Interop.Sys.Fcntl.DangerousSetIsNonBlocking(handle, 0) == 0) { // The socket successfully made blocking; retry the close(). return(SocketPal.GetSocketErrorForErrorCode(CloseHandle(handle))); } // The socket could not be made blocking; fall through to the regular abortive close. } // By default or if the non-abortive path failed, set linger timeout to zero to get an abortive close (RST). var linger = new Interop.Sys.LingerOption { OnOff = 1, Seconds = 0 }; errorCode = Interop.Sys.SetLingerOption(handle, &linger); #if DEBUG _closeSocketLinger = SocketPal.GetSocketErrorForErrorCode(errorCode); #endif if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"handle:{handle}, setsockopt():{errorCode}"); } switch (errorCode) { case Interop.Error.SUCCESS: case Interop.Error.EINVAL: case Interop.Error.ENOPROTOOPT: errorCode = CloseHandle(handle); break; // For other errors, it's too dangerous to try closesocket() - it might block! } return(SocketPal.GetSocketErrorForErrorCode(errorCode)); }
private unsafe SocketError InnerReleaseHandle() { int errorCode; // If _blockable was set in BlockingRelease, it's safe to block here, which means // we can honor the linger options set on the socket. It also means closesocket() might return WSAEWOULDBLOCK, in which // case we need to do some recovery. if (_blockable) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"handle:{handle} Following 'blockable' branch."); } errorCode = Interop.Sys.Close(handle); if (errorCode == -1) { errorCode = (int)Interop.Sys.GetLastError(); } if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"handle:{handle}, close()#1:{errorCode}"); } #if DEBUG _closeSocketHandle = handle; _closeSocketResult = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode); #endif // If it's not EWOULDBLOCK, there's no more recourse - we either succeeded or failed. if (errorCode != (int)Interop.Error.EWOULDBLOCK) { return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode)); } // The socket must be non-blocking with a linger timeout set. // We have to set the socket to blocking. errorCode = Interop.Sys.Fcntl.DangerousSetIsNonBlocking(handle, 0); if (errorCode == 0) { // The socket successfully made blocking; retry the close(). errorCode = Interop.Sys.Close(handle); if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"handle:{handle}, close()#2:{errorCode}"); } #if DEBUG _closeSocketHandle = handle; _closeSocketResult = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode); #endif return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode)); } // The socket could not be made blocking; fall through to the regular abortive close. } // By default or if CloseAsIs() path failed, set linger timeout to zero to get an abortive close (RST). var linger = new Interop.Sys.LingerOption { OnOff = 1, Seconds = 0 }; errorCode = (int)Interop.Sys.SetLingerOption(handle, &linger); #if DEBUG _closeSocketLinger = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode); #endif if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"handle:{handle}, setsockopt():{errorCode}"); } if (errorCode != 0 && errorCode != (int)Interop.Error.EINVAL && errorCode != (int)Interop.Error.ENOPROTOOPT) { // Too dangerous to try closesocket() - it might block! return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode)); } errorCode = Interop.Sys.Close(handle); #if DEBUG _closeSocketHandle = handle; _closeSocketResult = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode); #endif if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"handle:{handle}, close#3():{(errorCode == -1 ? (int)Interop.Sys.GetLastError() : errorCode)}"); } return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode)); }