mirror of https://github.com/ginuerzh/gost
4 changed files with 217 additions and 1 deletions
@ -0,0 +1,203 @@ |
|||||
|
package gost |
||||
|
|
||||
|
import ( |
||||
|
"errors" |
||||
|
"net" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/go-log/log" |
||||
|
"github.com/xtaci/tcpraw" |
||||
|
) |
||||
|
|
||||
|
type fakeTCPTransporter struct{} |
||||
|
|
||||
|
// FakeTCPTransporter creates a Transporter that is used by fake tcp client.
|
||||
|
func FakeTCPTransporter() Transporter { |
||||
|
return &fakeTCPTransporter{} |
||||
|
} |
||||
|
|
||||
|
func (tr *fakeTCPTransporter) Dial(addr string, options ...DialOption) (conn net.Conn, err error) { |
||||
|
opts := &DialOptions{} |
||||
|
for _, option := range options { |
||||
|
option(opts) |
||||
|
} |
||||
|
|
||||
|
raddr, er := net.ResolveTCPAddr("tcp", addr) |
||||
|
if er != nil { |
||||
|
return nil, er |
||||
|
} |
||||
|
c, err := tcpraw.Dial("tcp", addr) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
conn = &fakeTCPConn{ |
||||
|
raddr: raddr, |
||||
|
PacketConn: c, |
||||
|
} |
||||
|
return conn, nil |
||||
|
} |
||||
|
|
||||
|
func (tr *fakeTCPTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) { |
||||
|
return conn, nil |
||||
|
} |
||||
|
|
||||
|
func (tr *fakeTCPTransporter) Multiplex() bool { |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
type FakeTCPListenConfig struct { |
||||
|
TTL time.Duration |
||||
|
Backlog int |
||||
|
QueueSize int |
||||
|
} |
||||
|
|
||||
|
type fakeTCPListener struct { |
||||
|
ln net.PacketConn |
||||
|
connChan chan net.Conn |
||||
|
errChan chan error |
||||
|
connMap udpConnMap |
||||
|
config *FakeTCPListenConfig |
||||
|
} |
||||
|
|
||||
|
// FakeTCPListener creates a Listener for fake TCP server.
|
||||
|
func FakeTCPListener(addr string, cfg *FakeTCPListenConfig) (Listener, error) { |
||||
|
ln, err := tcpraw.Listen("tcp", addr) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
if cfg == nil { |
||||
|
cfg = &FakeTCPListenConfig{} |
||||
|
} |
||||
|
|
||||
|
backlog := cfg.Backlog |
||||
|
if backlog <= 0 { |
||||
|
backlog = defaultBacklog |
||||
|
} |
||||
|
|
||||
|
l := &fakeTCPListener{ |
||||
|
ln: ln, |
||||
|
connChan: make(chan net.Conn, backlog), |
||||
|
errChan: make(chan error, 1), |
||||
|
config: cfg, |
||||
|
} |
||||
|
go l.listenLoop() |
||||
|
return l, nil |
||||
|
} |
||||
|
|
||||
|
func (l *fakeTCPListener) listenLoop() { |
||||
|
for { |
||||
|
b := make([]byte, mediumBufferSize) |
||||
|
n, raddr, err := l.ln.ReadFrom(b) |
||||
|
if err != nil { |
||||
|
log.Logf("[ftcp] peer -> %s : %s", l.Addr(), err) |
||||
|
l.Close() |
||||
|
l.errChan <- err |
||||
|
close(l.errChan) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
conn, ok := l.connMap.Get(raddr.String()) |
||||
|
if !ok { |
||||
|
cc := &fakeTCPConn{ |
||||
|
raddr: raddr, |
||||
|
PacketConn: l.ln, |
||||
|
} |
||||
|
conn = newUDPServerConn(cc, raddr, l.config.TTL, l.config.QueueSize) |
||||
|
conn.onClose = func() { |
||||
|
l.connMap.Delete(raddr.String()) |
||||
|
log.Logf("[ftcp] %s closed (%d)", raddr, l.connMap.Size()) |
||||
|
} |
||||
|
|
||||
|
select { |
||||
|
case l.connChan <- conn: |
||||
|
l.connMap.Set(raddr.String(), conn) |
||||
|
log.Logf("[ftcp] %s -> %s (%d)", raddr, l.Addr(), l.connMap.Size()) |
||||
|
default: |
||||
|
conn.Close() |
||||
|
log.Logf("[ftcp] %s - %s: connection queue is full (%d)", raddr, l.Addr(), cap(l.connChan)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
select { |
||||
|
case conn.rChan <- b[:n]: |
||||
|
if Debug { |
||||
|
log.Logf("[ftcp] %s >>> %s : length %d", raddr, l.Addr(), n) |
||||
|
} |
||||
|
default: |
||||
|
log.Logf("[ftcp] %s -> %s : recv queue is full (%d)", raddr, l.Addr(), cap(conn.rChan)) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (l *fakeTCPListener) 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 *fakeTCPListener) Addr() net.Addr { |
||||
|
return l.ln.LocalAddr() |
||||
|
} |
||||
|
|
||||
|
func (l *fakeTCPListener) Close() error { |
||||
|
err := l.ln.Close() |
||||
|
l.connMap.Range(func(k interface{}, v *udpServerConn) bool { |
||||
|
v.Close() |
||||
|
return true |
||||
|
}) |
||||
|
|
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
type fakeTCPConn struct { |
||||
|
mss int |
||||
|
raddr net.Addr |
||||
|
net.PacketConn |
||||
|
} |
||||
|
|
||||
|
func (c *fakeTCPConn) Read(b []byte) (n int, err error) { |
||||
|
n, _, err = c.ReadFrom(b) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (c *fakeTCPConn) Write(b []byte) (n int, err error) { |
||||
|
return c.WriteTo(b, c.raddr) |
||||
|
} |
||||
|
|
||||
|
func (c *fakeTCPConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { |
||||
|
mss := c.mss |
||||
|
if mss <= 0 { |
||||
|
mss = 1460 |
||||
|
} |
||||
|
|
||||
|
for { |
||||
|
if len(b) == 0 { |
||||
|
break |
||||
|
} |
||||
|
var nn int |
||||
|
if len(b) <= mss { |
||||
|
nn, err = c.PacketConn.WriteTo(b, addr) |
||||
|
n += nn |
||||
|
break |
||||
|
} |
||||
|
nn, err = c.PacketConn.WriteTo(b[:mss], addr) |
||||
|
n += nn |
||||
|
if err != nil { |
||||
|
break |
||||
|
} |
||||
|
b = b[mss:] |
||||
|
} |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func (c *fakeTCPConn) RemoteAddr() net.Addr { |
||||
|
return c.raddr |
||||
|
} |
||||
Loading…
Reference in new issue