There are 3 IPs a multicast socket might need,
1. before joining a multicast group, we need to bind the socket, what does this bind do?
1) it tells the kernel which port this application want the data from;
1) it tells the kernel which port this application want the data from;
2) it tells the kernel what dest address the incoming packet should have.
so if we say any (0.0.0.0), any incoming packet with the correct port number will be forwarded to the app; if we say only x.y.z.d,
then only the packets with that addr will be forwarded to the app, others will be dropped;
For a multicast group, ideally should be the multicast ip or 0.0.0.0, cannot think of a 3rd case, unless we want to join several multicast
groups, but want to filter out some traffic here, but I am doubting we will ever need this.
2. When join a group, we need to provide the multicast addr, this is easy to understand; We also want to tell the kernel from which interface
this group's traffic will come from, if we don't specify it will be any, the kernel will select one for you(definitely, not all interfaces, so this might not works as you want), this is done
by local ip.
IP_ADD_MEMBERSHIP.
Recall that you need to tell the kernel which multicast groups you are interested in. If no process is interested in a group, packets destined to it that arrive to the host are discarded. In order to inform the kernel of your interests and, thus, become a member of that group, you should first fill a
ip_mreq
structure which is passed later to the kernel in theoptval
field of thesetsockopt()
system call.The ip_mreq structure (taken from
/usr/include/linux/in.h
) has the following members:struct ip_mreq
{
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
};
(Note: the "physical" definition of the structure is in the file above specified. Nonetheless, you should not include
<linux/in.h>
if you want your code to be portable. Instead, include<netinet/in.h>
which, in turn, includes<linux/in.h>
itself).The first member,imr_multiaddr
, holds the group address you want to join. Remember that memberships are also associated with interfaces, not just groups. This is the reason you have to provide a value for the second member:imr_interface
. This way, if you are in a multihomed host, you can join the same group in several interfaces. You can always fill this last member with the wildcard address (INADDR_ANY
) and then the kernel will deal with the task of choosing the interface.With this structure filled (say you defined it as:struct ip_mreq mreq;
) you just have to callsetsockopt()
this way:setsockopt (socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
Notice that you can join several groups to the same socket, not just one. The limit to this isIP_MAX_MEMBERSHIPS
and, as of version 2.0.33, it has the value of 20
6.1 IP_MULTICAST_LOOP.
You have to decide, as the application writer, whether you want the data you send to be looped back to your host or not. If you plan to have more than one process or user "listening", loopback must be enabled. On the other hand, if you are sending the images your video camera is producing, you probably don't want loopback, even if you want to see yourself on the screen. In that latter case, your application will probably receive the images from a device attached to the computer and send them to the socket. As the application already "has" that data, it is improbable it wants to receive it again on the socket. Loopback is by default enabled.Regard thatoptval
is a pointer. You can't write:setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, 0, 1);
to disable loopback. Instead write:
u_char loop;
setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
and setloop
to 1 to enable loopback or 0 to disable it.To know whether a socket is currently looping-back or not use something like:u_char loop;
int size;
getsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &size)
6.2 IP_MULTICAST_TTL.
If not otherwise specified, multicast datagrams are sent with a default value of 1, to prevent them to be forwarded beyond the local network. To change the TTL to the value you desire (from 0 to 255), put that value into a variable (here I name it "ttl") and write somewhere in your program:u_char ttl;
setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
The behavior withgetsockopt()
is similar to the one seen on IP_MULTICAST_LOOP.6.3 IP_MULTICAST_IF.
Usually, the system administrator specifies the default interface multicast datagrams should be sent from. The programmer can override this and choose a concrete outgoing interface for a given socket with this option.struct in_addr interface_addr;
setsockopt (socket, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr));
>From now on, all multicast traffic generated in this socket will be output from the interface chosen. To revert to the original behavior and let the kernel choose the outgoing interface based on the system administrator's configuration, it is enough to callsetsockopt()
with this same option andINADDR_ANY
in the interface field.In determining or selecting outgoing interfaces, the following ioctls might be useful:SIOCGIFADDR
(to get an interface's address),SIOCGIFCONF
(to get the list of all the interfaces) andSIOCGIFFLAGS
(to get an interface's flags and, thus, determine whether the interface is multicast capable or not -theIFF_MULTICAST
flag-).If the host has more than one interface and the IP_MULTICAST_IF option is not set, multicast transmissions are sent from the default interface, although the remainding interfaces might be used for multicast forwarding if the host is acting as a multicast router.