home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Network Support Encyclopedia 96-1
/
novell-nsepro-1996-1-cd2.iso
/
download
/
netware
/
dax1.exe
/
DAP
/
DAPE
/
DAPRECV.C
< prev
next >
Wrap
Text File
|
1992-07-15
|
11KB
|
276 lines
// ╔════════════════════════════════════════════════════════════════════╗
// ║ ║
// ║ module: daprecv.c ║
// ║ abstract: This module contains the receive logic for the engine ║
// ║ ║
// ║ environment: NetWare 3.x v3.11 ║
// ║ Network C for NLMs SDK ║
// ║ CLib v3.11 ║
// ║ ║
// ║ This software is provided as is and carries no warranty ║
// ║ whatsoever. Novell disclaims and excludes any and all implied ║
// ║ warranties of merchantability, title and fitness for a particular ║
// ║ purpose. Novell does not warrant that the software will satisfy ║
// ║ your requirements or that the software is without defect or error ║
// ║ or that operation of the software will be uninterrupted. You are ║
// ║ using the software at your risk. The software is not a product ║
// ║ of Novell, Inc. or any of subsidiaries. ║
// ║ ║
// ╟────────────────────────────────────────────────────────────────────╢
// ║ maintenance history: ║
// ║ level date pi description ║
// ╟────────────────────────────────────────────────────────────────────╢
// ║ 001 03/03/92 kl initial release. ║
// ╚════════════════════════════════════════════════════════════════════╝
#include <stdio.h>
#include <process.h>
#include <library.h>
#include <nwsemaph.h>
#include <errno.h>
#include "dap/dapsys.h"
//
// 'rQueueHead' points to a linked-list of DAPDATA structures which
// have received a request from their respective clients. The API
// DAPEnqueueServiceRequest() is called from the CP Layer, when a
// request is received from a client. It copies the data to the
// request buffer in the DAPDATA structure, and links the structure
// onto the service queue. The thread DAPServiceReplyQueue() then
// takes the request and calls the appropriate service routine.
//
STATIC DAPDATA *rQueueHead;
STATIC LONG recvSema;
STATIC LONG recvThreadID;
//
// Link the structure onto the request queue. Signal the semaphore
// to wake up the Service Request Queue thread.
//
// This queue is ordered just like the Ipx rQueueHead implementation
// in CLib. See NLM Reference Volume 1 for a complete description
// of queue Head pointers.
//
// This API is called by the CP Layer when a request is received.
//
void DAPEnqueueServiceRequest(UINT32 CPid, void *data)
{
char *error = "EnqueueServiceRequest called with %sactive DAPid (%x)\n";
UINT32 sessionID = ((DAPRequest *)data)->sessionID - 1;
DAPDATA *DAPid;
//
// Do some validation on the session ID
//
xDIAG4(DAPprintf("EREQ: Validate session id '%x'\n",sessionID));
if( sessionID > DAPGetMaximumNumberOfSessions() ){
//!!
// TBD: Handle not allocating a slot more gracefully
//!!
DIAG4("EREQ: Allocate a slot");
if((sessionID = DAPSeeIfActiveCPid(CPid)) != -1 ){
DAPprintf("Retry request from client for CPid (%x)\n",CPid);
}
else if((sessionID = DAPAllocateSlot()) == -1){
DAPprintf("Could not allocate DAP slot for CPid (%x)\n",CPid);
return;
}
//
// Put the new id in the request packet, so we can send it to
// the client when we answer this request.
//
((DAPRequest *)data)->sessionID = sessionID + 1;
}
xDIAG4(DAPprintf("EREQ: Client is at slot %d\n",sessionID));
DAPid = DAPGetClientArray() + sessionID;
//
// Remember the CP Session ID for later.
//!!
// Authentication at some point in time...
// !!SeeABOVE!!
//!!
DAPid->CPid = CPid;
//
// If this DAP structure is not idle, a request is being serviced.
//!!
// TBD: Handle this in a more friendly manner
//
// Note: We can't check the RECV state instead, since the reply
// could be overwritten if the outgoing thread didn't
// service before we received a new request.
//!!
// Need to do some sort of check here for correct session.
// Like compare the CPid with that in the session id or
// something...
//!!
if( !DAPSlotInUse(DAPid) ){
xDIAG1(DAPprintf(error, "in", DAPid));
return;
}
else if( DAPInUse(DAPid) ){
//
// This is a valid error if the client retries, while the
// engine is servicing the original request. For now, just
// ignore the duplicate request, maybe handle more intelligently
// later on. Like maybe acknowledging the retry or something.
//
if( ((DAPRequest *)data)->timesTried ){
xDIAG1(DAPprintf("EREQ: DAPid (%x) CPid (%x) retried %d\n", DAPid,
DAPid->CPid,((DAPRequest *)data)->timesTried));
}
else{
xDIAG1(DAPprintf(error, "", DAPid));
}
return;
}
//
// Change the state of this structure to active.
// It will remain in this state until ServiceReplyQueue() has
// sent the reply to the client. This means only one request
// per client can be processed at a time.
//
// This state set off in ServiceReplyQueue thread.
//
DAPStateON( DAPid, DAP_INUSE );
//
// Link this one onto the linked list.
//
if( DAPid->next = rQueueHead ){
DAPid->prev = DAPid->next->prev;
DAPid->next->prev = DAPid;
}
else{
DAPid->prev = DAPid;
}
rQueueHead = DAPid;
//
// Copy the request into the DAPRequest buffer
//
DAPid->dapRequest = *(DAPRequest *)data;
//
// Set state for 'sitting in request queue'.
//
DAPStateON( DAPid, DAP_RQSTQUEUE );
//
// Tell the service thread "there's work to-be-done!"
//
DIAG4("EREQ: WakeUp service request queue thread");
if( recvSema ) SignalLocalSemaphore(recvSema);
}
//
// This is the thread which services the request queue. It calls the
// respective DAP API, which will service the request.
//
STATIC void DAPServiceRequestQueue(void *threadID)
{
DAPDATA *queuedDAPid;
DAPDATA *currDAPid, *nextDAPid;
xDIAG4(int totQueued);
#define SuspendOrStop() if(!recvSema){*(LONG *)threadID = 0; ExitThread(EXIT_THREAD,0);}
*(LONG *)threadID = GetThreadID();
xDIAG1(RenameThread(GetThreadID(),"DAP_SREQ"));
while( 1 ){
//
// Wait for DAPid(s) to be posted to the rQueueHead
//
SuspendOrStop();
xDIAG4(delay(500));
WaitOnLocalSemaphore(recvSema);
SuspendOrStop();
//
// Since we can handle multiple requests in the loop below,
// we might wake up from the semaphore without any work to
// be done. If this is the case, just wait again...
//
if( !rQueueHead ) continue;
//
// Get and clear the queue head pointer.
//
nextDAPid = (queuedDAPid = rQueueHead)->prev, rQueueHead = NULL;
xDIAG4(totQueued = 0);
do{
xDIAG4(totQueued++);
//
// Process the newly received request
//
DAPStateON( currDAPid = nextDAPid, DAP_RECEIVING );
DAPStateOFF( currDAPid, DAP_RQSTQUEUE );
//
// Traverse the linked list backwards, in the order they
// were queued by DAPEnqueueServiceReply(). We have to
// get the pointer out before the next request comes in.
//
nextDAPid = currDAPid->prev;
//
// Dispatch the appropriate service routine
//
DAPDispatchRequestAPI(currDAPid);
DAPIncTotalRequests();
SuspendOrStop();
//
// Show we are no longer processing received message
//
DAPStateOFF( currDAPid, DAP_RECEIVING );
ThreadSwitch();
SuspendOrStop();
//
// When currDAPid == queuedDAPid, we have reached the end of
// the linked list. Loop back and wait for another message.
//
}while( currDAPid != queuedDAPid ); // until end of list
HEXDIAG4("Total queued was ", totQueued);
}
}
//!!
// Could pass a parameter or have a global or constant which told how
// many threads should be started (multithreaded version)
//!!
T_RC DAPInitializeRecvLogic()
{
//!!
// Don't need to worry about called more than once, since this
// is accomplished in the main DAPDeInitialize API
//!!
// We need a local semaphore to block the service thread
//
if( (recvSema = OpenLocalSemaphore(0)) == -1){
recvSema = 0; // so we don't accidentally close it
DIAG4("Could open DAP receiving semaphore");
return DAP_RESOURCE_ERROR;
}
if( BeginThread(DAPServiceRequestQueue,NULL,8192,&recvThreadID) == EFAILURE ){
DIAG4("Could open start ServiceRequestQueue thread");
return DAP_RESOURCE_ERROR;
}
ThreadSwitch(); // Give it a chance to run
DIAG4("Receive logic initialized");
return DAP_SUCCESS;
}
void DAPDeInitializeRecvLogic()
{
//
// Most of the time, this API will be called during atexit()
// processing.
//
if( recvSema ){
CloseLocalSemaphore(recvSema);
recvSema = 0; // signal thread to shut down ...
}
//!!
//while(recvThreadID) ThreadSwitch();
//!!
DIAG4("Receive logic de-initialized");
}