[comp.sources.unix] v14i094: Shared memory emulation for 4.2BSD, Part01/04

rsalz@bbn.com (Rich Salz) (05/18/88)

Submitted-by: libes@cme-durer.ARPA (Don Libes)
Posting-number: Volume 14, Issue 94
Archive-name: sharedmem/part01

This system emulates a shared memory system for 4.2BSD.  A common
memory server handles requests to access shared variables.  Because
communication uses TCP/IP, processes may be distributed across
machines.

The system is all user level code and requires no kernel
modifications.  This implementation provides interfaces for C and
Franz Lisp.  It is known to work on Sun UNIX releases from 1.0 to 3.4.

The system is documented by the files in the doc directory.
doc/usenix contains a paper that was presented at the Summer 1985
Usenix Conference.  The system has changed somewhat since then.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 4)."
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1424 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThe NBS Common Memory System (CMS)
XSept 25, 1987
X
XThis system emulates a shared memory system for 4.2BSD.  A common
Xmemory server handles requests to access shared variables.  Because
Xcommunication uses TCP/IP, processes may be distributed across
Xmachines.
X
XThe system is all user level code and requires no kernel
Xmodifications.  This implementation provides interfaces for C and
XFranz Lisp.  It is known to work on Sun UNIX releases from 1.0 to
X3.4.
X
XThe system is documented by the files in the doc directory.
Xdoc/usenix contains a paper that was presented at the Summer 1985
XUsenix Conference.  The system has changed somewhat since then.
X
XInstallation instructions
X
XThis package depends upon a tiny communications library called
Xstreamlib which must be installed first.
X
X	cd stream
X	cat README
X
Xand follow the directions in there.
X
XOnce you have installed streamlib, change to the common memory
Xsource directory and run make.
X
X	cd ../src
X	make install
X
XIf you would like to try out some of the examples, type:
X
X	make examples
X
XThe examples are numbered as sets.  I.e. client1 runs with server1.
XThe most interesting is server1y, server1z, client1a and client1b.
XRun these in 4 different windows.  They are documented by their
Xsource and serve as coding examples.
X
XDon Libes
XNational Bureau of Standards
XMetrology Building, Room A-127
XGaithersburg, MD  20899
X(301) 975-3535
X
Xlibes@cme-durer.arpa
Xuunet!cme-durer!libes
X
X
END_OF_FILE
if test 1424 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'cms.3' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cms.3'\"
else
echo shar: Extracting \"'cms.3'\" \(449 characters\)
sed "s/^X//" >'cms.3' <<'END_OF_FILE'
X.TH CMS 3NBS "11 January 1988"
X.SH NAME
Xshared memory system emulator
X.SH DESCRIPTION
X.PP
XThis system emulates a shared memory system.  A common memory
Xserver handles requests to access shared variables.  Because
Xcommunication uses TCP/IP, processes may be distributed across
Xmachines.
X.PP
XFor further information read the documents in the doc directory
Xthat comes with the common memory source.  There are several
Xexamples in the source directory.
END_OF_FILE
if test 449 -ne `wc -c <'cms.3'`; then
    echo shar: \"'cms.3'\" unpacked with wrong size!
fi
# end of 'cms.3'
fi
if test ! -d 'doc' ; then
    echo shar: Creating directory \"'doc'\"
    mkdir 'doc'
fi
if test ! -d 'doc/usenix' ; then
    echo shar: Creating directory \"'doc/usenix'\"
    mkdir 'doc/usenix'
fi
if test ! -d 'src' ; then
    echo shar: Creating directory \"'src'\"
    mkdir 'src'
fi
if test -f 'src/README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/README'\"
else
echo shar: Extracting \"'src/README'\" \(247 characters\)
sed "s/^X//" >'src/README' <<'END_OF_FILE'
XAm in the process of implementing a way to get the names of the open cm
Xvariables from the cmm.  Idea is to reserve a variable, say, cm_variable_names
Xwhich is written by the cmm whenever a new variable is declared (or the last
Xlink is deleted).
X
END_OF_FILE
if test 247 -ne `wc -c <'src/README'`; then
    echo shar: \"'src/README'\" unpacked with wrong size!
fi
# end of 'src/README'
fi
if test -f 'src/client1a.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/client1a.c'\"
else
echo shar: Extracting \"'src/client1a.c'\" \(795 characters\)
sed "s/^X//" >'src/client1a.c' <<'END_OF_FILE'
X/* client1a.c
XThis process, a, writes a string to variable a_var.
XIt then checks variable b_var for a new value, and if it is, prints it.
XIt then sleeps for 3 seconds.
X*/
X#include "cm.h"
X
X#define BUFFER_LENGTH	1000
Xchar a_data[BUFFER_LENGTH];
X
Xcm_value a_val = {a_data,BUFFER_LENGTH,0,0}, b_val = {0,0,0,1};
X
Xmain()
X{
X	cm_variable *a_var, *b_var;
X	int seqno = 0;
X
X	if (0> cm_init("a",0,0)) exit(-1);
X
X	if (!(a_var = cm_declare("a_var",CM_ROLE_NONXWRITER)))
X		exit(-1);
X	if (!(b_var = cm_declare("b_var",CM_ROLE_READER|CM_ROLE_WAKEUP)))
X		exit(-1);
X
X	for (;;) {
X		sprintf(a_data,"Message from a.  seq #%d",seqno++);
X		a_val.size = strlen(a_data) + 1;
X		cm_set_value(a_var,&a_val);
X		cm_sync(CM_NO_WAIT);
X		if (cm_get_new_value(b_var,&b_val))
X			printf("b_var: %s\n",b_val.data);
X		sleep(3);
X	}
X}
END_OF_FILE
if test 795 -ne `wc -c <'src/client1a.c'`; then
    echo shar: \"'src/client1a.c'\" unpacked with wrong size!
fi
# end of 'src/client1a.c'
fi
if test -f 'src/client1b.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/client1b.c'\"
else
echo shar: Extracting \"'src/client1b.c'\" \(807 characters\)
sed "s/^X//" >'src/client1b.c' <<'END_OF_FILE'
X/*
XThis process, b, writes a string to variable b_var.
XIt then checks variable a_var for a new value, and if it is, prints it.
XIt then sleeps for 5 seconds.
X*/
X#include <sys/time.h>
X#include "cm.h"
X
X#define BUFFER_LENGTH	1000
Xchar b_data[BUFFER_LENGTH];
X
Xcm_value a_val = {0,0,0,1}, b_val = {b_data,BUFFER_LENGTH,0,0};
X
Xmain()
X{
X	cm_variable *a_var, *b_var;
X	int seqno = 0;
X
X	if (0> cm_init("b",0,0)) exit(-1);
X
X	if (!(a_var = cm_declare("a_var",CM_ROLE_READER|CM_ROLE_WAKEUP)))
X		exit(-1);
X	if (!(b_var = cm_declare("b_var",CM_ROLE_NONXWRITER)))
X		exit(-1);
X
X	for (;;) {
X		sprintf(b_data,"Message from b.  seq #%d",seqno++);
X		b_val.size = strlen(b_data) + 1;
X		cm_set_value(b_var,&b_val);
X		cm_sync(CM_NO_WAIT);
X		if (cm_get_new_value(a_var,&a_val))
X			printf("a_var: %s\n",a_val.data);
X		sleep(5);
X	}
X}
X
END_OF_FILE
if test 807 -ne `wc -c <'src/client1b.c'`; then
    echo shar: \"'src/client1b.c'\" unpacked with wrong size!
fi
# end of 'src/client1b.c'
fi
if test -f 'src/client2.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/client2.c'\"
else
echo shar: Extracting \"'src/client2.c'\" \(1056 characters\)
sed "s/^X//" >'src/client2.c' <<'END_OF_FILE'
X/* client2.c
X this client writes the following to common memory:
Xs_var: a line read from stdin
Xi_var: the length of s_var
Xd_var: a random double variable
X*/
X#include <sys/time.h>
X#include "cm.h"
X
Xcm_variable *i_var, *d_var, *s_var;
Xcm_value i_val, d_val, s_val;
Xdouble d_val_data = 3.14159;
X
Xchar s_val_data[1000];
Xint i_val_data;
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X	if (argc>1) printf("going to host %s for cmm\n",argv[1]);
X	if (0 > cm_init("don",(argc>1?argv[1]:(char *)0),0)) exit(-1);
X
X	s_var = cm_declare("s_var",CM_ROLE_NONXWRITER);
X	i_var = cm_declare("i_var",CM_ROLE_NONXWRITER);
X	d_var = cm_declare("d_var",CM_ROLE_NONXWRITER);
X
X	d_val.data = (char *)&d_val_data;
X	d_val.size = sizeof(d_val_data);
X	s_val.data = s_val_data;
X	i_val.data = (char *)&i_val_data;
X
X	while (TRUE) {
X		cm_set_value(d_var,&d_val);
X
X		printf("enter string for s_val: ");
X		gets(s_val_data);
X		s_val.size = strlen(s_val_data);
X		cm_set_value(s_var,s_val);
X
X		i_val_data = strlen(s_val_data);
X		cm_set_value(i_var,&i_val);
X
X		if (0 > cm_sync(CM_NO_WAIT)) return;
X	}
X}
END_OF_FILE
if test 1056 -ne `wc -c <'src/client2.c'`; then
    echo shar: \"'src/client2.c'\" unpacked with wrong size!
