From 2d0ed40435f1b0a57d5c35677add28716c2952e3 Mon Sep 17 00:00:00 2001 From: Russ Garrett Date: Sun, 12 May 2019 10:29:21 +0100 Subject: [PATCH] Add an overall timeout on CAP negotiation At the moment it just hangs if the server doesn't support CAP. This adds a 15 second timeout to the CAP negotiation process, after which the connection continues. The timeout and error on failed SASL negotiation is preserved. --- irc.go | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/irc.go b/irc.go index de8f6a5..3c41873 100644 --- a/irc.go +++ b/irc.go @@ -36,6 +36,8 @@ const ( VERSION = "go-ircevent v2.1" ) +const CAP_TIMEOUT = time.Second * 15 + var ErrDisconnected = errors.New("Disconnect Called") // Read data from a connection. To be used as a goroutine. @@ -554,16 +556,29 @@ func (irc *Connection) negotiateCaps() error { close(saslResChan) return res.Err } - case <-time.After(time.Second * 15): + case <-time.After(CAP_TIMEOUT): close(saslResChan) - return errors.New("SASL setup timed out. This shouldn't happen.") + // Raise an error if we can't authenticate with SASL. + return errors.New("SASL setup timed out. Does the server support SASL?") } } - // Wait for all capabilities to be ACKed or NAKed before ending negotiation - for i := 0; i < len(irc.RequestCaps); i++ { - <-cap_chan + remaining_caps := len(irc.RequestCaps) + + select { + case <-cap_chan: + remaining_caps-- + case <-time.After(CAP_TIMEOUT): + // The server probably doesn't implement CAP LS, which is "normal". + return nil } + + // Wait for all capabilities to be ACKed or NAKed before ending negotiation + for remaining_caps > 0 { + <-cap_chan + remaining_caps-- + } + irc.pwrite <- fmt.Sprintf("CAP END\r\n") return nil