Skip to content

Commit 95350e8

Browse files
committed
An option to use the system multicast interface
- ssdp.SetMulticastSystemAssignedInterface() - ssdp.GetMulticastSystemAssignedInterface()
1 parent 307873a commit 95350e8

File tree

3 files changed

+68
-25
lines changed

3 files changed

+68
-25
lines changed

internal/multicast/interface.go

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ type InterfacesProviderFunc func() []net.Interface
1010
// If no provider are given, all possible interfaces will be used.
1111
var InterfacesProvider InterfacesProviderFunc
1212

13+
// SystemAssignedInterface indicates use the system assigned multicast interface or not.
14+
// InterfacesProvider will be ignored when this is true.
15+
var SystemAssignedInterface bool = false
16+
1317
// interfaces gets list of net.Interface to multicast UDP packet.
1418
func interfaces() ([]net.Interface, error) {
1519
if p := InterfacesProvider; p != nil {

internal/multicast/multicast.go

+44-23
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type Conn struct {
2222

2323
type connConfig struct {
2424
ttl int
25+
sysIf bool
2526
}
2627

2728
// Listen starts to receiving multicast messages.
@@ -42,16 +43,11 @@ func Listen(r *AddrResolver, opts ...ConnOption) (*Conn, error) {
4243
return nil, err
4344
}
4445
// configure socket to use with multicast.
45-
pconn, iflist, err := newIPv4MulticastConn(conn)
46+
pconn, ifplist, err := newIPv4MulticastConn(conn, cfg.sysIf)
4647
if err != nil {
4748
conn.Close()
4849
return nil, err
4950
}
50-
// store interfaces by pointer.
51-
ifplist := make([]*net.Interface, 0, len(iflist))
52-
for i := range iflist {
53-
ifplist = append(ifplist, &iflist[i])
54-
}
5551
// set TTL
5652
if cfg.ttl > 0 {
5753
err := pconn.SetTTL(cfg.ttl)
@@ -67,35 +63,58 @@ func Listen(r *AddrResolver, opts ...ConnOption) (*Conn, error) {
6763
}, nil
6864
}
6965

70-
func newIPv4MulticastConn(conn *net.UDPConn) (*ipv4.PacketConn, []net.Interface, error) {
71-
iflist, err := interfaces()
72-
if err != nil {
73-
return nil, nil, err
66+
// newIPv4MulticastConn create a new multicast connection.
67+
// 2nd return parameter will be nil when sysIf is true.
68+
func newIPv4MulticastConn(conn *net.UDPConn, sysIf bool) (*ipv4.PacketConn, []*net.Interface, error) {
69+
// sysIf: use system assigned multicast interface.
70+
// the empty iflist indicate it.
71+
var ifplist []*net.Interface
72+
if !sysIf {
73+
list, err := interfaces()
74+
if err != nil {
75+
return nil, nil, err
76+
}
77+
ifplist = make([]*net.Interface, 0, len(list))
78+
for i := range list {
79+
ifplist = append(ifplist, &list[i])
80+
}
7481
}
7582
addr, err := SendAddr()
7683
if err != nil {
7784
return nil, nil, err
7885
}
79-
pconn, err := joinGroupIPv4(conn, iflist, addr)
86+
pconn, err := joinGroupIPv4(conn, ifplist, addr)
8087
if err != nil {
8188
return nil, nil, err
8289
}
83-
return pconn, iflist, nil
90+
return pconn, ifplist, nil
8491
}
8592

8693
// joinGroupIPv4 makes the connection join to a group on interfaces.
87-
func joinGroupIPv4(conn *net.UDPConn, iflist []net.Interface, gaddr net.Addr) (*ipv4.PacketConn, error) {
94+
// This trys to use system assigned when iflist is nil or empty.
95+
func joinGroupIPv4(conn *net.UDPConn, ifplist []*net.Interface, gaddr net.Addr) (*ipv4.PacketConn, error) {
8896
wrap := ipv4.NewPacketConn(conn)
8997
wrap.SetMulticastLoopback(true)
98+
99+
// try to use the system assigned multicast interface when iflist is empty.
100+
if len(ifplist) == 0 {
101+
if err := wrap.JoinGroup(nil, gaddr); err != nil {
102+
ssdplog.Printf("failed to join group %s on system assigned multicast interface: %s", gaddr.String(), err)
103+
return nil, errors.New("no system assigned multicast interfaces had joined to group")
104+
}
105+
ssdplog.Printf("joined group %s on system assigned multicast interface", gaddr.String())
106+
return wrap, nil
107+
}
108+
90109
// add interfaces to multicast group.
91110
joined := 0
92-
for _, ifi := range iflist {
93-
if err := wrap.JoinGroup(&ifi, gaddr); err != nil {
94-
ssdplog.Printf("failed to join group %s on %s: %s", gaddr.String(), ifi.Name, err)
111+
for _, ifp := range ifplist {
112+
if err := wrap.JoinGroup(ifp, gaddr); err != nil {
113+
ssdplog.Printf("failed to join group %s on %s: %s", gaddr.String(), ifp.Name, err)
95114
continue
96115
}
97116
joined++
98-
ssdplog.Printf("joined group %s on %s (#%d)", gaddr.String(), ifi.Name, ifi.Index)
117+
ssdplog.Printf("joined group %s on %s (#%d)", gaddr.String(), ifp.Name, ifp.Index)
99118
}
100119
if joined == 0 {
101120
return nil, errors.New("no interfaces had joined to group")
@@ -117,12 +136,6 @@ type DataProvider interface {
117136
Bytes(*net.Interface) []byte
118137
}
119138

120-
//type multicastDataProviderFunc func(*net.Interface) []byte
121-
//
122-
//func (f multicastDataProviderFunc) Bytes(ifi *net.Interface) []byte {
123-
// return f(ifi)
124-
//}
125-
126139
type BytesDataProvider []byte
127140

128141
func (b BytesDataProvider) Bytes(ifi *net.Interface) []byte {
@@ -131,9 +144,11 @@ func (b BytesDataProvider) Bytes(ifi *net.Interface) []byte {
131144

132145
// WriteTo sends a multicast message to interfaces.
133146
func (mc *Conn) WriteTo(dataProv DataProvider, to net.Addr) (int, error) {
147+
// Send a multicast message directory when recipient "to" address is not multicast.
134148
if uaddr, ok := to.(*net.UDPAddr); ok && !uaddr.IP.IsMulticast() {
135149
return mc.writeToIfi(dataProv, to, nil)
136150
}
151+
// Send a multicast message to all interfaces (iflist).
137152
sum := 0
138153
for _, ifp := range mc.ifps {
139154
n, err := mc.writeToIfi(dataProv, to, ifp)
@@ -197,3 +212,9 @@ func ConnTTL(ttl int) ConnOption {
197212
cfg.ttl = ttl
198213
})
199214
}
215+
216+
func ConnSystemAssginedInterface() ConnOption {
217+
return connOptFunc(func(cfg *connConfig) {
218+
cfg.sysIf = true
219+
})
220+
}

ssdp.go

+20-2
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,36 @@ func SetMulticastSendAddrIPv4(addr string) error {
3636
return multicast.SetSendAddrIPv4(addr)
3737
}
3838

39-
var multicastTTL int
40-
4139
func defaultConnOpts() []multicast.ConnOption {
4240
var opts []multicast.ConnOption
4341
if multicastTTL > 0 {
4442
opts = append(opts, multicast.ConnTTL(multicastTTL))
4543
}
44+
if multicastSystemAssignedInterface {
45+
opts = append(opts, multicast.ConnSystemAssginedInterface())
46+
}
4647
return opts
4748
}
4849

50+
var multicastTTL int
51+
4952
// SetMulticastTTL sets default TTL of SSDP's UDP packets.
5053
// 0 default, 1 or greater set TTL.
5154
func SetMulticastTTL(ttl int) {
5255
multicastTTL = ttl
5356
}
57+
58+
var multicastSystemAssignedInterface bool
59+
60+
// SetMulticastSystemAssignedInterface updates state whether using the system
61+
// assigned multicast interface or provided interfaces.
62+
// Default is "false", it uses provided interface (see Interfaces also).
63+
func SetMulticastSystemAssignedInterface(enable bool) {
64+
multicastSystemAssignedInterface = enable
65+
}
66+
67+
// GetMulticastSystemAssignedInterface returns state using the system assigned
68+
// multicast interface or provided interfaces.
69+
func GetMulticastSystemAssignedInterface() bool {
70+
return multicastSystemAssignedInterface
71+
}

0 commit comments

Comments
 (0)