IP Multicast Initiative (IPMI)
Stardust.com, Inc
1901 S. Bascom Ave, #333
Campbell, CA 95008 USA
Tel: 408-879-8080
Fax: 408-879-8081
Web: http://www.ipmulticast.com/

Writing IP Multicast-enabled Applications

An IP Multicast Initiative White Paper

A technical description of IP Multicast APIs, and an overview of application requirements for their use

Scope Of This Document
Applications that can benefit from Multicast
Application Requirements for Multicast-enabling
Standard Muliticast APIs
Multicasting with care
Multicast API Limitations
Future application needs - Quality of Service
Concluding Remarks
Code Samples

More Information
Useful References


Microsoft Word Version -- PDF Version


Scope Of This Document
This document describes how to multicast-enable an application. This includes an overview of the types of applications that can benefit from multicast-enabling, the requirements for their eligibility, and a detailed description of the application programming interfaces (APIs) available for PC, Macintosh, and Unix platforms. It also briefly discusses the considerations of address and port usage, and scheduling-to avoid conflicts with other multicast applications. Finally, it considers future application enhancements to take advantage of RSVP, the quality of service protocol.

The intended audience is primarily application developers and project managers. The content is highly technical in nature, and makes a number of assumptions about the reader. It assumes an understanding of the mechanics of IP multicast from a host perspective (as described in the "How Multicast Works" white paper), it assumes familiarity with TCP/IP transport concepts-the differences between stream-oriented TCP connections and message-based UDP datagrams-and it assumes familiarity with standard network APIs.

 

Applications that can benefit from Multicast
We characterize the applications that can benefit most by adding multicast capabilities by the fact they distribute data among multiple network hosts simultaneously, rather than only exchanging data with only one host at a time. Two models of data distribution exist: one-to-many, and many-to-many. There are numerous examples of applications that implement these models.

A one-to-many application sends the same information to many receivers simultaneously. The data flow is one-way, from a single sender. An application that sends time-critical, real-time information-like stock quotes-is an ideal example of a one-to-many application that can benefit from multicast. Applications that send news and weather, and other less-immediate, but widely distributable information, are other good examples. The analogous technical model is broadcast radio, and television. The types of content these applications typically send, and the schedule coordination requirements are analogous also.

A many-to-many application is one that shares information with a number of machines simultaneously. In other words, in many-to-many applications the data flow is bi-directional. Each receiver is also a sender, so in effect, each many-to-many application acts as a one-to-many application (sending) and a many-to-one (receiving).

Other more specialized applications that don't obviously fit the data distribution models can benefit from multicast as well. For instance, applications that synchronize information among multiple network hosts-including exchange of internal application states, as well as data-are multicast candidates. Applications that attempt to discover other applications, or services, could use multicast also.

 

Application Requirements for Multicast-enabling
It is possible to create an application that does data distribution without using multicast. Many such applications exist. They use unicast datagram or connection-oriented stream transports to distribute data to each host individually. But as other IPMI white papers describe, these applications are less than optimal in many respects.

Non-multicast data distribution applications duplicate the data they send to each receiver and as a result of this duplication-and the network bandwidth it wastes-these applications cannot scale to service increasing numbers of receivers. They cannot distribute in a timely manner either, since the delivery to each host has to be serialized in some fashion. To illustrate, consider the logistics of newspaper delivery, versus news radio broadcasts.

Many existing data distribution applications can be easily adapted to use multicast, but others may require significant redesign. The ideal candidates are applications that currently use connection-less datagram transport (e.g. UDP). These are easiest to adapt, since they already use a message-oriented, "unreliable" transport.

On the other hand, applications that utilize connection-oriented, datastream protocols (e.g. TCP) need significant work. They usually depend on the reliable data delivery capabilities-acknowledged delivery, sequenced data, no duplicates--that the transport provides, so the application needs to be redesigned to implement these capabilities at the application layer.

Some datagram applications have implemented unicast reliability at the application layer, but reliable multicast algorithms have very different requirements. One cannot simply implement datagram versions of what TCP does. You can imagine the problem caused by acknowledgments from many receivers sent at once to a single sender (implosion). Implementing a reliable multicast transport is a difficult challenge, but certainly possible.

There are a number of implementations available that offer reliable multicast, including some commercial products that utilize it quite effectively for applications like multicast file transfer. Some of these algorithms have been proposed to the IETF as possible standards. None have been fully embraced yet; reliable multicast is a fairly recent area of research and development. Scalability and congestion avoidance issues on the Internet are a primary focus in these efforts.

The IPMI "Higher Level Protocols used with IP Multicast" white paper discusses reliable multicast in more detail. As a result of this and the complex algorithms involved, we will not cover the topic of reliable multicast applications any further in this document.

Adapting unicast datagram applications to multicast

Assuming you are adapting an application that currently uses unicast datagrams, the multicast-enabling requirements depend on the type of data distribution the application does, the application's role in host-to-host communications, and the desired operating characteristics. Table 1 summarizes the most significant considerations, and provides a brief description of what's required in an application.

