// Common, group Communication
// Copyright Alexander Liss

#include <string.h>
#include "socket.h"


	// IPSocketAddress

int IPSocketAddress::get(sockaddr& z)const
{
	sockaddr_in a;
	a.sin_family=AF_INET;
	a.sin_port=port;
	a.sin_addr.S_un.S_addr=address;
	memset(a.sin_zero,0,8);
	memcpy(&z,&a,sizeof(a));
	return 0;
}

int IPSocketAddress::put(const sockaddr& z)
{
	sockaddr_in a;
	memcpy(&a,&z,sizeof(a));
	if(a.sin_family!=AF_INET) return 1;
	port=a.sin_port;
	address=a.sin_addr.S_un.S_addr;
	return 0;
}


	// Socket

Socket::Socket(int type
#if( _WIN32_WINNT >= 0x0400 )				   
,DWORD flags,LPWSAPROTOCOL_INFO pi
#endif
)
{
#if( _WIN32_WINNT >= 0x0400 )
 
	handle= ::WSASocket(AF_INET,type,0,pi,0,flags); 

#else

	handle= ::socket(AF_INET,type,0); 

#endif
}

int Socket::bind(const IPSocketAddress& z)
{
	sockaddr a;
	
	z.get(a);

	return ::bind(handle,&a,sizeof(a));
}

int Socket::connect(const IPSocketAddress& z
#if (_WIN32_WINNT >= 0x0400)
	,LPWSABUF lpCallerData,             
	LPWSABUF lpCalleeData,             
	LPQOS  lpSQOS 
#endif
	)
{
	sockaddr a;
	
	z.get(a);

#if _WIN32_WINNT >= 0x0400

	return ::WSAConnect(handle,&a,sizeof(a),lpCallerData,lpCalleeData,lpSQOS,0);

#else

	return ::connect(handle,&a,sizeof(a));

#endif
}


int Socket::reconnect(
#if (_WIN32_WINNT >= 0x0400)
	LPWSABUF lpCallerData,             
	LPWSABUF lpCalleeData,             
	LPQOS  lpSQOS 
#endif
					  )
{
	sockaddr a;
	int size=sizeof(a);
	int g=::getpeername(handle,&a,&size);
	if(g) return 1;
#if _WIN32_WINNT >= 0x0400

	return ::WSAConnect(handle,&a,sizeof(a),lpCallerData,lpCalleeData,lpSQOS,0);

#else

	g=::connect(handle,&a,sizeof(a));

#endif
	if(g) return 2;
	return 0;
}


int Socket::get_address(IPSocketAddress& z)
{
	sockaddr a;
	int size=sizeof(a);
	int g=::getsockname(handle,&a,&size);
	if(g) return 1;
	z.put(a);
	return 0;
}

int Socket::get_peer_address(IPSocketAddress& z)
{
	sockaddr a;
	int size=sizeof(a);
	int g=::getpeername(handle,&a,&size);
	if(g) return 1;
	z.put(a);
	return 0;
}

int Socket::send(DWORD& r, const VOID *buf,DWORD len,DWORD flags)
{ 
	r=0;

	int g=::send(handle,(char*)buf,(int)len,(int)flags);

	if(g==SOCKET_ERROR)
	{
		r=0;
		return 1;
	}

	r=(DWORD)g;

	return 0;
}

int Socket::receive(DWORD& r, VOID *buf,DWORD limit,DWORD flags)
{
	r=0;

	int g=::recv(handle,(char*)buf,(int)limit,(int)flags);

	if(g==SOCKET_ERROR)
	{
		r=0;
		return 1;
	}

	r=(DWORD)g;

	return 0;
}


int Socket::send_to(DWORD& r,const VOID *buf,DWORD len,const IPSocketAddress& z,DWORD flags)
{
	sockaddr a;
	z.get(a);
	r=0;
	
	int g= ::sendto(handle,(char*)buf,(int)len,(int)flags,&a,sizeof(a));

	if(g==SOCKET_ERROR)
	{
		r=0;
		return 1;
	}

	r=(DWORD)g;

	return 0;
}

