LCOV - code coverage report
Current view: top level - eventdispatcher - pipe_connection.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 53 80 66.2 %
Date: 2021-09-19 09:06:58 Functions: 11 13 84.6 %
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
      17             : // along with this program; if not, write to the Free Software
      18             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      19             : 
      20             : /** \file
      21             :  * \brief Implementation of the Snap Communicator class.
      22             :  *
      23             :  * This class wraps the C poll() interface in a C++ object with many types
      24             :  * of objects:
      25             :  *
      26             :  * \li Server Connections; for software that want to offer a port to
      27             :  *     which clients can connect to; the server will call accept()
      28             :  *     once a new client connection is ready; this results in a
      29             :  *     Server/Client connection object
      30             :  * \li Client Connections; for software that want to connect to
      31             :  *     a server; these expect the IP address and port to connect to
      32             :  * \li Server/Client Connections; for the server when it accepts a new
      33             :  *     connection; in this case the server gets a socket from accept()
      34             :  *     and creates one of these objects to handle the connection
      35             :  *
      36             :  * Using the poll() function is the easiest and allows us to listen
      37             :  * on pretty much any number of sockets (on my server it is limited
      38             :  * at 16,768 and frankly over 1,000 we probably will start to have
      39             :  * real slowness issues on small VPN servers.)
      40             :  */
      41             : 
      42             : // self
      43             : //
      44             : #include    "eventdispatcher/pipe_connection.h"
      45             : 
      46             : #include    "eventdispatcher/exception.h"
      47             : 
      48             : 
      49             : // C++ lib
      50             : //
      51             : #include    <iostream>
      52             : 
      53             : 
      54             : // C lib
      55             : //
      56             : #include    <unistd.h>
      57             : #include    <sys/socket.h>
      58             : 
      59             : 
      60             : // last include
      61             : //
      62             : #include    <snapdev/poison.h>
      63             : 
      64             : 
      65             : 
      66             : namespace ed
      67             : {
      68             : 
      69             : 
      70             : 
      71             : /** \brief Initializes the pipe connection.
      72             :  *
      73             :  * This function creates pipes to quickly communicate between two
      74             :  * processes created with a fork() or fork() + execve().
      75             :  *
      76             :  * The function supports three types of pipes:
      77             :  *
      78             :  * * PIPE_BIDIRECTIONAL
      79             :  *
      80             :  *     Create Unix sockets that can be used to send and receive messages
      81             :  *     between two processes.
      82             :  *
      83             :  * * PIPE_CHILD_INPUT
      84             :  *
      85             :  *     A pipe for the input stream of a child. This type of pipe is to
      86             :  *     be used as a replacement to the stdin of a child process. This is
      87             :  *     used in the cppprocess library when creating a fork() + execve()
      88             :  *     process.
      89             :  *
      90             :  * * PIPE_CHILD_OUTPUT
      91             :  *
      92             :  *     A pipe for the output stream and error stream of a child. This
      93             :  *     type of pipe is to be used as a replacement to the stdout and
      94             :  *     stderr of a child process. This is used in the cppprocess when
      95             :  *     creating a fork() + execve() process.
      96             :  *
      97             :  * To save file descriptors (1 or 2), it is suggested that you
      98             :  * call the forked() function once you called fork(). It will
      99             :  * take care of closing the descriptors used by the other side
     100             :  * (those you do not need on your side).
     101             :  *
     102             :  * \warning
     103             :  * The file descriptors are opened in a non-blocking state. However, they
     104             :  * are not closed when you call fork() since they are to be used across
     105             :  * processes. If you want to do a fork() + execve(), duplicating the
     106             :  * necessary file descriptors and then call close().
     107             :  *
     108             :  * \warning
     109             :  * You need to create a new pipe_connection each time you want to create
     110             :  * a new child with fork(). If you want to create a a new process with
     111             :  * fork() + execve(), you want to create three pipe_connection, one per
     112             :  * stream (stdin, stdout, stderr). You can always create more if necessary
     113             :  * in your situation.
     114             :  *
     115             :  * \exception event_dispatcher_initialization_error
     116             :  * This exception is raised if the pipes (socketpair, pipe) cannot be
     117             :  * created.
     118             :  *
     119             :  * \param[in] type  The type of pipe to create.
     120             :  *
     121             :  * \sa forked()
     122             :  */
     123           9 : pipe_connection::pipe_connection(pipe_t type)
     124             :     : f_type(type)
     125           9 :     , f_parent(getpid())
     126             : {
     127           9 :     switch(type)
     128             :     {
     129           0 :     case pipe_t::PIPE_BIDIRECTIONAL:
     130           0 :         if(socketpair(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0, f_socket) != 0)
     131             :         {
     132             :             // pipe could not be created
     133           0 :             throw event_dispatcher_initialization_error("somehow the AF_LOCAL pipes used for a two way pipe connection could not be created.");
     134             :         }
     135           0 :         break;
     136             : 
     137           3 :     case pipe_t::PIPE_CHILD_INPUT:
     138           3 :         if(pipe(f_socket) != 0)
     139             :         {
     140             :             // pipe could not be created
     141           0 :             throw event_dispatcher_initialization_error("somehow the FIFO pipes used for a one way pipe (child input) connection could not be created.");
     142             :         }
     143           3 :         std::swap(f_socket[0], f_socket[1]);
     144           3 :         break;
     145             : 
     146           6 :     case pipe_t::PIPE_CHILD_OUTPUT:
     147           6 :         if(pipe(f_socket) != 0)
     148             :         {
     149             :             // pipe could not be created
     150           0 :             throw event_dispatcher_initialization_error("somehow the FIFO pipes used for a one way pipe (child output) connection could not be created.");
     151             :         }
     152           6 :         break;
     153             : 
     154             :     }
     155           9 : }
     156             : 
     157             : 
     158             : /** \brief Make sure to close the pipes.
     159             :  *
     160             :  * The destructor ensures that the pipes get closed.
     161             :  *
     162             :  * They may already have been closed if a broken pipe was detected.
     163             :  *
     164             :  * \sa close()
     165             :  */
     166          18 : pipe_connection::~pipe_connection()
     167             : {
     168           9 :     close();
     169           9 : }
     170             : 
     171             : 
     172             : /** \brief Get the type of pipe connections.
     173             :  *
     174             :  * This function returns the type of this connection, as specified
     175             :  * on the contructor.
     176             :  *
     177             :  * \return The type of the pipe.
     178             :  */
     179           0 : pipe_t pipe_connection::type() const
     180             : {
     181           0 :     return f_type;
     182             : }
     183             : 
     184             : 
     185             : /** \brief Read data from this pipe connection.
     186             :  *
     187             :  * This function reads up to count bytes from this pipe connection.
     188             :  *
     189             :  * The function makes sure to use the correct socket for the calling
     190             :  * process (i.e. depending on whether this is the parent or child.)
     191             :  *
     192             :  * Just like the system read(2) function, errno is set to the error
     193             :  * that happened when the function returns -1.
     194             :  *
     195             :  * The function returns an error (-1, errno = EBAD) if you try to
     196             :  * read from a read-only stream.
     197             :  *
     198             :  * \param[in] buf  A pointer to a buffer of data.
     199             :  * \param[in] count  The number of bytes to read from the pipe connection.
     200             :  *
     201             :  * \return The number of bytes read from this pipe socket, or -1 on errors.
     202             :  *
     203             :  * \sa write()
     204             :  */
     205           5 : ssize_t pipe_connection::read(void * buf, size_t count)
     206             : {
     207           5 :     if(f_parent == getpid())
     208             :     {
     209           5 :         if(f_type == pipe_t::PIPE_CHILD_INPUT)
     210             :         {
     211           0 :             errno = EBADF;
     212           0 :             return -1;
     213             :         }
     214             :     }
     215             :     else
     216             :     {
     217           0 :         if(f_type == pipe_t::PIPE_CHILD_OUTPUT)
     218             :         {
     219           0 :             errno = EBADF;
     220           0 :             return -1;
     221             :         }
     222             :     }
     223             : 
     224           5 :     int const s(get_socket());
     225           5 :     if(s == -1)
     226             :     {
     227           0 :         errno = EBADF;
     228           0 :         return -1;
     229             :     }
     230           5 :     return ::read(s, buf, count);
     231             : }
     232             : 
     233             : 
     234             : /** \brief Write data to this pipe connection.
     235             :  *
     236             :  * This function writes count bytes to this pipe connection.
     237             :  *
     238             :  * The function makes sure to use the correct socket for the calling
     239             :  * process (i.e. depending on whether this is the parent or child.)
     240             :  *
     241             :  * Just like the system write(2) function, errno is set to the error
     242             :  * that happened when the function returns -1.
     243             :  *
     244             :  * The function returns an error (-1, errno = EBAD) if you try to
     245             :  * write to a read-only stream.
     246             :  *
     247             :  * \param[in] buf  A pointer to a buffer of data.
     248             :  * \param[in] count  The number of bytes to write to the pipe connection.
     249             :  *
     250             :  * \return The number of bytes written to this pipe socket, or -1 on errors.
     251             :  *
     252             :  * \sa read()
     253             :  */
     254           3 : ssize_t pipe_connection::write(void const * buf, size_t count)
     255             : {
     256           3 :     if(f_parent == getpid())
     257             :     {
     258           3 :         if(f_type == pipe_t::PIPE_CHILD_OUTPUT)
     259             :         {
     260           0 :             errno = EBADF;
     261           0 :             return -1;
     262             :         }
     263             :     }
     264             :     else
     265             :     {
     266           0 :         if(f_type == pipe_t::PIPE_CHILD_INPUT)
     267             :         {
     268           0 :             errno = EBADF;
     269           0 :             return -1;
     270             :         }
     271             :     }
     272             : 
     273           3 :     int const s(get_socket());
     274           3 :     if(s == -1)
     275             :     {
     276           0 :         errno = EBADF;
     277           0 :         return -1;
     278             :     }
     279           3 :     if(buf != nullptr && count > 0)
     280             :     {
     281           3 :         return ::write(s, buf, count);
     282             :     }
     283           0 :     return 0;
     284             : }
     285             : 
     286             : 
     287             : /** \brief Close the other side sockets.
     288             :  *
     289             :  * This function closes the sockets not used by this side of the pipe.
     290             :  * This is useful to clean up file descriptors that we otherwise endup
     291             :  * to never use until this object is destroyed.
     292             :  *
     293             :  * Make sure to call this function only after you called the fork()
     294             :  * function. Calling this too early (before the fork() call) would
     295             :  * mean that you'd end up closing the file descriptors of the other
     296             :  * side before the other side received the socket information.
     297             :  *
     298             :  * The function can safely be called multiple times.
     299             :  *
     300             :  * \note
     301             :  * To close both sides, call the close() function.
     302             :  *
     303             :  * \sa close()
     304             :  */
     305           7 : void pipe_connection::forked()
     306             : {
     307           7 :     int const idx(f_parent == getpid() ? 1 : 0);
     308           7 :     if(f_socket[idx] != -1)
     309             :     {
     310           7 :         ::close(f_socket[idx]);
     311           7 :         f_socket[idx] = -1;
     312             :     }
     313           7 : }
     314             : 
     315             : 
     316             : /** \brief Close the sockets.
     317             :  *
     318             :  * This function closes the pair of sockets managed by this
     319             :  * pipe connection object.
     320             :  *
     321             :  * After this call, the pipe connection is closed and cannot be
     322             :  * used anymore. The read and write functions will return immediately
     323             :  * if called.
     324             :  *
     325             :  * The function can safely be called multiple times. It is also safe
     326             :  * to call the forked() function and then the close() function.
     327             :  *
     328             :  * \sa forked()
     329             :  */
     330          18 : void pipe_connection::close()
     331             : {
     332          18 :     if(f_socket[0] != -1)
     333             :     {
     334           9 :         ::close(f_socket[0]);
     335           9 :         f_socket[0] = -1;
     336             :     }
     337             : 
     338          18 :     if(f_socket[1] != -1)
     339             :     {
     340           2 :         ::close(f_socket[1]);
     341           2 :         f_socket[1] = -1;
     342             :     }
     343          18 : }
     344             : 
     345             : 
     346             : /** \brief This function returns the pipe of the other side.
     347             :  *
     348             :  * In some cases, it can be practical to find out the socket from the other
     349             :  * side of the pipe. This function returns that other socket.
     350             :  *
     351             :  * \note
     352             :  * The main reason for this function is to be able to extract the other
     353             :  * socket and create the necessary input/output/error stream in a child
     354             :  * process and close it.
     355             :  *
     356             :  * \return A pipe descriptor to listen on with poll().
     357             :  */
     358           9 : int pipe_connection::get_other_socket() const
     359             : {
     360           9 :     if(f_parent == getpid())
     361             :     {
     362           9 :         return f_socket[1];
     363             :     }
     364             : 
     365           0 :     return f_socket[0];
     366             : }
     367             : 
     368             : 
     369             : /** \brief Pipe connections accept reads.
     370             :  *
     371             :  * This function returns true meaning that the pipe connection can be
     372             :  * used to read data.
     373             :  *
     374             :  * \return true since a pipe connection is a reader.
     375             :  */
     376          13 : bool pipe_connection::is_reader() const
     377             : {
     378          13 :     if(f_parent == getpid())
     379             :     {
     380          13 :         if(f_type == pipe_t::PIPE_CHILD_INPUT)
     381             :         {
     382           3 :             return false;
     383             :         }
     384             :     }
     385             :     else
     386             :     {
     387           0 :         if(f_type == pipe_t::PIPE_CHILD_OUTPUT)
     388             :         {
     389           0 :             return false;
     390             :         }
     391             :     }
     392             : 
     393          10 :     return true;
     394             : }
     395             : 
     396             : 
     397             : /** \brief This function returns the pipe we want to listen on.
     398             :  *
     399             :  * This function returns the file descriptor of one of the two
     400             :  * sockets. The parent process returns the descriptor of socket
     401             :  * number 0. The child process returns the descriptor of socket
     402             :  * number 1.
     403             :  *
     404             :  * \note
     405             :  * If the close() function was called, this function returns -1.
     406             :  *
     407             :  * \return A pipe descriptor to listen on with poll().
     408             :  */
     409          48 : int pipe_connection::get_socket() const
     410             : {
     411          48 :     if(f_parent == getpid())
     412             :     {
     413          48 :         return f_socket[0];
     414             :     }
     415             : 
     416           0 :     return f_socket[1];
     417             : }
     418             : 
     419             : 
     420             : /** \var pipe_t::PIPE_BIDIRECTIONAL
     421             :  * \brief Used to create a bidirectional pipe.
     422             :  *
     423             :  * The pipe is bidirectional. You can read and write to it.
     424             :  */
     425             : 
     426             : 
     427             : /** \var pipe_t::PIPE_CHILD_INPUT
     428             :  * \brief Used to create an input stream for a child.
     429             :  *
     430             :  * This type defines a pipe where the parent writes to the pipe and the
     431             :  * child reads from the pipe.
     432             :  */
     433             : 
     434             : 
     435             : /** \var pipe_t::PIPE_CHILD_OUTPUT
     436             :  * \brief Used to create an output stream for a child.
     437             :  *
     438             :  * This type defines a pipe where the parent reads from the pipe and the
     439             :  * child writes to the pipe.
     440             :  */
     441             : 
     442             : 
     443             : 
     444           6 : } // namespace ed
     445             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13