datagram_multicast.cpp

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

Generated on Tue Feb 22 13:32:28 2011 for Fawkes API by  doxygen 1.4.7