LCOV - code coverage report
Current view: top level - libaddr - unix.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 180 180 100.0 %
Date: 2022-03-01 21:05:13 Functions: 25 25 100.0 %
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/libaddr
       4             : //
       5             : // Permission is hereby granted, free of charge, to any person obtaining a
       6             : // copy of this software and associated documentation files (the
       7             : // "Software"), to deal in the Software without restriction, including
       8             : // without limitation the rights to use, copy, modify, merge, publish,
       9             : // distribute, sublicense, and/or sell copies of the Software, and to
      10             : // permit persons to whom the Software is furnished to do so, subject to
      11             : // the following conditions:
      12             : //
      13             : // The above copyright notice and this permission notice shall be included
      14             : // in all copies or substantial portions of the Software.
      15             : //
      16             : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      17             : // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      18             : // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      19             : // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
      20             : // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
      21             : // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      22             : // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      23             : 
      24             : 
      25             : /** \file
      26             :  * \brief The implementation of the unix class.
      27             :  *
      28             :  * This file includes the implementation of the unix class. The one that
      29             :  * deals with low level Unix addresses.
      30             :  */
      31             : 
      32             : // self
      33             : //
      34             : #include    "libaddr/unix.h"
      35             : #include    "libaddr/addr_exception.h"
      36             : 
      37             : 
      38             : // snapdev lib
      39             : //
      40             : #include    <snapdev/join_strings.h>
      41             : #include    <snapdev/raii_generic_deleter.h>
      42             : #include    <snapdev/tokenize_string.h>
      43             : 
      44             : 
      45             : // libutf8 library
      46             : //
      47             : #include    <libutf8/libutf8.h>
      48             : 
      49             : 
      50             : // C++ library
      51             : //
      52             : #include    <iostream>
      53             : 
      54             : 
      55             : // C library
      56             : //
      57             : #include    <sys/stat.h>
      58             : 
      59             : 
      60             : // last include
      61             : //
      62             : #include    <snapdev/poison.h>
      63             : 
      64             : 
      65             : 
      66             : 
      67             : 
      68             : namespace addr
      69             : {
      70             : 
      71             : 
      72             : 
      73             : 
      74             : 
      75             : 
      76             : /** \brief Create a unix object that represents an unnamed socket.
      77             :  *
      78             :  * The default is to create an unnamed address. Note that you can later
      79             :  * change an address with functions such as the set_abstract() function.
      80             :  */
      81          89 : unix::unix()
      82             : {
      83          89 : }
      84             : 
      85             : 
      86             : /** \brief Create a unix object from a binary Unix address structure.
      87             :  *
      88             :  * This function initializes this Unix object with the specified sockaddr_un
      89             :  * address.
      90             :  *
      91             :  * \param[in] in  The Unix address.
      92             :  */
      93         113 : unix::unix(sockaddr_un const & un)
      94             : {
      95         113 :     set_un(un);
      96          61 : }
      97             : 
      98             : 
      99             : /** \brief Create an addr object from a binary IPv6 address.
     100             :  *
     101             :  * This function initializes this addr object with the specified IPv6
     102             :  * address. The is_ipv4() function will return false.
     103             :  *
     104             :  * \note
     105             :  * In this case, the \p address parameter is expected to be a bare
     106             :  * address. If you have a URI address, make sure to create the
     107             :  * unix address and then call the set_uri() function.
     108             :  *
     109             :  * \param[in] address  A Unix address in a string.
     110             :  * \param[in] abstract  Whether this address is considered abstract.
     111             :  */
     112         332 : unix::unix(std::string const & address, bool abstract)
     113             : {
     114         332 :     if(abstract)
     115             :     {
     116         128 :         set_abstract(address);
     117             :     }
     118         204 :     else if(!address.empty())
     119             :     {
     120         203 :         set_file(address);
     121             :     }
     122             :     //else -- this is the default so we don't need to call that function
     123             :     //{
     124             :     //    make_unnamed();
     125             :     //}
     126         244 : }
     127             : 
     128             : 
     129             : /** \brief Save a Unix address in this unix object.
     130             :  *
     131             :  * This function saves the specified Unix address in this unix object.
     132             :  *
     133             :  * Any type of address can be saved. The function determines what type
     134             :  * this address represents (i.e. file, abstract, or unnamed).
     135             :  *
     136             :  * \warning
     137             :  * This function does not just copy the input address in this unix
     138             :  * object. It applies our detection mechanism to detect which type
     139             :  * of address you are supplying and then call one of the set_file(),
     140             :  * set_abstract(), or make_unnamed() functions. Therefore, the function
     141             :  * may throw because the address is not considered compatible (invalid
     142             :  * UTF-8, includes control characters, etc.) Also, in the case of an
     143             :  * abstract name, if it includes '\0' characters, then it won't work
     144             :  * as expected. These will not be detected properly.
     145             :  *
     146             :  * \todo
     147             :  * I think that to properly support the abstract name we should offer
     148             :  * a size input parameter so we know of the exact size of the address.
     149             :  *
     150             :  * \exception addr_invalid_argument
     151             :  * The input address must be of type AF_UNIX or AF_LOCAL.
     152             :  *
     153             :  * \param[in] in  The Unix address to save in this unix object.
     154             :  */
     155         168 : void unix::set_un(struct sockaddr_un const & un)
     156             : {
     157         168 :     if(un.sun_family != AF_UNIX)
     158             :     {
     159         100 :         throw addr_invalid_structure("unix::set_un(): the input address does not represent a Unix address (family is not AF_UNIX).");
     160             :     }
     161             : 
     162          68 :     if(un.sun_path[0] != '\0')
     163             :     {
     164          33 :         if(strnlen(un.sun_path, sizeof(un.sun_path)) == sizeof(un.sun_path))
     165             :         {
     166           2 :             throw addr_invalid_argument("unix::set_un(): the input address filename is too long.");
     167             :         }
     168             : 
     169             :         // this is considered a file address
     170             :         // (we do not support a missing '\0' at the end of the name, but
     171             :         // the input could be missing it so we have to make sure by creating
     172             :         // a temp version of the name)
     173             :         //
     174          31 :         char temp[sizeof(un.sun_path) + 1];
     175          31 :         memcpy(temp, un.sun_path, sizeof(temp) - 1);
     176          31 :         temp[sizeof(temp) - 1] = '\0';
     177          31 :         set_file(un.sun_path);
     178             :     }
     179          35 :     else if(un.sun_path[1] != '\0')
     180             :     {
     181          33 :         std::size_t const len(strnlen(un.sun_path + 1, sizeof(un.sun_path) - 1));
     182          33 :         if(len == sizeof(un.sun_path) - 1)
     183             :         {
     184           2 :             throw addr_invalid_argument("unix::set_un(): the input abstract name is too long.");
     185             :         }
     186             : 
     187             :         // in case we are missing a '\0' at the end
     188             :         // (we are not compatible in that way too)
     189             :         //
     190             :         //char temp[sizeof(un.sun_path) + 1];
     191             :         //for(int idx(0); idx < sizeof(temp) - 1 && un.sun_path[idx + 1] != '\0'; ++idx)
     192             :         //{
     193             :         //    temp[idx] = un.sun_path[idx + 1];
     194             :         //}
     195             :         ////memcpy(temp, un.sun_path + 1, sizeof(temp) - 1);
     196             :         //temp[sizeof(temp) - 1] = '\0';
     197          31 :         set_abstract(std::string(un.sun_path + 1, len));
     198             :     }
     199             :     else
     200             :     {
     201           2 :         make_unnamed();
     202             :     }
     203          64 : }
     204             : 
     205             : 
     206             : /** \brief Change this Unix address in an unnamed Unix address.
     207             :  *
     208             :  * Transform this Unix address in an unnamed Unix address.
     209             :  *
     210             :  * \note
     211             :  * Linux accepts an abstract address as having the first sun_path
     212             :  * character set to '\0' and all the other characters set to anything
     213             :  * including all '\0'. We handle our abstract addresses as not supporting
     214             :  * zeroes. Therefore, we do not 100% match Linux.
     215             :  */
     216          97 : void unix::make_unnamed()
     217             : {
     218          97 :     memset(f_address.sun_path, 0, sizeof(f_address.sun_path));
     219          97 : }
     220             : 
     221             : 
     222             : /** \brief Set the this Unix address to the specified filename.
     223             :  *
     224             :  * This function changes address to the specified filename.
     225             :  *
     226             :  * The path does not need to be a full path. However, relative paths are
     227             :  * often considered dangerous.
     228             :  *
     229             :  * \exception addr_invalid_argument
     230             :  * If the input doesn't look like a valid filename, then the function
     231             :  * raises this exception.
     232             :  *
     233             :  * \param[in] file  The path to a file.
     234             :  */
     235         332 : void unix::set_file(std::string const & file)
     236             : {
     237         576 :     std::string const address(verify_path(file, false));
     238             : 
     239         244 :     memcpy(f_address.sun_path, address.c_str(), address.length());
     240         244 :     if(address.length() < sizeof(f_address.sun_path))
     241             :     {
     242             :         // clear the rest
     243             :         //
     244         488 :         memset(
     245         244 :               f_address.sun_path + address.length()
     246             :             , 0
     247         244 :             , sizeof(f_address.sun_path) - address.length());
     248             :     }
     249         244 : }
     250             : 
     251             : 
     252             : /** \brief Set the address to an Abstract Unix Address.
     253             :  *
     254             :  * This function saves the specified \p abstract path as an Abstract Unix
     255             :  * Address in this object.
     256             :  *
     257             :  * Note that we check the \p abstract path as if it were a file path. We
     258             :  * forbid control characters, and it has to be at least one character and
     259             :  * at most 106 characters.
     260             :  *
     261             :  * The function generates an abstract path. That means the file won't be
     262             :  * created on disk. You should choose a path which is not going to conflict
     263             :  * with any other system. It is conventional, in the dbus area, to make use
     264             :  * of your domain name in reverse order (Java-like). For example:
     265             :  *
     266             :  * \code
     267             :  *     u.set_abstract("/net/snapwebsite/settings");
     268             :  * \endcode
     269             :  *
     270             :  * \note
     271             :  * The Linux OS supports abstract paths which include any byte. However,
     272             :  * there are tools to look at those paths as strings, so limiting these
     273             :  * path to valid strings is something we think makes sense. It also
     274             :  * makes it possible for us to distinguish between unnamed and abstract
     275             :  * addresses without the need for another parameter such as an address
     276             :  * size.
     277             :  *
     278             :  * \exception addr_invalid_argument
     279             :  * If the input \p abstract path is not considered valid, then this
     280             :  * exception is raised.
     281             :  *
     282             :  * \param[in] abstract  The abstract path to save in this Unix address.
     283             :  */
     284         254 : void unix::set_abstract(std::string const & abstract)
     285             : {
     286         485 :     std::string const address(verify_path(abstract, true));
     287             : 
     288         231 :     f_address.sun_path[0] = '\0';
     289         231 :     strncpy(f_address.sun_path + 1, address.c_str(), sizeof(f_address.sun_path) - 1);
     290         231 :     if(address.length() < sizeof(f_address.sun_path) - 2)
     291             :     {
     292             :         // clear the rest
     293             :         //
     294         462 :         memset(
     295         231 :               f_address.sun_path + address.length() + 2
     296             :             , 0
     297         231 :             , sizeof(f_address.sun_path) - address.length() - 2);
     298             :     }
     299         231 : }
     300             : 
     301             : 
     302             : /** \brief Allow for URI like notation to set a Unix address.
     303             :  *
     304             :  * Since we often use a preference setting which is a string to define our
     305             :  * addresses, having a notation that clearly distinguishes between the
     306             :  * Unix address types seems to make sense.
     307             :  *
     308             :  * We support the following basic URI syntax:
     309             :  *
     310             :  * \code
     311             :  *     <type>:[<path>][?<mode>]
     312             :  * \endcode
     313             :  *
     314             :  * Where `\<type>` has to be one of:
     315             :  *
     316             :  * * `unix:` -- this is the only scheme we currently support
     317             :  *
     318             :  * Where `\<path>` is the path to the file or abstract filename. For unnamed
     319             :  * sockets, it must be an empty string. If it starts with more than one
     320             :  * slash, extraneous slashes are removed (actually, any extraneous slashes
     321             :  * within the name are removed).
     322             :  *
     323             :  * Where `\<mode>` must be one of:
     324             :  *
     325             :  * * `?unnamed` -- create an unnamed address, the `\<path>` must be empty
     326             :  * * `?file` -- create a file based address, the `\<path>` cannot be empty
     327             :  * * `?abstract` -- create an abstract address
     328             :  *
     329             :  * By default, when the `\<mode>` is not specified, the function creates
     330             :  * a file based address unless the address is empty in which case it
     331             :  * creates an unnamed address. The only way to create an abstract name
     332             :  * is by specifying the `?abstract` query string.
     333             :  *
     334             :  * \note
     335             :  * We do not use/support the `file:///` scheme because this is a reference
     336             :  * to a specific file, not a socket. We think that `unix:` is better adapted
     337             :  * to our situation.
     338             :  *
     339             :  * \warning
     340             :  * At the moment the parsing of the string is very basic. You must make sure
     341             :  * not to include anything more than what is allowed as presented above.
     342             :  *
     343             :  * \todo
     344             :  * Use the snap_uri once we extracted that in its own library.
     345             :  *
     346             :  * \exception addr_invalid_argument
     347             :  * If the URI can't be properly parsed, this function raises this exception.
     348             :  *
     349             :  * \param[in] uri  The URI to save in this address.
     350             :  */
     351         252 : void unix::set_uri(std::string const & uri)
     352             : {
     353             :     enum class uri_force_t
     354             :     {
     355             :         URI_FORCE_NONE,
     356             :         URI_FORCE_UNNAMED,
     357             :         URI_FORCE_FILE,
     358             :         URI_FORCE_ABSTRACT,
     359             :     };
     360             : 
     361         252 :     std::string::size_type const scheme_pos(uri.find(':'));
     362         252 :     if(scheme_pos == std::string::npos)
     363             :     {
     364           1 :         throw addr_invalid_argument("invalid URI for a Unix address, scheme not found (':' missing)");
     365             :     }
     366             : 
     367         502 :     std::string const scheme(uri.substr(0, scheme_pos));
     368             : 
     369         502 :     std::string address;
     370         502 :     std::string query;
     371             : 
     372         251 :     std::string::size_type query_pos(uri.find('?', scheme_pos + 1));
     373         251 :     if(query_pos == std::string::npos)
     374             :     {
     375          88 :         address = uri.substr(scheme_pos + 1);
     376             :     }
     377             :     else
     378             :     {
     379         163 :         address = uri.substr(scheme_pos + 1, query_pos - scheme_pos - 1);
     380         163 :         query = uri.substr(query_pos + 1);
     381             :     }
     382             : 
     383         251 :     uri_force_t force(uri_force_t::URI_FORCE_NONE);
     384         251 :     if(!query.empty())
     385             :     {
     386         163 :         if(query == "unnamed")
     387             :         {
     388          39 :             force = uri_force_t::URI_FORCE_UNNAMED;
     389             :         }
     390         124 :         else if(query == "file")
     391             :         {
     392          37 :             force = uri_force_t::URI_FORCE_FILE;
     393             :         }
     394          87 :         else if(query == "abstract")
     395             :         {
     396          86 :             force = uri_force_t::URI_FORCE_ABSTRACT;
     397             :         }
     398             :         else
     399             :         {
     400             :             throw addr_invalid_argument(
     401             :                   "\""
     402           2 :                 + query
     403           3 :                 + "\" is not a supported URI query string for a Unix address;"
     404           3 :                   " supported query strings are one of: \"unnamed\", \"file\" and \"abstract\".");
     405             :         }
     406             :     }
     407             : 
     408         250 :     if(scheme != "unix")
     409             :     {
     410             :         throw addr_invalid_argument(
     411             :               "\""
     412           2 :             + scheme
     413           3 :             + "\" is not a supported URI scheme for a Unix address;"
     414           3 :               " supported scheme are: \"stream\", \"dgram\" and \"seqpacket\".");
     415             :     }
     416             : 
     417         249 :     switch(force)
     418             :     {
     419          88 :     case uri_force_t::URI_FORCE_NONE:
     420          88 :         if(address.empty())
     421             :         {
     422          37 :             make_unnamed();
     423             :         }
     424             :         else
     425             :         {
     426          51 :             set_file(address);
     427             :         }
     428          76 :         break;
     429             : 
     430          39 :     case uri_force_t::URI_FORCE_UNNAMED:
     431          39 :         if(!address.empty())
     432             :         {
     433             :             throw addr_invalid_argument(
     434             :                   "address \""
     435           2 :                 + address
     436           3 :                 + "\" must be empty to represent an unnamed Unix address.");
     437             :         }
     438          38 :         make_unnamed();
     439          38 :         break;
     440             : 
     441          37 :     case uri_force_t::URI_FORCE_FILE:
     442          37 :         set_file(address);
     443          37 :         break;
     444             : 
     445          85 :     case uri_force_t::URI_FORCE_ABSTRACT:
     446          85 :         set_abstract(address);
     447          74 :         break;
     448             : 
     449             :     }
     450         225 : }
     451             : 
     452             : 
     453             : /** \brief Define this address given an open socket.
     454             :  *
     455             :  * This function tries to retrieve the address of a socket. If the function
     456             :  * succeeds, then it returns true meaning that the address is considered
     457             :  * valid.
     458             :  *
     459             :  * The function verifies that the address is indeed a Unix address. If not,
     460             :  * then it fails with EADDRNOTAVAIL and this object is not modified.
     461             :  *
     462             :  * \warning
     463             :  * The function makes sure that the name of the socket fits a
     464             :  * sockaddr_un.sun_path as per our rules (i.e. we force the presence
     465             :  * of the '\0' terminator). So this function may throw an exception
     466             :  * on Linux which supports socket names without the '\0'. Further,
     467             :  * if the name is not considered compatible with our verify_path()
     468             :  * function.
     469             :  *
     470             :  * \return true if the address was successfully retrieved.
     471             :  */
     472           5 : bool unix::set_from_socket(int s)
     473             : {
     474             :     // WARNING: the sockaddr (or sockaddr_storage) structure that the
     475             :     //          getsockname() expects is not large enough for a Unix
     476             :     //          socket so we use a sockaddr_un instead
     477             :     //
     478           5 :     sockaddr_un address;
     479           5 :     socklen_t length(sizeof(address));
     480           5 :     if(getsockname(s, reinterpret_cast<sockaddr *>(&address), &length) != 0)
     481             :     {
     482           1 :         return false;
     483             :     }
     484             : 
     485           4 :     if(address.sun_family != AF_UNIX)
     486             :     {
     487           1 :         errno = EADDRNOTAVAIL;
     488           1 :         return false;
     489             :     }
     490             : 
     491           3 :     if(length < sizeof(address))
     492             :     {
     493           3 :         memset(
     494             :                   reinterpret_cast<char *>(&address) + length
     495             :                 , 0
     496             :                 , sizeof(address) - length);
     497             :     }
     498             : 
     499           3 :     set_un(address);
     500             : 
     501           3 :     return true;
     502             : }
     503             : 
     504             : 
     505             : /** \brief Check whether this address represents file based Unix address.
     506             :  *
     507             :  * The function checks whether the path starts with a character other
     508             :  * than '\0'.
     509             :  *
     510             :  * \return true if this addr represents a file based Unix address.
     511             :  */
     512        1042 : bool unix::is_file() const
     513             : {
     514        1042 :     return f_address.sun_path[0] != '\0';
     515             : }
     516             : 
     517             : 
     518             : /** \brief Check whether this address represents an abstract Unix address.
     519             :  *
     520             :  * This function checks whether this Unix address represet an abstract
     521             :  * Unix address.
     522             :  *
     523             :  * An abstract Unix address has the first byte of the path set to '\0'
     524             :  * and the second not set to '\0'.
     525             :  *
     526             :  * \return true if this address represents an abstract Unix address.
     527             :  */
     528        1120 : bool unix::is_abstract() const
     529             : {
     530        1120 :     return f_address.sun_path[0] == '\0'
     531        1120 :         && f_address.sun_path[1] != '\0';
     532             : }
     533             : 
     534             : 
     535             : /** \brief Check whether this address represents an unnamed Unix address.
     536             :  *
     537             :  * This function checks whether the path represents and unnamed Unix address.
     538             :  *
     539             :  * An unnamed Unix address has all the bytes of the `sun_path` string set
     540             :  * to '\0', but we really only need to test the first two.
     541             :  *
     542             :  * \return true if the address represents an unnamed Unix address.
     543             :  */
     544        1120 : bool unix::is_unnamed() const
     545             : {
     546        1120 :     return f_address.sun_path[0] == '\0'
     547        1120 :         && f_address.sun_path[1] == '\0';
     548             : }
     549             : 
     550             : 
     551             : /** \brief Retrieve a copy of this Unix address.
     552             :  *
     553             :  * This function returns the Unix address as currently defined in this
     554             :  * unix object.
     555             :  *
     556             :  * The address is distinguished between an unnamed address and an
     557             :  * abstract name by the fact that `sun_path[1] != '\0'` for the
     558             :  * abstract path.
     559             :  *
     560             :  * \param[out] un  The structure where the address gets saved.
     561             :  */
     562         562 : void unix::get_un(sockaddr_un & un) const
     563             : {
     564         562 :     memcpy(&un, &f_address, sizeof(un));
     565         562 : }
     566             : 
     567             : 
     568             : /** \brief Return the path of this Unix address.
     569             :  *
     570             :  * This function returns the path of the Unix address. Note that you can know
     571             :  * if it was an unnamed address, the string will be empty. However, you can't
     572             :  * distinguish between a file or abstract name with this function. You can
     573             :  * always use the is_file() and is_abstract() to know.
     574             :  *
     575             :  * \return the path of this Unix address.
     576             :  */
     577         560 : std::string unix::to_string() const
     578             : {
     579         560 :     if(is_abstract())
     580             :     {
     581         230 :         return f_address.sun_path + 1;
     582             :     }
     583             : 
     584         330 :     return f_address.sun_path;
     585             : }
     586             : 
     587             : 
     588             : /** \brief Get the network type string
     589             :  *
     590             :  * Translate the network type into a string, which can be really useful
     591             :  * to log that information.
     592             :  *
     593             :  * Note that PUBLIC is the same as UNKNOWN, this function returns
     594             :  * "Unknown" in that case, though.
     595             :  *
     596             :  * \return The string representing the type of network.
     597             :  */
     598         560 : std::string unix::to_uri() const
     599             : {
     600         560 :     std::string result;
     601         560 :     result.reserve(125);
     602             : 
     603         560 :     result = "unix:";
     604             : 
     605         560 :     if(!is_unnamed())
     606             :     {
     607         461 :         char const * path(nullptr);
     608         922 :         std::string query;
     609         461 :         if(is_file())
     610             :         {
     611         231 :             path = f_address.sun_path;
     612             :         }
     613             :         else
     614             :         {
     615         230 :             path = f_address.sun_path + 1;
     616         230 :             query = "?abstract";
     617             :         }
     618             : 
     619         461 :         if(path[0] == '/')
     620             :         {
     621         179 :             result += "//";
     622             :         }
     623         461 :         result += path;
     624         461 :         result += query;
     625             :     }
     626             : 
     627         560 :     return result;
     628             : }
     629             : 
     630             : 
     631             : /** \brief Delete the socket file.
     632             :  *
     633             :  * This function will delete the socket file if it exists.
     634             :  *
     635             :  * The function does nothing if the address is not representing a file.
     636             :  * In that case, the function returns 0 and does not modify the errno
     637             :  * variable.
     638             :  *
     639             :  * \note
     640             :  * This function does not verify whether the file is in use. That means
     641             :  * you may delete a file that should not be deleted. It is your
     642             :  * responsibility to verify the current state of the socket. The
     643             :  * ed::local_stream_server_connection implementation takes care of
     644             :  * that for you if you want to have it easy.
     645             :  *
     646             :  * \return 0 if the unlink worked, -1 on error and errno is set.
     647             :  */
     648          21 : int unix::unlink()
     649             : {
     650          21 :     if(is_file())
     651             :     {
     652          10 :         return ::unlink(f_address.sun_path);
     653             :     }
     654             : 
     655          11 :     return 0;
     656             : }
     657             : 
     658             : 
     659             : /** \brief Check whether two addresses are equal.
     660             :  *
     661             :  * This function compares the left hand side (this) and the right
     662             :  * hand side (rhs) for equality. If both represent the same IP
     663             :  * address, then the function returns true.
     664             :  *
     665             :  * \warning
     666             :  * The function only compares the address itself. The family, port,
     667             :  * flow info, scope identifier, protocol are all ignored.
     668             :  *
     669             :  * \param[in] rhs  The other Unix address to compare against.
     670             :  *
     671             :  * \return true if \p this is equal to \p rhs.
     672             :  */
     673           6 : bool unix::operator == (unix const & rhs) const
     674             : {
     675           6 :     return f_address == rhs.f_address;
     676             : }
     677             : 
     678             : 
     679             : /** \brief Check whether two addresses are not equal.
     680             :  *
     681             :  * This function compares the left hand side (this) and the right
     682             :  * hand side (rhs) for inequality. If both represent the same IP
     683             :  * address, then the function returns false.
     684             :  *
     685             :  * \warning
     686             :  * The function only compares the address itself. The family, port,
     687             :  * flow info, scope identifier, protocol are all ignored.
     688             :  *
     689             :  * \param[in] rhs  The other Unix address to compare against.
     690             :  *
     691             :  * \return true if \p this is not equal to \p rhs.
     692             :  */
     693           3 : bool unix::operator != (unix const & rhs) const
     694             : {
     695           3 :     return f_address != rhs.f_address;
     696             : }
     697             : 
     698             : 
     699             : /** \brief Compare two addresses to know which one is smaller.
     700             :  *
     701             :  * This function compares the left hand side (this) and the right
     702             :  * hand side (rhs) to know which one is the smallest. If both
     703             :  * are equal or the left hand side is larger than the right hand
     704             :  * side, then it returns false, otherwise it returns true.
     705             :  *
     706             :  * \warning
     707             :  * The function only compares the address itself. The family, port,
     708             :  * flow info, scope identifier, protocol are all ignored.
     709             :  *
     710             :  * \param[in] rhs  The other Unix address to compare against.
     711             :  *
     712             :  * \return true if \p this is smaller than \p rhs.
     713             :  */
     714           3 : bool unix::operator < (unix const & rhs) const
     715             : {
     716           3 :     return f_address < rhs.f_address;
     717             : }
     718             : 
     719             : 
     720             : /** \brief Compare two addresses to know which one is smaller or equal.
     721             :  *
     722             :  * This function compares the left hand side (this) and the right
     723             :  * hand side (rhs) to know whether the left hand side is smaller or
     724             :  * equal to thr right handside.
     725             :  *
     726             :  * \warning
     727             :  * The function only compares the address itself. The family, port,
     728             :  * flow info, scope identifier, protocol are all ignored.
     729             :  *
     730             :  * \param[in] rhs  The other Unix address to compare against.
     731             :  *
     732             :  * \return true if \p this is smaller than \p rhs.
     733             :  */
     734           3 : bool unix::operator <= (unix const & rhs) const
     735             : {
     736           3 :     return f_address <= rhs.f_address;
     737             : }
     738             : 
     739             : 
     740             : /** \brief Compare two addresses to know which one is smaller.
     741             :  *
     742             :  * This function compares the left hand side (this) and the right
     743             :  * hand side (rhs) to know which one is the smallest. If both
     744             :  * are equal or the left hand side is larger than the right hand
     745             :  * side, then it returns false, otherwise it returns true.
     746             :  *
     747             :  * \warning
     748             :  * The function only compares the address itself. The family, port,
     749             :  * flow info, scope identifier, protocol are all ignored.
     750             :  *
     751             :  * \param[in] rhs  The other Unix address to compare against.
     752             :  *
     753             :  * \return true if \p this is smaller than \p rhs.
     754             :  */
     755           3 : bool unix::operator > (unix const & rhs) const
     756             : {
     757           3 :     return f_address > rhs.f_address;
     758             : }
     759             : 
     760             : 
     761             : /** \brief Compare two addresses to know which one is smaller.
     762             :  *
     763             :  * This function compares the left hand side (this) and the right
     764             :  * hand side (rhs) to know which one is the smallest. If both
     765             :  * are equal or the left hand side is larger than the right hand
     766             :  * side, then it returns false, otherwise it returns true.
     767             :  *
     768             :  * \warning
     769             :  * The function only compares the address itself. The family, port,
     770             :  * flow info, scope identifier, protocol are all ignored.
     771             :  *
     772             :  * \param[in] rhs  The other Unix address to compare against.
     773             :  *
     774             :  * \return true if \p this is smaller than \p rhs.
     775             :  */
     776           3 : bool unix::operator >= (unix const & rhs) const
     777             : {
     778           3 :     return f_address >= rhs.f_address;
     779             : }
     780             : 
     781             : 
     782             : /** \brief Check whether the specified \p path is a valid path.
     783             :  *
     784             :  * Although there are even less restriction on the path of an abstract
     785             :  * socket, we force you to have a valid UTF-8 string without any control
     786             :  * characters (especially not a '\0' character).
     787             :  *
     788             :  * \exception addr_invalid_argument
     789             :  * If \p path is empty or any invalid character is found within the string,
     790             :  * then this exception is raised.
     791             :  *
     792             :  * \exception libutf8::libutf8_exception_decoding
     793             :  * If an invalid UTF-8 character is found, then this exception is raised.
     794             :  *
     795             :  * \param[in] path  The path to be validated.
     796             :  * \param[in] abstract  Whether this is an abstract path (true) or not.
     797             :  *
     798             :  * \return A canonicalized version of \p path.
     799             :  */
     800         586 : std::string unix::verify_path(std::string const & path, bool abstract)
     801             : {
     802         586 :     if(path.empty())
     803             :     {
     804             :         throw addr_invalid_argument(
     805           2 :               std::string(abstract ? "an abstract" : "a Unix")
     806           3 :             + " filename can't be empty;"
     807           3 :               " use make_empty() if you want to use an unnamed socket.");
     808             :     }
     809             : 
     810         585 :     std::size_t const max_length(abstract
     811         585 :                 ? sizeof(f_address.sun_path) - 1
     812             :                 : sizeof(f_address.sun_path));
     813             : 
     814        1170 :     std::vector<std::string> segments;
     815         585 :     snapdev::tokenize_string(segments, path, "/", true);
     816         585 :     std::string p(snapdev::join_strings(segments, "/"));
     817         585 :     if(path[0] == '/')
     818             :     {
     819         181 :         p.insert(0, 1, '/');
     820             :     }
     821             : 
     822         585 :     if(p.length() >= max_length)
     823             :     {
     824             :         throw addr_invalid_argument(
     825          88 :               std::string(abstract ? "an abstract" : "a Unix")
     826         132 :             + " filename is limited to "
     827         176 :             + std::to_string(max_length)
     828         132 :             + " characters.");
     829             :     }
     830             : 
     831        1081 :     std::u32string u32(libutf8::to_u32string(p));
     832       21154 :     for(auto const & c : u32)
     833             :     {
     834       20678 :         if(c <= 0x1F                     // controls
     835       20647 :         || (c >= 0x7F && c <= 0x9F))    // graphic controls
     836             :         {
     837             :             throw addr_invalid_argument(
     838             :                   "path \""
     839         128 :                 + path
     840         192 :                 + "\" is not a valid UTF-8 string (it includes controls).");
     841             :         }
     842             :     }
     843             : 
     844         476 :     if(p == "/")
     845             :     {
     846             :             throw addr_invalid_argument(
     847           1 :                 "the root path (\"/\") is not a valid socket filename.");
     848             :     }
     849             : 
     850         950 :     return p;
     851             : }
     852             : 
     853             : 
     854             : 
     855           6 : }
     856             : // namespace addr
     857             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13