package gost

import (
	"errors"
	"net"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"fmt"

	"github.com/ginuerzh/gosocks5"
	"github.com/go-log/log"
	smux "gopkg.in/xtaci/smux.v1"
)

type forwardConnector struct {
}

// ForwardConnector creates a Connector for data forward client.
func ForwardConnector() Connector {
	return &forwardConnector{}
}

func (c *forwardConnector) Connect(conn net.Conn, addr string, options ...ConnectOption) (net.Conn, error) {
	return conn, nil
}

type baseForwardHandler struct {
	raddr   string
	group   *NodeGroup
	options *HandlerOptions
}

func (h *baseForwardHandler) Init(options ...HandlerOption) {
	if h.options == nil {
		h.options = &HandlerOptions{}
	}

	for _, opt := range options {
		opt(h.options)
	}

	h.group = NewNodeGroup() // reset node group

	h.group.SetSelector(&defaultSelector{},
		WithStrategy(h.options.Strategy),
		WithFilter(&FailFilter{
			MaxFails:    h.options.MaxFails,
			FailTimeout: h.options.FailTimeout,
		}),
	)

	n := 1
	addrs := append(strings.Split(h.raddr, ","), h.options.IPs...)
	for _, addr := range addrs {
		if addr == "" {
			continue
		}

		// We treat the remote target server as a node, so we can put them in a group,
		// and perform the node selection for load balancing.
		h.group.AddNode(Node{
			ID:     n,
			Addr:   addr,
			Host:   addr,
			marker: &failMarker{},
		})

		n++
	}
	if len(h.group.Nodes()) == 0 {
		h.group.AddNode(Node{ // dummy address
			ID:   n,
			Addr: ":0",
			Host: ":0",
		})
	}
}

type tcpDirectForwardHandler struct {
	*baseForwardHandler
}

// TCPDirectForwardHandler creates a server Handler for TCP port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func TCPDirectForwardHandler(raddr string, opts ...HandlerOption) Handler {
	h := &tcpDirectForwardHandler{
		baseForwardHandler: &baseForwardHandler{
			raddr:   raddr,
			group:   NewNodeGroup(),
			options: &HandlerOptions{},
		},
	}

	for _, opt := range opts {
		opt(h.options)
	}

	return h
}

func (h *tcpDirectForwardHandler) Init(options ...HandlerOption) {
	h.baseForwardHandler.Init(options...)
}

func (h *tcpDirectForwardHandler) Handle(conn net.Conn) {
	defer conn.Close()

	retries := 1
	if h.options.Chain != nil && h.options.Chain.Retries > 0 {
		retries = h.options.Chain.Retries
	}
	if h.options.Retries > 0 {
		retries = h.options.Retries
	}

	var cc net.Conn
	var node Node
	var err error
	for i := 0; i < retries; i++ {
		node, err = h.group.Next()
		if err != nil {
			log.Logf("[tcp] %s - %s : %s", conn.RemoteAddr(), h.raddr, err)
			return
		}

		log.Logf("[tcp] %s - %s", conn.RemoteAddr(), node.Addr)
		cc, err = h.options.Chain.Dial(node.Addr,
			RetryChainOption(h.options.Retries),
			TimeoutChainOption(h.options.Timeout),
		)
		if err != nil {
			log.Logf("[tcp] %s -> %s : %s", conn.RemoteAddr(), node.Addr, err)
			node.MarkDead()
		} else {
			break
		}
	}
	if err != nil {
		return
	}

	node.ResetDead()
	defer cc.Close()

	log.Logf("[tcp] %s <-> %s", conn.RemoteAddr(), node.Addr)
	transport(conn, cc)
	log.Logf("[tcp] %s >-< %s", conn.RemoteAddr(), node.Addr)
}

type udpDirectForwardHandler struct {
	*baseForwardHandler
}

// UDPDirectForwardHandler creates a server Handler for UDP port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func UDPDirectForwardHandler(raddr string, opts ...HandlerOption) Handler {
	h := &udpDirectForwardHandler{
		baseForwardHandler: &baseForwardHandler{
			raddr:   raddr,
			group:   NewNodeGroup(),
			options: &HandlerOptions{},
		},
	}

	for _, opt := range opts {
		opt(h.options)
	}

	return h
}

func (h *udpDirectForwardHandler) Init(options ...HandlerOption) {
	h.baseForwardHandler.Init(options...)
}