int Socket::receive_from(DWORD& r,VOID *buf,DWORD len, IPSocketAddress& z,DWORD flags)
{
	sockaddr a;
	int size=sizeof(a);
	r=0;
	
	int g=::recvfrom(handle,(char*)buf,(int)len,(int)flags,&a,&size);

	if(g==SOCKET_ERROR)
	{
		r=0;
		return 1;
	}

	z.put(a);

	r=(DWORD)g;

	return 0;
}

int Socket::send_loop(DWORD& len, const VOID *buf,DWORD data_size,DWORD flags)
{
	int g=0;
	DWORD z=0;
	len=0;
	
	while(len<data_size)
	{
		g=send(z,(char*)buf+len,data_size-len,flags);
		if(g) return 1;
		len+=z;
	}

	return 0;
}

int Socket::receive_loop(DWORD& len, VOID *buf,DWORD data_size,DWORD flags)
{
	int g=0;
	DWORD z=0;
	len=0;
	
	while(len<data_size)
	{
		g=receive(z,(char*)buf+len,data_size-len,flags);
		if(g) return 1;
		len+=z;
	}

	return 0;
}


int Socket::send_to_loop(DWORD& len,const VOID *buf,DWORD data_size,const IPSocketAddress& remote,DWORD flags)
{
	int g=0;
	DWORD z=0;
	len=0;
	
	while(len<data_size)
	{
		g=send_to(z,(char*)buf+len,data_size-len,remote,flags);
		if(g) return 1;
		len+=z;
	}

	return 0;
}


int Socket::receive_from_loop(DWORD& len,VOID *buf,DWORD data_size, IPSocketAddress& remote,DWORD flags)
{
	int g=0;
	DWORD z=0;
	len=0;
	
	while(len<data_size)
	{
		g=receive_from(z,(char*)buf+len,data_size-len,remote,flags);
		if(g) return 1;
		len+=z;
	}

	return 0;
}




#if (_WIN32_WINNT >= 0x0400)

int Socket::send_to( 
  DWORD&           NumberOfBytesSent,
  LPWSABUF          lpBuffers,                                     
  DWORD             dwBufferCount,  
  const IPSocketAddress&  peer,
  DWORD             dwFlags)
{
	sockaddr a;
	peer.get(a);

	return WSASendTo(handle,lpBuffers,dwBufferCount,&NumberOfBytesSent,dwFlags,&a,sizeof(a),0,0);
}

int Socket::receive_from( 
  DWORD&           NumberOfBytesReceived,
  LPWSABUF          lpBuffers,                                     
  DWORD             dwBufferCount,  
  IPSocketAddress&  peer,
  LPDWORD           lpdwFlags)
{
	sockaddr a;
	int size=sizeof(a);

	int g=WSARecvFrom(handle,lpBuffers,dwBufferCount,&NumberOfBytesReceived,lpdwFlags,&a,&size,0,0);

	if(!g) peer.put(a);

	return g;
}

int Socket::send_loop( 
  DWORD&			len,
  LPWSABUF          buf_array,                                     
  DWORD             count,
  DWORD             flags)
{
	if(count>64) return 1;

	len=0;

	int g=0;
	int k=0;
	DWORD z=0;
	WSABUF local_buf_array[64];
	DWORD data_size=0;
	for(int i=0;i<(int)count;++i)
	{
		data_size+=buf_array[i].len;
		local_buf_array[i]=buf_array[i];
	}


	for(;;)
	{
		z=0;
		g=send(z,&local_buf_array[k],count-k,flags);
		if(g)	return 1;

		len+=z;

		if(len>=data_size) break;

		for(int i=k;i<(int)count;++i)
		{

			if(z>=buf_array[i].len)
			{
				++k;
				z-=local_buf_array[i].len;
			}
			else break;
		}

		local_buf_array[k].buf+=z;
		local_buf_array[k].len-=z;

	}

	return 0;
}

