gcpegg-5.1.orig/ 42775 1750 1750 0 6711746050 12110 5ustar bdalebdalegcpegg-5.1.orig/Makefile100664 1750 1750 7217 6677445211 13660 0ustar bdalebdale # 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 gcpegg-5.1.orig/README100644 1750 1750 3305 6677446353 13100 0ustar bdalebdale 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 gcpegg-5.1.orig/basket.c100444 1750 1750 61331 6677445211 13646 0ustar bdalebdale/* 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 #include #include #include #include #include #include #include #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, "\ \n\ \n\ \n\ Basket %s Status Report\n\ \n\ \n\ \n\
\n\

Basket %s Status Report

\n\

Last update: %s UTC

\n\

Basket started at %s UTC
\n\ %s

\n\
\n\
\n\

Egg Status

\n\ \n\
NameNumberUp SinceLast PacketActive\n\ TrialsMissedCoverageMean\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, "Never contacted"); strcpy(ustime, ""); } else { strftime(udate, sizeof udate, "%Y-%m-%d %T", gmtime((time_t *) &eggtable[i].lastupd)); strftime(ustime, sizeof ustime, "%Y-%m-%d %T", gmtime((time_t *) &eggStatistics[i].firstPacket)); } if (eggtable[i].url == NULL) { url1[0] = url2[0] = 0; } else { sprintf(url1, "", eggtable[i].url); strcpy(url2, ""); } fprintf(hf, "
%s%s%s%d%s%s%s\n\ ", url1, eggtable[i].name, url2, eggtable[i].id, ustime, udate, eggtable[i].setup ? "Yes" : "No" ); if (eggStatistics[i].trials == 0) { fprintf(hf, "    \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, "%ld%ld%ld%%%.3f\n", eggStatistics[i].trials, eggStatistics[i].missing, coverage, eggStatistics[i].sum / eggStatistics[i].trials ); } } fprintf(hf, "\
\n\
\n\
\n\

Egg Status Table Fields

\n\ \n\
Name Egg name

\n\

Number Egg number. Thousands digit indicates type of random event generator.

\n\

Up Since Time and date in first packet received from egg since basket started.

\n\

Last Packet Time and date of most recently received packet from egg.

\n\

Active Has egg ever communicated with this basket since it was started?

\n\

Trials Number of trials received from this egg.

\n\

Missed Number of scheduled trials missed by egg due to synchronisation problems.

\n\

Coverage Percent of trials collected from this egg since basket\n\ started compared to the number scheduled by the protocol.

\n\

Mean Arithmetic mean of trials performed by this egg.\n\
\n\
\n\ \n\ \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 \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); } gcpegg-5.1.orig/basketrc.sample100644 1750 1750 720 6677445211 15167 0ustar bdalebdale#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 gcpegg-5.1.orig/byteorder.h100444 1750 1750 3053 6677445211 14356 0ustar bdalebdale/* 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; \ } gcpegg-5.1.orig/crc16.c100444 1750 1750 5640 6677445211 13274 0ustar bdalebdale/* 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; } gcpegg-5.1.orig/egg.c100444 1750 1750 72241 6677445211 13141 0ustar bdalebdale/* 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 #include #include #include #include #include #include #include #include #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 \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 } gcpegg-5.1.orig/eggrc.sample100664 1750 1750 5576 6677445212 14521 0ustar bdalebdale# 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 # # The primary basket is the name of the basket (defined # below) that should be contacted retrieve data from this Egg. # The connection type is "PERM" (permanent) or "DND" # (dial-and-drop). So far the code does not support the DND option. # The connection interval determines the time (in minutes) # between transmission attempts. If specified, and not equal to # ".", gives a URL (for example http://www.somesite.net/page.html) # which will be linked to the egg 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 # # 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 # # Specify the default data collection protocol. The arguments are # samples per record (1-10, though this should always be 5-10), # seconds per records (1-3000), # records per packet (1-60), and # bits per sample (32-255). # # REG # # Specify hardware device. Supported types include "PEAR" only at # this time. Port is serial port number (e.g. 1 for /dev/ttyS1); # is baud rate. # # NETUP