// Common, group Communication
// Copyright 2002 Alexander Liss
// Declarations of classes
// IPAddress, IPSocketAddress, ASocketBuffer,
// ASocket, ASocketNonBlocking, ASocketBlocking,
// ASocketNonBlockingPtr, ASocketBlockingPtr, ASocketListener
//
#ifndef __ASOCKET_H__
#define __ASOCKET_H__
// handle SIGPIPE signal, which is sent to the process in an attempt to send
// with a closed socket, this signal terminates the process by default
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
// data conversion
// network's byte order is big-endian
inline unsigned long host2net(unsigned long host_value){return htonl(host_value);}
inline unsigned short host2net(unsigned short host_value){return htons(host_value);}
inline unsigned long net2host(unsigned long net_value){return ntohl(net_value);}
inline unsigned short net2host(unsigned short net_value){return ntohs(net_value);}
// internet protocol address
struct IPAddress
{
IPAddress(unsigned long z=INADDR_ANY):address(host2net(z)){}
int set_address(unsigned long z);
int get_dotted(char * buf,unsigned limit)const;
int put_dotted(const char * buf);
int put(const sockaddr&);
protected:
unsigned long address; // bytes in a network order, will be different for IP5 and IP6
};
// address and port
struct IPSocketAddress: public IPAddress
{
IPSocketAddress(unsigned short p=0,unsigned long address=INADDR_ANY):
IPAddress(address),port(host2net(p)){}
IPSocketAddress(const IPAddress& z):IPAddress(z),port(0){}
int set_port(unsigned short z){port=host2net(z); return 0;}
int get(sockaddr&)const;
int put(const sockaddr&);
protected:
unsigned short port; // bytes in a network order
};
// recovery step callback, usually yield or sleep,
// until timeout "millisecond" is exhosted
typedef void (*SOCKET_RECOVERY)(unsigned& milliseconds,int& count);
// ASocket
// when status is zero, returns zero on success or errno
class ASocket
{
ASocket(const ASocket&); // forbidden
ASocket& operator=(const ASocket&); // forbidden
public:
enum Marker{none}; // used by listener only
int status;
// creates a socket
ASocket(int type=SOCK_STREAM);
// takes control of previously created handle,
// should be used by a listener only
ASocket(int h,Marker):status(0),handle(h)
{if(handle<0)status=1;}
virtual ~ASocket();
int get_handle()const{return handle;}
int get_own_address(IPSocketAddress& );
int get_peer_address(IPSocketAddress& );
// socket options
int set_keep_alive();
int set_TCP_nodelay();
// works with close(), ignored by shutdown()
int linger(int seconds);
int get_send_buffer_size(int & size);
// do not call on connected socket
int set_send_buffer_size(int size);
int get_receive_buffer_size(int & size);
// do not call on connected socket
int set_receive_buffer_size(int size);
int set_option(int name,const void *value,int value_len)
{return ::setsockopt(handle,SOL_SOCKET,name,value,value_len);}
int get_option(int name,void *value,int *value_len)
{return ::getsockopt(handle,SOL_SOCKET,name,value,value_len);}
int set_TCP_option(int name,const void *value,int value_len)
{return ::setsockopt(handle,IPPROTO_TCP,name,value,value_len);}
int get_TCP_option(int name,void *value,int *value_len)
{return ::getsockopt(handle,IPPROTO_TCP,name,value,value_len);}
// signalling, should not be used
// SIGURG will be sent to this process when OOB data arrives
int set_OOB_signalling();
// SIGIO will be sent to this process at IO event (data in, out buffer ready) occurs
int set_asynchronous();
// operations
int bind(const IPSocketAddress& own);
int connect(const IPSocketAddress& peer );
int reconnect();
// ignores linger()
int shutdown(int how=SHUT_RDWR){return ::shutdown(handle,how);}
// flags MSG_OOB or zero
int send(unsigned& sent, const void *buf,unsigned len,int flags=0);
// flags MSG_PEEK, MSG_OOB, (MSG_PEEK | MSG_OOB) or zero
int receive(unsigned& received, void *buf,unsigned limit,int flags=0);
// flags MSG_OOB or zero
int send_to(unsigned& sent,const void *buf,unsigned len,const IPSocketAddress& remote,int flags=0);
// flags MSG_OOB or zero
int receive_from(unsigned& received,void *buf,unsigned limit, IPSocketAddress& remote,int flags=0);
// use with specially allocated buffers coordinated with paging
int send( unsigned& sent, const msghdr *const buffers,int flags=0);
int receive( unsigned& received, msghdr *const buffers,int flags=0);
static bool can_recover(int error_number /*errno*/);
protected:
int handle;
IPSocketAddress peer; // for reconnect
};
// ASocketNonBlocking
class ASocketNonBlocking:public ASocket
{
ASocketNonBlocking(const ASocketNonBlocking&); // forbidden
ASocketNonBlocking& operator=(const ASocketNonBlocking&); // forbidden
public:
// creates a socket
ASocketNonBlocking(int type=SOCK_STREAM):ASocket(type)
{if(set_non_blocking()) status=2;}
// should be used by a listener only
ASocketNonBlocking(int h,ASocket::Marker m):ASocket(h,m)
{if(set_non_blocking()) status=2;}
virtual ~ASocketNonBlocking(){}
// following functions are called in a loop until "done"
// flags MSG_OOB or zero
int peek_step(bool& done,void *data, unsigned requested_size, int flags=0);
// called in a loop with the same buffer "data" until "done",
// accumulates data and updates "data_size"
int receive_step(bool& done,unsigned& data_size, void *data, unsigned size,int flags=0);
int send_step(bool& done,unsigned& data_size, const void *data,unsigned size,int flags=0);
// timeout and sleep_slice in milliseconds
// loops go to sleep for a sleep_slice, when processing can't be done
// both are blocking
int connect_loop(unsigned timeout,unsigned sleep_slice=10);
int send_loop(unsigned& sent,const void *buf,unsigned size,unsigned timeout,unsigned sleep_slice=10,int flags=0);
int receive_loop(unsigned& received, void *buf,unsigned size,unsigned timeout,unsigned sleep_slice=10,int flags=0);
// timeout in milliseconds
// loops wait on select(), when processing can't be done
// both are blocking
int send_loop2(unsigned& sent,const void *buf,unsigned size,unsigned timeout,int flags=0);
int receive_loop2(unsigned& received, void *buf,unsigned size,unsigned timeout,int flags=0);
private:
int set_non_blocking();
virtual void compiler_dummy();
};
// ASocketBlocking
class ASocketBlocking:public ASocket
{
ASocketBlocking(const ASocketBlocking&); // forbidden
ASocketBlocking& operator=(const ASocketBlocking&); // forbidden
public:
// creates a socket
ASocketBlocking(int type=SOCK_STREAM):ASocket(type),
recovery_timeout(0){}
// should be used by a listener only
ASocketBlocking(int h,ASocket::Marker m):ASocket(h,m),
recovery_timeout(0){}
virtual ~ASocketBlocking(){}
int set_recovery_timeout(unsigned milliseconds);
int send_loop(unsigned& sent,const void *buf,unsigned size,SOCKET_RECOVERY recovery=0,int flags=0);
int receive_loop(unsigned& received, void *buf,unsigned size,SOCKET_RECOVERY recovery=0,int flags=0);
private:
unsigned recovery_timeout;
virtual void compiler_dummy();
};
// ASocketNonBlockingPtr
// used as a base class, does not own socket
class ASocketNonBlockingPtr
{
public:
ASocketNonBlockingPtr():socket(0){}
ASocketNonBlockingPtr(const ASocketNonBlockingPtr& z):socket(z.socket){}
ASocketNonBlockingPtr(ASocketNonBlocking& z):socket(&z){}
virtual ~ASocketNonBlockingPtr(){}
ASocketNonBlockingPtr& operator==(const ASocketNonBlockingPtr& z)
{if(this!=&z) socket=z.socket; return *this;}
ASocketNonBlocking& get_socket(){return *socket;}
int set_socket(ASocketNonBlocking& z){socket=&z;return 0;}
bool is_set(){return socket!=0 && !socket->status;}
protected:
ASocketNonBlocking* socket;
private:
virtual void compiler_dummy0();
};
// ASocketBlockingPtr
// used as a base class, does not own socket
class ASocketBlockingPtr
{
public:
ASocketBlockingPtr():socket(0){}
ASocketBlockingPtr(const ASocketBlockingPtr& z):socket(z.socket){}
ASocketBlockingPtr(ASocketBlocking& z):socket(&z){}
virtual ~ASocketBlockingPtr(){}
ASocketBlockingPtr& operator==(const ASocketBlockingPtr& z)
{if(this!=&z) socket=z.socket; return *this;}
ASocketBlocking& get_socket(){return *socket;}
int set_socket(ASocketBlocking& z){socket=&z;return 0;}
bool is_set(){return socket!=0 && !socket->status;}
protected:
ASocketBlocking* socket;
private:
virtual void compiler_dummy0();
};
// ASocketListener
// does not own its listening socket
class ASocketListener: public ASocketBlockingPtr
{
ASocketListener(const ASocketListener&);
ASocketListener& operator==(const ASocketListener&);
public:
ASocketListener(){}
ASocketListener(ASocketBlocking& s):ASocketBlockingPtr(s){}
int listen(int backlog=SOMAXCONN);
// need to delete this object, when done with it
// sets non-blocking
ASocketNonBlocking * new_non_blocking_connection(IPAddress& peer );
// same properties as listener
ASocketBlocking * new_blocking_connection(IPAddress& peer );
private:
virtual void compiler_dummy1();
};
// functions
// ip address # n, requires shared library !
int IP_host(char * host_name,unsigned name_size_limit,IPAddress& address, int n=0);
// sleep 0.01 sec. and reduce milliseconds
void ASocketStdRecoveryStep(unsigned& milliseconds,int& );
#endif