home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3406 / ipc.c < prev    next >
C/C++ Source or Header  |  1991-05-23  |  11KB  |  446 lines

  1.  
  2. /* This module does all the inter-process communication. Hope I got 
  3.  * it right.
  4.  
  5.  * callable functions of this module:
  6.  
  7.  * void CreateServer(int portnum);
  8.  * void Client_run(char *server, int portnum);
  9.  * int CalcRequest(double x, y, dx, dy, cx, cy, 
  10.                    int iters, flags, xoff, yoff);
  11.  * void Invalidate(void);
  12.  * void FlushRequests(void);
  13.  * void CheckClients(int timeout); 
  14.  * void CloseDown(void);
  15.  * int PendingRequests(void);
  16.  
  17.  */
  18. #include <sys/types.h>
  19. #ifdef _AIX
  20. #include <sys/select.h>
  21. #endif
  22. #include <sys/types.h>
  23. #include <sys/time.h>
  24. #include <rpc/types.h>
  25. #include <rpc/xdr.h>
  26. #include <netinet/in.h>
  27. #include <unistd.h>
  28. #include <fcntl.h>
  29. #include <errno.h>
  30. #include <stdio.h>
  31. #include "ipc.h"
  32. #include "soc.h"
  33.  
  34. #define MAXHOST 8
  35.  
  36. #define PORTSTART IPPORT_USERRESERVED+926
  37.  
  38. #define SHORT_SIZE 2
  39. #define LONG_SIZE 4
  40. #define PACK_SIZE (6*8+4*4)
  41.  
  42. #define READY 0
  43. #define BUSY 1
  44. #define DEAD 2 /* Not yet impelented; for time-out. */
  45. #define OBSOLETE 3 /* client is busy, but result has become obsolete */
  46.  
  47. extern int errno;
  48.  
  49. static int soc1, soc2;
  50.  
  51. struct clientinfo {
  52.   int soc;
  53.   int status;
  54.   int x, y, w, h;
  55.   } client[MAXHOST];
  56.  
  57. static int clients= 0;
  58.  
  59. /* Queue of waiting calcrequests */
  60. struct waitqueue {
  61.   double x, y, dx, dy, cx, cy;
  62.   int w, h, iter, flags, xoff, yoff;
  63.   } *queue;
  64.  
  65. static int qlen= 0, qpos= 0;
  66.  
  67.  
  68. void CreateServer(portnum)
  69. int portnum;
  70. {
  71. if ((soc1= establish((u_short)portnum)) < 0) {
  72.   perror("establish");
  73.   exit(1);
  74.   }
  75. /* The socket should be marked non-blocking. */
  76. if (fcntl(soc1, F_SETFL, O_NDELAY) <0) {
  77.   perror("could not mark socket as non-blocking");
  78.   exit(1);
  79.   }
  80. }
  81.  
  82.  
  83. void Client_run(server, portnum)
  84. char *server;
  85. int portnum;
  86. {
  87. int p= 0;
  88.  
  89. while (p < MAXHOST && ((soc1= establish((u_short)(PORTSTART+p))) < 0)) 
  90.   p++;
  91.  
  92. if (soc1 < 0) {
  93.   perror("establish() failed");
  94.   exit(1);
  95.   }
  96.  
  97. if ((soc2= call_socket(server, portnum)) < 0) {
  98.   perror("call_socket() failed");
  99.   exit(1);
  100.   }
  101.  
  102. /* This socket shall block */
  103. if (fcntl(soc2, F_SETFL, 0) <0) {
  104.   perror("could not mark socket as blocking");
  105.   exit(1);
  106.   }
  107. /* Now the server knows we exist (no other handshaking is done),
  108.  * so loop waiting for incoming command (either QUIT or CALC)
  109.  */
  110.  
  111. for (;;) {
  112.   u_short cmd;
  113.   char xdrbuf[PACK_SIZE];
  114.   XDR xdrs;
  115.   int i;
  116.  
  117.   double x, y, dx, dy, cx, cy;
  118.   int w, h, iter, flags;
  119.   u_short *dest;
  120.   u_char *buf, *ptr;
  121.   u_long len, nlen;
  122.  
  123.   if (read_data(soc2, (char *)&cmd, SHORT_SIZE) < 0) {
  124.     /* an EOF condition... */
  125.     shutdown(soc1, 2);
  126.     close(soc1);
  127.     shutdown(soc2, 2);
  128.     close(soc2);
  129.     exit(0);
  130.     }
  131.  
  132.   cmd= ntohs(cmd);
  133.   switch(cmd) {
  134.     case QUIT:
  135.       shutdown(soc1, 2);
  136.       close(soc1);
  137.       shutdown(soc2, 2);
  138.       close(soc2);
  139.       exit(0);
  140.     case CALC:
  141.       xdrmem_create(&xdrs, xdrbuf, PACK_SIZE, XDR_DECODE);
  142.       if (read_data(soc2, (char *)xdrbuf, PACK_SIZE) < 0) {
  143.         /* EOF in the middle of read... */
  144.         shutdown(soc1, 2);
  145.         close(soc1);
  146.         shutdown(soc2, 2);
  147.         close(soc2);
  148.         exit(0);
  149.         }
  150.  
  151.       if (!(xdr_double(&xdrs, &x)  && xdr_double(&xdrs, &y) &&
  152.           xdr_double(&xdrs, &dx) && xdr_double(&xdrs, &dy) &&
  153.           xdr_double(&xdrs, &cx) && xdr_double(&xdrs, &cy) &&
  154.           xdr_int(&xdrs, &w) && xdr_int(&xdrs, &h) &&
  155.           xdr_int(&xdrs, &iter) && xdr_int(&xdrs, &flags) )) {
  156.         fprintf(stderr, "client xdr failed\n");
  157.         exit(1);
  158.         }
  159.  
  160.       xdr_destroy(&xdrs);
  161.       len= iterate(x, y, dx, dy, cx, cy,
  162.               w, h, iter, flags, &dest);
  163.       ptr= buf= (u_char *)malloc(SHORT_SIZE * len);
  164.       for (i= 0; i < len; i++) {
  165.         u_short tmp= htons(dest[i]);
  166.         *ptr++= (u_char)(tmp >> 8);
  167.         *ptr++= (u_char)(tmp & 0xff);
  168.         }
  169.       nlen= htonl(len);
  170.       if (write_data(soc2, (char *)&nlen, LONG_SIZE) < 0 ||
  171.           write_data(soc2, (char *)buf, (int)(SHORT_SIZE * len)) < 0) {
  172.         shutdown(soc1, 2);
  173.         close(soc1);
  174.         shutdown(soc2, 2);
  175.         close(soc2);
  176.         exit(0);
  177.         }
  178.       free(dest);
  179.       free(buf);
  180.       break;
  181.     default:
  182.       fprintf(stderr, "client received unknown command #%d\n",
  183.         cmd);
  184.     } /* switch */
  185.   } /* for */
  186. } /* client_run */
  187.  
  188.  
  189. void Recruit()
  190. {
  191. int soc;
  192. if ((soc= get_connection(soc1)) < 0) {
  193.   if (errno == EINTR || errno == EWOULDBLOCK)
  194.     return;
  195.   perror("accept");
  196.   exit(1);
  197.   }
  198. /* This socket should block when necessary */
  199. if (fcntl(soc, F_SETFL, 0) <0) {
  200.   perror("could not mark socket as blocking");
  201.   exit(1);
  202.   }
  203. if (clients == MAXHOST) {
  204.   /* If too many hosts, send QUIT command immediately. */
  205.   u_short cmd;
  206.   cmd= htons(QUIT);
  207.   write_data(soc, (char *)&cmd, SHORT_SIZE); /* if this fails, tough. */
  208.   shutdown(soc, 2);
  209.   close(soc);
  210.   return;
  211.   }
  212. /* record new client */
  213. client[clients].soc= soc;
  214. client[clients].status= READY;
  215. clients++;
  216. }
  217.  
  218.  
  219. int CalcRequest(x, y, dx, dy, cx, cy, w, h, iter, flags, xoff, yoff)
  220. double x, y, dx, dy, cx, cy;
  221. int w, h, iter, flags, xoff, yoff;
  222. {
  223. int cli;
  224. Recruit();
  225. if (clients == 0)
  226.   return(0); /* Cannot satisfy request */
  227.  
  228. for (cli= 0; cli < clients; cli++) {
  229.   if (client[cli].status == READY) {
  230.     /* Send request */
  231.     u_short cmd;
  232.     char xdrbuf[PACK_SIZE];
  233.     XDR xdrs;
  234.  
  235.     /* Cant use &-operator on auto variables */
  236.     double x2= x, y2= y, dx2= dx, dy2= dy, cx2= cx, cy2= cy;
  237.     int w2= w, h2= h, iter2= iter, flags2= flags;
  238.  
  239.     cmd= htons(CALC);
  240.     if (write_data(client[cli].soc, (char *)&cmd, SHORT_SIZE) < 0) {
  241.       shutdown(client[cli].soc, 2);
  242.       close(client[cli].soc);
  243.       client[cli].status = DEAD;
  244.       return(0);
  245.       }
  246.  
  247.     xdrmem_create(&xdrs, xdrbuf, PACK_SIZE, XDR_ENCODE);
  248.  
  249.     if (!(xdr_double(&xdrs, &x2)  && xdr_double(&xdrs, &y2) &&
  250.       xdr_double(&xdrs, &dx2) && xdr_double(&xdrs, &dy2) &&
  251.       xdr_double(&xdrs, &cx2) && xdr_double(&xdrs, &cy2) &&
  252.       xdr_int(&xdrs, &w2) && xdr_int(&xdrs, &h2) &&
  253.       xdr_int(&xdrs, &iter2) && xdr_int(&xdrs, &flags2) )) {
  254.       fprintf(stderr, "server xdr failed\n");
  255.       exit(1);
  256.       }
  257.  
  258.     if (write_data(client[cli].soc, (char *)xdrbuf, PACK_SIZE) < 0) {
  259.       shutdown(client[cli].soc, 2);
  260.       close(client[cli].soc);
  261.       client[cli].status = DEAD;
  262.       return(0);
  263.       }
  264.     xdr_destroy(&xdrs);
  265.     client[cli].status= BUSY;
  266.     client[cli].x= xoff; client[cli].y= yoff;
  267.     client[cli].w= w; client[cli].h= h;
  268.     return(1); /* Request succeeded */
  269.  
  270.     } /* if */
  271.   } /* for */
  272. /* Well, all clients were busy. Now we shall put the remaining
  273.  * requests into a queue waiting for processing in the future.
  274.  * (Formerly, we just blocked until a client became free.
  275.  * ie. CheckClient(BLOCK);  and then try again.)
  276.  */
  277.  
  278. if (qlen == 0)
  279.   queue= (struct waitqueue *)
  280.           malloc((qlen= 4) * sizeof(struct waitqueue));
  281. else if (qpos >= qlen)
  282.   queue= (struct waitqueue *)
  283.           realloc(queue, (qlen += 4) * sizeof(struct waitqueue));
  284. queue[qpos].x= x;   queue[qpos].y= y;
  285. queue[qpos].dx= dx; queue[qpos].dy= dy;
  286. queue[qpos].cx= cx; queue[qpos].cy= cy;
  287. queue[qpos].w= w;   queue[qpos].h= h;
  288. queue[qpos].iter= iter; queue[qpos].flags= flags;
  289. queue[qpos].xoff= xoff; queue[qpos].yoff= yoff;
  290. qpos ++;
  291. return(2); /* Succesfully queued */
  292.  
  293. } /* CalcRequest() */
  294.  
  295.  
  296. void CheckClients(timeout)
  297. int timeout;
  298. {
  299. int cli, i;
  300. fd_set ready;
  301. struct timeval *to= NULL; /* NULL would mean block infinitely */
  302. int width;
  303. Recruit();
  304.  
  305. if (timeout != BLOCK) {
  306.   to= (struct timeval *)malloc(sizeof(struct timeval));
  307.   to->tv_usec= 0;
  308.   if (timeout == NOBLOCK)
  309.     to->tv_sec= 0;
  310.   else
  311.     to->tv_sec= timeout;
  312.   }
  313. width= getdtablesize();
  314. FD_ZERO(&ready);
  315. for (cli= 0; cli < clients; cli++)
  316.   if (client[cli].status == BUSY || client[cli].status == OBSOLETE) 
  317.     FD_SET(client[cli].soc, &ready);
  318. if (select(width, &ready, (fd_set *)NULL, (fd_set *)NULL, to) < 0) {
  319.   perror("select");
  320.   exit(1);
  321.   }
  322. for (cli= 0; cli < clients; cli++) {
  323.   if (FD_ISSET(client[cli].soc, &ready))
  324.     {
  325.     void DrawImage();
  326.     u_short *dest;
  327.     u_char *buf, *ptr;
  328.     u_long len;
  329.  
  330.     if (read_data(client[cli].soc, (char *)&len, LONG_SIZE) < 0) {
  331.       shutdown(client[cli].soc, 2);
  332.       close(client[cli].soc);
  333.       client[cli].status = DEAD;
  334.       return;
  335.       }
  336.     len= ntohl(len);
  337.     dest= (u_short *)malloc(sizeof(short) * len);
  338.     ptr= buf= (u_char *)malloc(SHORT_SIZE * len);
  339.  
  340.     if (read_data(client[cli].soc, (char *)buf, (int)(SHORT_SIZE * len)) < 0) {
  341.       shutdown(client[cli].soc, 2);
  342.       close(client[cli].soc);
  343.       client[cli].status = DEAD;
  344.       return;
  345.       }
  346.  
  347.     /* Should the result be drawn on screen? */
  348.     if (client[cli].status == OBSOLETE) {
  349.       /* No, this is obsolete */
  350.       free(buf);
  351.       free(dest);
  352.       client[cli].status= READY;
  353.       }
  354.     else {
  355.       /* Go ahead, draw it */
  356.       for (i= 0; i < len; i++) {
  357.         dest[i]= (*ptr << 8)+(*(ptr+1));
  358.         ptr += 2;
  359.         }
  360.       free(buf);
  361.  
  362.       for (i= 0; i < len; i++)
  363.         dest[i]= ntohs(dest[i]);
  364.       DrawImage(client[cli].x, client[cli].y,
  365.              client[cli].w, client[cli].h, dest);
  366.       client[cli].status= READY;
  367.       } /* else */
  368.     } /* if FD_SET */
  369.   } /* for */
  370.  
  371. /* Now, if there is an idle client, and if there are requests
  372.  * waiting, handle the waiting requests. 
  373.  */
  374. while (qpos > 0) {
  375.   int c_free= 0;
  376.   for (cli= 0; cli < clients; cli++)
  377.     if (client[cli].status == READY)
  378.       c_free= 1;
  379.   if (c_free) {
  380.     qpos--;
  381.     CalcRequest(queue[qpos].x, queue[qpos].y,
  382.                 queue[qpos].dx, queue[qpos].dy,
  383.                 queue[qpos].cx, queue[qpos].cy,
  384.                 queue[qpos].w, queue[qpos].h,
  385.                 queue[qpos].iter, queue[qpos].flags,
  386.                 queue[qpos].xoff, queue[qpos].yoff);
  387.     }
  388.   else
  389.     break;
  390.   } /* while */
  391. } /* CheckClients */
  392.  
  393.  
  394. void Invalidate()
  395. {
  396. int cli;
  397.  
  398. for (cli= 0; cli < clients; cli++)
  399.   if (client[cli].status == BUSY)
  400.     client[cli].status= OBSOLETE;
  401. qpos= 0;
  402. }
  403.  
  404.  
  405. void FlushRequests()
  406. {
  407. /* If any of the clients is unreachable or down, this call will block
  408.  * forever. This would then be the most suitable place for time-outs.
  409.  */
  410. int cli;
  411.  
  412. for (cli= 0; cli < clients; cli++)
  413.   while (client[cli].status == BUSY  || client[cli].status == OBSOLETE)
  414.     CheckClients(BLOCK);
  415. }
  416.  
  417.  
  418. void CloseDown()
  419. {
  420. int cli;
  421.  
  422. FlushRequests();
  423. for (cli= 0; cli < clients; cli++)
  424.   if (client[cli].status != DEAD) {
  425.     u_short cmd;
  426.     cmd= htons(QUIT);
  427.     write_data(client[cli].soc, (char *)&cmd, SHORT_SIZE);
  428.     shutdown(client[cli].soc, 2);
  429.     close(client[cli].soc);
  430.     }
  431. shutdown(soc1, 2);
  432. close(soc1);
  433. }
  434.  
  435.  
  436. int PendingRequests()
  437. {
  438. int cli;
  439. for (cli= 0; cli < clients; cli++) {
  440.   if (client[cli].status == BUSY)
  441.     return(1);
  442.   }
  443. return(0);
  444. }
  445.  
  446.