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.
 
 
 
 
 
 

2648 lines
83 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
atp.c
Abstract:
This module contains the ATP protocol code.
Author:
Garth Conboy Initial Coding
Nikhil Kamkolkar Rewritten for microsoft coding style. mpized
Revision History:
--*/
#define IncludeAtpErrors 1
#include "atalk.h"
// Debug information.
#define Debug 0
#define VerboseMessages 0
#if Debug
#define DropEveryNthRequest 53
#define DropEveryNthResponse 53
#define DropEveryNthRelease 53
#endif
// Primos has no conecpt of "critical sections" so simulate it.
#if Iam a Primos
#undef EnterCriticalSection
#undef LeaveCriticalSection
#define EnterCriticalSection DeferTimerChecking
#define LeaveCriticalSection HandleDeferredTimerChecks
#endif
// Internal static routines.
ExternForVisibleFunction IncomingDdpHandler AtpPacketIn;
ExternForVisibleFunction TimerHandler AtpReleaseTimerExpired;
ExternForVisibleFunction TimerHandler AtpRequestTimerExpired;
ExternForVisibleFunction void AtpTransmitRelease(AtpSendRequest request);
ExternForVisibleFunction void AtpTransmitRequest(AtpSendRequest request);
ExternForVisibleFunction void
AtpTransmitResponse(long sourceSocket,
AppleTalkAddress destination,
short unsigned transactionId,
void far *responseOpaqueBuffer,
int responseBufferSize,
char far *responseUserBytes,
short unsigned bitmap,
Boolean explicitZero,
short maximumSinglePacketDataSize);
ExternForVisibleFunction short
AtpBitmapToBufferSize(short unsigned bitmap,
short maximumSinglePacketDataSize);
ExternForVisibleFunction short unsigned
AtpBufferSizeToBitmap(int bufferSize,
short maximumSinglePacketDataSize);
ExternForVisibleFunction short
AtpSynchUpResponseBuffer(AtpSendRequest request,
short maximumSinglePacketDataSize);
ExternForVisibleFunction AtpInfo FindAtpInfoFor(long mySocket);
// Deferred ATP packet queue:
#define MaximumDeferredPackets 10
typedef struct dp { struct dp far *next;
AppleTalkErrorCode errorCode;
int port;
AppleTalkAddress source;
long destinationSocket;
short datagramLength;
AppleTalkAddress actualDestination;
char datagram[1];
} far *DeferredPacket;
static volatile DeferredPacket headOfDeferredPacketList = empty;
static volatile DeferredPacket tailOfDeferredPacketList = empty;
static volatile short currentDeferredPacketCount = 0;
static volatile short handleAtpPacketsNesting = 0;
static volatile short deferIncomingAtpPacketsCount = 0;
//
// An item on the send-request or send-response lists can be removed either
// due to incoming packets OR a timer going off. When a timer goes off the
// handler is passed the address of the structure. It is not sufficient to
// walk the given list looking for the socket; a packet could have come in
// just before the timer handler got around to defering incoming packets, and
// that packet could have removed the item from the specified list, and if
// we're very unlucky, the address could have been reused, and we could get
// very confused. So, we identify each member of these lists with both their
// address's as well as a 32 bit ID.
//
typedef struct {long id;
long socket;
char far *pointer;
} AdditionalData;
static long nextId = 0;
AppleTalkErrorCode far AtpOpenSocketOnNode(
long far *socketHandle, // The Atp/Ddp socket opended; returned.
int port, // Port on which the socket should live.
ExtendedAppleTalkNodeNumber *desiredNode,
// Desired node for socket, empty if none.
int desiredSocket, // Desired static socket or zero for dynamic.
char far *datagramBuffers, // DDP datagram buffers.
int totalBufferSize) // How many of these guys.
{
long socket, index;
AtpInfo atpInfo;
AppleTalkErrorCode errorCode;
// Open the requested DDP socket.
if ((errorCode = OpenSocketOnNode(&socket, port, desiredNode, desiredSocket,
AtpPacketIn, (long)0, False,
datagramBuffers,
totalBufferSize, empty)) isnt ATnoError)
return(errorCode);
// We have to create and thread a new AtpInfo structure.
if ((atpInfo = (AtpInfo)Calloc(sizeof(*atpInfo), 1)) is empty)
{
ErrorLog("AtpOpenSocketOnNode", ISevError, __LINE__, port,
IErrAtpOutOfMemory, IMsgAtpOutOfMemory,
Insert0());
CloseSocketOnNode(socket);
return(AToutOfMemory);
}
DeferTimerChecking();
DeferAtpPackets();
CheckMod(index, socket, MaxAtpInfoHashBuckets, "AtpOpenSocketOnNode");
atpInfo->mySocket = socket;
atpInfo->maximumSinglePacketDataSize = AtpSinglePacketDataSize;
atpInfo->next = atpInfoHashBuckets[index];
atpInfoHashBuckets[index] = atpInfo;
HandleAtpPackets();
HandleDeferredTimerChecks();
if (socketHandle isnt empty)
*socketHandle = socket;
return(ATnoError);
} // AtpOpenSocketOnNode
AppleTalkErrorCode far AtpCloseSocketOnNode(
long socket) // The socket to close.
{
AtpInfo atpInfo, previousAtpInfo;
AtpReceiveRequest receiveRequest, nextReceiveRequest;
AtpSendRequest sendRequest, nextSendRequest;
AtpSendResponse sendResponse, nextSendResponse;
AppleTalkErrorCode errorCode;
long index;
//
// We're going to muck with the live ATP databases, defer incoming packets
// and hold off the timers...
//
DeferTimerChecking();
DeferAtpPackets();
// Find the correct ATP strcuture, so we can tear the beast down.
if ((atpInfo = FindAtpInfoFor(socket)) is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
//
// Cancel all pending requests and responses, and free the data structures
// in the OpenSocket node.
//
for (receiveRequest = atpInfo->receiveRequestQueue;
receiveRequest isnt empty;
receiveRequest = nextReceiveRequest)
{
nextReceiveRequest = receiveRequest->next;
AtpCancelRequestHandler(socket, receiveRequest->requestHandlerId, True);
}
for (sendRequest = atpInfo->sendRequestQueue;
sendRequest isnt empty;
sendRequest = nextSendRequest)
{
nextSendRequest = sendRequest->next;
AtpCancelRequest(socket, sendRequest->transactionId, True);
}
for (sendResponse = atpInfo->sendResponseQueue;
sendResponse isnt empty;
sendResponse = nextSendResponse)
{
nextSendResponse = sendResponse->next;
AtpCancelResponse(socket, sendResponse->destination,
sendResponse->transactionId, True);
}
// Release the AtpInfo structure.
CheckMod(index, socket, MaxAtpInfoHashBuckets, "AtpCloseSocketOnNode");
for (previousAtpInfo = empty,
atpInfo = atpInfoHashBuckets[index];
atpInfo isnt empty;
previousAtpInfo = atpInfo,
atpInfo = atpInfo->next)
if (atpInfo->mySocket is socket)
break;
if (atpInfo is empty)
ErrorLog("AtpCloseSocketOnNode", ISevError, __LINE__, UnknownPort,
IErrAtpAtpInfoMissing, IMsgAtpAtpInfoMissing,
Insert0());
else
{
if (previousAtpInfo is empty)
atpInfoHashBuckets[index] = atpInfo->next;
else
previousAtpInfo->next = atpInfo->next;
Free(atpInfo);
}
// Close the DDP socket!
errorCode = CloseSocketOnNode(socket);
HandleAtpPackets();
HandleDeferredTimerChecks();
return(errorCode);
} // AtpCloseSocketOnNode
AppleTalkErrorCode AtpSetCookieForSocket(
long socket, // The Atp socket for which to set the cookie.
long unsigned cookie) // The new cookie's value.
{
AtpInfo atpInfo;
//
// We're going to muck with the live ATP databases, defer incoming packets
// and hold off the timers...
//
DeferTimerChecking();
DeferAtpPackets();
// Find the correct ATP strcuture, in which to set the cookie.
if ((atpInfo = FindAtpInfoFor(socket)) is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
// Do the deed.
atpInfo->usersCookie = cookie;
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} // AspSetCookieForSession
AppleTalkErrorCode AtpGetCookieForSocket(
long socket, // The Atp socket for which to set the cookie.
long unsigned far *cookie) // Where to stick the cookie.
{
AtpInfo atpInfo;
//
// We're going to muck with the live ATP databases, defer incoming packets
// and hold off the timers...
//
DeferTimerChecking();
DeferAtpPackets();
// Find the correct ATP strcuture, from which to get the cookie.
if ((atpInfo = FindAtpInfoFor(socket)) is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
// Do the deed.
*cookie = atpInfo->usersCookie;
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} // AspGetCookieForSession
AppleTalkErrorCode near AtpMaximumSinglePacketDataSize(
//
long socket, // The address to adjust the send/recieve
// quantum for.
//
short maximumSinglePacketDataSize)
// New quantum size.
{
AtpInfo atpInfo;
if (maximumSinglePacketDataSize < 0 or
maximumSinglePacketDataSize > AtpSinglePacketDataSize)
return(ATatpBadBufferSize);
DeferTimerChecking();
DeferAtpPackets();
// Find our ATP info and set the new quantum size.
atpInfo = FindAtpInfoFor(socket);
if (atpInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
atpInfo->maximumSinglePacketDataSize = maximumSinglePacketDataSize;
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} // AtpMaximumSinglePacketDataSize
short unsigned _near AtpGetNextTransactionId(
//
long socket) // The AppleTalk address that we're going
// to post the transaction from.
//
{
AtpInfo atpInfo;
short unsigned transactionId;
Boolean inUse = True;
AtpSendRequest request;
DeferTimerChecking();
DeferAtpPackets();
atpInfo = FindAtpInfoFor(socket);
if (atpInfo is empty)
{
//
// There is no real way to return an error here, because our return
// type is "short unsigned"... but, so what? The only thing that can
// be done with a "next transaction id" is to call AtpPostRequest()
// will it... this socket will be the same one as was just passed to
// us, so the user will get the real "socket not open" error at that
// time. So, don't worry about the following "return(0)".
//
HandleAtpPackets();
HandleDeferredTimerChecks();
return(0);
}
// Okay, find one that's not currently in use.
transactionId = atpInfo->lastTransactionId;
while(inUse)
{
transactionId += 1; // Will wrap in 16 bits...
inUse = False;
for (request = atpInfo->sendRequestQueue;
request isnt empty;
request = request->next)
if (transactionId is request->transactionId)
{
inUse = True;
break;
}
}
// Okay, we've got one, note it as last used and return.
atpInfo->lastTransactionId = transactionId;
HandleAtpPackets();
HandleDeferredTimerChecks();
return(transactionId);
} // AtpGetNextTransactionId
#if Iam an OS2 // Too many stack temporaries...
#pragma optimize ("eg", off)
#endif
AppleTalkErrorCode far AtpPostRequest(
//
long sourceSocket, // "Our" AppleTalk address -- source of the
// request.
//
//
AppleTalkAddress destination, // Destination AppleTalk address. Who are
// we asking?
//
//
short unsigned transactionId, // The transaction ID for this request as
// returned from AtpGetNextTransactionId.
//
void far *requestOpaqueBuffer, // Request data.
int requestBufferSize, // Request data size, in bytes.
char far *requestUserBytes, // "UserBytes" for request (may be empty).
Boolean exactlyOnce, // Transaction type.
//
void far *responseOpaqueBuffer, // Buffer to store response in (may be
// empty).
//
int responseBufferSize, // Expected response size, in bytes.
//
char far *responseUserBytes, // Buffer to store "userBytes" from first
// response packet in (may be empty).
//
//
int retryCount, // How many times should we retry the
// request (-1 = forever).
//
//
int retryInterval, // How often should we retry the request
// in seconds (0 -> 2).
//
//
TRelTimerValue trelTimerValue, // How long should the other side wait
// for a release? (0 = 30 seconds).
//
AtpIncomingResponseHandler *completionRoutine,
//
// Routine to call when the request
// completes; may be empty.
//
//
long unsigned userData) // Arbitrary data passed on to the completion
// routine.
//
{
//
// We post an ATP request to a specified destination. When a complete
// response arrives (or when the request times out) we call the supplied
// completion routine as follows:
//
// (*completionRoutine)(errorCode, userData, source, opaqueBuffer,
// bufferSize, userBytes, transactionId);
//
// The arguments are:
//
// errorCode - an AppleTalkErrorCode; either ATnoError,
// ATatpRequestTimedOut or ATatpResponseBufferTooSmall
// [arguments following "source" will only be valid
// if errorCode is ATnoError].
//
// userData - a longword; the "userData" that was passed to the
// corresponding AtpPostRequest call.
//
// source - an AppleTalkAddress; the internet source of the ATP
// response (destination of the request).
//
// opaqueBuffer - a void*; as passed to AtpPostRequest where the ATP
// response data has been written.
//
// bufferSize - an int; the number of bytes actually stored in the
// location pointed to by "buffer".
//
// userBytes - a char*; as passed to AtpPostRequest where the ATP
// response "user bytes" have been written. If an
// Empty responseUserBytes buffer was passed into this
// routine, this argument will point to a temporary
// copy of the user bytes, which the handler can copy
// out.
//
// transactionId - a short unsigned int; the ATP transaction ID of the
// request.
//
//
AtpInfo atpInfo;
AtpSendRequest request;
short index;
AdditionalData additionalData;
//
// Okay we're ready to start threading a new request data structure... lets
// be private about it!
//
DeferTimerChecking();
DeferAtpPackets();
// Validate socket.
atpInfo = FindAtpInfoFor(sourceSocket);
if (atpInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
// Validate arguments.
if (requestBufferSize < 0 or
requestBufferSize > atpInfo->maximumSinglePacketDataSize)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpBadBufferSize);
}
if (responseBufferSize < 0 or
responseBufferSize > (atpInfo->maximumSinglePacketDataSize *
AtpMaximumResponsePackets))
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpBadBufferSize);
}
if (retryInterval is 0)
retryInterval = 2;
if (retryInterval < 0)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpBadRetryInfo);
}
if (retryCount isnt AtpInfiniteRetries and retryCount < 0)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpBadRetryInfo);
}
if (trelTimerValue < FirstValidTRelTimerValue or
trelTimerValue > LastValidTRelTimerValue)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpBadTRelTimer);
}
//
// Okay, allocate a request handler (or TCB as Apple would say) so we can
// start filling it in.
//
request = (AtpSendRequest)Calloc(sizeof(*request), 1);
if (request is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpCouldNotPostRequest);
}
// Fill 'er up!
request->sourceSocket = sourceSocket;
request->destination = destination;
request->transactionId = transactionId;
request->exactlyOnce = exactlyOnce;
request->completionRoutine = completionRoutine;
request->userData = userData;
request->requestOpaqueBuffer = requestOpaqueBuffer;
request->requestBufferSize = (short)requestBufferSize;
if (requestUserBytes isnt empty)
MoveMem(request->requestUserBytes, requestUserBytes, AtpUserBytesSize);
else
FillMem(request->requestUserBytes, 0, AtpUserBytesSize);
request->responseOpaqueBuffer = responseOpaqueBuffer;
request->responseBufferSize = (short)responseBufferSize;
request->responseUserBytes = responseUserBytes;
request->bitmap = AtpBufferSizeToBitmap(responseBufferSize,
atpInfo->maximumSinglePacketDataSize);
for (index = 0; index < AtpMaximumResponsePackets; index += 1)
request->packetsIn[index].received = False;
request->retryInterval = (short)retryInterval;
request->retryCount = (short)retryCount;
request->trelTimerValue = trelTimerValue;
// Enqueue it.
request->next = atpInfo->sendRequestQueue;
atpInfo->sendRequestQueue = request;
// Arm the retry timer, and we're finished.
request->id = additionalData.id = nextId++;
additionalData.socket = request->sourceSocket;
additionalData.pointer = (char *)request;
request->timerId = StartTimer(AtpRequestTimerExpired,
retryInterval,
sizeof(AdditionalData),
(char *)&additionalData);
// Okay, send the request.
AtpTransmitRequest(request);
#if VerboseMessages
printf("AtpPostRequest: from %d to %d:%d:%d; tid = %u.\n",
sourceSocket,
destination.networkNumber, destination.nodeNumber,
destination.socketNumber, transactionId);
#endif
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} // AtpPostRequest
AppleTalkErrorCode far AtpEnqueueRequestHandler(
long far *requestHandlerId,
long socket, // "Our" AppleTalk address.
//
void far *opaqueBuffer, // User "buffer" for request data (may be
// empty).
//
//
int bufferSize, // Size, in bytes, of buffer (ignored if
// buffer is empty).
//
//
char far *userBytes, // User buffer for ATP "userBytes" (may be
// empty).
//
AtpIncomingRequestHandler *completionRoutine,
// Routine to call when request comes in.
//
long unsigned userData) // Arbitrary data passed on to the completion
// routine.
//
{
//
// Our job in life is simply to enqueue a handler for an incoming ATP
// request to "our" (destination) socket. When a matching request arrives,
// we invoke the supplied completion routine as follows:
//
// (*completionRoutine)(errorCode, userData, source, opaqueBuffer,
// bufferSize, userBytes, exactlyOnce,
// trelTimerValue, transactionId, bitmap);
//
// The arguments are:
//
// errorCode - an AppleTalkErrorCode; either ATnoError or
// ATatpRequestBufferTooSmall. The latter if the
// buffer size specified in the AtpEnqueueRequestHandler
// call could not hold all of the ATP request data. In
// this case, as much data as will fit is returned.
// This also can be ATatpTransactionAborted.
//
// userData - a longword; the "userData" that was passed to the
// corresponding AtpEnqueueRequestHandler call.
//
// source - an AppleTalkAddress; the internet source of the ATP
// request.
//
// buffer - a void*; as passed to AtpEnqueueRequestHandler where
// the ATP request data has been written. If an empty
// pointer is passed to AtpEnqueueRequestHandler, when
// the completion routine is called this argument will
// simply point at the Atp data within the Ddp datagram;
// thus, potential removing a buffer copy. Note that
// if a non-Empty pointer was supplied, "opaque" data
// will be written into user space; an Empty pointer will
// cause a real "char *" to be passed to the completion
// routine.
//
// bufferSize - an int; the number of bytes stored in the location
// pointed to by "buffer".
//
// userBytes - a char*; as passed to AtpEnqueueRequestHandler where
// the ATP "user bytes" have been written. If an empty
// pointer is passed to AtpEnqueueRequestHandler, when
// the completion routine is called this argument will
// simply point at the Atp user bytes within the Ddp
// datagram; thus, potentially removing a small buffer
// copy.
//
// exactlyOnce - an int; "1" if exactly-once mode was requested, "0"
// otherwise.
//
// trelTimerValue- TRelTimerValue; how long should we expect to wait for
// a release.
//
// transactionId - a short unsigned int; the ATP transaction ID of the
// request.
//
// bitmap - a short unsigned int; the ATP response bitmap of the
// request.
//
//
AtpInfo atpInfo;
AtpReceiveRequest requestHandler;
Boolean inUse;
// Okay, we're going to enqueue the request handler, defer packets...
DeferTimerChecking();
DeferAtpPackets();
// Find out atpInfo.
atpInfo = FindAtpInfoFor(socket);
if (atpInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
if (bufferSize < 0)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpBadBufferSize);
}
if (completionRoutine is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpCompletionRoutineRequired);
}
// Pick a new requestHandlerId.
inUse = True;
while(inUse)
{
inUse = False;
if ((atpInfo->lastRequestHandlerId += 1) < 0)
atpInfo->lastRequestHandlerId = 0;
for (requestHandler = atpInfo->receiveRequestQueue;
requestHandler isnt empty;
requestHandler = requestHandler->next)
if (requestHandler->requestHandlerId is atpInfo->lastRequestHandlerId)
inUse = True;
}
// Allocate and enqueue the request handler.
requestHandler = (AtpReceiveRequest)Malloc(sizeof(*requestHandler));
if (requestHandler is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpCouldNotEnqueueRequest);
}
requestHandler->requestHandlerId = atpInfo->lastRequestHandlerId;
requestHandler->completionRoutine = completionRoutine;
requestHandler->userData = userData;
requestHandler->opaqueBuffer = opaqueBuffer;
requestHandler->bufferSize = (short)bufferSize;
requestHandler->userBytes = userBytes;
requestHandler->next = atpInfo->receiveRequestQueue;
atpInfo->receiveRequestQueue = requestHandler;
if (requestHandlerId isnt empty)
*requestHandlerId = requestHandler->requestHandlerId;
// Okay, the deed is done.
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} // AtpEnqueueRequestHandler
AppleTalkErrorCode far AtpPostResponse(
long sourceSocket, // "Our" AppleTalk address.
AppleTalkAddress destination, // Who are sending the response too?
short unsigned transactionId, // What request are we responding too?
void far *responseOpaqueBuffer, // Response data.
int responseBufferSize, // Size, in bytes, of buffer.
char far *responseUserBytes, // Response "user bytes", may be empty.
Boolean exactlyOnce, // Response mode.
AtpIncomingReleaseHandler *completionRoutine,
//
// Completion routine; called after xmit
// in non-exactly once mode; after release
// for exactly once mode; may be empty.
//
long unsigned userData) // User data passed to completionRoutine.
{
//
// If the completion rotuine is supplied, it is called as follows:
//
// (*completionRoutine)(errorCode, userData, source, transactionId);
//
// The arguments are:
//
// errorCode - an AppleTalkErrorCode; either ATnoError or
// ATatpNoRelease.
//
// userData - a longword; the "userData" that was passed to the
// corresponding AtpSendResponse call.
//
// source - an AppleTalkAddress; where did the release come
// from? The source of the request.
//
// transactionId - a short unsinged int; as passed to AtpSendResponse.
//
// The "completionRotuine" (if supplied) will be called before AtpSendResponse
// returns in non-exactly once mode.
//
StaticForSmallStack AtpSendResponse response;
StaticForSmallStack AtpInfo atpInfo;
StaticForSmallStack short unsigned bitmap;
StaticForSmallStack AdditionalData additionalData;
StaticForSmallStack Boolean explicitZero;
// We're mucking with the databases...
DeferTimerChecking();
DeferAtpPackets();
atpInfo = FindAtpInfoFor(sourceSocket);
if (atpInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
if (responseBufferSize < 0 or
responseBufferSize > (atpInfo->maximumSinglePacketDataSize *
AtpMaximumResponsePackets))
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpResponseTooBig);
}
//
// If we're exactly once mode, we should have a pending sendResponse structure
// created when the request came in.
//
if (exactlyOnce)
{
for (response = atpInfo->sendResponseQueue;
response isnt empty;
response = response->next)
if (transactionId is response->transactionId and
sourceSocket is response->sourceSocket and
AppleTalkAddressesEqual(&destination, &response->destination))
break;
if (response is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpNoMatchingTransaction);
}
if (responseBufferSize >
AtpBitmapToBufferSize(response->bitmap,
atpInfo->maximumSinglePacketDataSize))
{
HandleAtpPackets();
HandleDeferredTimerChecks();
//
return(ATatpResponseTooBig); // In this case, we'll let our caller
// try again with a smaller buffer,
// if that doesn't happen the response
// will get timed out when the release
// timer goes off.
//
}
if (response->responseBufferSize isnt AtpNoResponseKnownYet)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpAlreadyRespondedTo);
}
//
// Okay, all looks to be fine, fill in the needed field of the response
// structure.
//
response->completionRoutine = completionRoutine;
response->userData = userData;
bitmap = response->bitmap;
explicitZero = response->explicitZero;
if (responseUserBytes isnt empty)
MoveMem(response->responseUserBytes, responseUserBytes,
AtpUserBytesSize);
else
FillMem(response->responseUserBytes, 0, AtpUserBytesSize);
response->responseOpaqueBuffer = responseOpaqueBuffer;
response->responseBufferSize = (short)responseBufferSize;
}
else
{
bitmap = AtpBufferSizeToBitmap(responseBufferSize,
atpInfo->maximumSinglePacketDataSize);
explicitZero = (bitmap is 0);
}
// If exactly once mode, restart the release timer.
if (exactlyOnce)
{
CancelTimer(response->timerId);
additionalData.id = response->id;
additionalData.socket = response->sourceSocket;
additionalData.pointer = (char *)response;
response->timerId = StartTimer(AtpReleaseTimerExpired,
trelTimerSeconds[response->
trelTimerValue],
sizeof(AdditionalData),
(char *)&additionalData);
}
// Okay, send the response.
AtpTransmitResponse(sourceSocket, destination, transactionId,
responseOpaqueBuffer, responseBufferSize,
responseUserBytes, bitmap, explicitZero,
atpInfo->maximumSinglePacketDataSize);
#if VerboseMessages
printf("AtpPostResponse: from %d to %d:%d:%d; tid = %u.\n",
sourceSocket,
destination.networkNumber, destination.nodeNumber,
destination.socketNumber, transactionId);
#endif
//
// If we're not exactly once mode, and we have a completion routine, call
// it.
//
HandleAtpPackets();
HandleDeferredTimerChecks();
if (not exactlyOnce and completionRoutine isnt empty)
(*completionRoutine)(ATnoError, userData, destination, transactionId);
// All set...
return(ATnoError);
} // AtpPostResponse
#if Iam an OS2
#pragma optimize ("eg", on)
#endif
AppleTalkErrorCode far AtpCancelRequestHandler(
//
long socket, // AppleTalk address on which the request
// handler originated.
//
long requestHandlerId, // Transaction ID of the request.
//
Boolean cancelDueToClose) // All external caller's should pass "False;"
// Atp will internally use True or False.
//
{
AtpReceiveRequest requestHandler, previousRequestHandler;
AtpInfo atpInfo;
AtpIncomingRequestHandler *incomingRequest;
long unsigned userData;
static AppleTalkAddress dummyAddress;
AppleTalkErrorCode errorCode;
// Validate socket.
DeferTimerChecking();
DeferAtpPackets();
atpInfo = FindAtpInfoFor(socket);
if (atpInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
// See if we can find the specified receive request handler.
for (requestHandler = atpInfo->receiveRequestQueue,
previousRequestHandler = empty;
requestHandler isnt empty;
previousRequestHandler = requestHandler,
requestHandler = requestHandler->next)
if (requestHandler->requestHandlerId is requestHandlerId)
break;
if (requestHandler is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpNoMatchingTransaction);
}
// Okay, dequeue the request handler.
if (previousRequestHandler is empty)
atpInfo->receiveRequestQueue = requestHandler->next;
else
previousRequestHandler->next = requestHandler->next;
//
// We want to call the completion routine, so pull out the data before
// freeing the request handler.
//
incomingRequest = requestHandler->completionRoutine;
userData = requestHandler->userData;
Free(requestHandler);
// All set!
errorCode = (cancelDueToClose ? ATsocketClosed : ATatpTransactionAborted);
HandleAtpPackets();
HandleDeferredTimerChecks();
(*incomingRequest)(errorCode, userData, dummyAddress, empty,
0, empty, False, 0, 0, 0);
return(ATnoError);
} // AtpCancelRequestHandler
AppleTalkErrorCode far AtpCancelRequest(
//
long socket, // AppleTalk address on which the request
// originated.
//
short unsigned transactionId, // Transaction ID of the request.
//
Boolean cancelDueToClose) // All external caller's should pass "False;"
// Atp will internally use True or False.
//
{
AtpSendRequest request, previousRequest;
AtpInfo atpInfo;
AtpIncomingResponseHandler *incomingResponse;
long unsigned userData;
AppleTalkAddress destination;
AppleTalkErrorCode errorCode;
// Validate socket.
DeferTimerChecking();
DeferAtpPackets();
atpInfo = FindAtpInfoFor(socket);
if (atpInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
// Can we find the specified response control block?
for (previousRequest = empty,
request = atpInfo->sendRequestQueue;
request isnt empty;
previousRequest = request,
request = request->next)
if (request->transactionId is transactionId)
break;
if (request is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpNoMatchingTransaction);
}
// Unthread the request from the queue.
if (previousRequest is empty)
atpInfo->sendRequestQueue = request->next;
else
previousRequest->next = request->next;
CancelTimer(request->timerId);
// Call the completion routine with an abort.
incomingResponse = request->completionRoutine;
userData = request->userData;
destination = request->destination;
Free(request);
errorCode = (cancelDueToClose ? ATsocketClosed : ATatpTransactionAborted);
HandleAtpPackets();
HandleDeferredTimerChecks();
if (incomingResponse isnt empty)
(*incomingResponse)(errorCode, userData, destination,
empty, 0, empty, 0);
// All set.
return(ATnoError);
} // AtpCancelRequest
AppleTalkErrorCode far AtpCancelResponse(
//
long socket, // AppleTalk address on which the response
// originated (or should originate);
// destination of request.
//
//
AppleTalkAddress destination, // AppleTalk address of the source of the
// request; destination of the response.
//
short unsigned transactionId, // Transaction ID to cancel.
//
Boolean cancelDueToClose) // All external caller's should pass "False;"
// Atp will internally use True or False.
//
{
AtpSendResponse response, previousResponse;
AtpInfo atpInfo;
AtpIncomingReleaseHandler *incomingRelease;
long unsigned userData;
AppleTalkErrorCode errorCode;
// Validate socket.
DeferTimerChecking();
DeferAtpPackets();
atpInfo = FindAtpInfoFor(socket);
if (atpInfo is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
// Can we find the specified response control block?
for (previousResponse = empty,
response = atpInfo->sendResponseQueue;
response isnt empty;
previousResponse = response,
response = response->next)
if (response->transactionId is transactionId and
AppleTalkAddressesEqual(&destination, &response->destination))
break;
if (response is empty)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
return(ATatpNoMatchingTransaction);
}
// Unthread the response from the queue.
if (previousResponse is empty)
atpInfo->sendResponseQueue = response->next;
else
previousResponse->next = response->next;
CancelTimer(response->timerId);
// Call the completion routine with an abort.
incomingRelease = response->completionRoutine;
userData = response->userData;
Free(response);
errorCode = (cancelDueToClose ? ATsocketClosed : ATatpTransactionAborted);
HandleAtpPackets();
HandleDeferredTimerChecks();
if (incomingRelease isnt empty)
(*incomingRelease)(errorCode, userData, destination, 0);
// All set.
return(ATnoError);
} // AtpCancelResponse
void _near DeferAtpPackets(void)
{
EnterCriticalSection();
deferIncomingAtpPacketsCount += 1;
LeaveCriticalSection();
return;
} // DeferAtpPackets
void _near HandleAtpPackets(void)
{
DeferredPacket deferredPacket;
if (deferIncomingAtpPacketsCount is 0)
{
ErrorLog("HandleAtpPackets", ISevError, __LINE__, UnknownPort,
IErrAtpDeferCountZero, IMsgAtpDeferCountZero,
Insert0());
return;
}
// Decrement defer count.
EnterCriticalSection();
deferIncomingAtpPacketsCount -= 1;
//
// This routine can be called indirectly recursively via the call to
// AtpPacketIn... we don't want to let our stack frame get too big, so
// if we're already trying to handle deferred packets higher on the
// stack, just ignore it here.
//
if (handleAtpPacketsNesting isnt 0)
{
LeaveCriticalSection();
return;
}
handleAtpPacketsNesting += 1;
// If we're no longer defering packets, handle any queued ones.
if (deferIncomingAtpPacketsCount is 0)
{
while(headOfDeferredPacketList isnt empty)
{
deferredPacket = headOfDeferredPacketList;
headOfDeferredPacketList = headOfDeferredPacketList->next;
if (headOfDeferredPacketList is empty)
tailOfDeferredPacketList = empty;
if ((currentDeferredPacketCount -= 1) < 0)
{
ErrorLog("HandleAtpPackets", ISevError, __LINE__, UnknownPort,
IErrAtpBadDeferCount, IMsgAtpBadDeferCount,
Insert0());
currentDeferredPacketCount = 0;
}
LeaveCriticalSection();
AtpPacketIn(deferredPacket->errorCode, (long)0,
deferredPacket->port, deferredPacket->source,
deferredPacket->destinationSocket, DdpProtocolAtp,
deferredPacket->datagram, deferredPacket->datagramLength,
deferredPacket->actualDestination);
Free(deferredPacket);
EnterCriticalSection();
}
}
handleAtpPacketsNesting -= 1;
LeaveCriticalSection();
return;
} // HandleAtpPackets
ExternForVisibleFunction long far
AtpPacketIn(AppleTalkErrorCode errorCode,
long unsigned userData,
int port,
AppleTalkAddress source,
long destinationSocket,
int protocolType,
char far *datagram,
int datagramLength,
AppleTalkAddress actualDestination)
{
StaticForSmallStack AtpInfo atpInfo;
StaticForSmallStack short unsigned functionCode, sequenceNumber;
StaticForSmallStack Boolean endOfMessage, sendTransactionStatus;
StaticForSmallStack AtpReceiveRequest requestHandler;
StaticForSmallStack AtpSendResponse response, previousResponse;
StaticForSmallStack AtpSendRequest request, previousRequest;
StaticForSmallStack Boolean bufferTooSmall;
StaticForSmallStack short expectedResponseSize;
StaticForSmallStack short unsigned index;
StaticForSmallStack short unsigned correctBit, bitToReset;
StaticForSmallStack short startOffset, totalBufferSpaceNeeded;
StaticForSmallStack AdditionalData additionalData;
StaticForSmallStack DeferredPacket deferredPacket;
short unsigned bitmap;
unsigned short transactionId;
short atpDataSize;
#if Iam an OS2
//
// Can you spell "real hack"? Good... I knew you could. We really
// need stack space here (in stupid OS/2 land). And, this routine
// really needs to be reentrant... so malloc our dynamic data. Sigh.
//
struct { AtpIncomingRequestHandler *incomingRequest;
AtpIncomingResponseHandler *incomingResponse;
AtpIncomingReleaseHandler *incomingRelease;
char far *localBuffer, far *localUserBytes;
} far *localData = Malloc(sizeof(*localData));
#define incomingRequest (localData->incomingRequest)
#define incomingResponse (localData->incomingResponse)
#define incomingRelease (localData->incomingRelease)
#define localBuffer (localData->localBuffer)
#define localUserBytes (localData->localUserBytes)
#define FreeTempSpace() Free(localData)
#else
AtpIncomingRequestHandler *incomingRequest;
AtpIncomingResponseHandler *incomingResponse;
AtpIncomingReleaseHandler *incomingRelease;
char far *localBuffer, far *localUserBytes;
#define FreeTempSpace()
#endif
char tempUserBytes[AtpUserBytesSize];
short actualSize;
Boolean exactlyOnce;
TRelTimerValue trelTimerValue;
// Check for incoming errors...
bufferTooSmall = False;
if (errorCode isnt ATnoError and
errorCode isnt ATsocketClosed)
{
ErrorLog("AtpPacketIn", ISevError, __LINE__, port,
IErrAtpFunnyIncomingError, IMsgAtpFunnyIncomingError,
Insert0());
FreeTempSpace();
return((long)True);
}
// Should we be defering incoming packets?
EnterCriticalSection();
if (deferIncomingAtpPacketsCount > 0)
{
#if VerboseMessages
printf("AtpPacketIn: from %d:%d:%d to %d; Deferred.\n",
source.networkNumber, source.nodeNumber, source.socketNumber,
destinationSocket);
#endif
if (currentDeferredPacketCount is MaximumDeferredPackets)
{
LeaveCriticalSection();
ErrorLog("AtpPacketIn", ISevWarning, __LINE__, port,
IErrAtpLosingData, IMsgAtpLosingData,
Insert0());
FreeTempSpace();
return((long)True);
}
LeaveCriticalSection();
deferredPacket = (DeferredPacket)Malloc(sizeof(*deferredPacket) +
datagramLength);
if (deferredPacket is empty)
{
ErrorLog("AtpPacketIn", ISevError, __LINE__, port,
IErrAtpOutOfMemory, IMsgAtpOutOfMemory,
Insert0());
FreeTempSpace();
return((long)True);
}
//
// Fill in the data strcuture, and place the packet at the end of the
// queue.
//
deferredPacket->errorCode = errorCode;
deferredPacket->next = empty;
deferredPacket->port = port;
deferredPacket->source = source;
deferredPacket->destinationSocket = destinationSocket;
deferredPacket->datagramLength = (short)datagramLength;
deferredPacket->actualDestination = actualDestination;
if (datagram isnt empty)
MoveMem(deferredPacket->datagram, datagram, datagramLength);
EnterCriticalSection();
if (tailOfDeferredPacketList is empty)
tailOfDeferredPacketList = headOfDeferredPacketList = deferredPacket;
else
{
tailOfDeferredPacketList->next = deferredPacket;
tailOfDeferredPacketList = deferredPacket;
}
// All set... return.
currentDeferredPacketCount += 1;
LeaveCriticalSection();
FreeTempSpace();
return((long)True);
}
else
LeaveCriticalSection();
//
// Well, from hear on in, we're in the thick of it, so defer incoming
// packets.
//
DeferTimerChecking();
DeferAtpPackets();
if (errorCode is ATsocketClosed)
{
//
// If we're a result of a AtpCloseSocketOnNode, just ignore it, else
// somehow else the the socket got closed and we should use this
// oportunity to clean up our brains. If an AtpCloseSocketOnNode is
// already in progress, we won't be able to find our ATP info!
//
if (FindAtpInfoFor(destinationSocket) isnt empty)
AtpCloseSocketOnNode(destinationSocket);
HandleAtpPackets();
HandleDeferredTimerChecks();
FreeTempSpace();
return((long)True);
}
if (protocolType isnt DdpProtocolAtp)
{
HandleAtpPackets();
HandleDeferredTimerChecks();
FreeTempSpace();
return((long)True); // Why are these guys talking to us???
}
if (datagramLength < AtpDataOffset)
{
ErrorLog("AtpPacketIn", ISevWarning, __LINE__, port,
IErrAtpPacketTooShort, IMsgAtpPacketTooShort,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
FreeTempSpace();
return((long)True);
}
// Find the ATP descriptor for the destination.
if ((atpInfo = FindAtpInfoFor(destinationSocket)) is empty)
{
ErrorLog("AtpPacketIn", ISevError, __LINE__, port,
IErrAtpWhyUs, IMsgAtpWhyUs,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
FreeTempSpace();
return((long)True);
}
// Extract static fields from the ATP header.
functionCode = (short unsigned)(datagram[AtpCommandControlOffset] &
AtpFunctionCodeMask);
trelTimerValue = (TRelTimerValue)(datagram[AtpCommandControlOffset] &
AtpTRelTimerValueMask);
if (trelTimerValue > LastValidTRelTimerValue)
{
trelTimerValue = ThirtySecondsTRelTimer;
ErrorLog("AtpPacketIn", ISevWarning, __LINE__, port,
IErrAtpFunnyTRelTimerValue, IMsgAtpFunnyTRelTimerValue,
Insert0());
}
exactlyOnce = ((datagram[AtpCommandControlOffset] & AtpExactlyOnceMask)
isnt 0);
endOfMessage = ((datagram[AtpCommandControlOffset] & AtpEndOfMessageMask)
isnt 0);
sendTransactionStatus = ((datagram[AtpCommandControlOffset] &
AtpSendTransactionStatusMask) isnt 0);
bitmap = sequenceNumber = (unsigned char)datagram[AtpBitmapOffset];
transactionId = (unsigned short)
(((unsigned char)datagram[AtpTransactionIdOffset] << 8)
+ (unsigned char)datagram[AtpTransactionIdOffset + 1]);
atpDataSize = (short)(datagramLength - AtpDataOffset);
if (atpDataSize > atpInfo->maximumSinglePacketDataSize)
{
ErrorLog("AtpPacketIn", ISevVerbose, __LINE__, port,
IErrAtpTooMuchData, IMsgAtpTooMuchData,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
FreeTempSpace();
return((long)True);
}
// Okay, do the right thing based on the ATP function code.
switch(functionCode)
{
case AtpRequestFunctionCode:
#if VerboseMessages
printf("AtpPacketIn [Request]: from %d:%d:%d to %d; tid = %u.\n",
source.networkNumber, source.nodeNumber, source.socketNumber,
destinationSocket, transactionId);
#endif
//
// First, check to see if this is a request for a response that we
// already have queued and are awaiting a release for.
//
if (exactlyOnce)
for (response = atpInfo->sendResponseQueue;
response isnt empty;
response = response->next)
{
if (transactionId isnt response->transactionId or
not AppleTalkAddressesEqual(&source,
&response->destination) or
destinationSocket isnt response->sourceSocket)
continue;
//
// We know about this request already... re-transmit the response
// and restart the release timer.
//
CancelTimer(response->timerId);
additionalData.id = response->id;
additionalData.socket = response->sourceSocket;
additionalData.pointer = (char *)response;
response->timerId = StartTimer(AtpReleaseTimerExpired,
trelTimerSeconds[response->
trelTimerValue],
sizeof(AdditionalData),
(char *)&additionalData);
response->bitmap = bitmap;
#if VerboseMessages
printf("AtpPacketIn [Request]: already know response.\n");
#endif
AtpTransmitResponse(destinationSocket, source, transactionId,
response->responseOpaqueBuffer,
response->responseBufferSize,
response->responseUserBytes,
bitmap,
response->explicitZero,
atpInfo->maximumSinglePacketDataSize);
HandleAtpPackets();
HandleDeferredTimerChecks();
FreeTempSpace();
return((long)True);
}
// Okay, do we have a queued request handler?
if ((requestHandler = atpInfo->receiveRequestQueue) is empty)
#if VerboseMessages
printf("AtpPacketIn [Request]: ignored; no request handler.\n");
#else
;
#endif
else
{
// Decode the response bitmap...
if ((expectedResponseSize =
AtpBitmapToBufferSize(bitmap,
atpInfo->maximumSinglePacketDataSize)) < 0)
{
#if VerboseMessages
printf("AtpPacketIn [Request]: bad bitmap.\n");
#endif
HandleAtpPackets();
HandleDeferredTimerChecks();
FreeTempSpace();
return((long)True);
}
//
// Okay, if the request is in exactly-once mode, build a send-
// response structure for this beast. Set response data size
// to indicate that we don't have a response yet. Start the
// release timer.
//
if (exactlyOnce)
{
if ((response = (AtpSendResponse)Calloc(sizeof(*response), 1))
is empty)
{
ErrorLog("AtpPacketIn", ISevError, __LINE__, port,
IErrAtpOutOfMemory, IMsgAtpOutOfMemory,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
FreeTempSpace();
return((long)True);
}
else
{
response->sourceSocket = destinationSocket;
response->destination = source;
response->transactionId = transactionId;
response->trelTimerValue = trelTimerValue;
response->bitmap = bitmap;
response->explicitZero = (bitmap is 0);
response->responseBufferSize = AtpNoResponseKnownYet;
response->completionRoutine = empty;
response->next = atpInfo->sendResponseQueue;
atpInfo->sendResponseQueue = response;
response->id = additionalData.id = nextId++;
additionalData.socket = response->sourceSocket;
additionalData.pointer = (char *)response;
response->timerId = StartTimer(AtpReleaseTimerExpired,
trelTimerSeconds[trelTimerValue],
sizeof(AdditionalData),
(char *)&additionalData);
}
}
//
// Unthread the request handler from the queue and prepare
// to activate the handler.
//
atpInfo->receiveRequestQueue = requestHandler->next;
//
// Move the data into user space, if our called allocated space
// for this... otherwise, just pas along pointers into the Ddp
// datagram.
//
if (requestHandler->userBytes is empty)
localUserBytes = &datagram[AtpUserBytesOffset];
else
{
MoveMem(requestHandler->userBytes, &datagram[AtpUserBytesOffset],
AtpUserBytesSize);
localUserBytes = requestHandler->userBytes;
}
if (requestHandler->opaqueBuffer is empty)
localBuffer = &datagram[AtpDataOffset];
else
{
if (atpDataSize > requestHandler->bufferSize)
{
bufferTooSmall = True;
if (atpDataSize isnt 0)
MoveToOpaque(requestHandler->opaqueBuffer, 0,
&datagram[AtpDataOffset],
requestHandler->bufferSize);
atpDataSize = requestHandler->bufferSize;
}
else if (atpDataSize isnt 0)
MoveToOpaque(requestHandler->opaqueBuffer, 0,
&datagram[AtpDataOffset], atpDataSize);
localBuffer = requestHandler->opaqueBuffer;
}
//
// We're about to free the request handler structure, so pull
// out the information that we need to call the completion
// routine with.
//
incomingRequest = requestHandler->completionRoutine;
userData = requestHandler->userData;
// Free the request handler, and invoke the completion routine.
Free(requestHandler);
if (bufferTooSmall)
errorCode = ATatpRequestBufferTooSmall;
else
errorCode = ATnoError;
#if VerboseMessages
printf("AtpPacketIn [Request]: calling completion routine.\n");
#endif
HandleAtpPackets();
HandleDeferredTimerChecks();
(*incomingRequest)(errorCode, userData, source, localBuffer,
atpDataSize, localUserBytes, exactlyOnce,
trelTimerValue, transactionId, bitmap);
FreeTempSpace();
return((long)True);
}
break;
case AtpResponseFunctionCode:
#if VerboseMessages
printf("AtpPacketIn [Response]: from %d:%d:%d to %d; tid = %u.\n",
source.networkNumber, source.nodeNumber, source.socketNumber,
destinationSocket, transactionId);
#endif
// Okay, do we have a pending request to match this response?
for (previousRequest = empty,
request = atpInfo->sendRequestQueue;
request isnt empty;
previousRequest = request,
request = request->next)
if (transactionId is request->transactionId and
AppleTalkAddressesEqual(&source, &request->destination))
break;
if (request is empty)
{
ErrorLog("AtpPacketIn", ISevVerbose, __LINE__, port,
IErrAtpRespToDeadReq, IMsgAtpRespToDeadReq,
Insert0());
break;
}
//
// If we're the first response and the user cares about "userBytes",
// copy these for return. Save a local copy too, in case the user
// didn't supply us a buffer to hold 'em.
//
if (sequenceNumber is 0 and request->responseUserBytes isnt empty)
MoveMem(request->responseUserBytes, &datagram[AtpUserBytesOffset],
AtpUserBytesSize);
if (sequenceNumber is 0)
MoveMem(request->tempResponseUserBytes,
&datagram[AtpUserBytesOffset],
AtpUserBytesSize);
//
// The bitmap could be zero now, if the user only wanted the userBytes
// and not response buffer...
//
if (request->bitmap isnt 0)
{
//
// Do we want this response? Is the corresponding bit in our current
// bitmap set?
//
if (sequenceNumber > AtpMaximumResponsePackets-1)
{
ErrorLog("AtPacketIn", ISevWarning, __LINE__, port,
IErrAtpOutOfSequence, IMsgAtpOutOfSequence,
Insert0());
break;
}
correctBit = 1;
for (index = 0; index < sequenceNumber; index += 1)
correctBit <<= 1;
if ((request->bitmap & correctBit) is 0)
break; // We don't care...
//
// Okay, it's a response we want, clear the bit in the request
// bitmap.
//
request->bitmap &= (unsigned short)~correctBit;
//
// Okay, we have to move the data into the user's buffer space, is
// there room?
//
startOffset = (short)(sequenceNumber *
atpInfo->maximumSinglePacketDataSize);
totalBufferSpaceNeeded = (short)(startOffset + atpDataSize);
if (request->responseBufferSize < totalBufferSpaceNeeded)
{
//
// This should be a rare case; packet was within bitmap limits,
// but still wouldn't fit into user space. The other way this
// could occure is if the responder is sending less than full
// responses -- we don't "synch" up the user buffer until all
// packets hace been received.
//
// We want to give up now, call the completion rotuine signaling
// the error -- unthread and free the request control block --
// cancel the retry timer.
//
incomingResponse = request->completionRoutine;
userData = request->userData;
if (previousRequest is empty)
atpInfo->sendRequestQueue = request->next;
else
previousRequest->next = request->next;
CancelTimer(request->timerId);
Free(request);
HandleAtpPackets();
HandleDeferredTimerChecks();
if (incomingResponse isnt empty)
(*incomingResponse)(ATatpResponseBufferTooSmall, userData,
source, empty, 0, empty, 0);
FreeTempSpace();
return((long)True);
}
// Okay, we have room to copy the data into user space.
MoveToOpaque(request->responseOpaqueBuffer, startOffset,
&datagram[AtpDataOffset], atpDataSize);
request->packetsIn[sequenceNumber].received = True;
request->packetsIn[sequenceNumber].dataSize = atpDataSize;
//
// If the "endOfMessage" bit is set, we need to reset all higher
// order bits in the bitmap.
//
if (endOfMessage)
for (bitToReset = (unsigned short)(sequenceNumber + 1);
bitToReset < AtpMaximumResponsePackets;
bitToReset += 1)
{
request->packetsIn[bitToReset].received = False;
correctBit = 1;
for (index = 0; index < bitToReset; index += 1)
correctBit <<= 1;
request->bitmap &= (unsigned short)~correctBit;
}
//
// If the "send transaction status" bit is set, do it, and reset the
// the retry timer.
//
if (sendTransactionStatus)
{
CancelTimer(request->timerId);
additionalData.id = request->id;
additionalData.socket = request->sourceSocket;
additionalData.pointer = (char *)request;
request->timerId = StartTimer(AtpRequestTimerExpired,
request->retryInterval,
sizeof(AdditionalData),
(char *)&additionalData);
AtpTransmitRequest(request);
}
}
// If the bitmap is non-zero, we are still awaiting more responses.
if (request->bitmap isnt 0)
break;
//
// Great! We're got the entire response. We must:
// 1. Cancel the retry timer.
// 2. Send a release (if in exactly once mode).
// 3. Synch of the user buffer, if needed.
// 4. Unthread and free the request control block.
// 5. Call the completion routine.
//
//
CancelTimer(request->timerId);
if (request->exactlyOnce)
AtpTransmitRelease(request);
actualSize =
AtpSynchUpResponseBuffer(request,
atpInfo->maximumSinglePacketDataSize);
if (previousRequest is empty)
atpInfo->sendRequestQueue = request->next;
else
previousRequest->next = request->next;
//
// Pull data out of the request control block, so we can free it
// before the call.
//
incomingResponse = request->completionRoutine;
userData = request->userData;
localBuffer = request->responseOpaqueBuffer;
localUserBytes = request->responseUserBytes;
if (localUserBytes is Empty)
{
MoveMem(tempUserBytes, request->tempResponseUserBytes,
AtpUserBytesSize);
localUserBytes = tempUserBytes;
}
// Okay, free the control block and call the completion routine.
Free(request);
HandleAtpPackets();
HandleDeferredTimerChecks();
if (incomingResponse isnt empty)
(*incomingResponse)(ATnoError, userData, source, localBuffer,
actualSize, localUserBytes, transactionId);
FreeTempSpace();
return((long)True);
case AtpReleaseFunctionCode:
#if VerboseMessages
printf("AtpPacketIn [Release]: from %d:%d:%d to %d; tid = %u.\n",
source.networkNumber, source.nodeNumber, source.socketNumber,
destinationSocket, transactionId);
#endif
//
// Search our send-response queue for the current transaction; if not
// found, ignore the release.
//
for (previousResponse = empty,
response = atpInfo->sendResponseQueue;
response isnt empty;
previousResponse = response,
response = response->next)
if (transactionId is response->transactionId and
AppleTalkAddressesEqual(&source, &response->destination) and
destinationSocket is response->sourceSocket)
break;
if (response is empty)
{
ErrorLog("AtpPacketIn", ISevVerbose, __LINE__, port,
IErrAtpDeadRelease, IMsgAtpDeadRelease,
Insert0());
break;
}
//
// Okay, unthread the response, cancel the release timer, and free
// the structure. Call response completion routine, if needed.
//
if (previousResponse is empty)
atpInfo->sendResponseQueue = response->next;
else
previousResponse->next = response->next;
CancelTimer(response->timerId);
incomingRelease = response->completionRoutine;
userData = response->userData;
Free(response);
HandleAtpPackets();
HandleDeferredTimerChecks();
if (incomingRelease isnt empty)
(*incomingRelease)(ATnoError, userData, source, transactionId);
FreeTempSpace();
return((long)True);
default:
#if VerboseMessages
printf("AtpPacketIn [Bad]: from %d:%d:%d to %d; tid = %u.\n",
source.networkNumber, source.nodeNumber, source.socketNumber,
destinationSocket, transactionId);
#endif
break;
} // Switch on functionCode
// We're finished with this puppy...
HandleAtpPackets();
HandleDeferredTimerChecks();
FreeTempSpace();
return((long)True);
#if Iam an OS2
#undef incomingRequest
#undef incomingResponse
#undef incomingRelease
#undef localBuffer
#undef localUserBytes
#endif
#undef FreeTempSpace
} // AtpPacketIn
ExternForVisibleFunction void
AtpTransmitResponse(long sourceSocket,
AppleTalkAddress destination,
short unsigned transactionId,
void far *responseOpaqueBuffer,
int responseBufferSize,
char far *responseUserBytes,
short unsigned bitmap,
Boolean explicitZero,
short maximumSinglePacketDataSize)
{
StaticForSmallStack BufferDescriptor datagram;
StaticForSmallStack int remainingBytes;
StaticForSmallStack short unsigned int sequenceNumber;
StaticForSmallStack short unsigned int currentBit;
StaticForSmallStack short bytesInPacket;
StaticForSmallStack short bytesSent;
StaticForSmallStack Boolean firstLoop, error;
bytesSent = 0;
sequenceNumber = 0;
currentBit = 1;
firstLoop = True;
error = False;
if (responseBufferSize is AtpNoResponseKnownYet)
{
#if VerboseMessages
printf("AtpTransmitResponse: client hasn't supplied data yet.\n");
#endif
return; // 2nd request before client responded, ignore it.
}
// Send each response packet that is needed.
remainingBytes = responseBufferSize;
while(remainingBytes > 0 or (firstLoop and remainingBytes is 0))
{
firstLoop = False;
if ((bitmap & currentBit) isnt 0 or
(sequenceNumber is 0 and explicitZero)) // Do they want this chunk?
{
bytesInPacket = (short)((remainingBytes > maximumSinglePacketDataSize) ?
maximumSinglePacketDataSize :
remainingBytes);
//
// Depending on the nature of transmit completion, either reference
// or copy the user response buffer.
//
#if TransmitsCompleteSynchronously
if (bytesInPacket > 0)
{
Boolean freeOpaqueDataDescriptor;
void far *opaqueBuffer;
if ((opaqueBuffer =
SubsetOpaqueDataDescriptor(responseOpaqueBuffer, bytesSent,
bytesInPacket,
&freeOpaqueDataDescriptor))
is Empty)
error = True;
if (not error and
(datagram = DescribeBuffer(bytesInPacket, opaqueBuffer,
True)) is Empty)
{
if (freeOpaqueDataDescriptor)
FreeOpaqueDataDescriptor(opaqueBuffer);
error = True;
}
if (not error)
datagram->freeOpaqueDataDescriptor = freeOpaqueDataDescriptor;
}
else
datagram = Empty;
if ((datagram = AllocateHeader(datagram, AtpDataOffset)) is Empty)
error = True;
#else
if ((datagram = NewBufferDescriptor(AtpDataOffset +
bytesInPacket)) is Empty)
error = True;
#endif
if (error)
{
ErrorLog("AtpTransmitResponse", ISevWarning, __LINE__, UnknownPort,
IErrAtpOutOfMemory, IMsgAtpOutOfMemory,
Insert0());
return;
}
// Fill in the ATP header.
datagram->data[AtpCommandControlOffset] = AtpResponseFunctionCode;
datagram->data[AtpTransactionIdOffset] =
(char)(((transactionId >> 8) & 0xFF));
datagram->data[AtpTransactionIdOffset + 1] = (char)(transactionId & 0xFF);
datagram->data[AtpSequenceNumberOffset] = (char)sequenceNumber;
if (responseUserBytes isnt empty)
MoveMem(datagram->data + AtpUserBytesOffset, responseUserBytes,
AtpUserBytesSize);
else
FillMem(datagram->data + AtpUserBytesOffset, 0, AtpUserBytesSize);
// UserBytes only in first packet! Except for PAP!
if (sequenceNumber > 0 and
maximumSinglePacketDataSize isnt PapMaximumDataPacketSize)
FillMem(datagram->data + AtpUserBytesOffset, 0, AtpUserBytesSize);
#if not TransmitsCompleteSynchronously
if (bytesInPacket > 0)
MoveFromOpaque(datagram->data + AtpDataOffset,
responseOpaqueBuffer, bytesSent, bytesInPacket);
#endif
if ((remainingBytes -
maximumSinglePacketDataSize) <= 0) // Last chunk?
datagram->data[AtpCommandControlOffset] |= AtpEndOfMessageMask;
#if Debug
if (DropEveryNthResponse isnt 0 and
(RandomNumber() % DropEveryNthResponse) is 0)
{
FreeBufferChain(datagram);
continue;
}
#endif
DeliverDdp(sourceSocket, destination, DdpProtocolAtp, datagram,
AtpDataOffset + bytesInPacket, Empty, Empty, 0);
}
// Bump positions for next chunk.
sequenceNumber += 1;
currentBit <<= 1;
remainingBytes -= maximumSinglePacketDataSize;
bytesSent += maximumSinglePacketDataSize;
}
// All set.
return;
} // AtpTransmitResponse
ExternForVisibleFunction short
AtpBitmapToBufferSize(short unsigned bitmap,
short maximumSinglePacketDataSize)
{
short bitsOn = 0;
Boolean foundFirstZero = False;
short bitNumber;
bitmap &= 0xFF;
if (bitmap is 0)
return(0);
// A seqeunce of low-order bits must be set, we don't allow holes!
for (bitNumber = 1; bitNumber <= 8; bitNumber += 1)
{
bitsOn += (short)(bitmap & 1);
if ((bitmap & 1) is 0)
foundFirstZero = True;
else if (foundFirstZero)
{
ErrorLog("AtpBitmapToBufferSize", ISevWarning, __LINE__, UnknownPort,
IErrAtpBadBitmap, IMsgAtpBadBitmap,
Insert0());
return(-1);
}
bitmap >>= 1;
}
// Okay, we had a valid bitmap, return the required data size.
return((short)(bitsOn * maximumSinglePacketDataSize));
} // AtpBitmapToBufferSize
ExternForVisibleFunction void far
AtpReleaseTimerExpired(long unsigned timerId,
int dataSize,
char far *incomingAdditionalData)
{
StaticForSmallStack AtpSendResponse response, previousResponse,
nextResponse;
StaticForSmallStack AtpInfo atpInfo;
StaticForSmallStack long id;
StaticForSmallStack long us;
StaticForSmallStack AdditionalData far *additionalData;
AtpIncomingReleaseHandler *incomingRelease;
long unsigned userData;
short unsigned transactionId;
AppleTalkAddress destination;
// "Use" unneeded actual parameter.
timerId;
additionalData = (AdditionalData far *)incomingAdditionalData;
// Validate the data, it should be a pointer to a response control block.
if (dataSize isnt sizeof(AdditionalData))
{
ErrorLog("AtpReleaseTimerExpired", ISevError, __LINE__, UnknownPort,
IErrAtpBadDataSize, IMsgAtpBadDataSize,
Insert0());
HandleDeferredTimerChecks();
return;
}
// We're going to muck with the ATP structures... defer packets.
DeferAtpPackets();
response = (AtpSendResponse)(additionalData->pointer);
id = additionalData->id;
us = additionalData->socket;
// We need to unthread the SendResponse structure from the OpenSocket.
if ((atpInfo = FindAtpInfoFor(us)) is empty)
{
ErrorLog("AtpReleaseTimerExpired", ISevWarning, __LINE__, UnknownPort,
IErrAtpSocketClosed, IMsgAtpSocketClosed,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
for (previousResponse = empty,
nextResponse = atpInfo->sendResponseQueue;
nextResponse isnt empty and
(id isnt nextResponse->id or
nextResponse isnt response);
previousResponse = nextResponse,
nextResponse = nextResponse->next)
// Ring-around-the-rosey ;
if (nextResponse is empty)
{
ErrorLog("AtpReleaseTimerExpired", ISevVerbose, __LINE__, UnknownPort,
IErrAtpMissingResponse, IMsgAtpMissingResponse,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
//
// Pull enough data out of the response structure so we can call the
// completion routine, if needed.
//
incomingRelease = response->completionRoutine;
userData = response->userData;
destination = response->destination;
transactionId = response->transactionId;
if (previousResponse is empty)
atpInfo->sendResponseQueue = response->next;
else
previousResponse->next = response->next;
// Okay, free the guy, and we're done!
Free(response);
HandleAtpPackets();
HandleDeferredTimerChecks();
if (incomingRelease isnt empty)
(*incomingRelease)(ATatpNoRelease, userData, destination, transactionId);
return;
} // AtpReleaseTimerExpired
ExternForVisibleFunction short unsigned
AtpBufferSizeToBitmap(int bufferSize,
short maximumSinglePacketDataSize)
{
short unsigned bitmap = 0;
while(bufferSize > 0)
{
bitmap <<= 1;
bitmap += 1;
bufferSize -= maximumSinglePacketDataSize;
}
return(bitmap);
} // AtpBufferSizeToBitmap
ExternForVisibleFunction void AtpTransmitRequest(AtpSendRequest request)
{
BufferDescriptor datagram;
Boolean error = False;
//
// Depending on the nature of transmit completion, either reference
// or copy the user request buffer.
//
#if TransmitsCompleteSynchronously
if (request->requestBufferSize > 0)
{
if ((datagram = DescribeBuffer(request->requestBufferSize,
request->requestOpaqueBuffer,
True)) is Empty)
error = True;
}
else
datagram = Empty;
if ((datagram = AllocateHeader(datagram, AtpDataOffset)) is Empty)
error = True;
#else
if ((datagram = NewBufferDescriptor(AtpDataOffset +
request->requestBufferSize)) is Empty)
error = True;
#endif
if (error)
{
ErrorLog("AtpTransmitRequest", ISevWarning, __LINE__, UnknownPort,
IErrAtpOutOfMemory, IMsgAtpOutOfMemory,
Insert0());
return;
}
// Build an ATP request datagram from the passed request structure.
datagram->data[AtpCommandControlOffset] = AtpRequestFunctionCode;
datagram->data[AtpCommandControlOffset] |=
(char)(request->trelTimerValue & AtpTRelTimerValueMask);
if (request->exactlyOnce)
datagram->data[AtpCommandControlOffset] |= AtpExactlyOnceMask;
datagram->data[AtpBitmapOffset] = (char)(request->bitmap & 0xFF);
datagram->data[AtpTransactionIdOffset] =
(char)((request->transactionId >> 8) & 0xFF);
datagram->data[AtpTransactionIdOffset + 1] =
(char)(request->transactionId & 0xFF);
MoveMem(datagram->data + AtpUserBytesOffset, request->requestUserBytes,
AtpUserBytesSize);
#if not TransmitsCompleteSynchronously
if (request->requestBufferSize > 0)
MoveFromOpaque(datagram->data + AtpDataOffset,
request->requestOpaqueBuffer, 0,
request->requestBufferSize);
#endif
// Okay, deliver the DDP packet (ignore error)!
#if Debug
{
long temp;
if (DropEveryNthRequest isnt 0 and
((temp = RandomNumber()) % DropEveryNthRequest) is 0)
{
#if (Iam a Primos) and 0
printf("\nDropping request; rand = %d.\n", temp);
#endif
FreeBufferChain(datagram);
return;
}
}
#endif
DeliverDdp(request->sourceSocket, request->destination, DdpProtocolAtp,
datagram, AtpDataOffset + request->requestBufferSize,
Empty, Empty, 0);
return;
} // AtpTransmitRequest
ExternForVisibleFunction void far
AtpRequestTimerExpired(long unsigned timerId,
int dataSize,
char far *incomingAdditionalData)
{
StaticForSmallStack AtpSendRequest request, nextRequest, previousRequest;
StaticForSmallStack AtpInfo atpInfo;
StaticForSmallStack long us;
StaticForSmallStack long id;
StaticForSmallStack AdditionalData far *additionalData;
AtpIncomingResponseHandler *incomingResponse;
long unsigned userData;
AppleTalkAddress destination;
// "Use" unneeded actual parameter.
timerId;
additionalData = (AdditionalData far *)incomingAdditionalData;
// Validate the data, it should be a pointer to a request control block.
if (dataSize isnt sizeof(AdditionalData))
{
ErrorLog("AtpRequestTimerExpired", ISevError, __LINE__, UnknownPort,
IErrAtpBadDataSize, IMsgAtpBadDataSize,
Insert0());
HandleDeferredTimerChecks();
return;
}
DeferAtpPackets();
request = (AtpSendRequest)(additionalData->pointer);
id = additionalData->id;
us = additionalData->socket;
//
// Is this request still pending? There is a vauage chance that it has
// been freed out from under us.
//
if ((atpInfo = FindAtpInfoFor(us)) is empty)
{
ErrorLog("AtpRequestTimerExpired", ISevVerbose, __LINE__, UnknownPort,
IErrAtpSocketClosed, IMsgAtpSocketClosed,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
for (previousRequest = empty,
nextRequest = atpInfo->sendRequestQueue;
nextRequest isnt empty and
(id isnt nextRequest->id or
nextRequest isnt request);
previousRequest = nextRequest,
nextRequest = nextRequest->next)
// Boppity bopp ;
if (nextRequest is empty)
{
ErrorLog("AtpRequestTimerExpired", ISevVerbose, __LINE__, UnknownPort,
IErrAtpMissingRequest, IMsgAtpMissingRequest,
Insert0());
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
}
// Have we done all requested retries?
if (request->retryCount is 1) // We haven't decremented the count yet.
{
//
// We're finsihed with this request (due to timeout), unthread him from
// the SendRequest list...
//
if (previousRequest is empty)
atpInfo->sendRequestQueue = request->next;
else
previousRequest->next = request->next;
//
// We have to call the completion routine with an error... pull the needed
// information out of the control block so we can free it.
//
incomingResponse = request->completionRoutine;
userData = request->userData;
destination = request->destination;
Free(request);
HandleAtpPackets();
HandleDeferredTimerChecks();
if (incomingResponse isnt empty)
(*incomingResponse)(ATatpRequestTimedOut, userData, destination,
empty, 0, empty, 0);
return;
}
// If at first you don't succeed, try, try again...
if (request->retryCount isnt AtpInfiniteRetries)
request->retryCount -= 1;
request->timerId = StartTimer(AtpRequestTimerExpired,
request->retryInterval,
sizeof(AdditionalData),
(char *)additionalData);
AtpTransmitRequest(request);
HandleAtpPackets();
HandleDeferredTimerChecks();
return;
} // AtpRequestTimerExpired
ExternForVisibleFunction void AtpTransmitRelease(AtpSendRequest request)
{
BufferDescriptor datagram;
// Allocate a buffer chunk and build the release packet.
if ((datagram = NewBufferDescriptor(AtpDataOffset)) is Empty)
{
ErrorLog("AtpTransmitRelease", ISevError, __LINE__, UnknownPort,
IErrAtpOutOfMemory, IMsgAtpOutOfMemory,
Insert0());
return;
}
datagram->data[AtpCommandControlOffset] = AtpReleaseFunctionCode;
datagram->data[AtpBitmapOffset] = 0;
datagram->data[AtpTransactionIdOffset] =
(char)((request->transactionId >> 8) & 0xFF);
datagram->data[AtpTransactionIdOffset + 1] =
(char)(request->transactionId & 0xFF);
FillMem(datagram->data + AtpUserBytesOffset, 0, AtpUserBytesSize);
#if Debug
{
long temp;
if (DropEveryNthRelease isnt 0 and
((temp = RandomNumber()) % DropEveryNthRelease) is 0)
{
#if (Iam a Primos) and 0
printf("\nDropping release; rand = %d.\n", temp);
#endif
FreeBufferChain(datagram);
return;
}
}
#endif
DeliverDdp(request->sourceSocket, request->destination, DdpProtocolAtp,
datagram, AtpDataOffset, Empty, Empty, 0);
return;
} // AtpTransmitRelease
ExternForVisibleFunction short
AtpSynchUpResponseBuffer(AtpSendRequest request,
short maximumSinglePacketDataSize)
{
//
// If we're received shorter than expected responses, we need to "synch" up
// the user's response buffer. Also, return the actual size of the
// response.
//
// Note that when responses are received, we will place them at their
// sequenceNumber times maximumSinglePacketDataSize offsets within the user's
// buffer; thus, short responses may leave holes.
//
short index, packetOffset;
short actualSize = 0;
for (index = 0;
index < AtpMaximumResponsePackets and
request->packetsIn[index].received;
index += 1)
{
packetOffset = (short)(index * maximumSinglePacketDataSize);
if (actualSize isnt packetOffset)
MoveOpaqueToOpaque(request->responseOpaqueBuffer, actualSize,
request->responseOpaqueBuffer, packetOffset,
request->packetsIn[index].dataSize);
actualSize += request->packetsIn[index].dataSize;
}
return(actualSize);
} // AtpSynchUpResponseBuffer
ExternForVisibleFunction AtpInfo FindAtpInfoFor(long mySocket)
{
long index;
AtpInfo atpInfo;
CheckMod(index, mySocket, MaxAtpInfoHashBuckets, "FindAtpInfoFor");
for (atpInfo = atpInfoHashBuckets[index];
atpInfo isnt empty;
atpInfo = atpInfo->next)
if (atpInfo->mySocket is mySocket)
return(atpInfo);
return(empty);
} // FindAtpInfoFor