Sie sind auf Seite 1von 48

Chaptere19

multicasting

contents

multicast address
multicasting versus broadcasting on a LAN
multicasting on a WAN
multicast socket option
mcast_join and related function
dg_cli function using multicasting
receiving MBone session announcements
sending and receiving
SNTP

MULTICASTING

TCP/IP Protocol
Suite

Difference b/w multicasting and multiple unicasting

Multicasting starts with one single packet from the source that is duplicated by the
routers. The destination address in each packet is the same for all duplicates
In multiple unicasting, several packets start from the source with different
destination address. For example, when a person sends an e-mail message to a
group of people, this is multiple unicasting. The e-mail software creates replicas of
the message, each with a different destination address, and sends them one by one.

TCP/IP Protocol
Suite

Applications of Multicasting

Teleconferencing
Distance Learning
Dissemination of News
Access to distributed database

TCP/IP Protocol
Suite

Multicast Address
A multicast address is a destination address for a group of hosts
that have joined a multicast group.
A packet that uses a multicast address as a destination can reach
all members of the group unless there are some filtering
restriction by the receiver.
Multicast Address used in IPV4: In classful addressing,
multicast addresses occupied the only single block in class D. In
classless addressing the same block has been used for this
purpose.
In other words, the block assigned for multicasting is 224.0.0.0/4.
This means that the block has 2^28 = 268,435,456 addresses
(224.0.0.0 to 239,255.255.255).
TCP/IP Protocol
Suite

Delivery of Multicast Packets at Data Link Layer

Because the IP packet has a multicast IP address, the ARP protocol cannot
find the corresponding MAC (physical) address to forward the packet at
the data link layer.
What happens next depends on whether or not the underlying data link
layer supports physical multicast addresses.
Most LANs support physical multicast addressing. Ethernet is one of them.
An Ethernet physical address (MAC address) is six octets (48 bits) long. If
the first 25 bits in an Ethernet address are 00000001 00000000 01011110
0, this identifies a physical multicast address for the TCP/IP protocol.
The remaining 23 bits can be used to define a group.
To convert an IP multicast address into an Ethernet address, the multicast
router extracts the least significant 23 bits of a multicast IP address and
inserts them into a multicast Ethernet physical address

TCP/IP Protocol
Suite

Figure 10.10 Mapping class D to Ethernet


physical address

TCP/IP Protocol
Suite

Note:
An Ethernet multicast physical address
is in the range
01:00:5E:00:00:00
to
01:00:5E:7F:FF:FF.

TCP/IP Protocol
Suite

Example 2

Change the multicast IP address 230.43.14.7 to an Ethernet


multicast physical
Solution
We can do this in two steps:
a. We write the rightmost 23 bits of the IP address in hexadecimal. This
can be done by changing the rightmost 3 bytes to hexadecimal and then
subtracting 8 from the leftmost digit if it is greater than or equal to 8. In
our example, the result is 2B:0E:07.
b. We add the result of part a to the starting Ethernet multicast address,
which is (01:00:5E:00:00:00). The result is

01:00:5E:2B:0E:07
TCP/IP Protocol
Suite

10

Example 3

Change the multicast IP address 238.212.24.9 to an Ethernet


multicast address.
Solution
a. The right-most three bytes in hexadecimal are D4:18:09. We need to
subtract 8 from the leftmost digit, resulting in 54:18:09..
b. We add the result of part a to the Ethernet multicast starting address.
The result is

01:00:5E:54:18:09

TCP/IP Protocol
Suite

11

Unicast
a single interface

broadcast
multiple interfaces
LAN

multicast
a set of interfaces
LAN or WAN
Mbone
five socket opetions

multicast address
IPv4 class D address
224.0.0.0 ~ 239.255.255.255
(224.0.0.1: all hosts group), (224.0.0.2: all-routers group)

multicast address(2)
IPv6 multicast address
special IPv6 multicast address (flags)
ff02::1 => all-nodes group(all multicast-capable hosts on subnet
must join this group on all multicast-capable interfaces)
ff02::2 => all-routers group(all multicast-capable routers on subnet
must join this group on all multicast-capable interfaces)

Scope of multicast addresses


IPv6 multicast address have an explicit 4-bit scope field
that specifies how far the multicast packet will travel.

Node-local (1)
link-local (2)
site-local (5)
organization-local (8)
global (14)

remaining values are unassigned or reserved

*Organization must set its boundary routers not to forward


