Compare commits

..
11 Commits
8 changed files with 160 additions and 85 deletions
+2 -5
View File
@@ -6,11 +6,8 @@ cd $BUILD_DIR
sum="sha1sum"
if [ "$GO111MODULE" != "on" ]; then
echo "GO111MODULE is off"
else
echo "GO111MODULE is on"
fi
export GO111MODULE=on
echo "Setting GO111MODULE to" $GO111MODULE
if ! hash sha1sum 2>/dev/null; then
if ! hash shasum 2>/dev/null; then
+15 -17
View File
@@ -8,7 +8,6 @@ import (
"math/rand"
"net"
"os"
"sync"
"time"
"golang.org/x/crypto/pbkdf2"
@@ -21,19 +20,20 @@ import (
smuxv2 "github.com/xtaci/smux/v2"
)
// SALT is use for pbkdf2 key expansion
const SALT = "kcp-go"
// maximum supported smux version
const maxSmuxVer = 2
const (
// SALT is use for pbkdf2 key expansion
SALT = "kcp-go"
// maximum supported smux version
maxSmuxVer = 2
// stream copy buffer size
bufSize = 4096
)
// VERSION is injected by buildflags
var VERSION = "SELFBUILD"
// A pool for stream copying
var xmitBuf sync.Pool
func handleClient(mux generic.Mux, p1 net.Conn, quiet bool) {
// handleClient aggregates connection p1 on mux with 'writeLock'
func handleClient(mux generic.Mux, p1 net.Conn, ctrl *generic.CopyControl, quiet bool) {
logln := func(v ...interface{}) {
if !quiet {
log.Println(v...)
@@ -57,8 +57,7 @@ func handleClient(mux generic.Mux, p1 net.Conn, quiet bool) {
streamCopy := func(dst io.Writer, src io.ReadCloser) chan struct{} {
die := make(chan struct{})
go func() {
buf := xmitBuf.Get().([]byte)
if _, err := generic.CopyBuffer(dst, src, buf); err != nil {
if _, err := generic.Copy(dst, src, ctrl); err != nil {
if s2, ok := p2.(generic.Stream); ok {
// verbose error handling
cause := err
@@ -74,7 +73,6 @@ func handleClient(mux generic.Mux, p1 net.Conn, quiet bool) {
}
}
}
xmitBuf.Put(buf)
close(die)
}()
return die
@@ -99,9 +97,6 @@ func main() {
// add more log flags for debugging
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
xmitBuf.New = func() interface{} {
return make([]byte, 32768)
}
myApp := cli.NewApp()
myApp.Name = "kcptun"
@@ -464,11 +459,13 @@ func main() {
muxes := make([]struct {
session generic.Mux
ttl time.Time
ctrl *generic.CopyControl // for control of memory in copying
}, numconn)
for k := range muxes {
muxes[k].session = waitConn()
muxes[k].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
muxes[k].ctrl = &generic.CopyControl{Buffer: make([]byte, bufSize)}
}
chScavenger := make(chan generic.Mux, 128)
@@ -487,9 +484,10 @@ func main() {
chScavenger <- muxes[idx].session
muxes[idx].session = waitConn()
muxes[idx].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
muxes[idx].ctrl = &generic.CopyControl{Buffer: make([]byte, bufSize)}
}
go handleClient(muxes[idx].session, p1, config.Quiet)
go handleClient(muxes[idx].session, p1, muxes[idx].ctrl, config.Quiet)
rr++
}
}
+33 -29
View File
@@ -1,36 +1,40 @@
package generic
import "io"
import (
"io"
"net"
"sync"
)
// io.CopyBuffer has extra tests for interface like io.ReaderFrom and io.WriterTo
// which is not efficient in memory management from tests
func CopyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
if buf != nil && len(buf) == 0 {
panic("empty buffer in copyBuffer")
}
const bufSize = 4096
for {
nr, er := src.Read(buf)
if nr > 0 {
nw, ew := dst.Write(buf[0:nr])
if nw > 0 {
written += int64(nw)
}
if ew != nil {
err = ew
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
}
if er != nil {
if er != io.EOF {
err = er
}
break
type CopyControl struct {
Buffer []byte // shared buffer for copying controlled by mutex
sync.Mutex
}
// Memory optimized io.Copy function specified for this library
func Copy(dst io.Writer, src io.Reader, ctrl *CopyControl) (written int64, err error) {
// If the reader has a WriteTo method, use it to do the copy.
// Avoids an allocation and a copy.
if wt, ok := src.(io.WriterTo); ok {
return wt.WriteTo(dst)
}
// Similarly, if the writer has a ReadFrom method, use it to do the copy.
if rt, ok := dst.(io.ReaderFrom); ok {
return rt.ReadFrom(src)
}
// if src is net.TCPConn, and dst is a multiplexed connection
// reading can be controlled by writable events of smux
// and make the reading serialized
if tcpconn, ok := src.(*net.TCPConn); ok {
if ctrl != nil {
return rawCopy(dst, tcpconn, ctrl)
}
}
return written, err
// fallback to standard io.CopyBuffer
buf := make([]byte, bufSize)
return io.CopyBuffer(dst, src, buf)
}
+76
View File
@@ -0,0 +1,76 @@
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package generic
import (
"io"
"net"
"syscall"
)
func rawCopy(dst io.Writer, src *net.TCPConn, ctrl *CopyControl) (written int64, err error) {
c, err := src.SyscallConn()
if err != nil {
return 0, err
}
buf := ctrl.Buffer
var locked bool
for {
var er error
var nr int
rr := c.Read(func(s uintptr) bool {
ctrl.Lock() // acquire rights to read & write
locked = true
nr, er = syscall.Read(int(s), buf)
if er == syscall.EAGAIN {
ctrl.Unlock()
locked = false
return false
}
return true // keep lock
})
// read EOF
if nr == 0 && er == nil {
break
}
if nr > 0 {
nw, ew := dst.Write(buf[0:nr])
ctrl.Unlock()
locked = false
if nw > 0 {
written += int64(nw)
}
if ew != nil {
err = ew
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
}
if er != nil {
if er != io.EOF {
err = er
}
break
}
if rr != nil {
if rr != io.EOF {
err = rr
}
break
}
}
if locked {
ctrl.Unlock()
}
return written, err
}
+14
View File
@@ -0,0 +1,14 @@
// +build windows
package generic
import (
"io"
"net"
)
func rawCopy(dst io.Writer, src *net.TCPConn, ctrl *CopyControl) (written int64, err error) {
// fallback to standard io.CopyBuffer
buf := make([]byte, bufSize)
return io.CopyBuffer(dst, src, buf)
}
+2 -2
View File
@@ -13,8 +13,8 @@ require (
github.com/urfave/cli v1.21.0
github.com/xtaci/kcp-go v5.4.19+incompatible
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect
github.com/xtaci/smux v1.4.4
github.com/xtaci/smux/v2 v2.0.11
github.com/xtaci/smux v1.4.6
github.com/xtaci/smux/v2 v2.0.16
github.com/xtaci/tcpraw v1.2.25
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b // indirect
+4 -16
View File
@@ -19,26 +19,14 @@ github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU=
github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE=
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
github.com/xtaci/kcp-go v5.4.13+incompatible h1:s6ba2XTw8lAj+s6AQNob25dCvWDgwE+U1QpEVBUoYy8=
github.com/xtaci/kcp-go v5.4.13+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go v5.4.14+incompatible h1:kQZr/ngKQtYrgXSUxwF4A59mTMzUp0BDmtWIRuXYoqg=
github.com/xtaci/kcp-go v5.4.14+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go v5.4.15+incompatible h1:QLDulPaKjT4k4cGeviyC1mt00gwJ3r5epx8yCw6ACEc=
github.com/xtaci/kcp-go v5.4.15+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go v5.4.16+incompatible h1:/L7UP4P4H/oXpMnrb2W9oOxCMVpjPi3FJeMJmgN+SUE=
github.com/xtaci/kcp-go v5.4.16+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go v5.4.17+incompatible h1:RudP76JCx062JSxPxSjBl+457+fS0M7T8zEZPLpC0o8=
github.com/xtaci/kcp-go v5.4.17+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go v5.4.18+incompatible h1:zxzRP8V54vhJ8QAKEjf1b9g96R01prybCRchx6rEmtg=
github.com/xtaci/kcp-go v5.4.18+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/kcp-go v5.4.19+incompatible h1:vv7Ar1D9WZGiv6deIOluxrC26Oin/2jFtx8sFU5tlvw=
github.com/xtaci/kcp-go v5.4.19+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
github.com/xtaci/smux v1.4.4 h1:FukIfahko+KHhS9Gxppkp6756opZymvPOLNmpny1is4=
github.com/xtaci/smux v1.4.4/go.mod h1:LuA3S0xssf4fmGRJ7ow3EehgmDUzib4EcobaFNKvlMA=
github.com/xtaci/smux/v2 v2.0.11 h1:thVWmgGRciZ8iaATwpY2B/51aHzmMI6wrF7DfcJSckU=
github.com/xtaci/smux/v2 v2.0.11/go.mod h1:Iqy5a3Gax2p7WCKHOHkSNo/COthNFXd3/vqrcKNtzqI=
github.com/xtaci/smux v1.4.6 h1:p9e/qj3Bj0zUT8qJWdmAZfmx5lOcZh0vLL0bQ8jnA7M=
github.com/xtaci/smux v1.4.6/go.mod h1:LuA3S0xssf4fmGRJ7ow3EehgmDUzib4EcobaFNKvlMA=
github.com/xtaci/smux/v2 v2.0.16 h1:2pGGbkFKTaMHIctYaovpwRpgdwWYy/6ZPaOQo00VW08=
github.com/xtaci/smux/v2 v2.0.16/go.mod h1:Iqy5a3Gax2p7WCKHOHkSNo/COthNFXd3/vqrcKNtzqI=
github.com/xtaci/tcpraw v1.2.25 h1:VDlqo0op17JeXBM6e2G9ocCNLOJcw9mZbobMbJjo0vk=
github.com/xtaci/tcpraw v1.2.25/go.mod h1:dKyZ2V75s0cZ7cbgJYdxPvms7af0joIeOyx1GgJQbLk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+14 -16
View File
@@ -23,18 +23,18 @@ import (
"github.com/xtaci/tcpraw"
)
// SALT is use for pbkdf2 key expansion
const SALT = "kcp-go"
// maximum supported smux version
const maxSmuxVer = 2
const (
// SALT is use for pbkdf2 key expansion
SALT = "kcp-go"
// maximum supported smux version
maxSmuxVer = 2
// stream copy buffer size
bufSize = 4096
)
// VERSION is injected by buildflags
var VERSION = "SELFBUILD"
// A pool for stream copying
var xmitBuf sync.Pool
// handle multiplex-ed connection
func handleMux(conn net.Conn, config *Config) {
// check if target is unix domain socket
@@ -76,6 +76,9 @@ func handleMux(conn net.Conn, config *Config) {
panic("incorrect smux version")
}
// copy to stream control
copyControl := &generic.CopyControl{Buffer: make([]byte, bufSize)}
for {
stream, err := muxer.Accept()
if err != nil {
@@ -97,12 +100,12 @@ func handleMux(conn net.Conn, config *Config) {
p1.Close()
return
}
handleClient(p1, p2, config.Quiet)
handleClient(p1, p2, copyControl, config.Quiet)
}(stream)
}
}
func handleClient(p1 io.ReadWriteCloser, p2 net.Conn, quiet bool) {
func handleClient(p1 io.ReadWriteCloser, p2 net.Conn, ctrl *generic.CopyControl, quiet bool) {
logln := func(v ...interface{}) {
if !quiet {
log.Println(v...)
@@ -121,8 +124,7 @@ func handleClient(p1 io.ReadWriteCloser, p2 net.Conn, quiet bool) {
streamCopy := func(dst io.Writer, src io.ReadCloser) chan struct{} {
die := make(chan struct{})
go func() {
buf := xmitBuf.Get().([]byte)
if _, err := generic.CopyBuffer(dst, src, buf); err != nil {
if _, err := generic.Copy(dst, src, ctrl); err != nil {
if s1, ok := p1.(generic.Stream); ok {
// verbose error handling
cause := err
@@ -138,7 +140,6 @@ func handleClient(p1 io.ReadWriteCloser, p2 net.Conn, quiet bool) {
}
}
}
xmitBuf.Put(buf)
close(die)
}()
return die
@@ -163,9 +164,6 @@ func main() {
// add more log flags for debugging
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
xmitBuf.New = func() interface{} {
return make([]byte, 32768)
}
myApp := cli.NewApp()
myApp.Name = "kcptun"