forked from vishvananda/go-netlink
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhandler.go
86 lines (77 loc) · 2.15 KB
/
handler.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
package netlink
/*
Copyright (c) 2011, Abneptis LLC. All rights reserved.
Original Author: James D. Nurmi <[email protected]>
See LICENSE for details
*/
//import "log"
import (
"bufio"
"errors"
)
import "fmt"
import "sync"
// A handler implements a simple Mux for netlink messages, ensuring
// each query gets a unique sequence number and a channel to collect responses.
type Handler struct {
sock *Socket
recipients map[uint32]chan Message
next_seq uint32
lock sync.Mutex
}
// Used as an atomic counter for sequence numbering.
// No check is made to see that sequences aren't still in use on roll-over.
func (self *Handler) Seq() (out uint32) {
self.lock.Lock()
out = self.next_seq
self.next_seq++
self.lock.Unlock()
return
}
func NewHandler(sock *Socket) *Handler {
return &Handler{sock: sock, recipients: map[uint32]chan Message{}, next_seq: 1}
}
// Send a message. If SequenceNumber is unset, Seq() will be used
// to generate one.
func (self *Handler) Query(msg Message, l int) (ch chan Message, err error) {
if msg.Header.MessageSequence() == 0 {
msg.Header.SetMessageSequence(self.Seq())
}
ob, err := msg.MarshalNetlink()
if err == nil {
ch = make(chan Message, l)
self.recipients[msg.Header.MessageSequence()] = ch
_, err = self.sock.Write(ob)
}
return
}
// Usually called in a goroutine, Start spawns a thread
// that demux's incoming netlink responses.
// Echan is used to report internal netlink errors, and may
// be set to nil (but you will likely miss bugs!)
func (self *Handler) Start(echan chan error) {
r := bufio.NewReader(self.sock)
for {
msg, err := ReadMessage(r)
if err == nil {
if self.recipients[msg.Header.MessageSequence()] == nil {
if nil != echan {
echan <- errors.New(fmt.Sprintf("GoNetlink: No handler found for seq %d",
msg.Header.MessageSequence()))
}
continue
} else {
self.recipients[msg.Header.MessageSequence()] <- *msg
if msg.Header.MessageFlags()&NLM_F_MULTI == 0 {
close(self.recipients[msg.Header.MessageSequence()])
delete(self.recipients, msg.Header.MessageSequence())
}
}
} else {
if nil != echan {
echan <- err
}
}
}
return
}