mirror of https://github.com/python/cpython.git
491 lines
10 KiB
C
491 lines
10 KiB
C
/*
|
|
* Glue routines for mactcp module.
|
|
* Jack Jansen, CWI, 1994.
|
|
*
|
|
* Adapted from mactcp socket library, which was in turn
|
|
* adapted from ncsa telnet code.
|
|
*
|
|
* Original authors: Tom Milligan, Charlie Reiman
|
|
*/
|
|
|
|
# include <Memory.h>
|
|
# include <Files.h>
|
|
# include <Errors.h>
|
|
|
|
#include "tcpglue.h"
|
|
#include <Devices.h>
|
|
|
|
#ifndef __MWERKS__
|
|
#define TCPIOCompletionUPP TCPIOCompletionProc
|
|
#define NewTCPIOCompletionProc(x) (x)
|
|
#endif /* __MWERKS__ */
|
|
|
|
static short driver = 0;
|
|
|
|
#ifndef __powerc
|
|
/*
|
|
* Hack fix for MacTCP 1.0.X bug
|
|
*
|
|
* This hack doesn't work on the PPC. But then, people with new machines
|
|
* shouldn't run ancient buggy software. -- Jack.
|
|
*/
|
|
|
|
pascal char *ReturnA5(void) = {0x2E8D};
|
|
#endif /* !__powerc */
|
|
|
|
OSErr xOpenDriver()
|
|
{
|
|
if (driver == 0)
|
|
{
|
|
ParamBlockRec pb;
|
|
OSErr io;
|
|
|
|
pb.ioParam.ioCompletion = 0L;
|
|
pb.ioParam.ioNamePtr = "\p.IPP";
|
|
pb.ioParam.ioPermssn = fsCurPerm;
|
|
io = PBOpen(&pb,false);
|
|
if (io != noErr)
|
|
return(io);
|
|
driver = pb.ioParam.ioRefNum;
|
|
}
|
|
return noErr;
|
|
}
|
|
|
|
/*
|
|
* create a TCP stream
|
|
*/
|
|
OSErr xTCPCreate(buflen,notify,udp, pb)
|
|
int buflen;
|
|
TCPNotifyProc notify;
|
|
void *udp;
|
|
TCPiopb *pb;
|
|
{
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPCreate;
|
|
pb->csParam.create.rcvBuff = (char *)NewPtr(buflen);
|
|
pb->csParam.create.rcvBuffLen = buflen;
|
|
pb->csParam.create.notifyProc = notify;
|
|
pb->csParam.create.userDataPtr = udp;
|
|
return (xPBControlSync(pb));
|
|
}
|
|
|
|
|
|
/*
|
|
* start listening for a TCP connection
|
|
*/
|
|
OSErr xTCPPassiveOpen(TCPiopb *pb, short port, TCPIOCompletionProc completion,
|
|
void *udp)
|
|
{
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPPassiveOpen;
|
|
pb->csParam.open.validityFlags = timeoutValue | timeoutAction;
|
|
pb->csParam.open.ulpTimeoutValue = 255 /* seconds */;
|
|
pb->csParam.open.ulpTimeoutAction = 0 /* 1:abort 0:report */;
|
|
pb->csParam.open.commandTimeoutValue = 0 /* infinity */;
|
|
pb->csParam.open.remoteHost = 0;
|
|
pb->csParam.open.remotePort = 0;
|
|
pb->csParam.open.localHost = 0;
|
|
pb->csParam.open.localPort = port;
|
|
pb->csParam.open.dontFrag = 0;
|
|
pb->csParam.open.timeToLive = 0;
|
|
pb->csParam.open.security = 0;
|
|
pb->csParam.open.optionCnt = 0;
|
|
pb->csParam.open.userDataPtr = udp;
|
|
return (xPBControl(pb,completion));
|
|
}
|
|
|
|
/*
|
|
* connect to a remote TCP
|
|
*/
|
|
OSErr xTCPActiveOpen(TCPiopb *pb, short port, long rhost, short rport,
|
|
TCPIOCompletionProc completion)
|
|
{
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPActiveOpen;
|
|
pb->csParam.open.validityFlags = timeoutValue | timeoutAction;
|
|
pb->csParam.open.ulpTimeoutValue = 60 /* seconds */;
|
|
pb->csParam.open.ulpTimeoutAction = 1 /* 1:abort 0:report */;
|
|
pb->csParam.open.commandTimeoutValue = 0;
|
|
pb->csParam.open.remoteHost = rhost;
|
|
pb->csParam.open.remotePort = rport;
|
|
pb->csParam.open.localHost = 0;
|
|
pb->csParam.open.localPort = port;
|
|
pb->csParam.open.dontFrag = 0;
|
|
pb->csParam.open.timeToLive = 0;
|
|
pb->csParam.open.security = 0;
|
|
pb->csParam.open.optionCnt = 0;
|
|
return (xPBControl(pb,completion));
|
|
}
|
|
|
|
OSErr xTCPNoCopyRcv(pb,rds,rdslen,timeout,completion)
|
|
TCPiopb *pb;
|
|
rdsEntry *rds;
|
|
int rdslen;
|
|
int timeout;
|
|
TCPIOCompletionProc completion;
|
|
{
|
|
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPNoCopyRcv;
|
|
pb->csParam.receive.commandTimeoutValue = timeout; /* seconds, 0 = blocking */
|
|
pb->csParam.receive.rdsPtr = (Ptr)rds;
|
|
pb->csParam.receive.rdsLength = rdslen;
|
|
return (xPBControl(pb,completion));
|
|
}
|
|
|
|
OSErr xTCPBufReturn(TCPiopb *pb,rdsEntry *rds,TCPIOCompletionProc completion)
|
|
{
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPRcvBfrReturn;
|
|
pb->csParam.receive.rdsPtr = (Ptr)rds;
|
|
|
|
return (xPBControl(pb,completion));
|
|
}
|
|
|
|
/*
|
|
* send data
|
|
*/
|
|
OSErr xTCPSend(TCPiopb *pb, wdsEntry *wds, Boolean push, Boolean urgent, TCPIOCompletionProc completion)
|
|
{
|
|
if (driver == 0)
|
|
return invalidStreamPtr;
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPSend;
|
|
pb->csParam.send.validityFlags = timeoutValue | timeoutAction;
|
|
pb->csParam.send.ulpTimeoutValue = 60 /* seconds */;
|
|
pb->csParam.send.ulpTimeoutAction = 0 /* 0:abort 1:report */;
|
|
pb->csParam.send.pushFlag = push;
|
|
pb->csParam.send.urgentFlag = urgent;
|
|
pb->csParam.send.wdsPtr = (Ptr)wds;
|
|
return (xPBControl(pb,completion));
|
|
}
|
|
|
|
|
|
/*
|
|
* close a connection
|
|
*/
|
|
OSErr xTCPClose(TCPiopb *pb,TCPIOCompletionProc completion)
|
|
{
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPClose;
|
|
pb->csParam.close.validityFlags = timeoutValue | timeoutAction;
|
|
pb->csParam.close.ulpTimeoutValue = 60 /* seconds */;
|
|
pb->csParam.close.ulpTimeoutAction = 1 /* 1:abort 0:report */;
|
|
return (xPBControl(pb,completion));
|
|
}
|
|
|
|
/*
|
|
* abort a connection
|
|
*/
|
|
OSErr xTCPAbort(TCPiopb *pb)
|
|
{
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPAbort;
|
|
return (xPBControlSync(pb));
|
|
}
|
|
|
|
/*
|
|
* close down a TCP stream (aborting a connection, if necessary)
|
|
*/
|
|
OSErr xTCPRelease(pb)
|
|
TCPiopb *pb;
|
|
{
|
|
OSErr io;
|
|
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPRelease;
|
|
io = xPBControlSync(pb);
|
|
if (io == noErr)
|
|
DisposPtr(pb->csParam.create.rcvBuff); /* there is no release pb */
|
|
return(io);
|
|
}
|
|
|
|
#if 0
|
|
|
|
int
|
|
xTCPBytesUnread(sp)
|
|
SocketPtr sp;
|
|
{
|
|
TCPiopb *pb;
|
|
OSErr io;
|
|
|
|
if (!(pb = sock_fetch_pb(sp)))
|
|
return -1; /* panic */
|
|
|
|
if (driver == 0)
|
|
return(-1);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPStatus;
|
|
io = xPBControlSync(pb);
|
|
if (io != noErr)
|
|
return(-1);
|
|
return(pb->csParam.status.amtUnreadData);
|
|
}
|
|
|
|
int
|
|
xTCPBytesWriteable(sp)
|
|
SocketPtr sp;
|
|
{
|
|
TCPiopb *pb;
|
|
OSErr io;
|
|
long amount;
|
|
|
|
if (!(pb = sock_fetch_pb(sp)))
|
|
return -1; /* panic */
|
|
|
|
if (driver == 0)
|
|
return(-1);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPStatus;
|
|
io = xPBControlSync(pb);
|
|
if (io != noErr)
|
|
return(-1);
|
|
amount = pb->csParam.status.sendWindow-pb->csParam.status.amtUnackedData;
|
|
if (amount < 0)
|
|
amount = 0;
|
|
return amount;
|
|
}
|
|
|
|
int xTCPWriteBytesLeft(SocketPtr sp)
|
|
{
|
|
TCPiopb *pb;
|
|
OSErr io;
|
|
|
|
if (!(pb = sock_fetch_pb(sp)))
|
|
return -1; /* panic */
|
|
|
|
if (driver == 0)
|
|
return(-1);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPStatus;
|
|
io = xPBControlSync(pb);
|
|
if (io != noErr)
|
|
return(-1);
|
|
return (pb->csParam.status.amtUnackedData);
|
|
}
|
|
#endif
|
|
|
|
OSErr xTCPStatus(TCPiopb *pb, TCPStatusPB **spb)
|
|
{
|
|
OSErr io;
|
|
|
|
if (driver == 0)
|
|
return(-1);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPStatus;
|
|
io = xPBControlSync(pb);
|
|
if (io == noErr)
|
|
*spb = &pb->csParam.status;
|
|
return(io);
|
|
}
|
|
|
|
|
|
/*
|
|
* create a UDP stream, hook it to a socket.
|
|
*/
|
|
OSErr xUDPCreate(UDPiopb *pb,int buflen,ip_port *port, UDPNotifyProc asr, void *udp)
|
|
{
|
|
OSErr io;
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = UDPCreate;
|
|
pb->csParam.create.rcvBuff = (char *)NewPtr(buflen);
|
|
pb->csParam.create.rcvBuffLen = buflen;
|
|
pb->csParam.create.notifyProc = asr;
|
|
pb->csParam.create.userDataPtr = udp;
|
|
pb->csParam.create.localPort = *port;
|
|
if ( (io = xPBControlSync( (TCPiopb *)pb ) ) != noErr)
|
|
return io;
|
|
|
|
*port = pb->csParam.create.localPort;
|
|
return noErr;
|
|
}
|
|
|
|
/*
|
|
* ask for incoming data
|
|
*/
|
|
OSErr xUDPRead(UDPiopb *pb, int timeout, UDPIOCompletionProc completion)
|
|
{
|
|
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = UDPRead;
|
|
pb->csParam.receive.timeOut = timeout;
|
|
pb->csParam.receive.secondTimeStamp = 0/* must be zero */;
|
|
return (xPBControl ( (TCPiopb *)pb, (TCPIOCompletionProc)completion ));
|
|
}
|
|
|
|
OSErr xUDPBfrReturn(UDPiopb *pb, char *buff)
|
|
{
|
|
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = UDPBfrReturn;
|
|
pb->csParam.receive.rcvBuff = buff;
|
|
return ( xPBControl( (TCPiopb *)pb,(TCPIOCompletionProc)-1 ) );
|
|
}
|
|
|
|
/*
|
|
* send data
|
|
*/
|
|
OSErr xUDPWrite(UDPiopb *pb,ip_addr host,ip_port port,miniwds *wds,
|
|
UDPIOCompletionProc completion)
|
|
{
|
|
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = UDPWrite;
|
|
pb->csParam.send.remoteHost = host;
|
|
pb->csParam.send.remotePort = port;
|
|
pb->csParam.send.wdsPtr = (Ptr)wds;
|
|
pb->csParam.send.checkSum = true;
|
|
pb->csParam.send.sendLength = 0/* must be zero */;
|
|
return (xPBControl( (TCPiopb *)pb, (TCPIOCompletionProc)completion));
|
|
}
|
|
|
|
/*
|
|
* close down a UDP stream (aborting a read, if necessary)
|
|
*/
|
|
OSErr xUDPRelease(UDPiopb *pb) {
|
|
OSErr io;
|
|
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = UDPRelease;
|
|
io = xPBControlSync( (TCPiopb *)pb );
|
|
if (io == noErr) {
|
|
DisposPtr(pb->csParam.create.rcvBuff);
|
|
}
|
|
return(io);
|
|
}
|
|
|
|
ip_addr xIPAddr(void)
|
|
{
|
|
struct GetAddrParamBlock pbr;
|
|
OSErr io;
|
|
|
|
pbr.ioCRefNum = driver;
|
|
pbr.csCode = ipctlGetAddr;
|
|
io = xPBControlSync( (TCPiopb *)&pbr );
|
|
if (io != noErr)
|
|
return(0);
|
|
return(pbr.ourAddress);
|
|
}
|
|
|
|
long xNetMask()
|
|
{
|
|
struct GetAddrParamBlock pbr;
|
|
OSErr io;
|
|
|
|
pbr.ioCRefNum = driver;
|
|
pbr.csCode = ipctlGetAddr;
|
|
io = xPBControlSync( (TCPiopb *)&pbr);
|
|
if (io != noErr)
|
|
return(0);
|
|
return(pbr.ourNetMask);
|
|
}
|
|
|
|
unsigned short xMaxMTU()
|
|
{
|
|
struct UDPiopb pbr;
|
|
OSErr io;
|
|
|
|
pbr.ioCRefNum = driver;
|
|
pbr.csCode = UDPMaxMTUSize;
|
|
pbr.csParam.mtu.remoteHost = xIPAddr();
|
|
io = xPBControlSync( (TCPiopb *)&pbr );
|
|
if (io != noErr)
|
|
return(0);
|
|
return(pbr.csParam.mtu.mtuSize);
|
|
}
|
|
|
|
OSErr xPBControlSync(TCPiopb *pb)
|
|
{
|
|
(pb)->ioCompletion = 0L;
|
|
return PBControl((ParmBlkPtr)(pb),false);
|
|
}
|
|
|
|
#pragma segment SOCK_RESIDENT
|
|
|
|
OSErr xTCPRcv(pb,buf,buflen,timeout,completion)
|
|
TCPiopb *pb;
|
|
Ptr buf;
|
|
int buflen;
|
|
int timeout;
|
|
TCPIOCompletionProc completion;
|
|
{
|
|
|
|
if (driver == 0)
|
|
return(invalidStreamPtr);
|
|
|
|
pb->ioCRefNum = driver;
|
|
pb->csCode = TCPRcv;
|
|
pb->csParam.receive.commandTimeoutValue = timeout; /* seconds, 0 = blocking */
|
|
pb->csParam.receive.rcvBuff = buf;
|
|
pb->csParam.receive.rcvBuffLen = buflen;
|
|
return (xPBControl(pb,completion));
|
|
}
|
|
|
|
OSErr xPBControl(TCPiopb *pb,TCPIOCompletionProc completion)
|
|
{
|
|
#ifndef __MWERKS__
|
|
pb->ioNamePtr = ReturnA5();
|
|
#endif
|
|
|
|
if (completion == 0L)
|
|
{
|
|
(pb)->ioCompletion = 0L;
|
|
return(PBControl((ParmBlkPtr)(pb),false)); /* sync */
|
|
}
|
|
else if (completion == (TCPIOCompletionProc)-1L)
|
|
{
|
|
(pb)->ioCompletion = 0L;
|
|
return(PBControl((ParmBlkPtr)(pb),true)); /* async */
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
/* If I understand the PowerPC calling correctly this is the right
|
|
** code, but the MetroWerks headers seem to disagree. We'll see... -- Jack
|
|
*/
|
|
TCPIOCompletionUPP comp_upp = NewTCPIOCompletionProc(completion);
|
|
(pb)->ioCompletion = comp_upp;
|
|
#else
|
|
(pb)->ioCompletion = completion;
|
|
#endif
|
|
return(PBControl((ParmBlkPtr)(pb),true)); /* async */
|
|
}
|
|
}
|
|
|