text: /// @file acceptor.h
  ///
  /// Class for a TCP server to accept incoming connections.
  ///
  /// @author	Frank Pagliughi
  ///	@author	SoRo Systems, Inc.
  ///	@author	www.sorosys.com
  ///
  /// @date	December 2014
  
  // --------------------------------------------------------------------------
  // This file is part of the "sockpp" C++ socket library.
  //
  // Copyright (c) 2014-2019 Frank Pagliughi
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  // 1. Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  //
  // 2. Redistributions in binary form must reproduce the above copyright
  // notice, this list of conditions and the following disclaimer in the
  // documentation and/or other materials provided with the distribution.
  //
  // 3. Neither the name of the copyright holder nor the names of its
  // contributors may be used to endorse or promote products derived from this
  // software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  // --------------------------------------------------------------------------
  
  #ifndef __sockpp_acceptor_h
  #define __sockpp_acceptor_h
  
  #include "sockpp/inet_address.h"
  #include "sockpp/stream_socket.h"
  
  namespace sockpp {
  
  /////////////////////////////////////////////////////////////////////////////
  
  /**
   * Class for creating a streaming server.
   * Objects of this class bind and listen on streaming ports for incoming
   * connections. Normally, a server thread creates one of these and blocks on
   * the call to accept incoming connections. The call to accept creates and
   * returns a @ref stream_socket which can then be used for the actual
   * communications.
   */
  class acceptor : public socket
  {
  	/** The base class */
  	using base = socket;
  
  	// Non-copyable
  	acceptor(const acceptor&) =delete;
  	acceptor& operator=(const acceptor&) =delete;
  
  protected:
  	/** The default listener queue size. */
  	static const int DFLT_QUE_SIZE = 4;
  
  	/**
  	 * Creates an underlying acceptor socket.
  	 * The acceptor uses a stream socket type, but for our purposes is not
  	 * classified (derived from) a streaming socket, since it doesn't
  	 * support read and write to the socket.
  	 * @param domain The communications domain (address family).
  	 * @return An OS handle to a stream socket.
  	 */
  	static socket_t create_handle(int domain) {
  		return stream_socket::create_handle(domain);
  	}
  
  public:
  	/**
  	 * Creates an unconnected acceptor.
  	 */
  	acceptor() {}
  	/**
  	 * Creates an acceptor from an existing OS socket
  	 * handle and claims ownership of the handle.
  	 * @param handle A socket handle from the operating system.
  	 */
  	explicit acceptor(socket_t handle) : base(handle) {}
  	/**
  	 * Creates an acceptor socket and starts it listening to the specified
  	 * address.
  	 * @param addr The address to which this server should be bound.
  	 * @param queSize The listener queue size.
  	 */
  	acceptor(const sock_address& addr, int queSize=DFLT_QUE_SIZE) {
  		open(addr, queSize);
  	}
  	/**
  	 * Move constructor.
  	 * Creates an acceptor by moving the other acceptor to this one.
  	 * @param acc Another acceptor
  	 */
  	acceptor(acceptor&& acc) : base(std::move(acc)) {}
  	/**
  	 * Creates an unbound acceptor socket with an open OS socket handle.
  	 * An application would need to manually bind and listen to this
  	 * acceptor to get incoming connections.
  	 * @param domain The communications domain (address family).
  	 * @return An open, but unbound acceptor socket.
  	 */
  	static acceptor create(int domain);
  	/**
  	 * Move assignment.
  	 * @param rhs The other socket to move into this one.
  	 * @return A reference to this object.
  	 */
  	acceptor& operator=(acceptor&& rhs) {
  		base::operator=(std::move(rhs));
  		return *this;
  	}
  	/**
  	 * Sets the socket listening on the address to which it is bound.
  	 * @param queSize The listener queue size.
  	 * @return @em true on success, @em false on error
  	 */
  	bool listen(int queSize=DFLT_QUE_SIZE) {
  		return check_ret_bool(::listen(handle(), queSize));
  	};
  	/**
  	 * Opens the acceptor socket, binds it to the specified address, and starts
  	 * listening.
  	 * @param addr The address to which this server should be bound.
  	 * @param queSize The listener queue size.
  	 * @param reuseSock Whether the SO_REUSEPORT (or SO_REUSEADDR on Win32)
  	 *  				socket option should be used before binding and
  	 *  				listening.
  	 * @return @em true on success, @em false on error
  	 */
  	bool open(const sock_address& addr, int queSize=DFLT_QUE_SIZE, bool reuseSock=true);
  	/**
  	 * Accepts an incoming TCP connection and gets the address of the client.
  	 * @param clientAddr Pointer to the variable that will get the
  	 *  				 address of a client when it connects.
  	 * @return A socket to the remote client.
  	 */
  	stream_socket accept(sock_address* clientAddr=nullptr);
  };
  
  
  /////////////////////////////////////////////////////////////////////////////
  
  /**
   * Base template class for streaming servers of specific address families.
   * This is a base for creating socket acceptor classes for an individual
   * family. In most cases, all that is needed is a type definition specifying
   * which addresses type should be used to receive incoming connections,
   * like:
   *     using tcp_acceptor = acceptor_tmpl<tcp_socket>;
   */
  template <typename STREAM_SOCK, typename ADDR=typename STREAM_SOCK::addr_t>
  class acceptor_tmpl : public acceptor
  {
  	/** The base class */
  	using base = acceptor;
  
  	// Non-copyable
  	acceptor_tmpl(const acceptor_tmpl&) =delete;
  	acceptor_tmpl& operator=(const acceptor_tmpl&) =delete;
  
  public:
  	/** The type of streaming socket from the acceptor. */
  	using stream_sock_t = STREAM_SOCK;
  	/** The type of address for the acceptor and streams. */
  	using addr_t = ADDR;
  
  	/**
  	 * Creates an unconnected acceptor.
  	 */
  	acceptor_tmpl() {}
  	/**
  	 * Creates a acceptor and starts it listening on the specified address.
  	 * @param addr The TCP address on which to listen.
  	 * @param queSize The listener queue size.
  	 */
  	acceptor_tmpl(const addr_t& addr, int queSize=DFLT_QUE_SIZE) {
  		open(addr, queSize);
  	}
  	/**
  	 * Creates a acceptor and starts it listening on the specified port.
  	 * The acceptor binds to the specified port for any address on the local
  	 * host.
  	 * @param port The TCP port on which to listen.
  	 * @param queSize The listener queue size.
  	 */
  	acceptor_tmpl(in_port_t port, int queSize=DFLT_QUE_SIZE) {
  		open(port, queSize);
  	}
  	/**
  	 * Move constructor.
  	 * Creates an acceptor by moving the other acceptor to this one.
  	 * @param acc Another acceptor
  	 */
  	acceptor_tmpl(acceptor_tmpl&& acc) : base(std::move(acc)) {}
  	/**
  	 * Creates an unbound acceptor socket with an open OS socket handle.
  	 * An application would need to manually bind and listen to this
  	 * acceptor to get incoming connections.
  	 * @return An open, but unbound acceptor socket.
  	 */
  	static acceptor_tmpl create() {
  		return base::create(addr_t::ADDRESS_FAMILY);
  	}
  	/**
  	 * Move assignment.
  	 * @param rhs The other socket to move into this one.
  	 * @return A reference to this object.
  	 */
  	acceptor_tmpl& operator=(acceptor_tmpl&& rhs) {
  		base::operator=(std::move(rhs));
  		return *this;
  	}
  	/**
  	 * Gets the local address to which we are bound.
  	 * @return The local address to which we are bound.
  	 */
  	addr_t address() const { return addr_t(base::address()); }
  	/**
  	 * Binds the socket to the specified address.
  	 * @param addr The address to which we get bound.
  	 * @return @em true on success, @em false on error
  	 */
  	bool bind(const addr_t& addr) { return base::bind(addr); }
  	/**
  	 * Opens the acceptor socket, binds it to the specified address, and starts
  	 * listening.
  	 * @param addr The address to which this server should be bound.
  	 * @param queSize The listener queue size.
  	 * @return @em true on success, @em false on error
  	 */
  	bool open(const addr_t& addr, int queSize=DFLT_QUE_SIZE) {
  		return base::open(addr, queSize);
  	}
  	/**
  	 * Opens the acceptor socket, binds the socket to all adapters and starts it
  	 * listening.
  	 * @param port The TCP port on which to listen.
  	 * @param queSize The listener queue size.
  	 * @return @em true on success, @em false on error
  	 */
  	bool open(in_port_t port, int queSize=DFLT_QUE_SIZE) {
  		return open(addr_t(port), queSize);
  	}
  	/**
  	 * Accepts an incoming connection and gets the address of the client.
  	 * @param clientAddr Pointer to the variable that will get the
  	 *  				 address of a client when it connects.
  	 * @return A tcp_socket to the remote client.
  	 */
  	stream_sock_t accept(addr_t* clientAddr=nullptr) {
  		return stream_sock_t(base::accept(clientAddr));
  	}
  };
  
  /////////////////////////////////////////////////////////////////////////////
  // end namespace sockpp
  }
  
  #endif		// __sockpp_acceptor_h
  
  