fi
# end of 'src/client2.c'
fi
if test -f 'src/client8.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/client8.c'\"
else
echo shar: Extracting \"'src/client8.c'\" \(382 characters\)
sed "s/^X//" >'src/client8.c' <<'END_OF_FILE'
X/* client8.c - constantly write a variable to common memory (see server8.c) */
X
X#include <sys/time.h>
X#include "cm.h"
X
Xcm_variable *variable;
Xcm_value value = { "foo", 4, 4, 0};
X
Xmain()
X{
X	if (0>cm_init("constant writer",0,0)) exit(-1);
X
X	if (!(variable = cm_declare("variable",CM_ROLE_XWRITER))) exit(-1);
X
X	while (1) {
X		cm_set_value(variable,&value);
X		cm_sync(CM_NO_WAIT);
X	}
X}
END_OF_FILE
if test 382 -ne `wc -c <'src/client8.c'`; then
    echo shar: \"'src/client8.c'\" unpacked with wrong size!
fi
# end of 'src/client8.c'
fi
if test -f 'src/cm.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm.h'\"
else
echo shar: Extracting \"'src/cm.h'\" \(269 characters\)
sed "s/^X//" >'src/cm.h' <<'END_OF_FILE'
X/* cm.h - include common memory include files */
X
X#ifndef _TIME_
X#include <sys/time.h>
X#endif
X
X#include "cm_constants.h"
X#include "cm_var.h"
X#include "cm_sd.h"
X#include "cm_interface.h"
X#include "cm_slot.h"
X#include "cm_msg.h"
X#include "cm_sync.h"
X#include "cm_time.h"
END_OF_FILE
if test 269 -ne `wc -c <'src/cm.h'`; then
    echo shar: \"'src/cm.h'\" unpacked with wrong size!
fi
# end of 'src/cm.h'
fi
if test -f 'src/cm.lisp' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm.lisp'\"
else
echo shar: Extracting \"'src/cm.lisp'\" \(1622 characters\)
sed "s/^X//" >'src/cm.lisp' <<'END_OF_FILE'
X				; load in calls for common memory package
X				; Don Libes
X
X(cfasl '/usr/local/lib/Luser.o '_Lcm_init 'cm_init	"function"
X	"/usr/local/lib/libcm.a /usr/local/lib/libstream.a")
X(getaddress
X '_Lcm_declare			'cm_declare		"integer-function"
X '_Lcm_undeclare		'cm_undeclare		"subroutine"
X '_Lcm_sync			'cm_sync		"integer-function"
X '_Lcm_set_value		'cm_set_value		"subroutine"
X '_Lcm_get_value		'cm_get_value		"subroutine"
X '_Lcm_set_new_command_value	'cm_set_new_command_value "integer-function"
X '_Lcm_new_command_pending	'cm_new_command_pending	"integer-function"
X '_Lcm_get_new_command_value	'cm_get_new_command_value "integer-function"
X '_Lcm_status_equal		'cm_status_equal	"integer-function"
X '_Lcm_status_synchronized	'cm_status_synchronized	"integer-function"
X '_Lcm_set_status_value		'cm_set_status_value	"subroutine"
X '_Lcm_print_variable		'cm_print_variable	"subroutine"
X '_Lcm_exit			'cm_exit		"subroutine"
X)
X
X; access types, i.e. roles
X(setq oldibase ibase)
X(setq ibase 8)
X(setq CM_ROLE_NULL			000)
X(setq CM_ROLE_READER			001)
X(setq CM_ROLE_WAKEUP			002)
X(setq CM_ROLE_NONXWRITER		004)
X(setq CM_ROLE_NONEXCLUSIVE_WRITER	004)
X(setq CM_ROLE_EXCLUSIVE_WRITER		014)
X(setq CM_ROLE_XWRITER			014)
X(setq ibase oldibase)
X
X(setq CM_WAIT				0)
X(setq CM_NO_WAIT			1)
X(setq CM_WAIT_FOR_ALL			0)
X(setq CM_WAIT_AT_MOST_ONCE		2)
X(setq CM_WAIT_READ			4)
X
X;(setq CM_WAIT				0)
X;(setq CM_NO_WAIT			1)
X;(setq CM_WAIT_FOR_ALL			2)
X;(setq CM_WAIT_AT_MOST_ONCE		3)
X
X; define common memory value
X(c-declare
X    (struct cm_value
X	    (data * char)
X	    (msize unsigned-short)
X	    (size unsigned-short)
X	    (mallocable char)	
X    )
X)
END_OF_FILE
if test 1622 -ne `wc -c <'src/cm.lisp'`; then
    echo shar: \"'src/cm.lisp'\" unpacked with wrong size!
fi
# end of 'src/cm.lisp'
fi
if test -f 'src/cm_bytestuff.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm_bytestuff.h'\"
else
echo shar: Extracting \"'src/cm_bytestuff.h'\" \(372 characters\)
sed "s/^X//" >'src/cm_bytestuff.h' <<'END_OF_FILE'
X/* cm_bytestuff.h - byte stuffing aids */
X
X/* #byteadd is used to add offsets to structures */
X/*#define byteadd(a,b)	(((int)a) + ((int)b) + (((int)a) + (int)b) % 2)*/
X#define byteadd(a,b)	(align(((int)(a)) + ((int)(b))))
X
X/* align converts rounds up addresses if they are odd */
X/* if this is not done, longword stores fail on the 68000 */
X#define align(x)	((x) + (x)%2)
END_OF_FILE
if test 372 -ne `wc -c <'src/cm_bytestuff.h'`; then
    echo shar: \"'src/cm_bytestuff.h'\" unpacked with wrong size!
fi
# end of 'src/cm_bytestuff.h'
fi
if test -f 'src/cm_constants.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm_constants.h'\"
else
echo shar: Extracting \"'src/cm_constants.h'\" \(445 characters\)
sed "s/^X//" >'src/cm_constants.h' <<'END_OF_FILE'
X#define CM_PORT			1525
X
X/* maximums */
X#define CM_MSGSIZE		100000/* max length of all variables
X					sent to	server at one time */
X#define CM_SLOTSIZE		20000 /* max single variable length */
X#define CM_PROCESSNAMELENGTH	20
X#define CM_VARIABLENAMELENGTH	20
X#define CM_MAXVARIABLENAMELENGTH	20
X#define CM_MAXPROCESSNAMELENGTH	20
X#define CM_MAXUSERVARIABLES	100
X
X#define E_CMM_DIED		-1
X#define E_CM_INIT_FAILED		-2
X#define E_CM_WRONG_VERSION		-100
END_OF_FILE
if test 445 -ne `wc -c <'src/cm_constants.h'`; then
    echo shar: \"'src/cm_constants.h'\" unpacked with wrong size!
fi
# end of 'src/cm_constants.h'
fi
if test -f 'src/cm_man.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm_man.h'\"
else
echo shar: Extracting \"'src/cm_man.h'\" \(1966 characters\)
sed "s/^X//" >'src/cm_man.h' <<'END_OF_FILE'
X/*
X
XCommon memory is local to the CMM process.  It is composed of:
X
XAn array of variables.  Each variable is a structure with elements such as
Xa name, type, value, etc.
X
XVariable values can be stored in the variable structure if they are small
X(such as an int) or in a piece of malloc'd memory if they are large (such
Xas a string).
X
XAn array of process descriptors.  Each process descriptor is a structure.
XThe most important element of this structure is the wakeup field.  If it is
Xset, the process should be informed of new variable values.
X*/
X
X#define CM_MANAGER_NAME		"cm manager"
X#define CM_MAXVARIABLES		50
X#define CM_MAXPROCESSES		20
X
X#define is_new(proc,var)		(var->role[proc].new)
X#define is_reader(proc,var)		(var->role[proc].reader)
X#define is_wakeup(proc,var)		(var->role[proc].wakeup)
X#define is_writer(proc,var)		(var->role[proc].writer)
X#define is_nonxwriter(proc,var)		(var->role[proc].writer && \
X					 var->xwriter != proc)
X#define is_xwriter(proc,var)		(var->xwriter == proc)
X
X#define CM_NULL_PROCESS		-1
X
X/* process descriptors */
X/* this table is indexed by corresponding file descriptors (or sockets) */
Xstruct process {
X	char name[CM_PROCESSNAMELENGTH];
X	int inuse;
X	int wakeup;			/* per process wakeup */
X};
X
X/* this is how variables are stored internally to the cmm */
Xstruct variable {
X	char name[CM_VARIABLENAMELENGTH];
X	struct cm_value data;	/* data (and size, if necessary) */
X	unsigned long count;	/* nth definition of this var */
X	struct timeval timestamp;	/* when last written */
X	int command_association;
X	int xwriter;			/* name of exclusive writer */
X	int writers;			/* number of (any type of) writers */
X	int readers;			/* number of readers */
X	struct {
X	    unsigned reader : 1;	/* reader */
X	    unsigned writer : 1;	/* writer */
X	    unsigned wakeup : 1;	/* a-wake me */
X	    unsigned new    : 1;	/* changed but not read */
X	} role[CM_MAXPROCESSES];
X};
X
X/* internal errors specific to CMM */
X#define E_GET_VARIABLE_NO_SPACE		-1
END_OF_FILE
if test 1966 -ne `wc -c <'src/cm_man.h'`; then
    echo shar: \"'src/cm_man.h'\" unpacked with wrong size!
