Search code examples
javascriptgoogle-chrome-extensionbroadcastmulticastmultiplayer

How can chrome.socket be used for broadcasting or multicasting?


I want to create a Chrome Packaged App used for LAN only, where one instance serves as a server (session host) and other instances must discover the server and join the session. Can this be achieved with chrome.socket?

I have set up the server like this:

var socket = chrome.socket || chrome.experimental.socket;
socket.create('udp', {}, function(createInfo) {
    var publish_socket = createInfo.socketId;
    socket.bind(publish_socket, '225.0.0.42', 42424, function (result) {
        if (result < 0) console.error(result); // this works fine
        socket.recvFrom(publish_socket, null, function(recvFromInfo) {
            console.log(recvFromInfo); // UNABLE TO MAKE THIS HAPPEN
        });
    });
    // Chrome won't let me listen for app window closing
    var cleanup_timer;
    cleanup_timer = setInterval(function(){
            if (requesting_window.closed) {
                socket.destroy(publish_socket);
                clearInterval(cleanup_timer);
            }
        },
        5000
    );
});

The socket is bound, I can see it in ss -ua:

State      Recv-Q Send-Q      Local Address:Port          Peer Address:Port
UNCONN     0      0           225.0.0.42:42424            *:*

But the server never seems to receive any data. I have tried sending some data using nc -uv 225.0.0.42 42424 and the chrome.socket API but with no success:

socket.create('udp', {}, function(socketInfo) {
   var socketId = socketInfo.socketId;
   socket.sendTo(socketId, str2ab("discovering"), '225.0.0.42', 42424, function(writeInfo) {
       if (writeInfo.bytesWritten < 0) console.error(writeInfo);
   });
});  

This results in error code -15 on the client side and nothing on the server side.

I suspect there should be a multicast flag set somewhere but I couldn't find it.

I am using Chrome Version 23.0.1246.0 dev


Solution

  • To send multicast packets all you need to do is bind to a local interface (0.0.0.0 with a random port works, as you've discovered), and then address a packet to the correct group/port (which is what sendTo will do).

    To receive multicast data you need to both bind to the correct port (on 0.0.0.0 is fine), then join the correct multicast group. You can do the first bit with socket.bind, but the second is normally done with setsockopt and the flag IP_ADD_MEMBERSHIP. Unfortunately the Chrome socket API doesn't provide access to this.

    When you make this call the system sends an IGMP onto the network instructing the routers to forward multicast packets for a specific group to your interface, binding to the correct port is then enough to receive them. You can normally also instruct the OS to duplicate multicast packets with the loopback interface (so you can use multicast on the same machine). You'll probably find that your existing code will work if the machines are connected directly together, but not if you connect via a switch (as it will drop the packets as your haven't subscribed), and not if you're on the same machine (as the packets don't route via the loopback interface).

    The traditional solution to this is to create an IGMP packet yourself, which would allow multicast to work via a switch, but not on the local machine. Unfortunately this needs access to send raw IP packets (not TCP or UDP) and chrome.socket doesn't provide that.

    This means that without another program to join the multicast group on your behalf you won't be able to receive anything.