LCOV - code coverage report
Current view: top level - eventdispatcher - local_stream_client_connection.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 27 49 55.1 %
Date: 2021-09-19 09:06:58 Functions: 8 11 72.7 %
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/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 along
      17             : // with this program; if not, write to the Free Software Foundation, Inc.,
      18             : // 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      19             : 
      20             : /** \file
      21             :  * \brief Handle an AF_UNIX socket.
      22             :  *
      23             :  * Class used to handle a Unix socket.
      24             :  */
      25             : 
      26             : 
      27             : // self
      28             : //
      29             : #include    "eventdispatcher/local_stream_client_connection.h"
      30             : 
      31             : #include    "eventdispatcher/exception.h"
      32             : //#include    "eventdispatcher/utils.h"
      33             : 
      34             : 
      35             : // snaplogger lib
      36             : //
      37             : #include    <snaplogger/message.h>
      38             : 
      39             : 
      40             : // C lib
      41             : //
      42             : //#include    <netdb.h>
      43             : //#include    <arpa/inet.h>
      44             : //#include    <string.h>
      45             : 
      46             : 
      47             : // last include
      48             : //
      49             : #include    <snapdev/poison.h>
      50             : 
      51             : 
      52             : 
      53             : namespace ed
      54             : {
      55             : 
      56             : 
      57             : 
      58             : /** \class local_stream_client_connection
      59             :  * \brief Create a client socket and connect to a server.
      60             :  *
      61             :  * This class is a client socket implementation used to connect to a server.
      62             :  * The server is expected to be running at the time the client is created
      63             :  * otherwise it fails connecting.
      64             :  *
      65             :  * This class is not appropriate to connect to a server that may come and go
      66             :  * over time.
      67             :  */
      68             : 
      69             : 
      70             : 
      71             : 
      72             : /** \brief Construct a local_stream_client_connection object.
      73             :  *
      74             :  * The local_stream_client_connection constructor initializes a streaming
      75             :  * Unix socket object by connecting to the specified server. The server
      76             :  * is defined with the \p u parameters.
      77             :  *
      78             :  * \exception event_dispatcher_runtime_error
      79             :  * This exception is raised if the client cannot create the socket or it
      80             :  * cannot connect to the server.
      81             :  *
      82             :  * \param[in] u  The Unux address of the server to connect to.
      83             :  * \param[in] close_on_exec  Whether to close this socket on an execve() call.
      84             :  */
      85           1 : local_stream_client_connection::local_stream_client_connection(
      86             :               addr::unix const & address
      87             :             , bool const blocking
      88           1 :             , bool const close_on_exec)
      89           1 :     : f_address(address)
      90             : {
      91           1 :     sockaddr_un un;
      92           1 :     f_address.get_un(un);
      93           2 :     f_socket.reset(socket(
      94           1 :                   un.sun_family
      95             :                 , SOCK_STREAM | SOCK_NONBLOCK | (close_on_exec ? SOCK_CLOEXEC : 0)
      96             :                 , 0));
      97           1 :     if(f_socket == nullptr)
      98             :     {
      99           0 :         int const e(errno);
     100           0 :         SNAP_LOG_FATAL
     101           0 :             << "socket() failed to create a Unix socket descriptor (errno: "
     102             :             << e
     103             :             << " -- "
     104           0 :             << strerror(e)
     105             :             << ")"
     106             :             << SNAP_LOG_SEND;
     107           0 :         throw event_dispatcher_runtime_error("could not create socket for client");
     108             :     }
     109             : 
     110           1 :     if(f_address.is_unnamed())
     111             :     {
     112             :         // for an unnamed socket, we do not bind at all the user is
     113             :         // responsible for knowing where to read and where to write
     114             :         //
     115           0 :         return;
     116             :     }
     117             : 
     118           1 :     int r(-1);
     119           1 :     if(f_address.is_abstract())
     120             :     {
     121             :         // to create a correct abstract socket, we need to adjust the
     122             :         // size to the exact length of the address (i.e. we do not want
     123             :         // to send the '\0' after the name)
     124             :         //
     125           0 :         std::size_t const size(strlen(un.sun_path + 1));
     126           0 :         r = connect(
     127           0 :                   f_socket.get()
     128             :                 , reinterpret_cast<sockaddr const *>(&un)
     129             :                 , size);
     130             :     }
     131             :     else
     132             :     {
     133             :         // in this case we can send the entire address
     134             :         //
     135           2 :         r = connect(
     136           2 :                   f_socket.get()
     137             :                 , reinterpret_cast<sockaddr const *>(&un)
     138             :                 , sizeof(un));
     139             :     }
     140             : 
     141           1 :     if(r < 0)
     142             :     {
     143           0 :         int const e(errno);
     144           0 :         SNAP_LOG_FATAL
     145           0 :             << "connect() failed to connect a socket with address \""
     146           0 :             << f_address.to_uri()
     147           0 :             << "\" (errno: "
     148             :             << e
     149             :             << " -- "
     150           0 :             << strerror(e)
     151             :             << ")"
     152             :             << SNAP_LOG_SEND;
     153             :         throw event_dispatcher_runtime_error(
     154             :                   "could not connect client socket to \""
     155           0 :                 + f_address.to_uri()
     156           0 :                 + "\"");
     157             :     }
     158             : 
     159           1 :     if(!blocking)
     160             :     {
     161           1 :         non_blocking();
     162             :     }
     163             : }
     164             : 
     165             : 
     166             : /** \brief Clean up the TCP client object.
     167             :  *
     168             :  * This function cleans up the TCP client object by closing the attached socket.
     169             :  *
     170             :  * \note
     171             :  * DO NOT use the shutdown() call since we may end up forking and using
     172             :  * that connection in the child.
     173             :  */
     174           1 : local_stream_client_connection::~local_stream_client_connection()
     175             : {
     176           1 : }
     177             : 
     178             : 
     179             : /** \brief Close this connection.
     180             :  *
     181             :  * A connction automatically gets closed when it gets destroyed. There are
     182             :  * times, though, when it is useful to close the connection early
     183             :  * (specifically, when you receive an error).
     184             :  *
     185             :  * This function can be used to close the connection at any time. Many
     186             :  * of the other functions will stop working once the connection is
     187             :  * officially closed.
     188             :  */
     189           0 : void local_stream_client_connection::close()
     190             : {
     191           0 :     f_socket.reset();
     192           0 : }
     193             : 
     194             : 
     195             : /** \brief Get the Unix server address.
     196             :  *
     197             :  * This function returns the address used when creating the Unix server.
     198             :  *
     199             :  * \return The Unix address.
     200             :  */
     201           0 : addr::unix local_stream_client_connection::get_address() const
     202             : {
     203           0 :     return f_address;
     204             : }
     205             : 
     206             : 
     207             : /** \brief Check whether this connection is a reader.
     208             :  *
     209             :  * We change the default to true since Unix sockets are generally
     210             :  * always readers. You can still override this function and
     211             :  * return false if necessary.
     212             :  *
     213             :  * However, we do not override the is_writer() because that is
     214             :  * much more dynamic (i.e. you do not want to advertise as
     215             :  * being a writer unless you have data to write to the
     216             :  * socket.)
     217             :  *
     218             :  * \return Always true since this is a reader connection.
     219             :  */
     220           5 : bool local_stream_client_connection::is_reader() const
     221             : {
     222           5 :     return true;
     223             : }
     224             : 
     225             : 
     226             : /** \brief Get the socket descriptor.
     227             :  *
     228             :  * This function returns the TCP client socket descriptor. This can be
     229             :  * used to change the descriptor behavior (i.e. make it non-blocking for
     230             :  * example.)
     231             :  *
     232             :  * \return The socket descriptor.
     233             :  */
     234          25 : int local_stream_client_connection::get_socket() const
     235             : {
     236          25 :     return f_socket.get();
     237             : }
     238             : 
     239             : 
     240             : /** \brief Read data from the socket.
     241             :  *
     242             :  * A TCP socket is a stream type of socket and one can read data from it
     243             :  * as if it were a regular file. This function reads \p size bytes and
     244             :  * returns. The function returns early if the server closes the connection.
     245             :  *
     246             :  * If your socket is blocking, \p size should be exactly what you are
     247             :  * expecting or this function will block forever or until the server
     248             :  * closes the connection.
     249             :  *
     250             :  * The function returns -1 if an error occurs. The error is available in
     251             :  * errno as expected in the POSIX interface.
     252             :  *
     253             :  * \param[in,out] buf  The buffer where the data is read.
     254             :  * \param[in] size  The size of the buffer.
     255             :  *
     256             :  * \return The number of bytes read from the socket, or -1 on errors.
     257             :  */
     258           2 : ssize_t local_stream_client_connection::read(char * buf, size_t size)
     259             : {
     260           2 :     return ::read(f_socket.get(), buf, size);
     261             : }
     262             : 
     263             : 
     264             : /** \brief Write data to the socket.
     265             :  *
     266             :  * A TCP socket is a stream type of socket and one can write data to it
     267             :  * as if it were a regular file. This function writes \p size bytes to
     268             :  * the socket and then returns. This function returns early if the server
     269             :  * closes the connection.
     270             :  *
     271             :  * If your socket is not blocking, less than \p size bytes may be written
     272             :  * to the socket. In that case you are responsible for calling the function
     273             :  * again to write the remainder of the buffer until the function returns
     274             :  * a number of bytes written equal to \p size.
     275             :  *
     276             :  * The function returns -1 if an error occurs. The error is available in
     277             :  * errno as expected in the POSIX interface.
     278             :  *
     279             :  * \param[in] buf  The buffer with the data to send over the socket.
     280             :  * \param[in] size  The number of bytes in buffer to send over the socket.
     281             :  *
     282             :  * \return The number of bytes that were actually accepted by the socket
     283             :  * or -1 if an error occurs.
     284             :  */
     285           2 : ssize_t local_stream_client_connection::write(void const * buf, size_t size)
     286             : {
     287           2 :     return ::write(f_socket.get(), buf, size);
     288             : }
     289             : 
     290             : 
     291             : 
     292             : 
     293           6 : } // namespace ed
     294             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13