package socket import ( "errors" "fmt" "log" "net" "strings" "sync" "tunnel/pkg/server/env" "tunnel/pkg/server/opts" "tunnel/pkg/server/queue" ) var ErrAlreadyClosed = errors.New("already closed") type Conn interface { Send(wq queue.Q) error Recv(rq queue.Q) error Close() error } type S interface { Open(env env.Env) (Conn, error) Close() } type Single interface { Single() } type conn struct { net.Conn desc string info string once sync.Once } func newConn(cn net.Conn, desc, info string) *conn { c := &conn{Conn: cn, desc: desc, info: info} return c } func (c *conn) Send(wq queue.Q) error { return queue.IoCopy(c, wq.Writer()) } func (c *conn) Recv(rq queue.Q) error { return queue.IoCopy(rq.Reader(), c) } func (c *conn) String() string { return c.info } func (c *conn) Close() error { err := ErrAlreadyClosed c.once.Do(func() { log.Println("close", c.desc) err = c.Conn.Close() }) return err } func New(desc string) (S, error) { base, opts := opts.Parse(desc) args := strings.SplitN(base, "/", 2) var proto string var addr string if len(args) < 2 { addr = args[0] } else { proto, addr = args[0], args[1] } if proto == "" { proto = "tcp" } switch addr { case "loop": return newLoopSocket() case "proxy": return newProxySocket(proto) case "": return nil, fmt.Errorf("bad socket '%s'", desc) } if proto == "tun" { return newTunSocket(addr) } if opts.Bool("listen") { return newListenSocket(proto, addr, opts) } if opts.Bool("defer") { return newDeferSocket(proto, addr) } return newDialSocket(proto, addr) }