Android VpnService: TUN పఠనం నిలిచిపోవడం మరియు ENOBUFS రాత లోపాలు
ఎప్పుడూ తిరిగి రాని పఠనం మరియు ENOBUFS తో విఫలమయ్యే రాత వ్యతిరేక కారణాలను కలిగి ఉంటాయి. సరిచేతను ఎంచుకోవడానికి ప్రకటించిన విండో మరియు ప్యాకెట్ పొడవును కొలవండి.
ఒకే VpnService లూప్లో రెండు లక్షణాలు కనిపిస్తాయి మరియు రెండింటినీ ఒకే విషయంపై నిందిస్తారు: ఎప్పుడూ తిరిగి రాని పాఠకుడు, మరియు ENOBUFS తో విఫలమయ్యే రాత. ఇవి ఒకే బగ్ రకాలు కావు. నిలిచిన పఠనం peer తో ప్రవాహ నియంత్రణ గురించి అభిప్రాయ భేదం; విఫలమైన రాత ఇంటర్ఫేస్ అంగీకరించని ప్యాకెట్. వాటిని ఒకే సమస్యగా భావిస్తే, ఎప్పుడూ సంబంధం లేని బఫర్లను సర్దుబాటు చేయడంలో ఒక రోజు గడుపుతారు. క్రింది విభజన లూప్లోని ఏ సగం ముందు కొలవాలో నేను ఎలా నిర్ణయిస్తానో చెబుతుంది.
ఒక లూప్, రెండు స్వతంత్ర వైఫల్య బిందువులు
మీ సేవ TUN ఫైల్ డిస్క్రిప్టర్ నుండి IP ప్యాకెట్ చదువుతుంది, పరిశీలిస్తుంది, అదే డిస్క్రిప్టర్కు ప్రత్యుత్తరం రాస్తుంది. ఆ మార్గంలో విరిగిన ప్రతిదీ ఆ రెండు కాల్స్లో ఒకదానిలో కనిపిస్తుంది, అందుకే రెండింటినీ విరిగిన సొరంగం అని నివేదిస్తారు. కాల్స్కు వేర్వేరు ఒప్పందాలు ఉన్నాయి. పఠనం కర్నెల్ మీకు ప్యాకెట్ ఇచ్చే వరకు వేచి ఉంటుంది, రాత కర్నెల్కు తిరస్కరించే హక్కు ఉన్న ప్యాకెట్ను ఇస్తుంది.
పఠనాలు ఆలోచించడానికి సులభమైన సగం. ఏమీ తిరిగి ఇవ్వని పఠనం గానీ ఎప్పుడూ రాని ట్రాఫిక్ కోసం వేచి ఉంటుంది లేదా peer పంపడం ఆపినందుకు వేచి ఉంటుంది.
నిలిచిన పఠనం ప్రవాహ నియంత్రణపై అభిప్రాయ భేదం
TUN పరికరాన్ని చదవడం ప్యాకెట్ అందుబాటులో ఉండే వరకు నిరోధిస్తుంది. అది రూపకల్పన చేసిన ప్రవర్తన, అందుకే read లోపల నిలిచిన థ్రెడ్ నిష్క్రియ లింక్పై సాధారణంగా కనిపిస్తుంది. మీ స్వంత TCP స్టాక్ స్థానిక యాప్ నుండి డేటాను స్వీకరిస్తూనే ఉన్నా దూర peer మరింత పంపడానికి సరిపోయే విండోను ఎప్పుడూ ప్రకటించనప్పుడు అది హ్యాంగ్ అవుతుంది. Peer మీరు ప్రకటించిన విండోను నింపి, ACK మరియు విండో నవీకరణ కోసం వేచి, ఆగిపోతుంది. అప్పుడు మీ పాఠకుడికి తిరిగి ఇవ్వడానికి ఏమీ ఉండదు, యాప్ తెరిచి ఉన్నా నిశ్శబ్దంగా ఉన్న కనెక్షన్ను చూస్తుంది.
సాధారణ కారణాలు ప్రకటించిన విండోను ట్రాక్ చేయకుండా సాకెట్కు రాసే స్టాక్, మరియు తన బఫర్ ఖాళీ చేసిన తర్వాత విండో నవీకరణ పంపడం మరచిపోయే స్టాక్. బయటి నుండి రెండూ ఒకేలా కనిపిస్తాయి: బైట్లు బయటకు వెళ్తాయి, ఏమీ తిరిగి రాదు, ఏ లోపం లేవదు. పఠన థ్రెడ్ను పార్సింగ్, DNS పరిష్కారం లేదా డిస్క్ I/O పై నిరోధించడం సంబంధం లేని కారణంతో అదే ఆకారపు లక్షణాన్ని సృష్టిస్తుంది, కాబట్టి ప్రవాహ నియంత్రణను నిందించే ముందు థ్రెడ్ నిజంగా read లోపల ఉందని నిర్ధారించుకోండి.
Peer యొక్క పంపే క్యూ మరియు అది చివరిగా చూసిన విండోను తనిఖీ చేయండి. మీ విండో సున్నా కావడంతో peer డేటాను పట్టి ఉంచుతుంటే, సరిచేత మీ ACK మార్గంలో ఉంది, TUN పఠనంలో కాదు.
ENOBUFS పరిమాణ సమస్య, బఫర్ కొరత కాదు
TUN ఇంటర్ఫేస్పై ENOBUFS తిరిగి ఇచ్చే రాత సాధారణంగా ప్యాకెట్ పొడవును తిరస్కరిస్తుంది. ఇంటర్ఫేస్కు MTU ఉంటుంది, దాని కంటే పెద్ద ప్యాకెట్ క్యూలో పెట్టలేము, అదే ప్యాకెట్ను మళ్లీ ప్రయత్నించడం ప్రతిసారీ అదే విధంగా విఫలమవుతుంది. ఆ నిర్ణయాత్మకతే సూచన. నిజమైన బఫర్ కొరత ఒత్తిడి తగ్గినప్పుడు తొలగిపోతుంది, పరిమాణ తిరస్కరణ మీరు ఎంతసేపు వేచినా పట్టించుకోదు.
TCP కి దీనికోసమే ఒక యంత్రాంగం ఉంది, అదే ప్రజలు దాటవేసే దశ: MSS క్లాంప్. మీరు వినియోగదారు స్థలంలో సెగ్మెంట్లను సంశ్లేషణ చేసేటప్పుడు పేలోడ్ పరిమాణాన్ని మీరే ఎంచుకుంటారు, దాన్ని సొరంగం MTU కి బదులు స్థానిక ఇంటర్ఫేస్ MTU నుండి తీసుకోవడం సొరంగం మోయలేని సెగ్మెంట్లను విడుదల చేస్తుంది. రెండింటిలో చిన్నదానికి పరిమితం చేయండి. క్లాంప్ TCP ని మాత్రమే కవర్ చేస్తుంది, కాబట్టి చాలా పెద్ద UDP డేటాగ్రామ్ను మీ కోడ్ విభజించాలి లేదా వదిలేయాలి.
డీబగ్ చేస్తున్నప్పుడు మీరు రాసే ప్రతి ప్యాకెట్ పొడవును లాగ్ చేయండి. విఫలమయ్యే పొడవే సమాధానం, అది ప్రయత్నాల మధ్య మారదు.
కేసులను వేరుచేసే మూడు కొలతలు
రెండు వైఫల్యాలలో దేనికైనా మీకు డీబగ్గర్ అవసరం లేదు. సరైన విభాగానికి దారితీయడానికి మూడు పరిశీలనలు సరిపోతాయి, అవి పునర్నిర్మాణం కంటే తక్కువ సమయం తీసుకుంటాయి.
| 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 |
మూడవ వరుస సరిపోలితే, లూప్ స్వయంగా బాగుంది మరియు సమస్య సొరంగం చూడలేని చోట ఉంది: మీ స్వంత VPN ట్రాఫిక్ను సొరంగంలోకి తిరిగి తీసుకువెళ్లే అసురక్షిత రవాణా సాకెట్, ఇది సాధారణంగా విజయవంతమై తర్వాత ఏమీ అందించని కనెక్షన్గా కనిపిస్తుంది.
రెండు మార్గాలు ఆధారపడే ప్లంబింగ్ను బాగుచేయండి
ఇంటర్ఫేస్ సరిగ్గా నిర్మించబడే వరకు ఏ లక్షణాన్ని వెంటాడడం విలువైనది కాదు. ముఖ్యమైన builder కాల్స్ చిరునామా, మార్గం, MTU మరియు సమ్మతి, ఆ క్రమంలో:
Builder()
.addAddress(10.8.0.2, 32)
.addRoute(0.0.0.0, 0)
.setMtu(1400)
.establish()MTU ని నమూనా ఉపయోగించిన విలువపై వదలకుండా సొరంగం యొక్క నిజమైన విలువకు సెట్ చేయండి. తర్వాత మీరు రాసేదంతా ఆ సంఖ్యతో పరిమితమవుతుంది, మీరు సెట్ చేసే MTU మరియు మీరు పరిమితం చేసే MSS మధ్య భేదమే సరిచేత తర్వాత రాత వైఫల్యాన్ని తిరిగి తీసుకురావడానికి అత్యంత సాధారణ మార్గం. తర్వాత VPN సర్వర్కే ట్రాఫిక్ మోసే సాకెట్ను రక్షించండి. protect లేకుండా ఆ ప్యాకెట్లు మీ స్వంత సొరంగంలోకి తిరిగి మార్గనిర్దేశం చేయబడతాయి మరియు కనెక్షన్ ఎప్పటికీ పూర్తి కాదు, ఇది నిలిచిన పఠనంలా కనిపిస్తుంది కానీ మార్గనిర్దేశన లూప్.
సమ్మతిని దాటవేయలేము. prepare null తిరిగి ఇవ్వకుండా ప్రారంభమైన సేవకు ఇంటర్ఫేస్ రాదు, మరియు establish విసరడానికి బదులు null తిరిగి ఇస్తుంది, కాబట్టి లూప్ ప్రారంభించే ముందు డిస్క్రిప్టర్ను తనిఖీ చేయండి. VpnService సూచన నమూనాను కాపీ చేయడానికి బదులు builder ఒప్పందాన్ని నిర్ధారించే స్థలం.
ఒకసారి ఒక దిశను ధృవీకరించండి
TCP ని తాకే ముందు సొరంగం గుండా UDP ప్రతిధ్వని పంపి ప్యాకెట్ పొడవులను గమనించండి. తర్వాత చేతులు కలపడం తెరిచి సెగ్మెంట్లు మీరు లెక్కించిన MSS కి దిగువన ఉండేలా నిర్ధారించండి. కనెక్షన్లకు బదులు ప్యాకెట్లను లెక్కించండి, తద్వారా నిలిచిపోవడం వేలాడే సాకెట్గా కాకుండా కౌంటర్లో ఖాళీగా కనిపిస్తుంది. రాతల వర్షం తర్వాత పఠనాలు ఆగితే విండో అనుమానితం; రాతలు వెంటనే విఫలమైతే అది పొడవు.
తర్వాత పరికరాన్ని రీబూట్ చేసి ఒకసారి పునరావృతం చేయండి, ఎందుకంటే మొదటి నెట్వర్క్ మార్పు వరకు మాత్రమే పనిచేసే VpnService ప్రవాహ నియంత్రణది కాదు, మార్గనిర్దేశన సమస్య.