Skip to content

Commit

Permalink
Avoid create new slice for each Read and Write.
Browse files Browse the repository at this point in the history
  • Loading branch information
cyfdecyf committed Apr 25, 2015
1 parent a457853 commit c045c82
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 18 deletions.
47 changes: 36 additions & 11 deletions shadowsocks/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,22 @@ import (
type Conn struct {
net.Conn
*Cipher
readBuf []byte
writeBuf []byte
}

func NewConn(cn net.Conn, cipher *Cipher) *Conn {
return &Conn{cn, cipher}
func NewConn(c net.Conn, cipher *Cipher) *Conn {
return &Conn{
Conn: c,
Cipher: cipher,
readBuf: leakyBuf.Get(),
writeBuf: leakyBuf.Get()}
}

func (c *Conn) Close() error {
leakyBuf.Put(c.readBuf)
leakyBuf.Put(c.writeBuf)
return c.Conn.Close()
}

func RawAddr(addr string) (buf []byte, err error) {
Expand Down Expand Up @@ -72,7 +84,14 @@ func (c *Conn) Read(b []byte) (n int, err error) {
return
}
}
cipherData := make([]byte, len(b))

cipherData := c.readBuf
if len(b) > len(cipherData) {
cipherData = make([]byte, len(b))
} else {
cipherData = cipherData[:len(b)]
}

n, err = c.Conn.Read(cipherData)
if n > 0 {
c.decrypt(b[0:n], cipherData[0:n])
Expand All @@ -81,23 +100,29 @@ func (c *Conn) Read(b []byte) (n int, err error) {
}

func (c *Conn) Write(b []byte) (n int, err error) {
var cipherData []byte
dataStart := 0
var iv []byte
if c.enc == nil {
var iv []byte
iv, err = c.initEncrypt()
if err != nil {
return
}
}

cipherData := c.writeBuf
dataSize := len(b) + len(iv)
if dataSize > len(cipherData) {
cipherData = make([]byte, dataSize)
} else {
cipherData = cipherData[:dataSize]
}

if iv != nil {
// Put initialization vector in buffer, do a single write to send both
// iv and data.
cipherData = make([]byte, len(b)+len(iv))
copy(cipherData, iv)
dataStart = len(iv)
} else {
cipherData = make([]byte, len(b))
}
c.encrypt(cipherData[dataStart:], b)

c.encrypt(cipherData[len(iv):], b)
n, err = c.Conn.Write(cipherData)
return
}
5 changes: 5 additions & 0 deletions shadowsocks/leakybuf.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ type LeakyBuf struct {
freeList chan []byte
}

const bufSize = 4096
const maxNBuf = 2048

var leakyBuf = NewLeakyBuf(maxNBuf, bufSize)

// NewLeakyBuf creates a leaky buffer which can hold at most n buffer, each
// with bufSize bytes.
func NewLeakyBuf(n, bufSize int) *LeakyBuf {
Expand Down
9 changes: 2 additions & 7 deletions shadowsocks/pipe.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,11 @@ func SetReadTimeout(c net.Conn) {
}
}

const bufSize = 4096
const nBuf = 2048

var pipeBuf = NewLeakyBuf(nBuf, bufSize)

// PipeThenClose copies data from src to dst, closes dst when done.
func PipeThenClose(src, dst net.Conn, timeoutOpt int) {
defer dst.Close()
buf := pipeBuf.Get()
defer pipeBuf.Put(buf)
buf := leakyBuf.Get()
defer leakyBuf.Put(buf)
for {
if timeoutOpt == SET_TIMEOUT {
SetReadTimeout(src)
Expand Down

0 comments on commit c045c82

Please sign in to comment.