int Socket::receive_loop( 
  DWORD&			len,
  LPWSABUF          buf_array,                                     
  DWORD             count,
  LPDWORD           flags)
{
	if(count>64) return 1;

	len=0;

	int g=0;
	int k=0;
	DWORD z=0;
	WSABUF local_buf_array[64];
	DWORD data_size=0;
	for(int i=0;i<(int)count;++i)
	{
		data_size+=buf_array[i].len;
		local_buf_array[i]=buf_array[i];
	}


	for(;;)
	{
		z=0;
		g=receive(z,&local_buf_array[k],count-k,flags);
		if(g)	return 1;

		len+=z;

		if(len>=data_size) break;

		for(int i=k;i<(int)count;++i)
		{

			if(z>=buf_array[i].len)
			{
				++k;
				z-=local_buf_array[i].len;
			}
			else break;
		}

		local_buf_array[k].buf+=z;
		local_buf_array[k].len-=z;

	}

	return 0;
}

int Socket::send_to_loop( 
  DWORD&			len,
  LPWSABUF          buf_array,                                     
  DWORD             count,   
  const IPSocketAddress&  peer,
  DWORD             flags)
{
	if(count>64) return 1;

	len=0;

	int g=0;
	int k=0;
	DWORD z=0;
	WSABUF local_buf_array[64];
	DWORD data_size=0;
	for(int i=0;i<(int)count;++i)
	{
		data_size+=buf_array[i].len;
		local_buf_array[i]=buf_array[i];
	}


	for(;;)
	{
		z=0;
		g=send_to(z,&local_buf_array[k],count-k,peer,flags);
		if(g)	return 1;
		len+=z;

		if(len>=data_size) break;

		for(int i=k;i<(int)count;++i)
		{

			if(z>=buf_array[i].len)
			{
				++k;
				z-=local_buf_array[i].len;
			}
			else break;
		}

		local_buf_array[k].buf+=z;
		local_buf_array[k].len-=z;

	}

	return 0;
}

int Socket::receive_from_loop( 
  DWORD&			len,
  LPWSABUF          buf_array,                                     
  DWORD             count,  
  IPSocketAddress& peer,
  LPDWORD           flags)
{
	if(count>64) return 1;

	len=0;

	int g=0;
	int k=0;
	DWORD z=0;
	WSABUF local_buf_array[64];
	DWORD data_size=0;
	for(int i=0;i<(int)count;++i)
	{
		data_size+=buf_array[i].len;
		local_buf_array[i]=buf_array[i];
	}


	for(;;)
	{
		z=0;
		g=receive_from(z,&local_buf_array[k],count-k,peer,flags);
		if(g)	return 1;

		len+=z;

		if(len>=data_size) break;

		for(int i=k;i<(int)count;++i)
		{
			if(z>=buf_array[i].len)
			{
				++k;
				z-=local_buf_array[i].len;
			}
			else break;
		}

		local_buf_array[k].buf+=z;
		local_buf_array[k].len-=z;

	}

	return 0;
}

int Socket::connect_multipoint(const IPSocketAddress& z
	,LPWSABUF	lpCallerData,             
	LPWSABUF	lpCalleeData,             
	LPQOS		lpSQOS, 
	DWORD		dwFlags
	)
{
	sockaddr a;
	
	z.get(a);

	SOCKET g=::WSAJoinLeaf(handle,&a,sizeof(a),lpCallerData,lpCalleeData,lpSQOS,0,dwFlags);

	return g==INVALID_SOCKET;
}

#endif

int Socket::set_heartbeat()
{
	int z=1;
	
	return set_option(SOL_SOCKET,SO_KEEPALIVE,(const char *)&z,sizeof(z));

}

int Socket::linger(int seconds)
{
	struct linger z;

	if(seconds>0)
	{
		z.l_linger=seconds;	
		z.l_onoff=1;	
	}
	else
	{
		z.l_linger=0;	
		z.l_onoff=0;	
	}
	
	return set_option(SOL_SOCKET,SO_LINGER,(const char *)&z,sizeof(z));
}

