Repository: denoland/deno
File: ext/net/ops.rs (Rust)

Code before:
    .ok_or(NetError::NoResolvedAddress)?;

  let resource = state
    .borrow_mut()
    .resource_table
    .get::<UdpSocketResource>(rid)
    .map_err(|_| NetError::SocketClosed)?;
  let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
  let nwritten = socket.send_to(&zero_copy, &addr).await?;

  Ok(nwritten)
}

#[op2(async)]
pub async fn op_net_join_multi_v4_udp(
  state: Rc<RefCell<OpState>>,
  #[smi] rid: ResourceId,
  #[string] address: String,
  #[string] multi_interface: String,
) -> Result<(), NetError> {
  let resource = state
    .borrow_mut()
    .resource_table
    .get::<UdpSocketResource>(rid)
    .map_err(|_| NetError::SocketClosed)?;
  let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;

  let addr = Ipv4Addr::from_str(address.as_str())?;
  let interface_addr = Ipv4Addr::from_str(multi_interface.as_str())?;

  socket.join_multicast_v4(addr, interface_addr)?;

  Ok(())
}

#[op2(async)]
pub async fn op_net_join_multi_v6_udp(
  state: Rc<RefCell<OpState>>,
  #[smi] rid: ResourceId,
  #[string] address: String,
  #[smi] multi_interface: u32,
) -> Result<(), NetError> {
  let resource = state
    .borrow_mut()
    .resource_table
    .get::<UdpSocketResource>(rid)
    .map_err(|_| NetError::SocketClosed)?;
  let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;

  let addr = Ipv6Addr::from_str(address.as_str())?;


Review comment (bug):
I think this might be a bug.

`multi_interface` is optional, and when omitted will typically default to letting the OS choose one interface. I believe this is the same as passing `0.0.0.0` (`INADDR_ANY`).

> https://nodejs.org/api/dgram.html#socketaddmembershipmulticastaddress-multicastinterface
>  If the multicastInterface argument is not specified, the operating system will choose one interface and will add membership to it. 

> According to the [linux ipv4 man page](https://man7.org/linux/man-pages/man7/ip.7.html):
> imr_address is the address of the local interface
> with which the system should join the multicast group; if
> it is equal to INADDR_ANY, an appropriate interface is
> chosen by the system.


Here's a reproduction: https://github.com/ipshipyard/deno_helia/blob/main/ssdp.ts

Code after:
    .ok_or(NetError::NoResolvedAddress)?;

  let resource = state
    .borrow_mut()
    .resource_table
    .get::<UdpSocketResource>(rid)
    .map_err(|_| NetError::SocketClosed)?;
  let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;
  let nwritten = socket.send_to(&zero_copy, &addr).await?;

  Ok(nwritten)
}

#[op2(fast)]
pub fn op_net_validate_multicast(
  #[string] address: String,
  #[string] multi_interface: String,
) -> Result<(), NetError> {
  let addr = Ipv4Addr::from_str(address.as_str())?;
  let interface_addr = Ipv4Addr::from_str(multi_interface.as_str())?;

  if !addr.is_multicast() {
    return Err(NetError::InvalidHostname(address));
  }

  if !interface_addr.is_multicast() {
    return Err(NetError::InvalidHostname(multi_interface));
  }

  Ok(())
}

#[op2(async)]
pub async fn op_net_join_multi_v4_udp(
  state: Rc<RefCell<OpState>>,
  #[smi] rid: ResourceId,
  #[string] address: String,
  #[string] multi_interface: String,
) -> Result<(), NetError> {
  let resource = state
    .borrow_mut()
    .resource_table
    .get::<UdpSocketResource>(rid)
    .map_err(|_| NetError::SocketClosed)?;
  let socket = RcRef::map(&resource, |r| &r.socket).borrow().await;

  let addr = Ipv4Addr::from_str(address.as_str())?;
  let interface_addr = Ipv4Addr::from_str(multi_interface.as_str())?;

  socket.join_multicast_v4(addr, interface_addr)?;