Android VpnService: stíflað TUN-lestur á móti ENOBUFS-skrifvillum
Lestur sem snýr aldrei aftur og skrif sem mistakast með ENOBUFS hafa gagnstæðar orsakir. Mældu tilkynnta gluggann og pakkalengdina til að velja lagfæringuna.
Tvö einkenni koma fram í sama VpnService-lykkju og er kennt um sama hlutinn: lesari sem snýr aldrei aftur, og skrif sem mistakast með ENOBUFS. Þau eru ekki afbrigði af einni villu. Stíflað lestur er ágreiningur um flæðisstjórnun við jafningjann; misheppnuð skrif eru pakki sem viðmótið tekur ekki við. Ef þú meðhöndlar þau sem eitt vandamál eyðir þú degi í að stilla biðminni sem voru aldrei hluti af málinu. Skiptingin hér að neðan er hvernig ég ákveð hvaða helming lykkjunnar á að mæla fyrst.
Ein lykkja, tveir óháðir bilunarpunktar
Þjónustan þín les IP-pakka úr TUN-skráarlysingu, skoðar hann og skrifar svar aftur í sömu lýsinguna. Allt sem brotnar á þeirri leið kemur fram í öðru hvoru þessara tveggja kalla, þess vegna er tilkynnt um bæði sem bilaða göng. Köllin hafa mismunandi samninga. Lestur bíður þess að kjarninn afhendi þér pakka, og skrif afhenda kjarnanum pakka sem hann má hafna.
Lestur er sá auðveldi helmingur til að hugsa um. Lestur sem skilar engu annaðhvort bíður umferðar sem kemur aldrei eða bíður þess að jafninginn hætti að senda.
Stíflað lestur er ágreiningur um flæðisstjórnun
Lestur á TUN-tæki blokkar þar til pakki er tiltækur. Það er hönnuð hegðun, og þess vegna virðist þráður sem stendur í read eðlilegur á aðgerðarlausri tengingu. Það verður stífla þegar TCP-stakkinn þinn heldur áfram að taka við gögnum frá staðbundnu forritinu en tilkynnir aldrei nógu stóran glugga fyrir fjarlæga jafningjann að senda meira. Jafninginn fyllir gluggann sem þú tilkynntir, bíður ACK og gluggauppfærslu, og stoppar. Þá hefur lesarinn þinn ekkert að skila, og forritið sér tengingu sem er opin og þögul.
Algengu orsakirnar eru stackur sem skrifar í sokkinn án þess að fylgjast með tilkynnta glugganum, og annar sem gleymir að senda gluggauppfærslu eftir að hafa tæmt biðminnið. Að utan líta þeir eins út: bæti fara út, ekkert kemur til baka, engin villa er kastað. Að blokka lesþráðinn á þáttun, DNS-upplausn eða disk-I/O framleiðir sömu lögun einkenna af ótengdri ástæðu, svo staðfestu að þráðurinn sé raunverulega inni í read áður en þú kennir flæðisstjórnuninni um.
Athugaðu sendiröð jafningsins og gluggann sem hann sá síðast. Ef jafninginn heldur gögnum vegna þess að glugginn þinn er núll, er lagfæringin í ACK-leiðinni þinni, ekki í TUN-lestrinum.
ENOBUFS er stærðarvandamál, ekki biðminnisskortur
Skrif sem skila ENOBUFS á TUN-viðmóti hafna venjulega pakkalengdinni. Viðmótið hefur MTU, stærri pakki getur ekki farið í röð, og endurtaka sama pakka mistekst á sama hátt í hvert sinn. Sú fyrirsjáanleiki er vísbendingin. Raunverulegur biðminnisskortur hverfur þegar þrýstingur minnkar, en stærðarhöfnun er sama hve lengi þú bíður.
TCP hefur vélbúnað einmitt fyrir þetta, og það er skrefið sem fólk sleppir: MSS-klemmunin. Þegar þú býrð til hluta í notendarými velur þú stærð hleðslunnar, og að taka hana úr MTU staðbundna viðmótsins í stað MTU ganganna gefur frá sér hluta sem göngin geta ekki borið. Klemmdu að minni hvoru tveggja. Klemmunin nær aðeins yfir TCP, svo of stóran UDP-gagnapakka verður kóðinn þinn að sundra eða sleppa.
Skráðu lengd hvers pakka sem þú skrifar meðan þú kembir. Lengdin sem mistekst er svarið, og hún færist ekki milli tilrauna.
Þrjár mælingar sem aðgreina tilfellin
Þú þarft ekki kembiforrit fyrir hvora bilunina. Þrjár athuganir nægja til að beina þér að rétta hlutanum, og þær taka skemmri tíma en endurbygging.
| What you see | Where to look |
|---|---|
| Reader parked, peer send queue empty, last advertised window zero | Window updates in your ACK path |
| Write fails on one length and succeeds on a smaller one | MSS clamp and tunnel MTU |
| Both directions look fine, app still sees no data | Protected socket and routing loop |
Ef þriðja röðin passar er lykkjan sjálf í lagi og vandamálið er þar sem göngin sjá það ekki: óvarið flutningssokkur sem ber eigin VPN-umferð þína aftur inn í göngin, sem birtist venjulega sem tenging sem tekst og skilar svo engu.
Lagaðu pípulögnina sem báðar leiðirnar byggja á
Ekkert einkenni er þess virði að elta það fyrr en viðmótið er byggt rétt. Byggingarköllin sem skipta máli eru vistfangið, leiðin, MTU og samþykkið, í þeirri röð:
Builder()
.addAddress(10.8.0.2, 32)
.addRoute(0.0.0.0, 0)
.setMtu(1400)
.establish()Stilltu MTU á raunverulegt gildi ganganna í stað þess að láta það standa á því sem dæmið notaði. Allt sem þú skrifar síðar er bundið við þá tölu, og misræmi milli MTU sem þú stillir og MSS sem þú klemmir að er algengasta leiðin til að koma skrifvillunni aftur eftir lagfæringu. Verndaðu síðan sokkinn sem ber umferð til VPN-þjónsins sjálfs. Án protect er þeim pökkum beint aftur inn í eigin göng og tengingin klárast aldrei, sem lítur út eins og stíflað lestur en er leiðarlykkja.
Ekki er hægt að komast fram hjá samþykki. Þjónusta sem er ræst án þess að prepare skili null fær ekkert viðmót, og establish skilar null í stað þess að kasta, svo athugaðu lýsinguna áður en þú ræsir lykkjuna. VpnService-handbókin er staðurinn til að staðfesta byggingarsamninginn í stað þess að afrita dæmi.
Staðfestu eina átt í einu
Sendu UDP-bergmál í gegnum göngin og fylgstu með pakkalengdum áður en þú snertir TCP. Opnaðu síðan handaband og staðfestu að hlutarnir haldist undir MSS sem þú reiknaðir. Teldu pakka frekar en tengingar, svo stífla birtist sem bil í teljaranum í stað stíflaðs sokks. Ef lestur stöðvast eftir skrifhrinu er glugginn grunsamlegur; ef skrif mistakast samstundis er það lengdin.
Endurræstu síðan tækið og endurtaktu einu sinni, því VpnService sem virkar aðeins þar til fyrsta netbreytingin verður er leiðarvandamál en ekki flæðisstjórnunarvandamál.