![]() ![]() ![]() ![]() ![]() 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 ****************************************************/