func (h *udpDirectForwardHandler) Handle(conn net.Conn) {
	defer conn.Close()

	node, err := h.group.Next()
	if err != nil {
		log.Logf("[udp] %s - %s : %s", conn.RemoteAddr(), h.raddr, err)
		return
	}

	var cc net.Conn
	if h.options.Chain.IsEmpty() {
		raddr, err := net.ResolveUDPAddr("udp", node.Addr)
		if err != nil {
			node.MarkDead()
			log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err)
			return
		}
		cc, err = net.DialUDP("udp", nil, raddr)
		if err != nil {
			node.MarkDead()
			log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err)
			return
		}
	} else {
		var err error
		cc, err = getSOCKS5UDPTunnel(h.options.Chain, nil)
		if err != nil {
			log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err)
			return
		}
		cc = &udpTunnelConn{Conn: cc, raddr: node.Addr}
	}

	defer cc.Close()
	node.ResetDead()

	log.Logf("[udp] %s <-> %s", conn.RemoteAddr(), node.Addr)
	transport(conn, cc)
	log.Logf("[udp] %s >-< %s", conn.RemoteAddr(), node.Addr)
}

type tcpRemoteForwardHandler struct {
	*baseForwardHandler
}

// TCPRemoteForwardHandler creates a server Handler for TCP remote port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func TCPRemoteForwardHandler(raddr string, opts ...HandlerOption) Handler {
	h := &tcpRemoteForwardHandler{
		baseForwardHandler: &baseForwardHandler{
			raddr:   raddr,
			group:   NewNodeGroup(),
			options: &HandlerOptions{},
		},
	}

	for _, opt := range opts {
		opt(h.options)
	}

	return h
}

func (h *tcpRemoteForwardHandler) Init(options ...HandlerOption) {
	h.baseForwardHandler.Init(options...)
}

func (h *tcpRemoteForwardHandler) Handle(conn net.Conn) {
	defer conn.Close()

	retries := 1
	if h.options.Retries > 0 {
		retries = h.options.Retries
	}

	var cc net.Conn
	var node Node
	var err error
	for i := 0; i < retries; i++ {
		node, err = h.group.Next()
		if err != nil {
			log.Logf("[rtcp] %s - %s : %s", conn.LocalAddr(), h.raddr, err)
			return
		}
		cc, err = net.DialTimeout("tcp", node.Addr, h.options.Timeout)
		if err != nil {
			log.Logf("[rtcp] %s -> %s : %s", conn.LocalAddr(), node.Addr, err)
			node.MarkDead()
		} else {
			break
		}
	}
	if err != nil {
		return
	}

	defer cc.Close()
	node.ResetDead()

	log.Logf("[rtcp] %s <-> %s", conn.LocalAddr(), node.Addr)
	transport(cc, conn)
	log.Logf("[rtcp] %s >-< %s", conn.LocalAddr(), node.Addr)
}

type udpRemoteForwardHandler struct {
	*baseForwardHandler
}

// UDPRemoteForwardHandler creates a server Handler for UDP remote port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func UDPRemoteForwardHandler(raddr string, opts ...HandlerOption) Handler {
	h := &udpRemoteForwardHandler{
		baseForwardHandler: &baseForwardHandler{
			raddr:   raddr,
			group:   NewNodeGroup(),
			options: &HandlerOptions{},
		},
	}

	for _, opt := range opts {
		opt(h.options)
	}

	return h
}

func (h *udpRemoteForwardHandler) Init(options ...HandlerOption) {
	h.baseForwardHandler.Init(options...)
}

func (h *udpRemoteForwardHandler) Handle(conn net.Conn) {
	defer conn.Close()

	node, err := h.group.Next()
	if err != nil {
		log.Logf("[rudp] %s - %s : %s", conn.RemoteAddr(), h.raddr, err)
		return
	}

	raddr, err := net.ResolveUDPAddr("udp", node.Addr)
	if err != nil {
		node.MarkDead()
		log.Logf("[rudp] %s - %s : %s", conn.RemoteAddr(), node.Addr, err)
		return
	}
	cc, err := net.DialUDP("udp", nil, raddr)
	if err != nil {
		node.MarkDead()
		log.Logf("[rudp] %s - %s : %s", conn.RemoteAddr(), node.Addr, err)
		return
	}
	defer cc.Close()
	node.ResetDead()

	log.Logf("[rudp] %s <-> %s", conn.RemoteAddr(), node.Addr)
	transport(conn, cc)
	log.Logf("[rudp] %s >-< %s", conn.RemoteAddr(), node.Addr)
}

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)
}

