File: joinch.c

package info (click to toggle)
ssmping 0.9.1-4
  • links: PTS
  • area: main
  • in suites: bookworm, bullseye, sid, trixie
  • size: 216 kB
  • sloc: ansic: 1,692; makefile: 91
file content (88 lines) | stat: -rw-r--r-- 2,716 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
 * Copyright (C) 2005  Stig Venaas <venaas@uninett.no>
 * $Id:$
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 */

#include "ssmping.h"

#ifndef MCAST_JOIN_SOURCE_GROUP
#ifdef WIN32 /* Only useful on Vista */
#define MCAST_JOIN_SOURCE_GROUP         45
#endif
#ifdef linux
#define MCAST_JOIN_SOURCE_GROUP         46
#endif
struct group_source_req {
  uint32_t                gsr_interface; /* interface index */
  struct sockaddr_storage gsr_group;     /* group address */
  struct sockaddr_storage gsr_source;    /* source address */
};
#endif

void joinchannel(int s, struct sockaddr *src, struct sockaddr *grp, uint32_t intface, struct sockaddr *ifaddr) {
#ifdef MCAST_JOIN_SOURCE_GROUP
    int level;
    socklen_t addrlen;

#ifdef WIN32
    struct ip_mreq_source imsr;
#endif
    struct group_source_req gsreq;
    
    if (src->sa_family != grp->sa_family) {
	fprintf(stderr, "joinchannel failed, source and group must be of same address family\n");
	exit(1);
    }

    if (ifaddr && ifaddr->sa_family != grp->sa_family) {
	fprintf(stderr, "joinchannel failed, group and interface must be of same address family\n");
	exit(1);
    }
    
    switch (grp->sa_family) {
    case AF_INET:
	addrlen = sizeof(struct sockaddr_in);
	level = IPPROTO_IP;
	break;
    case AF_INET6:
	addrlen = sizeof(struct sockaddr_in6);
	level = IPPROTO_IPV6;
	break;
    default:
	fprintf(stderr, "joinchannel failed, unsupported address family\n");
	exit(1);
    }

    memset(&gsreq, 0, sizeof(gsreq));
    memcpy(&gsreq.gsr_source, src, addrlen);
    memcpy(&gsreq.gsr_group, grp, addrlen);
    gsreq.gsr_interface = intface;
#ifndef WIN32
    if (setsockopt(s, level, MCAST_JOIN_SOURCE_GROUP, (char *)&gsreq, sizeof(gsreq)) < 0)
	errx("Failed to join multicast channel");
#else
    if (setsockopt(s, level, MCAST_JOIN_SOURCE_GROUP, (char *)&gsreq, sizeof(gsreq)) >= 0)
	return;
    if (level != IPPROTO_IP)
	errx("Failed to join multicast channel");

    /* For Windows XP the above setsockopt fails, below works for IPv4
     * While for Windows Vista the above should work
     */
    
    memset(&imsr, 0, sizeof(imsr));
    imsr.imr_sourceaddr = ((struct sockaddr_in *)src)->sin_addr;
    imsr.imr_multiaddr = ((struct sockaddr_in *)grp)->sin_addr;
    imsr.imr_interface = ((struct sockaddr_in *)ifaddr)->sin_addr;

    if (setsockopt(s, level, IP_ADD_SOURCE_MEMBERSHIP, (char *)&imsr, sizeof(imsr)) < 0)
	errx("Failed to join multicast channel");
#endif
#else
    errx("Not built with SSM support, failed to join multicast channel");
#endif    
}