/*ident "@(#)ipc:ipcbuf.c 3.1" */ /****************************************************************************** * * C++ Standard Components, Release 3.0. * * Copyright (c) 1991, 1992 AT&T and Unix System Laboratories, Inc. * Copyright (c) 1988, 1989, 1990 AT&T. All Rights Reserved. * * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T and Unix System * Laboratories, Inc. The copyright notice above does not evidence * any actual or intended publication of such source code. * ******************************************************************************/ #include "ipclib.h" #ifndef O_RDONLY # include #endif #ifndef O_TRUNC # define O_TRUNC 0 #endif #ifndef O_CREAT # define O_CREAT 0 #endif #ifndef O_APPEND # define O_APPEND 0 #endif #ifdef __GNUG__ #define zapeof(x) ((x)&0377) #endif static String // includes trailing slash dirname_plus(const String& arg) { int base = arg.strrchr('/') + 1; if (base == 0) return "./"; else return arg.chunk(0, base); } extern int errno ; inline void save_errno(int& orig) { orig = ::errno ; ::errno = 0 ; } inline int restore_errno(int& orig) { if ( ::errno == 0 ) ::errno = orig ; return EOF ; } /* * Open a ipc connection. * Return: NULL if failure * this if success */ ipcbuf* ipcbuf::open (const String& path, const char* /* param */) { int errno_orig ; save_errno(errno_orig) ; String name = ipc_fix_name_ATTLC(path); char* p = new char[name.length()+10]; name.dump(p); key_t key = ftok(p, ipcstream::ftok_id ? ipcstream::ftok_id : 'z'); delete p; if (key == key_t(-1)) return 0; Monitor* sema1 = new Monitor(key,1); sema1->Open(); sema1->P(); Monitor* sema2 = new Monitor(key+1,1); sema2->Open(); sema2->V(); int fd; if ((fd = ::open(String(name+'a'), O_WRONLY)) < 0) { sema1->V(); delete sema1; delete sema2; return 0; } if ((p = cuserid(0)) == 0) { ::close(fd); sema1->V(); delete sema1; delete sema2; return 0; } errno = 0; {// note no if ofstream ofs(fd); ofs << p << " " << getuid() << " " << getgid() << "\n"; ofs.close(); } ::close(fd); if ((fd = ::open(String(name+'b'), O_RDONLY)) < 0) { sema1->V(); delete sema1; delete sema2; return 0; } {// note no if ifstream ifs(fd); String ans; ifs >> ans; if (ans == "Accept") { String temp; String dir = dirname_plus(name); ifs >> temp; String in_pipe = dir + temp; ifs >> temp; String out_pipe = dir + temp; out_xfd = ::open(out_pipe, O_WRONLY); in_xfd = ::open(in_pipe, O_RDONLY); if (in_xfd >= 0 && out_xfd >= 0) opened = 1; } else if (ans == "Reject") { ifs >> remote_errno; remote_reason = sgets(ifs); } else { remote_errno = -1; remote_reason = "Lost synch"; } ifs.close(); } ::close(fd); sema1->V(); delete sema1; delete sema2; return opened ? this : 0; } ipcbuf* ipcbuf::open (const char* path, const char* param) { return open(String(path), param); } /* * Empty an output buffer. * Returns: EOF on error * 0 on success */ int ipcbuf::overflow(int c) { int errno_orig ; save_errno(errno_orig) ; if ( !opened ) return restore_errno(errno_orig) ; if ( out_allocate() == EOF ) return restore_errno(errno_orig) ; register char* p = aux_base() ; register int count = pptr() - p; // pptr()==NULL does not imply p < pptr(), so we need separate // test. if ( pptr() && count > 0 ) { if (count != write(out_xfd,p,count)) return restore_errno(errno_orig) ; } setp(pbase(),epptr()) ; // cerr << "OverF:abase=" << (int)aux_base() << " pptr=" << (int)pptr() << endl; if ( c == EOF ) /* don't do anything */ ; else if ( pbase() == epptr() ) { // unbuffered char ch = c; // cerr << "OverF:pbase=" << (int)pbase() << " epptr=" << (int)epptr() << endl; // cerr << "OverF:xfdout=" << out_xfd << " errno=" << errno_orig << endl; if ( write(out_xfd,&ch,1)!=1 ) return restore_errno(errno_orig) ; } else { sputc(c) ; } restore_errno(errno_orig) ; return zapeof(c) ; } /* * Fill an input buffer. * Returns: EOF on error or end of input * next character on success */ int ipcbuf::underflow() { int count; if ( !opened ) return EOF ; if ( in_allocate() == EOF ) return EOF ; int orig_errno ; save_errno(orig_errno) ; if ( in_unbuffered() ) { #ifdef __hpux count = read(in_xfd,(void*)&lahead[0],1) ; #else count = read(in_xfd,&lahead[0],1) ; #endif setg(&lahead[0],&lahead[0],&lahead[count]) ; if ( count <= 0 ) return EOF ; } else { register int rdsize ; if ( blen() > 2*sizeof(long) ) { /* gptr must be set greater than base to * guarantee at least 1 char of pushback. * putting it farther will tend in many common * cases to keep things aligned. */ in_start = base()+sizeof(long) ; rdsize = blen()-sizeof(long) ; } else { in_start = base()+1 ; rdsize = blen()-1 ; } #ifdef __hpux count = read(in_xfd,(void*)in_start,rdsize) ; #else count = read(in_xfd,in_start,rdsize) ; #endif while ( count<=0 && ::errno==EINTR ) { /* * Signal caught and returned before any data * transfered. */ ::errno = 0 ; #ifdef __hpux count = read(in_xfd,(void*)in_start,rdsize) ; #else count = read(in_xfd,in_start,rdsize) ; #endif } if ( count <= 0 ) { setg(0,0,0) ; return restore_errno(orig_errno) ; } setg(base(),in_start,in_start+count) ; } restore_errno(orig_errno) ; return zapeof(*gptr()); } int ipcbuf::close() { int f = in_xfd ; int g = out_xfd ; overflow(); setg(0,0,0) ; setp(0,0) ; opened = 0 ; in_xfd = out_xfd = -1 ; int orig_errno ; save_errno(orig_errno) ; int ok = ::close(f) | ::close(g); restore_errno(orig_errno) ; return ok ; } int ipcbuf::sync() { return overflow() ; } ipcbuf::ipcbuf() : in_xfd(-1), out_xfd(-1), opened(0), x_get_unbuf(0), x_put_unbuf(0), aux_x_base(0), aux_alloc(0), owner(0) { } ipcbuf::ipcbuf(const char* path, const char* param) : in_xfd(-1), out_xfd(-1), opened(0), x_get_unbuf(0), x_put_unbuf(0), aux_x_base(0), aux_alloc(0), owner(0) { open(String(path), param); } ipcbuf::ipcbuf(const String& path, const char* param) : in_xfd(-1), out_xfd(-1), opened(0), x_get_unbuf(0), x_put_unbuf(0), aux_x_base(0), aux_alloc(0), owner(0) { open(path, param); } ipcbuf::ipcbuf(int in_fd, int out_fd) : in_xfd(in_fd), out_xfd(out_fd), opened(1), x_get_unbuf(0), x_put_unbuf(0), aux_x_base(0), aux_alloc(0), owner(0) { } ipcbuf::ipcbuf(String in_pipe, String out_pipe) : opened(1), x_get_unbuf(0), x_put_unbuf(0), aux_x_base(0), aux_alloc(0), owner(1), in_pip(in_pipe), out_pip(out_pipe) { if ((in_xfd = ::open(in_pipe, O_RDONLY)) < 0 || (out_xfd = ::open(out_pipe, O_WRONLY)) < 0) opened = 0; } ipcbuf::~ipcbuf() { close() ; if (owner) { unlink(in_pip); unlink(out_pip); } } streambuf* ipcbuf::setbuf(char*, int) { return 0; } streambuf* ipcbuf::set_in_buf(char* p , int len) { if ( base() ) return 0 ; if ( len <= 0 || p == 0 ) { // make it unbuffered setb(0,0,0) ; setg(0,0,0) ; in_unbuffered(1) ; } else { setb(p,p+len,0) ; setg(p,p,p) ; in_unbuffered(0) ; } return this; } streambuf* ipcbuf::set_out_buf(char* p , int len) { if ( aux_base() ) return 0 ; if ( len <= 0 || p == 0 ) { // make it unbuffered aux_setb(0,0,0) ; setp(0,0) ; out_unbuffered(1) ; } else { aux_setb(p,p+len,0) ; setp(p,p+len) ; out_unbuffered(0) ; } return this; } /* Allocate some space for the buffer. Returns: EOF on error 0 on success */ int ipcbuf::do_out_allocate() { char *buf = new char[STREAMBUFSIZE] ; if ( !buf ) return EOF ; aux_setb(buf,buf+STREAMBUFSIZE,1) ; return 0; }