#include "tclInt.h"
#include "tclPort.h"
#include "tclMacInt.h"
#include <AddressXlation.h>
#include <Aliases.h>
#undef Status
#include <Devices.h>
#include <Errors.h>
#include <Events.h>
#include <Files.h>
#include <Gestalt.h>
#include <MacTCP.h>
#include <Processes.h>
#include <Strings.h>
static int initialized = 0;
#ifndef TCL_DEBUG
#define Debugger()
#endif
#define CHANNEL_BUF_SIZE 8192
typedef struct {
char *name;
int port;
} PortInfo;
typedef struct TcpState {
TCPiopb pb;
ProcessSerialNumber psn;
StreamPtr tcpStream;
int port;
int flags;
int checkMask;
int watchMask;
Tcl_TcpAcceptProc *acceptProc;
ClientData acceptProcData;
wdsEntry dataSegment[2];
rdsEntry rdsarray[5+1];
Tcl_Channel channel;
int writeBufferSize;
void *writeBuffer;
struct TcpState *nextPtr;
} TcpState;
typedef struct DNRState {
struct hostInfo hostInfo;
int done;
ProcessSerialNumber psn;
} DNRState;
#define TCP_ASYNC_SOCKET (1<<0)
#define TCP_ASYNC_CONNECT (1<<1)
#define TCP_CONNECTED (1<<2)
#define TCP_PENDING (1<<3)
#define TCP_LISTENING (1<<4)
#define TCP_LISTEN_CONNECT (1<<5)
#define TCP_REMOTE_CLOSED (1<<6)
#define TCP_RELEASE (1<<7)
#define TCP_WRITING (1<<8)
#define TCP_SERVER_ZOMBIE (1<<9)
typedef struct SocketEvent {
Tcl_Event header;
TcpState *statePtr;
StreamPtr tcpStream;
} SocketEvent;
static pascal void CleanUpExitProc _ANSI_ARGS_((void));
static void ClearZombieSockets _ANSI_ARGS_((void));
static void CloseCompletionRoutine _ANSI_ARGS_((TCPiopb *pb));
static TcpState * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp,
int port, CONST char *host, CONST char *myAddr,
int myPort, int server, int async));
static pascal void DNRCompletionRoutine _ANSI_ARGS_((
struct hostInfo *hostinfoPtr,
DNRState *dnrStatePtr));
static void FreeSocketInfo _ANSI_ARGS_((TcpState *statePtr));
static long GetBufferSize _ANSI_ARGS_((void));
static OSErr GetHostFromString _ANSI_ARGS_((CONST char *name,
ip_addr *address));
static OSErr GetLocalAddress _ANSI_ARGS_((unsigned long *addr));
static void IOCompletionRoutine _ANSI_ARGS_((TCPiopb *pb));
static void InitMacTCPParamBlock _ANSI_ARGS_((TCPiopb *pBlock,
int csCode));
static void InitSockets _ANSI_ARGS_((void));
static TcpState * NewSocketInfo _ANSI_ARGS_((StreamPtr stream));
static OSErr ResolveAddress _ANSI_ARGS_((ip_addr tcpAddress,
Tcl_DString *dsPtr));
static void SocketCheckProc _ANSI_ARGS_((ClientData clientData,
int flags));
static int SocketEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
int flags));
static void SocketExitHandler _ANSI_ARGS_((ClientData clientData));
static void SocketFreeProc _ANSI_ARGS_((ClientData clientData));
static int SocketReady _ANSI_ARGS_((TcpState *statePtr));
static void SocketSetupProc _ANSI_ARGS_((ClientData clientData,
int flags));
static void TcpAccept _ANSI_ARGS_((TcpState *statePtr));
static int TcpBlockMode _ANSI_ARGS_((ClientData instanceData, int mode));
static int TcpClose _ANSI_ARGS_((ClientData instanceData,
Tcl_Interp *interp));
static int TcpGetHandle _ANSI_ARGS_((ClientData instanceData,
int direction, ClientData *handlePtr));
static int TcpGetOptionProc _ANSI_ARGS_((ClientData instanceData,
Tcl_Interp *interp, CONST char *optionName,
Tcl_DString *dsPtr));
static int TcpInput _ANSI_ARGS_((ClientData instanceData,
char *buf, int toRead, int *errorCodePtr));
static int TcpOutput _ANSI_ARGS_((ClientData instanceData,
CONST char *buf, int toWrite, int *errorCodePtr));
static void TcpWatch _ANSI_ARGS_((ClientData instanceData,
int mask));
static int WaitForSocketEvent _ANSI_ARGS_((TcpState *infoPtr,
int mask, int *errorCodePtr));
pascal void NotifyRoutine (
StreamPtr tcpStream,
unsigned short eventCode,
Ptr userDataPtr,
unsigned short terminReason,
struct ICMPReport *icmpMsg);
static Tcl_ChannelType tcpChannelType = {
"tcp",
(Tcl_ChannelTypeVersion)TcpBlockMode,
TcpClose,
TcpInput,
TcpOutput,
NULL,
NULL,
TcpGetOptionProc,
TcpWatch,
TcpGetHandle
};
ResultUPP resultUPP = NULL;
TCPIOCompletionUPP completeUPP = NULL;
TCPIOCompletionUPP closeUPP = NULL;
TCPNotifyUPP notifyUPP = NULL;
static PortInfo portServices[] = {
{"echo", 7},
{"discard", 9},
{"systat", 11},
{"daytime", 13},
{"netstat", 15},
{"chargen", 19},
{"ftp-data", 20},
{"ftp", 21},
{"telnet", 23},
{"telneto", 24},
{"smtp", 25},
{"time", 37},
{"whois", 43},
{"domain", 53},
{"gopher", 70},
{"finger", 79},
{"hostnames", 101},
{"sunrpc", 111},
{"nntp", 119},
{"exec", 512},
{"login", 513},
{"shell", 514},
{"printer", 515},
{"courier", 530},
{"uucp", 540},
{NULL, 0},
};
typedef struct ThreadSpecificData {
TcpState *socketList;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
static int socketsTestInited = false;
static int hasSockets = false;
static short driverRefNum = 0;
static int socketNumber = 0;
static int socketBufferSize = CHANNEL_BUF_SIZE;
static ProcessSerialNumber applicationPSN;
#define gestaltMacTCPVersion 'mtcp'
static void
InitSockets()
{
ParamBlockRec pb;
OSErr err;
long response;
ThreadSpecificData *tsdPtr;
if (! initialized) {
initialized = 1;
if (Gestalt(gestaltMacTCPVersion, &response) == noErr) {
hasSockets = true;
} else {
hasSockets = false;
}
if (!hasSockets) {
return;
}
pb.ioParam.ioCompletion = 0L;
pb.ioParam.ioNamePtr = "\p.IPP";
pb.ioParam.ioPermssn = fsCurPerm;
err = PBOpenSync(&pb);
if (err != noErr) {
hasSockets = 0;
return;
}
driverRefNum = pb.ioParam.ioRefNum;
socketBufferSize = GetBufferSize();
err = OpenResolver(NULL);
if (err != noErr) {
hasSockets = 0;
return;
}
GetCurrentProcess(&applicationPSN);
resultUPP = NewResultProc(DNRCompletionRoutine);
completeUPP = NewTCPIOCompletionProc(IOCompletionRoutine);
closeUPP = NewTCPIOCompletionProc(CloseCompletionRoutine);
notifyUPP = NewTCPNotifyProc(NotifyRoutine);
TclMacInstallExitToShellPatch(CleanUpExitProc);
}
tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
if (tsdPtr == NULL) {
tsdPtr->socketList = NULL;
Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
Tcl_CreateThreadExitHandler(SocketExitHandler, (ClientData) NULL);
}
}
static void
SocketExitHandler(
ClientData clientData)
{
if (hasSockets) {
Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
}
}
int
TclpHasSockets(
Tcl_Interp *interp)
{
InitSockets();
if (hasSockets) {
return TCL_OK;
}
if (interp != NULL) {
Tcl_AppendResult(interp, "sockets are not available on this system",
NULL);
}
return TCL_ERROR;
}
static void
SocketSetupProc(
ClientData data,
int flags)
{
TcpState *statePtr;
Tcl_Time blockTime = { 0, 0 };
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!(flags & TCL_FILE_EVENTS)) {
return;
}
for (statePtr = tsdPtr->socketList; statePtr != NULL;
statePtr = statePtr->nextPtr) {
if (statePtr->flags & TCP_RELEASE) {
continue;
}
if (SocketReady(statePtr)) {
Tcl_SetMaxBlockTime(&blockTime);
break;
}
}
}
static void
SocketCheckProc(
ClientData data,
int flags)
{
TcpState *statePtr;
SocketEvent *evPtr;
TcpState dummyState;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!(flags & TCL_FILE_EVENTS)) {
return;
}
for (statePtr = tsdPtr->socketList; statePtr != NULL;
statePtr = statePtr->nextPtr) {
if (statePtr->flags & TCP_RELEASE) {
if (!(statePtr->flags & TCP_PENDING)) {
dummyState.nextPtr = statePtr->nextPtr;
SocketFreeProc(statePtr);
statePtr = &dummyState;
}
continue;
}
if (!(statePtr->flags & TCP_PENDING) && SocketReady(statePtr)) {
statePtr->flags |= TCP_PENDING;
evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent));
evPtr->header.proc = SocketEventProc;
evPtr->statePtr = statePtr;
evPtr->tcpStream = statePtr->tcpStream;
Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
}
}
}
static int
SocketReady(
TcpState *statePtr)
{
TCPiopb statusPB;
int foundSomething = 0;
int didStatus = 0;
int amount;
OSErr err;
if (statePtr->flags & TCP_LISTEN_CONNECT) {
foundSomething = 1;
statePtr->checkMask |= TCL_READABLE;
}
if (statePtr->watchMask & TCL_READABLE) {
if (statePtr->checkMask & TCL_READABLE) {
foundSomething = 1;
} else if (statePtr->flags & TCP_CONNECTED) {
statusPB.ioCRefNum = driverRefNum;
statusPB.tcpStream = statePtr->tcpStream;
statusPB.csCode = TCPStatus;
err = PBControlSync((ParmBlkPtr) &statusPB);
didStatus = 1;
if ((err != noErr) ||
(statusPB.csParam.status.amtUnreadData > 0) ||
(statusPB.csParam.status.connectionState == 14)) {
statePtr->checkMask |= TCL_READABLE;
foundSomething = 1;
}
}
}
if (statePtr->watchMask & TCL_WRITABLE) {
if (statePtr->checkMask & TCL_WRITABLE) {
foundSomething = 1;
} else if (statePtr->flags & TCP_CONNECTED) {
if (!didStatus) {
statusPB.ioCRefNum = driverRefNum;
statusPB.tcpStream = statePtr->tcpStream;
statusPB.csCode = TCPStatus;
err = PBControlSync((ParmBlkPtr) &statusPB);
}
amount = statusPB.csParam.status.sendWindow -
statusPB.csParam.status.amtUnackedData;
if ((err != noErr) || (amount > 0)) {
statePtr->checkMask |= TCL_WRITABLE;
foundSomething = 1;
}
}
}
return foundSomething;
}
static void
InitMacTCPParamBlock(
TCPiopb *pBlock,
int csCode)
{
memset(pBlock, 0, sizeof(TCPiopb));
pBlock->ioResult = 1;
pBlock->ioCRefNum = driverRefNum;
pBlock->csCode = (short) csCode;
}
static int
TcpBlockMode(
ClientData instanceData,
int mode)
{
TcpState *statePtr = (TcpState *) instanceData;
if (mode == TCL_MODE_BLOCKING) {
statePtr->flags &= ~TCP_ASYNC_SOCKET;
} else {
statePtr->flags |= TCP_ASYNC_SOCKET;
}
return 0;
}
static int
TcpClose(
ClientData instanceData,
Tcl_Interp *interp)
{
TcpState *statePtr = (TcpState *) instanceData;
StreamPtr tcpStream;
TCPiopb closePB;
OSErr err;
tcpStream = statePtr->tcpStream;
statePtr->flags &= ~TCP_CONNECTED;
if ((statePtr->flags & TCP_LISTENING) ||
(statePtr->flags & TCP_LISTEN_CONNECT)) {
InitMacTCPParamBlock(&closePB, TCPClose);
closePB.tcpStream = tcpStream;
closePB.ioCompletion = NULL;
closePB.csParam.close.ulpTimeoutValue = 60 ;
closePB.csParam.close.ulpTimeoutAction = 1 ;
closePB.csParam.close.validityFlags = timeoutValue | timeoutAction;
err = PBControlSync((ParmBlkPtr) &closePB);
if (err != noErr) {
Debugger();
goto afterRelease;
}
statePtr->flags |= TCP_RELEASE;
InitMacTCPParamBlock(&statePtr->pb, TCPRelease);
statePtr->pb.tcpStream = statePtr->tcpStream;
err = PBControlSync((ParmBlkPtr) &statePtr->pb);
if (err != noErr) {
panic("error releasing server socket");
}
afterRelease:
if (err == noErr) {
ckfree((char *) statePtr->pb.csParam.create.rcvBuff);
}
FreeSocketInfo(statePtr);
return 0;
}
if (statePtr->flags & TCP_ASYNC_CONNECT) {
InitMacTCPParamBlock(&closePB, TCPClose);
closePB.tcpStream = tcpStream;
closePB.ioCompletion = NULL;
err = PBControlSync((ParmBlkPtr) &closePB);
if (err == noErr) {
statePtr->flags |= TCP_RELEASE;
InitMacTCPParamBlock(&closePB, TCPRelease);
closePB.tcpStream = tcpStream;
closePB.ioCompletion = NULL;
err = PBControlSync((ParmBlkPtr) &closePB);
}
if (err == noErr) {
ckfree((char *) closePB.csParam.create.rcvBuff);
}
FreeSocketInfo(statePtr);
return err;
}
if (!(statePtr->flags & TCP_WRITING)) {
InitMacTCPParamBlock(&statePtr->pb, TCPClose);
statePtr->pb.tcpStream = tcpStream;
statePtr->pb.ioCompletion = closeUPP;
statePtr->pb.csParam.close.userDataPtr = (Ptr) statePtr;
err = PBControlAsync((ParmBlkPtr) &statePtr->pb);
if (err != noErr) {
Debugger();
statePtr->flags |= TCP_RELEASE;
}
}
SocketFreeProc(instanceData);
return 0;
}
static void
CloseCompletionRoutine(
TCPiopb *pbPtr)
{
TcpState *statePtr;
OSErr err;
if (pbPtr->csCode == TCPClose) {
statePtr = (TcpState *) (pbPtr->csParam.close.userDataPtr);
} else {
statePtr = (TcpState *) (pbPtr->csParam.receive.userDataPtr);
}
if (statePtr == NULL) {
Debugger();
return;
}
WakeUpProcess(&statePtr->psn);
if (pbPtr->ioResult != noErr) {
statePtr->flags |= TCP_RELEASE;
return;
}
if (statePtr->flags & TCP_REMOTE_CLOSED) {
statePtr->flags |= TCP_RELEASE;
return;
}
if (statePtr->pb.csCode == TCPNoCopyRcv) {
InitMacTCPParamBlock(&statePtr->pb, TCPRcvBfrReturn);
statePtr->pb.tcpStream = statePtr->tcpStream;
statePtr->pb.ioCompletion = closeUPP;
statePtr->pb.csParam.receive.rdsPtr = (Ptr) statePtr->rdsarray;
statePtr->pb.csParam.receive.userDataPtr = (Ptr) statePtr;
err = PBControlAsync((ParmBlkPtr) &statePtr->pb);
} else {
InitMacTCPParamBlock(&statePtr->pb, TCPNoCopyRcv);
statePtr->pb.tcpStream = statePtr->tcpStream;
statePtr->pb.ioCompletion = closeUPP;
statePtr->pb.csParam.receive.commandTimeoutValue = 1;
statePtr->pb.csParam.receive.rdsPtr = (Ptr) statePtr->rdsarray;
statePtr->pb.csParam.receive.rdsLength = 5;
statePtr->pb.csParam.receive.userDataPtr = (Ptr) statePtr;
err = PBControlAsync((ParmBlkPtr) &statePtr->pb);
}
if (err != noErr) {
statePtr->flags |= TCP_RELEASE;
}
}
static void
SocketFreeProc(
ClientData clientData)
{
TcpState *statePtr = (TcpState *) clientData;
OSErr err;
TCPiopb statusPB;
if (!(statePtr->flags & TCP_RELEASE)) {
return;
}
statusPB.ioCRefNum = driverRefNum;
statusPB.tcpStream = statePtr->tcpStream;
statusPB.csCode = TCPStatus;
err = PBControlSync((ParmBlkPtr) &statusPB);
if ((statusPB.csParam.status.connectionState == 0) ||
(statusPB.csParam.status.connectionState == 2)) {
} else {
return;
}
InitMacTCPParamBlock(&statePtr->pb, TCPRelease);
statePtr->pb.tcpStream = statePtr->tcpStream;
err = PBControlSync((ParmBlkPtr) &statePtr->pb);
if (err != noErr) {
Debugger();
}
ckfree((char *) statePtr->pb.csParam.create.rcvBuff);
FreeSocketInfo(statePtr);
}
int
TcpInput(
ClientData instanceData,
char *buf,
int bufSize,
int *errorCodePtr)
{
TcpState *statePtr = (TcpState *) instanceData;
StreamPtr tcpStream;
OSErr err;
TCPiopb statusPB;
int toRead, dataAvail;
*errorCodePtr = 0;
errno = 0;
tcpStream = statePtr->tcpStream;
if (bufSize == 0) {
return 0;
}
toRead = bufSize;
if (statePtr->flags & TCP_REMOTE_CLOSED) {
return 0;
}
if ((statePtr->flags & TCP_ASYNC_CONNECT)
&& ! WaitForSocketEvent(statePtr, TCL_READABLE, errorCodePtr)) {
return -1;
}
while (1) {
statusPB.ioCRefNum = driverRefNum;
statusPB.tcpStream = tcpStream;
statusPB.csCode = TCPStatus;
err = PBControlSync((ParmBlkPtr) &statusPB);
if (err != noErr) {
Debugger();
statePtr->flags |= TCP_REMOTE_CLOSED;
return 0;
}
dataAvail = statusPB.csParam.status.amtUnreadData;
if (dataAvail < bufSize) {
toRead = dataAvail;
} else {
toRead = bufSize;
}
if (toRead != 0) {
InitMacTCPParamBlock(&statusPB, TCPRcv);
statusPB.tcpStream = tcpStream;
statusPB.csParam.receive.rcvBuff = buf;
statusPB.csParam.receive.rcvBuffLen = toRead;
err = PBControlSync((ParmBlkPtr) &statusPB);
statePtr->checkMask &= ~TCL_READABLE;
switch (err) {
case noErr:
if (dataAvail > bufSize) {
statePtr->checkMask |= TCL_READABLE;
}
return statusPB.csParam.receive.rcvBuffLen;
case connectionClosing:
*errorCodePtr = errno = ESHUTDOWN;
statePtr->flags |= TCP_REMOTE_CLOSED;
return 0;
case connectionDoesntExist:
case connectionTerminated:
*errorCodePtr = errno = ENOTCONN;
statePtr->flags |= TCP_REMOTE_CLOSED;
return 0;
case invalidStreamPtr:
default:
*errorCodePtr = EINVAL;
return -1;
}
}
if (statusPB.csParam.status.connectionState == 14) {
statePtr->flags |= TCP_REMOTE_CLOSED;
return 0;
}
if (statusPB.csParam.status.connectionState != 8) {
Debugger();
}
statePtr->checkMask &= ~TCL_READABLE;
if (statePtr->flags & TCP_ASYNC_SOCKET) {
*errorCodePtr = EWOULDBLOCK;
return -1;
}
if (!WaitForSocketEvent(statePtr, TCL_READABLE, errorCodePtr)) {
return -1;
}
}
}
static int
TcpGetHandle(
ClientData instanceData,
int direction,
ClientData *handlePtr)
{
TcpState *statePtr = (TcpState *) instanceData;
*handlePtr = (ClientData) statePtr->tcpStream;
return TCL_OK;
}
static int
TcpOutput(
ClientData instanceData,
CONST char *buf,
int toWrite,
int *errorCodePtr)
{
TcpState *statePtr = (TcpState *) instanceData;
StreamPtr tcpStream;
OSErr err;
int amount;
TCPiopb statusPB;
*errorCodePtr = 0;
tcpStream = statePtr->tcpStream;
if ((statePtr->flags & TCP_ASYNC_CONNECT)
&& ! WaitForSocketEvent(statePtr, TCL_WRITABLE, errorCodePtr)) {
return -1;
}
while (1) {
statusPB.ioCRefNum = driverRefNum;
statusPB.tcpStream = tcpStream;
statusPB.csCode = TCPStatus;
err = PBControlSync((ParmBlkPtr) &statusPB);
if ((err == connectionDoesntExist) || ((err == noErr) &&
(statusPB.csParam.status.connectionState == 14))) {
*errorCodePtr = errno = EPIPE;
return -1;
} else if (err != noErr) {
return -1;
}
amount = statusPB.csParam.status.sendWindow
- statusPB.csParam.status.amtUnackedData;
if (!(statePtr->flags & TCP_WRITING) && amount > 0) {
if (toWrite < amount) {
amount = toWrite;
}
if (amount > statePtr->writeBufferSize) {
if (statePtr->writeBuffer != (void *) NULL) {
ckfree(statePtr->writeBuffer);
}
statePtr->writeBuffer = (void *) ckalloc(amount);
statePtr->writeBufferSize = amount;
}
memcpy(statePtr->writeBuffer, buf, amount);
statePtr->dataSegment[0].ptr = statePtr->writeBuffer;
statePtr->dataSegment[0].length = amount;
statePtr->dataSegment[1].length = 0;
InitMacTCPParamBlock(&statePtr->pb, TCPSend);
statePtr->pb.ioCompletion = completeUPP;
statePtr->pb.tcpStream = tcpStream;
statePtr->pb.csParam.send.wdsPtr = (Ptr) statePtr->dataSegment;
statePtr->pb.csParam.send.pushFlag = 1;
statePtr->pb.csParam.send.userDataPtr = (Ptr) statePtr;
statePtr->flags |= TCP_WRITING;
err = PBControlAsync((ParmBlkPtr) &(statePtr->pb));
switch (err) {
case noErr:
return amount;
case connectionClosing:
*errorCodePtr = errno = ESHUTDOWN;
statePtr->flags |= TCP_REMOTE_CLOSED;
return -1;
case connectionDoesntExist:
case connectionTerminated:
*errorCodePtr = errno = ENOTCONN;
statePtr->flags |= TCP_REMOTE_CLOSED;
return -1;
case invalidStreamPtr:
default:
return -1;
}
}
if (statePtr->flags & TCP_ASYNC_SOCKET) {
statePtr->checkMask &= ~TCL_WRITABLE;
*errorCodePtr = EWOULDBLOCK;
return -1;
} else if (!WaitForSocketEvent(statePtr, TCL_WRITABLE, errorCodePtr)) {
return -1;
}
}
}
static int
TcpGetOptionProc(
ClientData instanceData,
Tcl_Interp *interp,
CONST char *optionName,
Tcl_DString *dsPtr)
{
TcpState *statePtr = (TcpState *) instanceData;
int doPeerName = false, doSockName = false, doError = false, doAll = false;
ip_addr tcpAddress;
char buffer[128];
OSErr err;
Tcl_DString dString;
TCPiopb statusPB;
int errorCode;
size_t len = 0;
if ((statePtr->flags & TCP_ASYNC_CONNECT)
&& ! WaitForSocketEvent(statePtr, TCL_WRITABLE, &errorCode)) {
if (interp) {
Tcl_AppendResult(interp, "connect is in progress and can't wait",
NULL);
}
return TCL_ERROR;
}
if (optionName == (CONST char *) NULL || optionName[0] == '\0') {
doAll = true;
} else {
len = strlen(optionName);
if (!strncmp(optionName, "-peername", len)) {
doPeerName = true;
} else if (!strncmp(optionName, "-sockname", len)) {
doSockName = true;
} else if (!strncmp(optionName, "-error", len)) {
doError = true;
} else {
return Tcl_BadChannelOption(interp, optionName,
"error peername sockname");
}
}
if (doAll || doError) {
if (doAll) {
Tcl_DStringAppendElement(dsPtr, "-error");
Tcl_DStringAppendElement(dsPtr, "");
} else {
Tcl_DStringAppend (dsPtr, "", -1);
return TCL_OK;
}
}
statusPB.ioCRefNum = driverRefNum;
statusPB.tcpStream = statePtr->tcpStream;
statusPB.csCode = TCPStatus;
err = PBControlSync((ParmBlkPtr) &statusPB);
if ((err == connectionDoesntExist) ||
((err == noErr) && (statusPB.csParam.status.connectionState == 14))) {
if (interp) {
Tcl_AppendResult(interp, "can't access socket info: ",
"connection reset by peer", NULL);
}
return TCL_ERROR;
} else if (err != noErr) {
if (interp) {
Tcl_AppendResult(interp, "unknown socket error", NULL);
}
Debugger();
return TCL_ERROR;
}
Tcl_DStringInit(&dString);
if (doAll || doSockName) {
if (doAll) {
Tcl_DStringAppendElement(dsPtr, "-sockname");
Tcl_DStringStartSublist(dsPtr);
}
tcpAddress = statusPB.csParam.status.localHost;
sprintf(buffer, "%d.%d.%d.%d", tcpAddress>>24,
tcpAddress>>16 & 0xff, tcpAddress>>8 & 0xff,
tcpAddress & 0xff);
Tcl_DStringAppendElement(dsPtr, buffer);
if (ResolveAddress(tcpAddress, &dString) == noErr) {
Tcl_DStringAppendElement(dsPtr, dString.string);
} else {
Tcl_DStringAppendElement(dsPtr, "<unknown>");
}
sprintf(buffer, "%d", statusPB.csParam.status.localPort);
Tcl_DStringAppendElement(dsPtr, buffer);
if (doAll) {
Tcl_DStringEndSublist(dsPtr);
}
}
if ((doAll || doPeerName) && (statePtr->flags & TCP_CONNECTED)) {
if (doAll) {
Tcl_DStringAppendElement(dsPtr, "-peername");
Tcl_DStringStartSublist(dsPtr);
}
tcpAddress = statusPB.csParam.status.remoteHost;
sprintf(buffer, "%d.%d.%d.%d", tcpAddress>>24,
tcpAddress>>16 & 0xff, tcpAddress>>8 & 0xff,
tcpAddress & 0xff);
Tcl_DStringAppendElement(dsPtr, buffer);
Tcl_DStringSetLength(&dString, 0);
if (ResolveAddress(tcpAddress, &dString) == noErr) {
Tcl_DStringAppendElement(dsPtr, dString.string);
} else {
Tcl_DStringAppendElement(dsPtr, "<unknown>");
}
sprintf(buffer, "%d", statusPB.csParam.status.remotePort);
Tcl_DStringAppendElement(dsPtr, buffer);
if (doAll) {
Tcl_DStringEndSublist(dsPtr);
}
}
Tcl_DStringFree(&dString);
return TCL_OK;
}
static void
TcpWatch(instanceData, mask)
ClientData instanceData;
int mask;
{
TcpState *statePtr = (TcpState *) instanceData;
statePtr->watchMask = mask;
}
static TcpState *
NewSocketInfo(
StreamPtr tcpStream)
{
TcpState *statePtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState));
statePtr->tcpStream = tcpStream;
statePtr->psn = applicationPSN;
statePtr->flags = 0;
statePtr->checkMask = 0;
statePtr->watchMask = 0;
statePtr->acceptProc = (Tcl_TcpAcceptProc *) NULL;
statePtr->acceptProcData = (ClientData) NULL;
statePtr->writeBuffer = (void *) NULL;
statePtr->writeBufferSize = 0;
statePtr->nextPtr = tsdPtr->socketList;
tsdPtr->socketList = statePtr;
return statePtr;
}
static void
FreeSocketInfo(
TcpState *statePtr)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (statePtr == tsdPtr->socketList) {
tsdPtr->socketList = statePtr->nextPtr;
} else {
TcpState *p;
for (p = tsdPtr->socketList; p != NULL; p = p->nextPtr) {
if (p->nextPtr == statePtr) {
p->nextPtr = statePtr->nextPtr;
break;
}
}
}
if (statePtr->writeBuffer != (void *) NULL) {
ckfree(statePtr->writeBuffer);
}
ckfree((char *) statePtr);
}
Tcl_Channel
Tcl_MakeTcpClientChannel(
ClientData sock)
{
TcpState *statePtr;
char channelName[20];
if (TclpHasSockets(NULL) != TCL_OK) {
return NULL;
}
statePtr = NewSocketInfo((StreamPtr) sock);
sprintf(channelName, "sock%d", socketNumber++);
statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
(ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE));
Tcl_SetChannelBufferSize(statePtr->channel, socketBufferSize);
Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", "auto crlf");
return statePtr->channel;
}
static TcpState *
CreateSocket(
Tcl_Interp *interp,
int port,
CONST char *host,
CONST char *myaddr,
int myport,
int server,
int async)
{
ip_addr macAddr;
OSErr err;
TCPiopb pb;
StreamPtr tcpStream;
TcpState *statePtr;
char * buffer;
if (host == NULL) {
err = GetLocalAddress(&macAddr);
} else {
err = GetHostFromString(host, &macAddr);
}
if (err != noErr) {
Tcl_SetErrno(EHOSTUNREACH);
if (interp != (Tcl_Interp *) NULL) {
Tcl_AppendResult(interp, "couldn't open socket: ",
Tcl_PosixError(interp), (char *) NULL);
}
return (TcpState *) NULL;
}
ClearZombieSockets();
buffer = ckalloc(socketBufferSize);
InitMacTCPParamBlock(&pb, TCPCreate);
pb.csParam.create.rcvBuff = buffer;
pb.csParam.create.rcvBuffLen = socketBufferSize;
pb.csParam.create.notifyProc = nil ;
err = PBControlSync((ParmBlkPtr) &pb);
if (err != noErr) {
Tcl_SetErrno(0);
if (interp != (Tcl_Interp *) NULL) {
Tcl_AppendResult(interp, "couldn't open socket: ",
Tcl_PosixError(interp), (char *) NULL);
}
return (TcpState *) NULL;
}
tcpStream = pb.tcpStream;
statePtr = NewSocketInfo(tcpStream);
statePtr->port = port;
if (server) {
InitMacTCPParamBlock(&statePtr->pb, TCPPassiveOpen);
statePtr->pb.tcpStream = tcpStream;
statePtr->pb.csParam.open.localPort = statePtr->port;
statePtr->pb.ioCompletion = completeUPP;
statePtr->pb.csParam.open.userDataPtr = (Ptr) statePtr;
statePtr->pb.csParam.open.ulpTimeoutValue = 100;
statePtr->pb.csParam.open.ulpTimeoutAction = 1 ;
statePtr->pb.csParam.open.commandTimeoutValue = 0 ;
statePtr->flags |= TCP_LISTENING;
err = PBControlAsync((ParmBlkPtr) &(statePtr->pb));
if (statePtr->port == 0) {
EventRecord dummy;
while (statePtr->pb.csParam.open.localPort == 0) {
WaitNextEvent(0, &dummy, 1, NULL);
if (statePtr->pb.ioResult != 0) {
break;
}
}
statePtr->port = statePtr->pb.csParam.open.localPort;
}
Tcl_SetErrno(EINPROGRESS);
} else {
InitMacTCPParamBlock(&statePtr->pb, TCPActiveOpen);
statePtr->pb.tcpStream = tcpStream;
statePtr->pb.csParam.open.remoteHost = macAddr;
statePtr->pb.csParam.open.remotePort = port;
statePtr->pb.csParam.open.localHost = 0;
statePtr->pb.csParam.open.localPort = myport;
statePtr->pb.csParam.open.userDataPtr = (Ptr) statePtr;
statePtr->pb.csParam.open.validityFlags = timeoutValue | timeoutAction;
statePtr->pb.csParam.open.ulpTimeoutValue = 60 ;
statePtr->pb.csParam.open.ulpTimeoutAction = 1 ;
statePtr->pb.csParam.open.commandTimeoutValue = 0;
statePtr->pb.ioCompletion = completeUPP;
if (async) {
statePtr->flags |= TCP_ASYNC_CONNECT;
err = PBControlAsync((ParmBlkPtr) &(statePtr->pb));
Tcl_SetErrno(EINPROGRESS);
} else {
err = PBControlSync((ParmBlkPtr) &(statePtr->pb));
}
}
switch (err) {
case noErr:
if (!async) {
statePtr->flags |= TCP_CONNECTED;
}
return statePtr;
case duplicateSocket:
Tcl_SetErrno(EADDRINUSE);
break;
case openFailed:
case connectionTerminated:
Tcl_SetErrno(ECONNREFUSED);
break;
case invalidStreamPtr:
case connectionExists:
default:
Debugger();
Tcl_SetErrno(err);
}
pb.ioCRefNum = driverRefNum;
pb.csCode = TCPRelease;
pb.tcpStream = tcpStream;
pb.ioCompletion = NULL;
err = PBControlSync((ParmBlkPtr) &pb);
if (interp != (Tcl_Interp *) NULL) {
Tcl_AppendResult(interp, "couldn't open socket: ",
Tcl_PosixError(interp), (char *) NULL);
}
ckfree(buffer);
FreeSocketInfo(statePtr);
return (TcpState *) NULL;
}
Tcl_Channel
Tcl_OpenTcpClient(
Tcl_Interp *interp,
int port,
CONST char *host,
CONST char *myaddr,
int myport,
int async)
{
TcpState *statePtr;
char channelName[20];
if (TclpHasSockets(interp) != TCL_OK) {
return NULL;
}
statePtr = CreateSocket(interp, port, host, myaddr, myport, 0, async);
if (statePtr == NULL) {
return NULL;
}
sprintf(channelName, "sock%d", socketNumber++);
statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
(ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE));
Tcl_SetChannelBufferSize(statePtr->channel, socketBufferSize);
Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", "auto crlf");
return statePtr->channel;
}
Tcl_Channel
Tcl_OpenTcpServer(
Tcl_Interp *interp,
int port,
CONST char *host,
Tcl_TcpAcceptProc *acceptProc,
ClientData acceptProcData)
{
TcpState *statePtr;
char channelName[20];
if (TclpHasSockets(interp) != TCL_OK) {
return NULL;
}
statePtr = CreateSocket(interp, port, host, NULL, 0, 1, 1);
if (statePtr == NULL) {
return NULL;
}
statePtr->acceptProc = acceptProc;
statePtr->acceptProcData = acceptProcData;
sprintf(channelName, "sock%d", socketNumber++);
statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
(ClientData) statePtr, 0);
Tcl_SetChannelBufferSize(statePtr->channel, socketBufferSize);
Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", "auto crlf");
return statePtr->channel;
}
static int
SocketEventProc(
Tcl_Event *evPtr,
int flags)
{
TcpState *statePtr;
SocketEvent *eventPtr = (SocketEvent *) evPtr;
int mask = 0;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!(flags & TCL_FILE_EVENTS)) {
return 0;
}
for (statePtr = tsdPtr->socketList; statePtr != NULL;
statePtr = statePtr->nextPtr) {
if ((statePtr == eventPtr->statePtr) &&
(statePtr->tcpStream == eventPtr->tcpStream)) {
break;
}
}
if (!statePtr) {
return 1;
}
statePtr->flags &= ~(TCP_PENDING);
if (statePtr->flags & TCP_RELEASE) {
SocketFreeProc(statePtr);
return 1;
}
if (statePtr->flags & TCP_LISTEN_CONNECT) {
if (statePtr->checkMask & TCL_READABLE) {
TcpAccept(statePtr);
}
return 1;
}
mask = statePtr->checkMask & statePtr->watchMask;
if (mask) {
Tcl_NotifyChannel(statePtr->channel, mask);
}
return 1;
}
static int
WaitForSocketEvent(
TcpState *statePtr,
int mask,
int *errorCodePtr)
{
OSErr err;
TCPiopb statusPB;
EventRecord dummy;
do {
statusPB.ioCRefNum = driverRefNum;
statusPB.tcpStream = statePtr->tcpStream;
statusPB.csCode = TCPStatus;
err = PBControlSync((ParmBlkPtr) &statusPB);
if (err != noErr) {
if (statePtr->flags & TCP_ASYNC_CONNECT) {
*errorCodePtr = EWOULDBLOCK;
return 0;
} else {
statePtr->checkMask |= (TCL_READABLE | TCL_WRITABLE);
return 1;
}
}
statePtr->checkMask = 0;
if ((statusPB.csParam.status.connectionState != 0)
&& (statusPB.csParam.status.connectionState != 4)
&& (statusPB.csParam.status.connectionState != 6)) {
if (statusPB.csParam.status.amtUnreadData > 0) {
statePtr->checkMask |= TCL_READABLE;
}
if (!(statePtr->flags & TCP_WRITING)
&& (statusPB.csParam.status.sendWindow -
statusPB.csParam.status.amtUnackedData) > 0) {
statePtr->flags &= ~(TCP_ASYNC_CONNECT);
statePtr->checkMask |= TCL_WRITABLE;
}
if (mask & statePtr->checkMask) {
return 1;
}
} else {
break;
}
WaitNextEvent(0, &dummy, 1, NULL);
} while (!(statePtr->flags & TCP_ASYNC_SOCKET));
*errorCodePtr = EWOULDBLOCK;
return 0;
}
static void
TcpAccept(
TcpState *statePtr)
{
TcpState *newStatePtr;
StreamPtr tcpStream;
char remoteHostname[255];
OSErr err;
ip_addr remoteAddress;
long remotePort;
char channelName[20];
statePtr->flags &= ~TCP_LISTEN_CONNECT;
statePtr->checkMask &= ~TCL_READABLE;
tcpStream = statePtr->tcpStream;
newStatePtr = NewSocketInfo(tcpStream);
newStatePtr->tcpStream = tcpStream;
sprintf(channelName, "sock%d", socketNumber++);
newStatePtr->flags |= TCP_CONNECTED;
newStatePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
(ClientData) newStatePtr, (TCL_READABLE | TCL_WRITABLE));
Tcl_SetChannelBufferSize(newStatePtr->channel, socketBufferSize);
Tcl_SetChannelOption(NULL, newStatePtr->channel, "-translation",
"auto crlf");
remoteAddress = statePtr->pb.csParam.open.remoteHost;
remotePort = statePtr->pb.csParam.open.remotePort;
ClearZombieSockets();
InitMacTCPParamBlock(&statePtr->pb, TCPCreate);
statePtr->pb.csParam.create.rcvBuff = ckalloc(socketBufferSize);
statePtr->pb.csParam.create.rcvBuffLen = socketBufferSize;
err = PBControlSync((ParmBlkPtr) &statePtr->pb);
if (err != noErr) {
Debugger();
statePtr->tcpStream = -1;
statePtr->flags |= TCP_SERVER_ZOMBIE;
}
tcpStream = statePtr->tcpStream = statePtr->pb.tcpStream;
InitMacTCPParamBlock(&statePtr->pb, TCPPassiveOpen);
statePtr->pb.tcpStream = tcpStream;
statePtr->pb.csParam.open.localHost = 0;
statePtr->pb.csParam.open.localPort = statePtr->port;
statePtr->pb.ioCompletion = completeUPP;
statePtr->pb.csParam.open.userDataPtr = (Ptr) statePtr;
statePtr->flags |= TCP_LISTENING;
err = PBControlAsync((ParmBlkPtr) &(statePtr->pb));
if (statePtr->acceptProc != NULL) {
sprintf(remoteHostname, "%d.%d.%d.%d", remoteAddress>>24,
remoteAddress>>16 & 0xff, remoteAddress>>8 & 0xff,
remoteAddress & 0xff);
(statePtr->acceptProc)(statePtr->acceptProcData, newStatePtr->channel,
remoteHostname, remotePort);
}
}
CONST char *
Tcl_GetHostName()
{
static int hostnameInited = 0;
static char hostname[255];
ip_addr ourAddress;
Tcl_DString dString;
OSErr err;
if (hostnameInited) {
return hostname;
}
if (TclpHasSockets(NULL) == TCL_OK) {
err = GetLocalAddress(&ourAddress);
if (err == noErr) {
Tcl_DStringInit(&dString);
err = ResolveAddress(ourAddress, &dString);
if (err == noErr) {
strcpy(hostname, dString.string);
} else {
sprintf(hostname, "%d.%d.%d.%d", ourAddress>>24, ourAddress>>16 & 0xff,
ourAddress>>8 & 0xff, ourAddress & 0xff);
}
Tcl_DStringFree(&dString);
hostnameInited = 1;
return hostname;
}
}
hostname[0] = '\0';
hostnameInited = 1;
return hostname;
}
static OSErr
ResolveAddress(
ip_addr tcpAddress,
Tcl_DString *dsPtr)
{
int i;
EventRecord dummy;
DNRState dnrState;
OSErr err;
for (i = 0; i < NUM_ALT_ADDRS; i++) {
dnrState.hostInfo.addr[i] = 0;
}
dnrState.done = 0;
GetCurrentProcess(&(dnrState.psn));
err = AddrToName(tcpAddress, &dnrState.hostInfo, resultUPP, (Ptr) &dnrState);
if (err == cacheFault) {
while (!dnrState.done) {
WaitNextEvent(0, &dummy, 1, NULL);
}
}
if (dnrState.hostInfo.rtnCode == noErr) {
i = strlen(dnrState.hostInfo.cname) - 1;
if (dnrState.hostInfo.cname[i] == '.') {
dnrState.hostInfo.cname[i] = '\0';
}
Tcl_DStringAppend(dsPtr, dnrState.hostInfo.cname, -1);
}
return dnrState.hostInfo.rtnCode;
}
static pascal void
DNRCompletionRoutine(
struct hostInfo *hostinfoPtr,
DNRState *dnrStatePtr)
{
dnrStatePtr->done = true;
WakeUpProcess(&(dnrStatePtr->psn));
}
static pascal void
CleanUpExitProc()
{
TCPiopb exitPB;
TcpState *statePtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
while (tsdPtr->socketList != NULL) {
statePtr = tsdPtr->socketList;
tsdPtr->socketList = statePtr->nextPtr;
exitPB.ioCRefNum = driverRefNum;
exitPB.csCode = TCPClose;
exitPB.tcpStream = statePtr->tcpStream;
exitPB.csParam.close.ulpTimeoutValue = 60 ;
exitPB.csParam.close.ulpTimeoutAction = 1 ;
exitPB.csParam.close.validityFlags = timeoutValue | timeoutAction;
exitPB.ioCompletion = NULL;
PBControlSync((ParmBlkPtr) &exitPB);
exitPB.ioCRefNum = driverRefNum;
exitPB.csCode = TCPRelease;
exitPB.tcpStream = statePtr->tcpStream;
exitPB.ioCompletion = NULL;
PBControlSync((ParmBlkPtr) &exitPB);
}
}
static OSErr
GetHostFromString(
CONST char *name,
ip_addr *address)
{
OSErr err;
int i;
EventRecord dummy;
DNRState dnrState;
if (TclpHasSockets(NULL) != TCL_OK) {
return 0;
}
for (i = 0; i < NUM_ALT_ADDRS; i++) {
dnrState.hostInfo.addr[i] = 0;
}
dnrState.done = 0;
GetCurrentProcess(&(dnrState.psn));
err = StrToAddr((char*)name, &dnrState.hostInfo, resultUPP, (Ptr) &dnrState);
if (err == cacheFault) {
while (!dnrState.done) {
WaitNextEvent(0, &dummy, 1, NULL);
}
}
if (dnrState.hostInfo.rtnCode == cacheFault) {
dnrState.done = 0;
err = StrToAddr((char*)name, &dnrState.hostInfo, resultUPP, (Ptr) &dnrState);
if (err == cacheFault) {
while (!dnrState.done) {
WaitNextEvent(0, &dummy, 1, NULL);
}
}
}
if (dnrState.hostInfo.rtnCode == noErr) {
*address = dnrState.hostInfo.addr[0];
}
return dnrState.hostInfo.rtnCode;
}
static void
IOCompletionRoutine(
TCPiopb *pbPtr)
{
TcpState *statePtr;
if (pbPtr->csCode == TCPSend) {
statePtr = (TcpState *) pbPtr->csParam.send.userDataPtr;
} else {
statePtr = (TcpState *) pbPtr->csParam.open.userDataPtr;
}
WakeUpProcess(&statePtr->psn);
if (pbPtr->ioResult != noErr) {
return;
}
if (statePtr->flags & TCP_ASYNC_CONNECT) {
statePtr->flags &= ~TCP_ASYNC_CONNECT;
statePtr->flags |= TCP_CONNECTED;
statePtr->checkMask |= TCL_READABLE & TCL_WRITABLE;
} else if (statePtr->flags & TCP_LISTENING) {
if (statePtr->port == 0) {
Debugger();
}
statePtr->flags &= ~TCP_LISTENING;
statePtr->flags |= TCP_LISTEN_CONNECT;
statePtr->checkMask |= TCL_READABLE;
} else if (statePtr->flags & TCP_WRITING) {
statePtr->flags &= ~TCP_WRITING;
statePtr->checkMask |= TCL_WRITABLE;
if (!(statePtr->flags & TCP_CONNECTED)) {
InitMacTCPParamBlock(&statePtr->pb, TCPClose);
statePtr->pb.tcpStream = statePtr->tcpStream;
statePtr->pb.ioCompletion = closeUPP;
statePtr->pb.csParam.close.userDataPtr = (Ptr) statePtr;
if (PBControlAsync((ParmBlkPtr) &statePtr->pb) != noErr) {
statePtr->flags |= TCP_RELEASE;
}
}
}
}
static OSErr
GetLocalAddress(
unsigned long *addr)
{
struct GetAddrParamBlock pBlock;
OSErr err = noErr;
static unsigned long localAddress = 0;
if (localAddress == 0) {
memset(&pBlock, 0, sizeof(pBlock));
pBlock.ioResult = 1;
pBlock.csCode = ipctlGetAddr;
pBlock.ioCRefNum = driverRefNum;
err = PBControlSync((ParmBlkPtr) &pBlock);
if (err != noErr) {
return err;
}
localAddress = pBlock.ourAddress;
}
*addr = localAddress;
return noErr;
}
static long
GetBufferSize()
{
UDPiopb iopb;
OSErr err = noErr;
long bufferSize;
memset(&iopb, 0, sizeof(iopb));
err = GetLocalAddress(&iopb.csParam.mtu.remoteHost);
if (err != noErr) {
return CHANNEL_BUF_SIZE;
}
iopb.ioCRefNum = driverRefNum;
iopb.csCode = UDPMaxMTUSize;
err = PBControlSync((ParmBlkPtr)&iopb);
if (err != noErr) {
return CHANNEL_BUF_SIZE;
}
bufferSize = (iopb.csParam.mtu.mtuSize * 4) + 1024;
if (bufferSize < CHANNEL_BUF_SIZE) {
bufferSize = CHANNEL_BUF_SIZE;
}
return bufferSize;
}
int
TclSockGetPort(
Tcl_Interp *interp,
char *string,
char *proto,
int *portPtr)
{
PortInfo *portInfoPtr = NULL;
if (Tcl_GetInt(interp, string, portPtr) == TCL_OK) {
if (*portPtr > 0xFFFF) {
Tcl_AppendResult(interp, "couldn't open socket: port number too high",
(char *) NULL);
return TCL_ERROR;
}
if (*portPtr < 0) {
Tcl_AppendResult(interp, "couldn't open socket: negative port number",
(char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
for (portInfoPtr = portServices; portInfoPtr->name != NULL; portInfoPtr++) {
if (!strcmp(portInfoPtr->name, string)) {
break;
}
}
if (portInfoPtr != NULL && portInfoPtr->name != NULL) {
*portPtr = portInfoPtr->port;
Tcl_ResetResult(interp);
return TCL_OK;
}
return TCL_ERROR;
}
static void
ClearZombieSockets()
{
TcpState *statePtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
for (statePtr = tsdPtr->socketList; statePtr != NULL;
statePtr = statePtr->nextPtr) {
if (statePtr->flags & TCP_RELEASE) {
SocketFreeProc(statePtr);
return;
}
}
}
pascal void NotifyRoutine (
StreamPtr tcpStream,
unsigned short eventCode,
Ptr userDataPtr,
unsigned short terminReason,
struct ICMPReport *icmpMsg)
{
StreamPtr localTcpStream;
unsigned short localEventCode;
unsigned short localTerminReason;
struct ICMPReport localIcmpMsg;
localTcpStream = tcpStream;
localEventCode = eventCode;
localTerminReason = terminReason;
localIcmpMsg = *icmpMsg;
}