Application Functionality Modifications Required
send multicast
on local subnet
nothing required other than send to a multicast (Class D) destination address, and relevant port number (multicast session parameters)
send multicast
beyond local subnet
modify the IP time-to-live (TTL) value according to the desired scope, and send to the session address and port number
receive data from a multicast address bind to a specific port number and join multicast group

Table 1: Summary of minimum multicast modifications

RFC 1112, "Host Extensions for IP Multicasting," describes what is required of a host's IP implementation to support multicast. In this description, it also prescribes the default behavior of multicast applications:

  • An application need not be a member of a multicast group to send datagrams to it
  • An application must explicitly join a multicast group to receive datagrams destined for that group
  • When an application joins a group, it joins on only one local interface
  • When an application sends to a multicast address, outgoing datagrams are sent from only one local interface
  • When an application sends to a multicast address, outgoing datagrams have an IP time-to-live (TTL) value of 1
  • When an application sends to a multicast address, all datagrams sent are also received on the same interface (i.e. datagrams "loop-back")

To allow an application to modify the default behavior, RFC 1112 recommends a number of APIs for multicast support:

  • To join a multicast group
  • To leave a multicast group
  • To set the IP TTL on a multicast datagram to adjust the scope
  • To set the local interface for multicast transmission and receipt
  • To disable loopback of outgoing multicast datagrams

The same year he wrote RFC 1112 (1989), Steve Deering also authored a paper called "IP Multicast Extensions for 4.3BSD UNIX and related systems." In this paper, Steve describes the Berkeley Sockets multicast APIs he implemented, which are the same APIs still in use today. They provide the functionality described above, and are now the de facto standard multicast APIs. Other APIs have also emerged for other network platforms, and they all provide basically the same functionality described by RFC 1112.

 

Standard Multicast APIs
As we mentioned, multicast APIs are currently available for a number of platforms. All are derived from the requirements set forth by RFC 1112, so they all have similar functionality. The APIs we describe in the remainder of this section are for
  • Unix (Berkeley Sockets)
  • Microsoft Windows (Windows Sockets)
  • Apple Macintosh (Open Transport)

Berkeley Sockets Multicast APIs

The Berkeley Sockets Multicast APIs are the same as those described by Steve Deering (as mentioned earlier). They complement the existing Berkeley Sockets APIs, which were designed to allow creating of network applications using virtually any network protocol suite, including TCP/IP, the so-called "Internet address family."

All of the Berkeley multicast APIs use the setsockopt() "socket option" function to initiate their actions (and for some options, the getsockopt() function is also available to retrieve the current setting).

IP_ADD_MEMBERSHIP to join a multicast group on a specific interface
IP_DROP_MEMBERSHIP
to leave a multicast group (no protocol action initiated with IGMP v1, but there is with IGMP v2)
IP_MULTICAST_IF to set or get default interface for use with multicast sends
IP_MULTICAST_LOOP to disable loopback of outgoing multicast datagrams
IP_MULTICAST_TTL to set the IP time-to-live of outgoing multicast datagrams.

Table 2: Summary of BSD set/getsockopt() multicast commands

The setsockopt() IP_ADD_MEMBERSHIP function is the most significant of all the APIs, in several respects. It is required to receive any datagrams destined for the specified multicast (group) address. Unlike other socket options, it actually initiates some network activity; it causes the underlying IP protocol stack to issue an IGMP (Internet Group Message Protocol) host membership report to notify the local router(s) of the group membership, as prescribed by RFC 1112.

For an example of how to use these de facto standard multicast APIs, see the "Code Samples" section of this white paper.

Windows Sockets Multicast APIs

Windows Sockets version 2 (a.k.a. WinSock 2), is a set of APIs designed for 32-bit Microsoft Windows platforms for creating network applications using virtually any network protocol. WinSock 2 is a superset of WinSock version 1.1, which was itself both a superset of Berkeley Sockets (new Windows-specific functions were added), and subset of Berkeley Sockets (not all APIs were supported; in particular, many ioctl()s were not supported).

WinSock 2 supports the Berkeley Sockets compatible TCP/IP protocol-specific APIs, as described above (and also described in the TCP/IP section of the "WinSock 2 Protocol-Specific Annex"). However, WinSock 2 has also defined a set of new protocol-independent (non-IP-specific) multipoint APIs that can support IP multicast, as shown in Table 3.

WSAEnumProtocols() To determine multicast support
WSASocket() To specify the multipoint type
WSAJoinLeaf() To join a multicast group and specify role (sender and/or receiver)
WSAIoctl() SIO_MULTICAST_SCOPE To set IP time-to-live
WSAIoctl() SIO_MULTIPOINT_LOOPBACK To disable loopback

Table 3: Summary of WinSock 2's protocol-independent multipoint APIs

To allow for qualification of various multipoint models, WinSock 2 has defined the concepts of a "data plane" and "control plane," each of which can be "rooted" or "non-rooted,". We won't go into detail about what these concepts mean here. Suffice it to say that IP multicast always has non-rooted data and control planes. You specify these roles when you request a multipoint socket using WSASocket().

The WSAEnumProtocols() function returns detailed descriptions of the protocols currently installed in a system in an array of protocol information structures (WSAPROTOCOL_INFO). Among the flags to describe the services provided by the IP/UDP protocol, the bit-flag XP1_SUPPORT_MULTIPOINT in the dwServiceFlags1 field indicates IP multicast support.