int Socket::get_send_buffer_size(int &size)
{
	int z=0;
	
	return get_option(SOL_SOCKET,SO_SNDBUF,(char *)&size,&z);
}

int Socket::set_send_buffer_size(int size)
{
	int z=size;
	
	return set_option(SOL_SOCKET,SO_SNDBUF,(const char *)&z,sizeof(z));
}

int Socket::get_receive_buffer_size(int &size)
{
	int z=0;
	
	return get_option(SOL_SOCKET,SO_RCVBUF,(char *)&size,&z);
}

int Socket::set_receive_buffer_size(int size)
{
	int z=size;
	
	return set_option(SOL_SOCKET,SO_RCVBUF,(const char *)&z,sizeof(z));
}

void Socket::abrupt_shutdown()
{
	::closesocket(handle);
}


bool Socket::receive_data_ready()
{
	timeval t;
	memset(&t,0,sizeof(timeval));

	fd_set r,we;

	r.fd_count=1;
	we.fd_count=0;

	r.fd_array[0]=handle;

	int n=select(0,&r,&we,&we,&t);

	if(n==1)
		return true;

	return false;
}

bool Socket::send_data_ready()
{
	timeval t;
	memset(&t,0,sizeof(timeval));

	fd_set w,re;

	w.fd_count=1;
	re.fd_count=0;

	w.fd_array[0]=handle;

	int n=select(0,&re,&re,&w,&t);

	if(n==1)
		return true;

	return false;
}

	// Listener

Socket *Listener::new_connection(IPSocketAddress& z
#if (_WIN32_WINNT >= 0x0400)					 
  ,LPCONDITIONPROC   lpfnCondition,  
  DWORD				dwCallbackData
#endif
  )
{
	sockaddr a;
	int size=sizeof(a);
	SOCKET s=INVALID_SOCKET;

#if (_WIN32_WINNT >= 0x0400)

	s=::WSAAccept(s,&a,&size,lpfnCondition,dwCallbackData);

#else

	s=::accept(s,&a,&size);

#endif

	if(s==INVALID_SOCKET) return 0;

	z.put(a);

	return new Socket(s);

}

	// SocketFile

BOOL SocketFile::get_result(DWORD& dwTransfer,BOOL bWait)
{
	if(!handle) return FALSE;
	return ::GetOverlappedResult(handle,&overlapped,&dwTransfer,bWait);
}

BOOL SocketFile::cancel()
{
	if(!handle) return FALSE;
	return ::CancelIo(handle);
}

void SocketFile::clear()
{
	handle=0;
	memset(&overlapped,0,sizeof(overlapped));
}

	// SocketFileOperation

int SocketFileOperation::send(DWORD& BytesActual,const VOID *lpBuffer,DWORD dwBytes)
{
	if(!handle) return 1;

	BOOL success = ::WriteFile(handle,lpBuffer,dwBytes,&BytesActual,&overlapped);

	if(success) return 0;
	return -1;
}

int SocketFileOperation::receive(DWORD& BytesActual, LPVOID lpBuffer,DWORD dwBytesLimit)
{
	if(!handle) return 1;

	BOOL success = ::ReadFile(handle,lpBuffer,dwBytesLimit,&BytesActual,&overlapped);

	if(success) return 0;
	return -1;
}

int SocketFileOperation::send_loop(DWORD& BytesActual,const VOID *lpBuffer,DWORD dwBytes,DWORD timeout, DWORD wait_slice)
{
	if(!handle) return 1;

	if(wait_slice<1 || timeout<1) return 2;

	BytesActual=0;

	int g=0,r=0;
	DWORD z=0;
	DWORD period=0;
	
	while(BytesActual<dwBytes)
	{
		z=0;

		g=send(z,(char*)lpBuffer+BytesActual,dwBytes-BytesActual);

		if(!g) 
		{
			BytesActual+=z;
			continue;
		}

		if(g>0) 
		{
			BytesActual+=z;
			r=3;
			break;
		}

		for(;;)
		{
			period+=wait_slice;

			if(period>timeout)
			{
				r=-1;
				break;
			}

			wait(wait_slice);

			BOOL success=get_result(z,FALSE);

			if(success) break;
		}

		BytesActual+=z;
	}

	return r;
}

