home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / TIMEXSRC.ZIP / BA_REQ.C < prev    next >
C/C++ Source or Header  |  1990-03-29  |  16KB  |  567 lines

  1. /* ba_req.c -- Request Processing
  2.  
  3.     February 1990    Mark E. Mallett, Personal Workstation Magazine
  4.  
  5. This module contains routines to process requests made of the
  6. background agent.  Requests are made via the named pipe, whose handle
  7. is RqpipeH.  Routines in the module serve to process individual
  8. requests.
  9.  
  10. Included are the following routines:
  11.  
  12.         process_request         Process a request from a client
  13.  
  14. */
  15.  
  16. #define INCL_BASE
  17.  
  18. #include <stdio.h>
  19. #include <malloc.h>
  20. #include <string.h>
  21. #include <sys/types.h>
  22. #include <os2.h>
  23.  
  24. #include "errhand.h"
  25. #include "timex.h"
  26. #include "ba_timex.h"
  27. #include "evpack.h"
  28.  
  29.  
  30. /* Local definitions */
  31.  
  32. typedef                                 /* Args for request processing */
  33.   struct {
  34.     TMXMSG      *rp_reqP;               /* Ptr to request buffer */
  35.     TMXMSG      *rp_rspP;               /* Ptr to response buffer */
  36.   }    RP;
  37.  
  38.  
  39. /* External data referenced */
  40.  
  41. extern  HSEM    Eventsem;               /* Semaphore for event list */
  42. extern  PEVENT  *PendingL;              /* List of events */
  43. extern  HPIPE   RqpipeH;                /* Handle for the request pipe */
  44. extern  ERRLIST *Werlist;               /* Wild condition list */
  45.  
  46. /* External routines used */
  47.  
  48. extern  void    db_write( void );       /* Write the database */
  49. extern  PEVENT  *event_find( char *nameP );
  50. extern  void    schedule( PEVENT *peventP );
  51.  
  52. /* Local data publicly available */
  53.  
  54.  
  55. /* Local routines and forward declarations */
  56.  
  57. static  void    errresp( TMXRSP_ERR *rspP, int code, char *msgP );
  58. static  void    return_event( TMXMSG *rspP, EVENT *eventP );
  59.  
  60. static  void    rq_add( RP *rpP );
  61. static  int     rq_add1(RP *);
  62. static  void    rq_del( RP *rpP );
  63. static  int     rq_del1(RP *);
  64. static  void    rq_get( RP *rpP );
  65. static  int     rq_get1(RP *);
  66. static  void    rq_getnext( RP *rpP );
  67. static  int     rq_getnext1(RP *);
  68. static  void    rq_modify( RP *rpP );
  69. static  int     rq_mod1(RP *);
  70.  
  71. /* Private data */
  72.  
  73. static struct {                         /* Dispatch for request codes */
  74.         int     rd_code;        /* The code */
  75.         void    (*rd_rtc)(      /* Routine to call */
  76.                         RP *rpP
  77.                          );
  78.               }
  79.                 Msgdisp[] =     {
  80.  
  81.         { REQ_ADD,      rq_add  },
  82.         { REQ_DEL,      rq_del  },
  83.         { REQ_GET,      rq_get  },
  84.         { REQ_GETNEXT,  rq_getnext },
  85.         { REQ_MODIFY,   rq_modify },
  86.         { 0,            NULL    }
  87.                                 };
  88.  
  89.  
  90. /*
  91.  
  92. *//* process_request()
  93.  
  94.         Process an incoming request
  95.  
  96. Accepts :
  97.  
  98.  
  99. Returns :
  100.  
  101.  
  102. Notes :
  103.  
  104.         This routine is called when a connection has been made to the
  105.         request pipe (RqpipeH); that is, when a client has opened the
  106.         pipe.  This routine is responsible for reading the request,
  107.         delegating its handling to the apppropriate routine, and
  108.         sending the response.
  109.  
  110. */
  111.  
  112. void
  113. process_request() {
  114.         int             status;
  115.         int             rdX;            /* Request dispatch table index */
  116.         USHORT          xferL;          /* Transfer length */
  117.         TMXMSG          *reqP;          /* Ptr to request message */
  118.         TMXMSG          *rspP;          /* Ptr to response message */
  119.         RP              rpblk;          /* Request processing block */
  120.         char            rcvbuf[512];    /* Request receive buffer */
  121.         char            rspbuf[512];    /* Request response buffer */
  122.  
  123.     /* Read the request. */
  124.     status = DosRead( RqpipeH, &rcvbuf[0], 512, &xferL );
  125.     if ( status != 0 ) {
  126.         warning( EC_NOTOK, "Pipe read failed (%d)", status );
  127.         return;
  128.     }
  129.     reqP = (TMXMSG *)&rcvbuf[0];
  130.     rspP = (TMXMSG *)&rspbuf[0];
  131.  
  132.     if ( xferL != reqP->m_len )
  133.         errresp( (TMXRSP_ERR *)rspP, 0, "Request length mismatch." );
  134.     else {
  135.         /* Dispatch according to request type */
  136.         for( rdX = 0; Msgdisp[rdX].rd_rtc != NULL; ++rdX )
  137.             if ( reqP->m_code == Msgdisp[rdX].rd_code )
  138.                 /* Found it */
  139.                 break;
  140.  
  141.         if ( Msgdisp[rdX].rd_rtc == NULL ) {
  142.             /* Invalid request; fill in response */
  143.             errresp( (TMXRSP_ERR *)rspP, 0, "Invalid request." );
  144.         }
  145.         else {
  146.             /* Hand off to dispatch. */
  147.             rpblk.rp_reqP = reqP;
  148.             rpblk.rp_rspP = rspP;
  149.             (*Msgdisp[rdX].rd_rtc)( &rpblk );
  150.         }
  151.     }
  152.  
  153.     /* Send the response back. */
  154.     status = DosWrite( RqpipeH, &rspbuf[0], rspP->m_len, &xferL );
  155.     if ( status != 0 )
  156.         warning( EC_NOTOK, "Pipe write failed (%d)", status );
  157.     else if ( rspP->m_len != xferL )
  158.         warning( EC_NOTOK, "Pipe write incomplete" );
  159.  
  160. }
  161. /*
  162.  
  163. *//* rq_add( rpP )
  164.  
  165.         Process the REQ_ADD request: add an event
  166.  
  167. */
  168.  
  169. static void
  170. rq_add(
  171.         RP              *rpP            /* Ptr to request parm blk */
  172. ) {
  173.         int             eval;           /* Error value */
  174.         char            *msgP;          /* Ptr to error return */
  175.  
  176.     /* Lock the event list so that we can manipulate it */
  177.     get_sem( "rq_add", "event list", Eventsem );
  178.  
  179.     /* Catch errors here so real routine can work */
  180.     eval = handle_error( rq_add1, rpP, Werlist, &msgP );
  181.  
  182.     /* Unlock the list */
  183.     rel_sem( "rq_add", "event list", Eventsem );
  184.  
  185.     /* Throw back an error if there was one */
  186.     if ( eval != CXNONE )
  187.         return_error( el_cond( Werlist, eval ), msgP );
  188.  
  189. }
  190.  
  191. static int
  192. rq_add1(
  193.         RP              *rpP            /* Ptr to request parm blk */
  194. ) {
  195.  
  196.         TMXMSG          *reqP;          /* Ptr to request message */
  197.         TMXMSG          *rspP;          /* Ptr to response message */
  198.         EVENT           *eventP;        /* Event that we create */
  199.         PEVENT          *newP;          /* Ptr to new pevent */
  200.  
  201.     reqP = rpP->rp_reqP;
  202.     rspP = rpP->rp_rspP;
  203.  
  204.     /* Make the new event */
  205.     eventP = event_unpack( (char *)&reqP[1], reqP->m_len - sizeof(TMXMSG) );
  206.  
  207.     /* Check for duplicate name */
  208.     if ( event_find( eventP->ev_nameP ) != NULL ) {
  209.         errresp( (TMXRSP_ERR *)rspP, 0, "Event already exists." );
  210.         free( eventP );
  211.         return( 0 );
  212.     }
  213.  
  214.     /* Make new event */
  215.     newP = emalloc( "rq_add", "new event", sizeof( PEVENT ) );
  216.     newP->pe_eventP = eventP;
  217.  
  218.     /* Schedule the new event */
  219.     schedule( newP );
  220.  
  221.     /* Write out the new event database */
  222.     db_write();
  223.  
  224.     /* Response is OK */
  225.     rspP->m_code = RSP_OK;
  226.     rspP->m_len = sizeof( TMXMSG );
  227.  
  228.     return( 0 );
  229. }
  230. /*
  231.  
  232. *//* rq_del( rpP )
  233.  
  234.         Process the REQ_DEL request: delete an event
  235.  
  236. */
  237.  
  238. static void
  239. rq_del(
  240.         RP              *rpP            /* Request parameter block */
  241. ) {
  242.         int             eval;           /* Error value */
  243.         char            *msgP;          /* Ptr to error return */
  244.  
  245.     /* Lock the event list so that we can manipulate it */
  246.     get_sem( "rq_del", "event list", Eventsem );
  247.  
  248.     /* Catch errors here so real routine can work */
  249.     eval = handle_error( rq_del1, rpP, Werlist, &msgP );
  250.  
  251.     /* Unlock the list */
  252.     rel_sem( "rq_del", "event list", Eventsem );
  253.  
  254.     /* Throw back an error if there was one */
  255.     if ( eval != CXNONE )
  256.         return_error( el_cond( Werlist, eval ), msgP );
  257. }
  258.  
  259.  
  260. static int
  261. rq_del1(
  262.         RP              *rpP            /* Ptr to request parm blk */
  263. ) {
  264.  
  265.         TMXREQ_DEL      *reqP;          /* Ptr to request message */
  266.         TMXMSG          *rspP;          /* Ptr to response message */
  267.         PEVENT          *peventP;       /* Event to delete */
  268.  
  269.     reqP = (TMXREQ_DEL *)rpP->rp_reqP;
  270.     rspP = rpP->rp_rspP;
  271.  
  272.     /* Attempt to find the event to delete */
  273.     peventP = event_find( &reqP->d_evname[0] );
  274.  
  275.     if ( peventP == NULL )
  276.         errresp( (TMXRSP_ERR *)rspP, 0, "No such event." );
  277.     else {
  278.         /* Unhook the event. */
  279.         unschedule( peventP );
  280.  
  281.         /* Get rid of it */
  282.         free( peventP->pe_eventP );
  283.         free( peventP );
  284.  
  285.         /* Write out the new event database */
  286.         db_write();
  287.  
  288.         /* Response is OK */
  289.         rspP->m_code = RSP_OK;
  290.         rspP->m_len = sizeof( TMXMSG );
  291.     }
  292.  
  293.     return( 0 );
  294. }
  295. /*
  296.  
  297. *//* rq_get( rpP )
  298.  
  299.         Process the REQ_GET request: Get an event's description
  300.  
  301. */
  302.  
  303. static void
  304. rq_get(
  305.         RP              *rpP            /* Request parameter block */
  306. ) {
  307.         int             eval;           /* Error value */
  308.         char            *msgP;          /* Ptr to error return */
  309.  
  310.     /* Lock the event list so that we can manipulate it */
  311.     get_sem( "rq_get", "event list", Eventsem );
  312.  
  313.     /* Catch errors here so real routine can work */
  314.     eval = handle_error( rq_get1, rpP, Werlist, &msgP );
  315.  
  316.     /* Unlock the list */
  317.     rel_sem( "rq_get", "event list", Eventsem );
  318.  
  319.     /* Throw back an error if there was one */
  320.     if ( eval != CXNONE )
  321.         return_error( el_cond( Werlist, eval ), msgP );
  322. }
  323.  
  324. static int
  325. rq_get1(
  326.         RP              *rpP
  327. ) {
  328.         TMXREQ_GET      *reqP;          /* Receive message header */
  329.         TMXMSG          *rspP;          /* Response message header */
  330.         PEVENT          *peventP;       /* Ptr to pending event */
  331.  
  332.     reqP = (TMXREQ_GET *)rpP->rp_reqP;
  333.     rspP = rpP->rp_rspP;
  334.  
  335.     /* Look for the event */
  336.     peventP = event_find( &reqP->g_evname[0] );
  337.  
  338.     /* Return the event */
  339.     if ( peventP == NULL )
  340.         errresp( (TMXRSP_ERR *)rspP, 0, "Event not found." );
  341.     else
  342.         return_event( rspP, peventP->pe_eventP );
  343.  
  344.     return( 0 );
  345. }
  346. /*
  347.  
  348. *//* rq_getnext( rpP )
  349.  
  350.         Process the REQ_GETNEXT request: Get the event after the
  351.                 one specified.
  352.  
  353. */
  354.  
  355. static void
  356. rq_getnext(
  357.         RP              *rpP            /* Request parameter block */
  358. ) {
  359.         int             eval;           /* Error value */
  360.         char            *msgP;          /* Ptr to error return */
  361.  
  362.     /* Lock the event list so that we can manipulate it */
  363.     get_sem( "rq_getnext", "event list", Eventsem );
  364.  
  365.     /* Catch errors here so real routine can work */
  366.     eval = handle_error( rq_getnext1, rpP, Werlist, &msgP );
  367.  
  368.     /* Unlock the list */
  369.     rel_sem( "rq_getnext", "event list", Eventsem );
  370.  
  371.     /* Throw back an error if there was one */
  372.     if ( eval != CXNONE )
  373.         return_error( el_cond( Werlist, eval ), msgP );
  374. }
  375.  
  376. static int
  377. rq_getnext1(
  378.         RP              *rpP
  379. ) {
  380.         TMXREQ_GET      *reqP;          /* Receive message header */
  381.         TMXMSG          *rspP;          /* Response message header */
  382.         PEVENT          *peventP;       /* Ptr to pending event */
  383.         PEVENT          *retP;          /* Ptr to the one to return */
  384.  
  385.     reqP = (TMXREQ_GET *)rpP->rp_reqP;
  386.     rspP = rpP->rp_rspP;
  387.  
  388.     /* Look for the event.  Note that the list of events is not kept
  389.        in alphabetical order, so we'll have to search the whole list
  390.        for the one that is the best candidate.  It would be possible
  391.        to also maintain a list of events by name, but I don't imagine
  392.        that there will be a whole lot of events in the system, so this
  393.        ought to suffice.  Besides, name-order is only important when
  394.        responding to edit requests, not in the normal operation. */
  395.  
  396.     retP = NULL;
  397.     for( peventP = PendingL; peventP != NULL; peventP = peventP->pe_nextP )
  398.         if ( stricmp( &reqP->g_evname[0],
  399.                  peventP->pe_eventP->ev_nameP ) < 0 ) {
  400.             /* We have a candidate; choose between it and the one already
  401.                selected. */
  402.             if ( ( retP == NULL ) ||
  403.                  ( stricmp( peventP->pe_eventP->ev_nameP,
  404.                               retP->pe_eventP->ev_nameP ) < 0 )
  405.                )
  406.                 retP = peventP;
  407.         }
  408.  
  409.     /* Return the event */
  410.     if ( retP == NULL ) {
  411.         rspP->m_code = RSP_OK;
  412.         rspP->m_len = sizeof( TMXMSG );
  413.     }
  414.     else
  415.         return_event( rspP, retP->pe_eventP );
  416.  
  417.     return( 0 );
  418. }
  419. /*
  420.  
  421. *//* rq_modify( rpP )
  422.  
  423.         Process the REQ_MODIFY request; modify an event.
  424.  
  425. This replaces an existing event with a new one.
  426.  
  427. */
  428.  
  429. static void
  430. rq_modify(
  431.         RP              *rpP            /* Ptr to request parm blk */
  432. ) {
  433.         int             eval;           /* Error value */
  434.         char            *msgP;          /* Ptr to error return */
  435.  
  436.     /* Lock the event list so that we can manipulate it */
  437.     get_sem( "rq_modify", "event list", Eventsem );
  438.  
  439.     /* Catch errors here so real routine can work */
  440.     eval = handle_error( rq_mod1, rpP, Werlist, &msgP );
  441.  
  442.     /* Unlock the list */
  443.     rel_sem( "rq_modify", "event list", Eventsem );
  444.  
  445.     /* Throw back an error if there was one */
  446.     if ( eval != CXNONE )
  447.         return_error( el_cond( Werlist, eval ), msgP );
  448.  
  449. }
  450.  
  451. static int
  452. rq_mod1(
  453.         RP              *rpP            /* Ptr to request parm blk */
  454. ) {
  455.  
  456.         char            *nameP;         /* Ptr to old name */
  457.         char            *evbufP;        /* Ptr to buffered event data */
  458.         TMXMSG          *reqP;          /* Ptr to request message */
  459.         TMXMSG          *rspP;          /* Ptr to response message */
  460.         EVENT           *eventP;        /* Event that we create */
  461.         PEVENT          *peventP;       /* Ptr to the current event */
  462.  
  463.     reqP = rpP->rp_reqP;
  464.     rspP = rpP->rp_rspP;
  465.  
  466.     /* Get the info */
  467.     nameP = (char *)&reqP[1];           /* Name of the event */
  468.     evbufP = nameP + strlen( nameP ) + 1;
  469.     eventP = event_unpack( evbufP,
  470.                  reqP->m_len - ( evbufP - (char *)reqP ) );
  471.  
  472.     /* Find the existing event */
  473.     peventP = event_find( nameP );
  474.  
  475.     if ( peventP == NULL ) {
  476.         errresp( (TMXRSP_ERR *)rspP, 0, "No such event." );
  477.         free( eventP );
  478.         return( 0 );
  479.     }
  480.  
  481.     /* Take it off the list. */
  482.     unschedule( peventP );
  483.  
  484.     /* Check for illegal modify (to another existing name) */
  485.     if ( event_find( eventP->ev_nameP ) != NULL ) {
  486.         errresp( (TMXRSP_ERR *)rspP, 0, "Duplicate event name." );
  487.         free( eventP );
  488.         schedule( peventP );
  489.         return( 0 );
  490.     }
  491.  
  492.     /* Replace the event info. */
  493.     free( peventP->pe_eventP );
  494.     peventP->pe_eventP = eventP;
  495.  
  496.     /* Reschedule it. */
  497.     schedule( peventP );
  498.  
  499.     /* Write out the new event database */
  500.     db_write();
  501.  
  502.     /* OK return. */
  503.     rspP->m_code = RSP_OK;
  504.     rspP->m_len = sizeof( TMXMSG );
  505.  
  506.     return( 0 );
  507. }
  508. /*
  509.  
  510. *//* return_event( rspP, eventP )
  511.  
  512.         Formats an event-return message
  513.  
  514. Accepts :
  515.  
  516.         rspP            Ptr to response block
  517.         eventP          Ptr to event block
  518.  
  519. Returns :
  520.  
  521.         < nothing >
  522.  
  523. */
  524.  
  525. static void
  526. return_event(
  527.         TMXMSG          *rspP,          /* Ptr to response block */
  528.         EVENT           *eventP         /* Ptr to event to return */
  529. ) {
  530.     rspP->m_code = RSP_EVENT;
  531.     rspP->m_len = sizeof( TMXMSG );
  532.     rspP->m_len += event_pack( eventP, (char *)&rspP[1],
  533.                                 512 - sizeof(TMXMSG) );
  534. }
  535. /*
  536.  
  537. *//* errresp( msgP, errcode, errmsgP )
  538.  
  539.         Fill in an error response message
  540.  
  541. Accepts :
  542.  
  543.         msgP            Ptr to message buffer
  544.         errcode         Ptr to error code
  545.         errmsgP         Ptr to error message string
  546.  
  547. Returns :
  548.  
  549.         *rspLP          Length of message
  550.         < message filled in >
  551.  
  552. */
  553.  
  554. static void
  555. errresp(
  556.         TMXRSP_ERR      *msgP,          /* Ptr to message buffer */
  557.         int             errcode,        /* Error code */
  558.         char            *errmsgP        /* Error message text */
  559. ) {
  560.  
  561.     msgP->e_msghdr.m_code = RSP_ERROR;
  562.     msgP->e_msghdr.m_len = sizeof( TMXRSP_ERR ) + strlen( errmsgP );
  563.  
  564.     msgP->e_code = errcode;
  565.     strcpy( &msgP->e_msg[0], errmsgP );
  566. }
  567.