1
0
Fork 0
mirror of https://github.com/apernet/hysteria.git synced 2025-04-05 21:47:39 +03:00

chore: replace guard routine with CloseWithErr()

This commit is contained in:
Haruue 2024-10-04 11:27:36 +08:00
parent 4ecbd57294
commit 931fc2fdb2
No known key found for this signature in database
GPG key ID: F6083B28CBCBC148

View file

@ -40,9 +40,6 @@ type udpSessionEntry struct {
DialFunc func(addr string, firstMsgData []byte) (conn UDPConn, actualAddr string, err error) DialFunc func(addr string, firstMsgData []byte) (conn UDPConn, actualAddr string, err error)
ExitFunc func(err error) ExitFunc func(err error)
timeoutChan chan struct{}
exitChan chan error
conn UDPConn conn UDPConn
connLock sync.Mutex connLock sync.Mutex
closed bool closed bool
@ -61,34 +58,30 @@ func newUDPSessionEntry(
DialFunc: dialFunc, DialFunc: dialFunc,
ExitFunc: exitFunc, ExitFunc: exitFunc,
timeoutChan: make(chan struct{}),
exitChan: make(chan error, 2),
} }
go func() {
// Guard routine
var err error
select {
case <-e.timeoutChan:
// Use nil error to indicate timeout.
case err = <-e.exitChan:
}
// We need this lock to ensure not to create conn after session exit
e.connLock.Lock()
e.closed = true
if e.conn != nil {
_ = e.conn.Close()
}
e.connLock.Unlock()
e.ExitFunc(err)
}()
return return
} }
func (e *udpSessionEntry) CloseWithErr(err error) {
// We need this lock to ensure not to create conn after session exit
e.connLock.Lock()
if e.closed {
// Already closed
e.connLock.Unlock()
return
}
e.closed = true
if e.conn != nil {
_ = e.conn.Close()
}
e.connLock.Unlock()
e.ExitFunc(err)
}
// Feed feeds a UDP message to the session. // Feed feeds a UDP message to the session.
// If the message itself is a complete message, or it completes a fragmented message, // If the message itself is a complete message, or it completes a fragmented message,
// the message is written to the session's UDP connection, and the number of bytes // the message is written to the session's UDP connection, and the number of bytes
@ -121,17 +114,18 @@ func (e *udpSessionEntry) Feed(msg *protocol.UDPMessage) (int, error) {
func (e *udpSessionEntry) initConn(firstMsg *protocol.UDPMessage) error { func (e *udpSessionEntry) initConn(firstMsg *protocol.UDPMessage) error {
// We need this lock to ensure not to create conn after session exit // We need this lock to ensure not to create conn after session exit
e.connLock.Lock() e.connLock.Lock()
defer e.connLock.Unlock()
if e.closed { if e.closed {
e.connLock.Unlock()
return errors.New("session is closed") return errors.New("session is closed")
} }
conn, actualAddr, err := e.DialFunc(firstMsg.Addr, firstMsg.Data) conn, actualAddr, err := e.DialFunc(firstMsg.Addr, firstMsg.Data)
if err != nil { if err != nil {
// Fail fast if DailFunc failed // Fail fast if DialFunc failed
// (usually indicates the connection has been rejected by the ACL) // (usually indicates the connection has been rejected by the ACL)
e.exitChan <- err e.connLock.Unlock()
e.CloseWithErr(err)
return err return err
} }
@ -141,6 +135,8 @@ func (e *udpSessionEntry) initConn(firstMsg *protocol.UDPMessage) error {
e.OriginalAddr = firstMsg.Addr e.OriginalAddr = firstMsg.Addr
} }
go e.receiveLoop() go e.receiveLoop()
e.connLock.Unlock()
return nil return nil
} }
@ -154,7 +150,7 @@ func (e *udpSessionEntry) receiveLoop() {
for { for {
udpN, rAddr, err := e.conn.ReadFrom(udpBuf) udpN, rAddr, err := e.conn.ReadFrom(udpBuf)
if err != nil { if err != nil {
e.exitChan <- err e.CloseWithErr(err)
return return
} }
e.Last.Set(time.Now()) e.Last.Set(time.Now())
@ -176,7 +172,7 @@ func (e *udpSessionEntry) receiveLoop() {
} }
err = sendMessageAutoFrag(e.IO, msgBuf, msg) err = sendMessageAutoFrag(e.IO, msgBuf, msg)
if err != nil { if err != nil {
e.exitChan <- err e.CloseWithErr(err)
return return
} }
} }
@ -185,10 +181,8 @@ func (e *udpSessionEntry) receiveLoop() {
// MarkTimeout marks the session to be cleaned up due to timeout. // MarkTimeout marks the session to be cleaned up due to timeout.
// Should only be called by the cleanup routine of the session manager. // Should only be called by the cleanup routine of the session manager.
func (e *udpSessionEntry) MarkTimeout() { func (e *udpSessionEntry) MarkTimeout() {
select { // nil error indicates timeout.
case e.timeoutChan <- struct{}{}: e.CloseWithErr(nil)
default:
}
} }
// sendMessageAutoFrag tries to send a UDP message as a whole first, // sendMessageAutoFrag tries to send a UDP message as a whole first,