1

Let me start by saying this is my first foray into the world of C after 20+ years of assembly programming for PLCs and MicroControllers.

I'm trying to send a UDP datagram to the network broadcast address, in this particular case, 192.168.1.255.

The error I'm getting is a bind failure with error code 10049 (from WSAGetLastError()). As you can see from the attached code, I've created the socket, populated sockaddr_in, and setsockopt() to SO_BROADCAST.

For the life of me I can't figure out what I'm doing wrong and any pointers would be gratefully received.

iResult = WSAStartup(MAKEWORD(2, 2), &wsaTxData);
if (iResult != NO_ERROR)
{
    WSAErrorString("WSAStartup for TX failed");
    return(-1);
}
XPLMDebugString("UDP Server: WSAStartup TX complete.\n");

if ((BeaconSocket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
    WSAErrorString("UDP Server: Could not create BECN socket");
    return(-1);
}

// setup the sockaddr_in structure
//
si_beacon.sin_family = AF_INET;
si_beacon.sin_addr.s_addr = inet_addr("192.168.1.255");
si_beacon.sin_port = htons(_UDP_TX_PORT);

// setup to broadcast
//
char so_broadcast_enabled = '1';
if (setsockopt(BeaconSocket, SOL_SOCKET, SO_BROADCAST, &so_broadcast_enabled, sizeof(so_broadcast_enabled)) == SOCKET_ERROR) {
    WSAErrorString("Error in setting Broadcast option");
    closesocket(BeaconSocket);
    return(-1);
}

// bind our socket
//
if (bind(BeaconSocket, (struct sockaddr *)&si_beacon, sizeof(si_beacon)) == SOCKET_ERROR)
{
    char buf[256];
    WSAErrorString("Bind to socket for UDP beacon failed");
    sprintf(buf, "Port %u, address %s\n", ntohs(si_beacon.sin_port), inet_ntoa(si_beacon.sin_addr));
    XPLMDebugString(buf);
    return(-1);
}

// start the UDP beacon
//
udp_becn_thread_id = CreateThread(NULL, 0, BeaconThread, NULL, 0, NULL);
if (!udp_becn_thread_id) {
    WSAErrorString("UDP Server: Error starting UDP Beacon");
    return (-1);
}

XPLMDebugString("UDP Server: bind complete. beacon ACTIVE.\n");


return(0);

1 Answers1

0

The issue is the IP address itself.
I copied the code to my computer (changed it a bit to get it to compile) and I got the error:

UDP Server: WSAStartup TX complete.
Bind to socket for UDP beacon failed
Port 47977, address 192.168.1.255

I then changed the line:

si_beacon.sin_addr.s_addr = inet_addr("192.168.1.255");

To

si_beacon.sin_addr.s_addr = inet_addr("192.168.0.127");

And when I ran it again, everything worked:

UDP Server: WSAStartup TX complete.
Done successfully

The issue is that the "bind" address needs to be your computers address on the local network. Not the remote client.
Another alternative is to use the address:

si_beacon.sin_addr.s_addr = inet_addr("0.0.0.0");

which binds to all network interfaces on the computer at once.

For reference, here's the version of the code that I used:

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <string.h>

#include <WinSock2.h>
#include <WS2tcpip.h> // For inet_pton

#pragma comment(lib, "ws2_32.lib")

int main()
{
    {
        WSADATA wsaTxData;
        memset(&wsaTxData, 0, sizeof(WSADATA));
        const int iResult = WSAStartup(MAKEWORD(2, 2), &wsaTxData);
        if (iResult != NO_ERROR)
        {
            printf("%s", "WSAStartup for TX failed.\n");
            return -1;
        }
        printf("%s", "UDP Server: WSAStartup TX complete.\n");
    }

    SOCKET BeaconSocket;
    memset(&BeaconSocket, 0, sizeof(SOCKET));

    if ((BeaconSocket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
        printf("%s", "UDP Server: Could not create BECN socket\n");
        return -1;
    }

    // setup the sockaddr_in structure
    //
    sockaddr_in si_beacon;
    memset(&si_beacon, 0, sizeof(sockaddr_in));
    si_beacon.sin_family = AF_INET;
    si_beacon.sin_addr.s_addr = inet_addr("0.0.0.0");
    const unsigned short port_num = 0xbb69;
    si_beacon.sin_port = htons(port_num);

    // setup to broadcast
    //
    char so_broadcast_enabled = '1';
    if (setsockopt(BeaconSocket, SOL_SOCKET, SO_BROADCAST, &so_broadcast_enabled, sizeof(so_broadcast_enabled)) == SOCKET_ERROR) {
        printf("%s", "Error in setting Broadcast option\n");
        closesocket(BeaconSocket);
        return(-1);
    }

    // bind our socket
    //
    if (bind(BeaconSocket, (struct sockaddr*)&si_beacon, sizeof(si_beacon)) == SOCKET_ERROR)
    {
        char buf[256];
        printf("%s", "Bind to socket for UDP beacon failed\n");
        sprintf_s(buf, "Port %u, address %s\n", ntohs(si_beacon.sin_port), inet_ntoa(si_beacon.sin_addr));
        printf("%s", buf);
        return(-1);
    }

    printf("%s", "Done successfully");

    return 0;
}
Ronen
  • 195
  • 7
  • I think I've got that. So when I come to transmit the beacon using sendto(), I guess I'll need a second sockaddr_in structure populated for the target address of 192.168.1.255. Would that be correct? Thanks for your patience. – Simon Grainger Mar 04 '22 at 22:33
  • I know very little about the Win32API, but it's terrible. If I were you I would be using C++ with boost::asio. Here is how to broadcast UDP with boost::asio https://stackoverflow.com/a/9310749/7753444 The API that winsock2 uses is the pinnacle of C being "efficiently dangerous". In any case I'm sure there are libraries in C for UDP broadcasting. You don't need to use the Win32API. There are too many places to go wrong. – Ronen Mar 04 '22 at 22:55