Network DatagramSocket proposal

Should be there soon!

Hi robiwan, I've once again pushed the newest changes to my private fork. I've added support to allow you to bind to a specific local address and also added the joinMulticast and leaveMulticast functions. The imr_interface parameter in the setockopt call will be set to the last address that the DatagramSocket was bound to - or INADDR_ANY if it was not bound to any local address.

Can you do some testing on this and tell me if this works for you?

Thank you!

Yes, seems to work just fine. Thanks!

Multicast support is now on latest tip on github

Awesome! Thanks Fabian.

Hi Fabian,

In revisiting the multicast issue on Linux, I've been implementing a UPnP discovery service which registers for multicasts ok (verified with netstat -g), and with "ethtool -S eth0 | grep multicast" I can see that the kernel receives multicasts. Also I've set *.rp_filter to zero.

But alas, no multicasts are received by the application. And on Windows, the same application works fine.

Just wanted to check if you or anyone else has some ideas here ?

Regards

/R

Ok, reading this post http://stackoverflow.com/a/21593145/255635, on Unix we should not bind the socket to the interface address, so if I change SocketHelpers::bindSocket to this:


    static bool bindSocket (const SocketHandle handle, const int port, const String& address) noexcept
    {
        if (handle <= 0 || port < 0)
            return false;
        struct sockaddr_in servTmpAddr;
        zerostruct (servTmpAddr); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct)
        servTmpAddr.sin_family = PF_INET;
        servTmpAddr.sin_addr.s_addr = htonl (INADDR_ANY);
        servTmpAddr.sin_port = htons ((uint16) port);
#ifdef _WIN32
        // Note: On UNIX, this does not work: http://stackoverflow.com/a/21593145/255635
        if (address.isNotEmpty())
            servTmpAddr.sin_addr.s_addr = ::inet_addr (address.toUTF8());
#endif
        return bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) >= 0;
    }

multicast starts working on Linux aswell... 

 

Thanks, that seems sensible! We'll review this and figure something out..

Thanks Jules,

While you're at it :), DatagramSocket does not have a close() method, which makes it impossible to do a construct like:

while(!threadShouldExit())

{

  int retval = m_socket->waitUntilReady(true, -1);

  if (retval < 0)

    break;

  ...

}

and using a small delay (like 0 or 1) gobbles up CPU on Linux. 

With a close() method I can do:

signalThreadToExit();

m_socket->close();

stopThread(1000);

which exits the UDP server thread cleanly.

Oh.. one more thing.. sorry ;) , in StreamingSocket::waitUntilReady, same CriticalSection is used when querying both reading and writing, this is a problem since in order to do a non-blocking write, you have to call waitUntilReady(false, 0) to see if the socket is ready for writing, and if the socket is blocked in waitUntilReady(true, -1) the lock is aquired and waitUntilRead(false, 0) will return -1.

Proposal: Use two locks, one for read, other for write. I've tried this and it seems to work fine.

 

Hi obiwan, we were thinking about adding close when we added the DatagramSocket class. However, I think it will call the exact same underlying API calls if you simply delete and re-create the socket, right?

Instead of closing the socket, could you also delete and re-create the socket? This is how it was intended.