/***************************************************************************
                          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
  *
  * A network socket, including SSL support.
  *
  * On WIN32 this class will not work until CSocket::SysInit() has been
  * called, normally by dclibInitDepLibs(), but that should
  * be better than initialising WinSock2 every time
  * a CSocket is created.
  */

#include <dclib/dcos.h>
#include <dclib/dclib-ssl-use.h>
#include <dclib/core/cstring.h>
#include <dclib/core/ctraffic.h>

#if DCLIB_USES_OPENSSL == 1

#include <openssl/ssl.h>
#include <openssl/err.h>

#else

/* this may also work for SSL builds */
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;

#endif

enum eSocketType {
	estTCP=0,
	estUDP
};

/*
 * esmSSLCLIENT and esmSSLSERVER are the old values for
 * changing to SSL mode during the NMDC protocol exchange
 *
 * esmFULLSSLCLIENT and esmFULLSSLSERVER are the new values
 * where the socket starts in SSL mode
 */
enum eSocketMode {
	esmSOCKET=0,
	esmSSLCLIENT,
	esmSSLSERVER,
	esmFULLSSLCLIENT,
	esmFULLSSLSERVER
};

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

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

class CSocket {
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 GetFreeSendBufferSize();

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

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

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

	/** */
	virtual bool ChangeSocketMode( eSocketMode mode, CString cert = CString(), CString key = CString() );
	
	/** Get SSL version */
	CString GetSSLVersion();
	/** Get SSL cipher */
	CString GetSSLCipher();
	/** Verify peer SSL certificate */
	CString VerifyPeerCertificate();
	
	/** */
	eSocketMode GetSocketMode() { return m_eSocketMode; }
	/** Gets the IP address with port of most recent connection attempt */
	CString GetResolvedIP() const { return m_sIP; }

	/**
	 * Initialises WinSock2 DLL, does nothing on non WIN32.
	 * Returns 0 if successful or some other WSA error code otherwise.
	 * Should be called once on program startup.
	 */
	static int SysInit();
	/**
	 * Shuts down WinSock2 DLL, does nothing on non WIN32.
	 * Returns 0 if successful or some other WSA error code otherwise.
	 * Should be called once on program shutdown.
	 */
	static int SysDeInit();

protected:
	/** */
	eSocketType SocketType;
	/** */
	SOCKET iHandle;
	/** */
	eSocketMode m_eSocketMode;

	/** */
	SSL_CTX * m_pCTX;
	/** */
	SSL * m_pSSL;

private:
	/** */
	int SocketError();
	/** */
	CString ext_strerror( int err );
	/** */
	CString sError;
	/** the IP address and port of the most recent connection attempt */
	CString m_sIP;
};

#endif
