Skip to content

Commit

Permalink
Optionally use TCP_CORK on client-side
Browse files Browse the repository at this point in the history
TCP_CORK/TCP_NOPUSH coalesces salt+address+initial data in one packet
  • Loading branch information
riobard committed Aug 9, 2020
1 parent c4371a6 commit 50676a7
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 2 deletions.
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
var config struct {
Verbose bool
UDPTimeout time.Duration
TCPCork bool
}

func main() {
Expand Down Expand Up @@ -61,6 +62,7 @@ func main() {
flag.StringVar(&flags.PluginOpts, "plugin-opts", "", "Set SIP003 plugin options. (e.g., \"server;tls;host=mydomain.me\")")
flag.BoolVar(&flags.UDP, "udp", false, "(server-only) enable UDP support")
flag.BoolVar(&flags.UDP, "tcp", true, "(server-only) enable TCP support")
flag.BoolVar(&config.TCPCork, "tcpcork", false, "(client-only) enable TCP_CORK (Linux) or TCP_NOPUSH (BSD) for the first few packets")
flag.DurationVar(&config.UDPTimeout, "udptimeout", 5*time.Minute, "UDP tunnel timeout")
flag.Parse()

Expand Down
6 changes: 5 additions & 1 deletion tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ func tcpLocal(addr, server string, shadow func(net.Conn) net.Conn, getAddr func(
return
}
defer rc.Close()
rc.(*net.TCPConn).SetKeepAlive(true)
tc := rc.(*net.TCPConn)
tc.SetKeepAlive(true)
if config.TCPCork {
timedCork(tc, 10*time.Millisecond)
}
rc = shadow(rc)

if _, err = rc.Write(tgt); err != nil {
Expand Down
17 changes: 17 additions & 0 deletions tcp_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package main

import (
"net"
"syscall"
"time"

"github.com/shadowsocks/go-shadowsocks2/pfutil"
"github.com/shadowsocks/go-shadowsocks2/socks"
Expand All @@ -22,3 +24,18 @@ func natLookup(c net.Conn) (socks.Addr, error) {
}
panic("not TCP connection")
}

func timedCork(c *net.TCPConn, d time.Duration) error {
rc, err := c.SyscallConn()
if err != nil {
return err
}
rc.Control(func(fd uintptr) { err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_NOPUSH, 1) })
if err != nil {
return err
}
time.AfterFunc(d, func() {
rc.Control(func(fd uintptr) { syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_NOPUSH, 0) })
})
return nil
}
17 changes: 17 additions & 0 deletions tcp_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package main

import (
"net"
"syscall"
"time"

"github.com/shadowsocks/go-shadowsocks2/nfutil"
"github.com/shadowsocks/go-shadowsocks2/socks"
Expand All @@ -26,3 +28,18 @@ func redir6Local(addr, server string, shadow func(net.Conn) net.Conn) {
logf("TCP6 redirect %s <-> %s", addr, server)
tcpLocal(addr, server, shadow, func(c net.Conn) (socks.Addr, error) { return getOrigDst(c, true) })
}

func timedCork(c *net.TCPConn, d time.Duration) error {
rc, err := c.SyscallConn()
if err != nil {
return err
}
rc.Control(func(fd uintptr) { err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_CORK, 1) })
if err != nil {
return err
}
time.AfterFunc(d, func() {
rc.Control(func(fd uintptr) { syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_CORK, 0) })
})
return nil
}
7 changes: 6 additions & 1 deletion tcp_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

package main

import "net"
import (
"net"
"time"
)

func redirLocal(addr, server string, shadow func(net.Conn) net.Conn) {
logf("TCP redirect not supported")
Expand All @@ -11,3 +14,5 @@ func redirLocal(addr, server string, shadow func(net.Conn) net.Conn) {
func redir6Local(addr, server string, shadow func(net.Conn) net.Conn) {
logf("TCP6 redirect not supported")
}

func timedCork(c *net.TCPConn, d time.Duration) error { return nil }

0 comments on commit 50676a7

Please sign in to comment.