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); }
public static unsafe SocketError GetLingerOption(SafeCloseSocket handle, out LingerOption optionValue) { var opt = new Interop.Sys.LingerOption(); Interop.Error err = Interop.Sys.GetLingerOption(handle.FileDescriptor, &opt); if (err != Interop.Error.SUCCESS) { optionValue = default(LingerOption); return GetSocketErrorForErrorCode(err); } optionValue = new LingerOption(opt.OnOff != 0, opt.Seconds); return SocketError.Success; }
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 (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") Following 'blockable' branch."); } errorCode = Interop.Sys.Close(handle); if (errorCode == -1) { errorCode = (int)Interop.Sys.GetLastError(); } if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") close()#1:" + errorCode.ToString()); } #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 (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") close()#2:" + errorCode.ToString()); } #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.DangerousSetLingerOption((int)handle, &linger); #if DEBUG _closeSocketLinger = SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode); #endif if (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") setsockopt():" + errorCode.ToString()); } 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 (GlobalLog.IsEnabled) { GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") close#3():" + (errorCode == -1 ? (int)Interop.Sys.GetLastError() : errorCode).ToString()); } return(SocketPal.GetSocketErrorForErrorCode((Interop.Error)errorCode)); }
public static unsafe SocketError SetLingerOption(SafeCloseSocket handle, LingerOption optionValue) { var opt = new Interop.Sys.LingerOption { OnOff = optionValue.Enabled ? 1 : 0, Seconds = optionValue.LingerTime }; Interop.Error err = Interop.Sys.SetLingerOption(handle.FileDescriptor, &opt); return err == Interop.Error.SUCCESS ? SocketError.Success : GetSocketErrorForErrorCode(err); }
private unsafe SocketError DoCloseHandle(bool abortive) { Interop.Error errorCode = Interop.Error.SUCCESS; // If abortive is not set, we're not running on the finalizer thread, so it's safe to block here. // We can honor the linger options set on the socket. It also means closesocket() might return // EWOULDBLOCK, 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)); }