When the TCP connection close in this code?


When I read this opensource code.

I have two questions about the two functions:

func listenTCP() {
    for {
        conn, err := tcpListener.Accept()
        if err != nil {
            if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
                log.Printf("Temporary error while accepting connection: %s", netErr)

            log.Fatalf("Unrecoverable error while accepting connection: %s", err)

        go handleTCPConn(conn)  // check below

func handleTCPConn(conn net.Conn) {
    log.Printf("Accepting TCP connection from %s with destination of %s", conn.RemoteAddr().String(), conn.LocalAddr().String())
    defer conn.Close()
    remoteConn, err := conn.(*tproxy.Conn).DialOriginalDestination(false)
    if err != nil {
        log.Printf("Failed to connect to original destination [%s]: %s", conn.LocalAddr().String(), err)
    defer remoteConn.Close()

    var streamWait sync.WaitGroup

    streamConn := func(dst io.Writer, src io.Reader) {
        io.Copy(dst, src)

    go streamConn(remoteConn, conn)
    go streamConn(conn, remoteConn)


Based on my understanding, I draw this diagram:

enter image description here

You see, the handleTCPConn created two goroutines for transmitting two direction(left -> right; right -> left)’s traffic,

My questions are:

  1. You see the code use sync.WaitGroup, if they only send left-> right traffic, there is no traffic in opposite direction, so the handleTCPConn will not end, right? if it is, the listenTCP for loop will create many of those handleTCPConn function calls, is there nothing wrong with this program?

  2. Every time the handleTCPConn is used, it will create a TCP connection to the remote server.

remoteConn, err := conn.(*tproxy.Conn).DialOriginalDestination(false)

My question is still in question 1, you can see that the handleTCPConn transmit the traffic once in both directions, and then ends it, whether the TCP connection is closed when does handleTCPConn end?
if they only transmit part of the data of a file(as per the application layer view), whether it is closed too? (i mean, if A->B->C: part data , then C->B->A: ACK ) .


per the golang docs, https://pkg.go.dev/io#Copy

Copy copies from src to dst until either EOF is reached on src or an error occurs. It returns the number of bytes copied and the first error encountered while copying, if any.

So when you start this program up, it will sit there and wait for you to hit the ‘proxy’, and send your bytes from the source to the destination… when the destination responds it will copy all those bytes back. if the destination doesn’t write any bytes and doesn’t close the connection i believe it’ll sit there forever, waiting for the far side to either close the socket or respond.

Same is true if you make this connection and the remote sides starts sending data (without a request first). If the "local" side never sends any bytes and doesn’t close the connection this code would wait forever as well.

As long as the remote side closes the connection gracefully, this code should exit with "0" bytes received and no error. If the remote side sends a reset, you should get an error of some kind

Answered By – Clint D

Answer Checked By – David Marino (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.