/* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SOCKET_CONNECTION_INCLUDED #define SOCKET_CONNECTION_INCLUDED #include "my_config.h" #include #include #include #include #include #include "my_psi_config.h" #include "mysql/components/services/psi_statement_bits.h" #include "mysql/psi/mysql_socket.h" // MYSQL_SOCKET #ifdef HAVE_POLL_H #include #endif class Channel_info; extern const char *MY_BIND_ALL_ADDRESSES; extern const char *ipv4_all_addresses; extern const char *ipv6_all_addresses; #ifdef HAVE_PSI_STATEMENT_INTERFACE extern PSI_statement_info stmt_info_new_packet; #endif /** Key Comparator for socket_map_t used in Mysqld_socket_listener */ struct Socket_lt_type { bool operator()(const MYSQL_SOCKET &s1, const MYSQL_SOCKET &s2) const { return mysql_socket_getfd(s1) < mysql_socket_getfd(s2); } }; // Enum denoting type of socket whether unix socket or tcp socket. enum class Socket_type { UNIX_SOCKET, TCP_SOCKET }; // Listen socket attributes. struct Socket_attr { explicit Socket_attr(Socket_type socket_type) : m_socket_type(socket_type) {} Socket_attr(Socket_type socket_type, const std::string &network_namespace) : m_socket_type(socket_type), m_network_namespace(network_namespace) {} Socket_type m_socket_type; std::string m_network_namespace; }; /** Typedef representing socket map type which hold the sockets and a corresponding bool which is true if it is unix socket and false for tcp socket. */ typedef std::map socket_map_t; // iterator type for socket map type. typedef std::map::const_iterator socket_map_const_iterator_t; /** Plain structure to collect together a host name/ip address and a corresponding network namespace if set and pass these information to different functions as a single unit. */ struct Bind_address_info { std::string address, network_namespace; Bind_address_info() = default; explicit Bind_address_info(const std::string &addr) : address(addr) {} Bind_address_info(const std::string &addr, const std::string &nspace) : address(addr), network_namespace(nspace) {} }; /** This class represents the Mysqld_socket_listener which prepare the listener sockets to recieve connection events from the client. The Mysqld_socket_listener may be composed of either or both a tcp socket which listen on a default mysqld tcp port or a user specified port via mysqld command-line and a unix socket which is bind to a mysqld defaul pathname. */ class Mysqld_socket_listener { /* Addresses to listen to and network namespace for every address if set. */ std::list m_bind_addresses; /* Address to listen to an admin connection request and network namespace if set. */ Bind_address_info m_admin_bind_address; uint m_tcp_port; // TCP port to bind to uint m_admin_tcp_port; // TCP port to bind to for support admin connection bool m_use_separate_thread_for_admin; // use a separate thread for listening // to admin interface uint m_backlog; // backlog specifying length of pending connection queue uint m_port_timeout; // port timeout value std::string m_unix_sockname; // unix socket pathname to bind to bool m_unlink_sockname; // Unlink socket & lock file if true. /* Map indexed by MYSQL socket fds and correspoding bool to distinguish between unix and tcp socket. */ socket_map_t m_socket_map; // map indexed by mysql socket fd and index MYSQL_SOCKET m_admin_interface_listen_socket; #ifdef HAVE_POLL struct poll_info_t { std::vector m_fds; std::vector m_pfs_fds; }; // poll related info. used in poll for listening to connection events. poll_info_t m_poll_info; #else struct select_info_t { fd_set m_read_fds, m_client_fds; my_socket m_max_used_connection; select_info_t() : m_max_used_connection(0) { FD_ZERO(&m_client_fds); } }; // select info for used in select for listening to connection events. select_info_t m_select_info; #endif // HAVE_POLL public: /** Constructor to setup a listener for listen to connect events from clients. @param bind_addresses list of addresses to listen to @param tcp_port TCP port to bind to @param admin_bind_addr address to listen admin connection @param admin_tcp_port TCP port for admin connection to bind @param use_separate_thread_for_admin Listen to connection requests on admin interface in a separate thread @param backlog backlog specifying length of pending connection queue used in listen. @param port_timeout portname. @param unix_sockname pathname for unix socket to bind to */ Mysqld_socket_listener(const std::list &bind_addresses, uint tcp_port, const Bind_address_info &admin_bind_addr, uint admin_tcp_port, bool use_separate_thread_for_admin, uint backlog, uint port_timeout, std::string unix_sockname); /** Set up a listener - set of sockets to listen for connection events from clients. In case a server is started with the option use_separate_thread_for_admin=true invocation of this method also spawns a thread to handle incoming connection requests on admin interface. @retval false listener sockets setup to be used to listen for connect events true failure in setting up the listener. */ bool setup_listener(); /** The body of the event loop that listen for connection events from clients. @retval Channel_info Channel_info object abstracting the connected client details for processing this connection. */ Channel_info *listen_for_connection_event(); /** Close the listener. In case a server is started with the option use_separate_thread_for_admin=true this method also shutdowns a thread for handling of incoming connection requests on admin interface and joins it. */ void close_listener(); ~Mysqld_socket_listener() { if (!m_socket_map.empty()) close_listener(); } private: /** Add a socket to a set of sockets being waiting for a new connection request. @param listen_socket Socket to listen for. */ void add_socket_to_listener(MYSQL_SOCKET listen_socket); /** Get a socket ready to accept incoming connection. @param[out] is_unix_socket has the value true in case a new incoming connection ready for acceptance pertains to unix socket domain. @param[out] is_admin_socket has the value true in case a new incoming connection is waiting for acceptance on admin interface. @return A socket ready to accept a new incoming connection. */ MYSQL_SOCKET get_ready_socket(bool *is_unix_socket, bool *is_admin_socket) const; /** Set up connection events for poll or select. @param socket_map sockets to listen for connection requests. */ void setup_connection_events(const socket_map_t &socket_map); }; ulong get_connection_errors_select(); ulong get_connection_errors_accept(); ulong get_connection_errors_tcpwrap(); #endif // SOCKET_CONNECTION_INCLUDED.