Your Browser is not longer supported

Please use Google Chrome, Mozilla Firefox or Microsoft Edge to view the page correctly
Loading...

{{viewport.spaceProperty.prod}}

Broadcast messages (AF_INET)

openNET Server

&pagelevel(3)&pagelevel

Using a datagram socket, it is possible to send broadcast packets to many networks connected to the system. The network itself must support broadcasts, since the system does not support simulation of broadcasts in the software. Broadcast messages can create a high network load because they force every machine on the network to serve them.

Broadcasting is only offered in the AF_INET address family since there is no broadcast mechanism in IPv6.

Broadcasting is typically used for one of the two reasons:

  • A resource is to be found in a local network whose address is initially unknown.

  • Important functions, such as the routing function, want to send information to all accessible computers.

To send a broadcast message,

  • first a datagram socket is generated,
  • then the socket is marked as allowed to send broadcast messages and
  • then a port number is assigned to the socket:
int on = 1;
int s = socket(AF_INET, SOCK_DGRAM, 0);
...
setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof on);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(MYPORT);
bind(s, (struct sockaddr *)&sin, sizeof sin);

The destination address of the message to be sent as a broadcast message depends on the network or networks on which the message is being sent. There is a short name for broadcast on the local network, namely the address INADDR_BROADCAST (defined in <netinet/in.h>).

BS2000 supports a method with which information about the network interfaces of the own computer can be queried. The ioctl() call SIOCGIFCONF or SIOCGLIFCONF returns the IPv4 network configuration of the computer as an ifconf or lifconf structure. Among other things, this contains a list of ifreq or lifreq structures. In this list, there is an ifreq or lifreq structure for each network interface on the computer.

The lifreq structure is declared in <net/if.h> as follows:

struct  lifreq {
        char                             lifr_name[LIFNAMSIZ];
        ...
        union {
                struct sockaddr_storage  lifru_addr;
                struct sockaddr_storage  lifru_broadaddr;
                unsigned long long       lifru_flags;
                ...
        } lifr_lifru;
#define  lifr_addr       lifr_lifru.lifru_addr
#define  lifr_broadaddr  lifr_lifru.lifru_broadaddr
#define  lifr_flags      lifr_lifru.lifru_flags
...
}; 

The following program code provides the IPv4 interface configuration:

  • Calling ioctl() with SIOCGLIFNUM returns the number of IPv4 network interfaces.
  • Calling ioctl() with SIOCGLIFCONF returns the list of IPv4 network interfaces.
  • The ioctl() calls with SIOCGLIFFLAGS return the flags of the respective network interface, e.g. whether the network interface is active and broadcast-capable.
  • The ioctl() calls with SIOCGLIFBRDADDR return the broadcast address of the respective network interface.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>

int main(int argc, char **argv)
{
    int              af=AF_INET, intaf;
    int              s, n;
    struct lifconf   lifc;
    struct lifreq  * plifreq;
    struct lifreq    lifr;
#    define NAMLEN    sizeof(lifr.lifr_name)
    struct lifnum    lif_num;
    int              lifreq_num;
    void           * addrptr;
    char             addrstr[INET6_ADDRSTRLEN + 1];

    s = socket(AF_INET, SOCK_DGRAM, 0);
    /*-------------- SIOCGLIFNUM --------------*/
    lif_num.lifn_family = af;
    lif_num.lifn_flags  = 0;
    if (ioctl(s, SIOCGLIFNUM, &lif_num) < 0) {
        perror("ioctl(SIOCGLIFNUM)");
        return 1;
    }
    lifc.lifc_len = lif_num.lifn_count * sizeof(struct lifreq);
    lifc.lifc_buf = malloc(lifc.lifc_len);
    /*-------------- SIOCGLIFCONF --------------*/
    lifc.lifc_family = af;
    lifc.lifc_flags  = 0;
    if (ioctl(s, SIOCGLIFCONF, &lifc) < 0) {
        perror("ioctl(SIOCGLIFCONF)");
        return 1;
    }
    lifreq_num = lifc.lifc_len / sizeof (struct lifreq);
    printf ("IPv4 interfaces: %d\n", lifreq_num);
    for (plifreq=lifc.lifc_req,n=0; n<lifreq_num; n++, plifreq++) {
        intaf = plifreq->lifr_addr.ss_family;
        if (intaf == AF_INET6) {
            addrptr = &((struct sockaddr_in6 *)&plifreq->lifr_addr)->sin6_addr;
        } else {
            addrptr = &((struct sockaddr_in *)&plifreq->lifr_addr)->sin_addr;
        }
        inet_ntop(intaf, addrptr, addrstr, INET6_ADDRSTRLEN);
        if (plifreq->lifr_addr.ss_family != af) {
            continue;
        }
        printf ("%-16s  %-*s  ", plifreq->lifr_name, INET_ADDRSTRLEN, addrstr);
        /*-------------- SIOCGLIFFLAGS --------------*/
        memset(&lifr, 0, sizeof(lifr));
        memcpy(&(lifr.lifr_name), plifreq->lifr_name, NAMLEN);
        if (ioctl(s, SIOCGLIFFLAGS, &lifr) < 0) {
            printf("UP=?  BC=?\n");
        } else {
            printf("UP=%s  BC=%s  ",
              lifr.lifr_flags & IFF_UP        ? "yes" : "no ",
              lifr.lifr_flags & IFF_BROADCAST ? "yes" : "no ");
            if (lifr.lifr_flags & IFF_BROADCAST) {
                /*-------------- SIOCGLIFBRDADDR --------------*/
                memset(&lifr, 0, sizeof(lifr));
                memcpy(&(lifr.lifr_name), plifreq->lifr_name, NAMLEN);
                if (ioctl(s, SIOCGLIFBRDADDR, &lifr) < 0) {
                    printf("BCADDR=?\n");
                } else{
                    addrptr = &((struct sockaddr_in *)&(lifr.lifr_broadaddr))->sin_addr;
                    inet_ntop(AF_INET, addrptr, addrstr, INET6_ADDRSTRLEN);
                    printf("BCADDR=%s\n", addrstr);
                }
            } else {
                printf("\n");
            }
        }
    }
    free(lifc.lifc_buf);
    return 0;
}

After a suitable broadcast address has been selected, you can now use this in the sendto() function:

struct sockaddr_in *dst;
...
dst = (struct sockaddr_in *)&(lifr.lifr_broadaddr);
...
sendto(s, buf, buflen, 0, (struct sockaddr *)&dst, sizeof dst);

A name is always assigned to the sending datagram socket, either by a call to the bind() function or implicitly by the system. Therefore, received broadcast messages always contain the address and port number of the sender.

The BCAM command BCOPTION can be used to control whether a network interface can receive broadcast messages (see the "BCAM" manual). This setting can neither be influenced nor determined with the socket functions setsockopt() and getsockopt(). Therefore, when using the broadcast mechanism, it must be ensured that this option is activated on the computers concerned.