From dfdca9f595d5fd1d1dd3d1aa5bbf41f540deba80 Mon Sep 17 00:00:00 2001 From: Adrian Lopez Date: Fri, 15 Mar 2019 14:16:37 +0100 Subject: [PATCH] Handle correctly servers not initiating close If we use the default handler to a Redis server, Switcher will keep the connection open forever, because Redis server is not going to initiate the close of the connection. With this new scheme, as soon as one channel has finished sending data, the two connections are closed and Shovel could finish. This follows the pattern seen in https://github.com/google/tcpproxy/blob/master/tcpproxy.go#L386 --- shovel.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/shovel.go b/shovel.go index 04dd184..a84aed7 100644 --- a/shovel.go +++ b/shovel.go @@ -2,27 +2,34 @@ package main import ( "io" + "log" + "strings" ) // proxy between two sockets func Shovel(local, remote io.ReadWriteCloser) error { errch := make(chan error, 1) + defer func() { + go local.Close() + }() + + defer func() { + go remote.Close() + }() + go chanCopy(errch, local, remote) go chanCopy(errch, remote, local) - for i := 0; i < 2; i++ { - if err := <-errch; err != nil { - // If this returns early the second func will push into the - // buffer, and the GC will clean up - return err - } - } + <-errch return nil } // copy between pipes, sending errors to channel func chanCopy(e chan error, dst, src io.ReadWriter) { _, err := io.Copy(dst, src) + if err != nil && !strings.HasSuffix(err.Error(), ": use of closed network connection") { + log.Printf("[ERROR] chanCopy: %v\n", err) + } e <- err }