Penguin
Note: You are viewing an old revision of this page. View the current version.

Acronym for Source Specific Multicast.

This is a relatively new form of multicast where only one person the group can transmit. Since the source address of the transmission is known in advance, a lot of the overhead with multicast (RP's etc) is no longer necessary. To run a network with SSM, all you need to enable is PIM-SM.

Anyway, here are some very trivial examples uncluttered by anything like error handling (grin!). Many Distributions don't have the required header files yet, so included in #ifndef's is the required information. This certainly works under Linux 2.6, but it's possible this is not supported in Linux 2.4. This works on AMD64 gentoo and 32bit debian.

The examples join the SSM group (ip-of-sender,232.1.1.1). In a real application you should randomly selected the 232.0.0.0/8 address to avoid conflicts.

Sender:

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>

/* Not everyone has the headers for this so improvise /
#ifndef MCAST_JOIN_SOURCE_GROUP
#define MCAST_JOIN_SOURCE_GROUP 46

struct group_source_req
{
        / Interface index.  /
        uint32_t gsr_interface;

        / Group address.  /
        struct sockaddr_storage gsr_group;

        / Source address.  /
        struct sockaddr_storage gsr_source;
};
#endif

int main(int argc, char argv[])
{
        struct group_source_req group_source_req;
        struct sockaddr_in group;
        struct sockaddr_in source;
        int fd = socket(AF_INET,SOCK_DGRAM,getprotobyname("udp")->p_proto);
        socklen_t socklen = sizeof(struct sockaddr_storage);
        struct sockaddr_in bindaddr;
        u_char loop = 1;

        / First bind to the port /
        bindaddr.sin_family = AF_INET;
        bindaddr.sin_port = htons(9990);
        bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);

        bind(fd,(struct sockaddr)&bindaddr,sizeof(bindaddr));
        / Now set up the SSM request /
        group_source_req.gsr_interface = 0; / "any" interface /
        group=(struct sockaddr_in)&group_source_req.gsr_group;
        source=(struct sockaddr_in)&group_source_req.gsr_source;

        group->sin_family = AF_INET;
        inet_aton("232.1.1.1",&group->sin_addr);
        group->sin_port = 0;    / Ignored /

        / Set the source to the name of the socket we created above /
        getsockname(fd,(struct sockaddr )source, &socklen);

        setsockopt(fd,SOL_IP,MCAST_JOIN_SOURCE_GROUP, &group_source_req,
                                sizeof(group_source_req));

        / Enable reception of our own multicast /
        loop = 1;
        setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
        / Set the TTL on packets to 250 /
        loop=250;
        setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &loop, sizeof(loop));
        / Now we care about the port we send to /
        group->sin_port = htons(9991);

        / Now send packets */
        while(1)? {
                sendto(fd,"Hello World",strlen("Hello World"),0,
                        (struct sockaddr)group,sizeof(struct sockaddr_in));
                sleep(1);
        }
        return 0;
}

And a reciever follows. Use it ./ssm-rec ip.address.of.sender

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>

/* Not everyone has the headers for this, so improvise /
#ifndef MCAST_JOIN_SOURCE_GROUP
#define MCAST_JOIN_SOURCE_GROUP 46

struct group_source_req
{
        / Interface index.  /
        uint32_t gsr_interface;

        / Group address.  /
        struct sockaddr_storage gsr_group;

        / Source address.  */
        struct sockaddr_storage gsr_source;
};
#endif

int main(int argc, char argv1?,&source->sin_addr);
        source->sin_port = 0;

        setsockopt(fd,SOL_IP,MCAST_JOIN_SOURCE_GROUP, &group_source_req,
                                sizeof(group_source_req));

        while(1)? {
                char buffer65536?;
                int ret=recv(fd,(char)buffer,sizeof(buffer),0);
                write(1,buffer,ret);
        }
        return 0;
}

I had one major problem while trying to debug this. My mistake was that the reciever wasn't binding to INADDR_ANY for the listening socket, but instead to an IP address on the machine causing all the multicast packets to be ignored. Ooops.


CategoryProgramming CategoryNetworking