init
This commit is contained in:
175
ftcp.go
Normal file
175
ftcp.go
Normal file
@ -0,0 +1,175 @@
|
||||
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
|
||||
}
|
||||
|
||||
// FakeTCPListenConfig is config for fake TCP Listener.
|
||||
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 {
|
||||
conn = newUDPServerConn(l.ln, raddr, &udpServerConnConfig{
|
||||
ttl: l.config.TTL,
|
||||
qsize: l.config.QueueSize,
|
||||
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 {
|
||||
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) RemoteAddr() net.Addr {
|
||||
return c.raddr
|
||||
}
|
Reference in New Issue
Block a user