Lastly, notice that an API to leave a multicast group is missing from this list. The only protocol-independent API to provide a way to leave a multicast group after joining, is to close a socket.

We have an example that shows how to use the protocol-independent multipoint APIs for IP multicast, see the "Code Samples" section of this white paper.

Open Transport/TCP Multicast APIs

Open Transport is a set of APIs recently defined by Apple Computer, Inc. as their new standard for creating network applications on Macintosh computers using virtually any communications device, or network protocol, including TCP/IP. Open Transport is a superset of the XTI standard networking API defined by the X/Open Unix vendor consortium (and XTI is itself a superset of TLI, another de facto standard network API).

Like Berkeley Sockets and WinSock, Open Transport (OT) is protocol-independent, but also includes some protocol-specific APIs for support of IP multicast. In OT terms, these extensions are called an "option management scheme." All of these IP multicast extensions use the OptionManagement() function (the standard C interface version is called OTOptionManagement()). As shown in Table 4, they have the same names as the Berkeley Sockets APIs, and provide the same functionality. However, not all of the Berkeley Sockets multicast options are supported.

IP_ADD_MEMBERSHIP to join a multicast group
IP_MULTICAST_LOOP to disable loopback of multicast outgoing datagrams
IP_MULTICAST_TTL to set the IP time-to-live of outgoing multicast datagrams.

Table 4: Summary of Open Transport's OptionManagement multicast APIs

For an example of how to use these Open Transport multicast APIs, see the "Code Samples" section of this white paper.

 

Multicasting with care
Multicast is great, and allows for many powerful and flexible applications that are relatively kind to the network, since-among other things-they can send a single data stream to multiple receivers simultaneously. However, it is still possible to abuse a network with multicast applications. To minimize the impact that applications have on a network, conscientious multicast application developers (and users) must always:
  • Minimize Scope: Don't send traffic further than you need by using an IP time-to-live (TTL) setting that corresponds to the maximum number of routers you need to traverse to reach your intended audience (session members). This can also be accomplished by using "thresholds," as configured on your multicast routers. Eventually, applications will likely use Administrative Scoping with special multicast addresses rather than TTL to limit scope.
  • Minimize Bandwidth Usage: Be aware of how much bandwidth your application requires, and what is available between your senders and receivers.
  • Schedule Usage: This relates to managing your bandwidth usage, relative to the network capacity, and current traffic load, but it also relates to port and address usage. The idea is to avoid bandwidth contention with other multicast sessions. Applications like the MBone's sd (session directory) utility and protocol can be invaluable in this effort (the protocol allows session schedule and attribute reporting, but does not allow an application to request address and port allocation).

Port and Address Considerations

With multicast applications, one refers to multicast sessions. The destination multicast address and destination port are, in effect, the session identifiers.

Any multicast application can send to and receive from different unicast addresses and port number within a single session (a multicast address is never used as a source address). In this case, a receiver can identify the sender of any datagram it receives by the source address and port number. Hence, the 5-tuple of 1) protocol, 2) local address, 3) local port number, 4) remote address and 5)remote port number comprise the unique value that identifies a message flow-all of the datagrams from any particular sender--within a session.

The session identifiers are an important consideration in the design and execution of a multicast application. On a private network, this is less of an issue, but on the Internet (or MBone) it is of paramount importance. Since any two (or more) applications using the same session parameters can interfere with each other's message flow-in effect, introducing garbage data, respectively-application developers must be careful in the choice of multicast address, port number, as well as when and where the application is used on the network.

On the MBone, the "session directory" application (sd) manages-and "advertises"-session schedules (on 224.2.2.2, port 4000). This application not only makes the multicast schedule widely available, but also assigns a unique multicast address and port number to each multicast application session (actually, to each message flow in a session). In other words, it manages the address/port space to help you to avoid conflicts. The use of sd is encouraged, if not required, on the Mbone (note: The IPMI "Higher Level Protocols Used with Multicast" white paper has more information on group setup protocols).

There is no way for an application to select a multicast address with complete safety (avoiding collisions), without using a "centralized" management scheme, like session directory. There is no way for an application to safely check whether anyone else is using a multicast address. Attempts at listening on an address for traffic, querying with IGMP for members, and trying to implement or listen to routing protocols are all strategies with limitations, difficulties and dangers.

In some (relatively rare) cases, the assignment of one or more permanent IP multicast addresses is in order. For example, standardized applications (like sd), and content providers with constant media streams warrant permanent multicast addresses. Anyone who feels they can justify an address assignment, can apply for one with the Internet Assigned Numbers Authority (IANA).

Among other things, IANA manages the multicast address space. They also maintain port number assignments for all of the Internet's well-known services (for more information, see http://www.isi.edu/iana).

 

Multicast API Limitations
Interoperability is not an API issue. The APIs are well-defined and relatively simple for IP multicast. The host implementations with full IP multicast support, all support the Internet Group Message Protocol (IGMP), according to RFC 1112 (an overview of which is covered in the IPMI white paper "How IP Multicast Works"). Virtually all host implementations of TCP/IP protocol stacks provide multicast support today. For those that do not, system patches are widely available.

