C# OpenVPN-tilstandsobservatør: overvåk sesjonen, ikke nettverkskortet
NetworkAvailabilityChanged er ikke en VPN-hendelse. Les tilstandsstrømmen fra klienten som eier tunnelen, beskytt mot utdaterte prober, og publiser beredskap per tilkobling.
Applikasjonen din fortsetter å virke mens tunnelen dør. Wi-Fi er fortsatt oppe, internett svarer fortsatt, og det private API-et appen er avhengig av, er blitt utilgjengelig. .NET-hendelsen folk vanligvis griper til her, NetworkAvailabilityChanged, beskriver ikke den situasjonen i det hele tatt. Den rapporterer en endring i maskinens samlede tilstand, og den tilstanden kan forbli sann gjennom en VPN-frakobling og gjenoppkobling. En observatør må overvåke klienten som eier tunnelen, ikke nettverksstakkens sammendrag av den.
Tilgjengelighet er et aggregat, ikke tunnelen din
NetworkAvailabilityChanged utløses når maskinens samlede tilgjengelighetssvar endres, og det svaret teller ethvert aktivt grensesnitt utenom loopback eller en tunnel.
Et VPN-brudd mens Wi-Fi er oppe endrer ingenting av det den måler, derfor kan hendelsen forbli taus gjennom nettopp feilen du bryr deg om.
Tilstandsstrømmen tilhører klienten som eier tunnelen
Finn ut hvilken komponent som eier tilkoblingen: OpenVPN GUI eller -tjeneste, OpenVPN Connect, eller en prosess applikasjonen din startet og kontrollerer. Dette er ulike eiere med ulike støttede grensesnitt, og observatøren må bruke det som passer til utrullingen. For en OpenVPN-prosess du har tillatelse til å integrere med, rapporterer administrasjonsgrensesnittet gjeldende tilstand, en historikk og sanntidsvarsler. Analyser de dokumenterte strukturerte meldingene i stedet for å søke etter ordet connected i en lokalisert GUI-tekst.
Administrasjonskanalen er en privilegert kontrollflate, så ikke åpne en ny lytter og ikke kjempe med GUI-en om en kanal den allerede holder.
Generasjonsvakter stopper utdaterte resultater
Hver observasjon tilhører et bestemt tilkoblingsforsøk. Øk en generasjonsteller når et nytt forsøk starter, når kanalen mistes og når klienten rapporterer avslutning.
Tenk på en probe startet under tilkobling A. Tunnelen faller, tilkobling B begynner, og deretter ankommer As forsinkede HTTP-suksess. Uten en vakt gjør det gamle resultatet skjermen grønn mens B fortsatt autentiserer. Avbrytelse reduserer bortkastet arbeid, og generasjonskontrollen er det som hindrer en utdatert fullføring i å bli gjeldende tilstand:
var generation = _generation;
var reachable = await ProbeAsync(token);
if (generation != _generation) return;
Publish(reachable);
Bruk samme regel rundt UI-utsendelsen, fordi den marshallede oppdateringen kan ankomme etter at generasjonen har flyttet seg videre.
Initialisering og gjenoppkobling er én livssyklus
Behandle første tilkobling, gjenoppkobling og kanaltap som én livssyklus med ett regelsett:
- Les gjeldende tilstand og abonner på varsler i ett trinn der grensesnittet tillater det.
- Merk hver observasjon med tilkoblingens identitet og generasjonen.
- Ugyldiggjør beredskap ved gjenoppkobling, avslutning eller en tapt observasjonskanal.
- Prob det private ressursen først etter at eieren rapporterer at initialiseringen er fullført.
- Publiser bare resultater som fortsatt tilhører gjeldende generasjon.
En tapt kanal betyr ukjent, ikke frakoblet. Å rapportere ukjent er ærligere enn å rapportere en frakobling du ikke kan bevise, og det hindrer gjenforsøkslogikken i å handle på en gjetning.
Rapporter bevis, ikke en boolean
Returner den navngitte sesjonstilstanden og ressurberedskapen som separate verdier, hver med en alder. En forbruker som må avgjøre noe, kan da se at den siste vellykkede proben er førti sekunder gammel, noe som er annen informasjon enn en fersk.
Et oppslag av offentlig IP er ikke bevis for at et privat API brukte den påkrevde ruten, så ikke presenter det som om det var det.
Hold håndhevelsen utenfor observatøren
En callback kjører i etterkant. Den kan ikke garantere at ingen pakke forlot maskinen mellom hendelsen og behandleren. Hvis designet krever blokkering, må nettverkspolicyen levere det, og observatørens jobb er å forklare bevisene til den som kaller. Å blande de to gir kode som tror den er en brannmur fordi den holder en boolean. Hold håndhevelseslaget kjedelig og testbart, og la observatøren forbli en leser.
Da blir UI-spørsmålet enkelt: vis det som er kjent, med alderen sin, og si ukjent når det er tilfelle.