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.
 
 
 
 
 
 

3869 lines
119 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
asp.c
Abstract:
This module contains the ASP protocol code.
Author:
Garth Conboy Initial Coding
Nikhil Kamkolkar Rewritten for microsoft coding style. mpized
Revision History:
--*/
#define IncludeAspErrors 1
#include "atalk.h"
#define VerboseMessages 0
ExternForVisibleFunction
AtpIncomingRequestHandler IncomingSlsTransaction;
ExternForVisibleFunction
AtpIncomingRequestHandler IncomingSssTransaction;
ExternForVisibleFunction
AtpIncomingRequestHandler IncomingWssTransaction;
ExternForVisibleFunction
AtpIncomingReleaseHandler IncomingRelease;
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
void
RemoveGetRequestInfo(GetRequestInfo targetGetRequestInfo);
ExternForVisibleFunction
void
FreeGetRequestInfo(GetRequestInfo targetGetRequestInfo);
// GLOBALS
static Boolean sessionMaintenanceTimerStarted = False;
static char getStatusResponseUserBytes[AtpUserBytesSize]; // Read only
void ShutdownAsp(void)
{
sessionMaintenanceTimerStarted = False;
return;
} // ShutdownAsp
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. This socket will be
// closed when the session listener is deleted, or
// if any errors occur while creating the 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;
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;
//
// 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;
while(not okay) {
okay = True;
if ((lastSessionListenerRefNum += 1) < 0) {
lastSessionListenerRefNum = 0;
if (wrapped) {
HandleAtpPackets();
HandleDeferredTimerChecks();
ErrorLog("AspCreateSessionListenerOnNode", ISevError, __LINE__, port,
IErrAspBadError, IMsgAspBadError,
Insert0());
if (existingAtpSocket < 0)
AtpCloseSocketOnNode(tempSocket);
return(ATinternalError);
}
wrapped = True;
}
for (sessionListenerInfo = sessionListenerInfoHead;
okay and sessionListenerInfo isnt empty;
sessionListenerInfo = sessionListenerInfo->next)
if (sessionListenerInfo->sessionListenerRefNum is
lastSessionListenerRefNum)
okay = False;
}
// 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);
return(AToutOfMemory);
}
sessionListenerInfo->sessionListenerRefNum = lastSessionListenerRefNum;
sessionListenerInfo->ourSocket = tempSocket;
sessionListenerInfo->closeSocket = (existingAtpSocket < 0);
sessionListenerInfo->port = port;
sessionListenerInfo->next = sessionListenerInfoHead;
sessionListenerInfoHead = sessionListenerInfo;
//
// 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);
return(errorCode);
}
// Set the refNum that we've used, and run away.
*sessionListenerRefNum = lastSessionListenerRefNum;
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} // AspCreateSessionListener
AppleTalkErrorCode far AspDeleteSessionListener(
long sessionListenerRefNum) // Who to delete.
{
SessionListenerInfo sessionListenerInfo, previousSessionListenerInfo;
AppleTalkErrorCode errorCode;
SessionInfo sessionInfo, nextSessionInfo;
GetSessionHandler getSessionHandler, nextGetSessionHandler;
GetRequestInfo getRequestInfo, nextGetRequestInfo;
DeferredCloseNotify deferredCloseNotify, nextDeferredCloseNotify;
// Find our target.
DeferTimerChecking();
DeferAtpPackets();
for (previousSessionListenerInfo = empty,
sessionListenerInfo = sessionListenerInfoHead;
sessionListenerInfo isnt empty;
previousSessionListenerInfo = sessionListenerInfo,
sessionListenerInfo = sessionListenerInfo->next)
if (sessionListenerInfo->sessionListenerRefNum is sessionListenerRefNum)
break;
if (sessionListenerInfo is empty) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
// Close the ATP socket that we're listening on.
if (not sessionListenerInfo->closeSocket)
errorCode = ATnoError; // Close not requested.
else
errorCode = AtpCloseSocketOnNode(sessionListenerInfo->ourSocket);
// Should also close all SSSs opened to this SLS.
for (sessionInfo = sessionListenerInfo->sessionList;
sessionInfo isnt empty;
sessionInfo = nextSessionInfo) {
nextSessionInfo = sessionInfo->nextForMySls;
AspCloseSession(sessionInfo->sessionRefNum, False);
}
// Remove him from our list.
if (previousSessionListenerInfo is empty)
sessionListenerInfoHead = sessionListenerInfo->next;
else
previousSessionListenerInfo->next = sessionListenerInfo->next;
// Free any getSession handlers.
for (getSessionHandler = sessionListenerInfo->getSessionHandlers;
getSessionHandler isnt empty;
getSessionHandler = nextGetSessionHandler) {
nextGetSessionHandler = getSessionHandler->next;
(*getSessionHandler->sessionOpenHandler)(ATaspSessionListenerDeleted,
getSessionHandler->userData,
(long)0, (long)0);
Free(getSessionHandler);
}
// Terminate and free any pending GetAnyRequests.
for (getRequestInfo = sessionListenerInfo->getRequestInfoList;
getRequestInfo isnt empty;
getRequestInfo = nextGetRequestInfo) {
nextGetRequestInfo = getRequestInfo->next;
RemoveGetRequestInfo(getRequestInfo);
if (not getRequestInfo->inUse)
(*getRequestInfo->completionRoutine)(ATaspSessionListenerDeleted,
getRequestInfo->userData,
(long)0, (long)0, empty, 0, 0,
getRequestInfo->
getRequestRefNum);
FreeGetRequestInfo(getRequestInfo);
}
//
// 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);
}
// Finaly, free the session listener...
if (sessionListenerInfo->serviceStatusSize > 0)
Free(sessionListenerInfo->serviceStatus);
if (sessionListenerInfo->freeOpaqueServiceStatus)
FreeOpaqueDataDescriptor(sessionListenerInfo->opaqueServiceStatus);
Free(sessionListenerInfo);
// All set!
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
} // AspDeleteSessionListener
AppleTalkErrorCode far AspSetStatus(
long sessionListenerRefNum, // What session listener?
void far *serviceStatusOpaque, // New server status "buffer"
int serviceStatusSize) // Size of block
{
SessionListenerInfo sessionListenerInfo;
if (serviceStatusSize > AtpMaximumTotalResponseSize)
return(ATaspStatusBufferTooBig);
// Okay, find the session listener...
DeferTimerChecking();
DeferAtpPackets();
for (sessionListenerInfo = sessionListenerInfoHead;
sessionListenerInfo isnt empty;
sessionListenerInfo = sessionListenerInfo->next)
if (sessionListenerInfo->sessionListenerRefNum is sessionListenerRefNum)
break;
if (sessionListenerInfo is empty) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
// Okay, we're set to replace the current status buffer...
if (sessionListenerInfo->serviceStatusSize > 0)
Free(sessionListenerInfo->serviceStatus);
if (sessionListenerInfo->freeOpaqueServiceStatus)
FreeOpaqueDataDescriptor(sessionListenerInfo->opaqueServiceStatus);
sessionListenerInfo->freeOpaqueServiceStatus = False;
if (serviceStatusSize > 0) {
sessionListenerInfo->serviceStatus = (char *)Malloc(serviceStatusSize);
if (sessionListenerInfo->serviceStatus is empty) {
ErrorLog("AspSetStatus", ISevError, __LINE__, UnknownPort,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
sessionListenerInfo->serviceStatusSize = 0;
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotSetStatus);
}
MoveFromOpaque(sessionListenerInfo->serviceStatus, serviceStatusOpaque, 0,
serviceStatusSize);
//
// Make a system dependent "opaque data descriptor" for our copy so
// that it will be usefull to pass to Atp.
//
if ((sessionListenerInfo->opaqueServiceStatus =
MakeOpaqueDataDescriptor(sessionListenerInfo->serviceStatus,
serviceStatusSize,
&sessionListenerInfo->
freeOpaqueServiceStatus)) is Empty) {
ErrorLog("AspSetStatus", ISevError, __LINE__, UnknownPort,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
Free(sessionListenerInfo->serviceStatus);
sessionListenerInfo->serviceStatusSize = 0;
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotSetStatus);
}
}
sessionListenerInfo->serviceStatusSize = (short)serviceStatusSize;
// All set!
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,
AtpGetNextTransactionId(ourSocket),
empty, 0, userBytes, True,
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) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
// Okay, build up and enqueue a new GetSession structure.
getSessionHandler = (GetSessionHandler)Calloc(sizeof(*getSessionHandler), 1);
if (getSessionHandler is empty) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotEnqueueHandler);
}
getSessionHandler->refNum = UniqueNumber();
getSessionHandler->privateSocket = privateSocket;
getSessionHandler->userData = userData;
getSessionHandler->sessionOpenHandler = completionRoutine;
getSessionHandler->next = sessionListenerInfo->getSessionHandlers;
sessionListenerInfo->getSessionHandlers = getSessionHandler;
// All set!
*getSessionRefNum = getSessionHandler->refNum;
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) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSessionListener);
}
// Okay, find the GetSession.
for (getSessionHandler = sessionListenerInfo->getSessionHandlers;
getSessionHandler isnt Empty;
previousGetSessionHandler = getSessionHandler,
getSessionHandler = getSessionHandler->next)
if (getSessionHandler->refNum is getSessionRefNum)
break;
if (getSessionHandler is Empty) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchGetSession);
}
//
// Okay, we've found the target GetSession handler, remove him from the
// list.
//
if (previousGetSessionHandler is Empty)
sessionListenerInfo->getSessionHandlers = getSessionHandler->next;
else
previousGetSessionHandler->next = getSessionHandler->next;
Free(getSessionHandler);
// All set!
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);
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);
return(ATaspCouldNotOpenSession);
}
sessionInfo = (SessionInfo)Calloc(sizeof(*sessionInfo), 1);
if (sessionInfo is empty) {
if (existingAtpSocket < 0)
AtpCloseSocketOnNode(tempSocket);
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();
// Thread the sessionInfo into the lookup table.
CheckMod(index, sessionRefNum, NumberOfAspSessionHashBuckets,
"AspOpenSession");
sessionInfo->next = sessionInfoHashBuckets[index];
sessionInfoHashBuckets[index] = sessionInfo;
// Build up our completion info block.
completionInfo = (CompletionInfo)Malloc(sizeof(*completionInfo));
if (completionInfo is empty) {
Free(sessionInfo);
if (existingAtpSocket < 0)
AtpCloseSocketOnNode(tempSocket);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotOpenSession);
}
completionInfo->completionRoutine = (void *)completionRoutine;
completionInfo->userData = userData;
completionInfo->sessionRefNum = sessionRefNum;
//
// Post the OpenSession request to the specified address... our caller
// presumably found this with a prior NBP lookup.
//
errorCode = AtpPostRequest(tempSocket, serverAddress,
AtpGetNextTransactionId(tempSocket),
empty, 0, userBytes, True,
empty, 0,
sessionInfo->sessionUserBytes,
AtpRetriesForAsp,
AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
IncomingOpenSessionResponse,
(long unsigned)completionInfo);
if (errorCode isnt ATnoError)
Free(completionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
} // AspOpenSessionOnNode
AppleTalkErrorCode far AspCloseSession(
long sessionRefNum, // Session to close.
//
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.
//
{
SessionListenerInfo sessionListenerInfo;
SessionRefNumMap sessionRefNumMap, previousSessionRefNumMap;
SessionInfo sessionInfo, previousSessionInfo;
GetRequestInfo getRequestInfo, nextGetRequestInfo;
long index;
char userBytes[AtpUserBytesSize];
AppleTalkErrorCode errorCode = ATnoError;
AppleTalkErrorCode closeCode;
Boolean notifiedOwnerOfClose = False;
if (remoteClose)
closeCode = ATaspRemoteSessionClose;
else
closeCode = ATaspLocalSessionClose;
// First, unthread this guy from the sessionInfoHash buckets.
DeferTimerChecking();
DeferAtpPackets();
CheckMod(index, sessionRefNum, NumberOfAspSessionHashBuckets,
"FindSessionInfoFor");
for (sessionInfo = sessionInfoHashBuckets[index],
previousSessionInfo = empty;
sessionInfo isnt empty;
previousSessionInfo = sessionInfo,
sessionInfo = sessionInfo->next)
if (sessionInfo->sessionRefNum is sessionRefNum)
break;
if (sessionInfo is empty) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (previousSessionInfo is empty)
sessionInfoHashBuckets[index] = sessionInfo->next;
else
previousSessionInfo->next = sessionInfo->next;
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...
errorCode = AtpPostRequest(sessionInfo->ourSocket,
sessionInfo->theirAddress,
AtpGetNextTransactionId(sessionInfo->ourSocket),
empty, 0, userBytes, False, empty, 0,
empty, AtpRetriesForAsp,
AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
empty, (long unsigned)0);
}
//
// Okay, now for server sessions, we need to unthread from the session list
// hanging off the SLS.
//
if (sessionInfo->serverSession) {
sessionListenerInfo = sessionInfo->mySessionListener;
for (sessionInfo = sessionListenerInfo->sessionList,
previousSessionInfo = empty;
sessionInfo isnt empty;
previousSessionInfo = sessionInfo,
sessionInfo = sessionInfo->nextForMySls)
if (sessionInfo->sessionRefNum is sessionRefNum)
break;
if (sessionInfo is empty) {
ErrorLog("AspCloseSession", ISevError, __LINE__, UnknownPort,
IErrAspNotOnSLSList, IMsgAspNotOnSLSList,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATinternalError);
}
if (previousSessionInfo is empty)
sessionListenerInfo->sessionList = sessionInfo->nextForMySls;
else
previousSessionInfo->nextForMySls = sessionInfo->nextForMySls;
// Cancel tickling to the other end.
if (AtpCancelRequest(sessionInfo->ourSocket,
sessionInfo->tickleTransactionId,
False) isnt ATnoError)
ErrorLog("AspCloseSession", ISevError, __LINE__, UnknownPort,
IErrAspCouldntCancelTickle, IMsgAspCouldntCancelTickle,
Insert0());
//
// Cancel the pending request handler. Don't bother checking for error
// here; we may have been called from IncomingSssTransaction (processing
// a Close command), in which case no new request handlers would have
// been posted.
//
AtpCancelRequestHandler(sessionInfo->ourSocket,
sessionInfo->atpRequestHandlerId, False);
// Also, we need to remove this guy's entry from the SLS's socket list.
DecrementSocketUsage(sessionListenerInfo, sessionInfo->ourSocket);
// Remove this fellow from the SessionRefNumMap.
CheckMod(index, (((sessionInfo->ourSocket & 0xFFFF) << 8) +
sessionInfo->sessionId), NumberOfSessionRefNumBuckets,
"AspCloseSession");
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("AspCloseSession", ISevError, __LINE__, UnknownPort,
IErrAspRefNumMapMissing, IMsgAspRefNumMapMissing,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATinternalError);
}
if (previousSessionRefNumMap is empty)
sessionRefNumMapHashBuckets[index] = sessionRefNumMap->next;
else
previousSessionRefNumMap->next = sessionRefNumMap->next;
Free(sessionRefNumMap);
// Lastly, we want to terminate any pending get request handlers.
for (getRequestInfo = sessionInfo->getRequestInfoList;
getRequestInfo isnt empty;
getRequestInfo = nextGetRequestInfo) {
nextGetRequestInfo = getRequestInfo->next;
RemoveGetRequestInfo(getRequestInfo);
if (not getRequestInfo->inUse) {
(*getRequestInfo->completionRoutine)(closeCode,
getRequestInfo->userData,
sessionInfo->sessionRefNum,
sessionInfo->usersCookie,
empty, 0, 0,
getRequestInfo->
getRequestRefNum);
notifiedOwnerOfClose = True;
}
FreeGetRequestInfo(getRequestInfo);
}
//
// If the session on the current session 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 notifiedOwnerOfClose) {
// If there is a GetAnyRequest handler, complete it. (only !inUse)
for (getRequestInfo = sessionInfo->mySessionListener->getRequestInfoList;
getRequestInfo isnt empty;
getRequestInfo = nextGetRequestInfo) {
nextGetRequestInfo = getRequestInfo->next;
if (not getRequestInfo->inUse) {
notifiedOwnerOfClose = True;
RemoveGetRequestInfo(getRequestInfo);
(*getRequestInfo->completionRoutine)(closeCode,
getRequestInfo->userData,
sessionInfo->sessionRefNum,
sessionInfo->usersCookie,
empty, 0, 0,
getRequestInfo->
getRequestRefNum);
FreeGetRequestInfo(getRequestInfo);
break;
}
}
}
if (not notifiedOwnerOfClose) {
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)
ErrorLog("AspCloseSession", ISevError, __LINE__, UnknownPort,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
else {
deferredCloseNotify->closeCode = closeCode;
deferredCloseNotify->sessionRefNum = sessionInfo->sessionRefNum;
deferredCloseNotify->usersCookie = sessionInfo->usersCookie;
deferredCloseNotify->next =
sessionInfo->mySessionListener->deferredCloseNotifyList;
sessionInfo->mySessionListener->deferredCloseNotifyList =
deferredCloseNotify;
}
}
}
else {
//
// Okay, close the WSS. This will cancel tickling and cancel the
// pending request handler. [Due to only one session per socket].
//
if (sessionInfo->closeOurSocket)
if (AtpCloseSocketOnNode(sessionInfo->ourSocket) isnt ATnoError)
ErrorLog("AspCloseSession", 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("AspCloseSession", ISevError, __LINE__, UnknownPort,
IErrAspListNotEmpty, IMsgAspListNotEmpty,
Insert0());
for (writeOrCommandInfo = sessionInfo->writeOrCommandInfoList;
writeOrCommandInfo isnt empty;
writeOrCommandInfo = nextWriteOrCommandInfo) {
nextWriteOrCommandInfo = writeOrCommandInfo->next;
Free(writeOrCommandInfo);
}
}
}
// Lastly, free the sessionInfo.
#if VerboseMessages
printf("ASP SessionRefNum %d closed.\n", sessionInfo->sessionRefNum);
#endif
Free(sessionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
} // 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;
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;
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) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (not sessionInfo->serverSession) {
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!
//
getRequestRefNum = sessionInfo->mySessionListener->lastGetRequestRefNum;
while(True) {
if ((getRequestRefNum += 1) < 0)
getRequestRefNum = 0;
if (FindGetRequestInfoFor(sessionInfo->mySessionListener,
getRequestRefNum) is Empty)
break;
}
sessionInfo->mySessionListener->lastGetRequestRefNum = getRequestRefNum;
getRequestInfo = (GetRequestInfo)Calloc(sizeof(*getRequestInfo), 1);
if (getRequestInfo is empty) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotGetRequest);
}
getRequestInfo->getRequestRefNum = getRequestRefNum;
getRequestInfo->mySessionInfo = sessionInfo;
getRequestInfo->mySessionListener = sessionInfo->mySessionListener;
getRequestInfo->opaqueBuffer = opaqueBuffer;
getRequestInfo->bufferSize = bufferSize;
getRequestInfo->completionRoutine = completionRoutine;
getRequestInfo->userData = userData;
// Link it up!
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] =
getRequestInfo;
// All set.
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) {
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.
//
if (sessionListenerInfo->deferredCloseNotifyList isnt Empty) {
deferredCloseNotify = sessionListenerInfo->deferredCloseNotifyList;
sessionListenerInfo->deferredCloseNotifyList = deferredCloseNotify->next;
(*completionRoutine)(deferredCloseNotify->closeCode, userData,
deferredCloseNotify->sessionRefNum,
deferredCloseNotify->usersCookie,
empty, 0, 0, (long)0);
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!
//
getRequestRefNum = sessionListenerInfo->lastGetRequestRefNum;
while(True) {
if ((getRequestRefNum += 1) < 0)
getRequestRefNum = 0;
if (FindGetRequestInfoFor(sessionListenerInfo,
getRequestRefNum) is Empty)
break;
}
sessionListenerInfo->lastGetRequestRefNum = getRequestRefNum;
getRequestInfo = (GetRequestInfo)Calloc(sizeof(*getRequestInfo), 1);
if (getRequestInfo is empty) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspCouldNotGetRequest);
}
getRequestInfo->getRequestRefNum = getRequestRefNum;
getRequestInfo->mySessionListener = sessionListenerInfo;
getRequestInfo->opaqueBuffer = opaqueBuffer;
getRequestInfo->bufferSize = bufferSize;
getRequestInfo->completionRoutine = completionRoutine;
getRequestInfo->userData = userData;
// Link it up!
getRequestInfo->next = sessionListenerInfo->getRequestInfoList;
sessionListenerInfo->getRequestInfoList = getRequestInfo;
sessionListenerInfo->getAnyRequestsSeen = True;
// Link this guy into the per-Sls getRequestInfo hash list.
CheckMod(index, getRequestRefNum, NumGetRequestInfoHashBuckets,
"AspGetRequest");
getRequestInfo->nextForMySessionListener =
sessionListenerInfo->getRequestInfoHashBuckets[index];
sessionListenerInfo->getRequestInfoHashBuckets[index] = getRequestInfo;
// All set.
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.
//
//
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (not sessionInfo->serverSession) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNotServerSession);
}
if (bufferSize > AtpMaximumTotalResponseSize) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspBufferTooBig);
}
// 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);
}
RemoveGetRequestInfo(getRequestInfo);
if (getRequestInfo->requestType isnt requestType or
not getRequestInfo->inUse) {
if (not getRequestInfo->inUse)
errorCode = ATaspNoOperationInProgress;
else
errorCode = ATaspWrongRequestType;
FreeGetRequestInfo(getRequestInfo);
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) {
FreeGetRequestInfo(getRequestInfo);
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;
errorCode = AtpPostResponse(sessionInfo->ourSocket,
getRequestInfo->source,
getRequestInfo->transactionId,
opaqueBuffer, bufferSize,
resultCode,
getRequestInfo->exactlyOnce,
IncomingRelease,
(long unsigned)completionInfo);
// Free the get request info.
FreeGetRequestInfo(getRequestInfo);
// All set!
if (errorCode isnt ATnoError)
Free(completionInfo);
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) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (not sessionInfo->serverSession) {
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);
}
RemoveGetRequestInfo(getRequestInfo);
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;
FreeGetRequestInfo(getRequestInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
}
//
// 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());
FreeGetRequestInfo(getRequestInfo);
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());
FreeGetRequestInfo(getRequestInfo);
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;
getRequestInfo->writeContinueInProgress = True;
getRequestInfo->writeContinueTransactionId =
AtpGetNextTransactionId(sessionInfo->ourSocket);
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) {
Free(completionInfo);
}
FreeGetRequestInfo(getRequestInfo);
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) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (sessionInfo->serverSession) {
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);
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->sequenceNumber = sessionInfo->nextSequenceNumber;
commandInfo->resultCode = resultCode;
commandInfo->next = sessionInfo->writeOrCommandInfoList;
sessionInfo->writeOrCommandInfoList = commandInfo;
// 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.
errorCode = AtpPostRequest(sessionInfo->ourSocket,
sessionInfo->theirAddress,
AtpGetNextTransactionId(sessionInfo->ourSocket),
opaqueCommandBuffer, commandBufferSize,
userBytes, True, opaqueReplyBuffer,
replyBufferSize, resultCode, AtpInfiniteRetries,
AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
IncomingWriteOrCommandComplete,
(long unsigned)completionInfo);
if (errorCode isnt ATnoError) {
sessionInfo->writeOrCommandInfoList = commandInfo->next;
Free(commandInfo);
Free(completionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
}
// Request out, sequence number used!
sessionInfo->nextSequenceNumber += 1;
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.
//
//
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (sessionInfo->serverSession) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNotWorkstationSession);
}
if (writeBufferSize > AtpMaximumTotalResponseSize) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspSizeError);
}
// 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);
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->sequenceNumber = sessionInfo->nextSequenceNumber;
writeInfo->writeCommand = True;
writeInfo->resultCode = resultCode;
writeInfo->writeOpaqueBuffer = opaqueWriteBuffer;
writeInfo->writeBufferSize = writeBufferSize;
writeInfo->next = sessionInfo->writeOrCommandInfoList;
sessionInfo->writeOrCommandInfoList = writeInfo;
// 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.
errorCode = AtpPostRequest(sessionInfo->ourSocket,
sessionInfo->theirAddress,
AtpGetNextTransactionId(sessionInfo->ourSocket),
opaqueCommandBuffer, commandBufferSize,
userBytes, True, opaqueReplyBuffer,
replyBufferSize, resultCode, AtpInfiniteRetries,
AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
IncomingWriteOrCommandComplete,
(long unsigned)completionInfo);
if (errorCode isnt ATnoError) {
sessionInfo->writeOrCommandInfoList = writeInfo->next;
Free(writeInfo);
Free(completionInfo);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
}
// Request is out, so the sequence number is used!
sessionInfo->nextSequenceNumber += 1;
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) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (sessionInfo->serverSession) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNotWorkstationSession);
}
sessionInfo->incomingAttentionHandler = handler;
sessionInfo->userDataForAttention = userData;
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) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATaspNoSuchSession);
}
if (not sessionInfo->serverSession) {
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,
AtpGetNextTransactionId(sessionInfo->ourSocket),
empty, 0, userBytes, False, empty, 0,
empty, AtpRetriesForAsp,
AtpIntervalSecondsForAsp,
ThirtySecondsTRelTimer,
empty, (long unsigned)0);
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;
// 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();
for (sessionListenerInfo = sessionListenerInfoHead;
sessionListenerInfo isnt empty;
sessionListenerInfo = sessionListenerInfo->next)
if (sessionListenerInfo->sessionListenerRefNum is sessionListenerRefNum)
break;
if (sessionListenerInfo is empty) {
ErrorLog("IncomingSlsTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspListenerInfoMissing, IMsgAspListenerInfoMissing,
Insert0());
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) {
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].
//
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;
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) {
if (SendAspErrorReturn(sessionListenerInfo->ourSocket, source,
transactionId, exactlyOnce, ATaspServerBusy)
isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__,
UnknownPort, IErrAspBadSrvrBusySend, IMsgAspBadSrvrBusySend,
Insert0());
break;
}
sessionListenerInfo->lastSessionId = sessionId;
// Okay, do we like the version number?
if (userBytes[AspVersionNumberOffset] isnt AspVersionBytes[0] or
userBytes[AspVersionNumberOffset + 1] isnt AspVersionBytes[1]) {
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.
//
if (sessionListenerInfo->getSessionHandlers->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.
if (MapSocketToAddress(sessionListenerInfo->ourSocket,
&slsAddress) isnt ATnoError) {
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) {
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) {
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__,
UnknownPort, IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
AtpCloseSocketOnNode(serverSessionSocket);
break; // Just let the open OpenSession request time-out...
}
socketInfo->socket = serverSessionSocket;
socketInfo->activeSessions = 1;
socketInfo->privateSocket =
sessionListenerInfo->getSessionHandlers->privateSocket;
socketInfo->next = sessionListenerInfo->socketList;
sessionListenerInfo->socketList = socketInfo;
}
else {
serverSessionSocket = socketInfo->socket;
socketInfo->activeSessions += 1;
}
// Get a new session ref num.
if ((sessionRefNum = GetNextSessionRefNum()) < 0) {
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspBadError, IMsgAspBadError,
Insert0());
DecrementSocketUsage(sessionListenerInfo,
serverSessionSocket);
break;
}
// 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) {
if (sessionInfo isnt empty)
Free(sessionInfo);
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspOutOfMemory, IMsgAspOutOfMemory,
Insert0());
DecrementSocketUsage(sessionListenerInfo,
serverSessionSocket);
break;
}
// Okay, start filling in the session node...
sessionInfo->mySessionListener = 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.
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] = sessionInfo;
// Finaly onto the session per SLS list...
sessionInfo->nextForMySls = sessionListenerInfo->sessionList;
sessionListenerInfo->sessionList = sessionInfo;
// All looks good; we can send back a OpenSessionReply.
if (MapSocketToAddress(serverSessionSocket, &sssAddress)
isnt ATnoError) {
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspCouldntMapAddress, IMsgAspCouldntMapAddress,
Insert0());
AtpCloseSocketOnNode(serverSessionSocket);
break; // Just let the open OpenSession request time-out...
}
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;
sessionInfo->tickleTransactionId =
AtpGetNextTransactionId(sessionInfo->ourSocket);
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());
//
// Post an ATP read on behalf of this session [not really for THIS
// particular session, but another read on the shared ATP socket...
// these are really demultiplexed in IncomingSssTransaction].
//
if (AtpEnqueueRequestHandler(&id, sessionInfo->ourSocket,
Empty, 0, Empty,
IncomingSssTransaction,
(long unsigned)sessionRefNum)
isnt ATnoError)
ErrorLog("IncomingSlsTransaction", ISevError, __LINE__, UnknownPort,
IErrAspCouldNotEnqueue, IMsgAspCouldNotEnqueue,
Insert0());
else
sessionInfo->atpRequestHandlerId = id;
//
// Lastly, we're ready to untread the session open handler and invoke
// the completion routine!
//
getSessionHandler = sessionListenerInfo->getSessionHandlers;
sessionOpenHandler = getSessionHandler->sessionOpenHandler;
userData = getSessionHandler->userData;
sessionListenerInfo->getSessionHandlers = getSessionHandler->next;
ourSocket = sessionInfo->ourSocket;
Free(getSessionHandler);
HandleAtpPackets();
HandleDeferredTimerChecks();
(*sessionOpenHandler)(ATnoError, userData, ourSocket,
sessionInfo->sessionRefNum);
needToUndefer = False;
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];
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.
//
ErrorLog("IncomingSlsTransaction", ISevVerbose, __LINE__,
UnknownPort, IErrAspSessionInfoMissing, IMsgAspSessionInfoMissing,
Insert0());
break;
}
#if VerboseMessages
printf("Tickle SSS (%d); sesRefNum = %d, sessionId = %d.\n",
sessionInfo->ourSocket,
sessionInfo->sessionRefNum, sessionId);
#endif
sessionInfo->lastContactTime = CurrentRelativeTime();
break;
case AspGetStatusCommand:
if (AtpPostResponse(sessionListenerInfo->ourSocket, source,
transactionId,
sessionListenerInfo->opaqueServiceStatus,
sessionListenerInfo->serviceStatusSize,
getStatusResponseUserBytes, exactlyOnce, empty,
(long unsigned)0) isnt ATnoError)
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...
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 bufferingSessionInfo, sessionInfo;
long id;
Boolean enqueueNewAtpRead = True;
short requestType;
Boolean needToUndefer = True;
short unsigned sequenceNumber;
void far *opaqueBuffer;
// 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;
}
//
// Okay, this is a little murcky... The sessionRefNum that we've gotten
// as "userData" is probably not the sessionRefNum of the session that
// really wants the incoming ATP request. This session will, however be
// on the same socket of the session that really wants the request.
// Remember that ATP doesn't have any concept of an ASP session, so all
// of the ATP reads posted (one for each ASP session) are the same to ATP
// (on the same socket).
//
// Now, to find the session that really wants the data, we know the
// socket (it will be the same as the above session), and by looking in
// the incoming packet we can find the sessionId. With these two, we can
// find the actual target sessionRefNum (sessionInfo). It is in this
// session that we check to see if there are any pending higher level
// ASP GetRequests. If so, we move the data out, call the designated
// completion routine. If not we check to see if there are any "any
// session GetRequest handlers" hanging off the ServiceListenerInfo,
// if so we move the data out. Failing this, else we ignore the incoming
// request. Sigh.
//
// Find the sessionInfo of the session that caught this request.
DeferTimerChecking();
DeferAtpPackets();
if ((bufferingSessionInfo = FindSessionInfoFor(bufferingSessionRefNum))
is empty) {
ErrorLog("IncomingSssTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspSessionBufMissing, IMsgAspSessionBufMissing,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
//
// Okay, now use the socket and the packet's sessionId to find the
// target sessionInfo.
//
if ((sessionInfo =
FindSessionInfoForSocket(bufferingSessionInfo->ourSocket,
(unsigned char)userBytes[AspSessionIdOffset]))
is empty) {
ErrorLog("IncomingSssTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspTargetSessionMissing, IMsgAspTargetSessionMissing,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
if (sessionInfo->mySessionListener isnt
bufferingSessionInfo->mySessionListener) {
ErrorLog("IncomingSssTransaction", ISevError, __LINE__, UnknownPort,
IErrAspWrongSLS, IMsgAspWrongSLS,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
if (sessionInfo->ourSocket isnt bufferingSessionInfo->ourSocket) {
//
// Yes, all ASP sessions that share GetRequest handlers will be on
// the same ATP (Ddp) socket!
//
ErrorLog("IncomingSssTransaction", ISevError, __LINE__, UnknownPort,
IErrAspWrongAddress, IMsgAspWrongAddress,
Insert0());
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.
//
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.
//
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) {
if (AtpCancelResponse(sessionInfo->ourSocket, source,
transactionId, False) isnt ATnoError)
ErrorLog("IncomingSssTransaction", ISevError, __LINE__,
UnknownPort, IErrAspBadCancelResponse, IMsgAspBadCancelResponse,
Insert0());
break;
}
else
sessionInfo->nextExpectedSequenceNumber += 1;
//
// 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;
}
//
// 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;
//
// Tag the get request info as in-use and call the user's handler
// routine.
//
getRequestInfo->inUse = True; {
AspIncomingCommandHandler *completionRoutine =
getRequestInfo->completionRoutine;
long unsigned userData = getRequestInfo->userData;
long sessionRefNum = sessionInfo->sessionRefNum;
long getRequestRefNum = getRequestInfo->getRequestRefNum;
long unsigned cookie = sessionInfo->usersCookie;
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(errorCode, userData, sessionRefNum, cookie,
opaqueBuffer, bufferSize, requestType,
getRequestRefNum);
needToUndefer = False;
}
break;
case AspCloseSessionCommand:
//
// Only re-enqueue the ATP read if the GetRequestHandler that was used
// for the "current" request was NOT owned by the session we're
// closing.
//
if (bufferingSessionInfo->sessionRefNum is
sessionInfo->sessionRefNum)
enqueueNewAtpRead = False;
// 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, True);
break;
default:
ErrorLog("IncomingSssTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspBadCommand, IMsgAspBadCommand,
Insert0());
break;
}
// Re-enqueue the ATP read.
if (enqueueNewAtpRead)
if (AtpEnqueueRequestHandler(&id, sessionInfo->ourSocket,
Empty, 0, Empty, IncomingSssTransaction,
(long unsigned)bufferingSessionInfo->
sessionRefNum) isnt ATnoError)
ErrorLog("IncomingSssTransaction", ISevError, __LINE__, UnknownPort,
IErrAspCouldNotEnqueue, IMsgAspCouldNotEnqueue,
Insert0());
else
bufferingSessionInfo->atpRequestHandlerId = id;
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 enqueueNewAtpRead = True;
Boolean callAttentionRoutine = False;
short unsigned attentionData;
short unsigned sequenceNumber;
// 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) {
ErrorLog("IncomingWssTransaction", ISevWarning, __LINE__, UnknownPort,
IErrAspSessionInfoMissing, IMsgAspSessionInfoMissing,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
if (sessionInfo->serverSession or
(unsigned char)userBytes[AspSessionIdOffset] isnt sessionInfo->sessionId) {
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, True);
enqueueNewAtpRead = False;
break;
case AspAttentionCommand:
if (sessionInfo->incomingAttentionHandler isnt empty) {
callAttentionRoutine = True;
attentionData =
(short unsigned)((userBytes[AspAttentionWordOffset] << 8) +
(unsigned char)userBytes[AspAttentionWordOffset + 1]);
}
// 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.
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)
break; // No luck, ignore the request.
if (not writeInfo->writeCommand) {
ErrorLog("IncomingWssTransaction", ISevWarning, __LINE__,
UnknownPort, IErrAspNotWriteCommand, IMsgAspNotWriteCommand,
Insert0());
break;
}
// How much data can the server take?
if (bufferSize < AspWriteDataSize) {
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;
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 needed.
if (enqueueNewAtpRead)
if (AtpEnqueueRequestHandler(&id, sessionInfo->ourSocket,
Empty, 0, Empty,
IncomingWssTransaction,
(long unsigned)sessionRefNum) isnt ATnoError)
ErrorLog("IncomingWssTransaction", ISevError, __LINE__, UnknownPort,
IErrAspCouldNotEnqueue, IMsgAspCouldNotEnqueue,
Insert0());
else
sessionInfo->atpRequestHandlerId = id;
// Call attention handler, if needed.
if (callAttentionRoutine) {
AspIncomingAttentionHandler *incomingAttentionHandler =
sessionInfo->incomingAttentionHandler;
long unsigned userData = sessionInfo->userDataForAttention;
long sessionRefNum = sessionInfo->sessionRefNum;
HandleAtpPackets();
HandleDeferredTimerChecks();
(*incomingAttentionHandler)(ATnoError, userData, sessionRefNum,
attentionData);
}
else {
HandleAtpPackets();
HandleDeferredTimerChecks();
}
return;
} // IncomingWssTransaction
ExternForVisibleFunction SessionInfo
FindSessionInfoForSocket(long socket,
unsigned char sessionId)
{
long index;
SessionRefNumMap sessionRefNumMap;
SessionInfo sessionInfo;
//
// First, given the socket and the session ID of an ASP session, we
// need to find the session reference number.
//
DeferTimerChecking();
DeferAtpPackets();
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) {
HandleAtpPackets();
HandleDeferredTimerChecks();
return(empty);
}
//
// Okay, now we have the session reference number... find the correct
// session info node.
//
sessionInfo = FindSessionInfoFor(sessionRefNumMap->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();
for (socketInfo = sessionListenerInfo->socketList,
previousSocketInfo = empty;
socketInfo isnt empty;
previousSocketInfo = socketInfo,
socketInfo = socketInfo->next)
if (socketInfo->socket is socket)
break;
if (socketInfo is empty) {
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;
AtpCloseSocketOnNode(socketInfo->socket);
Free(socketInfo);
}
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
} // DecrementSocketUsage
ExternForVisibleFunction AppleTalkErrorCode InitializeAsp(void)
{
// Start the session maintenance timer...
StartTimer(SessionMaintenanceTimerExpired, AspSessionMaintenanceSeconds,
0, empty);
sessionMaintenanceTimerStarted = True;
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)
for (sessionInfo = sessionInfoHashBuckets[index];
sessionInfo isnt empty;
sessionInfo = nextSessionInfo) {
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, False) isnt
ATnoError)
ErrorLog("SessionMaintenanceTimerExpired", ISevError,
__LINE__, UnknownPort, IErrAspCouldNotCloseSess,
IMsgAspCouldNotCloseSess, Insert0());
#if VerboseMessages
printf("Session maintenance; closing sessionRefNum = %d.\n",
sessionInfo->sessionRefNum);
#endif
sessionInfo = sessionInfoHashBuckets[index];
}
else
// "I'm not dead yet..." ;
}
// 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");
for (sessionInfo = sessionInfoHashBuckets[index];
sessionInfo isnt empty;
sessionInfo = sessionInfo->next)
if (sessionInfo->sessionRefNum is sessionRefNum)
break;
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;
// Touch unused formals...
source, transactionId;
completionRoutine =
(AspReplyCompleteHandler *)completionInfo->completionRoutine;
if (completionRoutine is empty) {
Free(completionInfo);
return;
}
//
// 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);
(*completionRoutine)(errorCode, userData, sessionRefNum, getRequestRefNum);
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;
// Touch unused formals...
source, transactionId, responseUserBytes;
completionRoutine =
(AspIncomingWriteDataHandler *)completionInfo->completionRoutine;
userData = completionInfo->userData;
sessionRefNum = completionInfo->sessionRefNum;
getRequestRefNum = completionInfo->getRequestRefNum;
Free(completionInfo);
(*completionRoutine)(errorCode, userData, sessionRefNum, getRequestRefNum,
opaqueResponseBuffer, responseBufferSize);
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) {
ErrorLog("IncomingOpenSessionResponse", ISevWarning, __LINE__, UnknownPort,
IErrAspSessionInfoMissing, IMsgAspSessionInfoMissing,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATaspCouldNotOpenSession, userData, (long)0);
return;
}
if (sessionInfo->serverSession or not sessionInfo->waitingForOpenReply) {
ErrorLog("IncomingOpenSessionResponse", ISevError, __LINE__, UnknownPort,
IErrAspSessionInfoBad, IMsgAspSessionInfoBad,
Insert0());
AspCloseSession(sessionRefNum, 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) {
AspCloseSession(sessionRefNum, 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,
AtpGetNextTransactionId(sessionInfo->ourSocket),
empty, 0, tickleUserBytes, False,
empty, 0, empty, AtpInfiniteRetries,
AspTickleSeconds,
ThirtySecondsTRelTimer,
empty, (long unsigned)0);
f (errorCode isnt ATnoError)
AspCloseSession(sessionRefNum, 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) {
AspCloseSession(sessionRefNum, False);
HandleAtpPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(errorCode, userData, (long)0);
return;
}
else
sessionInfo->atpRequestHandlerId = id;
// Okay, the workstation session is now in full operation.
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;
else if (errorCode is ATatpTransactionAborted)
;
else if (errorCode isnt ATnoError) {
(*completionRoutine)(errorCode, userData, sessionRefNum,
empty, empty, 0, 0);
return;
}
// Find our corresponding sessionInfo and write or command info.
DeferTimerChecking();
DeferAtpPackets();
sessionInfo = FindSessionInfoFor(sessionRefNum);
if (sessionInfo is empty) {
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;
}
for (writeOrCommandInfo = sessionInfo->writeOrCommandInfoList,
previousWriteOrCommandInfo = empty;
writeOrCommandInfo isnt empty;
previousWriteOrCommandInfo = writeOrCommandInfo,
writeOrCommandInfo = writeOrCommandInfo->next)
if (writeOrCommandInfo->sequenceNumber is sequenceNumber)
break;
if (writeOrCommandInfo is empty) {
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;
// 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);
return;
} // IncomingWriteOrCommandComplete
ExternForVisibleFunction long GetNextSessionRefNum(void)
{
Boolean inUse, wrapped = False;
//
// 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;
while(inUse) {
inUse = False;
if ((lastSessionRefNum += 1) < 0) {
lastSessionRefNum = 0;
if (wrapped) {
inUse = True;
break;
}
wrapped = True;
}
if (FindSessionInfoFor(lastSessionRefNum) isnt Empty)
inUse = True;
}
HandleAtpPackets();
HandleDeferredTimerChecks();
if (inUse)
return((long)-1);
else
return(lastSessionRefNum);
} // GetNextSessionRefNum
ExternForVisibleFunction SessionListenerInfo
FindSessionListenerInfoFor(long sessionListenerRefNum)
{
SessionListenerInfo sessionListenerInfo;
for (sessionListenerInfo = sessionListenerInfoHead;
sessionListenerInfo isnt empty;
sessionListenerInfo = sessionListenerInfo->next)
if (sessionListenerInfo->sessionListenerRefNum is sessionListenerRefNum)
break;
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");
for (getRequestInfo = sessionListenerInfo->getRequestInfoHashBuckets[index];
getRequestInfo isnt Empty;
getRequestInfo = getRequestInfo->nextForMySessionListener)
if (getRequestInfo->getRequestRefNum is getRequestRefNum)
break;
return(getRequestInfo);
} // FindGetRequestInfoFor
ExternForVisibleFunction void
RemoveGetRequestInfo(GetRequestInfo targetGetRequestInfo)
{
GetRequestInfo getRequestInfo, previousGetRequestInfo;
long index;
//
// 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 (targetGetRequestInfo->mySessionInfo is Empty) {
//
// Remove from the "next" (GetAnyRequest) list hanging off the session
// listener info structure.
//
for (previousGetRequestInfo = Empty,
getRequestInfo = targetGetRequestInfo->mySessionListener->
getRequestInfoList;
getRequestInfo isnt Empty;
previousGetRequestInfo = getRequestInfo,
getRequestInfo = getRequestInfo->next)
if (getRequestInfo is targetGetRequestInfo)
break;
//
// We should always be found... if not we have data structure corruption
// problems.
//
if (getRequestInfo is Empty) {
ErrorLog("RemoveGetRequestInfo", ISevError, __LINE__, UnknownPort,
IErrAspGetRequestListBad, IMsgAspGetRequestListBad,
Insert0());
Free(targetGetRequestInfo);
return;
}
// Okay, remove 'im from the list.
if (previousGetRequestInfo is Empty)
targetGetRequestInfo->mySessionListener->getRequestInfoList =
targetGetRequestInfo->next;
else
previousGetRequestInfo->next = targetGetRequestInfo->next;
}
else {
//
// Remove from the "next" (GetRequest) list handing off the session
// info structure.
//
for (previousGetRequestInfo = Empty,
getRequestInfo = targetGetRequestInfo->mySessionInfo->
getRequestInfoList;
getRequestInfo isnt Empty;
previousGetRequestInfo = getRequestInfo,
getRequestInfo = getRequestInfo->next)
if (getRequestInfo is targetGetRequestInfo)
break;
//
// We should always be found... if not we have data structure corruption
// problems.
//
if (getRequestInfo is Empty) {
ErrorLog("RemoveGetRequestInfo", ISevError, __LINE__, UnknownPort,
IErrAspGetRequestListBad, IMsgAspGetRequestListBad,
Insert0());
Free(targetGetRequestInfo);
return;
}
// Okay, remove 'im from the list.
if (previousGetRequestInfo is Empty)
targetGetRequestInfo->mySessionInfo->getRequestInfoList =
targetGetRequestInfo->next;
else
previousGetRequestInfo->next = targetGetRequestInfo->next;
}
// Remove from per-Sls hash list.
CheckMod(index, targetGetRequestInfo->getRequestRefNum,
NumGetRequestInfoHashBuckets, "RemoveGetRequestInfo");
for (previousGetRequestInfo = Empty,
getRequestInfo = targetGetRequestInfo->mySessionListener->
getRequestInfoHashBuckets[index];
getRequestInfo isnt Empty;
previousGetRequestInfo = getRequestInfo,
getRequestInfo = getRequestInfo->nextForMySessionListener)
if (getRequestInfo is targetGetRequestInfo)
break;
//
// We should always be found... if not we have data structure corruption
// problems.
//
if (getRequestInfo is Empty) {
ErrorLog("RemoveGetRequestInfo", ISevError, __LINE__, UnknownPort,
IErrAspGetRequestListBad, IMsgAspGetRequestListBad,
Insert0());
Free(targetGetRequestInfo);
return;
}
// Okay, remove from the hash chain.
if (previousGetRequestInfo is Empty)
targetGetRequestInfo->mySessionListener->getRequestInfoHashBuckets[index] =
targetGetRequestInfo->nextForMySessionListener;
else
previousGetRequestInfo->nextForMySessionListener =
targetGetRequestInfo->nextForMySessionListener;
return;
} // RemoveGetRequestInfo
ExternForVisibleFunction void
FreeGetRequestInfo(GetRequestInfo targetGetRequestInfo)
{
// We're set, free the beast, and run away.
if (targetGetRequestInfo->freeOpaqueWriteContinueData)
FreeOpaqueDataDescriptor(targetGetRequestInfo->opaqueWriteContinueData);
Free(targetGetRequestInfo);
return;
} // FreeGetRequestInfo
#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