/* begincopyright Copyright (c) 1988 Xerox Corporation. All rights reserved. Use and copying of this software and preparation of derivative works based upon this software are permitted. Any distribution of this software or derivative works must comply with all applicable United States export control laws. This software is made available AS IS, and Xerox Corporation makes no warranty about the software, its performance or its conformity to any specification. Any person obtaining a copy of this software is requested to send their name and post office or electronic mail address to: PCR Coordinator Xerox PARC 3333 Coyote Hill Rd. Palo Alto, CA 94304 endcopyright */ /* * CMUXGlue.c * * XR interface to Mentat Courier Mux * * Demers, April 25, 1990 9:11:44 am PDT */ #include <xr/BasicTypes.h> #include <xr/Errno.h> #include <xr/Threads.h> #include <xr/UIO.h> #include <sys/file.h> #include <stropts.h> #include "CMUX.h" #include "CMUXGlue.h" #include <xr/ThreadsMsgPrivate.h> #define MAX←MSG←SEND←BYTES 512 /* the most I'll send at once */ #define MAX←MSG←RECV←BYTES 534 /* the most I'll recv at once */ #define GETMSG(d, cp, dp, f) \ XR←GetMsg((d), (cp), (dp), (f)) #define PUTMSG(d, cp, dp, f) \ XR←PutMsg((d), (cp), (dp), (f)) #define XR←GetEnv(s) \ getenv(s) /* * the following stuff belongs in CedarPreBasics or something ... */ typedef XR←Pointer (*XR←CProc)(); typedef struct XR←MProcRep { XR←CProc mp←proc; XR←Pointer mp←data; } * XR←MProc; XR←CProc XR←CProcFromMProc(mp) XR←MProc mp; { return mp->mp←proc; } XR←Pointer XR←DataFromMProc(mp) XR←MProc mp; { return mp->mp←data; } XR←MProc XR←NewMProc(cp, data) XR←CProc cp; XR←Pointer data; { XR←MProc mp = (XR←MProc)XR←malloc( sizeof(struct XR←MProcRep) ); mp->mp←proc = cp; mp->mp←data = data; return mp; } /* * end of stuff to be moved */ /* * Debugging support */ static int XR←cmuxGlueDebugValue = 0; int XR←CMUXDebug(delta) int delta; { int ans = XR←cmuxGlueDebugValue; XR←cmuxGlueDebugValue += delta; return ans; } #define DebugMsg if(XR←cmuxGlueDebugValue != 0) XR←ConsoleMsg XR←CMUXDescriptor XR←CMUXCreate () { XR←CMUXDescriptor d; char * name; name = (char *)XR←GetEnv("COURIER←MUX←NAME"); if( name == NIL ) { name = COURIER←MUX←NAME←DEF; } d = XR←OpenStream(name, O←RDWR, 0); XR←SetGetBlocking(d, XR←UIO←BLOCKING←ALL←DATA); if( d < 0 ) d = -(XR←GetErrno()); DebugMsg("XR←CMUXCreate returns %d\n", d); return d; } void XR←CMUXDestroy (d) XR←CMUXDescriptor d; { DebugMsg("XR←CMUXDestroy %d\n", d); (void)XR←Close(d); } #define CONNECT←RETRIES 10 #define CONNECT←PAUSE←MSEC 300 int XR←CMUXConnect(d, type, addr, addrLen) XR←CMUXDescriptor d; XR←CMUXAddrType type; XR←Pointer addr; int addrLen; { char * buf = NIL; char lBuf[132]; int i, ret, typeCode; struct strioctl si; if( (addr == NIL) || (addrLen == 0) ) { ret = -EINVAL; goto Out; } DebugMsg("CMUXConnect %d to ", d); for( i = 0; i < addrLen; i += sizeof(unsigned) ) { DebugMsg( "%d ", *((unsigned *)(addr + i)) ); } buf = lBuf; if( addrLen > ((sizeof lBuf) - (2*sizeof(short)))) { buf = (char *)XR←malloc(addrLen + (2*sizeof(short))); if( buf == NIL ) { ret = -ENOMEM; goto Out; } } for( i = 0; i <= CONNECT←RETRIES; i++ ) { ShortToBE16(addrLen, buf); buf += sizeof(short); switch(type) { case XR←CMUX←ADDR←TYPE←DFLT←NAME: typeCode = -COUR←DEF←ADDR←TYPE; break; case XR←CMUX←ADDR←TYPE←DFLT←ADDR: typeCode = COUR←DEF←ADDR←TYPE; break; case XR←CMUX←ADDR←TYPE←XNS←NAME: typeCode = -COUR←XNS←ADDR←TYPE; break; case XR←CMUX←ADDR←TYPE←XNS←ADDR: typeCode = COUR←XNS←ADDR←TYPE; break; default: ret = -EINVAL; goto Out; } ShortToBE16(typeCode, buf); buf += sizeof(short); (void)bcopy( ((char *)(addr)), buf, addrLen ); buf -= 2*sizeof(short); si.ic←cmd = CMUX←ADDR←REQ; si.ic←len = addrLen + 2*sizeof(short); si.ic←dp = buf; si.ic←timout = -1; ret = XR←IOCtl(d, I←STR, &si); if( ret >= 0 ) break; ret = -(XR←GetErrno()); DebugMsg("CMUXConnect IOCtl errno %d\n", -ret); if( (ret != -EINTR) || (typeCode > 0) ) break; (void)XR←PauseAbortable(XR←MsecToTicks(CONNECT←PAUSE←MSEC)); } Out: if( (buf != lBuf) && (buf != NIL) ) XR←free(buf); XR←SetErrno(-ret); DebugMsg("CMUXConnect returns %d\n", ret); return ret; } int cmuxReadMsgDefaultClientBufLen = 2*MAX←MSG←RECV←BYTES; int XR←CMUXReadMsg(d, ignoreAborts, timeoutMsec, allocaterFunc, allocaterClientData) XR←CMUXDescriptor d; bool ignoreAborts; unsigned timeoutMsec; XR←CMUXAllocaterFunc allocaterFunc; XR←Pointer allocaterClientData; { struct strbuf ctlBuf; struct strbuf dataBuf; int flags; char lBuf[MAX←MSG←RECV←BYTES]; XR←Pointer clientBufPtr; int clientBufLen; int len, ret; int err = 0; long totalLen = 0; ctlBuf.buf = lBuf; ctlBuf.maxlen = (sizeof lBuf); clientBufLen = cmuxReadMsgDefaultClientBufLen; /* DEBUG */ clientBufPtr = (*allocaterFunc)( 0, clientBufLen, allocaterClientData ); if( clientBufPtr == NIL ) { XR←SetErrno(ENOMEM); return(-ENOMEM); } dataBuf.buf = ((char *)(clientBufPtr)); dataBuf.maxlen = clientBufLen; if( timeoutMsec != XR←WAIT←FOREVER←MSEC ) { (void) XR←SetGetTimeout(d, timeoutMsec); } for (;;) { flags = 0; dataBuf.len = ctlBuf.len = 0; ret = GETMSG(d, &ctlBuf, &dataBuf, &flags); if( ret < 0 ) { DebugMsg("CMUXReadMsg botch 0\n"); err = XR←GetErrno(); break; } len = dataBuf.len; if( len == -1 ) { DebugMsg("CMUXReadMsg botch 1\n"); err = EIO; break; } dataBuf.buf += len; dataBuf.maxlen -= len; totalLen += len; DebugMsg("CMUXReadMsg ctllen %d datalen %d\n", ctlBuf.len, len); if (ctlBuf.len == 0) { /* end of data */ if( (len == 0) && (totalLen == 0) ) { /* Bulk Data abort from previous call */ if( ignoreAborts ) continue; err = EPIPE; } break; } if (dataBuf.maxlen >= MAX←MSG←RECV←BYTES) { /* guaranteed there's enough room for the next message */ continue; } clientBufPtr = (*allocaterFunc)( totalLen, clientBufLen, allocaterClientData ); if( clientBufPtr != NIL ) { dataBuf.buf = ((char *)(clientBufPtr)); dataBuf.maxlen = clientBufLen; clientBufLen = 2*clientBufLen; continue; } /* Blow off the rest */ for(;;) { flags = 0; dataBuf.len = ctlBuf.len = 0; ret = GETMSG(d, &ctlBuf, &dataBuf, &flags); if( (ret < 0) || (ctlBuf.len == 0) ) break; } err = ENOMEM; break; } if( timeoutMsec != XR←WAIT←FOREVER←MSEC ) { (void) XR←SetGetTimeout(d, XR←WAIT←FOREVER←MSEC); } if (err != 0) { (void) (*allocaterFunc)(0, 0, allocaterClientData); /* free */ XR←SetErrno(err); return(-err); } return(totalLen); } int XR←CMUXWriteMsg (d, hdr, hdrLen, body, bodyLen) XR←CMUXDescriptor d; XR←Pointer hdr; int hdrLen; XR←Pointer body; int bodyLen; { struct strbuf s1; struct strbuf s2; int err; s1.buf = ((char *)(hdr)); s1.len = hdrLen; s1.maxlen = hdrLen; s2.buf = ((char *)(body)); s2.len = bodyLen; s2.maxlen = bodyLen; if( PUTMSG (d, &s1, &s2, 0) == 0 ) return(0); if( (err = XR←GetErrno()) != ERANGE ) { DebugMsg("CMUXWriteMsg PutMsg 1 failed %d\n", err); return(-err); } s2.len = -1; if( PUTMSG(d, &s1, &s2, 0) != 0 ) { err = XR←GetErrno(); DebugMsg("CMUXWriteMsg PutMsg 2 failed %d\n", err); return(-err); } s1.len = MAX←MSG←SEND←BYTES; s1.buf = ((char *)(body)); while (bodyLen > 0) { if( bodyLen <= (2*MAX←MSG←SEND←BYTES) ) { if( bodyLen > MAX←MSG←SEND←BYTES ) { s1.len = MAX←MSG←SEND←BYTES; s2.buf = &(s1.buf[MAX←MSG←SEND←BYTES]); s2.len = bodyLen - MAX←MSG←SEND←BYTES; bodyLen -= s2.len; } else { s1.len = bodyLen; s2.len = 0; } } if( PUTMSG(d, &s1, &s2, 0) != 0 ) { err = XR←GetErrno(); DebugMsg("CMUXWriteMsg PutMsg 3 failed %d\n", err); return(-err); } bodyLen -= MAX←MSG←SEND←BYTES; s1.buf += MAX←MSG←SEND←BYTES; } return(0); } static int XR←CMUXUnblockStream(d) XR←CMUXDescriptor d; { int junkBuf[1]; struct strioctl si; si.ic←cmd = CMUX←UNBLOCK←STREAM; si.ic←dp = (char *)(&junkBuf[0]); si.ic←len = 0; si.ic←timout = -1; return( XR←IOCtl(d, I←STR, &si) ); } int XR←CMUXBDTRead(d, buf, nBytes) XR←CMUXDescriptor d; XR←Pointer buf; unsigned nBytes; { int ans; if( (ans = XR←Read(d, buf, nBytes)) < 0 ) ans = -XR←GetErrno(); return ans; } int XR←CMUXBDTWrite(d, buf, nBytes) XR←CMUXDescriptor d; XR←Pointer buf; unsigned nBytes; { int ans; if( (ans = XR←Write(d, buf, nBytes)) < 0 ) ans = -XR←GetErrno(); return ans; } int XR←CMUXFinishBDT (d, source, sendAbort) XR←CMUXDescriptor d; bool source; bool sendAbort; { char junkBuf[128]; struct strbuf s1; struct strbuf s2; if( source ) { if( sendAbort ) { s1.buf = junkBuf; s1.len = 0; s1.maxlen = 0; s2.buf = junkBuf; s2.len = 0; s2.maxlen = 0; if( XR←PutMsg(d, &s1, &s2, 0) != -1 ) { while( XR←Read(d, junkBuf, (sizeof junkBuf)) > 0 ) continue; } else if( XR←GetErrno() == ERANGE ) { (void)XR←CMUXUnblockStream(d); /* Since the other side has already done an ABORT, * just do an end-of-bulk indication */ (void)XR←Write(d, junkBuf, 0); } } else /* !sendAbort */ { if( (XR←Write(d, junkBuf, 0) == -1) && (XR←GetErrno() == ERANGE) ) { (void)XR←CMUXUnblockStream(d); (void)XR←Write(d, junkBuf, 0); } } } else /* !source */ { if( sendAbort ) { (void)XR←CMUXWriteMsg(d, junkBuf, 0, junkBuf, 0); while( XR←Read(d, junkBuf, (sizeof junkBuf)) > 0 ) continue; } else /* !sendAbort */ { /* nothing */ } } return 0; } int XR←CMUXServerAdd(d, pgm, loVersion, hiVersion) XR←CMUXDescriptor d; unsigned pgm; unsigned loVersion, hiVersion; { struct { unsigned buf←pgm; unsigned short buf←loVersion; unsigned short buf←hiVersion; } theBuf; struct strioctl si; si.ic←cmd = CMUX←SERVER←ADD; LongToBE32(pgm, &(theBuf.buf←pgm) ); ShortToBE16( ((short)(loVersion)), &(theBuf.buf←loVersion) ); ShortToBE16( ((short)(hiVersion)), &(theBuf.buf←hiVersion) ); si.ic←dp = (char *)(&theBuf); si.ic←len = (sizeof theBuf); si.ic←timout = -1; return( XR←IOCtl(d, I←STR, &si) ); } int XR←CMUXServerQuit(d) XR←CMUXDescriptor d; { int junkBuf[1]; struct strioctl si; si.ic←cmd = CMUX←SERVER←QUIT; si.ic←dp = (char *)(&junkBuf[0]); si.ic←len = 0; si.ic←timout = -1; return( XR←IOCtl(d, I←STR, &si) ); } /* * DEBUGGING STUFF */ char PARC←CHS←XNSAddr[] = { 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0xaa, 0x00, 0x7f, 0xac, 0x00, 0x05 }; int DebugCMUXPutXNSAddr(a) unsigned char *a; { XR←ConsoleMsg( "%x.%x.%x.%x:", a[0], a[1], a[2], a[3]); XR←ConsoleMsg( "%x.%x.%x.", a[4], a[5], a[6]); XR←ConsoleMsg( "%x.%x.%x:", a[7], a[8], a[9]); XR←ConsoleMsg( "%x.%x\n", a[10], a[11]); } void DebugCMUXFillCallHdr(hdr, pgmNum, pgmVers, procNum) char *hdr; int pgmNum, pgmVers, procNum; { /* msgtype = call(0) */ hdr[0] = 0; hdr[1] = 0; /* transactionID = 0 */ hdr[2] = 0; hdr[3] = 0; /* program number */ hdr[4] = (pgmNum >> 24) & 0xFF; hdr[5] = (pgmNum >> 16) & 0xFF; hdr[6] = (pgmNum >> 8) & 0xFF; hdr[7] = (pgmNum & 0xFF); /* program version */ hdr[8] = (pgmVers >> 8) & 0xFF; hdr[9] = pgmVers & 0xFF; /* proc number */ hdr[10] = (procNum >> 8) & 0xFF; hdr[11] = procNum & 0xFF; } XR←Pointer DebugCMUXMkBuffer(nBytes) unsigned nBytes; { unsigned *p = (unsigned *)XR←malloc(nBytes+sizeof(unsigned)); p[0] = nBytes; return ((XR←Pointer)(p)); } XR←Pointer DebugCMUXAllocater(startIndex, nBytes, clientData) unsigned startIndex; unsigned nBytes; XR←Pointer clientData; { unsigned len; if( clientData == NIL ) return NIL; len = * ((unsigned *)(clientData)); if( len < ( sizeof(unsigned) + startIndex + nBytes ) ) return NIL; return ( clientData + sizeof(unsigned) + startIndex ); } int debugCMUXSavedErrno = 0; static int WRAP(n) { debugCMUXSavedErrno = XR←GetErrno(); return n; } int DebugCMUXCreate() { return WRAP( XR←CMUXCreate() ); } void DebugCMUXDestroy(d) int d; { (void) WRAP( (XR←CMUXDestroy(d), 0) ); } int DebugCMUXConnectXNSAddr(d, addr) int d; int *addr; { return WRAP( XR←CMUXConnect(d, XR←CMUX←ADDR←TYPE←XNS←ADDR, addr, 12) ); } int DebugCMUXConnectXNSName(d, name) int d; char *name; { return WRAP( XR←CMUXConnect(d, XR←CMUX←ADDR←TYPE←XNS←NAME, name, 1+strlen(name)) ); } int DebugCMUXRetrieveAddresses(d, replyBuf) int d; XR←Pointer replyBuf; { int hdr[3]; int junk = 0; int ans; DebugCMUXFillCallHdr( &(hdr[0]), /*pgmNum=*/ 2, /*pgmVers=*/ 3, /*procNum=*/ 0 ); XR←ConsoleMsg("Sending call ... "); ans = WRAP( XR←CMUXWriteMsg(d, &(hdr[0]), (sizeof hdr), &junk, 0) ); if( ans < 0 ) { DebugMsg("CMUXWriteMsg ans %d errno %d\n", ans, debugCMUXSavedErrno); return (-1); } DebugMsg("reading reply ... "); ans = WRAP( XR←CMUXReadMsg(d, TRUE, DebugCMUXAllocater, replyBuf) ); if( ans < 0 ) { DebugMsg("CMUXReadMsg ans %d errno %d\n", ans, debugCMUXSavedErrno); return (-1); } DebugMsg( "got %d bytes\n", ans ); return ans; }