int SocketFileOperation::receive_loop(DWORD& BytesActual,const VOID *lpBuffer,DWORD dwBytes,DWORD timeout, DWORD wait_slice)
{
	if(!handle) return 1;

	if(wait_slice<1 || timeout<1) return 2;

	BytesActual=0;

	int g=0,r=0;
	DWORD z=0;
	DWORD period=0;
	
	while(BytesActual<dwBytes)
	{
		z=0;

		g=receive(z,(char*)lpBuffer+BytesActual,dwBytes-BytesActual);

		if(!g) 
		{
			BytesActual+=z;
			continue;
		}

		if(g>0) 
		{
			BytesActual+=z;
			r=3;
			break;
		}

		for(;;)
		{
			period+=wait_slice;

			if(period>timeout)
			{
				r=-1;
				break;
			}

			wait(wait_slice);

			BOOL success=get_result(z,FALSE);

			if(success) break;
		}

		BytesActual+=z;
	}

	return r;
}



	// SocketFileOperationEx

int SocketFileOperationEx::send(const VOID *lpBuffer,DWORD dwBytesLimit)
{
	if(!handle) return 1;

	BOOL success = ::WriteFileEx(handle,lpBuffer,dwBytesLimit,&overlapped,completion_routine);

	if(success) return 0;
	return -1;
}

int SocketFileOperationEx::receive( LPVOID lpBuffer, DWORD dwBytesLimit)
{
	if(!handle) return 1;

	BOOL success = ::ReadFileEx(handle,lpBuffer,dwBytesLimit,&overlapped,completion_routine);

	if(success) return 0;
	return -1;
}


#if (_WIN32_WINNT >= 0x0400)


	// SocketOperation

void SocketOperation::clear()
{
	socket=0;
	completion_routine=0;
	memset(&overlapped,0,sizeof(overlapped));
}


int SocketOperation::send_to( 
  DWORD&  NumberOfBytesSent,
  LPWSABUF          lpBuffers,                                     
  DWORD             dwBufferCount,  
  const IPSocketAddress&  peer,
  DWORD             dwFlags)
{
	sockaddr a;
	peer.get(a);

	return WSASendTo(socket->get_handle(),lpBuffers,dwBufferCount,&NumberOfBytesSent,dwFlags,&a,sizeof(a),&overlapped,completion_routine);
}

int SocketOperation::receive_from(
  DWORD&  NumberOfBytesReceived,
  LPWSABUF          lpBuffers,                                     
  DWORD             dwBufferCount,  
  IPSocketAddress&  peer,
  LPDWORD           lpdwFlags)
{
	sockaddr a;
	int size=sizeof(a);

	int g=WSARecvFrom(socket->get_handle(),lpBuffers,dwBufferCount,&NumberOfBytesReceived,lpdwFlags,&a,&size,&overlapped,completion_routine);

	if(!g) peer.put(a);

	return g;
}

int SocketOperation::send_loop( 
  DWORD&			BytesActual,
  LPWSABUF          lpBuffers,                                     
  DWORD             dwBufferCount,
  DWORD				timeout, 
  DWORD				wait_slice,
  DWORD             dwFlags)
{	
	if(dwBufferCount>64) return 1;

	if(wait_slice<1 || timeout<1) return 2;

	BytesActual=0;

	int g=0,r=0;
	DWORD z=0;
	int k=0;
	DWORD period=0;	
	WSABUF local_buf_array[64];
	DWORD data_size=0;

	for(int i=0;i<(int)dwBufferCount;++i)
	{
		data_size+=lpBuffers[i].len;
		local_buf_array[i]=lpBuffers[i];
	}


	while(BytesActual<data_size)
	{
		for(int i=k;i<(int)dwBufferCount;++i)
		{
			if(z>=lpBuffers[i].len)
			{
				++k;
				z-=local_buf_array[i].len;
			}
			else break;
		}

		local_buf_array[k].buf+=z;
		local_buf_array[k].len-=z;

		z=0;

		g=send(z,&local_buf_array[k],dwBufferCount-k,dwFlags);

		if(!g) 
		{
			BytesActual+=z;
			continue;
		}

		if(g>0) 
		{
			BytesActual+=z;
			r=3;
			break;
		}

		for(;;)
		{
			period+=wait_slice;

			if(period>timeout)
			{
				r=-1;
				break;
			}

			wait(wait_slice);

			BOOL success=get_result(z,FALSE);

			if(success) break;
		}

		BytesActual+=z;
	}

	return r;
}

