Skip to content

Commit

Permalink
Implement io.ReaderFrom/WriterTo for Conn (#13)
Browse files Browse the repository at this point in the history
This change increase performance when proxying wrapped connections using io.Copy.
Since go 1.11 copying between tcp connections uses the splice system call on linux yielding considerable performance improvments.
See: https://golang.org/doc/go1.11#net
  • Loading branch information
databus23 authored and jefferai committed Jan 8, 2020
1 parent 1266648 commit f0b8253
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 0 deletions.
16 changes: 16 additions & 0 deletions protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,22 @@ func (p *Conn) Read(b []byte) (int, error) {
return p.bufReader.Read(b)
}

func (p *Conn) ReadFrom(r io.Reader) (int64, error) {
if rf, ok := p.conn.(io.ReaderFrom); ok {
return rf.ReadFrom(r)
}
return io.Copy(p.conn, r)
}

func (p *Conn) WriteTo(w io.Writer) (int64, error) {
var err error
p.once.Do(func() { err = p.checkPrefix() })
if err != nil {
return 0, err
}
return p.bufReader.WriteTo(w)
}

func (p *Conn) Write(b []byte) (int, error) {
return p.conn.Write(b)
}
Expand Down
51 changes: 51 additions & 0 deletions protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package proxyproto

import (
"bytes"
"io"
"net"
"testing"
"time"
Expand Down Expand Up @@ -432,3 +433,53 @@ func testParse_ipv4_checkfunc(t *testing.T) {
}
}
}

type testConn struct {
readFromCalledWith io.Reader
net.Conn // nil; crash on any unexpected use
}

func (c *testConn) ReadFrom(r io.Reader) (int64, error) {
c.readFromCalledWith = r
return 0, nil
}
func (c *testConn) Write(p []byte) (int, error) {
return len(p), nil
}
func (c *testConn) Read(p []byte) (int, error) {
return 1, nil
}

func TestCopyToWrappedConnection(t *testing.T) {
innerConn := &testConn{}
wrappedConn := NewConn(innerConn, 0)
dummySrc := &testConn{}

io.Copy(wrappedConn, dummySrc)
if innerConn.readFromCalledWith != dummySrc {
t.Error("Expected io.Copy to delegate to ReadFrom function of inner destination connection")
}
}

func TestCopyFromWrappedConnection(t *testing.T) {
wrappedConn := NewConn(&testConn{}, 0)
dummyDst := &testConn{}

io.Copy(dummyDst, wrappedConn)
if dummyDst.readFromCalledWith != wrappedConn.conn {
t.Errorf("Expected io.Copy to pass inner source connection to ReadFrom method of destination")
}
}

func TestCopyFromWrappedConnectionToWrappedConnection(t *testing.T) {
innerConn1 := &testConn{}
wrappedConn1 := NewConn(innerConn1, 0)
innerConn2 := &testConn{}
wrappedConn2 := NewConn(innerConn2, 0)

io.Copy(wrappedConn1, wrappedConn2)
if innerConn1.readFromCalledWith != innerConn2 {
t.Errorf("Expected io.Copy to pass inner source connection to ReadFrom of inner destination connection")
}

}

0 comments on commit f0b8253

Please sign in to comment.