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 multicast_addr_s textual representation of the multicast IP address
45  * to use for multicast communication. NOT a hostname!
46  * @param port port
47  * @param timeout timeout, if 0 all operationsare blocking, otherwise it
48  * is tried for timeout seconds.
49  */
51  unsigned short port,
52  float timeout)
53  : Socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP, timeout)
54 {
55  multicast_addr = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
56 
57  struct in_addr a;
58  if ( inet_aton(multicast_addr_s, &a) == -1 ) {
59  throw SocketException("Invalid address given");
60  }
61  multicast_addr->sin_family = AF_INET;
62  multicast_addr->sin_addr.s_addr = a.s_addr;
63  multicast_addr->sin_port = htons(port);
64 
65  //set_ttl(1);
66  set_loop(false);
67 }
68 
69 
70 /** Destructor. */
72 {
73  free(multicast_addr);
74 }
75 
76 
77 /** Copy constructor.
78  * @param datagram_socket socket to copy.
79  */
81  : Socket(datagram_socket)
82 {
83  multicast_addr = (struct ::sockaddr_in *)malloc(sizeof(struct ::sockaddr_in));
84  memcpy(multicast_addr, datagram_socket.multicast_addr, sizeof(struct ::sockaddr_in));
85 }
86 
87 
88 /** Bind socket.
89  * This will make the socket listen for incoming traffic. It will also add this host to
90  * the appropriate multicast group.
91  */
92 void
94 {
95  int reuse = 1;
96  if ( setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
97  throw SocketException("Could not set SO_REUSEADDR", errno);
98  }
99 
100  struct ip_mreq imr;
101  imr.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
102  imr.imr_interface.s_addr = htonl( INADDR_ANY );
103  if ( setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)) == -1 ) {
104  throw SocketException("Could not add multicast group membership", errno);
105  }
106 
107  struct ::sockaddr_in local;
108  local.sin_family = AF_INET;
109  local.sin_addr.s_addr = INADDR_ANY;
110  local.sin_port = multicast_addr->sin_port;
111 
112  if (::bind(sock_fd, (struct ::sockaddr *) &local, sizeof(local)) < 0) {
113  throw SocketException("Could not bind to port", errno);
114  }
115 }
116 
117 
118 /** Clone socket.
119  * @return a copied instance of MulticastDatagramSocket.
120  */
121 Socket *
123 {
124  return new MulticastDatagramSocket(*this);
125 }
126 
127 
128 /** Send data.
129  * This will send the given data to the multicast address specified
130  * in the constructor.
131  * @param buf buffer to write
132  * @param buf_len length of buffer, number of bytes to write to stream
133  */
134 void
135 MulticastDatagramSocket::send(void *buf, unsigned int buf_len)
136 {
137  try {
138  Socket::send(buf, buf_len, (struct ::sockaddr *)multicast_addr, sizeof(struct ::sockaddr_in));
139  } catch (SocketException &e) {
140  e.append("MulticastDatagramSocket::send(void*, unsigned int) failed");
141  throw;
142  }
143 }
144 
145 
146 /** Set loopback of sent packets.
147  * @param loop true to deliver sent packets to local sockets, false prevent delivering
148  */
149 void
151 {
152  int l = (loop ? 1 : 0);
153  if (setsockopt(sock_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &l, sizeof(l)) == -1) {
154  throw SocketException("MulticastDatagramSocket::set_loop: setsockopt failed", errno);
155  }
156 }
157 
158 
159 /** Set multicast time-to-live (TTL)
160  * @param ttl time-to-live
161  */
162 void
164 {
165  if ( ttl < 0 ) ttl = -ttl;
166  if ( setsockopt( sock_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl) ) == -1 ) {
167  throw SocketException("MulticastDatagramSocket::set_ttl: setsockopt failed", errno);
168  }
169 }
170 
171 } // 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.
Socket base class.
Definition: socket.h:65
virtual void bind()
Bind socket.
virtual ~MulticastDatagramSocket()
Destructor.
Multicast datagram socket.
virtual void send(void *buf, unsigned int buf_len)
Send data.
MulticastDatagramSocket(const char *multicast_addr_s, unsigned short port, float timeout=0.f)
Constructor.
int sock_fd
Socket file descriptor.
Definition: socket.h:125
virtual void send(void *buf, size_t buf_len)
Write to the socket.
Definition: socket.cpp:608
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