int SocketOperation::receive_loop( 
  DWORD&			BytesActual,
  LPWSABUF          lpBuffers,                                     
  DWORD             dwBufferCount,
  DWORD				timeout, 
  DWORD				wait_slice,
  LPDWORD           lpdwFlags)
{
	if(dwBufferCount>64) return 1;

	if(wait_slice<1 || timeout<1) return 2;

	BytesActual=0;

	int g=0,r=0;
	DWORD z=0;
	int k=0;
	DWORD period=0;	
	WSABUF local_buf_array[64];
	DWORD data_size=0;

	for(int i=0;i<(int)dwBufferCount;++i)
	{
		data_size+=lpBuffers[i].len;
		local_buf_array[i]=lpBuffers[i];
	}


	while(BytesActual<data_size)
	{
		for(int i=k;i<(int)dwBufferCount;++i)
		{
			if(z>=lpBuffers[i].len)
			{
				++k;
				z-=local_buf_array[i].len;
			}
			else break;
		}

		local_buf_array[k].buf+=z;
		local_buf_array[k].len-=z;

		z=0;

		g=receive(z,&local_buf_array[k],dwBufferCount-k,lpdwFlags);

		if(!g) 
		{
			BytesActual+=z;
			continue;
		}

		if(g>0) 
		{
			BytesActual+=z;
			r=3;
			break;
		}

		for(;;)
		{
			period+=wait_slice;

			if(period>timeout)
			{
				r=-1;
				break;
			}

			wait(wait_slice);

			BOOL success=get_result(z,FALSE);

			if(success) break;
		}

		BytesActual+=z;
	}

	return r;
}

int SocketOperation::send_to_loop( 
  DWORD&			BytesActual,
  LPWSABUF          lpBuffers,                                     
  DWORD             dwBufferCount,   
  const IPSocketAddress&  peer,
  DWORD				timeout, 
  DWORD				wait_slice,
  DWORD             dwFlags)
{
	if(dwBufferCount>64) return 1;

	if(wait_slice<1 || timeout<1) return 2;

	BytesActual=0;

	int g=0,r=0;
	DWORD z=0;
	int k=0;
	DWORD period=0;	
	WSABUF local_buf_array[64];
	DWORD data_size=0;

	for(int i=0;i<(int)dwBufferCount;++i)
	{
		data_size+=lpBuffers[i].len;
		local_buf_array[i]=lpBuffers[i];
	}


	while(BytesActual<data_size)
	{
		for(int i=k;i<(int)dwBufferCount;++i)
		{
			if(z>=lpBuffers[i].len)
			{
				++k;
				z-=local_buf_array[i].len;
			}
			else break;
		}

		local_buf_array[k].buf+=z;
		local_buf_array[k].len-=z;

		z=0;

		g=send_to(z,&local_buf_array[k],dwBufferCount-k,peer,dwFlags);

		if(!g) 
		{
			BytesActual+=z;
			continue;
		}

		if(g>0) 
		{
			BytesActual+=z;
			r=3;
			break;
		}

		for(;;)
		{
			period+=wait_slice;

			if(period>timeout)
			{
				r=-1;
				break;
			}

			wait(wait_slice);

			BOOL success=get_result(z,FALSE);

			if(success) break;
		}

		BytesActual+=z;
	}

	return r;
}

