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 exported struct { info string Channel } type Channel interface { Send(wq queue.Q) error Recv(rq queue.Q) error Close() error } type S interface { Open(env env.Env) (Channel, error) Close() } type listenSocket struct { proto, addr string listen net.Listener } type conn struct { net.Conn once sync.Once } func (c exported) String() string { return c.info } func newConn(cn net.Conn) Channel { c := &conn{Conn: cn} log.Println("open", c) 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 { local, remote := c.LocalAddr(), c.RemoteAddr() return fmt.Sprintf("%s/%s->%s", local.Network(), local, remote) } func (c *conn) Close() error { err := ErrAlreadyClosed c.once.Do(func() { log.Println("close", c) err = c.Conn.Close() }) return err } func New(desc string, env env.Env) (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 addr == "loop" { return newLoopSocket() } if proto == "" { proto = "tcp" } if addr == "" { return nil, fmt.Errorf("bad socket '%s'", desc) } if proto == "tun" { return newTunSocket(addr) } if _, ok := opts["listen"]; ok { return newListenSocket(proto, addr) } if _, ok := opts["defer"]; ok { return newDeferSocket(proto, addr) } return newDialSocket(proto, addr) }