multicast packets outside network

multicasting versus broadcasting on a


LAN
One host sends a multicast packet and any interested host
receives the packet.
Benefit
reducing the load on all the hosts not interested in the multicast
packets

multicasting on a WAN

A host sends the audio packets and the multicast receivers are
waiting to receive

MRP: Multicast Routing Protocol

multicast socket option


The API support for multicasting requires only five new
socket options.
Figure 19.7

multicast socket option(2)


IP_ADD_MEMBERSHIP, IPV6_ADD_MEMBERSHIP

join a multicast group on s specified local


interface.
Struct ip_mreq{
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};

Struct ipv6_mreq{
struct in6_addr ipv6mr_multiaddr;
struct int ipv6mr_interface;
};

multicast socket option(3)

IP_DROP_MEMBERSHIP, IPV6_DROP_MEMBERSHIP

leave a multicast group on a specified local


interface.
If the local interface is not specified, the first
matching multicasting group membership is
dropped.

multicast socket option(4)


IP_MULTICAST_IF, IPV6_MULTICAST_IF
specify the interface for outgoing multicast
datagrams sent on this socket.
This interface is specified as either an in_addr
structure for IPv4 or an interface index for
IPv6.

multicast socket option(5)


IP_MULTICAST_TTL, IPV6_MULTICAST_TTL

set the IPv4 TTL or the IPv6 hop limit for


outgoing multicast datagrams.
If this is not specified , both default to 1, which
restricts the datagram to the local subnet.

multicast socket option(6)


IP_MULTICAST_LOOP, IPV6_MULTICAST_LOOP

enable or disable local loopback of multicast


datagrams.
Default loopback is enabled.
This is similar to broadcasting.

mcast_join and related function


#include unp.h
int mcast_join(int sockfd, const struct sockaddr *addr, socklen_t salen, const char
*ifname, u_int ifindex);
int mcast_leave(int sockfd, const struct sockaddr *addr, socklen_t salen);
int mcast_set_if(int sockfd, const char *ifname, u_int ifindex);
int mcast_set_loop(int sockfd, int flag);
int mcast_set_ttl(int sockfd, int ttl);
All above return :0 if ok, -1 on error
int mcast_get_if(int sockfd);
return : nonnegative interface index if OK, -1 error
int mcast_get_loop(int sockfd);
return : current loopback flag if OK, -1 error
int mcast_get_ttl(int sockfd);
return : current TTL or hop limit if OK, -1 error

#include "unp.h"
#include <net/if.h>
int mcast_join(int sockfd, const SA *sa, socklen_t salen, const char *ifname, u_int ifindex)
{
switch (sa->sa_family) {
case AF_INET: {
struct ip_mreq mreq;
struct ifreq
ifreq;
memcpy(&mreq.imr_multiaddr, &((struct sockaddr_in *) sa)->sin_addr,
sizeof(struct in_addr));
if (ifindex > 0) {
if (if_indextoname(ifindex, ifreq.ifr_name) == NULL) {
errno = ENXIO; /* i/f index not found */
return(-1);
}
goto doioctl;
} else if (ifname != NULL) {
strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
doioctl:
if (ioctl(sockfd, SIOCGIFADDR, &ifreq) < 0)
return(-1);
memcpy(&mreq.imr_interface,
&((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr,
sizeof(struct in_addr));
} else
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
return(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)));
}

#ifdef
IPV6
case AF_INET6: {
struct ipv6_mreq mreq6;
memcpy(&mreq6.ipv6mr_multiaddr, &((struct sockaddr_in6 *) sa)->sin6_addr,
sizeof(struct in6_addr));
if (ifindex > 0)
mreq6.ipv6mr_interface = ifindex;
else if (ifname != NULL)
if ( (mreq6.ipv6mr_interface = if_nametoindex(ifname)) == 0) {
errno = ENXIO; /* i/f name not found */
return(-1);
}
else
mreq6.ipv6mr_interface = 0;
return(setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
&mreq6, sizeof(mreq6)));
}
#endif
default:
errno = EPROTONOSUPPORT;
return(-1);
}
}

#include "unp.h"
int mcast_set_loop(int sockfd, int onoff)
{
switch (sockfd_to_family(sockfd)) {
case AF_INET: {
u_char
flag;
flag = onoff;
return(setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
&flag, sizeof(flag)));
}
#ifdef
IPV6
case AF_INET6: {
u_int flag;
flag = onoff;
return(setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
sizeof(flag)));
}
#endif

