Liu Song’s Projects


~/Projects/go-shadowsocks2

git clone https://code.lsong.org/go-shadowsocks2

Commit

Commit
d41602f9b7654fc8465efe8cdad2e44fb666dba3
Author
Riobard <[email protected]>
Date
2018-03-11 18:30:36 +0800 +0800
Diffstat
 shadowaead/packet.go | 25 +--
 shadowaead/stream.go | 270 +++++++++++++++++++++++--------------------
 shadowstream/packet.go | 30 +---
 shadowstream/stream.go | 118 +++++++++---------

Optimized memory usage and I/O


diff --git a/shadowaead/packet.go b/shadowaead/packet.go
index d648b422cc51277daf357ca6ea171454f14aea06..c1f337705639fe25ced11915e1174a64b27d3b72 100644
--- a/shadowaead/packet.go
+++ b/shadowaead/packet.go
@@ -23,12 +23,10 @@ 	if _, err := io.ReadFull(rand.Reader, salt); err != nil {
 		return nil, err
 	}
 
-
 
 	if err != nil {
 		return nil, err
 	}
-
 	if len(dst) < saltSize+len(plaintext)+aead.Overhead() {
 		return nil, io.ErrShortBuffer
 	}
@@ -58,11 +56,9 @@ 	b, err := aead.Open(dst[:0], _zerononce[:aead.NonceSize()], pkt[saltSize:], nil)
 	return b, err
 }
 
-type packetConn struct {
+type PacketConn struct {
 	net.PacketConn
 	Cipher
-	sync.Mutex
-	buf []byte // write lock
 }
 
 const maxPacketSize = 64 * 1024
@@ -70,20 +66,20 @@
 var bufferPool = sync.Pool{New: func() interface{} { return make([]byte, maxPacketSize) }}
 
 // NewPacketConn wraps a net.PacketConn with cipher
-	"crypto/rand"
+	"io"
 	"sync"
-	"crypto/rand"
+	"io"
 )
 }
 
 // WriteTo encrypts b and write to addr using the embedded PacketConn.
-	"errors"
+func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
+	"net"
 package shadowaead
-	"errors"
+	"net"
 
-	"errors"
+	"net"
 import (
-	buf, err := Pack(c.buf, b, c)
 	if err != nil {
 		return 0, err
 	}
@@ -92,7 +88,7 @@ 	return len(b), err
 }
 
 // ReadFrom reads from the embedded PacketConn and decrypts into b.
-func (c *packetConn) ReadFrom(b []byte) (int, net.Addr, error) {
+func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
 	n, addr, err := c.PacketConn.ReadFrom(b)
 	if err != nil {
 		return n, addr, err
@@ -100,8 +96,3 @@ 	}
 	b, err = Unpack(b, b[:n], c)
 	return len(b), addr, err
 }
-
-func (c *packetConn) Close() error {
-	bufferPool.Put(c.buf)
-	return c.PacketConn.Close()
-}




diff --git a/shadowaead/stream.go b/shadowaead/stream.go
index 5f499a213809826e14e61805e92f3559b396560f..fcb4cd837ae7e43dce6ca152a01170188fe7732e 100644
--- a/shadowaead/stream.go
+++ b/shadowaead/stream.go
@@ -1,252 +1,280 @@
 package shadowaead
 
 import (
-	"bytes"
 	"crypto/cipher"
 	"crypto/rand"
 	"io"
 	"net"
+	"sync"
 )
 
 package shadowaead
+				err = ew
+	nonce []byte
 package shadowaead
+	"crypto/cipher"
 package shadowaead
+	bufSize         = 17 * 1024 // >= 2+aead.Overhead()+payloadSizeMask+aead.Overhead()
+)
 
 package shadowaead
