/*************************************************************************** * 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 #include #include #include #include #include #include #include #include "configfile.h" #include "logging.h" #define DEFAULT_DEVICE "eth0" #define DEFAULT_GROUP "224.0.0.1" #define DEFAULT_PORT 2000 static struct sockaddr_in dest_addr; int mcast_init() { struct ip_mreq multiaddr; struct ifreq ifr; // open socket int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd == -1) { log_print(LOG_ERROR, "mcast_init: socket()"); return -1; } // get device flags char *mcastdev = config_get_string("global", "mcastdev", DEFAULT_DEVICE); strncpy(ifr.ifr_name, mcastdev, sizeof(ifr.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) != 0) { log_print(LOG_WARN, "mcast_init: ioctl(SIOCGIFFLAGS)"); close(sockfd); 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(sockfd); return -1; } if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, sizeof(ifr.ifr_name)) < 0) { log_print(LOG_WARN, "mcast_init: setsockopt(SO_BINDTODEVICE)"); // close(sockfd); // return -1; } char *mcastgroup = config_get_string("global", "mcastgroup", DEFAULT_GROUP); int mcastport = config_get_int("global", "mcastport", DEFAULT_PORT); dest_addr.sin_family = AF_INET; inet_aton(mcastgroup, &dest_addr.sin_addr); dest_addr.sin_port = htons(mcastport); if (bind(sockfd, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) < 0) { log_print(LOG_WARN, "mcast_init: bind()"); close(sockfd); return -1; } // get interface address if (ioctl(sockfd, SIOCGIFADDR, &ifr) != 0) { log_print(LOG_WARN, "mcast_init: ioctl(SIOCGIFADDR)"); close(sockfd); return -1; } // check address family if (ifr.ifr_addr.sa_family != AF_INET) { log_print(LOG_WARN, "mcast_init: unknown address family"); close(sockfd); return -1; } char loop = 1; if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))) { log_print(LOG_WARN, "mcast_init: setsockopt(IP_MULTICAST_LOOP)"); close(sockfd); 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(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multiaddr, sizeof(multiaddr)) == -1) { log_print(LOG_WARN, "mcast_init: setsockopt(IP_ADD_MEMBERSHIP)"); close(sockfd); return -1; } return sockfd; } 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); }