fi
# end of 'src/cm_man.h'
fi
if test -f 'src/cm_msg.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm_msg.h'\"
else
echo shar: Extracting \"'src/cm_msg.h'\" \(938 characters\)
sed "s/^X//" >'src/cm_msg.h' <<'END_OF_FILE'
X/*
X
XThis file contains definitions relating to message passing between
Xthe CM manager and user.
X
XFollowing is the structure of a message.  Unfortunately, this is illegal
Xbecause "number" is variable as well as the sizeof(slot).  This structure
Xwill be built dynamically when necessary and discarded after the message
Xhas been used (read or written).  In order to make it legal, we will leave
Xcomment out the "slot" field and read/write that by hand.  This hack will
Xbe used throughout the message code.  Yuck.
X
X*/
X
Xstruct msg {
X	int version;		/* version of cmm system */
X	int size;		/* size of msg structure itself */
X	int slots;			/* number of slots */
X	char name[CM_PROCESSNAMELENGTH];
X	char read_wait;		/* TRUE, if sender waiting for an acknowledgement */
X	struct slot data[1];	/* really want [0] */
X} ;
X
X/*
X
XEach message is composed of a header.  The header includes the process name,
Xnumber of slots, and the slots themselves.
X
X*/
X
X
END_OF_FILE
if test 938 -ne `wc -c <'src/cm_msg.h'`; then
    echo shar: \"'src/cm_msg.h'\" unpacked with wrong size!
fi
# end of 'src/cm_msg.h'
fi
if test -f 'src/cm_sd.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm_sd.h'\"
else
echo shar: Extracting \"'src/cm_sd.h'\" \(384 characters\)
sed "s/^X//" >'src/cm_sd.h' <<'END_OF_FILE'
X/* cm_sd.h - sized-data structures */
X
X/* there is no reason why the items typed as shorts cannot be longer */
X
Xtypedef struct cm_value {
X	char *data;
X	unsigned short msize;	/* max size of data */
X	unsigned short size;	/* size of data used */
X	char mallocable;	/* TRUE, if we can free and malloc data */
X} cm_value;
X
Xstruct cm_flattened_data {
X	unsigned short size;
X	char data[1];
X};
END_OF_FILE
if test 384 -ne `wc -c <'src/cm_sd.h'`; then
    echo shar: \"'src/cm_sd.h'\" unpacked with wrong size!
fi
# end of 'src/cm_sd.h'
fi
if test -f 'src/cm_sync.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm_sync.h'\"
else
echo shar: Extracting \"'src/cm_sync.h'\" \(327 characters\)
sed "s/^X//" >'src/cm_sync.h' <<'END_OF_FILE'
X/* cm_sync.h */
X
X/* OR together one from first set to one from second set */
X/* defaults are CM_WAIT|CM_WAIT_FOR_ALL */
X
X/* first set of options */
X#define CM_WAIT			0
X#define CM_NO_WAIT		1
X/* second set of options */
X#define CM_WAIT_FOR_ALL		0
X#define CM_WAIT_AT_MOST_ONCE	2
X/* third set of options */
X#define CM_WAIT_READ		4
END_OF_FILE
if test 327 -ne `wc -c <'src/cm_sync.h'`; then
    echo shar: \"'src/cm_sync.h'\" unpacked with wrong size!
fi
# end of 'src/cm_sync.h'
fi
if test -f 'src/cm_time.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm_time.c'\"
else
echo shar: Extracting \"'src/cm_time.c'\" \(667 characters\)
sed "s/^X//" >'src/cm_time.c' <<'END_OF_FILE'
X/* these are utilities for dealing with timeouts */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include "cm_time.h"
X
Xstruct timeval cm_period_zero, cm_period_infinite;
X
X/* set up some useful constants */
Xcm_time_init()
X{
X	cm_time_zero(&cm_period_zero);
X	cm_period_infinite.tv_sec = (u_long)1000000;
X	cm_period_infinite.tv_usec = (long)0;
X}
X
Xcm_time_zero(p)
Xstruct timeval *p;
X{
X	p->tv_sec = (u_long)0;
X	p->tv_usec = (long)0;
X}
X
Xcm_time_set(p,s,u)
Xstruct timeval *p;
Xint s;
Xint u;
X{
X	p->tv_sec = (u_long)s;
X	p->tv_usec = (long)u;
X}
X
Xcm_time_copy(from,to)
Xstruct timeval *from, *to;
X{
X	safebcopy((char *)from,(char *)to,sizeof(struct timeval));
X}
END_OF_FILE
if test 667 -ne `wc -c <'src/cm_time.c'`; then
    echo shar: \"'src/cm_time.c'\" unpacked with wrong size!
fi
# end of 'src/cm_time.c'
fi
if test -f 'src/cm_time.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm_time.h'\"
else
echo shar: Extracting \"'src/cm_time.h'\" \(116 characters\)
sed "s/^X//" >'src/cm_time.h' <<'END_OF_FILE'
Xextern struct timeval cm_period_zero, cm_period_infinite;
X
X#define time_now(x) gettimeofday(x,(struct timezone *)0)
END_OF_FILE
if test 116 -ne `wc -c <'src/cm_time.h'`; then
    echo shar: \"'src/cm_time.h'\" unpacked with wrong size!
fi
# end of 'src/cm_time.h'
fi
if test -f 'src/cm_util.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm_util.c'\"
else
echo shar: Extracting \"'src/cm_util.c'\" \(2023 characters\)
sed "s/^X//" >'src/cm_util.c' <<'END_OF_FILE'
X/* utilities */
X
X#include <stdio.h>
X#include <strings.h>
X#include <ctype.h>
X#include <varargs.h>
X
X/* uh-oh, looks like Lisp has a bcopy too! */
X/* and it doesn't do the same thing as the C bcopy!  */
X/* Now who wants to know how long this took me to find? */
Xstatic bcopy(s1,s2,length)
Xchar *s1, *s2;
Xint length;
X{
X    while (0 < length--) *s2++ = *s1++;
X}
X
Xvoid
Xsafebcopy(b1,b2,length)
Xchar *b1, *b2;
Xint length;
X{
X    eprintf(9,"safebcopy(%x,%x,%d)\n",b1,b2,length);
X    if (!b1) {
X	printf("error: bcopy dest is null ptr\n");
X	abort();
X    } else if (!b2) {
X	printf("error: bcopy src is null ptr\n");
X	abort();
X    } else bcopy(b1,b2,length);
X}
X
X/* dump first 20 bytes starting at s in hex */
Xhex20(s)
Xchar *s;
X{
X	int i;
X	for (i=0;i<20;i++) printf("%2x",0xff & s[i]);
X	putchar('\n');
X}
X
X/* dump length bytes worth of s in ascii */
Xascii_dump(s,length)
Xchar *s;
Xint length;
X{
X	int i;
X	for (i=0;i<length;i++) {
X		if (isascii(s[i]) && isprint(s[i])) {
X			printf(" %c",s[i]);
X		} else {
X			printf(" %02x",0xff & s[i]);
X		}
X	}
X	putchar('/n');
X}
X
Xint cm_debug_level;   	/* controls how many debugging statements are
X				/* printed.  0 means none, higher numbers mean
X				/* more. */
X/* levels are:
X0	nothing
X1
X2	msgs send/received
X3	msgs init, aborted
X4
X5	slots composed, decomposed
X6	slots broken out
X7
X8
X9	bcopy, strcpy, malloc
X*/
Xset_cm_debug_level(level)
Xint level;
X{
X	cm_debug_level = level;
X	eprintf(1,"cm debug level is %d\n",cm_debug_level);
X}
X
X
X/* Debugging function, use like printf, but the global var debug_level */
X/* controls how much is printed */
X#if 0
X/* Yes, I know its gross */
X/*VARARGS2*/
Xeprintf(level,fmt,v1,v2,v3,v4,v5,v6,v7,v8,v9)
Xint level;
Xchar *fmt;
Xint v1, v2, v3, v4, v5, v6, v7, v8, v9;
X{
X	if (cm_debug_level >= level) printf(fmt,v1,v2,v3,v4,v5,v6,v7,v8,v9);
X}
X#endif
X
X/*VARARGS2*/
Xeprintf(level,fmt,va_alist)
Xint level;
Xchar *fmt;
Xva_dcl
X{
X	va_list pvar;
X
X	va_start(pvar);
X	/* & may be incorrect in following statement */
X	if (cm_debug_level >= level) _doprnt(fmt,pvar,stderr);
X	va_end(pvar);
X}
END_OF_FILE
if test 2023 -ne `wc -c <'src/cm_util.c'`; then
    echo shar: \"'src/cm_util.c'\" unpacked with wrong size!
