Originally, the only way to join or leave a multicast group was via the setsockopt API. Winsock 2 introduces a protocol-independent method of multicasting with the WSAJoinLeaf API (discussed in the next section), but as we will soon see, the setsockopt method is much more flexible even though it is more closely tied to the protocol being used.
There are two socket options that control joining and leaving groups: IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. The socket option level is IPPROTO_IP. The input parameter is a struct ip_mreq structure, which is defined as
struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* local IP address of interface */ };
The imr_multiaddr field is the 32-bit IPv4 address of the multicast group in network-byte order and imr_interface is the 32-bit IPv4 address of the local interface on which to join the multicast group (also specified in network-byte order). The following code snippet illustrates joining a multicast group.
SOCKET s; SOCKADDR_IN localif; struct ip_mreq mreq; s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); localif.sin_family = AF_INET; localif.sin_port = htons(5150); localif.sin_addr.s_addr = htonl(INADDR_ANY); bind(s, (SOCKADDR *)&localif, sizeof(localif)); mreq.imr_interface.s_addr = inet_addr("157.124.22.104"); mreq.imr_multiaddr.s_addr = inet_addr("234.5.6.7"); setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
Note that the socket should be bound to the wildcard address (INADDR_ANY) before joining the group. In this example, the socket is joined to the multicast group 234.5.6.7 on the local interface 157.124.22.104. Multiple groups may be joined on the same socket on the same or different interface.
Once one or more multicast groups are joined, the IP_DROP_MEMBERSHIP option is used to leave a particular group. Again, the struct ip_mreq structure is the input parameter. The local interface and multicast group to drop are the arguments of the structure. For example, given the code sample you just saw, the following code drops the multicast group previously joined:
// Join the group as shown above mreq.imr_interface.s_addr = inet_addr("157.124.22.104"); mreq.imr_multiaddr.s_addr = inet_addr("234.5.6.7"); setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
Finally, if the application exits or the socket is closed, any multicast groups joined by that process or socket are cleaned up.
An IPv4 multicasting sample that uses setsockopt is provided on the companion CD in the directory IP-SETSOCKOPT. |
|
IP source multicasting is available on systems that support the IGMPv3 protocol and allows a socket to join a multicast group on an interface while specifying a set of source addresses to accept data from. There are two possible modes in which a socket may join a group. The first is the INCLUDE mode, in which a socket joins a group specifying N number of valid source addresses to accept data from. The other mode is EXCLUDE, in which a socket joins a group specifying to accept data from anyone except the N source addresses listed. Depending on which mode is used, the socket options differ.
To join a multicast group while using the INCLUDE mode, the socket options are IP_ADD_SOURCE_MEMBERSHIP and IP_DROP_SOURCE_MEMBERSHIP. The first step is to add one or more sources. Both socket options take a struct ip_mreq_source structure, which is defined as
struct ip_mreq_source { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_sourceaddr; /* IP address of source */ struct in_addr imr_interface; /* local IP address of interface */ };
The imr_multiaddr and imr_interface fields are the same as in the struct ip_mreq structure. The new field imr_sourceaddr specifies the 32-bit IP address of the source to accept data from. If there are multiple valid sources, then the IP_ADD_SOURCE_MEMBERSHIP is called again with the same multicast address and interface with the other valid source. The following code sample joins a multicast group on a local interface with two valid sources:
SOCKET s; SOCKADDR_IN localif; struct ip_mreq_source mreqsrc; s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); localif.sin_family = AF_INET; localif.sin_port = htons(5150); localif.sin_addr.s_addr = htonl(INADDR_ANY); bind(s, (SOCKADDR *)&localif, sizeof(localif)); mreqsrc.imr_interface.s_addr = inet_addr("157.124.22.104"); mreqsrc.imr_multiaddr.s_addr = inet_addr("234.5.6.7"); mreqsrc.imr_sourceaddr.s_addr = inet_addr("172.138.104.10"); setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&mreqsrc, sizeof(mreqsrc)); mreqsrc.imr_sourceaddr.s_addr = inet_addr("172.141.87.101"); setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&mreqsrc, sizeof(mreqsrc));
To remove a source from the INCLUDE set, the IP_DROP_SOURCE_ MEMBERSHIP is called with the multicast group, local interface, and source to be removed.
To join a multicast group that excludes one or more sources, the multicast group is joined with IP_ADD_MEMBERSHIP. Using IP_ADD_MEMBERSHIP to join a group is equivalent to joining a group in the EXCLUDE mode except that no one is excluded. Data sent to the joined group is accepted regardless of the source. Once the group is joined, then the IP_BLOCK_SOURCE option is called to exclude the given source. Again, the struct ip_mreq_source structure is the input parameter that specifies the source to block. The following example joins a group and then excludes a single source:
SOCKET s; SOCKADDR_IN localif; struct ip_mreq mreq; struct ip_mreq_source mreqsrc; s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); localif.sin_family = AF_INET; localif.sin_port = htons(5150); localif.sin_addr.s_addr = htonl(INADDR_ANY); bind(s, (SOCKADDR *)&localif, sizeof(localif)); // Join a group - the filter is EXCLUDE none mreq.imr_interface.s_addr = inet_addr("157.124.22.104"); mreq.imr_multiaddr.s_addr = inet_addr("234.5.6.7"); setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)); mreqsrc.imr_interface = mreq.imr_interface; mreqsrc.imr_multiaddr = mreq.imr_multiaddr; mreqsrc.imr_sourceaddr.s_addr = inet_addr("172.138.104.10"); setsockopt(s, IPPROTO_IP, IP_BLOCK_SOURCE, (char *)&mreqsrc, sizeof(mreqsrc));
If after some point, the application wishes to accept data from a source previously blocked, it may remove that source from the exclude set by calling setsockopt with IP_UNBLOCK_SOURCE. A struct ip_mreq_source is the input parameter that specifies the source to accept data from.
An IPv4 source multicasting sample that uses setsockopt is provided on the companion CD in the directory IP-SOURCE. |