Skip to content

Commit 5367060

Browse files
committed
Use multicast server from game-controller
Listening on all interfaces for multicast traffic seems to have side-effects, so cycling through them until messages are received is more robust.
1 parent a4da55c commit 5367060

File tree

3 files changed

+70
-57
lines changed

3 files changed

+70
-57
lines changed

cmd/ssl-status-board/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func main() {
2323
}
2424

2525
refereeBoard := board.NewBoard(config.RefereeConnection)
26-
refereeBoard.MulticastReceiver.SkipInterfaces = config.RefereeConnection.SkipInterfaces
26+
refereeBoard.MulticastServer.SkipInterfaces = config.RefereeConnection.SkipInterfaces
2727
refereeBoard.Start()
2828
http.HandleFunc(config.RefereeConnection.SubscribePath, refereeBoard.WsHandler)
2929

pkg/board/board.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,28 @@ import (
1111

1212
// Board contains the state of this referee board
1313
type Board struct {
14-
cfg RefereeConfig
15-
refereeData []byte
16-
mutex sync.Mutex
17-
MulticastReceiver *sslnet.MulticastReceiver
14+
cfg RefereeConfig
15+
refereeData []byte
16+
mutex sync.Mutex
17+
MulticastServer *sslnet.MulticastServer
1818
}
1919

2020
// NewBoard creates a new referee board
2121
func NewBoard(cfg RefereeConfig) (b *Board) {
2222
b = new(Board)
2323
b.cfg = cfg
24-
b.MulticastReceiver = sslnet.NewMulticastReceiver(b.handlingMessage)
24+
b.MulticastServer = sslnet.NewMulticastServer(b.handlingMessage)
2525
return
2626
}
2727

2828
// Start listening for messages
2929
func (b *Board) Start() {
30-
b.MulticastReceiver.Start(b.cfg.MulticastAddress)
30+
b.MulticastServer.Start(b.cfg.MulticastAddress)
3131
}
3232

3333
// Stop listening for messages
3434
func (b *Board) Stop() {
35-
b.MulticastReceiver.Stop()
35+
b.MulticastServer.Stop()
3636
}
3737

3838
func (b *Board) handlingMessage(data []byte) {

pkg/sslnet/multicast_receiver.go

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,64 +9,74 @@ import (
99

1010
const maxDatagramSize = 8192
1111

12-
type MulticastReceiver struct {
13-
activeIfis map[string]bool
14-
connections []*net.UDPConn
12+
type MulticastServer struct {
13+
connection *net.UDPConn
1514
running bool
1615
consumer func([]byte)
1716
mutex sync.Mutex
1817
SkipInterfaces []string
18+
Verbose bool
1919
}
2020

21-
func NewMulticastReceiver(consumer func([]byte)) (r *MulticastReceiver) {
22-
r = new(MulticastReceiver)
23-
r.activeIfis = map[string]bool{}
21+
func NewMulticastServer(consumer func([]byte)) (r *MulticastServer) {
22+
r = new(MulticastServer)
2423
r.consumer = consumer
2524
return
2625
}
2726

28-
func (r *MulticastReceiver) Start(multicastAddress string) {
27+
func (r *MulticastServer) Start(multicastAddress string) {
2928
r.running = true
3029
go r.receive(multicastAddress)
3130
}
3231

33-
func (r *MulticastReceiver) Stop() {
32+
func (r *MulticastServer) Stop() {
3433
r.mutex.Lock()
3534
defer r.mutex.Unlock()
3635
r.running = false
37-
for _, c := range r.connections {
38-
if err := c.Close(); err != nil {
39-
log.Println("Could not close connection: ", err)
40-
}
36+
if err := r.connection.Close(); err != nil {
37+
log.Println("Could not close connection: ", err)
4138
}
4239
}
4340

44-
func (r *MulticastReceiver) receive(multicastAddress string) {
41+
func (r *MulticastServer) receive(multicastAddress string) {
42+
log.Printf("Receiving on %v", multicastAddress)
43+
var currentIfiIdx = 0
4544
for r.isRunning() {
46-
ifis, _ := net.Interfaces()
47-
for _, ifi := range ifis {
48-
if ifi.Flags&net.FlagMulticast == 0 || // No multicast support
49-
r.skipInterface(ifi.Name) {
50-
continue
51-
}
52-
r.mutex.Lock()
53-
if _, ok := r.activeIfis[ifi.Name]; !ok {
54-
// interface not active, (re-)start receiving
55-
go r.receiveOnInterface(multicastAddress, ifi)
56-
}
57-
r.mutex.Unlock()
45+
ifis := r.interfaces()
46+
currentIfiIdx = currentIfiIdx % len(ifis)
47+
ifi := ifis[currentIfiIdx]
48+
r.receiveOnInterface(multicastAddress, ifi)
49+
currentIfiIdx++
50+
if currentIfiIdx >= len(ifis) {
51+
// cycled though all interfaces once, make a short break to avoid producing endless log messages
52+
time.Sleep(1 * time.Second)
5853
}
59-
time.Sleep(1 * time.Second)
6054
}
6155
}
6256

63-
func (r *MulticastReceiver) isRunning() bool {
57+
func (r *MulticastServer) isRunning() bool {
6458
r.mutex.Lock()
6559
defer r.mutex.Unlock()
6660
return r.running
6761
}
6862

69-
func (r *MulticastReceiver) skipInterface(ifiName string) bool {
63+
func (r *MulticastServer) interfaces() (interfaces []net.Interface) {
64+
interfaces = []net.Interface{}
65+
ifis, err := net.Interfaces()
66+
if err != nil {
67+
log.Println("Could not get available interfaces: ", err)
68+
}
69+
for _, ifi := range ifis {
70+
if ifi.Flags&net.FlagMulticast == 0 || // No multicast support
71+
r.skipInterface(ifi.Name) {
72+
continue
73+
}
74+
interfaces = append(interfaces, ifi)
75+
}
76+
return
77+
}
78+
79+
func (r *MulticastServer) skipInterface(ifiName string) bool {
7080
for _, skipIfi := range r.SkipInterfaces {
7181
if skipIfi == ifiName {
7282
return true
@@ -75,52 +85,55 @@ func (r *MulticastReceiver) skipInterface(ifiName string) bool {
7585
return false
7686
}
7787

78-
func (r *MulticastReceiver) receiveOnInterface(multicastAddress string, ifi net.Interface) {
88+
func (r *MulticastServer) receiveOnInterface(multicastAddress string, ifi net.Interface) {
7989
addr, err := net.ResolveUDPAddr("udp", multicastAddress)
8090
if err != nil {
8191
log.Printf("Could resolve multicast address %v: %v", multicastAddress, err)
8292
return
8393
}
8494

85-
listener, err := net.ListenMulticastUDP("udp", &ifi, addr)
95+
r.connection, err = net.ListenMulticastUDP("udp", &ifi, addr)
8696
if err != nil {
8797
log.Printf("Could not listen at %v: %v", multicastAddress, err)
8898
return
8999
}
90100

91-
if err := listener.SetReadBuffer(maxDatagramSize); err != nil {
101+
if err := r.connection.SetReadBuffer(maxDatagramSize); err != nil {
92102
log.Println("Could not set read buffer: ", err)
93103
}
94104

95-
r.mutex.Lock()
96-
r.connections = append(r.connections, listener)
97-
r.activeIfis[ifi.Name] = true
98-
r.mutex.Unlock()
99-
100-
log.Printf("Listening on %s (%s)", multicastAddress, ifi.Name)
105+
if r.Verbose {
106+
log.Printf("Listening on %s (%s)", multicastAddress, ifi.Name)
107+
}
101108

109+
first := true
102110
data := make([]byte, maxDatagramSize)
103111
for {
104-
n, _, err := listener.ReadFrom(data)
112+
if err := r.connection.SetDeadline(time.Now().Add(300 * time.Millisecond)); err != nil {
113+
log.Println("Could not set deadline on connection: ", err)
114+
}
115+
n, _, err := r.connection.ReadFromUDP(data)
105116
if err != nil {
106-
log.Println("ReadFromUDP failed:", err)
117+
if r.Verbose {
118+
log.Println("ReadFromUDP failed:", err)
119+
}
107120
break
108121
}
109122

123+
if first {
124+
log.Printf("Got first data packets from %s (%s)", multicastAddress, ifi.Name)
125+
first = false
126+
}
127+
110128
r.consumer(data[:n])
111129
}
112130

113-
log.Printf("Stop listening on %s (%s)", multicastAddress, ifi.Name)
131+
if r.Verbose {
132+
log.Printf("Stop listening on %s (%s)", multicastAddress, ifi.Name)
133+
}
114134

115-
if err := listener.Close(); err != nil {
135+
if err := r.connection.Close(); err != nil {
116136
log.Println("Could not close listener: ", err)
117137
}
118-
r.mutex.Lock()
119-
delete(r.activeIfis, ifi.Name)
120-
for i, c := range r.connections {
121-
if c == listener {
122-
r.connections = append(r.connections[:i], r.connections[i+1:]...)
123-
}
124-
}
125-
r.mutex.Unlock()
138+
return
126139
}

0 commit comments

Comments
 (0)