|
Next: Examples Up: Program Previous: Server: pserver.c   Contents   Index |
/******************************************************************************/
/* pclient.h - client process(es) 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 "ppclient.h" /* include file PeStO client */
/* END include ****************************************************************/
/* BEGIN library subroutines **************************************************/
FILE *p_open(name,mode,tb)
char *name; /* pathname */
char *mode; /* filemode */
int tb; /* time bound (in minutes) */
{
int sd; /* socket descriptor */
pmessage buf; /* message buffer */
long mt,ct,cct,ret,wet,crt;
long ctb,mtb,t,rlet,wlet;
int fd;
int cached,cf,commstat,rewrite,within;
pso_errno=PSO_ENOERROR;
if(strchr(mode,'w')!=NULL||strchr(mode,'a')!=NULL||
(strchr(mode,'r')!=NULL&&strchr(mode,'+')!=NULL)) {
/* BEGIN open for WRITING *************************************************/
/* ... */
/* END open for WRITING ****************************************************/
}
else {
if(strchr(mode,'r')!=NULL) {
/* BEGIN open for READING **************************************************/
if((cached=read_info(name,&mt,&ct,&cct,&ret,&wet,&crt,&fd))==NOT_OK)
return NULL;
time(&t);
ctb=60*(long)tb; /* consistency time bound (in seconds) */
if(!cached) {
/* BEGIN open for READING and NOT CACHED *******************************/
/* ... */
/* END open for READING and NOT CACHED *********************************/
}
else {
/* BEGIN open for READING and CACHED ************************************/
cf=(ct==ctb);
if(ctb<0) {
/* BEGIN open for READING and CACHED and OPTIMISTIC ******************/
if(wet>=t||ret>=t) /* file is read- or writelocked */
return pfopen(name,mode,fd,0L,0L);
if((commstat=ptaco())==NOT_OK) {
unlock_file(fd);
return NULL;
}
within=(t+ctb<=ct||(wet>0&&t+ctb<=wet)||(ret>0&&t+ctb<=ret));
if(commstat!=CONNECTED) /* DISCONNECTED or WEAKLY CONNECTED */ {
if(within)
/*
At this point we know that the cached file is within the
specified (consistency) time bound.
We do not care whether we know the cached file is consistent
(cf) or not (!cf).
*/
return pfopen(name,mode,fd,0L,0L);
else {
pso_errno=PSO_ENOTWITHIN;
unlock_file(fd);
return NULL;
}
}
/* send request to server and receive reply */
pbuf(&buf,READ_OPEN,0L,0L,ct,cct,mt,name);
if(prequest(&sa,&sd,&buf)==NOT_OK||buf.status==NOT_OK) {
/*
We could not request the file from the server, so we use the
cached version (if its within the specified time bound).
*/
if(within) {
close_sock(sd);
return pfopen(name,mode,fd,0L,0L);
}
else {
pso_errno=PSO_ENOTWITHIN;
unlock_file(fd);
close_sock(sd);
return NULL;
}
}
if(buf.request==ISLOCKED)
/*
Note, that even if the file is writelocked on the server we will
read it - being optimistic.
*/
if(mt==buf.mt)
buf.request=CONSISTENT;
else
buf.request=INCONSISTENT;
switch(buf.request) {
case NOTFOUND:
if(within) {
pso_errno=PSO_ENOTWITHIN;
break;
}
else {
close_sock(sd);
return pfopen(name,mode,fd,0L,0L);
}
case INCONSISTENT:
pbuf(&buf,SEND_FILE,0L,0L,buf.ct,buf.cct,buf.mt,name);
if(preceive(&sa,&sd,&buf)==NOT_OK) {
if(within) {
close_sock(sd);
return pfopen(name,mode,fd,0L,0L);
}
else {
pso_errno=PSO_ENOTWITHIN;
break;
}
}
else
crt=buf.crt;
case CONSISTENT:
if(update_info(fd,buf.mt,buf.ct,buf.cct,ret,wet,crt)==NOT_OK)
break;
else {
close_sock(sd);
return pfopen(name,mode,fd,0L,0L);
}
case NOTLOCKED:
case WASLOCKED:
/*
Note, that the file should not have been attempted locked or
locked, because we did not ask for a lock (buf.ret=0L)!
*/
pso_errno=PSO_ESERVERERROR;
break;
default:
pso_errno=PSO_EUNKNOWNREPLY;
}
unlock_file(fd);
close_sock(sd);
return NULL;
/* END open for READING and CACHED and OPTIMISTIC ********************/
}
else
if(ctb==0) {
/* BEGIN open for READING and CACHED and STRICT ********************/
/* ... */
/* END open for READING and CACHED and STRICT **********************/
}
else {
/* BEGIN open for READING and CACHED and PESSIMISTIC ***************/
/* ... */
/* END open for READING and CACHED and PESSIMISTIC *****************/
}
/* END open for READING and CACHED *************************************/
}
/* END open for READING **************************************************/
}
else {
pso_errno=PSO_EBADMODE;
return NULL;
}
}
}
int p_close(fp,etb)
FILE *fp;
int etb; /* expiration time bound (in minutes) */
{
char name[PATHNAME_MAX];
int cached,commstat,request,status,updated;
long t,et,mt,ct,cct,ret,wet,crt,rlet,wlet;
int fd,sd;
struct stat stbuf;
pmessage buf;
pso_errno=PSO_ENOERROR;
time(&t);
if(etb<0)
etb=0;
if(etb>0)
et=t+60*(long)etb; /* expiration time */
#ifdef SYSV5
if((fp->_flag&01)==0)
request=WRITE_CLOSE;
else
request=READ_CLOSE;
#else
if((fp->_flags&04)==0)
request=READ_CLOSE;
else
request=WRITE_CLOSE;
#endif
if(pgetname(fp,name,&rlet,&wlet)==NOT_OK) {
pso_errno=PSO_ENOTFOUND;
fclose(fp);
return NOT_OK;
}
if((cached=read_info(name,&mt,&ct,&cct,&ret,&wet,&crt,&fd))==NOT_OK) {
pdelname(fp);
fclose(fp);
return NOT_OK;
}
if(!cached) {
pso_errno=PSO_ENOTCACHED;
delete_info(name);
pdelname(fp);
fclose(fp);
unlock_file(fd);
return NOT_OK;
}
if(ct!=cct) {
pso_errno=PSO_ENOTCONSISTENT;
pdelname(fp);
fclose(fp);
unlock_file(fd);
return NOT_OK;
}
if(stat(name,&stbuf)==-1) {
if(errno==ENOENT)
pso_errno=PSO_ENOTFOUND;
else
pso_errno=PSO_EERROR;
pdelname(fp);
fclose(fp);
unlock_file(fd);
return NOT_OK;
}
if(stbuf.st_mtime>=crt&&request==WRITE_CLOSE)
updated=UPDATED;
else
updated=NOT_UPDATED;
if((commstat=ptaco())==NOT_OK) {
unlock_file(fd);
return NOT_OK;
}
if(commstat==DISCONNECTED) {
if(etb==0) {
if(pdelname(fp)==NOT_OK) {
fclose(fp);
unlock_file(fd);
return NOT_OK;
}
if(fclose(fp)==EOF) {
pso_errno=PSO_ENOTCLOSED;
unlock_file(fd);
return NOT_OK;
}
if(unlock_file(fd)==NOT_OK)
return NOT_OK;
}
else {
/* wait for better communication status or timeout on et */
while((commstat=ptaco())!=DISCONNECTED&&et<t) {
sleep(SLEEPTIME);
time(&t);
}
}
}
if(commstat==DISCONNECTED) {
if(updated) {
switch(fork()) {
case -1:
pso_errno=PSO_EERROR;
return NOT_OK;
case 0: /* child process - wait for better communication */
fclose(stdin);
fclose(stderr);
#ifdef SYSV5
signal(SIGCLD,SIG_IGN);
#else
#ifndef LINUX
signal(SIGCLD,sig_child);
#else
signal(SIGCLD,SIG_IGN);
#endif
#endif
while((commstat=ptaco())!=DISCONNECTED)
sleep(SLEEPTIME);
pbuf(&buf,request,rlet,wlet,ct,cct,mt,name);
pclosesend(&sa,&sd,&buf,fd,updated,crt);
exit(0);
default: /* parent */
return TIMEOUT;
}
}
else
return TIMEOUT;
}
tryagain:
/* send request to server and receive reply */
pbuf(&buf,request,rlet,wlet,ct,cct,mt,name);
if(prequest(&sa,&sd,&buf)==NOT_OK||buf.status==NOT_OK) {
if(etb==0) {
if(pdelname(fp)==NOT_OK) {
fclose(fp);
unlock_file(fd);
close_sock(sd);
return NOT_OK;
}
if(fclose(fp)==EOF) {
pso_errno=PSO_ENOTCLOSED;
unlock_file(fd);
close_sock(sd);
return NOT_OK;
}
if(unlock_file(fd)==NOT_OK) {
close_sock(sd);
return NOT_OK;
}
commstat=DISCONNECTED;
}
else {
while((commstat=ptaco())!=DISCONNECTED&&et<t) {
sleep(SLEEPTIME);
time(&t);
}
if(commstat!=DISCONNECTED&&et>t) {
close_sock(sd);
goto tryagain;
}
}
}
if(commstat==DISCONNECTED) {
if(updated) {
switch(fork()) {
case -1:
pso_errno=PSO_EERROR;
return NOT_OK;
case 0: /* child process - wait for better communication */
fclose(stdin);
fclose(stderr);
#ifdef SYSV5
signal(SIGCLD,SIG_IGN);
#else
#ifndef LINUX
signal(SIGCLD,sig_child);
#else
signal(SIGCLD,SIG_IGN);
#endif
#endif
while((commstat=ptaco())!=DISCONNECTED)
sleep(SLEEPTIME);
pbuf(&buf,request,rlet,wlet,ct,cct,mt,name);
pclosesend(&sa,&sd,&buf,fd,updated,crt);
exit(0);
default: /* parent */
close_sock(sd);
return TIMEOUT;
}
}
else {
close_sock(sd);
return TIMEOUT;
}
}
switch(buf.request) {
case INCONSISTENT: /* has been updated on the server in the mean time */
case ISLOCKED: /* has been locked on the server in the mean time */
status=FAILURE;
break;
case CONSISTENT:
if(updated) {
if(pdelname(fp)==NOT_OK) {
pso_errno=PSO_EERROR;
fclose(fp);
break;
}
if(fclose(fp)==-1) {
pso_errno=PSO_EERROR;
break;
}
else {
pbuf(&buf,RECV_FILE,0L,0L,buf.ct,buf.cct,buf.mt,name);
if(prequest(&sa,&sd,&buf)==NOT_OK||buf.status==NOT_OK) {
if(buf.status==NOT_OK)
pso_errno=PSO_ESERVERERROR;
break;
}
else {
if(send_file(sd,name)==NOT_OK)
break;
else {
pbuf(&buf,SEND_STAT,0L,0L,buf.ct,buf.cct,buf.mt,name);
if(prequest(&sa,&sd,&buf)==NOT_OK||buf.status==NOT_OK) {
if(buf.status==NOT_OK)
pso_errno=PSO_ESERVERERROR;
break;
}
else {
if(wlet>t)
wlet=t;
if(update_info(fd,buf.mt,buf.ct,buf.cct,ret,wlet,crt)==NOT_OK)
break;
else {
status=SUCCESS;
break;
}
}
}
}
}
}
else {
if(request==READ_CLOSE)
if(rlet>t)
rlet=t;
else
rlet=ret;
if(request==WRITE_CLOSE)
if(wlet>t)
wlet=t;
else
wlet=wet;
if(update_info(fd,buf.mt,buf.ct,buf.cct,rlet,wlet,crt)==NOT_OK)
break;
else {
status=SUCCESS;
break;
}
}
default:
pso_errno=PSO_EUNKNOWNREPLY;
}
if(pso_errno==PSO_ENOERROR) {
if(!updated) {
if(pdelname(fp)==NOT_OK) {
fclose(fp);
unlock_file(fd);
close_sock(sd);
return NOT_OK;
}
if(fclose(fp)==EOF) {
pso_errno=PSO_ENOTCLOSED;
unlock_file(fd);
close_sock(sd);
return NOT_OK;
}
}
if(unlock_file(fd)==NOT_OK) {
close_sock(sd);
return NOT_OK;
}
close_sock(sd);
return status;
}
else {
if(!updated) {
pdelname(fp);
fclose(fp);
}
unlock_file(fd);
close_sock(sd);
return NOT_OK;
}
}
int p_lock(name,mode,letb)
char *name,*mode;
int letb; /* lock expiration time bound (in minutes) */
{
/* ... */
}
int p_unlock(name,mode)
char *name,*mode;
{
/* ... */
}
int p_remove(name)
char *name;
{
/* ... */
}
int p_stat(name,mt,ct,cct,ret,wet)
char *name;
long *mt,*ct,*cct,*ret,*wet;
{
int cached;
long crt;
int fd;
pso_errno=PSO_ENOERROR;
if((cached=read_info(name,mt,ct,cct,ret,wet,&crt,&fd))==NOT_OK)
return NOT_OK;
else {
if(!cached)
if(delete_info(name)==NOT_OK)
return NOT_OK;
if(unlock_file(fd)==NOT_OK)
return NOT_OK;
else
return cached;
}
}
int p_comm()
{
pso_errno=PSO_ENOERROR;
return ptaco();
}
long p_time(flag)
int flag;
{
/* ... */
}
/* END library subroutines ****************************************************/