mirror of https://github.com/ginuerzh/gost
19 changed files with 756 additions and 590 deletions
@ -0,0 +1,66 @@ |
|||||
|
package gost |
||||
|
|
||||
|
import "net" |
||||
|
|
||||
|
// tcpTransporter is a raw TCP transporter.
|
||||
|
type tcpTransporter struct{} |
||||
|
|
||||
|
// TCPTransporter creates a raw TCP client.
|
||||
|
func TCPTransporter() Transporter { |
||||
|
return &tcpTransporter{} |
||||
|
} |
||||
|
|
||||
|
func (tr *tcpTransporter) Dial(addr string, options ...DialOption) (net.Conn, error) { |
||||
|
opts := &DialOptions{} |
||||
|
for _, option := range options { |
||||
|
option(opts) |
||||
|
} |
||||
|
|
||||
|
timeout := opts.Timeout |
||||
|
if timeout <= 0 { |
||||
|
timeout = DialTimeout |
||||
|
} |
||||
|
if opts.Chain == nil { |
||||
|
return net.DialTimeout("tcp", addr, timeout) |
||||
|
} |
||||
|
return opts.Chain.Dial(addr) |
||||
|
} |
||||
|
|
||||
|
func (tr *tcpTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) { |
||||
|
return conn, nil |
||||
|
} |
||||
|
|
||||
|
func (tr *tcpTransporter) Multiplex() bool { |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
type tcpListener struct { |
||||
|
net.Listener |
||||
|
} |
||||
|
|
||||
|
// TCPListener creates a Listener for TCP proxy server.
|
||||
|
func TCPListener(addr string) (Listener, error) { |
||||
|
laddr, err := net.ResolveTCPAddr("tcp", addr) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
ln, err := net.ListenTCP("tcp", laddr) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
return &tcpListener{Listener: tcpKeepAliveListener{ln}}, nil |
||||
|
} |
||||
|
|
||||
|
type tcpKeepAliveListener struct { |
||||
|
*net.TCPListener |
||||
|
} |
||||
|
|
||||
|
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) { |
||||
|
tc, err := ln.AcceptTCP() |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
tc.SetKeepAlive(true) |
||||
|
tc.SetKeepAlivePeriod(KeepAliveTime) |
||||
|
return tc, nil |
||||
|
} |
||||
@ -0,0 +1,357 @@ |
|||||
|
package gost |
||||
|
|
||||
|
import ( |
||||
|
"errors" |
||||
|
"net" |
||||
|
"sync" |
||||
|
"sync/atomic" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/go-log/log" |
||||
|
) |
||||
|
|
||||
|
// udpTransporter is a raw UDP transporter.
|
||||
|
type udpTransporter struct{} |
||||
|
|
||||
|
// UDPTransporter creates a Transporter for UDP client.
|
||||
|
func UDPTransporter() Transporter { |
||||
|
return &udpTransporter{} |
||||
|
} |
||||
|
|
||||
|
func (tr *udpTransporter) Dial(addr string, options ...DialOption) (net.Conn, error) { |
||||
|
raddr, err := net.ResolveUDPAddr("udp", addr) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
conn, err := net.ListenUDP("udp", nil) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return &udpClientConn{ |
||||
|
UDPConn: conn, |
||||
|
raddr: raddr, |
||||
|
}, nil |
||||
|
} |
||||
|
|
||||
|
func (tr *udpTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) { |
||||
|
return conn, nil |
||||
|
} |
||||
|
|
||||
|
func (tr *udpTransporter) Multiplex() bool { |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
// UDPListenConfig is the config for UDP Listener.
|
||||
|
type UDPListenConfig struct { |
||||
|
TTL time.Duration // timeout per connection
|
||||
|
Backlog int // connection backlog
|
||||
|
QueueSize int // recv queue size per connection
|
||||
|
} |
||||
|
|
||||
|
type udpListener struct { |
||||
|
ln net.PacketConn |
||||
|
connChan chan net.Conn |
||||
|
errChan chan error |
||||
|
connMap udpConnMap |
||||
|
config *UDPListenConfig |
||||
|
} |
||||
|
|
||||
|
// UDPListener creates a Listener for UDP server.
|
||||
|
func UDPListener(addr string, cfg *UDPListenConfig) (Listener, error) { |
||||
|
laddr, err := net.ResolveUDPAddr("udp", addr) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
ln, err := net.ListenUDP("udp", laddr) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
if cfg == nil { |
||||
|
cfg = &UDPListenConfig{} |
||||
|
} |
||||
|
|
||||
|
backlog := cfg.Backlog |
||||
|
if backlog <= 0 { |
||||
|
backlog = defaultBacklog |
||||
|
} |
||||
|
|
||||
|
l := &udpListener{ |
||||
|
ln: ln, |
||||
|
connChan: make(chan net.Conn, backlog), |
||||
|
errChan: make(chan error, 1), |
||||
|
config: cfg, |
||||
|
} |
||||
|
go l.listenLoop() |
||||
|
return l, nil |
||||
|
} |
||||
|
|
||||
|
func (l *udpListener) listenLoop() { |
||||
|
for { |
||||
|
b := make([]byte, mediumBufferSize) |
||||
|
n, raddr, err := l.ln.ReadFrom(b) |
||||
|
if err != nil { |
||||
|
log.Logf("[udp] peer -> %s : %s", l.Addr(), err) |
||||
|
l.Close() |
||||
|
l.errChan <- err |
||||
|
close(l.errChan) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
conn, ok := l.connMap.Get(raddr.String()) |
||||
|
if !ok { |
||||
|
conn = newUDPServerConn(l.ln, raddr, &udpServerConnConfig{ |
||||
|
ttl: l.config.TTL, |
||||
|
qsize: l.config.QueueSize, |
||||
|
onClose: func() { |
||||
|
l.connMap.Delete(raddr.String()) |
||||
|
log.Logf("[udp] %s closed (%d)", raddr, l.connMap.Size()) |
||||
|
}, |
||||
|
}) |
||||
|
|
||||
|
select { |
||||
|
case l.connChan <- conn: |
||||
|
l.connMap.Set(raddr.String(), conn) |
||||
|
log.Logf("[udp] %s -> %s (%d)", raddr, l.Addr(), l.connMap.Size()) |
||||
|
default: |
||||
|
conn.Close() |
||||
|
log.Logf("[udp] %s - %s: connection queue is full (%d)", raddr, l.Addr(), cap(l.connChan)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
select { |
||||
|
case conn.rChan <- b[:n]: |
||||
|
if Debug { |
||||
|
log.Logf("[udp] %s >>> %s : length %d", raddr, l.Addr(), n) |
||||
|
} |
||||
|
default: |
||||
|
log.Logf("[udp] %s -> %s : recv queue is full (%d)", raddr, l.Addr(), cap(conn.rChan)) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (l *udpListener) Accept() (conn net.Conn, err error) { |
||||
|
var ok bool |
||||
|
select { |
||||
|
case conn = <-l.connChan: |
||||
|
case err, ok = <-l.errChan: |
||||
|
if !ok { |
||||
|
err = errors.New("accpet on closed listener") |
||||
|
} |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (l *udpListener) Addr() net.Addr { |
||||
|
return l.ln.LocalAddr() |
||||
|
} |
||||
|
|
||||
|
func (l *udpListener) Close() error { |
||||
|
err := l.ln.Close() |
||||
|
l.connMap.Range(func(k interface{}, v *udpServerConn) bool { |
||||
|
v.Close() |
||||
|
return true |
||||
|
}) |
||||
|
|
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
type udpConnMap struct { |
||||
|
m sync.Map |
||||
|
size int64 |
||||
|
} |
||||
|
|
||||
|
func (m *udpConnMap) Get(key interface{}) (conn *udpServerConn, ok bool) { |
||||
|
v, ok := m.m.Load(key) |
||||
|
if ok { |
||||
|
conn, ok = v.(*udpServerConn) |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (m *udpConnMap) Set(key interface{}, conn *udpServerConn) { |
||||
|
m.m.Store(key, conn) |
||||
|
atomic.AddInt64(&m.size, 1) |
||||
|
} |
||||
|
|
||||
|
func (m *udpConnMap) Delete(key interface{}) { |
||||
|
m.m.Delete(key) |
||||
|
atomic.AddInt64(&m.size, -1) |
||||
|
} |
||||
|
|
||||
|
func (m *udpConnMap) Range(f func(key interface{}, value *udpServerConn) bool) { |
||||
|
m.m.Range(func(k, v interface{}) bool { |
||||
|
return f(k, v.(*udpServerConn)) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
func (m *udpConnMap) Size() int64 { |
||||
|
return atomic.LoadInt64(&m.size) |
||||
|
} |
||||
|
|
||||
|
// udpServerConn is a server side connection for UDP client peer, it implements net.Conn and net.PacketConn.
|
||||
|
type udpServerConn struct { |
||||
|
conn net.PacketConn |
||||
|
raddr net.Addr |
||||
|
rChan chan []byte |
||||
|
closed chan struct{} |
||||
|
closeMutex sync.Mutex |
||||
|
nopChan chan int |
||||
|
config *udpServerConnConfig |
||||
|
} |
||||
|
|
||||
|
type udpServerConnConfig struct { |
||||
|
ttl time.Duration |
||||
|
qsize int |
||||
|
onClose func() |
||||
|
} |
||||
|
|
||||
|
func newUDPServerConn(conn net.PacketConn, raddr net.Addr, cfg *udpServerConnConfig) *udpServerConn { |
||||
|
if conn == nil || raddr == nil { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
if cfg == nil { |
||||
|
cfg = &udpServerConnConfig{} |
||||
|
} |
||||
|
qsize := cfg.qsize |
||||
|
if qsize <= 0 { |
||||
|
qsize = defaultQueueSize |
||||
|
} |
||||
|
c := &udpServerConn{ |
||||
|
conn: conn, |
||||
|
raddr: raddr, |
||||
|
rChan: make(chan []byte, qsize), |
||||
|
closed: make(chan struct{}), |
||||
|
nopChan: make(chan int), |
||||
|
config: cfg, |
||||
|
} |
||||
|
go c.ttlWait() |
||||
|
return c |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) Read(b []byte) (n int, err error) { |
||||
|
n, _, err = c.ReadFrom(b) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { |
||||
|
select { |
||||
|
case bb := <-c.rChan: |
||||
|
n = copy(b, bb) |
||||
|
case <-c.closed: |
||||
|
err = errors.New("read from closed connection") |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
select { |
||||
|
case c.nopChan <- n: |
||||
|
default: |
||||
|
} |
||||
|
|
||||
|
addr = c.raddr |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) Write(b []byte) (n int, err error) { |
||||
|
return c.WriteTo(b, c.raddr) |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { |
||||
|
n, err = c.conn.WriteTo(b, addr) |
||||
|
|
||||
|
if n > 0 { |
||||
|
if Debug { |
||||
|
log.Logf("[udp] %s <<< %s : length %d", addr, c.LocalAddr(), n) |
||||
|
} |
||||
|
|
||||
|
select { |
||||
|
case c.nopChan <- n: |
||||
|
default: |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) Close() error { |
||||
|
c.closeMutex.Lock() |
||||
|
defer c.closeMutex.Unlock() |
||||
|
|
||||
|
select { |
||||
|
case <-c.closed: |
||||
|
return errors.New("connection is closed") |
||||
|
default: |
||||
|
if c.config.onClose != nil { |
||||
|
c.config.onClose() |
||||
|
} |
||||
|
close(c.closed) |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) ttlWait() { |
||||
|
ttl := c.config.ttl |
||||
|
if ttl == 0 { |
||||
|
ttl = defaultTTL |
||||
|
} |
||||
|
timer := time.NewTimer(ttl) |
||||
|
defer timer.Stop() |
||||
|
|
||||
|
for { |
||||
|
select { |
||||
|
case <-c.nopChan: |
||||
|
if !timer.Stop() { |
||||
|
<-timer.C |
||||
|
} |
||||
|
timer.Reset(ttl) |
||||
|
case <-timer.C: |
||||
|
c.Close() |
||||
|
return |
||||
|
case <-c.closed: |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) LocalAddr() net.Addr { |
||||
|
return c.conn.LocalAddr() |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) RemoteAddr() net.Addr { |
||||
|
return c.raddr |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) SetDeadline(t time.Time) error { |
||||
|
return c.conn.SetDeadline(t) |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) SetReadDeadline(t time.Time) error { |
||||
|
return c.conn.SetReadDeadline(t) |
||||
|
} |
||||
|
|
||||
|
func (c *udpServerConn) SetWriteDeadline(t time.Time) error { |
||||
|
return c.conn.SetWriteDeadline(t) |
||||
|
} |
||||
|
|
||||
|
type udpClientConn struct { |
||||
|
*net.UDPConn |
||||
|
raddr net.Addr |
||||
|
} |
||||
|
|
||||
|
func (c *udpClientConn) Write(b []byte) (int, error) { |
||||
|
if c.raddr != nil { |
||||
|
return c.WriteTo(b, c.raddr) |
||||
|
} |
||||
|
return c.UDPConn.Write(b) |
||||
|
} |
||||
|
|
||||
|
func (c *udpClientConn) RemoteAddr() net.Addr { |
||||
|
if c.raddr != nil { |
||||
|
return c.raddr |
||||
|
} |
||||
|
return c.UDPConn.RemoteAddr() |
||||
|
} |
||||
Loading…
Reference in new issue