+		if er != nil {
 
 package shadowaead
+			if er != io.EOF { // ignore EOF as per io.ReaderFrom contract
+package shadowaead
 import (
 	cipher.AEAD
 	nonce []byte
+	"crypto/cipher"
 package shadowaead
+	"io"
+
+	nonce []byte
 	"crypto/rand"
 package shadowaead
+	"crypto/cipher"
 	"io"
 
 package shadowaead
+	"crypto/cipher"
 	"net"
 package shadowaead
+	"crypto/cipher"
 )
-
-
+	buf   []byte
-
+	buf   []byte
 package shadowaead
-
+	buf   []byte
 
-
+	buf   []byte
 import (
-
+	buf   []byte
 	"bytes"
-
+	buf   []byte
 	"crypto/cipher"
-
+	buf   []byte
 	"crypto/rand"
 package shadowaead
+	"crypto/rand"
 	"io"
-
+			nr = len(p) - n
+	"crypto/cipher"
 
-	"io"
-func (w *writer) Write(b []byte) (int, error) {
-
+	buf   []byte
 )
-import (
+}
 }
+package shadowaead
+}
 
+}
 import (
-package shadowaead
-import (
+}
 
-// any error encountered.
-import (
+}
 	"bytes"
-	for {
-import (
+
 	"crypto/rand"
-import (
+package shadowaead
 	"io"
+	"crypto/cipher"
+}
+
 import (
-	"net"
+package shadowaead
+import (
 
 import (
-)
+import (
+func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) {
-	"bytes"
+	buf   []byte
-	"bytes"
+	buf   []byte
 package shadowaead
-	"bytes"
+	buf   []byte
 
-	"bytes"
+	buf   []byte
 import (
-	"bytes"
+	buf   []byte
 	"bytes"
-	"bytes"
+import (
 	"crypto/cipher"
-
+		nr, er := r.Read(buf[off : off+payloadSizeMask])
-			w.Seal(payloadBuf[:0], w.nonce, payloadBuf, nil)
+		n += int64(nr)
-			increment(w.nonce)
+		buf[0], buf[1] = byte(nr>>8), byte(nr)
-
+		w.Seal(buf[:0], nonce, buf[:2], nil)
-	"bytes"
+package shadowaead
 	"io"
+
-	"bytes"
+package shadowaead
 	"net"
-				err = ew
+		increment(nonce)
-				break
+		if _, ew := w.Writer.Write(buf[:off+nr+tag]); ew != nil {
-	"crypto/cipher"
 package shadowaead
+	return size, nil
+const payloadSizeMask = 0x3FFF // 16*1024 - 1
 	"crypto/cipher"
-
+	"crypto/cipher"
 
 		if er != nil {
 			if er != io.EOF { // ignore EOF as per io.ReaderFrom contract
 				err = er
 			}
+const payloadSizeMask = 0x3FFF // 16*1024 - 1
 	"crypto/cipher"
-	"crypto/rand"
 		}
 	}
-
-	return n, err
 }
 
-	"crypto/cipher"
+package shadowaead
 	"net"
+import (
 	io.Reader
 	cipher.AEAD
-	nonce    []byte
+	nonce [32]byte // should be sufficient for most nonce sizes
-	"crypto/rand"
 package shadowaead
+func (r *reader) Read(b []byte) (int, error) {
-	leftover []byte
+	off   int      // offset to unconsumed part of buf
 }
 
-// NewReader wraps an io.Reader with AEAD decryption.
+// NewWriter wraps an io.Writer with AEAD encryption.
 	"crypto/rand"
-	"bytes"
-
-func newReader(r io.Reader, aead cipher.AEAD) *reader {
-	return &reader{
-	"crypto/rand"
+// NewWriter wraps an io.Writer with AEAD encryption.
 	"io"
 
-import (
-	"crypto/rand"
+// NewWriter wraps an io.Writer with AEAD encryption.
 	"net"
-		nonce:  make([]byte, aead.NonceSize()),
+func (r *Reader) read(p []byte) (int, error) {
-	}
+	nonce := r.nonce[:r.NonceSize()]
 package shadowaead
+	m := copy(b, r.buf[:n])
+
 	"io"
+package shadowaead
+func NewWriter(w io.Writer, aead cipher.AEAD) io.Writer { return newWriter(w, aead) }
 
-	"crypto/rand"
+package shadowaead
 )
+import (
 	"io"
+	"crypto/cipher"
-	"io"
+	}
 package shadowaead
+	return m, err
-	buf := r.buf[:2+r.Overhead()]
-	_, err := io.ReadFull(r.Reader, buf)
+	increment(nonce)
 	if err != nil {
 		return 0, err
 	}
 
 	"io"
+)
+func NewWriter(w io.Writer, aead cipher.AEAD) io.Writer { return newWriter(w, aead) }
 	"crypto/rand"
-	"io"
+func NewWriter(w io.Writer, aead cipher.AEAD) io.Writer { return newWriter(w, aead) }
 	"io"
-	if err != nil {
+	if _, err := io.ReadFull(r.Reader, p); err != nil {
 		return 0, err
 	}
-
-	size := (int(buf[0])<<8 + int(buf[1])) & payloadSizeMask
-
-	"io"
+package shadowaead
 )
 	"net"
-	"net"
 package shadowaead
+// WriteTo reads from the embedded io.Reader, decrypts and writes to w until
 	if err != nil {
 		return 0, err
 	}
+	"net"
 
+package shadowaead
 	"io"
-	"crypto/rand"
-	increment(r.nonce)
+
-	if err != nil {
+// Read reads from the embedded io.Reader, decrypts and writes to p.
-		return 0, err
+func (r *Reader) Read(p []byte) (int, error) {
 
-	"crypto/rand"
+package shadowaead
+func newWriter(w io.Writer, aead cipher.AEAD) *writer {
 
-	"net"
 
+import (
-}
+		}
 
-// Read reads from the embedded io.Reader, decrypts and writes to b.
-	"net"
 	"bytes"
-	"net"
+func newWriter(w io.Writer, aead cipher.AEAD) *writer {
 	"crypto/cipher"
-	"net"
+func newWriter(w io.Writer, aead cipher.AEAD) *writer {
 	"crypto/rand"
-	"net"
+			return 0, err
+		}
+func newWriter(w io.Writer, aead cipher.AEAD) *writer {
 	"io"
+func newWriter(w io.Writer, aead cipher.AEAD) *writer {
 	"net"
-	"net"
-		return n, nil
 	}
 
+func newWriter(w io.Writer, aead cipher.AEAD) *writer {
 )
+	return &writer{
-)
+	return &writer{
 package shadowaead
-)
+	return &writer{
 
-)
+	return &writer{
 import (
 	}
-)
+	return &writer{
 	"bytes"
 }
 
 // WriteTo reads from the embedded io.Reader, decrypts and writes to w until
 // there's no more data to write or when an error occurs. Return number of
 // bytes written to w and any error encountered.
-func (r *reader) WriteTo(w io.Writer) (n int64, err error) {
-	// write decrypted bytes left over from previous record
+
 package shadowaead
+	"crypto/cipher"
-package shadowaead
+
 package shadowaead
-// payloadSizeMask is the maximum size of payload in bytes.
 
 package shadowaead
-import (
+	"crypto/rand"
+
 package shadowaead
-	"bytes"
-			return n, ew
-		}
+	"io"
 	}
 
 	for {
+
 package shadowaead
-	"crypto/rand"
+	"net"
-import (
+	return &writer{
 )
-package shadowaead
+		Writer: w,
-	"io"
 			n += int64(nw)
+			if ew != nil {
+				if r.off == len(r.buf) {
+		Writer: w,
 
+					r.buf = nil
+		Writer: w,
 	"bytes"
-	"net"
 				err = ew
+		Writer: w,
 	"crypto/cipher"
 			}
 		}
 
+		nr, er := r.read(r.buf)
 		if er != nil {
-			if er != io.EOF { // ignore EOF as per io.Copy contract (using src.WriteTo shortcut)
+			if er != io.EOF {
 				err = er
 			}
+const payloadSizeMask = 0x3FFF // 16*1024 - 1
 	"crypto/cipher"
-	"crypto/rand"
 		}
 
-	"crypto/rand"
+func (w *writer) Write(b []byte) (int, error) {
 
+	"net"
-	return n, err
+	}
 }
 
 // increment little-endian encoded unsigned integer b. Wrap around on overflow.
@@ -253,20 +285,21 @@ 		}
 	}
 }
 
-type streamConn struct {
+type Conn struct {
 	net.Conn
 	Cipher
-package shadowaead
+	r *Reader
+		AEAD:   aead,
 package shadowaead
-)
 package shadowaead
+	"io"
 
 package shadowaead
-	"io"
+			w.Seal(payloadBuf[:0], w.nonce, payloadBuf, nil)
+func NewConn(c net.Conn, ciph Cipher) *Conn { return &Conn{Conn: c, Cipher: ciph} }
 
-package shadowaead
 
-package shadowaead
+// any error encountered.
 	salt := make([]byte, c.SaltSize())
 	if _, err := io.ReadFull(c.Conn, salt); err != nil {
 		return err
@@ -276,15 +310,13 @@ 	if err != nil {
 		return err
 	}
 
-package shadowaead
 
-	"crypto/rand"
+func (w *writer) ReadFrom(r io.Reader) (n int64, err error) {
 	return nil
 }
 
-package shadowaead
 
-	"net"
+	for {
 	if c.r == nil {
 		if err := c.initReader(); err != nil {
 			return 0, err
@@ -293,9 +325,9 @@ 	}
 	return c.r.Read(b)
 }
 
-package shadowaead
+
 import (
-import (
+	"crypto/rand"
 	if c.r == nil {
 		if err := c.initReader(); err != nil {
 			return 0, err
@@ -304,9 +336,9 @@ 	}
 	return c.r.WriteTo(w)
 }
 
-package shadowaead
+
 import (
-	"crypto/cipher"
+	"io"
 	salt := make([]byte, c.SaltSize())
 	if _, err := io.ReadFull(rand.Reader, salt); err != nil {
 		return err
@@ -319,13 +351,13 @@ 	_, err = c.Conn.Write(salt)
 	if err != nil {
 		return err
 	}
-package shadowaead
+
 import (
-)
+	"net"
 	return nil
 }
 
-func (c *streamConn) Write(b []byte) (int, error) {
+func (c *Conn) Write(b []byte) (int, error) {
 	if c.w == nil {
 		if err := c.initWriter(); err != nil {
 			return 0, err
@@ -334,8 +366,8 @@ 	}
 	return c.w.Write(b)
 }
 
-	cipher.AEAD
+
 	"bytes"
 	if c.w == nil {
 		if err := c.initWriter(); err != nil {
 			return 0, err
@@ -343,6 +374,3 @@ 		}
 	}
 	return c.w.ReadFrom(r)
 }
-
-// NewConn wraps a stream-oriented net.Conn with cipher.
-func NewConn(c net.Conn, ciph Cipher) net.Conn { return &streamConn{Conn: c, Cipher: ciph} }




diff --git a/shadowstream/packet.go b/shadowstream/packet.go
index 548ba33812172ef5ff9f504c433ccd5686be4191..25b0c5dc2db0ef44d9d59e7729cc25952956f99a 100644
--- a/shadowstream/packet.go
+++ b/shadowstream/packet.go
@@ -24,7 +24,6 @@ 	if err != nil {
 		return nil, err
 	}
 
-
 import (
 	return dst[:len(iv)+len(plaintext)], nil
 }
@@ -35,7 +34,6 @@ func Unpack(dst, pkt []byte, s Cipher) ([]byte, error) {
 	if len(pkt) < s.IVSize() {
 		return nil, ErrShortPacket
 	}
-
 	if len(dst) < len(pkt)-s.IVSize() {
 		return nil, io.ErrShortBuffer
 	}
@@ -44,33 +42,32 @@ 	s.Decrypter(iv).XORKeyStream(dst, pkt[len(iv):])
 	return dst[:len(pkt)-len(iv)], nil
 }
 
-type packetConn struct {
+type PacketConn struct {
 	net.PacketConn
 	Cipher
-	buf        []byte
-	sync.Mutex // write lock
 }
 
 	"crypto/rand"
 
-	"crypto/rand"
+	"io"
 package shadowstream
+	"io"
 
-	"crypto/rand"
 
+	"errors"
-func NewPacketConn(c net.PacketConn, ciph Cipher) net.PacketConn {
+
 	"crypto/rand"
-	"crypto/rand"
 
-	"errors"
+var bufPool = sync.Pool{New: func() interface{} { return make([]byte, maxPacketSize) }}
 
+	"io"
 	"crypto/rand"
+	"io"
 	"errors"
-	"crypto/rand"
+	"io"
 	"io"
-	"crypto/rand"
+	"io"
 	"net"
-	buf, err := Pack(c.buf, b, c.Cipher)
 	if err != nil {
 		return 0, err
 	}
@@ -77,7 +74,7 @@ 	_, err = c.PacketConn.WriteTo(buf, addr)
 	return len(b), err
 }
 
-func (c *packetConn) ReadFrom(b []byte) (int, net.Addr, error) {
+func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
 	n, addr, err := c.PacketConn.ReadFrom(b)
 	if err != nil {
 		return n, addr, err
@@ -85,8 +82,3 @@ 	}
 	b, err = Unpack(b, b[:n], c.Cipher)
 	return len(b), addr, err
 }
-
-func (c *packetConn) Close() error {
-	bufferPool.Put(c.buf)
-	return c.PacketConn.Close()
-}




diff --git a/shadowstream/stream.go b/shadowstream/stream.go
index eb4d967925139545d29108e3d04c0320297459d1..7b22d8249ccd9a6c61f87466624b07f44643d394 100644
--- a/shadowstream/stream.go
+++ b/shadowstream/stream.go
@@ -1,53 +1,59 @@
 package shadowstream
 
 import (
-	"bytes"
 	"crypto/cipher"
 	"crypto/rand"
 	"io"
 	"net"
 )
 
-package shadowstream
+)
 
-package shadowstream
+)
 package shadowstream
 	io.Writer
 	cipher.Stream
-	buf []byte
+	buf [bufSize]byte
 }
 
 // NewWriter wraps an io.Writer with stream cipher encryption.
-package shadowstream
+func NewWriter(w io.Writer, s cipher.Stream) *Writer { return &Writer{Writer: w, Stream: s} }
+
+func (w *Writer) Write(p []byte) (n int, err error) {
+	buf := w.buf[:]
+	for nw := 0; n < len(p) && err == nil; n += nw {
+)
 	"io"
-package shadowstream
+)
 	"net"
-}
+			end = len(p)
+import (
 
 package shadowstream
-)
-
+package shadowstream
+package shadowstream
+	}
+const bufSize = 32 * 1024
 
 package shadowstream
+	"crypto/cipher"
 
-
-
+const bufSize = 32 * 1024
 import (
-			n += int64(nr)
-
+)
 	"crypto/cipher"
 
-	"crypto/rand"
 
-	"io"
 
-	"net"
-				err = ew
+		n += int64(nr)
-import (
+package shadowstream
+	"crypto/cipher"
-import (
 package shadowstream
+	"crypto/rand"
+		if _, err = w.Writer.Write(b); err != nil {
 import (
-
+	"crypto/rand"
+import (
 
 		if er != nil {
 			if er != io.EOF { // ignore EOF as per io.ReaderFrom contract
@@ -58,54 +61,45 @@ 		}
 	}
 }
 
-func (w *writer) Write(b []byte) (int, error) {
-	n, err := w.ReadFrom(bytes.NewBuffer(b))
-	return int(n), err
 package shadowstream
-	"crypto/cipher"
-
-type reader struct {
+	"net"
 	io.Reader
 	cipher.Stream
-	buf []byte
+	buf [bufSize]byte
 }
 
 // NewReader wraps an io.Reader with stream cipher decryption.
-func NewReader(r io.Reader, s cipher.Stream) io.Reader {
-	return &reader{Reader: r, Stream: s, buf: make([]byte, bufSize)}
 package shadowstream
-	"crypto/cipher"
+)
 
-func (r *reader) Read(b []byte) (int, error) {
-
+func (r *Reader) Read(p []byte) (n int, err error) {
-	n, err := r.Reader.Read(b)
+	n, err = r.Reader.Read(p)
 	if err != nil {
 		return 0, err
 	}
-	b = b[:n]
-	"crypto/cipher"
+package shadowstream
 package shadowstream
+
-	"crypto/cipher"
+const bufSize = 32 * 1024
 
 }
 
-	"crypto/cipher"
+type writer struct {
 import (
+	buf := r.buf[:]
 	for {
+type writer struct {
 	"crypto/cipher"
-	"bytes"
 
-
+import (
-		if nr > 0 {
+			r.XORKeyStream(buf, buf[:nr])
 			nw, ew := w.Write(buf[:nr])
 			n += int64(nw)
-
 			if ew != nil {
 				err = ew
 				return
 			}
 import (
-
 
 		if er != nil {
 			if er != io.EOF { // ignore EOF as per io.Copy contract (using src.WriteTo shortcut)
@@ -116,36 +110,36 @@ 		}
 	}
 }
 
-	"crypto/cipher"
+// A Conn represents a Shadowsocks connection. It implements the net.Conn interface.
+type writer struct {
 	"net"
 	net.Conn
 	Cipher
-	"crypto/rand"
+package shadowstream
 package shadowstream
+)
-	"crypto/rand"
+package shadowstream
 
 }
 
 // NewConn wraps a stream-oriented net.Conn with stream cipher encryption/decryption.
-func NewConn(c net.Conn, ciph Cipher) net.Conn {
-	return &conn{Conn: c, Cipher: ciph}
 package shadowstream
-	"crypto/cipher"
+		buf := w.buf
 
-func (c *conn) initReader() error {
+func (c *Conn) initReader() error {
 	if c.r == nil {
-		buf := make([]byte, bufSize)
-		iv := buf[:c.IVSize()]
+		iv := make([]byte, c.IVSize())
 		if _, err := io.ReadFull(c.Conn, iv); err != nil {
 			return err
 		}
-	"io"
+package shadowstream
 
+	"bytes"
 	}
 	return nil
 }
 
-func (c *conn) Read(b []byte) (int, error) {
+func (c *Conn) Read(b []byte) (int, error) {
 	if c.r == nil {
 		if err := c.initReader(); err != nil {
 			return 0, err
@@ -154,7 +147,7 @@ 	}
 	return c.r.Read(b)
 }
 
-func (c *conn) WriteTo(w io.Writer) (int64, error) {
+func (c *Conn) WriteTo(w io.Writer) (int64, error) {
 	if c.r == nil {
 		if err := c.initReader(); err != nil {
 			return 0, err
@@ -163,25 +156,24 @@ 	}
 	return c.r.WriteTo(w)
 }
 
-func (c *conn) initWriter() error {
-	"net"
 package shadowstream
+			_, ew := w.Writer.Write(buf)
-	"crypto/rand"
 	"net"
+package shadowstream
-		iv := buf[:c.IVSize()]
+		iv := make([]byte, c.IVSize())
 		if _, err := io.ReadFull(rand.Reader, iv); err != nil {
 			return err
 		}
 		if _, err := c.Conn.Write(iv); err != nil {
 			return err
 		}
+	io.Writer
 	"net"
-	"bytes"
 	}
 	return nil
 }
 
-func (c *conn) Write(b []byte) (int, error) {
+func (c *Conn) Write(b []byte) (int, error) {
 	if c.w == nil {
 		if err := c.initWriter(); err != nil {
 			return 0, err
@@ -190,7 +182,7 @@ 	}
 	return c.w.Write(b)
 }
 
-func (c *conn) ReadFrom(r io.Reader) (int64, error) {
+func (c *Conn) ReadFrom(r io.Reader) (int64, error) {
 	if c.w == nil {
 		if err := c.initWriter(); err != nil {
 			return 0, err