Fluxo full-duplex e backpressure em um relay SOCKS
Projete o fluxo do relay em torno de fluxos de bytes independentes, I/O parcial, buffers limitados e backpressure, em vez de tamanhos de resposta adivinhados.
O handshake do SOCKS foi concluído. Agora o relay lê do cliente, escreve no destino, espera uma resposta completa e só então lê do cliente novamente. Essa sequência pode travar um aplicativo perfeitamente válido.
Depois que o túnel TCP é estabelecido, o SOCKS não define as mensagens dentro dele. O destino pode enviar primeiro. Os dois lados podem enviar de forma independente. Um lado pode enviar um registro curto e então esperar a resposta do outro.
Encaminhe bytes, não transações adivinhadas
Uma chamada de recebimento retorna os bytes disponíveis de acordo com suas flags e o estado do socket. Ela não informa a um relay genérico que a resposta do aplicativo está completa. Esperar que um buffer arbitrariamente grande se encha pode impedir o encaminhamento da pequena mensagem de que o par precisa para continuar.
Use o modelo de concorrência existente do aplicativo para atender as duas direções: um event loop, I/O assíncrono ou outro design escolhido deliberadamente. O comportamento importante é que o progresso em uma direção não exige uma fronteira de mensagem inventada na outra.
Mantenha dois buffers pendentes limitados
Dados lidos do cliente ainda podem estar esperando para chegar ao destino, enquanto dados do destino esperam para chegar ao cliente. Rastreie esses bytes pendentes separadamente.
Um envio pode gravar menos bytes do que o solicitado. Mantenha a parte não gravada; não a descarte nem repita o buffer inteiro. Um socket temporariamente não gravável é motivo para esperar o evento de prontidão correto, não para girar continuamente.
Limite os buffers. Se o destino estiver lento, continuar lendo dados ilimitados do cliente apenas move a fila para a memória do relay. Backpressure significa pausar as leituras quando o buffer pendente correspondente estiver cheio e retomá-las quando as gravações abrirem espaço.
Um fim em uma direção exige uma política
O TCP pode fechar uma direção de envio enquanto a outra direção ainda tem dados úteis. Decida como propagar essa condição depois que os bytes armazenados forem drenados, e distinga o fechamento ordenado de um erro ou prazo.
Nada disso exige que o relay descriptografe ou analise o payload do aplicativo. Ele precisa de tratamento correto do fluxo. Aumentar apenas o tamanho do buffer não conserta um relay que espera pelo lado errado ou presume que cada leitura corresponde a uma requisição inteira.