home *** CD-ROM | disk | FTP | other *** search
-
- /* This module does all the inter-process communication. Hope I got
- * it right.
-
- * callable functions of this module:
-
- * void CreateServer(int portnum);
- * void Client_run(char *server, int portnum);
- * int CalcRequest(double x, y, dx, dy, cx, cy,
- int iters, flags, xoff, yoff);
- * void Invalidate(void);
- * void FlushRequests(void);
- * void CheckClients(int timeout);
- * void CloseDown(void);
- * int PendingRequests(void);
-
- */
- #include <sys/types.h>
- #ifdef _AIX
- #include <sys/select.h>
- #endif
- #include <sys/types.h>
- #include <sys/time.h>
- #include <rpc/types.h>
- #include <rpc/xdr.h>
- #include <netinet/in.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <stdio.h>
- #include "ipc.h"
- #include "soc.h"
-
- #define MAXHOST 8
-
- #define PORTSTART IPPORT_USERRESERVED+926
-
- #define SHORT_SIZE 2
- #define LONG_SIZE 4
- #define PACK_SIZE (6*8+4*4)
-
- #define READY 0
- #define BUSY 1
- #define DEAD 2 /* Not yet impelented; for time-out. */
- #define OBSOLETE 3 /* client is busy, but result has become obsolete */
-
- extern int errno;
-
- static int soc1, soc2;
-
- struct clientinfo {
- int soc;
- int status;
- int x, y, w, h;
- } client[MAXHOST];
-
- static int clients= 0;
-
- /* Queue of waiting calcrequests */
- struct waitqueue {
- double x, y, dx, dy, cx, cy;
- int w, h, iter, flags, xoff, yoff;
- } *queue;
-
- static int qlen= 0, qpos= 0;
-
-
- void CreateServer(portnum)
- int portnum;
- {
- if ((soc1= establish((u_short)portnum)) < 0) {
- perror("establish");
- exit(1);
- }
- /* The socket should be marked non-blocking. */
- if (fcntl(soc1, F_SETFL, O_NDELAY) <0) {
- perror("could not mark socket as non-blocking");
- exit(1);
- }
- }
-
-
- void Client_run(server, portnum)
- char *server;
- int portnum;
- {
- int p= 0;
-
- while (p < MAXHOST && ((soc1= establish((u_short)(PORTSTART+p))) < 0))
- p++;
-
- if (soc1 < 0) {
- perror("establish() failed");
- exit(1);
- }
-
- if ((soc2= call_socket(server, portnum)) < 0) {
- perror("call_socket() failed");
- exit(1);
- }
-
- /* This socket shall block */
- if (fcntl(soc2, F_SETFL, 0) <0) {
- perror("could not mark socket as blocking");
- exit(1);
- }
- /* Now the server knows we exist (no other handshaking is done),
- * so loop waiting for incoming command (either QUIT or CALC)
- */
-
- for (;;) {
- u_short cmd;
- char xdrbuf[PACK_SIZE];
- XDR xdrs;
- int i;
-
- double x, y, dx, dy, cx, cy;
- int w, h, iter, flags;
- u_short *dest;
- u_char *buf, *ptr;
- u_long len, nlen;
-
- if (read_data(soc2, (char *)&cmd, SHORT_SIZE) < 0) {
- /* an EOF condition... */
- shutdown(soc1, 2);
- close(soc1);
- shutdown(soc2, 2);
- close(soc2);
- exit(0);
- }
-
- cmd= ntohs(cmd);
- switch(cmd) {
- case QUIT:
- shutdown(soc1, 2);
- close(soc1);
- shutdown(soc2, 2);
- close(soc2);
- exit(0);
- case CALC:
- xdrmem_create(&xdrs, xdrbuf, PACK_SIZE, XDR_DECODE);
- if (read_data(soc2, (char *)xdrbuf, PACK_SIZE) < 0) {
- /* EOF in the middle of read... */
- shutdown(soc1, 2);
- close(soc1);
- shutdown(soc2, 2);
- close(soc2);
- exit(0);
- }
-
- if (!(xdr_double(&xdrs, &x) && xdr_double(&xdrs, &y) &&
- xdr_double(&xdrs, &dx) && xdr_double(&xdrs, &dy) &&
- xdr_double(&xdrs, &cx) && xdr_double(&xdrs, &cy) &&
- xdr_int(&xdrs, &w) && xdr_int(&xdrs, &h) &&
- xdr_int(&xdrs, &iter) && xdr_int(&xdrs, &flags) )) {
- fprintf(stderr, "client xdr failed\n");
- exit(1);
- }
-
- xdr_destroy(&xdrs);
- len= iterate(x, y, dx, dy, cx, cy,
- w, h, iter, flags, &dest);
- ptr= buf= (u_char *)malloc(SHORT_SIZE * len);
- for (i= 0; i < len; i++) {
- u_short tmp= htons(dest[i]);
- *ptr++= (u_char)(tmp >> 8);
- *ptr++= (u_char)(tmp & 0xff);
- }
- nlen= htonl(len);
- if (write_data(soc2, (char *)&nlen, LONG_SIZE) < 0 ||
- write_data(soc2, (char *)buf, (int)(SHORT_SIZE * len)) < 0) {
- shutdown(soc1, 2);
- close(soc1);
- shutdown(soc2, 2);
- close(soc2);
- exit(0);
- }
- free(dest);
- free(buf);
- break;
- default:
- fprintf(stderr, "client received unknown command #%d\n",
- cmd);
- } /* switch */
- } /* for */
- } /* client_run */
-
-
- void Recruit()
- {
- int soc;
- if ((soc= get_connection(soc1)) < 0) {
- if (errno == EINTR || errno == EWOULDBLOCK)
- return;
- perror("accept");
- exit(1);
- }
- /* This socket should block when necessary */
- if (fcntl(soc, F_SETFL, 0) <0) {
- perror("could not mark socket as blocking");
- exit(1);
- }
- if (clients == MAXHOST) {
- /* If too many hosts, send QUIT command immediately. */
- u_short cmd;
- cmd= htons(QUIT);
- write_data(soc, (char *)&cmd, SHORT_SIZE); /* if this fails, tough. */
- shutdown(soc, 2);
- close(soc);
- return;
- }
- /* record new client */
- client[clients].soc= soc;
- client[clients].status= READY;
- clients++;
- }
-
-
- int CalcRequest(x, y, dx, dy, cx, cy, w, h, iter, flags, xoff, yoff)
- double x, y, dx, dy, cx, cy;
- int w, h, iter, flags, xoff, yoff;
- {
- int cli;
- Recruit();
- if (clients == 0)
- return(0); /* Cannot satisfy request */
-
- for (cli= 0; cli < clients; cli++) {
- if (client[cli].status == READY) {
- /* Send request */
- u_short cmd;
- char xdrbuf[PACK_SIZE];
- XDR xdrs;
-
- /* Cant use &-operator on auto variables */
- double x2= x, y2= y, dx2= dx, dy2= dy, cx2= cx, cy2= cy;
- int w2= w, h2= h, iter2= iter, flags2= flags;
-
- cmd= htons(CALC);
- if (write_data(client[cli].soc, (char *)&cmd, SHORT_SIZE) < 0) {
- shutdown(client[cli].soc, 2);
- close(client[cli].soc);
- client[cli].status = DEAD;
- return(0);
- }
-
- xdrmem_create(&xdrs, xdrbuf, PACK_SIZE, XDR_ENCODE);
-
- if (!(xdr_double(&xdrs, &x2) && xdr_double(&xdrs, &y2) &&
- xdr_double(&xdrs, &dx2) && xdr_double(&xdrs, &dy2) &&
- xdr_double(&xdrs, &cx2) && xdr_double(&xdrs, &cy2) &&
- xdr_int(&xdrs, &w2) && xdr_int(&xdrs, &h2) &&
- xdr_int(&xdrs, &iter2) && xdr_int(&xdrs, &flags2) )) {
- fprintf(stderr, "server xdr failed\n");
- exit(1);
- }
-
- if (write_data(client[cli].soc, (char *)xdrbuf, PACK_SIZE) < 0) {
- shutdown(client[cli].soc, 2);
- close(client[cli].soc);
- client[cli].status = DEAD;
- return(0);
- }
- xdr_destroy(&xdrs);
- client[cli].status= BUSY;
- client[cli].x= xoff; client[cli].y= yoff;
- client[cli].w= w; client[cli].h= h;
- return(1); /* Request succeeded */
-
- } /* if */
- } /* for */
- /* Well, all clients were busy. Now we shall put the remaining
- * requests into a queue waiting for processing in the future.
- * (Formerly, we just blocked until a client became free.
- * ie. CheckClient(BLOCK); and then try again.)
- */
-
- if (qlen == 0)
- queue= (struct waitqueue *)
- malloc((qlen= 4) * sizeof(struct waitqueue));
- else if (qpos >= qlen)
- queue= (struct waitqueue *)
- realloc(queue, (qlen += 4) * sizeof(struct waitqueue));
- queue[qpos].x= x; queue[qpos].y= y;
- queue[qpos].dx= dx; queue[qpos].dy= dy;
- queue[qpos].cx= cx; queue[qpos].cy= cy;
- queue[qpos].w= w; queue[qpos].h= h;
- queue[qpos].iter= iter; queue[qpos].flags= flags;
- queue[qpos].xoff= xoff; queue[qpos].yoff= yoff;
- qpos ++;
- return(2); /* Succesfully queued */
-
- } /* CalcRequest() */
-
-
- void CheckClients(timeout)
- int timeout;
- {
- int cli, i;
- fd_set ready;
- struct timeval *to= NULL; /* NULL would mean block infinitely */
- int width;
- Recruit();
-
- if (timeout != BLOCK) {
- to= (struct timeval *)malloc(sizeof(struct timeval));
- to->tv_usec= 0;
- if (timeout == NOBLOCK)
- to->tv_sec= 0;
- else
- to->tv_sec= timeout;
- }
- width= getdtablesize();
- FD_ZERO(&ready);
- for (cli= 0; cli < clients; cli++)
- if (client[cli].status == BUSY || client[cli].status == OBSOLETE)
- FD_SET(client[cli].soc, &ready);
- if (select(width, &ready, (fd_set *)NULL, (fd_set *)NULL, to) < 0) {
- perror("select");
- exit(1);
- }
- for (cli= 0; cli < clients; cli++) {
- if (FD_ISSET(client[cli].soc, &ready))
- {
- void DrawImage();
- u_short *dest;
- u_char *buf, *ptr;
- u_long len;
-
- if (read_data(client[cli].soc, (char *)&len, LONG_SIZE) < 0) {
- shutdown(client[cli].soc, 2);
- close(client[cli].soc);
- client[cli].status = DEAD;
- return;
- }
- len= ntohl(len);
- dest= (u_short *)malloc(sizeof(short) * len);
- ptr= buf= (u_char *)malloc(SHORT_SIZE * len);
-
- if (read_data(client[cli].soc, (char *)buf, (int)(SHORT_SIZE * len)) < 0) {
- shutdown(client[cli].soc, 2);
- close(client[cli].soc);
- client[cli].status = DEAD;
- return;
- }
-
- /* Should the result be drawn on screen? */
- if (client[cli].status == OBSOLETE) {
- /* No, this is obsolete */
- free(buf);
- free(dest);
- client[cli].status= READY;
- }
- else {
- /* Go ahead, draw it */
- for (i= 0; i < len; i++) {
- dest[i]= (*ptr << 8)+(*(ptr+1));
- ptr += 2;
- }
- free(buf);
-
- for (i= 0; i < len; i++)
- dest[i]= ntohs(dest[i]);
- DrawImage(client[cli].x, client[cli].y,
- client[cli].w, client[cli].h, dest);
- client[cli].status= READY;
- } /* else */
- } /* if FD_SET */
- } /* for */
-
- /* Now, if there is an idle client, and if there are requests
- * waiting, handle the waiting requests.
- */
- while (qpos > 0) {
- int c_free= 0;
- for (cli= 0; cli < clients; cli++)
- if (client[cli].status == READY)
- c_free= 1;
- if (c_free) {
- qpos--;
- CalcRequest(queue[qpos].x, queue[qpos].y,
- queue[qpos].dx, queue[qpos].dy,
- queue[qpos].cx, queue[qpos].cy,
- queue[qpos].w, queue[qpos].h,
- queue[qpos].iter, queue[qpos].flags,
- queue[qpos].xoff, queue[qpos].yoff);
- }
- else
- break;
- } /* while */
- } /* CheckClients */
-
-
- void Invalidate()
- {
- int cli;
-
- for (cli= 0; cli < clients; cli++)
- if (client[cli].status == BUSY)
- client[cli].status= OBSOLETE;
- qpos= 0;
- }
-
-
- void FlushRequests()
- {
- /* If any of the clients is unreachable or down, this call will block
- * forever. This would then be the most suitable place for time-outs.
- */
- int cli;
-
- for (cli= 0; cli < clients; cli++)
- while (client[cli].status == BUSY || client[cli].status == OBSOLETE)
- CheckClients(BLOCK);
- }
-
-
- void CloseDown()
- {
- int cli;
-
- FlushRequests();
- for (cli= 0; cli < clients; cli++)
- if (client[cli].status != DEAD) {
- u_short cmd;
- cmd= htons(QUIT);
- write_data(client[cli].soc, (char *)&cmd, SHORT_SIZE);
- shutdown(client[cli].soc, 2);
- close(client[cli].soc);
- }
- shutdown(soc1, 2);
- close(soc1);
- }
-
-
- int PendingRequests()
- {
- int cli;
- for (cli= 0; cli < clients; cli++) {
- if (client[cli].status == BUSY)
- return(1);
- }
- return(0);
- }
-
-