commit 60f9e65
Hubert Hirtz
·
2021-09-19 15:15:53 +0000 UTC
parent 185ea09
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).
1 files changed,
+25,
-62
+25,
-62
1@@ -115,8 +115,7 @@ type Session struct {
2 host string
3 auth SASLClient
4
5- availableCaps map[string]string
6- enabledCaps map[string]struct{}
7+ enabledCaps map[string]struct{}
8
9 // ISUPPORT features
10 casemap func(string) string
11@@ -144,7 +143,6 @@ func NewSession(out chan<- Message, params SessionParams) *Session {
12 user: params.Username,
13 real: params.RealName,
14 auth: params.Auth,
15- availableCaps: map[string]string{},
16 enabledCaps: map[string]struct{}{},
17 casemap: CasemapRFC1459,
18 chantypes: "#&",
19@@ -159,9 +157,21 @@ func NewSession(out chan<- Message, params SessionParams) *Session {
20 pendingChannels: map[string]time.Time{},
21 }
22
23- s.out <- NewMessage("CAP", "LS", "302")
24+ s.out <- NewMessage("CAP", "LS", "302") // needed to advertise 302 support
25+ for capability := range SupportedCapabilities {
26+ s.out <- NewMessage("CAP", "REQ", capability)
27+ }
28 s.out <- NewMessage("NICK", s.nick)
29 s.out <- NewMessage("USER", s.user, "0", "*", s.real)
30+ if s.auth != nil {
31+ s.out <- NewMessage("AUTHENTICATE", s.auth.Handshake())
32+ resp, err := s.auth.Respond("+")
33+ if err != nil {
34+ panic(err)
35+ }
36+ s.out <- NewMessage("AUTHENTICATE", resp)
37+ }
38+ s.out <- NewMessage("CAP", "END")
39
40 return s
41 }
42@@ -466,53 +476,18 @@ func (s *Session) handleUnregistered(msg Message) Event {
43 switch msg.Command {
44 case "AUTHENTICATE":
45 if s.auth != nil {
46- res, err := s.auth.Respond(msg.Params[0])
47- if err != nil {
48- s.out <- NewMessage("AUTHENTICATE", "*")
49+ if msg.Params[0] == "+" {
50+ // Server has processed the "AUTHENTICATE <mechanism>" message
51 } else {
52- s.out <- NewMessage("AUTHENTICATE", res)
53+ // Unexpected AUTHENTICATE message from server, abort authentication.
54+ s.out <- NewMessage("AUTHENTICATE", "*")
55 }
56 }
57 case rplLoggedin:
58- s.out <- NewMessage("CAP", "END")
59 s.acct = msg.Params[2]
60 s.host = ParsePrefix(msg.Params[1]).Host
61 case errNicklocked, errSaslfail, errSasltoolong, errSaslaborted, errSaslalready, rplSaslmechs:
62- s.out <- NewMessage("CAP", "END")
63- case "CAP":
64- switch msg.Params[1] {
65- case "LS":
66- var willContinue bool
67- var ls string
68-
69- if msg.Params[2] == "*" {
70- willContinue = true
71- ls = msg.Params[3]
72- } else {
73- willContinue = false
74- ls = msg.Params[2]
75- }
76-
77- for _, c := range ParseCaps(ls) {
78- s.availableCaps[c.Name] = c.Value
79- }
80-
81- if !willContinue {
82- for c := range s.availableCaps {
83- if _, ok := SupportedCapabilities[c]; !ok {
84- continue
85- }
86- s.out <- NewMessage("CAP", "REQ", c)
87- }
88-
89- _, ok := s.availableCaps["sasl"]
90- if s.auth == nil || !ok {
91- s.out <- NewMessage("CAP", "END")
92- }
93- }
94- default:
95- return s.handleRegistered(msg)
96- }
97+ // Auth failed, let registration end anyway.
98 case errNicknameinuse:
99 s.out <- NewMessage("NICK", msg.Params[1]+"_")
100 case rplSaslsuccess:
101@@ -563,38 +538,26 @@ func (s *Session) handleRegistered(msg Message) Event {
102 delete(s.enabledCaps, c.Name)
103 }
104
105- if s.auth != nil && c.Name == "sasl" {
106- h := s.auth.Handshake()
107- s.out <- NewMessage("AUTHENTICATE", h)
108- } else if len(s.channels) != 0 && c.Name == "multi-prefix" {
109+ if c.Name == "multi-prefix" {
110 // TODO merge NAMES commands
111 for channel := range s.channels {
112 s.out <- NewMessage("NAMES", channel)
113 }
114 }
115 }
116- case "NAK":
117- // do nothing
118 case "NEW":
119 for _, c := range ParseCaps(msg.Params[2]) {
120- s.availableCaps[c.Name] = c.Value
121- _, ok := SupportedCapabilities[c.Name]
122- if !ok {
123- continue
124+ if _, ok := SupportedCapabilities[c.Name]; ok {
125+ s.out <- NewMessage("CAP", "REQ", c.Name)
126 }
127- s.out <- NewMessage("CAP", "REQ", c.Name)
128- }
129-
130- _, ok := s.availableCaps["sasl"]
131- if s.acct == "" && ok {
132- // TODO authenticate
133+ // TODO authenticate if necessary
134 }
135 case "DEL":
136 for _, c := range ParseCaps(msg.Params[2]) {
137- delete(s.availableCaps, c.Name)
138 delete(s.enabledCaps, c.Name)
139 }
140 }
141+ // do nothing on LS and NAK
142 case "JOIN":
143 nickCf := s.Casemap(msg.Prefix.Name)
144 channelCf := s.Casemap(msg.Params[0])
145@@ -747,7 +710,7 @@ func (s *Session) handleRegistered(msg Message) Event {
146 if c, ok := s.channels[channelCf]; ok {
147 return ModeChangeEvent{
148 Channel: c.Name,
149- Mode: strings.Join(msg.Params[1:], " "),
150+ Mode: strings.Join(msg.Params[1:], " "),
151 }
152 }
153 case "PRIVMSG", "NOTICE":