Dy simptoma shfaqen në të njëjtin cikël VpnService dhe të dyja fajësojnë të njëjtën gjë: një lexues që nuk kthehet kurrë, dhe një shkrim që dështon me ENOBUFS. Nuk janë variante të një bug-u të vetëm. Një lexim i bllokuar është mospajtim për kontrollin e rrjedhës me peer-in; një shkrim i dështuar është një paketë që ndërfaqja nuk do ta pranojë. Nëse i trajtoni si një problem të vetëm, do të kaloni një ditë duke rregulluar buferë që nuk ishin përfshirë kurrë. Ndarja më poshtë është si vendos se cilën gjysmë të ciklit instrumentoj fillimisht.

Një cikël, dy pika dështimi të pavarura

Shërbimi juaj lexon një paketë IP nga përshkruesi i skedarit TUN, e inspekton dhe shkruan një përgjigje përsëri në të njëjtin përshkrues. Gjithçka që prishet në atë rrugë shfaqet në njërën nga këto dy thirrje, prandaj të dyja raportohen si tunel i prishur. Thirrjet kanë kontrata të ndryshme. Leximi pret që kerneli t'ju japë një paketë, dhe shkrimi i jep kernelit një paketë që ai ka të drejtë ta refuzojë.

Leximet janë gjysma e lehtë për të menduar. Një lexim që nuk kthen asgjë ose pret trafik që nuk vjen kurrë ose pret sepse peer-i ndaloi së dërguari.

Një lexim i bllokuar është mospajtim për kontrollin e rrjedhës

Leximi i një pajisjeje TUN bllokohet derisa një paketë të jetë e disponueshme. Ky është sjellje e projektuar, dhe prandaj një thread i ndalur brenda read duket normal në një lidhje boshe. Bëhet bllokim kur stack-u juaj TCP vazhdon të pranojë të dhëna nga aplikacioni lokal por nuk shpall kurrë një dritare të mjaftueshme që peer-i i largët të dërgojë më shumë. Peer-i mbush dritaren që keni shpallur, pret një ACK dhe një përditësim të dritares, dhe ndalon. Atëherë lexuesi juaj nuk ka asgjë për të kthyer, dhe aplikacioni sheh një lidhje të hapur dhe të qetë.

Shkaqet e zakonshme janë një stack që shkruan në socket pa ndjekur dritaren e shpallur, dhe një tjetër që harron të dërgojë një përditësim të dritares pasi zbraz buferin e tij. Nga jashtë duken identike: bajtët dalin, asgjë nuk kthehet, asnjë gabim nuk ngrihet. Bllokimi i thread-it të leximit në parsing, zgjidhje DNS ose I/O disku prodhon të njëjtën formë simptome për një arsye të palidhur, prandaj konfirmoni që thread-i është me të vërtetë brenda read përpara se të fajësoni kontrollin e rrjedhës.

Kontrolloni radhën e dërgimit të peer-it dhe dritaren që pa për herë të fundit. Nëse peer-i mban të dhëna sepse dritarja juaj është zero, rregullimi është në rrugën tuaj ACK, jo në leximin TUN.

ENOBUFS është problem madhësie, jo mungesë buferi

Një shkrim që kthen ENOBUFS në një ndërfaqe TUN zakonisht refuzon gjatësinë e paketës. Ndërfaqja ka një MTU, një paketë më e madhe nuk mund të vihet në radhë, dhe përsëritja e së njëjtës paketë dështon në të njëjtën mënyrë çdo herë. Ky determinizëm është shenja. Një mungesë e vërtetë buferi pastrohet kur presioni bie, ndërsa një refuzim madhësie nuk interesohet sa gjatë prisni.

TCP ka një mekanizëm pikërisht për këtë, dhe është hapi që njerëzit e kapërcejnë: clamp-i MSS. Kur sintetizoni segmente në hapësirën e përdoruesit ju zgjidhni madhësinë e payload-it, dhe marrja e saj nga MTU-ja e ndërfaqes lokale në vend të MTU-së së tunelit lëshon segmente që tuneli nuk mund t'i mbajë. Kufizojeni në më të voglin e dyve. Clamp-i mbulon vetëm TCP, prandaj një datagram UDP tepër i madh duhet të fragmentohet ose të hidhet nga kodi juaj.

Regjistroni gjatësinë e çdo pakete që shkruani gjatë korrigjimit. Gjatësia që dështon është përgjigjja, dhe nuk do të ndryshojë midis provave.

Tre matje që i ndajnë rastet

Nuk ju nevojitet një debugger për asnjërën nga dy dështimet. Tre vëzhgime mjaftojnë për t'ju drejtuar në seksionin e duhur, dhe marrin më pak kohë se një rindërtim.

What you seeWhere to look
Reader parked, peer send queue empty, last advertised window zeroWindow updates in your ACK path
Write fails on one length and succeeds on a smaller oneMSS clamp and tunnel MTU
Both directions look fine, app still sees no dataProtected socket and routing loop

Nëse rreshti i tretë përputhet, cikli vetë është në rregull dhe problemi qëndron aty ku tuneli nuk mund ta shohë: një socket transporti i pambrojtur që e çon trafikun tuaj VPN përsëri në tunel, gjë që zakonisht shfaqet si një lidhje që ka sukses dhe pastaj nuk dorëzon asgjë.

Rregulloni hidraulikun nga i cili varen të dyja rrugët

Asnjë simptomë nuk ia vlen të ndiqet derisa ndërfaqja të ndërtohet si duhet. Thirrjet builder që kanë rëndësi janë adresa, rruga, MTU-ja dhe pëlqimi, në atë rend:

Builder()
  .addAddress(10.8.0.2, 32)
  .addRoute(0.0.0.0, 0)
  .setMtu(1400)
  .establish()

Vendosni MTU-në në vlerën reale të tunelit në vend që ta lini në atë që përdori shembulli. Gjithçka që shkruani më vonë kufizohet nga ai numër, dhe mospërputhja midis MTU-së që vendosni dhe MSS-së në të cilën kufizoni është mënyra më e zakonshme për të rikthyer dështimin e shkrimit pas një rregullimi. Pastaj mbroni socket-in që transporton trafikun drejt vetë serverit VPN. Pa protect ato paketa ridrejtohen përsëri në tunelin tuaj dhe lidhja nuk përfundon kurrë, gjë që duket si lexim i bllokuar por është një cikël rrugëtimi.

Pëlqimi nuk mund të anashkalohet. Një shërbim i nisur pa prepare që kthen null nuk merr ndërfaqe, dhe establish kthen null në vend që të hedhë, prandaj kontrolloni përshkruesin përpara se të nisni ciklin. Referenca e VpnService është vendi për të konfirmuar kontratën e builder në vend që të kopjoni një shembull.

Verifikoni një drejtim njëherësh

Dërgoni një jehonë UDP përmes tunelit dhe vëzhgoni gjatësitë e paketave përpara se të prekni TCP. Pastaj hapni një shtrëngim duarsh dhe konfirmoni që segmentet mbeten nën MSS-në që keni llogaritur. Numëroni paketa, jo lidhje, që një bllokim të shfaqet si një boshllëk në numërues në vend të një socket të varur. Nëse leximet ndalen pas një breshërie shkrimesh, dritarja është e dyshuara; nëse shkrimet dështojnë menjëherë, është gjatësia.

Pastaj rindizni pajisjen dhe përsëritni një herë, sepse një VpnService që funksionon vetëm deri në ndryshimin e parë të rrjetit është problem rrugëtimi dhe jo i kontrollit të rrjedhës.

Artikuj të ngjashëm