Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for listening to multicast group #5352

Closed
sgtsquiggs opened this issue Jan 28, 2019 · 4 comments
Closed

Support for listening to multicast group #5352

sgtsquiggs opened this issue Jan 28, 2019 · 4 comments
Labels
feature request Requests for new plugin and for new features to existing plugins

Comments

@sgtsquiggs
Copy link
Contributor

Feature Request

I believe this feature could be added easily to the exisitng socket_listener input plugin. I have it working locally but I'm not sure how to cleanly integrate. For my requirements I only need the very simple multicast implementation (via net.ListenMulticastUDP) so there isn't much change.

Proposal:

Adding multicast:// multicast4:// multicast6:// network type handling to service_address config option:

case "udp", "udp4", "udp6", "ip", "ip4", "ip6", "unixgram", "multicast", "multicast4", "multicast6":
	var (
		err error
		pc net.PacketConn
	)

	switch spl[0] {
	case "multicast", "multicast4", "multicast6":
		var addr *net.UDPAddr
		spl[0] = strings.Replace(spl[0], "multicast", "udp", 1)
		if addr, err = net.ResolveUDPAddr(spl[0], spl[1]); err == nil {
			pc, err = net.ListenMulticastUDP(spl[0], nil, addr)
		}
	default:
		pc, err = net.ListenPacket(spl[0], spl[1])
	}
	if err != nil {
		return err
	}

	if sl.ReadBufferSize.Size > 0 {
		if srb, ok := pc.(setReadBufferer); ok {
			srb.SetReadBuffer(int(sl.ReadBufferSize.Size))
		} else {
			log.Printf("W! Unable to set read buffer on a %s socket", spl[0])
		}
	}

	psl := &packetSocketListener{
		PacketConn:     pc,
		SocketListener: sl,
	}

	sl.Closer = psl
	go psl.listen()

Current behavior:

Does not support multicast

Desired behavior:

Support multicast

Use case: [Why is this important (helps with prioritizing requests)]

I'm monitoring alerts sent from one application to other related applications via multicast group

@danielnelson
Copy link
Contributor

I'm new to working with multicast, but it seems that a more advanced configuration would allow listening to a specific address on an interface and potentially with multiple multicast groups? We could potentially expose these as settings, or it might just be overkill.

@phemmer Any thoughts on this one?

@phemmer
Copy link
Contributor

phemmer commented Feb 5, 2019

In principal I don't think there's anything wrong with the idea.
However in regards to the exposed interface, I don't think I'd do this by adding multicast:// as a protocol. The multicast address space is well defined. If we added it as a separate protocol, then udp://224.0.0.0 would be invalid configuration, just as multicast://1.0.0.1. I think it'd be better to support udp://224.0.0.1, recognize this as multicast, and do the appropriate setup.

In regards to listening on a specific interface, we can add support for udp://1.2.3.4%ifname. This would be usable on both unicast and multicast addresses. The syntax %ifname is stolen from the official IPv6 address specification format, so would be broadly compatible.

@sgtsquiggs
Copy link
Contributor Author

With @phemmer's input:

	case "udp", "udp4", "udp6", "ip", "ip4", "ip6", "unixgram":
		pc, err := udpListen(spl[0], spl[1])
		if err != nil {
			return err
		}

		if sl.ReadBufferSize.Size > 0 {
			if srb, ok := pc.(setReadBufferer); ok {
				srb.SetReadBuffer(int(sl.ReadBufferSize.Size))
			} else {
				log.Printf("W! Unable to set read buffer on a %s socket", spl[0])
			}
		}

		psl := &packetSocketListener{
			PacketConn:     pc,
			SocketListener: sl,
		}

		sl.Closer = psl
		go psl.listen()

and

func udpListen(network string, address string) (net.PacketConn, error) {
	switch network {
	case "udp", "udp4", "udp6":
		var addr *net.UDPAddr
		var err error
		var ifi *net.Interface
		if spl := strings.SplitN(address, "%", 2); len(spl) == 2 {
			address = spl[0]
			ifi, err = net.InterfaceByName(spl[1])
			if err != nil {
				return nil, err
			}
		}
		addr, err = net.ResolveUDPAddr(network, address)
		if err == nil {
			if addr.IP.IsMulticast() {
				return net.ListenMulticastUDP(network, ifi, addr)
			}
		}
	}
	return net.ListenPacket(network, address)
}

@danielnelson
Copy link
Contributor

Looks good, can you create a pull request?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Requests for new plugin and for new features to existing plugins
Projects
None yet
Development

No branches or pull requests

3 participants