LCOV - code coverage report
Current view: top level - eventdispatcher - local_stream_client_connection.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 29 50 58.0 %
Date: 2022-06-18 10:10:36 Functions: 8 11 72.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2012-2022  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 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] address  The Unix address of the server to connect to.
      83             :  * \param[in] blocking  Whether the socket has to be opened in blocking mode.
      84             :  * \param[in] close_on_exec  Whether to close this socket on an execve() call.
      85             :  */
      86           1 : local_stream_client_connection::local_stream_client_connection(
      87             :               addr::unix const & address
      88             :             , bool const blocking
      89           1 :             , bool const close_on_exec)
      90           1 :     : f_address(address)
      91             : {
      92           1 :     sockaddr_un un;
      93           1 :     f_address.get_un(un);
      94           3 :     f_socket.reset(socket(
      95           1 :                   un.sun_family
      96             :                 , SOCK_STREAM
      97           1 :                     | (blocking ? 0 : SOCK_NONBLOCK)
      98           1 :                     | (close_on_exec ? SOCK_CLOEXEC : 0)
      99             :                 , 0));
     100           1 :     if(f_socket == nullptr)
     101             :     {
     102           0 :         int const e(errno);
     103           0 :         SNAP_LOG_FATAL
     104           0 :             << "socket() failed to create a Unix socket descriptor (errno: "
     105             :             << e
     106             :             << " -- "
     107           0 :             << strerror(e)
     108             :             << ")"
     109             :             << SNAP_LOG_SEND;
     110           0 :         throw runtime_error("could not create socket for client");
     111             :     }
     112             : 
     113           1 :     if(f_address.is_unnamed())
     114             :     {
     115             :         // for an unnamed socket, we do not bind at all the user is
     116             :         // responsible for knowing where to read and where to write
     117             :         //
     118           0 :         return;
     119             :     }
     120             : 
     121           1 :     int r(-1);
     122           1 :     if(f_address.is_abstract())
     123             :     {
     124             :         // to create a correct abstract socket, we need to adjust the
     125             :         // size to the exact length of the address (i.e. we do not want
     126             :         // to send the '\0' after the name)
     127             :         //
     128           0 :         std::size_t const size(strlen(un.sun_path + 1));
     129           0 :         r = connect(
     130           0 :                   f_socket.get()
     131             :                 , reinterpret_cast<sockaddr const *>(&un)
     132             :                 , size);
     133             :     }
     134             :     else
     135             :     {
     136             :         // in this case we can send the entire address
     137             :         //
     138           2 :         r = connect(
     139           2 :                   f_socket.get()
     140             :                 , reinterpret_cast<sockaddr const *>(&un)
     141             :                 , sizeof(un));
     142             :     }
     143             : 
     144           1 :     if(r < 0)
     145             :     {
     146           0 :         int const e(errno);
     147           0 :         SNAP_LOG_FATAL
     148             :             << "connect() failed to connect a socket with address \""
     149           0 :             << f_address.to_uri()
     150           0 :             << "\" (errno: "
     151             :             << e
     152             :             << " -- "
     153           0 :             << strerror(e)
     154             :             << ")"
     155             :             << SNAP_LOG_SEND;
     156             :         throw runtime_error(
     157             :                   "could not connect client socket to \""
     158           0 :                 + f_address.to_uri()
     159           0 :                 + "\"");
     160             :     }
     161             : 
     162           1 :     if(!blocking)
     163             :     {
     164           1 :         non_blocking();
     165             :     }
     166             : }
     167             : 
     168             : 
     169             : /** \brief Clean up the TCP client object.
     170             :  *
     171             :  * This function cleans up the TCP client object by closing the attached socket.
     172             :  *
     173             :  * \note
     174             :  * DO NOT use the shutdown() call since we may end up forking and using
     175             :  * that connection in the child.
     176             :  */
     177           1 : local_stream_client_connection::~local_stream_client_connection()
     178             : {
     179           1 : }
     180             : 
     181             : 
     182             : /** \brief Close this connection.
     183             :  *
     184             :  * A connction automatically gets closed when it gets destroyed. There are
     185             :  * times, though, when it is useful to close the connection early
     186             :  * (specifically, when you receive an error).
     187             :  *
     188             :  * This function can be used to close the connection at any time. Many
     189             :  * of the other functions will stop working once the connection is
     190             :  * officially closed.
     191             :  */
     192           0 : void local_stream_client_connection::close()
     193             : {
     194           0 :     f_socket.reset();
     195           0 : }
     196             : 
     197             : 
     198             : /** \brief Get the Unix server address.
     199             :  *
     200             :  * This function returns the address used when creating the Unix server.
     201             :  *
     202             :  * \return The Unix address.
     203             :  */
     204           0 : addr::unix local_stream_client_connection::get_address() const
     205             : {
     206           0 :     return f_address;
     207             : }
     208             : 
     209             : 
     210             : /** \brief Check whether this connection is a reader.
     211             :  *
     212             :  * We change the default to true since Unix sockets are generally
     213             :  * always readers. You can still override this function and
     214             :  * return false if necessary.
     215             :  *
     216             :  * However, we do not override the is_writer() because that is
     217             :  * much more dynamic (i.e. you do not want to advertise as
     218             :  * being a writer unless you have data to write to the
     219             :  * socket.)
     220             :  *
     221             :  * \return Always true since this is a reader connection.
     222             :  */
     223           5 : bool local_stream_client_connection::is_reader() const
     224             : {
     225           5 :     return true;
     226             : }
     227             : 
     228             : 
     229             : /** \brief Get the socket descriptor.
     230             :  *
     231             :  * This function returns the TCP client socket descriptor. This can be
     232             :  * used to change the descriptor behavior (i.e. make it non-blocking for
     233             :  * example.)
     234             :  *
     235             :  * \return The socket descriptor.
     236             :  */
     237          25 : int local_stream_client_connection::get_socket() const
     238             : {
     239          25 :     return f_socket.get();
     240             : }
     241             : 
     242             : 
     243             : /** \brief Read data from the socket.
     244             :  *
     245             :  * A TCP socket is a stream type of socket and one can read data from it
     246             :  * as if it were a regular file. This function reads \p size bytes and
     247             :  * returns. The function returns early if the server closes the connection.
     248             :  *
     249             :  * If your socket is blocking, \p size should be exactly what you are
     250             :  * expecting or this function will block forever or until the server
     251             :  * closes the connection.
     252             :  *
     253             :  * The function returns -1 if an error occurs. The error is available in
     254             :  * errno as expected in the POSIX interface.
     255             :  *
     256             :  * \param[in,out] buf  The buffer where the data is read.
     257             :  * \param[in] size  The size of the buffer.
     258             :  *
     259             :  * \return The number of bytes read from the socket, or -1 on errors.
     260             :  */
     261           2 : ssize_t local_stream_client_connection::read(char * buf, size_t size)
     262             : {
     263           2 :     return ::read(f_socket.get(), buf, size);
     264             : }
     265             : 
     266             : 
     267             : /** \brief Write data to the socket.
     268             :  *
     269             :  * A TCP socket is a stream type of socket and one can write data to it
     270             :  * as if it were a regular file. This function writes \p size bytes to
     271             :  * the socket and then returns. This function returns early if the server
     272             :  * closes the connection.
     273             :  *
     274             :  * If your socket is not blocking, less than \p size bytes may be written
     275             :  * to the socket. In that case you are responsible for calling the function
     276             :  * again to write the remainder of the buffer until the function returns
     277             :  * a number of bytes written equal to \p size.
     278             :  *
     279             :  * The function returns -1 if an error occurs. The error is available in
     280             :  * errno as expected in the POSIX interface.
     281             :  *
     282             :  * \param[in] buf  The buffer with the data to send over the socket.
     283             :  * \param[in] size  The number of bytes in buffer to send over the socket.
     284             :  *
     285             :  * \return The number of bytes that were actually accepted by the socket
     286             :  * or -1 if an error occurs.
     287             :  */
     288           2 : ssize_t local_stream_client_connection::write(void const * buf, size_t size)
     289             : {
     290           2 :     return ::write(f_socket.get(), buf, size);
     291             : }
     292             : 
     293             : 
     294             : 
     295             : 
     296           6 : } // namespace ed
     297             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13