Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4189 lines
148 KiB

/* asp.c, /appletalk/source, Garth Conboy, 04/01/89 */
/* Copyright (c) 1989 by Pacer Software Inc., La Jolla, CA */
/* GC - Initial coding.
GC - (12/08/89): AppleTalk phase II comes to town (not quite as good
as Santa Claus coming to town, but...)
GC - (07/08/90): Get session handlers should be terminated (with the new
ATaspSessionListenerDeleted error) when a session
listener is deleted.
GC - (08/18/90): New error logging mechanism.
GC - (03/24/92): Localize use of lastSessionRefNum to
GetNextSessionRefNum().
GC - (03/24/92): Removed "sessionListenerInfo->acceptingOpensNow".
GC - (03/24/92): Changed return type of AspGetSession to "long"; added
AspCancelGetSession();
GC - (03/24/92): Added FindSessionListenerInfoFor().
GC - (03/27/92): No longer use any "session buffering" for incoming
requests. Atp EnqueueRequestHandlers are not posted so
that Atp will simply pass up pointers into the Ddp
datagrams. Avoid a buffer copy.
GC - (03/29/92): Introduced GetAnyRequest(). This allows general get
requests on a session listener: any incoming requests
to any server session on the Sls will cause this call
to complete.
GC - (05/20/92): A much less compute intensive algorithm is now used
when we're looking for the next not-in-use session
reference number.
GC - (06/27/92): All buffers coming from user space are now "opaque," they
may or may not be "char *." We now use the new routines
MoveFromOpaque() and MoveToOpaque() to access these
"buffer"s rather than MemMove(). Note that "user bytes"
are left as "char *"s, ous caller's would be aware of this
and copy any "opaque" user bytes to some place "real"
before calling us!
GC - (06/27/92): Removed the various "copyRequired" arguments. Our
callers are now required to keep the various request and
response buffers around until the given transaction
completes.
GC - (06/28/92): Got rid of the "sendCloseSession" static, it's now an
argument to AspCloseSession... the way it should be.
"Works great, less code!"
GC - (07/10/92): Added AspSetCookieForSession() and
AspGetCookieForSession().
GC - (07/20/92): For Nikki at Microsoft: AspCreateSessionListener now can
optionally take an already open Atp socket on which to
create the session listener.
GC - (09/02/92): A Empty buffer may now be passed to AspGetAnyRequest and
AspGetRequest in which case a pointer to the actual
Atp/Ddp buffer will passed to the completion routine,
which must then copy the data before it returns.
GC - (09/02/92): Changed the return type and the argument list for
AspCreateSessionListenerOnNode to be a little more
reasonable.
GC - (11/07/92): Adjusted session close handling per Microsoft's requests;
two new error codes: ATaspLocalSessionClose and
ATaspRemoteSessionClose replace ATaspSessionClosed.
If "GetAnyRequest"s are being used on a listener, we
now can keep a queue of closes that we couldn't notify
anybody about, and we defer this notification until
the next GetAnyRequest comes in.
GC - (12/12/92): Locks and reference counts come to town.
GC - (12/22/92): Some corrections to the above changes. Also, now we
use the eventual sessionRefNum as the GetSession refNum.
*** Make the PVCS source control system happy:
$Header$
$Log$
***
Yep, this module contains all of the code for managing the AppleTalk
ASP protocol.
*/
#define IncludeAspErrors 1
#include "atalk.h"
#define VerboseMessages 0
ExternForVisibleFunction AtpIncomingRequestHandler IncomingSlsTransaction;
ExternForVisibleFunction AtpIncomingRequestHandler IncomingSssTransaction;
ExternForVisibleFunction AtpIncomingRequestHandler IncomingWssTransaction;
ExternForVisibleFunction AtpIncomingReleaseHandler IncomingRelease;
ExternForVisibleFunction AtpIncomingReleaseHandler SendStatusComplete;
ExternForVisibleFunction AtpIncomingResponseHandler IncomingWriteContinueResponse;
ExternForVisibleFunction AtpIncomingResponseHandler IncomingGetStatusResponse;
ExternForVisibleFunction AtpIncomingResponseHandler IncomingOpenSessionResponse;
ExternForVisibleFunction AtpIncomingResponseHandler IncomingWriteOrCommandComplete;
ExternForVisibleFunction long GetNextSessionRefNum(void);
ExternForVisibleFunction SessionInfo
FindSessionInfoForSocket(long socket,
unsigned char sessionId);
ExternForVisibleFunction SessionInfo FindSessionInfoFor(long sessionRefNum);
ExternForVisibleFunction AppleTalkErrorCode
SendAspErrorReturn(long sourceSocket,
AppleTalkAddress destination,
short unsigned transactionId,
Boolean exactlyOnce,
int errorCode);
ExternForVisibleFunction void
DecrementSocketUsage(SessionListenerInfo sessionListenerInfo,
long socket);
ExternForVisibleFunction TimerHandler SessionMaintenanceTimerExpired;
ExternForVisibleFunction AppleTalkErrorCode InitializeAsp(void);
ExternForVisibleFunction SessionListenerInfo
FindSessionListenerInfoFor(long sessionListenerRefNum);
ExternForVisibleFunction GetRequestInfo
FindGetRequestInfoFor(SessionListenerInfo sessionListenerInfo,
long getRequestRefNum);
ExternForVisibleFunction Boolean far
UnlinkGetRequestInfo(GetRequestInfo targetGetRequestInfo);
ExternForVisibleFunction Boolean far
UnlinkGetSessionHandler(GetSessionHandler getSessionHandler);
ExternForVisibleFunction void far
UnlinkSessionListenerInfo(SessionListenerInfo sessionListenerInfo);
ExternForVisibleFunction void far
UnlinkSessionInfo(SessionInfo sessionInfo);
ExternForVisibleFunction CloseCompletionRoutine AspServiceListenerCloseComplete;
static Boolean sessionMaintenanceTimerStarted = False;
static char getStatusResponseUserBytes[AtpUserBytesSize]; /* Read only */
/* *** External entry points *** */
void far ShutdownAsp(void)
{
sessionMaintenanceTimerStarted = False;
return;
} /* ShutdownAsp */
/* More of the protocol suite should be as simple as AspGetParams... */
AppleTalkErrorCode _near AspGetParams(
int far *maxCommandSize, /* Maximum supported command size. */
int far *quantumSize) /* Maximum data size of command reply or write. */
{
*maxCommandSize = AtpSinglePacketDataSize;
*quantumSize = AtpMaximumTotalResponseSize;
return(ATnoError);
} /* AspGetParams */
AppleTalkErrorCode far AspCreateSessionListenerOnNode(
int port, /* Port on which the socket should live. */
long existingAtpSocket, /* "-1" if we should open our own Atp socket
for the session listener; if ">= 0" this is
an already open Atp socket on which to create
the Asp session listener. */
int desiredSocket, /* Desired static socket or zero for dynamic.
Ignored if the above argument is ">= 0". */
long far *sessionListenerRefNum,
/* New session listener refNum. */
long *socket)
/* Full ATP socket we'll open (the socket that
the session listener will be open on). */
{
SessionListenerInfo sessionListenerInfo, currentSessionListenerInfo;
Boolean okay, wrapped = False;
int index;
AppleTalkErrorCode errorCode;
long tempSocket;
/* First call? */
if (not sessionMaintenanceTimerStarted)
if ((errorCode = InitializeAsp()) isnt ATnoError)
return(errorCode);
/* Create a session listener on an ATP socket; return the session listener
reference number. */
if (existingAtpSocket >= 0)
tempSocket = existingAtpSocket;
else
if ((errorCode = AtpOpenSocketOnNode(&tempSocket, port, empty,
desiredSocket, empty,
0)) isnt ATnoError)
return(errorCode);
if (socket isnt empty)
*socket = tempSocket;
/* Okay, allocate, fill in, and thread, a new session listener. */
sessionListenerInfo =
(SessionListenerInfo)Calloc(sizeof(*sessionListenerInfo), 1);
if (sessionListenerInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
ErrorLog("AspCreateSessionListenerOnNode", ISevError, __LINE__, port,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
if (existingAtpSocket < 0)
AtpCloseSocketOnNode(tempSocket, Empty, (long unsigned)0);
return(AToutOfMemory);
}
/* Find a free session listener reference number. There souldn't be too
many of these session listeners going at a time, so don't bother hashing
here. */
DeferTimerChecking();
DeferAtpPackets();
okay = False;
TakeLock(AspLock);
while(not okay)
{
okay = True;
if ((lastSessionListenerRefNum += 1) < 0)
{
lastSessionListenerRefNum = 0;
if (wrapped)
{
ReleaseLock(AspLock);
HandleAtpPackets();
HandleDeferredTimerChecks();
Free(sessionListenerInfo);
ErrorLog("AspCreateSessionListenerOnNode", ISevError, __LINE__, port,
IErrAspBadError, IMsgAspBadError,
Insert0());
if (existingAtpSocket < 0)
AtpCloseSocketOnNode(tempSocket, Empty, (long unsigned)0);
return(ATinternalError);
}
wrapped = True;
}
for (currentSessionListenerInfo = sessionListenerInfoHead;
okay and currentSessionListenerInfo isnt empty;
currentSessionListenerInfo = currentSessionListenerInfo->next)
if (currentSessionListenerInfo->sessionListenerRefNum is
lastSessionListenerRefNum)
okay = False;
}
sessionListenerInfo->sessionListenerRefNum = lastSessionListenerRefNum;
sessionListenerInfo->ourSocket = tempSocket;
sessionListenerInfo->closeSocket = (existingAtpSocket < 0);
sessionListenerInfo->port = port;
sessionListenerInfo->next = sessionListenerInfoHead;
sessionListenerInfoHead = Link(sessionListenerInfo);
ReleaseLock(AspLock);
/* Enqueue a few ATP request handlers for this new session listener;
we'll need to be able to handle GetStatus, OpenSession and Tickle
request on the session listener socker (SLS) all other requests will
go to the server session socket (SSS). */
for (index = 0; index < OutstandingSlsHandlers; index += 1)
if ((errorCode = AtpEnqueueRequestHandler(empty, tempSocket, empty, 0,
empty, IncomingSlsTransaction,
(long unsigned)
lastSessionListenerRefNum))
isnt ATnoError)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
AspDeleteSessionListener(lastSessionListenerRefNum,
Empty, (long unsigned)0);
return(errorCode);
}
/* Set the refNum that we've used, and run away. */
*sessionListenerRefNum = sessionListenerInfo->sessionListenerRefNum;
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspCreateSessionListener */
AppleTalkErrorCode far AspDeleteSessionListener(
long sessionListenerRefNum, /* Who to delete. */
CloseCompletionRoutine far *closeCompletionRoutine,
/* Routine to call when the close completes. */
long unsigned closeUserData) /* User data for the above. */
{
SessionListenerInfo sessionListenerInfo;
SessionInfo sessionInfo, nextSessionInfo;
GetRequestInfo getRequestInfo, nextGetRequestInfo;
GetSessionHandler getSessionHandler, nextGetSessionHandler;
/* Find our target. */
DeferTimerChecking();
DeferAtpPackets();
if ((sessionListenerInfo =
FindSessionListenerInfoFor(sessionListenerRefNum)) is Empty or
sessionListenerInfo->closing)
{
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
/* Set about closing. */
TakeLock(AspLock);
sessionListenerInfo->closing = True;
sessionListenerInfo->closeContext.closeCompletionRoutine =
closeCompletionRoutine;
sessionListenerInfo->closeContext.closeUserData = closeUserData;
ReleaseLock(AspLock);
/* Free any getSession handlers. */
TakeLock(AspLock);
getSessionHandler = Link(sessionListenerInfo->getSessionHandlers);
ReleaseLock(AspLock);
while (getSessionHandler isnt Empty)
{
getSessionHandler->openInProgress = True; /* Call completion rotuine. */
getSessionHandler->errorCode = ATaspSessionListenerDeleted;
TakeLock(AspLock);
nextGetSessionHandler = Link(getSessionHandler->next);
ReleaseLock(AspLock);
if (not UnlinkGetSessionHandler(getSessionHandler))
UnlinkGetSessionHandler(getSessionHandler);
getSessionHandler = nextGetSessionHandler;
}
/* Should also close all SSSs opened to this SLS. */
TakeLock(AspLock);
sessionInfo = Link(sessionListenerInfo->sessionList);
ReleaseLock(AspLock);
while (sessionInfo isnt Empty)
{
AspCloseSession(sessionInfo->sessionRefNum, Empty, (long unsigned)0,
False);
TakeLock(AspLock);
nextSessionInfo = Link(sessionInfo->nextForMySls);
ReleaseLock(AspLock);
UnlinkSessionInfo(sessionInfo);
sessionInfo = nextSessionInfo;
}
/* Okay, unlink (twice) to set the rest of the operation into action. */
/* Terminate and free any pending GetAnyRequests. */
TakeLock(AspLock);
getRequestInfo = Link(sessionListenerInfo->getRequestInfoList);
ReleaseLock(AspLock);
while (getRequestInfo isnt Empty)
{
getRequestInfo->errorCode = ATaspSessionListenerDeleted;
TakeLock(AspLock);
nextGetRequestInfo = Link(getRequestInfo->next);
ReleaseLock(AspLock);
if (not UnlinkGetRequestInfo(getRequestInfo))
UnlinkGetRequestInfo(getRequestInfo);
getRequestInfo = nextGetRequestInfo;
}
UnlinkSessionListenerInfo(sessionListenerInfo);
UnlinkSessionListenerInfo(sessionListenerInfo);
/* All set! */
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspDeleteSessionListener */
AppleTalkErrorCode far AspSetStatus(
long sessionListenerRefNum, /* What session listener? */
void far *serviceStatusOpaque, /* New server status "buffer" */
int serviceStatusSize) /* Size of block */
{
SessionListenerInfo sessionListenerInfo;
char far *newServiceStatus = Empty;
void far *newOpaqueServiceStatus = Empty;
Boolean newFreeOpaqueServiceStatus = False;
short newServiceStatusSize = (short)serviceStatusSize;
char far *freeServiceStatus = Empty;
void far *freeOpaqueServiceStatus = Empty;
if (serviceStatusSize > AtpMaximumTotalResponseSize)
return(ATaspStatusBufferTooBig);
/* Okay, find the session listener... */
DeferTimerChecking();
DeferAtpPackets();
if ((sessionListenerInfo = FindSessionListenerInfoFor(sessionListenerRefNum))
is Empty or sessionListenerInfo->closing)
{
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
/* Build up our new Status information */
if (serviceStatusSize > 0)
{
newServiceStatus = (char *)Malloc(serviceStatusSize);
if (newServiceStatus is Empty)
{
ErrorLog("AspSetStatus", ISevError, __LINE__, UnknownPort,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotSetStatus);
}
MoveFromOpaque(newServiceStatus, serviceStatusOpaque, 0,
serviceStatusSize);
/* Make a system dependent "opaque data descriptor" for our copy so
that it will be usefull to pass to Atp. */
if ((newOpaqueServiceStatus =
MakeOpaqueDataDescriptor(newServiceStatus, serviceStatusSize,
&newFreeOpaqueServiceStatus)) is Empty)
{
ErrorLog("AspSetStatus", ISevError, __LINE__, UnknownPort,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
Free(newServiceStatus);
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotSetStatus);
}
}
/* Okay, we're set to replace the current status buffer... */
TakeLock(AspLock);
if (not sessionListenerInfo->statusSendInProgress)
{
/* No send in progress, just replace. */
if (sessionListenerInfo->serviceStatusSize > 0)
freeServiceStatus = sessionListenerInfo->serviceStatus;
if (sessionListenerInfo->freeOpaqueServiceStatus)
freeOpaqueServiceStatus = sessionListenerInfo->opaqueServiceStatus;
sessionListenerInfo->serviceStatus = newServiceStatus;
sessionListenerInfo->opaqueServiceStatus = newOpaqueServiceStatus;
sessionListenerInfo->freeOpaqueServiceStatus = newFreeOpaqueServiceStatus;
sessionListenerInfo->serviceStatusSize = newServiceStatusSize;
}
else
{
/* A send is in progress, we must fill up the "next status slot" and
let it be copied to the "current status slot" when the send completes.
If the "nest status slot" is already in use, grab its info to free
when we've released our lock. */
if (sessionListenerInfo->newServiceStatusPending)
{
if (sessionListenerInfo->newServiceStatusSize > 0)
freeServiceStatus = sessionListenerInfo->newServiceStatus;
if (sessionListenerInfo->newFreeOpaqueServiceStatus)
freeOpaqueServiceStatus = sessionListenerInfo->newOpaqueServiceStatus;
}
/* Okay, now fill up the "next status slot" with our current info. */
sessionListenerInfo->newServiceStatus = newServiceStatus;
sessionListenerInfo->newOpaqueServiceStatus = newOpaqueServiceStatus;
sessionListenerInfo->newFreeOpaqueServiceStatus = newFreeOpaqueServiceStatus;
sessionListenerInfo->newServiceStatusSize = newServiceStatusSize;
sessionListenerInfo->newServiceStatusPending = True;
}
ReleaseLock(AspLock);
/* Free any remants there may be. */
if (freeServiceStatus isnt Empty)
Free(freeServiceStatus);
if (freeOpaqueServiceStatus isnt Empty)
FreeOpaqueDataDescriptor(freeOpaqueServiceStatus);
/* All set! */
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspSetStatus */
AppleTalkErrorCode far AspGetStatus(
long ourSocket, /* "Us"; who should the server respond to? */
AppleTalkAddress serverAddress, /* The server from which we should request
the status buffer (SLS). */
void far *opaqueBuffer, /* User "buffer" to place the status in! */
int bufferSize, /* Size of the above buffer. */
AspIncomingStatusHandler *completionRoutine,
/* User rotuine to call when that status
comes in. */
long unsigned userData) /* User data to pass along to the completion
rotuine. */
{
char userBytes[AtpUserBytesSize];
AppleTalkErrorCode errorCode;
CompletionInfo completionInfo;
/* We place a get status request and call a supplied completion routine when
the request completes. The completion routine is given the following
arguments:
errorCode - AppleTalkErrorCode; How did the request complete?
userData - long unsigned; as passed to this rotuine.
opaqueBuffer - void *; status "buffer," as passed to us.
bufferSize - int; actual length of status buffer.
*/
/* Set up userBytes for a status request. */
userBytes[AspCommandTypeOffset] = AspGetStatusCommand;
userBytes[AspCommandTypeOffset + 1] = 0;
userBytes[AspCommandTypeOffset + 2] = 0;
userBytes[AspCommandTypeOffset + 3] = 0;
/* Build up our completion info block. */
completionInfo = (CompletionInfo)Malloc(sizeof(*completionInfo));
if (completionInfo is empty)
return(ATaspCouldNotGetStatus);
completionInfo->completionRoutine = (void *)completionRoutine;
completionInfo->userData = userData;
/* Post the GetStatus request to the specified address... our caller
presumably found this with a prior NBP lookup. */
errorCode = AtpPostRequest(ourSocket, serverAddress,
Empty,
empty, 0, userBytes, False,
opaqueBuffer, bufferSize, empty,
AtpRetriesForAsp,
AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
IncomingGetStatusResponse,
(long unsigned)completionInfo);
if (errorCode isnt ATnoError)
Free(completionInfo);
return(errorCode);
} /* AspGetStatus */
AppleTalkErrorCode far AspGetSession(
long sessionListenerRefNum, /* What session listener? */
Boolean privateSocket, /* When we create the ASP connection
should it be on its own ATP socket? */
long *getSessionRefNum, /* Ref num of the created handler. */
AspIncomingSessionOpenHandler *completionRoutine,
/* Who do we call when the get session
command comes in and is completed. */
long unsigned userData) /* User data passed to the completion
routine. */
{
SessionListenerInfo sessionListenerInfo;
GetSessionHandler getSessionHandler;
/* Enqueue a handler for an incoming OpenSessionCommand for a specified
session listener. Return a unique identifier for the get-session, so
that it can be canceled later. When the OpenSession command comes in,
we'll call the supplied completion routine with the following arguments:
errorCode - AppleTalkErrorCode; how did the operation complete?
userData - long unsigned; as passed to this routine.
socket - long; the fully qualified AppleTalk socket on
which the ASP session is now open.
sessionRefNum - long; the session reference number for the new
ASP session.
The type of this routine is AspIncomingSessionOpenHandler.
*/
/* Okay, find the session listener... */
DeferTimerChecking();
DeferAtpPackets();
sessionListenerInfo = FindSessionListenerInfoFor(sessionListenerRefNum);
if (sessionListenerInfo is Empty or sessionListenerInfo->closing)
{
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
/* Okay, build up and enqueue a new GetSession structure. */
getSessionHandler = (GetSessionHandler)Calloc(sizeof(*getSessionHandler), 1);
if (getSessionHandler is empty)
{
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotEnqueueHandler);
}
if ((getSessionHandler->sessionRefNum = GetNextSessionRefNum()) < 0)
{
ErrorLog("AspGetSession", ISevError, __LINE__, UnknownPort,
IErrAspBadError, IMsgAspBadError,
Insert0());
Free(getSessionHandler);
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotEnqueueHandler);
}
getSessionHandler->privateSocket = privateSocket;
getSessionHandler->userData = userData;
getSessionHandler->sessionOpenHandler = completionRoutine;
getSessionHandler->mySessionListenerInfo = Link(sessionListenerInfo);
TakeLock(AspLock);
if (sessionListenerInfo->closing)
{
ReleaseLock(AspLock);
Free(getSessionHandler);
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
getSessionHandler->next = sessionListenerInfo->getSessionHandlers;
sessionListenerInfo->getSessionHandlers = Link(getSessionHandler);
*getSessionRefNum = getSessionHandler->sessionRefNum;
ReleaseLock(AspLock);
/* All set! */
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspGetSession */
AppleTalkErrorCode far AspCancelGetSession(
long sessionListenerRefNum, /* What session listener? */
long getSessionRefNum) /* What GetSession to cancel? */
{
SessionListenerInfo sessionListenerInfo;
GetSessionHandler getSessionHandler, previousGetSessionHandler = Empty;
/* Okay, find the session listener... */
DeferTimerChecking();
DeferAtpPackets();
sessionListenerInfo = FindSessionListenerInfoFor(sessionListenerRefNum);
if (sessionListenerInfo is Empty or sessionListenerInfo->closing)
{
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
/* Okay, find the GetSession. */
TakeLock(AspLock);
for (getSessionHandler = sessionListenerInfo->getSessionHandlers;
getSessionHandler isnt Empty;
previousGetSessionHandler = getSessionHandler,
getSessionHandler = getSessionHandler->next)
if (getSessionHandler->sessionRefNum is getSessionRefNum)
break;
if (getSessionHandler is Empty)
{
ReleaseLock(AspLock);
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchGetSession);
}
/* Okay, we've found the target GetSession handler, remove him from the
list. */
if (getSessionHandler->openInProgress)
getSessionHandler->canceled = True;
Link(getSessionHandler);
ReleaseLock(AspLock);
if (not UnlinkGetSessionHandler(getSessionHandler))
UnlinkGetSessionHandler(getSessionHandler);
/* All set! */
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspCancelGetSession */
AppleTalkErrorCode far AspOpenSessionOnNode(
int port, /* "Our" port number. */
long existingAtpSocket, /* "-1" if we should open our own Atp socket
for the new session; if ">= 0" this is
an already open Atp socket on which to
open the session. */
int desiredSocket, /* Desired socket; zero for dynamic. */
AppleTalkAddress serverAddress, /* Address of the server (SLS). */
long *ourSocket, /* The full address of the WSS that we
opened. */
AspIncomingOpenReplyHandler *completionRoutine,
/* Routine to call with the OpenReply. */
long unsigned userData) /* User data to pass to the completion
routine. */
{
AppleTalkErrorCode errorCode;
char userBytes[AtpUserBytesSize];
CompletionInfo completionInfo;
SessionInfo sessionInfo;
long index, tempSocket;
AppleTalkAddress ourAddress;
long sessionRefNum;
/* Post an OpenSession request. Call a supplied completion routine when the
request completes (or times-out). The arguments are as follows:
errorCode - AppleTalkErrorCode; how did the request complete?
userData - long unsigned; as passed to this routine.
sessionRefNum - long; session reference number of the new session.
*/
/* First call? */
if (not sessionMaintenanceTimerStarted)
if ((errorCode = InitializeAsp()) isnt ATnoError)
return(errorCode);
/* Try to open the WSS. */
if (existingAtpSocket < 0)
{
if ((errorCode = AtpOpenSocketOnNode(&tempSocket, port, empty,
desiredSocket, empty, 0)) isnt
ATnoError)
return(errorCode);
}
else
tempSocket = existingAtpSocket;
if (MapSocketToAddress(tempSocket, &ourAddress) isnt ATnoError)
{
ErrorLog("AspOpenSessionOnNode", ISevError, __LINE__, port,
IErrAspCouldntMapAddress, IMsgAspCouldntMapAddress,
Insert0());
if (existingAtpSocket < 0)
AtpCloseSocketOnNode(tempSocket, Empty, (long unsigned)0);
return(ATinternalError);
}
if (ourSocket isnt empty)
*ourSocket = tempSocket;
/* Set up userBytes for an open-session request. */
userBytes[AspCommandTypeOffset] = AspOpenSessionCommand;
userBytes[AspWssNumberOffset] = ourAddress.socketNumber;
userBytes[AspVersionNumberOffset] = AspVersionBytes[0];
userBytes[AspVersionNumberOffset + 1] = AspVersionBytes[1];
/* Get a new sessionRefNum and allocate a new sessionInfo. */
if ((sessionRefNum = GetNextSessionRefNum()) < 0)
{
ErrorLog("AspOpenSessionOnNode", ISevError, __LINE__, port,
IErrAspBadError, IMsgAspBadError,
Insert0());
if (existingAtpSocket < 0)
AtpCloseSocketOnNode(tempSocket, Empty, (long unsigned)0);
return(ATaspCouldNotOpenSession);
}
sessionInfo = (SessionInfo)Calloc(sizeof(*sessionInfo), 1);
if (sessionInfo is empty)
{
if (existingAtpSocket < 0)
AtpCloseSocketOnNode(tempSocket, Empty, (long unsigned)0);
return(ATaspCouldNotOpenSession);
}
/* Fill in what we can... */
DeferTimerChecking();
DeferAtpPackets();
sessionInfo->sessionRefNum = sessionRefNum;
sessionInfo->serverSession = False;
sessionInfo->waitingForOpenReply = True;
sessionInfo->ourPort = port;
sessionInfo->ourSocket = tempSocket;
sessionInfo->closeOurSocket = (existingAtpSocket < 0);
sessionInfo->slsAddress = serverAddress;
sessionInfo->lastContactTime = CurrentRelativeTime();
/* Build up our completion info block. */
completionInfo = (CompletionInfo)Malloc(sizeof(*completionInfo));
if (completionInfo is empty)
{
Free(sessionInfo);
if (existingAtpSocket < 0)
AtpCloseSocketOnNode(tempSocket, Empty, (long unsigned)0);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotOpenSession);
}
completionInfo->completionRoutine = (void *)completionRoutine;
completionInfo->userData = userData;
completionInfo->sessionRefNum = sessionRefNum;
/* Thread the sessionInfo into the lookup table. */
CheckMod(index, sessionRefNum, NumberOfAspSessionHashBuckets,
"AspOpenSession");
TakeLock(AspLock);
sessionInfo->next = sessionInfoHashBuckets[index];
sessionInfoHashBuckets[index] = Link(sessionInfo);
ReleaseLock(AspLock);
/* Post the OpenSession request to the specified address... our caller
presumably found this with a prior NBP lookup. */
errorCode = AtpPostRequest(tempSocket, serverAddress,
Empty,
empty, 0, userBytes, True,
empty, 0,
sessionInfo->sessionUserBytes,
AtpRetriesForAsp,
AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
IncomingOpenSessionResponse,
(long unsigned)completionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
if (errorCode isnt ATnoError)
{
AspCloseSession(sessionRefNum, Empty, (long unsigned)0, True);
Free(completionInfo);
}
return(errorCode);
} /* AspOpenSessionOnNode */
AppleTalkErrorCode far AspCloseSession(
long sessionRefNum, /* Session to close. */
CloseCompletionRoutine far *closeCompletionRoutine,
/* Close completion rotuine. */
long unsigned closeUserData,
/* User data for above. */
Boolean remoteClose) /* All external callers should pass "False."
If "True" we won't send a Close command
to the remote side -- we're closing due to
receiving such a close. */
{
SessionInfo sessionInfo;
AppleTalkErrorCode closeCode;
char userBytes[AtpUserBytesSize];
GetRequestInfo getRequestInfo, nextGetRequestInfo;
if (remoteClose)
closeCode = ATaspRemoteSessionClose;
else
closeCode = ATaspLocalSessionClose;
DeferTimerChecking();
DeferAtpPackets();
if ((sessionInfo = FindSessionInfoFor(sessionRefNum)) is Empty or
sessionInfo->closing)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
/* Set about closing. */
TakeLock(AspLock);
sessionInfo->closing = True;
sessionInfo->closeContext.closeCompletionRoutine = closeCompletionRoutine;
sessionInfo->closeContext.closeUserData = closeUserData;
sessionInfo->closeCode = closeCode;
ReleaseLock(AspLock);
if (not remoteClose)
{
/* Build up the user bytes for the ATP close request. */
userBytes[AspCommandTypeOffset] = AspCloseSessionCommand;
userBytes[AspSessionIdOffset] = sessionInfo->sessionId;
userBytes[AspAttentionWordOffset] = 0;
userBytes[AspAttentionWordOffset + 1] = 0;
/* Post the request... */
AtpPostRequest(sessionInfo->ourSocket, sessionInfo->theirAddress,
Empty, empty, 0, userBytes, False, empty, 0,
empty, AtpRetriesForAsp, AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer, empty, (long unsigned)0);
}
if (sessionInfo->serverSession)
{
/* We want to terminate any pending get request handlers. */
TakeLock(AspLock);
getRequestInfo = Link(sessionInfo->getRequestInfoList);
ReleaseLock(AspLock);
while (getRequestInfo isnt Empty)
{
getRequestInfo->errorCode = closeCode;
getRequestInfo->sessionRefNum = sessionRefNum;
getRequestInfo->usersCookie = sessionInfo->usersCookie;
/* Tag if the following Unlinks will really complete a GetRequest,
thus notifing the session's owner of the close (otherwise, if
we're doing GetAnyRequests, we'll use one of these later to
notify the owner). */
if (not getRequestInfo->inUse)
sessionInfo->notifiedOwnerOfClose = True;
TakeLock(AspLock);
nextGetRequestInfo = Link(getRequestInfo->next);
ReleaseLock(AspLock);
if (not UnlinkGetRequestInfo(getRequestInfo))
UnlinkGetRequestInfo(getRequestInfo);
getRequestInfo = nextGetRequestInfo;
}
}
/* Lastly, Unlink (twice) to set the close into motion. */
#if VerboseMessages
printf("ASP SessionRefNum %d closeing.\n", sessionInfo->sessionRefNum);
#endif
UnlinkSessionInfo(sessionInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspCloseSession */
AppleTalkErrorCode AspSetCookieForSession(
long sessionRefNum, /* Session to set cookie for. */
long unsigned cookie) /* New cookie. */
{
SessionInfo sessionInfo;
/* Find the target session. */
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
/* Set the cookie and run away. */
sessionInfo->usersCookie = cookie;
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspSetCookieForSession */
AppleTalkErrorCode AspGetCookieForSession(
long sessionRefNum, /* Session to set cookie for. */
long unsigned far *cookie) /* Cookie return address. */
{
SessionInfo sessionInfo;
/* Find the target session. */
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
/* Get the cookie and run away. */
*cookie = sessionInfo->usersCookie;
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspGetCookieForSession */
AppleTalkErrorCode far AspGetRequest(
long sessionRefNum, /* Session to read from. */
void far *opaqueBuffer, /* "Buffer" to fill with request. May be
Empty. */
int bufferSize, /* Size of buffer. */
AspIncomingCommandHandler *completionRoutine,
/* Routine to call when the request comes
in. */
long unsigned userData) /* User data passed on to the completion
routine. */
{
SessionInfo sessionInfo;
GetRequestInfo getRequestInfo;
long getRequestRefNum, index;
/* We enqueue a handler for an incoming Write or Command on a particular
server session. When one comes in we call the supplied completion
routine with the following arguments:
errorCode - AppleTalkErrorCode; condition of request.
userData - long unsigned; as passed to us.
sessionRefNum - long; the session to respond to (as passed to us).
usersCookie - This session cookie.
opaqueBuffer - void *; "buffer" space for request data, as
passed to us; if Empty was passed in this is the
actual "char *" pointer to the real Atp/Ddp
buffer that contains the request.
bufferSize - int; ammount of buffer space actually used.
requestType - short; AspWriteCommand or AspCommandCommand.
getRequestRefNum - long unsigned; used for reply.
*/
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty or sessionInfo->closing)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (not sessionInfo->serverSession)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNotServerSession);
}
if (bufferSize > AtpSinglePacketDataSize)
bufferSize = AtpSinglePacketDataSize;
/* Build up a new GetRequestInfo node. First find a free GetRequestRefNum.
Don't worry, in 99.9999% of the cases, this loop will execute once! */
TakeLock(AspLock);
while(True)
{
sessionInfo->mySessionListener->lastGetRequestRefNum += 1;;
if ((sessionInfo->mySessionListener->lastGetRequestRefNum += 1) < 0)
sessionInfo->mySessionListener->lastGetRequestRefNum = 0;
getRequestRefNum = sessionInfo->mySessionListener->lastGetRequestRefNum;
ReleaseLock(AspLock);
if ((getRequestInfo = FindGetRequestInfoFor(sessionInfo->mySessionListener,
getRequestRefNum)) is Empty)
break;
UnlinkGetRequestInfo(getRequestInfo);
TakeLock(AspLock);
}
getRequestInfo = (GetRequestInfo)Calloc(sizeof(*getRequestInfo), 1);
if (getRequestInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotGetRequest);
}
getRequestInfo->getRequestRefNum = getRequestRefNum;
getRequestInfo->mySessionInfo = Link(sessionInfo);
getRequestInfo->mySessionListener = Link(sessionInfo->mySessionListener);
getRequestInfo->opaqueBuffer = opaqueBuffer;
getRequestInfo->bufferSize = bufferSize;
getRequestInfo->completionRoutine = completionRoutine;
getRequestInfo->userData = userData;
/* Link it up! */
TakeLock(AspLock);
if (sessionInfo->closing)
{
ReleaseLock(AspLock);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
getRequestInfo->next = sessionInfo->getRequestInfoList;
sessionInfo->getRequestInfoList = getRequestInfo;
/* Link this guy into the per-Sls getRequestInfo hash list. */
CheckMod(index, getRequestRefNum, NumGetRequestInfoHashBuckets,
"AspGetRequest");
getRequestInfo->nextForMySessionListener =
sessionInfo->mySessionListener->getRequestInfoHashBuckets[index];
sessionInfo->mySessionListener->getRequestInfoHashBuckets[index] =
Link(getRequestInfo);
ReleaseLock(AspLock);
/* All set. */
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspGetRequest */
AppleTalkErrorCode far AspGetAnyRequest(
long sessionListenerRefNum, /* Session listener from whos sessions we
should read from. */
void far *opaqueBuffer, /* "Buffer" to fill with request. May be
Empty. */
int bufferSize, /* Size of buffer. */
AspIncomingCommandHandler *completionRoutine,
/* Routine to call when the request comes
in. */
long unsigned userData) /* User data passed on to the completion
routine. */
{
SessionListenerInfo sessionListenerInfo;
GetRequestInfo getRequestInfo;
long getRequestRefNum, index;
DeferredCloseNotify deferredCloseNotify;
/* We enqueue a handler for an incoming Write or Command targeted at any
server session to the specified session listener. When one comes in
we call the supplied completion routine with the following arguments:
errorCode - AppleTalkErrorCode; condition of request.
userData - long unsigned; as passed to us.
sessionRefNum - long; the session refNum of the target of the
incoming request.
usersCookie - long; this sessions cookie.
opaqueBuffer - void *; buffer space for request data, as passed
to us; if Empty was passed in this is the
actual "char *" pointer to the real Atp/Ddp
buffer that contains the request.
bufferSize - int; ammount of buffer space actually used.
requestType - short; AspWriteCommand or AspCommandCommand.
getRequestRefNum - long unsigned; used for reply.
*/
DeferTimerChecking();
DeferAtpPackets();
sessionListenerInfo = FindSessionListenerInfoFor(sessionListenerRefNum);
if (sessionListenerInfo is empty or sessionListenerInfo->closing)
{
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
if (bufferSize > AtpSinglePacketDataSize)
bufferSize = AtpSinglePacketDataSize;
/* If there is a deferred close on the session listener, complete this
this GetAnyRequest now with the old news. */
TakeLock(AspLock);
if (sessionListenerInfo->deferredCloseNotifyList isnt Empty)
{
deferredCloseNotify = sessionListenerInfo->deferredCloseNotifyList;
sessionListenerInfo->deferredCloseNotifyList = deferredCloseNotify->next;
ReleaseLock(AspLock);
(*completionRoutine)(deferredCloseNotify->closeCode, userData,
deferredCloseNotify->sessionRefNum,
deferredCloseNotify->usersCookie,
empty, 0, 0, (long)0);
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
}
/* Build up a new GetRequestInfo node. First find a free GetRequestRefNum.
Don't worry, in 99.9999% of the cases, this loop will execute once! */
while(True)
{
sessionListenerInfo->lastGetRequestRefNum += 1;;
if ((sessionListenerInfo->lastGetRequestRefNum += 1) < 0)
sessionListenerInfo->lastGetRequestRefNum = 0;
getRequestRefNum = sessionListenerInfo->lastGetRequestRefNum;
ReleaseLock(AspLock);
if ((getRequestInfo = FindGetRequestInfoFor(sessionListenerInfo,
getRequestRefNum)) is Empty)
break;
UnlinkGetRequestInfo(getRequestInfo);
TakeLock(AspLock);
}
getRequestInfo = (GetRequestInfo)Calloc(sizeof(*getRequestInfo), 1);
if (getRequestInfo is empty)
{
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotGetRequest);
}
getRequestInfo->getRequestRefNum = getRequestRefNum;
getRequestInfo->mySessionListener = Link(sessionListenerInfo);
getRequestInfo->opaqueBuffer = opaqueBuffer;
getRequestInfo->bufferSize = bufferSize;
getRequestInfo->completionRoutine = completionRoutine;
getRequestInfo->userData = userData;
/* Link it up! */
TakeLock(AspLock);
if (sessionListenerInfo->closing)
{
Free(getRequestInfo);
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
getRequestInfo->next = sessionListenerInfo->getRequestInfoList;
sessionListenerInfo->getRequestInfoList = getRequestInfo;
sessionListenerInfo->getAnyRequestsSeen = True;
/* Link this guy into the per-Sls getRequestInfo hash list. */
CheckMod(index, getRequestRefNum, NumGetRequestInfoHashBuckets,
"AspGetAnyRequest");
getRequestInfo->nextForMySessionListener =
sessionListenerInfo->getRequestInfoHashBuckets[index];
sessionListenerInfo->getRequestInfoHashBuckets[index] = Link(getRequestInfo);
ReleaseLock(AspLock);
/* All set. */
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspGetAnyRequest */
AppleTalkErrorCode far AspReply(
long sessionRefNum, /* Session to respond from. */
long getRequestRefNum, /* Request we're responding to. */
short requestType, /* Write or Command; from request. */
char far *resultCode, /* Four byte reply result code. */
void far *opaqueBuffer, /* Response data. */
int bufferSize, /* Size of response data. */
AspReplyCompleteHandler *completionRoutine,
/* Routine to call when the response
completes (may be empty). */
long unsigned userData) /* User data to pass to completion
routine. */
{
SessionInfo sessionInfo;
GetRequestInfo getRequestInfo;
CompletionInfo completionInfo;
AppleTalkErrorCode errorCode;
/* Reply to a specified ASP request. An optional completion routine should
be called when the reply completes. Its arguments are:
errorCode - AppleTalkErrorCode; how did the reply complete?
Okay or time-out?
userData - long unsigned; user data as passed to this
routine.
sessionRefNum - long; the session's identifier.
getRequestRefNum - long; the request's identifier.
*/
if (bufferSize > AtpMaximumTotalResponseSize)
return(ATaspBufferTooBig);
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is Empty or sessionInfo->closing)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (not sessionInfo->serverSession)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNotServerSession);
}
/* Can we find the specified request (that we're trying to respond to)? */
getRequestInfo = FindGetRequestInfoFor(sessionInfo->mySessionListener,
getRequestRefNum);
if (getRequestInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchRequest);
}
if (getRequestInfo->requestType isnt requestType or
not getRequestInfo->inUse)
{
if (not getRequestInfo->inUse)
errorCode = ATaspNoOperationInProgress;
else
errorCode = ATaspWrongRequestType;
getRequestInfo->inUse = True; /* Don't call completion routine. */
if (not UnlinkGetRequestInfo(getRequestInfo))
UnlinkGetRequestInfo(getRequestInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
}
/* We'll need to handle a reply complete, see if we can get the memory
for the identifier. */
completionInfo = (CompletionInfo)Malloc(sizeof(*completionInfo));
if (completionInfo is empty)
{
if (not UnlinkGetRequestInfo(getRequestInfo))
UnlinkGetRequestInfo(getRequestInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotPostReply);
}
/* Okay, post the reply; fill in the reply complete info first. */
completionInfo->completionRoutine = (void *)completionRoutine;
completionInfo->userData = userData;
completionInfo->sessionRefNum = sessionRefNum;
completionInfo->getRequestRefNum = getRequestRefNum;
Link(sessionInfo);
errorCode = AtpPostResponse(sessionInfo->ourSocket,
getRequestInfo->source,
getRequestInfo->transactionId,
opaqueBuffer, bufferSize,
resultCode,
getRequestInfo->exactlyOnce,
IncomingRelease,
(long unsigned)completionInfo);
if (errorCode isnt ATnoError)
{
UnlinkSessionInfo(sessionInfo);
Free(completionInfo);
}
/* Free the get request info. */
if (not UnlinkGetRequestInfo(getRequestInfo))
UnlinkGetRequestInfo(getRequestInfo);
UnlinkSessionInfo(sessionInfo);
/* All set! */
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
} /* AspReply */
#if Iam an OS2 /* Too many stack temporaries... */
#pragma optimize ("eg", off)
#endif
AppleTalkErrorCode far AspWriteContinue(
long sessionRefNum,
long getRequestRefNum,
void far *opaqueBuffer,
int bufferSize,
AspIncomingWriteDataHandler *completionRoutine,
long unsigned userData)
{
SessionInfo sessionInfo;
GetRequestInfo getRequestInfo;
CompletionInfo completionInfo;
AppleTalkErrorCode errorCode;
char userBytes[AtpUserBytesSize];
/* Post a WriteContinue ATP request. We call a completion routine with the
following arguments when the request completes:
errorCode - AppleTalkErrorCode; how did the request complete?
Okay or time-out?
userData - long unsigned; user data as passed to this
routine.
sessionRefNum - long; the session's identifier.
getRequestRefNum - long; the request's identifier.
opaqueBuffer - void *; "buffer" with received data, as passed
to us.
bufferSize - int; how much data is in the buffer?
*/
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty or sessionInfo->closing)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (not sessionInfo->serverSession)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNotServerSession);
}
if (bufferSize > AtpMaximumTotalResponseSize)
bufferSize = AtpMaximumTotalResponseSize;
/* Can we find the specified request (a WriteCommand)? */
getRequestInfo = FindGetRequestInfoFor(sessionInfo->mySessionListener,
getRequestRefNum);
if (getRequestInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchRequest);
}
TakeLock(AspLock);
if (getRequestInfo->requestType isnt AspWriteCommand or
not getRequestInfo->inUse or
getRequestInfo->writeContinueInProgress)
{
if (getRequestInfo->writeContinueInProgress)
errorCode = ATaspOperationAlreadyInProgress;
else if (not getRequestInfo->inUse)
errorCode = ATaspNoOperationInProgress;
else
errorCode = ATaspWrongRequestType;
getRequestInfo->inUse = True; /* Don't call completion routine. */
if (not UnlinkGetRequestInfo(getRequestInfo))
UnlinkGetRequestInfo(getRequestInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
}
getRequestInfo->writeContinueInProgress = True;
ReleaseLock(AspLock);
/* We'll need to handle a request complete, see if we can get the memory
for the identifier. */
completionInfo = (CompletionInfo)Malloc(sizeof(*completionInfo));
if (completionInfo is empty)
{
ErrorLog("AspWriteContinue", ISevError, __LINE__, UnknownPort,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
if (not UnlinkGetRequestInfo(getRequestInfo))
UnlinkGetRequestInfo(getRequestInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotPostWriteContinue);
}
/* Build the writeContinue command. */
userBytes[AspCommandTypeOffset] = AspWriteDataCommand;
userBytes[AspSessionIdOffset] = sessionInfo->sessionId;
userBytes[AspSequenceNumberOffset] =
(char)(getRequestInfo->sequenceNumber >> 8);
userBytes[AspSequenceNumberOffset + 1] =
(char)(getRequestInfo->sequenceNumber & 0xFF);
/* Build the ATP data... two bytes of expected response size. We need to
pass Atp an "opaque" descriptor (not a "char *"), so build this too! */
getRequestInfo->writeContinueData[0] = (char)(bufferSize >> 8);
getRequestInfo->writeContinueData[1] = (char)(bufferSize & 0xFF);
if ((getRequestInfo->opaqueWriteContinueData =
MakeOpaqueDataDescriptor(getRequestInfo->writeContinueData, 2,
&getRequestInfo->
freeOpaqueWriteContinueData)) is Empty)
{
ErrorLog("AspWriteContinue", ISevError, __LINE__, UnknownPort,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
if (not UnlinkGetRequestInfo(getRequestInfo))
UnlinkGetRequestInfo(getRequestInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotPostWriteContinue);
}
/* Okay, post the request; fill in the completion info first. */
completionInfo->completionRoutine = (void *)completionRoutine;
completionInfo->userData = userData;
completionInfo->sessionRefNum = sessionRefNum;
completionInfo->getRequestRefNum = getRequestRefNum;
Link(sessionInfo);
errorCode = AtpPostRequest(sessionInfo->ourSocket,
sessionInfo->theirAddress,
&getRequestInfo->writeContinueTransactionId,
getRequestInfo->opaqueWriteContinueData, 2,
userBytes, True, opaqueBuffer, bufferSize, empty,
AtpInfiniteRetries, AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
IncomingWriteContinueResponse,
(long unsigned)completionInfo);
if (errorCode isnt ATnoError)
{
if (not UnlinkGetRequestInfo(getRequestInfo))
UnlinkGetRequestInfo(getRequestInfo);
UnlinkSessionInfo(sessionInfo);
Free(completionInfo);
}
UnlinkGetRequestInfo(getRequestInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
} /* AspWriteContinue */
#if Iam an OS2
#pragma optimize ("eg", on)
#endif
AppleTalkErrorCode far AspCommand(
long sessionRefNum, /* Session to send the command to. */
void far *opaqueCommandBuffer, /* Command buffer to send. */
int commandBufferSize, /* Size of command. */
char far *resultCode, /* Location to store the result code into.
Maybe empty, in which case the completion
routine will be passed a pointer to where
it can copy the result code byte from. */
void far *opaqueReplyBuffer, /* Buffer to hold the command reply data. */
int replyBufferSize, /* Size of above. */
AspWriteOrCommCompleteHandler *completionRoutine,
/* Routine to call on completion. */
long unsigned userData) /* User data to pass to the above routine. */
{
SessionInfo sessionInfo;
WriteOrCommandInfo commandInfo;
CompletionInfo completionInfo;
AppleTalkErrorCode errorCode;
char userBytes[AtpUserBytesSize];
/* Post an ASP command, call a completion routine with the following
arguments:
errorCode - AppleTalkErrorCode; how did the request complete?
userData - long unsigned; as passed to us.
sessionRefNum - long; the session that posted the request.
resultCode - char *; result returned from the server.
opaqueBuffer - void *; reply "buffer" from the server, as passed
to us.
bufferSize - int; size of the above buffer.
*/
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty or sessionInfo->closing)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (sessionInfo->serverSession)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNotWorkstationSession);
}
/* Get the two blocks of memory that we'll need to post this request. */
if ((commandInfo = (WriteOrCommandInfo)Calloc(sizeof(*commandInfo), 1))
is empty or
(completionInfo = (CompletionInfo)Malloc(sizeof(*completionInfo)))
is empty)
{
if (commandInfo isnt empty)
Free(commandInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotPostRequest);
}
/* Complete and thread the command info. We'll increment the sequence nubmer
when we know the request got out okay. */
commandInfo->resultCode = resultCode;
TakeLock(AspLock);
commandInfo->sequenceNumber = sessionInfo->nextSequenceNumber;
sessionInfo->nextSequenceNumber += 1;
commandInfo->next = sessionInfo->writeOrCommandInfoList;
sessionInfo->writeOrCommandInfoList = commandInfo;
ReleaseLock(AspLock);
/* Build the userBytes for an ASP command. */
userBytes[AspCommandTypeOffset] = AspCommandCommand;
userBytes[AspSessionIdOffset] = sessionInfo->sessionId;
userBytes[AspSequenceNumberOffset] =
(char)(commandInfo->sequenceNumber >> 8);
userBytes[AspSequenceNumberOffset + 1] =
(char)(commandInfo->sequenceNumber & 0xFF);
/* Build up the structure that we need to know what to do on ATP
completion. */
completionInfo->completionRoutine = (void *)completionRoutine;
completionInfo->userData = userData;
completionInfo->sessionRefNum = sessionRefNum;
completionInfo->sequenceNumber = commandInfo->sequenceNumber;
/* Okay, post the request. */
Link(sessionInfo);
errorCode = AtpPostRequest(sessionInfo->ourSocket,
sessionInfo->theirAddress,
Empty,
opaqueCommandBuffer, commandBufferSize,
userBytes, True, opaqueReplyBuffer,
replyBufferSize, resultCode, AtpInfiniteRetries,
AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
IncomingWriteOrCommandComplete,
(long unsigned)completionInfo);
if (errorCode isnt ATnoError)
{
ReleaseLock(AspLock);
RemoveFromListNoUnlink(sessionInfo->writeOrCommandInfoList, commandInfo,
next);
sessionInfo->nextSequenceNumber -= 1;
ReleaseLock(AspLock);
Free(commandInfo);
Free(completionInfo);
UnlinkSessionInfo(sessionInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
}
/* Request out! */
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspCommand */
AppleTalkErrorCode far AspWrite(
long sessionRefNum, /* Session to send the command to. */
void far *opaqueCommandBuffer, /* Command "buffer" to send. */
int commandBufferSize, /* Size of command. */
void far *opaqueWriteBuffer, /* "Buffer" to write to the server. */
int writeBufferSize, /* Size of write buffer. */
char far *resultCode, /* Location to store the result code into.
Maybe empty, in which case the completion
routine will be passed a pointer to where
it can copy the result code byte from. */
void far *opaqueReplyBuffer, /* "Buffer" to hold the command reply data. */
int replyBufferSize, /* Size of above. */
AspWriteOrCommCompleteHandler *completionRoutine,
/* Routine to call on completion. */
long unsigned userData) /* User data to pass to the above routine. */
{
SessionInfo sessionInfo;
WriteOrCommandInfo writeInfo;
CompletionInfo completionInfo;
AppleTalkErrorCode errorCode;
char userBytes[AtpUserBytesSize];
/* Post an ASP command, call a completion routine with the following
arguments:
errorCode - AppleTalkErrorCode; how did the request complete?
userData - long unsigned; as passed to us.
sessionRefNum - long; the session that posted the request.
resultCode - char *; result returned from the server.
opaqueBuffer - void *; reply "buffer" from the server, as passed
to us.
bufferSize - int; size of the above buffer.
*/
if (writeBufferSize > AtpMaximumTotalResponseSize)
return(ATaspSizeError);
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty or sessionInfo->closing)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (sessionInfo->serverSession)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNotWorkstationSession);
}
/* Get the two blocks of memory that we'll need to post this request. */
if ((writeInfo = (WriteOrCommandInfo)Calloc(sizeof(*writeInfo), 1))
is empty or
(completionInfo = (CompletionInfo)Malloc(sizeof(*completionInfo)))
is empty)
{
if (writeInfo isnt empty)
Free(writeInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotPostRequest);
}
/* Complete and thread the write info. We'll increment the next sequence
number when we know we're going to be okay. */
writeInfo->writeCommand = True;
writeInfo->resultCode = resultCode;
writeInfo->writeOpaqueBuffer = opaqueWriteBuffer;
writeInfo->writeBufferSize = writeBufferSize;
TakeLock(AspLock);
writeInfo->sequenceNumber = sessionInfo->nextSequenceNumber;
sessionInfo->nextSequenceNumber += 1;
writeInfo->next = sessionInfo->writeOrCommandInfoList;
sessionInfo->writeOrCommandInfoList = writeInfo;
ReleaseLock(AspLock);
/* Build the userBytes for an ASP write. */
userBytes[AspCommandTypeOffset] = AspWriteCommand;
userBytes[AspSessionIdOffset] = sessionInfo->sessionId;
userBytes[AspSequenceNumberOffset] =
(char)(writeInfo->sequenceNumber >> 8);
userBytes[AspSequenceNumberOffset + 1] =
(char)(writeInfo->sequenceNumber & 0xFF);
/* Build up the structure that we need to know what to do on ATP
completion. */
completionInfo->completionRoutine = (void *)completionRoutine;
completionInfo->userData = userData;
completionInfo->sessionRefNum = sessionRefNum;
completionInfo->sequenceNumber = writeInfo->sequenceNumber;
/* Okay, post the request. */
Link(sessionInfo);
errorCode = AtpPostRequest(sessionInfo->ourSocket,
sessionInfo->theirAddress,
Empty,
opaqueCommandBuffer, commandBufferSize,
userBytes, True, opaqueReplyBuffer,
replyBufferSize, resultCode, AtpInfiniteRetries,
AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
IncomingWriteOrCommandComplete,
(long unsigned)completionInfo);
if (errorCode isnt ATnoError)
{
TakeLock(AspLock);
RemoveFromListNoUnlink(sessionInfo->writeOrCommandInfoList, writeInfo,
next);
sessionInfo->nextSequenceNumber -= 1;
ReleaseLock(AspLock);
Free(writeInfo);
Free(completionInfo);
UnlinkSessionInfo(sessionInfo);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
}
/* Request is out! */
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspWrite */
AppleTalkErrorCode far AspGetAttention(
long sessionRefNum, /* Session to get attention from. */
AspIncomingAttentionHandler *handler,
/* Routine to call when an attention
comes in. */
long unsigned userData) /* User data to pass on to the handler when
an attention comes in. */
{
SessionInfo sessionInfo;
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty or sessionInfo->closing)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (sessionInfo->serverSession)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNotWorkstationSession);
}
TakeLock(AspLock);
sessionInfo->incomingAttentionHandler = handler;
sessionInfo->userDataForAttention = userData;
ReleaseLock(AspLock);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} /* AspGetAttention */
AppleTalkErrorCode far AspSendAttention(
long sessionRefNum, /* Session to send attention to. */
short unsigned attentionData) /* Two bytes of attention data... */
{
SessionInfo sessionInfo;
char userBytes[AtpUserBytesSize];
AppleTalkErrorCode errorCode;
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty or sessionInfo->closing)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (not sessionInfo->serverSession)
{
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNotServerSession);
}
/* Build up the user bytes for the ATP request. */
userBytes[AspCommandTypeOffset] = AspAttentionCommand;
userBytes[AspSessionIdOffset] = sessionInfo->sessionId;
userBytes[AspAttentionWordOffset] = (char)(attentionData >> 8);
userBytes[AspAttentionWordOffset + 1] = (char)(attentionData & 0xFF);
/* Post the request... */
errorCode = AtpPostRequest(sessionInfo->ourSocket,
sessionInfo->theirAddress,
Empty,
empty, 0, userBytes, False, empty, 0,
empty, AtpRetriesForAsp,
AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
empty, (long unsigned)0);
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
} /* AspSendAttention */
ExternForVisibleFunction void far
IncomingSlsTransaction(AppleTalkErrorCode errorCode,
long unsigned userData,
AppleTalkAddress source,
void far *buffer, /* Really "char *." */
int bufferSize,
char far *userBytes,
Boolean exactlyOnce,
TRelTimerValue trelTimerValue,
short unsigned transactionId,
short unsigned bitmap)
{
StaticForSmallStack GetSessionHandler getSessionHandler;
StaticForSmallStack long serverSessionSocket;
StaticForSmallStack Boolean inUse;
StaticForSmallStack long id;
StaticForSmallStack SessionRefNumMap sessionRefNumMap;
StaticForSmallStack unsigned char sessionId;
StaticForSmallStack char outgoingUserBytes[AtpUserBytesSize];
StaticForSmallStack SessionListenerInfo sessionListenerInfo;
StaticForSmallStack SocketInfo socketInfo;
StaticForSmallStack AppleTalkAddress sssAddress;
StaticForSmallStack long index, sessionRefNum;
SessionInfo sessionInfo;
long ourSocket;
long sessionListenerRefNum = (long)userData;
AspIncomingSessionOpenHandler *sessionOpenHandler;
Boolean needToUndefer = True;
Boolean newSocket = False;
/* Touch all formals... */
buffer, bufferSize, bitmap, trelTimerValue;
if (errorCode is ATsocketClosed)
return; /* Session listener closed... */
else if (errorCode is ATatpTransactionAborted)
return; /* Somebody canceled our get request... */
/* Find the correct session listener: */
DeferTimerChecking();
DeferAtpPackets();
sessionListenerInfo = FindSessionListenerInfoFor(sessionListenerRefNum);
if (sessionListenerInfo is Empty or sessionListenerInfo->closing)
{
if (sessionListenerInfo is Empty)
ErrorLog("IncomingSlsTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspListenerInfoMissing, IMsgAspListenerInfoMissing,
Insert0());
else
UnlinkSessionListenerInfo(sessionListenerInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
/* If we have some sort of AppleTalk error, we could try to re-enqueue the
request handler but, more than likely, the error would happen again (and
quickly) and we'd end up hanging the driver. So, just drop the handler
on the floor... */
if (errorCode isnt ATnoError and errorCode isnt ATatpResponseBufferTooSmall)
{
UnlinkSessionListenerInfo(sessionListenerInfo);
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspLostSLSPacket, IMsgAspLostSLSPacket,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
/* Okay, break up on ASP command type. */
switch(userBytes[AspCommandTypeOffset])
{
case AspOpenSessionCommand:
/* First, is there a free sessionId for a new ASP session? Only
go 'round this once [sessionId's are one byte beasts]. Also check
the getSessionHandlerList, for any session Ids that may be reserved
during an open that is currently in progress. */
TakeLock(AspLock);
for (sessionId = (unsigned char)(sessionListenerInfo->lastSessionId + 1);
sessionId isnt sessionListenerInfo->lastSessionId;
sessionId += 1)
{
inUse = False;
for (sessionInfo = sessionListenerInfo->sessionList;
not inUse and sessionInfo isnt empty;
sessionInfo = sessionInfo->nextForMySls)
if (sessionInfo->sessionId is sessionId)
inUse = True;
for (getSessionHandler = sessionListenerInfo->getSessionHandlers;
not inUse and getSessionHandler isnt Empty;
getSessionHandler = getSessionHandler->next)
if (getSessionHandler->openInProgress and
getSessionHandler->sessionId is sessionId)
inUse = True;
if (not inUse)
break;
}
/* Does the session listener have a GetSession pending? We should also
be busy if we couldn't find a free session ID. */
if (sessionListenerInfo->getSessionHandlers is empty or inUse)
{
ReleaseLock(AspLock);
if (SendAspErrorReturn(sessionListenerInfo->ourSocket, source,
transactionId, exactlyOnce, ATaspServerBusy)
isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__,
UnknownPort, IErrAspBadSrvrBusySend, IMsgAspBadSrvrBusySend,
Insert0());
break;
}
/* Reserve the sessionId while weÕre processing the open! */
sessionListenerInfo->lastSessionId = sessionId;
getSessionHandler = sessionListenerInfo->getSessionHandlers;
getSessionHandler->sessionId = sessionId;
getSessionHandler->openInProgress = True;
Link(getSessionHandler);
ReleaseLock(AspLock);
/* Okay, do we like the version number? */
if (userBytes[AspVersionNumberOffset] isnt AspVersionBytes[0] or
userBytes[AspVersionNumberOffset + 1] isnt AspVersionBytes[1])
{
getSessionHandler->openInProgress = False;
UnlinkGetSessionHandler(getSessionHandler);
if (SendAspErrorReturn(sessionListenerInfo->ourSocket, source,
transactionId, exactlyOnce,
ATaspBadVersionNumber)
isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__,
UnknownPort, IErrAspBadBadVersionSend, IMsgAspBadBadVersionSend,
Insert0());
break;
}
/* We need to open (or find) a Server Session Socket (SSS) now. There
are two choices: first, if our GetSession call requested a "private"
we need to open a new one; second, if not, we should check to see if
we can overload a previous SSS. */
TakeLock(AspLock);
if (getSessionHandler->privateSocket)
socketInfo = empty;
else
for (socketInfo = sessionListenerInfo->socketList;
socketInfo isnt empty;
socketInfo = socketInfo->next)
if (not socketInfo->privateSocket and
socketInfo->activeSessions < MaximumAspSessionsPerSocket)
break;
/* Allocate a new socket, if needed. */
if (socketInfo is empty)
{
AppleTalkAddress slsAddress;
ExtendedAppleTalkNodeNumber slsNode;
/* The SSS must be on the same AppleTalk node as our SLS. */
ReleaseLock(AspLock);
if (MapSocketToAddress(sessionListenerInfo->ourSocket,
&slsAddress) isnt ATnoError)
{
getSessionHandler->openInProgress = False;
UnlinkGetSessionHandler(getSessionHandler);
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__,
UnknownPort, IErrAspCouldntMapAddress, IMsgAspCouldntMapAddress,
Insert0());
if (SendAspErrorReturn(sessionListenerInfo->ourSocket, source,
transactionId, exactlyOnce,
ATaspServerBusy) isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__,
UnknownPort, IErrAspBadAddrNotMappedSend, IMsgAspBadAddrNotMappedSend,
Insert0());
break;
}
slsNode.networkNumber = slsAddress.networkNumber;
slsNode.nodeNumber = slsAddress.nodeNumber;
errorCode = AtpOpenSocketOnNode(&serverSessionSocket,
sessionListenerInfo->port,
&slsNode, 0, empty, 0);
if (errorCode isnt ATnoError)
{
getSessionHandler->openInProgress = False;
UnlinkGetSessionHandler(getSessionHandler);
if (SendAspErrorReturn(sessionListenerInfo->ourSocket, source,
transactionId, exactlyOnce,
ATaspServerBusy) isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__,
UnknownPort, IErrAspBadNoSocketsSend, IMsgAspBadNoSocketsSend,
Insert0());
break;
}
/* Okay, build a new socket structure. */
socketInfo = (SocketInfo)Calloc(sizeof(*socketInfo), 1);
if (socketInfo is empty)
{
getSessionHandler->openInProgress = False;
UnlinkGetSessionHandler(getSessionHandler);
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__,
UnknownPort, IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
AtpCloseSocketOnNode(serverSessionSocket, Empty,
(long unsigned)0);
break; /* Just let the open OpenSession request time-out... */
}
socketInfo->socket = serverSessionSocket;
socketInfo->activeSessions = 1;
socketInfo->privateSocket =
getSessionHandler->privateSocket;
TakeLock(AspLock);
socketInfo->next = sessionListenerInfo->socketList;
sessionListenerInfo->socketList = socketInfo;
ReleaseLock(AspLock);
newSocket = True;
}
else
{
serverSessionSocket = socketInfo->socket;
socketInfo->activeSessions += 1;
ReleaseLock(AspLock);
}
/* Grab our session ref num. */
sessionRefNum = getSessionHandler->sessionRefNum;
/* Now we need to think about allocating a session info block. */
sessionInfo = (SessionInfo)Calloc(sizeof(*sessionInfo), 1);
sessionRefNumMap =
(SessionRefNumMap)Calloc(sizeof(*sessionRefNumMap), 1);
if (sessionInfo is empty or
sessionRefNumMap is empty)
{
getSessionHandler->openInProgress = False;
UnlinkGetSessionHandler(getSessionHandler);
if (sessionInfo isnt empty)
Free(sessionInfo);
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
DecrementSocketUsage(sessionListenerInfo,
serverSessionSocket);
break;
}
/* Can we get the address to send the eventual open reply too? */
if (MapSocketToAddress(serverSessionSocket, &sssAddress)
isnt ATnoError)
{
getSessionHandler->openInProgress = False;
UnlinkGetSessionHandler(getSessionHandler);
Free(sessionInfo);
Free(sessionRefNumMap);
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspCouldntMapAddress, IMsgAspCouldntMapAddress,
Insert0());
DecrementSocketUsage(sessionListenerInfo,
serverSessionSocket);
break;
}
/* Okay, start filling in the session node... */
sessionInfo->mySessionListener = Link(sessionListenerInfo);
sessionInfo->sessionRefNum = sessionRefNum;
sessionInfo->sessionId = sessionId;
sessionInfo->serverSession = True;
sessionInfo->ourPort = sessionListenerInfo->port;
sessionInfo->ourSocket = serverSessionSocket;
sessionInfo->theirAddress = source;
sessionInfo->theirAddress.socketNumber = userBytes[AspWssNumberOffset];
if (MapSocketToAddress(sessionListenerInfo->ourSocket,
&sessionInfo->slsAddress) isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspCouldntMapAddress, IMsgAspCouldntMapAddress,
Insert0());
sessionInfo->lastContactTime = CurrentRelativeTime();
/* Pretty easy so far, but before we're finished, we need to thread
the node into three (yes three) lookup tables... Sigh. */
/* First the mapping table for ASP address to session ref number. */
TakeLock(AspLock);
if (sessionListenerInfo->closing or getSessionHandler->canceled)
{
ReleaseLock(AspLock);
/* Undo above link, when filling sessionInfo. */
UnlinkSessionListenerInfo(sessionListenerInfo);
Free(sessionInfo);
Free(sessionRefNumMap);
getSessionHandler->openInProgress = False;
UnlinkGetSessionHandler(getSessionHandler);
DecrementSocketUsage(sessionListenerInfo,
serverSessionSocket);
break;
}
CheckMod(index, (((sessionInfo->ourSocket & 0xFFFF) << 8) +
sessionId),
NumberOfSessionRefNumBuckets, "IncomingSlsTransaction");
sessionRefNumMap->socket = sessionInfo->ourSocket;
sessionRefNumMap->sessionId = sessionId;
sessionRefNumMap->sessionRefNum = sessionRefNum;
sessionRefNumMap->next = sessionRefNumMapHashBuckets[index];
sessionRefNumMapHashBuckets[index] = sessionRefNumMap;
/* Now the session ref number hash table. */
CheckMod(index, sessionRefNum, NumberOfAspSessionHashBuckets,
"IncomingSlsTransaction");
sessionInfo->next = sessionInfoHashBuckets[index];
sessionInfoHashBuckets[index] = Link(sessionInfo);
/* Finaly onto the session per SLS list... */
sessionInfo->nextForMySls = sessionListenerInfo->sessionList;
sessionListenerInfo->sessionList = sessionInfo;
Link(sessionInfo);
ReleaseLock(AspLock);
/* Send the open reply. */
outgoingUserBytes[AspSssNumberOffset] = sssAddress.socketNumber;
outgoingUserBytes[AspSessionIdOffset] = sessionId;
outgoingUserBytes[AspErrorCodeOffset] =
(char)((unsigned short)ATnoError >> 8);
outgoingUserBytes[AspErrorCodeOffset + 1] = (char)(ATnoError & 0xFF);
if (AtpPostResponse(sessionListenerInfo->ourSocket, source,
transactionId, empty, 0, outgoingUserBytes,
exactlyOnce, empty, (long unsigned)0)
isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspBadOpenOkaySend, IMsgAspBadOpenOkaySend,
Insert0());
/* Now, we should start tickling on this session! */
outgoingUserBytes[AspCommandTypeOffset] = AspTickleCommand;
outgoingUserBytes[AspSessionIdOffset] = sessionId;
outgoingUserBytes[AspErrorCodeOffset] = 0;
outgoingUserBytes[AspErrorCodeOffset + 1] = 0;
if (AtpPostRequest(sessionInfo->ourSocket,
sessionInfo->theirAddress,
&sessionInfo->tickleTransactionId,
empty, 0, outgoingUserBytes, False,
empty, 0, empty, AtpInfiniteRetries,
AspTickleSeconds,
ThirtySecondsTRelTimer,
empty, (long unsigned)0)
isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspCouldntStartTickle, IMsgAspCouldntStartTickle,
Insert0());
/* If we're a new Atp socket, post a few GetRequest handlers to be
shared by all sessions operating on this socket. */
if (newSocket)
for (index = 0; index < GetRequestHandlersPerSocket; index += 1)
{
if (AtpEnqueueRequestHandler(&id, sessionInfo->ourSocket,
Empty, 0, Empty,
IncomingSssTransaction,
(long unsigned)sessionInfo->
ourSocket) isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__,
UnknownPort, IErrAspCouldNotEnqueue,
IMsgAspCouldNotEnqueue, Insert0());
}
/* Lastly, we're ready to untread the session open handler and invoke
the completion routine! The latter comes for free by "fer sure"
unlinking the getRequestInfo. */
getSessionHandler->socket = sessionInfo->ourSocket;
getSessionHandler->sessionRefNum = sessionInfo->sessionRefNum;
if (not UnlinkGetSessionHandler(getSessionHandler))
UnlinkGetSessionHandler(getSessionHandler);
UnlinkSessionInfo(sessionInfo);
break;
case AspTickleCommand:
/* Find the correct session info node, and note that we've heard
a peep from him recently. */
sessionId = (unsigned char)userBytes[AspSessionIdOffset];
TakeLock(AspLock);
for (sessionInfo = sessionListenerInfo->sessionList;
sessionInfo isnt empty;
sessionInfo = sessionInfo->nextForMySls)
if (sessionInfo->sessionId is sessionId)
break;
if (sessionInfo is empty)
{
/* This might be okay if tickling got started before the OpenSession
reply arrived. */
ReleaseLock(AspLock);
ErrorLog("IncomingSlsTransaction", ISevVerbose, __LINE__,
UnknownPort, IErrAspSessionInfoMissing, IMsgAspSessionInfoMissing,
Insert0());
break;
}
Link(sessionInfo);
ReleaseLock(AspLock);
#if VerboseMessages
printf("Tickle SSS (%d); sesRefNum = %d, sessionId = %d.\n",
sessionInfo->ourSocket,
sessionInfo->sessionRefNum, sessionId);
#endif
sessionInfo->lastContactTime = CurrentRelativeTime();
UnlinkSessionInfo(sessionInfo);
break;
case AspGetStatusCommand:
Link(sessionListenerInfo);
sessionListenerInfo->statusSendInProgress = True;
if (AtpPostResponse(sessionListenerInfo->ourSocket, source,
transactionId,
sessionListenerInfo->opaqueServiceStatus,
sessionListenerInfo->serviceStatusSize,
getStatusResponseUserBytes, exactlyOnce,
SendStatusComplete,
(long unsigned)sessionListenerInfo) isnt ATnoError)
{
SendStatusComplete(ATnoError, (long unsigned)sessionListenerInfo,
source, transactionId);
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspBadStatusSend, IMsgAspBadStatusSend,
Insert0());
}
break;
default:
ErrorLog("IncomingSlsTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspBadCommandToSLS, IMsgAspBadCommandToSLS,
Insert0());
break;
}
/* Re-enqueue the request handler. */
if (AtpEnqueueRequestHandler(empty, sessionListenerInfo->ourSocket, empty, 0,
empty, IncomingSlsTransaction,
(long unsigned)sessionListenerInfo->
sessionListenerRefNum) isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspCouldNotEnqueue, IMsgAspCouldNotEnqueue,
Insert0());
/* Now, see, that didn't hurt much... */
UnlinkSessionListenerInfo(sessionListenerInfo);
if (needToUndefer)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
}
return;
} /* IncomingSlsTransaction */
ExternForVisibleFunction void far
IncomingSssTransaction(AppleTalkErrorCode errorCode,
long unsigned userData,
AppleTalkAddress source,
void far *buffer, /* Really "char *." */
int bufferSize,
char far *userBytes,
Boolean exactlyOnce,
TRelTimerValue trelTimerValue,
short unsigned transactionId,
short unsigned bitmap)
{
GetRequestInfo getRequestInfo;
long bufferingSessionRefNum = (long)userData;
SessionInfo sessionInfo;
long id;
short requestType;
Boolean needToUndefer = True;
short unsigned sequenceNumber;
void far *opaqueBuffer;
long ourSocket = (long)userData;
/* Touch unused formal... */
bitmap, trelTimerValue;
if (errorCode is ATatpResponseBufferTooSmall)
errorCode = ATaspBufferTooSmall;
else if (errorCode is ATsocketClosed)
return; /* Session closed... */
else if (errorCode is ATatpTransactionAborted)
return; /* Somebody canceled our get request... */
else if (errorCode isnt ATnoError)
{
ErrorLog("IncomingSssTransaction", ISevError, __LINE__, UnknownPort,
IErrAspIncomingError, IMsgAspIncomingError,
Insert0());
return;
}
DeferTimerChecking();
DeferAtpPackets();
/* Okay, using the socket (userData) and the packet's sessionId to find the
target sessionInfo. */
if ((sessionInfo =
FindSessionInfoForSocket(ourSocket,
(unsigned char)userBytes[AspSessionIdOffset]))
is empty or sessionInfo->closing)
{
if (sessionInfo is Empty)
ErrorLog("IncomingSssTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspTargetSessionMissing, IMsgAspTargetSessionMissing,
Insert0());
else
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
/* Note that we've heard from this guy... so that session maintenance doesn't
close this session out from under us! */
sessionInfo->lastContactTime = CurrentRelativeTime();
/* Process the request. */
switch (requestType = userBytes[AspCommandTypeOffset])
{
case AspCommandCommand:
case AspWriteCommand:
/* Is there a getRequest handler for this session that not currently
being used? First check the per-session handler list, then check
the global list on the ServiceListenerInfo. */
TakeLock(AspLock);
for (getRequestInfo = sessionInfo->getRequestInfoList;
getRequestInfo isnt empty;
getRequestInfo = getRequestInfo->next)
if (not getRequestInfo->inUse)
break;
if (getRequestInfo is Empty)
for (getRequestInfo =
sessionInfo->mySessionListener->getRequestInfoList;
getRequestInfo isnt empty;
getRequestInfo = getRequestInfo->next)
if (not getRequestInfo->inUse)
break;
if (getRequestInfo is Empty)
{
/* We don't have a usable queued get request handler.
We should cancel the ATP transaction so that when the request
is resent, ATP will give it to us again and we can recheck for
a request handler at that time. Otherwise, ATP would think
that the given TID was already delived [it had been given to
ASP] and would not deliver it again, thus the ASP client would
never see the request and we would end up with a "hung"
transaction. */
ReleaseLock(AspLock);
if (AtpCancelResponse(sessionInfo->ourSocket, source,
transactionId, False) isnt ATnoError)
ErrorLog("IncomingSssTransaction", ISevError, __LINE__,
UnknownPort, IErrAspBadCancelResponse, IMsgAspBadCancelResponse,
Insert0());
break;
}
/* Verify sequence number. */
sequenceNumber =
(short unsigned)((userBytes[AspSequenceNumberOffset] << 8) +
(unsigned char)userBytes[AspSequenceNumberOffset + 1]);
if (sequenceNumber isnt sessionInfo->nextExpectedSequenceNumber)
{
ReleaseLock(AspLock);
if (AtpCancelResponse(sessionInfo->ourSocket, source,
transactionId, False) isnt ATnoError)
ErrorLog("IncomingSssTransaction", ISevError, __LINE__,
UnknownPort, IErrAspBadCancelResponse, IMsgAspBadCancelResponse,
Insert0());
break;
}
else
sessionInfo->nextExpectedSequenceNumber += 1;
/* Tag the get request info as in-use. */
getRequestInfo->inUse = True;
Link(getRequestInfo);
ReleaseLock(AspLock);
/* Place the information from the ATP request into our getRequest
node that we'll need for the reply. */
getRequestInfo->requestType = requestType;
getRequestInfo->source = source;
getRequestInfo->exactlyOnce = exactlyOnce;
getRequestInfo->transactionId = transactionId;
getRequestInfo->sequenceNumber = sequenceNumber;
/* Move as much as we can of the ATP data into the ASP buffer. If
our caller didn't give us any place to put the data, just pass
a pointer to the actual "char *" Atp/Ddp incoming buffer. */
if (getRequestInfo->opaqueBuffer is Empty)
opaqueBuffer = (void *)buffer;
else
{
if (bufferSize > getRequestInfo->bufferSize)
{
errorCode = ATaspBufferTooSmall;
bufferSize = getRequestInfo->bufferSize;
}
MoveToOpaque(getRequestInfo->opaqueBuffer, 0, buffer, bufferSize);
opaqueBuffer = getRequestInfo->opaqueBuffer;
}
{
AspIncomingCommandHandler *completionRoutine =
getRequestInfo->completionRoutine;
long unsigned userData = getRequestInfo->userData;
long sessionRefNum = sessionInfo->sessionRefNum;
long getRequestRefNum = getRequestInfo->getRequestRefNum;
long unsigned cookie = sessionInfo->usersCookie;
#if IamNot a Primos
HandleAtpPackets();
HandleDeferredTimerChecks();
#endif
(*completionRoutine)(errorCode, userData, sessionRefNum, cookie,
opaqueBuffer, bufferSize, requestType,
getRequestRefNum);
#if Iam a Primos
HandleAtpPackets();
HandleDeferredTimerChecks();
#endif
UnlinkGetRequestInfo(getRequestInfo);
needToUndefer = False;
}
break;
case AspCloseSessionCommand:
/* Send CloseSession reply & close the session. */
AtpPostResponse(sessionInfo->ourSocket, source, transactionId,
empty, 0, empty, exactlyOnce, empty,
(long unsigned)0);
/* Close the session! */
AspCloseSession(sessionInfo->sessionRefNum, Empty, (long unsigned)0,
True);
break;
default:
ErrorLog("IncomingSssTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspBadCommand, IMsgAspBadCommand,
Insert0());
break;
}
/* Re-enqueue the ATP read. */
if (AtpEnqueueRequestHandler(&id, sessionInfo->ourSocket,
Empty, 0, Empty, IncomingSssTransaction,
(long unsigned)sessionInfo->ourSocket)
isnt ATnoError)
ErrorLog("IncomingSssTransaction", ISevError, __LINE__, UnknownPort,
IErrAspCouldNotEnqueue, IMsgAspCouldNotEnqueue,
Insert0());
UnlinkSessionInfo(sessionInfo);
if (needToUndefer)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
}
return;
} /* IncomingSssTransaction */
ExternForVisibleFunction void far
IncomingWssTransaction(AppleTalkErrorCode errorCode,
long unsigned userData,
AppleTalkAddress source,
void far *buffer,
/* Really "char *." */
int bufferSize,
char far *userBytes,
Boolean exactlyOnce,
TRelTimerValue trelTimerValue,
short unsigned transactionId,
short unsigned bitmap)
{
StaticForSmallStack SessionInfo sessionInfo;
StaticForSmallStack WriteOrCommandInfo writeInfo;
StaticForSmallStack long id;
StaticForSmallStack int writeSize;
long sessionRefNum = (long)userData;
Boolean callAttentionRoutine = False;
short unsigned attentionData;
short unsigned sequenceNumber;
AspIncomingAttentionHandler *incomingAttentionHandler;
long unsigned userDataForAttention;
/* Touch unused formal... */
bitmap, trelTimerValue;
if (errorCode is ATsocketClosed)
return; /* Session closed... */
else if (errorCode is ATatpTransactionAborted)
return; /* Somebody canceled our get request... */
else if (errorCode is ATatpResponseBufferTooSmall)
errorCode = ATnoError; /* We've got extra data, but who cares? */
else if (errorCode isnt ATnoError)
{
ErrorLog("IncomingWssTransaction", ISevError, __LINE__, UnknownPort,
IErrAspIncomingError, IMsgAspIncomingError,
Insert0());
return;
}
/* Find and verify our sessionInfo. */
DeferTimerChecking();
DeferAtpPackets();
if ((sessionInfo = FindSessionInfoFor(sessionRefNum)) is empty
or sessionInfo->closing)
{
UnlinkSessionInfo(sessionInfo);
ErrorLog("IncomingWssTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspSessionInfoMissing, IMsgAspSessionInfoMissing,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
if (sessionInfo->serverSession or
(unsigned char)userBytes[AspSessionIdOffset] isnt sessionInfo->sessionId)
{
UnlinkSessionInfo(sessionInfo);
ErrorLog("IncomingWssTransaction", ISevError, __LINE__, UnknownPort,
IErrAspBadError, IMsgAspBadError,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
/* Okay, handle the command. */
sessionInfo->lastContactTime = CurrentRelativeTime();
switch(userBytes[AspCommandTypeOffset])
{
case AspTickleCommand:
#if VerboseMessages
printf("Tickle WSS (%d); sesRefNum = %d, sessionId = %d.\n",
sessionInfo->ourSocket,
sessionInfo->sessionRefNum,
sessionInfo->sessionId);
#endif
break;
case AspCloseSessionCommand:
/* Send CloseSession reply & close the session. */
AtpPostResponse(sessionInfo->ourSocket, source, transactionId,
empty, 0, empty, exactlyOnce, empty,
(long unsigned)0);
AspCloseSession(sessionRefNum, Empty, (long unsigned)0, True);
break;
case AspAttentionCommand:
TakeLock(AspLock);
if (sessionInfo->incomingAttentionHandler isnt empty)
{
callAttentionRoutine = True;
incomingAttentionHandler = sessionInfo->incomingAttentionHandler;
userDataForAttention = sessionInfo->userDataForAttention;
attentionData =
(short unsigned)((userBytes[AspAttentionWordOffset] << 8) +
(unsigned char)userBytes[AspAttentionWordOffset + 1]);
}
ReleaseLock(AspLock);
/* Send AttentionReply */
AtpPostResponse(sessionInfo->ourSocket, source, transactionId,
empty, 0, empty, exactlyOnce, empty,
(long unsigned)0);
break;
case AspWriteDataCommand:
/* Try to find a matching write command. */
TakeLock(AspLock);
sequenceNumber =
(short unsigned)((userBytes[AspSequenceNumberOffset] << 8) +
(unsigned char)userBytes[AspSequenceNumberOffset + 1]);
for (writeInfo = sessionInfo->writeOrCommandInfoList;
writeInfo isnt empty;
writeInfo = writeInfo->next)
if (writeInfo->sequenceNumber is sequenceNumber)
break;
if (writeInfo is empty)
{
ReleaseLock(AspLock);
break; /* No luck, ignore the request. */
}
if (not writeInfo->writeCommand)
{
ReleaseLock(AspLock);
ErrorLog("IncomingWssTransaction", ISevWarning, __LINE__,
UnknownPort, IErrAspNotWriteCommand, IMsgAspNotWriteCommand,
Insert0());
break;
}
/* How much data can the server take? */
if (bufferSize < AspWriteDataSize)
{
ReleaseLock(AspLock);
ErrorLog("IncomingWssTransaction", ISevWarning, __LINE__,
UnknownPort, IErrAspBadWritePacket, IMsgAspBadWritePacket,
Insert0());
break;
}
writeSize = (((unsigned char *)buffer)[0] << 8) +
((unsigned char *)buffer)[1];
writeInfo->acceptedBytes = writeSize;
if (writeSize > writeInfo->writeBufferSize)
writeSize = writeInfo->writeBufferSize;
/* Post the response... */
writeInfo->writeReplyPosted = True;
ReleaseLock(AspLock);
AtpPostResponse(sessionInfo->ourSocket, source, transactionId,
writeInfo->writeOpaqueBuffer, writeSize,
empty, exactlyOnce, empty, (long unsigned)0);
break;
default:
ErrorLog("IncomingWssTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspFunnyCommand, IMsgAspFunnyCommand,
Insert0());
break;
}
/* Re-enqueue the requestHandler. */
if (AtpEnqueueRequestHandler(&id, sessionInfo->ourSocket,
Empty, 0, Empty,
IncomingWssTransaction,
(long unsigned)sessionRefNum) isnt ATnoError)
ErrorLog("IncomingWssTransaction", ISevError, __LINE__, UnknownPort,
IErrAspCouldNotEnqueue, IMsgAspCouldNotEnqueue,
Insert0());
/* Call attention handler, if needed. */
if (callAttentionRoutine)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
(*incomingAttentionHandler)(ATnoError, userDataForAttention,
sessionInfo->sessionRefNum,
attentionData);
}
else
{
HandleAtpPackets();
HandleDeferredTimerChecks();
}
UnlinkSessionInfo(sessionInfo);
return;
} /* IncomingWssTransaction */
ExternForVisibleFunction SessionInfo
FindSessionInfoForSocket(long socket,
unsigned char sessionId)
{
long index;
SessionRefNumMap sessionRefNumMap;
SessionInfo sessionInfo;
long sessionRefNum;
/* First, given the socket and the session ID of an ASP session, we
need to find the session reference number. */
DeferTimerChecking();
DeferAtpPackets();
TakeLock(AspLock);
CheckMod(index, (((socket & 0xFFFF) << 8) + sessionId),
NumberOfSessionRefNumBuckets, "FindSessionInfoForSocket");
for (sessionRefNumMap = sessionRefNumMapHashBuckets[index];
sessionRefNumMap isnt empty;
sessionRefNumMap = sessionRefNumMap->next)
if (socket is sessionRefNumMap->socket and
sessionId is sessionRefNumMap->sessionId)
break;
if (sessionRefNumMap is empty)
{
ReleaseLock(AspLock);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(empty);
}
/* Okay, now we have the session reference number... find the correct
session info node. */
sessionRefNum = sessionRefNumMap->sessionRefNum;
ReleaseLock(AspLock);
sessionInfo = FindSessionInfoFor(sessionRefNum);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(sessionInfo);
} /* FindSessionInfoForSocket */
ExternForVisibleFunction AppleTalkErrorCode SendAspErrorReturn(
long sourceSocket,
AppleTalkAddress destination,
short unsigned transactionId,
Boolean exactlyOnce,
int errorCode)
{
char userBytes[AtpUserBytesSize];
userBytes[AspSssNumberOffset] = 0;
userBytes[AspSessionIdOffset] = 0;
userBytes[AspErrorCodeOffset] = (char)((unsigned short)errorCode >> 8);
userBytes[AspErrorCodeOffset + 1] = (char)(errorCode & 0xFF);
return(AtpPostResponse(sourceSocket, destination, transactionId, empty, 0,
userBytes, exactlyOnce, empty,
(long unsigned)0));
} /* SendAspErrorReturn */
ExternForVisibleFunction void DecrementSocketUsage(
SessionListenerInfo sessionListenerInfo,
long socket)
{
SocketInfo socketInfo, previousSocketInfo;
/* Walk a socket list looking for a given socket, if found decrement its
usage count; if zero, free the node. */
DeferAtpPackets();
DeferTimerChecking();
TakeLock(AspLock);
for (socketInfo = sessionListenerInfo->socketList,
previousSocketInfo = empty;
socketInfo isnt empty;
previousSocketInfo = socketInfo,
socketInfo = socketInfo->next)
if (socketInfo->socket is socket)
break;
if (socketInfo is empty)
{
ReleaseLock(AspLock);
ErrorLog("DecrementSocketUsage", ISevError, __LINE__, UnknownPort,
IErrAspSocketNotFound, IMsgAspSocketNotFound,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
socketInfo->activeSessions -= 1;
if (socketInfo->activeSessions < 0)
{
ErrorLog("DecrementSocketUsage", ISevError, __LINE__, UnknownPort,
IErrAspBadUsageCount, IMsgAspBadUsageCount,
Insert0());
socketInfo->activeSessions = 0;
}
if (socketInfo->activeSessions is 0)
{
if (previousSocketInfo is empty)
sessionListenerInfo->socketList = socketInfo->next;
else
previousSocketInfo->next = socketInfo->next;
ReleaseLock(AspLock);
AtpCloseSocketOnNode(socketInfo->socket, Empty, (long unsigned)0);
Free(socketInfo);
}
else
ReleaseLock(AspLock);
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
} /* DecrementSocketUsage */
ExternForVisibleFunction AppleTalkErrorCode InitializeAsp(void)
{
/* Start the session maintenance timer... */
TakeLock(AspLock);
if (sessionMaintenanceTimerStarted)
{
ReleaseLock(AspLock);
return(ATnoError);
}
sessionMaintenanceTimerStarted = True;
ReleaseLock(AspLock);
StartTimer(SessionMaintenanceTimerExpired, AspSessionMaintenanceSeconds,
0, empty);
return(ATnoError);
} /* InitializeAsp */
ExternForVisibleFunction void far
SessionMaintenanceTimerExpired(long unsigned timerId,
int dataSize,
char far *incomingAdditionalData)
{
SessionInfo sessionInfo, nextSessionInfo;
int index;
long unsigned now = CurrentRelativeTime();
/* Touch unused formals... */
timerId, dataSize, incomingAdditionalData;
/* Walk through all of the active session to see if any have died.
"Bring out your dead..." */
DeferAtpPackets();
for (index = 0; index < NumberOfAspSessionHashBuckets; index += 1)
{
TakeLock(AspLock);
sessionInfo = Link(sessionInfoHashBuckets[index]);
ReleaseLock(AspLock);
while (sessionInfo isnt empty)
{
nextSessionInfo = sessionInfo->next;
#if VerboseMessages
printf("SesRefNum = %d; Now = %u; LastContactTime = %u.\n",
sessionInfo->sessionRefNum, now,
sessionInfo->lastContactTime);
#endif
if (sessionInfo->lastContactTime + AspSessionMaintenanceSeconds < now)
{
if (AspCloseSession(sessionInfo->sessionRefNum, Empty,
(long unsigned)0, False) isnt
ATnoError)
ErrorLog("SessionMaintenanceTimerExpired", ISevError,
__LINE__, UnknownPort, IErrAspCouldNotCloseSess,
IMsgAspCouldNotCloseSess, Insert0());
#if VerboseMessages
printf("Session maintenance; closing sessionRefNum = %d.\n",
sessionInfo->sessionRefNum);
#endif
}
else
/* "I'm not dead yet..." */ ;
/* Move to next sesion on list. */
TakeLock(AspLock);
nextSessionInfo = Link(sessionInfo->next);
ReleaseLock(AspLock);
UnlinkSessionInfo(sessionInfo);
sessionInfo = nextSessionInfo;
}
}
/* Restart the timer and exit. */
StartTimer(SessionMaintenanceTimerExpired, AspSessionMaintenanceSeconds,
0, empty);
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
} /* SessionMaintenanceTimerExpired */
ExternForVisibleFunction SessionInfo FindSessionInfoFor(long sessionRefNum)
{
SessionInfo sessionInfo;
long index;
/* Given a session ref num, return its session info structure. */
DeferTimerChecking();
DeferAtpPackets();
CheckMod(index, sessionRefNum, NumberOfAspSessionHashBuckets,
"FindSessionInfoFor");
TakeLock(AspLock);
for (sessionInfo = sessionInfoHashBuckets[index];
sessionInfo isnt empty;
sessionInfo = sessionInfo->next)
if (sessionInfo->sessionRefNum is sessionRefNum)
break;
if (sessionInfo isnt Empty)
Link(sessionInfo);
ReleaseLock(AspLock);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(sessionInfo);
} /* FindSessionInfoFor */
ExternForVisibleFunction void far
IncomingRelease(AppleTalkErrorCode errorCode,
long unsigned incomingUserData,
AppleTalkAddress source,
short unsigned transactionId)
{
CompletionInfo completionInfo = (CompletionInfo)incomingUserData;
AspReplyCompleteHandler *completionRoutine;
long unsigned userData;
long sessionRefNum;
long getRequestRefNum;
SessionInfo sessionInfo;
/* Touch unused formals... */
source, transactionId;
completionRoutine =
(AspReplyCompleteHandler *)completionInfo->completionRoutine;
/* We have a completion routine to call, pull out the data, free the info
node, call the completion routine. */
userData = completionInfo->userData;
sessionRefNum = completionInfo->sessionRefNum;
getRequestRefNum = completionInfo->getRequestRefNum;
Free(completionInfo);
sessionInfo = FindSessionInfoFor(sessionRefNum);
UnlinkSessionInfo(sessionInfo); /* Undo the link surrounding the
Atp transaction */
if (completionRoutine isnt Empty)
(*completionRoutine)(errorCode, userData, sessionRefNum,
getRequestRefNum);
UnlinkSessionInfo(sessionInfo); /* The implied Link, above. */
return;
} /* IncomingRelease */
ExternForVisibleFunction void far
IncomingWriteContinueResponse(AppleTalkErrorCode errorCode,
long unsigned incomingUserData,
AppleTalkAddress source,
void far *opaqueResponseBuffer,
int responseBufferSize,
char far *responseUserBytes,
short unsigned transactionId)
{
CompletionInfo completionInfo = (CompletionInfo)incomingUserData;
AspIncomingWriteDataHandler *completionRoutine;
long unsigned userData;
long sessionRefNum;
long getRequestRefNum;
SessionInfo sessionInfo;
/* Touch unused formals... */
source, transactionId, responseUserBytes;
completionRoutine =
(AspIncomingWriteDataHandler *)completionInfo->completionRoutine;
userData = completionInfo->userData;
sessionRefNum = completionInfo->sessionRefNum;
getRequestRefNum = completionInfo->getRequestRefNum;
Free(completionInfo);
sessionInfo = FindSessionInfoFor(sessionRefNum);
UnlinkSessionInfo(sessionInfo); /* Undo the link surrounding the
Atp transaction */
(*completionRoutine)(errorCode, userData, sessionRefNum, getRequestRefNum,
opaqueResponseBuffer, responseBufferSize);
UnlinkSessionInfo(sessionInfo); /* The implied Link, above. */
return;
} /* IncomingWriteContinueResponse */
ExternForVisibleFunction void far
IncomingGetStatusResponse(AppleTalkErrorCode errorCode,
long unsigned incomingUserData,
AppleTalkAddress source,
void far *opaqueResponseBuffer,
int responseBufferSize,
char far *responseUserBytes,
short unsigned transactionId)
{
CompletionInfo completionInfo = (CompletionInfo)incomingUserData;
AspIncomingStatusHandler *completionRoutine;
long unsigned userData;
/* Touch unused formals... */
source, transactionId, responseUserBytes;
completionRoutine =
(AspIncomingStatusHandler *)completionInfo->completionRoutine;
userData = completionInfo->userData;
Free(completionInfo);
(*completionRoutine)(errorCode, userData, opaqueResponseBuffer,
responseBufferSize);
return;
} /* IncomingGetStatusResponse */
ExternForVisibleFunction void far
IncomingOpenSessionResponse(AppleTalkErrorCode errorCode,
long unsigned incomingUserData,
AppleTalkAddress source,
void far *responseBuffer,
/* Really "char *." */
int responseBufferSize,
char far *responseUserBytes,
short unsigned transactionId)
{
CompletionInfo completionInfo = (CompletionInfo)incomingUserData;
AspIncomingOpenReplyHandler *completionRoutine;
long unsigned userData;
long sessionRefNum;
SessionInfo sessionInfo;
char tickleUserBytes[AtpUserBytesSize];
long id;
/* Touch unused formals... */
responseBuffer, responseBufferSize, transactionId;
/* Extract our completion information. */
completionRoutine =
(AspIncomingOpenReplyHandler *)completionInfo->completionRoutine;
userData = completionInfo->userData;
sessionRefNum = completionInfo->sessionRefNum;
Free(completionInfo);
/* See if we can find the sessionInfo, and make sure it's in a state that
we like (California, no doubt). */
DeferTimerChecking();
DeferAtpPackets();
if ((sessionInfo = FindSessionInfoFor(sessionRefNum)) is empty or
sessionInfo->closing)
{
UnlinkSessionInfo(sessionInfo);
ErrorLog("IncomingOpenSessionResponse", ISevWarning, __LINE__, UnknownPort,
IErrAspSessionInfoMissing, IMsgAspSessionInfoMissing,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATaspCouldNotOpenSession, userData, (long)0);
return;
}
if (sessionInfo->serverSession or not sessionInfo->waitingForOpenReply)
{
UnlinkSessionInfo(sessionInfo);
ErrorLog("IncomingOpenSessionResponse", ISevError, __LINE__, UnknownPort,
IErrAspSessionInfoBad, IMsgAspSessionInfoBad,
Insert0());
AspCloseSession(sessionRefNum, Empty, (long unsigned)0, False);
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATaspCouldNotOpenSession, userData, (long)0);
return;
}
/* Okay, all set check error codes. */
if (errorCode is ATnoError)
errorCode = (responseUserBytes[AspErrorCodeOffset] << 8) +
(unsigned char)(responseUserBytes[AspErrorCodeOffset + 1]);
if (errorCode isnt ATnoError)
{
UnlinkSessionInfo(sessionInfo);
AspCloseSession(sessionRefNum, Empty, (long unsigned)0, False);
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(errorCode, userData, (long)0);
return;
}
/* Okay fill in some more of the session info. */
sessionInfo->theirAddress = source;
sessionInfo->theirAddress.socketNumber =
responseUserBytes[AspSssNumberOffset];
sessionInfo->sessionId = (unsigned char)responseUserBytes[AspSessionIdOffset];
sessionInfo->lastContactTime = CurrentRelativeTime();
sessionInfo->waitingForOpenReply = False;
/* Well, all looks pretty good so far, start to tickle the SLS on the
other side of this session. */
tickleUserBytes[AspCommandTypeOffset] = AspTickleCommand;
tickleUserBytes[AspSessionIdOffset] = sessionInfo->sessionId;
tickleUserBytes[AspErrorCodeOffset] = 0;
tickleUserBytes[AspErrorCodeOffset+ 1] = 0;
errorCode = AtpPostRequest(sessionInfo->ourSocket,
sessionInfo->slsAddress,
Empty,
empty, 0, tickleUserBytes, False,
empty, 0, empty, AtpInfiniteRetries,
AspTickleSeconds,
ThirtySecondsTRelTimer,
empty, (long unsigned)0);
if (errorCode isnt ATnoError)
{
UnlinkSessionInfo(sessionInfo);
AspCloseSession(sessionRefNum, Empty, (long unsigned)0, False);
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(errorCode, userData, (long)0);
return;
}
/* Okay, enqueue a ReqeustHandler on the WSS. */
if ((errorCode = AtpEnqueueRequestHandler(&id, sessionInfo->ourSocket,
Empty, 0, Empty,
IncomingWssTransaction,
(long unsigned)sessionRefNum))
isnt ATnoError)
{
UnlinkSessionInfo(sessionInfo);
AspCloseSession(sessionRefNum, Empty, (long unsigned)0, False);
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(errorCode, userData, (long)0);
return;
}
/* Okay, the workstation session is now in full operation. */
UnlinkSessionInfo(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATnoError, userData, sessionRefNum);
return;
} /* IncomingOpenSessionResponse */
ExternForVisibleFunction void far
IncomingWriteOrCommandComplete(AppleTalkErrorCode errorCode,
long unsigned incomingUserData,
AppleTalkAddress source,
void far *opaqueResponseBuffer,
int responseBufferSize,
char far *responseUserBytes,
short unsigned transactionId)
{
StaticForSmallStack SessionInfo sessionInfo;
StaticForSmallStack WriteOrCommandInfo writeOrCommandInfo, previousWriteOrCommandInfo;
CompletionInfo completionInfo = (CompletionInfo)incomingUserData;
AspWriteOrCommCompleteHandler *completionRoutine;
long unsigned userData;
long sessionRefNum;
short unsigned sequenceNumber;
int acceptedBytes = 0;
/* Touch unused formals... */
source, transactionId;
/* Extract our completion information. */
completionRoutine =
(AspWriteOrCommCompleteHandler *)completionInfo->completionRoutine;
userData = completionInfo->userData;
sessionRefNum = completionInfo->sessionRefNum;
sequenceNumber = completionInfo->sequenceNumber;
Free(completionInfo);
if (errorCode is ATatpResponseBufferTooSmall)
errorCode = ATaspSizeError;
/* Find our corresponding sessionInfo and write or command info. */
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty or (errorCode isnt ATnoError and
errorCode isnt ATaspSizeError and
errorCode isnt ATatpTransactionAborted))
{
UnlinkSessionInfo(sessionInfo); /* Possible above Link. */
UnlinkSessionInfo(sessionInfo); /* Possible Atp transaction Link. */
if (errorCode isnt ATatpTransactionAborted)
ErrorLog("IncomingWriteOrCommandComplete", ISevWarning, __LINE__,
UnknownPort, IErrAspSessionInfoMissing,
IMsgAspSessionInfoMissing, Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
if (errorCode isnt ATatpTransactionAborted)
errorCode = ATaspCouldNotPostRequest;
(*completionRoutine)(errorCode, userData, sessionRefNum,
empty, empty, 0, 0);
return;
}
UnlinkSessionInfo(sessionInfo); /* Undo the link surrounding the
Atp transaction */
TakeLock(AspLock);
for (writeOrCommandInfo = sessionInfo->writeOrCommandInfoList,
previousWriteOrCommandInfo = empty;
writeOrCommandInfo isnt empty;
previousWriteOrCommandInfo = writeOrCommandInfo,
writeOrCommandInfo = writeOrCommandInfo->next)
if (writeOrCommandInfo->sequenceNumber is sequenceNumber)
break;
if (writeOrCommandInfo is empty)
{
ReleaseLock(AspLock);
UnlinkSessionInfo(sessionInfo);
ErrorLog("IncomingWriteOrCommandComplete", ISevWarning, __LINE__,
UnknownPort, IErrAspCommandInfoMissing, IMsgAspCommandInfoMissing,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATaspCouldNotPostRequest, userData, sessionRefNum,
empty, empty, 0, 0);
return;
}
/* Un-thread the write or command info... */
if (previousWriteOrCommandInfo is empty)
sessionInfo->writeOrCommandInfoList = writeOrCommandInfo->next;
else
previousWriteOrCommandInfo->next = writeOrCommandInfo->next;
ReleaseLock(AspLock);
/* Okay, call the completion routine... */
if (writeOrCommandInfo->writeCommand)
{
if (writeOrCommandInfo->writeReplyPosted and
writeOrCommandInfo->acceptedBytes <
writeOrCommandInfo->writeBufferSize)
errorCode = ATaspSizeError;
acceptedBytes = writeOrCommandInfo->acceptedBytes;
}
Free(writeOrCommandInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(errorCode, userData, sessionRefNum, responseUserBytes,
opaqueResponseBuffer, responseBufferSize, acceptedBytes);
UnlinkSessionInfo(sessionInfo);
return;
} /* IncomingWriteOrCommandComplete */
ExternForVisibleFunction long GetNextSessionRefNum(void)
{
Boolean inUse, wrapped = False;
int index;
SessionListenerInfo sessionListenerInfo;
GetSessionHandler getSessionHandler;
SessionInfo sessionInfo;
/* Pick a new session refernence number for this guy... Why I'm
bothering to check to see if the sessionRefNum is currently in
is use is a real mystery... it won't overflow for some 500 years
at a rate of 10,000 new connections per day... */
DeferTimerChecking();
DeferAtpPackets();
inUse = True;
TakeLock(AspLock);
while(inUse)
{
inUse = False;
if ((lastSessionRefNum += 1) < 0)
{
lastSessionRefNum = 0;
if (wrapped)
{
inUse = True;
break;
}
wrapped = True;
}
/* Check the active sessions for the session refNum. */
for (index = 0;
not inUse and index < NumberOfAspSessionHashBuckets;
index += 1)
for (sessionInfo = sessionInfoHashBuckets[index];
not inUse and sessionInfo isnt empty;
sessionInfo = sessionInfo->next)
if (sessionInfo->sessionRefNum is lastSessionRefNum)
inUse = True;
/* Checking the pending GetSessions for the refNum. */
for (sessionListenerInfo = sessionListenerInfoHead;
not inUse and sessionListenerInfo isnt Empty;
sessionListenerInfo = sessionListenerInfo->next)
for (getSessionHandler = sessionListenerInfo->getSessionHandlers;
not inUse and getSessionHandler isnt Empty;
getSessionHandler = getSessionHandler->next)
if (getSessionHandler->sessionRefNum is lastSessionRefNum)
inUse = True;
}
ReleaseLock(AspLock);
HandleAtpPackets();
HandleDeferredTimerChecks();
if (inUse)
return((long)-1);
else
return(lastSessionRefNum);
} /* GetNextSessionRefNum */
ExternForVisibleFunction SessionListenerInfo
FindSessionListenerInfoFor(long sessionListenerRefNum)
{
SessionListenerInfo sessionListenerInfo;
TakeLock(AspLock);
for (sessionListenerInfo = sessionListenerInfoHead;
sessionListenerInfo isnt empty;
sessionListenerInfo = sessionListenerInfo->next)
if (sessionListenerInfo->sessionListenerRefNum is sessionListenerRefNum)
break;
if (sessionListenerInfo isnt Empty)
Link(sessionListenerInfo);
ReleaseLock(AspLock);
return(sessionListenerInfo);
} /* FindSessionListenerInfoFor */
ExternForVisibleFunction GetRequestInfo
FindGetRequestInfoFor(SessionListenerInfo sessionListenerInfo,
long getRequestRefNum)
{
long index;
GetRequestInfo getRequestInfo;
/* Look in the per-Sls hash table for the specified getRequestRefNum. */
CheckMod(index, getRequestRefNum, NumGetRequestInfoHashBuckets,
"FindGetRequestInfoFor");
TakeLock(AspLock);
for (getRequestInfo = sessionListenerInfo->getRequestInfoHashBuckets[index];
getRequestInfo isnt Empty;
getRequestInfo = getRequestInfo->nextForMySessionListener)
if (getRequestInfo->getRequestRefNum is getRequestRefNum)
{
Link(getRequestInfo);
ReleaseLock(AspLock);
return(getRequestInfo);
}
ReleaseLock(AspLock);
return(Empty);
} /* FindGetRequestInfoFor */
ExternForVisibleFunction Boolean far
UnlinkGetRequestInfo(GetRequestInfo getRequestInfo)
{
long index;
if (getRequestInfo is Empty)
return(False);
/* Are we the last referant? */
TakeLock(AspLock);
if (not UnlinkNoFree(getRequestInfo))
{
ReleaseLock(AspLock);
return(False);
}
/* Yes. A GetRequestInfo lives on two lists:
1. Either a "next" chain off a SessionInfo or a SessionListenerInfo;
mySessionInfo will be Empty in the latter case.
2. The per-Sls hash list (off the SessionListenerInfo).
Remove the passed node from both lists, and then free the node. */
if (getRequestInfo->mySessionInfo is Empty)
{
/* Remove from the "next" (GetAnyRequest) list hanging off the session
listener info structure. */
if (RemoveFromListNoUnlink(getRequestInfo->mySessionListener->
getRequestInfoList, getRequestInfo,
next) is Empty)
{
/* We should always be found... if not we have data structure corruption
problems. */
ErrorLog("UnlinkGetRequestInfo", ISevError, __LINE__, UnknownPort,
IErrAspGetRequestListBad, IMsgAspGetRequestListBad,
Insert0());
}
}
else
{
/* Remove from the "next" (GetRequest) list handing off the session
info structure. */
if (RemoveFromListNoUnlink(getRequestInfo->mySessionInfo->
getRequestInfoList, getRequestInfo,
next) is Empty)
{
/* We should always be found... if not we have data structure corruption
problems. */
ErrorLog("UnlinkGetRequestInfo", ISevError, __LINE__, UnknownPort,
IErrAspGetRequestListBad, IMsgAspGetRequestListBad,
Insert0());
}
}
/* Remove from per-Sls hash list. */
CheckMod(index, getRequestInfo->getRequestRefNum,
NumGetRequestInfoHashBuckets, "UnlinkGetRequestInfo");
if (RemoveFromListNoUnlink(getRequestInfo->mySessionListener->
getRequestInfoHashBuckets[index],
getRequestInfo, nextForMySessionListener) is
Empty)
{
/* We should always be found... if not we have data structure corruption
problems. */
ErrorLog("UnlinkGetRequestInfo", ISevError, __LINE__, UnknownPort,
IErrAspGetRequestListBad, IMsgAspGetRequestListBad,
Insert0());
}
ReleaseLock(AspLock);
/* If requested, call the completion routine. */
if (not getRequestInfo->inUse)
(*getRequestInfo->completionRoutine)(getRequestInfo->errorCode,
getRequestInfo->userData,
getRequestInfo->sessionRefNum,
getRequestInfo->usersCookie,
getRequestInfo->opaqueBuffer,
getRequestInfo->bufferSize,
getRequestInfo->requestType,
getRequestInfo->getRequestRefNum);
/* Okay, now we can undo the back links. */
if (getRequestInfo->mySessionInfo isnt Empty)
UnlinkSessionInfo(getRequestInfo->mySessionInfo);
UnlinkSessionListenerInfo(getRequestInfo->mySessionListener);
/* We're set, free the beast, and run away. */
if (getRequestInfo->freeOpaqueWriteContinueData)
FreeOpaqueDataDescriptor(getRequestInfo->opaqueWriteContinueData);
Free(getRequestInfo);
return(True);
} /* UnlinkGetRequestInfo */
ExternForVisibleFunction Boolean far
UnlinkGetSessionHandler(GetSessionHandler getSessionHandler)
{
/* Are we the last referant? */
TakeLock(AspLock);
if (not UnlinkNoFree(getSessionHandler))
{
ReleaseLock(AspLock);
return(False);
}
/* Yes, we are... remove from the list, call the completion routine, Unlink from
the session listener and free the beast. */
if (RemoveFromListNoUnlink(getSessionHandler->mySessionListenerInfo->
getSessionHandlers,
getSessionHandler, next) is Empty)
ErrorLog("UnlinkGetSessionHandler", ISevError, __LINE__, UnknownPort,
IErrAspGetSessionListBad, IMsgAspGetSessionListBad,
Insert0());
ReleaseLock(AspLock);
if (getSessionHandler->openInProgress)
(*getSessionHandler->sessionOpenHandler)(getSessionHandler->errorCode,
getSessionHandler->userData,
getSessionHandler->socket,
getSessionHandler->sessionRefNum);
UnlinkSessionListenerInfo(getSessionHandler->mySessionListenerInfo);
Free(getSessionHandler);
return(True);
} /* UnlinkGetSessionHandler */
ExternForVisibleFunction void far
UnlinkSessionListenerInfo(SessionListenerInfo sessionListenerInfo)
{
DeferredCloseNotify deferredCloseNotify, nextDeferredCloseNotify;
AppleTalkErrorCode errorCode;
if (sessionListenerInfo is Empty)
return;
/* Are we the last referant? */
TakeLock(AspLock);
if (not UnlinkNoFree(sessionListenerInfo))
{
ReleaseLock(AspLock);
return;
}
/* Remove him from our list. */
if (RemoveFromListNoUnlink(sessionListenerInfoHead, sessionListenerInfo,
next) is Empty)
{
ReleaseLock(AspLock);
ErrorLog("UnlinkSessionListenerInfo", ISevError, __LINE__, UnknownPort,
IErrAspListenerInfoMissing, IMsgAspListenerInfoMissing,
Insert0());
}
else
ReleaseLock(AspLock);
/* If we have any closes that we've deferred notification for... we're
out of luck now, so free 'em. */
for (deferredCloseNotify = sessionListenerInfo->deferredCloseNotifyList;
deferredCloseNotify isnt Empty;
deferredCloseNotify = nextDeferredCloseNotify)
{
nextDeferredCloseNotify = deferredCloseNotify->next;
Free(deferredCloseNotify);
}
/* Close the ATP socket that we're listening on. */
if (sessionListenerInfo->closeSocket)
{
if ((errorCode = AtpCloseSocketOnNode(sessionListenerInfo->ourSocket,
AspServiceListenerCloseComplete,
(long unsigned)sessionListenerInfo))
isnt ATnoError)
AspServiceListenerCloseComplete(ATnoError,
(long unsigned)sessionListenerInfo, 0);
}
else
AspServiceListenerCloseComplete(ATnoError,
(long unsigned)sessionListenerInfo, 0);
/* All set. */
return;
} /* UnlinkSessionListenerInfo */
ExternForVisibleFunction void far
AspServiceListenerCloseComplete(AppleTalkErrorCode errorCode,
long unsigned userData,
long cookie)
{
SessionListenerInfo sessionListenerInfo = (SessionListenerInfo)userData;
/* If there is a completion routine, call it. */
if (sessionListenerInfo->closeContext.closeCompletionRoutine isnt Empty)
(*(sessionListenerInfo->closeContext.closeCompletionRoutine))(
errorCode, sessionListenerInfo->closeContext.closeUserData,
sessionListenerInfo->sessionListenerRefNum);
/* Finaly, free the session listener... */
if (sessionListenerInfo->serviceStatusSize > 0)
Free(sessionListenerInfo->serviceStatus);
if (sessionListenerInfo->freeOpaqueServiceStatus)
FreeOpaqueDataDescriptor(sessionListenerInfo->opaqueServiceStatus);
Free(sessionListenerInfo);
return;
} /* AspServiceListenerCloseComplete */
ExternForVisibleFunction void far
UnlinkSessionInfo(SessionInfo sessionInfo)
{
SessionRefNumMap sessionRefNumMap, previousSessionRefNumMap;
GetRequestInfo getRequestInfo;
long index;
AppleTalkErrorCode errorCode = ATnoError;
if (sessionInfo is Empty)
return;
/* Are we the last referant. */
TakeLock(AspLock);
if (not UnlinkNoFree(sessionInfo))
{
ReleaseLock(AspLock);
return;
}
/* Yes, remove from the session ref num hash list. */
CheckMod(index, sessionInfo->sessionRefNum, NumberOfAspSessionHashBuckets,
"UnlinkSessionInfo");
if (RemoveFromListNoUnlink(sessionInfoHashBuckets[index], sessionInfo,
next) is Empty)
ErrorLog("UnlinkSessionInfo", ISevError, __LINE__, UnknownPort,
IErrAspSessionInfoMissing, IMsgAspSessionInfoMissing,
Insert0());
/* Okay, now for server sessions, we need to unthread from the session list
hanging off the SLS. */
if (sessionInfo->serverSession)
{
if (RemoveFromListNoUnlink(sessionInfo->mySessionListener->sessionList,
sessionInfo, nextForMySls) is Empty)
ErrorLog("UnlinkSessionInfo", ISevError, __LINE__, UnknownPort,
IErrAspNotOnSLSList, IMsgAspNotOnSLSList,
Insert0());
/* Remove this fellow from the SessionRefNumMap. */
CheckMod(index, (((sessionInfo->ourSocket & 0xFFFF) << 8) +
sessionInfo->sessionId), NumberOfSessionRefNumBuckets,
"UnlinkSessionInfo");
for (sessionRefNumMap = sessionRefNumMapHashBuckets[index],
previousSessionRefNumMap = empty;
sessionRefNumMap isnt empty;
previousSessionRefNumMap = sessionRefNumMap,
sessionRefNumMap = sessionRefNumMap->next)
if (sessionRefNumMap->sessionRefNum is sessionInfo->sessionRefNum)
break;
if (sessionRefNumMap is empty)
ErrorLog("UnlinkSessionInfo", ISevError, __LINE__, UnknownPort,
IErrAspRefNumMapMissing, IMsgAspRefNumMapMissing,
Insert0());
else
{
if (previousSessionRefNumMap is empty)
sessionRefNumMapHashBuckets[index] = sessionRefNumMap->next;
else
previousSessionRefNumMap->next = sessionRefNumMap->next;
Free(sessionRefNumMap);
}
/* If the session on the current sessions listener have been dealt with
via the GetAnyRequest mechanism, and we haven't been able to notify
anybody about the close (above), we need to complete a GetAnyRequest
with the news. */
if (sessionInfo->mySessionListener->getAnyRequestsSeen and
not sessionInfo->notifiedOwnerOfClose)
{
/* If there is a GetAnyRequest handler, complete it. */
if (sessionInfo->mySessionListener->getRequestInfoList isnt Empty)
{
getRequestInfo = Link(sessionInfo->mySessionListener->
getRequestInfoList);
getRequestInfo->sessionRefNum = sessionInfo->sessionRefNum;
getRequestInfo->usersCookie = sessionInfo->usersCookie;
getRequestInfo->errorCode = sessionInfo->closeCode;
ReleaseLock(AspLock);
UnlinkGetRequestInfo(getRequestInfo);
UnlinkGetRequestInfo(getRequestInfo);
}
else
{
DeferredCloseNotify deferredCloseNotify;
/* Okay, we haven't been able to notify anybody! Note the refNum
and the usersCookie in the sessionListener, we'll notify about
the close the next time a GetAnyRequest comes in. */
if ((deferredCloseNotify = Malloc(sizeof(*deferredCloseNotify))) is
Empty)
{
ReleaseLock(AspLock);
ErrorLog("UnlinkSessionInfo", ISevError, __LINE__, UnknownPort,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
}
else
{
deferredCloseNotify->closeCode = sessionInfo->closeCode;
deferredCloseNotify->sessionRefNum = sessionInfo->sessionRefNum;
deferredCloseNotify->usersCookie = sessionInfo->usersCookie;
deferredCloseNotify->next =
sessionInfo->mySessionListener->deferredCloseNotifyList;
sessionInfo->mySessionListener->deferredCloseNotifyList =
deferredCloseNotify;
ReleaseLock(AspLock);
}
}
}
else
ReleaseLock(AspLock);
/* Cancel tickling to the other end. */
if (AtpCancelRequest(sessionInfo->ourSocket,
sessionInfo->tickleTransactionId,
False) isnt ATnoError)
ErrorLog("UnlinkSessionInfo", ISevError, __LINE__, UnknownPort,
IErrAspCouldntCancelTickle, IMsgAspCouldntCancelTickle,
Insert0());
/* Also, we need to remove this guy's entry from the SLS's socket list. */
DecrementSocketUsage(sessionInfo->mySessionListener,
sessionInfo->ourSocket);
UnlinkSessionListenerInfo(sessionInfo->mySessionListener);
}
else
{
/* Okay, close the WSS. This will cancel tickling and cancel the
pending request handler. [Due to only one session per socket]. */
ReleaseLock(AspLock);
if (sessionInfo->closeOurSocket)
if (AtpCloseSocketOnNode(sessionInfo->ourSocket, Empty,
(long unsigned)0) isnt ATnoError)
ErrorLog("UnlinkSessionInfo", ISevError, __LINE__, UnknownPort,
IErrAspBadSocketClose, IMsgAspBadSocketClose,
Insert0());
/* Closing the socket should have freed the list of pending write or
commands [due to the inherent canceling of pending requests].
Check this... */
if (sessionInfo->writeOrCommandInfoList isnt empty)
{
WriteOrCommandInfo writeOrCommandInfo, nextWriteOrCommandInfo;
ErrorLog("UnlinkSessionInfo", ISevError, __LINE__, UnknownPort,
IErrAspListNotEmpty, IMsgAspListNotEmpty,
Insert0());
for (writeOrCommandInfo = sessionInfo->writeOrCommandInfoList;
writeOrCommandInfo isnt empty;
writeOrCommandInfo = nextWriteOrCommandInfo)
{
nextWriteOrCommandInfo = writeOrCommandInfo->next;
Free(writeOrCommandInfo);
}
}
}
/* If there is a close completion routine, call it before we free the
sessionInfo. */
if (sessionInfo->closeContext.closeCompletionRoutine isnt Empty)
(*(sessionInfo->closeContext.closeCompletionRoutine))(
ATnoError, sessionInfo->closeContext.closeUserData,
sessionInfo->sessionRefNum);
Free(sessionInfo);
/* All set. */
return;
} /* UnlinkSessionInfo */
ExternForVisibleFunction void far
SendStatusComplete(AppleTalkErrorCode errorCode,
long unsigned userData,
AppleTalkAddress source,
short unsigned transactionId)
{
SessionListenerInfo sessionListenerInfo = (SessionListenerInfo)userData;
char far *freeServiceStatus = Empty;
void far *freeOpaqueServiceStatus = Empty;
/* A send status is complete, we may have switch to a new status for
the session listener. */
TakeLock(AspLock);
if (sessionListenerInfo->newServiceStatusPending)
{
if (sessionListenerInfo->serviceStatusSize > 0)
freeServiceStatus = sessionListenerInfo->serviceStatus;
if (sessionListenerInfo->freeOpaqueServiceStatus)
freeOpaqueServiceStatus = sessionListenerInfo->opaqueServiceStatus;
sessionListenerInfo->serviceStatus =
sessionListenerInfo->newServiceStatus;
sessionListenerInfo->opaqueServiceStatus =
sessionListenerInfo->newOpaqueServiceStatus;
sessionListenerInfo->freeOpaqueServiceStatus =
sessionListenerInfo->newFreeOpaqueServiceStatus;
sessionListenerInfo->serviceStatusSize =
sessionListenerInfo->newServiceStatusSize;
sessionListenerInfo->newServiceStatusPending = False;
}
/* Okay, the send is now really complete. */
sessionListenerInfo->statusSendInProgress = False;
ReleaseLock(AspLock);
/* If there is an "old status" free it. */
if (freeServiceStatus isnt Empty)
Free(freeServiceStatus);
if (freeOpaqueServiceStatus isnt Empty)
FreeOpaqueDataDescriptor(freeOpaqueServiceStatus);
/* Otherwise, we're all set, remove our link to the session listener. */
UnlinkSessionListenerInfo(sessionListenerInfo);
return;
} /* SendStatusComplete */
#if Verbose or (Iam a Primos)
void DumpAspInfo(void)
{
SessionListenerInfo sessionListenerInfo;
GetSessionHandler getSessionHandler;
SocketInfo socketInfo;
SessionInfo sessionInfo;
WriteOrCommandInfo writeOrCommandInfo;
GetRequestInfo getRequestInfo;
short numberOfSessionListeners = 0;
short numberOfGetSessions = 0;
short numberOfServerSessions = 0;
short numberOfServerSockets = 0;
short numberOfWorkstationSessions = 0;
short numberOfGetRequests = 0;
short numberOfGetAnyRequests = 0;
short numberOfCommands = 0;
short numberOfWrites = 0;
short numberOfWriteContinues = 0;
short serverSessionsForThisSls, count, totalSessions, index;
/* Verify structures and count interesting information [I'm sure somebody
will be interested]. */
DeferTimerChecking();
DeferAtpPackets();
/* Walk our list of session listeners. */
for (sessionListenerInfo = sessionListenerInfoHead;
sessionListenerInfo isnt empty;
sessionListenerInfo = sessionListenerInfo->next)
{
numberOfSessionListeners += 1;
/* Count the number of GetSession handlers pending on this session
listener. */
for (getSessionHandler = sessionListenerInfo->getSessionHandlers;
getSessionHandler isnt empty;
getSessionHandler = getSessionHandler->next)
numberOfGetSessions += 1;
/* Walk the socket list and count the number of sockets and sessions. */
serverSessionsForThisSls = 0;
for (socketInfo = sessionListenerInfo->socketList;
socketInfo isnt empty;
socketInfo = socketInfo->next)
{
numberOfServerSockets += 1;
numberOfServerSessions += socketInfo->activeSessions;
serverSessionsForThisSls += socketInfo->activeSessions;
}
/* Count the GetAnyRequests. */
for (getRequestInfo = sessionListenerInfo->getRequestInfoList;
getRequestInfo isnt empty;
getRequestInfo = getRequestInfo->next)
numberOfGetAnyRequests += 1;
/* Walk the sessionInfos hanging off this session listener. */
count = 0;
for (sessionInfo = sessionListenerInfo->sessionList;
sessionInfo isnt empty;
sessionInfo = sessionInfo->nextForMySls)
{
count += 1;
if (not sessionInfo->serverSession)
printf("Workstation session hanging off SLS list!\n");
/* For a server, there should be no WriteOrCommands... */
if (sessionInfo->writeOrCommandInfoList isnt empty)
printf("WriteOrCommands hanging off server session!\n");
/* Walk get request list. */
for (getRequestInfo = sessionInfo->getRequestInfoList;
getRequestInfo isnt empty;
getRequestInfo = getRequestInfo->next)
numberOfGetRequests += 1;
}
if (count isnt serverSessionsForThisSls)
printf("Consistency error. Server session count mismatch.\n");
}
/* Okay, now lets get another look at the same picture. Walk the session
hash table. */
totalSessions = 0;
for (index = 0; index < NumberOfAspSessionHashBuckets; index += 1)
for (sessionInfo = sessionInfoHashBuckets[index];
sessionInfo isnt empty;
sessionInfo = sessionInfo->next)
{
totalSessions += 1;
if (sessionInfo->serverSession)
continue;
numberOfWorkstationSessions += 1;
if (sessionInfo->getRequestInfoList isnt Empty)
printf("GetRequests hanging off workstation session!\n");
/* Walk pending writeOrCommand list. */
for (writeOrCommandInfo = sessionInfo->writeOrCommandInfoList;
writeOrCommandInfo isnt empty;
writeOrCommandInfo = writeOrCommandInfo->next)
{
if (writeOrCommandInfo->writeCommand)
numberOfWrites += 1;
else
numberOfCommands += 1;
if (writeOrCommandInfo->writeReplyPosted)
numberOfWriteContinues += 1;
}
}
if (totalSessions isnt (numberOfServerSessions + numberOfWorkstationSessions))
printf("Total sessions mismatch!.\n");
/* Print the report. */
printf("\n");
printf("%.3d session lisenters are currently active.\n",
numberOfSessionListeners);
printf("%.3d get session handlers are pending on the SLSs.\n",
numberOfGetSessions);
printf("%.3d server sessions are active on %.3d ATP sockets.\n",
numberOfServerSessions, numberOfServerSockets);
printf("%.3d get any request handlers are pending on the session listeners.\n",
numberOfGetAnyRequests);
printf("%.3d get request handlers are pending on the server sessions.\n",
numberOfGetRequests);
printf("%.3d workstations sessions are active.\n",
numberOfWorkstationSessions);
printf("%.3d commands and %.3d writes are pending on the workstation sessions.\n",
numberOfCommands, numberOfWrites);
printf("%.3d of the writes are processing write replies.\n",
numberOfWriteContinues);
printf("\n");
/* All set! */
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
} /* DumpAspInfo */
#endif