LCOV - code coverage report
Current view: top level - eventdispatcher - udp_base.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 58 1.7 %
Date: 2019-08-08 02:52:36 Functions: 2 10 20.0 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.12