Although the support of multicast on an internetwork is ultimately dependent on the multicast router protocols in use-their interoperability and ubiquity-these routing protocols do not directly affect the host implementations or multicast APIs. Conversely, the multicast APIs in a multicast host implementation have no direct effect over the router protocols either.

This dichotomy between host and router responsibilities is good. It represents a division of labor that ultimately simplifies multicast application development on hosts. However, it also sacrifices some control in multicast applications, or application "self-awareness."

For example, as a result there are no APIs to allow a multicast application to determine the multicast capability of other hosts or routers. There are no standard APIs (or protocols) available to discover how many and which hosts are receiving multicast traffic, to find the routes to those hosts, or to discover anything else about those routes. The only way for a multicast application to retrieve this information is to either implement an application protocol to exchange statistics between group members (as RTCP does; for more information see the "Higher Level Protocols used with IP Multicast" white paper).

This is not a large problem, but it is one to be aware of. If you need to know this type of information, you will need to plan on implementing support for it in your applications yourself. In particular, you'll need to implement a protocol by which session members can exchange performance, and other useful session management information.

 

Future application needs - Quality of Service
Quality of service is synonymous with bandwidth reservation. Requesting that a portion of the available network bandwidth between a sender and receiver be dedicated to each of an application's message flows. This is of particular appeal to applications that send audio and video, or other "real-time," high-bandwidth, or mission-critical data, where reliable and consistent delivery is a concern.

The IETF is close to finalizing version 1 of the ReSerVation Protocol (RSVP) for use with the Internet Protocol (both IPv4 and IPv6). Although it is still somewhat experimental, beta implementations for hosts and routers are available. Some Internet service providers (ISPs) are also providing experimental RSVP support.

Use with multicast has always been a focus of RSVP designers. Receivers initiate reservation requests, which flow "upstream" to the sender. The local system, and each router on the upstream path, can accept or reject reservation requests. Routers also "merge" reservation requests from multiple downstream receivers, as they propagate the requests toward the sender.

A receiver application can make a reservation request for itself, or on behalf of another application. To do so, requires a set of RSVP-relevant APIs. There are currently a number of standard RSVP API proposals that multicast application programmers should be aware of for possible future enhancement of their applications:

  • The Internet Draft RFC, RSVP Application Programming Interface (RAPI) for SunOS/BSD: v4.0, by Braden and Hoffman describes a set of APIs that provide low-level access to the protocol services
  • The WinSock 2 Application Programming Interface specification has a set of easy to use, generic (protocol-independent) APIs that will map to RSVP services.
  • The WinSock 2 Protocol-Specific Annex specification has some RSVP protocol-specific APIs available for low-level access to the protocol services

 

Concluding Remarks
IP Multicast enables many new types of applications and reduces network congestion and server loads. This document began by describing the types of applications that can most benefit from multicast, and what is required for an application to be eligible for multicast-enabling.

Converting unicast datagram applications to take advantage of multicast requires the use of only a few multicast-specific APIs to override some of the defaults in a unicast datagram application. Senders need only send to a multicast address and adjust the IP time-to-live according to the desired scope, and possibly disable the loopback. A receiver need only join a multicast group.

On the other hand, converting applications that currently use reliable, connection-oriented protocols (TCP) to multicast (UDP) can be a significant challenge. We only had a brief discussion of this topic; some effective products shipping already, but standard protocols for reliable multicast are still a subject of research.

We also considered what it takes to make sure your multicast application remains network friendly. And finally, we briefly mentioned near-future APIs relevant to many multicast applications, to provide the bandwidth reservation (using RSVP).

 

Code Samples
This section contains three code samples, that demonstrate how to use each of the three APIs described in the "Standard Multicast APIs" section of this white paper. Each sample does basically the same thing (and they can communicate with each other): Each application acts as both a sender and receiver (as both a client application and a server, per se):
  • Gets a datagram (UDP) communication endpoint (a.k.a., a "socket")
  • Names the socket (we arbitrarily use port 3456)
  • Joins a multicast group (we arbitrarily selected 234.5.6.7)
  • Sets the IP TTL (we set TTL to a value of 2 so datagrams can traverse a single multicast-capable router "hop", but no more, in order to minimize network impact)
  • Disables loopback
  • Sends a datagram, then waits to receive a datagram (it will appear to do nothing as it waits)
  • When it receives a datagram, it prints the message and the address of the sender, then sends another datagram in response

When you start a second instance of any of these test applications, the datagram that the second instance sends will trigger the first to send again, and that will trigger the second instance to send again, and so on, in a loop. In other words, two (or more) applications running have a Ping-Pong effect between each other.

Please use with caution! This sample program is for demonstration only. The number of iterations is limited purposefully, since this application is capable of generating significant network traffic. Because it sends a datagram in immediate response to every datagram it receives, without a limit this application is capable of flooding a network with traffic.

Also note that, for brevity, we have removed error checking from the function calls in these samples. We strongly encourage you to check the returns from all function calls in your own application code.

Application Requirements