default:
errno = EPROTONOSUPPORT;
return(-1);
}

&flag,

dg_cli function using multicasting

Receiving MBone session announcements


To receive a multimedia conference on the MBone a
site needs to know only the multicast address of the
conference and the UDP ports for the conferences
data streams.(audio, video)
SAP(Session Announce Protocol)
describe the way

SDP(Session Description Protocol)


the contents of these announcements

A site wishing to announce a session on the Mbone


periodically sends a multicast packet containing a description of the session
to a well-known multicast group and UDP port

Sites on Mbone
run sdr program
receives these announcements
provides an interactive user interface that displays the information
lets user send announcements

A sample program
only receives these session announcements to show an example of a simple
multicast receiving program

The program receiving the periodic SAP/SDP announcements


#include "unp.h"
#define SAP_NAME
"sap.mcast.net"
#define SAP_PORT
"9875"
void
loop(int, socklen_t);
int main(int argc, char **argv)
{
int sockfd;
const int
on = 1;
socklen_t
salen;
struct sockaddr *sa;

/* default group name and port */

if (argc == 1)
sockfd = Udp_client(SAP_NAME, SAP_PORT, (void **) &sa, &salen);
else if (argc == 4)
sockfd = Udp_client(argv[1], argv[2], (void **) &sa, &salen);
else err_quit("usage: mysdr <mcast-addr> <port#> <interface-name>");

Setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));


Bind(sockfd, sa, salen);
Mcast_join(sockfd, sa, salen, (argc == 4) ? argv[3] : NULL, 0);
loop(sockfd, salen);
/* receive and print */
exit(0);

#include "unp.h"
void loop(int sockfd, socklen_t salen)
{ char buf[MAXLINE+1];
socklen_t
len;
ssize_t
n;
struct sockaddr *sa;
struct sap_packet {
uint32_t
sap_header;
uint32_t
sap_src;
char sap_data[1];
} *sapptr;
sa = Malloc(salen);
for ( ; ; ) {
len = salen;
n = Recvfrom(sockfd, buf, MAXLINE, 0, sa, &len);
buf[n] = 0;
/* null terminate */
sapptr = (struct sap_packet *) buf;
if ( (n -= 2 * sizeof(uint32_t)) <= 0)
err_quit("n = %d", n);
printf("From %s\n%s\n", Sock_ntop(sa, len), sapptr->sap_data);
}
}

sending and receiving


Sends and receives multicast datagrams
First part
sends a multicast datagram to a specific group
every 5 seconds and the datagram contains the
senders hostname and process ID

Second part
an infinite loop that joins the multicast group to
which the first part is sending and prints every
received datagrams

#include
void
void

"unp.h"
recv_all(int, socklen_t);
send_all(int, SA *, socklen_t);

int main(int argc, char **argv)