int SocketOperation::receive_from_loop( 
  DWORD&			BytesActual,
  LPWSABUF          lpBuffers,                                     
  DWORD             dwBufferCount,  
  IPSocketAddress&	peer,
  DWORD				timeout, 
  DWORD				wait_slice,
  LPDWORD           lpdwFlags)
{
	if(dwBufferCount>64) return 1;

	if(wait_slice<1 || timeout<1) return 2;

	BytesActual=0;

	int g=0,r=0;
	DWORD z=0;
	int k=0;
	DWORD period=0;	
	WSABUF local_buf_array[64];
	DWORD data_size=0;

	for(int i=0;i<(int)dwBufferCount;++i)
	{
		data_size+=lpBuffers[i].len;
		local_buf_array[i]=lpBuffers[i];
	}


	while(BytesActual<data_size)
	{
		for(int i=k;i<(int)dwBufferCount;++i)
		{
			if(z>=lpBuffers[i].len)
			{
				++k;
				z-=local_buf_array[i].len;
			}
			else break;
		}

		local_buf_array[k].buf+=z;
		local_buf_array[k].len-=z;

		z=0;

		g=receive_from(z,&local_buf_array[k],dwBufferCount-k,peer,lpdwFlags);

		if(!g) 
		{
			BytesActual+=z;
			continue;
		}

		if(g>0) 
		{
			BytesActual+=z;
			r=3;
			break;
		}

		for(;;)
		{
			period+=wait_slice;

			if(period>timeout)
			{
				r=-1;
				break;
			}

			wait(wait_slice);

			BOOL success=get_result(z,FALSE);

			if(success) break;
		}

		BytesActual+=z;
	}

	return r;
}


	// SocketWaitableCollection

void SocketWaitableCollection::copy(const SocketWaitableCollection& z)
{
	size=z.size;
	for(int i=0;i<size;++i)
		handles[i]=z.handles[i];
}


int SocketWaitableCollection::add(const SocketEvent& z)
{
	if (size >= WSA_MAXIMUM_WAIT_EVENTS)
        return 1;

    handles[size++] = z.get_handle();

	return 0;
}

int SocketWaitableCollection::add(const SocketWaitableCollection & z)
{
	if(size+z.size>WSA_MAXIMUM_WAIT_EVENTS)
		return 1;

    for (int i = 0; i < z.size; i++) 
		handles[size++] = z.handles[i];

	return 0;
}  


int monitor(SocketEvent& signal,const Socket& socket,long event_flags)
{
	return ::WSAEventSelect(socket.get_handle(),signal.get_handle(),event_flags);
}

	// wait functions

DWORD wait(const SocketEvent& z,DWORD milliseconds,BOOL alertable)
{
	SocketWaitableCollection c;
	c.add(z);
	return wait(c,FALSE,milliseconds,alertable);
}

DWORD wait(const SocketWaitableCollection& z, BOOL bWaitAll, DWORD milliseconds,BOOL alertable)
{
    
    if (z.size == 0) 
        return WSA_WAIT_FAILED;
    
    return ::WSAWaitForMultipleEvents ( z.size, z.handles, bWaitAll, milliseconds,alertable);
}


#endif // _WIN32_WINNT >= 0x0400


DWORD wait_receive_ready(Socket& s,DWORD milliseconds)
{
	timeval t;
	t.tv_sec=milliseconds/1000;
	t.tv_usec=(milliseconds-t.tv_sec*1000)*10; // microseconds

	fd_set r,we;

	r.fd_count=1;
	we.fd_count=0;

	r.fd_array[0]=s.get_handle();

	int n=select(0,&r,&we,&we,&t);

	if(n==1)
		return 0;	// ready

	if(n==0)
		return 1;	// timeout

	return 2;		// error
}

	// IP_host

int IP_host(StrBuffer& n,IPAddress& a, int i)
{
	hostent *hp;  
	char name[1000];
	
	if ( gethostname(name, 1000) != 0 )
		return 1;
	
	if ( !(hp = gethostbyname(name)) )
		return 2;

	n.set(name);

	memcpy ( &a.address, hp->h_addr_list[i], hp->h_length);

	return 0;
}