< Summary

Information
Class: Renci.SshNet.Abstractions.SocketExtensions
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Abstractions\SocketExtensions.cs
Line coverage
62%
Covered lines: 43
Uncovered lines: 26
Coverable lines: 69
Total lines: 132
Line coverage: 62.3%
Branch coverage
65%
Covered branches: 13
Total branches: 20
Branch coverage: 65%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.cctor()100%1100%
.ctor()100%1100%
ExecuteAsync(...)100%2100%
SetCompleted()100%4100%
SetCancelled()100%10%
GetAwaiter()100%1100%
get_IsCompleted()100%1100%
System.Runtime.CompilerServices.INotifyCompletion.OnCompleted(...)50%450%
GetResult()50%645.45%
ConnectAsync()0%20%
ReceiveAsync()100%2100%

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Abstractions\SocketExtensions.cs

#LineLine coverage
 1using System;
 2using System.Net;
 3using System.Net.Sockets;
 4using System.Runtime.CompilerServices;
 5using System.Threading;
 6using System.Threading.Tasks;
 7
 8namespace Renci.SshNet.Abstractions
 9{
 10    // Async helpers based on https://devblogs.microsoft.com/pfxteam/awaiting-socket-operations/
 11    internal static class SocketExtensions
 12    {
 13        private sealed class AwaitableSocketAsyncEventArgs : SocketAsyncEventArgs, INotifyCompletion
 14        {
 115            private static readonly Action SENTINEL = () => { };
 16
 17            private bool _isCancelled;
 18            private Action _continuationAction;
 19
 4220            public AwaitableSocketAsyncEventArgs()
 4221            {
 4422                Completed += (sender, e) => SetCompleted();
 4223            }
 24
 25            public AwaitableSocketAsyncEventArgs ExecuteAsync(Func<SocketAsyncEventArgs, bool> func)
 4226            {
 4227                if (!func(this))
 4028                {
 4029                    SetCompleted();
 4030                }
 31
 4232                return this;
 4233            }
 34
 35            public void SetCompleted()
 4236            {
 4237                IsCompleted = true;
 38
 4239                var continuation = _continuationAction ?? Interlocked.CompareExchange(ref _continuationAction, SENTINEL,
 4240                if (continuation is not null)
 241                {
 242                    continuation();
 243                }
 4244            }
 45
 46            public void SetCancelled()
 047            {
 048                _isCancelled = true;
 049                SetCompleted();
 050            }
 51
 52#pragma warning disable S1144 // Unused private types or members should be removed
 53            public AwaitableSocketAsyncEventArgs GetAwaiter()
 54#pragma warning restore S1144 // Unused private types or members should be removed
 4255            {
 4256                return this;
 4257            }
 58
 12659            public bool IsCompleted { get; private set; }
 60
 61            void INotifyCompletion.OnCompleted(Action continuation)
 262            {
 263                if (_continuationAction == SENTINEL || Interlocked.CompareExchange(ref _continuationAction, continuation
 064                {
 65                    // We have already completed; run continuation asynchronously
 066                    _ = Task.Run(continuation);
 067                }
 268            }
 69
 70#pragma warning disable S1144 // Unused private types or members should be removed
 71            public void GetResult()
 72#pragma warning restore S1144 // Unused private types or members should be removed
 4273            {
 4274                if (_isCancelled)
 075                {
 076                    throw new TaskCanceledException();
 77                }
 78
 4279                if (!IsCompleted)
 080                {
 81                    // We don't support sync/async
 082                    throw new InvalidOperationException("The asynchronous operation has not yet completed.");
 83                }
 84
 4285                if (SocketError != SocketError.Success)
 086                {
 087                    throw new SocketException((int)SocketError);
 88                }
 4289            }
 90        }
 91
 92        public static async Task ConnectAsync(this Socket socket, IPEndPoint remoteEndpoint, CancellationToken cancellat
 093        {
 094            cancellationToken.ThrowIfCancellationRequested();
 95
 096            using (var args = new AwaitableSocketAsyncEventArgs())
 097            {
 098                args.RemoteEndPoint = remoteEndpoint;
 99
 100#if NET || NETSTANDARD2_1_OR_GREATER
 0101                await using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs)o).SetCancelled(), args, us
 102#else
 0103                using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs) o).SetCancelled(), args, useSync
 104#endif // NET || NETSTANDARD2_1_OR_GREATER
 0105                {
 0106                    await args.ExecuteAsync(socket.ConnectAsync);
 0107                }
 0108            }
 0109        }
 110
 111        public static async Task<int> ReceiveAsync(this Socket socket, byte[] buffer, int offset, int length, Cancellati
 42112        {
 42113            cancellationToken.ThrowIfCancellationRequested();
 114
 42115            using (var args = new AwaitableSocketAsyncEventArgs())
 42116            {
 42117                args.SetBuffer(buffer, offset, length);
 118
 119#if NET || NETSTANDARD2_1_OR_GREATER
 42120                await using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs) o).SetCancelled(), args, u
 121#else
 0122                using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs) o).SetCancelled(), args, useSync
 123#endif // NET || NETSTANDARD2_1_OR_GREATER
 42124                {
 42125                    await args.ExecuteAsync(socket.ReceiveAsync);
 42126                }
 127
 42128                return args.BytesTransferred;
 129            }
 42130        }
 131    }
 132}