Fawkes API Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * datagram_multicast.cpp - Fawkes datagram multicast socket (UDP) 00004 * 00005 * Created: Fri Nov 10 10:02:54 2006 (on train to Google, Hamburg) 00006 * Copyright 2006 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <netcomm/socket/datagram_multicast.h> 00025 00026 #include <sys/socket.h> 00027 #include <netinet/in.h> 00028 #include <arpa/inet.h> 00029 #include <cstdlib> 00030 #include <cstring> 00031 #include <cerrno> 00032 00033 namespace fawkes { 00034 00035 /** @class MulticastDatagramSocket netcomm/socket/datagram.h 00036 * Multicast datagram socket. 00037 * An multicast UDP socket on top of IP. 00038 * 00039 * @ingroup NetComm 00040 * @author Tim Niemueller 00041 */ 00042 00043 /** Constructor. 00044 * @param multicast_addr_s textual representation of the multicast IP address 00045 * to use for multicast communication. NOT a hostname! 00046 * @param port port 00047 * @param timeout timeout, if 0 all operationsare blocking, otherwise it 00048 * is tried for timeout seconds. 00049 */ 00050 MulticastDatagramSocket::MulticastDatagramSocket(const char *multicast_addr_s, 00051 unsigned short port, 00052 float timeout) 00053 : Socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP, timeout) 00054 { 00055 multicast_addr = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in)); 00056 00057 struct in_addr a; 00058 if ( inet_aton(multicast_addr_s, &a) == -1 ) { 00059 throw SocketException("Invalid address given"); 00060 } 00061 multicast_addr->sin_family = AF_INET; 00062 multicast_addr->sin_addr.s_addr = a.s_addr; 00063 multicast_addr->sin_port = htons(port); 00064 00065 //set_ttl(1); 00066 set_loop(false); 00067 } 00068 00069 00070 /** Destructor. */ 00071 MulticastDatagramSocket::~MulticastDatagramSocket() 00072 { 00073 free(multicast_addr); 00074 } 00075 00076 00077 /** Copy constructor. 00078 * @param datagram_socket socket to copy. 00079 */ 00080 MulticastDatagramSocket::MulticastDatagramSocket(MulticastDatagramSocket &datagram_socket) 00081 : Socket(datagram_socket) 00082 { 00083 multicast_addr = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in)); 00084 memcpy(multicast_addr, datagram_socket.multicast_addr, sizeof(struct ::sockaddr_in)); 00085 } 00086 00087 00088 /** Bind socket. 00089 * This will make the socket listen for incoming traffic. It will also add this host to 00090 * the appropriate multicast group. 00091 */ 00092 void 00093 MulticastDatagramSocket::bind() 00094 { 00095 int reuse = 1; 00096 if ( setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) { 00097 throw SocketException("Could not set SO_REUSEADDR", errno); 00098 } 00099 00100 struct ip_mreq imr; 00101 imr.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr; 00102 imr.imr_interface.s_addr = htonl( INADDR_ANY ); 00103 if ( setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)) == -1 ) { 00104 throw SocketException("Could not add multicast group membership", errno); 00105 } 00106 00107 struct ::sockaddr_in local; 00108 local.sin_family = AF_INET; 00109 local.sin_addr.s_addr = INADDR_ANY; 00110 local.sin_port = multicast_addr->sin_port; 00111 00112 if (::bind(sock_fd, (struct ::sockaddr *) &local, sizeof(local)) < 0) { 00113 throw SocketException("Could not bind to port", errno); 00114 } 00115 } 00116 00117 00118 /** Clone socket. 00119 * @return a copied instance of MulticastDatagramSocket. 00120 */ 00121 Socket * 00122 MulticastDatagramSocket::clone() 00123 { 00124 return new MulticastDatagramSocket(*this); 00125 } 00126 00127 00128 /** Send data. 00129 * This will send the given data to the multicast address specified 00130 * in the constructor. 00131 * @param buf buffer to write 00132 * @param buf_len length of buffer, number of bytes to write to stream 00133 */ 00134 void 00135 MulticastDatagramSocket::send(void *buf, unsigned int buf_len) 00136 { 00137 try { 00138 Socket::send(buf, buf_len, (struct ::sockaddr *)multicast_addr, sizeof(struct ::sockaddr_in)); 00139 } catch (SocketException &e) { 00140 e.append("MulticastDatagramSocket::send(void*, unsigned int) failed"); 00141 throw; 00142 } 00143 } 00144 00145 00146 /** Set loopback of sent packets. 00147 * @param loop true to deliver sent packets to local sockets, false prevent delivering 00148 */ 00149 void 00150 MulticastDatagramSocket::set_loop(bool loop) 00151 { 00152 int l = (loop ? 1 : 0); 00153 if (setsockopt(sock_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &l, sizeof(l)) == -1) { 00154 throw SocketException("MulticastDatagramSocket::set_loop: setsockopt failed", errno); 00155 } 00156 } 00157 00158 00159 /** Set multicast time-to-live (TTL) 00160 * @param ttl time-to-live 00161 */ 00162 void 00163 MulticastDatagramSocket::set_ttl(int ttl) 00164 { 00165 if ( ttl < 0 ) ttl = -ttl; 00166 if ( setsockopt( sock_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl) ) == -1 ) { 00167 throw SocketException("MulticastDatagramSocket::set_ttl: setsockopt failed", errno); 00168 } 00169 } 00170 00171 } // end namespace fawkes