diff --git a/shadowsocks/pipe.go b/shadowsocks/pipe.go index 3355ff4..e78abd1 100644 --- a/shadowsocks/pipe.go +++ b/shadowsocks/pipe.go @@ -5,25 +5,30 @@ import ( "net" ) -func Pipe(src net.Conn, dst net.Conn, end chan int) { +func Pipe(src, dst net.Conn, end chan int) { + // Should not use io.Copy here. + // io.Copy will try to use the ReadFrom interface of TCPConn, but the src + // here is not a regular file, so sendfile is not applicable. + // io.Copy will fallback to the normal copy after discovering this, + // introducing unnecessary overhead. buf := make([]byte, 4096) for { num, err := src.Read(buf) - if err == nil { - _, err := dst.Write(buf[0:num]) - if err != nil { + // read may return EOF with num > 0 + // should always process num > 0 bytes before handling error + if num > 0 { + if _, err = dst.Write(buf[0:num]); err != nil { log.Println("write:", err) - end <- 1 - return + break } - } else { - log.Println("read:", err) - end <- 1 - return } - if num == 0 { - end <- 1 - return + if num == 0 { // num == 0 should associate with EOF + break + } + if err != nil { + log.Println("read:", err) + break } } + end <- 1 }