Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Problem with sf::UdpSocket::Send with sf::IpAddress::Broadcast on Windows + fix.  (Read 2130 times)

0 Members and 2 Guests are viewing this topic.

Daid

  • Newbie
  • *
  • Posts: 29
    • View Profile
Discovered and worked around this issue a while back. But putting it here for reference.

When using sf::UdpSocket::Send with the target address of sf::IpAddress::Broadcast on windows. You would expect the UDP packet to be broadcast to the whole network you are connected to. However, this isn't happening. What is happening is that it is broadcast on the first enabled network adapter. And nothing else. This is extremely evident when you are connected to both wifi and wired network, or have VirtualBox virtual networks setup.

The end result is that local server discovery did not always for for me. Now, even with this fixed (fix below), broadcasting on windows only works if the network is not classified as "public network". So for the broadcasting server discovery implementors out there, I do recommend you broadcast both ways, from the server to let them know you are there, and from the clients to let them know you are looking for a server. This gives the highest chance of success.

The fix isn't that complex to code. You need to iterate on all networks, and broadcast your packet per network:
#ifdef _WIN32
#include <winsock2.h>
#include <iphlpapi.h>
#endif
[code]

[code=cpp]#ifdef _WIN32
    //On windows, using a single broadcast address seems to send the UPD package only on 1 interface.
    // So use the windows API to get all addresses, construct broadcast addresses and send out the packets to all of them.
    PMIB_IPADDRTABLE pIPAddrTable;
    DWORD tableSize = 0;
    GetIpAddrTable(NULL, &tableSize, 0);
    if (tableSize > 0)
    {
        pIPAddrTable = (PMIB_IPADDRTABLE)calloc(tableSize, 1);
        if (GetIpAddrTable(pIPAddrTable, &tableSize, 0) == NO_ERROR)
        {
            for(unsigned int n=0; n<pIPAddrTable->dwNumEntries; n++)
            {
                sf::IpAddress ip(ntohl((pIPAddrTable->table[n].dwAddr & pIPAddrTable->table[n].dwMask) | ~pIPAddrTable->table[n].dwMask));
                socket.send(packet, ip, port_nr);
            }
        }
        free(pIPAddrTable);
    }
#else
    socket.send(packet, sf::IpAddress::Broadcast, port_nr);
#endif
And you need to link to "iphlpapi" as well for the GetIpAddrTable function.