-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Please expose multicast for UDP Datagram #10706
Comments
Do you have have an example of something you might want to do with this? What is the API in Node? What is the API in Go? How would you want it to look in Deno? |
In node the call is |
Came here to ask for the same thing. I'm playing around with the new (unstable) For the ipv4 addresses, I can send to the broadcast address (ex: 192.168.1.255), and receive it via my local address (ex: 192.168.1.10). However, that doesn't work for ipv6 addresses. AFAICT (I am not an expert on UDP networking 😅) they don't support broadcast addresses, only multicast, which requires the membership addition at the socket level. I'd love it if it were a part of the call to listenDatagram, that way it could handle joining/leaving the multicast group automatically. ex: let conn = Deno.listenDatagram({
transport: "udp",
port: 3030,
hostname: "fe80::1%0",
joinMulticast: [
"ff02::1",
],
} Questions that leaves me with (again, as a relative newbie to IPv6 UDP):
|
I have the time and inclination to help contribute this feature! I'm receiving a grant to add peer discovery on local networks for a distributed database, and my preferred approach would be to implement a userland module for DNS Service Discovery (used by many printers the world over) and use it in conjunction with mDNS. For this Deno needs multicasting capabilities, and I would like to help add them. It would be great to know which kinds of APIs would be preferred before I start working on a PR. @lucacasonato Do you have a preference between explicit calls for multicast membership (e.g. Node's Perhaps this could even nudge |
An explicit and imperative API for multicast, where explicit calls to So Deno's DatagramConn.joinMulticast(addr: string, interface: string | number) // interface could be IP address or IPv6 interface index / scope ID
DatagramConn.leaveMulticast(addr: string, interface: string | number)
DatagramConn.setMulticastLoopback(loopback: boolean)
DatagramConn.setMulticastTTL(ttl: number) And some example usage: const listener = Deno.listenDatagram({
transport: "udp",
port: 5353,
hostname: "224.0.0.251"
});
const interfaces = Deno.networkInterfaces();
// Let's pretend the first interface is IPv4
const ipv4Interface = interfaces[0];
// Join the mDNS multicast group with an IPv4 address. Deno determines whether the address is IPv4 or IPv6, and calls join_multicast_v4 or join_multicast_v6 as is appropriate.
listener.joinMulticast("224.0.0.251", interfaces[0].address);
// Or with IPv6
const ipv6Interface = interfaces[1];
listener.joinMulticast("ff02::fb", ipv6Interface.scopeid);
// Tweak multicast settings
listener.setMulticastLoopback(true);
listener.setMulticastTTL(255);
// And leave multicast groups before closing.
listener.leaveMulticast("224.0.0.251", interfaces[0].address);
listener.leaveMulticast("ff02::fb", ipv6Interface.scopeid);
// Or maybe leave automatically when the connection is closed?
listener.close(); There are already analogues for all of these methods on Would a PR with an API like this for multicasting be considered? |
I don't hold all the keys to the castle but I would welcome such a PR heartily. Only thing I might think of is if there should be separate APIs for IPv4 and 6: Since you need to know which you're using anyway for the first parameter. |
@aapoalas I was wondering about that too. If we followed the API of DatagramConn.joinMulticastV4(addr: string, interface: string)
DatagramConn.joinMulticastV6(addr: string, interface: number) // interface is scopeid
DatagramConn.leaveMulticastV4(addr: string, interface: string)
DatagramConn.leaveMulticast6(addr: string, interface: number) // interface is scopeid
DatagramConn.setMulticastLoopbackV4(loopback: boolean)
DatagramConn.setMulticastLoopbackV6(loopback: boolean)
DatagramConn.setMulticastTTL(ttl: number) // May or may not do anything to IPv6 connections. It's very explicit, but also kind of a lot? Node's |
The good news is that I now have a branch of Deno that can receive multicast messages. The less good news is the API isn't quite there yet. I tried the API style with a single There's a part of me that wants to see if an API like this makes sense... const membership = DatagramConn.joinMulticastV4(address, interface);
membership.setMulticastLoopback(true); // calls UdpSocket.set_multicast_loopback_V4 under the hood
membership.leave(); // calls UdpSocket.leave_multicast_v4 with the original address + interface under the hood
membership.setTTL(50); // This method would not be available on an IPv6 membership. This way you get only the methods each kind of membership can actually perform, and can only call to leave a membership if you've already joined one to begin with. |
PR for multicasting opened: #17811 |
My five cents on this issue. We need broadcast and multicast functionality for deno import { Buffer } from "node:buffer";
import { createSocket } from "node:dgram";
// https://github.com/denoland/deno_std/blob/main/bytes/concat.ts
export function concat(...buf: Uint8Array[]): Uint8Array {
let length = 0;
for (const b of buf) {
length += b.length;
}
const output = new Uint8Array(length);
let index = 0;
for (const b of buf) {
output.set(b, index);
index += b.length;
}
return output;
}
export const createMagickPacket = (mac: string): Uint8Array => {
const octets = mac.match(/[0-9a-fA-F]{2}/g);
let packet = new Uint8Array(0x06).fill(0xff);
const macArr = Uint8Array.from(octets!.map((octet) => parseInt(octet, 16)));
for (let i = 0; i < 16; i++) {
packet = concat(packet, macArr);
}
return packet;
};
export const wake = (macAddress: string) => {
const magicPacket = Buffer.from(createMagickPacket(macAddress));
const socket = createSocket("udp4");
socket.on("error", (e) => console.error(e));
socket.once("listening", () => socket.setBroadcast(true));
return new Promise((resolve, reject) => {
socket.send(
magicPacket,
0,
magicPacket.length,
9,
"255.255.255.255",
(err, res) => {
const result = res == magicPacket.length;
if (err) return reject(err);
resolve(result);
socket.close();
},
);
});
};
wake('DEVICE_MAC_ADDRESS'); Similar problems occur with multicast using
In other words, I'm really looking forward to the broadcast/multicast implementation for As one reason why this is needed is to implement functionality for the smart home, where multicast traffic is often used. For interact with mDNS (RFC 6762) or DNS-SD (RFC 6763) as example. UPD: As @sgwilym suggested broadcasting is on by default when |
Please expose multicast functions for Datagram connections. The functions can be found in std::net::UdpSocket. It will mostly likely require a new function to check if an address is either IPv4 or IPv6.
The text was updated successfully, but these errors were encountered: