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