Line data Source code
1 : // Copyright (c) 2012-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/eventdispatcher
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program; if not, write to the Free Software
18 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : /** \file
21 : * \brief Event dispatch class.
22 : *
23 : * Class used to handle events.
24 : */
25 :
26 :
27 : // self
28 : //
29 : #include "eventdispatcher/udp_base.h"
30 :
31 : #include "eventdispatcher/exception.h"
32 :
33 :
34 : // libaddr lib
35 : //
36 : #include <libaddr/iface.h>
37 :
38 :
39 : // C lib
40 : //
41 : #include <net/if.h>
42 : #include <netinet/ip.h>
43 : #include <netinet/udp.h>
44 : #include <sys/ioctl.h>
45 :
46 :
47 : // last include
48 : //
49 : #include <snapdev/poison.h>
50 :
51 :
52 :
53 :
54 : namespace ed
55 : {
56 :
57 :
58 :
59 : /** \brief Initialize a UDP base object.
60 : *
61 : * This function initializes the UDP base object using the address and the
62 : * port as specified.
63 : *
64 : * The port is expected to be a host side port number (i.e. 59200).
65 : *
66 : * The \p addr parameter is a textual address. It may be an IPv4 or IPv6
67 : * address and it can represent a host name or an address defined with
68 : * just numbers. If the address cannot be resolved then an error occurs
69 : * and the constructor throws.
70 : *
71 : * \note
72 : * The socket is open in this process. If you fork() and exec() then the
73 : * socket gets closed by the operating system (i.e. close on exec()).
74 : *
75 : * \warning
76 : * We only make use of the first address found by getaddrinfo(). All
77 : * the other addresses are ignored.
78 : *
79 : * \todo
80 : * Add a constructor that supports a libaddr::addr object instead of
81 : * just a string address.
82 : *
83 : * \exception udp_client_server_parameter_error
84 : * The \p addr parameter is empty or the port is out of the supported range.
85 : *
86 : * \exception udp_client_server_runtime_error
87 : * The server could not be initialized properly. Either the address cannot be
88 : * resolved, the port is incompatible or not available, or the socket could
89 : * not be created.
90 : *
91 : * \param[in] addr The address to convert to a numeric IP.
92 : * \param[in] port The port number.
93 : * \param[in] family The family used to search for 'addr'.
94 : */
95 0 : udp_base::udp_base(std::string const & addr, int port, int family)
96 : : f_port(port)
97 0 : , f_addr(addr)
98 : {
99 : // the address can't be an empty string
100 : //
101 0 : if(f_addr.empty())
102 : {
103 0 : throw event_dispatcher_invalid_parameter("the address cannot be an empty string");
104 : }
105 :
106 : // the port must be between 0 and 65535
107 : // (although 0 won't work right as far as I know)
108 : //
109 0 : if(f_port < 0 || f_port >= 65536)
110 : {
111 0 : throw event_dispatcher_invalid_parameter("invalid port for a client socket");
112 : }
113 :
114 : // for the getaddrinfo() function, convert the port to a string
115 : //
116 0 : std::string const port_str(std::to_string(f_port));
117 :
118 : // define the getaddrinfo() hints
119 : // we are only interested by addresses representing datagrams and
120 : // acceptable by the UDP protocol
121 : //
122 0 : struct addrinfo hints = addrinfo();
123 0 : hints.ai_family = family;
124 0 : hints.ai_socktype = SOCK_DGRAM;
125 0 : hints.ai_protocol = IPPROTO_UDP;
126 :
127 : // retrieve the list of addresses defined by getaddrinfo()
128 : //
129 0 : struct addrinfo * info;
130 0 : int const r(getaddrinfo(addr.c_str(), port_str.c_str(), &hints, &info));
131 0 : if(r != 0 || info == nullptr)
132 : {
133 0 : throw event_dispatcher_invalid_parameter("invalid address or port: \"" + addr + ":" + port_str + "\"");
134 : }
135 0 : f_addrinfo = raii_addrinfo_t(info);
136 :
137 : // now create the socket with the very first socket family
138 : //
139 0 : f_socket.reset(socket(f_addrinfo->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP));
140 0 : if(f_socket == nullptr)
141 : {
142 0 : throw event_dispatcher_runtime_error(("could not create socket for: \"" + addr + ":" + port_str + "\"").c_str());
143 : }
144 0 : }
145 :
146 :
147 : /** \brief Clean up the UDP base class.
148 : *
149 : * This function is here because it handles the creation of the virtual table.
150 : */
151 0 : udp_base::~udp_base()
152 : {
153 0 : }
154 :
155 :
156 : /** \brief Retrieve a copy of the socket identifier.
157 : *
158 : * This function return the socket identifier as returned by the socket()
159 : * function. This can be used to change some flags.
160 : *
161 : * \return The socket used by this UDP client.
162 : */
163 0 : int udp_base::get_socket() const
164 : {
165 0 : return f_socket.get();
166 : }
167 :
168 :
169 : /** \brief Set whether this UDP socket is to be used to broadcast messages.
170 : *
171 : * This function sets the BROADCAST flagon the socket. This is important
172 : * because by default it is expected that the socket is not used in
173 : * broadcast mode. This makes sure that was your intention.
174 : *
175 : * \note
176 : * We do not try to automatically set the flag for (1) the OS implementation
177 : * expects the end user application to systematically set the flag if
178 : * required and (2) it's complicated to know whether the address represents
179 : * the broadcast address (i.e. you need to get the info on the corresponding
180 : * interface to get the network mask, see whether the interface supports
181 : * broadcasting, etc.) We'll eventually implement that test in our
182 : * libaddr library one day. However, that would be a test we use in the
183 : * send() function to catch errors early (i.e. determine whether the
184 : * socket can be sent to in the current state).
185 : *
186 : * \param[in] state Whether to set (true) or remove (false) the broadcast
187 : * flag on this UDP socket.
188 : */
189 0 : void udp_base::set_broadcast(bool state)
190 : {
191 0 : int const value(state ? 1 : 0);
192 0 : setsockopt(f_socket.get(), SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
193 0 : }
194 :
195 :
196 : /** \brief Retrieve the size of the MTU on that connection.
197 : *
198 : * Linux offers a ioctl() function to retrieve the MTU's size. This
199 : * function uses that and returns the result. If the call fails,
200 : * then the function returns -1.
201 : *
202 : * The function returns the MTU's size of the socket on this side.
203 : * If you want to communicate effectively with another system, you
204 : * want to also ask about the MTU on the other side of the socket.
205 : *
206 : * \note
207 : * MTU stands for Maximum Transmission Unit.
208 : *
209 : * \note
210 : * PMTUD stands for Path Maximum Transmission Unit Discovery.
211 : *
212 : * \note
213 : * PLPMTU stands for Packetization Layer Path Maximum Transmission Unit
214 : * Discovery.
215 : *
216 : * \todo
217 : * We need to support the possibly of dynamically changing MTU size
218 : * that the Internet may generate (or even a LAN if you let people
219 : * tweak their MTU "randomly".) This is done by preventing
220 : * defragmentation (see IP_NODEFRAG in `man 7 ip`) and also by
221 : * asking for MTU size discovery (IP_MTU_DISCOVER). The size
222 : * discovery changes over time as devices on the MTU path (the
223 : * route taken by the packets) changes over time. The idea is
224 : * to find the smallest MTU size of the MTU path and use that
225 : * to send packets of that size at the most. Note that packets
226 : * are otherwise automatically broken in smaller chunks and
227 : * rebuilt on the other side, but that is not efficient if you
228 : * expect to lose quite a few packets along the way. The limit
229 : * for chunked packets is a little under 64Kb.
230 : *
231 : * \note
232 : * errno is either EBADF or set by ioctl().
233 : *
234 : * \sa
235 : * See `man 7 netdevice`
236 : *
237 : * \return -1 if the MTU could not be retrieved, the MTU's size otherwise.
238 : */
239 0 : int udp_base::get_mtu_size() const
240 : {
241 0 : if(f_socket != nullptr
242 0 : && f_mtu_size == 0)
243 : {
244 0 : addr::addr a;
245 0 : switch(f_addrinfo->ai_family)
246 : {
247 0 : case AF_INET:
248 0 : a.set_ipv4(*reinterpret_cast<struct sockaddr_in *>(f_addrinfo->ai_addr));
249 0 : break;
250 :
251 0 : case AF_INET6:
252 0 : a.set_ipv6(*reinterpret_cast<struct sockaddr_in6 *>(f_addrinfo->ai_addr));
253 0 : break;
254 :
255 0 : default:
256 0 : f_mtu_size = -1;
257 0 : errno = EBADF;
258 0 : break;
259 :
260 : }
261 0 : if(f_mtu_size == 0)
262 : {
263 0 : std::string iface_name;
264 0 : addr::iface::pointer_t i(find_addr_interface(a));
265 0 : if(i != nullptr)
266 : {
267 0 : iface_name = i->get_name();
268 : }
269 :
270 0 : if(iface_name.empty())
271 : {
272 0 : f_mtu_size = -1;
273 0 : errno = EBADF;
274 : }
275 : else
276 : {
277 0 : ifreq ifr = {};
278 0 : strncpy(ifr.ifr_name, iface_name.c_str(), sizeof(ifr.ifr_name) - 1);
279 0 : if(ioctl(f_socket.get(), SIOCGIFMTU, &ifr) == 0)
280 : {
281 0 : f_mtu_size = ifr.ifr_mtu;
282 : }
283 : else
284 : {
285 0 : f_mtu_size = -1;
286 : // errno -- defined by ioctl()
287 : }
288 : }
289 : }
290 : }
291 :
292 0 : return f_mtu_size;
293 : }
294 :
295 :
296 : /** \brief Determine the size of the data buffer we can use.
297 : *
298 : * This function gets the MTU of the connection (i.e. not the PMTUD
299 : * or PLPMTUD yet...) and subtract the space necessary for the IP and
300 : * UDP headers. This is called the Maximum Segment Size (MSS).
301 : *
302 : * \todo
303 : * If the IP address (in f_addr) is an IPv6, then we need to switch to
304 : * the corresponding IPv6 subtractions.
305 : *
306 : * \todo
307 : * Look into the the IP options because some options add to the size
308 : * of the IP header. It's incredible that we have to take care of that
309 : * on our end!
310 : *
311 : * \todo
312 : * For congestion control, read more as described on ietf.org:
313 : * https://tools.ietf.org/html/rfc8085
314 : *
315 : * \todo
316 : * The sizes that will always work (as long as all the components of the
317 : * path are working as per the UDP RFC) are (1) for IPv4, 576 bytes, and
318 : * (2) for IPv6, 1280 bytes. This size is called EMTU_S which stands for
319 : * "Effective Maximum Transmission Unit for Sending."
320 : *
321 : * \return The size of the MMU, which is the MTU minus IP and UDP headers.
322 : */
323 0 : int udp_base::get_mss_size() const
324 : {
325 : // where these structures are defined
326 : //
327 : // ether_header -- /usr/include/net/ethernet.h
328 : // iphdr -- /usr/include/netinet/ip.h
329 : // udphdr -- /usr/include/netinet/udp.h
330 : //
331 0 : int const mtu(get_mtu_size()
332 : //- sizeof(ether_header) // WARNING: this is for IPv4 only -- this is "transparent" to the MTU (i.e. it wraps the 1,500 bytes)
333 : //- ETHER_CRC_LEN // this is the CRC for the ethernet which appears at the end of the packet
334 : - sizeof(iphdr) // WARNING: this is for IPv4 only
335 : //- ... // the IP protocol accepts options!
336 0 : - sizeof(udphdr)
337 0 : );
338 :
339 0 : return mtu <= 0 ? -1 : mtu;
340 : }
341 :
342 :
343 : /** \brief Retrieve the port used by this UDP client.
344 : *
345 : * This function returns the port used by this UDP client. The port is
346 : * defined as an integer, host side.
347 : *
348 : * \return The port as expected in a host integer.
349 : */
350 0 : int udp_base::get_port() const
351 : {
352 0 : return f_port;
353 : }
354 :
355 :
356 : /** \brief Retrieve a copy of the address.
357 : *
358 : * This function returns a copy of the address as it was specified in the
359 : * constructor. This does not return a canonicalized version of the address.
360 : *
361 : * The address cannot be modified. If you need to send data on a different
362 : * address, create a new UDP client.
363 : *
364 : * \return A string with a copy of the constructor input address.
365 : */
366 0 : std::string udp_base::get_addr() const
367 : {
368 0 : return f_addr;
369 : }
370 :
371 :
372 :
373 6 : } // namespace ed
374 : // vim: ts=4 sw=4 et
|