{
int
sendfd, recvfd;
const int
on = 1;
socklen_t
salen;
struct sockaddr *sasend, *sarecv;
if (argc != 3) err_quit("usage: sendrecv <IP-multicast-address> <port#>");
sendfd = Udp_client(argv[1], argv[2], (void **) &sasend, &salen);
recvfd = Socket(sasend->sa_family, SOCK_DGRAM, 0);
Setsockopt(recvfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
sarecv = Malloc(salen);
memcpy(sarecv, sasend, salen);
Bind(recvfd, sarecv, salen);
Mcast_join(recvfd, sasend, salen, NULL, 0);
Mcast_set_loop(sendfd, 0);

if (Fork() == 0)
recv_all(recvfd, salen);

/* child -> receives */

send_all(sendfd, sasend, salen);

/* parent -> sends */

#include "unp.h"
#include <sys/utsname.h>
#define SENDRATE

/* send one datagram every 5 seconds */

void
send_all(int sendfd, SA *sadest, socklen_t salen)
{
static char
line[MAXLINE];
struct utsname myname;

/* hostname and process ID */

if (uname(&myname) < 0)
err_sys("uname error");;
snprintf(line, sizeof(line), "%s, %d\n", myname.nodename, getpid());
for ( ; ; ) {
Sendto(sendfd, line, strlen(line), 0, sadest, salen);
sleep(SENDRATE);
}
}

#include "unp.h"
void
recv_all(int recvfd, socklen_t salen)
{
int
n;
char
line[MAXLINE+1];
socklen_t
len;
struct sockaddr
*safrom;
safrom = Malloc(salen);
for ( ; ; ) {
len = salen;
n = Recvfrom(recvfd, line, MAXLINE, 0, safrom, &len);
line[n] = 0;
/* null terminate */
printf("from %s: %s", Sock_ntop(safrom, len), line);
}
}

SNTP
NTP => so sophisticated protocol
SNTP => simplified version of NTP
hosts do not need the complexity of a complete NTP
implementation.
A client listening for NTP broadcast or multicasts on
all attached networks and then prints the time
difference between the NTP packet and the hosts
current time-of-day

#define JAN_1970 2208988800UL


/* 1970 - 1900 in seconds */
struct l_fixedpt {
/* 64-bit fixed-point */
uint32_t int_part;
uint32_t fraction; };
struct s_fixedpt {
/* 32-bit fixed-point */
u_short int_part;
u_short fraction; };
struct ntpdata {
/* NTP header */
u_char status;
u_char stratum;
u_char ppoll;
int precision:8;
struct s_fixedpt
distance;
struct s_fixedpt
dispersion;
uint32_t refid;
struct l_fixedpt
reftime;
struct l_fixedpt
org;
struct l_fixedpt
rec;
struct l_fixedpt
xmt; };
#define
#define

VERSION_MASK
MODE_MASK

0x38
0x07

#define
#define
#define

MODE_CLIENT
3
MODE_SERVER
4
MODE_BROADCAST

#include "sntp.h"
int main(int argc, char **argv)
{
int
sockfd;
char
buf[MAXLINE];
ssize_t
n;
socklen_t
salen, len;
struct ifi_info
*ifi;
struct sockaddr
*mcastsa, *wild, *from;
struct timeval
now;
if (argc != 2)

err_quit("usage: ssntp <IPaddress>");

sockfd = Udp_client(argv[1], "ntp", (void **) &mcastsa, &salen);


wild = Malloc(salen);
memcpy(wild, mcastsa, salen);
/* copy family and port */
sock_set_wild(wild, salen);
Bind(sockfd, wild, salen); /* bind wildcard */

Figure 19.18 ( 2/2 )


#ifdef
MCAST
/* 4obtain interface list and process each one */
for (ifi = Get_ifi_info(mcastsa->sa_family, 1); ifi != NULL;
ifi = ifi->ifi_next) {
if (ifi->ifi_flags & IFF_MULTICAST)
Mcast_join(sockfd, mcastsa, salen, ifi->ifi_name, 0);
printf("joined %s on %s\n",
Sock_ntop(mcastsa, salen), ifi->ifi_name);
}
#endif
from = Malloc(salen);
for ( ; ; ) {
len = salen;
n = Recvfrom(sockfd, buf, sizeof(buf), 0, from, &len);
Gettimeofday(&now, NULL);
sntp_proc(buf, n, &now);
}
}

#include "sntp.h
void sntp_proc(char *buf, ssize_t n, struct timeval *nowptr)
{
int version, mode;
uint32_t
nsec, useci;
double
usecf;
struct timeval curr, diff;
struct ntpdata *ntp;
if (n < sizeof(struct ntpdata)) {
printf("\npacket too small: %d bytes\n", n);
return;
}
ntp = (struct ntpdata *) buf;
version = (ntp->status & VERSION_MASK) >> 3;
mode = ntp->status & MODE_MASK;
printf("\nv%d, mode %d, strat %d, ", version, mode, ntp->stratum);
if (mode == MODE_CLIENT) {
printf("client\n");
return;
}

nsec = ntohl(ntp->xmt.int_part) - JAN_1970;


useci = htonl(ntp->xmt.fraction); /* 32-bit integer fraction */
usecf = useci;
/* integer fraction -> double */
usecf /= 4294967296.0;
/* divide by 2**32 -> [0, 1.0) */
useci = usecf * 1000000.0;
/* fraction -> parts per million */
curr = *nowptr;
/* make a copy as we might modify it below */
if ( (diff.tv_usec = curr.tv_usec - useci) < 0) {
diff.tv_usec += 1000000;
curr.tv_sec--;
}
diff.tv_sec = curr.tv_sec - nsec;
useci = (diff.tv_sec * 1000000) + diff.tv_usec;
/* diff in microsec */
printf("clock difference = %d usec\n", useci);
}

SNTP(2)
One socket per unicast address
One socket per broadcast address
One socket per interface on which the multicast group is joined