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

Generated by: LCOV version 1.13