Fawkes API  Fawkes Development Version
datagram_multicast.cpp
1 
2 /***************************************************************************
3  * datagram_multicast.cpp - Fawkes datagram multicast socket (UDP)
4  *
5  * Created: Fri Nov 10 10:02:54 2006 (on train to Google, Hamburg)
6  * Copyright 2006 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <netcomm/socket/datagram_multicast.h>
25 
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <cstdlib>
30 #include <cstring>
31 #include <cerrno>
32 
33 namespace fawkes {
34 
35 /** @class MulticastDatagramSocket netcomm/socket/datagram.h
36  * Multicast datagram socket.
37  * An multicast UDP socket on top of IP.
38  *
39  * @ingroup NetComm
40  * @author Tim Niemueller
41  */
42 
43 /** Constructor.
44  * @param addr_type Specify IPv4 or IPv6
45  * @param multicast_addr_s textual representation of the multicast IP address
46  * to use for multicast communication. NOT a hostname!
47  * @param port port
48  * @param timeout timeout, if 0 all operationsare blocking, otherwise it
49  * is tried for timeout seconds.
50  */
52  const char *multicast_addr_s,
53  unsigned short port,
54  float timeout)
55  : Socket(addr_type, UDP, timeout)
56 {
57  multicast_addr = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
58 
59  struct in_addr a;
60  if ( inet_aton(multicast_addr_s, &a) == -1 ) {
61  throw SocketException("Invalid address given");
62  }
63  multicast_addr->sin_family = AF_INET;
64  multicast_addr->sin_addr.s_addr = a.s_addr;
65  multicast_addr->sin_port = htons(port);
66 
67  //set_ttl(1);
68  set_loop(false);
69 }
70 
71 
72 /** Destructor. */
74 {
75  free(multicast_addr);
76 }
77 
78 
79 /** Copy constructor.
80  * @param datagram_socket socket to copy.
81  */
83  : Socket(datagram_socket)
84 {
85  multicast_addr = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
86  memcpy(multicast_addr, datagram_socket.multicast_addr, sizeof(struct ::sockaddr_in));
87 }
88 
89 
90 /** Bind socket.
91  * This will make the socket listen for incoming traffic. It will also add this host to
92  * the appropriate multicast group.
93  */
94 void
96 {
97  int reuse = 1;
98  if ( setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
99  throw SocketException(errno, "Could not set SO_REUSEADDR");
100  }
101 
102  struct ip_mreq imr;
103  imr.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
104  imr.imr_interface.s_addr = htonl( INADDR_ANY );
105  if ( setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)) == -1 ) {
106  throw SocketException(errno, "Could not add multicast group membership");
107  }
108 
109  struct ::sockaddr_in local;
110  local.sin_family = AF_INET;
111  local.sin_addr.s_addr = INADDR_ANY;
112  local.sin_port = multicast_addr->sin_port;
113 
114  if (::bind(sock_fd, (struct ::sockaddr *) &local, sizeof(local)) < 0) {
115  throw SocketException(errno, "Could not bind to port");
116  }
117 }
118 
119 
120 void
121 MulticastDatagramSocket::bind(const unsigned short int port)
122 {
123  multicast_addr->sin_port = htons(port);
124  bind();
125 }
126 
127 
128 void
129 MulticastDatagramSocket::bind(const unsigned short int port,
130  const char *hostname)
131 {
132  free(multicast_addr);
133  multicast_addr = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
134 
135  struct in_addr a;
136  if ( inet_aton(hostname, &a) == -1 ) {
137  throw SocketException("Invalid address given");
138  }
139  multicast_addr->sin_family = AF_INET;
140  multicast_addr->sin_addr.s_addr = a.s_addr;
141  multicast_addr->sin_port = htons(port);
142  bind();
143 }
144 
145 /** Clone socket.
146  * @return a copied instance of MulticastDatagramSocket.
147  */
148 Socket *
150 {
151  return new MulticastDatagramSocket(*this);
152 }
153 
154 
155 /** Send data.
156  * This will send the given data to the multicast address specified
157  * in the constructor.
158  * @param buf buffer to write
159  * @param buf_len length of buffer, number of bytes to write to stream
160  */
161 void
162 MulticastDatagramSocket::send(void *buf, size_t buf_len)
163 {
164  try {
165  Socket::send(buf, buf_len, (struct ::sockaddr *)multicast_addr, sizeof(struct ::sockaddr_in));
166  } catch (SocketException &e) {
167  e.append("MulticastDatagramSocket::send(void*, unsigned int) failed");
168  throw;
169  }
170 }
171 
172 
173 /** Set loopback of sent packets.
174  * @param loop true to deliver sent packets to local sockets, false prevent delivering
175  */
176 void
178 {
179  int l = (loop ? 1 : 0);
180  if (setsockopt(sock_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &l, sizeof(l)) == -1) {
181  throw SocketException(errno, "MulticastDatagramSocket::set_loop: setsockopt failed");
182  }
183 }
184 
185 
186 /** Set multicast time-to-live (TTL)
187  * @param ttl time-to-live
188  */
189 void
191 {
192  if ( ttl < 0 ) ttl = -ttl;
193  if ( setsockopt( sock_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl) ) == -1 ) {
194  throw SocketException(errno, "MulticastDatagramSocket::set_ttl: setsockopt failed");
195  }
196 }
197 
198 } // end namespace fawkes
void set_ttl(int ttl)
Set multicast time-to-live (TTL)
Fawkes library namespace.
void set_loop(bool loop)
Set loopback of sent packets.
AddrType
Address type specification.
Definition: socket.h:78
Socket base class.
Definition: socket.h:65
virtual void bind()
Bind socket.
virtual ~MulticastDatagramSocket()
Destructor.
MulticastDatagramSocket(AddrType addr_type, const char *multicast_addr_s, unsigned short port, float timeout=0.f)
Constructor.
Multicast datagram socket.
int sock_fd
Socket file descriptor.
Definition: socket.h:140
virtual void send(void *buf, size_t buf_len)
Write to the socket.
Definition: socket.cpp:816
virtual void send(void *buf, size_t buf_len)
Send data.
virtual Socket * clone()
Clone socket.
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:341
Socket exception.
Definition: socket.h:58