LCOV - code coverage report
Current view: top level - eventdispatcher - udp_base.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 41 2.4 %
Date: 2022-06-18 10:10:36 Functions: 2 10 20.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2012-2022  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
      35             : //
      36             : #include    <libaddr/iface.h>
      37             : 
      38             : 
      39             : // C++
      40             : //
      41             : #include    <sstream>
      42             : 
      43             : 
      44             : // C
      45             : //
      46             : #include    <net/if.h>
      47             : #include    <netinet/ip.h>
      48             : #include    <netinet/udp.h>
      49             : #include    <sys/ioctl.h>
      50             : 
      51             : 
      52             : // last include
      53             : //
      54             : #include    <snapdev/poison.h>
      55             : 
      56             : 
      57             : 
      58             : 
      59             : namespace ed
      60             : {
      61             : 
      62             : 
      63             : 
      64             : /** \brief Initialize a UDP base object.
      65             :  *
      66             :  * This function initializes the UDP base object using the address and the
      67             :  * port as specified.
      68             :  *
      69             :  * The port is expected to be a host side port number (i.e. 59200).
      70             :  *
      71             :  * The \p address parameter is a libaddr address. It may be an IPv4 or IPv6
      72             :  * address and it correspond to a host name or be an address defined with
      73             :  * just numbers.
      74             :  *
      75             :  * \note
      76             :  * The socket is open in this process. If you fork() and exec() then the
      77             :  * socket gets closed by the operating system (i.e. close on exec()).
      78             :  *
      79             :  * \exception udp_client_server_parameter_error
      80             :  * The \p address parameter is empty or the port is out of the supported range.
      81             :  *
      82             :  * \exception udp_client_server_runtime_error
      83             :  * The server could not be initialized properly. Either the address cannot be
      84             :  * resolved, the port is incompatible or not available, or the socket could
      85             :  * not be created.
      86             :  *
      87             :  * \param[in] address  The address and port.
      88             :  */
      89           0 : udp_base::udp_base(addr::addr const & address)
      90           0 :     : f_address(address)
      91             : {
      92             :     // create the socket
      93             :     //
      94           0 :     f_socket.reset(socket(f_address.get_family(), SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP));
      95           0 :     if(f_socket == nullptr)
      96             :     {
      97           0 :         std::stringstream ss;
      98             :         ss << "could not create socket for: \""
      99           0 :            << f_address.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_PORT)
     100           0 :            << "\".";
     101           0 :         throw runtime_error(ss.str());
     102             :     }
     103           0 : }
     104             : 
     105             : 
     106             : /** \brief Clean up the UDP base class.
     107             :  *
     108             :  * This function is here because it handles the creation of the virtual table.
     109             :  */
     110           0 : udp_base::~udp_base()
     111             : {
     112           0 : }
     113             : 
     114             : 
     115             : /** \brief Retrieve a copy of the socket identifier.
     116             :  *
     117             :  * This function return the socket identifier as returned by the socket()
     118             :  * function. This can be used to change some flags.
     119             :  *
     120             :  * \return The socket used by this UDP client.
     121             :  */
     122           0 : int udp_base::get_socket() const
     123             : {
     124           0 :     return f_socket.get();
     125             : }
     126             : 
     127             : 
     128             : /** \brief Set whether this UDP socket is to be used to broadcast messages.
     129             :  *
     130             :  * This function sets the BROADCAST flag on the socket. This is important
     131             :  * because by default it is expected that the socket is not used in
     132             :  * broadcast mode. This makes sure that was your intention.
     133             :  *
     134             :  * \note
     135             :  * We do not try to automatically set the flag for (1) the OS implementation
     136             :  * expects the end user application to systematically set the flag if
     137             :  * required and (2) it's complicated to know whether the address represents
     138             :  * the broadcast address (i.e. you need to get the info on the corresponding
     139             :  * interface to get the network mask, see whether the interface supports
     140             :  * broadcasting, etc.) We'll eventually implement that test in our
     141             :  * libaddr library one day. However, that would be a test we use in the
     142             :  * send() function to catch errors early (i.e. determine whether the
     143             :  * socket can be sent to in the current state).
     144             :  *
     145             :  * \param[in] state  Whether to set (true) or remove (false) the broadcast
     146             :  * flag on this UDP socket.
     147             :  */
     148           0 : void udp_base::set_broadcast(bool state)
     149             : {
     150           0 :     int const value(state ? 1 : 0);
     151           0 :     setsockopt(f_socket.get(), SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
     152           0 : }
     153             : 
     154             : 
     155             : /** \brief Retrieve the size of the MTU on that connection.
     156             :  *
     157             :  * Linux offers a ioctl() function to retrieve the MTU's size. This
     158             :  * function uses that and returns the result. If the call fails,
     159             :  * then the function returns -1.
     160             :  *
     161             :  * The function returns the MTU's size of the socket on this side.
     162             :  * If you want to communicate effectively with another system, you
     163             :  * want to also ask about the MTU on the other side of the socket.
     164             :  *
     165             :  * \note
     166             :  * MTU stands for Maximum Transmission Unit.
     167             :  *
     168             :  * \note
     169             :  * PMTUD stands for Path Maximum Transmission Unit Discovery.
     170             :  *
     171             :  * \note
     172             :  * PLPMTU stands for Packetization Layer Path Maximum Transmission Unit
     173             :  * Discovery.
     174             :  *
     175             :  * \todo
     176             :  * We need to support the possibly of dynamically changing MTU size
     177             :  * that the Internet may generate (or even a LAN if you let people
     178             :  * tweak their MTU "randomly".) This is done by preventing
     179             :  * defragmentation (see IP_NODEFRAG in `man 7 ip`) and also by
     180             :  * asking for MTU size discovery (IP_MTU_DISCOVER). The size
     181             :  * discovery changes over time as devices on the MTU path (the
     182             :  * route taken by the packets) changes over time. The idea is
     183             :  * to find the smallest MTU size of the MTU path and use that
     184             :  * to send packets of that size at the most. Note that packets
     185             :  * are otherwise automatically broken in smaller chunks and
     186             :  * rebuilt on the other side, but that is not efficient if you
     187             :  * expect to lose quite a few packets along the way. The limit
     188             :  * for chunked packets is a little under 64Kb.
     189             :  *
     190             :  * \note
     191             :  * errno is either EBADF or set by ioctl().
     192             :  *
     193             :  * \sa
     194             :  * See `man 7 netdevice`
     195             :  *
     196             :  * \return -1 if the MTU could not be retrieved, the MTU's size otherwise.
     197             :  */
     198           0 : int udp_base::get_mtu_size() const
     199             : {
     200           0 :     if(f_socket != nullptr
     201           0 :     && f_mtu_size == 0)
     202             :     {
     203           0 :         std::string iface_name;
     204           0 :         addr::iface::pointer_t i(find_addr_interface(f_address));
     205           0 :         if(i != nullptr)
     206             :         {
     207           0 :             iface_name = i->get_name();
     208             :         }
     209             : 
     210           0 :         if(iface_name.empty())
     211             :         {
     212           0 :             f_mtu_size = -1;
     213           0 :             errno = EBADF;
     214             :         }
     215             :         else
     216             :         {
     217           0 :             ifreq ifr = {};
     218           0 :             strncpy(ifr.ifr_name, iface_name.c_str(), sizeof(ifr.ifr_name) - 1);
     219           0 :             if(ioctl(f_socket.get(), SIOCGIFMTU, &ifr) == 0)
     220             :             {
     221           0 :                 f_mtu_size = ifr.ifr_mtu;
     222             :             }
     223             :             else
     224             :             {
     225           0 :                 f_mtu_size = -1;
     226             :                 // errno -- defined by ioctl()
     227             :             }
     228             :         }
     229             :     }
     230             : 
     231           0 :     return f_mtu_size;
     232             : }
     233             : 
     234             : 
     235             : /** \brief Determine the size of the data buffer we can use.
     236             :  *
     237             :  * This function gets the MTU of the connection (i.e. not the PMTUD
     238             :  * or PLPMTUD yet...) and subtract the space necessary for the IP and
     239             :  * UDP headers. This is called the Maximum Segment Size (MSS).
     240             :  *
     241             :  * \todo
     242             :  * If the IP address (in f_addr) is an IPv6, then we need to switch to
     243             :  * the corresponding IPv6 subtractions.
     244             :  *
     245             :  * \todo
     246             :  * Look into the the IP options because some options add to the size
     247             :  * of the IP header. It's incredible that we have to take care of that
     248             :  * on our end!
     249             :  *
     250             :  * \todo
     251             :  * For congestion control, read more as described on ietf.org:
     252             :  * https://tools.ietf.org/html/rfc8085
     253             :  *
     254             :  * \todo
     255             :  * The sizes that will always work (as long as all the components of the
     256             :  * path are working as per the UDP RFC) are (1) for IPv4, 576 bytes, and
     257             :  * (2) for IPv6, 1280 bytes. This size is called EMTU_S which stands for
     258             :  * "Effective Maximum Transmission Unit for Sending."
     259             :  *
     260             :  * \return The size of the MMU, which is the MTU minus IP and UDP headers.
     261             :  */
     262           0 : int udp_base::get_mss_size() const
     263             : {
     264             :     // where these structures are defined
     265             :     //
     266             :     // ether_header -- /usr/include/net/ethernet.h
     267             :     // iphdr -- /usr/include/netinet/ip.h
     268             :     // udphdr -- /usr/include/netinet/udp.h
     269             :     //
     270           0 :     int const mtu(get_mtu_size()
     271             :             //- sizeof(ether_header)    // WARNING: this is for IPv4 only -- this is "transparent" to the MTU (i.e. it wraps the 1,500 bytes)
     272             :             //- ETHER_CRC_LEN           // this is the CRC for the ethernet which appears at the end of the packet
     273             :             - sizeof(iphdr)             // WARNING: this is for IPv4 only
     274             :             //- ...                     // the IP protocol accepts options!
     275           0 :             - sizeof(udphdr)
     276           0 :         );
     277             : 
     278           0 :     return mtu <= 0 ? -1 : mtu;
     279             : }
     280             : 
     281             : 
     282             : /** \brief Retrieve a copy of the address.
     283             :  *
     284             :  * This function returns a copy of the address as it was specified in the
     285             :  * constructor. This does not return a canonicalized version of the address.
     286             :  *
     287             :  * The address cannot be modified. If you need to send data on a different
     288             :  * address, create a new UDP client.
     289             :  *
     290             :  * \note
     291             :  * If you set the port to 0 and then do a bind (i.e. create a server,
     292             :  * listening socket), then the port will automatically be assigned
     293             :  * by the network stack. This is allowed for the UDP server.
     294             :  *
     295             :  * \return A string with a copy of the constructor input address.
     296             :  */
     297           0 : addr::addr udp_base::get_address() const
     298             : {
     299           0 :     return f_address;
     300             : }
     301             : 
     302             : 
     303             : 
     304           6 : } // namespace ed
     305             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13