fi
# end of 'src/cm_util.c'
fi
if test -f 'src/cm_var.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cm_var.h'\"
else
echo shar: Extracting \"'src/cm_var.h'\" \(255 characters\)
sed "s/^X//" >'src/cm_var.h' <<'END_OF_FILE'
X/* access types, i.e. roles */
X#define CM_ROLE_NULL			000
X#define CM_ROLE_READER			001
X#define CM_ROLE_WAKEUP			002
X#define CM_ROLE_NONXWRITER		004
X#define CM_ROLE_NONEXCLUSIVE_WRITER	004
X#define CM_ROLE_EXCLUSIVE_WRITER	010
X#define CM_ROLE_XWRITER			010
END_OF_FILE
if test 255 -ne `wc -c <'src/cm_var.h'`; then
    echo shar: \"'src/cm_var.h'\" unpacked with wrong size!
fi
# end of 'src/cm_var.h'
fi
if test ! -d 'src/franz' ; then
    echo shar: Creating directory \"'src/franz'\"
    mkdir 'src/franz'
fi
if test -f 'src/franz/dfuncs.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/franz/dfuncs.h'\"
else
echo shar: Extracting \"'src/franz/dfuncs.h'\" \(1350 characters\)
sed "s/^X//" >'src/franz/dfuncs.h' <<'END_OF_FILE'
X/*					-[Mon Dec  3 16:37:08 1984 by layer]-
X * 	dfuncs.h			$Locker:  $
X * external function declaration
X *
X * $Header: dfuncs.h,v 40.6 85/03/12 12:54:37 layer Exp $
X *
X * (c) copyright 1982, Regents of the University of California
X * Enhancements (c) copyright 1984, Franz Inc., Oakland California
X */
X 
Xchar *brk();
Xchar *pinewstr();
Xchar *inewstr();
Xchar *newstr();
Xchar *sbrk();
Xchar *xsbrk();
Xchar *ysbrk();
Xint csizeof();
Xlispval Iget();
Xlispval Imakeht();
Xlispval Imkrtab();
Xlispval Iputprop();
Xlispval Istsrch();
Xlispval Lfuncal();
Xlispval Lnegp();
Xlispval Lread();
Xlispval Lsub();
Xlispval copval();
Xlispval csegment();
Xlispval error();
Xlispval errorh();
Xlispval errorh1();
Xlispval errorh2();
Xlispval eval();
Xlispval gc();
Xlispval getatom();
Xlispval inewatom();
Xlispval inewint();
Xlispval inewval();
Xlispval matom();
Xlispval mfun();
Xlispval mstr();
Xlispval newarray();
Xlispval newdot();
Xlispval newdoub();
Xlispval newfunct();
Xlispval newint();
Xlispval newsdot();
Xlispval newval();
Xlispval newhunk();
Xlispval pnewdot();
Xlispval pnewdb();
Xlispval pnewhunk();
Xlispval pnewint();
Xlispval pnewsdot();
Xlispval pnewval();
Xlispval popnames();
Xlispval r();
Xlispval ratomr();
Xlispval readr();
Xlispval readrx();
Xlispval readry();
Xlispval typefrob();
Xlispval typred();
Xlispval unprot();
Xlispval verify();
Xstruct atom	*makeatom();
Xstruct atom	*newatom();
END_OF_FILE
if test 1350 -ne `wc -c <'src/franz/dfuncs.h'`; then
    echo shar: \"'src/franz/dfuncs.h'\" unpacked with wrong size!
fi
# end of 'src/franz/dfuncs.h'
fi
if test -f 'src/franz/lconf.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/franz/lconf.h'\"
else
echo shar: Extracting \"'src/franz/lconf.h'\" \(16 characters\)
sed "s/^X//" >'src/franz/lconf.h' <<'END_OF_FILE'
X#define sun_4_2
END_OF_FILE
if test 16 -ne `wc -c <'src/franz/lconf.h'`; then
    echo shar: \"'src/franz/lconf.h'\" unpacked with wrong size!
fi
# end of 'src/franz/lconf.h'
fi
if test -f 'src/franz/ltypes.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/franz/ltypes.h'\"
else
echo shar: Extracting \"'src/franz/ltypes.h'\" \(1031 characters\)
sed "s/^X//" >'src/franz/ltypes.h' <<'END_OF_FILE'
X/*					-[Wed May 15 10:14:01 1985 by layer]-
X * 	ltypes.h			$Locker:  $
X * lisp data type defs
X *
X * $Header: ltypes.h,v 40.6 85/05/16 03:58:00 smh Exp $
X *
X * (c) copyright 1982, Regents of the University of California
X * Enhancements (c) copyright 1984, Franz Inc., Oakland California
X */
X 
X/* type flags */
X
X#define	UNBO	-1
X#define	STRNG	0
X#define	ATOM	1
X#define	INT	2
X#define	DTPR	3
X#define DOUB	4
X#define	BCD	5
X#define	PORT	6
X#define	ARRAY	7
X#define OTHER   8
X#define SDOT	9
X#define VALUE	10
X
X#define HUNK2	11		/* The hunks */
X#define HUNK4	12
X#define HUNK8	13
X#define HUNK16	14
X#define HUNK32	15
X#define HUNK64	16
X#define HUNK128	17
X
X#define VECTOR  18
X#define VECTORI 19
X
X#define NUMSPACES (VECTORI + 1)
X
X#define	HUNKP(a1)	((TYPE(a1) >= HUNK2) & (TYPE(a1) <= HUNK128))
X
X#define HASHTP(p)	((p)->v.vector[VPropOff] == hasht_atom)
X#define PACKAGEP(p)	((p)->v.vector[VPropOff] == pkg_atom)
X#define INSTANCEP(p)	((TYPE((p)->v.vector[VPropOff]) == VECTOR) && \
X			 ((p)->v.vector[VPropOff]->v.vector[VPROPOFF] == \
X			  flavor))
X
END_OF_FILE
if test 1031 -ne `wc -c <'src/franz/ltypes.h'`; then
    echo shar: \"'src/franz/ltypes.h'\" unpacked with wrong size!
fi
# end of 'src/franz/ltypes.h'
fi
if test -f 'src/franz/module.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/franz/module.h'\"
else
echo shar: Extracting \"'src/franz/module.h'\" \(1662 characters\)
sed "s/^X//" >'src/franz/module.h' <<'END_OF_FILE'
X/*					-[Sat Jun  2 08:09:36 1984 by jkf]-
X * 	module.h			$Locker:  $
X * 
X *  module interface includes
X *
X * $Header: module.h,v 40.2 84/11/13 14:23:46 schlafly Exp $
X *
X * (c) copyright 1984, Franz Inc., Oakland California
X */
X
X/*
X * All C coded modules will contain a VERSION
X * header in which the rcs header is stored
X */
X 
X#ifndef lint
X#define VERSION(s)	static char *rcsid = s
X#else
X#define VERSION(s)
X#endif
X
X
X/*
X * All variables are either private in the module or else are
X * shared among 2 or more files.
X * Private variables are declared Private inside the file.
X * Non-private variables are either declared Public in a .h file which
X * all files that wish to reference that variable must include,
X * or are declared Export in a C (non-header) file.  C files wishing
X * to reference those variables declare the variable Import.
X * 
X *
X * Private corresponds to 'static' in C, although it usually isn't a good
X * idea to declare variables or functions to be static if you want to debug
X * the code with something like adb.
X * Export corresponds to '' (nothing), and Import to 'extern'.
X * Public corresponds to 'extern' in C, although there must be one file
X * in which the 'extern' isn't declared.  To order to strip the extern,
X * the macro DefineData should be set before including files.
X *
X * Public should be used instead of Import and Export since it assures
X * that every module gets the same declaration.  However it does require
X * a .h file, and this may be too much effort for one or two variables.
X *
X */
X 
X#define Private static
X#define Export
X#define Import extern
X
X#ifdef DefineData
X# define Public
X#else
X# define Public extern
X#endif
END_OF_FILE
if test 1662 -ne `wc -c <'src/franz/module.h'`; then
    echo shar: \"'src/franz/module.h'\" unpacked with wrong size!
