-
Notifications
You must be signed in to change notification settings - Fork 0
/
protocol.go
524 lines (443 loc) · 12.7 KB
/
protocol.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
package lib
import (
"encoding/gob"
"fmt"
"io"
"log"
"strings"
"time"
)
// Message types. Sent on the wire - do not reorder or delete types.
const (
SS_MSG_TYPE_UNKNOWN uint32 = iota
SS_MSG_TYPE_HELLO
SS_MSG_TYPE_BURST_COMPLETE
SS_MSG_TYPE_SYNC
SS_MSG_TYPE_CLIENT
SS_MSG_TYPE_SERVER
SS_MSG_TYPE_KILL
SS_MSG_TYPE_SPLIT
SS_MSG_TYPE_CHANNEL
SS_MSG_TYPE_CHANNEL_MODE
SS_MSG_TYPE_MEMBERSHIP
SS_MSG_TYPE_MEMBERSHIP_END
SS_MSG_TYPE_PM
SS_MSG_TYPE_CM
)
type SSKillReason uint8
const (
SS_KILL_REASON_QUIT SSKillReason = iota
SS_KILL_REASON_COLLISION
SS_KILL_REASON_SENDQ
SS_KILL_REASON_RECVQ
)
type ssMessageConstructor func() SSMessage
var constructorMap map[uint32]ssMessageConstructor
func init() {
constructorMap = make(map[uint32]ssMessageConstructor)
constructorMap[SS_MSG_TYPE_HELLO] = func() SSMessage {
return &SSHello{}
}
constructorMap[SS_MSG_TYPE_BURST_COMPLETE] = func() SSMessage {
return &SSBurstComplete{}
}
constructorMap[SS_MSG_TYPE_SYNC] = func() SSMessage {
return &SSSync{}
}
constructorMap[SS_MSG_TYPE_CLIENT] = func() SSMessage {
return &SSClient{}
}
constructorMap[SS_MSG_TYPE_SERVER] = func() SSMessage {
return &SSServer{}
}
constructorMap[SS_MSG_TYPE_KILL] = func() SSMessage {
return &SSKill{}
}
constructorMap[SS_MSG_TYPE_SPLIT] = func() SSMessage {
return &SSSplit{}
}
constructorMap[SS_MSG_TYPE_CHANNEL] = func() SSMessage {
return &SSChannel{}
}
constructorMap[SS_MSG_TYPE_MEMBERSHIP] = func() SSMessage {
return &SSMembership{}
}
constructorMap[SS_MSG_TYPE_MEMBERSHIP_END] = func() SSMessage {
return &SSMembershipEnd{}
}
constructorMap[SS_MSG_TYPE_PM] = func() SSMessage {
return &SSPrivateMessage{}
}
constructorMap[SS_MSG_TYPE_CM] = func() SSMessage {
return &SSChannelMessage{}
}
constructorMap[SS_MSG_TYPE_CHANNEL_MODE] = func() SSMessage {
return &SSChannelMode{}
}
}
var GobServerProtocolFactory ServerProtocolFactory = &gobServerProtocolFactory{}
// A Gossamer server-to-server message.
type SSMessage interface {
String() string
messageType() uint32
}
// Message header used to identify what message is being transmitted next.
type SSMessageHeader struct {
Type uint32
}
/// Introduction message sent by one server to another at the beginning of link.
type SSHello struct {
Protocol uint32
LocalTimeMs uint64
Name string
Description string
DefaultSubnet string
}
func (msg SSHello) String() string {
return fmt.Sprintf("hello(%d, %d, %s, %s, %s)", msg.Protocol, msg.LocalTimeMs, msg.Name, msg.Description, msg.DefaultSubnet)
}
func (msg SSHello) messageType() uint32 {
return SS_MSG_TYPE_HELLO
}
type SSBurstComplete struct {
Server string
}
func (msg SSBurstComplete) String() string {
return fmt.Sprintf("burstComplete(%s)", msg.Server)
}
func (msg SSBurstComplete) messageType() uint32 {
return SS_MSG_TYPE_BURST_COMPLETE
}
type SSSync struct {
Sequence uint32
Reply bool
Origin string
ReplyFrom string
}
func (msg SSSync) String() string {
if msg.Reply {
return fmt.Sprintf("syncReply(%s:%d, %s)", msg.Origin, msg.Sequence, msg.ReplyFrom)
} else {
return fmt.Sprintf("sync(%s:%d)", msg.Origin, msg.Sequence)
}
}
func (msg SSSync) messageType() uint32 {
return SS_MSG_TYPE_SYNC
}
type SSClient struct {
Subnet string
Server string
Nick, Ident, Vident, Host, Vhost string
Ip, Vip string
Gecos string
Ts time.Time
}
func (msg SSClient) String() string {
return fmt.Sprintf("client(%s, %s, %s, ident(%s, %s), host(%s, %s), ip(%s, %s), %s, ts(%v))", msg.Subnet, msg.Server, msg.Nick, msg.Ident, msg.Vident, msg.Host, msg.Vhost, msg.Ip, msg.Vip, msg.Gecos, msg.Ts)
}
func (msg SSClient) messageType() uint32 {
return SS_MSG_TYPE_CLIENT
}
type SSServer struct {
Name string
Desc string
Via string
}
func (msg SSServer) String() string {
return fmt.Sprintf("server(%s, %s, via(%s))", msg.Name, msg.Desc, msg.Via)
}
func (msg SSServer) messageType() uint32 {
return SS_MSG_TYPE_SERVER
}
type SSKill struct {
// Id of the client being killed.
Id SSClientId
// Server doing the killing.
Server string
// Whether this kill message is instructional (server A telling server B to kill B's client)
// or authoritative (server B broadcasting a kill of its own client)
Authority bool
// If this kill was initiated by another client, who it was.
By SSClientId
// Textual reason for the kill.
Reason string
// Numerical code indicating the reason for the kill (for statistics, etc).
ReasonCode SSKillReason
}
func (msg SSKill) String() string {
if msg.Authority {
return fmt.Sprintf("kill(id(%v), server(%s), by(%v), reason(%s))", msg.Id, msg.Server, msg.By, msg.Server)
} else {
return fmt.Sprintf("kill?(id(%v), server(%s), by(%v), reason(%s))", msg.Id, msg.Server, msg.By, msg.Server)
}
}
func (msg SSKill) messageType() uint32 {
return SS_MSG_TYPE_KILL
}
type SSSplit struct {
Server string
Reason string
}
func (msg SSSplit) messageType() uint32 {
return SS_MSG_TYPE_SPLIT
}
func (msg SSSplit) String() string {
return fmt.Sprintf("split(%s, %s)", msg.Server, msg.Reason)
}
type SSChannel struct {
Name string
Subnet string
Ts time.Time
Members []*SSMembership
}
func (msg SSChannel) messageType() uint32 {
return SS_MSG_TYPE_CHANNEL
}
func (msg SSChannel) String() string {
members := make([]string, len(msg.Members))
for idx, member := range msg.Members {
members[idx] = member.String()
}
return fmt.Sprintf("channel(%s, %s, %s, [%s])", msg.Name, msg.Subnet, msg.Ts, strings.Join(members, ", "))
}
type SSMembership struct {
Client SSClientId
Channel SSChannelId
Ts time.Time
IsOwner, IsAdmin, IsOp, IsHalfop, IsVoice bool
}
func (msg SSMembership) messageType() uint32 {
return SS_MSG_TYPE_MEMBERSHIP
}
func (msg SSMembership) String() string {
modes := make([]string, 0, 5)
if msg.IsOwner {
modes = append(modes, "owner")
}
if msg.IsAdmin {
modes = append(modes, "admin")
}
if msg.IsOp {
modes = append(modes, "op")
}
if msg.IsHalfop {
modes = append(modes, "halfop")
}
if msg.IsVoice {
modes = append(modes, "voice")
}
return fmt.Sprintf("membership(%s, %s, [%s])", msg.Channel, msg.Client, strings.Join(modes, ", "))
}
type SSPrivateMessage struct {
From SSClientId
To SSClientId
Message string
}
func (msg SSPrivateMessage) messageType() uint32 {
return SS_MSG_TYPE_PM
}
func (msg SSPrivateMessage) String() string {
return fmt.Sprintf("msg(%s -> %s, %s)", msg.From, msg.To, msg.Message)
}
type SSChannelMessage struct {
From SSClientId
To SSChannelId
Message string
}
func (msg SSChannelMessage) messageType() uint32 {
return SS_MSG_TYPE_CHANNEL
}
func (msg SSChannelMessage) String() string {
return fmt.Sprintf("msg(%s -> %s, %s", msg.From, msg.To, msg.Message)
}
type SSMembershipEnd struct {
Channel SSChannelId
Client SSClientId
Reason string
}
func (msg SSMembershipEnd) messageType() uint32 {
return SS_MSG_TYPE_MEMBERSHIP_END
}
func (msg SSMembershipEnd) String() string {
return fmt.Sprintf("part(%s, %s, %s)", msg.Channel, msg.Client, msg.Reason)
}
type SSModeDelta uint8
const (
SS_MODE_UNCHANGED SSModeDelta = iota
SS_MODE_ADDED
SS_MODE_REMOVED
)
func SSModeDeltaFromModeDelta(value ModeDelta) SSModeDelta {
switch value {
case MODE_UNCHANGED:
return SS_MODE_UNCHANGED
case MODE_ADDED:
return SS_MODE_ADDED
case MODE_REMOVED:
return SS_MODE_REMOVED
default:
panic("Unknown ModeDelta")
}
}
func (value SSModeDelta) ToModeDelta() ModeDelta {
switch value {
case SS_MODE_UNCHANGED:
return MODE_UNCHANGED
case SS_MODE_ADDED:
return MODE_ADDED
case SS_MODE_REMOVED:
return MODE_REMOVED
default:
panic("Unknown SSModeDelta")
}
}
type SSMemberModeDelta struct {
Client SSClientId
IsOwner, IsAdmin, IsOp, IsHalfop, IsVoice SSModeDelta
}
func SSMemberModeDeltaFromMemberModeDelta(value MemberModeDelta) SSMemberModeDelta {
return SSMemberModeDelta{
Client: value.Client.Id(),
IsOwner: SSModeDeltaFromModeDelta(value.IsOwner),
IsAdmin: SSModeDeltaFromModeDelta(value.IsAdmin),
IsOp: SSModeDeltaFromModeDelta(value.IsOp),
IsHalfop: SSModeDeltaFromModeDelta(value.IsHalfop),
IsVoice: SSModeDeltaFromModeDelta(value.IsVoice),
}
}
func (delta SSMemberModeDelta) ToMemberModeDelta(n *Node) (MemberModeDelta, bool) {
client, found := n.lookupClientById(delta.Client)
if !found {
return MemberModeDelta{}, false
}
return MemberModeDelta{
Client: client,
IsOwner: delta.IsOwner.ToModeDelta(),
IsAdmin: delta.IsAdmin.ToModeDelta(),
IsOp: delta.IsOp.ToModeDelta(),
IsHalfop: delta.IsHalfop.ToModeDelta(),
IsVoice: delta.IsVoice.ToModeDelta(),
}, true
}
type SSChannelModeDelta struct {
TopicProtected, NoExternalMessages, Moderated, Secret SSModeDelta
Limit, Key SSModeDelta
LimitValue uint32
KeyValue string
}
func ChannelModeDeltaToSSChannelModeDelta(value ChannelModeDelta) SSChannelModeDelta {
return SSChannelModeDelta{
Key: SSModeDeltaFromModeDelta(value.Key),
Limit: SSModeDeltaFromModeDelta(value.Limit),
Moderated: SSModeDeltaFromModeDelta(value.Moderated),
NoExternalMessages: SSModeDeltaFromModeDelta(value.NoExternalMessages),
Secret: SSModeDeltaFromModeDelta(value.Secret),
TopicProtected: SSModeDeltaFromModeDelta(value.TopicProtected),
KeyValue: value.KeyValue,
LimitValue: value.LimitValue,
}
}
func (delta SSChannelModeDelta) ToChannelModeDelta() ChannelModeDelta {
return ChannelModeDelta{
Key: delta.Key.ToModeDelta(),
Limit: delta.Limit.ToModeDelta(),
Moderated: delta.Moderated.ToModeDelta(),
NoExternalMessages: delta.NoExternalMessages.ToModeDelta(),
Secret: delta.Secret.ToModeDelta(),
TopicProtected: delta.TopicProtected.ToModeDelta(),
KeyValue: delta.KeyValue,
LimitValue: delta.LimitValue,
}
}
type SSChannelMode struct {
From SSClientId
Channel SSChannelId
Mode SSChannelModeDelta
MemberMode []SSMemberModeDelta
}
func (msg SSChannelMode) messageType() uint32 {
return SS_MSG_TYPE_CHANNEL_MODE
}
func (msg SSChannelMode) String() string {
return fmt.Sprintf("mode(%s, %s)", msg.Channel, msg.From)
}
// TODO Why does SSClientId have Server?
type SSClientId struct {
Server string
Subnet string
Nick string
}
func (id SSClientId) String() string {
return fmt.Sprintf("%s:%s@%s", id.Subnet, id.Nick, id.Server)
}
type SSChannelId struct {
Subnet string
Name string
}
func (id SSChannelId) String() string {
return fmt.Sprintf("#%s:%s", id.Subnet, id.Name)
}
type ServerProtocolFactory interface {
Reader(reader io.Reader) ServerProtocolReader
Writer(writer io.Writer) ServerProtocolWriter
}
// A Gossamer server-to-server message reader.
type ServerProtocolReader interface {
ReadMessage() (msg SSMessage, err error)
}
type gobServerProtocolReader struct {
decoder *gob.Decoder
}
// Construct a ServerProtcolReader from the underlying io.Reader which interprets
// incoming data using the gob encoding.
func NewGobServerProtocolReader(reader io.Reader) ServerProtocolReader {
dec := gob.NewDecoder(reader)
return &gobServerProtocolReader{dec}
}
func (spr *gobServerProtocolReader) ReadMessage() (msg SSMessage, err error) {
var header SSMessageHeader
err = spr.decoder.Decode(&header)
if err != nil {
return
}
ctor, ok := constructorMap[header.Type]
if !ok {
log.Fatalf("Unknown message type: %d", header.Type)
}
msg = ctor()
err = spr.decoder.Decode(msg)
if err != nil {
msg = nil
}
return
}
// A Gossamer server-to-server message writer.
type ServerProtocolWriter interface {
WriteMessage(msg SSMessage) error
}
type gobServerProtocolWriter struct {
encoder *gob.Encoder
}
// Construct a ServerProtocolWriter from the underlying io.Writer which serializes
// outgoing messages using the gob encoding.
func NewGobServerProtocolWriter(writer io.Writer) ServerProtocolWriter {
enc := gob.NewEncoder(writer)
return &gobServerProtocolWriter{enc}
}
func (spw *gobServerProtocolWriter) WriteMessage(msg SSMessage) (err error) {
var header SSMessageHeader
header.Type = msg.messageType()
err = spw.encoder.Encode(header)
if err != nil {
return
}
err = spw.encoder.Encode(msg)
return
}
type gobServerProtocolFactory struct{}
func (gspf gobServerProtocolFactory) Reader(reader io.Reader) ServerProtocolReader {
return NewGobServerProtocolReader(reader)
}
func (gspf gobServerProtocolFactory) Writer(writer io.Writer) ServerProtocolWriter {
return NewGobServerProtocolWriter(writer)
}