type udpDirectForwardListener struct {
	ln       net.PacketConn
	connChan chan net.Conn
	errChan  chan error
	ttl      time.Duration
	connMap  udpConnMap
}

// UDPDirectForwardListener creates a Listener for UDP port forwarding server.
func UDPDirectForwardListener(addr string, ttl time.Duration) (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
	}
	l := &udpDirectForwardListener{
		ln:       ln,
		connChan: make(chan net.Conn, 128),
		errChan:  make(chan error, 1),
		ttl:      ttl,
	}
	go l.listenLoop()
	return l, nil
}

func (l *udpDirectForwardListener) 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, l.ttl)
			conn.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", raddr, l.Addr())
			}
		}

		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 : read queue is full", raddr, l.Addr())
		}
	}
}

func (l *udpDirectForwardListener) 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 *udpDirectForwardListener) Addr() net.Addr {
	return l.ln.LocalAddr()
}

func (l *udpDirectForwardListener) Close() error {
	err := l.ln.Close()
	l.connMap.Range(func(k interface{}, v *udpServerConn) bool {
		v.Close()
		return true
	})

	return err
}

type udpServerConn struct {
	conn       net.PacketConn
	raddr      net.Addr
	rChan      chan []byte
	closed     chan struct{}
	closeMutex sync.Mutex
	ttl        time.Duration
	nopChan    chan int
	onClose    func()
}

func newUDPServerConn(conn net.PacketConn, raddr net.Addr, ttl time.Duration) *udpServerConn {
	c := &udpServerConn{
		conn:    conn,
		raddr:   raddr,
		rChan:   make(chan []byte, 128),
		closed:  make(chan struct{}),
		nopChan: make(chan int),
		ttl:     ttl,
	}
	go c.ttlWait()
	return c
}

func (c *udpServerConn) Read(b []byte) (n int, 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:
	}

	return
}

