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 <arpa/inet.h>
25 #include <netcomm/socket/datagram_multicast.h>
26 #include <netinet/in.h>
27 #include <sys/socket.h>
28 
29 #include <cerrno>
30 #include <cstdlib>
31 #include <cstring>
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 /** Destructor. */
73 {
74  free(multicast_addr);
75 }
76 
77 /** Assignment operator.
78  * @param s socket to copy from
79  * @return reference to this instance
80  */
83 {
85  free(multicast_addr);
86  multicast_addr = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
87  memcpy(multicast_addr, s.multicast_addr, sizeof(struct ::sockaddr_in));
88  return *this;
89 }
90 
91 /** Copy constructor.
92  * @param datagram_socket socket to copy.
93  */
95 : Socket(datagram_socket)
96 {
97  multicast_addr = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
98  memcpy(multicast_addr, datagram_socket.multicast_addr, sizeof(struct ::sockaddr_in));
99 }
100 
101 /** Bind socket.
102  * This will make the socket listen for incoming traffic. It will also add this host to
103  * the appropriate multicast group.
104  */
105 void
107 {
108  int reuse = 1;
109  if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
110  throw SocketException(errno, "Could not set SO_REUSEADDR");
111  }
112 
113  struct ip_mreq imr;
114  imr.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
115  imr.imr_interface.s_addr = htonl(INADDR_ANY);
116  if (setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)) == -1) {
117  throw SocketException(errno, "Could not add multicast group membership");
118  }
119 
120  struct ::sockaddr_in local;
121  local.sin_family = AF_INET;
122  local.sin_addr.s_addr = INADDR_ANY;
123  local.sin_port = multicast_addr->sin_port;
124 
125  if (::bind(sock_fd, (struct ::sockaddr *)&local, sizeof(local)) < 0) {
126  throw SocketException(errno, "Could not bind to port");
127  }
128 }
129 
130 void
131 MulticastDatagramSocket::bind(const unsigned short int port)
132 {
133  multicast_addr->sin_port = htons(port);
134  bind();
135 }
136 
137 void
138 MulticastDatagramSocket::bind(const unsigned short int port, const char *hostname)
139 {
140  free(multicast_addr);
141  multicast_addr = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
142 
143  struct in_addr a;
144  if (inet_aton(hostname, &a) == -1) {
145  throw SocketException("Invalid address given");
146  }
147  multicast_addr->sin_family = AF_INET;
148  multicast_addr->sin_addr.s_addr = a.s_addr;
149  multicast_addr->sin_port = htons(port);
150  bind();
151 }
152 
153 /** Clone socket.
154  * @return a copied instance of MulticastDatagramSocket.
155  */
156 Socket *
158 {
159  return new MulticastDatagramSocket(*this);
160 }
161 
162 /** Send data.
163  * This will send the given data to the multicast address specified
164  * in the constructor.
165  * @param buf buffer to write
166  * @param buf_len length of buffer, number of bytes to write to stream
167  */
168 void
169 MulticastDatagramSocket::send(void *buf, size_t buf_len)
170 {
171  try {
172  Socket::send(buf, buf_len, (struct ::sockaddr *)multicast_addr, sizeof(struct ::sockaddr_in));
173  } catch (SocketException &e) {
174  e.append("MulticastDatagramSocket::send(void*, unsigned int) failed");
175  throw;
176  }
177 }
178 
179 /** Set loopback of sent packets.
180  * @param loop true to deliver sent packets to local sockets, false prevent delivering
181  */
182 void
184 {
185  int l = (loop ? 1 : 0);
186  if (setsockopt(sock_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &l, sizeof(l)) == -1) {
187  throw SocketException(errno, "MulticastDatagramSocket::set_loop: setsockopt failed");
188  }
189 }
190 
191 /** Set multicast time-to-live (TTL)
192  * @param ttl time-to-live
193  */
194 void
196 {
197  if (ttl < 0)
198  ttl = -ttl;
199  if (setsockopt(sock_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1) {
200  throw SocketException(errno, "MulticastDatagramSocket::set_ttl: setsockopt failed");
201  }
202 }
203 
204 } // end namespace fawkes
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:333
Multicast datagram socket.
virtual void send(void *buf, size_t buf_len)
Send data.
void set_loop(bool loop)
Set loopback of sent packets.
void set_ttl(int ttl)
Set multicast time-to-live (TTL)
MulticastDatagramSocket & operator=(MulticastDatagramSocket &s)
Assignment operator.
virtual Socket * clone()
Clone socket.
MulticastDatagramSocket(AddrType addr_type, const char *multicast_addr_s, unsigned short port, float timeout=0.f)
Constructor.
virtual ~MulticastDatagramSocket()
Destructor.
virtual void bind()
Bind socket.
Socket exception.
Definition: socket.h:57
Socket base class.
Definition: socket.h:64
int sock_fd
Socket file descriptor.
Definition: socket.h:137
AddrType
Address type specification.
Definition: socket.h:75
Socket & operator=(Socket &socket)
Copy constructor.
Definition: socket.cpp:250
virtual void send(void *buf, size_t buf_len)
Write to the socket.
Definition: socket.cpp:846
Fawkes library namespace.