fi
# end of 'src/franz/module.h'
fi
if test -f 'src/franz/public.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/franz/public.h'\"
else
echo shar: Extracting \"'src/franz/public.h'\" \(1909 characters\)
sed "s/^X//" >'src/franz/public.h' <<'END_OF_FILE'
X/*					-[Tue May 21 17:05:40 1985 by layer]-
X * 	public.h			$Locker:  $
X *
X *   definition for Public data objects which all files are permitted
X *   to look at. [These are the very public data objects]
X *
X * $Header: public.h,v 40.5 85/05/21 17:24:04 layer Exp $
X *
X * 
X * (c) copyright 1984, Franz Inc., Oakland California
X */
X
X#ifdef apollo
Xextern
X#else
XPublic
X#endif
Xstruct nament *bnp;	/* first free bindstack entry */
XPublic struct nament *bnplim,	/* limit of bindstack */
X		     *orgbnp;	/* base of the bindstack */
X
X
X#ifdef NPINREG
XImport
X#else
X#ifdef apollo
Xextern
X#else
XPublic
X#endif apollo
X#endif NPINREG
X	struct	 argent *lbot,	/* base of arguments to function */
X		         *np;	/* first free namestack entry */
X			 
XPublic struct argent *nplim,	/* one above limit of namestack */
X		     *orgnp;	/* first slot in the namestack */
X		     
X#ifdef apollo
Xextern
X#else
XPublic
X#endif apollo
X    word retval;		/* used by each error/prog call	 */
X				/* retval could be an int */
X#ifdef apollo
Xextern
X#else
XPublic
X#endif apollo
Xlispval  lispretval;	/* used by non-local go  */
X
XPublic lispval datalim;		/* limit of valid data area */
X
XPublic lispval vtemp;		/* used in a few macros as a temp */
XPublic long sigintcnt;		/* count of interrupts since processed */
X				/* sigintcnt could be an int */
X
XImport char typetable[];		/* one byte per page */
X
X#ifdef MVR
X/* Stuff having to do with Multiple Values */
X#ifdef apollo
Xextern
X#else
XPublic
X#endif apollo
Xint nmvr;	    /* # of multiple values being returned less 1 */
XImport int mmvr;	    /* Max # of multiple values possibly returned*/
X#ifdef apollo
Xextern
X#else
XPublic
X#endif apollo
Xlispval *mvals;	    /* pointer to a static storage area for them */
XPublic lispval *mvalsMMVR;  /* pointer to end of storage area for them */
X#define clrnmv() (nmvr = 0);
X#endif MVR
X
X#ifdef Savelisp
XPublic lispval relvectors;  /* for save/restorelisp */
X#endif Savelisp
END_OF_FILE
if test 1909 -ne `wc -c <'src/franz/public.h'`; then
    echo shar: \"'src/franz/public.h'\" unpacked with wrong size!
fi
# end of 'src/franz/public.h'
fi
if test -f 'src/man_put_slot.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/man_put_slot.c'\"
else
echo shar: Extracting \"'src/man_put_slot.c'\" \(1541 characters\)
sed "s/^X//" >'src/man_put_slot.c' <<'END_OF_FILE'
X/*
X
XThese routines build slots for the cmm.  These slots are placed into a
Xmsg structure and sent to the user.
X
X*/
X
X#include <stdio.h>
X#include <sys/time.h>
X#include "cm_constants.h"
X#include "cm_sd.h"
X#include "cm_slot.h"	/* definitions of slot structures */
X#include "cm_bytestuff.h"
X
Xextern struct msg *omsg;	/* this is soooo... messy */
X
Xput_slot_read_response(m,name,count,timestamp,cmd,data)
Xstruct msg *m;
Xchar *name;
Xunsigned long count;
Xstruct timeval *timestamp;
Xint cmd;
Xcm_value *data;
X{
X	struct big_slot s;
X	unsigned int size;
X
X	init_slot(&s,name,CM_SLOT_READ_RESPONSE);
X	size = align(sizeof(struct slot_hdr));
X	size += align(sizeof(struct slot_read_response_hdr));
X	s.subslot.read_response.srr_count = count;
X	cm_time_copy(timestamp,&s.subslot.read_response.srr_timestamp);
X	s.subslot.read_response.srr_command_association = cmd;
X	size += cm_sd_to_flat(data,&s.subslot.read_response.fdata);
X	finish_slot(m,&s,size);
X}
X
X/* error slots should never be generated by the user since infinite loops */
X/* could result between the user and cmm sending each other back error slots */
Xput_slot_error(m,name,type,string)
Xstruct msg *m;
Xchar *name;
Xint type;
Xchar *string;
X{
X	struct big_slot s;
X	unsigned int size;
X
X	fprintf(stdout,"slot error in <%s>  type %d - %s\n",name,type,string);
X	
X	init_slot(&s,name,CM_SLOT_ERROR);
X	size = align(sizeof(struct slot_hdr));
X	size += align(sizeof(struct slot_error_hdr));
X	size += strlen(string) + 1;
X	s.subslot.error.se_type = type;
X	strcpy(s.subslot.error.msg,string);
X	finish_slot(m,&s,size);
X}
END_OF_FILE
if test 1541 -ne `wc -c <'src/man_put_slot.c'`; then
    echo shar: \"'src/man_put_slot.c'\" unpacked with wrong size!
fi
# end of 'src/man_put_slot.c'
fi
if test -f 'src/msg.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/msg.c'\"
else
echo shar: Extracting \"'src/msg.c'\" \(966 characters\)
sed "s/^X//" >'src/msg.c' <<'END_OF_FILE'
X/* msg.c */
X
X#include <sys/time.h>
X#include "cm_constants.h"
X#include "cm_sd.h"
X#include "cm_slot.h"
X#include "cm_msg.h"
X#include "cm_bytestuff.h"
X
Xextern int cm_debug_level;
X
X/* returns NULL if no more slots */
Xstruct slot *
Xnextslot(m,s)
Xstruct msg *m;
Xstruct slot *s;
X{
X	struct slot *next;
X
X	next = (struct slot *)byteadd(s,s->s_size);
X	if (next >= (struct slot *)byteadd(m,m->size))
X		return((struct slot *)0);
X	return(next);
X}
X
Xprint_msg(m)
Xstruct msg *m;
X{
X	struct slot *s;
X
X	eprintf(3,"msg header:");
X	eprintf(3," size = %d",m->size);
X	eprintf(3," slots = %d",m->slots);
X	eprintf(3," name = %s",m->name);
X	eprintf(3," read_wait = %d\n",m->read_wait);
X	for (s=m->data;s;s=nextslot(m,s)) {
X		eprintf(5,"slot: name = %s",s->s_name);
X		eprintf(5," &slot = %x",s);
X		eprintf(5," size = %d\n",s->s_size);
X		if (s->s_size == 0) {
X			eprintf(5,"0 length slot encountered in print_msg\n");
X			break;
X		}
X	}
X	if (cm_debug_level >= 10) ascii_dump((char *)m,m->size);
X}
X
END_OF_FILE
if test 966 -ne `wc -c <'src/msg.c'`; then
    echo shar: \"'src/msg.c'\" unpacked with wrong size!
fi
# end of 'src/msg.c'
fi
if test -f 'src/name.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/name.c'\"
else
echo shar: Extracting \"'src/name.c'\" \(216 characters\)
sed "s/^X//" >'src/name.c' <<'END_OF_FILE'
X/* set_cm_process_name.c */
X
X#include <stdio.h>
X#include "cm_constants.h"
X
Xchar cm_process_name[CM_PROCESSNAMELENGTH];
X
Xset_cm_process_name(name)
Xchar *name;
X{
X	strncpy(cm_process_name,name,CM_PROCESSNAMELENGTH);
X}
X
END_OF_FILE
if test 216 -ne `wc -c <'src/name.c'`; then
    echo shar: \"'src/name.c'\" unpacked with wrong size!
fi
# end of 'src/name.c'
fi
if test -f 'src/put_slot.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/put_slot.c'\"
else
echo shar: Extracting \"'src/put_slot.c'\" \(2010 characters\)
sed "s/^X//" >'src/put_slot.c' <<'END_OF_FILE'
X/*
X
XThese are some utility routines for building slots.  These slots
Xare placed in a msg structure and sent from the user to the cmm or vice-versa.
X
X*/
X
X#include <stdio.h>
X#include <sys/time.h>
X#include <strings.h>
X#include "cm_constants.h"
X#include "cm_sd.h"
X#include "cm_slot.h"	/* definitions of slot structures */
X#include "cm_msg.h"	/* definitions of msg structures */
X#include "cm_bytestuff.h"
X
X#define TRUE 1
X#define FALSE 0
X
Xextern char cm_process_name[];
X
Xint	/* returns # of bytes written into msg structure */
Xfinish_slot(m,slot,slotsize)
Xstruct msg *m;
Xstruct slot *slot;
Xunsigned int slotsize;
X{
X	if (m->size + slotsize > CM_MSGSIZE) {
X		fprintf(stderr,"too much data for msg!!\n");
X		fprintf(stderr,"output msg size = %d  slotsize = %d  CM_MSGSIZE = %d\n",
X			m->size,slotsize,CM_MSGSIZE);
X		return(0);
X	}
X	/* copy slot into msg after previous slot */
X	slot->s_size = slotsize; /* this is not aligned, right? */
X	eprintf(10,"finish_slot: bcopying slot (size = %d) into msg\n",
X						slot->s_size);
X	safebcopy((char *)slot,(char *)byteadd(m,m->size),slotsize);
X	eprintf(10,"finish_slot: after bcopy, message slot size = %d\n",
X				((struct slot *)byteadd(m,m->size))->s_size);
X	m->slots++;
X	m->size += align(slotsize);
X	return(align(slotsize));
X}
X
Xinit_msg(m)
Xstruct msg *m;
X{
X	m->version = CMM_VERSION;
X	m->slots = 0;
X	m->read_wait = FALSE;
X	strcpy(m->name,cm_process_name);
X	m->size = sizeof(struct msg) - sizeof(struct slot);
X}
X
X/*
Xinit_slot does the following:
X	sets the slot name and type
X*/
Xinit_slot(s,name,type)
Xstruct slot *s;
Xchar *name;
Xint type;
X{
X	s->s_type = type;
X	strcpy(s->s_name,name);
X}
X
Xchar *
Xcm_slot_type(t)
Xint t;
X{
X	switch (t) {
X	case CM_SLOT_NULL: return("null slot type");
X	case CM_SLOT_DECLARE: return("declare");
X	case CM_SLOT_WRITE: return("write");
X	case CM_SLOT_READ: return("read");
X	case CM_SLOT_READ_RESPONSE: return("read response");
X	case CM_SLOT_ERROR: return("error");
X	case CM_SLOT_UNDECLARE: return("undeclare");
X	default: return("unknown slot type");
X	}
X}
END_OF_FILE
if test 2010 -ne `wc -c <'src/put_slot.c'`; then
    echo shar: \"'src/put_slot.c'\" unpacked with wrong size!
