/* File: PPCEntry.c Contains: PPC Dispatcher of various calls Written by: Sangam, Eric M. Trehus Copyright: © 1989-1992 by Apple Computer, Inc., all rights reserved. Change History (most recent first): <39> 4/14/92 BBM : Remove unfinished PPC code that is under the contitional “TheFutute”, and remove the conditional “CubeE” since that is reality. Remove conditionals, since all they do is confuse. <38> 10/4/91 JSM Change PsychoticFarmerOrLater conditionals to TheFuture. <37> 9/30/91 DTY Dean’s in the dog house. The System build got derailed with that last change. <36> 9/29/91 DTY Conditionalize <33> through <35> out of CubeE. <35> 6/26/91 EMT Add support to kill PPCInform calls <34> 6/10/91 EMT Check for duplicate completion. <33> 6/4/91 EMT Roll in StoreAndForward Revisions <32> 1/7/91 EMT Fix bug that causes machine to hang in PPCStart and IPCListPorts, related to GetMyZone call. <31> 12/13/90 EMT Change calling conventions to support new glue, and Inline Async/Sync parameterless calls. <30> 11/28/90 EMT Fix/Work around bug that prevents my completion routine from being called. <29> 11/8/90 EMT Change how PPCStart and IPCListports determine if the session is local or not. Because we can't assume that the zone name in our globals is correct. <28> 11/6/90 EMT Changing CheckLocName to not used IUEqualString where it is not needed <27> 10/30/90 EMT Fix usage and bug in PPCCommonPBEntry, that would not call completion routine if an error occured because we weren't initialized or had no globals. <26> 10/19/90 JSM Break out PPCEntry() into separate routines for new dispatching scheme. <25> 10/18/90 EMT Change userName to machineName where needed <24> 10/11/90 EMT Remove #define DEBUG <23> 9/21/90 EMT Update constants, types, and field names as dictated by PPCToolBox.h <22> 9/16/90 EMT Fix bug <21> 9/15/90 EMT Fix CheckLocName bug introduced. <20> 9/14/90 EMT Make changes to support only type specification in PPCOpen with location name. <19> 9/5/90 EMT Make this file C3.0 friendly <18> 9/4/90 EMT Eric's changes rolled in <17> 8/6/90 S Bug Fixes. <16> 6/28/90 S To Improve Dynamic allocation and fix other bugs. <15> 4/24/90 S To Un fix Jeff's code changes. <14> 4/18/90 JSM Add prototype for AvoidDuplicateCompletion, miscellaneous code size reductions. <13> 4/10/90 S To Support Network IPCList Port call when incomming sessions are prevented. <11> 3/5/90 S Don't Look for User &Group File at PPCOpen. <10> 2/27/90 S Don't allow BOTH for PPCOpen. <9> 2/13/90 S Some Error Code Changes. <8> 2/7/90 S Bug Fix with PPCOpen call. <7> 2/5/90 S Included check to ignore duplicate check for locName for PPCOpen. <6> 2/5/90 S Included Checking for netVisible Flag before making NBP registration. <5> 1/30/90 S Bug Fixes <3+> 1/12/90 S Bug Fixes <2+> 1/5/90 S Some Error Codes <1.3> 10/12/89 CVC no change <1.2> 10/12/89 CVC Handling NoLocName in PortLocName <1.1> 9/25/89 ss Support port types. <1.0> 9/18/89 CVC Adding PPC toolbox for the first time. Old Revision History: 05/30/89 Sangam New Today 07/20/89 Sangam 1.0d2 release today! 07/25/89 Sangam Nbp name is concatenated strings for setuser nbp name 08/01/89 Sangam Fixed PPOpen for not registering name when ADSP is not there 08/09/89 Sangam Reverted back to unpacked format for location name 10/09/89 Sangam Handling NoLocName in PortLocName. Returning noUserRecErr if user & group file is not there but user wants authentication 1/4/90 Sangam Some bug fixes and return errorcode changes. */ #include "PPCCommon.h" #include /*---------------------------------------------------------------------------------------- Prototypes used only in this file. ----------------------------------------------------------------------------------------*/ STATIC Boolean PPCCommonPBEntry(void *PB, PPCGlobalParamsPtr *ppcglobPtrPtr); STATIC OSErr PPCCommonPBExit(void *PB, PPCGlobalParamsPtr ppcglobPtr); STATIC void NetOpenCompletion(void); // <36> STATIC void CallCompletionRoutine(PPCParamBlockPtr PB,OSErr ioResult); STATIC Boolean LocNameTaken(LocationNamePtr locationName,PPCGlobalParamsPtr ppcglobPtr); STATIC void BeginLocalOrRemote(PPCGlobalParamsPtr ppcglobPtr,PPCParamBlockPtr PB,void *portPtr); STATIC void LocalOrNot(void); STATIC void DoGetMyZone(XCallParam *xpb,Boolean async,ProcPtr compRtn,Str32 zoneName); /*---------------------------------------------------------------------------------------- Main entry point to the PPCOpen call. ----------------------------------------------------------------------------------------*/ OSErr ppcOpen(PPCOpenPBPtr openPB) { PPCGlobalParamsPtr ppcglobPtr; PPCPortEntryPtr portPtr; // <36> LocationNamePtr theLocName; if (PPCCommonPBEntry(openPB, &ppcglobPtr)) // do common entry code for parameter block based calls { openPB->csCode = PPCOpenCall; // save command code openPB->nbpRegistered = false; openPB->portRefNum = 0; theLocName = openPB->locationName; if(openPB->resFlag) // <36> Enforce resFlag == 0 { // <36> CompleteWithResult(openPB,badReqErr); // <36> goto Done; // <36> } // <36> if (!ValidPortName(openPB->portName)) // <36> make sure the Port name looks good { // <36> CompleteWithResult(openPB,badPortNameErr); // <36> goto Done; // <36> } if (CheckPortName(openPB->portName, ppcglobPtr)) // make sure the Port name is not already in use { CompleteWithResult(openPB,portNameExistsErr); goto Done; } if (openPB->serviceType != ppcServiceRealTime) // make sure we support this serviceType { CompleteWithResult(openPB,badServiceMethodErr); goto Done; } if (openPB->networkVisible && openPB->locationName) { if (theLocName->locationKindSelector != ppcNBPTypeLocation) { CompleteWithResult(openPB,nameTypeErr); // <36> goto Done; // <36> } if (theLocName->u.nbpType[0] > 32 || theLocName->u.nbpType[0] == 0) { CompleteWithResult(openPB,badLocNameErr); goto Done; } if(LocNameTaken(openPB->locationName,ppcglobPtr)) { CompleteWithResult(openPB,nbpDuplicate); goto Done; } } if (!(portPtr = GetPortTable(openPB, ppcglobPtr))) // make sure this port exists { CompleteWithResult(openPB,noPortErr); goto Done; } if (portPtr->locationInfo) // If client wants a location name with the port { if(ppcglobPtr->allowIncommingRequests) // Are we allowing incomming IAC. { PortLocationTablePtr locInfo; locInfo = portPtr->locationInfo; RegisterName(ppcglobPtr->machineName, // use our machine name locInfo->typeStr, // use the type specified. "\p*", // always * ppcglobPtr->adspSocket, // socket to register name on true, // Call ASyncronously (ProcPtr)NetOpenCompletion, // NBPCompletion routine (Ptr)&locInfo->nteQEle, // ntePtr &locInfo->nbpPB); // PB for NBP call } else // Port open, location name not registered. { portPtr->openPB = nil; // This is important CompleteWithResult(openPB,noErr); goto Done; } } else // Port open without a location name. { portPtr->openPB = nil; // This is important CompleteWithResult(openPB,noErr); goto Done; } } Done: return PPCCommonPBExit(openPB, ppcglobPtr); } /*---------------------------------------------------------------------------------------- Main entry point to the PPCStart call. ----------------------------------------------------------------------------------------*/ OSErr ppcStart(PPCStartPBPtr startPB) { PPCGlobalParamsPtr ppcglobPtr; OSErr result; PPCPortEntryPtr portPtr; // do common entry code for parameter block based calls if (PPCCommonPBEntry(startPB, &ppcglobPtr)) { startPB->csCode = PPCStartCall; // save command code if (!ValidPortName(startPB->portName)) { CompleteWithResult(startPB,badPortNameErr); } else if (startPB->serviceType != ppcServiceRealTime) { CompleteWithResult(startPB,badServiceMethodErr); } else if ((portPtr = PortRefNumtoPtr(startPB->portRefNum, ppcglobPtr)) == nil) { CompleteWithResult(startPB,noPortErr); // <36> } else if (result = VerifyLocNameFormat(startPB->locationName)) { CompleteWithResult(startPB,result); } else BeginLocalOrRemote(ppcglobPtr,(PPCParamBlockPtr)startPB,portPtr); } return PPCCommonPBExit(startPB, ppcglobPtr); } /*---------------------------------------------------------------------------------------- Main entry point to the PPCInformCall. ----------------------------------------------------------------------------------------*/ OSErr ppcInform(PPCInformPBPtr informPB) { PPCGlobalParamsPtr ppcglobPtr; PPCPortEntryPtr portPtr; // do common entry code for parameter block based calls if (PPCCommonPBEntry(informPB, &ppcglobPtr)) { informPB->csCode = PPCInformCall; // save command code if ((portPtr = PortRefNumtoPtr(informPB->portRefNum, ppcglobPtr)) == nil) { CompleteWithResult(informPB,noPortErr); } #ifdef notDefined // <36> else // <36> if(portPtr->serviceType == StoreAndForward || portPtr->serviceType == Both) // <36> { // <36> } // <36> #endif // <36> else // <36> { // <36> SetPortInformQue(informPB, portPtr); // <36> Wait for somthing. } // <36> } return PPCCommonPBExit(informPB, ppcglobPtr); } /*---------------------------------------------------------------------------------------- Main entry point to the PPCAccept call. ----------------------------------------------------------------------------------------*/ OSErr ppcAccept(PPCAcceptPBPtr acceptPB) { PPCGlobalParamsPtr ppcglobPtr; CommonSessionParams *sessPtr; // do common entry code for parameter block based calls if (PPCCommonPBEntry(acceptPB, &ppcglobPtr)) { acceptPB->csCode = PPCAcceptCall; // save command code if ((sessPtr = SessRefNumtoPtr(acceptPB->sessRefNum, ppcglobPtr)) == nil) { CompleteWithResult(acceptPB,noSessionErr); } else if (sessPtr->sessState != AwaitAcceptReq) { if (sessPtr->sessState == AwaitAbortComp) CompleteWithResult(acceptPB,noSessionErr); else CompleteWithResult(acceptPB,badReqErr); } else if (sessPtr->sessUse == locUse) { AcceptLocalSession(acceptPB, sessPtr,ppcglobPtr); } else if (sessPtr->sessUse == netUse) { AcceptNetworkSession(acceptPB,(NetIPCParamsPtr)sessPtr); } else { CompleteWithResult(acceptPB,paramErr); // <36> } } return PPCCommonPBExit(acceptPB, ppcglobPtr); } /*---------------------------------------------------------------------------------------- Main entry point to the PPCReject call. ----------------------------------------------------------------------------------------*/ OSErr ppcReject(PPCRejectPBPtr rejectPB) { PPCGlobalParamsPtr ppcglobPtr; CommonSessionParams *sessPtr; // do common entry code for parameter block based calls if (PPCCommonPBEntry(rejectPB, &ppcglobPtr)) { rejectPB->csCode = PPCRejectCall; // save command code if ((sessPtr = SessRefNumtoPtr(rejectPB->sessRefNum, ppcglobPtr)) == nil) { CompleteWithResult(rejectPB,noSessionErr); } else if (sessPtr->sessState != AwaitAcceptReq) { if (sessPtr->sessState == AwaitAbortComp) CompleteWithResult(rejectPB,noSessionErr); else CompleteWithResult(rejectPB,badReqErr); } else if (sessPtr->sessUse == locUse) { RejectLocalSession(rejectPB, sessPtr, ppcglobPtr); } else if (sessPtr->sessUse == netUse) { RejectNetworkSession(rejectPB,(NetIPCParamsPtr)sessPtr); } else { CompleteWithResult(rejectPB,paramErr); // <36> } } return PPCCommonPBExit(rejectPB, ppcglobPtr); } /*---------------------------------------------------------------------------------------- Main entry point to the PPCWrite call. ----------------------------------------------------------------------------------------*/ OSErr ppcWrite(PPCWritePBPtr writePB) { PPCGlobalParamsPtr ppcglobPtr; CommonSessionParams *sessPtr; // do common entry code for parameter block based calls if (PPCCommonPBEntry(writePB, &ppcglobPtr)) { writePB->csCode = PPCWriteCall; // save command code writePB->actualLength = 0; if ((sessPtr = SessRefNumtoPtr(writePB->sessRefNum, ppcglobPtr)) == nil) { CompleteWithResult(writePB,noSessionErr); // <36> } else if (sessPtr->sessState != DataXferState) { if (sessPtr->sessState == AwaitAbortComp) CompleteWithResult(writePB,noSessionErr); else CompleteWithResult(writePB,badReqErr); } else if (sessPtr->sessUse == locUse) { WriteLocalData( writePB, sessPtr, ppcglobPtr); } else if (sessPtr->sessUse == netUse) { WriteNetworkData(writePB,(NetIPCParamsPtr)sessPtr); } else // <36> { // <36> CompleteWithResult(writePB,paramErr); // <36> } } return PPCCommonPBExit(writePB, ppcglobPtr); } /*---------------------------------------------------------------------------------------- Main entry point to the PPCRead call. ----------------------------------------------------------------------------------------*/ OSErr ppcRead(PPCReadPBPtr readPB) { PPCGlobalParamsPtr ppcglobPtr; CommonSessionParams *sessPtr; // do common entry code for parameter block based calls if (PPCCommonPBEntry(readPB, &ppcglobPtr)) { readPB->csCode = PPCReadCall; // save command code readPB->actualLength = 0; if ((sessPtr = SessRefNumtoPtr(readPB->sessRefNum, ppcglobPtr)) == nil) { CompleteWithResult(readPB,noSessionErr); // <36> } else if (sessPtr->sessState != DataXferState) { if (sessPtr->sessState == AwaitAbortComp) CompleteWithResult(readPB,noSessionErr); else CompleteWithResult(readPB,badReqErr); } else if (sessPtr->sessUse == locUse) { ReadLocalData( readPB, sessPtr, ppcglobPtr); } else if (sessPtr->sessUse == netUse) { ReadNetworkData( readPB,(NetIPCParamsPtr)sessPtr); } else { CompleteWithResult(readPB,paramErr); } } return PPCCommonPBExit(readPB, ppcglobPtr); } /*---------------------------------------------------------------------------------------- Main entry point to the PPCEnd call. ----------------------------------------------------------------------------------------*/ OSErr ppcEnd(PPCEndPBPtr endPB) { PPCGlobalParamsPtr ppcglobPtr; CommonSessionParams *sessPtr; // do common entry code for parameter block based calls if (PPCCommonPBEntry(endPB, &ppcglobPtr)) { endPB->csCode = PPCEndCall; // save command code if (sessPtr = SessRefNumtoPtr(endPB->sessRefNum, ppcglobPtr)) { if (sessPtr->sessState == DataXferState) { if (sessPtr->sessUse == locUse) { sessPtr = DeleteSessByRefNum(endPB->sessRefNum, ppcglobPtr); EndLocalSession( endPB, sessPtr, ppcglobPtr); } else if (sessPtr->sessUse == netUse) { sessPtr = DeleteSessByRefNum(endPB->sessRefNum, ppcglobPtr); EndNetworkSession(endPB,(NetIPCParamsPtr) sessPtr); } else { CompleteWithResult(endPB,noSessionErr); } } else { CompleteWithResult(endPB,noSessionErr); } } else { CompleteWithResult(endPB,noSessionErr); } } return PPCCommonPBExit(endPB, ppcglobPtr); } /*---------------------------------------------------------------------------------------- Main entry point to the PPCClose call. ----------------------------------------------------------------------------------------*/ OSErr ppcClose(PPCClosePBPtr closePB) { PPCGlobalParamsPtr ppcglobPtr; PPCPortEntryPtr portPtr; // do common entry code for parameter block based calls if (PPCCommonPBEntry(closePB, &ppcglobPtr)) { closePB->csCode = PPCCloseCall; // save command code if (portPtr = DeletePortByRefNum(closePB->portRefNum, ppcglobPtr)) { ClosePortTable(closePB, portPtr, ppcglobPtr); } else { CompleteWithResult(closePB,noPortErr); } } return PPCCommonPBExit(closePB, ppcglobPtr); } /*---------------------------------------------------------------------------------------- Main entry point to the IPCListPorts call. ----------------------------------------------------------------------------------------*/ OSErr ipcListPorts(IPCListPortsPBPtr listPB) { PPCGlobalParamsPtr ppcglobPtr; OSErr result; // do common entry code for parameter block based calls if (PPCCommonPBEntry(listPB, &ppcglobPtr)) { listPB->csCode = IPCListPortsCall; // save command code if (!ValidPortName(listPB->portName)) { CompleteWithResult(listPB,badPortNameErr); // <36> } else if (result = VerifyLocNameFormat(listPB->locationName)) { CompleteWithResult(listPB,result); } else BeginLocalOrRemote(ppcglobPtr,(PPCParamBlockPtr)listPB,NULL); } return PPCCommonPBExit(listPB, ppcglobPtr); } /*---------------------------------------------------------------------------------------- PPCCommonPBEntry is called at the beginning of all parameter block based calls. It returns true if PPC can even deal with PB calls right now. We make sure we have globals, and that we are initialized first. We then prepare ourself to process the request. WARNING: This routine has strange calling conventions. It depends upon register D1 having the the PPCToolBox trap word in register D1. C ----------------------------------------------------------------------------------------*/ STATIC Boolean PPCCommonPBEntry(void *PB, PPCGlobalParamsPtr *ppcglobPtrPtr) PPCParamBlockPtr PB; { PPCGlobalParamsPtr ppcglobPtr; PBWriteResPtr res; // <36> unsigned short PPCTrap; PPCTrap = GetD1(); #ifdef DEBUG if(PPCTrap != 0xA0DD && PPCTrap != 0xA4DD) DebugStr("\pRegister D1 did not have our trap word"); #endif if(*ppcglobPtrPtr = ppcglobPtr = getGlobal()) // get globals { // save application's A5 res = (PBWriteResPtr)(PB->startParam.Reserved); // <36> res->ApplA5 = GetA5(); // <36> res->cmdMode = PPCTrap & 0x0400?true:false; // <36> if (!ppcglobPtr->inited) { CompleteWithResult(PB,notInitErr); return(false); } // mark PB as busy PB->startParam.ioResult = 1; // increment nesting level ++ppcglobPtr->inEntry; // replenish resources if call made synchronously if(!res->cmdMode) // <36> Replenish(ppcglobPtr); return(true); // We are prepared to process this request. } else // No Globals, return false and let PPCCommonPBExit handle it. { return false; } } /*---------------------------------------------------------------------------------------- PPCCommonPBExit is called at the end of all parameter block based calls. Note if PPCCommonPBEntry returned false because we don't have globals, we will no this here since the ppcglobPtr will be NULL. So we have to complete the request differently in this because CompleteWithResult depends upon globals being present. ----------------------------------------------------------------------------------------*/ STATIC OSErr PPCCommonPBExit(void *PB, PPCGlobalParamsPtr ppcglobPtr) PPCParamBlockPtr PB; { short result = PB->startParam.ioResult; if(ppcglobPtr) // Should always be no zero, but one never knows! { if(ppcglobPtr->inEntry == 1) // If at outermost Entry in stack frame { PPCParamBlockPtr tempPB; // complete all pending calls. do { short p; p = spl(kNoInterrupts); // Extremely Critical Code. if(!ppcglobPtr->CompletedPBQueue.qSize) // if the queue is empty { --ppcglobPtr->inEntry; // We will allow direct call of comp routines. spl(p); // restore the interrupt level. break; // Done with this loop. } else // Somthing is in the queue! { spl(p); // Restore interrupts to the way they were. tempPB = ServeQueue(&ppcglobPtr->CompletedPBQueue); // Get user PB. CallCompletionRoutine(tempPB,tempPB->startParam.ioResult); // Call comp routine } } while(true); // Repeat until the queue is empty. if (!((PBWriteResPtr)(PB->startParam.Reserved))->cmdMode) // <36> if Synchronous { while (PB->startParam.ioResult == 1); // Wait for the call to complete. return PB->startParam.ioResult; } } else // Not at top level. --ppcglobPtr->inEntry; // Decrease our level indicator. // if call still processing, return noErr, else return result return(result == 1 ? noErr : result); } else { CallCompletionRoutine(PB,noGlobalsErr); return(noGlobalsErr); } } STATIC void NetOpenCompletion(void) { PPCPortEntryPtr portPtr; PortLocationTablePtr locInfo; PPCOpenPBPtr openPB; locInfo = GetA0(); portPtr = locInfo->portPtr; openPB = (PPCOpenPBPtr)(portPtr->openPB); /* get back the openPB */ if (locInfo->nbpPB.ioResult == noErr) portPtr->nbpRegistered = openPB->nbpRegistered = true; // we did register with nbp portPtr->openPB = nil; // This is important CompleteWithResult(openPB,noErr); } // NetNBPCompletion STATIC void CallCompletionRoutine(PPCParamBlockPtr PB,OSErr ioResult) { PPCReservedPtr res = (PPCReservedPtr)(&(PB->startParam.Reserved[0])); if (res->cmdMode) // if Asynchronous { callCompletion(PB, ioResult); // Save AppA5 and call completion } } /*---------------------------------------------------------------------------------------- CompleteWithResult prepares and completes the usage of the client's parameter block with the specified result code. If we are not inEntry, then the call is complete immediatly, otherwise it is place on the CompletedPBQueue to be served later when the stack unwinds within PPCCommonPBExit. ----------------------------------------------------------------------------------------*/ OSErr CompleteWithResult(void *PB,OSErr Result) PPCParamBlockPtr PB; { PPCGlobalParamsPtr ppcglobPtr; PB->closeParam.ioResult = Result; ppcglobPtr = getGlobal(); if(ppcglobPtr->inEntry) { EnQueue(PB,&ppcglobPtr->CompletedPBQueue); } else CallCompletionRoutine(PB,Result); return(Result); // For callers convience! } /*---------------------------------------------------------------------------------------- VerifyLocNameFormat is used to verify that a location name can be used to start a session. It just checks the structure. ----------------------------------------------------------------------------------------*/ OSErr VerifyLocNameFormat(LocationNamePtr locName) { if(locName) { if (locName->locationKindSelector == ppcNoLocation) return noErr; // NoLocation implies local. if (locName->locationKindSelector != ppcNBPLocation) return nameTypeErr; // we don't understand any other type if (locName->u.nbpEntity.objStr[0] > 32 || locName->u.nbpEntity.typeStr[0] > 32 || locName->u.nbpEntity.zoneStr[0] > 32) return badLocNameErr; // NOTE: little known AppleTalk fact, a zero length zone string indicates this zone. // That is why I won't check for minimum length on the zone string here. if (locName->u.nbpEntity.objStr[0] == 0 || locName->u.nbpEntity.typeStr[0] == 0) return badLocNameErr; } return(noErr); } /*---------------------------------------------------------------------------------------- LocationNameLocal Determines if the given location name exists on this machine. ----------------------------------------------------------------------------------------*/ Boolean LocationNameLocal(LocationNamePtr locName) { PortLocationTablePtr locInfo; PPCGlobalParamsPtr ppcglobPtr; PPCPortEntryPtr portPtr; // <36> if(!locName) return(true); if (locName->locationKindSelector == ppcNoLocation) return(true); ppcglobPtr = getGlobal(); if(locName->u.nbpEntity.zoneStr[0] == 0 || (locName->u.nbpEntity.zoneStr[0] == 1 && locName->u.nbpEntity.zoneStr[1] == '*') || EqualString(locName->u.nbpEntity.zoneStr,ppcglobPtr->zoneName,false,true)) { // At this point the zone is our zone, so we will check the object. if(EqualString(locName->u.nbpEntity.objStr,ppcglobPtr->machineName,false,true)) { if(EqualString(locName->u.nbpEntity.typeStr, ppcglobPtr->configData.ppctoolboxName,false,true)) return(true); else { short sr; sr = spl(kNoInterrupts); // Make sure we don't have any problems. FOREACHELEMENT(portPtr,&ppcglobPtr->OpenPortQueue) { if (locInfo = portPtr->locationInfo) { if (EqualString(locName->u.nbpEntity.typeStr, locInfo->typeStr,false,true)) { spl(sr); return(true); // Name is locally registered already } } } spl(sr); } } } NotLocal: return(false); } /*---------------------------------------------------------------------------------------- LocNameTaken determines if the typeStr is currently in use in this machine for some port. ----------------------------------------------------------------------------------------*/ STATIC Boolean LocNameTaken(LocationNamePtr locationName,PPCGlobalParamsPtr ppcglobPtr) { short sr; Boolean isTaken; PPCPortEntryPtr portPtr; // <36> isTaken = false; sr = spl(kNoInterrupts); FOREACHELEMENT(portPtr,&ppcglobPtr->OpenPortQueue) { if(portPtr->locationInfo) { if(EqualString(locationName->u.nbpType, portPtr->locationInfo->typeStr, false,true)) /* case insensitive, diacritical sensitive */ { isTaken = true; break; } } } spl(sr); return(isTaken); } /*---------------------------------------------------------------------------------------- BeginLocalOrRemote begins a local or remote request for IPCListPorts or PPCStart. It has a side effect of updating our global down-below with our current zone name, keeping it fresh. NOTE there exists an interesting, but harmless race condition, worst case we perform a GetMyZone call and when it completes have nothing to processes, casue it was already taken care of. ----------------------------------------------------------------------------------------*/ STATIC void BeginLocalOrRemote(PPCGlobalParamsPtr ppcglobPtr,PPCParamBlockPtr PB,void *portPtr) { short sr; PB->startParam.intUsePtr = portPtr; // Remember this for later in case of PPCStart. EnQueue(PB,&ppcglobPtr->BeginLRQueue); sr = spl(kNoInterrupts); if(ppcglobPtr->BeginLRQueue.qSize == 1) // Not currently performing a GetMyZone. { spl(sr); DoGetMyZone(&ppcglobPtr->xpb, // Use this parameter block true, // do this asyncrhonously (ProcPtr)LocalOrNot, // Completion Routine. &ppcglobPtr->zoneName); // here is where to put the zone name. } else spl(sr); } /*---------------------------------------------------------------------------------------- LocalOrNot is chained from BeginLocalOrRemote. It processes the list pending IPCListPorts and PPCStart requests by branching to the appropriate routine, or completing the request with an error if we don't support remote request. ----------------------------------------------------------------------------------------*/ STATIC void LocalOrNot(void) { PPCGlobalParamsPtr ppcglobPtr; Boolean Local; PPCParamBlockPtr PB; ppcglobPtr = getGlobal(); if(ppcglobPtr->xpb.ioResult) BlockMove("\p*",ppcglobPtr->zoneName,2); while(PB = ServeQueue(&ppcglobPtr->BeginLRQueue)) // Batch process the requests. { Local = LocationNameLocal(PB->startParam.locationName); if (!Local && !ppcglobPtr->canRemote) // If its remote, and we can't, then { CompleteWithResult(PB,localOnlyErr); continue; } if(PB->startParam.csCode == PPCStartCall) { if(Local) StartLocalSession((PPCStartPBPtr)PB,(PPCPortEntryPtr)PB->startParam.intUsePtr, ppcglobPtr); else StartNetworkSession((PPCStartPBPtr)PB,(PPCPortEntryPtr)PB->startParam.intUsePtr, ppcglobPtr); } else // Must be an IPCListPorts request { if(Local) ListLocalPorts((IPCListPortsPBPtr)PB, ppcglobPtr); else ListNetworkPorts((IPCListPortsPBPtr)PB, ppcglobPtr); } } } /*---------------------------------------------------------------------------------------- DoGetMyZone performs the task of a GetMyZone call, its just a nice interface to perform such a boring task. ----------------------------------------------------------------------------------------*/ STATIC void DoGetMyZone(XCallParam *xpb, Boolean async, ProcPtr compRtn, Str32 zoneName) { OSErr result; xpb->ioCompletion = compRtn; xpb->zipBuffPtr = (Ptr)zoneName; xpb->zipInfoField[0] = 0; xpb->zipInfoField[1] = 0; xpb->xppTimeout = 1; xpb->xppRetry = 3; if (getGlobal()->mppOpen) { #ifdef JimFixedTheGlue result = DMFix(GetMyZone((XPPParmBlkPtr)xpb, async),xpb); #else xpb->csCode = xCall; xpb->xppSubCode = zipGetMyZone; xpb->ioRefNum = xppRefNum; result = DMFix(PBControl((ParmBlkPtr)xpb, async),xpb); #endif } else // pretend we are .XPP for a moment. { BlockMove("\p*",zoneName,2); xpb->ioResult = noErr; FakeCompletion(xpb); } } /*---------------------------------------------------------------------------------------- DMFix checks to see if the error code in a parameter block was returned by the Device Manager. The Device Manger fails to call the completion routine specified in the parameter block. So I will check for the known cases when this happens, and if its one of them, call the completion routine as if I were the device manager doing its job properly. ----------------------------------------------------------------------------------------*/ OSErr DMFix(OSErr Result,void *thePB) MPPparms *thePB; { if(Result == notOpenErr || Result == badUnitErr) { if(thePB->ioCompletion) // Assume if completion routine specified, call is async. { FakeCompletion(thePB); // Calls the completion routine with Device Manager calling conventions. } } return(Result); }