/***************************************************************************
 $RCSfile: socket.h,v $
                             -------------------
    cvs         : $Id: socket.h,v 1.12 2003/01/25 13:59:18 cstim Exp $
    begin       : Tue Aug 28 2001
    copyright   : (C) 2001 by Martin Preuss
    email       : martin@aquamaniac.de
*/

/***************************************************************************
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library 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     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
 *   MA  02111-1307  USA                                                   *
 *                                                                         *
 ***************************************************************************/


#ifndef C_SOCKET_H
#define C_SOCKET_H


#define SOCKET_TYPE_TCP 1
#define SOCKET_TYPE_UDP 2

#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>

namespace HBCI {
  class SocketSet;
  class Socket;
}

#include <openhbci/error.h>
#include <openhbci/inetaddress.h>

namespace HBCI {

/**
 * @short This class is needed by calls to the select method of Socket.
 * @author Martin Preuss<martin@aquamaniac.de>
 */
class SocketSet {
    friend class Socket;
private:
    fd_set _set;
    int _highest;
public:
    SocketSet();
    ~SocketSet();

    /**
     * Adds the given socket to this set.
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    void addSocket(Socket *s);

    /**
     * Removes the given socket from this set.
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    void removeSocket(Socket *s);

    /**
     * Checks whether the given socket is in this set.
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    bool hasSocket(Socket *s);

    /**
     * Clears this set.
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    void clear();
};


/**
 * @short This class allows portable access to sockets.
 * @author Martin Preuss<martin@aquamaniac.de>
 */
class Socket {
    friend class SocketSet;
private:
  int _sock;

    static int _initcount;

    bool _waitSocketRead(long timeout);
    bool _waitSocketWrite(long timeout);

public:
    Socket();
    Socket(int stype);
    Socket(const Socket &s);

    virtual ~Socket();

    void operator=(const Socket &s);

    /**
     * Connects to another host (TCP).
     * @author Martin Preuss<martin@aquamaniac.de>
     * @param addr address to connect
     * @param port port to connect
     */
    Error startConnect(const InetAddress &addr,
		       unsigned short port);

    /**
     * Checks whether the connection started by @ref startConnect() has
     * been established meanwhile.
     * @author Martin Preuss<martin@aquamaniac.de>
     * @param timeout how long to wait (in milliseconds)
     */
    Error checkConnect(long timeout);

    /**
     * Aborts a connection try started by @ref startConnect().
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    void abortConnect();

    /**
     * Closes the current connection, invalidating this Socket.
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    Error close();

    /**
     * Binds this socket to the given address and port.
     * @author Martin Preuss<martin@aquamaniac.de>
     * @param addr addr to bind to (may be an empty address)
     * @param port port to bin to
     */
    void bind(const InetAddress &addr, unsigned short port);

    /**
     * Make the socket listen for incoming connections.
     * @author Martin Preuss<martin@aquamaniac.de>
     * @param backlog how many incoming connections to queue. If that number
     * is exceeded then clients will get an error messages when trying to
     * connect to us.
     */
    void listen(int backlog);

    /**
     * Waits for an incoming connection and accepts it.
     * @author Martin Preuss<martin@aquamaniac.de>
     * @return a new socket which can be used for comunication with the new
     * client.
     * @param tm timeout in milliseconds
     */
    Socket *accept(long tm);

    /**
     * Returns the address of the peer (the host at the other side).
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    InetAddress getPeerAddress();

    /**
     * Returns the port of the peer.
     * @author Martin Preuss<martin@aquamaniac.de>
     */
    unsigned short getPeerPort();

    /**
     * This method waits for mutliple sockets to change state.
     * @author Martin Preuss<martin@aquamaniac.de>
     * @return number of sockets whose state have changed
     * @param rs set of readable sockets (0 if none)
     * @param ws set of writeable sockets (0 if none)
     * @param xs set of sockets to wait on for exceptions (0 if none)
     * @param timeout timeout in milliseconds (<0 to wait for ever,
     * ==0 to do not wait at all)
     */
    int select(SocketSet *rs,
               SocketSet *ws,
               SocketSet *xs,
               long timeout);

    /**
     * Reads data from the socket.
     * @author Martin Preuss<martin@aquamaniac.de>
     * @param data reference to a string to receive the data read
     * @param size maximum size of the data to be received
     * @param timeout timeout for reading in milliseconds
     */
    virtual Error readData(string &data, unsigned int size, long timeout);

    /**
     * Writes data into the socket.
     * @author Martin Preuss<martin@aquamaniac.de>
     * @param data reference to the string to be send
     * @param timeout timeout for writing in milliseconds
     */
    virtual Error writeData(string &data, long timeout);

    /**
     * Reads data from the socket.
     * @author Martin Preuss<martin@aquamaniac.de>
     * @param data reference to a string to receive the data read
     * @param size maximum size of the data to be received
     * @param timeout timeout for reading in milliseconds
     * @param addr reference to a string receiving the peers addr
     * @param port reference to an int to receive the pers port
     */
    Error readDataFrom(string &data, unsigned int size, long timeout,
                           InetAddress &addr,
                           unsigned short &port);

    /**
     * Writes data into the socket.
     * @author Martin Preuss<martin@aquamaniac.de>
     * @param data reference to the string to be send
     * @param timeout timeout for writing in microseconds
     * @param addr addr to send the data to
     * @param port port to send the data to
     */
    Error writeDataTo(string &data, long timeout,
                          const InetAddress &addr,
                          unsigned short port);

};

} /* namespace HBCI */

#endif




