/* * Sockets-based client/server class library header file, * by Alex Belits * * This source/code is public free; you can distribute it and/or modify * it under terms of the GNU General Library Public License (published * by the Free Software Foundation) either version two of this License, * or any later version. * */ #ifndef SOCKOBJ #define SOCKOBJ #include #include #include #include #include #include #include #include #include #include #include #ifdef IRIX #include "irix-fix.h" #endif #define POLLOUT_ALLOWED 0100 /* "flag", allowing POLLOUT set */ #ifdef PSEUDOPOLL #include "pseudopoll.h" #else #ifdef DIGITAL #include #else #include #endif #endif #if defined(AIX4)||defined (GLIBC) #define sockaddr_size_type size_t #else #define sockaddr_size_type int #endif /**************************************** *** common daemon global variables ****************************************/ extern int logfd; /* log file descriptor for daemon */ extern int tmplogfd; /* temporary additional log fd */ extern pid_t g_pid; /* daemon pid */ /**************************************** *** fatal error message (stderr may be *** directed to /dev/null after daemon *** installation, so it will be useless) ****************************************/ void fatal(char *fmt,...); /**************************************** *** log error message ****************************************/ void errlog(char *fmt,...); /**************************************** *** log message ****************************************/ void log(char *fmt,...); /**************************************** *** daemon cleanup function, executed *** after any kind of killing except *** SIGKILL ****************************************/ void cleanup(SIGARGS); /**************************************** *** daemon "function 1", useless ****************************************/ void usrfn0(SIGARGS); /**************************************** *** daemon "function 2", useless ****************************************/ void usrfn1(SIGARGS); /**************************************** *** child finishing driver function ****************************************/ void mywait(SIGACTARGS); /**************************************** *** daemon installer ****************************************/ int daemonize(char *cmd,char *logfilename,int* handles,int nhandles,void (*doexit)(void)); /* End of common daemon functions */ /* */ /**************************************** *** server-specific global variables ****************************************/ extern char hostname[256]; /* host name */ extern int errno1; /* additional errno */ extern int critical; /* critical section flag */ extern int global_nconnections; /* number of connections */ extern int global_npipes; /* number of pipes and sockets to processes */ /**************************************** *** global hostname setup ****************************************/ int hostsetup(void); /* */ class ServerSocket; class Wheel; class ServerConnection; class ServerConnectionApp; class WriteBuffer; class ServerProcess; class ClientConnection; /**************************************** *** ServerSocket class ****************************************/ class ServerSocket{ private: int maxclients; __s32 localaddr; struct sockaddr_in myaddress; int h; public: int status; char *name; int port; Wheel *wheel; int indexforwheel; int handleindexforwheel; ServerSocket(char *xname,int xport,int xmaxclients,__s32 xlocaladdr=0); //constructor virtual ~ServerSocket(void); //destructor /**************************************** *** get handle ****************************************/ inline int gethandle(void){ return h; } virtual void emptyfn(ServerConnection *client); virtual void connectfn(ServerConnection *client); virtual void disconnectfn(ServerConnection *client); virtual void splitfn(ServerConnection *client,ServerProcess *process); virtual void splitparentfn(ServerConnection *client,ServerProcess *process); virtual void unsplitfn(ServerConnection *client,ServerProcess *process); virtual void afterunsplitfn(ServerConnection *client,ServerProcess *process); virtual int prioritydatafn(ServerConnection *client); virtual int datafn(ServerConnection *client); virtual int pipedatafn(ServerConnection *client,ServerProcess *process); virtual int pipeprioritydatafn(ServerConnection *client,ServerProcess *process); }; /**************************************** *** ServerProcess class ****************************************/ enum{ITSELF,PARENT}; class ServerProcess{ private: int whoami; pid_t pid; public: int destr; Wheel *wheel; int closeonexit; int nevercloseonexit; int indexforwheel; int buffsize; ServerConnection *clientconnection; WriteBuffer *clientbuffer; int writehandle; int readhandle; int writehandlepos; int readhandlepos; ServerProcess(Wheel *xwheel,int i,int xbuffsize,int keeppipes,int xcloseonexit,int nevercloseonexit=0); // constructor virtual ~ServerProcess(void); // destructor virtual void mainfunction(void); // main user function inline pid_t getprocid(void){ return pid; } int killme(int sig=SIGTERM); }; /**************************************** *** ServerConnection class ****************************************/ class ServerConnection{ private: struct sockaddr *hisaddress; sockaddr_size_type hisaddresslength; public: int h; int destr; ServerConnectionApp *app; ServerSocket *socket; ServerConnection*** passingwritebuffers; int npassingwritebuffers; Wheel *wheel; int indexforwheel; ServerConnection(ServerSocket *xsocket,ClientConnection *xclient=NULL); // constructor ServerConnection(int xh,struct sockaddr *xhisadress,int xhisaddresslength,ServerSocket *xsocket); // constructor for // existing connections virtual ~ServerConnection(void); // destructor /**************************************** *** get handle ****************************************/ inline int gethandle(void){ return h; } /**************************************** *** get address ****************************************/ inline struct sockaddr *getaddress(void){ return hisaddress; } }; /**************************************** *** ServerConnectionApp class ****************************************/ class ServerConnectionApp{ public: ServerConnection *connection; ServerConnectionApp(ServerConnection *xconnection=NULL); // constructor virtual ~ServerConnectionApp(void); // destructor }; /**************************************** *** WriteBuffer class ****************************************/ extern int _bcounter; // global buffers counter class WriteBuffer{ private: char *wptr; char *rptr; char *buff; int size; int nbytes; ServerConnection **connections; int connectionssize; int connectionshead; int connectionstail; int connectionsinbuffer; char **freebuffers; struct iovec *externalbuffers; int nexternalbuffers; int maxexternalbuffers; int totalextbufferssize; int closeonexit; int startpollonexit; public: WriteBuffer(int xsize,int nconnections){ if(xsize) buff=(char*)malloc(xsize); else buff=NULL; size=xsize; nbytes=0; closeonexit=0; startpollonexit=0; rptr=buff; wptr=buff; freebuffers=NULL; externalbuffers=NULL; nexternalbuffers=0; maxexternalbuffers=0; totalextbufferssize=0; connectionssize=0; connectionshead=0; connectionstail=0; connectionsinbuffer=0; if(nconnections){ connections=(ServerConnection**) malloc(nconnections*sizeof(ServerConnection*)); if(connections){ connectionssize=nconnections; } }else connections=NULL; _bcounter++; #ifdef DEBUG log("WriteBuffer::WriteBuffer: %d buffers",_bcounter); #endif if(xsize&&!buff){ size=-1; return; } return; } inline int AddConnectionHandle(int index,ServerConnection *connection){ if(!connections) return -1; int i; connections[index]=connection; if(connection){ for(i=0;inpassingwritebuffers;i++){ if(!connections[index]->passingwritebuffers[i]){ connections[index]->passingwritebuffers[i]=connections+index; return 0; } } connections[index]=NULL; return 1; } return 0; } inline void RemoveConnectionHandle(int index){ if(!connections) return; if(!connections[index]) return; int i; for(i=0;inpassingwritebuffers;i++){ if(connections[index]->passingwritebuffers[i]==connections+index){ #ifdef DEBUG log("Handle removed"); #endif connections[index]->passingwritebuffers[i]=NULL; connections[index]=NULL; return; } } log("Error: can't remove handle, inconsistent buffers!"); } inline int PutConnection(ServerConnection *connection){ if(connectionsinbuffer>=connectionssize) return -1; if(AddConnectionHandle(connectionshead,connection)) return -1; connectionshead++; if(connectionshead>=connectionssize) connectionshead=0; connectionsinbuffer++; return 0; } inline ~WriteBuffer(void){ int i; if(connections){ while(connectionsinbuffer){ if(connections[connectionstail]){ RemoveConnectionHandle(connectionstail); } connectionstail++; connectionsinbuffer--; if(connectionstail>=connectionssize) connectionstail=0; } free(connections); } if(buff){ free(buff); } if(freebuffers){ for(i=0;il1) l=l1; if(wptr+l>buff+size){ l1=size-(wptr-buff); return put(s,l1)+put(s+l1,l-l1); }else{ memcpy(wptr,s,l); nbytes+=l; wptr+=l; if(wptr>=buff+size) wptr=buff; return l; } } int writeout(int h); // send data from buffer void empty(void); // empty buffer /**************************************** *** query amount of data in buffer ****************************************/ inline int query(void){ return nbytes+totalextbufferssize; } /**************************************** *** get buffer size ****************************************/ inline int getsize(void){ return size+totalextbufferssize; } int resize(int xsize); // resize buffer /**************************************** *** set close-on-exit ****************************************/ inline void setcloseonexit(int xcloseonexit){ closeonexit=xcloseonexit; } /**************************************** *** get close-on-exit ****************************************/ inline int getcloseonexit(void){ return closeonexit; } /**************************************** *** set start-poll-on-exit ****************************************/ inline void setstartpollonexit(int xstartpollonexit){ startpollonexit=xstartpollonexit; } /**************************************** *** get start-poll-on-exit ****************************************/ inline int getstartpollonexit(void){ return startpollonexit; } }; /**************************************** *** Wheel class ****************************************/ class Wheel{ private: pid_t pid; struct pollfd *fdarray; int *pollout_allowed; ServerSocket **sockets; ServerProcess **processes; ServerProcess **readhandlepositions; WriteBuffer **buffers; ServerConnection **clients; public: ServerProcess *current_process; int lflag; int fdarraysize; int socketarraysize; int buffsize; int nindex; Wheel(int nsockets,int nclients,int xbuffsize); // constructor ~Wheel(void); // destructor void dropeveryone(void); // drop everyone void onepass(void); // one pass void mainloop(void); // main program loop inline void setreadhandle(ServerProcess *rprocess,int readhandlepos){ if(readhandlepos<0||readhandlepos>=fdarraysize) return; readhandlepositions[readhandlepos]=rprocess; } /**************************************** *** remove pipes to server's process ****************************************/ inline int removepipes(int readhandlepos,int writehandlepos){ int r=-1; if(writehandlepos>=0){ if(fdarray[writehandlepos].fd>=0){ fdarray[writehandlepos].fd=-1; fdarray[writehandlepos].events=0; fdarray[writehandlepos].revents=0; pollout_allowed[writehandlepos]=0; if(writehandlepos+1==nindex){ nindex--; while(nindex>0&&fdarray[nindex-1].fd<0) nindex--; } #ifdef DEBUG log("Wheel::removepipes: deleting buffer at %d",writehandlepos); #endif delete buffers[writehandlepos]; buffers[writehandlepos]=NULL; r=0; } } if(readhandlepos>=0){ readhandlepositions[readhandlepos]=NULL; if(fdarray[readhandlepos].fd>=0){ fdarray[readhandlepos].fd=-1; fdarray[readhandlepos].events=0; fdarray[readhandlepos].revents=0; pollout_allowed[readhandlepos]=0; if(readhandlepos+1==nindex){ nindex--; while(nindex>0&&fdarray[nindex-1].fd<0) nindex--; } #ifdef DEBUG log("Wheel::removepipes: deleting buffer at %d",readhandlepos); #endif delete buffers[readhandlepos]; buffers[readhandlepos]=NULL; r=0; } } return r; } /**************************************** *** start polling ****************************************/ inline void startpolling(int i){ fdarray[i].events=POLLIN|POLLPRI; pollout_allowed[i]=1; fcntl(fdarray[i].fd,F_SETFL,FNDELAY); } /**************************************** *** stop polling ****************************************/ inline void stoppolling(int i){ fdarray[i].events=0; pollout_allowed[i]=0; } /**************************************** *** stop polling for input ****************************************/ inline void stoppollinput(int i){ fdarray[i].events&=~POLLIN; } void purgebuffer(int index); // purge buffer int flushbuffer(int index); // flush buffer int addserversocket(ServerSocket *s); // add server socket to wheel int addserverconnection(ServerConnection *s); // add server connection to wheel void removeserversocket(int i); // remove server socket from wheel int addnewhandle(int handle,int flags,int buffsize,int nconnections=0); // add handle and create buffer friend void cleanupserverdriver(SIGARGS); // signal driver - server cleanup /**************************************** *** get client connection by number ****************************************/ inline ServerConnection *getclientbynumber(int index){ return clients[index]; } /**************************************** *** get buffer by number ****************************************/ inline WriteBuffer *getbufferbynumber(int index){ return buffers[index]; } /**************************************** *** get process ****************************************/ inline ServerProcess *getprocess(int index){ return processes[index]; } /**************************************** *** set process ****************************************/ inline void setprocess(int index,ServerProcess *p){ processes[index]=p; } /**************************************** *** set client ****************************************/ inline void setclient(int index,ServerConnection *p){ clients[index]=p; } /**************************************** *** search for empty process slot ****************************************/ inline int searchempty(ServerProcess **array,int length){ int i; for(i=0;i=0){ if(index>=nindex) nindex=index+1; }else{ fdarray[index].events=0; fdarray[index].revents=0; if(index+1==nindex){ nindex--; while(nindex>0&&fdarray[nindex-1].fd<0) nindex--; } } } /**************************************** *** set events ****************************************/ inline void setevents(int index,int events){ fdarray[index].events=events&~POLLOUT_ALLOWED; pollout_allowed[index]=((events&POLLOUT_ALLOWED)==POLLOUT_ALLOWED); } friend class ServerProcess; }; extern Wheel *glob_wheel; // global wheel pointer /* */ /**************************************** *** client ****************************************/ class ClientConnection{ int resolved; public: int h; char *name; int port; int localport; __s32 localaddr; struct sockaddr_in address; ClientConnection(char *xname,int xport,int xlocalport=0,__s32 xlocaladdr=0); ~ClientConnection(void); int lookupname(char *xname=NULL); int connecttoserver(char *xname=NULL,int xport=-1); int disconnectfromserver(void); }; #endif /* End of library functions */