Flusso full-duplex e contropressione in un relay SOCKS
Progettate il flusso del relay attorno a flussi di byte indipendenti, I/O parziale, buffer limitati e contropressione invece di dimensioni di risposta ipotizzate.
La stretta di mano SOCKS è riuscita. Ora il relay legge dal client, scrive verso la destinazione, attende una risposta completa e solo dopo rilegge dal client. Questa sequenza può bloccare un'applicazione del tutto valida.
Una volta stabilito il tunnel TCP, SOCKS non definisce i messaggi al suo interno. La destinazione potrebbe inviare per prima. Entrambi i lati possono inviare in modo indipendente. Un lato può inviare un record breve e poi attendere la risposta dell'altro.
Inoltrate byte, non transazioni presunte
Una chiamata di ricezione restituisce i byte disponibili in base ai suoi flag e allo stato del socket. Non dice a un relay generico che la risposta dell'applicazione è completa. Attendere che si riempia un buffer arbitrariamente grande può impedire l'inoltro del piccolo messaggio necessario al pari per proseguire.
Usate il modello di concorrenza esistente dell'applicazione per servire entrambe le direzioni: un ciclo di eventi, I/O asincrono o un'altra progettazione scelta deliberatamente. Il comportamento importante è che il progresso in una direzione non richieda un confine di messaggio inventato nell'altra.
Mantenete due buffer in sospeso limitati
I dati letti dal client possono essere ancora in attesa di raggiungere la destinazione, mentre i dati della destinazione attendono di raggiungere il client. Tracciate separatamente questi byte in sospeso.
Un invio può scrivere meno byte del richiesto. Conservate la parte non scritta; non scartatela e non riprodurre l'intero buffer. Un socket temporaneamente non scrivibile è motivo di attendere l'evento di prontezza corretto, non di girare continuamente.
Limitate i buffer. Se la destinazione è lenta, continuare a leggere dati client illimitati sposta soltanto la coda nella memoria del relay. La contropressione significa sospendere le letture quando il buffer in sospeso corrispondente è pieno e riprenderle quando le scritture liberano spazio.
Una fine in una direzione richiede una politica
TCP può chiudere una direzione di invio mentre l'altra direzione ha ancora dati utili. Decidete come propagare quella condizione dopo aver svuotato i byte memorizzati, e distinguete la chiusura ordinata da un errore o da una scadenza.
Nulla di tutto ciò richiede che il relay decifri o analizzi il carico utile dell'applicazione. Serve una corretta gestione del flusso. Aumentare solo la dimensione del buffer non può riparare un relay che attende il lato sbagliato o presume che ogni lettura corrisponda a una richiesta intera.