fi
# end of 'src/put_slot.c'
fi
if test -f 'src/server1y.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/server1y.c'\"
else
echo shar: Extracting \"'src/server1y.c'\" \(652 characters\)
sed "s/^X//" >'src/server1y.c' <<'END_OF_FILE'
X/* server1y.c
X
XThis process prints the latest values of variables a_var and b_var when
Xthe user presses return.
X
X*/
X#include <sys/time.h>
X#include "cm.h"
X
Xcm_value a_val = {0,0,0,1}, b_val = {0,0,0,1};
X
Xmain()
X{
X	cm_variable *a_var, *b_var;
X
X	if (0>cm_init("press return",0,0)) exit(-1);
X
X	if (!(a_var = cm_declare("a_var",CM_ROLE_READER)))
X			exit(-1);
X	if (!(b_var = cm_declare("b_var",CM_ROLE_READER)))
X			exit(-1);
X
X	printf("press return for latest values\n");
X	for (;;) {
X		getchar();
X		cm_sync(CM_WAIT_READ);
X		cm_get_value(a_var,&a_val);
X		printf("a_var: %s\n",a_val.data);
X		cm_get_value(b_var,&b_val);
X		printf("b_var: %s\n",b_val.data);
X	}
X}
END_OF_FILE
if test 652 -ne `wc -c <'src/server1y.c'`; then
    echo shar: \"'src/server1y.c'\" unpacked with wrong size!
fi
# end of 'src/server1y.c'
fi
if test -f 'src/server1z.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/server1z.c'\"
else
echo shar: Extracting \"'src/server1z.c'\" \(610 characters\)
sed "s/^X//" >'src/server1z.c' <<'END_OF_FILE'
X/* server1.c
XThis process, s, prints the latest values of variables a_var and b_var
X*/
X#include <sys/time.h>
X#include "cm.h"
X
Xcm_value a_val = {0,0,0,1}, b_val = {0,0,0,1};
X
Xmain()
X{
X	cm_variable *a_var, *b_var;
X
X	if (0>cm_init("s",0,0)) exit(-1);
X
X	if (!(a_var = cm_declare("a_var",CM_ROLE_READER|CM_ROLE_WAKEUP)))
X			exit(-1);
X	if (!(b_var = cm_declare("b_var",CM_ROLE_READER|CM_ROLE_WAKEUP)))
X			exit(-1);
X
X	for (;;) {
X		cm_sync(CM_WAIT_AT_MOST_ONCE);
X		if (cm_get_new_value(a_var,&a_val))
X			printf("a_var: %s\n",a_val.data);
X		if (cm_get_new_value(b_var,&b_val))
X			printf("b_var: %s\n",b_val.data);
X	}
X}
END_OF_FILE
if test 610 -ne `wc -c <'src/server1z.c'`; then
    echo shar: \"'src/server1z.c'\" unpacked with wrong size!
fi
# end of 'src/server1z.c'
fi
if test -f 'src/server2.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/server2.c'\"
else
echo shar: Extracting \"'src/server2.c'\" \(823 characters\)
sed "s/^X//" >'src/server2.c' <<'END_OF_FILE'
X/* all this server does is print out whatever its given */
X
X/* Note, this has not been converted over to use cmm v7!!! */
X
X#include <sys/time.h>
X#include "cm.h"
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X	cm_variable *i_var, *d_var, *s_var;
X	char s_val[1000];
X	int i_val;
X	double d_val;
X
X	if (argc>1) printf("going to host %s for cmm\n",argv[1]);
X	if (0 > cm_init("printer",(argc>1?argv[1]:(char *)0),0)) exit(-1);
X
X	i_var = cm_declare("i_var",CM_ROLE_READER | CM_ROLE_WAKEUP);
X	d_var = cm_declare("d_var",CM_ROLE_READER);
X	s_var = cm_declare("s_var",CM_ROLE_READER);
X
X	while (TRUE) {
X		if (0 > cm_sync(CM_WAIT_AT_MOST_ONCE)) return;
X		cm_get_value(i_var,&i_val);
X		printf("i_var = %d\n",i_val);
X		cm_get_value(d_var,&d_val);
X		printf("d_var = %g\n",d_val);
X		cm_get_value(s_var,s_val);
X		printf("s_var = %s\n",s_val);
X	}
X}
END_OF_FILE
if test 823 -ne `wc -c <'src/server2.c'`; then
    echo shar: \"'src/server2.c'\" unpacked with wrong size!
fi
# end of 'src/server2.c'
fi
if test -f 'src/server8a.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/server8a.c'\"
else
echo shar: Extracting \"'src/server8a.c'\" \(388 characters\)
sed "s/^X//" >'src/server8a.c' <<'END_OF_FILE'
X/* server8a.c - constant wait on common memory to test that cmm doesn't */
X/* blow up when we die and it is writing to us (SIGPIPE) */
X
X#include <sys/time.h>
X#include "cm.h"
X
Xcm_variable *variable;
X
Xmain()
X{
X	if (0>cm_init("constant reader SIGPIPE",0,0)) exit(-1);
X
X	if (!(variable = cm_declare("variable",CM_ROLE_READER|CM_ROLE_WAKEUP))) exit(-1);
X
X	while (1) {
X		cm_sync(CM_WAIT);
X	}
X}
END_OF_FILE
if test 388 -ne `wc -c <'src/server8a.c'`; then
    echo shar: \"'src/server8a.c'\" unpacked with wrong size!
fi
# end of 'src/server8a.c'
fi
if test -f 'src/server8b.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/server8b.c'\"
else
echo shar: Extracting \"'src/server8b.c'\" \(366 characters\)
sed "s/^X//" >'src/server8b.c' <<'END_OF_FILE'
X/* server8b.c - receive updates from common memory but do not read() */
X/* see if cmm eventually hangs on write() */
X
X#include <sys/time.h>
X#include "cm.h"
X
Xcm_variable *variable;
X
Xmain()
X{
X	if (0>cm_init("constant reader hang",0,0)) exit(-1);
X
X	if (!(variable = cm_declare("variable",CM_ROLE_READER|CM_ROLE_WAKEUP))) exit(-1);
X
X	cm_sync(CM_NO_WAIT);
X	sigpause();
X}
END_OF_FILE
if test 366 -ne `wc -c <'src/server8b.c'`; then
    echo shar: \"'src/server8b.c'\" unpacked with wrong size!
fi
# end of 'src/server8b.c'
fi
if test -f 'src/usr_get_slot.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/usr_get_slot.c'\"
else
echo shar: Extracting \"'src/usr_get_slot.c'\" \(1508 characters\)
sed "s/^X//" >'src/usr_get_slot.c' <<'END_OF_FILE'
X/*
X
Xthese functions are used by the user to read and process information from
Xincoming slots 
X
X*/
X
X#include <stdio.h>
X#include <sys/time.h>
X#include "cm_constants.h"
X#include "cm_sd.h"
X#include "cm_interface.h"
X#include "cm_slot.h"
X
Xcm_variable *get_variable();
X
Xuser_decode_slot(s)
Xstruct slot *s;
X{
X	int rc = 0;
X
X	switch (s->s_type) {
X	case CM_SLOT_READ_RESPONSE:
X		rc = get_slot_read_response(s->s_name,
X				&s->subslot.read_response);
X		break;
X	case CM_SLOT_ERROR:
X		rc = get_slot_error(s->s_name,&s->subslot.error);
X		break;
X	default:
X		fprintf(stderr,"user_decode_slot: unknown slot type (%d)...msg aborted\n",s->s_type);
X		rc = E_CM_GET_SLOT_UNKNOWN_SLOT_TYPE;
X		break;
X	}
X	return(rc);
X}
X
X/* returns 0 if ok, negative if problem decoding slot */
Xint
Xget_slot_error(name,s)
Xchar *name;
Xstruct slot_error *s;
X{
X	fprintf(stderr,"CMM: error processing variable <%s> - %s\n",name,
X		s->msg);
X	/* isn't there a "type" field in the error subslot, too? */
X	return(0);
X}
X
X/* 0 if ok, negative if problem decoding slot */
Xint
Xget_slot_read_response(name,s)
Xchar *name;
Xstruct slot_read_response *s;
X{
X	int rc;
X	cm_variable *v;
X
X	if (!(v = get_variable(name))) {
X		fprintf(stderr,"get_slot_read_response: <%s> unknown (sent from cm)\n",v->name);
X		return(E_CM_GET_SLOT_GET_VARIABLE);
X	}
X
X	if (0 > cm_flat_to_sd(&s->fdata,&v->data))
X		return(E_CM_GET_SLOT_FLAT_TO_SD);
X	v->count = s->srr_count;
X	v->command_association = s->srr_command_association;
X	cm_time_copy(&s->srr_timestamp,&v->timestamp);
X	return(0);
X}
X	
END_OF_FILE
if test 1508 -ne `wc -c <'src/usr_get_slot.c'`; then
    echo shar: \"'src/usr_get_slot.c'\" unpacked with wrong size!