To use this application on any system, it must be IP Multicast-capable. Each of the three platforms we deal with here fulfill this in different ways:

  • Unix systems must have the relevant kernel patches installed
  • Windows systems must have WinSock 2 installed, or a WinSock 1.1 implementation that supports the BSD multicast APIs
  • Apple systems must have Open Transport installed with TCP/IP support

It is not necessary to be connected to the MBone to use these applications, nor even to have a multicast capable router installed. You can use these applications on a single subnet between hosts. In fact, you can even use these on a single host--without any active network connection, in some cases--if you disable loopback in the application.

Berkeley Sockets multicast code sample

The following code snippet illustrates the use of all the Berkeley Sockets the multicast APIs, except IP_MULTICAST_IF.

[Download the source code]

#include <sys/types.h>   /* include files for IP Sockets */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFSIZE   1024
#define TTL_VALUE 2
#define TEST_ADDR "234.5.6.7"
#define TEST_PORT 3456
#define LOOPMAX 10
int main(){
  struct sockaddr_in stLocal, stTo, stFrom;
  char achIn[BUFSIZE];
  char achOut[] = "Message number:              ";
  int s;
  struct ip_mreq stMreq;
  int iTmp, i;

  /* get a datagram socket */
  s = socket(AF_INET, SOCK_DGRAM, 0);

  /* avoid EADDRINUSE error on bind() */ 
  iTmp = TRUE;
  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 
 (char *)&iTmp, sizeof(iTmp));

  /* name the socket */
  stLocal.sin_family = 	 AF_INET;
  stLocal.sin_addr.s_addr = htonl(INADDR_ANY);
  stLocal.sin_port = 	 htons(TEST_PORT);
  bind(s, (struct sockaddr*) &stLocal, sizeof(stLocal));

  /* join the multicast group. */
  stMreq.imr_multiaddr.s_addr = inet_addr(TEST_ADDR);
  stMreq.imr_interface.s_addr = INADDR_ANY;
  setsockopt(s, 
     IPPROTO_IP, 
     IP_ADD_MEMBERSHIP, 
     (char *)&stMreq, 
     sizeof(stMreq));

  /* set TTL to traverse up to multiple routers */
  iTmp = TTL_VALUE;
  setsockopt(s, 
     IPPROTO_IP, 
     IP_MULTICAST_TTL, 
     (char *)&iTmp, 
     sizeof(iTmp));

  /* disable loopback */
  iTmp = FALSE;
  setsockopt(s, 
     IPPROTO_IP, 
     IP_MULTICAST_LOOP, 
     (char *)&iTmp, 
     sizeof(iTmp));

  /* assign our destination address */
  stTo.sin_family =      AF_INET;
  stTo.sin_addr.s_addr = inet_addr(TEST_ADDR);
  stTo.sin_port =        htons(TEST_PORT);

  for (i=0;i<LOOPMAX;i++) {
    int addr_size = sizeof(struct sockaddr_in);
    static iCounter = 1;
    int i;

    /* send to the multicast address */
    itoa(iCounter++, &achOut[16], 10);
    i = sendto(s, achOut, sizeof(achOut), 
      0,(struct sockaddr*)&stTo, addr_size);
    if (i < 0) {
perror("sendto() failed\n");
      exit(1);
    }

    i = recvfrom(s, achIn, BUFSIZE, 0,
      (struct sockaddr*)&stFrom, &addr_size);
    if (i < 0) {
      perror("recvfrom() failed\n");
      exit(1);
    }
    printf("From host:%s port:%d, %s\n",
      inet_ntoa(stFrom.sin_addr), 
      ntohs(stFrom.sin_port), achIn);
  }
} /* end main() */  

WinSock 2 protocol-independent multicast-code sample

The following code sample uses function calls described in the Windows Sockets 2 Application Programming Interface specification. Many of these functions are protocol-independent equivalents of Berkeley Sockets functions, and could be replaced by them. Actually, because WinSock 2 also supports the protocol-specific BSD multicast APIs, with the addition of calls to WSAStartup() and WSACleanup() at the beginning and end, the BSD sample program above can be used with WinSock 2 implementations.

Note: At the time of this writing, WinSock 2 is shipping as the native network interface on Windows NT version 4, and is in beta for Windows 95. The calls to disable loop back (using either setsockopt() IF_MULTICAST_LOOP or WSAIoctl() SIO_MULTIPOINT_LOOPBACK) always fail, as does the call to WSIoctl() SIO_MULTICAST_SCOPE (the equivalent setsockopt() IP_MULTICAST_TTL does work, however). Since you cannot disable loopback, you need only run a single instance on a machine to see it in action sending to and receiving from itself.

[Download the source code]


