Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
zaptcp.c
/*----------------------------------------------------------------- |
ZapTCP application patch sample |
Steve Falkeburg MacDTS 6/29/93 |
written in Think C 6.0 |
-----------------------------------------------------------------*/ |
#ifndef __TYPES__ |
#include <Types.h> |
#endif |
#ifndef __MEMORY__ |
#include <Memory.h> |
#endif |
#ifndef __DEVICES__ |
#include <Devices.h> |
#endif |
#ifndef __MEMORY__ |
#include <Memory.h> |
#endif |
#ifndef __PACKAGES__ |
#include <Packages.h> |
#endif |
#ifndef __NOTIFICATION__ |
#include <Notification.h> |
#endif |
#ifndef __TRAPS__ |
#include <Traps.h> |
#endif |
#ifndef THINK_C |
#include <SysEqu.h> |
#include <strings.h> |
#endif |
#include <MacTCPCommonTypes.h> |
#include <TCPPB.h> |
#include <stdio.h> |
#include <string.h> |
/*** DEFINES ***/ |
#define kRAMBasedMask (1<<6) |
#define kDrvrOpenMask (1<<5) |
#define kDriverNameOffset 0x12 |
/*** GLOBALS ***/ |
static long etsAddr; // previous trap address of _ExitToShell |
/*** PROTOTYPES ***/ |
pascal void ExitToShellPatch(void); |
OSErr ZapTCP(void); |
void AlertConnReleased(unsigned long remoteHost,unsigned short remotePort); |
void AlertStreamReleased(unsigned long stream); |
void LongToHex(unsigned long num,char *hexStr); |
void LongToIPAddr(unsigned long num,char *ipStr); |
void CNumToString(unsigned long num,char *str); |
short GetDriverRefNum(StringPtr dName,Boolean *isOpen); |
OSErr PostNotify(StringPtr notifStr); |
/*** FUNCTIONS ***/ |
// installs our patch to _ExitToShell |
// |
void InstallZapTCP(void) |
{ |
long etsPatch; |
etsAddr = NGetTrapAddress(_ExitToShell,ToolTrap); |
etsPatch = (long)StripAddress((Ptr)ExitToShellPatch); |
NSetTrapAddress(etsPatch,_ExitToShell,ToolTrap); |
} |
// this is our _ExitToShell patch, which will be called when the app crashes or quits. |
// it even gets called on force-quits and bus errors. |
// |
pascal void ExitToShellPatch(void) |
{ |
long savedA5; |
long etsNext,etsOld,ourEtsPatch; |
savedA5 = SetCurrentA5(); |
etsNext = etsAddr; |
etsNext++; |
etsNext--; /* generate additional references so it doesn't optimize out */ |
ZapTCP(); |
SetA5(savedA5); |
// unpatch ourselves (if nobody has patched in the meantime |
etsOld = NGetTrapAddress(_ExitToShell,ToolTrap); |
ourEtsPatch = (long)StripAddress((Ptr)ExitToShellPatch); |
if (etsOld==ourEtsPatch) { |
NSetTrapAddress(etsNext,_ExitToShell,ToolTrap); |
} |
asm { |
move.l etsNext,a0 |
unlk a6 |
move.l a0,-(sp) |
rts |
} |
} |
// here's the patch code. this is called on response to _ExitToShell, and searches the |
// list of open streams for streams in our heap. if it finds any, those streams are released. |
// |
OSErr ZapTCP(void) |
{ |
THz theZone; |
short drvrRefNum; |
OSErr err; |
TCPiopb tcpBlock; |
StreamPtr *curStream; |
long theStream; |
unsigned long streamIndex,maxStreams; |
Boolean isOpen; |
theZone = ApplicZone(); |
// get the MacTCP driver refnum, exiting if it never opened |
drvrRefNum = GetDriverRefNum("\p.ipp",&isOpen); |
if (!isOpen) |
return noErr; |
// call TCPGlobalInfo, which returns a list of the open connections and streams |
tcpBlock.ioCRefNum = drvrRefNum; |
tcpBlock.csCode = TCPGlobalInfo; |
err = PBControl((ParmBlkPtr)&tcpBlock,false); |
if (err!=noErr) |
return err; |
// check each stream to see if its buffers are in our application heap. if so, |
// release the connection via TCPAbort and TCPRelease. |
curStream = *tcpBlock.csParam.globalInfo.tcpCDBTable; |
maxStreams = tcpBlock.csParam.globalInfo.tcpParamPtr->tcpMaxConn; |
for (streamIndex=0; streamIndex<maxStreams; streamIndex++,curStream++) { |
theStream = *curStream; |
if (theStream && (theStream%2)==0 && PtrZone((Ptr)theStream)==theZone) { // only release streams in our heap |
tcpBlock.csCode = TCPStatus; |
tcpBlock.tcpStream = theStream; |
err = PBControl((ParmBlkPtr)&tcpBlock,false); |
if (err==noErr) |
AlertConnReleased(tcpBlock.csParam.status.remoteHost,(unsigned short)tcpBlock.csParam.status.remotePort); |
else |
AlertStreamReleased(theStream); |
// abort connection |
tcpBlock.csCode = TCPAbort; |
tcpBlock.tcpStream = theStream; |
err = PBControl((ParmBlkPtr)&tcpBlock,false); |
// release stream |
tcpBlock.csCode = TCPRelease; |
tcpBlock.tcpStream = theStream; |
err = PBControl((ParmBlkPtr)&tcpBlock,false); |
} |
} |
return err; |
} |
// notify the user that a connection was closed |
// |
void AlertConnReleased(unsigned long remoteHost,unsigned short remotePort) |
{ |
char hostStr[256]; |
char portStr[256]; |
char *messageStr; |
messageStr = (char *)NewPtrSys(256); |
if (MemError()!=noErr) |
return; |
LongToIPAddr(remoteHost,hostStr); |
CNumToString(remotePort,portStr); |
strcpy(messageStr,"Warning: TCP connection released (remote addr: "); |
strcat(messageStr,hostStr); |
strcat(messageStr," remote port: "); |
strcat(messageStr,portStr); |
strcat(messageStr,")"); |
c2pstr(messageStr); |
PostNotify((StringPtr)messageStr); |
} |
// notify the user that a stream not associated with a connection was released |
// |
void AlertStreamReleased(unsigned long stream) |
{ |
char streamStr[256]; |
char *messageStr; |
messageStr = (char *)NewPtrSys(256); |
if (MemError()!=noErr) |
return; |
LongToHex(stream,streamStr); |
strcpy(messageStr,"Warning: TCP stream released (memory location: $"); |
strcat(messageStr,streamStr); |
strcat(messageStr,")"); |
c2pstr(messageStr); |
PostNotify((StringPtr)messageStr); |
} |
// convert a long into a hex string for display |
// |
void LongToHex(unsigned long num,char *hexStr) |
{ |
unsigned long nibble; |
short bitCount; |
char hexChar[2]; |
hexChar[1] = '\0'; |
hexStr[0] = '\0'; |
for (bitCount=0; bitCount<32; bitCount+=4) { |
nibble = ((num & 0xf0000000) >> 28) & 0x0000000f; |
num = num << 4; |
if (nibble<=9 && nibble>=0) |
hexChar[0] = '0'+(char)nibble; |
else if (nibble>=10 && nibble <= 15) |
hexChar[0] = 0x37+(char)nibble; |
else |
Debugger(); |
strcat(hexStr,hexChar); |
} |
} |
// convert a long into an ip address (x.x.x.x) for display |
// |
void LongToIPAddr(unsigned long num,char *ipStr) |
{ |
short bitCount; |
unsigned long octet; |
char octStr[256]; |
ipStr[0] = '\0'; |
for (bitCount=0; bitCount<32; bitCount+=8) { |
octet = ((num & 0xff000000) >> 24) & 0x000000ff; |
num = num << 8; |
CNumToString(octet,octStr); |
strcat(ipStr,octStr); |
if (bitCount!=24) |
strcat(ipStr,"."); |
} |
} |
// convert a number into a C string for display |
// |
void CNumToString(unsigned long num,char *str) |
{ |
unsigned long place,digit; |
char addStr[2]; |
Boolean firstDig; |
str[0] = '\0'; |
addStr[1] = '\0'; |
firstDig = true; |
for (place = 1000000000; place!=0; place = place/10) { |
digit = num/place; |
num -= (place*digit); |
if (digit) |
firstDig = false; |
if (digit>0 || !firstDig || (num==0&&place==1)) { |
addStr[0] = '0'+(char)digit; |
strcat(str,addStr); |
} |
} |
} |
// get the refnum of a driver given its name, and tell us whether it's already open |
// |
short GetDriverRefNum(StringPtr dName,Boolean *isOpen) |
{ |
short negCount; |
DCtlHandle dceH; |
Ptr drivePtr; |
StringPtr s; |
short drvrRefNum; |
#ifdef __SYSEQU__ |
negCount = -* (short *) (UnitNtryCnt); |
#else |
negCount = -UnitNtryCnt; |
#endif |
// check to see that driver is installed, obtain refnum |
drvrRefNum = -12+1; |
do { |
dceH = GetDCtlEntry(--drvrRefNum); |
s = (StringPtr)""; |
if ((dceH != nil) && ((**dceH).dCtlDriver!=nil)) { |
if ((**dceH).dCtlFlags & kRAMBasedMask) |
drivePtr = *((Handle)(**dceH).dCtlDriver); |
else |
drivePtr = (Ptr) (**dceH).dCtlDriver; |
if (drivePtr!=nil) { |
s = (StringPtr)(drivePtr+kDriverNameOffset); |
} |
} |
} while ((drvrRefNum!=negCount) && (EqualString(dName,s,false,true)==false)); |
if (EqualString(dName,s,false,true)==false) |
drvrRefNum = 0; |
else |
*isOpen = ((**dceH).dCtlFlags & kDrvrOpenMask)!=0; |
return drvrRefNum; |
} |
// use the notification manager to post a notification alert to the user |
// |
OSErr PostNotify(StringPtr notifStr) |
{ |
OSErr err; |
NMRecPtr nmPtr; |
nmPtr = (NMRecPtr) NewPtrSys(sizeof(NMRec)); |
if (MemError()!=noErr) |
return MemError(); |
nmPtr->qType = nmType; |
nmPtr->nmMark = 0; |
nmPtr->nmIcon = nil; |
nmPtr->nmSound = 0; |
nmPtr->nmStr = notifStr; |
nmPtr->nmResp = nil; |
err = NMInstall(nmPtr); |
return err; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14