diff options
Diffstat (limited to 'timerserver.cpp')
-rw-r--r-- | timerserver.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/timerserver.cpp b/timerserver.cpp new file mode 100644 index 0000000..df5389a --- /dev/null +++ b/timerserver.cpp @@ -0,0 +1,273 @@ +#include <iostream> +#include <fstream> +#include <string> +#include <vector> +#include <sstream> +#include <cstdlib> +#include <cstring> +#include <unistd.h> +#include <fcntl.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/un.h> + +#define SOCKET_PATH "/tmp/._timer_sock.socket" + +using namespace std; + +enum MessageType { + MT_STOP, + MT_STATUS, + MT_WAYPOINT +}; + +void recvall(unsigned int sock,char *buf,int num){ + int ret,acc=0; + do { + ret=recv(sock,buf+acc,num-acc,0); + if(ret==-1){ + perror("recv"); + exit(1); + } + if(ret==0){ //peer closed its side + close(sock); + exit(1); + } + acc+=ret; + } while(acc<num); +} + +void sendall(unsigned int sock,const char *buf,int num){ + int ret,acc=0; + do { + ret=send(sock,buf+acc,num-acc,0); + if(ret==-1){ + perror("send"); + exit(1); + } + acc+=ret; + } while(acc<num); +} +void sendall(unsigned int sock,const char *buf){ + sendall(sock,buf,strlen(buf)); +} + +void addwaypoint(vector<pair<time_t,string>> &waypoints,string desc){ + time_t tim=time(NULL); + waypoints.push_back({tim,desc}); + char *buf=ctime(&tim); + buf[strlen(buf)-1]='\0'; + cout<<"Added waypoint on "<<buf<<": "<<desc<<endl; +} + +unsigned int parseUInt32BE(const unsigned char *buf){ + return (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3]; +} +unsigned int parseUInt32BE(const char *buf){ + return parseUInt32BE((unsigned char*)buf); +} + +bool strendequ(const char *str,const char *suffix){ + const int len1=strlen(str),len2=strlen(suffix); + return len2>len1?false:strcmp(str+len1-len2,suffix)==0; +} + +void unlink_socketpath(void){ + unlink(SOCKET_PATH); +} + +void sendwaypoints(unsigned int sock,vector<pair<time_t,string>> &waypoints){ + stringstream ss; + for(pair<time_t,string> &p : waypoints){ + char *buf=ctime(&p.first); + buf[strlen(buf)-1]='\0'; + ss<<buf<<": "<<p.second<<endl; + } + string s=ss.str(); + int len=s.size(); + char buf[4]; + buf[0]=0xff&(len>>24); + buf[1]=0xff&(len>>16); + buf[2]=0xff&(len>>8); + buf[3]=0xff&len; + sendall(sock,buf,4); + sendall(sock,s.c_str(),len); +} + +void act_server(void){ + vector<pair<time_t,string>> waypoints; + addwaypoint(waypoints,"Start"); + pid_t pid=fork(); + if(pid==-1){ + perror("fork"); + exit(1); + } + if(pid!=0){ //parent + cerr<<"Forking into background."<<endl; + exit(0); + } + //child, becoming a daemon + setsid(); + close(0); close(1); close(2); + open("/dev/null",O_RDONLY); + open("/dev/null",O_WRONLY); + open("/dev/null",O_WRONLY); + //now we're a daemon. Yay! + atexit(unlink_socketpath); + unsigned int s,s2; + s=socket(AF_UNIX,SOCK_STREAM,0); + if(s==-1){ + perror("socket"); + exit(1); + } + struct sockaddr_un local; + local.sun_family=AF_UNIX; + strcpy(local.sun_path,SOCKET_PATH); + if(::bind(s,(struct sockaddr*)&local,strlen(local.sun_path)+1+sizeof(local.sun_family))==-1){ + perror("bind"); + exit(1); + } + listen(s,2); + while(true){ + struct sockaddr_un remote; + unsigned int len=sizeof(struct sockaddr_un); + s2=accept(s,(struct sockaddr*)&remote,&len); + char buf[256]; + recvall(s2,buf,4); + unsigned int msglen=parseUInt32BE(buf); + if(msglen>256){ + close(s2); + continue; + } + recvall(s2,buf,msglen); + switch(buf[0]){ + case MT_STOP: + addwaypoint(waypoints,"Stop"); + buf[0]=1; + sendall(s2,buf,1); + sendwaypoints(s2,waypoints); + close(s2); + close(s); + exit(0); + case MT_STATUS: + buf[0]=1; + sendall(s2,buf,1); + sendwaypoints(s2,waypoints); + break; + case MT_WAYPOINT: + addwaypoint(waypoints,string(buf+1,msglen-1)); + buf[0]=1; + sendall(s2,buf,1); + break; + default: + buf[0]=0; + sendall(s2,buf,1); + break; + } + } +} + +unsigned int getclientsock(void){ + unsigned int s; + struct sockaddr_un remote; + s=socket(AF_UNIX,SOCK_STREAM,0); + if(s==-1){ + perror("socket"); + exit(1); + } + remote.sun_family=AF_UNIX; + strcpy(remote.sun_path,SOCKET_PATH); + if(connect(s,(struct sockaddr*)&remote,strlen(SOCKET_PATH)+1+sizeof(remote.sun_family))==-1){ + perror("connect"); + exit(1); + } + return s; +} + +void act_client_timerstop(void){ + unsigned int s=getclientsock(); + char buf[5]; + buf[0]=0; + buf[1]=0; + buf[2]=0; + buf[3]=1; + buf[4]=MT_STOP; + sendall(s,buf,5); + recvall(s,buf,1); + if(buf[0]!=1){ + cerr<<"Didn't receive acknowledgement from server!"<<endl; + exit(1); + } + recvall(s,buf,4); + int len=parseUInt32BE(buf); + char msg[len+1]; + recvall(s,msg,len); + msg[len]='\0'; + cout<<"Results:"<<endl; + cout<<msg<<flush; +} + +void act_client_timerstatus(void){ + unsigned int s=getclientsock(); + char buf[5]; + buf[0]=0; + buf[1]=0; + buf[2]=0; + buf[3]=1; + buf[4]=MT_STATUS; + sendall(s,buf,5); + recvall(s,buf,1); + if(buf[0]!=1){ + cerr<<"Didn't receive acknowledgement from server!"<<endl; + exit(1); + } + recvall(s,buf,4); + int len=parseUInt32BE(buf); + char msg[len+1]; + recvall(s,msg,len); + msg[len]='\0'; + cout<<"Status:"<<endl; + cout<<msg<<flush; + cout<<"Now:"<<endl; + time_t tim=time(NULL); + cout<<ctime(&tim)<<flush; +} + +void act_client_timerwaypoint(void){ + unsigned int s=getclientsock(); + cout<<"Enter the description for this waypoint: "<<flush; + string line; + getline(cin,line); + const int buflen=4+1+line.size(); + char buf[buflen]; + buf[0]=0; + buf[1]=0; + buf[2]=0; + buf[3]=buflen-4; + buf[4]=MT_WAYPOINT; + memcpy(buf+5,line.c_str(),line.size()); + sendall(s,buf,buflen); + recvall(s,buf,1); + if(buf[0]!=1){ + cerr<<"Didn't receive acknowledgement from server!"<<endl; + exit(1); + } + cout<<"Waypoint added."<<endl; +} + +int main(int argc,char **argv){ + ios_base::sync_with_stdio(false); + if(strendequ(argv[0],"timerstop")){ + act_client_timerstop(); + } else if(strendequ(argv[0],"timerwaypoint")||strendequ(argv[0],"timerwp")){ + act_client_timerwaypoint(); + } else if(strendequ(argv[0],"timerstatus")){ + act_client_timerstatus(); + } else if(strendequ(argv[0],"timer")||strendequ(argv[0],"timerserver")){ + act_server(); + } else { + cerr<<"Unknown calling name \""<<argv[0]<<"\"!"<<endl; + return 1; + } + return 0; +} |