mirror of
https://github.com/cmz0228/hysteria-dev.git
synced 2025-06-09 05:49:54 +00:00
Merge pull request #917 from apernet/fix-reconnect
fix: incorrect reconnect logic that causes blocking when dialing connections
This commit is contained in:
commit
80bc3b3a44
@ -56,53 +56,56 @@ func (rc *reconnectableClientImpl) reconnect() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc *reconnectableClientImpl) TCP(addr string) (net.Conn, error) {
|
// clientDo calls f with the current client.
|
||||||
|
// If the client is nil, it will first reconnect.
|
||||||
|
// It will also detect if the client is closed, and if so,
|
||||||
|
// set it to nil for reconnect next time.
|
||||||
|
func (rc *reconnectableClientImpl) clientDo(f func(Client) (interface{}, error)) (interface{}, error) {
|
||||||
rc.m.Lock()
|
rc.m.Lock()
|
||||||
defer rc.m.Unlock()
|
|
||||||
if rc.closed {
|
if rc.closed {
|
||||||
|
rc.m.Unlock()
|
||||||
return nil, coreErrs.ClosedError{}
|
return nil, coreErrs.ClosedError{}
|
||||||
}
|
}
|
||||||
if rc.client == nil {
|
if rc.client == nil {
|
||||||
// No active connection, connect first
|
// No active connection, connect first
|
||||||
if err := rc.reconnect(); err != nil {
|
if err := rc.reconnect(); err != nil {
|
||||||
|
rc.m.Unlock()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn, err := rc.client.TCP(addr)
|
client := rc.client
|
||||||
|
rc.m.Unlock()
|
||||||
|
|
||||||
|
ret, err := f(client)
|
||||||
if _, ok := err.(coreErrs.ClosedError); ok {
|
if _, ok := err.(coreErrs.ClosedError); ok {
|
||||||
// Connection closed, reconnect
|
// Connection closed, set client to nil for reconnect next time
|
||||||
if err := rc.reconnect(); err != nil {
|
rc.m.Lock()
|
||||||
return nil, err
|
if rc.client == client {
|
||||||
|
// This check is in case the client is already changed by another goroutine
|
||||||
|
rc.client = nil
|
||||||
}
|
}
|
||||||
return rc.client.TCP(addr)
|
rc.m.Unlock()
|
||||||
|
}
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *reconnectableClientImpl) TCP(addr string) (net.Conn, error) {
|
||||||
|
if c, err := rc.clientDo(func(client Client) (interface{}, error) {
|
||||||
|
return client.TCP(addr)
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
// OK or some other temporary error
|
return c.(net.Conn), nil
|
||||||
return conn, err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc *reconnectableClientImpl) UDP() (HyUDPConn, error) {
|
func (rc *reconnectableClientImpl) UDP() (HyUDPConn, error) {
|
||||||
rc.m.Lock()
|
if c, err := rc.clientDo(func(client Client) (interface{}, error) {
|
||||||
defer rc.m.Unlock()
|
return client.UDP()
|
||||||
if rc.closed {
|
}); err != nil {
|
||||||
return nil, coreErrs.ClosedError{}
|
|
||||||
}
|
|
||||||
if rc.client == nil {
|
|
||||||
// No active connection, connect first
|
|
||||||
if err := rc.reconnect(); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
|
||||||
}
|
|
||||||
conn, err := rc.client.UDP()
|
|
||||||
if _, ok := err.(coreErrs.ClosedError); ok {
|
|
||||||
// Connection closed, reconnect
|
|
||||||
if err := rc.reconnect(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return rc.client.UDP()
|
|
||||||
} else {
|
} else {
|
||||||
// OK or some other temporary error
|
return c.(HyUDPConn), nil
|
||||||
return conn, err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user