#include "cdevSocketStream.h"

// *****************************************************************************
// * cdevSocketStream::cdevSocketStream :
// *	Constructor for the cdevSocketStream class.  Only serves to initialize
// *	the readRetryCount variable.
// *****************************************************************************
cdevSocketStream::cdevSocketStream ( void )
	{
	}

// *****************************************************************************
// * cdevSocketStream::send :
// *	Send an n byte message to the connected socket.
// *****************************************************************************
ssize_t cdevSocketStream::send(const void *buf, size_t n, int flags) const
	{
	int retval;
	if((retval = ::send(getHandle(), (const char *) buf, n, flags))<=0)
		{
		int errCode = GetSocketErrno();
		
		if(errCode==EAGAIN || errCode==EWOULDBLOCK)  retval = 0;
		}
	return retval;
	}

// *****************************************************************************
// * cdevSocketStream::send_n :
// *	This method will transmit an n byte message to a connected socket, 
// *	waiting until all data has been transmitted or an error occurs.
// *****************************************************************************
ssize_t cdevSocketStream::send_n(const void *buf, size_t n, int flags) const
	{
	ssize_t amntsent = 0;
	int result   = 0;
	
	while(amntsent<(ssize_t)n && result>=0)
		{
		if((result = ::send(getHandle(), (const char *)buf+amntsent, n-amntsent, flags))<=0)
			{
			int errCode = GetSocketErrno();

			if(errCode==EAGAIN || errCode==EWOULDBLOCK) result = 0;
			else result = -1;
			}
		else amntsent+=result;
		}
	return (amntsent>=(ssize_t)n)?amntsent:-1;
	}


// *****************************************************************************
// * cdevSocketStream::recv :
// *	Recv an n byte message from the connected socket.
// *****************************************************************************
ssize_t cdevSocketStream::recv(void *buf, size_t n, int flags)
	{
	int retval = 0;

	if((retval = ::recv(getHandle(), (char *)buf, n, flags))<=0)
		{
		int errCode = GetSocketErrno();

		if(errCode==EAGAIN || errCode==EWOULDBLOCK) retval = 0;
		}
	return retval;
	}


// *****************************************************************************
// * cdevSocketStream::recv_n :
// *	This method will receive an n byte message from a connected socket, 
// *	waiting until all data has been received or an error occurs.
// *****************************************************************************
ssize_t cdevSocketStream::recv_n(void *buf, size_t n, int flags) 
	{
	ssize_t amntrecv = 0;
	int result   = 0;
	
	while(amntrecv < (ssize_t)n)
		{
		if((result = ::recv(getHandle(), (char *)buf+amntrecv, n-amntrecv, flags)) < 0)
			{
			  return -1;
			}
		else if (result == 0)
		  break;
		else amntrecv+=result;
		}
	return amntrecv;
	}


// *****************************************************************************
// * cdevSocketStream::closeReader :
// *	Shut down just the reading end of a cdevSocket. 
// *****************************************************************************
int cdevSocketStream::closeReader(void)
	{
	return ::shutdown(getHandle(), 0);
	}


// *****************************************************************************
// * cdevSocketStream::closeWriter :
// *	Shut down just the writing end of a cdevSocket. 
// *****************************************************************************
int cdevSocketStream::closeWriter(void)
	{
	return ::shutdown(getHandle(), 1);
	}


int cdevSocketStream::getBlockingSemantics ( void ) const
	{
	return O_NONBLOCK;
	}

int cdevSocketStream::getRcvLowWaterMark ( void ) const
	{
	return 0;
	}
	
int cdevSocketStream::getRcvBufferSize ( void ) const
	{
	return 56000;
	}

int cdevSocketStream::getSndLowWaterMark ( void ) const
	{
	return 16000;
	}
	
int cdevSocketStream::getSndBufferSize ( void ) const
	{
	return 56000;
	}
	
int cdevSocketStream::configureHandle ( void )
	{
	int retval = 0;
	int parm   = 1;
	
	
	if(getBlockingSemantics()==O_NONBLOCK && setFlags(O_NONBLOCK)==-1)
		{
		retval = -1;
		}

	setOption(IPPROTO_TCP, TCP_NODELAY, &parm, sizeof(parm));

	if((parm = getRcvBufferSize())>0) 
		{
		setOption(SOL_SOCKET, SO_RCVBUF, &parm, sizeof(parm));
		}
#ifndef __linux
	if((parm = getRcvLowWaterMark())>0)
		{
		setOption(SOL_SOCKET, SO_RCVLOWAT, &parm, sizeof(parm));
		}
#endif
		
	if((parm = getSndBufferSize())>0)
		{
		setOption(SOL_SOCKET, SO_SNDBUF, &parm, sizeof(parm));
		}

#ifndef __linux
	if((parm = getSndLowWaterMark())>0)
		{
		setOption(SOL_SOCKET, SO_SNDLOWAT, &parm, sizeof(parm));
		}
#endif

	return retval;
	}
