Here are some trivial examples of working SSM code. They certainly work under LinuxKernel2.6, and have been tested on amd64 in Gentoo and on ia32 DebianLinux. It's possible that SSM is not supported in Linux 2.4. The examples join the SSM group ip-of-sender, 232.1.1.1. In a real application you should randomly select the 232.0.0.0/8 address at runtime to avoid conflicts.
Note that some information is included in #ifndefs since many LinuxDistributions don't install the required header files yet.
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. This caused all the multicast packets to be ignored. Oops.
Another bug was due to the server using the SSM source of the unassigned address. Oops.
#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; }
Pass the IP address of the sender as CommandLine argument: ./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 *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); struct sockaddr_in bindaddr; /* Setup the socket to listen on */ bindaddr.sin_family = AF_INET; bindaddr.sin_port = htons(9991); bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(fd,(struct sockaddr*)&bindaddr,sizeof(bindaddr)); /* Set up the connection to the group */ group_source_req.gsr_interface = 0; group=(struct sockaddr_in*)&group_source_req.gsr_group; source=(struct sockaddr_in*)&group_source_req.gsr_source; /* Group is 232.1.1.1 */ group->sin_family = AF_INET; inet_aton("232.1.1.1",&group->sin_addr); group->sin_port = 0; /* Source is 10.1.20.9 */ source->sin_family = AF_INET; inet_aton(argv[1],&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 buffer[65536]; int ret=recv(fd,(char*)buffer,sizeof(buffer),0); write(1,buffer,ret); } return 0; }
#! /usr/bin/python import getopt import socket import sys if not hasattr(socket, 'IP_MULTICAST_TTL'): setattr(socket, 'IP_MULTICAST_TTL', 33) if not hasattr(socket, 'IP_ADD_SOURCE_MEMBERSHIP'): setattr(socket, 'IP_ADD_SOURCE_MEMBERSHIP', 39) if sys.argv[1] == 'send': opts, args = getopt.getopt(sys.argv[2:], 't:s:g:p:') opts = dict(opts) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) if '-t' in opts: s.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, chr(int(opts['-t']))) if '-s' in opts: s.bind((opts['-s'], 0)) s.connect((opts['-g'], int(opts['-p']))) print 'READY.' while True: s.send(sys.stdin.readline()) elif sys.argv[1] == 'recv': opts, args = getopt.getopt(sys.argv[2:], 'g:i:s:p:') opts = dict(opts) opts.setdefault('-i', '0.0.0.0') imr = (socket.inet_pton(socket.AF_INET, opts['-g']) + socket.inet_pton(socket.AF_INET, opts['-i']) + socket.inet_pton(socket.AF_INET, opts['-s'])) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) s.setsockopt(socket.SOL_IP, socket.IP_ADD_SOURCE_MEMBERSHIP, imr) s.bind((opts['-g'], int(opts['-p']))) print 'READY.' while True: print repr(s.recvfrom(4096))
Part of CategoryProgramming and CategoryNetworking
One page links to SourceSpecificMulticastExample: