Skip to content

Commit 7c37417

Browse files
authored
Query every available network interface (#32)
* wip query every interface that is both UP and MULTICAST'able * re-create netifs list before doing mdns.Query queries are re-created each loop. in case netif disappears, we won't use it next time (and caching will handle removal) clean-up timeouts, additional interval for queries clean-up control flow, split up main loop func a bit * not exported type * review * oops * review
1 parent 72e4b39 commit 7c37417

File tree

1 file changed

+126
-40
lines changed

1 file changed

+126
-40
lines changed

main.go

Lines changed: 126 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"os"
2727
"strconv"
2828
"strings"
29+
"sync"
2930
"time"
3031

3132
properties "github.com/arduino/go-properties-orderedmap"
@@ -49,8 +50,11 @@ const mdnsServiceName = "_arduino._tcp"
4950
// since the last time they've been found by an mDNS query.
5051
const portsTTL = time.Second * 60
5152

52-
// This is interval at which mDNS queries are made.
53-
const discoveryInterval = time.Second * 15
53+
// Interval at which we check available network interfaces and call mdns.Query()
54+
const queryInterval = time.Second * 30
55+
56+
// mdns.Query() will either exit early or timeout after this amount of time
57+
const queryTimeout = time.Second * 15
5458

5559
// IP address used to check if we're connected to a local network
5660
var ipv4Addr = &net.UDPAddr{
@@ -64,6 +68,12 @@ var ipv6Addr = &net.UDPAddr{
6468
Port: 5353,
6569
}
6670

71+
// QueryParam{} has to select which IP version(s) to use
72+
type connectivity struct {
73+
IPv4 bool
74+
IPv6 bool
75+
}
76+
6777
// MDNSDiscovery is the implementation of the network pluggable-discovery
6878
type MDNSDiscovery struct {
6979
cancelFunc func()
@@ -140,55 +150,131 @@ func (d *MDNSDiscovery) StartSync(eventCB discovery.EventCallback, errorCB disco
140150
ctx, cancel := context.WithCancel(context.Background())
141151
go func() {
142152
defer close(queriesChan)
153+
queryLoop(ctx, queriesChan)
154+
}()
155+
go func() {
156+
for entry := range queriesChan {
157+
if d.entriesChan != nil {
158+
d.entriesChan <- entry
159+
}
160+
}
161+
}()
162+
d.cancelFunc = cancel
163+
return nil
164+
}
143165

144-
disableIPv6 := false
145-
// Check if the current network supports IPv6
146-
mconn6, err := net.ListenMulticastUDP("udp6", nil, ipv6Addr)
166+
func queryLoop(ctx context.Context, queriesChan chan<- *mdns.ServiceEntry) {
167+
for {
168+
var interfaces []net.Interface
169+
var conn connectivity
170+
var wg sync.WaitGroup
171+
172+
interfaces, err := availableInterfaces()
147173
if err != nil {
148-
disableIPv6 = true
149-
} else {
150-
mconn6.Close()
174+
goto NEXT
151175
}
152176

153-
// We must check if we're connected to a local network, if we don't
154-
// the subsequent mDNS query would fail and return an error.
155-
mconn4, err := net.ListenMulticastUDP("udp4", nil, ipv4Addr)
156-
if err != nil {
177+
conn = checkConnectivity()
178+
if !conn.available() {
179+
goto NEXT
180+
}
181+
182+
wg.Add(len(interfaces))
183+
184+
for n := range interfaces {
185+
params := makeQueryParams(&interfaces[n], conn, queriesChan)
186+
go func() {
187+
defer wg.Done()
188+
mdns.Query(params)
189+
}()
190+
}
191+
192+
wg.Wait()
193+
194+
NEXT:
195+
select {
196+
case <-time.After(queryInterval):
197+
case <-ctx.Done():
157198
return
158199
}
159-
// If we managed to open a connection close it, mdns.Query opens
160-
// another one on the same IP address we use and it would fail
161-
// if we leave this open.
200+
}
201+
}
202+
203+
func (conn *connectivity) available() bool {
204+
return conn.IPv4 || conn.IPv6
205+
}
206+
207+
func checkConnectivity() connectivity {
208+
// We must check if we're connected to a local network, if we don't
209+
// the subsequent mDNS query would fail and return an error.
210+
// If we managed to open a connection close it, mdns.Query opens
211+
// another one on the same IP address we use and it would fail
212+
// if we leave this open.
213+
out := connectivity{
214+
IPv4: true,
215+
IPv6: true,
216+
}
217+
218+
// Check if the current network supports IPv6
219+
mconn6, err := net.ListenMulticastUDP("udp6", nil, ipv6Addr)
220+
if err != nil {
221+
out.IPv6 = false
222+
} else {
223+
mconn6.Close()
224+
}
225+
226+
// And the same for IPv4
227+
mconn4, err := net.ListenMulticastUDP("udp4", nil, ipv4Addr)
228+
if err != nil {
229+
out.IPv4 = false
230+
} else {
162231
mconn4.Close()
232+
}
233+
234+
return out
235+
}
236+
237+
func availableInterfaces() ([]net.Interface, error) {
238+
interfaces, err := net.Interfaces()
239+
if err != nil {
240+
return nil, err
241+
}
163242

164-
params := &mdns.QueryParam{
165-
Service: mdnsServiceName,
166-
Domain: "local",
167-
Timeout: discoveryInterval,
168-
Entries: queriesChan,
169-
WantUnicastResponse: false,
170-
DisableIPv6: disableIPv6,
243+
var out []net.Interface
244+
for _, netif := range interfaces {
245+
if netif.Flags&net.FlagUp == 0 {
246+
continue
171247
}
172-
for {
173-
if err := mdns.Query(params); err != nil {
174-
errorCB("mdns lookup error: " + err.Error())
175-
}
176-
select {
177-
default:
178-
case <-ctx.Done():
179-
return
180-
}
248+
249+
if netif.Flags&net.FlagMulticast == 0 {
250+
continue
181251
}
182-
}()
183-
go func() {
184-
for entry := range queriesChan {
185-
if d.entriesChan != nil {
186-
d.entriesChan <- entry
187-
}
252+
253+
if netif.HardwareAddr == nil {
254+
continue
188255
}
189-
}()
190-
d.cancelFunc = cancel
191-
return nil
256+
257+
out = append(out, netif)
258+
}
259+
260+
if len(out) == 0 {
261+
return nil, fmt.Errorf("no valid network interfaces")
262+
}
263+
264+
return out, nil
265+
}
266+
267+
func makeQueryParams(netif *net.Interface, conn connectivity, queriesChan chan<- *mdns.ServiceEntry) (params *mdns.QueryParam) {
268+
return &mdns.QueryParam{
269+
Service: mdnsServiceName,
270+
Domain: "local",
271+
Timeout: queryTimeout,
272+
Interface: netif,
273+
Entries: queriesChan,
274+
WantUnicastResponse: false,
275+
DisableIPv4: !conn.IPv4,
276+
DisableIPv6: !conn.IPv6,
277+
}
192278
}
193279

194280
func toDiscoveryPort(entry *mdns.ServiceEntry) *discovery.Port {

0 commit comments

Comments
 (0)