/***************************************************************************
                          csocket.h  -  description
                             -------------------
    begin                : Sat Oct 6 2001
    copyright            : (C) 2001-2003 by Mathias Küster
    email                : mathen@users.berlios.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef CSOCKET_H
#define CSOCKET_H

/**
  *@author Mathias Küster
  */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <dclib/dcos.h>
#include <dclib/core/cobject.h>
#include <dclib/core/cstring.h>
#include <dclib/core/clist.h>

#ifdef HAVE_SSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif

typedef enum eSocketType {
	estTCP=0,
	estUDP
} eSocketType;

typedef enum eSocketMode {
	esmSOCKET=0,
	esmSSLCLIENT,
	esmSSLSERVER
} eSocketMode;

typedef enum eSocketLog {
	eslNONE=0,
	eslSEND,
	eslRECV,
	eslBOTH
} eSocketLog;

typedef enum eConnectState {
	ecsSUCCESS=0,
	ecsAGAIN,
	ecsERROR
} eConnectState;

typedef enum eTrafficType {
	ettRX=0,
	ettTX,
	ettDATARX,
	ettDATATX,
	ettCONTROLRX,
	ettCONTROLTX,
	ettRESET
} eTrafficType;

class DLL_EXPORT CTraffic : public CObject {
public:
	/** */
	CTraffic()
	{
		ResetTraffic();
	}
	/** */
	virtual ~CTraffic() {};

	/** */
	void AddTraffic( eTrafficType type, ulonglong n )
	{
		m_Thread.Lock();

		switch(type)
		{
			case ettRX:
				m_nRx += n;
				break;
			case ettTX:
				m_nTx += n;
				break;
			case ettDATARX:
				m_nDataRx += n;
				break;
			case ettDATATX:
				m_nDataTx += n;
				break;
			case ettCONTROLRX:
				m_nControlRx += n;
				break;
			case ettCONTROLTX:
				m_nControlTx += n;
				break;
			default:
				break;
		}

		m_Thread.UnLock();
	}

	/** */
	ulonglong GetTraffic( eTrafficType type )
	{
		ulonglong n;

		m_Thread.Lock();

		switch(type)
		{
			case ettRX:
				n = m_nRx;
				break;
			case ettTX:
				n = m_nTx;
				break;
			case ettDATARX:
				n = m_nDataRx;
				break;
			case ettDATATX:
				n = m_nDataTx;
				break;
			case ettCONTROLRX:
				n = m_nControlRx;
				break;
			case ettCONTROLTX:
				n = m_nControlTx;
				break;
			default:
				n = 0;
				break;
		}

		m_Thread.UnLock();

		return n;
	}

	/** */
	void ResetTraffic()
	{
		m_Thread.Lock();

		m_nRx        = 0;
		m_nTx        = 0;
		m_nDataRx    = 0;
		m_nDataTx    = 0;
		m_nControlRx = 0;
		m_nControlTx = 0;

		m_Thread.UnLock();
	}

private:
	/** */
	CThread m_Thread;
	/** */
	ulonglong m_nRx;
	/** */
	ulonglong m_nTx;
	/** */
	ulonglong m_nDataRx;
	/** */
	ulonglong m_nDataTx;
	/** */
	ulonglong m_nControlRx;
	/** */
	ulonglong m_nControlTx;
};

class DLL_EXPORT CSocket : public CObject {
public: 
	/** */
	CSocket( eSocketType type = estTCP );
	/** */
	virtual ~CSocket();

	/** */
	static CTraffic m_Traffic;
	/** */
	static eSocketLog m_eSocketLog;
	/** */
	eConnectState Connect( CString Host, bool iAsync );
	/** */
	eConnectState Connect( CString Host, int Port, bool iAsync );
	/** */
	int IsConnect();
	/** */
	int Disconnect();
	/** */
	int Read( char * buffer, int len, int sec_timeout=0, int usec_timeout=0 );
	/** */
	int Write( const unsigned char * buffer, int len, int sec_timeout=0, int usec_timeout=0 );
	/** */
	int GetInterfaceList( CList<CString> * interfacelist );
	/** */
	CString GetInterfaceIP( CString iface );
	/** */
	int GetFreeSendBufferSize();

	/** */
	int SetSocket( int handle, eSocketType sockettype );

	/** */
	static bool GetHostByName( const char * name, struct sockaddr_in * sin );
	/** */
	static CString GetHostByName( CString Host );
	/** */
	static void ParseHost( CString host, CString & ip, unsigned int & port );

	/** */
	int Accept();
	/** */
	int Listen( int port, CString ip = "" );
	/** */
	bool GetPeerName( CString * host, int * port );

	/** */
	CString GetSocketError() { return sError; };

	/** rfc1918 */
	static bool IsPrivateAddressSpace( const char * cp );

	/** */
	virtual bool ChangeSocketMode( eSocketMode mode, CString cert="", CString key="" );
	/** */
	eSocketMode GetSocketMode() { return m_eSocketMode; }


protected:
	/** */
	eSocketType SocketType;
	/** */
	SOCKET iHandle;
	/** */
	eSocketMode m_eSocketMode;
	/** */
	bool m_bSSLInit;
#ifdef HAVE_SSL
	/** */
	SSL_CTX *m_pCTX;
	/** */
	SSL *m_pSSL;
#endif
	/** */
	static CThread m_cs_ghbn;

private:
	/** */
	int SocketError();
	/** */
	CString ext_strerror( int err );
	/** */
	CString sError;
};

#endif
