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 >
Wrap
C/C++ Source or Header
|
1991-05-23
|
11KB
|
446 lines
/* 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);
}