fi
# end of 'src/usr_get_slot.c'
fi
if test -f 'src/usr_put_slot.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/usr_put_slot.c'\"
else
echo shar: Extracting \"'src/usr_put_slot.c'\" \(2058 characters\)
sed "s/^X//" >'src/usr_put_slot.c' <<'END_OF_FILE'
X
X/*
X
XThese routines build slots for the user.  These slots are placed into a
Xmsg structure and sent to the cmm.  The all return 0 for failure, or a
Xpositive number indicating the number of bytes in the slot.
X
X*/
X
X#include <stdio.h>
X#include <sys/time.h>
X#include "cm_constants.h"
X#include "cm_sd.h"
X#include "cm_slot.h"
X#include "cm_msg.h"
X#include "cm_bytestuff.h"
X#include "cm_interface.h"
X
X/* this indicates that the user wants the cmm to send back the latest value */
X/* of all variables */
Xput_slot_read(m)
Xstruct msg *m;
X{
X	struct slot s;
X	unsigned int size;
X
X	init_slot(&s,"read all",CM_SLOT_READ);
X	size = align(sizeof(struct slot_hdr));
X/*	size += align(sizeof(struct slot_read));*/
X	return(finish_slot(m,&s,size));
X}
X
Xint	/* returns size of data written in msg */
Xput_slot_write(m,name,data,cmd)
Xstruct msg *m;
Xchar *name;
Xcm_value *data;
Xint cmd;
X{
X	struct big_slot s;
X	unsigned int size;
X
X	init_slot((struct slot *)&s,name,CM_SLOT_WRITE);
X	size = align(sizeof(struct slot_hdr));
X	size += align(sizeof(struct slot_write_hdr));
X	s.subslot.write.sw_command_association = cmd;
X	size += cm_sd_to_flat(data,&s.subslot.write.fdata);
X	return(finish_slot(m,(struct slot *)&s,size));
X}
X
Xint
Xput_slot_declare(m,name,role,cmd_assoc)
Xstruct msg *m;
Xchar *name;
Xstruct usr_var_role *role;
Xint cmd_assoc;
X{
X	struct slot s;
X	unsigned int size;
X
X	init_slot(&s,name,CM_SLOT_DECLARE);
X	size = align(sizeof(struct slot_hdr));
X	size += align(sizeof(struct slot_declare));
X	/* could do some checking on the following */
X	s.subslot.declare.role.reader = role->reader;
X	s.subslot.declare.role.wakeup = role->wakeup;
X	s.subslot.declare.role.xwriter = role->xwriter;
X	s.subslot.declare.role.nonxwriter = role->nonxwriter;
X	s.subslot.declare.command_association = cmd_assoc;
X	return(finish_slot(m,&s,size));
X}
X
Xint
Xput_slot_undeclare(m,name)
Xstruct msg *m;
Xchar *name;
X{
X	struct slot s;
X	unsigned int size;
X
X	init_slot(&s,name,CM_SLOT_UNDECLARE);
X	size = align(sizeof(struct slot_hdr));
X/*	size += align(sizeof(struct slot_undeclare));*/
X	return(finish_slot(m,&s,size));
X}
END_OF_FILE
if test 2058 -ne `wc -c <'src/usr_put_slot.c'`; then
    echo shar: \"'src/usr_put_slot.c'\" unpacked with wrong size!
fi
# end of 'src/usr_put_slot.c'
fi
if test -f 'src/usr_var.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/usr_var.c'\"
else
echo shar: Extracting \"'src/usr_var.c'\" \(2280 characters\)
sed "s/^X//" >'src/usr_var.c' <<'END_OF_FILE'
X/* usr_var.c - utility functions for user only! */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <strings.h>
X
X#include "cm_constants.h"
X#include "cm_sd.h"
X#include "cm_interface.h"
X
Xcm_variable cm_variables[CM_MAXUSERVARIABLES];
X
Xcm_variable *
Xget_variable(name)
Xchar *name;
X{
X        int i;
X
X	eprintf(10,"entering get_variable(%s)\n",name);
X        for (i=0;i<CM_MAXUSERVARIABLES;i++) {
X                /* create it if we come to an empty variable */
X                if (!cm_variables[i].status.inuse) {
X		    eprintf(10,"get_variable: found empty variable slot\n");
X                    strcpy(cm_variables[i].name,name);
X		    cm_sd_clear(&cm_variables[i].data);
X		    cm_variables[i].role.reader = 0;
X		    cm_variables[i].role.nonxwriter = 0;
X		    cm_variables[i].role.wakeup = 0;
X		    cm_variables[i].role.xwriter = 0;
X		    cm_variables[i].old_count = 0;
X		    cm_variables[i].count = 0;
X		    cm_variables[i].command_association = 0;
X		    cm_time_zero(&cm_variables[i].timestamp);
X		    cm_variables[i].status.inuse = TRUE;
X		    cm_variables[i].status.written = FALSE;
X		    cm_variables[i].status.declared = FALSE;
X                    return(&cm_variables[i]);
X                }
X                /* found an old definition */
X                if (!(strcmp(cm_variables[i].name,name))) {
X			eprintf(10,"get_variable() found old defn\n");
X                        return(&cm_variables[i]);
X                }
X        }
X        /* no old definition and no space for a new one!!!! */
X        return(NULL);
X}
X
X/*
XThe following function allows the user to step through all the common
Xmemory values, for example, to see if any have changed.  If v is NULL,
Xthe first value is returned.  If no more cm_variables are in use, NULL is
Xreturned.
X
XThis function is also used by the common memory system itself, as it
Xhides the implementation of the user cm_variables as a large array.
XPresumably, it will be changed to have a hash index in the future
Xfor speed.
X*/
Xcm_variable *
Xnext_user_variable(v)
Xcm_variable *v;	/* if NULL, start from the beginning */
X{
X	if (v == 0) v = cm_variables;	/* reinitialize */
X	else v++;			/* next one */
X
X	for (;v<&cm_variables[CM_MAXUSERVARIABLES];v++) {
X		if (v->status.inuse) return(v);
X	}
X	return((cm_variable *)NULL);
X}
END_OF_FILE
if test 2280 -ne `wc -c <'src/usr_var.c'`; then
    echo shar: \"'src/usr_var.c'\" unpacked with wrong size!
fi
# end of 'src/usr_var.c'
fi
if test ! -d 'stream' ; then
    echo shar: Creating directory \"'stream'\"
    mkdir 'stream'
fi
if test -f 'stream/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stream/Makefile'\"
else
echo shar: Extracting \"'stream/Makefile'\" \(932 characters\)
sed "s/^X//" >'stream/Makefile' <<'END_OF_FILE'
XCOMMON = stream.o sized_io.o
XOFILES = $(COMMON) reader.o writer.o
XHFILES = inet.h
XCFLAGS =
X#CFLAGS = -g -DDEBUG
XLIB = libstream.a
X
X# for testing purposes
X
Xtest: libstream.a reader writer
X
Xlibstream.a: stream.o sized_io.o
X	ar cr libstream.a  `lorder $(COMMON) | tsort` 
X	ranlib libstream.a
X
Xcleanup:
X	rm $(OFILES) libstream.a
X
Xinstall: libstream.a makedirs
X	cp $(HFILES) /usr/local/include/inet/stream
X	cp libstream.a /usr/local/lib
X	cp stream.3 /usr/local/man/manl/sized_io.l
X
Xmakedirs: /usr/local/include/inet /usr/local/include/inet/stream
X
X/usr/local/include/inet:
X	mkdir /usr/local/include/inet
X
X/usr/local/include/inet/stream:
X	mkdir /usr/local/include/inet/stream
X
Xlint:
X	lint -u stream.c _sized_io.c
X
Xlintc:
X	lint -Cstream stream.c _sized_io.c
X	su -c "mv llib-lstream.ln /usr/lib/lint" -f
X
Xreader: reader.o $(COMMON)
X	cc $(CFLAGS) -o reader reader.o $(LIB)
X
Xwriter:	writer.o $(COMMON)
X	cc $(CFLAGS) -o writer writer.o $(LIB)
END_OF_FILE
if test 932 -ne `wc -c <'stream/Makefile'`; then
    echo shar: \"'stream/Makefile'\" unpacked with wrong size!
