mirror of https://github.com/lianthony/NT4.0
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.
532 lines
27 KiB
532 lines
27 KiB
/* asp.h, /appletalk/ins, Garth Conboy, 04/01/89 */
|
|
/* Copyright (c) 1989 by Pacer Software Inc., La Jolla, CA */
|
|
|
|
/* GC - Initial coding.
|
|
GC - (12/09/89): AppleTalk phase II comes to town.
|
|
GC - (03/24/92): Added a refNum to GetSessionHandler such that we can
|
|
cancel outstanding AspGetSessions.
|
|
GC - (03/27/92): Removed buffering for GetRequests... Atp now just passes
|
|
up pointers into the Ddp buffers. Data structure changes
|
|
to support AspGetAnyRequest().
|
|
GC - (07/08/92): We now store/retrieve a user-suppiled magic cookie on a
|
|
per-session basis.
|
|
|
|
*** Make the PVCS source control system happy:
|
|
$Header$
|
|
$Log$
|
|
***
|
|
|
|
ASP specific declarations.
|
|
|
|
*/
|
|
|
|
/* ASP command type bytes: */
|
|
|
|
#define AspCloseSessionCommand 1
|
|
#define AspCommandCommand 2
|
|
#define AspGetStatusCommand 3
|
|
#define AspOpenSessionCommand 4
|
|
#define AspTickleCommand 5
|
|
#define AspWriteCommand 6
|
|
#define AspWriteDataCommand 7
|
|
#define AspAttentionCommand 8
|
|
|
|
/* ASP version: */
|
|
|
|
#define AspVersionBytes "\001\000"
|
|
|
|
/* Offsets into the ATP user bytes for finding various fields: */
|
|
|
|
#define AspCommandTypeOffset 0
|
|
#define AspCommandResultOffset 0
|
|
#define AspSssNumberOffset 0
|
|
#define AspSessionIdOffset 1
|
|
#define AspWssNumberOffset 1
|
|
#define AspVersionNumberOffset 2
|
|
#define AspErrorCodeOffset 2
|
|
#define AspAttentionWordOffset 2
|
|
#define AspSequenceNumberOffset 2
|
|
|
|
#define AspCommandResultSize 4
|
|
|
|
/* ASP timer values: */
|
|
|
|
#define AtpIntervalSecondsForAsp 2
|
|
#define AspTickleSeconds 30
|
|
#define AspSessionMaintenanceSeconds 120
|
|
#define AtpRetriesForAsp 10 /* For open, status, close;
|
|
infinite for others. */
|
|
#define AspWriteDataSize 2 /* WriteData command has two
|
|
bytes of data with it. */
|
|
|
|
/* Session status size: */
|
|
|
|
#define AspMaximumStatusSize AtpMaximumTotalResponseSize
|
|
|
|
/* How many ATP request handlers should be posted on each session listener
|
|
socket (SLS) for handling Open, GetStatus and Tickle events. */
|
|
|
|
#define OutstandingSlsHandlers 3
|
|
|
|
/* Routine type that we call when we get an ASP OpenSessionCommand. */
|
|
|
|
typedef void far AspIncomingSessionOpenHandler(APPLETALK_ERROR errorCode,
|
|
long unsigned userData,
|
|
long socket,
|
|
long sessionRefNum);
|
|
|
|
/* Routine type to call when an OpenSession completes. */
|
|
|
|
typedef void far AspIncomingOpenReplyHandler(APPLETALK_ERROR errorCode,
|
|
long unsigned userData,
|
|
long sessionRefNum);
|
|
|
|
/* Routine type that we call when an attention comes in. */
|
|
|
|
typedef void far AspIncomingAttentionHandler(APPLETALK_ERROR errorCode,
|
|
long unsigned userData,
|
|
long sessionRefNum,
|
|
short unsigned attentionData);
|
|
|
|
/* Type of routine to call when a AspGetStatus completes: */
|
|
|
|
typedef void far AspIncomingStatusHandler(APPLETALK_ERROR errorCode,
|
|
long unsigned userData,
|
|
void far *opaqueBuffer,
|
|
int bufferSize);
|
|
|
|
/* Routine type to call when a Command or Write request comes in (as a response
|
|
to an AspGetReqeust call). */
|
|
|
|
typedef void far AspIncomingCommandHandler(APPLETALK_ERROR errorCode,
|
|
long unsigned userData,
|
|
long sessionRefNum,
|
|
long unsigned usersCookie,
|
|
void far *opaqueBuffer,
|
|
int bufferSize,
|
|
short requestType,
|
|
long getRequestRefNum);
|
|
|
|
/* Routine type to call when a reply completes. */
|
|
|
|
typedef void far AspReplyCompleteHandler(APPLETALK_ERROR errorCode,
|
|
long unsigned userData,
|
|
long sessionRefNum,
|
|
long getRequestRefNum);
|
|
|
|
/* Routine type to call when a write-continue completes. */
|
|
|
|
typedef void far AspIncomingWriteDataHandler(APPLETALK_ERROR errorCode,
|
|
long unsigned userData,
|
|
long sessionRefNum,
|
|
long getRequestRefNum,
|
|
void far *opaqueBuffer,
|
|
int bufferSize);
|
|
|
|
/* Routine type to call when a write or a command completes. */
|
|
|
|
typedef void far AspWriteOrCommCompleteHandler(APPLETALK_ERROR errorCode,
|
|
long unsigned userData,
|
|
long sessionRefNum,
|
|
char far *resultCode,
|
|
void far *opaqueBuffer,
|
|
int bufferSize,
|
|
int acceptedBytes);
|
|
|
|
/* The node that ATP needs to point to (as userData) in order for us to
|
|
be able to handle reply-completes and write-continue-completes [also,
|
|
command-replies and write-replies]. */
|
|
|
|
typedef struct { void far *completionRoutine;
|
|
long unsigned userData;
|
|
long sessionRefNum;
|
|
long getRequestRefNum;
|
|
short unsigned sequenceNumber;
|
|
} far *CompletionInfo;
|
|
|
|
/* The basic theory here is as follows. [A "basic theory" is just like a
|
|
"design", but shorter.] We maintain two main databases for support of
|
|
ASP.
|
|
|
|
First, a list of SessionListeners; each call to the routine
|
|
"AspCreateSessionListener" will create a new one of these. Clients will
|
|
issue their AspOpenSession requests to the ATP socket associated with the
|
|
given session listener (the SLS).
|
|
|
|
Second, a list (actually a hash table by SessionReferenceNumber) of active
|
|
ASP sessions; these are created in one of two ways: a server session is
|
|
created when the completion routine passed to "AspGetSession" is activated,
|
|
a workstation session is created by a call to AspOpenSession.
|
|
|
|
All server sessions are logically associated with the SLS that their
|
|
open request went to. If the SLS is deleted (via AspDeleteSessionListener)
|
|
all of its server sessions are also closed. A server session will actually
|
|
operate over a different socket (the SSS), but tickles will still go to the
|
|
SLS. Workstation sessions are outgoing and thus not associated with an SLS;
|
|
they too operate over an ATP socket (the WSS). Multiple server and
|
|
workstation ASP sessions may be multiplexed over a single SSS or WSS.
|
|
The caller to "AspGetSession" or "AspOpenSession" may specify that a
|
|
"private session" is desired, in which case multiplexing will not be
|
|
performed.
|
|
|
|
A "true" ASP address is a full ATP socket plus an 8-bit session ID
|
|
used within ASP. Thus, to really represent a fully qualified ASP session
|
|
36 bits are needed [not a nice number to work with]. So, to keep things
|
|
neat for our callers we represent each active session with a 32 bit session
|
|
reference number. We keep a hash table so that we can map an incoming
|
|
ASP packet (it's destination socket ("our" side of the connection) and
|
|
the contained session ID) to it's correct sessionRefNum. We then hash
|
|
this guy to come up with the correct session structure (sessionInfo node).
|
|
|
|
Note that when ASP tickle transactions come in to the server-side of an
|
|
ASP connection that they are addressed to the "wrong" socket (they go to
|
|
the SLS rather than the SSS). Thus, when a tickle comes in we need to
|
|
walk the list of all sessions on all SSSs owned by the SLS to find the
|
|
session ID that was contianed in the tickle packet. Of course, session
|
|
IDs need to be unique for all connections "spawned" by an SLS, regardless
|
|
of socket number (SSS)!
|
|
|
|
All of this said, the nodes of these two main lists (the session listener
|
|
list and the session list) are defined below. The members of the session
|
|
listener list will be linked to any server-members of the session list that
|
|
were created by the given session listener (SLS).
|
|
|
|
Got this? There will be a quiz later, neatness will count.
|
|
*/
|
|
|
|
/* The following list is linked off the session listener list to hold all of
|
|
the pending AspGetSession requests... */
|
|
|
|
typedef struct openSes { struct openSes far *next;
|
|
long refNum;
|
|
Boolean privateSocket;
|
|
AspIncomingSessionOpenHandler *sessionOpenHandler;
|
|
long unsigned userData;
|
|
} far *GetSessionHandler;
|
|
|
|
/* The following nodes are linked off the SessionListenerInfo nodes to keep
|
|
track of which ATP sockets are really in use for ASP sessions. */
|
|
|
|
typedef struct socInfo { struct socInfo far *next;
|
|
/* Next link. */
|
|
long socket; /* The ATP/DDP socket that we
|
|
describe. */
|
|
short activeSessions;
|
|
/* How many ASP sessions are
|
|
operating over this socket? */
|
|
Boolean privateSocket;
|
|
/* Don't overload this socket flag;
|
|
user wants only one ASP session
|
|
on this socket. */
|
|
} far *SocketInfo;
|
|
|
|
/* On non-private ATP sockets, what is the maximum number of ASP sessions
|
|
we'll run over each? */
|
|
|
|
#define MaximumAspSessionsPerSocket 16
|
|
|
|
/* Each workstation session has a list of writes/commands outstanding. These
|
|
are the nodes: */
|
|
|
|
typedef struct comInfo { struct comInfo far *next;
|
|
/* Link; we may have a number of
|
|
these guys queued. */
|
|
short unsigned sequenceNumber;
|
|
/* ASP sequence number for the
|
|
write or command. */
|
|
Boolean writeCommand;
|
|
/* We're a Write command. */
|
|
Boolean writeReplyPosted;
|
|
/* We've received a writeContinue,
|
|
and have posted the reply. */
|
|
char far *resultCode;
|
|
/* Where to we store that ASP
|
|
code. */
|
|
void far *writeOpaqueBuffer;
|
|
/* Data the workstation would like
|
|
to write to the server. */
|
|
int writeBufferSize;
|
|
/* Size of a above. */
|
|
int acceptedBytes; /* How much data is the server
|
|
willing to accept? */
|
|
} far *WriteOrCommandInfo;
|
|
|
|
/* Each server session will have a list of handlers for incoming requests [both
|
|
to be processed and "currently" being processed]. There is also a list of
|
|
these nodes hanging off the SessionListenerInfo used to process
|
|
GetAnyRequest. These are the nodes: */
|
|
|
|
typedef struct reqInfo { struct reqInfo far *next;
|
|
/* Link; we can have a number of
|
|
these guys queued off either
|
|
the SessionInfo or
|
|
SessionListenerInfo. */
|
|
struct reqInfo far *nextForMySessionListener;
|
|
/* Link; in per-Sls hash list. */
|
|
struct sesInfo far *mySessionInfo;
|
|
/* If on a SessionInfo list,
|
|
which one? */
|
|
struct slsInfo far *mySessionListener;
|
|
/* Who begat us? */
|
|
long getRequestRefNum;
|
|
/* This request's number as given
|
|
to our caller. */
|
|
Boolean inUse; /* Is our buffer currently filled
|
|
with a request, awaiting a reply
|
|
to come down from our caller?
|
|
That is, if true, we cannot use
|
|
this buffer for an incoming
|
|
request. */
|
|
short requestType; /* Command or Write. */
|
|
short unsigned sequenceNumber;
|
|
/* ASP sequence number as generated
|
|
by the workstation. */
|
|
AppleTalkAddress source;
|
|
/* The true source of the request,
|
|
it does not have to be the
|
|
Wss. */
|
|
Boolean exactlyOnce;
|
|
/* ATP mode of the request. */
|
|
short unsigned transactionId;
|
|
/* ATP transaction ID of the
|
|
incoming request. */
|
|
char far *opaqueBuffer;
|
|
/* "Buffer" for the incoming request
|
|
data. */
|
|
int bufferSize; /* Allocated size of "buffer". */
|
|
AspIncomingCommandHandler *completionRoutine;
|
|
/* User routine to call when the
|
|
request comes in. */
|
|
long unsigned userData;
|
|
/* User data to be passed on to the
|
|
completion routine. */
|
|
Boolean writeContinueInProgress;
|
|
/* Are we doing a write continue
|
|
now? */
|
|
char writeContinueData[AspWriteDataSize];
|
|
/* When we issue the Atp request,
|
|
this is it's "data" -- the
|
|
expected response size. */
|
|
void far *opaqueWriteContinueData;
|
|
/* Opaque descriptor for above. */
|
|
Boolean freeOpaqueWriteContinueData;
|
|
/* Do we free the above? */
|
|
short unsigned writeContinueTransactionId;
|
|
/* ATP transaction ID of the ATP
|
|
request. */
|
|
} far *GetRequestInfo;
|
|
|
|
/* The session list members: */
|
|
|
|
typedef struct sesInfo { struct sesInfo far *next;
|
|
/* Overflow of hash by session
|
|
reference number. */
|
|
struct slsInfo far *mySessionListener;
|
|
/* Who begat us, if server
|
|
session? */
|
|
long sessionRefNum;
|
|
/* My session reference number. */
|
|
long unsigned usersCookie;
|
|
/* A 32-bit "thing" that can be
|
|
stored and retrieved on a per-
|
|
session basis. */
|
|
struct sesInfo far *nextForMySls;
|
|
/* Link for server sessions created
|
|
by a given SLS. */
|
|
unsigned char sessionId;
|
|
/* The 8-bit ASP ID of this
|
|
session. */
|
|
Boolean serverSession;
|
|
/* Am I a server session? */
|
|
short unsigned tickleTransactionId;
|
|
/* For "server" sessions only,
|
|
the ATP TID of the tickle. */
|
|
Boolean waitingForOpenReply;
|
|
/* Workstation session, but not
|
|
really alive yet! */
|
|
int ourPort; /* What port does our address
|
|
exist on? */
|
|
long ourSocket; /* Address of "this" side of the
|
|
connection. */
|
|
Boolean closeOurSocket;
|
|
/* For workstation sessions only;
|
|
do we close the socket when
|
|
the session closes? For multi-
|
|
plexed server sessions, we
|
|
always close the socket when
|
|
the usage drops to zero, because
|
|
we've always opened the socket
|
|
originally. */
|
|
AppleTalkAddress theirAddress;
|
|
/* Address of "the other" side of
|
|
the connection. */
|
|
AppleTalkAddress slsAddress;
|
|
/* The SLS associated with with
|
|
this session. */
|
|
long atpRequestHandlerId;
|
|
/* The ID of the AtpRequestHandler
|
|
currently posted for this
|
|
session, so that we can cancel
|
|
it on an ASP session close. */
|
|
char sessionUserBytes[AtpUserBytesSize];
|
|
/* UserBytes for responses to
|
|
Atp requests posted by this
|
|
session. */
|
|
short unsigned nextSequenceNumber;
|
|
/* ASP request number [for outgoing
|
|
"workstation" transactions]. */
|
|
short unsigned nextExpectedSequenceNumber;
|
|
/* Sequence number expected on
|
|
next incoming write or
|
|
command from the workstation. */
|
|
GetRequestInfo getRequestInfoList;
|
|
/* List of handlers for incoming
|
|
requests to this server
|
|
session. */
|
|
WriteOrCommandInfo writeOrCommandInfoList;
|
|
/* List of outgoing request from
|
|
a workstation. */
|
|
AspIncomingAttentionHandler
|
|
*incomingAttentionHandler;
|
|
/* For workstation sessions... who
|
|
do we call with an attention. */
|
|
long unsigned userDataForAttention;
|
|
/* User data to pass on to the
|
|
attention handler. */
|
|
long unsigned lastContactTime;
|
|
/* When was the last time we heard
|
|
from the other end? */
|
|
} far *SessionInfo;
|
|
|
|
/* Lists GetRequestInfos can exist in two places: for specific sessions they
|
|
will live on the SessionInfo, for "any session to this server" they will
|
|
live on the SessionListenerInfo. We want to make the getRequestRefNum
|
|
unique over all "get requests" to an SLS, so we need to keep track of
|
|
these guys on a per server basis. To do this, we keep a hash table (by
|
|
getRequestRefNum) in each SessionListenerInfo. The following is this
|
|
hash table. */
|
|
|
|
#define NumGetRequestInfoHashBuckets 11
|
|
|
|
typedef GetRequestInfo GetRequestInfoHashBuckets[NumGetRequestInfoHashBuckets];
|
|
|
|
/* If sessions are being handled using GetAnyRequests, we may have a case where
|
|
a session closes (either locally or remotely) and we don't have any
|
|
current GetAnyRequests pending and we have no specified GetRequests pending.
|
|
In this case we don't have anybody to tell about the session close, so we
|
|
keep a list of sessions that have closed that we have "deferred notification"
|
|
for -- in this list is non-Empty when a GetAnyRequest is posted, we complete
|
|
it imediately with a SessionClosed error code telling what refNum closed. */
|
|
|
|
typedef struct dcn {struct dcn far *next;
|
|
APPLETALK_ERROR closeCode;
|
|
long sessionRefNum;
|
|
long unsigned usersCookie;
|
|
} far *DeferredCloseNotify;
|
|
|
|
/* The session listener list members: */
|
|
|
|
typedef struct slsInfo { struct slsInfo far *next;
|
|
/* Next on list. */
|
|
long sessionListenerRefNum;
|
|
/* Our number. */
|
|
long ourSocket; /* What address are we listening
|
|
on? */
|
|
Boolean closeSocket;
|
|
/* True if we opened the service
|
|
listener socket. */
|
|
int port; /* What port does our address
|
|
exist on? */
|
|
SessionInfo sessionList;
|
|
/* List of sessions created by this
|
|
session listener. */
|
|
SocketInfo socketList;
|
|
/* Info on the sockets that our
|
|
various sessions are using. */
|
|
unsigned char lastSessionId;
|
|
/* The last ASP session ID that we
|
|
used on this SLS. */
|
|
char far *serviceStatus;
|
|
/* The status to return to a Get
|
|
Status request; we're allocated
|
|
this buffer and copied any user
|
|
status to it. */
|
|
void far *opaqueServiceStatus;
|
|
/* An "opaque" descriptor for the
|
|
status block. */
|
|
Boolean freeOpaqueServiceStatus;
|
|
/* Do we have to free the above? */
|
|
short serviceStatusSize;
|
|
/* Size of status block. */
|
|
GetSessionHandler getSessionHandlers;
|
|
/* Who do we call when an
|
|
OpenSession comes in? */
|
|
long lastGetRequestRefNum;
|
|
/* Reference number for incoming
|
|
Commands or Writes to a any
|
|
session to this server. */
|
|
GetRequestInfo getRequestInfoList;
|
|
/* List of handlers for incoming
|
|
requests to ANY session on
|
|
this server. */
|
|
GetRequestInfoHashBuckets getRequestInfoHashBuckets;
|
|
/* See comment above. */
|
|
Boolean getAnyRequestsSeen;
|
|
/* For the life of this listener,
|
|
have there been GetAnyRequests?
|
|
Used to tune session close
|
|
reporting. */
|
|
DeferredCloseNotify deferredCloseNotifyList;
|
|
/* See commend above the declaration
|
|
of DeferredCloseNoitfy. */
|
|
} far *SessionListenerInfo;
|
|
|
|
/* Nodes used to map an ASP packet's address (destination or "our" side) to
|
|
it's sessionRefNum: */
|
|
|
|
typedef struct sesMap { struct sesMap far *next;
|
|
long socket;
|
|
unsigned char sessionId;
|
|
long sessionRefNum;
|
|
} far *SessionRefNumMap;
|
|
|
|
/* Head of the session listener list: */
|
|
|
|
#ifndef InitializeData
|
|
extern
|
|
#endif
|
|
SessionListenerInfo sessionListenerInfoHead;
|
|
|
|
/* Hash table (by sessionRefNum) for the session table: */
|
|
|
|
#define NumberOfAspSessionHashBuckets 23
|
|
|
|
#ifndef InitializeData
|
|
extern
|
|
#endif
|
|
SessionInfo sessionInfoHashBuckets[NumberOfAspSessionHashBuckets];
|
|
|
|
/* Hash table (by "((socket & 0xFFFF) << 8) + sessionId") for finding a given
|
|
session's sessionRefNum. */
|
|
|
|
#define NumberOfSessionRefNumBuckets 23
|
|
|
|
#ifndef InitializeData
|
|
extern
|
|
#endif
|
|
SessionRefNumMap sessionRefNumMapHashBuckets[NumberOfSessionRefNumBuckets];
|
|
|
|
/* What is the next value that we should use for a session listener reference
|
|
number? */
|
|
|
|
#ifndef InitializeData
|
|
extern
|
|
#endif
|
|
long lastSessionListenerRefNum;
|
|
|
|
/* What is the next value that we should use for a session reference number? */
|
|
|
|
#ifndef InitializeData
|
|
extern
|
|
#endif
|
|
long lastSessionRefNum;
|