channel.go raw

   1  // Package multicast provides a UDP multicast connection with an in-process multicast interface for sending and
   2  // receiving.
   3  //
   4  // In order to allow processes on the same machine (windows) to receive the messages this code enables multicast
   5  // loopback. It is up to the consuming library to discard messages it sends. This is only necessary because the net
   6  // standard library disables loopback by default though on windows this takes effect whereas on unix platforms it does
   7  // not.
   8  //
   9  // This code was derived from the information found here:
  10  // https://stackoverflow.com/questions/43109552/how-to-set-ip-multicast-loop-on-multicast-udpconn-in-golang
  11  
  12  package multicast
  13  
  14  import (
  15  	"net"
  16  	
  17  	"golang.org/x/net/ipv4"
  18  	
  19  	"github.com/p9c/p9/pkg/util/routeable"
  20  )
  21  
  22  func Conn(port int) (conn *net.UDPConn, e error) {
  23  	var ipv4Addr = &net.UDPAddr{IP: net.IPv4(224, 0, 0, 1), Port: port}
  24  	if conn, e = net.ListenUDP("udp4", ipv4Addr); E.Chk(e) {
  25  		return
  26  	}
  27  	D.Ln("listening on", conn.LocalAddr(), "to", conn.RemoteAddr())
  28  	pc := ipv4.NewPacketConn(conn)
  29  	// var ifaces []net.Interface
  30  	var iface *net.Interface
  31  	// if ifaces, e = net.Interfaces(); E.Chk(e) {
  32  	// }
  33  	// // This grabs the first physical interface with multicast that is up. Note that this should filter out
  34  	// // VPN connections which would normally be selected first but don't actually have a multicast connection
  35  	// // to the local area network.
  36  	// for i := range ifaces {
  37  	// 	if ifaces[i].Flags&net.FlagMulticast != 0 &&
  38  	// 		ifaces[i].Flags&net.FlagUp != 0 &&
  39  	// 		ifaces[i].HardwareAddr != nil {
  40  	// 		iface = ifaces[i]
  41  	// 		break
  42  	// 	}
  43  	// }
  44  	ifcs, _ := routeable.GetAllInterfacesAndAddresses()
  45  	for _, ifc := range ifcs {
  46  		iface = ifc
  47  		if e = pc.JoinGroup(iface, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 1)}); E.Chk(e) {
  48  			return
  49  		}
  50  		// test
  51  		var loop bool
  52  		if loop, e = pc.MulticastLoopback(); e == nil {
  53  			D.F("MulticastLoopback status:%v\n", loop)
  54  			if !loop {
  55  				if e = pc.SetMulticastLoopback(true); e != nil {
  56  					E.F("SetMulticastLoopback error:%v\n", e)
  57  				}
  58  			}
  59  			D.Ln("Multicast Loopback enabled on", ifc.Name)
  60  		}
  61  	}
  62  	return
  63  }
  64