cachesyncd/multicast.c

118 lines
3.8 KiB
C

/***************************************************************************
* Copyright (C) 06/2006 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "configfile.h"
#include "logging.h"
static struct sockaddr_in dest_addr;
int mcast_init()
{
struct ip_mreq multiaddr;
struct ifreq ifr;
char *mcastdev, *mcastgroup;
int mcastport, sock;
// open socket
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
log_print(LOG_ERROR, "mcast_init: socket()");
return -1;
}
// get device flags
mcastdev = config_get_string("global", "mcastdev", "eth0");
strncpy(ifr.ifr_name, mcastdev, sizeof(ifr.ifr_name));
if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
log_print(LOG_WARN, "mcast_init: ioctl(SIOCGIFFLAGS)");
close(sock);
return -1;
}
// check device flags
if ((ifr.ifr_flags & (IFF_UP | IFF_MULTICAST)) != (IFF_UP | IFF_MULTICAST)) {
log_print(LOG_WARN, "mcast_init: device %s not up");
close(sock);
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, sizeof(ifr.ifr_name)) < 0) {
log_print(LOG_WARN, "mcast_init: setsockopt(SO_BINDTODEVICE)");
// close(sock);
// return -1;
}
mcastgroup = config_get_string("global", "mcastgroup", "224.0.0.1");
mcastport = config_get_int("global", "mcastport", 2000);
dest_addr.sin_family = AF_INET;
inet_aton(mcastgroup, &dest_addr.sin_addr);
dest_addr.sin_port = htons(mcastport);
if (bind(sock, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) < 0) {
log_print(LOG_WARN, "mcast_init: bind()");
return -1;
}
// get interface address
if (ioctl(sock, SIOCGIFADDR, &ifr) != 0) {
log_print(LOG_WARN, "mcast_init: ioctl(SIOCGIFADDR)");
close(sock);
return -1;
}
// check address family
if (ifr.ifr_addr.sa_family != AF_INET) {
log_print(LOG_WARN, "mcast_init: unknown address family");
close(sock);
return -1;
}
inet_aton(mcastgroup, &multiaddr.imr_multiaddr);
multiaddr.imr_interface.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&multiaddr, sizeof(multiaddr)) == -1) {
log_print(LOG_WARN, "mcast_init: setsockopt(IP_ADD_MEMBERSHIP)");
close(sock);
return -1;
}
return sock;
}
int mcast_send(int sock, char *buf, int len)
{
return sendto(sock, buf, len, MSG_NOSIGNAL, (const struct sockaddr*)&dest_addr, sizeof(dest_addr));
}
void msock_close(int sock)
{
close(sock);
}