--- /dev/null
+# Configuration file for egg collection software
+# This specifies the egg configuration information, the contact
+# information for its basket(s), and initial data acquisition parameters.
+
+# Each line consists of a case-sensitive keyword and a series of
+# options. Defined keywords are:
+#
+# EGG <name> <id> <ip addr> <primbasket> <conntype> <connival> <url>
+#
+# The primary basket <primbasket> is the name of the basket (defined
+# below) that should be contacted retrieve data from this Egg.
+# The connection type <conntype> is "PERM" (permanent) or "DND"
+# (dial-and-drop). So far the code does not support the DND option.
+# The connection interval <connival> determines the time (in minutes)
+# between transmission attempts. If specified, and not equal to
+# ".", <url> gives a URL (for example http://www.somesite.net/page.html)
+# which will be linked to the egg <name> in status reports. Note that
+# this specification has meaning only in the .basketrc file. For
+# compatibility, it is permitted in an .eggrc file, but is ignored.
+#
+# BASKET <name> <ip addr>
+#
+# This entry tells us about the existence of a set of baskets. The
+# basket named as primary is the one which will be contacted
+# initially.
+#
+# PROTOCOL <samprec> <secrec> <recpkt> <trialsz>
+#
+# Specify the default data collection protocol. The arguments are
+# <samprec> samples per record (1-10, though this should always be 5-10),
+# <secrec> seconds per records (1-3000),
+# <recpkt> records per packet (1-60), and
+# <trialsz> bits per sample (32-255).
+#
+# REG <type> <port> <baud>
+#
+# Specify hardware device. Supported types include "PEAR" only at
+# this time. Port is serial port number (e.g. 1 for /dev/ttyS1);
+# <baud> is baud rate.
+#
+# NETUP <script> <args> ...
+# NETDOWN <script> <args> ...
+#
+# Provide script files to be run to bring up and tear down the network
+# connection on demand. These will only be used if connection type is
+# DND.
+
+#EGG halley 1 10.0.0.111 halley PERM 1
+#BASKET halley 10.0.0.111
+#EGG halley 1 10.0.0.111 mercury DND 3
+#BASKET mercury 10.0.0.125
+
+#EGG noosphere 28 128.112.35.133 noosphere PERM 1
+#BASKET noosphere 128.112.35.133
+
+# diesse -> diesse
+#EGG diesse 37 193.8.230.134 diesse PERM 1
+#BASKET diesse 193.8.230.134
+
+# noosphere -> diesse
+EGG noosphere 28 128.112.35.133 diesse PERM 1
+BASKET diesse 193.8.230.134
+
+# throop -> diesse
+#EGG throop 1003 193.8.230.132 diesse PERM 1 http://www.fourmilab.ch/
+#BASKET diesse 193.8.230.134
+
+# jura -> jura
+#EGG jura 1004 193.8.230.130 jura PERM 1 http://www.fourmilab.ch/
+#BASKET jura 193.8.230.130
+
+# diesse -> noosphere
+#EGG diesse.fourmilab.ch 37 193.8.230.134 noosphere PERM 1
+#BASKET noosphere 128.112.35.133
+
+#EGG diesse 37 193.8.230.134 jura PERM 1
+#BASKET jura 193.8.230.130
+
+#BASKET tonga 209.157.90.137
+#BASKET tonga1 209.157.90.138
+PROTOCOL 10 10 6 200
+#REG PEAR 2 9600
+REG PSEUDO 1 9600
+#REG ORION 1 9600
+NETUP pppscript up
+NETDOWN pppscript down
--- /dev/null
+
+# Debug options you can define on the following line:
+
+# -DALT_UI -- Select an alternative user interface
+# that doesn't require curses. This allows
+# running an egg even if there's a problem
+# with terminal configuration.
+#
+# -DDEBUG -- General debug output
+#
+# -DHEXDUMP -- Dump network packets sent and received
+# in hexadecimal, identifying the recipient
+# or sender by IP address. Handy when
+# tracking down byte alignment problems.
+#
+# -DNICE=x -- Priority increment (positive value) which
+# eggsh raises to while collecting data when
+# run by super-user. Default is 10. Setting
+# -DNICE=0 disables the priority adjustment
+# mechanism.
+#
+# -DNO_UI -- Disable user interface in the egg. This
+# is handy when you want to watch other
+# debug output.
+#
+# -DPACKETDUMP -- Interpreted dump of packets.
+#
+# -DSTORAGE_DEBUG -- Debug output from storage.c database
+# functions.
+#
+# -DTESTPORT -- Use EGGPORT = 2074, BASKETPORT = 2075.
+# This permits testing an experimental
+# version of eggsh and basket on a machine
+# which is running production version(s)
+# on the standard ports.
+#
+# -DUSLEEP -- Use a built-in emulation of usleep()
+# based on setitimer() instead of the
+# system library function (which may not
+# exist on all flavours of Unix).
+
+#DEBUGOPTIONS = -DDEBUG -DPACKETDUMP -DTESTPORT -DHEXDUMP -DNO_UI -DSTORAGE_DEBUG
+
+#DEBUGOPTIONS = -DTESTPORT -DDEBUG -DPACKETDUMP -DNO_UI -DALT_UI
+
+#DEBUGOPTIONS = -DTESTPORT
+
+#DEBUGOPTIONS =
+
+#DEBUGOPTIONS = -DTESTPORT -DALT_UI -DNO_UI
+
+#DEBUGOPTIONS = -DDEBUG -DALT_UI -DNO_UI
+
+#DEBUGOPTIONS = -DDEBUG -DNO_UI -DHEXDUMP
+
+# Build for throop/Orion egg
+#DEBUGOPTIONS = -DNO_UI -DALT_UI -DDEBUG -DUSLEEP -DFLUSH
+
+# Current debug options
+#DEBUGOPTIONS = -DNO_UI -DALT_UI -DDEBUG -DTESTPORT
+
+DEBUGOPTIONS = -DREPORT=1 -DEGG_DYNAMIC
+
+# For Linux with GCC
+CC = gcc
+PFLAGS = -g -ansi -Wall -DLinux -DUSLEEP -D_GNU_SOURCE
+LIBS = -lncurses
+
+# For Solaris 2.6 with Sun compiler
+#CC = cc
+#PFLAGS = -g -DSolaris
+#LIBS = -lcurses -lsocket -lnsl
+
+# Silicon Graphics Irix 5.3 with SGI compiler. Yes
+# we do define "Solaris" along with "Irix" for such a build.
+#CC = cc
+#PFLAGS = -g -DSolaris -DIrix -DUSLEEP
+#LIBS = -lcurses
+
+CFLAGS = $(PFLAGS) $(DEBUGOPTIONS)
+
+HWOBJ = reg_orion.o reg_pear.o reg_pseudo.o
+APPOBJ = storage.o network.o crc16.o genlib.o xdsub.o
+EGGOBJ = egg.o eggui.o lecuyer.o usleep.o
+BASKETOBJ = basket.o
+TESTOBJ = testmain.o
+
+PROGRAMS = eggsh basket regtest
+
+default: $(PROGRAMS)
+
+all: $(PROGRAMS) tarballs
+
+eggsh: $(EGGOBJ) $(HWOBJ) $(APPOBJ)
+ $(CC) $(CFLAGS) -o eggsh $(EGGOBJ) $(HWOBJ) $(APPOBJ) $(LIBS)
+
+examine: $(APPOBJ) examine.o
+ $(CC) $(CFLAGS) -o examine storage.o crc16.o genlib.o examine.o
+
+basket: $(BASKETOBJ) $(APPOBJ)
+ $(CC) $(CFLAGS) -o basket $(BASKETOBJ) $(APPOBJ) $(LIBS)
+
+tarballs: $(PROGRAMS)
+ tar czf eggware.tgz sample.eggrc eggsh regtest README
+ tar czf eggsrc.tgz sample.eggrc sample.basketrc $(PROGRAMS) README Makefile *.c *.h
+
+test: eggsh
+ eggsh 1 9600 200 10 10
+
+clean:
+ rm -f $(PROGRAMS) *.o *.bak .*.bak core dumpreg.dat egg.status eggsample.pid
+
+cleandata:
+ rm -rf 199*-*
+
+basket.o: basket.c global.h genlib.h storage.h network.h version.h
+
+#collect.o: collect.c global.h genlib.h regs.h collect.h
+
+egg.o: egg.c global.h genlib.h storage.h network.h regs.h version.h
+
+eggui.o: eggui.c global.h genlib.h errnos.h eggui.h regs.h version.h
+
+global.h: byteorder.h
+
+hw_pear.o: hw_pear.c global.h genlib.h
+
+lecuyer.o: lecuyer.c
+
+network.o: network.c global.h genlib.h network.h
+
+regs.h: reg.h
+
+reg_orion.o: reg_orion.c reg.h
+
+reg_pear.o: reg_pear.c reg.h
+
+reg_pseudo.o: reg_pseudo.c reg.h lecuyer.h
+
+storage.o: storage.c global.h genlib.h storage.h
+
+usleep.o: usleep.c
--- /dev/null
+ GCP (EGG) Software README
+
+ Setting up to host an egg for the Global Consciousness Project
+
+The experiment produces data and stores them on your local disk as well
+as shipping the data to the central server. You will want to create a
+separate directory for the egg material. If you have a computer sent
+from the GCP, the directory will be /home/egg. The software will create
+within that directory subdirectories to store the data. The storage
+load is not large (see the architecture document on the website,
+http://noosphere.princeton.edu, for more detail. After some months
+you may wish to remove old data, but leave two or more months' data for
+backup.
+
+The program you need to run is eggsh. It uses a configuration file
+called .eggrc, and you must edit the line near the end to enter your IP
+address. This should be a fixed IP address if possible, but the basket
+software can accept data from eggs at dynamic addresses. A file called
+sample.eggrc or eggrc.mod can be renamed to .eggrc if the .eggrc is not
+present. The "joe" editor is relatively user-friendly.
+
+If the program does not run, you may need to recompile on your machine.
+There is a makefile. Do make clean, then make.
+
+The sample .eggrc file specifies the first serial port, and if you are
+using a different port, you must change that specification.
+
+The sample pppscript file assumes you will have a fixed IP. You will
+have more appropriate pppscript and pppchat models at the time you are
+setting up.
+
+Let us know about ways to make this process simple and efficient. Write
+down your experiences and difficulties, and send to us any useful notes
+that can be part of the instructions for other hosts.
+
+Thanks
+
+RDN, last update: 99-03-14
+
--- /dev/null
+/* PROGRAM: basket
+ * FILE: $Header: /home/egg/src/RCS/basket.c,v 1.8 1999/02/28 19:58:49 ghn Exp $
+ * PURPOSE: Main program for basket software
+ * AUTHOR: Greg Nelson
+ * DATE: 98-06-28
+ *
+ * REVISED:
+ * $Log: basket.c,v $
+ * Revision 1.8 1999/02/28 19:58:49 ghn
+ * Version 5.1: Support for ip address masks to allow us to limit egg
+ * spoofing to users on a limited subnet (cf. EGG_DYNAMIC). Added
+ * flexible interface/port cmdline arguments and config file arguments.
+ * Report the eggs we are accepting.
+ *
+ * Revision 1.7 1999/01/01 23:52:31 ghn
+ * Allow basket to start with no net connection and handle connection
+ * going up and down.
+ *
+ * Revision 1.6 1998/12/31 22:07:56 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.5 1998/08/03 20:40:13 kelvin
+ * PACKETDUMP, SIGHUP reset when signal caught.
+ *
+ * Revision 1.4 1998/08/01 18:52:49 ghn
+ * Added John's byte-order-independence changes.
+ *
+ * Revision 1.3 1998/08/01 17:02:05 ghn
+ * Incorporate John's Solaris fixes and terminate STAT lines properly.
+ *
+ * Revision 1.2 1998/07/21 11:44:04 ghn
+ * Added headers.
+ *
+ * Copyright 1998 - Greg Nelson
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include "global.h"
+#include "genlib.h"
+#include "storage.h"
+#include "network.h"
+#include "errnos.h"
+#include "version.h"
+
+#define EGGSTATS "egg.status"
+
+static int32 BasketReceiveDataPacket(char *pktbuf, int16 isegg, int16 thisegg,
+ struct sockaddr_in *rhost);
+static void MakeRequest(ReqPacket *pkt, uint16 eggid, uint32 whence);
+static void MakeSettings(SettingsPacket *pkt, uint16 eggid);
+static void LoadRCFile(void);
+static void LoadEggStats(void);
+static void SaveEggStats(void);
+static void handle_sighup(int arg);
+
+EggEntry eggtable[MAX_EGGS];
+BasketEntry baskettable[MAX_BASKETS];
+EggHeader protocol;
+
+short numeggs, numbaskets;
+char *pgmname; /* Program name from argv[0] */
+char *myaddr; /* Interface to bind */
+int16 myport; /* Service port to bind */
+
+static int htmlInterval = 0; /* HTML status file update interval in seconds */
+static char htmlFile[256] = ""; /* HTML status file name */
+static uint32 upsince = 0; /* Basket start time */
+#define htmlReport (htmlFile[0] != 0) /* Make HTML report ? */
+
+struct {
+ uint32 firstPacket; /* Time of "first contact" with egg */
+ uint32 trials; /* Number of trials received */
+ uint32 missing; /* Number of missing samples */
+ double sum; /* Sum of trials to date */
+} eggStatistics[MAX_EGGS];
+
+/* updateHTML -- Update HTML status file if a decent interval
+ has passed since the last update. */
+
+static void updateHTML(void)
+{
+ if (htmlReport) {
+ int i;
+ static uint32 lastHtml = 0;
+ uint32 now = getzulutime(NULL);
+ char udate[256], ustime[256];
+ static char timeFormat[] = "%Y-%m-%d %T";
+
+ /* When first called, set the last HTML update interval to
+ the present moment. This defers generation of the first
+ HTML report until htmlInterval elapses. This prevents
+ issuing a potentially-misleading HTML report based on
+ incomplete information. */
+
+ if (lastHtml == 0) {
+ lastHtml = now;
+ }
+
+ if ((now - lastHtml) >= htmlInterval) {
+ FILE *hf;
+
+ lastHtml = now;
+ hf = fopen(htmlFile, "w");
+ if (hf == NULL) {
+ fprintf(stderr, "Cannot open HTML status file %s. Updates discarded.\n", htmlFile);
+ htmlFile[0] = 0; /* Suppress further updates */
+ return;
+ }
+
+ strftime(udate, sizeof udate, timeFormat, gmtime((time_t *) &now));
+ strftime(ustime, sizeof ustime, timeFormat, gmtime((time_t *) &upsince));
+
+ fprintf(hf, "\
+<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n\
+<html version=\"-//W3C//DTD HTML 3.2 Final//EN\">\n\
+<head>\n\
+<title>Basket %s Status Report</title>\n\
+<meta http-equiv=\"Refresh\" content=\"%d\">\n\
+</head>\n\
+<body>\n\
+<center>\n\
+<h1>Basket %s Status Report</h1>\n\
+<h3>Last update: %s UTC</h3>\n\
+<h4>Basket started at %s UTC<br>\n\
+%s</h4>\n\
+</center>\n\
+<center>\n\
+<h2>Egg Status</h2>\n\
+<table border cellpadding=4>\n\
+<tr><th>Name<th>Number<th>Up Since<th>Last Packet<th>Active\n\
+<th>Trials<th>Missed<th>Coverage<th>Mean\n\
+",
+ baskettable[0].name, htmlInterval, baskettable[0].name, udate, ustime, Version);
+
+ for (i = 0; i < numeggs; i++) {
+ char url1[256], url2[256];
+
+ if ((eggtable[i].lastupd == 0) || (eggStatistics[i].firstPacket == 0)) {
+ strcpy(udate, "<td colspan=2 align=center><em>Never contacted</em>");
+ strcpy(ustime, "");
+ } else {
+ strftime(udate, sizeof udate, "<td align=center>%Y-%m-%d %T", gmtime((time_t *) &eggtable[i].lastupd));
+ strftime(ustime, sizeof ustime, "<td align=center>%Y-%m-%d %T", gmtime((time_t *) &eggStatistics[i].firstPacket));
+ }
+ if (eggtable[i].url == NULL) {
+ url1[0] = url2[0] = 0;
+ } else {
+ sprintf(url1, "<a href=\"%s\">", eggtable[i].url);
+ strcpy(url2, "</a>");
+ }
+ fprintf(hf, "<tr><td>%s%s%s<td align=center>%d%s%s<td align=center>%s\n\
+",
+ url1,
+ eggtable[i].name,
+ url2,
+ eggtable[i].id,
+ ustime,
+ udate,
+ eggtable[i].setup ? "Yes" : "No"
+ );
+
+ if (eggStatistics[i].trials == 0) {
+ fprintf(hf, "<td align=center> <td align=center> <td align=center> <td align=center> \n");
+ } else {
+ uint32 coverage;
+
+ /* The following expression computes "coverage" for
+ the egg--the percentage of samples received
+ to the number prescribed by the protocol
+ for the time in which the egg has been in contact. */
+ coverage = (100L * eggStatistics[i].trials * protocol.samp_rec) /
+ (protocol.sec_rec * (now - eggStatistics[i].firstPacket));
+ if (coverage > 100) {
+ coverage = 100;
+ }
+
+ fprintf(hf, "<td align=center>%ld<td align=center>%ld<td align=center>%ld%%<td align=center>%.3f\n",
+ eggStatistics[i].trials,
+ eggStatistics[i].missing,
+ coverage,
+ eggStatistics[i].sum / eggStatistics[i].trials
+ );
+ }
+ }
+
+
+ fprintf(hf, "\
+</table>\n\
+</center>\n\
+<center>\n\
+<h4>Egg Status Table Fields</h4>\n\
+<table width=\"75%%\" cellpadding=3>\n\
+<tr><td valign=top><b>Name</b> <td>Egg name<p>\n\
+<tr><td valign=top><b>Number</b> <td>Egg number. Thousands digit indicates type of random event generator.<p>\n\
+<tr><td valign=top><b>Up Since</b> <td>Time and date in first packet received from egg since basket started.<p>\n\
+<tr><td valign=top><b>Last Packet</b> <td>Time and date of most recently received packet from egg.<p>\n\
+<tr><td valign=top><b>Active</b> <td>Has egg ever communicated with this basket since it was started?<p>\n\
+<tr><td valign=top><b>Trials</b> <td>Number of trials received from this egg.<p>\n\
+<tr><td valign=top><b>Missed</b> <td>Number of scheduled trials missed by egg due to synchronisation problems.<p>\n\
+<tr><td valign=top><b>Coverage</b> <td>Percent of trials collected from this egg since basket\n\
+ started compared to the number scheduled by the protocol.<p>\n\
+<tr><td valign=top><b>Mean</b> <td>Arithmetic mean of trials performed by this egg.\n\
+</table>\n\
+</center>\n\
+</body>\n\
+</html>\n");
+ fclose(hf);
+#ifdef DEBUG
+ fprintf(stderr, "Updating HTML file %s at %s",
+ htmlFile, asctime(gmtime((time_t *) &now)));
+#endif
+ }
+ }
+}
+
+static void Usage(void) {
+ printf("Usage: %s [-i interface] [-p port]\n", pgmname);
+ exit(-1);
+}
+
+/* Main program. */
+
+int main(int argc, char *argv[]) {
+ char *pktbuf;
+ uint16 pkttype, pktsize, pkt_eggid;
+ int sdlisten, res;
+ struct sockaddr_in rhost;
+ ReqPacket rpkt;
+ SettingsPacket spkt;
+ int i, isbasket, isegg, thisegg;
+ char *remname;
+#ifdef SIGACTION_WORKING
+ struct sigaction sigact;
+#endif
+#ifdef EGG_DYNAMIC
+ uint32 ipvalidate, ipmatch, ipmask;
+#endif
+
+ pgmname = argv[0];
+ argv++; argc--;
+
+ /* Defaults correspond to original usage */
+ myport = BASKETPORT;
+ myaddr = NULL;
+
+ while (argc) {
+ if (argv[0][0] == '-') {
+ switch(argv[0][1]) {
+ case 'i': /* Specify interface */
+ if (argc < 2) Usage();
+ myaddr = argv[1];
+ argv++; argc--;
+ break;
+ case 'p': /* Specify port */
+ if (argc < 2) Usage();
+ myport = atoi(argv[1]);
+ if (myport < 0) Usage();
+ argv++; argc--;
+ break;
+ default: /* Oops. */
+ Usage();
+ }
+ } else {
+ Usage();
+ }
+ argv++; argc--;
+ }
+
+ LoadRCFile();
+ LoadEggStats();
+
+#ifdef Solaris
+ /* Solaris has an eccentric definition of sigaction() which
+ doesn't seem to even work according to Sun's own
+ documentation. (sa_flags is a 4 element array of
+ unsigned longs, with no mention of how one stores the
+ flags into it.) Let's just use plain old signal for
+ the moment. */
+ signal(SIGHUP, handle_sighup);
+#else
+#ifdef SIGACTION_WORKING
+ sigact.sa_handler = handle_sighup;
+ sigact.sa_mask = 0;
+ sigact.sa_flags = 0;
+ sigact.sa_restorer = NULL;
+ sigaction(SIGHUP, &sigact, NULL);
+#else
+ signal(SIGHUP, handle_sighup);
+#endif
+#endif
+
+ /* No connection at outset */
+ sdlisten = -1;
+
+ /* Initialize storage system. */
+ InitStorage("%Y-%m/%Y-%m-%d-$b");
+
+ upsince = getzulutime(NULL);
+
+ fprintf(stderr, "Starting basket %s.\n", Version);
+
+ /* Inner loop is currently single thread:
+ 1A. Wait for connection. When a connection comes in,
+ packet has been decrypted and verified.
+ 1B. Validate connection.
+ 1C. Reply to connection. */
+ while (1) {
+ /* If no current listening connection, try to get one,
+ and if that fails, sleep and try later. */
+
+ if (sdlisten < 0) {
+ /* Get a listening socket at BASKETPORT.
+ Only allow our */
+ sdlisten = InitNetwork(myaddr, myport);
+ if (sdlisten < 0) {
+ sleep(1);
+ continue;
+ }
+ }
+
+ /* 1A. Wait for connection. */
+ res = NetListen(sdlisten, &pktbuf, &rhost, TRUE);
+ if (res < 0) {
+ fprintf(stderr, "NetListen error: %d\n", res);
+ continue;
+ }
+
+ /* 1B. Validate connection.
+ Remote host address is in rhost. Make sure this is either an
+ egg or a basket, and set the flag appropriately. */
+#ifdef EGG_DYNAMIC
+ ipvalidate = ntohl(rhost.sin_addr.s_addr);
+#endif
+
+ isegg = isbasket = 0;
+ for (i = 0; i < numeggs; i++) {
+#ifdef EGG_DYNAMIC
+ /* When mask == 32: ipmask = 0xFFFFFFFF (all significant)
+ mask == 16: ipmask = 0xFFFF0000 (only top half sig)
+ mask == 0: ipmask = 0x00000000 (none significant) */
+ ipmask = (0xFFFFFFFF << (32-eggtable[i].netmask));
+ ipmatch = ntohl(eggtable[i].ipaddr.sin_addr.s_addr);
+ if ((ipvalidate & ipmask) == (ipmatch & ipmask)) {
+ isegg = eggtable[i].id;
+ thisegg = i;
+ remname = eggtable[i].name;
+ }
+#else
+ if (!memcmp(&(rhost.sin_addr),
+ &(eggtable[i].ipaddr.sin_addr),
+ sizeof(rhost.sin_addr))) {
+ isegg = eggtable[i].id;
+ thisegg = i;
+ remname = eggtable[i].name;
+ }
+#endif
+ }
+ for (i = 0; i < numbaskets; i++) {
+ if (!memcmp(&(rhost.sin_addr),
+ &(baskettable[i].ipaddr.sin_addr),
+ sizeof(rhost.sin_addr))) {
+ isbasket = 1;
+ remname = baskettable[i].name;
+ }
+ }
+
+ if (!isegg && !isbasket) {
+ fprintf(stderr, "Attempt to connect from unknown source: %s\n",
+ sockaddr2dquad(&rhost));
+ continue;
+ }
+
+ memcpy(&pkttype, pktbuf, sizeof(uint16));
+ memcpy(&pktsize, pktbuf+sizeof(uint16), sizeof(uint16));
+ pkttype = ntohs(pkttype);
+ pktsize = ntohs(pktsize);
+ if (pktsize < 6) {
+ fprintf(stderr, "Packet doesn't contain an egg id, why?\n");
+ continue;
+ }
+ pkt_eggid = ntohs(*((uint16 *) (pktbuf + 4)));
+
+ /* Am I hearing from who I think I am? */
+#if EGG_DYNAMIC
+ /* Have to assume the best case before testing: that the
+ pkt_eggid is actually correct. */
+ for (i = 0; i < numeggs; i++) if (eggtable[i].id == pkt_eggid) break;
+
+ if (i == numeggs) {
+ /* Must be a spoof, and possibly an attempt to crash software too. */
+ fprintf(stderr, "%s: Egg spoofing? %s reporting itself as %d\n",
+ pgmname, hl2dquad(ipvalidate), pkt_eggid);
+ continue;
+ }
+
+ ipmask = (0xFFFFFFFF << (32-eggtable[i].netmask));
+ ipmatch = ntohl(eggtable[i].ipaddr.sin_addr.s_addr);
+ if ((ipvalidate & ipmask) != (ipmatch & ipmask)) {
+ fprintf(stderr, "%s: Egg spoofing? %s reporting itself as %d\n",
+ pgmname, hl2dquad(ipvalidate), pkt_eggid);
+ continue;
+ } else {
+ isegg = eggtable[i].id;
+ thisegg = i;
+ remname = eggtable[i].name;
+ }
+#else
+ if (isegg != pkt_eggid) {
+ fprintf(stderr, "%s: Egg spoofing? %d reporting itself as %d\n",
+ pgmname, isegg, pkt_eggid);
+ continue;
+ }
+#endif
+
+ /* 1D. Reply to connection. */
+ switch(pkttype) {
+ case DATA_PACKET:
+ /* Put it away. */
+ BasketReceiveDataPacket(pktbuf, isegg, thisegg, &rhost);
+
+ break;
+ case REQ_PACKET:
+ /* Is this how baskets communicate? */
+ break;
+ case AWAKE_PACKET:
+#ifdef PACKETDUMP
+ {
+ uint32 egg_now_time;
+
+ memcpy(&egg_now_time, pktbuf + 6, sizeof egg_now_time);
+ egg_now_time = ntohl(egg_now_time);
+ fprintf(stderr, "Awake egg %d (%s) at its %lu: %s",
+ pkt_eggid, eggtable[thisegg].name, egg_now_time,
+ asctime(gmtime((time_t *) &egg_now_time)));
+ }
+#endif
+
+ /* Calculate last data received from this egg, decide what
+ to ask for. */
+ MakeRequest(&rpkt, isegg, eggtable[thisegg].lastupd);
+ rhost.sin_port = htons(EGGPORT);
+ res = NetTalk(&rhost, (char *)&rpkt, TRUE);
+ if (res < 0) fprintf(stderr, "NetTalk error %d.\n", res);
+
+ /* If setup looks like it's out of date, correct it. */
+ if (!eggtable[thisegg].setup) {
+ MakeSettings(&spkt, thisegg);
+ rhost.sin_port = htons(EGGPORT);
+ res = NetTalk(&rhost, (char *)&spkt, TRUE);
+ if (res < 0) fprintf(stderr, "NetTalk error %d.\n", res);
+ }
+ break;
+
+ case SETTINGS_PACKET:
+ /* I don't have settings, Bozo. */
+ break;
+ }
+ free(pktbuf);
+ }
+}
+
+/* handle_sighup -- Catch SIGHUP and reload configuraton files. */
+
+static void handle_sighup(int arg) {
+ /* Reread the RC file */
+ LoadRCFile();
+ LoadEggStats();
+#ifdef DEBUG
+ fprintf(stderr, "Received SIGHUP: reloading configuration files.\n");
+#endif
+#ifndef SIGACTION_WORKING
+ signal(SIGHUP, handle_sighup); /* Reset signal handler for bottom-feeder signal() */
+#endif
+}
+
+/* LoadRCFile -- Load basket configuration file. */
+
+static void LoadRCFile(void) {
+ FILE *fp;
+ char linebuf[200];
+ char *myargv[MAX_PARSE], *tp;
+ int myargc, lcount, p, i;
+
+ if ((fp = fopen(".basketrc", "r")) == NULL) {
+ if ((fp = fopen("~/.basketrc", "r")) == NULL) {
+ if ((fp = fopen("/etc/basketrc", "r")) == NULL) {
+ fprintf(stderr, "%s: Couldn't find a basket RC file.\n", pgmname);
+ exit(-1);
+ }
+ }
+ }
+
+ numeggs = numbaskets = 0;
+ lcount = 0;
+
+ while(fgets(linebuf, 200, fp) != NULL) {
+ /* Comments and blank lines ignored. */
+ lcount++;
+ if (*linebuf == '#' || *linebuf == '\n') continue;
+ Parse(linebuf, &myargc, myargv);
+ if (myargc == 0) continue;
+ if (!strcmp(myargv[0], "EGG")) {
+ if (myargc < 7 || myargc > 8) {
+ fprintf(stderr, "%s: RC error, line %d, poor %s format\n",
+ pgmname, lcount, myargv[0]);
+ exit(-1);
+ }
+
+ eggtable[numeggs].name = mallocpy(myargv[1]);
+ eggtable[numeggs].id = atoi(myargv[2]);
+ dquad2sockaddr(&(eggtable[numeggs].ipaddr),
+ &(eggtable[numeggs].netmask),
+ myargv[3]);
+ eggtable[numeggs].primbasket = mallocpy(myargv[4]);
+ eggtable[numeggs].conntype = (!strcmp(myargv[5], "PERM"))?CONN_PERM:CONN_DND;
+ eggtable[numeggs].connival = atoi(myargv[6]);
+ eggtable[numeggs].url = NULL;
+ if ((myargc > 7) && (strcmp(myargv[7], ".") != 0)) {
+ eggtable[numeggs].url = mallocpy(myargv[7]);
+ }
+ numeggs++;
+ } else if (!strcmp(myargv[0], "BASKET")) {
+ if (myargc != 3) {
+ fprintf(stderr, "%s: RC error, line %d, poor %s format\n",
+ pgmname, lcount, myargv[0]);
+ exit(-1);
+ }
+ baskettable[numbaskets].name = mallocpy(myargv[1]);
+ dquad2sockaddr(&(baskettable[numbaskets].ipaddr), NULL, myargv[2]);
+ numbaskets++;
+ } else if (!strcmp(myargv[0], "PROTOCOL")) {
+ if (myargc != 5) {
+ fprintf(stderr, "%s: RC error, line %d, poor %s format\n",
+ pgmname, lcount, myargv[0]);
+ exit(-1);
+ }
+ protocol.samp_rec = atoi(myargv[1]);
+ protocol.sec_rec = atoi(myargv[2]);
+ protocol.rec_pkt = atoi(myargv[3]);
+ protocol.trialsz = atoi(myargv[4]);
+ } else if (!strcmp(myargv[0], "HTML")) {
+ if (myargc != 3) {
+ fprintf(stderr, "%s: RC error, line %d, poor %s format\n",
+ pgmname, lcount, myargv[0]);
+ exit(-1);
+ }
+ htmlInterval = atoi(myargv[1]);
+ strcpy(htmlFile, myargv[2]);
+#ifdef DEBUG
+ fprintf(stderr, "Updating HTML file %s every %d seconds.\n", htmlFile, htmlInterval);
+#endif
+ } else if (!strcmp(myargv[0], "PORT") ||
+ !strcmp(myargv[0], "INTERFACE")) {
+ if (myargc != 2) {
+ fprintf(stderr, "%s: RC error, line %d, poor %s format\n",
+ pgmname, lcount, myargv[0]);
+ exit(-1);
+ }
+ tp = (char *) malloc(200);
+ for (*tp = 0, p = 1; p < myargc; p++) {
+ strcat(tp, myargv[p]);
+ if (p < myargc-1) strcat(tp, " ");
+ }
+
+ if (!strcmp(myargv[0], "PORT")) {
+ if (atoi(tp) <= 0) {
+ fprintf(stderr, "%s: RC error, ignoring bad port %d, using %d\n",
+ pgmname, atoi(tp), myport);
+ } else {
+ myport = atoi(tp);
+ }
+ free(tp);
+ } else if (!strcmp(myargv[0], "INTERFACE")) myaddr = tp;
+ } else {
+ fprintf(stderr, "%s: RC error, %s is unknown keyword\n", pgmname, myargv[0]);
+ exit(-1);
+ }
+ }
+ fclose(fp);
+
+#if REPORT > 0
+ /* Report a list of the eggs that we are accepting. */
+ for (i = 0; i < numeggs; i++) {
+ fprintf(stderr, "Egg %2d:\tid = %4d\tip=%s/%d\n",
+ i, eggtable[i].id,
+ sockaddr2dquad(&(eggtable[i].ipaddr)),
+ eggtable[i].netmask);
+ }
+#endif
+}
+
+/* BasketReceiveDataPacket -- Process a data packet received frm an egg. */
+
+static int32 BasketReceiveDataPacket(char *pkt, int16 isegg, int16 thisegg,
+ struct sockaddr_in *rhost) {
+ EggHeader *dpktp;
+ EggCarton result;
+ ReqPacket rpkt;
+ uint16 offset, rec;
+ uint32 latest;
+ int32 res;
+#ifdef DEBUG
+ uint16 i;
+#endif
+
+ EggHeader dpk;
+ char *pktP = pkt;
+
+ /* Unpack the portable header into a host-order and aligned
+ EggHeader packet. */
+
+ dpktp = &dpk;
+ unpackShort(dpk.type);
+ unpackShort(dpk.pktsize);
+ unpackShort(dpk.eggid);
+ unpackShort(dpk.samp_rec);
+ unpackShort(dpk.sec_rec);
+ unpackShort(dpk.rec_pkt);
+ unpackByte(dpk.trialsz);
+ unpackShort(dpk.numrec);
+
+ /* This spoofing test is probably completely redundant now. */
+#ifndef EGG_DYNAMIC
+ /* Am I hearing from an egg, and is it who I think it is? */
+ if (isegg && isegg != dpktp->eggid) {
+ fprintf(stderr, "%s: Egg spoofing? %d reporting itself as %d\n",
+ pgmname, isegg, dpktp->eggid);
+ return -1;
+ }
+#endif
+
+ /* Save the packet header in the result EggCarton buffer. */
+
+ memcpy(&(result.hdr), dpktp, sizeof(EggHeader));
+ offset = sizeof(EggHeader);
+
+#ifdef DEBUG
+ {
+ uint32 stamp = 0;
+ char *spktp = pktP;
+
+ if (result.hdr.numrec > 0) {
+ unpackLong(stamp);
+ }
+ pktP = spktp;
+ fprintf(stderr, "Received packet: %d records from egg %d (%s).\n",
+ result.hdr.numrec, dpktp->eggid, eggtable[thisegg].name);
+ }
+#endif
+
+ /* Unpack the individual data records from the packet and
+ transcribe to the result EggCarton. */
+
+ for (latest = 0, rec = 0; rec < result.hdr.numrec; rec++) {
+ unpackLong(result.records[rec].timestamp); /* Record timestamp */
+ if (result.records[rec].timestamp > latest)
+ latest = result.records[rec].timestamp;
+#ifdef DEBUG
+ fprintf(stderr, " %10lu ", result.records[rec].timestamp);
+#endif
+ /* Assumes sizeof(trial) = 1 */
+ unpackBytes(&(result.records[rec].trials), result.hdr.samp_rec);
+#ifdef DEBUG
+ for (i = 0; i < result.hdr.samp_rec; i++) {
+ fprintf(stderr, "%3d ", result.records[rec].trials[i]);
+ }
+ fprintf(stderr, "%s", asctime(gmtime((time_t *) &result.records[rec].timestamp)));
+#endif
+ }
+
+ /* Save the packet in the basket database file. */
+
+ if ((res = SavePacket(&result)) < 0) return res;
+
+ /* If we're generating an HTML report, update the per-basket
+ statistics based on the content of this packet. */
+
+ if (htmlReport) {
+ int r, t;
+ uint32 ptrials = 0, psum = 0, dropped = 0;
+
+ /* Update the egg status for HTML report. */
+
+ for (r = 0; r < result.hdr.rec_pkt; r++) {
+ for (t = 0; t < result.hdr.samp_rec; t++) {
+ if (result.records[r].trials[t] != EGG_MISSING_DATA) {
+ ptrials++;
+ psum += result.records[r].trials[t];
+ } else {
+ dropped++;
+ }
+ }
+ }
+ eggStatistics[thisegg].trials += ptrials;
+ eggStatistics[thisegg].sum += psum;
+
+ /* If this is the first packet received from the egg, and
+ the first sample in it is missing, don't count missing
+ samples against this egg, since it's probable this is
+ the first packet collected since the egg started, which
+ will contain initial missing samples for time before the
+ egg started. */
+
+ if (eggStatistics[thisegg].firstPacket != 0) {
+ eggStatistics[thisegg].missing += dropped;
+ } else {
+ eggStatistics[thisegg].firstPacket = result.records[0].timestamp;
+ }
+ }
+
+ if (latest > eggtable[thisegg].lastupd) {
+ eggtable[thisegg].lastupd = latest;
+ SaveEggStats();
+ updateHTML(); /* Update HTML status file, if warranted */
+ if (latest < getzulutime(NULL)) {
+ /* Get more data if it looks like there should be more. */
+ MakeRequest(&rpkt, isegg, eggtable[thisegg].lastupd);
+ rhost->sin_port = htons(EGGPORT);
+ res = NetTalk(rhost, (char *)&rpkt, TRUE);
+ if (res < 0) fprintf(stderr, "NetTalk error %d.\n", (int)res);
+ }
+ }
+
+ /* If the protocol now in effect differs from that of the
+ packet just received from the egg, mark the egg as not
+ set-up, and thus in need of a SETTINGS_PACKET to reset
+ its protocol. */
+
+ eggtable[thisegg].setup = (protocol.samp_rec == dpktp->samp_rec &&
+ protocol.sec_rec == dpktp->sec_rec &&
+ protocol.rec_pkt == dpktp->rec_pkt &&
+ protocol.trialsz == dpktp->trialsz);
+
+ return ERR_NONE;
+}
+
+/* MakeRequest -- Assemble a request packet for a given egg,
+ specifying, in whence, the time and date
+ of the last sample received from that egg. */
+
+static void MakeRequest(ReqPacket *pkt, uint16 eggid, uint32 whence) {
+ char *pktP = (char *) pkt;
+
+ packShort(REQ_PACKET);
+ packShort((4 * sizeof(uint16)) + sizeof(uint32));
+ packShort(eggid);
+ packLong(whence);
+}
+
+/* MakeSettings -- Create a settings packet. This packet,
+ sent periodically to connected eggs,
+ informs them of any change in protocol. */
+
+static void MakeSettings(SettingsPacket *pkt, uint16 eggid) {
+ char *pktP = (char *) pkt;
+
+ packShort(SETTINGS_PACKET);
+ packShort((7 * sizeof(uint16)) + sizeof(uint32) + sizeof(trial));
+ packShort(eggid);
+ packLong(getzulutime(NULL));
+ packShort(protocol.samp_rec);
+ packShort(protocol.sec_rec);
+ packShort(protocol.rec_pkt);
+ packByte(protocol.trialsz);
+}
+
+/* LoadEggStats -- Initialise in-memory egg status table
+ from the EGGSTATS file. */
+
+static void LoadEggStats(void) {
+ FILE *fp;
+ char linebuf[200], *myargv[MAX_PARSE], *name;
+ int i, f, myargc, id, setup;
+ int32 lastupd;
+
+ /* Default stats */
+ for (i = 0; i < numeggs; i++) {
+ eggtable[i].lastupd = 0;
+ eggtable[i].setup = 0;
+ }
+
+ if ((fp = fopen(EGGSTATS, "r")) == NULL) return;
+
+ while(fgets(linebuf, 200, fp) != NULL) {
+ /* Comments and blank lines ignored. */
+ if (*linebuf == '#' || *linebuf == '\n') continue;
+ Parse(linebuf, &myargc, myargv);
+ if (myargc == 0) continue;
+ if (!strcmp(myargv[0], "STAT") && myargc == 5) {
+ name = myargv[1];
+ id = atoi(myargv[2]);
+ lastupd = atol(myargv[3]);
+ setup = atoi(myargv[4]);
+ for (f = 0, i = 0; i < numeggs; i++) {
+ if (eggtable[i].id == id &&
+ !strcmp(eggtable[i].name, name)) {
+ eggtable[i].lastupd = lastupd;
+ eggtable[i].setup = setup;
+ f = 1;
+ }
+ }
+ if (!f) fprintf(stderr, "%s: Egg '%s' no longer hosted.\n", pgmname, name);
+ }
+ }
+ fclose(fp);
+}
+
+/* SaveEggStats -- Dump in-memory egg status to the EGGSTATS file. */
+
+static void SaveEggStats(void) {
+ FILE *fp;
+ int i;
+
+ if ((fp = fopen(EGGSTATS, "w")) == NULL) {
+ /* Couldn't write stats! */
+ fprintf(stderr, "%s: Couldn't save egg stats!\n", pgmname);
+ return;
+ }
+
+ fprintf(fp, "# Status lines of form:\n");
+ fprintf(fp, "# STAT <eggname> <eggid> <lastupdzulu> <setupvalid>\n");
+ for (i = 0; i < numeggs; i++) {
+ fprintf(fp, "STAT %s %d %ld %d\n",
+ eggtable[i].name,
+ eggtable[i].id,
+ eggtable[i].lastupd,
+ eggtable[i].setup);
+ }
+ fclose(fp);
+}
--- /dev/null
+#BASKET diesse 193.8.230.134
+#BASKET jura 193.8.230.130
+BASKET noosphere 128.112.35.133
+EGG diesse 37 193.8.230.134 diesse PERM 1 http://www.fourmilab.ch/
+EGG noosphere 28 128.112.35.133 noosphere PERM 1 http://noosphere.princeton.edu/
+EGG throop 1003 193.8.230.132 throop PERM 1
+EGG jura 1004 193.8.230.130 jura PERM 1
+EGG dicklnx.psy.uva.nl 1000 145.18.117.41 diesse PERM 1 http://www.psy.uva.nl/bierman
+PROTOCOL 10 10 6 200
+HTML 60 /ftp/entrenous/k/basket.html
--- /dev/null
+/*
+
+ Byte-order invariant definitions
+
+*/
+
+/* The following macros allow packing fields of various types
+ into a byte-oriented packet with a running pointer named
+ pktP. The reason we store then memcpy rather than storing
+ through a cast of pktP to the desired type is that the
+ latter approach can result in alignment faults when run
+ on RISC machines which typically require values to be
+ aligned at an even multiple of their length. */
+
+#define packShort(x) { \
+ short s = htons((short) (x)); \
+ memcpy(pktP, &s, sizeof(short)); \
+ pktP += sizeof(short); \
+ }
+
+#define packLong(x) { \
+ long l = htonl((long) (x)); \
+ memcpy(pktP, &l, sizeof(long)); \
+ pktP += sizeof(long); \
+ }
+
+#define packByte(x) { \
+ char c = (x); \
+ memcpy(pktP, &c, sizeof(char)); \
+ pktP += sizeof(char); \
+ }
+
+#define packBytes(x, n) { \
+ memcpy(pktP, x, n); \
+ pktP += n; \
+ }
+
+/* These macros unpack fields of various lengths from a
+ byte-packet packet in network byte order pointed to by
+ pktP. Note that the argument of these macros must be
+ an lvalue. */
+
+#define unpackShort(x) { \
+ short s; \
+ memcpy(&s, pktP, sizeof(short)); \
+ pktP += sizeof(short); \
+ x = ntohs(s); \
+ }
+
+#define unpackLong(x) { \
+ long l; \
+ memcpy(&l, pktP, sizeof(long)); \
+ pktP += sizeof(long); \
+ x = ntohl(l); \
+ }
+
+#define unpackByte(x) { \
+ *((char *) &x) = (char) *pktP++; \
+ }
+
+#define unpackBytes(x, n) { \
+ memcpy(x, pktP, n); \
+ pktP += n; \
+ }
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/crc16.c,v 1.1 1998/07/21 11:42:15 ghn Exp $
+ * PURPOSE: Functions to calculate CRC checksum
+ * AUTHOR: Greg Nelson
+ * DATE: 98-04-12
+ *
+ * REVISED: $Log: crc16.c,v $
+ * REVISED: Revision 1.1 1998/07/21 11:42:15 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+#include "global.h"
+
+/* Calculate 16 bit CRC checksum on specified block */
+
+#define TBLSIZE 256
+#define CRC16_POLY 0xA001
+#define CRC16_INIT 0
+
+uint16 CRC16Table[TBLSIZE] = {
+ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
+ 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
+ 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
+ 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
+ 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
+ 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
+ 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+ 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
+ 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
+ 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
+ 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
+ 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
+ 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
+ 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+ 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
+ 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
+ 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
+ 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
+ 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
+ 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
+ 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+ 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
+ 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
+ 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
+ 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
+ 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
+ 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
+ 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+ 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
+ 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
+ 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
+ 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040};
+
+uint16 BlockCRC16(byte *block, uint32 len) {
+ uint16 crc;
+ uint32 i, indx;
+
+ crc = CRC16_INIT;
+ for (i = 0; i < len; i++) {
+ indx = (uint8)(*block++ ^ crc);
+ crc >>= 8;
+ crc ^= CRC16Table[indx];
+ }
+ return crc;
+}
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/egg.c,v 1.8 1999/02/28 20:01:43 ghn Exp $
+ * PURPOSE: EGG site data collection
+ * AUTHOR: Greg Nelson
+ * DATE: 98-06-20
+ *
+ * REVISED:
+ * $Log: egg.c,v $
+ * Revision 1.8 1999/02/28 20:01:43 ghn
+ * Version 5.1: Added command line parsing for interface/port configuration.
+ * Changed default interface to 0.0.0.0, so that egg will normally bind to
+ * all incoming interfaces. Reports interface/port it is using, right before
+ * the screen gets cleared and you can't see it.
+ *
+ * Revision 1.7 1999/01/01 23:57:20 ghn
+ * Remove excess code associated with CPU-bound version and "OLDWAY" UI
+ * and egg HW selection. Add back in updated block algorithm description.
+ * Allow non-CPU-bound version to exchange more than 1 packet per second.
+ * Get rid of warnings when network is not reachable, assuming this is a
+ * transient error.
+ *
+ * Revision 1.6 1998/12/31 22:07:56 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.5 1998/08/03 20:35:55 kelvin
+ * PACKETDUMP support.
+ *
+ * Revision 1.4 1998/08/01 21:34:26 ghn
+ * Connected user interface and added PSEUDO suppor into main line.
+ *
+ * Revision 1.3 1998/08/01 18:51:25 ghn
+ * Added John's byte-order-independence changes.
+ *
+ * Revision 1.2 1998/08/01 17:04:26 ghn
+ * Lots of fixes from John, plus DND support.
+ *
+ * Revision 1.1 1998/07/21 11:41:35 ghn
+ * Initial revision
+ *
+ * Copyright 1998 - Greg Nelson
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include "global.h"
+#include "genlib.h"
+#include "storage.h"
+#include "network.h"
+#include "eggui.h"
+#include "errnos.h"
+#include "regs.h"
+#include "regtable.h"
+#include "version.h"
+
+/* Good old Linux doesn't define the following functions
+ by default in the #include files the manual page claims
+ it does, and the conditional declarations with __USE_xx
+ doesn't work. Explicitly declare them, which doesn't
+ seem to do any harm on systems where these functions are
+ properly declared. If you get errors on the following
+ declarations, you can probably get around them by #ifdef-ing
+ the declarations off for your platform. */
+
+extern int nice(int inc);
+extern int strcasecmp(const char *s1, const char *s2);
+
+/* Prototypes for forward functions. */
+
+static void MakeAwake(AwakePacket *pkt);
+static void MakeDataPkt(char **pkt, EggCarton *src);
+static void LoadRCFile(char *filename);
+static double SetCollOpts(void);
+static int GreetBasket(void);
+static void handle_sigkill(int arg), handle_sighup(int arg);
+
+EggEntry eggtable[MAX_EGGS];
+BasketEntry baskettable[MAX_BASKETS];
+EggHeader protocol;
+REG_driver *configuredREG = NULL; /* Configured REG driver */
+
+short numeggs = 0, numbaskets = 0;
+
+static DevOpts devopts; /* Device options for REG */
+static CollectRecord coll;
+static EggCarton savebuffer;
+char *pgmname; /* Program name from argv[0] */
+char *myaddr; /* Interface to bind */
+int16 myport; /* Service port to bind */
+int32 lastDataSent = 0; /* Time last packet sent to basket */
+
+/* If no priority increment has been specified at compile time, set to
+ our default of ±10. [+/- 10, for folks without 8bit editors] */
+
+#ifndef NICE
+#define NICE 10
+#endif
+static int niceness = NICE; /* Priority increment/decrement for collection */
+
+/* Status exported to user interface. */
+
+int32 time_latency = 0, time_housekeeping = 0;
+
+#ifdef ALT_UI
+static double mean_Packet = 0.0, mean_Grand = 0.0;
+static int32 total_Packets = 0;
+#endif
+
+/* resetCarton -- Clear existing data from savebuffer and
+ reinitialise for a sampling interval
+ beginning at the specified start_time. */
+
+static void resetCarton(uint32 start_time)
+{
+ int i;
+ uint32 sec_pkt;
+
+ /* Save current collection options to packet. */
+
+ memcpy(&(savebuffer.hdr), &(coll.opts), sizeof(EggHeader));
+
+ /* Set number of records in packet and clear record
+ buffers to missing data. */
+
+ savebuffer.hdr.numrec = savebuffer.hdr.rec_pkt; /* Mark all records present */
+
+ /* Align start_time to even multiple of seconds per
+ packet. */
+
+ sec_pkt = savebuffer.hdr.sec_rec * savebuffer.hdr.rec_pkt;
+ start_time = sec_pkt * (start_time / sec_pkt);
+
+ for (i = 0; i < savebuffer.hdr.rec_pkt; i++) {
+ savebuffer.records[i].timestamp = start_time;
+ start_time += savebuffer.hdr.sec_rec;
+#if MAXBITS < 256
+ memset(savebuffer.records[i].trials, EGG_MISSING_DATA, MAXSAMP_REC);
+#else
+#error "Can't represent MAXBITS in a byte value."
+#endif
+ }
+}
+
+/* saveProtocol -- Save current protocol in the .eggprotocolrc file. */
+
+static void saveProtocol(void)
+{
+ FILE *rcfile;
+
+ rcfile = fopen(".eggprotocolrc", "w");
+ if (rcfile == NULL) {
+ fprintf(stderr, "%s: Cannot create .eggprotocolrc file.\n", pgmname);
+ exit(-1);
+ }
+ fprintf(rcfile, "#\n# Current protocol for egg\n#\n");
+ fprintf(rcfile, "# PROTOCOL <samp_rec> <sec_rec> <rec_pkt> <trialsz>\n");
+ fprintf(rcfile, "PROTOCOL %d %d %d %d\n", protocol.samp_rec, protocol.sec_rec,
+ protocol.rec_pkt, protocol.trialsz);
+ fclose(rcfile);
+}
+
+static void Usage(void) {
+ printf("Usage: %s [-i interface] [-p port]\n", pgmname);
+ exit(-1);
+}
+
+/* Main program. */
+
+int main(int argc, char *argv[]) {
+ char *pktbuf, *outpktbuf;
+ uint16 pkttype, pktsize;
+ int sdlisten, res;
+ struct sockaddr_in rhost;
+ EggCarton retrcart;
+ int i, isbasket;
+ char *remname;
+ int32 lastconn, lastsend;
+ double sps;
+#ifdef SIGACTION_WORKING
+ struct sigaction sigact;
+#endif
+ FILE *pidfile, *rcfile;
+
+ pgmname = argv[0];
+ argv++; argc--;
+
+ /* Defaults correspond to original usage */
+ myport = EGGPORT;
+ myaddr = "0.0.0.0";
+
+ while (argc) {
+ if (argv[0][0] == '-') {
+ switch(argv[0][1]) {
+ case 'i': /* Specify interface */
+ if (argc < 2) Usage();
+ myaddr = argv[1];
+ argv++; argc--;
+ break;
+ case 'p': /* Specify port */
+ if (argc < 2) Usage();
+ myport = atoi(argv[1]);
+ if (myport < 0) Usage();
+ argv++; argc--;
+ break;
+ default: /* Oops. */
+ Usage();
+ }
+ } else {
+ Usage();
+ }
+ argv++; argc--;
+ }
+
+#ifdef Solaris
+ /* Solaris has an eccentric definition of sigaction() which
+ doesn't seem to even work according to Sun's own
+ documentation. (sa_flags is a 4 element array of
+ unsigned longs, with no mention of how one stores the
+ flags into it.) Let's just use plain old signal for
+ the moment. */
+ signal(SIGKILL, handle_sigkill);
+ signal(SIGHUP, handle_sighup);
+#else
+#ifdef SIGACTION_WORKING
+ sigact.sa_handler = handle_sigkill;
+ sigact.sa_mask = 0;
+ sigact.sa_flags = 0;
+ sigact.sa_restorer = NULL;
+ sigaction(SIGKILL, &sigact, NULL);
+
+ sigact.sa_handler = handle_sighup;
+ sigaction(SIGHUP, &sigact, NULL);
+#else
+ signal(SIGKILL, handle_sigkill);
+ signal(SIGHUP, handle_sighup);
+#endif
+#endif
+
+ fprintf(stderr, "Starting egg %s.\n", Version);
+
+ /* Save our process ID in a file for folks who might wish
+ to send us a signal. */
+
+ pidfile = fopen("eggsample.pid", "w");
+ if (pidfile == NULL) {
+ fprintf(stderr, "Unable to create eggsample.pid file.\n");
+ exit(-1);
+ }
+ fprintf(pidfile, "%d\n", getpid());
+ fclose(pidfile);
+
+ /* If we aren't being run by the super-user, disable the
+ priority raising and lowering mechanism. */
+
+ if (getuid() != 0) {
+ niceness = 0;
+ }
+
+#ifdef DEBUG
+ printf("User ID = %d. Niceness = %d.\n", getuid(), niceness);
+ printf("REG drivers installed: ");
+ for (i = 0; reg_table[i] != NULL; i++) {
+ printf(" %s", reg_table[i]->reg_name);
+ }
+ printf("\n");
+#endif
+
+ LoadRCFile(NULL);
+
+ /* If an auxiliary configuration file exists, load it on
+ top of the arguments loaded from the main RC file. If
+ it doesn't exist, create it. */
+
+ if ((rcfile = fopen(".eggprotocolrc", "r")) != NULL) {
+ fclose(rcfile);
+ LoadRCFile(".eggprotocolrc");
+ } else {
+ saveProtocol();
+ }
+
+ if (configuredREG == NULL) {
+ fprintf(stderr, "%s: RC error, no REG specified for egg.\n",
+ pgmname);
+ exit(-1);
+ }
+#ifdef DEBUG
+ else {
+ printf("REG configured: %s = %d, %d, %ld\n", configuredREG ->reg_name,
+ devopts.type, devopts.port, devopts.baud);
+ }
+#endif
+
+
+ sps = SetCollOpts();
+
+ if ((coll.dd = OpenDev(&devopts)) < 0) {
+ fprintf(stderr, "Couldn't talk to hardware device.\n");
+ exit(1);
+ }
+
+ if (EvalSpeed(coll.dd) < coll.opts.trialsz * sps) {
+ fprintf(stderr, "Requested speed exceeds device capabilities.\n");
+ exit(-1);
+ }
+
+#if REPORT > 0
+ if (myaddr) {
+ fprintf(stderr, "TCP configured: %s.%d\n", myaddr, myport);
+ } else {
+ fprintf(stderr, "TCP configured: hostname.%d\n", myport);
+ }
+#endif
+
+ UIInit();
+
+ sdlisten = -1; /* No conn yet. */
+ lastconn = lastsend = 0;
+
+ /* Initialise carton to zero time, indicating no data in
+ initial carton. */
+ resetCarton(0);
+
+ /* Initialize storage system */
+ InitStorage("%Y-%m/%Y-%m-%d-$06E");
+
+ /* Inner loop is currently two threads which are both processed
+ together through NBIO.
+
+ 2A. Adjust priority and sleep until time computed below (2H).
+ 2B. Busy wait until second ticks over.
+ 2C. Empty REG input buffer (if needed), then collect sample.
+ 2D. Lower priority to handle bookkeeping; save packet.
+ 2E. Update user interface.
+
+ 2F. Send awake packet if connival is passed.
+ 2G. [DND only] Put net to sleep if we've been waiting more than a minute
+
+ 1A. Wait for connection. When a connection comes in,
+ packet has been decrypted and verified.
+ 1B. Validate connection.
+ 1C. Reply to connection.
+ 1D. If we have more than MINSLEEP time left in second,
+ go back to 1A.
+
+ 2H. Compute new sleep time.
+ */
+
+ while (1) {
+ static int sleeptime = 0;
+ static struct timeval t, lt = {0, 0};
+ struct timeval ct;
+ trial sample;
+ int havedata;
+ uint32 rindex;
+#ifdef DEBUG
+ uint32 msec, usec;
+#endif
+
+#ifndef SLACK
+#define SLACK 50000 /* CPU loop resynchronisation time in microseconds */
+#endif
+
+#ifndef MINSLEEP
+#define MINSLEEP 100000 /* Minimum sleep time, usec */
+#endif
+
+ /* 2A. If we have successfully computed a sleep time until
+ the window opens to collect the next sample, give up
+ the CPU until that time arrives. */
+
+ if (niceness != 0) {
+ nice(-niceness); /* Raise priority for re-dispatch */
+ }
+ if (sleeptime > 0) {
+ Usleep((unsigned) sleeptime);
+ }
+
+ /* 2B. We're now close to the start of the next second. Watch the
+ time until the second changes, then collect the next sample.
+ Note that this method of doing things enforces the one
+ sample/second that has become standard practise. The code at
+ the bottom of the loop could be changed to allow for a longer
+ interval, but this code enforces a minimum of a 1-second change
+ for each sample. */
+
+ while (1) {
+ gettimeofday(&t, NULL);
+ if (lt.tv_sec == 0) lt.tv_sec = t.tv_sec;
+ if (t.tv_sec != lt.tv_sec) break;
+ }
+
+ /* 2C. It is now time to collect the next sample. Discard any
+ any data in the input queue and get the sample. */
+
+ Discard(coll.dd);
+ sample = Sample(coll.dd, coll.opts.trialsz);
+ if (niceness != 0) {
+ nice(niceness); /* Collection done. Lower priority to normal. */
+ }
+
+ /* 2D. Okay, we're now in "quality time"--the slack after collection
+ of a sample until the time for the next sample arrives.
+ Now is an excellent time to do all kinds of housekeeping.
+ First of all, see if the sample just collected fits into
+ the packet currently being assembled. If not, we need to
+ save the last packet in the egg data file and initialise
+ a new packet for the time period in which this sample was
+ collected. */
+
+ if ((savebuffer.records[0].timestamp == 0) ||
+ ((savebuffer.records[0].timestamp +
+ (savebuffer.hdr.sec_rec * savebuffer.hdr.rec_pkt)) <= t.tv_sec)) {
+
+ if (savebuffer.records[0].timestamp != 0) {
+ static int firstpacket = 1;
+#ifdef ALT_UI
+ int r, t;
+ uint32 ptrials = 0, psum = 0;
+ static uint32 totalTrials = 0;
+ static double totalGrand = 0.0;
+#endif
+
+ /* Sample isn't within current packet. Dump packet to the egg
+ data file and reinitialise to the window containing the
+ sample we just collected. But first, a little gimmick. If
+ this is the first packet we've collected and it contains
+ one or more missing samples at the beginning, discard it.
+ This keeps the routine missing samples in the first packet
+ after the egg starts up from being reported as missing
+ samples due to genuine synchronisation errors. */
+
+ if (!(firstpacket && (savebuffer.records[0].trials[0] == EGG_MISSING_DATA))) {
+ SavePacket(&savebuffer);
+ }
+#ifdef DEBUG
+ else {
+ fprintf(stderr, "Dropping first packet to discard start-up missing samples.\n");
+ }
+#endif
+ firstpacket = 0;
+
+#ifdef ALT_UI
+ /* Update the last packet and grand mean data for the debug
+ interface status display. */
+
+ for (r = 0; r < savebuffer.hdr.rec_pkt; r++) {
+ for (t = 0; t < savebuffer.hdr.samp_rec; t++) {
+ if (savebuffer.records[r].trials[t] != EGG_MISSING_DATA) {
+ ptrials++;
+ psum += savebuffer.records[r].trials[t];
+ }
+ }
+ }
+ mean_Packet = ((double) psum) / ptrials;
+ totalGrand += psum;
+ totalTrials += ptrials;
+ mean_Grand = totalGrand / totalTrials;
+ total_Packets++;
+ printf("Packets sent: %ld Packet mean: %6.2f Grand mean: %6.2f\n",
+ total_Packets, mean_Packet, mean_Grand);
+#endif
+ }
+
+ /* Check for change to the collection parameters...
+ now is the time to implement it. */
+
+ if (coll.opts.rec_pkt != protocol.rec_pkt ||
+ coll.opts.trialsz != protocol.trialsz ||
+ coll.opts.sec_rec != protocol.sec_rec ||
+ coll.opts.samp_rec != protocol.samp_rec) {
+ sps = SetCollOpts();
+ saveProtocol();
+ }
+ /* Reinitialise carton to interval containing sample */
+ resetCarton(t.tv_sec);
+ }
+
+ /* Store the sample into the carton, which is now guaranteed to
+ bracket the interval in which it was collected. */
+
+#ifdef DEBUG
+ /* But let's be sure it really *is* in the interval. */
+ if (t.tv_sec < savebuffer.records[0].timestamp ||
+ t.tv_sec >= (savebuffer.records[0].timestamp + savebuffer.hdr.sec_rec * savebuffer.hdr.rec_pkt)) {
+ fprintf(stderr, "***Sample, collected at %ld, is not within packet starting at %ld.\n",
+ t.tv_sec, savebuffer.records[0].timestamp);
+ exit(-1);
+ }
+#endif
+
+ rindex = t.tv_sec - savebuffer.records[0].timestamp;
+ savebuffer.records[rindex / savebuffer.hdr.sec_rec].trials[rindex % savebuffer.hdr.sec_rec] = sample;
+
+ /* 2E. Update user interface. */
+
+#ifndef NO_UI
+ coll.data.trials[coll.sampct] = sample;
+ coll.sampct++;
+ UIUpdate(coll.sampct >= coll.opts.samp_rec, &coll);
+
+ if (coll.sampct >= coll.opts.samp_rec) {
+ coll.sampct = 0;
+ }
+#endif
+
+ /* Now that the current sample has been dealt which, check
+ for egg-initiated actions whose time has come. */
+
+ /* 2F. First of all, it it's time to prod the basket with an
+ awake packet, lob one over the pole. */
+
+ if (getzulutime(NULL) - lastconn > (eggtable[0].connival * 60L)) {
+ lastsend = lastconn = getzulutime(NULL);
+
+ /* If this is a dial-and-drop egg, connect to the network before
+ sending the packet. */
+
+ if (sdlisten < 0 && eggtable[0].conntype == CONN_DND) {
+ sdlisten = NetUp(eggtable[0].upcmd, myaddr, myport);
+ }
+
+ GreetBasket();
+ }
+
+ /* 2G. If this is a dial-and-drop egg and it's been more than a
+ minute since we sent anything, tear down the network connection. */
+
+ if (eggtable[0].conntype == CONN_DND && sdlisten >= 0) {
+ if ((getzulutime(NULL) - lastsend) > 60L) {
+ NetDown(eggtable[0].dncmd, sdlisten);
+ sdlisten = -1;
+ }
+ }
+
+ /* Now deal with basket-initiated requests received on the socket
+ since the last time around the loop. To improve throughput for
+ dialup connections, we may come back here several times if we
+ have more data and if time allows. */
+
+ do {
+ havedata = 0; /* Don't loop unless net activity happens. */
+
+ /* 1A. Wait for connection. */
+ if (eggtable[0].conntype == CONN_PERM) {
+ if (sdlisten < 0) {
+ /* Initialize networking, get a listening socket at EGGPORT */
+ sdlisten = InitNetwork(myaddr, myport);
+ }
+ }
+ if (sdlisten >= 0) {
+ res = NetListen(sdlisten, &pktbuf, &rhost, FALSE);
+ if (res < 0 && res != ERR_COMM_TMOUT) {
+ fprintf(stderr, "NetListen error: %d\n", res);
+ break; /* Out of do loop */
+ }
+ /* Data present, process networking thread */
+ if (res == ERR_NONE) {
+ /* 1B. Validate connection.
+ Remote host address is in rhost. Make sure this is either an
+ egg or a basket, and set the flag appropriately. */
+ isbasket = 0;
+ for (i = 0; i < numbaskets; i++) {
+ if (!memcmp(&(rhost.sin_addr),
+ &(baskettable[i].ipaddr.sin_addr),
+ sizeof(rhost.sin_addr))) {
+ isbasket = 1;
+ remname = baskettable[i].name;
+ }
+ }
+
+ if (!isbasket) {
+ fprintf(stderr, "Attempt to connect from unknown source: %s",
+ sockaddr2dquad(&rhost));
+ break; /* Out of do loop */
+ }
+
+ havedata = 1; /* Initial assumption, until disproven. */
+
+ memcpy(&pkttype, pktbuf, sizeof(uint16));
+ memcpy(&pktsize, pktbuf+sizeof(uint16), sizeof(uint16));
+ pkttype = ntohs(pkttype);
+ pktsize = ntohs(pktsize);
+
+ /* 1C. Reply to connection. */
+ switch(pkttype) {
+ case DATA_PACKET:
+ case AWAKE_PACKET:
+ /* Not acceptable at an eggsite. */
+ fprintf(stderr, "%s: EGG could not accept %d packet\n",
+ pgmname, pkttype);
+ break;
+
+ /* Request for data from a basket. */
+
+ case REQ_PACKET:
+ {
+ uint16 reggid;
+ uint32 stime;
+ char *pktP = pktbuf + (2 * sizeof(uint16));
+
+ unpackShort(reggid);
+ unpackLong(stime);
+#ifdef PACKETDUMP
+ fprintf(stderr, "Request: eggid = %d, starttm = %ld: %s",
+ reggid, stime, asctime(gmtime((time_t *) &stime)));
+#endif
+ res = LoadPacket(stime, reggid, &retrcart);
+ }
+ if (res == ERR_NONE) {
+ /* NetPacketize it */
+ MakeDataPkt(&outpktbuf, &retrcart);
+ rhost.sin_port = htons(BASKETPORT);
+ res = NetTalk(&rhost, outpktbuf, TRUE);
+ if (res < 0) {
+ fprintf(stderr, "NetTalk failed (%d)\n", res);
+ }
+ free(outpktbuf);
+ lastDataSent = lastsend = getzulutime(NULL);
+ } else if (res == ERR_EOF) {
+ /* End of data. If DND, bring down connection */
+ if (eggtable[0].conntype == CONN_DND) {
+ NetDown(eggtable[0].dncmd, sdlisten);
+ sdlisten = -1;
+ }
+ havedata = 0;
+ }
+ break;
+
+ case SETTINGS_PACKET:
+ /* Update settings in buffer, will change at next packet
+ boundary. */
+
+ { char *pktP = pktbuf + (3 * sizeof(uint16)) + sizeof(uint32);
+
+ unpackShort(protocol.samp_rec);
+ unpackShort(protocol.sec_rec);
+ unpackShort(protocol.rec_pkt);
+ unpackByte(protocol.trialsz);
+ }
+#ifdef PACKETDUMP
+ fprintf(stderr, "Settings: samp_rec = %d, sec_rec = %d, rec_pkt = %d, trialsz = %d\n",
+ protocol.samp_rec, protocol.sec_rec, protocol.rec_pkt, protocol.trialsz);
+#endif
+ break;
+ }
+ free(pktbuf);
+ }
+ }
+ gettimeofday(&ct, NULL);
+ } while (havedata && ct.tv_usec < 1000000L - MINSLEEP);
+
+ /* 2H. Compute the length in microseconds we should sleep before
+ the top of the next second. Note that we compute the interval
+ based on the time at the bottom of the loop, after dealing with
+ whatever housekeeping requests may have been performed since
+ collecting the last sample. */
+
+ gettimeofday(&ct, NULL);
+ if (lt.tv_sec == 0) {
+ lt.tv_sec = t.tv_sec - 1;
+ }
+ time_latency = (((t.tv_sec - lt.tv_sec) - 1) * 1000000L) + t.tv_usec;
+ time_housekeeping = ((ct.tv_sec - t.tv_sec) * 1000000L) + (ct.tv_usec - t.tv_usec);
+#ifdef DEBUG
+ usec = time_latency;
+ msec = usec / 1000;
+ usec %= 1000;
+ printf("Sampling latency: %ld.%03ld msec", msec, usec);
+
+ usec = time_housekeeping;
+ msec = usec / 1000;
+ usec %= 1000;
+ printf(" Housekeeping time: %ld.%03ld msec\n", msec, usec);
+#endif
+ lt = ct;
+ sleeptime = ((1000000 - SLACK) - ct.tv_usec);
+ /* printf("Sleep time = %d usec\n", sleeptime); */
+ }
+}
+
+/* EGG specific */
+
+/* LoadRCFile -- Read in a configuration file. If the filename
+ argument is NULL, the default file is read.
+ Otherwise, configuration statements are read
+ from the file given by the argument. */
+
+static void LoadRCFile(char *filename) {
+ FILE *fp;
+ char linebuf[200];
+ char *myargv[MAX_PARSE], *tp;
+ int myargc, lcount, p, b, i;
+
+ if (filename != NULL) {
+ if ((fp = fopen(filename, "r")) == NULL) {
+ fprintf(stderr, "%s: Cannot open auxiliary configuration file %s.\n", pgmname, filename);
+ exit(-1);
+ }
+ } else {
+ if ((fp = fopen(".eggrc", "r")) == NULL) {
+ if ((fp = fopen("~/.eggrc", "r")) == NULL) {
+ if ((fp = fopen("/etc/eggrc", "r")) == NULL) {
+ fprintf(stderr, "%s: Couldn't find a egg RC file.\n", pgmname);
+ exit(-1);
+ }
+ }
+ }
+ }
+
+ lcount = 0;
+
+ while(fgets(linebuf, 200, fp) != NULL) {
+ /* Comments and blank lines ignored. */
+ lcount++;
+ if (*linebuf == '#' || *linebuf == '\n') continue;
+ Parse(linebuf, &myargc, myargv);
+ if (myargc == 0) continue;
+ if (!strcmp(myargv[0], "EGG")) {
+ if (myargc < 7 || myargc > 8) {
+ fprintf(stderr, "%s: RC error, line %d, poor %s format\n",
+ pgmname, lcount, myargv[0]);
+ exit(-1);
+ }
+ if (numeggs > 0) {
+ fprintf(stderr, "%s: RC error, line %d, only one EGG allowed\n",
+ pgmname, lcount);
+ exit(-1);
+ }
+
+ eggtable[0].name = mallocpy(myargv[1]);
+ eggtable[0].id = atoi(myargv[2]);
+ dquad2sockaddr(&(eggtable[0].ipaddr), NULL, myargv[3]);
+ eggtable[0].primbasket = mallocpy(myargv[4]);
+ eggtable[0].conntype = (!strcmp(myargv[5], "PERM"))?CONN_PERM:CONN_DND;
+ eggtable[0].connival = atoi(myargv[6]);
+ eggtable[0].url = NULL; /* URL specification is permitted, but ignored */
+ numeggs = 1;
+ } else if (!strcmp(myargv[0], "BASKET")) {
+ if (myargc != 3) {
+ fprintf(stderr, "%s: RC error, line %d, poor %s format\n",
+ pgmname, lcount, myargv[0]);
+ exit(-1);
+ }
+ baskettable[numbaskets].name = mallocpy(myargv[1]);
+ dquad2sockaddr(&(baskettable[numbaskets].ipaddr), NULL, myargv[2]);
+ numbaskets++;
+ } else if (!strcmp(myargv[0], "PROTOCOL")) {
+ if (myargc != 5) {
+ fprintf(stderr, "%s: RC error, line %d, poor %s format\n",
+ pgmname, lcount, myargv[0]);
+ exit(-1);
+ }
+ protocol.samp_rec = atoi(myargv[1]);
+ protocol.sec_rec = atoi(myargv[2]);
+ protocol.rec_pkt = atoi(myargv[3]);
+ protocol.trialsz = atoi(myargv[4]);
+
+ /* REG: Configure Random Event Generator for this egg. */
+
+ } else if (!strcmp(myargv[0], "REG")) {
+ if (myargc != 4) {
+ fprintf(stderr, "%s: RC error, line %d, poor %s format\n",
+ pgmname, lcount, myargv[0]);
+ exit(-1);
+ }
+ if (configuredREG != NULL) {
+ fprintf(stderr, "%s: RC error, line %d, multiple REGs specified.\n",
+ pgmname, lcount);
+ exit(-1);
+ }
+ for (i = 0; reg_table[i] != NULL; i++) {
+ if (strcasecmp(myargv[1], reg_table[i]->reg_name) == 0) {
+ configuredREG = reg_table[i];
+ devopts.type = reg_table[i]->reg_type;
+ }
+ }
+ if (configuredREG == NULL) {
+ fprintf(stderr, "%s: RC error, line %d, unknown REG type %s specified.\n",
+ pgmname, lcount, myargv[1]);
+ exit(-1);
+ }
+
+ devopts.port = atoi(myargv[2]);
+ devopts.baud = atoi(myargv[3]);
+ } else if (!strcmp(myargv[0], "NETUP") ||
+ !strcmp(myargv[0], "NETDOWN") ||
+ !strcmp(myargv[0], "PORT") ||
+ !strcmp(myargv[0], "INTERFACE")) {
+ if (myargc < 2) {
+ fprintf(stderr, "%s: RC error, line %d, poor %s format\n",
+ pgmname, lcount, myargv[0]);
+ exit(-1);
+ }
+ tp = (char *) malloc(200);
+ for (*tp = 0, p = 1; p < myargc; p++) {
+ strcat(tp, myargv[p]);
+ if (p < myargc-1) strcat(tp, " ");
+ }
+
+ if (!strcmp(myargv[0], "NETUP")) eggtable[0].upcmd = tp;
+ else if (!strcmp(myargv[0], "NETDOWN")) eggtable[0].dncmd = tp;
+ else if (!strcmp(myargv[0], "PORT")) {
+ if (atoi(tp) <= 0) {
+ fprintf(stderr, "%s: RC error, ignoring bad port %d, using %d\n",
+ pgmname, atoi(tp), myport);
+ } else {
+ myport = atoi(tp);
+ }
+ free(tp);
+ } else if (!strcmp(myargv[0], "INTERFACE")) myaddr = tp;
+ } else {
+ fprintf(stderr, "%s: RC error, %s is unknown keyword\n", pgmname, myargv[0]);
+ exit(-1);
+ }
+ }
+
+ /* Consistency checks done only after loading the main
+ configuration file. */
+
+ if (filename == NULL) {
+ for (p = -1, b = 0; b < numbaskets; b++) {
+ if (!strcmp(baskettable[b].name, eggtable[0].primbasket)) p = b;
+ }
+
+ if (p != 0) {
+ fprintf(stderr, "%s: RC error, primary basket should be listed first.\n", pgmname);
+ exit(-1);
+ }
+ } else {
+ printf("Reloaded auxiliary configuration file %s.\n", filename);
+ }
+ fclose(fp);
+}
+
+/* MakeAwake -- Make a egg awake packet to let the basket
+ know we're on line. */
+
+static void MakeAwake(AwakePacket *pkt) {
+ char *pktP = (char *) pkt;
+
+ packShort(AWAKE_PACKET);
+ packShort((4 * sizeof(uint16)) + sizeof(uint32));
+ packShort(eggtable[0].id);
+ packLong(getzulutime(NULL));
+}
+
+/* MakeDataPkt -- Build a canonical network byte order data packet
+ from the data collected in an EggCarton. */
+
+static void MakeDataPkt(char **pkt, EggCarton *src) {
+ uint16 pktsize, rec;
+ char *pktP;
+
+ pktsize = (7 * sizeof(uint16)) + sizeof(trial) + /* Header */
+ (src->hdr.numrec * (sizeof(uint32) + /* Trial data */
+ src->hdr.samp_rec * sizeof(trial))) +
+ sizeof(uint16); /* CRC-16 */
+ *pkt = pktP = (char *) malloc(pktsize);
+
+ /* Assemble header fields into data packet. */
+
+ packShort(src->hdr.type = DATA_PACKET);
+ packShort(src->hdr.pktsize = pktsize);
+ packShort(src->hdr.eggid);
+ packShort(src->hdr.samp_rec);
+ packShort(src->hdr.sec_rec);
+ packShort(src->hdr.rec_pkt);
+ packByte(src->hdr.trialsz);
+ packShort(src->hdr.numrec);
+
+ /* Append data records to packet. */
+
+ for (rec = 0; rec < src->hdr.numrec; rec++) {
+ packLong(src->records[rec].timestamp);
+ packBytes(&(src->records[rec].trials), src->hdr.samp_rec);
+ }
+
+ /* No need to calculate CRC -- NetTalk does that for us.
+ Note that we did reserve space for the CRC when
+ allocating the packet buffer. */
+}
+
+/* SetCollOpts -- Set collection options from the protocol
+ specified in the .rc file or by a basket. */
+
+static double SetCollOpts(void) {
+ double sps;
+
+ coll.opts.eggid = eggtable[0].id;
+
+ coll.opts.rec_pkt = protocol.rec_pkt;
+ if (coll.opts.rec_pkt < 1) coll.opts.rec_pkt = 1;
+ if (coll.opts.rec_pkt > MAXREC_PKT) coll.opts.rec_pkt = MAXREC_PKT;
+
+ coll.opts.trialsz = protocol.trialsz;
+ if (coll.opts.trialsz < MINBITS) {
+ fprintf(stderr, "Attempt to set trial size below %d, to %d.\n",
+ MINBITS, coll.opts.trialsz);
+ coll.opts.trialsz = MINBITS;
+ }
+ if (coll.opts.trialsz > MAXBITS) {
+ fprintf(stderr, "Attempt to set trial size above %d, to %d.\n",
+ MAXBITS, coll.opts.trialsz);
+ coll.opts.trialsz = MAXBITS;
+ }
+
+ coll.opts.sec_rec = protocol.sec_rec;
+ if (coll.opts.sec_rec < 1) {
+ fprintf(stderr, "Attempt to set seconds/record below 1, to %d.\n",
+ coll.opts.sec_rec);
+ coll.opts.sec_rec = 1;
+ }
+ if (coll.opts.sec_rec > MAXSEC_REC) {
+ fprintf(stderr, "Attempt to set seconds/record above %d, to %d.\n",
+ MAXSEC_REC, coll.opts.sec_rec);
+ coll.opts.sec_rec = MAXSEC_REC;
+ }
+
+ coll.opts.samp_rec = protocol.samp_rec;
+ if (coll.opts.samp_rec < 1) {
+ fprintf(stderr, "Attempt to set samples/record below 1, to %d.\n",
+ coll.opts.samp_rec);
+ coll.opts.samp_rec = 1;
+ }
+ if (coll.opts.samp_rec > MAXSAMP_REC) {
+ fprintf(stderr, "Attempt to set samples/record above %d, to %d.\n",
+ MAXSAMP_REC, coll.opts.samp_rec);
+ coll.opts.samp_rec = MAXSAMP_REC;
+ }
+
+ sps = (double)coll.opts.samp_rec / (double)coll.opts.sec_rec;
+
+ fprintf(stderr, "Effective sample rate is about %f samp/sec or %f bits/sec\n",
+ sps, coll.opts.trialsz * sps);
+ fprintf(stderr, "Packets contain %d records\n", coll.opts.rec_pkt);
+
+ return sps;
+}
+
+/* GreetBasket -- Send an awake packet to each configured
+ basket. */
+
+static int GreetBasket(void) {
+ int i, b;
+ struct sockaddr_in bhost;
+ AwakePacket awake;
+
+ MakeAwake(&awake);
+
+ for (b = 0; b < numbaskets; b++) {
+ memset(&bhost, 0, sizeof(struct sockaddr_in));
+ memcpy(&bhost, &(baskettable[b].ipaddr), sizeof(bhost));
+ bhost.sin_port = htons(BASKETPORT);
+ bhost.sin_family = AF_INET;
+
+ /* Don't gripe about network unreachable. Just means
+ network is down right now, try later. */
+ i = NetTalk(&bhost, (char *)&awake, FALSE);
+ if (i < 0) {
+ /* Couldn't get to this one, try others. */
+#ifdef DEBUG
+ fprintf(stderr, "%s: Failure to reach basket '%s'\n",
+ pgmname, baskettable[b].name);
+#endif
+ } else {
+ return ERR_NONE;
+ }
+ }
+
+ return ERR_COMM_TMOUT;
+}
+
+/* handle_sigkill -- KILL signal handler. Terminate user interface
+ and exit. */
+
+static void handle_sigkill(int arg) {
+ UIClose();
+ exit(-1);
+}
+
+/* handle_sighup -- HUP signal handler. Reload protocol from the
+ .eggprotocolrc file. */
+
+static void handle_sighup(int arg) {
+ LoadRCFile(".eggprotocolrc");
+#ifndef SIGACTION_WORKING
+ signal(SIGHUP, handle_sighup);
+#endif
+}
--- /dev/null
+# Configuration file for egg collection software
+# This specifies the egg configuration information, the contact
+# information for its basket(s), and initial data acquisition parameters.
+
+# Each line consists of a case-sensitive keyword and a series of
+# options. Defined keywords are:
+#
+# EGG <name> <id> <ip addr> <primbasket> <conntype> <connival> <url>
+#
+# The primary basket <primbasket> is the name of the basket (defined
+# below) that should be contacted retrieve data from this Egg.
+# The connection type <conntype> is "PERM" (permanent) or "DND"
+# (dial-and-drop). So far the code does not support the DND option.
+# The connection interval <connival> determines the time (in minutes)
+# between transmission attempts. If specified, and not equal to
+# ".", <url> gives a URL (for example http://www.somesite.net/page.html)
+# which will be linked to the egg <name> in status reports. Note that
+# this specification has meaning only in the .basketrc file. For
+# compatibility, it is permitted in an .eggrc file, but is ignored.
+#
+# BASKET <name> <ip addr>
+#
+# This entry tells us about the existence of a set of baskets. The
+# basket named as primary is the one which will be contacted
+# initially.
+#
+# PROTOCOL <samprec> <secrec> <recpkt> <trialsz>
+#
+# Specify the default data collection protocol. The arguments are
+# <samprec> samples per record (1-10, though this should always be 5-10),
+# <secrec> seconds per records (1-3000),
+# <recpkt> records per packet (1-60), and
+# <trialsz> bits per sample (32-255).
+#
+# REG <type> <port> <baud>
+#
+# Specify hardware device. Supported types include "PEAR" only at
+# this time. Port is serial port number (e.g. 1 for /dev/ttyS1);
+# <baud> is baud rate.
+#
+# NETUP <script> <args> ...
+# NETDOWN <script> <args> ...
+#
+# Provide script files to be run to bring up and tear down the network
+# connection on demand. These will only be used if connection type is
+# DND.
+
+#EGG halley 1 10.0.0.111 halley PERM 1
+#BASKET halley 10.0.0.111
+#EGG halley 1 10.0.0.111 mercury DND 3
+#BASKET mercury 10.0.0.125
+
+#EGG noosphere 28 128.112.35.133 noosphere PERM 1
+#BASKET noosphere 128.112.35.133
+
+# diesse -> diesse
+#EGG diesse 37 193.8.230.134 diesse PERM 1
+#BASKET diesse 193.8.230.134
+
+# noosphere -> diesse
+EGG noosphere 28 128.112.35.133 diesse PERM 1
+BASKET diesse 193.8.230.134
+
+# throop -> diesse
+#EGG throop 1003 193.8.230.132 diesse PERM 1 http://www.fourmilab.ch/
+#BASKET diesse 193.8.230.134
+
+# jura -> jura
+#EGG jura 1004 193.8.230.130 jura PERM 1 http://www.fourmilab.ch/
+#BASKET jura 193.8.230.130
+
+# diesse -> noosphere
+#EGG diesse.fourmilab.ch 37 193.8.230.134 noosphere PERM 1
+#BASKET noosphere 128.112.35.133
+
+#EGG diesse 37 193.8.230.134 jura PERM 1
+#BASKET jura 193.8.230.130
+
+#BASKET tonga 209.157.90.137
+#BASKET tonga1 209.157.90.138
+PROTOCOL 10 10 6 200
+#REG PEAR 2 9600
+REG PSEUDO 1 9600
+#REG ORION 1 9600
+NETUP pppscript up
+NETDOWN pppscript down
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/eggui.c,v 1.8 1999/02/28 20:02:54 ghn Exp $
+ * PURPOSE: EGG site user interface
+ * AUTHOR: Greg Nelson
+ * DATE: 98-06-28
+ *
+ * REVISED:
+ * $Log: eggui.c,v $
+ * Revision 1.8 1999/02/28 20:02:54 ghn
+ * Version 5.1: The user interface now leaves the cursor at the bottom of
+ * the screen and responds to ^L to redraw the entire screen.
+ *
+ * Revision 1.7 1999/01/01 23:58:56 ghn
+ * Take out "CPU_BOUND" conditionals; we won't run CPU_BOUND any more.
+ *
+ * Revision 1.6 1998/12/31 22:07:56 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.5 1998/08/03 20:36:28 kelvin
+ * Show time of last data collection by basket.
+ *
+ * Revision 1.4 1998/08/01 21:33:28 ghn
+ * Added real implementation for ncursed() based UI for egg.
+ *
+ * Revision 1.3 1998/08/01 18:51:25 ghn
+ * Added John's byte-order-independence changes.
+ *
+ * Revision 1.2 1998/08/01 17:05:48 ghn
+ * Trivial additions of curses related code.
+ *
+ * Revision 1.1 1998/07/21 11:41:23 ghn
+ * Initial revision
+ *
+ * Copyright 1998 - Greg Nelson
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <curses.h>
+
+/* Curses takes it upon itself to define TRUE and FALSE,
+ incompatibly, as it happens, with the definitions in
+ global.h. So, clear out the CURSES definitions. */
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#include "global.h"
+#include "genlib.h"
+#include "errnos.h"
+#include "regs.h"
+#include "version.h"
+
+#ifndef NO_UI
+static int32 inittm = 0;
+#endif
+
+extern int32 lastDataSent;
+extern int32 time_latency, time_housekeeping;
+
+/* Initialize user interface, as needed. */
+int32 UIInit(void) {
+#ifndef NO_UI
+ initscr();
+ cbreak(); noecho();
+ nonl();
+ intrflush(stdscr, FALSE);
+ keypad(stdscr, TRUE);
+ timeout(0);
+ clear();
+ move(0, 0);
+ printw("Please wait, initializing...");
+ refresh();
+ inittm = 0;
+#endif
+ return ERR_NONE;
+}
+
+/* Close down user interface */
+int32 UIClose(void) {
+#ifndef NO_UI
+ endwin();
+#endif
+ return ERR_NONE;
+}
+
+/* Update user interface once on every data collection, receiving the
+ current collection result and CollectRecord. */
+int32 UIUpdate(int32 cres, CollectRecord *coll) {
+#ifndef NO_UI
+ char *tmstr;
+ double recavg;
+ static double grandavg = 0;
+ static int32 totsamp = 0;
+ int32 i, line, now;
+
+ if ((i = getch()) != ERR) {
+ if (i == 12) clear();
+ }
+
+ if (inittm == 0) {
+ inittm = getzulutime(NULL);
+ clear();
+ }
+
+ /* Show protocol. */
+
+ if (coll->sampct == 1) {
+ line = 11;
+ move(line++, 5); printw("Samples per record: %3d", (int)coll->opts.samp_rec);
+ move(line++, 5); printw("Seconds per record: %3d", (int)coll->opts.sec_rec);
+ move(line++, 5); printw("Records per packet: %3d", (int)coll->opts.rec_pkt);
+ move(line++, 5); printw("Bits per trial: %3d", (int)coll->opts.trialsz);
+ refresh();
+ }
+
+ if (cres < 0) return ERR_NONE;
+
+ line = 0;
+ move(line++, 3);
+ printw("EGG %s ID %d REG %s %s", eggtable[0].name, eggtable[0].id,
+ configuredREG->reg_name, Version);
+
+ tmstr = ctime(&inittm); tmstr[strlen(tmstr)-1] = 0;
+ move(line++, 5);
+ printw("Up since %25s", tmstr);
+
+ move(line++, 5);
+ now = getzulutime(NULL);
+ tmstr = ctime(&now); tmstr[strlen(tmstr)-1] = 0;
+ printw("Last sample at %25s", tmstr);
+
+ move(line++, 5);
+ tmstr = ctime(&lastDataSent);
+ tmstr[strlen(tmstr)-1] = 0;
+ printw("Last packet at %25s", lastDataSent == 0 ? "Never" : tmstr);
+
+ /* Note that for a non-CPU_BOUND built, UIUpdate is passed a
+ collection record filled with the last 10 samples collected.
+ Since missing samples do not figure in this record, there
+ is no need to test EGG_MISSING_DATA when computing the
+ mean below. */
+
+ /* Show mean since egg started and, each time 10 samples
+ are collected, the mean for the last 10 samples. */
+
+ line++;
+ grandavg *= totsamp;
+ grandavg += coll->data.trials[coll->sampct-1]; totsamp++;
+ grandavg /= totsamp;
+ move(line++, 5);
+ printw("Grand mean: %6.2f", grandavg);
+
+ if (cres == 1) {
+ for (recavg = 0, i = 0; i < coll->opts.samp_rec; i++)
+ recavg += coll->data.trials[i];
+ recavg /= coll->opts.samp_rec;
+ move(line, 5);
+ printw("Last record mean: %6.2f (%d seconds)", recavg, coll->opts.sec_rec);
+ }
+ line++; /* Advance whether we show record mean or not */
+
+ /* Show latency (lapse between start of second as measured by
+ the computer's clock and when collection of the sample
+ actually began) and time elapsed in housekeeping (saving
+ packets in local files, talking to the basket, updating
+ the user interface, etc.) following collection of the sample.
+ If housekeeping time frequently consumes a substantial portion
+ of the inter-sample interval, the probability of lost
+ samples increases. Both times are shown in milliseconds. */
+
+ line++;
+ move(line++, 5);
+ printw("Sampling latency: ");
+ clrtoeol();
+ printw("%.3f ms", time_latency / 1000.0);
+ move(line++, 5);
+ printw("Housekeeping time: ");
+ clrtoeol();
+ printw("%.3f ms", time_housekeeping / 1000.0);
+
+ move(16, 0);
+
+ refresh();
+#endif
+
+ return ERR_NONE;
+}
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/eggui.h,v 1.3 1999/01/02 00:01:40 ghn Exp $
+ * PURPOSE: EGG site user interface
+ * AUTHOR: Greg Nelson
+ * DATE: 98-06-28
+ *
+ * REVISED:
+ * $Log: eggui.h,v $
+ * Revision 1.3 1999/01/02 00:01:40 ghn
+ * Removed obsolete "collect.h" include.
+ *
+ * Revision 1.2 1998/12/31 22:11:05 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.1 1998/07/21 11:40:13 ghn
+ * Initial revision
+ *
+ * Copyright 1998 - Greg Nelson
+ */
+
+/* Initialize user interface, as needed. */
+extern int32 UIInit(void);
+
+/* Close down user interface */
+extern int32 UIClose(void);
+
+/* Update user interface once on every data collection, receiving the
+ current collection result and CollectRecord. */
+extern int32 UIUpdate(int32 cres, CollectRecord *coll);
--- /dev/null
+/* PROGRAM: all
+ * FILE: $Header: /home/ghn/projects/PEAR/egg/eggsh/RCS/errnos.h,v 1.1 1998/07/21 11:39:53 ghn Exp $
+ * PURPOSE: Definitions for error constants
+ * AUTHOR: Greg Nelson
+ * DATE: 98-05-09
+ *
+ * REVISED: $Log: errnos.h,v $
+ * REVISED: Revision 1.1 1998/07/21 11:39:53 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+/* 0 - no error */
+#define ERR_NONE 0
+
+/* -1 to -99 - generic errors */
+#define ERR_OTHER -1 /* Catchall for other errors */
+#define ERR_NOMEM -2 /* Could not allocate memory */
+#define ERR_NIMP -3 /* Not implemented */
+#define ERR_WRONGARGN -4 /* Wrong number of arguments. */
+#define ERR_INRANGE -5 /* Input out of range */
+#define ERR_OTIMEOUT -6 /* Got a timeout, not from COMM */
+#define ERR_STRTOOLONG -7 /* String was longer than allowed */
+
+/* -100 to -199 - comm errors */
+#define ERR_STRAYINPUT -100 /* Stray characters were received */
+#define ERR_PKT_BADSTX -101 /* Packet did not begin with STX */
+#define ERR_PKT_BADLEN -102 /* Length word could not be read */
+#define ERR_PKT_SHORT -103 /* Packet was not long enough */
+#define ERR_PKT_CKSUM -104 /* Packet checksum did not match */
+#define ERR_PKT_BADETX -105 /* Packet did not end with ETX */
+#define ERR_COMM_TMOUT -106 /* Timeout during communication */
+#define ERR_COMM_BRK -107 /* Received break character */
+#define ERR_COMM_PARITY -108 /* Received parity error */
+#define ERR_COMM_FRAME -109 /* Received framing error */
+#define ERR_COMM_OVERRN -110 /* Received overrun error */
+#define ERR_BUFF_FULL -111 /* Buffer was too full to queue msg */
+#define ERR_NOREPLY -112 /* Device did not reply to hails */
+#define ERR_RESPINVAL -113 /* Response was invalid */
+#define ERR_COMM_BTMOUT -114 /* Timeout inside body of message */
+#define ERR_PORT_INACT -115 /* Attempt to use an inactive port */
+
+/* -200 to -299 - math errors */
+#define ERR_DIV0 -200 /* Attempt to divide by zero */
+#define ERR_NOSOLN -201 /* Couldn't solve for discontinuities */
+#define ERR_APPROX -202 /* Result was an inexact approximation */
+#define ERR_NOVARS -203 /* No parameters were variable */
+#define ERR_SINGULAR -204 /* Matrix was singular, unsolvable */
+#define ERR_OVERFLOW -205 /* Numerical overflow */
+
+/* -300 to -399 - DLL specific errors */
+#define ERR_NOTSUPP -300 /* Current device does not support fn */
+#define ERR_RESOURCE -301 /* Ran out of a DLL limited resource */
+#define ERR_DEVDRVR -302 /* Windows device driver returned err */
+#define ERR_DEVSELECT -303 /* Selecting a device failed (general) */
+#define ERR_NOENT -320 /* File not found */
+#define ERR_CNREAD -321 /* Couldn't read desired data from file */
+#define ERR_CNWRITE -322 /* Couldn't write desired data to file */
+#define ERR_EOF -323 /* End of file reached unexpectedly */
+#define ERR_DLGCAN -324 /* Dialog canceled, not an "error" */
--- /dev/null
+/* PROGRAM: examine
+ * FILE: $Header: /home/egg/src/RCS/examine.c,v 1.1 1998/07/21 11:39:04 ghn Exp $
+ * PURPOSE: Testing data retrieval from database
+ * AUTHOR: Greg Nelson
+ * DATE: 98-05-09
+ *
+ * REVISED: $Log: examine.c,v $
+ * REVISED: Revision 1.1 1998/07/21 11:39:04 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "global.h"
+#include "storage.h"
+
+EggEntry eggtable[MAX_EGGS];
+
+int main(int argc, char *argv[]) {
+ int i, j, k, trials;
+ FILE *fp;
+ EggCarton pktbuf;
+
+ pgmname = argv[0];
+
+ if (argc != 1 && argc != 2) {
+ printf("Usage: %s [infile]\n", pgmname);
+ exit(-1);
+ }
+
+ InitStorage(NULL);
+
+ if (argc == 1) fp = stdin;
+ else fp = fopen(argv[1], "r");
+
+ trials = 0;
+ while (1) {
+ i = LoadPacket(fp, &pktbuf);
+ if (i < 0) {
+ printf("Total trials: %d\n", trials);
+ exit(-1);
+ }
+
+ printf("Packet of %d records read\n", pktbuf.hdr.numrec);
+ for (j = 0; j < pktbuf.hdr.numrec; j++) {
+ printf("Record: %d points\n %ld: ",
+ pktbuf.hdr.samp_rec,
+ pktbuf.records[j].timestamp);
+ for (k = 0; k < pktbuf.hdr.samp_rec; k++) {
+ printf("%3d ", pktbuf.records[j].trials[k]);
+ trials++;
+ }
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/genlib.c,v 1.6 1999/02/28 20:05:18 ghn Exp $
+ * PURPOSE: General library
+ * AUTHOR: Greg Nelson
+ * DATE: 98-05-09
+ *
+ * REVISED:
+ * $Log: genlib.c,v $
+ * Revision 1.6 1999/02/28 20:05:18 ghn
+ * Version 5.1: Changed dquad2sockaddr interface to support ip/mm mask,
+ * created hl2dquad to translate host-long to dotted quad, and modified
+ * sockaddr2dquad to use this.
+ *
+ * Revision 1.5 1998/12/31 22:07:56 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.4 1998/08/03 20:43:35 kelvin
+ * File byte-order independence.
+ *
+ * Revision 1.3 1998/08/01 18:51:25 ghn
+ * Added John's byte-order-independence changes.
+ *
+ * Revision 1.2 1998/08/01 17:07:29 ghn
+ * Casting fixes from John plus better parsing.
+ *
+ * Revision 1.1 1998/07/21 11:38:15 ghn
+ * Initial revision
+ *
+ * Copyright 1998 - Greg Nelson
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include "global.h"
+#include "genlib.h"
+
+int32 getzulutime(struct timeval *ztv) {
+ struct timeval ttv;
+
+ if (ztv) {
+ gettimeofday(ztv, NULL);
+ return ztv->tv_sec;
+ } else {
+ gettimeofday(&ttv, NULL);
+ return ttv.tv_sec;
+ }
+}
+
+/* Get time difference (tv1-tv2) in msec. Only works if less than 24
+ days have passed. */
+int32 deltams(struct timeval *tv1, struct timeval *tv2) {
+ return (tv1->tv_sec - tv2->tv_sec) * 1000L +
+ (tv1->tv_usec - tv2->tv_usec) / 1000L;
+}
+
+/* Look up an EGG id. If we can't get it from environment, do a nutty
+ thing using CRC of uname block, which should be pretty unique. */
+uint16 GetID(void) {
+ char *idstr;
+ struct utsname utsname;
+
+ if ((idstr = getenv("EGGID")) != NULL) {
+ return atoi(idstr);
+ } else {
+ uname(&utsname);
+ return BlockCRC16((byte *)(&utsname), sizeof(struct utsname));
+ }
+}
+
+char *Packetize(EggCarton *src) {
+ char *rbuf;
+ uint32 lbuf;
+ uint16 pktsize, rec;
+ char *pktP;
+
+ pktsize = (7 * sizeof(uint16)) + sizeof(trial) + /* Header */
+ sizeof(char) + /* ...including pad byte for trialsz */
+ (src->hdr.numrec * (sizeof(uint32) + /* Trial data */
+ src->hdr.samp_rec * sizeof(trial))) +
+ sizeof(uint32); /* CRC and terminator */
+ rbuf = pktP = (char *) malloc(pktsize);
+
+ /* Assemble header fields into data packet. */
+
+ packShort(src->hdr.type = DATA_PACKET);
+ packShort(src->hdr.pktsize = pktsize);
+ packShort(src->hdr.eggid);
+ packShort(src->hdr.samp_rec);
+ packShort(src->hdr.sec_rec);
+ packShort(src->hdr.rec_pkt);
+ packByte(0); /* Pad byte in case we want to expand trialsz */
+ packByte(src->hdr.trialsz);
+ packShort(src->hdr.numrec);
+
+ /* Append data records to packet. */
+
+ for (rec = 0; rec < src->hdr.numrec; rec++) {
+ packLong(src->records[rec].timestamp);
+ packBytes(&(src->records[rec].trials), src->hdr.samp_rec);
+ }
+ /* Get CRC, pack into base(32,32,64) notation, and add tag byte (0xFF) */
+ lbuf = BlockCRC16((byte *) rbuf, pktP - rbuf);
+ lbuf = ((lbuf & 0xF800) << 13) |
+ ((lbuf & 0x07C0) << 10) |
+ ((lbuf & 0x003F) << 8) |
+ (0x00FF);
+ packLong(lbuf);
+ if ((pktP - rbuf) != pktsize) {
+ fprintf(stderr, "Length mismatch assembling packet. Computed: %d, actually packed: %d.\n",
+ pktsize, pktP - rbuf);
+ }
+ return rbuf;
+}
+
+int32 Unpacketize(EggCarton *dst, char *src) {
+ char *pktP = src;
+ char pad;
+ uint16 rec;
+ uint32 lbuf, filecrc;
+
+ /* Unpack the portable header into a host-order and aligned
+ EggHeader packet. */
+
+ unpackShort(dst->hdr.type);
+ unpackShort(dst->hdr.pktsize);
+ unpackShort(dst->hdr.eggid);
+ unpackShort(dst->hdr.samp_rec);
+ unpackShort(dst->hdr.sec_rec);
+ unpackShort(dst->hdr.rec_pkt);
+ unpackByte(pad); /* Pad in case we later grow trialsz */
+ unpackByte(dst->hdr.trialsz);
+ unpackShort(dst->hdr.numrec);
+
+ if (dst->hdr.type != DATA_PACKET) {
+#ifdef DEBUG
+ fprintf(stderr, "Invalid header type 0x%04X in packet read from file.\n", dst->hdr.type);
+#endif
+ return -1;
+ }
+
+ /* Unpack the data records from the file packet. */
+
+ for (rec = 0; rec < dst->hdr.numrec; rec++) {
+ unpackLong(dst->records[rec].timestamp);
+ /* Assumes sizeof(trial) = 1 */
+ unpackBytes(&(dst->records[rec].trials), dst->hdr.samp_rec);
+ }
+
+ /* Compute the CRC, reassemble into record terminator,
+ and compare with terminator in file. */
+
+ lbuf = BlockCRC16((byte *) src, pktP - src);
+ lbuf = ((lbuf & 0xF800) << 13) |
+ ((lbuf & 0x07C0) << 10) |
+ ((lbuf & 0x003F) << 8) |
+ (0x00FF);
+
+ unpackLong(filecrc);
+
+ if (lbuf != filecrc) {
+#ifdef DEBUG
+ fprintf(stderr, "Bad CRC in packet read from file. Read 0x%08lX, computed 0x%08lX.\n", filecrc, lbuf);
+#endif
+ return -2;
+ }
+
+ if (dst->hdr.pktsize != (pktP - src)) {
+#ifdef DEBUG
+ fprintf(stderr, "Length mismatch decoding packet. Header: %d, length decoded: %d.\n",
+ dst->hdr.pktsize, pktP - src);
+#endif
+ return -1;
+ }
+
+ /* One final little tweak. Since we included a pad byte to allow
+ for growth in trialsz, hdr.pktsize will include it. Subtract
+ one to hide the existence of the pad in the file from the
+ caller. In all probability the caller isn't going to look at
+ pktsize, but you can't be too careful. */
+
+ dst->hdr.pktsize--;
+
+ return 0;
+}
+
+void Parse(char *input, int *argc, char *argv[]) {
+ char *tp;
+
+ *argc = 0;
+
+ tp = strtok(input, " \t\n");
+ while (tp != NULL && *argc < MAX_PARSE) {
+ argv[*argc] = tp;
+ *argc += 1;
+ tp = strtok(NULL, " \t\n");
+ }
+}
+
+char *mallocpy(char *input) {
+ char *res;
+
+ res = (char *)malloc(1+strlen(input));
+ if (res) strcpy(res, input);
+ return res;
+}
+
+void dquad2sockaddr(struct sockaddr_in *sinp, int16 *mask, char *dquad) {
+ char *tp, *loser;
+ long saddr;
+ short qcount;
+
+ loser = mallocpy(dquad);
+
+ tp = strtok(loser, ".");
+ for (qcount = 0, saddr = 0; qcount < 4 && tp != NULL; qcount++) {
+ saddr = (saddr << 8) | (atoi(tp) & 0xFF);
+ tp = strtok(NULL, ".");
+ }
+ if (mask) {
+ *mask = 32;
+ strcpy(loser, dquad);
+ tp = strtok(loser, "/");
+ if (tp) {
+ tp = strtok(NULL, "/");
+ if (tp) *mask = atoi(tp);
+ }
+ }
+ free(loser);
+
+ sinp->sin_family = AF_INET;
+ sinp->sin_port = 0; /* To be filled in later */
+ sinp->sin_addr.s_addr = htonl(saddr);
+}
+
+char *sockaddr2dquad(struct sockaddr_in *sinp) {
+ long saddr;
+
+ saddr = ntohl(sinp->sin_addr.s_addr);
+ return hl2dquad(saddr);
+}
+
+char *hl2dquad(long addr) {
+ static char resout[16];
+
+ sprintf(resout, "%ld.%ld.%ld.%ld",
+ (addr >> 24) & 0xFF, (addr >> 16) & 0xFF,
+ (addr >> 8) & 0xFF, addr & 0xFF);
+
+ return resout;
+}
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/genlib.h,v 1.3 1999/02/28 20:05:35 ghn Exp $
+ * PURPOSE: Define general library interface
+ * AUTHOR: Greg Nelson
+ * DATE: 98-05-09
+ *
+ * REVISED:
+ * $Log: genlib.h,v $
+ * Revision 1.3 1999/02/28 20:05:35 ghn
+ * Version 5.1: Changed dquad2sockaddr interface to support ip/mm mask,
+ * created hl2dquad to translate host-long to dotted quad, and modified
+ * sockaddr2dquad to use this.
+ *
+ * Revision 1.2 1998/12/31 22:11:05 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.1 1998/07/21 11:38:04 ghn
+ * Initial revision
+ *
+ * Copyright 1998 - Greg Nelson
+ */
+
+#ifndef _GENLIB_H
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include "global.h"
+
+#define MAX_PARSE 20
+
+#ifdef OBSOLETE
+/* This is actually 366 * 24 * 60 * 60, as opposed the actual length
+ of the mean solar year which is about 365.2524 days. */
+#define SEC_PER_YEAR 31622400L
+#endif
+
+/* Get time in GMT reference frame. If ztv is NULL, simply returns
+ seconds. Otherwise, returns complete timeval in ztv as well. */
+extern int32 getzulutime(struct timeval *ztv);
+
+/* Get difference in msec between two tvs. */
+extern int32 deltams(struct timeval *tv1, struct timeval *tv2);
+
+/* Look up an EGG id. */
+extern uint16 GetID(void);
+
+/* Create a proper checksummed and packetized byte stream from the raw
+ data in memory. Return result is malloc'ed, so should be freed by
+ caller. */
+extern char *Packetize(EggCarton *src);
+
+extern int32 Unpacketize(EggCarton *dst, char *src);
+
+/* Compute CRC16 checksum given block and length (from crc16.c) */
+extern uint16 BlockCRC16(byte *block, uint32 len);
+
+extern void Parse(char *input, int *argc, char *argv[]);
+extern char *mallocpy(char *input);
+extern void dquad2sockaddr(struct sockaddr_in *sinp, int16 *mask, char *dquad);
+extern char *sockaddr2dquad(struct sockaddr_in *sinp); /* Static buffer! */
+extern char *hl2dquad(long addr); /* Static buffer! */
+
+
+/* Access to system or emulated usleep(). */
+
+#ifdef USLEEP
+extern void sf_usleep(unsigned t);
+#define Usleep sf_usleep
+#else
+#define Usleep usleep
+#endif
+
+#define _GENLIB_H
+#endif /* _GENLIB_H */
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/global.h,v 1.5 1999/02/28 20:10:29 ghn Exp $
+ * PURPOSE: Declare global types, constants, and variables
+ * AUTHOR: Greg Nelson
+ * DATE: 98-04-12
+ *
+ * REVISED:
+ * $Log: global.h,v $
+ * Revision 1.5 1999/02/28 20:10:29 ghn
+ * Version 5.1: Added netmask field for egg.
+ *
+ * Revision 1.4 1998/12/31 22:11:05 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.3 1998/08/01 18:51:25 ghn
+ * Added John's byte-order-independence changes.
+ *
+ * Revision 1.2 1998/08/01 17:08:20 ghn
+ * Added upcmd and dncmd for DND.
+ *
+ * Revision 1.1 1998/07/21 11:37:56 ghn
+ * Initial revision
+ *
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+#ifndef _GLOBAL_H
+
+#include <netinet/in.h>
+
+#include "byteorder.h" /* Build byte-order independent version */
+
+/* Good for i386, but be careful... */
+typedef unsigned char byte;
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+typedef char int8;
+typedef short int16;
+typedef long int32;
+
+/* Some fixed assumptions:
+ Trial type is always bitsum.
+ Bit spacing method does not need to be communicated, since we'll
+ choose something at compile time.
+ Record size ranges from one to MAXSAMP_REC trials, which are assumed to
+ be evenly spaced starting at timestamp.
+ Records always begin on round seconds divisible by sec_rec, which
+ can range from one to MAXSEC_REC.
+*/
+
+/* Some adjustable assumptions: */
+
+#define MINBITS 32 /* Minimum bits per trial */
+#define MAXBITS 253 /* Maximum bits per trial */
+#define MAXSAMP_REC 10 /* Maximum samples/record */
+#define MAXSEC_REC 3000 /* Maximum seconds/record */
+
+#define SEC_PKT 60 /* Desired number of seconds per packet */
+#define MAXREC_PKT 60 /* Maximum number of records per packet
+ For 1-second records (typ) this is 1 min */
+
+#define EGG_MISSING_DATA 254 /* Value used to represent missing data in trials array. */
+
+#if MAXBITS < 256
+typedef uint8 trial;
+#else
+#error "Can't represent MAXBITS in a byte value."
+#endif
+
+#if MAXBITS >= EGG_MISSING_DATA
+#error "MAXBITS is >= EGG_MISSING_DATA: ambiguous trial data possible."
+#endif
+
+typedef struct eggrec {
+ uint32 timestamp; /* Seconds since the epoch (19700101000000Z) */
+ trial trials[MAXSAMP_REC]; /* Trial values */
+} EggRec; /* Normally 16 bytes total */
+
+/* Make sure type field of packet is non-zero so that CRC works. */
+
+typedef struct genpacket {
+ uint16 type;
+ uint16 pktsize;
+} GenPacket;
+
+#define DATA_PACKET 0x0101
+typedef struct eggheader {
+ uint16 type; /* type */
+ uint16 pktsize; /* Number of bytes in packet */
+ uint16 eggid; /* Identifying number for device */
+ uint16 samp_rec; /* Number of samples per record */
+ uint16 sec_rec; /* Number of seconds per record */
+ uint16 rec_pkt; /* Number of records per packet */
+ trial trialsz; /* Number of bits per trial */
+ uint16 numrec; /* Number of valid records */
+} EggHeader;
+
+#define REQ_PACKET 0x0202
+typedef struct reqpacket {
+ uint16 type; /* type */
+ uint16 pktsize; /* Number of bytes in packet */
+ uint16 eggid; /* Identifying number for device */
+ uint32 starttm; /* Time for first record to send */
+ uint16 cksum; /* No data, checksum goes inside */
+} ReqPacket;
+
+#define AWAKE_PACKET 0x0303
+typedef struct awakepacket {
+ uint16 type; /* type */
+ uint16 pktsize; /* Number of bytes in packet */
+ uint16 eggid; /* Identifying number for device */
+ uint32 nowtm; /* Egg's identification of "now" (zulu) */
+ uint16 cksum; /* No data, checksum goes inside */
+} AwakePacket;
+
+#define SETTINGS_PACKET 0x0404
+typedef struct setpacket {
+ uint16 type; /* type */
+ uint16 pktsize; /* Number of bytes in packet */
+ uint16 eggid; /* Identifying number for device */
+ uint32 nowtm; /* Egg's identification of "now" (zulu) */
+ uint16 samp_rec; /* Number of samples per record */
+ uint16 sec_rec; /* Number of seconds per record */
+ uint16 rec_pkt; /* Number of records per packet */
+ trial trialsz; /* Number of bits per trial */
+ uint16 cksum; /* No data, checksum goes inside */
+} SettingsPacket;
+
+/* An EggCarton is the in-memory representation of a data
+ packet. Fields in it are thus in host byte order,
+ being translated, as appropriate, when transferred
+ to and from a DATA_PACKET by Packetize() and
+ Unpacketize(). */
+
+typedef struct eggpkt {
+ EggHeader hdr; /* Header (type = DATA_PACKET) */
+ EggRec records[MAXREC_PKT];
+} EggCarton;
+
+typedef struct collect {
+ EggHeader opts;
+ EggRec data;
+ uint16 sampct; /* Count of completed samples in rec */
+ int32 dd; /* Device handle */
+} CollectRecord;
+
+#define CONN_PERM 0
+#define CONN_DND 1
+
+typedef struct eggentry {
+ char *name;
+ int16 id;
+ struct sockaddr_in ipaddr;
+ int16 netmask; /* Number of significant bits, default 32. */
+ char *primbasket;
+ int16 conntype;
+ int16 connival; /* Connect interval in minutes */
+ int32 lastupd; /* Zulutime of last update received */
+ int16 setup; /* Does setup match config file? */
+ char *upcmd; /* Command to bring net up (req if conntype == DND) */
+ char *dncmd; /* Command to bring net down */
+ char *url; /* URL describing basket or NULL */
+} EggEntry;
+
+typedef struct basketentry {
+ char *name;
+ struct sockaddr_in ipaddr;
+} BasketEntry;
+
+#define MAX_EGGS 100
+#define MAX_BASKETS 5
+
+extern EggEntry eggtable[MAX_EGGS];
+extern BasketEntry baskettable[MAX_BASKETS];
+extern short numeggs, numbaskets;
+extern EggHeader protocol;
+
+extern char *pgmname; /* For error messages to announce program name */
+
+#define TRUE -1
+#define FALSE 0
+
+#define _GLOBAL_H
+#endif /* _GLOBAL_H */
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/hw_pear.c,v 1.3 1998/08/01 18:50:39 ghn Exp $
+ * PURPOSE: PEAR (Bradish box/micro-REG) hardware interface
+ * AUTHOR: Greg Nelson
+ * DATE: 98-04-12
+ *
+ * REVISED: $Log: hw_pear.c,v $
+ * REVISED: Revision 1.3 1998/08/01 18:50:39 ghn
+ * REVISED: Added John's byte-order-independence changes and PSEUDO support.
+ * REVISED:
+ * REVISED: Revision 1.2 1998/08/01 17:13:51 ghn
+ * REVISED: Added John's Solaris support and DUMPREG option.
+ * REVISED:
+ * REVISED: Revision 1.1 1998/07/21 11:37:41 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+/* Define this to dump samples from the REG which we actually use into
+ a file named dumpreg.dat. This can be used to debug serial port
+ mode problems (for example, setting the character frame to 7 bits,
+ or telling it to ignore breaks, which will lose all zero bytes. */
+/* #define DUMPREG */
+
+#include <stdio.h>
+#define __USE_BSD
+#include <termios.h>
+#undef __USE_BSD
+#include <unistd.h>
+#include <fcntl.h>
+#define __USE_BSD
+#include <errno.h>
+#undef __USE_BSD
+
+#include "global.h"
+#include "genlib.h"
+#include "hwapi.h"
+
+#define MAXDEV 20
+
+int32 oldbits[MAXDEV], bitsleft[MAXDEV];
+
+#ifdef DUMPREG
+static FILE *dumpfile; /* REG dump file handle */
+static unsigned char dumpbuf[1024]; /* REG dump buffer */
+static int dumpptr = 0; /* Pointer into dump buffer */
+#endif
+
+#ifdef PSEUDORANDOM_TEST
+#include <stdlib.h>
+static int pseudo = FALSE; /* Nonzero if using pseudo-REG */
+#endif
+
+int32 OpenDev(DevOpts *opts) {
+ char ttydev[30];
+ speed_t baudcon;
+ struct termios tt;
+ int32 TTY_fd, res;
+
+#ifdef DUMPREG
+ dumpfile = fopen("dumpreg.dat", "w");
+ setbuf(dumpfile, NULL);
+ dumpptr = 0;
+#endif
+
+#ifdef PSEUDORANDOM_TEST
+ if (opts->type == 0xFF) {
+ TTY_fd = 1;
+ oldbits[TTY_fd] = bitsleft[TTY_fd] = 0;
+ srandom(time(NULL));
+ pseudo = TRUE;
+ fprintf(stderr, "**** WARNING! This egg has been configured to\n\
+ use a pseudorandom sequence generator to\n\
+ permit testing on machines not equipped\n\
+ with an REG. Data from this egg should not\n\
+ be used for analysis.\n");
+ return TTY_fd;
+ }
+#endif
+
+#ifdef Solaris
+ /* Serial ports (at least built-in ones) have names of
+ /dev/term/a, /dev/term/b, etc. Map the port numbers
+ from the RC file into this nomenclature, with "1"
+ designating /dev/term/a. */
+ sprintf(ttydev, "/dev/term/%c", 'a' + (opts->port - 1));
+#else
+ sprintf(ttydev, "/dev/ttyS%d", opts->port);
+#endif
+
+ switch(opts->baud) {
+ case 1200: baudcon = B1200; break;
+ case 2400: baudcon = B2400; break;
+ case 4800: baudcon = B4800; break;
+ case 9600: baudcon = B9600; break;
+ case 19200: baudcon = B19200; break;
+ case 38400: baudcon = B38400; break;
+#ifndef Irix
+ case 115200: baudcon = B115200; break;
+#endif
+ default:
+ printf("%s: Baud rate %ld not supported.\n", pgmname, opts->baud);
+ return -1;
+ }
+
+ fprintf(stderr, "Opening %s at %ld\n", ttydev, opts->baud);
+ if ((TTY_fd = open(ttydev, O_RDWR | O_NDELAY)) < 0) {
+ perror(pgmname);
+ return -1;
+ }
+
+ if (TTY_fd >= MAXDEV) {
+ fprintf(stderr, "%s: Too many devices open.\n", pgmname);
+ close(TTY_fd);
+ return -1;
+ }
+
+ res = tcgetattr(TTY_fd, &tt);
+#ifdef Solaris
+ tt.c_iflag = 0;
+ tt.c_oflag = 0;
+ tt.c_cflag = baudcon | CS8 | CREAD | CLOCAL;
+ tt.c_lflag = 0;
+ tt.c_cc[VMIN] = 1; /* This many chars satisfies reads */
+ tt.c_cc[VTIME] = 0; /* or in this many tenths of seconds */
+#else
+ res = cfsetospeed(&tt, baudcon);
+ cfmakeraw(&tt);
+ tt.c_oflag &= (~(TABDLY | ONLCR));
+#endif
+ res = tcsetattr(TTY_fd, TCSANOW, &tt);
+
+ oldbits[TTY_fd] = bitsleft[TTY_fd] = 0;
+ return TTY_fd;
+}
+
+#define SAMP_PERIOD 1000 /* msec */
+#define MARGIN .95 /* how much to headroom to allow in
+ speed measurement */
+
+int32 EvalSpeed(int32 dd) {
+ struct timeval start, end;
+ int32 bitct, samp;
+
+ if (dd < 0) return -1;
+
+#ifdef PSEUDORANDOM_TEST
+ if (pseudo) {
+ return 500;
+ }
+#endif
+
+ gettimeofday(&start, NULL);
+ bitct = 0;
+ while (1) {
+ gettimeofday(&end, NULL);
+ if (deltams(&end, &start) >= SAMP_PERIOD) break;
+ samp = Sample(dd, 1);
+ bitct++;
+ }
+
+ return (int32)(bitct * MARGIN);
+}
+
+int32 Sample(int32 dd, uint16 bits) {
+ int32 bc, sum, n1;
+ uint8 c1;
+
+ if (dd < 0) return -1;
+
+ sum = bc = 0;
+ while (bc < bits) {
+ if (bitsleft[dd]) {
+ sum += (oldbits[dd] & 0x01);
+ oldbits[dd] >>= 1;
+ bitsleft[dd]--;
+ bc++;
+ } else {
+ do {
+#ifdef PSEUDORANDOM_TEST
+ if (pseudo) {
+ n1 = 1;
+ c1 = (uint8) ((random() >> 5) & 0xFF);
+ } else
+#endif
+ n1 = read(dd, &c1, 1);
+ } while (n1 == 0 || (n1 == -1 && errno == EAGAIN));
+ if (n1 == -1) {
+ /* Fatal error occurred, die now? */
+ return -1;
+ }
+#ifdef DUMPREG
+ dumpbuf[dumpptr++] = c1;
+ if (dumpptr >= sizeof(dumpbuf)) {
+ fwrite(dumpbuf, sizeof(dumpbuf), 1, dumpfile);
+ dumpptr = 0;
+ }
+#endif
+ oldbits[dd] = c1;
+ bitsleft[dd] = 8;
+ }
+ }
+
+ return sum;
+}
+
+int32 Discard(int32 dd) {
+ int32 disc, n1;
+ uint8 c1;
+
+ if (dd < 0) return -1;
+
+ disc = bitsleft[dd];
+ bitsleft[dd] = 0;
+
+#ifdef PSEUDORANDOM_TEST
+ if (pseudo) {
+ return 32;
+ }
+#endif
+
+ do {
+ n1 = read(dd, &c1, 1);
+ if (n1 == 1) disc++;
+ } while (n1 == 1);
+
+ return disc;
+}
+
+int32 CloseDev(int32 dd) {
+ if (dd < 0) return -1;
+
+#ifdef PSEUDORANDOM_TEST
+ if (!pseudo)
+#endif
+ close(dd);
+ return 0;
+}
+
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/ghn/projects/PEAR/egg/eggsh/RCS/hwapi.h,v 1.1 1998/07/21 11:37:32 ghn Exp $
+ * PURPOSE: Define interface to hardware layer
+ * AUTHOR: Greg Nelson
+ * DATE: 98-04-12
+ *
+ * REVISED: $Log: hwapi.h,v $
+ * REVISED: Revision 1.1 1998/07/21 11:37:32 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ */
+
+typedef struct devopts {
+ uint16 type; /* 0 = PEAR */
+ uint16 port;
+ uint32 baud;
+} DevOpts;
+
+/* Open a device.
+
+ DevOpts should contain any necessary information to determine how
+ this is to be done. The return value, if >= 0, is a device handle.
+ Otherwise it indicated an error. */
+int32 OpenDev(DevOpts *opts);
+
+/* Evaluate speed.
+
+ dd is the device handle returned by opening the device. The
+ function returns the estimated number of bits/second that the
+ device will produce, which should be used as a limit in setting the
+ data rate. */
+int32 EvalSpeed(int32 dd);
+
+/* Sample from a device.
+
+ dd is the device handle returned by opening the device. The number
+ of bits requested will be sampled from the device immediately
+ (waiting as needed to collect the data, with no discards) and the
+ result will be returned. */
+int32 Sample(int32 dd, uint16 bits);
+
+/* Discard spare data from device.
+
+ dd is the device handle returned by opening the device. The input
+ stream is consumed until a wait would be required. The number of
+ bits discarded is returned. */
+int32 Discard(int32 dd);
+
+/* Close a device.
+
+ Closes a specified device handle. */
+int32 CloseDev(int32 dd);
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/ipproto.c,v 1.1 1998/07/21 11:37:21 ghn Exp $
+ * PURPOSE: Declarations/definitions of IP data protocols for Egg
+ * AUTHOR: Greg Nelson
+ * DATE: 98-04-12
+ *
+ * REVISED: $Log: ipproto.c,v $
+ * REVISED: Revision 1.1 1998/07/21 11:37:21 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+#include <string.h>
+#include "global.h"
+#include "crc16.h"
+
+int32 PackPacket(char *buf, uint32 bufsize, EggCarton *cart) {
+ int32 rec, ntrl, llen;
+ uint16 crc;
+
+ if (bufsize < sizeof(EggHeader)) return -1;
+
+ memcpy(buf, &(cart->hdr), sizeof(EggHeader));
+ buf += sizeof(EggHeader);
+
+ ntrl = card->hdr.reclen;
+ llen = sizeof(uint32) + ntrl * sizeof(trial);
+
+ for (rec = 0; rec < cart->hdr.numrec; rec++) {
+ memcpy(buf, &(card->records[rec].timestamp), sizeof(uint32));
+ memcpy(buf + sizeof(uint32),
+ &(card->records[rec].trials), ntrl * sizeof(trial));
+ crc = BlockCRC16((byte *)buf, llen);
+ memcpy(buf + llen, &crc, sizeof(uint16));
+ buf += llen + sizeof(uint16);
+ }
+}
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/ghn/projects/PEAR/egg/eggsh/RCS/ipproto.h,v 1.1 1998/07/21 11:37:06 ghn Exp $
+ * PURPOSE: Declarations/definitions of IP data protocols for Egg
+ * AUTHOR: Greg Nelson
+ * DATE: 98-04-12
+ *
+ * REVISED: $Log: ipproto.h,v $
+ * REVISED: Revision 1.1 1998/07/21 11:37:06 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+#include "global.h"
+
+uint32 PackPacket(char *buf, uint32 bufsize, EggCarton *cart);
--- /dev/null
+/*
+
+ L'Ecuyer's two-sequence pseudorandom generator with a 32 cell
+ Bays-Durham shuffle on the back end.
+
+ When updating the individual generators, an intermediate value as
+ large as 64 bits is required. Many modern C compilers provide a
+ "long long" 64-bit integer type. If this type is available,
+ compile this file with LONGLONG defined and it will be used,
+ generally improving execution speed. If the compiler does not
+ implement "long long", compile without LONGLONG and Schrage's
+ algorithm will be used to perform the computation using only
+ 32 bit arithmetic.
+
+ For additional details, see L'Ecuyer's paper:
+
+ L'Ecuyer, P. "Communications of the ACM", Vol. 31, p. 742 (1988).
+
+ and that of Bays and Durham:
+
+ Bays, Carter, and S.D. Durham. "ACM Transactions on
+ Mathematical Software", Vol. 2, p. 59 (1976).
+
+ Schrage's multiple-precision modular algorithm is described in:
+
+ Schrage, P. "ACM Transactions on Mathematical Software",
+ Vol. 5, p. 132 (1979).
+
+*/
+
+#include <stdio.h>
+#include <assert.h>
+
+#define LONGLONG
+
+#ifdef LONGLONG
+#define int64 long long
+#else
+#define int64 long
+#endif
+#define int32 long
+
+/* L'Ecuyer's recommended multiplier and modulus for the two
+ multiplicative congruential generators. Even though the
+ values fit in 32 bits, we declare them as int64 so that the
+ arithmetic in calculating the next value will be automatically
+ done in int64 without need for casting when LONGLONG is defined.
+ In a non-LONGLONG build int64 is defined as long, so these values
+ participate correctly in the Schrage algorithm computation. */
+
+#define mul1 ((int64) 40014)
+#define mod1 ((int64) 2147483563)
+#define mul2 ((int64) 40692)
+#define mod2 ((int64) 2147483399)
+
+#define shuffleSize 32 /* Shuffle table size */
+#define warmup 19 /* Number of initial warmup results to "burn" */
+
+static int32 gen1, gen2, state;
+static int32 shuffle[shuffleSize]; /* Bays-Durham shuffle table */
+
+/* Update generator which, using either long long arithmetic or
+ Schrage's algorithm depending on whether LONGLONG is defined.
+ The definition for Schrage's algorithm relies, for efficiency,
+ on the C compiler performing compile-time constant arithmetic
+ for the quotient and remainder of the modulus and multiplier.
+ If you're porting this to a language which lacks that feature,
+ you'll want to predefine the quotient and remainder for each
+ generator and use the explicit values. */
+
+#ifdef LONGLONG
+#define updgen(which) gen##which = (int32) ((gen##which * mul##which) % mod##which)
+#else
+#define updgen(which) { \
+ int32 t = gen##which / (mod##which / mul##which); \
+ \
+ gen##which = mul##which * (gen##which - (t * (mod##which / mul##which))) - \
+ t * ((mod##which % mul##which)); \
+ if (gen##which < 0) { \
+ gen##which += mod##which; \
+ } \
+ }
+#endif
+
+/* LEsetSeed -- Set seed for generator. Subsequent values will be based
+ on the given nonzero seed. */
+
+void LEsetSeed(int32 seed)
+{
+ int32 i;
+
+ assert(seed != 0);
+
+ gen1 = gen2 = (int32) (seed & 0x7FFFFFFFL);
+
+ /* "Warm up" the generator for a number of rounds to eliminate
+ any residual inflence of the seed. */
+
+ for (i = 0; i < warmup; i++) {
+ updgen(1);
+ }
+
+ /* Fill the shuffle table with values. */
+
+ for (i = 0; i < shuffleSize; i++) {
+ updgen(1);
+ shuffle[(shuffleSize - 1) - i] = gen1;
+ }
+ state = shuffle[0];
+}
+
+/* LEnextByte -- Get next byte from generator. */
+
+unsigned char LEnextByte(void)
+{
+ int i;
+
+ updgen(1);
+ updgen(2);
+
+ /* Extract shuffle table index from most significant part
+ of the previous result. */
+
+ i = state / (1 + (((int32) mod1) - 1) / shuffleSize);
+
+ /* New state is sum of generators modulo one of their moduli. */
+
+ state = (int32) (((shuffle[i]) + ((unsigned int32) gen2)) % mod1);
+
+ /* Replace value in shuffle table with generator 1 result. */
+
+ shuffle[i] = gen1;
+
+ return (unsigned char) (state / (1 + (((int32) mod1) - 1) / 256));
+}
--- /dev/null
+/*
+
+ Definitions for L'Ecuyer pseudorandom sequence generator.
+
+*/
+
+extern void LEsetSeed(long seed);
+extern unsigned char LEnextByte(void);
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/network.c,v 1.7 1999/02/28 20:14:20 ghn Exp $
+ * PURPOSE: Network communication functions
+ * AUTHOR: Greg Nelson
+ * DATE: 98-05-09
+ *
+ * REVISED:
+ * $Log: network.c,v $
+ * Revision 1.7 1999/02/28 20:14:20 ghn
+ * Version 5.1: Modified InitNetwork to take interface (addr) argument as
+ * well as port, and handle various cases of interface (NULL, IP,
+ * hostname) gracefully. Modified NetUp to call this new version.
+ *
+ * Revision 1.6 1999/01/02 00:01:01 ghn
+ * Socket and sockaddr_in corrections suggested by Mike Cheponis
+ * incorporated.
+ * perror() turned off for ENETUNREACH/EHOSTUNREACH unless app specifies
+ * "gripe" argument to NetTalk.
+ *
+ * Revision 1.5 1998/12/31 22:07:56 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.4 1998/08/03 20:39:03 kelvin
+ * inet_ntoa warning fix, bad packet diagnostics.
+ *
+ * Revision 1.3 1998/08/01 18:51:25 ghn
+ * Added John's byte-order-independence changes.
+ *
+ * Revision 1.2 1998/08/01 17:16:39 ghn
+ * Added DND support and John's typecasts.
+ *
+ * Revision 1.1 1998/07/21 11:36:45 ghn
+ * Initial revision
+ *
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include <string.h>
+#include "global.h"
+#include "genlib.h"
+#include "network.h"
+#include "errnos.h"
+
+#define MAXBUFSIZE 512
+char buffer[MAXBUFSIZE];
+
+/* Eventually, these might deal with encryption and decryption or
+ validation processes, but until such time as we actually do
+ something with these, they are no-ops. */
+#define PktEncrypt(buf, len) ERR_NONE
+#define PktDecrypt(buf, len) ERR_NONE
+
+#ifdef HEXDUMP
+extern void xd(FILE *out, void *bub, int bufl, int dochar);
+#endif
+
+int32 InitNetwork(char *addr, int32 port) {
+ struct protoent *pp;
+ struct hostent *hp;
+ struct sockaddr_in sin;
+ struct utsname uts;
+ int32 sd;
+ int32 argp;
+
+ if ((pp = getprotobyname("udp")) == NULL) {
+ perror("getprotobyname");
+ exit(-1);
+ }
+
+ /* Optimistically: */
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_port = htons(port);
+ sin.sin_family = AF_INET;
+
+ /* Try to convert dotted quad. Hope this is okay for null addr? */
+ if (!addr || !inet_aton(addr, &(sin.sin_addr))) {
+ /* Nope, so try to gethostbyname */
+ if (!addr) {
+ /* No addr at all, use host name from uname */
+ if (uname(&uts) < 0) {
+ perror("uname");
+ exit(-1);
+ }
+ } else {
+ strcpy(uts.nodename, addr);
+ }
+
+ if ((hp = gethostbyname(uts.nodename)) == NULL) {
+ fprintf(stderr, "gethostbyname(%s): %s", uts.nodename, strerror(errno));
+ exit(-1);
+ }
+
+ if (hp->h_addrtype != AF_INET) {
+ fprintf(stderr, "Host is not on the internet!\n");
+ exit(-1);
+ }
+
+ memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length);
+ }
+
+ if ((sd = socket(PF_INET, SOCK_DGRAM, 0)) <= 0) {
+ printf("Could not make socket\n");
+ exit(-1);
+ }
+
+ if (bind(sd, (struct sockaddr *)(&sin), sizeof(sin)) != 0) {
+ if (errno == EADDRNOTAVAIL) {
+ /* Network probably not up yet. */
+ close(sd); /* Error pointed out my Mike Cheponis */
+ return ERR_NOREPLY;
+ }
+ perror("bind");
+ exit(-1);
+ }
+
+ argp = 1;
+#ifndef Solaris
+ if (ioctl(sd, FIONBIO, (char *)&argp) != 0) {
+ perror("ioctl FIONBIO");
+ exit(-1);
+ }
+#endif
+
+ return sd;
+}
+
+/* Bring net up with command */
+int32 NetUp(char *cmd, char *addr, int32 port) {
+ int res;
+
+ res = system(cmd);
+ /* 0x7e00 = perm denied
+ 0x7f00 = command not found
+ 256 * cmd if command runs */
+ if (res != 0) return ERR_OTHER;
+
+ return InitNetwork(addr, port);
+}
+
+/* Bring net down with command */
+int NetDown(char *cmd, int32 oldsd) {
+ int res;
+
+ /* Close existing connection */
+ if (oldsd >= 0) close(oldsd);
+
+ res = system(cmd);
+ if (res != 0) return ERR_OTHER;
+
+ return ERR_NONE;
+}
+
+int NetGetAddr(struct sockaddr_in *sin, char *host, uint16 port) {
+ struct hostent *hp;
+
+ if ((hp = gethostbyname(host)) == NULL) {
+ fprintf(stderr, "gethostbyname(%s): %s", host, strerror(errno));
+ return ERR_INRANGE;
+ }
+
+ if (hp->h_addrtype != AF_INET) {
+ fprintf(stderr, "Host is not on the internet!\n");
+ return ERR_INRANGE;
+ }
+
+ memset(sin, 0, sizeof(struct sockaddr_in));
+ sin->sin_port = htons(port);
+ sin->sin_family = AF_INET;
+ memcpy(&(sin->sin_addr), hp->h_addr, hp->h_length);
+
+ return ERR_NONE;
+}
+
+/* Listen for a data request.
+
+ Listen on specified socket sd. When one is received, validate the
+ checksum, and, if successful, allocate memory and stuff it as a
+ character array. Return the remote sockaddr_in, if the sin pointer
+ is not null, and block until something interesting happens if block
+ is true. */
+int NetListen(int sd, char **pktbuf,
+ struct sockaddr_in *sin,
+ int block) {
+ fd_set fdset;
+ struct timeval timeout, *top;
+ int32 nfound;
+ int32 size;
+ int32 count;
+ int32 res;
+ short pktsize;
+ uint16 pkttype, cksumt, cksumc;
+
+ if (sd < 0) return ERR_INRANGE;
+
+ FD_ZERO(&fdset);
+ FD_SET(sd, &fdset);
+ timeout.tv_sec = timeout.tv_usec = 0;
+
+ /* Wait for an incoming connection.
+ If block is true, we wait indefinitely; otherwise, we
+ return immediately because of zero timeout. */
+
+ if (block) top = NULL; else top = &timeout;
+ nfound = select(FD_SETSIZE, &fdset, 0, 0, top);
+
+ if (nfound < 0) {
+ if (errno == EWOULDBLOCK) return ERR_COMM_TMOUT;
+ perror("select");
+ return ERR_OTHER;
+ }
+
+ /* No connections, go back to main loop. */
+ if (nfound == 0) return ERR_COMM_TMOUT;
+
+#ifdef DEBUG
+ fprintf(stderr, "Net port got a request!\n");
+#endif
+
+ if (!FD_ISSET(sd, &fdset)) {
+ fprintf(stderr, "Confused condition -- FD not part of set.\n");
+ return 0;
+ }
+
+ size = sizeof(*sin);
+ count = recvfrom(sd, buffer, MAXBUFSIZE, 0,
+ (struct sockaddr *)sin, (int *)&size);
+ if (count < 0) {
+ /* Don't wait for it. */
+ if (errno == EWOULDBLOCK) return ERR_COMM_TMOUT;
+ perror("recvfrom");
+ return ERR_OTHER;
+ }
+
+#ifdef HEXDUMP
+ fprintf(stderr, "Received %ld bytes from %s\n", count,
+ inet_ntoa(sin->sin_addr));
+ xd(stderr, buffer, count, FALSE);
+#endif
+
+ /* Mangle buffer as needed */
+ if ((res = PktDecrypt(buffer, count)) < 0) {
+ fprintf(stderr, "Packet decryption failed with %d.\n", (int)res);
+ return res;
+ }
+
+ /* Verify length and CRC of packet. In making these
+ protocol-level sanity checks, we transform the relevant
+ fields in the packet from network to host byte order
+ as required. Note, however, that the packet returned
+ to the caller remains, in its entirety, in network
+ byte order and even references to protocol-common
+ fields, if made, must be converted by the code which
+ invokes this function. */
+
+ { uint16 rpkttype, rpktsize, rcrc;
+
+ memcpy(&rpkttype, buffer, sizeof rpkttype);
+ memcpy(&rpktsize, buffer + 2, sizeof rpktsize);
+ memcpy(&rcrc, buffer + (count - 2), sizeof rcrc);
+ pktsize = ntohs(rpktsize);
+ if (pktsize != count) {
+#ifdef DEBUG
+ fprintf(stderr, "** Bad packet length: pktsize = %d, count = %ld.\n",
+ pktsize, count);
+#endif
+ return ERR_PKT_BADLEN;
+ }
+ cksumt = ntohs(rcrc);
+ cksumc = BlockCRC16((byte *) buffer, count - 2);
+ if (cksumc != cksumt) {
+#ifdef DEBUG
+ fprintf(stderr, "** Bad packet CRC: packet = %04X, computed = %04X.\n",
+ cksumt, cksumc);
+#endif
+ return ERR_PKT_CKSUM;
+ }
+ pkttype = ntohs(rpkttype);
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "Recv packet type %04x, %d bytes (hdr), cks = %04x\n",
+ pkttype, pktsize, cksumt);
+#endif /* DEBUG */
+
+ /* Hand back the packet */
+ *pktbuf = (char *)malloc(count);
+ memcpy(*pktbuf, buffer, count);
+
+ return ERR_NONE;
+}
+
+/* Send a data packet.
+
+ Checksum the packet, create a socket, and send it to the specified
+ port of the specified host. Length of packet to be extracted from
+ packet header. */
+
+ /* The entire contents of the packet passed to NetTalk must
+ be in network byte order. Fields within the packet used
+ to append the CRC, determine the number of bytes to send,
+ etc. are converted to host byte order as needed. */
+
+int NetTalk(struct sockaddr_in *sin, char *pkt, int gripe) {
+ uint16 pktsize, cksum;
+ static struct protoent *pp = NULL;
+ int i, out_sock;
+
+ memcpy(&pktsize, pkt + 2, 2);
+ pktsize = ntohs(pktsize);
+#ifdef DEBUG
+ if (pktsize > 1500) {
+ fprintf(stderr, "Bogus packet size of %ud bytes. Suspect byte alignment bug.\n", pktsize);
+ abort();
+ }
+#endif
+ cksum = htons(BlockCRC16((byte *) pkt, pktsize - sizeof(uint16)));
+ memcpy(pkt+pktsize-sizeof(uint16), &cksum, sizeof(uint16));
+
+ if (pp == NULL) { /* Only get protocol code the first time */
+ if ((pp = getprotobyname("udp")) == NULL) {
+ perror("getprotobyname");
+ return ERR_OTHER;
+ }
+ }
+
+ if ((out_sock = socket(AF_INET, SOCK_DGRAM, pp->p_proto)) < 0) {
+ perror("socket");
+ return ERR_OTHER;
+ }
+
+ i = sendto(out_sock, pkt, pktsize,
+ 0, (struct sockaddr *)sin,
+ sizeof(struct sockaddr));
+ if (i == -1) {
+ /* We only report on certain errors if told to "gripe", because
+ it is a normal occurence if in PERM mode with a variably
+ available net connection. */
+ if ((errno != ENETUNREACH && errno != EHOSTUNREACH) || gripe) perror("sendto");
+ close(out_sock);
+ return ERR_OTHER;
+ }
+
+#ifdef HEXDUMP
+ fprintf(stderr, "Sent %d bytes to %s\n", pktsize, inet_ntoa(sin->sin_addr));
+ xd(stderr, pkt, pktsize, FALSE);
+#endif
+
+ i = close(out_sock);
+ if (i < 0) {
+ perror("close");
+ }
+
+ return ERR_NONE;
+}
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/network.h,v 1.6 1999/02/28 20:14:26 ghn Exp $
+ * PURPOSE: Definitions for network communication functions
+ * AUTHOR: Greg Nelson
+ * DATE: 98-05-09
+ *
+ * REVISED:
+ * $Log: network.h,v $
+ * Revision 1.6 1999/02/28 20:14:26 ghn
+ * Version 5.1: Modified InitNetwork to take interface (addr) argument as
+ * well as port, and handle various cases of interface (NULL, IP,
+ * hostname) gracefully. Modified NetUp to call this new version.
+ *
+ * Revision 1.5 1999/01/02 00:02:24 ghn
+ * Modified NetTalk() api to offer "gripe" argument to silence some perror()s.
+ *
+ * Revision 1.4 1998/12/31 22:11:05 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.3 1998/08/01 18:51:25 ghn
+ * Added John's byte-order-independence changes.
+ *
+ * Revision 1.2 1998/08/01 17:17:40 ghn
+ * Added DND support.
+ *
+ * Revision 1.1 1998/07/21 11:36:34 ghn
+ * Initial revision
+ *
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+#ifndef _NETWORK_H
+#define _NETWORK_H
+
+#include <netinet/in.h>
+
+#ifdef TESTPORT
+#define EGGPORT 2074
+#define BASKETPORT 2075
+#else
+#define EGGPORT 1105
+#define BASKETPORT 2510
+#endif
+
+/* Initialize network subsystem, returning socket descriptor */
+extern int32 InitNetwork(char *addr, int32 port);
+
+/* Bring net up with command */
+extern int32 NetUp(char *cmd, char *addr, int32 port);
+
+/* Bring net down with command */
+extern int NetDown(char *cmd, int32 oldsd);
+
+/* Get a sockaddr given a host and port */
+extern int NetGetAddr(struct sockaddr_in *sin, char *host, uint16 port);
+
+/* Listen for a data request.
+
+ Listen on specified socket sd. When one is received, validate the
+ checksum, and, if successful, allocate memory and stuff it as a
+ character array. Return the remote sockaddr_in, if the sin pointer
+ is not null, and block until something interesting happens if block
+ is true. */
+extern int NetListen(int sd, char **pktbuf,
+ struct sockaddr_in *sin,
+ int block);
+
+/* Send a data packet.
+
+ Create a socket, checksum the packet, and send it to the specified
+ addr in sin. Length of packet to be extracted from packet
+ header. */
+extern int NetTalk(struct sockaddr_in *sin, char *pkt, int gripe);
+
+#endif /* !_NETWORK_H */
--- /dev/null
+/*
+
+ Random event generator definitions
+
+ This file contains definitions common to all random
+ event generators. All implement the interface defined
+ here.
+
+*/
+
+
+typedef struct {
+ uint16 type; /* Device type code (allows supporting
+ multiple devices with common driver
+ code). */
+ uint16 port; /* Port ID. Meaning depends on nature
+ of hardware, and may mean nothing at
+ all. */
+ uint32 baud; /* Baud rate for devices connected to
+ a serial port. This may have a
+ different meaning for devices
+ connected to, for example, a
+ parallel port or SCSI string. */
+} DevOpts;
+
+typedef struct {
+ char *reg_name; /* Name of REG, corresponding to
+ the name on the REG statement
+ in .eggrc */
+ uint16 reg_type; /* REG type code, corresponding
+ to type field in the DevOpts
+ structure. */
+
+ /* The following functions are used to call the methods
+ of the REG device driver. */
+
+ /* Open a device.
+
+ DevOpts should contain any necessary information to determine how
+ this is to be done. The return value, if >= 0, is a device handle.
+ Otherwise it indicates an error. */
+
+ int32 (*reg_OpenDev)(DevOpts *opts);
+
+ /* Evaluate speed.
+
+ dd is the device handle returned by opening the device. The
+ function returns the estimated number of bits/second that the
+ device will produce, which should be used as a limit in setting the
+ data rate. */
+
+ int32 (*reg_EvalSpeed)(int32 dd);
+
+ /* Sample from a device.
+
+ dd is the device handle returned by opening the device. The number
+ of bits requested will be sampled from the device immediately
+ (waiting as needed to collect the data, with no discards) and the
+ result will be returned. */
+
+ int32 (*reg_Sample)(int32 dd, uint16 bits);
+
+ /* Discard spare data from device.
+
+ dd is the device handle returned by opening the device. The input
+ stream is consumed until a wait would be required. The number of
+ bits discarded is returned. */
+
+ int32 (*reg_Discard)(int32 dd);
+
+ /* Close a device.
+
+ Closes a specified device handle. */
+
+ int32 (*reg_CloseDev)(int32 dd);
+} REG_driver;
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/reg_orion.c,v 1.1 1998/12/31 22:04:39 ghn Exp $
+ * PURPOSE: PEAR (Bradish box/micro-REG) hardware interface
+ * AUTHOR: Greg Nelson
+ * DATE: 98-04-12
+ *
+ * REVISED: $Log: reg_orion.c,v $
+ * REVISED: Revision 1.1 1998/12/31 22:04:39 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * REVISED: Revision 1.3 1998/08/01 18:50:39 ghn
+ * REVISED: Added John's byte-order-independence changes and PSEUDO support.
+ * REVISED:
+ * REVISED: Revision 1.2 1998/08/01 17:13:51 ghn
+ * REVISED: Added John's Solaris support and DUMPREG option.
+ * REVISED:
+ * REVISED: Revision 1.1 1998/07/21 11:37:41 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+/* Define this to dump samples from the REG which we actually use into
+ a file named dumpreg.dat. This can be used to debug serial port
+ mode problems (for example, setting the character frame to 7 bits,
+ or telling it to ignore breaks, which will lose all zero bytes. */
+/* #define DUMPREG */
+
+#include <stdio.h>
+#ifdef __USE_BSD
+#undef __USE_BSD
+#endif
+#define __USE_BSD
+#include <termios.h>
+#undef __USE_BSD
+#include <unistd.h>
+#include <fcntl.h>
+#define __USE_BSD
+#include <errno.h>
+#undef __USE_BSD
+
+#include "global.h"
+#include "genlib.h"
+#include "reg.h"
+
+#define MAXDEV 20
+
+/* The Orion REG is powered by the serial port into which
+ it is plugged. If the port is not providing power to
+ the REG before we initialise it, the REG may deliver
+ garbage data as the power comes up. To guard against
+ this we take two precautions. First of all, we sleep
+ REG_INIT seconds after initialising the serial port to
+ let the REG start up and stabilise after power is
+ turned on, and we further discard REG_DISCARD initial
+ samples which may have been queued as the REG was
+ powering up. If either of these symbols is not defined
+ or zero, the corresponding start-up action will not
+ be taken. */
+
+#define REG_INIT 10 /* REG power on delay */
+#define REG_DISCARD 1024 /* Bytes to discard at start-up */
+
+static int32 oldbits[MAXDEV], bitsleft[MAXDEV];
+
+#ifdef DUMPREG
+static FILE *dumpfile; /* REG dump file handle */
+static unsigned char dumpbuf[1024]; /* REG dump buffer */
+static int dumpptr = 0; /* Pointer into dump buffer */
+#endif
+
+#ifdef FLUSH
+extern int flush_fd; /* File descriptor for auto-flush */
+#endif
+
+static int32 OpenDev(DevOpts *opts) {
+ char ttydev[30];
+ speed_t baudcon;
+ struct termios tt;
+ int32 TTY_fd, res;
+
+#ifdef DUMPREG
+ dumpfile = fopen("dumpreg.dat", "w");
+ setbuf(dumpfile, NULL);
+ dumpptr = 0;
+#endif
+
+#ifdef Solaris
+ /* Serial ports (at least built-in ones) have names of
+ /dev/term/a, /dev/term/b, etc. Map the port numbers
+ from the RC file into this nomenclature, with "1"
+ designating /dev/term/a. */
+#ifdef Irix
+ sprintf(ttydev, "/dev/ttyd%d", opts->port);
+#else
+ sprintf(ttydev, "/dev/term/%c", 'a' + (opts->port - 1));
+#endif
+#else
+ sprintf(ttydev, "/dev/ttyS%d", opts->port);
+#endif
+
+ switch(opts->baud) {
+ case 1200: baudcon = B1200; break;
+ case 2400: baudcon = B2400; break;
+ case 4800: baudcon = B4800; break;
+ case 9600: baudcon = B9600; break;
+ case 19200: baudcon = B19200; break;
+ case 38400: baudcon = B38400; break;
+#ifndef Irix
+ case 115200: baudcon = B115200; break;
+#endif
+ default:
+ printf("%s: Baud rate %ld not supported.\n", pgmname, opts->baud);
+ return -1;
+ }
+
+ fprintf(stderr, "Opening %s at %ld\n", ttydev, opts->baud);
+ if ((TTY_fd = open(ttydev, O_RDONLY
+#ifdef CPU_BOUND
+ | O_NDELAY
+#endif
+ )) < 0) {
+ perror(pgmname);
+fprintf(stderr, "Error in open(%s)\n", ttydev);
+ return -1;
+ }
+
+ if (TTY_fd >= MAXDEV) {
+ fprintf(stderr, "%s: Too many devices open.\n", pgmname);
+ close(TTY_fd);
+ return -1;
+ }
+
+ res = tcgetattr(TTY_fd, &tt);
+#ifdef Solaris
+ tt.c_iflag = 0;
+ tt.c_oflag = 0;
+#ifdef SWITCH_READ
+ tt.c_cflag = baudcon | CS8 | CLOCAL;
+#else
+ tt.c_cflag = baudcon | CS8 | CREAD | CLOCAL;
+#endif
+ tt.c_lflag = 0;
+ tt.c_cc[VMIN] = 1; /* This many chars satisfies reads */
+ tt.c_cc[VTIME] = 0; /* or in this many tenths of seconds */
+#else
+ res = cfsetospeed(&tt, baudcon);
+ cfmakeraw(&tt);
+ tt.c_oflag &= (~(TABDLY | ONLCR));
+#endif
+ res = tcsetattr(TTY_fd, TCSANOW, &tt);
+
+ oldbits[TTY_fd] = bitsleft[TTY_fd] = 0;
+
+ /* Perform start-up power on delay and data flush. */
+
+#ifdef REG_INIT
+ if (REG_INIT > 0) {
+ sleep(REG_INIT);
+ }
+#endif
+
+#ifdef REG_DISCARD
+ if (REG_DISCARD > 0) {
+ int d, n1;
+ char c1;
+
+ for (d = 0; d < REG_DISCARD; d++) {
+ do {
+ n1 = read(TTY_fd, &c1, 1);
+ } while (n1 == 0 || (n1 == -1 && errno == EAGAIN));
+ }
+ }
+#endif
+
+#ifdef FLUSH
+ flush_fd = TTY_fd;
+#endif
+
+ return TTY_fd;
+}
+
+static int32 Sample(int32 dd, uint16 bits) {
+ int32 bc, sum, n1;
+ uint8 c1;
+
+#ifdef Solaris
+#ifdef SWITCH_READ
+ struct termios tt;
+
+ tcgetattr(dd, &tt);
+ tt.c_cflag |= CREAD;
+ tcsetattr(dd, TCSANOW, &tt);
+#endif
+#endif
+
+ if (dd < 0) return -1;
+
+ sum = bc = 0;
+ while (bc < bits) {
+ if (bitsleft[dd]) {
+ sum += (oldbits[dd] & 0x01);
+ oldbits[dd] >>= 1;
+ bitsleft[dd]--;
+ bc++;
+ } else {
+ do {
+ n1 = read(dd, &c1, 1);
+ } while (n1 == 0 || (n1 == -1 && errno == EAGAIN));
+ if (n1 == -1) {
+ /* Fatal error occurred, die now? */
+ return -1;
+ }
+
+ /* Orion REG does not compensate for first order bias. XOR
+ each sample with 01010101b to invert the sense of
+ alternate bits in the samples. */
+
+ c1 ^= 0x55;
+#ifdef DUMPREG
+ dumpbuf[dumpptr++] = c1;
+ if (dumpptr >= sizeof(dumpbuf)) {
+ fwrite(dumpbuf, sizeof(dumpbuf), 1, dumpfile);
+ dumpptr = 0;
+ }
+#endif
+ oldbits[dd] = c1;
+ bitsleft[dd] = 8;
+ }
+ }
+
+#ifdef Solaris
+#ifdef SWITCH_READ
+ tcgetattr(dd, &tt);
+ tt.c_cflag &= ~CREAD;
+ tcsetattr(dd, TCSANOW, &tt);
+#endif
+#endif
+ return sum;
+}
+
+#define SAMP_PERIOD 1000 /* msec */
+#define MARGIN .95 /* how much to headroom to allow in
+ speed measurement */
+
+static int32 EvalSpeed(int32 dd) {
+ struct timeval start, end;
+ int32 bitct, samp;
+
+ if (dd < 0) return -1;
+
+ gettimeofday(&start, NULL);
+ bitct = 0;
+ while (1) {
+ gettimeofday(&end, NULL);
+ if (deltams(&end, &start) >= SAMP_PERIOD) break;
+ samp = Sample(dd, 1);
+ bitct++;
+ }
+
+ return (int32)(bitct * MARGIN);
+}
+
+static int32 Discard(int32 dd) {
+ int32 disc;
+#ifdef CPU_BOUND
+ int32 n1;
+ uint8 c1;
+#endif
+
+ if (dd < 0) return -1;
+
+ disc = bitsleft[dd];
+ bitsleft[dd] = 0;
+
+#ifdef CPU_BOUND
+ do {
+ n1 = read(dd, &c1, 1);
+ if (n1 == 1) disc++;
+ } while (n1 == 1);
+#else
+ tcflush(dd, TCIFLUSH);
+#endif
+
+ return disc;
+}
+
+static int32 CloseDev(int32 dd) {
+ if (dd < 0) return -1;
+
+ close(dd);
+ return 0;
+}
+
+/* Driver description table. */
+
+REG_driver REG_orion = {
+ "ORION",
+ 1000,
+ OpenDev,
+ EvalSpeed,
+ Sample,
+ Discard,
+ CloseDev
+ };
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/reg_pear.c,v 1.1 1998/12/31 22:04:39 ghn Exp $
+ * PURPOSE: PEAR (Bradish box/micro-REG) hardware interface
+ * AUTHOR: Greg Nelson
+ * DATE: 98-04-12
+ *
+ * REVISED: $Log: reg_pear.c,v $
+ * REVISED: Revision 1.1 1998/12/31 22:04:39 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * REVISED: Revision 1.3 1998/08/01 18:50:39 ghn
+ * REVISED: Added John's byte-order-independence changes and PSEUDO support.
+ * REVISED:
+ * REVISED: Revision 1.2 1998/08/01 17:13:51 ghn
+ * REVISED: Added John's Solaris support and DUMPREG option.
+ * REVISED:
+ * REVISED: Revision 1.1 1998/07/21 11:37:41 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+/* Define this to dump samples from the REG which we actually use into
+ a file named dumpreg.dat. This can be used to debug serial port
+ mode problems (for example, setting the character frame to 7 bits,
+ or telling it to ignore breaks, which will lose all zero bytes. */
+/* #define DUMPREG */
+
+#include <stdio.h>
+#ifdef __USE_BSD
+#undef __USE_BSD
+#endif
+#define __USE_BSD
+#include <termios.h>
+#undef __USE_BSD
+#include <unistd.h>
+#include <fcntl.h>
+#define __USE_BSD
+#include <errno.h>
+#undef __USE_BSD
+
+#include "global.h"
+#include "genlib.h"
+#include "reg.h"
+
+#define MAXDEV 20
+
+static int32 oldbits[MAXDEV], bitsleft[MAXDEV];
+
+#ifdef DUMPREG
+static FILE *dumpfile; /* REG dump file handle */
+static unsigned char dumpbuf[1024]; /* REG dump buffer */
+static int dumpptr = 0; /* Pointer into dump buffer */
+#endif
+
+static int32 OpenDev(DevOpts *opts) {
+ char ttydev[30];
+ speed_t baudcon;
+ struct termios tt;
+ int32 TTY_fd, res;
+
+#ifdef DUMPREG
+ dumpfile = fopen("dumpreg.dat", "w");
+ setbuf(dumpfile, NULL);
+ dumpptr = 0;
+#endif
+
+#ifdef Solaris
+ /* Serial ports (at least built-in ones) have names of
+ /dev/term/a, /dev/term/b, etc. Map the port numbers
+ from the RC file into this nomenclature, with "1"
+ designating /dev/term/a. */
+#ifdef Irix
+ sprintf(ttydev, "/dev/ttyd%d", opts->port);
+#else
+ sprintf(ttydev, "/dev/term/%c", 'a' + (opts->port - 1));
+#endif
+#else
+ sprintf(ttydev, "/dev/ttyS%d", opts->port);
+#endif
+
+ switch(opts->baud) {
+ case 1200: baudcon = B1200; break;
+ case 2400: baudcon = B2400; break;
+ case 4800: baudcon = B4800; break;
+ case 9600: baudcon = B9600; break;
+ case 19200: baudcon = B19200; break;
+ case 38400: baudcon = B38400; break;
+#ifndef Irix
+ case 115200: baudcon = B115200; break;
+#endif
+ default:
+ printf("%s: Baud rate %ld not supported.\n", pgmname, opts->baud);
+ return -1;
+ }
+
+ fprintf(stderr, "Opening %s at %ld\n", ttydev, opts->baud);
+ if ((TTY_fd = open(ttydev, O_RDONLY
+#ifdef CPU_BOUND
+ | O_NDELAY
+#endif
+ )) < 0) {
+ perror(pgmname);
+ return -1;
+ }
+
+ if (TTY_fd >= MAXDEV) {
+ fprintf(stderr, "%s: Too many devices open.\n", pgmname);
+ close(TTY_fd);
+ return -1;
+ }
+
+ res = tcgetattr(TTY_fd, &tt);
+#ifdef Solaris
+ tt.c_iflag = 0;
+ tt.c_oflag = 0;
+ tt.c_cflag = baudcon | CS8 | CREAD | CLOCAL;
+ tt.c_lflag = 0;
+ tt.c_cc[VMIN] = 1; /* This many chars satisfies reads */
+ tt.c_cc[VTIME] = 0; /* or in this many tenths of seconds */
+#else
+ res = cfsetospeed(&tt, baudcon);
+ cfmakeraw(&tt);
+ tt.c_oflag &= (~(TABDLY | ONLCR));
+#endif
+ res = tcsetattr(TTY_fd, TCSANOW, &tt);
+
+ oldbits[TTY_fd] = bitsleft[TTY_fd] = 0;
+ return TTY_fd;
+}
+
+static int32 Sample(int32 dd, uint16 bits) {
+ int32 bc, sum, n1;
+ uint8 c1;
+
+ if (dd < 0) return -1;
+
+ sum = bc = 0;
+ while (bc < bits) {
+ if (bitsleft[dd]) {
+ sum += (oldbits[dd] & 0x01);
+ oldbits[dd] >>= 1;
+ bitsleft[dd]--;
+ bc++;
+ } else {
+ do {
+ n1 = read(dd, &c1, 1);
+ } while (n1 == 0 || (n1 == -1 && errno == EAGAIN));
+ if (n1 == -1) {
+ /* Fatal error occurred, die now? */
+ return -1;
+ }
+#ifdef DUMPREG
+ dumpbuf[dumpptr++] = c1;
+ if (dumpptr >= sizeof(dumpbuf)) {
+ fwrite(dumpbuf, sizeof(dumpbuf), 1, dumpfile);
+ dumpptr = 0;
+ }
+#endif
+ oldbits[dd] = c1;
+ bitsleft[dd] = 8;
+ }
+ }
+
+ return sum;
+}
+
+#define SAMP_PERIOD 1000 /* msec */
+#define MARGIN .95 /* how much to headroom to allow in
+ speed measurement */
+
+static int32 EvalSpeed(int32 dd) {
+ struct timeval start, end;
+ int32 bitct, samp;
+
+ if (dd < 0) return -1;
+
+ gettimeofday(&start, NULL);
+ bitct = 0;
+ while (1) {
+ gettimeofday(&end, NULL);
+ if (deltams(&end, &start) >= SAMP_PERIOD) break;
+ samp = Sample(dd, 1);
+ bitct++;
+ }
+
+ return (int32)(bitct * MARGIN);
+}
+
+static int32 Discard(int32 dd) {
+ int32 disc;
+#ifdef CPU_BOUND
+ int32 n1;
+ uint8 c1;
+#endif
+
+ if (dd < 0) return -1;
+
+ disc = bitsleft[dd];
+ bitsleft[dd] = 0;
+
+#ifdef CPU_BOUND
+ do {
+ n1 = read(dd, &c1, 1);
+ if (n1 == 1) disc++;
+ } while (n1 == 1);
+#else
+ tcflush(dd, TCIFLUSH);
+#endif
+
+ return disc;
+}
+
+static int32 CloseDev(int32 dd) {
+ if (dd < 0) return -1;
+
+ close(dd);
+ return 0;
+}
+
+/* Driver description table. */
+
+REG_driver REG_pear = {
+ "PEAR",
+ 0,
+ OpenDev,
+ EvalSpeed,
+ Sample,
+ Discard,
+ CloseDev
+ };
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/reg_pseudo.c,v 1.1 1998/12/31 22:04:39 ghn Exp $
+ * PURPOSE: PEAR (Bradish box/micro-REG) hardware interface
+ * AUTHOR: Greg Nelson
+ * DATE: 98-04-12
+ *
+ * REVISED: $Log: reg_pseudo.c,v $
+ * REVISED: Revision 1.1 1998/12/31 22:04:39 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * REVISED: Revision 1.3 1998/08/01 18:50:39 ghn
+ * REVISED: Added John's byte-order-independence changes and PSEUDO support.
+ * REVISED:
+ * REVISED: Revision 1.2 1998/08/01 17:13:51 ghn
+ * REVISED: Added John's Solaris support and DUMPREG option.
+ * REVISED:
+ * REVISED: Revision 1.1 1998/07/21 11:37:41 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+/* Define this to dump samples from the REG which we actually use into
+ a file named dumpreg.dat. */
+/* #define DUMPREG */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "global.h"
+#include "genlib.h"
+#include "reg.h"
+#include "lecuyer.h"
+
+#define MAXDEV 20
+
+static int32 oldbits[MAXDEV], bitsleft[MAXDEV];
+
+#ifdef DUMPREG
+static FILE *dumpfile; /* REG dump file handle */
+static unsigned char dumpbuf[1024]; /* REG dump buffer */
+static int dumpptr = 0; /* Pointer into dump buffer */
+#endif
+
+static int32 OpenDev(DevOpts *opts) {
+ int32 seed;
+ int i;
+
+ seed = time(NULL);
+ LEsetSeed(seed);
+
+ for (i = 0; i < 37; i++) {
+ seed = (seed << 3) ^ LEnextByte();
+ }
+ LEsetSeed(seed);
+ seed = LEnextByte();
+ for (i = 0; i < (seed & 0x37); i++) {
+ (void) LEnextByte();
+ }
+ return 0;
+}
+
+static int32 Sample(int32 dd, uint16 bits) {
+ int32 bc, sum;
+ uint8 c1;
+
+ sum = bc = 0;
+ while (bc < bits) {
+ if (bitsleft[dd]) {
+ sum += (oldbits[dd] & 0x01);
+ oldbits[dd] >>= 1;
+ bitsleft[dd]--;
+ bc++;
+ } else {
+ c1 = LEnextByte();
+#ifdef DUMPREG
+ dumpbuf[dumpptr++] = c1;
+ if (dumpptr >= sizeof(dumpbuf)) {
+ fwrite(dumpbuf, sizeof(dumpbuf), 1, dumpfile);
+ dumpptr = 0;
+ }
+#endif
+ oldbits[dd] = c1;
+ bitsleft[dd] = 8;
+ }
+ }
+
+ return sum;
+}
+
+#define SAMP_PERIOD 1000 /* msec */
+#define MARGIN .95 /* how much to headroom to allow in
+ speed measurement */
+
+static int32 EvalSpeed(int32 dd) {
+ struct timeval start, end;
+ int32 bitct, samp;
+
+ gettimeofday(&start, NULL);
+ bitct = 0;
+ while (1) {
+ gettimeofday(&end, NULL);
+ if (deltams(&end, &start) >= SAMP_PERIOD) break;
+ samp = Sample(dd, 1);
+ bitct++;
+ }
+
+ return (int32)(bitct * MARGIN);
+}
+
+static int32 Discard(int32 dd) {
+ int32 disc;
+
+ disc = bitsleft[dd];
+ bitsleft[dd] = 0;
+ return disc;
+}
+
+static int32 CloseDev(int32 dd) {
+ return 0;
+}
+
+/* Driver description table. */
+
+REG_driver REG_pseudo = {
+ "PSEUDO",
+ 2000,
+ OpenDev,
+ EvalSpeed,
+ Sample,
+ Discard,
+ CloseDev
+ };
--- /dev/null
+/*
+
+ Random event generator driver interface.
+
+*/
+
+#include "reg.h"
+
+extern REG_driver *configuredREG; /* REG selected by .eggrc file */
+
+/* Access to methods within the configured REG driver. */
+
+#define OpenDev(opts) (*configuredREG->reg_OpenDev)(opts)
+#define EvalSpeed(dd) (*configuredREG->reg_EvalSpeed)(dd)
+#define Sample(dd, bits) (*configuredREG->reg_Sample)(dd, bits)
+#define Discard(dd) (*configuredREG->reg_Discard)(dd)
+#define CloseDev(dd) (*configuredREG->reg_CloseDev)(dd)
--- /dev/null
+/*
+
+ Table of available Random Event Generator drivers
+
+*/
+
+#define REGs(x) x##pear, x##pseudo, x##orion
+
+extern REG_driver REGs(REG_);
+
+static REG_driver *reg_table[] = {
+ REGs(®_), NULL
+};
--- /dev/null
+#include <stdio.h>
+#ifdef __USE_BSD
+#undef __USE_BSD
+#endif
+#define __USE_BSD
+#include <termios.h>
+#undef __USE_BSD
+#include <unistd.h>
+#include <fcntl.h>
+#define __USE_BSD
+#include <errno.h>
+#undef __USE_BSD
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <time.h>
+#include <string.h>
+#include <utmp.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <syslog.h>
+#include "paths.h"
+
+int Sample(int fd, int bits);
+
+int main(int argc, char *argv[]) {
+ int TTY_fd;
+ int i, res, n1, mean;
+ struct termios tt;
+ speed_t baud;
+
+ if (argc != 3) {
+ printf("Usage: %s <tty> <baud>\n", argv[0]);
+ exit(-1);
+ }
+
+ switch(atoi(argv[2])) {
+ case 1200: baud = B1200; break;
+ case 2400: baud = B2400; break;
+ case 4800: baud = B4800; break;
+ case 9600: baud = B9600; break;
+ case 19200: baud = B19200; break;
+ case 38400: baud = B38400; break;
+ case 115200: baud = B115200; break;
+ default:
+ printf("%s: Baud rate %s not supported.\n", argv[0], argv[2]);
+ exit(-1);
+ }
+
+ if ((TTY_fd = open(argv[1], O_RDWR | O_NDELAY)) < 0) {
+ fprintf(stderr, "%s: %s\n", argv[1], sys_errlist[errno]);
+ exit(1);
+ }
+
+ res = tcgetattr(TTY_fd, &tt);
+ res = cfsetospeed(&tt, baud);
+ cfmakeraw(&tt);
+ tt.c_oflag &= (~(TABDLY | ONLCR));
+ res = tcsetattr(TTY_fd, TCSANOW, &tt);
+
+ mean = 0;
+ for (i = 0; i < 100; i++) {
+ n1 = Sample(TTY_fd, 200);
+ printf("%3d ", n1);
+ fflush(stdout);
+ if (i % 20 == 19) printf("\n");
+ mean += n1;
+ }
+ printf("Mean of first 100 REG200 trials = %f\n", (double)mean / 100.0);
+
+ exit(0);
+ for (i = 100; i < 200; i++) {
+ n1 = Sample(TTY_fd, i);
+ printf("%3d: %3d\n", i, n1);
+ }
+ return 0;
+}
+
+static int oldbits = 0;
+static int bitsleft = 0;
+int Sample(int fd, int bits) {
+ int bc, sum, n1;
+ unsigned char c1;
+
+ sum = bc = 0;
+ while (bc < bits) {
+ if (bitsleft) {
+ sum += (oldbits & 0x01);
+ oldbits >>= 1;
+ bitsleft--;
+ bc++;
+ } else {
+ do {
+ n1 = read(fd, &c1, 1);
+ } while (n1 == 0 || (n1 == -1 && errno == EAGAIN));
+ if (n1 == -1) {
+ /* Fatal error occurred, die now? */
+ exit(-errno);
+ }
+ oldbits = c1;
+ bitsleft = 8;
+#if 0
+ printf("Sampled %c%c%c%c%c%c%c%c\n",
+ ((oldbits & 0x80)?'1':'0'),
+ ((oldbits & 0x40)?'1':'0'),
+ ((oldbits & 0x20)?'1':'0'),
+ ((oldbits & 0x10)?'1':'0'),
+ ((oldbits & 0x08)?'1':'0'),
+ ((oldbits & 0x04)?'1':'0'),
+ ((oldbits & 0x02)?'1':'0'),
+ ((oldbits & 0x01)?'1':'0'));
+#endif
+ }
+ }
+
+ return sum;
+}
+
+
--- /dev/null
+#BASKET diesse 193.8.230.134
+#BASKET jura 193.8.230.130
+BASKET noosphere 128.112.35.133
+EGG diesse 37 193.8.230.134 diesse PERM 1 http://www.fourmilab.ch/
+EGG noosphere 28 128.112.35.133 noosphere PERM 1 http://noosphere.princeton.edu/
+EGG throop 1003 193.8.230.132 throop PERM 1
+EGG jura 1004 193.8.230.130 jura PERM 1
+EGG dicklnx.psy.uva.nl 1000 145.18.117.41 diesse PERM 1 http://www.psy.uva.nl/bierman
+PROTOCOL 10 10 6 200
+HTML 60 /ftp/entrenous/k/basket.html
--- /dev/null
+# Configuration file for egg collection software
+# This specifies the egg configuration information, the contact
+# information for its basket(s), and initial data acquisition parameters.
+
+# Each line consists of a case-sensitive keyword and a series of
+# options. Defined keywords are:
+#
+# EGG <name> <id> <ip addr> <primbasket> <conntype> <connival> <url>
+#
+# The primary basket <primbasket> is the name of the basket (defined
+# below) that should be contacted retrieve data from this Egg.
+# The connection type <conntype> is "PERM" (permanent) or "DND"
+# (dial-and-drop). So far the code does not support the DND option.
+# The connection interval <connival> determines the time (in minutes)
+# between transmission attempts. If specified, and not equal to
+# ".", <url> gives a URL (for example http://www.somesite.net/page.html)
+# which will be linked to the egg <name> in status reports. Note that
+# this specification has meaning only in the .basketrc file. For
+# compatibility, it is permitted in an .eggrc file, but is ignored.
+#
+# BASKET <name> <ip addr>
+#
+# This entry tells us about the existence of a set of baskets. The
+# basket named as primary is the one which will be contacted
+# initially.
+#
+# PROTOCOL <samprec> <secrec> <recpkt> <trialsz>
+#
+# Specify the default data collection protocol. The arguments are
+# <samprec> samples per record (1-10, though this should always be 5-10),
+# <secrec> seconds per records (1-3000),
+# <recpkt> records per packet (1-60), and
+# <trialsz> bits per sample (32-255).
+#
+# REG <type> <port> <baud>
+#
+# Specify hardware device. Supported types include "PEAR" only at
+# this time. Port is serial port number (e.g. 1 for /dev/ttyS1);
+# <baud> is baud rate.
+#
+# NETUP <script> <args> ...
+# NETDOWN <script> <args> ...
+#
+# Provide script files to be run to bring up and tear down the network
+# connection on demand. These will only be used if connection type is
+# DND.
+
+#EGG halley 1 10.0.0.111 halley PERM 1
+#BASKET halley 10.0.0.111
+#EGG halley 1 10.0.0.111 mercury DND 3
+#BASKET mercury 10.0.0.125
+
+#EGG noosphere 28 128.112.35.133 noosphere PERM 1
+#BASKET noosphere 128.112.35.133
+
+# diesse -> diesse
+#EGG diesse 37 193.8.230.134 diesse PERM 1
+#BASKET diesse 193.8.230.134
+
+# noosphere -> diesse
+EGG noosphere 28 128.112.35.133 diesse PERM 1
+BASKET diesse 193.8.230.134
+
+# throop -> diesse
+#EGG throop 1003 193.8.230.132 diesse PERM 1 http://www.fourmilab.ch/
+#BASKET diesse 193.8.230.134
+
+# jura -> jura
+#EGG jura 1004 193.8.230.130 jura PERM 1 http://www.fourmilab.ch/
+#BASKET jura 193.8.230.130
+
+# diesse -> noosphere
+#EGG diesse.fourmilab.ch 37 193.8.230.134 noosphere PERM 1
+#BASKET noosphere 128.112.35.133
+
+#EGG diesse 37 193.8.230.134 jura PERM 1
+#BASKET jura 193.8.230.130
+
+#BASKET tonga 209.157.90.137
+#BASKET tonga1 209.157.90.138
+PROTOCOL 10 10 6 200
+#REG PEAR 2 9600
+REG PSEUDO 1 9600
+#REG ORION 1 9600
+NETUP pppscript up
+NETDOWN pppscript down
--- /dev/null
+#!/bin/csh
+
+if ("$1" == "up") then
+ echo "Bringing net up"
+
+ /usr/sbin/pppd connect '/usr/sbin/chat -v ABORT BUSY ABORT "NO CARRIER" "" ATZ OK ATS71=1 OK ATS80=1 OK ATDT4828060 CONNECT ""' /dev/cua0 115200 name halebopp remotename whitehole debug crtscts modem defaultroute 10.0.0.111:10.0.0.116
+
+ # Wait for connection success
+ set timer = 8
+ while ($timer > 0)
+ if (-e "/var/run/ppp0.pid") exit 0
+ sleep 1
+ @ timer = $timer - 1
+ end
+
+ echo "Couldn't get it up!"
+ exit -1
+endif
+
+if ("$1" == "down") then
+ echo "Bringing net down"
+ if (! -e "/var/run/ppp0.pid") exit 0
+ set pid = `cat /var/run/ppp0.pid`
+ kill $pid
+
+ exit 0
+endif
+
+echo "Usage: pppscript up down"
+exit 1
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/storage.c,v 1.4 1998/12/31 22:07:56 ghn Exp $
+ * PURPOSE: Data storage functions
+ * AUTHOR: Greg Nelson
+ * DATE: 98-05-09
+ *
+ * REVISED:
+ * $Log: storage.c,v $
+ * Revision 1.4 1998/12/31 22:07:56 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.3 1998/08/03 20:32:46 kelvin
+ * File byte-order independence, STORAGE_DEBUG
+ *
+ * Revision 1.2 1998/08/01 17:18:45 ghn
+ * Fixes to prevent core dumps and make "database" engine work correctly.
+ *
+ * Revision 1.1 1998/07/21 11:36:21 ghn
+ * Initial revision
+ *
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include "global.h"
+#include "genlib.h"
+#include "storage.h"
+#include "errnos.h"
+
+/* Some systems (e.g. Linux) implement strdup but don't define
+ it by default in string.h. Define it explicitly here, which
+ doesn't seem to do any harm on other systems. If you encounter
+ an error on the following declaration, disable it for your
+ platform. */
+
+extern char *strdup (const char *s1);
+
+/* Eventually, these might deal with making a safe copy or mounting
+ and unmounting a partition. Until such time as we actually do
+ something with these, they are no-ops. */
+#define Protect(x)
+#define Unprotect(x)
+
+#define DATAFMT "%Y%m/%%e"
+#define PROJSTART 901947600L
+
+static char *datafmt; /* Data file format string */
+
+/* Prototypes for forward functions. */
+
+static int32 FileLoadPacket(FILE *fp, EggCarton *cart);
+static int32 next_filename(char *fn, uint32 tindex, int16 eggid,
+ int16 *lastind, int16 mustexist);
+static int32 next_poss_fn(char *fn, uint32 tindex, int16 eggid);
+
+/* The seek optimisation table saves the file name, last
+ packet returned, and corresponding file of the next
+ packet (if any) in the file, for the last SEEK_OPT_MAX
+ requests. This allows LoadNextPacket to avoid searching
+ the entire database for the next packet if the request
+ matches one in the seek optimisation table.
+
+*/
+
+#define SEEK_OPT_MAX MAX_BASKETS
+
+struct seekopt {
+ char filename[256];
+ uint32 last_time;
+ long next_packet;
+};
+
+static struct seekopt seekOpt[SEEK_OPT_MAX];
+static int seekOptIndex = 0;
+
+/* The initialization provides a way to specify a format for the
+ database file names. If the argument is null, it uses a default
+ from the environment, or it takes the default given above. This
+ string is used as an argument to strftime(3) which replaces certain
+ characters with corresponding fields of the date and time. This
+ provides an automatic way of generating a logical new filename on a
+ periodic basis. Note that you can call InitStorage as many times
+ as you wish to change the format for file names opened
+ subsequently. */
+
+int32 InitStorage(char *path) {
+ char *p, *np;
+ char ns[256], pa[12];
+ int changed = 0;
+
+ /* First, take this opportunity to clear the seek optimisation
+ table. If we're changing the file name format, none of the
+ items in it will be valid in any case. */
+
+ memset(seekOpt, 0, sizeof seekOpt);
+
+ /* Set the path based on the environment variable, argument,
+ or default. */
+
+ if (path == NULL) {
+ if ((path = getenv("EGG_DATA")) == NULL) {
+ path = DATAFMT;
+ }
+ }
+
+ /* If the path contains any of our special "$" editing
+ codes, interpolate the requested text into the string.
+ Strftime "%" editing codes are left intact. */
+
+ ns[0] = 0;
+ p = path;
+ while ((np = strchr(p, '$')) != NULL) {
+ char *phrargs = np + 1;
+
+ /* Copy portion of string prior to phrase to output. */
+
+ if (np > p) {
+ int l = strlen(ns);
+
+ memcpy(ns + l, p, np - p);
+ ns[l + (np - p)] = 0;
+ }
+
+ /* Parse format phrase and possible arguments. */
+
+ while ((*phrargs != 0) && !isalpha(*phrargs)) {
+ phrargs++;
+ }
+ if (*phrargs == 0) {
+ fprintf(stderr, "Data format string error in:\n %s\nunterminated $ phrase.\n", path);
+ exit(-1);
+ }
+
+ /* Copy arguments, if any, to second character of arguments
+ string for possible use by phrase interpreters in
+ sprintf. */
+
+ pa[0] = '%'; /* Start editing phrase */
+ pa[1] = 0;
+ if (phrargs > (np + 1)) {
+ memcpy(pa + 1, np + 1, phrargs - (np + 1));
+ pa[1 + (phrargs - (np + 1))] = 0;
+ }
+/*fprintf(stderr, "Phrase arguments = <%s>\n", pa);*/
+
+ /* Now interpret the specific format phrase letters.
+ The value selected by each phrase should be concatenated
+ to the output string ns. Available format phrases
+ are:
+
+ $b Basket name
+ $e Egg name
+ $[0][n]E Egg number, right justified,
+ optionally zero filled in n characters
+
+ */
+
+
+ switch (*phrargs) {
+
+ case 'b': /* Basket name */
+ strcat(ns, baskettable[0].name);
+ break;
+
+ case 'e': /* Egg name */
+ strcat(ns, eggtable[0].name);
+ break;
+
+ case 'E': /* Egg number, edited decimal number */
+ strcat(pa, "d");
+ sprintf(ns + strlen(ns), pa, eggtable[0].id);
+ break;
+
+ default:
+ fprintf(stderr, "Data format string error in:\n %s\nunknown phrase $%c.\n",
+ path, *phrargs);
+ exit(-1);
+ }
+
+ /* Adjust pointer to resume scan following the phrase
+ in the source string. */
+
+ p = phrargs + 1;
+ changed++;
+ }
+
+ if (changed) {
+ strcat(ns, p); /* Concatenate balance of string */
+ path = strdup(ns);
+ if (path == NULL) {
+ fprintf(stderr, "Cannot allocate memory for file name format string.\n");
+ exit(-1);
+ }
+/*printf("Expanded path name phrase = <%s>\n", path); exit(0);*/
+ }
+
+ datafmt = path;
+ return 0;
+}
+
+/* Save packet is the basic save function. It does not take a
+ filename, relying on the datafmt variable created during
+ initialization to generate an appropriate filename. The
+ date for the saved data is based on the timestamp of the packet's
+ first record. */
+
+int32 SavePacket(EggCarton *cart) {
+ FILE *fp;
+ char *packet, datatmp[255], datafile[255], *sp;
+ int32 pktime, res;
+
+ pktime = cart->records[0].timestamp;
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "SavePacket for %lu: %s", pktime, asctime(gmtime((time_t *) &pktime)));
+#endif
+
+ /* Generate the file name corresponding to the date of
+ the first record in the packet. Since we know the
+ date, there's no need to use next_filename. */
+
+ res = next_poss_fn(datafile, pktime, cart->hdr.eggid);
+
+ /* Open the file for appending. */
+
+ Unprotect(datafile);
+ fp = fopen(datafile, "a");
+
+ /* If we can't open the file, the odds are it's because
+ the file is in a directory we've yet to create. */
+
+ if (fp == NULL) {
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "SavePacket: no such file %s\n", datafile);
+#endif
+ sp = strrchr(datafile, '/');
+ while (sp) {
+ strncpy(datatmp, datafile, sp - datafile);
+ datatmp[sp - datafile] = 0;
+ mkdir(datatmp, 0777);
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "SavePacket: mkdir %s\n", datatmp);
+#endif
+ sp = strchr(sp + 1, '/');
+ }
+
+ /* Now try re-opening the file. */
+
+ Unprotect(datafile);
+ if ((fp = fopen(datafile, "a")) == NULL) {
+ fprintf(stderr, "SavePacket: cannot create database file %s.\n", datafile);
+ exit(-1);
+ }
+ }
+
+ if (!fp) {
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "SavePacket: error opening %s\n", datafile);
+#endif
+ return -2;
+ }
+ packet = Packetize(cart);
+ if (!packet) return -1;
+ fwrite(packet, sizeof(char), cart->hdr.pktsize, fp);
+ free(packet);
+ fclose(fp);
+ Protect(datafile);
+ cart->hdr.numrec = 0;
+
+ return 1;
+}
+
+/* Open database for reading, positioning to specified location.
+ If eggid is less than zero, it will load any packet. */
+int32 OpenDatabase(DBRec *dbp, uint32 tindex, int16 eggid) {
+ int32 res;
+
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "OpenDatabase: Egg = %d, tindex = %ld %s",
+ eggid, tindex, asctime(gmtime((time_t *) &tindex)));
+#endif
+ dbp->eggind = 0;
+ dbp->fp = NULL;
+ if ((res = next_filename(dbp->fn, tindex, eggid, &(dbp->eggind), TRUE)) < 0)
+ return res;
+
+ Unprotect(dbp->fn);
+ dbp->fp = fopen(dbp->fn, "r");
+ if (dbp->fp == NULL) {
+ Protect(dbp->fn);
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "OpenDatabase -- EOF\n");
+#endif
+ return ERR_EOF;
+ } else {
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "OpenDatabase -- Opened %s\n", dbp->fn);
+#endif
+ return ERR_NONE;
+ }
+}
+
+/* Close database */
+int32 CloseDatabase(DBRec *dbp) {
+ fclose(dbp->fp);
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "CloseDatabase -- Closed %s\n", dbp->fn);
+#endif
+ Protect(dbp->fn);
+ dbp->fp = NULL;
+ /* We preserve file name; this lets us not open the same
+ file name again unless we want to. */
+ return ERR_NONE;
+}
+
+/* Reset database allows us to open same file name again. */
+int32 ResetDatabase(DBRec *dbp) {
+ *(dbp->fn) = 0;
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "ResetDatabase\n");
+#endif
+ return ERR_NONE;
+}
+
+/* Load next packet fitting specified time index and egg id.
+ If eggid is less than zero, it will load any packet. */
+
+static int32 LoadNextPacket(DBRec *dbp, uint32 tindex, int16 eggid, EggCarton *cart) {
+ EggCarton pktbuf;
+ int32 res, i;
+ uint32 findex = tindex, now;
+
+ now = getzulutime(NULL);
+ if (findex < PROJSTART) {
+ findex = PROJSTART;
+ }
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "LoadNextPacket(%s, %lu, %d)\n", dbp->fn, tindex, eggid);
+#endif
+
+ /* See if the start address for this request is present
+ in the seek optimisation table. If so, seek directly
+ to the address to avoid having to read through all
+ earlier packets in the database. */
+
+ i = seekOptIndex;
+ /* Conditioning while on tindex > 0 causes seek optimisation to be
+ skipped when a request for any packet is received. */
+ while (tindex > 0) {
+ i--;
+ if (i < 0) {
+ i = SEEK_OPT_MAX - 1;
+ }
+ if (strcmp(seekOpt[i].filename, dbp->fn) == 0 &&
+ seekOpt[i].last_time == tindex) {
+ fseek(dbp->fp, seekOpt[i].next_packet, SEEK_SET);
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "LoadNextPacket; Seek optimised [%ld] to %ld for\n file %s at %lu %s",
+ i,
+ seekOpt[i].next_packet,
+ seekOpt[i].filename,
+ seekOpt[i].last_time,
+ asctime(gmtime((time_t *) &(seekOpt[i].last_time))));
+
+#endif
+ break;
+ }
+ if (i == seekOptIndex) {
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "LoadNextPacket; Cannot optimise seek in file %s\n at %lu %s",
+ dbp->fn, tindex, asctime(gmtime((time_t *) &(tindex))));
+#endif
+ break; /* Search wrapped table--cannot optimise */
+ }
+ }
+
+ while (1) {
+ res = FileLoadPacket(dbp->fp, &pktbuf);
+ if (res == ERR_EOF) {
+ /* File is finished. Close and open the next. We assume
+ that tindex and eggid have been tracking appropriately. */
+ CloseDatabase(dbp);
+
+ /* Advance findex to start of next day after the one we've
+ just exhausted. */
+
+#define SECONDS_PER_DAY (24L * 60 * 60)
+ findex = ((findex / SECONDS_PER_DAY) + 1) * SECONDS_PER_DAY;
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "LoadNextPacket; EOF, CloseDatabase, findex = %lu: %s",
+ findex, asctime(gmtime((time_t *) &findex)));
+#endif
+ if (findex > now) {
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "LoadNextPacket; EOF findex = %lu > now = %lu %s",
+ findex, now, asctime(gmtime((time_t *) &now)));
+#endif
+ return ERR_EOF;
+ }
+ /* Do not reset database; we won't open same one again. */
+ if ((res = OpenDatabase(dbp, findex, eggid)) < 0) return res;
+ continue;
+ }
+/*
+fprintf(stderr, "Eggid = %d Packet.eggid = %d\n", eggid, pktbuf.hdr.eggid);
+*/
+ if (eggid >= 0 && pktbuf.hdr.eggid != eggid) continue;
+ for (i = 0; i < pktbuf.hdr.numrec; i++) {
+/*fprintf(stderr, " Rec %ld timestamp = %lu tindex = %lu\n", i, pktbuf.records[i].timestamp, tindex);
+*/
+ if (pktbuf.records[i].timestamp > tindex) {
+ memcpy(cart, &pktbuf, sizeof(EggCarton));
+
+ /* Save the location of the packet following this one
+ in the seek optimisation table. */
+
+ strcpy(seekOpt[seekOptIndex].filename, dbp->fn);
+ seekOpt[seekOptIndex].last_time = pktbuf.records[pktbuf.hdr.numrec - 1].timestamp;
+ seekOpt[seekOptIndex].next_packet = ftell(dbp->fp);
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "LoadNextPacket; Seek optimisation[%d] for %s\n to address %ld for time %lu %s",
+ seekOptIndex,
+ seekOpt[seekOptIndex].filename,
+ seekOpt[seekOptIndex].next_packet,
+ seekOpt[seekOptIndex].last_time,
+ asctime(gmtime((time_t *) &(seekOpt[seekOptIndex].last_time))));
+#endif
+ seekOptIndex = (seekOptIndex + 1) % SEEK_OPT_MAX;
+ return ERR_NONE;
+ }
+ }
+ }
+}
+
+/* Load next packet following a particular time index and egg id */
+
+int32 LoadPacket(uint32 tindex, int16 eggid, EggCarton *cart) {
+ DBRec db;
+ int32 res;
+
+ ResetDatabase(&db); /* Here we need to be able to open same db as
+ last time. */
+ if ((res = OpenDatabase(&db, tindex, eggid)) < 0) return res;
+ if ((res = LoadNextPacket(&db, tindex, eggid, cart)) < 0) return res;
+ return CloseDatabase(&db);
+}
+
+static int32 FileLoadPacket(FILE *fp, EggCarton *cart) {
+ char *rbuf;
+ int32 res;
+ uint16 pksize;
+
+ if (feof(fp)) return ERR_EOF;
+
+ if (fread(&(cart->hdr.type), sizeof(uint16), 1, fp) != 1) {
+ if (feof(fp)) return ERR_EOF; else return ERR_CNREAD;
+ }
+ if (fread(&(cart->hdr.pktsize), sizeof(uint16), 1, fp) != 1) {
+ if (feof(fp)) return ERR_EOF; else return ERR_CNREAD;
+ }
+
+ /* Since the file packet is in network byte order, we need to
+ be sure the length field is in host order before using
+ it to allocate and read the balance of the packet from the
+ file. Once that's done, Unpacketize will take responsibility
+ for getting all the packet fields into host order. */
+ pksize = ntohs(cart->hdr.pktsize);
+
+ rbuf = (char *)malloc(pksize);
+ if (!rbuf) return ERR_NOMEM;
+
+ memcpy(rbuf, &(cart->hdr), 2*sizeof(uint16));
+ if (fread(rbuf+4, pksize - 4, 1, fp) != 1) return ERR_CNREAD;
+
+ res = Unpacketize(cart, rbuf);
+ free(rbuf);
+
+ return res;
+}
+
+static int32 next_filename(char *fn, uint32 tindex, int16 eggid,
+ int16 *lastind, int16 mustexist) {
+ struct stat statbuf;
+ uint32 findex, now;
+ int32 res;
+ char ldf[255];
+
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "next_filename: egg = %d, mustexist = %d, tindex = %lu %s",
+ eggid, mustexist, tindex, asctime(gmtime((time_t *) &tindex)));
+#endif
+ if (eggid < 0 && !mustexist) {
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "next_filename: egg ID out of range.\n");
+#endif
+ return ERR_INRANGE;
+ }
+
+ /* Can't go back before project began. */
+ now = getzulutime(NULL);
+ if (tindex < PROJSTART) {
+ findex = PROJSTART;
+ } else {
+ findex = tindex;
+ }
+
+ /* Search possible file names until one is found. We jump by days,
+ assuming files don't have a greater granularity than that. In
+ the existence-testing process, we are checking to make sure the
+ file name is different each time. */
+
+ if (lastind == NULL) eggid = eggtable[0].id;
+ else {
+ if (eggid < 0) eggid = eggtable[(*lastind)++].id;
+ if (*lastind == numeggs) *lastind = 0;
+ }
+
+ strcpy(ldf, fn);
+ do {
+ res = next_poss_fn(fn, findex, eggid);
+ findex += 86400L;
+ if (!strcmp(fn, ldf)) continue;
+ strcpy(ldf, fn);
+ /* Check for file. If stat fails, reason is ENOENT, isn't it? */
+ if (stat(fn, &statbuf) >= 0) {
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "next_filename: Found file %s\n", fn);
+#endif
+ return ERR_NONE;
+ }
+ if (!mustexist) {
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "next_filename: File %s does not exist.\n", fn);
+#endif
+ return ERR_NOENT;
+ }
+ } while (findex < now+86400L);
+
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "next_filename: End of file.\n");
+#endif
+ return ERR_EOF;
+}
+
+/* tindex and eggid must be defined here */
+static int32 next_poss_fn(char *fn, uint32 tindex, int16 eggid) {
+ char datatmp[255], *sp;
+ int16 eggind;
+ struct tm *tm;
+
+ tm = gmtime((time_t *) &tindex);
+ strftime(datatmp, 255, datafmt, tm);
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "next_poss_fn: egg = %d, tindex = %lu %s",
+ eggid, tindex, asctime(tm));
+#endif
+
+ /* If an %e phrase remains after processing by strftime
+ (it should be specified as %%e in the original
+ DATAFMT specification), interpolate the egg number
+ from this packet. */
+
+ if ((sp = strchr(datatmp, '%')) != NULL) {
+ if (sp[1] == 'e') {
+ for (eggind = 0;
+ eggind < numeggs && eggtable[eggind].id != eggid;
+ eggind++);
+ if (eggind == numeggs) {
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "next_poss_fn: Egg number out of range.\n");
+#endif
+ return ERR_INRANGE;
+ }
+ *sp = 0;
+ strcpy(fn, datatmp);
+ strcat(fn, eggtable[eggind].name);
+ strcat(fn, sp + 2);
+ } else {
+ fprintf(stderr, "Bad file format expr: %%%c\n", sp[1]);
+ strcpy(fn, datatmp);
+ return ERR_INRANGE;
+ }
+ } else {
+ strcpy(fn, datatmp);
+ }
+#ifdef STORAGE_DEBUG
+ fprintf(stderr, "next_poss_fn: File name = %s\n", fn);
+#endif
+ return ERR_NONE;
+}
--- /dev/null
+/* PROGRAM: eggsh
+ * FILE: $Header: /home/egg/src/RCS/storage.h,v 1.3 1998/12/31 22:11:05 ghn Exp $
+ * PURPOSE: Definitions for data storage functions
+ * AUTHOR: Greg Nelson
+ * DATE: 98-05-09
+ *
+ * REVISED:
+ * $Log: storage.h,v $
+ * Revision 1.3 1998/12/31 22:11:05 ghn
+ * Rev 5 code: includes multi-reg support, HTML, etc.
+ *
+ * Revision 1.2 1998/08/01 17:19:48 ghn
+ * Added ResetDatabase function.
+ *
+ * Revision 1.1 1998/07/21 11:35:10 ghn
+ * Initial revision
+ *
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+typedef struct dbase {
+ FILE *fp;
+ int16 eggind;
+ char fn[256];
+} DBRec;
+
+/* The initialization provides a way to specify a format for the
+ database file names. If the argument is null, it uses a default
+ from the environment, or a compiled default. This string is used
+ as an argument to strftime(3) which replaces certain characters
+ with corresponding fields of the date and time. This provides an
+ automatic way of generating a logical new filename on a periodic
+ basis.
+
+ The other function of the initialization is to clear static
+ variable used to incrementally collect records for SaveRecord until
+ a complete packet is available for storage to disk. */
+extern int32 InitStorage(char *path);
+
+/* Save packet is the basic save function. It does not take a
+ filename, relying on the datafmt variable created during
+ initialization to generate an appropriate filename. The
+ date for the saved data is based on the timestamp of the packet's
+ first record. */
+extern int32 SavePacket(EggCarton *cart);
+
+/* Open database for reading, positioning to specified location.
+ If eggid is less than zero, it will load any packet. */
+extern int32 OpenDatabase(DBRec *db, uint32 tindex, int16 eggid);
+
+/* Close database */
+extern int32 CloseDatabase(DBRec *db);
+
+/* Reset database allows us to open same file name again. */
+extern int32 ResetDatabase(DBRec *dbp);
+
+/* Load next packet following a particular time index and egg id. If
+ eggid is less than zero, it will load any packet. This is
+ essentially a shortcut for getting one packet. */
+
+extern int32 LoadPacket(uint32 tindex, int16 eggid, EggCarton *cart);
+
--- /dev/null
+/* PROGRAM: testmain
+ * FILE: $Header: /home/egg/src/RCS/testmain.c,v 1.1 1998/07/21 11:34:11 ghn Exp $
+ * PURPOSE: First draft eggsh
+ * AUTHOR: Greg Nelson
+ * DATE: 98-05-09
+ *
+ * REVISED: $Log: testmain.c,v $
+ * REVISED: Revision 1.1 1998/07/21 11:34:11 ghn
+ * REVISED: Initial revision
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "global.h"
+#include "genlib.h"
+#include "hwapi.h"
+#include "collect.h"
+#include "storage.h"
+#include "network.h"
+#include "errnos.h"
+
+#define BASKETHOST "halebopp.qtmsys.com"
+
+char *baskethost = BASKETHOST;
+
+void MakeAwake(AwakePacket *pkt);
+void MakeDataPkt(char **pkt, EggCarton *src);
+
+int main(int argc, char *argv[]) {
+ int res, cdres, i;
+ int32 sdlisten;
+ double sps;
+ int32 collyes, collno, alignover, alignwait;
+ DevOpts devopts;
+ CollectRecord coll;
+ EggCarton retrcart;
+ AwakePacket awake;
+ ReqPacket *rpktp;
+ struct sockaddr_in rhost, bhost;
+ char *pktbuf, *outpktbuf;
+ uint16 pkttype, pktsize;
+
+ pgmname = argv[0];
+
+ if (argc != 6) {
+ printf("Usage: %s <ttynum> <baud> <trialsz> <sec_rec> <samp_rec>\n", pgmname);
+ exit(-1);
+ }
+
+ devopts.port = atoi(argv[1]);
+ devopts.baud = atoi(argv[2]);
+ coll.opts.trialsz = atoi(argv[3]);
+ coll.opts.sec_rec = atoi(argv[4]);
+ coll.opts.samp_rec = atoi(argv[5]);
+ coll.opts.eggid = GetID();
+
+ coll.opts.rec_pkt = SEC_PKT / coll.opts.sec_rec;
+ if (coll.opts.rec_pkt < 1) coll.opts.rec_pkt = 1;
+ if (coll.opts.rec_pkt > MAXREC_PKT) coll.opts.rec_pkt = MAXREC_PKT;
+
+ if (coll.opts.trialsz < MINBITS || coll.opts.trialsz > MAXBITS) {
+ fprintf(stderr, "Trial size must be between %d and %d.\n",
+ MINBITS, MAXBITS);
+ exit(-1);
+ }
+
+ if (coll.opts.sec_rec < 1 || coll.opts.sec_rec > MAXSEC_REC) {
+ fprintf(stderr, "Seconds/record must be between 1 and %d.\n", MAXSEC_REC);
+ exit(-1);
+ }
+
+ if (coll.opts.samp_rec < 1 || coll.opts.samp_rec > MAXSAMP_REC) {
+ fprintf(stderr, "Samples/record must be between 1 and %d.\n", MAXSAMP_REC);
+ exit(-1);
+ }
+
+ sps = (double)coll.opts.samp_rec / (double)coll.opts.sec_rec;
+
+ printf("Effective sample rate is about %f samp/sec or %f bits/sec\n",
+ sps, coll.opts.trialsz * sps);
+ printf("Packets contain %d records\n", coll.opts.rec_pkt);
+
+ if ((coll.dd = OpenDev(&devopts)) < 0) exit(1);
+ if (EvalSpeed(coll.dd) < coll.opts.trialsz * sps) {
+ fprintf(stderr, "Requested speed exceeds device capabilities.\n");
+ exit(-1);
+ }
+
+ coll.sampct = 0;
+ collyes = collno = 0;
+ alignover = alignwait = 0;
+
+ InitStorage(NULL);
+ sdlisten = InitNetwork(EGGPORT);
+
+ /* Get us aligned for the first time */
+ while(AlignRecord(&coll, TRUE) < 0);
+
+ while(1) {
+ res = NetListen(sdlisten, &pktbuf, &rhost, FALSE);
+ if (res < 0 && res != ERR_COMM_TMOUT) {
+ fprintf(stderr, "NetListen error: %d\n", res);
+ continue;
+ }
+ if (res == ERR_NONE) {
+ pkttype = ((GenPacket *)pktbuf)->type;
+ pktsize = ((GenPacket *)pktbuf)->pktsize;
+ switch(pkttype) {
+ case DATA_PACKET:
+ fprintf(stderr, "Egg received data?\n");
+ break;
+ case REQ_PACKET:
+ /* Basket wants data! */
+ rpktp = (ReqPacket *)pktbuf;
+
+ /* Find the desired data. */
+ res = LoadNextPacket(rpktp->starttm, &retrcart);
+
+ if (res == ERR_NONE) {
+ /* NetPacketize it */
+ MakeDataPkt(&outpktbuf, &retrcart);
+ rhost.sin_port = htons(BASKETPORT);
+ res = NetTalk(&rhost, outpktbuf);
+ if (res < 0) {
+ fprintf(stderr, "NetTalk failed (%d)\n", res);
+ }
+ free(outpktbuf);
+ }
+ break;
+ case AWAKE_PACKET:
+ fprintf(stderr, "Egg received awake?\n");
+ break;
+ case SETTINGS_PACKET:
+ /* Install new settings! */
+ break;
+ }
+ free(pktbuf);
+ }
+
+ if (coll.sampct == 0) {
+ cdres = AlignRecord(&coll, FALSE);
+ if (cdres < 0) {
+ if (cdres == -3) alignover++; else alignwait++;
+ continue;
+ }
+ }
+ cdres = CollectData(&coll);
+ if (cdres < 0) {
+ collno++;
+ continue;
+ }
+ collyes++;
+ if (cdres == 1) {
+ SaveRecord(&coll);
+ MakeAwake(&awake);
+ i = NetGetAddr(&bhost, baskethost, BASKETPORT);
+ i = NetTalk(&bhost, (char *)&awake);
+ printf(" collect:nodata over:wait = %ld:%ld %ld:%ld\n",
+ collyes, collno, alignover, alignwait);
+ printf("Record: %d points (transmission %d)\n %ld: ",
+ coll.sampct, i, coll.data.timestamp);
+ for (i = 0; i < coll.sampct; i++)
+ printf("%3d ", coll.data.trials[i]);
+ printf("\n");
+ coll.sampct = 0;
+ }
+ }
+
+ return 0;
+}
+
+
+void MakeAwake(AwakePacket *pkt) {
+ struct timeval now;
+
+ pkt->type = AWAKE_PACKET;
+ pkt->pktsize = sizeof(AwakePacket);
+ pkt->eggid = GetID();
+ getzulutime(&now);
+ pkt->nowtm = now.tv_sec;
+}
+
+void MakeDataPkt(char **pkt, EggCarton *src) {
+ uint16 pktsize, offset, rec, sbuf;
+ uint32 lbuf;
+
+ pktsize = sizeof(EggHeader);
+ pktsize += src->hdr.numrec * (sizeof(uint32) +
+ src->hdr.samp_rec * sizeof(trial));
+ pktsize += sizeof(uint16); /* Checksum */
+
+ src->hdr.type = DATA_PACKET;
+ src->hdr.pktsize = pktsize;
+
+ *pkt = (char *)malloc(pktsize);
+ memcpy(*pkt, &(src->hdr), sizeof(EggHeader));
+ offset = sizeof(EggHeader);
+
+ for (rec = 0; rec < src->hdr.numrec; rec++) {
+ lbuf = src->records[rec].timestamp;
+ memcpy((*pkt)+offset, &lbuf, sizeof(uint32));
+ offset += sizeof(uint32);
+ /* Assumes sizeof(trial) = 1 */
+ memcpy((*pkt)+offset, &(src->records[rec].trials), src->hdr.samp_rec);
+ offset += src->hdr.samp_rec;
+ }
+
+ /* Normal CRC */
+ sbuf = BlockCRC16(*pkt, offset);
+ memcpy((*pkt)+offset, &sbuf, sizeof(uint16));
+ offset += sizeof(uint16);
+
+ if (offset != pktsize) {
+ fprintf(stderr, "Error in packet generation!\n");
+ }
+}
+
--- /dev/null
+/* PROGRAM: testudp
+ * FILE: $Header: /home/egg/src/RCS/testudp.c,v 1.2 1998/07/21 11:34:48 ghn Exp $
+ * PURPOSE: Testing UDP communications (fake basket)
+ * AUTHOR: Greg Nelson
+ * DATE: 98-05-09
+ *
+ * REVISED: $Log: testudp.c,v $
+ * REVISED: Revision 1.2 1998/07/21 11:34:48 ghn
+ * REVISED: Testing UDP communications (fake basket)
+ * REVISED:
+ * Copyright 1998 - Greg Nelson
+ * Redistributable under the terms of the GNU Public Licence (GPL)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include "global.h"
+#include "genlib.h"
+#include "hwapi.h"
+#include "collect.h"
+#include "storage.h"
+#include "network.h"
+
+int main(int argc, char *argv[]) {
+ ReqHeader rhdr;
+ struct protoent *pp;
+ struct hostent *hp;
+ struct sockaddr_in rhost;
+ int32 i;
+ int32 out_sock;
+
+ pgmname = argv[0];
+
+ if (argc != 2) {
+ printf("Usage: %s <host>\n", pgmname);
+ exit(-1);
+ }
+
+ if ((pp = getprotobyname("udp")) == NULL) {
+ perror("getprotobyname");
+ exit(-1);
+ }
+
+ if ((hp = gethostbyname(argv[1])) == NULL) {
+ fprintf(stderr, "gethostbyname(%s): %s", argv[1], strerror(errno));
+ exit(-1);
+ }
+
+ if (hp->h_addrtype != AF_INET) {
+ fprintf(stderr, "Host is not on the internet!\n");
+ exit(-1);
+ }
+
+ rhost.sin_port = htons(EGGPORT);
+ rhost.sin_family = AF_INET;
+ memcpy(&(rhost.sin_addr), hp->h_addr, hp->h_length);
+
+ rhdr.type = REQ_PACKET;
+ rhdr.pktsize = sizeof(ReqHeader);
+ rhdr.eggid = 30800; /* halebopp! */
+ rhdr.samp_rec = 10;
+ rhdr.sec_rec = 10;
+ rhdr.rec_pkt = 6;
+ rhdr.trialsz = 200;
+ rhdr.starttm = 0;
+ rhdr.cksum = BlockCRC16((byte *)&rhdr, sizeof(ReqHeader)-2);
+
+ if ((out_sock = socket(AF_INET, SOCK_DGRAM, pp->p_proto)) < 0) {
+ perror("socket");
+ exit(-1);
+ }
+
+ i = sendto(out_sock, &rhdr, rhdr.pktsize,
+ 0, (struct sockaddr *)&rhost,
+ sizeof(struct sockaddr));
+ if (i == -1) {
+ perror("sendto");
+ exit(-1);
+ }
+ if (i != rhdr.pktsize) {
+ fprintf(stderr, "Failed to send complete packet (%ld/%d)\n",
+ i, rhdr.pktsize);
+ exit(-1);
+ }
+
+ exit(0);
+}
--- /dev/null
+/*
+
+ Emulation of BSD usleep()
+
+ Note that this is not a complete emulation in that
+ it destroys any pre-existing setitimer(), but it's
+ good enough for programs which don't have interval
+ timers running across calls on usleep(). It does
+ save and restore an existing SIGALRM handler.
+
+*/
+
+#ifdef USLEEP
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+
+#ifdef Solaris
+typedef void (*signalFUNC)(int);
+#define signal(a, b) sigset(a, (signalFUNC) b)
+#define signalFUNCreturn (signalFUNC)
+#endif
+
+#ifndef signalFUNCreturn
+#define signalFUNCreturn
+#endif
+
+#ifdef FLUSH
+#include <termios.h>
+int flush_fd = -1; /* File descriptor for auto-flush */
+#endif
+
+volatile static int waiting;
+
+static void getalrm(int i)
+{
+ waiting = 0;
+}
+
+void sf_usleep(unsigned t)
+{
+ static struct itimerval it;
+ void (*oldsig)();
+
+ oldsig = signalFUNCreturn signal(SIGALRM, getalrm);
+#ifdef FLUSH
+#define FLUSHTIME 100000 /* Flush interval in microseconds */
+ if (flush_fd != -1) {
+ while (t > FLUSHTIME) {
+ it.it_value.tv_sec = 0;
+ it.it_value.tv_usec = FLUSHTIME;
+ t -= FLUSHTIME;
+ tcflush(flush_fd, TCIFLUSH);
+ waiting = 1;
+ if (setitimer(ITIMER_REAL, &it, NULL))
+ return /*error*/;
+ while (waiting) {
+ pause();
+ }
+ (void) signal(SIGALRM, getalrm);
+ }
+ }
+#endif
+
+ it.it_value.tv_sec = t / 1000000;
+ it.it_value.tv_usec = t % 1000000;
+ waiting = 1;
+ if (setitimer(ITIMER_REAL, &it, NULL))
+ return /*error*/;
+ while (waiting) {
+ pause();
+ }
+ signal(SIGALRM, oldsig);
+}
+#endif
--- /dev/null
+/*
+
+ Egg and basket version information.
+
+*/
+
+#define Version "Release 5.1 (1999-02-28 Dynamic Eggs)"
--- /dev/null
+/*
+
+ Hex dump utility
+
+ by John Walker
+ WWW home page: http://www.fourmilab.ch/
+
+ This program is in the public domain.
+
+*/
+
+#ifdef HEXDUMP
+
+#include <stdio.h>
+#include <string.h>
+
+#define EOS '\0'
+
+static char addrformat[80] = "%6X";
+static char dataformat1[80] = "%02X";
+static int bytesperline = 16, doublechar = 0,
+ dflen = 2;
+static unsigned long fileaddr;
+static unsigned char lineecho[32];
+
+/* OUTLINE -- Edit a line of binary data into the selected output
+ format. */
+
+static void outline(FILE *out, unsigned char *dat, int len)
+{
+ char oline[132];
+ int i;
+
+ sprintf(oline, addrformat, fileaddr);
+ strcat(oline, ":");
+ for (i = 0; i < len; i++) {
+ char outedit[80];
+
+ sprintf(outedit, dataformat1, dat[i]);
+ strcat(oline, (i == (bytesperline / 2)) ? " " : " ");
+ strcat(oline, outedit);
+ }
+
+ if (doublechar) {
+ char oc[2];
+ int shortfall = ((bytesperline - len) * (dflen + 1)) +
+ (len <= (bytesperline / 2) ? 1 : 0);
+
+ while (shortfall-- > 0) {
+ strcat(oline, " ");
+ }
+ oc[1] = EOS;
+ strcat(oline, " | ");
+ for (i = 0; i < len; i++) {
+ int b = dat[i];
+
+ /* Map non-printing characters to "." according to the
+ definitions for ISO 8859/1 Latin-1. */
+
+ if (b < ' ' || (b > '~' && b < 145)
+ || (b > 146 && b < 160)) {
+ b = '.';
+ }
+ oc[0] = b;
+ strcat(oline, oc);
+ }
+ }
+ strcat(oline, "\n");
+ fputs(oline, out);
+}
+
+/* XD -- Dump a buffer.
+
+ xd(out, buf, bufl, dochar);
+
+ out FILE * to which output is sent.
+ buf Address of buffer to dump.
+ bufl Buffer length in bytes.
+ dochar If nonzero, show ASCII/ISO characters
+ as well as hexadecimal.
+
+*/
+
+void xd(FILE *out, void *bub, int bufl, int dochar)
+{
+ int b, bp;
+ unsigned char *buf = (unsigned char *) bub;
+
+ bp = 0;
+ fileaddr = 0;
+ doublechar = dochar;
+
+ while (bufl-- > 0) {
+ b = *buf++;
+ if (bp >= bytesperline) {
+ outline(out, lineecho, bp);
+ bp = 0;
+ fileaddr += bytesperline;
+ }
+ lineecho[bp++] = b;
+ }
+
+ if (bp > 0) {
+ outline(out, lineecho, bp);
+ }
+}
+#endif