示例#1
0
            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);
            }
示例#2
0
        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));
            }
示例#4
0
        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);
        }
示例#5
0
        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));
        }