Profil von Thomas Boor auf LinkedIn anzeigen Instagram

Thomas Boor


UNIX-Systemprogrammierung


[Home]   [Impressum]   [Kontakt]   [CV (curriculum vitae) ]   [Veröffentlichungen]   [Vermittler für IT-Freelancer]
[IMS Infos]   [IT Infos]   [Internet-Tips]   [Info-Pages & Service-URLs]   [Downloads]   [Internet Radio]   [Aphorismen & Zitate]
[(my) blog]

Thema: IGMP (Internet Group Management Protocol) zum Lesen von Multicast (MC) Paketen.

Aufgabe: T-Home-Multicast-Streams sollen empfangen werden.

Stichworte: UDP Multicast IGMP sockets IP_ADD_MEMBERSHIP recvmsg

Es gelten folgende Multicast-Quellen:

  • 239.35.10.4:10000 ARD
  • 239.35.10.5:10000 ZDF
  • 239.35.10.18:10000 Arte

Was ist zu tun?

  • Erzeugen eines socket auf dem lokalen Rechner; wichtig dabei:
    • Die Adresse, auf der gelauscht wird, muss INADDR_ANY sein, damit der lokale kernel die Pakete nicht dropped.
    • Der Port, auf dem gelauscht wird, muss der Port des Mutlicats-Ziels sein; im Beipiel also immer 10000.
  • Falls mehrere Streams empfangen werden sollen, muessen also mehrere sockets mit gleicher IP/Port-Kombination geoeffnet werden; damit dies funktioniert, muss die socket-Option SO_REUSEADDR gesetzt werden
  • Die socket-Option IP_ADD_MEMBERSHIP muss gesetzt werden, dabei gibt die Struktur ip_mreq die Ziel-Multicast-Adresse sowie die lokale Interface_Adresse an; (damit weiss der adressierte Router, auf dem die MCs anstehen, wohin die Pakete weitergeleitet werden sollen.) Durch diese Option wird ein IGMP-Paket an den Router des Providers gesendet.

Erhält der Router des Providers nun Pakete für die angegebene MC-Adresse, leitet er diese an alle Interfaces (Rechner) weiter, die ein IP_ADD_MEMBERSHIP ausgesprochen haben.

Nachfolgend die essentiellen Systemcalls zur Lösung der Aufgabe.

// Socket anlegen:
int fd = socket(AF_INET, SOCK_DGRAM, 0);
// REUSEADDR fuer den socket setzen:
int reuse = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) {
	// Fehlerbehandlung
}
// 'bind' auf ip=INADDR_ANY und Port=10000
struct sockaddr_in localSock;
localSock.sin_family = AF_INET;
localSock.sin_port = htons(10000);
localSock.sin_addr.s_addr = INADDR_ANY;
if (bind(fd, (struct sockaddr*)&localSock, sizeof(localSock))) {
	// Fehlerbehandlung
}
// Struktur ip_mreq mit Ziel-MC und lokalem Interface fuellen, ADD_MEMBERSHIP f. MC aussprechen:
struct ip_mreq group;
group.imr_multiaddr.s_addr = inet_addr("239.35.10.4");		// Ziel-Multicast-Adresse
group.imr_interface.s_addr = inet_addr("192.168.2.104");	// lokales Interface
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0) {
	// Fehlerbehandlung
}
// Daten vom Socket lesen (i.d.R. in einer loop):
int datalen;
char databuf[1024];
int bytes_read = read(fd, databuf, datalen);

Mit den o.a. Systemcalls kann man einfach einen MC empfangen, Moechte man gleichzeitig mehrerer MCs empfangen, hat man mehrere Socket mit gleicher IP/Port-Kombination. Ein einfache Loesung des Problems ist es, an einem socket nur die Pakete zu lesen, die zum gew. MC gehoeren.

Hier muss das Lesen modifiziert werden, um bei jedem empfangenen Paket die Ziel-Adresse ermitteln zu koennen. (Statt 'read' oder 'recv' muss 'recvmsg' verwendet werden. Zusätzlich muss zuvor die Socket-Option IP_PKTINFO gesetzt werden; man lese ggf. 'man ip', 'man recvmsg' u.a.)

Hier wieder auf die essentiellen Systemcalls beschraenkte Loesung:

// Weitere socket-Option setzen: Paket-Infos gefordert:
int on = 1;
setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
// recvmsg statt read, dafuer iovec und msghdr fuellen:
int bytes_received;
struct sockaddr_in6 from;
struct iovec iovec[1];
struct msghdr msg;
char msg_control[1024];
char udp_packet[1500];

iovec[0].iov_base = udp_packet;
iovec[0].iov_len = sizeof(udp_packet);
msg.msg_name = &from;
msg.msg_namelen = sizeof(from);
msg.msg_iov = iovec;
msg.msg_iovlen = sizeof(iovec) / sizeof(*iovec);
msg.msg_control = msg_control;
msg.msg_controllen = sizeof(msg_control);
msg.msg_flags = 0;
bytes_received = recvmsg(soc, &msg, 0);
// Durch Control-Msgs iterieren, IP-Addr (IPPROTO_IP) suchen und lesen:
struct in_pktinfo in_pktinfo;
struct cmsghdr* cmsg;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != 0; cmsg = CMSG_NXTHDR(&msg, cmsg))
{
  if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
    in_pktinfo = *(struct in_pktinfo*)CMSG_DATA(cmsg);
	// in_pktinfo_.ipi_addr hat jetzt die MC-Zeileadresse, vergleiche, ggf. verwerfen
  }
}
Weiterfuehrende Links:

Wikipedia, IGMP

NETWORK PROGRAMMING LINUX SOCKET PART 13: MULTICAST

Get dst-adr of a udp-packet



Sitemap
Home  |  Kontakt  |  CV (curriculum vitae)  |  Veröffentlichungen  |  IMS Infos  |  IT Infos  |  Info-Pages & Service-URLs DiffServ / QoS in IPv4 und IPv6
Internet Radio  |  Vermittler für IT-Freelancer  |  musical essentials (en)  |  youtube links  |  Aphorismen und Zitate  |  Latein für Smalltalker  |  Downloads  |  Impressum
[fun] [Lyrik] [Limmericks] [MatheGimmicks] [Bauernregeln] [Witze]
CV in deutsch CV in english


sponsored links



accu