mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-27 10:29:32 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
2534 lines
79 KiB
C
2534 lines
79 KiB
C
/*
|
|
File: Eppc.c
|
|
|
|
Contains: Routines which implement Event Process-to-Process Communication (EPPC),
|
|
aka high-level events.
|
|
|
|
Written by: Jay Moreland
|
|
|
|
Copyright: © 1989-1992 by Apple Computer, Inc., all rights reserved.
|
|
|
|
Change History (most recent first):
|
|
|
|
<26> 5/29/92 DCL Included Script.h. GetEnvirons moved for the New Inside Mac.
|
|
<25> 11/25/91 DTY Add #include <MemoryMgrPriv.h> to get interface for MoveHLow in
|
|
its new home.
|
|
<24> 11/21/91 DTY Rolling in the 7¥Up version of findFreeSessionRecord that
|
|
allocates the session record low in the System Heap instead of
|
|
in the middle of the temporary heap. This is conditionalized for
|
|
CubeE only until a decision is made about whether this is really
|
|
the way we want to fix the problem.
|
|
<23> 3/29/91 JWM CCN,#85997: In GetSpecificHighLevelEvent, it was possible to
|
|
exit without restoring eppcBlk->mfMsgBlk to its original value.
|
|
This would cause event_common to call flushMsg for a HLE that
|
|
was still linked into the app's HLE Queue. As part of flushMsg
|
|
the memory would be returned to the free pool. This caused weird
|
|
memory roaching problems. The fix is a one line addition in
|
|
c_GetSpecificHighLevelEvent during the error path for the second
|
|
copyMsg.
|
|
<22> 3/26/91 DTY Having been thoroughly chastised by Jay for touching the source
|
|
code without him standing next to me, IÕm about to risk his
|
|
wrath again to make things the way they were in version <20>.
|
|
<21> 3/25/91 DTY JDR, #85618: The Gang of Five relegated this bug to Post 7.0, so
|
|
it needed to be rolled out. The other change, JWM-001, was left
|
|
in.
|
|
<20> 3/25/91 JWM jc,#JWM-001,#85618: ¥removing a DisposHandle from inside a loop
|
|
where interrupts are disabled. ¥removing the restriction on
|
|
starting a session when the application is being coerced.
|
|
<19> 3/18/91 JWM ewa,#85038, #85039: ¥The System crashes when
|
|
GetSpecificHighLevelEvent is called twice in a row with no
|
|
events pending and there is a partial HLEvent outstanding.
|
|
¥GetSpecificHighLevelEvent goes through the HighLevelEventQueue
|
|
twice if AcceptHighLevelEvent is called for the last event in
|
|
the HighLevelEventQueue from within the filter function.
|
|
<18> 2/26/91 JWM DFH,#83798: fix bug where ports are sometimes left open.
|
|
<17> 2/21/91 DFH dba,#82504, #82681, #83168, #83182, #83207: HiNewHandle rolled
|
|
into ProcessMgrHiNewHandle.
|
|
<16> 2/21/91 JWM ewa,#83492,#78885: ¥The System crashes when processing a return
|
|
receipt over a network for an application which has quit and is
|
|
no longer running. Fix is in scanReadBQ. ¥QuarkXPress 3.0 Ñ
|
|
Double clicking on the document opens the app, but not the
|
|
document. fix is in makePortname. ¥Also call PPC post processor
|
|
routines (scanReadBQ, scanWriteBQ and scanInformBQ) when
|
|
GetSpecificHighLevelEvent is called. This is for AppleEvent
|
|
manager.
|
|
<15> 2/9/91 JWM DFH,#79583,#81622,#82463: ¥Restart and Shutdown don't work in
|
|
low memory conditions. Routines getPPCRead, getPPCInformPB,
|
|
findFreeSessionRecord, GetMsgEventBuffer, fetchMsgData use to
|
|
call ProcessMgrHiNewHandle. ProcessMgrHiNewHandle just searched
|
|
the Process Managers heap. The routines now call GMBlk which
|
|
follows an unsucessful search of the Process Manager's heap with
|
|
a search of the System's heap. In addition,
|
|
AppleEventExtensions.c and Puppet.c were modified to use GMBlk
|
|
instead of just looking in the Process Manager's heap. GMBlk is
|
|
defined in Data.h and implemented in Memory.c. ¥Event PPC does
|
|
not register the correct port name with the correct name script
|
|
for foriegn systems. The PPCPortname has a script code which was
|
|
being stuffed with 0 in makePortName. A call is now made to
|
|
GetEnvirons to fetch the script code of the system script. This
|
|
value is place in the PPCPortName when open the PPCPort on
|
|
behalf of the app. ¥The maximum number of IDENTICAL Portnames
|
|
that can be browsed on the browser is 8. Any number over 8 will
|
|
not be recognize as EPPC aware application. A bug was introduced
|
|
in 7.0b1 in the routine GetNextPortName. StringByte is defined
|
|
as having a 0 based index instead of 1 based index. This caused
|
|
the code which runs in an attempt to generate a unique
|
|
PPCPortname to generate 8 uniques name instead of the 99 it
|
|
should have.
|
|
<14> 1/28/91 LN Changed connectionInValid to conectionInvalid to match change in
|
|
EPPC.h. Sorry Jay.
|
|
<13> 1/10/91 JWM (DFH) ¥1 BRC #79831 allow app to post using kCurrentProcess
|
|
constant. The change was in a parameter to the first
|
|
EPPCBlkFromPSN in GetConnectionType. Before <13>, EPPCBlkFromPSN
|
|
was called using the PSN Ptr in the PostHighLevelEvent. The fix
|
|
was to use the PSN in the process table. This means when the
|
|
caller of PostHighLevelEvent uses pCurrentProcess or
|
|
pFrontProcess, GetConnectionType will find the eppcBlk
|
|
associated with the target process. (EMT) ¥2 To keep the IO
|
|
completion routine (KnockKnock) from someday getting hung while
|
|
spinning on the ioresult field in the async PPCAccept or
|
|
PPCReject parameter block, a new switch was added for command
|
|
completion of a PPCAccept and PPCReject. The ppcInformBlk was
|
|
modified to include a PPCRejectParams structure
|
|
(ppcInformReplyPB). This structure is used for both the async
|
|
PPCReject and the async PPCAccept which occur when processing a
|
|
completion of a PPCInform. This change is isolated to
|
|
KnockKnock. (DFH) ¥3 Rework the DisableInterrupts and
|
|
EnableInterrupts macros to require fewer instruction for
|
|
compiler generated setup.
|
|
<12> 12/21/90 LN change constStrxxxParameter to ConstStrxxxParam as per change in
|
|
Types.h
|
|
<11> 12/21/90 DFH (gb) Added A5 setup in GetNextHighLevelEvent.
|
|
<10> 12/20/90 DFH (dba) Convert GetNextHighLevelEvent to a dispatch.
|
|
<9> 12/19/90 gbm (dba) Fix pointer arithmetic bugs throughout the file, including
|
|
the one that kept us from quitting applications with the 32-bit
|
|
Memory Manager.
|
|
<8> 12/14/90 JWM change rtrnReciptMsgID to rtrnReceiptMsgID
|
|
<7> 12/13/90 JWM Make the checkin comments look right
|
|
<6> 12/13/90 JWM DFH ¥1 Fix a bug with doDuplicateNameOpen. The termination of the loop
|
|
is wrong.
|
|
DFH ¥2 Added a call to Delete User Identity after a StartSecureSession
|
|
call. eppc doesn't need the User Identity. Deleting it frees up
|
|
resources inside the PPCToolbox.
|
|
DFH ¥3 StartSecureSession may cause the Dialog Manager to run. It is
|
|
best if our app's A5 is in the machine because user items in
|
|
dialog windows behind the authentication dialog(s) may execute.
|
|
Some user item procedures assume that A5 points to the application's
|
|
global not the Process Manager's globals.
|
|
DFH ¥4 The PPCToolbox as of 7.0B3 will no longer return errors through
|
|
PPCInit. References to ppcInitErr have been removed. In addition
|
|
a message was formatted and sent to the Shell if ppcInitErr did not
|
|
equal 0 (noErr). This message will be elimated in Startup.c.
|
|
DFH ¥5 BRC #78779-During PostHighLevelEvent to a remote machine,
|
|
if a proper port location is specified, but not a proper port name (i.e.
|
|
port name doesn't exist on the target machine), then the authentication
|
|
dialog is brought up. This behavior was fixed by making guestAllowed
|
|
return destPortErr (-906) if listPortPB.actualCount IS 0. getSessionID
|
|
will see the destPortErr and not call StartSecureSession.
|
|
DFH ¥6 Request from DTS to place TICKS in the when field of the event when
|
|
the message arrives. This is now done in KnockKnock when a read completes.
|
|
DFH ¥7 BRC # 78336ÐHighLevel event posted shortly before an application quits
|
|
does not get delivered to its target. This ÔbugÕ needs fixing. It is
|
|
due to closing the ppc port of an application during _ExitToShell. This
|
|
close causes all outstanding i/o for a port to go to completion. Any
|
|
post an application did between his last _WaitNextEvent and _ExitToShell
|
|
may not be delivered. This is due to the facts that processing the
|
|
i/o completion queues for PPCToolbox calls occurs during WaitNextEvent
|
|
if the system decides to call GetNextHLE and that PPCClose causes any
|
|
outstanding PPCWrites to end with an error. A goal for eppc has been
|
|
to shield the application writer from the async nature of the PPCToolbox
|
|
In this spirit, code was changed to keep ppc ports open after
|
|
application calls _ExitToShell if the port has PPCWrites which are
|
|
still pending. This allow the posts of a terminated application to
|
|
complete. Note: the PPCWrite still could error, but no one is
|
|
listening.
|
|
Changes to affect leaving the ppc port open after application
|
|
_ExitToShell involved storing the address of the last PPCWrite in
|
|
the session record, not breaking connections with outstanding
|
|
PPCWrites during _ExitToShell, closing the port when the last PPCWrite
|
|
completed and weaning all code paths in eppc that run after
|
|
_ExitToShell from there dependence on the EPPCBlk which goes away
|
|
at _ExitToShell.
|
|
DFH ¥8 An application posting a high level event from the background which
|
|
requires the network authenication dialog will receive an error
|
|
noUserInteractionAllowed (Ð610). This was done to fix the User Interface
|
|
NoÐNo of bringing up the a modal dialog when the application was
|
|
not the frontmost. Note: this situation occurs only on the first
|
|
post to a remote target. The application writer should use the
|
|
notification manager to indicate a need to interact with the user.
|
|
When the user brings the application forward, the application writer
|
|
should do the post again. After the post is sucessful, the
|
|
application can return to the background and post messages to the
|
|
remote target without the noUserInteractionAllowed error.
|
|
DFH ¥9 In eppc:getSessionID there were two error paths which did not release
|
|
the session table entry correctly.
|
|
<5> 11/26/90 DFH Change trespass() to dbmsg().
|
|
<4> 11/6/90 JWM ¥1 for the priority 1 bug dealing with an assert error when the
|
|
sender quits before the receiver has been delivered all his
|
|
messages.
|
|
¥2 you can now post messages of minimum unsigned long through
|
|
maximum unsigned long, if you have the memory.
|
|
¥3 In previous releases, when you didnÕt accept a message fully
|
|
an incorrect return message receipt was return to the sender.
|
|
This is now fixed and works as documented.
|
|
¥4 In previous releases three memory allocations and two memory
|
|
releases were necessary for each message received. In this
|
|
version each number has been reduced by one.
|
|
¥5 In previous releases, if the first PPCRead failed, the
|
|
connection would go dormant. In this release if the first
|
|
PPCRead fails for reasons other than sessionClosedErr or
|
|
noSessionErr, the connection is broken and the targetÕs session
|
|
table entry is updated to reflect the connection was explicitly
|
|
broken. If the reason was sessionClosedErr or noSessionErr, the
|
|
targetÕs connection table entry is updated to reflect the
|
|
connection was broken by the other end. Both these states are
|
|
seen from the programmerÕs view as sessionClosedErr if he tries
|
|
to post using for him what is a valid connection. He must
|
|
repost his message to establish a new connection with his
|
|
target.
|
|
¥6 In previous releases, if the second PPCRead failed, the
|
|
connection was broken and the targetÕs session table entry is
|
|
updated as in ¥4. However in the second read there are two
|
|
different classes of errors Ð memory errors and PPCToolbox
|
|
errors. In this release, memory errors cause the system to
|
|
restart the second read at a later time when, hopefully, the
|
|
memory configuration has changed. This change keeps the system
|
|
from breaking a session because of memory shortage. In the
|
|
previous release breaking the connection because of memory
|
|
failure caused the PPCWrites on the other end of the connection
|
|
to fail. Sometimes there were a lot of writes. For instance in
|
|
the Large Data Buffer test.
|
|
<2> 10/30/90 csd Update the symbols to match the headers on BBS.
|
|
<0> 9/02/89 JM New Today.
|
|
|
|
*/
|
|
|
|
#include <Errors.h>
|
|
#include <MFPrivate.h>
|
|
#include <Memory.h>
|
|
#include <MemoryMgrPriv.h>
|
|
#include <PPCToolBox.h>
|
|
#include <AppleEventsInternal.h>
|
|
#include <Errors.h>
|
|
#include <Resources.h>
|
|
#include <Values.h>
|
|
#include <Script.h>
|
|
|
|
#include "Data.h"
|
|
#include "Glue.h"
|
|
#include "Zone.h"
|
|
#include "Lomem.h"
|
|
#include "Patches.h"
|
|
#include "AppleEventExtensions.h"
|
|
|
|
#define IS ==
|
|
#define ISNT !=
|
|
#define AND &&
|
|
#define OR ||
|
|
|
|
#define ppcOpenCmd 1
|
|
#define ppcStartCmd 2
|
|
#define ppcInformCmd 3
|
|
#define ppcAcceptCmd 4
|
|
#define ppcRejectCmd 5
|
|
#define ppcWriteCmd 6
|
|
#define ppcReadCmd 7
|
|
#define ppcEndCmd 8
|
|
#define ppcCloseCmd 9
|
|
#define IPCListPortsCmd 10
|
|
|
|
typedef short ConnectionType;
|
|
#define eppcConnection (0)
|
|
#define systemReceiverConnection (1)
|
|
#define systemSenderConnection (2)
|
|
#define noEppcConnection (3)
|
|
#define badConnection (4)
|
|
|
|
#define noSessionID (0)
|
|
#define systemSessionID (-1)
|
|
|
|
#define INITIALIZED(eBlk) (eBlk->portID != 0)
|
|
#define TarEPPCBlkPtr(pPtr) (&(pPtr->eppcBlk))
|
|
#define CanDoEPPC(pPtr) (INITIALIZED(TarEPPCBlkPtr(pPtr)))
|
|
|
|
/* status bits in the Inform, Read and Write parameter blocks */
|
|
|
|
#define closeInProgress 0x8000
|
|
|
|
/* status bits in cTableEntry */
|
|
|
|
#define informConnection 0x8000
|
|
#define startConnection 0x4000
|
|
#define sessionClosed 0x2000
|
|
#define sessionEnded 0x1000
|
|
#define waitingForWrites 0x0800
|
|
#define HLEQDoesNotExist 0x0400
|
|
|
|
#define sizeOfPPCpbHeader (sizeof(LINKTYPE)+sizeof(Handle)+sizeof(EPPCBlkPtr)+2*sizeof(unsigned long))
|
|
#define sizeOfPPCWriteBlk (sizeOfPPCpbHeader+sizeof(PPCWritePBRec))
|
|
#define sizeOfPPCReadBlk (sizeOfPPCpbHeader+sizeof(PPCReadPBRec))
|
|
#define sizeOfPPCInformBlk (sizeOfPPCpbHeader+sizeof(PPCInformPBRec))
|
|
|
|
#define CheckForFatalError assert
|
|
|
|
#define SYNCHRONOUS 0
|
|
#define ASYNCHRONOUS 1
|
|
|
|
#define NROFINFORMPBS 3
|
|
|
|
#define MAXNROFTRIES 99
|
|
|
|
typedef struct ppcWriteBlk {
|
|
LINKTYPE ppcWriteBlkQ;
|
|
Handle pbHdl;
|
|
EPPCBlkPtr pbID;
|
|
unsigned long portID;
|
|
unsigned long status;
|
|
PPCWritePBRec ppcWritePB;
|
|
MFmsgBlk mfMsgBlk;
|
|
} ppcWriteBlk, *ppcWritePBPtr;
|
|
|
|
typedef struct ppcReadBlk {
|
|
LINKTYPE ppcReadBlkQ;
|
|
Handle pbHdl;
|
|
EPPCBlkPtr pbID;
|
|
unsigned long portID;
|
|
unsigned long status;
|
|
PPCReadPBRec ppcReadPB;
|
|
MFmsgBlk mfMsgBlk;
|
|
} ppcReadBlk, *ppcReadPBPtr;
|
|
|
|
typedef struct ppcInformBlk {
|
|
LINKTYPE ppcInformBlkQ;
|
|
Handle pbHdl;
|
|
EPPCBlkPtr pbID;
|
|
unsigned long portID;
|
|
unsigned long status;
|
|
PPCInformPBRec ppcInformPB;
|
|
PPCRejectPBRec ppcInformReplyPB; // <13>
|
|
PPCPortRec portName;
|
|
LocationNameRec portLoc;
|
|
} ppcInformBlk, *ppcInformPBPtr;
|
|
|
|
typedef struct cTableEntry {
|
|
LINKTYPE sLList; /* queue element */
|
|
Handle sHdl; /* handle for element */
|
|
unsigned long sportID; /* port id for _ExitToShell fix */
|
|
unsigned long sID; /* session id */
|
|
short status; /* status word */
|
|
PPCReadPBPtr srPB; /* outstanding read */
|
|
PPCWritePBPtr swPB; /* outstanding write */
|
|
EPPCBlkPtr sEppcBlkPtr;/* eppc control block */
|
|
PPCPortRec sPName; /* whose port name - depends on status */
|
|
LocationNameRec sLocName; /* whose location - depends on status */
|
|
} cTableEntry, *cTableEntryPtr, **cTableEntryHdl;
|
|
|
|
void KnockKnock(PPCParamBlockPtr ppcPB);
|
|
ConnectionType GetConnectionType(ProcessSerialNumberPtr postersPSN, unsigned long receiverID, unsigned long postingOptions, unsigned long *connectionID, ProcessSerialNumberPtr targetsPSN, OSErr *err);
|
|
unsigned long validateSessionID(ProcessSerialNumberPtr ownersPSN, unsigned long sessionID, OSErr *err);
|
|
Boolean PSNFromName(const PPCPortPtr portName, ProcessSerialNumberPtr pPSN);
|
|
Boolean PSNFromSignature(const ResType signature, ProcessSerialNumberPtr pPSN);
|
|
Boolean findElement(char *A, char *B);
|
|
Boolean byPBID(ppcWritePBPtr A, EPPCBlk *B);
|
|
MFmsgBlkPtr GetMsgEventBuffer (u_long lengthInBytes, OSErr *err);
|
|
unsigned long getSessionID(ProcessSerialNumberPtr sendersPSN, TargetIDPtr portN, OSErr *err);
|
|
EPPCBlkPtr EPPCBlkFromPSN(ProcessSerialNumberPtr psn);
|
|
PPCParamBlockPtr getPPCInformPB(EPPCBlkPtr refCon, unsigned short portRefNum, OSErr *err);
|
|
PPCParamBlockPtr getPPCReadPB(EPPCBlkPtr refCon, unsigned long sessionID, OSErr *err);
|
|
void releasePPCpb(PPCParamBlockPtr pb);
|
|
void postMsgToPPC(const MFmsgBlkPtr msgBlk, unsigned long sessionID, OSErr *err);
|
|
MFmsgBlkPtr fetchMsgData(EPPCBlkPtr eppcBlkPtr, MFmsgBlkPtr mfMsgBlk, OSErr *err);
|
|
void scanInformBQ(void);
|
|
void scanWriteBQ(void);
|
|
void scanReadBQ(void);
|
|
void getSessionRecord(SenderIDPtr senderID, EPPCBlk *recvrEppcB);
|
|
HighLevelEventMsgHdl
|
|
copyMsg(MFmsgBlkPtr aMsg, OSErr *err);
|
|
Boolean guestAllowed(TargetIDPtr portN, OSErr *err);
|
|
Boolean comparePortLocation(LocationNamePtr L1, LocationNamePtr L2);
|
|
Boolean comparePortNames(PPCPortPtr N1, PPCPortPtr N2);
|
|
void closePPCPort(unsigned long portID);
|
|
void openPPCPort(EPPCBlkPtr eppcB);
|
|
Boolean PortNameAndLocationAreEqual(PPCPortPtr portName, LocationNamePtr locName, TargetIDPtr targetID);
|
|
TargetID getTIDfromEppcBlk(EPPCBlkPtr eppcBPtr);
|
|
ppcReadPBPtr startPPCRead(EPPCBlkPtr eppcBPtr, unsigned long sessionID, OSErr *err);
|
|
ppcReadPBPtr restartPPCRead(ppcReadPBPtr rPB, OSErr *err);
|
|
PEntryPtr PEntryFromPSN(ProcessSerialNumberPtr pPSN);
|
|
cTableEntryPtr findSessionRecord(unsigned long sessionRefNum);
|
|
cTableEntryPtr findFreeSessionRecord(void);
|
|
void makePortName(EPPCBlkPtr eppcB);
|
|
void doDuplicateNameOpen(EPPCBlkPtr eppcB, PPCOpenPBPtr PPCpb);
|
|
void GetNextPortName(EPPCBlkPtr eppcB);
|
|
void DeleteBQEntries(unsigned long portID, LINKLIST *theBQ);
|
|
void qPPCPb(ppcWritePBPtr wPBPtr, LINKLIST *BQList);
|
|
void FlushHLEQueue(EPPCBlkPtr eppcBlk, Boolean sendReturnReceipts, short rtnMsg);
|
|
Boolean NameFromPSN(PPCPortPtr portName, ProcessSerialNumberPtr pPSN);
|
|
Boolean bySessionID(cTableEntryPtr A, unsigned long *B);
|
|
Boolean bysEppcBlkPtr(cTableEntryPtr A, EPPCBlk *B);
|
|
Boolean byportID(cTableEntryPtr A, unsigned long *B);
|
|
Boolean byportIDforPB(ppcWriteBlk *A, unsigned long *B);
|
|
short breakConnections(unsigned long portID);
|
|
void endSessionAfterAReadError(cTableEntryPtr sRec, OSErr err);
|
|
|
|
#pragma parameter DisableInterrupts(__A0)
|
|
void DisableInterrupts(unsigned short *oldMask) = {0x40D0, 0x007C, 0x0700};
|
|
/* move sr, (a0)
|
|
* ori.w 0x0700, sr
|
|
*/
|
|
|
|
#pragma parameter EnableInterrupts(__D0)
|
|
void EnableInterrupts(unsigned short oldMask) = {0x46C0};
|
|
/* move.w d0,sr
|
|
*/
|
|
|
|
typedef pascal Boolean
|
|
(*hleFilter_ptr)(unsigned long *params, Ptr msgBuff, SenderIDPtr senderID);
|
|
|
|
typedef pascal OSErr
|
|
(*StartSecureSession_ptr)(PPCStartPBPtr,
|
|
Str32 userName,
|
|
Boolean useDefault,
|
|
Boolean allowGuest,
|
|
Boolean *guestSelected,
|
|
ConstStr255Param prompt);
|
|
|
|
#pragma segment eppc_segment
|
|
|
|
StringPtr SSSPromptpStr; /* prompt string for StartSecureSession */
|
|
StringPtr MacOSPortNamepStr; /* port name of kSystemProcess */
|
|
StringPtr MacOSPortTypepStr; /* port type of kSystemProcess */
|
|
|
|
LINKLIST eppcBQ = {nil,nil,nil,0,0,sizeof(EPPCBlk),nil};
|
|
LINKLIST ppcInformBQ = {nil,nil,nil,0,0,sizeof(ppcInformBlk),nil};
|
|
LINKLIST ppcReadBQ = {nil,nil,nil,0,0,sizeof(ppcReadBlk),nil};
|
|
LINKLIST ppcWriteBQ = {nil,nil,nil,0,0,sizeof(ppcWriteBlk),nil};
|
|
|
|
LINKLIST connectionQ = {nil,nil,nil,0,0,sizeof(cTableEntry),nil};
|
|
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
ePPCInit(void)
|
|
{
|
|
Handle hdl;
|
|
|
|
/* Ask the PPC Toolbox to initialize.*/
|
|
ppcInitErr = PPCInit();
|
|
|
|
/* Check for acceptable result, then try for our string resource */
|
|
if ((hdl = Get1Resource('STR#',-16415)) ISNT nil)
|
|
{
|
|
MoveHHi(hdl);
|
|
HLock(hdl);
|
|
|
|
SSSPromptpStr = *hdl+(Ptr)2;
|
|
|
|
MacOSPortNamepStr = (Ptr)SSSPromptpStr + (Ptr)(*(char *)SSSPromptpStr);
|
|
MacOSPortNamepStr += (Ptr)1;
|
|
|
|
MacOSPortTypepStr = (Ptr)MacOSPortNamepStr + (Ptr)(*(char *)MacOSPortNamepStr);
|
|
MacOSPortTypepStr += (Ptr)1;
|
|
}
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
pascal OSErr
|
|
c_GetPortNameFromPSN(PPCPortPtr portName, ProcessSerialNumberPtr pPSN)
|
|
{
|
|
unsigned long olda5;
|
|
Boolean foundIt;
|
|
|
|
olda5 = ProcessMgrA5SimpleSetup();
|
|
foundIt = NameFromPSN(portName,pPSN);
|
|
A5SimpleRestore(olda5);
|
|
return (foundIt) ? noErr : noPortErr;
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
pascal OSErr
|
|
c_GetPSNFromPortName(PPCPortPtr portName, ProcessSerialNumberPtr psnStorage)
|
|
{
|
|
unsigned long olda5;
|
|
Boolean foundIt;
|
|
|
|
olda5 = ProcessMgrA5SimpleSetup();
|
|
foundIt = PSNFromName(portName, psnStorage);
|
|
A5SimpleRestore(olda5);
|
|
return (foundIt) ? noErr : procNotFound;
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
pascal Boolean
|
|
c_GetSpecificHighLevelEvent(ProcPtr aFilter, unsigned long *params, OSErr *err)
|
|
{
|
|
Boolean answer = false;
|
|
HighLevelEventMsgHdl msgCopyHandle;
|
|
unsigned long olda5;
|
|
MFmsgBlkPtr aMsg, bMsg, outstandingMsg;
|
|
Ptr theBuff;
|
|
EPPCBlkPtr eppcB;
|
|
int priority;
|
|
SenderID senderID;
|
|
|
|
olda5 = ProcessMgrA5SimpleSetup();
|
|
|
|
scanInformBQ();
|
|
scanReadBQ();
|
|
scanWriteBQ();
|
|
|
|
assert(pCurrentProcess ISNT pNullProcess);
|
|
assert(EqualPSNConst(kSystemProcess, &pCurrentProcess->p_serialNumber) IS false);
|
|
|
|
*err = noErr;
|
|
eppcB = &pCurrentProcess->eppcBlk; /* It maybe a bad assumption that pCurrentProcess an app */
|
|
|
|
if (eppcB->portID IS 0)
|
|
*err = noPortErr;
|
|
if (aFilter IS NULL)
|
|
*err = paramErr;
|
|
if (*err ISNT noErr)
|
|
{
|
|
A5SimpleRestore(olda5);
|
|
return(answer);
|
|
}
|
|
|
|
if (eppcB->mfMsgBlk ISNT nil)
|
|
{
|
|
aMsg = eppcB->mfMsgBlk;
|
|
msgCopyHandle = copyMsg(aMsg, err);
|
|
if (*err IS noErr) ;
|
|
else
|
|
{
|
|
A5SimpleRestore(olda5);
|
|
return(answer);
|
|
}
|
|
theBuff = *msgCopyHandle;
|
|
aMsg->msgStatus |= getSpecificHLE;
|
|
senderID.sessionID = (aMsg->sendermfid.sessionID IS systemSessionID) ? systemSessionID : aMsg->targetmfid.sessionID;
|
|
getSessionRecord(&senderID, eppcB);
|
|
A5SimpleRestore(olda5);
|
|
answer = CALL_FNC_PTR(hleFilter_ptr, aFilter, (params, theBuff, &senderID));
|
|
olda5 = ProcessMgrA5SimpleSetup();
|
|
DisposHandle(msgCopyHandle);
|
|
CheckForFatalError(MEMERROR IS noErr);
|
|
aMsg->msgStatus &= ~getSpecificHLE;
|
|
if (aMsg->msgStatus & msgPartialyAccepted)
|
|
{
|
|
aMsg->msgStatus &= ~msgPartialyAccepted;
|
|
aMsg->MFRefcon = 0;
|
|
if (aMsg->msgStatus & msgCompletelyAccepted)
|
|
flushMsg(aMsg,msgWasFullyAccepted);
|
|
else
|
|
flushMsg(aMsg,msgWasPartiallyAccepted);
|
|
eppcB->mfMsgBlk = nil;
|
|
}
|
|
if (answer != false)
|
|
{
|
|
A5SimpleRestore(olda5);
|
|
return(answer);
|
|
}
|
|
}
|
|
|
|
outstandingMsg = eppcB->mfMsgBlk;
|
|
|
|
for (priority=1;priority>=0;--priority) {
|
|
qset(&(eppcB->msgQ[priority]));
|
|
if (ll_length() IS 0)
|
|
aMsg = nil;
|
|
else
|
|
{
|
|
lltail();
|
|
llretrieve(&aMsg);
|
|
}
|
|
while (aMsg ISNT nil)
|
|
{
|
|
msgCopyHandle = copyMsg(aMsg, err);
|
|
if (*err IS noErr) ;
|
|
else {
|
|
answer = false;
|
|
eppcB->mfMsgBlk = outstandingMsg;
|
|
A5SimpleRestore(olda5);
|
|
return(answer);
|
|
}
|
|
theBuff = *msgCopyHandle;
|
|
eppcB->mfMsgBlk = aMsg;
|
|
aMsg->msgStatus |= getSpecificHLE;
|
|
senderID.sessionID = (aMsg->sendermfid.sessionID IS systemSessionID) ? systemSessionID : aMsg->targetmfid.sessionID;
|
|
getSessionRecord(&senderID, eppcB);
|
|
A5SimpleRestore(olda5);
|
|
answer = CALL_FNC_PTR(hleFilter_ptr, aFilter, (params, theBuff, &senderID));
|
|
olda5 = ProcessMgrA5SimpleSetup();
|
|
DisposHandle(msgCopyHandle);
|
|
CheckForFatalError(MEMERROR IS noErr);
|
|
aMsg->msgStatus &= ~getSpecificHLE;
|
|
qset(&(eppcB->msgQ[priority])); /* the user may have called something which
|
|
undid our call to qset(), so redo it */
|
|
|
|
if (aMsg->msgStatus & msgPartialyAccepted) /* was AcceptHighLevelEvent called? */
|
|
{
|
|
aMsg->msgStatus &= ~msgPartialyAccepted;
|
|
aMsg->MFRefcon = 0; /* in case we AcceptHLEvent this one again */
|
|
|
|
bMsg = aMsg->MFmsgBlkQ.previous;
|
|
lldelete();
|
|
flushMsg(aMsg,(aMsg->msgStatus & msgCompletelyAccepted) ? msgWasFullyAccepted:msgWasPartiallyAccepted);
|
|
|
|
qset(&(eppcB->msgQ[priority])); /* flushMsg may have called something which
|
|
undid our call to qset(), so redo it */
|
|
if (ll_length()) /* now find our next HLE */
|
|
if (bMsg ISNT nil)
|
|
{
|
|
eppcB->msgQ[priority].clp = bMsg;
|
|
aMsg = bMsg; /* llprevious() would return head of list */
|
|
}
|
|
else
|
|
{
|
|
aMsg = nil;
|
|
}
|
|
else
|
|
aMsg = nil; /* we deleted the last HLE */
|
|
}
|
|
else
|
|
{
|
|
if (llprevious())
|
|
llretrieve(&aMsg);
|
|
else
|
|
aMsg = nil;
|
|
}
|
|
if (answer != false)
|
|
break;
|
|
}
|
|
if (answer != false)
|
|
break;
|
|
} /* end of 'for loop' for each HLEvent Q attached to this port */
|
|
|
|
eppcB->mfMsgBlk = outstandingMsg;
|
|
A5SimpleRestore(olda5);
|
|
return(answer);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
HighLevelEventMsgHdl
|
|
copyMsg(MFmsgBlkPtr aMsg, OSErr *err)
|
|
{
|
|
HighLevelEventMsgHdl aHdl;
|
|
Ptr theCopyPtr;
|
|
|
|
aHdl = ProcessMgrHiNewHandle(sizeof(HighLevelEventMsg)+aMsg->eppcMsgBlk.msgLength, nil);
|
|
if ((*err = MEMERROR) != noErr)
|
|
return(aHdl);
|
|
HLock(aHdl);
|
|
theCopyPtr = *aHdl;
|
|
BlockMove(&aMsg->eppcMsgBlk,theCopyPtr,sizeof(HighLevelEventMsg));
|
|
theCopyPtr += (Ptr)sizeof(HighLevelEventMsg);
|
|
BlockMove(aMsg->addrOfMsg,theCopyPtr,aMsg->eppcMsgBlk.msgLength);
|
|
return(aHdl);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
pascal OSErr
|
|
c_AcceptHighLevelEvent(SenderIDPtr senderID, u_long *msgRefcon, Ptr msgBuff, u_long *msgLen)
|
|
{
|
|
unsigned long olda5;
|
|
short err;
|
|
unsigned long xferCount;
|
|
MFmsgBlkPtr mfMsgBlk;
|
|
|
|
/* save away the current caller's state, set major zone */
|
|
|
|
olda5 = ProcessMgrA5SimpleSetup();
|
|
err = noErr;
|
|
|
|
/* not sure about reference to pCurrentProcess being assumable. Bad things happen
|
|
* if it doesn't point to an app.
|
|
*/
|
|
|
|
if (pCurrentProcess->eppcBlk.mfMsgBlk) { /* is there a message for accepting? */
|
|
|
|
/* mfMsgBlk was set in event_common if we were delivering a pEvent.what = kHighLevelEvent or in
|
|
* GetSpecificHighLevelEvent.
|
|
*/
|
|
|
|
mfMsgBlk = (pCurrentProcess->eppcBlk.mfMsgBlk);
|
|
mfMsgBlk->msgStatus |= msgPartialyAccepted;
|
|
|
|
/* Can message fit into the user's buffer? */
|
|
|
|
if ((mfMsgBlk->eppcMsgBlk.msgLength - mfMsgBlk->MFRefcon) > *msgLen) {
|
|
|
|
/* message is larger than user's buffer */
|
|
|
|
xferCount = *msgLen; /* move what we can */
|
|
err = bufferIsSmall; /* tell the user his buffer is small */
|
|
/* tell the user how much is left to move */
|
|
*msgLen = mfMsgBlk->eppcMsgBlk.msgLength - mfMsgBlk->MFRefcon - *msgLen;
|
|
}
|
|
else {
|
|
/* message fits fine */
|
|
|
|
xferCount = mfMsgBlk->eppcMsgBlk.msgLength - mfMsgBlk->MFRefcon;
|
|
*msgLen = xferCount;
|
|
}
|
|
|
|
/* Move message */
|
|
|
|
if (msgBuff ISNT NULL && xferCount ISNT 0)
|
|
BlockMove(mfMsgBlk->addrOfMsg + (Ptr)mfMsgBlk->MFRefcon,msgBuff,xferCount);
|
|
*msgRefcon = mfMsgBlk->eppcMsgBlk.userRefcon;
|
|
senderID->sessionID = (mfMsgBlk->sendermfid.sessionID IS systemSessionID) ? systemSessionID : mfMsgBlk->targetmfid.sessionID;
|
|
getSessionRecord(senderID, &pCurrentProcess->eppcBlk);
|
|
|
|
/* Check to see if we moved all the message */
|
|
|
|
mfMsgBlk->MFRefcon += xferCount;
|
|
if (mfMsgBlk->MFRefcon >= mfMsgBlk->eppcMsgBlk.msgLength) {
|
|
|
|
/* message is all moved. Send the return receipt and release the memory */
|
|
|
|
mfMsgBlk->msgStatus |= msgCompletelyAccepted;
|
|
flushMsg(mfMsgBlk,msgWasFullyAccepted);
|
|
pCurrentProcess->eppcBlk.mfMsgBlk = nil;
|
|
}
|
|
}
|
|
else
|
|
err = noOutstandingHLE; /* HummÉ no High Level Event. His mistake or mine? */
|
|
|
|
|
|
/* restore caller's world */
|
|
|
|
A5SimpleRestore(olda5);
|
|
return(err);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
getSessionRecord(SenderIDPtr senderID, EPPCBlk *recvrEppcB)
|
|
{
|
|
cTableEntryPtr sRec;
|
|
|
|
MemClear(&senderID->location, sizeof(LocationNameRec));
|
|
MemClear(&senderID->name, sizeof(PPCPortRec));
|
|
MemClear(&senderID->recvrName, sizeof(PPCPortRec));
|
|
sRec = findSessionRecord(senderID->sessionID);
|
|
if (sRec ISNT nil)
|
|
{
|
|
senderID->name = sRec->sPName;
|
|
if (sRec->sLocName.locationKindSelector IS ppcNBPLocation)
|
|
senderID->location = sRec->sLocName;
|
|
else
|
|
senderID->location.locationKindSelector = ppcNoLocation;
|
|
senderID->recvrName = sRec->sEppcBlkPtr->nameOfMsgQ;
|
|
}
|
|
else
|
|
{
|
|
if (senderID->sessionID IS systemSessionID)
|
|
{
|
|
BlockMove(MacOSPortNamepStr, &senderID->name.name, *(char *)MacOSPortNamepStr+1);
|
|
senderID->name.portKindSelector = ppcByString;
|
|
BlockMove(MacOSPortTypepStr, &senderID->name.u.portTypeStr, *(char *)MacOSPortTypepStr+1);
|
|
senderID->recvrName = recvrEppcB->nameOfMsgQ;
|
|
}
|
|
}
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
FlushHLEQueue(EPPCBlkPtr eppcBlk, Boolean sendReturnReceipts, short rtnMsg)
|
|
{
|
|
MFmsgBlkPtr aMsg=eppcBlk->mfMsgBlk;
|
|
int priority;
|
|
|
|
if (aMsg ISNT nil)
|
|
if (sendReturnReceipts)
|
|
flushMsg(aMsg, rtnMsg);
|
|
else
|
|
{
|
|
RelMsgEventBuffer(aMsg);
|
|
}
|
|
|
|
for (priority=1;priority>=0;priority--)
|
|
{
|
|
LINKLIST *theMsgQ = &(eppcBlk->msgQ[priority]);
|
|
|
|
qset(theMsgQ);
|
|
llhead();
|
|
while(ll_length() ISNT 0)
|
|
{
|
|
llretrieve(&aMsg);
|
|
lldelete();
|
|
if (sendReturnReceipts)
|
|
{
|
|
flushMsg(aMsg, rtnMsg);
|
|
qset(theMsgQ); /* flush queue may undo our qset, so redo it. */
|
|
}
|
|
else
|
|
{
|
|
RelMsgEventBuffer(aMsg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
flushMsg(MFmsgBlkPtr msgBlk, unsigned short rtnModifiers)
|
|
{
|
|
if ((msgBlk->eppcMsgBlk.postingOptions & nReturnReceipt) AND ((msgBlk->msgStatus & getSpecificHLE) IS 0))
|
|
postReturnReceipt(msgBlk,rtnModifiers);
|
|
RelMsgEventBuffer(msgBlk);
|
|
}
|
|
/*_____________________________________fetchMsgData______________________________________*/
|
|
MFmsgBlkPtr
|
|
fetchMsgData(EPPCBlkPtr eppcBlkPtr, MFmsgBlkPtr mfMsgBlk, OSErr *err)
|
|
{
|
|
ppcReadPBPtr readPB;
|
|
Handle aHdl;
|
|
|
|
aHdl = GMBlk(sizeof(ppcReadBlk)+mfMsgBlk->eppcMsgBlk.msgLength, err);
|
|
if (*err ISNT noErr)
|
|
return nil;
|
|
|
|
HLock(aHdl);
|
|
readPB = *aHdl;
|
|
MemClear(readPB,sizeof(ppcReadBlk)+mfMsgBlk->eppcMsgBlk.msgLength);
|
|
readPB->pbHdl = aHdl;
|
|
readPB->pbID = eppcBlkPtr;
|
|
readPB->ppcReadPB.bufferPtr = readPB + 1; // <9>
|
|
readPB->ppcReadPB.bufferLength = mfMsgBlk->eppcMsgBlk.msgLength;
|
|
readPB->mfMsgBlk = *mfMsgBlk;
|
|
readPB->mfMsgBlk.addrOfMsg = readPB->ppcReadPB.bufferPtr;
|
|
readPB->mfMsgBlk.pbHandle = aHdl;
|
|
|
|
readPB->ppcReadPB.csCode = ppcReadCmd;
|
|
readPB->ppcReadPB.ioCompletion = nil;
|
|
readPB->ppcReadPB.sessRefNum = mfMsgBlk->targetmfid.sessionID;
|
|
|
|
if (mfMsgBlk->eppcMsgBlk.msgLength IS 0);
|
|
else
|
|
*err = PPCRead(&readPB->ppcReadPB,SYNCHRONOUS);
|
|
return (&readPB->mfMsgBlk);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
postReturnReceipt(const MFmsgBlkPtr mfMsgBlk, signed short rtnModifiers)
|
|
{
|
|
EventRecord theEvent;
|
|
u_long receiverID;
|
|
u_long msgRefcon;
|
|
u_long postingOptions;
|
|
|
|
if (mfMsgBlk->targetmfid.sessionID IS systemSessionID)
|
|
{
|
|
receiverID = &mfMsgBlk->sendermfid.localPSN;
|
|
postingOptions = receiverIDisPSN;
|
|
}
|
|
else
|
|
{
|
|
receiverID = mfMsgBlk->targetmfid.sessionID;
|
|
postingOptions = receiverIDisSessionID;
|
|
}
|
|
msgRefcon = mfMsgBlk->eppcMsgBlk.userRefcon;
|
|
|
|
theEvent.message = HighLevelEventMsgClass;
|
|
LONG_TO_PT(rtrnReceiptMsgID,&theEvent.where);
|
|
theEvent.modifiers = rtnModifiers;
|
|
|
|
PostHighLevelEvent(&theEvent, receiverID, msgRefcon, nil, 0, postingOptions);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
pascal short
|
|
c_PostHighLevelEvent(EventRecord *theEvent, u_long receiverID, u_long msgRefcon, Ptr msgBuff, u_long msgLen, u_long postingOptions)
|
|
{
|
|
ProcessSerialNumber SendersPSN;
|
|
unsigned long olda5, connectionID;
|
|
short err, anotherErr;
|
|
ConnectionType connectionType;
|
|
MFmsgBlkPtr msgBlk;
|
|
ProcessSerialNumber aPSN;
|
|
|
|
olda5 = ProcessMgrA5SimpleSetup();
|
|
err = noErr;
|
|
|
|
/* Make sure msgLen is reasonable */
|
|
if (msgBuff == nil)
|
|
msgLen = 0;
|
|
else if (msgLen > 0x0000ffffL)
|
|
{
|
|
A5SimpleRestore(olda5);
|
|
return(ddpLenErr);
|
|
}
|
|
|
|
(void) GetSystemClientProcess(&SendersPSN);
|
|
connectionType = GetConnectionType(&SendersPSN, receiverID, postingOptions, &connectionID, &aPSN, &err);
|
|
if (connectionType == badConnection)
|
|
{
|
|
A5SimpleRestore(olda5);
|
|
return(err);
|
|
}
|
|
|
|
/* badConnection has been weeded out. Try and get memory for message and necessary control info */
|
|
|
|
if ((msgBlk = GetMsgEventBuffer(msgLen, &anotherErr)) IS nil)
|
|
{
|
|
A5SimpleRestore(olda5);
|
|
return(anotherErr);
|
|
}
|
|
|
|
/* Set up the event record we'll give to the target */
|
|
msgBlk->eppcMsgBlk.theMsgEvent = *theEvent;
|
|
msgBlk->eppcMsgBlk.theMsgEvent.what = kHighLevelEvent;
|
|
msgBlk->eppcMsgBlk.theMsgEvent.when = TICKS;
|
|
|
|
/* Set up the message and refcon */
|
|
if (msgLen != 0)
|
|
BlockMove(msgBuff, msgBlk->addrOfMsg, msgLen);
|
|
msgBlk->eppcMsgBlk.userRefcon = msgRefcon;
|
|
msgBlk->MFRefcon = 0;
|
|
msgBlk->eppcMsgBlk.postingOptions = postingOptions;
|
|
|
|
/* Set up routing information */
|
|
msgBlk->sendermfid.localPSN = SendersPSN;
|
|
msgBlk->targetmfid.localPSN = aPSN;
|
|
msgBlk->sendermfid.sessionID = connectionID;
|
|
msgBlk->targetmfid.sessionID = noSessionID;
|
|
|
|
/* msgBlk is complete. Put it where it belongs based on connectionType. */
|
|
if (connectionType == eppcConnection)
|
|
{
|
|
postMsgToPPC(msgBlk, connectionID, &anotherErr);
|
|
if ((postingOptions & receiverIDMask) == receiverIDisTargetID)
|
|
((TargetIDPtr)receiverID)->sessionID = (anotherErr == noErr) ? connectionID : noSessionID;
|
|
err = anotherErr;
|
|
}
|
|
else if (connectionType == systemSenderConnection)
|
|
{
|
|
msgBlk->msgStatus |= localOnly;
|
|
postMsg(msgBlk);
|
|
}
|
|
else if (connectionType == systemReceiverConnection)
|
|
{
|
|
HandleSystemMessage(msgBlk, &err);
|
|
}
|
|
else if (connectionType == noEppcConnection)
|
|
TranslateAppleEvent(msgBlk, &err);
|
|
|
|
A5SimpleRestore(olda5);
|
|
return(err);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
CreateMsgQ(PEntryPtr pProc)
|
|
{
|
|
EPPCBlk eppcB;
|
|
short i;
|
|
|
|
MemClear(&eppcB,sizeof(EPPCBlk));
|
|
|
|
eppcB.pTablePtr = pProc;
|
|
qset(&eppcB.msgQ[0]);
|
|
qitemsize(sizeof(MFmsgBlk)); /* actually represents the header size only */
|
|
qset(&eppcB.msgQ[1]);
|
|
qitemsize(sizeof(MFmsgBlk)); /* actually represents the header size only */
|
|
|
|
/* Build eppcB port name from resource or p_taskmode */
|
|
|
|
makePortName(&eppcB);
|
|
|
|
openPPCPort(&eppcB);
|
|
|
|
if (eppcB.createErr IS noErr)
|
|
|
|
/* carve out a parameter block for a async PPCInform call and start the Informs*/
|
|
|
|
for (i=0;i<NROFINFORMPBS;i++)
|
|
{
|
|
eppcB.iPBs[i] = (PPCInformPBPtr)getPPCInformPB(&pProc->eppcBlk, eppcB.portID, &eppcB.createErr);
|
|
if (eppcB.createErr ISNT noErr)
|
|
break;
|
|
eppcB.createErr = PPCInform(eppcB.iPBs[i],ASYNCHRONOUS);
|
|
if (eppcB.createErr ISNT noErr)
|
|
break;
|
|
} /* end of for loop */
|
|
|
|
if (eppcB.createErr ISNT noErr)
|
|
closePPCPort(eppcB.portID);
|
|
|
|
pProc->eppcBlk = eppcB;
|
|
if (eppcB.createErr IS noErr)
|
|
{
|
|
qset(&eppcBQ);
|
|
q_push(&pProc->eppcBlk);
|
|
}
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
makePortName(EPPCBlkPtr eppcB)
|
|
{
|
|
Ptr namePtr = nil;
|
|
short lenOfPortName;
|
|
Handle hdl;
|
|
|
|
if ((eppcB->pTablePtr->p_taskmode & modeHighLevelEventAware) AND ((hdl = (Handle)Get1Resource('eppc',0)) ISNT nil))
|
|
{
|
|
namePtr = *hdl;
|
|
eppcB->optionFlags = *(unsigned long *)namePtr;
|
|
if (eppcB->pTablePtr->p_taskmode & modeLocalAndRemoteHLEvents)
|
|
eppcB->optionFlags |= registerOnNetwork;
|
|
namePtr += (Ptr)sizeof(unsigned long);
|
|
eppcB->reserved1 = *(unsigned long *)namePtr;
|
|
namePtr += (Ptr)sizeof(unsigned long);
|
|
|
|
eppcB->nameOfMsgQ.nameScript = *(short *)namePtr;
|
|
namePtr += (Ptr)sizeof(short);
|
|
lenOfPortName = *(char *)namePtr;
|
|
namePtr += (Ptr)sizeof(char);
|
|
eppcB->nameOfMsgQ.name[0] = lenOfPortName;
|
|
BlockMove(namePtr,&eppcB->nameOfMsgQ.name[1],lenOfPortName);
|
|
eppcB->nameOfMsgQ.portKindSelector = ppcByString;
|
|
eppcB->nameOfMsgQ.u.portTypeStr[0] = 8;
|
|
BlockMove((Ptr)&eppcB->pTablePtr->p_signature,(Ptr)&eppcB->nameOfMsgQ.u.portTypeStr[1],4);
|
|
BlockMove("ep01",(Ptr)&eppcB->nameOfMsgQ.u.portTypeStr[5],4);
|
|
ReleaseResource(hdl);
|
|
return;
|
|
}
|
|
|
|
if (eppcB->pTablePtr->p_taskmode & modeHighLevelEventAware)
|
|
{
|
|
if (eppcB->pTablePtr->p_taskmode & modeLocalAndRemoteHLEvents)
|
|
eppcB->optionFlags |= registerOnNetwork;
|
|
eppcB->reserved1 = 0;
|
|
eppcB->nameOfMsgQ.nameScript = (short)GetEnvirons(smSysScript);
|
|
BlockMove(CURAPNAME, &eppcB->nameOfMsgQ.name, *((unsigned char *)CURAPNAME) + 1);
|
|
eppcB->nameOfMsgQ.portKindSelector = ppcByString;
|
|
eppcB->nameOfMsgQ.u.portTypeStr[0] = 8;
|
|
BlockMove((Ptr)&eppcB->pTablePtr->p_signature,(Ptr)&eppcB->nameOfMsgQ.u.portTypeStr[1],4);
|
|
BlockMove("ep01",(Ptr)&eppcB->nameOfMsgQ.u.portTypeStr[5],4);
|
|
return;
|
|
}
|
|
eppcB->createErr = -1;
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
openPPCPort(EPPCBlkPtr eppcB) {
|
|
PPCOpenPBRec PPCpb;
|
|
|
|
if (eppcB->createErr ISNT noErr)
|
|
return;
|
|
MemClear(&PPCpb,sizeof(PPCOpenPBRec));
|
|
PPCpb.csCode = ppcOpenCmd;
|
|
PPCpb.ioCompletion = NULL;
|
|
PPCpb.serviceType = ppcServiceRealTime;
|
|
|
|
if (eppcB->optionFlags & registerOnNetwork)
|
|
PPCpb.networkVisible = true;
|
|
|
|
PPCpb.portName = &eppcB->nameOfMsgQ;
|
|
PPCpb.locationName = NULL;
|
|
|
|
eppcB->createErr = PPCOpen(&PPCpb, SYNCHRONOUS);
|
|
|
|
/* If error was name duplication, try adjusting the name until it works */
|
|
if (eppcB->createErr IS portNameExistsErr)
|
|
doDuplicateNameOpen(eppcB, &PPCpb);
|
|
|
|
/* Check result of PPCOpen or doDuplicateNameOpen */
|
|
if (eppcB->createErr IS noErr)
|
|
eppcB->portID = PPCpb.portRefNum;
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
doDuplicateNameOpen(register EPPCBlkPtr eppcB, register PPCOpenPBPtr PPCpb)
|
|
{
|
|
register short nrOfTries;
|
|
|
|
nrOfTries = MAXNROFTRIES;
|
|
do {
|
|
GetNextPortName(eppcB);
|
|
eppcB->createErr = PPCOpen(PPCpb, SYNCHRONOUS);
|
|
} while ((eppcB->createErr IS portNameExistsErr) AND (--nrOfTries > 0));
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
GetNextPortName(EPPCBlkPtr eppcB)
|
|
{
|
|
char lsd, msd;
|
|
|
|
lsd = StringByte(eppcB->nameOfMsgQ.u.portTypeStr, 7);
|
|
msd = StringByte(eppcB->nameOfMsgQ.u.portTypeStr, 6);
|
|
if (lsd IS '9')
|
|
{
|
|
lsd = '0';
|
|
if (msd IS '9')
|
|
msd = '0';
|
|
else
|
|
msd++;
|
|
}
|
|
else
|
|
lsd++;
|
|
StringByte(eppcB->nameOfMsgQ.u.portTypeStr, 7) = lsd;
|
|
StringByte(eppcB->nameOfMsgQ.u.portTypeStr, 6) = msd;
|
|
}
|
|
/*_________________________________________closePPCPort___________________________________*/
|
|
void
|
|
closePPCPort(unsigned long portID)
|
|
{
|
|
PPCClosePBRec closePB;
|
|
|
|
if (portID ISNT 0) {
|
|
closePB.csCode = ppcCloseCmd;
|
|
closePB.ioCompletion = nil;
|
|
closePB.portRefNum = portID;
|
|
PPCClose(&closePB, SYNCHRONOUS);
|
|
}
|
|
DeleteBQEntries(portID, &ppcReadBQ);
|
|
DeleteBQEntries(portID, &ppcWriteBQ);
|
|
DeleteBQEntries(portID, &ppcInformBQ);
|
|
return;
|
|
}
|
|
/*_____________________________________________DestroyMsgQ____________________________________*/
|
|
void
|
|
DestroyMsgQ(EPPCBlk *eppcBlk)
|
|
{
|
|
unsigned short oldMask = 0;
|
|
short i;
|
|
register PPCParamBlockPtr *pIPB;
|
|
|
|
if (INITIALIZED(eppcBlk) == false)
|
|
return;
|
|
|
|
/* tell KnockKnock to reject informs */
|
|
|
|
pIPB = &eppcBlk->iPBs[0];
|
|
DisableInterrupts(&oldMask);
|
|
for (i=NROFINFORMPBS; i > 0; i--)
|
|
{
|
|
ppcInformPBPtr thePB = (Ptr)*pIPB - sizeOfPPCpbHeader; // <9>
|
|
|
|
thePB->status |= closeInProgress;
|
|
pIPB++;
|
|
}
|
|
EnableInterrupts(oldMask);
|
|
|
|
/* take care of outstanding messages */
|
|
|
|
FlushHLEQueue(eppcBlk, false, 0);
|
|
|
|
if (breakConnections(eppcBlk->portID) IS 0)
|
|
closePPCPort(eppcBlk->portID);
|
|
|
|
/* remove the eppc block from the chain because its memory is going away*/
|
|
|
|
qset(&eppcBQ);
|
|
llsetMatch((ProcPtr)findElement);
|
|
llhead();
|
|
if (llcheck(eppcBlk))
|
|
lldelete();
|
|
else
|
|
assert(0);
|
|
}
|
|
/*_______________________________________breakConnections_________________________________*/
|
|
short
|
|
breakConnections(unsigned long portID)
|
|
{
|
|
OSErr ppcEndErr;
|
|
PPCEndPBRec endPB;
|
|
cTableEntryPtr sRec;
|
|
short nrOfSessionsLeftOpen = 0;
|
|
|
|
qset(&connectionQ);
|
|
if (ll_length() ISNT 0)
|
|
{
|
|
llsetMatch((ProcPtr)byportID);
|
|
llhead();
|
|
while (llcheck(&portID))
|
|
{
|
|
llretrieve(&sRec);
|
|
|
|
sRec->status |= HLEQDoesNotExist;
|
|
|
|
if (sRec->swPB IS nil)
|
|
{
|
|
if (!(sRec->status & (sessionClosed+sessionEnded)))
|
|
{
|
|
endPB.csCode = ppcEndCmd;
|
|
endPB.ioCompletion = nil;
|
|
endPB.sessRefNum = sRec->sID;
|
|
ppcEndErr = PPCEnd(&endPB,SYNCHRONOUS);
|
|
if (ppcEndErr IS noErr OR ppcEndErr IS noSessionErr) ;
|
|
else
|
|
assert(0);
|
|
}
|
|
lldelete();
|
|
DisposHandle(sRec->sHdl);
|
|
}
|
|
else
|
|
{
|
|
nrOfSessionsLeftOpen++;
|
|
sRec->status |= waitingForWrites;
|
|
if (!llnext())
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return(nrOfSessionsLeftOpen);
|
|
}
|
|
#if 0
|
|
/*____________________________________________DeleteBQEntries_________________________________*/
|
|
void
|
|
DeleteBQEntries(unsigned long portID, LINKLIST *theBQ)
|
|
{
|
|
ppcWritePBPtr pb;
|
|
unsigned short oldMask;
|
|
|
|
qset(theBQ);
|
|
DisableInterrupts(&oldMask);
|
|
if (ll_length() ISNT 0)
|
|
{
|
|
llsetMatch((ProcPtr)byportIDforPB);
|
|
llhead();
|
|
while (llcheck(&portID))
|
|
{
|
|
llretrieve(&pb);
|
|
lldelete();
|
|
DisposHandle(pb->pbHdl);
|
|
}
|
|
}
|
|
EnableInterrupts(oldMask);
|
|
}
|
|
#else
|
|
/*____________________________________________DeleteBQEntries_________________________________*/
|
|
void
|
|
DeleteBQEntries(unsigned long portID, LINKLIST *theBQ)
|
|
{
|
|
ppcWritePBPtr pb;
|
|
ppcWritePBPtr nextPB;
|
|
unsigned short oldMask;
|
|
LINKLIST aListToDisposeOf;
|
|
|
|
MemClear(&aListToDisposeOf, sizeof(LINKLIST));
|
|
qset(theBQ);
|
|
DisableInterrupts(&oldMask);
|
|
++theBQ->listInUse;
|
|
if (ll_length() ISNT 0)
|
|
{
|
|
llhead();
|
|
llretrieve(&pb);
|
|
while (pb ISNT nil)
|
|
{
|
|
if (llnext())
|
|
llretrieve(&nextPB);
|
|
else
|
|
nextPB = nil;
|
|
if (pb->portID IS portID)
|
|
{
|
|
theBQ->clp = pb;
|
|
lldelete();
|
|
qset(&aListToDisposeOf);
|
|
q_push(pb);
|
|
qset(theBQ);
|
|
}
|
|
if (nextPB ISNT nil)
|
|
theBQ->clp = nextPB;
|
|
pb = nextPB;
|
|
}
|
|
}
|
|
--theBQ->listInUse;
|
|
EnableInterrupts(oldMask);
|
|
|
|
qset(&aListToDisposeOf);
|
|
while (ll_length() ISNT 0)
|
|
{
|
|
q_pop(&pb);
|
|
DisposHandle(pb->pbHdl);
|
|
}
|
|
}
|
|
#endif
|
|
/*__________________________________GetMsgEventBuffer__________________________________________*/
|
|
MFmsgBlkPtr
|
|
GetMsgEventBuffer(u_long lengthInBytes, OSErr *err)
|
|
{
|
|
ppcWritePBPtr msgBlk = nil;
|
|
Handle aHdl = nil;
|
|
|
|
aHdl = GMBlk(sizeof(ppcWriteBlk)+lengthInBytes, err);
|
|
if (*err ISNT noErr)
|
|
return(nil);
|
|
HLock(aHdl);
|
|
msgBlk = *aHdl;
|
|
MemClear(msgBlk,sizeof(ppcWriteBlk)+lengthInBytes);
|
|
msgBlk->pbHdl = aHdl;
|
|
msgBlk->mfMsgBlk.pbHandle = aHdl;
|
|
msgBlk->mfMsgBlk.eppcMsgBlk.version = 3;
|
|
msgBlk->mfMsgBlk.eppcMsgBlk.HighLevelEventMsgHeaderLength = sizeof(HighLevelEventMsg);
|
|
msgBlk->mfMsgBlk.eppcMsgBlk.msgLength = lengthInBytes;
|
|
msgBlk->mfMsgBlk.addrOfMsg = (lengthInBytes IS 0) ? NULL : msgBlk + 1; // <9>
|
|
return(&msgBlk->mfMsgBlk);
|
|
}
|
|
/*_____________________________________RelMsgEventBuffer________________________________________*/
|
|
void
|
|
RelMsgEventBuffer (MFmsgBlkPtr mfMsgBlk)
|
|
{
|
|
|
|
if (mfMsgBlk->msgStatus & getSpecificHLE)
|
|
return;
|
|
DisposHandle(mfMsgBlk->pbHandle);
|
|
CheckForFatalError(MEMERROR IS noErr);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
postMsg(const MFmsgBlkPtr msgBlk)
|
|
{
|
|
PEntryPtr pTargetProc;
|
|
EPPCBlkPtr teppcBlk;
|
|
|
|
pTargetProc = PEntryFromPSN(&msgBlk->targetmfid.localPSN);
|
|
CheckForFatalError(pTargetProc != nil);
|
|
teppcBlk = TarEPPCBlkPtr(pTargetProc);
|
|
if (msgBlk->eppcMsgBlk.postingOptions & nAttnMsg)
|
|
qset(&(teppcBlk->msgQ[1]));
|
|
else
|
|
qset(&(teppcBlk->msgQ[0]));
|
|
q_push(msgBlk);
|
|
|
|
/* Wake him up, if necessary */
|
|
CancelSleep(pTargetProc);
|
|
}
|
|
/*____________________________________postMsgToPPC___________________________________________*/
|
|
void
|
|
postMsgToPPC(const MFmsgBlkPtr msgBlk, unsigned long sessionID, OSErr *err)
|
|
{
|
|
ppcWritePBPtr writePB;
|
|
unsigned long *along;
|
|
cTableEntryPtr sRec;
|
|
|
|
writePB = (ppcWritePBPtr) ((Ptr)msgBlk - sizeOfPPCWriteBlk); // <9>
|
|
|
|
writePB->ppcWritePB.csCode = ppcWriteCmd;
|
|
writePB->ppcWritePB.ioCompletion = KnockKnock;
|
|
writePB->ppcWritePB.sessRefNum = sessionID;
|
|
writePB->ppcWritePB.blockCreator = msgBlk->eppcMsgBlk.theMsgEvent.message;
|
|
along = &(msgBlk->eppcMsgBlk.theMsgEvent.where);
|
|
writePB->ppcWritePB.blockType = *along;
|
|
writePB->ppcWritePB.bufferLength = sizeof(HighLevelEventMsg)+msgBlk->eppcMsgBlk.msgLength;
|
|
writePB->ppcWritePB.bufferPtr = &msgBlk->eppcMsgBlk;
|
|
writePB->pbID = EPPCBlkFromPSN(&msgBlk->sendermfid.localPSN);
|
|
|
|
/* The following code was added to keep track of the last PPCWrite. */
|
|
/* A new field was created in the connection table entry record (session */
|
|
/* record) - swPB. Into this field we store the address of the ppcWritePBPtr*/
|
|
/* The swPB is used in ScanWriteBQ. This is part of the fix for lost post */
|
|
/* during _ExitToShell */
|
|
|
|
sRec = findSessionRecord(sessionID);
|
|
sRec->swPB = writePB;
|
|
writePB->portID = sRec->sportID;
|
|
|
|
*err = PPCWrite(&writePB->ppcWritePB,ASYNCHRONOUS);
|
|
|
|
}
|
|
/*_____________________________GetNextHighLevelEvent____________________________________________*/
|
|
pascal Boolean
|
|
c_GetNextHighLevelEvent(short eventmask, EventRecord *pReturnEvent, Boolean pullevent)
|
|
{
|
|
MFmsgBlkPtr aMsg, bMsg;
|
|
short priority;
|
|
unsigned long olda5;
|
|
Boolean retVal;
|
|
|
|
olda5 = ProcessMgrA5SimpleSetup();
|
|
retVal = false;
|
|
scanInformBQ();
|
|
scanReadBQ();
|
|
scanWriteBQ();
|
|
|
|
assert(pCurrentProcess ISNT pNullProcess);
|
|
assert(EqualPSNConst(kSystemProcess, &pCurrentProcess->p_serialNumber) IS false);
|
|
|
|
for (priority=1;priority>=0;priority--)
|
|
{
|
|
if (pCurrentProcess->eppcBlk.msgQ[priority].listlength ISNT 0 AND (eventmask & networkMask))
|
|
{
|
|
qset(&pCurrentProcess->eppcBlk.msgQ[priority]);
|
|
lltail();
|
|
llretrieve(&aMsg);
|
|
*pReturnEvent = aMsg->eppcMsgBlk.theMsgEvent;
|
|
if (pullevent)
|
|
{
|
|
q_pop(&bMsg);
|
|
CheckForFatalError(bMsg IS aMsg);
|
|
pCurrentProcess->eppcBlk.mfMsgBlk = (Handle)bMsg;
|
|
}
|
|
|
|
retVal = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
A5SimpleRestore(olda5);
|
|
return(retVal);
|
|
}
|
|
/*________________________________________scanInformBQ__________________________________________*/
|
|
void
|
|
scanInformBQ(void)
|
|
{
|
|
ppcInformPBPtr iPB;
|
|
PPCEndPBRec ppcEndPB;
|
|
OSErr err;
|
|
unsigned short oldMask = 0;
|
|
cTableEntryPtr sRec;
|
|
|
|
for (;;)
|
|
{
|
|
DisableInterrupts(&oldMask);
|
|
++ppcInformBQ.listInUse;
|
|
if (ppcInformBQ.listlength IS 0)
|
|
{
|
|
--ppcInformBQ.listInUse;
|
|
EnableInterrupts(oldMask);
|
|
break;
|
|
}
|
|
qset(&ppcInformBQ);
|
|
q_pop(&iPB);
|
|
--ppcInformBQ.listInUse;
|
|
EnableInterrupts(oldMask);
|
|
|
|
if (iPB->ppcInformPB.ioResult ISNT noErr)
|
|
{
|
|
releasePPCpb(&iPB->ppcInformPB);
|
|
continue;
|
|
}
|
|
|
|
if (iPB->ppcInformReplyPB.csCode IS ppcRejectCmd);
|
|
else
|
|
if ((sRec = findFreeSessionRecord()) ISNT nil)
|
|
{
|
|
sRec->status |= informConnection;
|
|
if (iPB->status & closeInProgress)
|
|
sRec->status |= HLEQDoesNotExist;
|
|
|
|
sRec->sID = iPB->ppcInformPB.sessRefNum;
|
|
|
|
sRec->sPName = *(iPB->ppcInformPB.portName);
|
|
if (iPB->ppcInformPB.requestType IS ppcRemoteOrigin)
|
|
sRec->sLocName = *(iPB->ppcInformPB.locationName);
|
|
else
|
|
sRec->sLocName.locationKindSelector = ppcNoLocation;
|
|
|
|
sRec->sEppcBlkPtr = iPB->pbID; /* pbID may no longer be valid */
|
|
sRec->sportID = iPB->portID;
|
|
|
|
sRec->srPB = startPPCRead(iPB->pbID, iPB->ppcInformPB.sessRefNum, &err);
|
|
if (err ISNT noErr)
|
|
DisposHandle(sRec->sHdl);
|
|
else
|
|
{
|
|
qset(&connectionQ);
|
|
q_push(sRec);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MemClear(&ppcEndPB,sizeof(PPCEndPBRec));
|
|
ppcEndPB.sessRefNum = iPB->ppcInformPB.sessRefNum;
|
|
ppcEndPB.csCode = ppcEndCmd;
|
|
ppcEndPB.ioCompletion = nil;
|
|
PPCEnd(&ppcEndPB,SYNCHRONOUS);
|
|
}
|
|
|
|
iPB->ppcInformPB.sessRefNum = 0;
|
|
MemClear(iPB->ppcInformPB.locationName, sizeof(LocationNameRec));
|
|
MemClear(iPB->ppcInformPB.portName, sizeof(PPCPortRec));
|
|
|
|
err = PPCInform(&iPB->ppcInformPB,ASYNCHRONOUS);
|
|
}
|
|
}
|
|
/*____________________________________scanWriteBQ_______________________________________________*/
|
|
void
|
|
scanWriteBQ(void)
|
|
{
|
|
ppcWritePBPtr wPB = nil;
|
|
ppcWritePBPtr lastwPB = nil;
|
|
unsigned short oldMask = 0;
|
|
cTableEntryPtr sRec;
|
|
PPCEndPBRec ppcEndPB;
|
|
|
|
for (;;)
|
|
{
|
|
DisableInterrupts(&oldMask);
|
|
++ppcWriteBQ.listInUse;
|
|
if (ppcWriteBQ.listlength IS 0)
|
|
{
|
|
--ppcWriteBQ.listInUse;
|
|
EnableInterrupts(oldMask);
|
|
break;
|
|
};
|
|
qset(&ppcWriteBQ);
|
|
q_pop(&wPB);
|
|
--ppcWriteBQ.listInUse;
|
|
EnableInterrupts(oldMask);
|
|
|
|
sRec = findSessionRecord(wPB->ppcWritePB.sessRefNum);
|
|
|
|
if (sRec IS nil)
|
|
{
|
|
releasePPCpb(&wPB->ppcWritePB);
|
|
continue;
|
|
}
|
|
|
|
if (wPB->ppcWritePB.ioResult IS noErr);
|
|
else
|
|
{
|
|
/* closing the port or ending a session causes writes to go to completion */
|
|
|
|
if (wPB->ppcWritePB.ioResult IS noSessionErr OR wPB->ppcWritePB.ioResult IS sessClosedErr)
|
|
sRec->status |= sessionClosed;
|
|
else
|
|
{
|
|
if (sRec->status & waitingForWrites);
|
|
else
|
|
{
|
|
MemClear(&ppcEndPB,sizeof(PPCEndPBRec));
|
|
ppcEndPB.sessRefNum = wPB->ppcWritePB.sessRefNum;
|
|
ppcEndPB.csCode = ppcEndCmd;
|
|
ppcEndPB.ioCompletion = nil;
|
|
PPCEnd(&ppcEndPB,SYNCHRONOUS);
|
|
sRec->status |= sessionEnded;
|
|
}
|
|
}
|
|
}
|
|
releasePPCpb(&wPB->ppcWritePB);
|
|
|
|
lastwPB = sRec->swPB;
|
|
if (lastwPB IS wPB)
|
|
{
|
|
sRec->swPB = nil;
|
|
if (sRec->status & waitingForWrites)
|
|
{
|
|
unsigned long portID = sRec->sportID;
|
|
|
|
sRec->status &= ~waitingForWrites;
|
|
if (breakConnections(portID) IS 0)
|
|
closePPCPort(portID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*_____________________________________scanReadBQ____________________________________________*/
|
|
void
|
|
scanReadBQ(void)
|
|
{
|
|
ppcReadPBPtr rPB;
|
|
OSErr err;
|
|
unsigned short oldMask = 0;
|
|
cTableEntryPtr sRec;
|
|
MFmsgBlkPtr aMFmsg;
|
|
|
|
/* Loop until the queue is empty. The queue is added to by KnockKnock, the
|
|
io completion for PPCToolbox calls. The loop is terminated when the queue
|
|
length goes to 0. Notice the calls to DisableInterrupts around the queue
|
|
manipulation logic.
|
|
*/
|
|
for (;;)
|
|
{
|
|
DisableInterrupts(&oldMask);
|
|
++ppcReadBQ.listInUse;
|
|
if (ppcReadBQ.listlength IS 0)
|
|
{
|
|
--ppcReadBQ.listInUse;
|
|
EnableInterrupts(oldMask);
|
|
break; /* the queue is empty. exit the for loop. */
|
|
}
|
|
qset(&ppcReadBQ);
|
|
q_pop(&rPB);
|
|
--ppcReadBQ.listInUse;
|
|
EnableInterrupts(oldMask);
|
|
|
|
sRec = findSessionRecord(rPB->ppcReadPB.sessRefNum);
|
|
|
|
if (sRec IS nil)
|
|
{
|
|
releasePPCpb(&rPB->ppcReadPB); /* could not find a session record match */
|
|
continue; /* for this completed read. This should */
|
|
} /* mean that DestroyMsgQ ended the */
|
|
/* session (i.e. the target has called */
|
|
/* _ExitToShell */
|
|
|
|
if (rPB->ppcReadPB.ioResult IS noErr);
|
|
else
|
|
{
|
|
endSessionAfterAReadError(sRec, rPB->ppcReadPB.ioResult);
|
|
continue;
|
|
}
|
|
|
|
/* set up to get the data portion of this High Level Event, if any. */
|
|
|
|
rPB->mfMsgBlk.targetmfid.sessionID = rPB->ppcReadPB.sessRefNum;
|
|
|
|
/* The next assignment determines the local target of the message. Note: you
|
|
cannot assume that the target is still alive (i.e. rPB->pbID->pTablePtr is
|
|
valid). If HLEQDoesNotExist is set, then the app called _ExitToShell and
|
|
we need to set localPSN accordingly.
|
|
*/
|
|
|
|
if (sRec->status & HLEQDoesNotExist)
|
|
{
|
|
SetPSN(kNoProcess, &rPB->mfMsgBlk.targetmfid.localPSN);
|
|
}
|
|
else
|
|
rPB->mfMsgBlk.targetmfid.localPSN = rPB->pbID->pTablePtr->p_serialNumber;
|
|
|
|
rPB->mfMsgBlk.addrOfMsg = nil;
|
|
|
|
aMFmsg = fetchMsgData(rPB->pbID, &rPB->mfMsgBlk, &err);
|
|
if (err IS noErr);
|
|
else /* There was an error during fetchMsgData */
|
|
{
|
|
if (aMFmsg IS nil) /* Was it a memory error? */
|
|
{
|
|
rPB->mfMsgBlk.msgStatus |= msgMemoryRestart;
|
|
qset(&ppcReadBQ);
|
|
DisableInterrupts(&oldMask);
|
|
++ppcReadBQ.listInUse;
|
|
if (ppcReadBQ.listlength IS 0)
|
|
q_push(rPB);
|
|
else
|
|
{
|
|
lltail();
|
|
lladd(rPB);
|
|
}
|
|
--ppcReadBQ.listInUse;
|
|
EnableInterrupts(oldMask);
|
|
break;
|
|
}
|
|
else /* it was not a memory error */
|
|
{
|
|
endSessionAfterAReadError(sRec, err);
|
|
if (aMFmsg)
|
|
RelMsgEventBuffer(aMFmsg);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (sRec->status & HLEQDoesNotExist)
|
|
RelMsgEventBuffer(aMFmsg);
|
|
else
|
|
{
|
|
/* Put the HLE on the appropriate list */
|
|
|
|
if (rPB->mfMsgBlk.eppcMsgBlk.postingOptions & nAttnMsg)
|
|
qset(&(rPB->pbID->msgQ[1]));
|
|
else
|
|
qset(&(rPB->pbID->msgQ[0]));
|
|
q_push(aMFmsg);
|
|
|
|
/* Wake him up, if necessary */
|
|
CancelSleep(rPB->pbID->pTablePtr);
|
|
}
|
|
|
|
/* start the outstanding read on this session */
|
|
|
|
sRec->srPB = restartPPCRead(rPB, &err);
|
|
}
|
|
}
|
|
/*__________________________________endSessionAfterAReadError________________________________________*/
|
|
void
|
|
endSessionAfterAReadError(cTableEntryPtr sRec, OSErr err)
|
|
{
|
|
PPCEndPBRec ppcEndPB;
|
|
|
|
if (err IS noSessionErr OR err IS sessClosedErr)
|
|
sRec->status |= sessionClosed;
|
|
else
|
|
{
|
|
if (sRec->status & waitingForWrites);
|
|
else
|
|
{
|
|
MemClear(&ppcEndPB,sizeof(PPCEndPBRec));
|
|
ppcEndPB.sessRefNum = sRec->sID;
|
|
ppcEndPB.csCode = ppcEndCmd;
|
|
ppcEndPB.ioCompletion = nil;
|
|
PPCEnd(&ppcEndPB,SYNCHRONOUS);
|
|
sRec->status |= sessionEnded;
|
|
}
|
|
}
|
|
releasePPCpb(sRec->srPB);
|
|
sRec->srPB = nil;
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
/* GetConnectionType. Returns the type of connection we can have from the sender to the receiver.
|
|
* It takes as input a SendersPSN, a receiverID, postion options.
|
|
* It returns, in addition to type of connection, connectionID, PSN of the target, and err.
|
|
* Results: eppcConnection means the connection is routed thru the PPCToolbox.
|
|
* noEppcConnection means that the receiver was located, but it cannot understand EPPC.
|
|
* systemReceiverConnection means the message was addressed to "the system"
|
|
* systemSenderConnection means the message was from the "the system"
|
|
* badConnection means that there is no possibility of connection.
|
|
* If the result is eppcConnection, the target is in connectionID. Otherwise, it is in targetsPSN.
|
|
* If the result is badConnection or noEppcConnection, the appropriate error code is returned
|
|
* in err. This error should be returned in the noEppcConnection case if the event can not
|
|
* be translated.
|
|
* Note: ¥ SendersPSN can be kSystemProcess, kNoProcess, or somebodies PSN.
|
|
* ¥ SendersPSN equal to kNoProcess is an error, I thought; I coded.
|
|
* ¥ SendersPSN equal to kSystemProcess means someone called us with SystemMode
|
|
* turned on.
|
|
* ¥ receiverID is the target identification. How receiverID is interpeted is determined
|
|
* by postingOptions. There are four options as of 7.0aA7.
|
|
* ¥ connectionID is the target identification. On output how connectionID is interpeted is
|
|
* determined by type of connection. There are five types as of 7.0aA7.
|
|
* ¥ targetsPSN is the target process serial number. On output how targetsPSN is
|
|
* interpeted is determined by type of connection. There are five options as of 7.0aA7.
|
|
* ¥ err is error. Means something.
|
|
*/
|
|
ConnectionType
|
|
GetConnectionType(ProcessSerialNumberPtr SendersPSN, unsigned long receiverID, unsigned long postingOptions, unsigned long *connectionID, ProcessSerialNumberPtr targetsPSN, OSErr *err)
|
|
{
|
|
PEntryPtr pReceiverProc;
|
|
EPPCBlkPtr eppcBPtr;
|
|
TargetID tID;
|
|
ProcessSerialNumber PSNFromSign;
|
|
ConnectionType retVal;
|
|
cTableEntryPtr sRec;
|
|
|
|
/* Assume the worst */
|
|
retVal = badConnection;
|
|
|
|
/* Sender must be able to do EPPC if a return receipt was requested
|
|
* NOTE: nReturnReceipt check is first because kSystemProcess may send
|
|
* an event when pCurrentProcess is nil.
|
|
*/
|
|
if ( ((postingOptions & nReturnReceipt) != 0) && (CanDoEPPC(pCurrentProcess) == false) )
|
|
{
|
|
*err = connectionInvalid;
|
|
*connectionID = noSessionID;
|
|
SetPSN(kNoProcess, targetsPSN);
|
|
return(retVal);
|
|
}
|
|
|
|
/* Determine specific connection type. */
|
|
if ((postingOptions &= receiverIDMask) IS receiverIDisPSN)
|
|
{
|
|
pReceiverProc = PEntryFromPSN((ProcessSerialNumberPtr) receiverID);
|
|
if (pReceiverProc != nil)
|
|
{
|
|
eppcBPtr = EPPCBlkFromPSN(&pReceiverProc->p_serialNumber); // <13>
|
|
if (eppcBPtr ISNT nil) { /* yes, target has eppcBlk */
|
|
/* Now consider the sender's identity */
|
|
if (EqualPSNConst(kSystemProcess, SendersPSN) == false)
|
|
{
|
|
tID = getTIDfromEppcBlk(eppcBPtr);
|
|
if ((*connectionID = getSessionID(SendersPSN,&tID, err)) != 0)
|
|
{
|
|
*targetsPSN = *((ProcessSerialNumberPtr) receiverID);
|
|
retVal = eppcConnection;
|
|
}
|
|
else /* we couldn't get a sessionID */
|
|
{
|
|
SetPSN(kNoProcess, targetsPSN);
|
|
retVal = badConnection;
|
|
}
|
|
}
|
|
else
|
|
{ /* SendersPSN was kSystemProcess and target has eppcBlk */
|
|
*err = noErr;
|
|
*connectionID = systemSessionID;
|
|
*targetsPSN = *((ProcessSerialNumberPtr) receiverID);
|
|
retVal = systemSenderConnection;
|
|
}
|
|
}
|
|
else /* target had no eppcBlk. */
|
|
{
|
|
*err = destPortErr;
|
|
*connectionID = noSessionID;
|
|
*targetsPSN = *((ProcessSerialNumberPtr) receiverID);
|
|
retVal = noEppcConnection;
|
|
}
|
|
}
|
|
else /* we didn't find a process table for the target. See if it is a special case */
|
|
if ( EqualPSNConst(kSystemProcess, (ProcessSerialNumberPtr)(receiverID)) )
|
|
{
|
|
*err = noErr;
|
|
*connectionID = systemSessionID;
|
|
*targetsPSN = *((ProcessSerialNumberPtr) receiverID);
|
|
retVal = systemReceiverConnection;
|
|
}
|
|
else /* not a special case. Oh wellÉ not connection */
|
|
{
|
|
*err = procNotFound;
|
|
*connectionID = noSessionID;
|
|
SetPSN(kNoProcess, targetsPSN);
|
|
retVal = badConnection;
|
|
}
|
|
}
|
|
|
|
if (postingOptions IS receiverIDisTargetID)
|
|
{
|
|
if ((*connectionID = getSessionID(SendersPSN,(TargetIDPtr)receiverID, err)) != 0)
|
|
{
|
|
retVal = eppcConnection;
|
|
}
|
|
}
|
|
|
|
if (postingOptions IS receiverIDisSignature)
|
|
{
|
|
if (PSNFromSignature((ResType)receiverID, &PSNFromSign))
|
|
{
|
|
eppcBPtr = EPPCBlkFromPSN(&PSNFromSign);
|
|
if (eppcBPtr ISNT nil) {
|
|
if (EqualPSNConst(kSystemProcess, SendersPSN) == false)
|
|
{
|
|
tID = getTIDfromEppcBlk(eppcBPtr);
|
|
if ((*connectionID = getSessionID(SendersPSN,&tID, err)) != 0)
|
|
{
|
|
*targetsPSN = PSNFromSign;
|
|
retVal = eppcConnection;
|
|
}
|
|
else
|
|
{
|
|
SetPSN(kNoProcess, targetsPSN);
|
|
retVal = badConnection;
|
|
}
|
|
}
|
|
else /* SendersPSN was kSystemProcess and target has eppcBlk */
|
|
{
|
|
*err = noErr;
|
|
*connectionID = systemSessionID;
|
|
*targetsPSN = PSNFromSign;
|
|
retVal = systemSenderConnection;
|
|
}
|
|
}
|
|
else /* target had no eppcBlk. */
|
|
{
|
|
*err = destPortErr;
|
|
*connectionID = noSessionID;
|
|
*targetsPSN = PSNFromSign;
|
|
retVal = noEppcConnection;
|
|
}
|
|
}
|
|
else /* couldn't find a PSN from the signature. check special case */
|
|
{
|
|
if ( NULLPROC_SIGNATURE IS (ResType)receiverID )
|
|
{
|
|
*err = noErr;
|
|
*connectionID = systemSessionID;
|
|
SetPSN(kSystemProcess, targetsPSN);
|
|
retVal = systemReceiverConnection;
|
|
}
|
|
else /* not a special case. Oh wellÉ not connection */
|
|
{
|
|
*err = connectionInvalid;
|
|
*connectionID = noSessionID;
|
|
SetPSN(kNoProcess, targetsPSN);
|
|
retVal = badConnection;
|
|
}
|
|
}
|
|
} /* end of receiverIDisSignature */
|
|
|
|
if (postingOptions IS receiverIDisSessionID)
|
|
{
|
|
sRec = findSessionRecord(receiverID);
|
|
if (sRec ISNT nil)
|
|
{
|
|
if (EqualPSNConst(kSystemProcess, SendersPSN) == false)
|
|
{
|
|
if ((*connectionID = validateSessionID(SendersPSN, receiverID, err)) != 0)
|
|
{
|
|
SetPSN(kNoProcess, targetsPSN);
|
|
retVal = eppcConnection;
|
|
}
|
|
else
|
|
{
|
|
SetPSN(kNoProcess, targetsPSN);
|
|
retVal = badConnection;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*err = noErr;
|
|
*connectionID = systemSessionID;
|
|
*targetsPSN = sRec->sEppcBlkPtr->pTablePtr->p_serialNumber;
|
|
retVal = systemSenderConnection;
|
|
}
|
|
}
|
|
else /* no connection. check for special cases */
|
|
{
|
|
if (receiverID IS systemSessionID)
|
|
{
|
|
*err = noErr;
|
|
*connectionID = systemSessionID;
|
|
SetPSN(kSystemProcess, targetsPSN);
|
|
retVal = systemReceiverConnection;
|
|
}
|
|
else /* not a special case. Oh wellÉ not connection */
|
|
{
|
|
*err = connectionInvalid;
|
|
*connectionID = noSessionID;
|
|
SetPSN(kNoProcess, targetsPSN);
|
|
retVal = badConnection;
|
|
}
|
|
}
|
|
} /* end of receiverIDisSessionID */
|
|
return (retVal);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
unsigned long
|
|
validateSessionID(ProcessSerialNumberPtr ownersPSN, unsigned long sessionID, OSErr *err)
|
|
{
|
|
cTableEntryPtr sRec;
|
|
|
|
sRec = findSessionRecord(sessionID);
|
|
if (sRec ISNT nil)
|
|
if ( EqualPSN(ownersPSN, &sRec->sEppcBlkPtr->pTablePtr->p_serialNumber))
|
|
{
|
|
if (sRec->status & (sessionClosed+sessionEnded))
|
|
{
|
|
qset(&connectionQ);
|
|
llhead();
|
|
llsetMatch((ProcPtr)findElement);
|
|
if (llcheck(sRec))
|
|
{
|
|
lldelete();
|
|
DisposHandle(sRec->sHdl);
|
|
}
|
|
*err = sessClosedErr;
|
|
return(0);
|
|
}
|
|
*err = noErr;
|
|
return(sessionID);
|
|
}
|
|
*err = connectionInvalid;
|
|
return(0);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
comparePortNames(PPCPortPtr N1, PPCPortPtr N2)
|
|
{
|
|
short i;
|
|
|
|
if (N1->nameScript ISNT N2->nameScript)
|
|
return(true);
|
|
if (N1->name[0] ISNT N2->name[0])
|
|
return(true);
|
|
if (N1->name[0]) {
|
|
for(i=1;i<=(N1->name[0]);++i)
|
|
if (N1->name[i] ISNT N2->name[i])
|
|
return(true);
|
|
}
|
|
if (N1->portKindSelector ISNT N2->portKindSelector)
|
|
return(true);
|
|
if (N1->portKindSelector IS ppcByString) {
|
|
if (N1->u.portTypeStr[0] ISNT N2->u.portTypeStr[0])
|
|
return(true);
|
|
if (N1->u.portTypeStr[0]) {
|
|
for(i=1;i<=(N1->u.portTypeStr[0]);++i)
|
|
if (N1->u.portTypeStr[i] ISNT N2->u.portTypeStr[i])
|
|
return(true);
|
|
}
|
|
}
|
|
else {
|
|
if (N1->u.port.creator ISNT N2->u.port.creator)
|
|
return(true);
|
|
if (N1->u.port.type ISNT N2->u.port.type)
|
|
return(true);
|
|
}
|
|
return(false);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
comparePortLocation(LocationNamePtr L1, LocationNamePtr L2)
|
|
{
|
|
short i;
|
|
|
|
if (L1->locationKindSelector ISNT L2->locationKindSelector)
|
|
return(true);
|
|
if (L1->locationKindSelector IS ppcNoLocation)
|
|
return(false);
|
|
if (L1->u.nbpEntity.objStr[0] ISNT L2->u.nbpEntity.objStr[0])
|
|
return(true);
|
|
if (L1->u.nbpEntity.objStr[0]) {
|
|
for(i=1;i<=(L1->u.nbpEntity.objStr[0]);++i)
|
|
if (L1->u.nbpEntity.objStr[i] ISNT L2->u.nbpEntity.objStr[i])
|
|
return(true);
|
|
}
|
|
if (L1->u.nbpEntity.typeStr[0] ISNT L2->u.nbpEntity.typeStr[0])
|
|
return(true);
|
|
if (L1->u.nbpEntity.typeStr[0]) {
|
|
for(i=1;i<=(L1->u.nbpEntity.typeStr[0]);++i)
|
|
if (L1->u.nbpEntity.typeStr[i] ISNT L2->u.nbpEntity.typeStr[i])
|
|
return(true);
|
|
}
|
|
if (L1->u.nbpEntity.zoneStr[0] ISNT L2->u.nbpEntity.zoneStr[0])
|
|
return(true);
|
|
if (L1->u.nbpEntity.zoneStr[0]) {
|
|
for(i=1;i<=(L1->u.nbpEntity.zoneStr[0]);++i)
|
|
if (L1->u.nbpEntity.zoneStr[i] ISNT L2->u.nbpEntity.zoneStr[i])
|
|
return(true);
|
|
}
|
|
return(false);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
PortNameAndLocationAreEqual(PPCPortPtr portName, LocationNamePtr locName, TargetIDPtr targetID)
|
|
{
|
|
Boolean different;
|
|
|
|
if ((different = comparePortNames(portName, &targetID->name)) == false)
|
|
if (locName IS nil)
|
|
return (targetID->location.locationKindSelector IS ppcNoLocation);
|
|
else
|
|
different = comparePortLocation(locName, &targetID->location);
|
|
return(!different);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
TargetID
|
|
getTIDfromEppcBlk(EPPCBlkPtr eppcBPtr)
|
|
{
|
|
TargetID tID;
|
|
|
|
MemClear(&tID,sizeof(TargetID));
|
|
tID.name = eppcBPtr->nameOfMsgQ;
|
|
tID.location.locationKindSelector = ppcNoLocation;
|
|
return(tID);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
cTableEntryPtr
|
|
findSessionRecord(unsigned long sessionRefNum)
|
|
{
|
|
cTableEntryPtr sRec = nil;
|
|
|
|
if (sessionRefNum IS 0 OR sessionRefNum IS -1)
|
|
return(sRec);
|
|
|
|
qset(&connectionQ);
|
|
if (ll_length() ISNT 0)
|
|
{
|
|
llsetMatch((ProcPtr)bySessionID);
|
|
llhead();
|
|
if (llcheck((char *)&sessionRefNum))
|
|
llretrieve((char *)&sRec);
|
|
}
|
|
|
|
return(sRec);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
#if !CubeE // <24> Keep the old version around for
|
|
cTableEntryPtr // <24> Non CubeE builds for now.
|
|
findFreeSessionRecord(void)
|
|
{
|
|
Handle aHdl;
|
|
OSErr err;
|
|
|
|
aHdl = GMBlk(sizeof(cTableEntry), &err);
|
|
if (err ISNT noErr)
|
|
return(nil);
|
|
HLock(aHdl);
|
|
MemClear(*aHdl,sizeof(cTableEntry));
|
|
|
|
((cTableEntryPtr)(*aHdl))->sHdl = aHdl;
|
|
return(*aHdl);
|
|
}
|
|
#endif
|
|
|
|
#if CubeE // <24> The ÒfixedÓ version from 7-Up
|
|
cTableEntryPtr
|
|
findFreeSessionRecord(void)
|
|
{
|
|
Handle aHdl;
|
|
|
|
aHdl = NewHandleSysClear(sizeof(cTableEntry)); // <24> Allocate the block in the System heap
|
|
if (!aHdl)
|
|
return(nil);
|
|
|
|
MoveHLow(aHdl); // <24> Move it low in the System heap
|
|
HLock(aHdl); // <24> before locking it.
|
|
|
|
((cTableEntryPtr)(*aHdl))->sHdl = aHdl;
|
|
return(*aHdl);
|
|
}
|
|
#endif
|
|
|
|
/*____________________________________getSessionID_____________________________________________*/
|
|
unsigned long
|
|
getSessionID(ProcessSerialNumberPtr sendersPSN, TargetIDPtr portN, OSErr *err)
|
|
{
|
|
PPCStartPBRec pbS;
|
|
cTableEntryPtr sRec;
|
|
TargetID senderTID;
|
|
Boolean portMatchfound = false;
|
|
Boolean enableGuestButton;
|
|
Str255 userName;
|
|
Boolean guestSelected;
|
|
EPPCBlkPtr postersEppcBlk;
|
|
Ptr funcPtr=StartSecureSession;
|
|
unsigned long myA5;
|
|
|
|
*err = noErr;
|
|
|
|
if ((postersEppcBlk = EPPCBlkFromPSN(sendersPSN)) IS nil)
|
|
{
|
|
*err = noPortErr;
|
|
return(0);
|
|
}
|
|
|
|
if (postersEppcBlk->createErr)
|
|
{
|
|
*err = postersEppcBlk->createErr;
|
|
return(0);
|
|
}
|
|
|
|
/* see if connection already exists */
|
|
|
|
senderTID = getTIDfromEppcBlk(postersEppcBlk);
|
|
|
|
qset(&connectionQ);
|
|
llhead();
|
|
if (ll_length() ISNT 0)
|
|
llretrieve(&sRec);
|
|
else
|
|
sRec = nil;
|
|
while (sRec)
|
|
{
|
|
if (sRec->sID)
|
|
{
|
|
if (sRec->sEppcBlkPtr IS postersEppcBlk)
|
|
if (PortNameAndLocationAreEqual(&sRec->sPName, &sRec->sLocName, portN))
|
|
{
|
|
portMatchfound = true;
|
|
break;
|
|
}
|
|
else
|
|
if (PortNameAndLocationAreEqual(&sRec->sEppcBlkPtr->nameOfMsgQ, nil, portN))
|
|
if (PortNameAndLocationAreEqual(&sRec->sPName, &sRec->sLocName, &senderTID))
|
|
{
|
|
portMatchfound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (llnext())
|
|
llretrieve(&sRec);
|
|
else
|
|
sRec = nil;
|
|
}
|
|
|
|
if (portMatchfound)
|
|
if (sRec->status & (sessionClosed+sessionEnded))
|
|
{
|
|
*err = sessClosedErr;
|
|
lldelete();
|
|
DisposHandle(sRec->sHdl);
|
|
return(0);
|
|
}
|
|
else
|
|
return(sRec->sID);
|
|
|
|
/* connection didn't exist. See if we have a free one to give out. */
|
|
|
|
if ((sRec = findFreeSessionRecord()) IS nil)
|
|
{
|
|
*err = sessTableErr; /* session table has no free entries */
|
|
return (0);
|
|
}
|
|
|
|
MemClear(&pbS,sizeof(PPCStartPBRec));
|
|
pbS.csCode = ppcStartCmd;
|
|
pbS.portRefNum = postersEppcBlk->portID;
|
|
pbS.ioCompletion = nil;
|
|
pbS.serviceType = ppcServiceRealTime;
|
|
|
|
if (portN->location.locationKindSelector IS ppcNBPLocation)
|
|
pbS.locationName = &portN->location;
|
|
else
|
|
pbS.locationName = nil;
|
|
pbS.portName = &portN->name;
|
|
|
|
/* The following if statement causes noUserInteractionAllowed to be returned if we are */
|
|
/* establishing a remote connection and the application is not frontmost or is being */
|
|
/* coerced. */
|
|
/* For 7.0B6 the check for the application being coerced was removed. A background app */
|
|
/* may want to come to the foreground and post a HLE which requires a session to be */
|
|
/* established. The app may still be in the coerced state, yet pFrontProcess IS */
|
|
/* pCurrentProcess and the app is in the frontmost layer of windows. At this point */
|
|
/* it should be OK for authentication to occur. Hopefully.
|
|
|
|
/* This does not deal with the app filling in the NBP name of his local machine. */
|
|
|
|
#if 0
|
|
if ((pbS.locationName ISNT nil) AND ((pFrontProcess ISNT pCurrentProcess) OR (coercionState ISNT CS_DONE)))
|
|
#else
|
|
if ((pbS.locationName ISNT nil) AND (pFrontProcess ISNT pCurrentProcess))
|
|
#endif
|
|
{
|
|
DisposHandle(sRec->sHdl);
|
|
*err = noUserInteractionAllowed;
|
|
return(0);
|
|
}
|
|
|
|
enableGuestButton = guestAllowed(portN, err);
|
|
if (*err ISNT noErr)
|
|
{
|
|
DisposHandle(sRec->sHdl);
|
|
return (0);
|
|
}
|
|
|
|
MemClear(&userName,sizeof(Str255));
|
|
|
|
/* StartSecureSession may cause the Dialog Manager to run. It is best if our
|
|
app's A5 is in the machine because user items in dialog windows behind the
|
|
authentication dialog(s) may execute. Some user item procedure assume that
|
|
A5 points to the application's global not the Process Manager's globals.
|
|
*/
|
|
myA5 = CurrentA5SimpleSetup();
|
|
*err = CALL_FNC_PTR(StartSecureSession_ptr, funcPtr, (&pbS, &userName, false, enableGuestButton, &guestSelected, nil));
|
|
A5SimpleRestore(myA5);
|
|
|
|
/*
|
|
*err = StartSecureSession (&pbS, &userName, false, enableGuestButton, &guestSelected, nil);
|
|
*/
|
|
if (*err ISNT noErr)
|
|
{
|
|
DisposHandle(sRec->sHdl);
|
|
return (0);
|
|
}
|
|
|
|
/* delete user identity. eppc doesn't use it. deleting it frees PPCToolbox resources. */
|
|
|
|
DeleteUserIdentity (pbS.userRefNum);
|
|
|
|
/* fill in the connection entry */
|
|
|
|
sRec->status |= startConnection;
|
|
sRec->sID = pbS.sessRefNum;
|
|
|
|
sRec->sEppcBlkPtr = postersEppcBlk;
|
|
sRec->sportID = postersEppcBlk->portID;
|
|
|
|
sRec->sPName = portN->name;
|
|
if (portN->location.locationKindSelector IS ppcNBPLocation)
|
|
sRec->sLocName = portN->location;
|
|
else
|
|
sRec->sLocName.locationKindSelector = ppcNoLocation;
|
|
|
|
sRec->srPB = startPPCRead(postersEppcBlk, sRec->sID, err);
|
|
if (sRec->srPB IS nil)
|
|
{
|
|
DisposHandle(sRec->sHdl);
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
qset(&connectionQ);
|
|
q_push(sRec);
|
|
}
|
|
|
|
return(sRec->sID);
|
|
}
|
|
/*_________________________________restartPPCRead_____________________________________________*/
|
|
PPCReadPBPtr
|
|
restartPPCRead(ppcReadPBPtr rPB, OSErr *err)
|
|
{
|
|
|
|
MemClear(&rPB->mfMsgBlk,sizeof(MFmsgBlk));
|
|
rPB->mfMsgBlk.pbHandle = rPB->pbHdl;
|
|
*err = PPCRead(&rPB->ppcReadPB,ASYNCHRONOUS);
|
|
|
|
return(&rPB->ppcReadPB);
|
|
}
|
|
/*___________________________________startPPCRead_____________________________________________*/
|
|
PPCReadPBPtr
|
|
startPPCRead(EPPCBlkPtr eppcBPtr, unsigned long sessionID, OSErr *err)
|
|
{
|
|
PPCReadPBPtr rPB;
|
|
|
|
rPB = getPPCReadPB(eppcBPtr, sessionID, err);
|
|
if (*err IS noErr)
|
|
*err = PPCRead(rPB,ASYNCHRONOUS);
|
|
|
|
return(rPB);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
guestAllowed(TargetIDPtr portN, OSErr *err)
|
|
{
|
|
PortInfoRec infoBuff;
|
|
IPCListPortsPBRec listPortPB;
|
|
|
|
*err = noErr;
|
|
if (portN->location.locationKindSelector IS ppcNoLocation)
|
|
return(false);
|
|
MemClear(&listPortPB,sizeof(IPCListPortsPBRec));
|
|
listPortPB.csCode = IPCListPortsCmd;
|
|
listPortPB.requestCount = 1;
|
|
listPortPB.portName = &portN->name;
|
|
listPortPB.locationName = &portN->location;
|
|
listPortPB.bufferPtr = &infoBuff;
|
|
*err = IPCListPorts(&listPortPB,SYNCHRONOUS);
|
|
if (*err ISNT noErr)
|
|
return(false);
|
|
if (listPortPB.actualCount IS 1)
|
|
return (!infoBuff.authRequired);
|
|
else
|
|
{
|
|
*err = destPortErr;
|
|
return(false);
|
|
}
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
findElement(char *A, char *B)
|
|
{
|
|
return((*(LINKTYPE *)A).item IS (*(LINKTYPE *)B).item);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
byPSN(EPPCBlkPtr A, ProcessSerialNumberPtr B)
|
|
{
|
|
return(EqualPSN(&(A->pTablePtr->p_serialNumber),B));
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
byPortName(EPPCBlkPtr A, PPCPortPtr B)
|
|
{
|
|
return(!comparePortNames(&A->nameOfMsgQ,B));
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
bySignature(EPPCBlkPtr A, ResType *B)
|
|
{
|
|
return(A->pTablePtr->p_signature IS *B);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
byPBID(ppcWritePBPtr A, EPPCBlk *B)
|
|
{
|
|
return(A->pbID IS B);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
bySessionID(cTableEntryPtr A, unsigned long *B)
|
|
{
|
|
return(A->sID IS *B);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
bysEppcBlkPtr(cTableEntryPtr A, EPPCBlk *B)
|
|
{
|
|
return(A->sEppcBlkPtr IS B);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
byportIDforPB(ppcWriteBlk *A, unsigned long *B)
|
|
{
|
|
return(A->portID IS *B);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
byportID(cTableEntryPtr A, unsigned long *B)
|
|
{
|
|
return(A->sportID IS *B);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
PSNFromName(PPCPortPtr portName, ProcessSerialNumberPtr pPSN)
|
|
{
|
|
EPPCBlkPtr eppcB = nil;
|
|
Boolean retVal;
|
|
|
|
qset(&eppcBQ);
|
|
if (ll_length() ISNT 0)
|
|
{
|
|
llsetMatch((ProcPtr)byPortName);
|
|
llhead();
|
|
if (llcheck(portName))
|
|
llretrieve((char *)&eppcB);
|
|
}
|
|
|
|
/* Set output parameter and function value */
|
|
if (retVal = (eppcB != nil))
|
|
*pPSN = eppcB->pTablePtr->p_serialNumber;
|
|
else
|
|
SetPSN(kNoProcess, pPSN);
|
|
|
|
return(retVal);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
NameFromPSN(PPCPortPtr portName, ProcessSerialNumberPtr pPSN)
|
|
{
|
|
EPPCBlkPtr eppcB = nil;
|
|
Boolean retVal;
|
|
|
|
qset(&eppcBQ);
|
|
if (ll_length() ISNT 0)
|
|
{
|
|
llsetMatch((ProcPtr)byPSN);
|
|
llhead();
|
|
if (llcheck(pPSN))
|
|
llretrieve((char *)&eppcB);
|
|
}
|
|
|
|
/* Set output parameter and function value */
|
|
if (retVal = (eppcB != nil))
|
|
*portName = eppcB->nameOfMsgQ;
|
|
|
|
return(retVal);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
Boolean
|
|
PSNFromSignature(ResType qid, ProcessSerialNumberPtr pPSN)
|
|
{
|
|
EPPCBlkPtr eppcB = nil;
|
|
Boolean retVal;
|
|
|
|
qset(&eppcBQ);
|
|
if (ll_length() ISNT 0)
|
|
{
|
|
llsetMatch((ProcPtr)bySignature);
|
|
llhead();
|
|
if (llcheck((char *)&qid))
|
|
llretrieve((char *)&eppcB);
|
|
}
|
|
|
|
/* Set output parameter and function value */
|
|
if (retVal = (eppcB != nil))
|
|
*pPSN = eppcB->pTablePtr->p_serialNumber;
|
|
else
|
|
SetPSN(kNoProcess, pPSN);
|
|
|
|
return(retVal);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
EPPCBlkPtr
|
|
EPPCBlkFromPSN(ProcessSerialNumberPtr pPSN)
|
|
{
|
|
qset(&eppcBQ);
|
|
if (ll_length() IS 0)
|
|
return(nil);
|
|
|
|
llsetMatch((ProcPtr)byPSN);
|
|
llhead();
|
|
if (llcheck((char *)pPSN))
|
|
return(eppcBQ.clp);
|
|
else
|
|
return(nil);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
releasePPCpb(PPCParamBlockPtr pb)
|
|
{
|
|
if (pb IS nil)
|
|
return;
|
|
(Ptr)pb -= sizeOfPPCpbHeader;
|
|
DisposHandle(((ppcReadPBPtr)pb)->pbHdl);
|
|
CheckForFatalError(MEMERROR IS noErr);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
PPCInformPBPtr
|
|
getPPCInformPB(EPPCBlkPtr refCon, unsigned short portID, OSErr *err)
|
|
{
|
|
Handle aHdl;
|
|
ppcInformPBPtr ppcInformBlkPtr;
|
|
|
|
/* carve out a parameter block for a async PPC call */
|
|
aHdl = GMBlk(sizeof(ppcInformBlk), err);
|
|
if (*err ISNT noErr)
|
|
return(nil);
|
|
HLock(aHdl);
|
|
ppcInformBlkPtr = *aHdl;
|
|
MemClear(ppcInformBlkPtr,sizeof(ppcInformBlk));
|
|
ppcInformBlkPtr->pbID = refCon;
|
|
ppcInformBlkPtr->portID = portID;
|
|
ppcInformBlkPtr->pbHdl = aHdl;
|
|
ppcInformBlkPtr->ppcInformPB.portName = &ppcInformBlkPtr->portName;
|
|
ppcInformBlkPtr->ppcInformPB.locationName = &ppcInformBlkPtr->portLoc;
|
|
|
|
ppcInformBlkPtr->ppcInformPB.csCode = ppcInformCmd;
|
|
ppcInformBlkPtr->ppcInformPB.ioCompletion = KnockKnock;
|
|
ppcInformBlkPtr->ppcInformPB.portRefNum = portID;
|
|
ppcInformBlkPtr->ppcInformPB.autoAccept = false;
|
|
|
|
return(&ppcInformBlkPtr->ppcInformPB);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
PPCReadPBPtr
|
|
getPPCReadPB(EPPCBlkPtr refCon, unsigned long sessionID, OSErr *err)
|
|
{
|
|
Handle aHdl;
|
|
ppcReadPBPtr ppcReadBlkPtr;
|
|
|
|
/* carve out a parameter block for a async PPC call */
|
|
|
|
aHdl = GMBlk(sizeof(ppcReadBlk), err);
|
|
if (*err ISNT noErr)
|
|
return(nil);
|
|
HLock(aHdl);
|
|
ppcReadBlkPtr = *aHdl;
|
|
MemClear(ppcReadBlkPtr,sizeof(ppcReadBlk));
|
|
|
|
ppcReadBlkPtr->pbID = refCon;
|
|
ppcReadBlkPtr->portID = refCon->portID;
|
|
ppcReadBlkPtr->pbHdl = aHdl;
|
|
ppcReadBlkPtr->ppcReadPB.bufferPtr = &ppcReadBlkPtr->mfMsgBlk.eppcMsgBlk;
|
|
ppcReadBlkPtr->ppcReadPB.bufferLength = sizeof(HighLevelEventMsg);
|
|
|
|
ppcReadBlkPtr->ppcReadPB.csCode = ppcReadCmd;
|
|
ppcReadBlkPtr->ppcReadPB.ioCompletion = KnockKnock;
|
|
ppcReadBlkPtr->ppcReadPB.sessRefNum = sessionID;
|
|
|
|
return(&ppcReadBlkPtr->ppcReadPB);
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
extern LINKLIST *list;
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
qPPCPb(ppcWritePBPtr wPBPtr, LINKLIST *BQList)
|
|
{
|
|
LINKLIST *oldList = list;
|
|
|
|
assert(!BQList->listInUse);
|
|
qset(BQList);
|
|
q_push(wPBPtr);
|
|
list = oldList;
|
|
}
|
|
/*____________________________________________________________________________________________*/
|
|
void
|
|
KnockKnock( PPCParamBlockPtr ppcPb )
|
|
{
|
|
ppcWritePBPtr wPBPtr;
|
|
ppcInformPBPtr iPBPtr;
|
|
|
|
wPBPtr = (ppcWritePBPtr)((Ptr)ppcPb - (Ptr)sizeOfPPCpbHeader);
|
|
|
|
switch(ppcPb->startParam.csCode) {
|
|
case ppcInformCmd:
|
|
|
|
/* closing the port causes all async calls to go to completion */
|
|
if (ppcPb->informParam.ioResult ISNT noErr)
|
|
{
|
|
qPPCPb(wPBPtr, &ppcInformBQ);
|
|
break;
|
|
}
|
|
|
|
iPBPtr = (ppcInformPBPtr)wPBPtr;
|
|
iPBPtr->ppcInformReplyPB.ioCompletion = KnockKnock;
|
|
iPBPtr->ppcInformReplyPB.sessRefNum = ppcPb->informParam.sessRefNum; // <13>
|
|
|
|
/* if close is in progress on the port reject the incoming session */
|
|
|
|
if (wPBPtr->status & closeInProgress)
|
|
PPCReject(&iPBPtr->ppcInformReplyPB,ASYNCHRONOUS);
|
|
else
|
|
PPCAccept(&iPBPtr->ppcInformReplyPB,ASYNCHRONOUS);
|
|
break;
|
|
case ppcWriteCmd:
|
|
qPPCPb(wPBPtr, &ppcWriteBQ);
|
|
break;
|
|
case ppcReadCmd:
|
|
wPBPtr->mfMsgBlk.eppcMsgBlk.theMsgEvent.when = TICKS;
|
|
qPPCPb(wPBPtr, &ppcReadBQ);
|
|
break;
|
|
case ppcAcceptCmd:
|
|
case ppcRejectCmd:
|
|
iPBPtr = (ppcInformPBPtr)((Ptr)wPBPtr - (Ptr)sizeof(PPCInformPBRec));
|
|
qPPCPb(iPBPtr, &ppcInformBQ);
|
|
break;
|
|
case ppcOpenCmd:
|
|
case ppcStartCmd:
|
|
case ppcEndCmd:
|
|
case ppcCloseCmd:
|
|
case IPCListPortsCmd:
|
|
default:
|
|
dbmsg("Eppc completion routine called for unknown command.");
|
|
break;
|
|
}
|
|
}
|