Beispiel #1
0
        private async Task <IntPtr> DialAsync(VpnData vpnData, CancellationToken cancellationToken)
        {
            Log.Information($"VPN dialing");

            TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool>();

            var handle = VpnApi.Dial(EntryName, vpnData.User, vpnData.Pwd,
                                     (message, state, errorCode, extendedErrorCode) =>
            {
                Log.Information($"VPN dialing {state} ({VpnApi.RasErrorMessage(errorCode)}, {message}, {extendedErrorCode})");
                if (state == RasConnectionState.Connected)
                {
                    tcs.TrySetResult(true);
                }
                else
                {
                    if (errorCode != 0)
                    {
                        tcs.TrySetException(new VpnException($"VPN setup failed ({VpnApi.RasErrorMessage(errorCode)})"));
                    }
                }
            });

            try
            {
                var timeout = Task.Delay(10000, cancellationToken);

                var res = await Task.WhenAny(timeout, tcs.Task);

                if (res == timeout)
                {
                    throw new VpnException("Timeout during VPN setup");
                }

                return(handle);
            }
            catch
            {
                await HangUpAsync(handle);

                throw;
            }
        }
Beispiel #2
0
        private async Task MaintainConnection(VpnData vpnData, CancellationToken cancellationToken, TaskCompletionSource <bool> firstTime, Action <VpnRuntimeState> onStateChanged)
        {
            Task   awaitConnectionChanged = null;
            IntPtr handle = IntPtr.Zero;

            bool      statInitialized = false;
            RAS_STATS prevStat        = new RAS_STATS();

            string serverIpAddress = null;

            try
            {
                while (!_cts.IsCancellationRequested)
                {
                    try
                    {
                        if (handle == IntPtr.Zero)
                        {
                            Log.Information("VPN Connecting");
                            handle = await ReconnectAsync(vpnData, _cts.Token);

                            var info = VpnApi.GetProjectionInfoEx(handle);
                            serverIpAddress = $"{info.ipv4ServerAddress.addr[0]}.{info.ipv4ServerAddress.addr[1]}.{info.ipv4ServerAddress.addr[2]}.{info.ipv4ServerAddress.addr[3]}";


                            firstTime?.TrySetResult(true);
                            firstTime       = null;
                            statInitialized = false;

                            var eventHandle = VpnApi.RegisterForTermination(handle);
                            awaitConnectionChanged = TaskHelper.WaitOneAsync(eventHandle, "VPN state changed");
                        }

                        if (handle != IntPtr.Zero)
                        {
                            var status = VpnApi.GetState(handle);
                            var stat   = VpnApi.GetStatisitcs(handle);

                            if (status.connectionState != RasConnectionState.Connected)
                            {
                                if (status.errorCode == 0)
                                {
                                    throw new VpnException($"VPN in wrong '{status.connectionState}' state");
                                }
                                else
                                {
                                    throw new VpnException($"VPN error '{VpnApi.RasErrorMessage(status.errorCode)}'");
                                }
                            }

                            if (!statInitialized)
                            {
                                statInitialized = true;
                                prevStat        = stat;
                            }

                            var delta = GetStatDelta(stat, prevStat);
                            prevStat = stat;

                            if (delta.dwTimeoutErr + delta.dwFramingErr + delta.dwCrcErr + delta.dwHardwareOverrunErr + delta.dwBufferOverrunErr + delta.dwAlignmentErr > 0)
                            {
                                Log.Warning($"VPN errors {delta.dwTimeoutErr},{delta.dwFramingErr},{delta.dwCrcErr},{delta.dwHardwareOverrunErr},{delta.dwBufferOverrunErr},{delta.dwAlignmentErr}");
                            }


                            onStateChanged(new VpnRuntimeState
                            {
                                Connected       = true,
                                SentKbs         = (int)delta.dwBytesXmited / (1024 / 8),
                                ReceivedKbs     = (int)delta.dwBytesRcved / (1024 / 8),
                                ServerIpAddress = serverIpAddress
                            });
                        }
                    }
                    catch (Exception e) when(TaskHelper.IsCancellation(e))
                    {
                        Log.Error(e, "VPN cancellation");
                        throw;
                    }
                    catch (Exception e)
                    {
                        Log.Error(e, "VPN maintanance error");
                        firstTime?.TrySetException(e);
                        firstTime       = null;
                        serverIpAddress = null;

                        onStateChanged(new VpnRuntimeState {
                            Connected = false, ErrorMessage = e.Message
                        });

                        await HangUpAsync(handle);

                        handle = IntPtr.Zero;
                        awaitConnectionChanged = null;
                    }

                    var delay = Task.Delay(1000, cancellationToken);
                    if (awaitConnectionChanged != null)
                    {
                        var result = await Task.WhenAny(delay, awaitConnectionChanged);

                        if (result == awaitConnectionChanged)
                        {
                            Log.Information("VPN short wait");
                            awaitConnectionChanged = null; //it is raised once and not usable anymore
                        }
                    }
                    else
                    {
                        await delay;
                    }
                }
            }
            finally
            {
                Log.Information("VPN exiting maintainance");
                await HangUpAsync(handle);

                onStateChanged(new VpnRuntimeState {
                    Connected = false
                });
                _disconnected?.TrySetResult(true);
            }
        }