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
33namespace 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 */
105void
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
130void
131MulticastDatagramSocket::bind(const unsigned short int port)
132{
133 multicast_addr->sin_port = htons(port);
134 bind();
135}
136
137void
138MulticastDatagramSocket::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 */
156Socket *
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 */
168void
169MulticastDatagramSocket::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 */
182void
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 */
194void
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,...) noexcept
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.