func (c *udpServerConn) Write(b []byte) (n int, err error) {
	n, err = c.conn.WriteTo(b, c.raddr)

	if n > 0 {
		if Debug {
			log.Logf("[udp] %s <<< %s : length %d", c.RemoteAddr(), 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.onClose != nil {
			c.onClose()
		}
		close(c.closed)
	}
	return nil
}

func (c *udpServerConn) ttlWait() {
	ttl := c.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 tcpRemoteForwardListener struct {
	addr       net.Addr
	chain      *Chain
	connChan   chan net.Conn
	ln         net.Listener
	session    *muxSession
	sessionMux sync.Mutex
	closed     chan struct{}
	closeMux   sync.Mutex
	errChan    chan error
}

// TCPRemoteForwardListener creates a Listener for TCP remote port forwarding server.
func TCPRemoteForwardListener(addr string, chain *Chain) (Listener, error) {
	laddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	ln := &tcpRemoteForwardListener{
		addr:     laddr,
		chain:    chain,
		connChan: make(chan net.Conn, 1024),
		closed:   make(chan struct{}),
		errChan:  make(chan error),
	}

	if !ln.isChainValid() {
		ln.ln, err = net.Listen("tcp", ln.addr.String())
		return ln, err
	}

	go ln.listenLoop()

	return ln, err
}

func (l *tcpRemoteForwardListener) isChainValid() bool {
	lastNode := l.chain.LastNode()
	if (lastNode.Protocol == "forward" && lastNode.Transport == "ssh") ||
		lastNode.Protocol == "socks5" {
		return true
	}
	return false
}

func (l *tcpRemoteForwardListener) listenLoop() {
	var tempDelay time.Duration

	for {
		conn, err := l.accept()

		select {
		case <-l.closed:
			if conn != nil {
				conn.Close()
			}
			return
		default:
		}

		if err != nil {
			if tempDelay == 0 {
				tempDelay = 1000 * time.Millisecond
			} else {
				tempDelay *= 2
			}
			if max := 6 * time.Second; tempDelay > max {
				tempDelay = max
			}
			log.Logf("[rtcp] accept error: %v; retrying in %v", err, tempDelay)
			time.Sleep(tempDelay)
			continue
		}

		tempDelay = 0

		select {
		case l.connChan <- conn:
		default:
			conn.Close()
			log.Logf("[rtcp] %s - %s: connection queue is full", conn.RemoteAddr(), conn.LocalAddr())
		}
	}
}

func (l *tcpRemoteForwardListener) Accept() (conn net.Conn, err error) {
	if l.ln != nil {
		return l.ln.Accept()
	}

	select {
	case conn = <-l.connChan:
	case <-l.closed:
		err = errors.New("closed")
	}

	return
}

func (l *tcpRemoteForwardListener) accept() (conn net.Conn, err error) {
	lastNode := l.chain.LastNode()
	if lastNode.Protocol == "forward" && lastNode.Transport == "ssh" {
		return l.chain.Dial(l.addr.String())
	}

	if lastNode.Protocol == "socks5" {
		if lastNode.GetBool("mbind") {
			return l.muxAccept() // multiplexing support for binding.
		}

		cc, er := l.chain.Conn()
		if er != nil {
			return nil, er
		}
		conn, err = l.waitConnectSOCKS5(cc)
		if err != nil {
			cc.Close()
		}
	}
	return
}

func (l *tcpRemoteForwardListener) muxAccept() (conn net.Conn, err error) {
	session, err := l.getSession()
	if err != nil {
		return nil, err
	}
	cc, err := session.Accept()
	if err != nil {
		session.Close()
		return nil, err
	}

	return cc, nil
}

func (l *tcpRemoteForwardListener) getSession() (s *muxSession, err error) {
	l.sessionMux.Lock()
	defer l.sessionMux.Unlock()

	if l.session != nil && !l.session.IsClosed() {
		return l.session, nil
	}

	conn, err := l.chain.Conn()
	if err != nil {
		return nil, err
	}

	defer func(c net.Conn) {
		if err != nil {
			c.Close()
		}
	}(conn)

	conn.SetDeadline(time.Now().Add(HandshakeTimeout))
	defer conn.SetDeadline(time.Time{})

	conn, err = socks5Handshake(conn, nil, l.chain.LastNode().User)
	if err != nil {
		return nil, err
	}
	req := gosocks5.NewRequest(CmdMuxBind, toSocksAddr(l.addr))
	if err := req.Write(conn); err != nil {
		log.Log("[rtcp] SOCKS5 BIND request: ", err)
		return nil, err
	}

	rep, err := gosocks5.ReadReply(conn)
	if err != nil {
		log.Log("[rtcp] SOCKS5 BIND reply: ", err)
		return nil, err
	}
	if rep.Rep != gosocks5.Succeeded {
		log.Logf("[rtcp] bind on %s failure", l.addr)
		return nil, fmt.Errorf("Bind on %s failure", l.addr.String())
	}
	log.Logf("[rtcp] BIND ON %s OK", rep.Addr)

	// Upgrade connection to multiplex stream.
	session, err := smux.Server(conn, smux.DefaultConfig())
	if err != nil {
		return nil, err
	}
	l.session = &muxSession{
		conn:    conn,
		session: session,
	}

	return l.session, nil
}

func (l *tcpRemoteForwardListener) waitConnectSOCKS5(conn net.Conn) (net.Conn, error) {
	conn, err := socks5Handshake(conn, nil, l.chain.LastNode().User)
	if err != nil {
		return nil, err
	}
	req := gosocks5.NewRequest(gosocks5.CmdBind, toSocksAddr(l.addr))
	if err := req.Write(conn); err != nil {
		log.Log("[rtcp] SOCKS5 BIND request: ", err)
		return nil, err
	}

	// first reply, bind status
	conn.SetReadDeadline(time.Now().Add(ReadTimeout))
	rep, err := gosocks5.ReadReply(conn)
	if err != nil {
		log.Log("[rtcp] SOCKS5 BIND reply: ", err)
		return nil, err
	}
	conn.SetReadDeadline(time.Time{})
	if rep.Rep != gosocks5.Succeeded {
		log.Logf("[rtcp] bind on %s failure", l.addr)
		return nil, fmt.Errorf("Bind on %s failure", l.addr.String())
	}
	log.Logf("[rtcp] BIND ON %s OK", rep.Addr)

	// second reply, peer connected
	rep, err = gosocks5.ReadReply(conn)
	if err != nil {
		log.Log("[rtcp]", err)
		return nil, err
	}
	if rep.Rep != gosocks5.Succeeded {
		log.Logf("[rtcp] peer connect failure: %d", rep.Rep)
		return nil, errors.New("peer connect failure")
	}

	log.Logf("[rtcp] PEER %s CONNECTED", rep.Addr)
	return conn, nil
}

func (l *tcpRemoteForwardListener) Addr() net.Addr {
	if l.ln != nil {
		return l.ln.Addr()
	}
	return l.addr
}

func (l *tcpRemoteForwardListener) Close() error {
	if l.ln != nil {
		return l.ln.Close()
	}

	l.closeMux.Lock()
	defer l.closeMux.Unlock()

	select {
	case <-l.closed:
		return nil
	default:
		close(l.closed)
	}
	return nil
}

type udpRemoteForwardListener struct {
	addr     net.Addr
	chain    *Chain
	connMap  udpConnMap
	connChan chan net.Conn
	ln       *net.UDPConn
	errChan  chan error
	ttl      time.Duration
	closed   chan struct{}
	closeMux sync.Mutex
	once     sync.Once
}

// UDPRemoteForwardListener creates a Listener for UDP remote port forwarding server.
func UDPRemoteForwardListener(addr string, chain *Chain, ttl time.Duration) (Listener, error) {
	laddr, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		return nil, err
	}

	ln := &udpRemoteForwardListener{
		addr:     laddr,
		chain:    chain,
		connChan: make(chan net.Conn, 128),
		errChan:  make(chan error, 1),
		ttl:      ttl,
		closed:   make(chan struct{}),
	}

	go ln.listenLoop()

	err = <-ln.errChan

	return ln, err
}

func (l *udpRemoteForwardListener) isChainValid() bool {
	lastNode := l.chain.LastNode()
	return lastNode.Protocol == "socks5"
}

func (l *udpRemoteForwardListener) listenLoop() {
	for {
		conn, err := l.connect()
		if err != nil {
			log.Logf("[rudp] %s : %s", l.Addr(), err)
			return
		}

		func() {
			defer conn.Close()

			for {
				b := make([]byte, mediumBufferSize)
				n, raddr, err := conn.ReadFrom(b)
				if err != nil {
					log.Logf("[rudp] %s : %s", l.Addr(), err)
					break
				}

				uc, ok := l.connMap.Get(raddr.String())
				if !ok {
					uc = newUDPServerConn(conn, raddr, l.ttl)
					uc.onClose = func() {
						l.connMap.Delete(raddr.String())
						log.Logf("[rudp] %s closed (%d)", raddr, l.connMap.Size())
					}

					select {
					case l.connChan <- uc:
						l.connMap.Set(raddr.String(), uc)
						log.Logf("[rudp] %s -> %s (%d)", raddr, l.Addr(), l.connMap.Size())
					default:
						uc.Close()
						log.Logf("[rudp] %s - %s: connection queue is full", raddr, l.Addr())
					}
				}

				select {
				case uc.rChan <- b[:n]:
					if Debug {
						log.Logf("[rudp] %s >>> %s : length %d", raddr, l.Addr(), n)
					}
				default:
					log.Logf("[rudp] %s -> %s : write queue is full", raddr, l.Addr())
				}
			}
		}()
	}
}

func (l *udpRemoteForwardListener) connect() (conn net.PacketConn, err error) {
	var tempDelay time.Duration

	for {
		select {
		case <-l.closed:
			return nil, errors.New("closed")
		default:
		}

		lastNode := l.chain.LastNode()
		if lastNode.Protocol == "socks5" {
			var cc net.Conn
			cc, err = getSOCKS5UDPTunnel(l.chain, l.addr)
			if err != nil {
				log.Logf("[rudp] %s : %s", l.Addr(), err)
			} else {
				conn = &udpTunnelConn{Conn: cc}
			}
		} else {
			var uc *net.UDPConn
			uc, err = net.ListenUDP("udp", l.addr.(*net.UDPAddr))
			if err == nil {
				l.addr = uc.LocalAddr()
				conn = uc
			}
		}

		l.once.Do(func() {
			l.errChan <- err
			close(l.errChan)
		})

		if err != nil {
			if tempDelay == 0 {
				tempDelay = 1000 * time.Millisecond
			} else {
				tempDelay *= 2
			}
			if max := 6 * time.Second; tempDelay > max {
				tempDelay = max
			}
			log.Logf("[rudp] Accept error: %v; retrying in %v", err, tempDelay)
			time.Sleep(tempDelay)
			continue
		}
		return
	}
}

func (l *udpRemoteForwardListener) Accept() (conn net.Conn, err error) {
	select {
	case conn = <-l.connChan:
	case <-l.closed:
		err = errors.New("accpet on closed listener")
	}
	return
}

func (l *udpRemoteForwardListener) Addr() net.Addr {
	return l.addr
}

func (l *udpRemoteForwardListener) Close() error {
	l.closeMux.Lock()
	defer l.closeMux.Unlock()

	select {
	case <-l.closed:
		return nil
	default:
		l.connMap.Range(func(k interface{}, v *udpServerConn) bool {
			v.Close()
			return true
		})
		close(l.closed)
	}

	return nil
}
