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 >
Text File  |  1992-07-15  |  11KB  |  276 lines

  1. //   ╔════════════════════════════════════════════════════════════════════╗
  2. //   ║                                                                    ║
  3. //   ║ module:      daprecv.c                                             ║
  4. //   ║ abstract:    This module contains the receive logic for the engine ║
  5. //   ║                                                                    ║
  6. //   ║ environment: NetWare 3.x v3.11                                     ║
  7. //   ║              Network C for NLMs SDK                                ║
  8. //   ║              CLib v3.11                                            ║
  9. //   ║                                                                    ║
  10. //   ║  This software is provided as is and carries no warranty           ║
  11. //   ║  whatsoever.  Novell disclaims and excludes any and all implied    ║
  12. //   ║  warranties of merchantability, title and fitness for a particular ║
  13. //   ║  purpose.  Novell does not warrant that the software will satisfy  ║
  14. //   ║  your requirements or that the software is without defect or error ║
  15. //   ║  or that operation of the software will be uninterrupted.  You are ║
  16. //   ║  using the software at your risk.  The software is not a product   ║
  17. //   ║  of Novell, Inc. or any of subsidiaries.                           ║
  18. //   ║                                                                    ║
  19. //   ╟────────────────────────────────────────────────────────────────────╢
  20. //   ║ maintenance history:                                               ║
  21. //   ║ level    date      pi   description                                ║
  22. //   ╟────────────────────────────────────────────────────────────────────╢
  23. //   ║  001   03/03/92    kl   initial release.                           ║
  24. //   ╚════════════════════════════════════════════════════════════════════╝
  25.  
  26. #include <stdio.h>
  27. #include <process.h>
  28. #include <library.h>
  29. #include <nwsemaph.h>
  30. #include <errno.h>
  31.  
  32. #include "dap/dapsys.h"
  33.  
  34. //
  35. //  'rQueueHead' points to a linked-list of DAPDATA structures which
  36. //  have received a request from their respective clients.  The API
  37. //  DAPEnqueueServiceRequest() is called from the CP Layer, when a
  38. //  request is received from a client.  It copies the data to the
  39. //  request buffer in the DAPDATA structure, and links the structure
  40. //  onto the service queue.  The thread DAPServiceReplyQueue() then
  41. //  takes the request and calls the appropriate service routine.
  42. //
  43.  
  44. STATIC  DAPDATA     *rQueueHead;
  45. STATIC  LONG        recvSema;
  46. STATIC  LONG        recvThreadID;
  47.  
  48. //
  49. //  Link the structure onto the request queue.  Signal the semaphore
  50. //  to wake up the Service Request Queue thread.
  51. //
  52. //  This queue is ordered just like the Ipx rQueueHead implementation
  53. //  in CLib.  See NLM Reference Volume 1 for a complete description
  54. //  of queue Head pointers.
  55. //
  56. //  This API is called by the CP Layer when a request is received.
  57. //
  58.  
  59. void    DAPEnqueueServiceRequest(UINT32 CPid, void *data)
  60. {
  61.         char    *error = "EnqueueServiceRequest called with %sactive DAPid (%x)\n";
  62.         UINT32  sessionID = ((DAPRequest *)data)->sessionID - 1;
  63.         DAPDATA *DAPid;
  64.         //
  65.         //  Do some validation on the session ID
  66.         //
  67.         xDIAG4(DAPprintf("EREQ: Validate session id '%x'\n",sessionID));
  68.         if( sessionID > DAPGetMaximumNumberOfSessions() ){
  69.             //!!
  70.             //  TBD:  Handle not allocating a slot more gracefully
  71.             //!!
  72.             DIAG4("EREQ: Allocate a slot");
  73.             if((sessionID = DAPSeeIfActiveCPid(CPid)) != -1 ){
  74.                 DAPprintf("Retry request from client for CPid (%x)\n",CPid);
  75.             }
  76.             else if((sessionID = DAPAllocateSlot()) == -1){
  77.                 DAPprintf("Could not allocate DAP slot for CPid (%x)\n",CPid);
  78.                 return;
  79.             }
  80.             //
  81.             //  Put the new id in the request packet, so we can send it to
  82.             //  the client when we answer this request.
  83.             //
  84.             ((DAPRequest *)data)->sessionID = sessionID + 1;
  85.         }
  86.         xDIAG4(DAPprintf("EREQ: Client is at slot %d\n",sessionID));
  87.         DAPid = DAPGetClientArray() + sessionID;
  88.         //
  89.         //  Remember the CP Session ID for later.
  90.         //!!
  91.         //  Authentication at some point in time...
  92.         //  !!SeeABOVE!!
  93.         //!!
  94.         DAPid->CPid = CPid;
  95.         //
  96.         //  If this DAP structure is not idle, a request is being serviced.
  97.         //!!
  98.         //  TBD: Handle this in a more friendly manner
  99.         //  
  100.         //  Note: We can't check the RECV state instead, since the reply
  101.         //        could be overwritten if the outgoing thread didn't
  102.         //        service before we received a new request.
  103.         //!!
  104.         //  Need to do some sort of check here for correct session.
  105.         //  Like compare the CPid with that in the session id or
  106.         //  something...
  107.         //!!
  108.         if( !DAPSlotInUse(DAPid) ){
  109.             xDIAG1(DAPprintf(error, "in", DAPid));
  110.             return;
  111.         }
  112.         else if( DAPInUse(DAPid) ){
  113.             //
  114.             //  This is a valid error if the client retries, while the
  115.             //  engine is servicing the original request.  For now, just
  116.             //  ignore the duplicate request, maybe handle more intelligently
  117.             //  later on.  Like maybe acknowledging the retry or something.
  118.             //
  119.             if( ((DAPRequest *)data)->timesTried ){
  120.                 xDIAG1(DAPprintf("EREQ: DAPid (%x) CPid (%x) retried %d\n", DAPid, 
  121.                                  DAPid->CPid,((DAPRequest *)data)->timesTried));
  122.             }
  123.             else{
  124.                 xDIAG1(DAPprintf(error, "", DAPid));
  125.             }
  126.             return;
  127.         }
  128.         //
  129.         //  Change the state of this structure to active.
  130.         //  It will remain in this state until ServiceReplyQueue() has
  131.         //  sent the reply to the client.  This means only one request
  132.         //  per client can be processed at a time.
  133.         //
  134.         //  This state set off in ServiceReplyQueue thread.
  135.         //
  136.         DAPStateON( DAPid, DAP_INUSE );
  137.         //
  138.         //  Link this one onto the linked list.
  139.         //
  140.         if( DAPid->next = rQueueHead ){
  141.             DAPid->prev = DAPid->next->prev;
  142.             DAPid->next->prev = DAPid;
  143.         }
  144.         else{
  145.             DAPid->prev = DAPid;
  146.         }
  147.         rQueueHead = DAPid;
  148.         //
  149.         //  Copy the request into the DAPRequest buffer
  150.         //
  151.         DAPid->dapRequest = *(DAPRequest *)data;
  152.         //
  153.         //  Set state for 'sitting in request queue'.
  154.         //
  155.         DAPStateON( DAPid, DAP_RQSTQUEUE );
  156.         //
  157.         //  Tell the service thread "there's work to-be-done!"
  158.         //
  159.         DIAG4("EREQ: WakeUp service request queue thread");
  160.         if( recvSema ) SignalLocalSemaphore(recvSema);
  161. }
  162.  
  163. //
  164. //  This is the thread which services the request queue.  It calls the
  165. //  respective DAP API, which will service the request.
  166. //
  167.  
  168. STATIC  void    DAPServiceRequestQueue(void *threadID)
  169. {
  170.         DAPDATA         *queuedDAPid;
  171.         DAPDATA         *currDAPid, *nextDAPid;
  172.         xDIAG4(int totQueued);
  173.  
  174.         #define SuspendOrStop() if(!recvSema){*(LONG *)threadID = 0; ExitThread(EXIT_THREAD,0);}
  175.  
  176.         *(LONG *)threadID = GetThreadID();
  177.         xDIAG1(RenameThread(GetThreadID(),"DAP_SREQ"));
  178.  
  179.         while( 1 ){
  180.             //
  181.             //  Wait for DAPid(s) to be posted to the rQueueHead
  182.             //
  183.             SuspendOrStop();
  184.             xDIAG4(delay(500));
  185.             WaitOnLocalSemaphore(recvSema);
  186.             SuspendOrStop();
  187.             //
  188.             //  Since we can handle multiple requests in the loop below,
  189.             //  we might wake up from the semaphore without any work to
  190.             //  be done.  If this is the case, just wait again...
  191.             //
  192.             if( !rQueueHead ) continue;
  193.             //
  194.             //  Get and clear the queue head pointer.
  195.             //
  196.             nextDAPid = (queuedDAPid = rQueueHead)->prev, rQueueHead = NULL;
  197.             xDIAG4(totQueued = 0);
  198.             do{
  199.                 xDIAG4(totQueued++);
  200.                 //
  201.                 //  Process the newly received request
  202.                 //
  203.                 DAPStateON( currDAPid = nextDAPid, DAP_RECEIVING );
  204.                 DAPStateOFF( currDAPid, DAP_RQSTQUEUE );
  205.                 //
  206.                 //  Traverse the linked list backwards, in the order they
  207.                 //  were queued by DAPEnqueueServiceReply().  We have to
  208.                 //  get the pointer out before the next request comes in.
  209.                 //
  210.                 nextDAPid = currDAPid->prev;
  211.                 //
  212.                 //  Dispatch the appropriate service routine
  213.                 //
  214.                 DAPDispatchRequestAPI(currDAPid);
  215.                 DAPIncTotalRequests();
  216.                 SuspendOrStop();
  217.                 //
  218.                 //  Show we are no longer processing received message
  219.                 //
  220.                 DAPStateOFF( currDAPid, DAP_RECEIVING );
  221.                 ThreadSwitch();
  222.                 SuspendOrStop();
  223.                 //
  224.                 //  When currDAPid == queuedDAPid, we have reached the end of
  225.                 //  the linked list.  Loop back and wait for another message.
  226.                 //
  227.             }while( currDAPid != queuedDAPid );     // until end of list
  228.             HEXDIAG4("Total queued was ", totQueued);
  229.         }
  230. }
  231.  
  232. //!!
  233. //  Could pass a parameter or have a global or constant which told how
  234. //  many threads should be started (multithreaded version)
  235. //!!
  236.  
  237. T_RC    DAPInitializeRecvLogic()
  238. {
  239.         //!!
  240.         //  Don't need to worry about called more than once, since this
  241.         //  is accomplished in the main DAPDeInitialize API
  242.         //!!
  243.         //  We need a local semaphore to block the service thread
  244.         //
  245.         if( (recvSema = OpenLocalSemaphore(0)) == -1){
  246.             recvSema = 0;       // so we don't accidentally close it
  247.             DIAG4("Could open DAP receiving semaphore");
  248.             return DAP_RESOURCE_ERROR;
  249.         }
  250.         if( BeginThread(DAPServiceRequestQueue,NULL,8192,&recvThreadID) == EFAILURE ){
  251.             DIAG4("Could open start ServiceRequestQueue thread");
  252.             return DAP_RESOURCE_ERROR;
  253.         }
  254.         ThreadSwitch();         // Give it a chance to run
  255.  
  256.         DIAG4("Receive logic initialized");
  257.  
  258.         return DAP_SUCCESS;
  259. }
  260.  
  261. void    DAPDeInitializeRecvLogic()
  262. {
  263.         //
  264.         //  Most of the time, this API will be called during atexit()
  265.         //  processing.
  266.         //
  267.         if( recvSema ){
  268.             CloseLocalSemaphore(recvSema);
  269.             recvSema = 0;       // signal thread to shut down ...
  270.         }
  271.         //!!
  272.         //while(recvThreadID) ThreadSwitch();
  273.         //!!
  274.         DIAG4("Receive logic de-initialized");
  275. }
  276.