client: use server interface as multicast interface (#762) (#847)

this fixes most errors "found no interface that is multicast-capable
and can communicate with IP".
This commit is contained in:
Alessandro Ros
2025-08-04 15:17:49 +02:00
committed by GitHub
parent f23a365cc5
commit e9db56f913
4 changed files with 73 additions and 30 deletions

View File

@@ -252,6 +252,48 @@ func supportsGetParameter(header base.Header) bool {
return false
}
func interfaceOfConn(c net.Conn) (*net.Interface, error) {
var localIP net.IP
switch addr := c.LocalAddr().(type) {
case *net.TCPAddr:
localIP = addr.IP
case *net.UDPAddr:
localIP = addr.IP
default:
return nil, fmt.Errorf("unknown connection type: %T", c.LocalAddr())
}
interfaces, err := net.Interfaces()
if err != nil {
return nil, err
}
for _, iface := range interfaces {
var addrs []net.Addr
addrs, err = iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip != nil && ip.Equal(localIP) {
return &iface, nil
}
}
}
return nil, fmt.Errorf("no interface found for IP %s", localIP)
}
type clientState int
const (
@@ -1796,9 +1838,16 @@ func (c *Client) doSetup(
remoteIP = c.nconn.RemoteAddr().(*net.TCPAddr).IP
}
var intf *net.Interface
intf, err = interfaceOfConn(c.nconn)
if err != nil {
cm.close()
return nil, err
}
err = cm.createUDPListeners(
true,
remoteIP,
intf,
net.JoinHostPort(thRes.Destination.String(), strconv.FormatInt(int64(thRes.Ports[0]), 10)),
net.JoinHostPort(thRes.Destination.String(), strconv.FormatInt(int64(thRes.Ports[1]), 10)),
)

View File

@@ -101,17 +101,17 @@ func (cm *clientMedia) close() {
}
func (cm *clientMedia) createUDPListeners(
multicastEnable bool,
multicastSourceIP net.IP,
multicast bool,
multicastInterface *net.Interface,
rtpAddress string,
rtcpAddress string,
) error {
if rtpAddress != ":0" {
l1 := &clientUDPListener{
c: cm.c,
multicastEnable: multicastEnable,
multicastSourceIP: multicastSourceIP,
address: rtpAddress,
c: cm.c,
multicast: multicast,
multicastInterface: multicastInterface,
address: rtpAddress,
}
err := l1.initialize()
if err != nil {
@@ -119,10 +119,10 @@ func (cm *clientMedia) createUDPListeners(
}
l2 := &clientUDPListener{
c: cm.c,
multicastEnable: multicastEnable,
multicastSourceIP: multicastSourceIP,
address: rtcpAddress,
c: cm.c,
multicast: multicast,
multicastInterface: multicastInterface,
address: rtcpAddress,
}
err = l2.initialize()
if err != nil {
@@ -146,10 +146,8 @@ func (cm *clientMedia) createUDPListeners(
rtcpPort := rtpPort + 1
cm.udpRTPListener = &clientUDPListener{
c: cm.c,
multicastEnable: false,
multicastSourceIP: nil,
address: net.JoinHostPort("", strconv.FormatInt(int64(rtpPort), 10)),
c: cm.c,
address: net.JoinHostPort("", strconv.FormatInt(int64(rtpPort), 10)),
}
err = cm.udpRTPListener.initialize()
if err != nil {
@@ -158,10 +156,8 @@ func (cm *clientMedia) createUDPListeners(
}
cm.udpRTCPListener = &clientUDPListener{
c: cm.c,
multicastEnable: false,
multicastSourceIP: nil,
address: net.JoinHostPort("", strconv.FormatInt(int64(rtcpPort), 10)),
c: cm.c,
address: net.JoinHostPort("", strconv.FormatInt(int64(rtcpPort), 10)),
}
err = cm.udpRTCPListener.initialize()
if err != nil {

View File

@@ -29,10 +29,10 @@ type packetConn interface {
}
type clientUDPListener struct {
c *Client
multicastEnable bool
multicastSourceIP net.IP
address string
c *Client
multicast bool
multicastInterface *net.Interface
address string
pc packetConn
readFunc readFunc
@@ -47,13 +47,9 @@ type clientUDPListener struct {
}
func (u *clientUDPListener) initialize() error {
if u.multicastEnable {
intf, err := multicast.InterfaceForSource(u.multicastSourceIP)
if err != nil {
return err
}
u.pc, err = multicast.NewSingleConn(intf, u.address, u.c.ListenPacket)
if u.multicast {
var err error
u.pc, err = multicast.NewSingleConn(u.multicastInterface, u.address, u.c.ListenPacket)
if err != nil {
return err
}

View File

@@ -13,6 +13,8 @@ type Conn interface {
}
// InterfaceForSource returns a multicast-capable interface that can communicate with given IP.
//
// Deprecated: not used anymore.
func InterfaceForSource(ip net.IP) (*net.Interface, error) {
if ip.Equal(net.ParseIP("127.0.0.1")) {
return nil, fmt.Errorf("IP 127.0.0.1 can't be used as source of a multicast stream. Use the LAN IP of your PC")