// 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;
}