add timeout for handshake but not for target connecting

better algorithm for backend retry
This commit is contained in:
git 2018-11-16 14:14:55 +08:00
parent c66751b017
commit 1823009c5c
2 changed files with 33 additions and 13 deletions

View File

@ -106,7 +106,7 @@ func (c *Chain) Dial(addr string, opts ...ChainOption) (conn net.Conn, err error
opt(options) opt(options)
} }
retries := 1 retries := 10 //maximum retry
if c != nil && c.Retries > 0 { if c != nil && c.Retries > 0 {
retries = c.Retries retries = c.Retries
} }
@ -119,6 +119,9 @@ func (c *Chain) Dial(addr string, opts ...ChainOption) (conn net.Conn, err error
if err == nil { if err == nil {
break break
} }
if err == ErrNoneAvailable {
break
}
} }
return return
} }
@ -128,6 +131,7 @@ func (c *Chain) dialWithOptions(addr string, options *ChainOptions) (net.Conn, e
options = &ChainOptions{} options = &ChainOptions{}
} }
route, err := c.selectRouteFor(addr) route, err := c.selectRouteFor(addr)
//log.Log("Connecting", addr, "using", route.Nodes()[0].Addr, "failcount", route.Nodes()[0].failCount)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -138,17 +142,12 @@ func (c *Chain) dialWithOptions(addr string, options *ChainOptions) (net.Conn, e
return net.DialTimeout("tcp", addr, options.Timeout) return net.DialTimeout("tcp", addr, options.Timeout)
} }
conn, err := route.getConn() conn, err := route.getConn(addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
cc, err := route.LastNode().Client.Connect(conn, addr) return conn, nil
if err != nil {
conn.Close()
return nil, err
}
return cc, nil
} }
func (c *Chain) resolve(addr string, resolver Resolver, hosts *Hosts) string { func (c *Chain) resolve(addr string, resolver Resolver, hosts *Hosts) string {
@ -194,7 +193,7 @@ func (c *Chain) Conn(opts ...ChainOption) (conn net.Conn, err error) {
if err != nil { if err != nil {
continue continue
} }
conn, err = route.getConn() conn, err = route.getConn("")
if err != nil { if err != nil {
log.Log(err) log.Log(err)
continue continue
@ -206,7 +205,7 @@ func (c *Chain) Conn(opts ...ChainOption) (conn net.Conn, err error) {
} }
// getConn obtains a connection to the last node of the chain. // getConn obtains a connection to the last node of the chain.
func (c *Chain) getConn() (conn net.Conn, err error) { func (c *Chain) getConn(addr string) (conn net.Conn, err error) {
if c.IsEmpty() { if c.IsEmpty() {
err = ErrEmptyChain err = ErrEmptyChain
return return
@ -225,7 +224,10 @@ func (c *Chain) getConn() (conn net.Conn, err error) {
node.MarkDead() node.MarkDead()
return return
} }
node.ResetDead()
if len(nodes) > 1 {
node.ResetDead() // don't reset the last node as we are going to check if it will connect successfully.
}
preNode := node preNode := node
for _, node := range nodes[1:] { for _, node := range nodes[1:] {
@ -242,13 +244,27 @@ func (c *Chain) getConn() (conn net.Conn, err error) {
node.MarkDead() node.MarkDead()
return return
} }
node.ResetDead() if len(nodes) > 1 {
node.ResetDead()
}
cn = cc cn = cc
preNode = node preNode = node
} }
conn = cn conn = cn
if addr != "" {
var cc net.Conn
cc, err = node.Client.Connect(conn, addr)
if err != nil {
if _, ok := err.(*net.OpError); ok {
node.MarkDead()
}
conn.Close()
return
}
conn = cc
}
node.ResetDead()
return return
} }

View File

@ -215,9 +215,13 @@ func (c *socks5Connector) Connect(conn net.Conn, addr string) (net.Conn, error)
) )
cc := gosocks5.ClientConn(conn, selector) cc := gosocks5.ClientConn(conn, selector)
conn.SetDeadline(time.Now().Add(time.Second * 5))
if err := cc.Handleshake(); err != nil { if err := cc.Handleshake(); err != nil {
conn.SetDeadline(time.Time{})
return nil, err return nil, err
} }
conn.SetDeadline(time.Time{})
conn = cc conn = cc
host, port, err := net.SplitHostPort(addr) host, port, err := net.SplitHostPort(addr)