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

Generated by: LCOV version 1.12