![]() ![]() ![]() ![]() ![]() Next: Client: pclient.h Up: Program Previous: Program   Contents   Index |
/*******************************************************************************/ /* pserver.c - server process for PeStO file server */ /* */ /* Written by: Michael G. S\o rensen, September-November 1996, DIKU */ /*******************************************************************************/ /* BEGIN include ***************************************************************/ #include "pesto.h" /* include file for PeStO client and PeStO server */ #include "ppserver.h" /* include file for PeStO server */ /* END include *****************************************************************/ /* BEGIN globals ***************************************************************/ int sd1,sd2; /* socket descriptors */ struct sockaddr_in sa1,sa2; /* socket addresses (on the Internet) */ long t; struct linger l; /* END globals *****************************************************************/ /* BEGIN PeStO file server *****************************************************/ void p_server() { char host[HOSTNAME_MAX]; /* name of host */ struct hostent *hp; /* result of hostname lookup */ pmessage buf; /* message buffer */ struct stat stbuf; /* file status buffer */ int locked,readlocked,writelocked; long ret,wet,rlet,wlet; int fd; int flag; char lockname[LOCKNAME_MAX]; char logstr[1000]; char *inet_ntoa(); close_sock(sd1); if((hp=gethostbyaddr((char *)&sa2.sin_addr,sizeof(struct in_addr),sa2.sin_family))==NULL) strcpy(host,inet_ntoa(sa2.sin_addr)); else strcpy(host,hp->h_name); #ifdef LOG time(&t); sprintf(logstr,"Startup from %s port %u at %s",host,ntohs(sa2.sin_port),ctime(&t)); plog(logstr); #endif l.l_onoff=1; l.l_linger=1; if(setsockopt(sd2,SOL_SOCKET,SO_LINGER,&l,sizeof(struct linger))==-1) { pso_errno=PSO_EERROR; close_sock(sd2); exit(NOT_OK); } if(recv(sd2,&buf,sizeof(buf),0)!=sizeof(buf)) { pso_errno=PSO_EERROR; close_sock(sd2); exit(NOT_OK); } #ifdef LOG sprintf(logstr,"Request from client initiated %s",ctime(&(buf.t))); plog(logstr); #endif /* handle the request and give a reply */ switch(buf.request){ case READ_OPEN: case WRITE_OPEN: /* BEGIN open for READING or WRITING *************************************/ /* Possible returns are: buf.status is set to NOT_OK or OK, and if OK then buf.request is set to CONSISTENT, INCONSISTENT, NOTFOUND, ISLOCKED or WASLOCKED. If CONSISTENT then buf.ct and buf.cct are set. If INCONSISTENT then buf.mt and buf.cct are set. If ISLOCKED or WASLOCKED then also CONSISTENT if buf.ct is equal to buf.ct else INCONSISTENT. If buf.request is READ_OPEN then the content of buf.wet is ignored, and similarly the content of buf.ret is ignored if buf.request is WRITE_OPEN. */ #ifdef LOG if(buf.request==READ_OPEN) sprintf(logstr,"READ_OPEN %s\n",buf.name); else sprintf(logstr,"WRITE_OPEN %s\n",buf.name); plog(logstr); #endif buf.status=OK; if(stat(buf.name,&stbuf)==-1) /* check existense and status of file */ { if(errno==ENOENT) /* No such file or directory */ buf.request=NOTFOUND; else buf.status=NOT_OK; } else { if((locked=read_lock(buf.name,host,&ret,&wet,&fd))==NOT_OK) buf.status=NOT_OK; else { time(&t); readlocked=(locked&&ret>=t); writelocked=(locked&&wet>=t); buf.cct=t; /* set consistency check time for file */ if(stbuf.st_mtime==buf.mt) /* check modification time of file */ { flag=CONSISTENT; buf.ct=t; } else { flag=INCONSISTENT; buf.mt=stbuf.st_mtime; } if(writelocked||(readlocked&&buf.request==WRITE_OPEN)) buf.request=ISLOCKED; else { if((buf.request==READ_OPEN&&buf.ret<t)|| (buf.request==WRITE_OPEN&&buf.wet<t)) /* no locking required */ { if((buf.request==READ_OPEN&&buf.ret>0L)|| (buf.request==WRITE_OPEN&&buf.wet>0L)) buf.request=NOTLOCKED; else buf.request=flag; } else /* locking required */ { /* At this point we know that the client wishes to put a readlock on the file. But that will only be the case if neither a read- nor a writelock was previously obtained. Still we might have an out-dated (timeout'ed) entry in the lock(file). */ if((locked=lookup_lock(fd,host,&ret,&wet))==NOT_OK) buf.status=NOT_OK; else { if(locked&&(wet>=t||ret>=t)) /* Note, that this should not be! Here we have a client asking for a lock although the client already has one. This could be the result of unsynchronized clocks. */ buf.status=NOT_OK; else { if(buf.request==READ_OPEN) { rlet=buf.ret; wlet=0L; } else { wlet=buf.wet; rlet=0L; } if(locked) { if(update_lock(fd,host,rlet,wlet)==NOT_OK) buf.status=NOT_OK; else buf.request=WASLOCKED; } else { if(write_lock(fd,host,rlet,wlet)==NOT_OK) buf.status=NOT_OK; else buf.request=WASLOCKED; } } } } } if(unlock_file(fd)==NOT_OK) buf.status=NOT_OK; } } psend(sd2,&buf); break; /* END open for READING or WRITING ***************************************/ /* ... */ default: /* BEGIN request UNKNOWN *************************************************/ /* Returns buf.status set to NOT_OK. */ #ifdef LOG sprintf(logstr,"UNKNOWN\n"); plog(logstr); #endif buf.status=NOT_OK; psend(sd2,&buf); break; /* END request UNKNOWN ***************************************************/ } #ifdef LOG time(&t); sprintf(logstr,"Completed %s port %u at %s",host,ntohs(sa2.sin_port),ctime(&t)); plog(logstr); #endif close_sock(sd2); } /* END PeStO file server *******************************************************/ /* BEGIN main ******************************************************************/ void main() { struct hostent *hp; /* result of hostname lookup */ int len; /* address length */ char localhost[HOSTNAME_MAX]; #ifndef SYSV5 #ifndef LINUX int fd; int sig_child(); #endif #endif memset((char *)&sa1,0,sizeof(struct sockaddr_in)); memset((char *)&sa2,0,sizeof(struct sockaddr_in)); if(gethostname(localhost,HOSTNAME_MAX)==-1) { pso_errno=PSO_EERROR; exit(NOT_OK); } if((hp=gethostbyname(localhost))==NULL) { pso_errno=PSO_EERROR; exit(NOT_OK); } if((sa1.sin_family=hp->h_addrtype)!=AF_INET) { pso_errno=PSO_EBADADDRESS; exit(NOT_OK); } sa1.sin_port=ntohs(PORT); if((sd1=socket(AF_INET,SOCK_STREAM,0))==-1) { pso_errno=PSO_EERROR; exit(NOT_OK); } if(bind(sd1,(void *)&sa1,sizeof(struct sockaddr_in))==-1) { pso_errno=PSO_EERROR; close_sock(sd1); exit(NOT_OK); } if(listen(sd1,10)==-1) { pso_errno=PSO_EERROR; close_sock(sd1); exit(NOT_OK); } #ifdef SYSV5 setpgrp(); #else #ifndef LINUX setpgrp(0,getpid()); if((fd=open("/dev/tty",O_RDWR))>=0) { ioctl(fd,TIOCNOTTY,(char *)NULL); /* loose controlling tty */ close(fd); } #else setpgrp(); #endif #endif switch(fork()) { case -1: pso_errno=PSO_EERROR; close_sock(sd1); exit(NOT_OK); case 0: /* child process */ fclose(stdin); fclose(stderr); #ifdef SYSV5 signal(SIGCLD,SIG_IGN); #else #ifndef LINUX signal(SIGCLD,sig_child); #else signal(SIGCLD,SIG_IGN); #endif #endif for(;;) { len=sizeof(struct sockaddr_in); if((sd2=accept(sd1,(void *)&sa2,&len))==-1) { pso_errno=PSO_EERROR; close_sock(sd1); exit(NOT_OK); } switch(fork()) { case -1: pso_errno=PSO_EERROR; close_sock(sd1); close_sock(sd2); exit(NOT_OK); case 0: /* child process */ p_server(); exit(OK); default: /* parent process */ close_sock(sd2); } } default: /* parent process */ close_sock(sd1); exit(OK); } } /* END main ********************************************************************/