/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM is free software; you can redistribute it and/or modify it    
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; only version 2 of the License.      
 * 
 * NMM 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 for more details.  
 * 
 * You should have received a copy of the GNU General Public License 
 * along with NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#ifndef NMM_SOCKACCEPTOR_HPP
#define NMM_SOCKACCEPTOR_HPP NMM_SOCKACCEPTOR_HPP

#include "nmm/nmm_prefix.hpp"

#include "NetExceptions.hpp"
#include "Sock.hpp"

#include "nmm/nmm_inttypes.hpp"

#include "visibility.hpp"

namespace NMM {

  /** This wrapper class can be used to accept and control a network connection.
   * With tcp, this is a wrapper for the socket(2), bind(2), listen(2) and accept(2) functions.
   * With udp, a dummy implementation is provided for binding a socket and finding a free port.
   * No emulation of tcp functonality is done for udp. A udp SockAcceptor can only accept one connection,
   * then it must be opened again. Also the accept method trivially succeeds for udp and does nothing
   * but returning the udp socket.
   */
  class DLLEXPORT SockAcceptor {
  public:
    /** @name Constructor & Destructor
      */
    //@{
    /** Default constructor
      */
    SockAcceptor();

    /** Destructor
      */
    ~SockAcceptor();
    //@ }


    /** @name Accepting Methods
      */
    //@{
    /** Init a new port and calls bind and listen on it.
     * If the transport protocol is "udp", this method simple creates a udp socket and binds it to the given address.
     * @param addr Local address, address part should be INADDR_ANY, port should be the port to listen on
     * @param proto Transport protocol, must be either "tcp" or "udp"
     * @exception ConnectionException if creating, binding or listening on the socket fails
     */
    void open(const INetAddr& addr, const char* proto = "tcp")
      throw (const ConnectionException&);
    
    /** This method closes the SockAcceptor
     */
    void close()
      throw (const ConnectionException&);
    
    /** Scans for free port between [from,to], bind and listen on it.
     *
     * The used port is stored in the given INetAddr.
     * The INetAddr address value should be INADDR_ANY.
     *
     * @param addr Reference to the addr. The hostname must be the address of the localhost.
     *        The used port is stored in addr
     * @param from Begin of the port range
     * @param to End of the port range
     * @param proto The used protocol, must be either "tcp" or "udp"
     * @exception ConnectionExcepion if listening failed on all ports in the given port range
     */
    void tryOpen(INetAddr& addr, u_int32_t from, u_int32_t to, const char* proto = "tcp")
      throw (const ConnectionException&);
    
    /** This method accepts an incoming method.
     * If the transport protocol is UDP, this method simply stores the internal socket in the Sock object and
     * the SockAcceptor must be opened again to accept a new connection.
     * If the transport protocol is TCP, this method also calls setPeerAddress on the Sock object, based on
     * the address returned by the accept(2) call. With udp, the peer address must be set manually or using a
     * SockConnector.
     * @param sock Stores the new socket in the given sock
     */
    void accept(Sock& sock)
      throw (const ConnectionException&);
    //@}
    
    /** @name Status Methods
     */
    //@{
    /** This method returns the internal socket.
     * @return The current socket which is used to accept connections.
     */
    SocketHandle getSocket();
    
    /** This method tests if connections are waiting. You should use the NetReactor to be informed for incoming connections
     * @return True if connections are waiting, otherwise false
     */
    bool isAcceptable();
    
    /** This method disables blocking for accepting a connection.
     */
    void setNonBlocking();
    //@}
    
  private: //methods
    /** Disabled copy constructor.
     */
    SockAcceptor(const SockAcceptor&) throw() {}
    
    /** Disabled assignment operator.
     */
    SockAcceptor& operator=(const SockAcceptor&) throw() { return *this; }
    
    /** Creates a BindingException. Based on the given error code a error message is created and stored in the BindingException. 
     *
     * @param _errno specifies the error code
     */
    void createBindException(int _errno);

    /** Creates an Exception that occurs during the listen command. Based on the given error code a error message is 
     * created and stored in Exception. 
     *
     * @param _errno specifies the error code
     */
    void createListenException(int _errno);

    /** Creates an Exception that occurs during instantiation of a new socket. Based on the given error code a error message is 
     * created and stored in Exception. 
     *
     * @param _errno specifies the error code
     */
    void createSocketException(int _errno);

    /** Creates an Exception that occurs during shutting down of a connection. Based on the given error code a error message is 
     * created and stored in Exception. 
     *
     * @param _errno specifies the error code
     */
    void createShutdownException(int _errno);

    /** Creates an Exception that occurs during accepting a connection. Based on the given error code a error message is 
     * created and stored in Exception. 
     *
     * @param _errno specifies the error code
     */
    void createAcceptException(int _errno);

  private: //member
    SocketHandle __socket; ///<The internal socket for accepting incoming connections
    string __trans_prot;   ///<The transport protocol which can be "TCP" or "UDP"
  };

}

#include "nmm/nmm_suffix.hpp"

#endif
