summaryrefslogtreecommitdiff
path: root/irc/session.go
diff options
context:
space:
mode:
authorHubert Hirtz <hubert@hirtz.pm>2021-09-19 17:15:53 +0200
committerHubert Hirtz <hubert@hirtz.pm>2021-09-28 21:07:04 +0200
commit60f9e6570e40c0a0cbb10976b0ec6a7076fdb453 (patch)
tree419d5389b182c4e3c50c264472335ba7b140f28a /irc/session.go
parentadd compiled doc to gitignore (diff)
Eager registration
Decreases the number of roundtrips necessary for registration. A typical registration might look like this: - C: CAP LS; NICK; USER - S: CAP LS - C: CAP REQ - S: CAP ACK - C: AUTHENTICATE <mesh> - S: AUTHENTICATE + - C: AUTHENTICATE <user/pass payload> - S: RPL_SASLSUCCESS - C: CAP END - S: welcome batch By sending client messages eagerly, despite the number of message not decreasing (it's increasing when the client supports more caps than the server), the number of roundtrips is decreased to 1 (not counting TCP and TLS negotiation).
Diffstat (limited to '')
-rw-r--r--irc/session.go87
1 files changed, 25 insertions, 62 deletions
diff --git a/irc/session.go b/irc/session.go
index 716d3fb..ec90631 100644
--- a/irc/session.go
+++ b/irc/session.go
@@ -115,8 +115,7 @@ type Session struct {
host string
auth SASLClient
- availableCaps map[string]string
- enabledCaps map[string]struct{}
+ enabledCaps map[string]struct{}
// ISUPPORT features
casemap func(string) string
@@ -144,7 +143,6 @@ func NewSession(out chan<- Message, params SessionParams) *Session {
user: params.Username,
real: params.RealName,
auth: params.Auth,
- availableCaps: map[string]string{},
enabledCaps: map[string]struct{}{},
casemap: CasemapRFC1459,
chantypes: "#&",
@@ -159,9 +157,21 @@ func NewSession(out chan<- Message, params SessionParams) *Session {
pendingChannels: map[string]time.Time{},
}
- s.out <- NewMessage("CAP", "LS", "302")
+ s.out <- NewMessage("CAP", "LS", "302") // needed to advertise 302 support
+ for capability := range SupportedCapabilities {
+ s.out <- NewMessage("CAP", "REQ", capability)
+ }
s.out <- NewMessage("NICK", s.nick)
s.out <- NewMessage("USER", s.user, "0", "*", s.real)
+ if s.auth != nil {
+ s.out <- NewMessage("AUTHENTICATE", s.auth.Handshake())
+ resp, err := s.auth.Respond("+")
+ if err != nil {
+ panic(err)
+ }
+ s.out <- NewMessage("AUTHENTICATE", resp)
+ }
+ s.out <- NewMessage("CAP", "END")
return s
}
@@ -466,53 +476,18 @@ func (s *Session) handleUnregistered(msg Message) Event {
switch msg.Command {
case "AUTHENTICATE":
if s.auth != nil {
- res, err := s.auth.Respond(msg.Params[0])
- if err != nil {
- s.out <- NewMessage("AUTHENTICATE", "*")
+ if msg.Params[0] == "+" {
+ // Server has processed the "AUTHENTICATE <mechanism>" message
} else {
- s.out <- NewMessage("AUTHENTICATE", res)
+ // Unexpected AUTHENTICATE message from server, abort authentication.
+ s.out <- NewMessage("AUTHENTICATE", "*")
}
}
case rplLoggedin:
- s.out <- NewMessage("CAP", "END")
s.acct = msg.Params[2]
s.host = ParsePrefix(msg.Params[1]).Host
case errNicklocked, errSaslfail, errSasltoolong, errSaslaborted, errSaslalready, rplSaslmechs:
- s.out <- NewMessage("CAP", "END")
- case "CAP":
- switch msg.Params[1] {
- case "LS":
- var willContinue bool
- var ls string
-
- if msg.Params[2] == "*" {
- willContinue = true
- ls = msg.Params[3]
- } else {
- willContinue = false
- ls = msg.Params[2]
- }
-
- for _, c := range ParseCaps(ls) {
- s.availableCaps[c.Name] = c.Value
- }
-
- if !willContinue {
- for c := range s.availableCaps {
- if _, ok := SupportedCapabilities[c]; !ok {
- continue
- }
- s.out <- NewMessage("CAP", "REQ", c)
- }
-
- _, ok := s.availableCaps["sasl"]
- if s.auth == nil || !ok {
- s.out <- NewMessage("CAP", "END")
- }
- }
- default:
- return s.handleRegistered(msg)
- }
+ // Auth failed, let registration end anyway.
case errNicknameinuse:
s.out <- NewMessage("NICK", msg.Params[1]+"_")
case rplSaslsuccess:
@@ -563,38 +538,26 @@ func (s *Session) handleRegistered(msg Message) Event {
delete(s.enabledCaps, c.Name)
}
- if s.auth != nil && c.Name == "sasl" {
- h := s.auth.Handshake()
- s.out <- NewMessage("AUTHENTICATE", h)
- } else if len(s.channels) != 0 && c.Name == "multi-prefix" {
+ if c.Name == "multi-prefix" {
// TODO merge NAMES commands
for channel := range s.channels {
s.out <- NewMessage("NAMES", channel)
}
}
}
- case "NAK":
- // do nothing
case "NEW":
for _, c := range ParseCaps(msg.Params[2]) {
- s.availableCaps[c.Name] = c.Value
- _, ok := SupportedCapabilities[c.Name]
- if !ok {
- continue
+ if _, ok := SupportedCapabilities[c.Name]; ok {
+ s.out <- NewMessage("CAP", "REQ", c.Name)
}
- s.out <- NewMessage("CAP", "REQ", c.Name)
- }
-
- _, ok := s.availableCaps["sasl"]
- if s.acct == "" && ok {
- // TODO authenticate
+ // TODO authenticate if necessary
}
case "DEL":
for _, c := range ParseCaps(msg.Params[2]) {
- delete(s.availableCaps, c.Name)
delete(s.enabledCaps, c.Name)
}
}
+ // do nothing on LS and NAK
case "JOIN":
nickCf := s.Casemap(msg.Prefix.Name)
channelCf := s.Casemap(msg.Params[0])
@@ -747,7 +710,7 @@ func (s *Session) handleRegistered(msg Message) Event {
if c, ok := s.channels[channelCf]; ok {
return ModeChangeEvent{
Channel: c.Name,
- Mode: strings.Join(msg.Params[1:], " "),
+ Mode: strings.Join(msg.Params[1:], " "),
}
}
case "PRIVMSG", "NOTICE":