|
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 ********************************************************************/