home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Network Support Encyclopedia 96-1
/
novell-nsepro-1996-1-cd2.iso
/
download
/
netware
/
dax1.exe
/
CP
/
CPS
/
CPRECV.C
< prev
next >
Wrap
Text File
|
1992-07-15
|
11KB
|
243 lines
// ╔════════════════════════════════════════════════════════════════════╗
// ║ ║
// ║ module: cprecv.c ║
// ║ abstract: This module contains the routines to handle incoming ║
// ║ requests from clients. ║
// ║ ║
// ║ 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 01/29/92 kl initial release. ║
// ╚════════════════════════════════════════════════════════════════════╝
#include <string.h>
#include <nwsemaph.h>
#include <process.h>
#include <errno.h>
#include "cp/cpsys.h"
//------------------------------------------------------------------------
//
// Miscellaneous variables needed by this module.
//
STATIC LONG recvSemaHandle; // used in recv ECBs
STATIC IPX_ECB *recvQueueHead; // queue head pointer (ipx)
STATIC LONG recvThreadID; // id of this thread
//
//
// 'recvs' is an array of structures, each one having what we need to
// receive a single request from a client.
//
STATIC CPCOMMDATA recvs[CPSNUMRECVELEM];
//
// This variable contains a pointer to the API in the DAP layer that
// will be called when a new request is received by the CP Layer.
//
STATIC (*DAPEnqueueRequest)(UINT32, void *);
//------------------------------------------------------------------------
// **********************************************************************
// * Initialize an Ipx Listen ECB and Packet *
// **********************************************************************
void CPInitRecvPacket(WORD socket, // socket to receive on
long semHandle, // IPX will signal if non-zero
IPX_ECB **queueHead, // ptr to linked list when cplt
IPX_ECB *ecb, // the ecb
IPX_HEADER *hdr, // the ipx header
void *reply, // the data portion
WORD sizeReply) // the data portion size
{
//
// The semHandle field, if set, will cause IPX to call
// SignalLocalSemaphore with this handle, when a packet is received.
// This way, you can block a thread from execution via WaitOnLocalSem
// until a message comes in. No need for ESR's!
//
ecb->semHandle = semHandle;
//
// Note that since the socket is a parameter to the IPX CLIB
// functions, it can be init'ed here, or simply passed via Receive.
// If you init here, then pass 0 when you call IpxReceive...
//
ecb->socket = socket;
//
// Queuehead is a pointer to an ECB pointer that will be set to
// point to a completed ECB. It will be used to form a double-
// threaded linked list of completed ECB's.
//
ecb->queueHead = queueHead;
ecb->fragCount = 2;
ecb->fragList[0].fragAddress = hdr;
ecb->fragList[0].fragSize = sizeof( IPX_HEADER );
ecb->fragList[1].fragAddress = reply;
ecb->fragList[1].fragSize = sizeReply;
}
// **********************************************************************
// * This is the thread that monitors the queuehead pointer waiting *
// * for incoming messages. It then verifies a valid client sent the *
// * message (registers a new client if necessary), then enqueues the *
// * request to the DAP layer via the API registered during init. *
// **********************************************************************
STATIC void CPRecvMessageThread(void *threadID)
{
IPX_ECB *queuedECB;
IPX_ECB *recvECB, *nextECB;
IPX_HEADER *IPXinfo;
CPMESSAGE *CPinfo;
UINT32 sessionID;
*(LONG *)threadID = GetThreadID();
xDIAG1(RenameThread(GetThreadID(),"CP_RECV"));
#define SuspendOrStop() if(!recvSemaHandle){*(LONG *)threadID = 0; ExitThread(EXIT_THREAD,0);}
while( 1 ){
//
// Wait for an ECB(s) to be posted off the queueHead
//
SuspendOrStop();
WaitOnLocalSemaphore(recvSemaHandle);
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( !recvQueueHead ) continue;
//
// Get and clear the queue head pointer.
//
nextECB = (queuedECB = IpxGetAndClearQ(&recvQueueHead))->prev;
do{
//
// Process the newly received request
//
recvECB = nextECB;
if( recvECB->status == NULL ){ // if successful receive...
DIAG4("*\n* Received new request\n*");
//
// get the session id, allocate if necessary
//
IPXinfo = (IPX_HEADER *)recvECB->fragList[0].fragAddress;
CPinfo = (CPMESSAGE *)recvECB->fragList[1].fragAddress;
//
// Get the session ID on whoever sent this...
//
//<<!!>>
// Enhance by creating some way to tell the client we
// were unable to allocate a session for him...
//<<!!>>
if( (sessionID = CPGetSessionID(IPXinfo,CPinfo) ) != -1){
//
// enqueue the request. Note how we'll just ignore
// the request if we can't get a session ID.
//!!
// Need to authenticate the session ID in the
// EnqueueRequest API I guess... That is, make
// sure from the DAP perspective that this is
// a valid match 'sessionID' and DAPserverid.
//!!
DAPEnqueueRequest(sessionID,CPinfo->msg);
}
else{
DIAG1("Unable to get sessionID for client");
}
}
else{
HEXDIAG1("Error receiving message: ",recvECB->status);
}
//
// Traverse the linked list backwards, in the order they
// were received by IPX.
//
nextECB = recvECB->prev;
//
// Resubmit the ECB to IPX to receive next message.
//
IpxReceive(CPGetAdvertisingSocket(), recvECB);
//
// Don't hog the CPU!
//
SuspendOrStop();
ThreadSwitch();
//
// When recvECB == queuedECB, we have reached the end of
// the linked list. Loop back and wait for another message.
//
}while( recvECB != queuedECB ); // until end of list
}
}
T_RC CPInitializeRecvLogic(void (*EnqueueRequestAPI)(UINT32, void *))
{
int i;
WORD socket = CPGetAdvertisingSocket();
//
// We need a local semaphore to block the receive thread
//
if( (recvSemaHandle = OpenLocalSemaphore(0)) == -1){
recvSemaHandle = 0; // so we don't accidentally close it
return CP_RESOURCE_ERROR;
}
//
// Remember the API that will be called by the receiving thread
// that will handle any incoming requests.
//
DAPEnqueueRequest = EnqueueRequestAPI;
//
// Get our recv ECBs ready.
//
for(i=0; i < CPSNUMRECVELEM; ++i){
CPInitRecvPacket(socket,
recvSemaHandle,
&recvQueueHead,
&recvs[i].ecb,
&recvs[i].ipx,
&recvs[i].cpmsg,
sizeof recvs[i].cpmsg);
IpxReceive(socket, &recvs[i].ecb);
}
if( BeginThread(CPRecvMessageThread,NULL,8192,&recvThreadID) == EFAILURE ){
return CP_RESOURCE_ERROR;
}
ThreadSwitch();
return CP_SUCCESS;
}
void CPDeInitializeRecvLogic()
{
int i;
if( recvSemaHandle ) CloseLocalSemaphore(recvSemaHandle);
//
// If any packets are still pending, cancel them.
//
for(i=0; i < CPSNUMRECVELEM; ++i){
if( recvs[i].ecb.status > 0 && recvs[i].ecb.status < 0xF000 )
IpxCancelEvent(&recvs[i].ecb);
}
}