LCOV - code coverage report
Current view: top level - eventdispatcher - tcp_server.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 86 1.2 %
Date: 2019-08-08 02:52:36 Functions: 2 12 16.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Event Dispatcher
       2             : // Copyright (c) 2012-2019  Made to Order Software Corp.  All Rights Reserved
       3             : //
       4             : // This program is free software; you can redistribute it and/or modify
       5             : // it under the terms of the GNU General Public License as published by
       6             : // the Free Software Foundation; either version 2 of the License, or
       7             : // (at your option) any later version.
       8             : //
       9             : // This program is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             : // GNU General Public License for more details.
      13             : //
      14             : // You should have received a copy of the GNU General Public License
      15             : // along with this program; if not, write to the Free Software
      16             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      17             : 
      18             : // make sure we use OpenSSL with multi-thread support
      19             : // (TODO: move to .cpp once we have the impl!)
      20             : //#define OPENSSL_THREAD_DEFINES
      21             : 
      22             : 
      23             : // self
      24             : //
      25             : #include    "eventdispatcher/tcp_server.h"
      26             : 
      27             : #include    "eventdispatcher/exception.h"
      28             : 
      29             : 
      30             : // snaplogger lib
      31             : //
      32             : #include    <snaplogger/message.h>
      33             : 
      34             : 
      35             : // snapdev lib
      36             : //
      37             : #include    <snapdev/not_reached.h>
      38             : //#include "snapdev/not_used.h"
      39             : //#include "snapdev/raii_generic_deleter.h"
      40             : //
      41             : //
      42             : //// C++
      43             : ////
      44             : //#include <sstream>
      45             : //#include <iomanip>
      46             : 
      47             : 
      48             : // C lib
      49             : //
      50             : //#include <netdb.h>
      51             : //#include <netinet/tcp.h>
      52             : #include <poll.h>
      53             : //#include <string.h>
      54             : //#include <sys/ioctl.h>
      55             : //#include <sys/socket.h>
      56             : //#include <sys/types.h>
      57             : //#include <unistd.h>
      58             : 
      59             : 
      60             : // last include
      61             : //
      62             : #include "snapdev/poison.h"
      63             : 
      64             : 
      65             : 
      66             : 
      67             : //#ifndef OPENSSL_THREADS
      68             : //#error "OPENSSL_THREADS is not defined. Snap! requires support for multiple threads in OpenSSL."
      69             : //#endif
      70             : 
      71             : namespace ed
      72             : {
      73             : 
      74             : 
      75             : 
      76             : /** \brief Initialize the server and start listening for connections.
      77             :  *
      78             :  * The server constructor creates a socket, binds it, and then listen to it.
      79             :  *
      80             :  * By default the server accepts a maximum of \p max_connections (set to
      81             :  * 0 or less to get the default tcp_server::MAX_CONNECTIONS) in its waiting queue.
      82             :  * If you use the server and expect a low connection rate, you may want to
      83             :  * reduce the count to 5. Although some very busy servers use larger numbers.
      84             :  * This value gets clamped to a minimum of 5 and a maximum of 1,000.
      85             :  *
      86             :  * Note that the maximum number of connections is actually limited to
      87             :  * /proc/sys/net/core/somaxconn connections. This number is generally 128 
      88             :  * in 2016. So the  super high limit of 1,000 is anyway going to be ignored
      89             :  * by the OS.
      90             :  *
      91             :  * The address is made non-reusable (which is the default for TCP sockets.)
      92             :  * It is possible to mark the server address as immediately reusable by
      93             :  * setting the \p reuse_addr to true.
      94             :  *
      95             :  * By default the server is marked as "keepalive". You can turn it off
      96             :  * using the keepalive() function with false.
      97             :  *
      98             :  * \exception tcp_client_server_parameter_error
      99             :  * This exception is raised if the address parameter is an empty string or
     100             :  * otherwise an invalid IP address, or if the port is out of range.
     101             :  *
     102             :  * \exception tcp_client_server_runtime_error
     103             :  * This exception is raised if the socket cannot be created, bound to
     104             :  * the specified IP address and port, or listen() fails on the socket.
     105             :  *
     106             :  * \param[in] addr  The address to listen on. It may be set to "0.0.0.0".
     107             :  * \param[in] port  The port to listen on.
     108             :  * \param[in] max_connections  The number of connections to keep in the listen queue.
     109             :  * \param[in] reuse_addr  Whether to mark the socket with the SO_REUSEADDR flag.
     110             :  * \param[in] auto_close  Automatically close the client socket in accept and the destructor.
     111             :  */
     112           0 : tcp_server::tcp_server(std::string const & addr, int port, int max_connections, bool reuse_addr, bool auto_close)
     113           0 :     : f_max_connections(max_connections <= 0 ? MAX_CONNECTIONS : max_connections)
     114             :     //, f_socket(-1) -- auto-init
     115             :     , f_port(port)
     116             :     , f_addr(addr)
     117             :     //, f_accepted_socket(-1) -- auto-init
     118             :     //, f_keepalive(true) -- auto-init
     119           0 :     , f_auto_close(auto_close)
     120             : {
     121           0 :     if(f_addr.empty())
     122             :     {
     123           0 :         throw event_dispatcher_invalid_parameter("the address cannot be an empty string.");
     124             :     }
     125           0 :     if(f_port < 0 || f_port >= 65536)
     126             :     {
     127           0 :         throw event_dispatcher_invalid_parameter("invalid port for a client socket.");
     128             :     }
     129           0 :     if(f_max_connections < 5)
     130             :     {
     131           0 :         f_max_connections = 5;
     132             :     }
     133           0 :     else if(f_max_connections > 1000)
     134             :     {
     135           0 :         f_max_connections = 1000;
     136             :     }
     137             : 
     138             :     addrinfo hints;
     139           0 :     memset(&hints, 0, sizeof(hints));
     140           0 :     hints.ai_family = AF_UNSPEC;
     141           0 :     hints.ai_socktype = SOCK_STREAM;
     142           0 :     hints.ai_protocol = IPPROTO_TCP;
     143           0 :     std::string port_str(std::to_string(f_port));
     144           0 :     addrinfo * addrinfo(nullptr);
     145           0 :     int const r(getaddrinfo(addr.c_str(), port_str.c_str(), &hints, &addrinfo));
     146           0 :     raii_addrinfo_t addr_info(addrinfo);
     147           0 :     if(r != 0
     148           0 :     || addrinfo == nullptr)
     149             :     {
     150           0 :         throw event_dispatcher_runtime_error("invalid address or port: \"" + addr + ":" + port_str + "\"");
     151             :     }
     152             : 
     153           0 :     f_socket = socket(addr_info.get()->ai_family, SOCK_STREAM, IPPROTO_TCP);
     154           0 :     if(f_socket < 0)
     155             :     {
     156           0 :         int const e(errno);
     157           0 :         std::string err("socket() failed to create a socket descriptor (errno: ");
     158           0 :         err += std::to_string(e);
     159           0 :         err += " -- ";
     160           0 :         err += strerror(e);
     161           0 :         err += ")";
     162           0 :         throw event_dispatcher_runtime_error("could not create socket for client");
     163             :     }
     164             : 
     165             :     // this should be optional as reusing an address for TCP/IP is not 100% safe
     166           0 :     if(reuse_addr)
     167             :     {
     168             :         // try to mark the socket address as immediately reusable
     169             :         // if this fails, we ignore the error (TODO log an INFO message)
     170           0 :         int optval(1);
     171           0 :         socklen_t const optlen(sizeof(optval));
     172           0 :         snap::NOTUSED(setsockopt(f_socket, SOL_SOCKET, SO_REUSEADDR, &optval, optlen));
     173             :     }
     174             : 
     175           0 :     if(bind(f_socket, addr_info.get()->ai_addr, addr_info.get()->ai_addrlen) < 0)
     176             :     {
     177           0 :         close(f_socket);
     178           0 :         throw event_dispatcher_runtime_error("could not bind the socket to \"" + f_addr + "\"");
     179             :     }
     180             : 
     181             :     // start listening, we expect the caller to then call accept() to
     182             :     // acquire connections
     183           0 :     if(listen(f_socket, f_max_connections) < 0)
     184             :     {
     185           0 :         close(f_socket);
     186           0 :         throw event_dispatcher_runtime_error("could not listen to the socket bound to \"" + f_addr + "\"");
     187             :     }
     188           0 : }
     189             : 
     190             : 
     191             : /** \brief Clean up the server sockets.
     192             :  *
     193             :  * This function ensures that the server sockets get cleaned up.
     194             :  *
     195             :  * If the \p auto_close parameter was set to true in the constructor, then
     196             :  * the last accepter socket gets closed by this function.
     197             :  *
     198             :  * \note
     199             :  * DO NOT use the shutdown() call since we may end up forking and using
     200             :  * that connection in the child.
     201             :  */
     202           0 : tcp_server::~tcp_server()
     203             : {
     204           0 :     close(f_socket);
     205           0 :     if(f_auto_close && f_accepted_socket != -1)
     206             :     {
     207           0 :         close(f_accepted_socket);
     208             :     }
     209           0 : }
     210             : 
     211             : 
     212             : /** \brief Retrieve the socket descriptor.
     213             :  *
     214             :  * This function returns the socket descriptor. It can be used to
     215             :  * tweak things on the socket such as making it non-blocking or
     216             :  * directly accessing the data.
     217             :  *
     218             :  * \return The socket descriptor.
     219             :  */
     220           0 : int tcp_server::get_socket() const
     221             : {
     222           0 :     return f_socket;
     223             : }
     224             : 
     225             : 
     226             : /** \brief Retrieve the maximum number of connections.
     227             :  *
     228             :  * This function returns the maximum number of connections that can
     229             :  * be accepted by the socket. This was set by the constructor and
     230             :  * it cannot be changed later.
     231             :  *
     232             :  * \return The maximum number of incoming connections.
     233             :  */
     234           0 : int tcp_server::get_max_connections() const
     235             : {
     236           0 :     return f_max_connections;
     237             : }
     238             : 
     239             : 
     240             : /** \brief Return the server port.
     241             :  *
     242             :  * This function returns the port the server was created with. This port
     243             :  * is exactly what the server currently uses. It cannot be changed.
     244             :  *
     245             :  * \return The server port.
     246             :  */
     247           0 : int tcp_server::get_port() const
     248             : {
     249           0 :     return f_port;
     250             : }
     251             : 
     252             : 
     253             : /** \brief Retrieve the server IP address.
     254             :  *
     255             :  * This function returns the IP address used to bind the socket. This
     256             :  * is the address clients have to use to connect to the server unless
     257             :  * the address was set to all zeroes (0.0.0.0) in which case any user
     258             :  * can connect.
     259             :  *
     260             :  * The IP address cannot be changed.
     261             :  *
     262             :  * \return The server IP address.
     263             :  */
     264           0 : std::string tcp_server::get_addr() const
     265             : {
     266           0 :     return f_addr;
     267             : }
     268             : 
     269             : 
     270             : /** \brief Return the current status of the keepalive flag.
     271             :  *
     272             :  * This function returns the current status of the keepalive flag. This
     273             :  * flag is set to true by default (in the constructor.) It can be
     274             :  * changed with the keepalive() function.
     275             :  *
     276             :  * The flag is used to mark new connections with the SO_KEEPALIVE flag.
     277             :  * This is used whenever a service may take a little to long to answer
     278             :  * and avoid losing the TCP connection before the answer is sent to
     279             :  * the client.
     280             :  *
     281             :  * \return The current status of the keepalive flag.
     282             :  */
     283           0 : bool tcp_server::get_keepalive() const
     284             : {
     285           0 :     return f_keepalive;
     286             : }
     287             : 
     288             : 
     289             : /** \brief Set the keepalive flag.
     290             :  *
     291             :  * This function sets the keepalive flag to either true (i.e. mark connection
     292             :  * sockets with the SO_KEEPALIVE flag) or false. The default is true (as set
     293             :  * in the constructor,) because in most cases this is a feature people want.
     294             :  *
     295             :  * \param[in] yes  Whether to keep new connections alive even when no traffic
     296             :  * goes through.
     297             :  */
     298           0 : void tcp_server::set_keepalive(bool yes)
     299             : {
     300           0 :     f_keepalive = yes;
     301           0 : }
     302             : 
     303             : 
     304             : /** \brief Accept a connection.
     305             :  *
     306             :  * A TCP server accepts incoming connections. This call is a blocking call.
     307             :  * If no connections are available on the line, then the call blocks until
     308             :  * a connection becomes available.
     309             :  *
     310             :  * To prevent being blocked by this call you can either check the status of
     311             :  * the file descriptor (use the get_socket() function to retrieve the
     312             :  * descriptor and use an appropriate wait with 0 as a timeout,) or transform
     313             :  * the socket in a non-blocking socket (not tested, though.)
     314             :  *
     315             :  * This TCP socket implementation is expected to be used in one of two ways:
     316             :  *
     317             :  * (1) the main server accepts connections and then fork()'s to handle the
     318             :  * transaction with the client, in that case we want to set the \p auto_close
     319             :  * parameter of the constructor to true so the accept() function automatically
     320             :  * closes the last accepted socket.
     321             :  *
     322             :  * (2) the main server keeps a set of connections and handles them alongside
     323             :  * the main server connection. Although there are limits to what you can do
     324             :  * in this way, it is very efficient, but this also means the accept() call
     325             :  * cannot close the last accepted socket since the rest of the software may
     326             :  * still be working on it.
     327             :  *
     328             :  * The function returns a client/server socket. This is the socket one can
     329             :  * use to communicate with the client that just connected to the server. This
     330             :  * descriptor can be written to or read from.
     331             :  *
     332             :  * This function is the one that applies the keepalive flag to the
     333             :  * newly accepted socket.
     334             :  *
     335             :  * \note
     336             :  * If you prevent SIGCHLD from stopping your code, you may want to allow it
     337             :  * when calling this function (that is, if you're interested in getting that
     338             :  * information immediately, otherwise it is cleaner to always block those
     339             :  * signals.)
     340             :  *
     341             :  * \note
     342             :  * DO NOT use the shutdown() call since we may end up forking and using
     343             :  * that connection in the child.
     344             :  *
     345             :  * \param[in] max_wait_ms  The maximum number of milliseconds to wait for
     346             :  *            a message. If set to -1 (the default), accept() will block
     347             :  *            indefintely.
     348             :  *
     349             :  * \return A client socket descriptor or -1 if an error occured, -2 if timeout and max_wait is set.
     350             :  */
     351           0 : int tcp_server::accept( int const max_wait_ms )
     352             : {
     353             :     // auto-close?
     354           0 :     if(f_auto_close && f_accepted_socket != -1)
     355             :     {
     356             :         // if the close is interrupted, make sure we try again otherwise
     357             :         // we could lose that stream until next restart (this could happen
     358             :         // if you have SIGCHLD)
     359           0 :         if(close(f_accepted_socket) == -1)
     360             :         {
     361           0 :             if(errno == EINTR)
     362             :             {
     363           0 :                 close(f_accepted_socket);
     364             :             }
     365             :         }
     366             :     }
     367           0 :     f_accepted_socket = -1;
     368             : 
     369           0 :     if( max_wait_ms > -1 )
     370             :     {
     371             :         pollfd fd;
     372           0 :         fd.events = POLLIN | POLLPRI | POLLRDHUP;
     373           0 :         fd.fd = f_socket;
     374           0 :         int const retval(poll(&fd, 1, max_wait_ms));
     375             : 
     376             : // on newer system each input of select() must be a distinct fd_set...
     377             : //        fd_set s;
     378             : //        //
     379             : //        FD_ZERO(&s);
     380             : //#pragma GCC diagnostic push
     381             : //#pragma GCC diagnostic ignored "-Wold-style-cast"
     382             : //        FD_SET(f_socket, &s);
     383             : //#pragma GCC diagnostic pop
     384             : //        //
     385             : //        struct timeval timeout;
     386             : //        timeout.tv_sec = max_wait_ms / 1000;
     387             : //        timeout.tv_usec = (max_wait_ms % 1000) * 1000;
     388             : //        int const retval = select(f_socket + 1, &s, nullptr, &s, &timeout);
     389             :         //
     390           0 :         if( retval == -1 )
     391             :         {
     392             :             // error
     393             :             //
     394           0 :             return -1;
     395             :         }
     396           0 :         else if( retval == 0 )
     397             :         {
     398             :             // timeout
     399             :             //
     400           0 :             return -2;
     401             :         }
     402             :     }
     403             : 
     404             :     // accept the next connection
     405             :     struct sockaddr_in accepted_addr;
     406           0 :     socklen_t addr_len(sizeof(accepted_addr));
     407           0 :     memset(&accepted_addr, 0, sizeof(accepted_addr));
     408           0 :     f_accepted_socket = ::accept(f_socket, reinterpret_cast<struct sockaddr *>(&accepted_addr), &addr_len);
     409             : 
     410             :     // mark the new connection with the SO_KEEPALIVE flag
     411           0 :     if(f_accepted_socket != -1 && f_keepalive)
     412             :     {
     413             :         // if this fails, we ignore the error, but still log the event
     414           0 :         int optval(1);
     415           0 :         socklen_t const optlen(sizeof(optval));
     416           0 :         if(setsockopt(f_accepted_socket, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) != 0)
     417             :         {
     418             :             SNAP_LOG_WARNING
     419             :                 << "tcp_server::accept(): an error occurred trying to mark"
     420           0 :                    " accepted socket with SO_KEEPALIVE.";
     421             :         }
     422             :     }
     423             : 
     424           0 :     return f_accepted_socket;
     425             : }
     426             : 
     427             : 
     428             : /** \brief Retrieve the last accepted socket descriptor.
     429             :  *
     430             :  * This function returns the last accepted socket descriptor as retrieved by
     431             :  * accept(). If accept() was never called or failed, then this returns -1.
     432             :  *
     433             :  * Note that it is possible that the socket was closed in between in which
     434             :  * case this value is going to be an invalid socket.
     435             :  *
     436             :  * \return The last accepted socket descriptor.
     437             :  */
     438           0 : int tcp_server::get_last_accepted_socket() const
     439             : {
     440           0 :     return f_accepted_socket;
     441             : }
     442             : 
     443             : 
     444             : 
     445           6 : } // namespace ed
     446             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12