fi
# end of 'stream/Makefile'
fi
if test -f 'stream/README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stream/README'\"
else
echo shar: Extracting \"'stream/README'\" \(2493 characters\)
sed "s/^X//" >'stream/README' <<'END_OF_FILE'
XThis package provides a quick-and-easy means of providing reliable
Xand large-packet communication between processes.
X
XIt is especially nice because initport() does all the hard work of
Xinitializing TCP connections, and select_server_stream() does the
Xhard work of connecting processes to each other.
X
XTo install, type
X
X	make install
X
XTo test, type
X
X	make test
X	reader
X	writer	(in different window)
X	writer  (in yet another window)
X	writer  (in yet ...)
X	and so on.
X
X
Xreader and writer are two programs that should communicate with
Xeach other.  Type things into any of the writers and reader will
Xprint it out prefaced by the file descriptor the data came in on.
X
XBugs and problems to Don Libes
XNational Bureau of Standards
XBldg 220, Rm A-127
XGaithersburg, MD  20899
X(301) 975-3535
X
X
XSYNOPSIS
X
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <inet.h>
X
X	cc [options] [files] sized_io.o stream.o
X
XDESCRIPTION
X
XThis package implements packet or stream IO between a server process and
Xa number of client processes, using the TCP/IP (stream) facilities.
X
XA client uses the call:
X
X	s = initport(PORT_NUMBER(XXX),CLIENT,SOCK_STREAM);
X
Xs is the server's data socket and is used as a file descriptor in further
Xcommunication.  The port may be specified by name (PORT_NAME("foo")), if it
Xis registered.
X
XSimilarly, the server uses the following call:
X
X	s = initport(PORT_NUMBER(XXX),SERVER,SOCK_STREAM);
X
Xs is the server's connection socket.  To receive data or connections, the
Xserver calls select_server_stream().
X
X	client = select_server_stream(s,&fds);
X
XThis returns a file descriptor corresponding to a client, when a client has
Xsent a message to the server.  It handles initial connections as well as
Xclient deaths.  s is the server's connection socket that was returned by
Xinitport().  fds is an int used by select...() for storing a bit string
Xcorresponding to client sockets.  Initialize it to 0, and don't mess with it
Xafter that.
X
XTo use the file descriptors in a stream-oriented manner, use read() and
Xwrite().  To use the file descriptors in a packet-oriented manner, use
Xsized_read() and sized_write().  The sized...() calls read and write one
Xpacket at a time, while packet boundaries are ignored in read() and write().
X
X	cc = sized_read(fd,buffer,maxsize)
X	cc = sized_write(fd,buffer,size)
X
XThe arguments for sized_read() and sized_write() are very similar to read()
Xand write().  The only difference is that in sized_read(), maxsize is the
Xmaximum size of an acceptable packet.
END_OF_FILE
if test 2493 -ne `wc -c <'stream/README'`; then
    echo shar: \"'stream/README'\" unpacked with wrong size!
fi
# end of 'stream/README'
fi
if test -f 'stream/inet.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stream/inet.h'\"
else
echo shar: Extracting \"'stream/inet.h'\" \(417 characters\)
sed "s/^X//" >'stream/inet.h' <<'END_OF_FILE'
X#define TRUE		1
X#define FALSE		0
X
X#define PORT_TYPE_NAME		1
X#define PORT_TYPE_NUMBER	2
X
X#define PORT_NAME(name)		PORT_TYPE_NAME,name,(u_short)0
X#define PORT_NUMBER(number)	PORT_TYPE_NUMBER,0,(u_short)number
X
X/* sockettypes are SOCKET_STREAM and SOCKET_DGRAM */
X
X#define DATAGRAM_FLAGS	0		/* for recv and sendto */
X
X#define SERVER		1
X#define CLIENT		2
X#define server		(role == SERVER)
X#define client		(role == CLIENT)
END_OF_FILE
if test 417 -ne `wc -c <'stream/inet.h'`; then
    echo shar: \"'stream/inet.h'\" unpacked with wrong size!
fi
# end of 'stream/inet.h'
fi
if test -f 'stream/reader.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stream/reader.c'\"
else
echo shar: Extracting \"'stream/reader.c'\" \(729 characters\)
sed "s/^X//" >'stream/reader.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X#include "inet.h"
X
Xchar buf[2000];
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X	int writer;
X	int cc;
X	int fd;
X	int fds = 0;
X
X	/* if an arg is provided, use that as the hostname to look for the */
X	/* service */
X	fd = initport(PORT_NUMBER(2000),SERVER,SOCK_STREAM,(char *)0);
X	if (fd < 0) {
X		fprintf(stderr,"initport() = %d\n",fd);
X		exit(-1);
X	}
X
X        while (TRUE) {
X		writer = select_server_stream(fd,&fds);
X		cc = sized_read(writer,buf,2000);
X		if (cc <= 0) {
X			printf("%d: EOF\n",writer);
X			close(writer);
X			continue;
X		}
X		printf("%d: %s\n",writer,buf);
X		if (cc == 1) cc = sized_write(writer,"1 char",6);
X	}
X}
END_OF_FILE
if test 729 -ne `wc -c <'stream/reader.c'`; then
    echo shar: \"'stream/reader.c'\" unpacked with wrong size!
fi
# end of 'stream/reader.c'
fi
if test -f 'stream/stream.3' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stream/stream.3'\"
else
echo shar: Extracting \"'stream/stream.3'\" \(2306 characters\)
sed "s/^X//" >'stream/stream.3' <<'END_OF_FILE'
X.TH SIZED_IO 3NBS "11 January 1988"
X.SH NAME
Xinitport, sized_read, sized_write - send datagrams using TCP
X.SH SYNOPSIS
X.B #include <sys/socket.h>
X.br
X.B #include <netinet/in.h>
X.br
X.B #include <inet.h>
X.PP
X.B int s = initport(PORT_NUMBER(XXX),SERVER,SOCK_STREAM);
X.PP
X.B int client = select_server_stream(s,&fds);
X.br
X.B int s;
X.br
X.B int fds;
X.PP
X.B int cc = sized_read(fd,buffer,maxsize)
X.br
X.B int cc = sized_write(fd,buffer,size)
X.br
X.B int fd;
X.br
X.B char *buffer;
X.br
X.B int maxsize;
X.SH DESCRIPTION
XThis package implements packet or stream IO between a server
Xprocess and a number of client processes, using the TCP/IP (stream)
Xfacilities.  It is particularly useful to send packets larger than
Xthat allowed by UDP.  UDP packets are also not reliable - these are.
X.PP
XA client uses the call:
X.PP
X.B	s = initport(PORT_NUMBER(XXX),CLIENT,SOCK_STREAM);
X.PP
Xs is the server's data socket and is used as a file descriptor in further
Xcommunication.  The port may be specified by name (PORT_NAME("foo")), if it
Xis registered.
X.PP
XSimilarly, the server uses the following call:
X.PP
X.B	s = initport(PORT_NUMBER(XXX),SERVER,SOCK_STREAM);
X.PP
Xs is the server's connection socket.  To receive data or connections, the
Xserver calls select_server_stream().
X.PP
X.B	client = select_server_stream(s,&fds);
X.PP
XThis returns a file descriptor corresponding to a client, when a client has
Xsent a message to the server.  It handles initial connections as well as
Xclient deaths.  s is the server's connection socket that was returned by
Xinitport().  fds is an int used by select...() for storing a bit string
Xcorresponding to client sockets.  Initialize it to 0, and don't mess with it
Xafter that.
X.PP
XTo use the file descriptors in a stream-oriented manner, use read() and
Xwrite().  To use the file descriptors in a packet-oriented manner, use
Xsized_read() and sized_write().  The sized...() calls read and write one
Xpacket at a time, while packet boundaries are ignored in read() and write().
X.PP
X.B	cc = sized_read(fd,buffer,maxsize)
X.PP
X.B	cc = sized_write(fd,buffer,size)
X.PP
XThe arguments for sized_read() and sized_write() are very similar to read()
Xand write().  The only difference is that in sized_read(), maxsize is the
Xmaximum size of an acceptable packet.
X.SH AUTHOR
XDon Libes - National Bureau of Standards
END_OF_FILE
if test 2306 -ne `wc -c <'stream/stream.3'`; then
    echo shar: \"'stream/stream.3'\" unpacked with wrong size!
fi
# end of 'stream/stream.3'
fi
if test -f 'stream/writer.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stream/writer.c'\"
else
echo shar: Extracting \"'stream/writer.c'\" \(763 characters\)
sed "s/^X//" >'stream/writer.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X/* #include <netdb.h> */
X#include "inet.h"
X
Xchar msg[2000];
X
Xstruct timeval timeout = {0L, 0L};
Xint maxfds;
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X	int cc;
X	int i;
X	int fd;
X	int readfds;
X
X	maxfds = getdtablesize();
X	fd = initport(PORT_NUMBER(2000),CLIENT,SOCK_STREAM,argc>1?argv[1]:"");
X
X	if (fd < 0) {
X		fprintf(stderr,"initport() = %d\n",fd);
X		exit(-1);
X	}
X	for (i=0;;i++) {
X		printf("%d: ",i);
X		gets(msg);
X		cc = sized_write(fd,msg,strlen(msg)+1);
X		readfds = 1<<fd;
X		if (0 < select(maxfds,&readfds,0,0,&timeout)
X		   && readfds == 1<<fd) {
X			cc = sized_read(fd,msg,2000);
X			msg[cc] = '\0';
X			printf("msg from server: %s\n",msg);
X		}
X	}
X}
END_OF_FILE
if test 763 -ne `wc -c <'stream/writer.c'`; then
    echo shar: \"'stream/writer.c'\" unpacked with wrong size!
fi
# end of 'stream/writer.c'
fi
echo shar: End of archive 1 \(of 4\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.