LCOV - code coverage report
Current view: top level - eventdispatcher - utils.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 23 4.3 %
Date: 2019-08-08 02:52:36 Functions: 2 4 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Snap Communicator -- classes to ease handling communication between processes
       2             : // Copyright (c) 2012-2019  Made to Order Software Corp.  All Rights Reserved
       3             : //
       4             : // This program is free software; you can redistribute it and/or modify
       5             : // it under the terms of the GNU General Public License as published by
       6             : // the Free Software Foundation; either version 2 of the License, or
       7             : // (at your option) any later version.
       8             : //
       9             : // This program is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             : // GNU General Public License for more details.
      13             : //
      14             : // You should have received a copy of the GNU General Public License
      15             : // along with this program; if not, write to the Free Software
      16             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      17             : 
      18             : 
      19             : // self
      20             : //
      21             : #include    "eventdispatcher/utils.h"
      22             : 
      23             : #include    "eventdispatcher/exception.h"
      24             : 
      25             : 
      26             : // snaplogger lib
      27             : //
      28             : #include    <snaplogger/message.h>
      29             : 
      30             : 
      31             : // snapdev lib
      32             : //
      33             : #include    <snapdev/not_reached.h>
      34             : 
      35             : 
      36             : // last include
      37             : //
      38             : #include    <snapdev/poison.h>
      39             : 
      40             : 
      41             : 
      42             : /** \file
      43             :  * \brief Various helper functions.
      44             :  *
      45             :  * These functions are useful for our event dispatcher environment.
      46             :  */
      47             : 
      48             : namespace ed
      49             : {
      50             : 
      51             : 
      52             : 
      53             : /** \brief Get the current date.
      54             :  *
      55             :  * This function retrieves the current date and time with a precision
      56             :  * of microseconds.
      57             :  *
      58             :  * \todo
      59             :  * This is also defined in snap_child::get_current_date() so we should
      60             :  * unify that in some way...
      61             :  *
      62             :  * \return The time in microseconds.
      63             :  */
      64           0 : std::int64_t get_current_date()
      65             : {
      66             :     timeval tv;
      67           0 :     if(gettimeofday(&tv, nullptr) != 0)
      68             :     {
      69           0 :         int const err(errno);
      70             :         SNAP_LOG_FATAL
      71           0 :             << "gettimeofday() failed with errno: "
      72           0 :             << err
      73           0 :             << " ("
      74           0 :             << strerror(err)
      75           0 :             << ")";
      76           0 :         throw event_dispatcher_runtime_error("gettimeofday() failed");
      77             :     }
      78             : 
      79           0 :     return static_cast<int64_t>(tv.tv_sec) * static_cast<int64_t>(1000000)
      80           0 :          + static_cast<int64_t>(tv.tv_usec);
      81             : }
      82             : 
      83             : 
      84             : 
      85             : /** \brief Get the current date.
      86             :  *
      87             :  * This function retrieves the current date and time with a precision
      88             :  * of nanoseconds.
      89             :  *
      90             :  * \return The time in nanoseconds.
      91             :  */
      92           0 : std::int64_t get_current_date_ns()
      93             : {
      94             :     timespec ts;
      95           0 :     if(clock_gettime(CLOCK_REALTIME_COARSE, &ts) != 0)
      96             :     {
      97           0 :         int const err(errno);
      98             :         SNAP_LOG_FATAL
      99           0 :             << "clock_gettime() failed with errno: "
     100           0 :             << err
     101           0 :             << " ("
     102           0 :             << strerror(err)
     103           0 :             << ")";
     104           0 :         throw event_dispatcher_runtime_error("clock_gettime() failed");
     105             :     }
     106             : 
     107           0 :     return static_cast<int64_t>(ts.tv_sec) * static_cast<int64_t>(1000000000)
     108           0 :          + static_cast<int64_t>(ts.tv_nsec);
     109             : }
     110             : 
     111             : 
     112             : 
     113             : 
     114             : 
     115             : 
     116             : 
     117             : 
     118             : 
     119             : // ========================= HELPER FUNCTIONS TO DELETE ======================
     120             : 
     121             : 
     122             : 
     123             : ///** \brief Check wether a string represents an IPv4 address.
     124             : // *
     125             : // * This function quickly checks whether the specified string defines a
     126             : // * valid IPv4 address. It supports all classes (a.b.c.d, a.b.c., a.b, a)
     127             : // * and all numbers can be in decimal, hexadecimal, or octal.
     128             : // *
     129             : // * \note
     130             : // * The function can be called with a null pointer in which case it
     131             : // * immediate returns false.
     132             : // *
     133             : // * \param[in] ip  A pointer to a string holding an address.
     134             : // *
     135             : // * \return true if the \p ip string represents an IPv4 address.
     136             : // *
     137             : // * \sa snap_inet::inet_pton_v6()
     138             : // */
     139             : //bool is_ipv4(char const * ip)
     140             : //{
     141             : //    if(ip == nullptr)
     142             : //    {
     143             : //        return false;
     144             : //    }
     145             : //
     146             : //    // we must have (1) a number then (2) a dot or end of string
     147             : //    // with a maximum of 4 numbers and 3 dots
     148             : //    //
     149             : //    int64_t addr[4];
     150             : //    size_t pos(0);
     151             : //    for(;; ++ip, ++pos)
     152             : //    {
     153             : //        if(*ip < '0' || *ip > '9' || pos >= sizeof(addr) / sizeof(addr[0]))
     154             : //        {
     155             : //            // not a valid number
     156             : //            return false;
     157             : //        }
     158             : //        int64_t value(0);
     159             : //
     160             : //        // number, may be decimal, octal, or hexadecimal
     161             : //        if(*ip == '0')
     162             : //        {
     163             : //            if(ip[1] == 'x' || ip[1] == 'X')
     164             : //            {
     165             : //                // expect hexadecimal
     166             : //                bool first(true);
     167             : //                for(ip += 2;; ++ip, first = false)
     168             : //                {
     169             : //                    if(*ip >= '0' && *ip <= '9')
     170             : //                    {
     171             : //                        value = value * 16 + *ip - '0';
     172             : //                    }
     173             : //                    else if(*ip >= 'a' && *ip <= 'f')
     174             : //                    {
     175             : //                        value = value * 16 + *ip - 'a' + 10;
     176             : //                    }
     177             : //                    else if(*ip >= 'A' && *ip <= 'F')
     178             : //                    {
     179             : //                        value = value * 16 + *ip - 'A' + 10;
     180             : //                    }
     181             : //                    else
     182             : //                    {
     183             : //                        if(first)
     184             : //                        {
     185             : //                            // not even one digit, not good
     186             : //                            return false;
     187             : //                        }
     188             : //                        // not valid hexadecimal, may be '.' or '\0' (tested below)
     189             : //                        break;
     190             : //                    }
     191             : //                    if(value >= 0x100000000)
     192             : //                    {
     193             : //                        // too large even if we have no dots
     194             : //                        return false;
     195             : //                    }
     196             : //                }
     197             : //            }
     198             : //            else
     199             : //            {
     200             : //                // expect octal
     201             : //                for(++ip; *ip >= '0' && *ip <= '8'; ++ip)
     202             : //                {
     203             : //                    value = value * 8 + *ip - '0';
     204             : //                    if(value >= 0x100000000)
     205             : //                    {
     206             : //                        // too large even if we have no dots
     207             : //                        return false;
     208             : //                    }
     209             : //                }
     210             : //            }
     211             : //        }
     212             : //        else
     213             : //        {
     214             : //            // expect decimal
     215             : //            for(; *ip >= '0' && *ip <= '9'; ++ip)
     216             : //            {
     217             : //                value = value * 10 + *ip - '0';
     218             : //                if(value >= 0x100000000)
     219             : //                {
     220             : //                    // too large even if we have no dots
     221             : //                    return false;
     222             : //                }
     223             : //            }
     224             : //        }
     225             : ////std::cerr << "value[" << pos << "] = " << value << "\n";
     226             : //        addr[pos] = value;
     227             : //        if(*ip != '.')
     228             : //        {
     229             : //            if(*ip != '\0')
     230             : //            {
     231             : //                return false;
     232             : //            }
     233             : //            ++pos;
     234             : //            break;
     235             : //        }
     236             : //    }
     237             : //
     238             : ////std::cerr << "pos = " << pos << "\n";
     239             : //    switch(pos)
     240             : //    {
     241             : //    case 1:
     242             : //        // one large value is considered valid for IPv4
     243             : //        // max. was already checked
     244             : //        return true;
     245             : //
     246             : //    case 2:
     247             : //        return addr[0] < 256 && addr[1] < 0x1000000;
     248             : //
     249             : //    case 3:
     250             : //        return addr[0] < 256 && addr[1] < 256 && addr[2] < 0x10000;
     251             : //
     252             : //    case 4:
     253             : //        return addr[0] < 256 && addr[1] < 256 && addr[2] < 256 && addr[3] < 256;
     254             : //
     255             : //    //case 0: (can happen on empty string)
     256             : //    default:
     257             : //        // no values, that is incorrect!?
     258             : //        return false;
     259             : //
     260             : //    }
     261             : //
     262             : //    snap::NOTREACHED();
     263             : //}
     264             : //
     265             : //
     266             : ///** \brief Check wether a string represents an IPv6 address.
     267             : // *
     268             : // * This function quickly checks whether the specified string defines a
     269             : // * valid IPv6 address. It supports the IPv4 notation at times used
     270             : // * inside an IPv6 notation.
     271             : // *
     272             : // * \note
     273             : // * The function can be called with a null pointer in which case it
     274             : // * immediate returns false.
     275             : // *
     276             : // * \param[in] ip  A pointer to a string holding an address.
     277             : // *
     278             : // * \return true if the \p ip string represents an IPv6 address.
     279             : // */
     280             : //bool is_ipv6(char const * ip)
     281             : //{
     282             : //    if(ip == nullptr)
     283             : //    {
     284             : //        return false;
     285             : //    }
     286             : //
     287             : //    // an IPv6 is a set of 16 bit numbers separated by colon
     288             : //    // the last two numbers can represented in dot notation (ipv4 class a)
     289             : //    //
     290             : //    bool found_colon_colon(false);
     291             : //    int count(0);
     292             : //    if(*ip == ':'
     293             : //    && ip[1] == ':')
     294             : //    {
     295             : //        found_colon_colon = true;
     296             : //        ip += 2;
     297             : //    }
     298             : //    for(; *ip != '\0'; ++ip)
     299             : //    {
     300             : //        if(count >= 8)
     301             : //        {
     302             : //            return false;
     303             : //        }
     304             : //
     305             : //        // all numbers are in hexadecimal
     306             : //        int value(0);
     307             : //        bool first(true);
     308             : //        for(;; ++ip, first = false)
     309             : //        {
     310             : //            if(*ip >= '0' && *ip <= '9')
     311             : //            {
     312             : //                value = value * 16 + *ip - '0';
     313             : //            }
     314             : //            else if(*ip >= 'a' && *ip <= 'f')
     315             : //            {
     316             : //                value = value * 16 + *ip - 'a' + 10;
     317             : //            }
     318             : //            else if(*ip >= 'A' && *ip <= 'F')
     319             : //            {
     320             : //                value = value * 16 + *ip - 'A' + 10;
     321             : //            }
     322             : //            else
     323             : //            {
     324             : //                if(first)
     325             : //                {
     326             : //                    // not even one digit, not good
     327             : //                    return false;
     328             : //                }
     329             : //                // not valid hexadecimal, may be ':' or '\0' (tested below)
     330             : //                break;
     331             : //            }
     332             : //            if(value >= 0x10000)
     333             : //            {
     334             : //                // too large, must be 16 bit numbers
     335             : //                return false;
     336             : //            }
     337             : //        }
     338             : //        ++count;
     339             : ////std::cerr << count << ". value=" << value << " -> " << static_cast<int>(*ip) << "\n";
     340             : //        if(*ip == '\0')
     341             : //        {
     342             : //            break;
     343             : //        }
     344             : //
     345             : //        // note: if we just found a '::' then here *ip == ':' still
     346             : //        if(*ip == '.')
     347             : //        {
     348             : //            // if we have a '.' we must end with an IPv4 and we either
     349             : //            // need found_colon_colon to be true or the count must be
     350             : //            // exactly 6 (1 "missing" colon)
     351             : //            //
     352             : //            if(!found_colon_colon
     353             : //            && count != 7)  // we test with 7 because the first IPv4 number was already read
     354             : //            {
     355             : //                return false;
     356             : //            }
     357             : //            // also the value is 0 to 255 or it's an error too, but the
     358             : //            // problem here is that we need a decimal number and we just
     359             : //            // checked it as an hexadecimal...
     360             : //            //
     361             : //            if((value & 0x00f) >= 0x00a
     362             : //            || (value & 0x0f0) >= 0x0a0
     363             : //            || (value & 0xf00) >= 0xa00)
     364             : //            {
     365             : //                return false;
     366             : //            }
     367             : //            // transform back to a decimal number to verify the max.
     368             : //            //
     369             : //            value = (value & 0x00f) + (value & 0x0f0) / 16 * 10 + (value & 0xf00) / 256 * 100;
     370             : //            if(value > 255)
     371             : //            {
     372             : //                return false;
     373             : //            }
     374             : //            // now check the other numbers
     375             : //            int pos(1); // start at 1 since we already have 1 number checked
     376             : //            for(++ip; *ip != '\0'; ++ip, ++pos)
     377             : //            {
     378             : //                if(*ip < '0' || *ip > '9' || pos >= 4)
     379             : //                {
     380             : //                    // not a valid number
     381             : //                    return false;
     382             : //                }
     383             : //
     384             : //                // only expect decimal in this case in class d (a.b.c.d)
     385             : //                value = 0;
     386             : //                for(; *ip >= '0' && *ip <= '9'; ++ip)
     387             : //                {
     388             : //                    value = value * 10 + *ip - '0';
     389             : //                    if(value > 255)
     390             : //                    {
     391             : //                        // too large
     392             : //                        return false;
     393             : //                    }
     394             : //                }
     395             : //
     396             : //                if(*ip != '.')
     397             : //                {
     398             : //                    if(*ip != '\0')
     399             : //                    {
     400             : //                        return false;
     401             : //                    }
     402             : //                    break;
     403             : //                }
     404             : //            }
     405             : //
     406             : //            // we got a valid IPv4 at the end of IPv6 and we
     407             : //            // found the '\0' so we are all good...
     408             : //            //
     409             : //            return true;
     410             : //        }
     411             : //
     412             : //        if(*ip != ':')
     413             : //        {
     414             : //            return false;
     415             : //        }
     416             : //
     417             : //        // double colon?
     418             : //        if(ip[1] == ':')
     419             : //        {
     420             : //#pragma GCC diagnostic push
     421             : //#pragma GCC diagnostic ignored "-Wstrict-overflow"
     422             : //            if(!found_colon_colon && count < 6)
     423             : //#pragma GCC diagnostic pop
     424             : //            {
     425             : //                // we can accept one '::'
     426             : //                ++ip;
     427             : //                found_colon_colon = true;
     428             : //            }
     429             : //            else
     430             : //            {
     431             : //                // a second :: is not valid for an IPv6
     432             : //                return false;
     433             : //            }
     434             : //        }
     435             : //    }
     436             : //
     437             : //    return count == 8 || (count >= 1 && found_colon_colon);
     438             : //}
     439             : //
     440             : //
     441             : ///** \brief Retrieve an address and a port from a string.
     442             : // *
     443             : // * This function breaks up an address and a port number from a string.
     444             : // *
     445             : // * The address can either be an IPv4 address followed by a colon and
     446             : // * the port number, or an IPv6 address written between square brackets
     447             : // * ([::1]) followed by a colon and the port number. We also support
     448             : // * just a port specification as in ":4040".
     449             : // *
     450             : // * Port numbers are limited to a number between 1 and 65535 inclusive.
     451             : // * They can only be specified in base 10.
     452             : // *
     453             : // * The port is optional only if a \p default_port is provided (by
     454             : // * default the \p default_port parameter is set to zero meaning that
     455             : // * it is not specified.)
     456             : // *
     457             : // * If the addr_port string is empty, then the addr and port parameters
     458             : // * are not modified, which means you want to define them with defaults
     459             : // * before calling this function.
     460             : // *
     461             : // * \exception snapwebsites_exception_invalid_parameters
     462             : // * If any parameter is considered invalid (albeit the validity of the
     463             : // * address is not checked since it could be a fully qualified domain
     464             : // * name) then this exception is raised.
     465             : // *
     466             : // * \param[in] addr_port  The address and port pair.
     467             : // * \param[in,out] addr  The address part, without the square brackets for
     468             : // *                IPv6 addresses.
     469             : // * \param[in,out] port  The port number (1 to 65535 inclusive.)
     470             : // * \param[in] protocol  The protocol for the port (i.e. "tcp" or "udp")
     471             : // */
     472             : //void get_addr_port(QString const & addr_port, QString & addr, int & port, char const * protocol)
     473             : //{
     474             : //    // if there is a colon, we may have a port or IPv6
     475             : //    //
     476             : //    int const p(addr_port.lastIndexOf(":"));
     477             : //    if(p != -1)
     478             : //    {
     479             : //        QString port_str;
     480             : //
     481             : //        // if there is a ']' then we have an IPv6
     482             : //        //
     483             : //        int const bracket(addr_port.lastIndexOf("]"));
     484             : //        if(bracket != -1)
     485             : //        {
     486             : //            // we must have a starting '[' otherwise it is wrong
     487             : //            //
     488             : //            if(addr_port[0] != '[')
     489             : //            {
     490             : //                SNAP_LOG_FATAL("invalid address/port specification in \"")(addr_port)("\" (missing '[' at the start.)");
     491             : //                throw tcp_client_server_parameter_error("get_addr_port(): invalid [IPv6]:port specification, '[' missing.");
     492             : //            }
     493             : //
     494             : //            // extract the address
     495             : //            //
     496             : //            addr = addr_port.mid(1, bracket - 1); // exclude the '[' and ']'
     497             : //
     498             : //            // is there a port?
     499             : //            //
     500             : //            if(p == bracket + 1)
     501             : //            {
     502             : //                // IPv6 port specification is just after the ']'
     503             : //                //
     504             : //                port_str = addr_port.mid(p + 1); // ignore the ':'
     505             : //            }
     506             : //            else if(bracket != addr_port.length() - 1)
     507             : //            {
     508             : //                // the ']' is not at the very end when no port specified
     509             : //                //
     510             : //                SNAP_LOG_FATAL("invalid address/port specification in \"")(addr_port)("\" (']' is not at the end)");
     511             : //                throw tcp_client_server_parameter_error("get_addr_port(): invalid [IPv6]:port specification, ']' not at the end.");
     512             : //            }
     513             : //        }
     514             : //        else
     515             : //        {
     516             : //            // IPv4 port specification
     517             : //            //
     518             : //            if(p > 0)
     519             : //            {
     520             : //                // if p is zero, then we just had a port (:4040)
     521             : //                //
     522             : //                addr = addr_port.mid(0, p); // ignore the ':'
     523             : //            }
     524             : //            port_str = addr_port.mid(p + 1); // ignore the ':'
     525             : //        }
     526             : //
     527             : //        // if port_str is still empty, we had an IPv6 without port
     528             : //        //
     529             : //        if(!port_str.isEmpty())
     530             : //        {
     531             : //            // first check whether the port is a number
     532             : //            //
     533             : //            bool ok(false);
     534             : //            port = port_str.toInt(&ok, 10); // force base 10
     535             : //            if(!ok)
     536             : //            {
     537             : //                // not a valid number, try to get it from /etc/services
     538             : //                //
     539             : //                struct servent const * s(getservbyname(port_str.toUtf8().data(), protocol));
     540             : //                if(s == nullptr)
     541             : //                {
     542             : //                    SNAP_LOG_FATAL("invalid port specification in \"")(addr_port)("\", port not a decimal number nor a known service name.");
     543             : //                    throw tcp_client_server_parameter_error("get_addr_port(): invalid addr:port specification, port number or name is not valid.");
     544             : //                }
     545             : //                port = s->s_port;
     546             : //            }
     547             : //        }
     548             : //    }
     549             : //    else if(!addr_port.isEmpty())
     550             : //    {
     551             : //        // just an IPv4 address specified, no port
     552             : //        //
     553             : //        addr = addr_port;
     554             : //    }
     555             : //
     556             : //    // the address could end up being the empty string here
     557             : //    if(addr.isEmpty())
     558             : //    {
     559             : //        SNAP_LOG_FATAL("invalid address/port specification in \"")(addr_port)("\", address is empty.");
     560             : //        throw tcp_client_server_parameter_error("get_addr_port(): invalid addr:port specification, address is empty (this generally happens when a request is done with no default address).");
     561             : //    }
     562             : //
     563             : //    // finally verify that the port is in range
     564             : //    if(port <= 0
     565             : //    || port > 65535)
     566             : //    {
     567             : //        SNAP_LOG_FATAL("invalid address/port specification in \"")(addr_port)("\", port out of bounds.");
     568             : //        throw tcp_client_server_parameter_error("get_addr_port(): invalid addr:port specification, port number is out of bounds (1 .. 65535).");
     569             : //    }
     570             : //}
     571             : 
     572             : 
     573           6 : } // namespace ed
     574             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12