#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); } unsigned int getclientsock(void){ unsigned int s; struct sockaddr_un remote; s=socket(AF_UNIX,SOCK_STREAM,0); if(s==(unsigned int)-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_server(int numargs,char **args){ //args == argv+1, numargs == argc-1 vector<pair<time_t,string>> waypoints; if(numargs){ stringstream ss; for(int i=0;i<numargs;i++)ss<<(i?" ":"")<<args[i]; string line=ss.str(); cout<<"Timer description: "<<line<<endl; addwaypoint(waypoints,line.c_str()); } else 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==(unsigned int)-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; } } } 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(int numargs,char **args){ unsigned int s=getclientsock(); string line; if(numargs){ stringstream ss; for(int i=0;i<numargs;i++)ss<<(i?" ":"")<<args[i]; line=ss.str(); cout<<"Waypoint description: "<<line<<endl; } else { cout<<"Enter the description for this waypoint: "<<flush; 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(argc-1,argv+1); } else if(strendequ(argv[0],"timerstatus")){ act_client_timerstatus(); } else if(strendequ(argv[0],"timer")||strendequ(argv[0],"timerstart")||strendequ(argv[0],"timerserver")){ act_server(argc-1,argv+1); } else { cerr<<"Unknown calling name \""<<argv[0]<<"\"!"<<endl; return 1; } return 0; }