/* 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 #include #include #include #include #include #include "CMUX.h" #include "CMUXGlue.h" #include #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; }