The SOCKS handshake succeeded. Now the relay reads from the client, writes to the destination, waits for a full response, and only then reads the client again. That sequence can deadlock a perfectly valid application.

Once the TCP tunnel is established, SOCKS does not define the messages inside it. The destination might send first. Both sides might send independently. One side might send a short record and then wait for the other's answer.

Relay bytes, not guessed transactions

A receive call returns available bytes according to its flags and socket state. It does not tell a generic relay that an application response is complete. Waiting for an arbitrary large buffer to fill can prevent forwarding the small message the peer needs to continue.

Use the application's existing concurrency model to service both directions: an event loop, asynchronous I/O, or another deliberately chosen design. The important behavior is that progress in one direction does not require an invented message boundary in the other.

Keep two bounded pending buffers

Data read from the client may still be waiting to reach the destination, while data from the destination waits to reach the client. Track those pending bytes separately.

A send can write fewer bytes than requested. Retain the unwritten portion; do not drop it or replay the entire buffer. A temporarily unwritable socket is a reason to wait for the correct readiness event, not spin continuously.

Bound the buffers. If the destination is slow, continuing to read unlimited client data simply moves the queue into the relay's memory. Backpressure means pausing reads when the corresponding pending buffer is full and resuming when writes make room.

An end in one direction needs a policy

TCP can close a sending direction while the other direction still has useful data. Decide how to propagate that condition after buffered bytes drain, and distinguish orderly close from an error or deadline.

None of this requires the relay to decrypt or parse the application's payload. It needs correct stream handling. Increasing the buffer size alone cannot repair a relay that waits for the wrong side or assumes every read corresponds to one whole request.

متعلقہ مضامین