#include <winsock2.h>
#define BUFSIZE     1024
#define MAXADDRSTR  16
#define LOOPMAX 10
int main() {
    int nRet, i;
    int nIP_TTL = 2;
    BOOL  bFlag;
    DWORD dFlag;
    DWORD cbRet;
    int iLen = MAXADDRSTR;
    char strDestMulti[MAXADDRSTR] = "234.5.6.7";
    SOCKADDR_IN stSrcAddr, stDestAddr;
    SOCKET hSock, hNewSock;
    u_short nDestPort = 3456;
    WSABUF stWSABuf;
    char achInBuf [BUFSIZE];
    char achOutBuf[] = "Message number:           ";
    WSADATA stWSAData;

    /* init WinSock */
    WSAStartup(0x0202, &stWSAData);

    /* convert address string to value */
    stDestAddr.sin_family = AF_INET; 
    nRet = WSAStringToAddress (
      strDestMulti,    			/* address string */
      AF_INET,         			/* address family */
      NULL,            			/* protocol info structure */
      (LPSOCKADDR)&stDestAddr,/* socket address string */
      &iLen);          			/* length of socket structure */

    /* get a socket */
    hSock = WSASocket(AF_INET, SOCK_DGRAM, 0,
    (LPWSAPROTOCOL_INFO)NULL, 0, 
    WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF);

    /* allow reuse of the local port number */
    bFlag = TRUE;
    nRet = setsockopt(hSock, SOL_SOCKET, SO_REUSEADDR, 
      (char *)&bFlag, sizeof (bFlag));

    /* name the socket */
    stSrcAddr.sin_family = PF_INET;
    stSrcAddr.sin_port = htons (nDestPort);
    stSrcAddr.sin_addr.s_addr = INADDR_ANY;
    nRet = bind (hSock, 
	(struct sockaddr FAR *)&stSrcAddr, 
	sizeof(struct sockaddr));

    /* byte swap host to network order */
    stDestAddr.sin_family = PF_INET;
    nRet = WSAHtons(
		hSock,			/* socket */
		nDestPort,		/* host order value */
		&(stDestAddr.sin_port)); /* network order value */

    /* set the IP TTL */ 
    nRet = WSAIoctl (hSock,   		/* socket */
      SIO_MULTICAST_SCOPE,    		/* IP Time-To-Live */
      &nIP_TTL,               		/* input */
      sizeof (nIP_TTL),        		/* size */
      NULL,                    		/* output */
      0,                       		/* size */
      &cbRet,                  		/* bytes returned */
      NULL,                    		/* overlapped */
      NULL);                   		/* completion routine */

    /* disable loopback */
    bFlag = FALSE;
    nRet = WSAIoctl (hSock,    		/* socket */
      SIO_MULTIPOINT_LOOPBACK,		/* turn loopBack off */
      &bFlag,				/* input */
      sizeof (bFlag),      		/* size */
      NULL,                  		/* output */
      0,		        	/* size */
      &cbRet,            		/* bytes returned */
      NULL,         	 		/* overlapped */
      NULL);                     	/* completion routine */

    /* join the multicast group */
    NewSock = WSAJoinLeaf (hSock,	/* socket */
      (PSOCKADDR)&stDestAddr, 		/* multicast address */
      sizeof (stDestAddr),    		/* length of addr struct */	
      NULL,                   		/* caller data buffer */
      NULL,                   		/* callee data buffer */
      NULL,                   		/* socket QOS setting */
      NULL,                   		/* socket group QOS */
      JL_BOTH);               		/* do both: send and recv */

    /* send and receive loop */
    for (i=0;i<LOOPMAX;i++) {
      static iCounter = 1;

      /* send data */
      stWSABuf.buf = achOutBuf;
      stWSABuf.len = lstrlen(achOutBuf);
      cbRet = 0;
      itoa(iCounter++, &achOutBuf[16], 10);
      nRet = WSASendTo (hSock,   	/* socket */
		  &stWSABuf,    	/* output buffer structure */
		  1,            	/* buffer count */
		  &cbRet,       	/* number of bytes sent */
		  0,	        	/* flags */
		  (struct sockaddr*)&stDestAddr,/* destination address */
		  sizeof(struct sockaddr), /* size of addr structure */
		  NULL,	        	/* overlapped structure */
		  NULL);        	/* overlapped callback */

		if (nRet == SOCKET_ERROR) {
		  printf("WSASendTo() failed, Err: %d\n",
 		  WSAGetLastError());
		}

		stWSABuf.buf = achInBuf;
		stWSABuf.len = BUFSIZE;
		cbRet = 0;
		iLen = sizeof (stSrcAddr);
		dFlag = 0;
    		nRet = WSARecvFrom (hSock, /* socket */
		  &stWSABuf,	      /* input buffer structure */
		  1,                       /* buffer count */
		  &cbRet,                  /* number of bytes recv'd */
		  &dFlag,                  /* flags */
        	  (struct sockaddr *)&stSrcAddr,/* source address */
		  &iLen,                   /* size of addr structure */
		  NULL,                    /* overlapped structure */
		  NULL);                   /* overlapped callback */

		if (nRet == SOCKET_ERROR) {
			printf("WSARecvFrom() failed, Err:%d\n",
  			WSAGetLastError());
		} else {
			/* convert address value to string */
			u_short nPort = 0;
			char achAddr[BUFSIZE];
			iLen = BUFSIZE;
			nRet = WSAAddressToString(
				(struct sockaddr *)&stSrcAddr,/* source address */
				sizeof(stSrcAddr),  /* size of addr struct */
				NULL,               /* protocol info */
				achAddr,            /* address string */
				&iLen);             /* addr string buf len */
			
		        /* convert from network to host byte order */
			nRet = WSANtohs(hSock, /* socket */
				stSrcAddr.sin_port, /* host order value */
				&nPort);            /* network order value */
			}
		        printf ("Message from %s, port %d: %s\r\n",
			   achAddr[0] ? achAddr : "??", nPort, achInBuf);
	    }
	} /* end for(;;) */

  /* tell WinSock we're leaving */
  WSACleanup();

  return (0);
} /* end main() */

