home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: SysTools / SysTools.zip / pmcron03.zip / server.c < prev    next >
C/C++ Source or Header  |  1996-05-09  |  17KB  |  321 lines

  1. /* Copyright (c) 1995 Florian Große-Coosmann, RCS section at the eof         */
  2. /* This module includes all functions needed to communicate with the pipe.   */
  3. #define INCL_NOPM
  4. #define INCL_NOCOMMON
  5. #define INCL_DOSSEMAPHORES
  6. #define INCL_DOSNMPIPES
  7. #define INCL_DOSFILEMGR
  8. #define INCL_DOSPROCESS
  9. #include <os2.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <time.h>
  14. #include <ctype.h>
  15. #include <errno.h>
  16. #include <fcntl.h>
  17. #include <io.h>
  18. #include "server.h"
  19.  
  20.  
  21. char  PipeName[] = DEF_PIPENAME;        /* the name of the beast             */
  22. int   pipehandle = -1;                  /* not open at startup               */
  23.  
  24. /*****************************************************************************/
  25. /*  function name : IsPipeThere                                              */
  26. /*                                                                           */
  27. /*  return value  : 1 if the pipe already exists (another crond is           */
  28. /*                  running), 0 if not                                       */
  29. /*                                                                           */
  30. /*  description   : tries to open the named pipe and decides wether the      */
  31. /*                  daemon is alredy running.                                */
  32. /*****************************************************************************/
  33. int IsPipeThere(void)
  34. {
  35.    int handle;
  36.    if ((handle = open(PipeName,O_BINARY | O_RDWR)) == -1) {
  37.       if (errno == ENOENT)              /* only ENOENT is OK, since the pipe */
  38.          return(0);                     /* may be in use or in a disconneted */
  39.                                         /* state.                            */
  40.       return(1);
  41.    }
  42.    close(handle);
  43.    return(1);
  44. }
  45.  
  46. /*****************************************************************************/
  47. /*  function name : WaitClientDisconnect                                     */
  48. /*                                                                           */
  49. /*  description   : waits until the client closes the pipe. This is needed   */
  50. /*                  to provide data send back, since the client has to       */
  51. /*                  receive the data before we close the pipe.               */
  52. /*                  We wait until the pipe is closed, either by the client   */
  53. /*                  or by the cron thread which will close it after a        */
  54. /*                  timeout (currently about 1 minute).                      */
  55. /*                                                                           */
  56. /*  note          : Maybe, this function is unnessesary if we use the        */
  57. /*                  NP_NOWRITEBEHIND-flag while opening the pipe?            */
  58. /*****************************************************************************/
  59. void WaitClientDisConnect(void)
  60. {
  61.    ULONG err,state,done;
  62.    AVAILDATA avail;
  63.    time_t kill;
  64.    unsigned wait = 32;
  65.    char DummyBuf[1];
  66.    kill = time(NULL) + 20;              /* don't believe in the cron thread! */
  67.                                         /* Close the pipe after 20 minutes.  */
  68.                                         /* That's more than enough.          */
  69.    do {
  70.       err = DosPeekNPipe(pipehandle,
  71.                          DummyBuf,
  72.                          1,
  73.                          &done,
  74.                          &avail,
  75.                          &state);
  76.       if ((err != 0) || (state != NP_STATE_CONNECTED))
  77.          return;                        /* pipe is closed                    */
  78.       DosSleep(wait);                   /* first, wait 1 time slice, double  */
  79.       wait <<= 1;                       /* the waiting time until the maximum*/
  80.       if (wait > 1000)                  /* of 1 second is reached            */
  81.          wait = 1000;
  82.    } while (time(NULL) < kill);
  83. }
  84.  
  85. /*****************************************************************************/
  86. /*  function name : ReadBlockedMsgPipe                                       */
  87. /*                                                                           */
  88. /*  arguments     : pointer to the handle of the pipe, buffer, size of the   */
  89. /*                  buffer, minimum to read before returning                 */
  90. /*                                                                           */
  91. /*  return value  : bytes that have been read or -errno in case of an        */
  92. /*                  error                                                    */
  93. /*                                                                           */
  94. /*  description   : reads bytes out of the pipe. Some possible errors were   */
  95. /*                  checked to correct reading problems.                     */
  96. /*                  Normally, the function returns after reading a minimum   */
  97. /*                  of bytes.                                                */
  98. /*                                                                           */
  99. /*  note          : the file may have been closed externally while reading   */
  100. /*                  in this function. The pipes work in the correct manner   */
  101. /*                  in this case but sockets return an errno of EINTR.       */
  102. /*                  This is an acceptable error in most cases of retry       */
  103. /*                  but we have to abort! (There is no way for both          */
  104. /*                  handles to figure out the close operation, really.)      */
  105. /*                  Therefore, we use the pointer to the handle to see       */
  106. /*                  wether the pipe or socket has been closed.               */
  107. /*****************************************************************************/
  108. int ReadBlockedMsgPipe(volatile int *hf,char *buffer,size_t maxbuffer,
  109.                                                               size_t minbuffer)
  110. {
  111.    int i;
  112.    int done = 0;
  113.    errno = 0;
  114.    i = read(*hf,buffer,maxbuffer);
  115.    if (i > 0) {                         /* looks fine..                      */
  116.       done = i;
  117.       if ((size_t) i >= minbuffer)      /* is it enough?                     */
  118.          return(i);                     /* yes, all done                     */
  119.    }
  120.                                         /* i <= 0:                           */
  121.    else if ((errno != EAGAIN) && (errno != EINTR)) /* accept interrupts and  */
  122.                                         /* empty read buffers only           */
  123.       return((errno) ? -errno : -EINVAL); /* unexpected error                */
  124.    while (((errno == EAGAIN) ||         /* these errnos are "good" errnos    */
  125.            (errno == EINTR) ||
  126.            (errno == 0)) &&
  127.           (done < minbuffer)) {
  128.       if (*hf == -1)                    /* has the file been closed from     */
  129.          break;                         /* the cron thread?                  */
  130.       errno = 0;                        /* reset errno and try to read       */
  131.       i = read(*hf,buffer + done,maxbuffer - (size_t) done); /* another chunk*/
  132.       if (i > 0)                        /* read OK?                          */
  133.          done += i;
  134.                                         /* maybe, we run into an error if we */
  135.                                         /* read 0 bytes again and again but  */
  136.                                         /* we'll be killed by the cron thread*/
  137.                                         /* after a timeout, he's a good      */
  138.                                         /* fellow :-)                        */
  139.    }
  140.    if (done > 0)                        /* anything done?                    */
  141.       return(done);                     /* ignore any errors                 */
  142.    return((errno) ? -errno : -EINVAL);  /* errno not set? choose EINVAL      */
  143. }
  144.  
  145. /*****************************************************************************/
  146. /*  function name : ScanNumber                                               */
  147. /*                                                                           */
  148. /*  arguments     : 0-terminated string, buffer for the result               */
  149. /*                                                                           */
  150. /*  return value  : errno value in case of an error, 0 otherwise             */
  151. /*                                                                           */
  152. /*  description   : tries to convert the string to a positive decimal        */
  153. /*                  number and puts it to the supplied buffer. Leading       */
  154. /*                  and trailing whitespaces are accepted.                   */
  155. /*****************************************************************************/
  156. int ScanNumber(char *s,ULONG *num)
  157. {
  158.    ULONG val;
  159.    char *ptr;
  160.    while (isspace(*s))                  /* jump over leading whitespaces     */
  161.       s++;
  162.    if ((*s == '\0') || (*s == '-'))     /* empty string or the negation sign?*/
  163.       return(EINVAL);
  164.    errno = 0;
  165.    val = strtoul(s,&ptr,10);            /* try to convert                    */
  166.    if ((s == ptr) || (errno))           /* nothing done or an error?         */
  167.       return(EINVAL);
  168.    while (isspace(*ptr))                /* jump over trailing whitespaces    */
  169.       ptr++;
  170.    if (*ptr != '\0')                    /* any more characters in the string?*/
  171.       return(EINVAL);
  172.    *num = val;                          /* assign value and return OK        */
  173.    return(0);
  174. }
  175.  
  176. /*****************************************************************************/
  177. /*  function name : ProcessRequest                                           */
  178. /*                                                                           */
  179. /*  arguments     : pointer to a pipe or socket handle, name of the pipe     */
  180. /*                  or socket.                                               */
  181. /*                                                                           */
  182. /*  description   : processes one request from the pipe or socket. The       */
  183. /*                  pipe or socket must be in the CONNECTED state.           */
  184. /*                                                                           */
  185. /*  note          : the file may have been closed externally while doing     */
  186. /*                  some work in this function. The pipes work in the        */
  187. /*                  correct manner in this case but sockets return an        */
  188. /*                  errno of EINTR.                                          */
  189. /*                  This is an acceptable error in most cases of retry       */
  190. /*                  but we have to abort! (There is no way for both          */
  191. /*                  handles to figure out the close operation, really.)      */
  192. /*                  Therefore, we use the pointer to the handle to see       */
  193. /*                  wether the pipe or socket has been closed.               */
  194. /*****************************************************************************/
  195. void ProcessRequest(volatile int *hf,char *name)
  196. {
  197.    char tmpbuf[0x1000];
  198.    char *buf = NULL,Request;
  199.  
  200.    int err,done = 0;
  201.    ULONG i;
  202.                                         /* read the requested function       */
  203.    if ((done = ReadBlockedMsgPipe(hf,tmpbuf,sizeof(tmpbuf)-1,1)) < 0) {
  204.       errno = -done;                    /* set back the errno value          */
  205.       Perror(name);                     /* and print it to the output file   */
  206.       return;
  207.    }
  208.                                         /* analyse the function code         */
  209.    if (done == 0) {                     /* pipe opened and closed immediately*/
  210.       Message(Get(IDS_0ByteCommunication));
  211.       return;
  212.    }
  213.    tmpbuf[done] = 0;                    /* terminate the request             */
  214.    err = EINVAL;                        /* assume an error, if err != 0 the  */
  215.                                         /* code below fills the answer buffer*/
  216.                                         /* with the appropriate error message*/
  217.    Request = tmpbuf[0];                 /* extract the request code          */
  218.    switch (Request) {
  219.       case 'D':                         /* Delete                            */
  220.          if ((done < 2) || (ScanNumber(tmpbuf + 1,&i) != 0))
  221.             break;
  222.          BlockProcess();                /* block the job list                */
  223.          if ((i == 0) || (LookupEntryNum(i,0) == NULL)) {   /* job number    */
  224.             err = 0;                    /* doesn't exist? Set the reply      */
  225.             strcpy(tmpbuf,Get(IDS_JobNotFound));   /* explicitely            */
  226.          } else if ((err = DeleteEntryNum(i,tmpbuf)) == 0)
  227.             JobsModified();             /* the list is modified              */
  228.          UnBlockProcess();              /* allow other threads to continue   */
  229.          break;
  230.  
  231.       case 'R':                         /* Read list request                 */
  232.          if (done != 1)
  233.             break;
  234.          BlockProcess();                /* block the job list                */
  235.          buf = CreateList(CL_USER);     /* create a buffer with all jobs and */
  236.                                         /* their job numbers                 */
  237.          UnBlockProcess();              /* allow other threads to continue   */
  238.          if (buf == NULL) {             /* not enough memory? Don't stop the */
  239.             err = ENOMEM;               /* process, since the cron thread is */
  240.             Message(Get(IDS_NotEnoughMemory));  /* the only important thread */
  241.          } else {                       /* there are data to send back. They */
  242.             err = 0;                    /* may be larger than every standard */
  243.                                         /* buffer, thus send them in a       */
  244.                                         /* different write operation         */
  245.             sprintf(tmpbuf,"crond: %lu Data OK\r\n",  /* don't change this!!!*/
  246.                            (unsigned long) strlen(buf));
  247.          }
  248.          break;
  249.  
  250.       case 'N':                         /* New Entry                         */
  251.          if (done < 2)
  252.             break;
  253.          BlockProcess();                /* block the job list                */
  254.          if ((err = NewEntry(tmpbuf + 1,(size_t) (done - 1),tmpbuf)) == 0)
  255.             JobsModified();
  256.          UnBlockProcess();              /* allow other threads to continue   */
  257.          break;
  258.  
  259.       default:                          /* err has been set to EINVAL, that's*/
  260.          ;                              /* pretty good                       */
  261.    }
  262.    if (err)                             /* any errors? Convert them to a     */
  263.       sprintf(tmpbuf,"crond: %s\r\n",GetError(err));  /* message             */
  264.  
  265.    if ((done = write(*hf,tmpbuf,strlen(tmpbuf))) < 0) {  /* error while      */
  266.       if (buf != NULL)                  /* writing the answer?               */
  267.          free(buf);
  268.       Perror(Get(IDS_ErrRequest));      /* notice it in out output file      */
  269.       return;
  270.    } else if ((size_t) done != strlen(tmpbuf)) {   /* can't write the whole  */
  271.       if (buf != NULL)                  /* message back?                     */
  272.          free(buf);
  273.       Message(Get(IDS_ErrRequestIncomplete));
  274.       return;
  275.    }
  276.    if ((Request != 'R') || (err)) {     /* no more transmits or an error?    */
  277.       if (buf != NULL)                  /* should never happen...            */
  278.          free(buf);
  279.       return;
  280.    }
  281.                                         /* Request == 'R', send the data     */
  282.                                         /* buffer but first of all let us    */
  283.                                         /* transmit the data. crontab expects*/
  284.                                         /* a small buffer of one line. If    */
  285.                                         /* we use pipes over a network or    */
  286.                                         /* to DOS boxes the data may be      */
  287.                                         /* collected. This will cause an     */
  288.                                         /* error with much data.             */
  289.    DosResetBuffer(*hf);
  290.    if ((done = write(*hf,buf,strlen(buf))) < 0)
  291.       Perror(Get(IDS_ErrList));
  292.    else if ((size_t) done != strlen(buf))
  293.       Message(Get(IDS_ErrListIncomplete),
  294.               done,(unsigned long) strlen(buf));
  295.    free(buf);
  296. }
  297.  
  298. /* RCS depending informations
  299.  *
  300.  * $Name: Version121 $
  301.  *
  302.  * $Log: server.c $
  303.  * Revision 1.4  1995/10/18 09:46:10  Florian
  304.  * Problems while writing to DOS-boxes or networks: need flushing between
  305.  * writes.
  306.  *
  307.  * Revision 1.3  1995/03/15 09:07:34  Florian
  308.  * Some minor bugs fixed.
  309.  * TCP/IP support added.
  310.  *
  311.  * Revision 1.2  1995/02/20 12:53:23  Florian
  312.  * All dialogs are placed into a notebook.
  313.  * Some bugs fixed.
  314.  *
  315.  * Revision 1.1  1995/02/03 10:42:48  Florian
  316.  * Initial revision
  317.  *
  318.  *
  319.  */
  320. static char rcsid[] = "@(#)$Id: server.c 1.4 1995/10/18 09:46:10 Florian Rel $";
  321.