//=================================================================
//
//        eCosTestSocket.h
//
//        Socket test class
//
//=================================================================
//####COPYRIGHTBEGIN####
//
// -------------------------------------------
// The contents of this file are subject to the Cygnus eCos Public License
// Version 1.0 (the "License"); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://sourceware.cygnus.com/ecos
// 
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
// License for the specific language governing rights and limitations under
// the License.
// 
// The Original Code is eCos - Embedded Cygnus Operating System, released
// September 30, 1998.
// 
// The Initial Developer of the Original Code is Cygnus.  Portions created
// by Cygnus are Copyright (C) 1998, 1999 Cygnus Solutions.
// All Rights Reserved.
// -------------------------------------------
//
//####COPYRIGHTEND####
//=================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):     sdf
// Contributors:  sdf
// Date:          1999-04-01
// Description:   This class abstracts tcp/ip sockets for use in the testing infrastructure
// Usage:
//
//####DESCRIPTIONEND####

#include "eCosTest.h"
#include "eCosTestUtils.h"

#ifndef _SOCKETUTILS_H
#define _SOCKETUTILS_H

class CeCosTestSerial;
class CeCosTestSocket;

extern int SSRead (CeCosTestSerial &serial,CeCosTestSocket &socket,void *pBuf,unsigned int nSize,unsigned int &nRead);
typedef bool (CALLBACK FilterFunc)(void *&,unsigned int &,CeCosTestSerial&,CeCosTestSocket &,void *);
extern bool ConnectSocketToSerial (int nListenSock,const char *pszPort, int nBaud,FilterFunc *pSerialToSocketFilterFunc=0,FilterFunc *pSocketToSerialFilterFunc=0,void *pParam=0,bool *pbStop=0);

class CeCosTestSocket {
    friend int SSRead (CeCosTestSerial &serial,CeCosTestSocket &socket,void *pBuf,unsigned int nSize,unsigned int &nRead);
public:	
	typedef int /*CeCosTest::Duration*/ Duration;
protected:
	static Duration nDefaultSocketTimeout; // milliseconds
    // Return the last socket error
public:	
	typedef bool (CALLBACK StopFunc)(void *);
	
	// Listen and this form of constructor used to act as server
	static int Listen(int nTcpPort);
	CeCosTestSocket (); // Caller promises to call Accept() or Connect() later

    // Accept-like ctor (act as server)
	CeCosTestSocket (int sock /*result of previous call of Listen*/, bool *pbStop=0);
    // Connect-like ctor (act as client)
    CeCosTestSocket (CeCosTestUtils::String strHost,int port,Duration dTimeout);

    bool Accept(int sock /*result of previous call of Listen*/, bool *pbStop=0);
	// This form of constructor used to act as client
    bool Connect(CeCosTestUtils::String strHost,int port,Duration dTimeout);
	~CeCosTestSocket();

    int Client() const { return m_nClient; }
    int Sock() const { return m_nSock; }

	bool send(const void *pData,unsigned int nLength,const char *pszMsg="",int dTimeout=nDefaultSocketTimeout,StopFunc *pFunc=0,void *pParam=0){
	    return sendrecv(true,pData,nLength,pszMsg,dTimeout,pFunc,pParam);
	}
	bool recv(const void *pData,unsigned int nLength,const char *pszMsg="",int dTimeout=nDefaultSocketTimeout,StopFunc *pFunc=0,void *pParam=0){
		return sendrecv(false,pData,nLength,pszMsg,dTimeout,pFunc,pParam);
	}
	bool Ok() { return -1!=m_nSock; }
    // Close the given socket
    int SocketError() { return m_nErr; }
    // Return last socket error, translated to a string
    CeCosTestUtils::String SocketErrString();
    
    bool recvInteger (int &n,const char * const pszMsg="",Duration dTimeout=nDefaultSocketTimeout);
    bool sendInteger (int n,const char * const pszMsg="",Duration dTimeout=nDefaultSocketTimeout);

    bool recvString  (CeCosTestUtils::String &str,const char * const pszMsg="",Duration dTimeout=nDefaultSocketTimeout);
    bool sendString  (const char *pszString,const char * const pszMsg="",Duration dTimeout=nDefaultSocketTimeout);
	
    static bool CloseSocket (int &sock);
    int OpenRC() const { return m_nOpenrc; }
    bool Peek (unsigned int &nAvail);

protected:
    // Set appropriate socket options (most importantly, non-blocking mode)
    bool SetSocketOptions ();
	int m_nSock;
    int m_nClient;
    int m_nOpenrc;
    int m_nErr;
    void SaveError() { 
        #ifdef _WIN32
        m_nErr=WSAGetLastError();
        #else
        m_nErr=errno;
        #endif
    }
	bool sendrecv(bool bSend,const void *pData,unsigned int nLength,const char *pszMsg="",int dTimeout=nDefaultSocketTimeout,StopFunc *pFunc=0,void *pParam=0);

};
#endif