Open Transport multicast code sample

The Open Transport /TCP Developer Note specification from Apple Computer describes IP protocol-specifics, including the APIs for IP multicast support. These APIs differ from BSD Sockets, but they are modeled after BSD Sockets to an extent. There are many equivalencies: Most importantly, the multicast options used by the OTOptionManagement() function, are the same as the setsockopt() multicast options.

[Download the source code]

#include <stdio.h>
#include <OpenTransport.h>
#include <OpenTptInternet.h>

#define BUFSIZE   128
#define TTL_VALUE 2
#define TEST_ADDR 0xEA050607; /* 234.5.6.7 */
#define TEST_PORT 3456
#define IADDRLEN  16

void main() {
  int i;
  OSStatus err;
  EndpointRef udp_ep = nil;
  UInt8 buf[BUFSIZE];
  UInt8 bufOut = "Message number:               ";
  InetAddress IAddrBuf;    /* same as BSD struct sockaddr_in */
  InetAddress src_addr, dest_addr;
  TBind     BindReq, BindRet;
  TOption*  OptBuf;
  TOptMgmt  OptReq, OptRet;
  TIPAddMulticast MCAddr;  /* same as BSD struct mreq */
  TUnitData udata;

  /* Init Open Transport */
  err = InitOpenTransport();

  /* get a datagram endpoint */
  *ep = OTOpenEndpoint(
      OTCreateConfiguration(kUDPName), 0, nil, &err)

  /* name the endpoint */
  BindReq.addr.len = IADDRLEN;
  BindReq.addr.buf = &IAddrBuf;
  OTInitInetAddress (&IAddrBuf, TEST_PORT, 0L);
  err = OTBind (*ep, &BindReq, &BindRet);

  /* join the multicast group */
  OptBuf = (*TOption)buf;
  OptBuf->level  = INET_IP;
  OptBuf->name   = IP_ADD_MEMBERSHIP;
  OptBuf->len    = BUFSIZE;
  OptBuf->status = 0;
  *(TIPAddMulticast *)OptBuf->value = &MCAddr;
  MCAddr.multicastGroupAddress = TEST_ADDR;
  MCAddr.multicastAddress      = 0L;

  OptReq.opt.buf   = &MCAddr;
  OptReq.opt.len   = sizeof(TIPAddMulticast);
  OptReq.opt.flags = T_CHECK;
  
  OptRet.opt.buf    = buf;
  OptRet.opt.maxlen = BUFSIZE;
  err = OTOptionManagement (ep, &OptReq, &OptRet);

  /* set TTL to traverse multiple routers */
  OptBuf->level  = INET_IP;
  OptBuf->name   = IP_MULTICAST_TTL;
  OptBuf->len    = BUFSIZE;
  OptBuf->status = 0;
  *(UInt8 *)OptBuf->value = TTL_VALUE;
  
  OptReq.opt.buf   = buf;
  OptReq.opt.len   = kOTOneByteOptionSize;
  OptReq.opt.flags = T_CHECK;
  
  OptRet.opt.buf    = buf;
  OptRet.opt.maxlen = kOTFourByteOptionSize;
  err = OTOptionManagement (ep, &OptReq, &OptRet);

  /* disable loopback */
  OptBuf->level  = INET_IP;
  OptBuf->name   = IP_MULTICAST_LOOP;
  OptBuf->len    = BUFSIZE;
  OptBuf->status = 0;
  *(UInt8 *)OptBuf->value = 0;
  
  OptReq.opt.buf   = buf;
  OptReq.opt.len   = kOTOneByteOptionSize;
  OptReq.opt.flags = T_CHECK;
  
  OptRet.opt.buf    = buf;
  OptRet.opt.maxlen = kOTFourByteOptionSize;
  err = OTOptionManagement (ep, &OptReq, &OptRet);

  /* assign our destination address */
  OTInitInetAddress (&dest_addr, TEST_PORT, TEST_ADDR);
  
  for (i=0; i<MAXLOOP; i++) {
    OTResult look;
    static iCounter = 1;
	  
    udata.addr.len = sizeof(dest_addr);
    udata.addr.buf = (unsigned char *) &dest_addr;
	  
    udata.opt.len = 0;
    udata.opt.buf = nil;
	  
    itoa(iCounter++, &bufOut[16], 10);
    udata.udata.len = sizeof(bufOut);
    udata.udata.buf = bufOut;
	  
    err = OTSndUData (ep, &udata);
    if (err != noErr) {
      printf ("OTSndUData() failed: %d\n, err);
    }
	  
    udata.addr.buf    = (UInt8 *) &src_addr;
    udata.addr.maxlen = sizeof (struct InetAddress);
	  
    udata.opt.buf    = nil;
    udata.opt.maxlen = 0;
	  
    udata.udata.buf    = buf;
    udata.udata.maxlen = BUFSIZE;
	  
    err = OTRcvUData (ep, &udata, nil);
    if (err == noErr) {
      printf ("From host: 0x%lx, %s\n", buf);
    } else {
      printf ("OTRcvUData() failed: %d\n, err);
    }
  }
  
  /* close the endpoint */
  OTCloseProvider (ep);

  /* sign-off Open Transport */
  CloseOpenTransport();

} /* end main() */
More Information
IP Multicast Initiative (IPMI)

There are many other technical aspects of IP Multicast and business benefits that were not discussed here. The IP Multicast Initiative web site at http://www.ipmulticast.com/ has a technical resource center which provides more background in-depth information including white papers and relevant RFC’s. The web site also offers a product and services directory and lists members of the IP Multicast Initiative who can be contacted for information and assistance.

The IP Multicast Initiative provides marketing and educational services to promote the creation, use and deployment of multicast products and solutions. Supported by a growing number of the most important vendors in the IP Multicast arena, the Initiative and its services are managed and provided by Stardust.com, Inc.

For more information about the Initiative and membership, or to see other white papers, contact Stardust.com at 408-879-8080 or visit the Initiative web site.

 

Useful References
The following references are recommended; many were used in the preparation of this document. The authors are gratefully acknowledged.

Books

Apple Computer, Open Transport Client Developer Note, preliminary revision 1.1.1b6, 7/30/96 http://devworld.apple.com/dev/opentransport/docs/Open_Tpt_TCP_IP_Dev_Note.pdf

Apple Computer, Open Transport/TCP Developer Note, revision 1.1.1b6, 8/7/96 http://devworld.apple.com/dev/opentransport/docs/Open_Transport_Client_Note.pdf

Steve Deering, IP Multicast Extensions for 4.3BSD and Related Systems, Stanford University, 1989 http://portal.research.bell-labs.com/ipmulticast.README.new

Christian Huitema, IPv6: The New Internet Protocol, Prentice-Hall, 1996, ISBN 0-13-241936-X

Vinay Kumar, MBONE: Interactive Media on the Internet, New Riders, 1996 ISBN 1-56205-397-3. See pages 168-169 for a description of the kernel patches available for a number of Unix systems.

Open Software Foundation, OSF/1 Operating System: Network Applications Programmer's Guide, Prentice Hall, ISBN 0-13-640145-7

Bob Quinn and Dave Shute, Windows Sockets Network Programming, Addison-Wesley, 1996, ISBN 0-201-63372-8 http://www.sockets.com/

W.Richard Stevens, TCP/IP Illustrated, Volume 1 - The Protocols, Addison-Wesley, 1994, ISBN 0-201-63346-9

W.Richard Stevens, Unix Network Programming, The bible for Berkeley Sockets, although it doesn't include multicast APIs, Prentice-Hall, 1990, ISBN 0-13-949876-1

Windows Sockets 2 Application Programming Interface, revision 2.2.0 http://www.intel.com/ial/winsock2/specs.htm

Windows Sockets 2 Protocol-Specific Annex, revision 2.0.3, contains Sockets-compatible multicast APIs (in TCP/IP section), and RSVP APIs. http://www.intel.com/ial/winsock2/specs.htm

Gary R. Wright, W.Richard Stevens, TCP/IP Illustrated, Volume 2 - The Implementation, Addison-Wesley, 1995, ISBN 0-201-63354-X

IETF RFCs

[ See http://ds.internic.net/rfc/rfcnnnn.txt, where nnnn is the RFC number]:

RFC 1112 Host Extensions for IP Multicasting

RFC 1700 Assigned Numbers by Internet Assigned Numbers Authority (IANA). For the latest number assignments of multicast addresses, among (many) other things see http://www.isi.edu/iana

IETF RFCs (as of 11/96)

[ See ftp://ietf.org/internet-drafts/xxx, where xxx is the draft file name]:

Advanced Sockets API for IPv6 [draft-stevens-advanced-api-00.txt]

Resource ReSerVation Protocol (RSVP) - Version 1 Functional Specification [draft-ietf-rsvp-spec-14.txt]

RSVP Application Programming Interface (RAPI) for SunOS/BSD: v4.0 [draft-ietf-rsvp-bsdapi.txt] (ftp://ftp.isi.edu/rsvp/docs/rsvpapi.txt)

 

Rev:042997-01

© Copyright 1995-1997 Stardust Technologies, Inc. All Rights Reserved. Stardustâ is a registered trademark of Stardust Technologies. All trademarks acknowledged. IPMI is a division of Stardust Labs.

RESTRICTED RIGHTS LEGEND

USE, DUPLICATION, OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO RESTRICTIONS AS SET FORTH IN SUBPARAGRAPH (c) (1) (ii) OF THE RIGHTS IN TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013 or subparagraphs (c) (1) and (2) of Commercial Computer Software—Restricted Rights at 48 CFR 52.227-19, as applicable.

Stardust Technologies Inc. 1901 S. Bascom Ave., Suite 333, Campbell, CA 95008