LCOV - code coverage report
Current view: top level - eventdispatcher - udp_base.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 67 1.5 %
Date: 2021-09-19 09:06:58 Functions: 2 11 18.2 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13