예제 #1
0
        private async Task <IntPtr> ReconnectAsync(VpnData vpnData, CancellationToken cancellationToken)
        {
            var connection = VpnApi.GetConnections().FirstOrDefault(s => s.szEntryName == EntryName);

            if (connection.szEntryName == EntryName && connection.hrasconn != IntPtr.Zero)
            {
                var state = VpnApi.GetState(connection.hrasconn);
                if (state.connectionState == RasConnectionState.Connected)
                {
                    Log.Information("Vpn is already connected");
                    return(connection.hrasconn);
                }
                else
                {
                    Log.Information($"Vpn is active but state is '{state.connectionState}'");
                    await HangUpAsync(connection.hrasconn);
                }
            }

            var entries = VpnApi.GetEntryNames();

            var myEntry = entries.FirstOrDefault(s => s.szEntryName == EntryName);

            if (myEntry.szEntryName == EntryName)
            {
                Log.Information($"VPN removing entry");
                VpnApi.DeleteEntry(EntryName);
            }

            CreateEntry(vpnData);

            var id = await DialAsync(vpnData, cancellationToken);

            //var info = VpnApi.GetProjectionInfoEx(id);

            return(id);
        }
예제 #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);
            }
        }