/* * Totally original code by: John Logajan, March 1989. * 4248 Hamline Ave * Arden Hills, MN 55112 * * (john@logajan.mn.org or ...rutgers!bungia!logajan!john) * * G engine extracted, converted into C by: Orc (david parsons) (3/91) * * Many of the comments are left over from the Basic version, but the * code has been chopped up around them, so they have less relation * to the current code than you might hope for. A good understanding * of the G protocol is probably needed to understand this code. */ #include #include #include #include #ifdef DEBUGX #define DEBUG(a,b) fprintf(stdout, "%s %s\n", a, b) #else #define DEBUG(a,b) #endif /* important character constants */ #define DLE 0x10 /* G commands */ #define RR 0x20 /* received packet */ #define RJ 0x10 /* reject packet */ #define INITA 0x38 /* the init sequence */ #define INITB 0x30 /* " " */ #define INITC 0x28 /* " " */ #define CLOSE 0x08 /* close up session */ #define DATAPK 0x80 /* full data packet */ #define SHRTPK 0xC0 /* short data packet */ /* various buffer sizes */ #define HDRSIZ 6 #define RPKTSIZ 64 #define RPKTSZH (RPKTSIZ+HDRSIZ) #define RWINSIZ 3 #define RPKTCOD 2 /* coded RPKTSIZ (32 * 2^(PKTCOD-1)) */ #define UNACKED (((Xseq-Xack)+8) & 7) extern unsigned long Chk(); /* G checksummer */ extern unsigned char *realloc(); /* to allocate Xmit buffers */ unsigned char Rcvbf[RPKTSIZ]; unsigned char *Xppt = (unsigned char *)0; unsigned char *Xpd, *Xph; unsigned int Rseq, Rrseq, Xseq, Xack; unsigned Xwinsiz; /* Xmit window size */ unsigned Control; /* latest packet control byte */ unsigned Wcc; unsigned Found; unsigned char *Wrklin; /* for Wrqtpkt() */ unsigned Dpkt; unsigned Frmcmd, Ptyp; unsigned Rr, Rsum; unsigned Xctrl; unsigned Xpf; unsigned Xpktcod, Xpktsiz, Xpktszh; extern int (*cdf)(); extern jmp_buf Sjbuf; extern int Debug; static int Sizes[] = { 1, 32, 64, 128, 256, 512, 1024, 2048, 4096, 0 } ; gturnon() { register unsigned Bit; register unsigned retry; int Inita, Initb, Initc; Rseq = Rrseq = Xseq = Xack = Inita = Initb = Initc = 0; for (retry=1; retry<=10; retry++) { if (Inita == 0 || Initb == 0) { Wcc = INITA | RWINSIZ; Wctlpkt(2); } Waitframe(); if (Found && (Control & 0xF8) == INITA) { Inita = 1; Xwinsiz = Control & 7; if (Xwinsiz > 3) Xwinsiz = 3; /*ADD: was RPKTCOD=(int)(Log(RPKTSIZ)/Log(2)-4.9)*/ Wcc = INITB | (RPKTCOD-1); /*ADD*/ Wctlpkt(2); Waitframe(); } if (Found && (Control & 0xF8) == INITB) { Initb = 1; Xpktcod = 1+(Control & 7); /*ADD: was Xpktsiz = 32 * 2^(Xpktcod-1)*/ Xpktsiz = Sizes[Xpktcod]; /*ADD*/ Xpktszh = HDRSIZ + Xpktsiz; } if (Inita && Initb) break; } if (Initb) { Wcc = INITC | RWINSIZ; Wctlpkt(2); /* initc window size. */ for (retry=1; retry<=3; retry++) { Waitframe(); if (Found && (Control & 0xF8) == INITC) { Initc = 1; break; } } } if (Inita && Initb && Initc) { Xack = Xseq; if (Xppt = realloc(Xppt, (int)(9 * Xpktszh))) return 0; logerror("Out of memory allocating Xmit bfr"); } return 1; } gwrmsg(cntrl, msg) char *msg; { static unsigned char workline[512]; sprintf(Wrklin=workline, "%c%s", cntrl, msg); DEBUG("gwrmsg", Wrklin); while (Wrqtpkt()) ; } gwrdata(file) FILE *file; { DEBUG("gwrdata", ""); while (Wfilepkt(fileno(file))) ; if (Debug > 1 && Debug < 7) putc('\n', stderr); } grdmsg(text) register char *text; { register unsigned size; do { size = Waitdata(text); text += size; } while (size > 0 && memchr(text-size, 0, size) == 0); *text = 0; return 0; } grddata(file) FILE *file; { register unsigned size; char bfr[RPKTSIZ]; register long fsize; for (fsize=0; size = Waitdata(bfr); ) if (write(fileno(file), bfr, size) != size) { printmsg(2, "disk write error"); return -1; } else if (Debug > 1 && Debug < 7) { fprintf(stderr, "\r%ld ", fsize += size); fflush(stderr); } if (Debug > 1 && Debug < 7) putc('\n', stderr); return 0; } gturnoff() { static unsigned char hup[] = { 0x10, 0x09, 0xA2, 0xAA, 0x08, 0x09 }; printmsg(8, "Gturnoff"); ttywrite(hup, HDRSIZ); Waitframe(); if (Frmcmd == RR) Waitframe(); if (Frmcmd != CLOSE) { logerror("Failed waiting for CLOSE!"); longjmp(Sjbuf, 1); } } Waitframe() { register unsigned int Rsum1, Rsum2, Wfr, Xs; unsigned int Pkcod; unsigned char Wfp[HDRSIZ]; Rsum = Found = Rr = Dpkt = 0; Wfr = Rcv(Wfp, HDRSIZ); while (Wfr == 0) { if (Wfp[0] == DLE) { Pkcod = Wfp[1]; Rsum1 = Wfp[2]; Rsum2 = Wfp[3]; Control = Wfp[4]; Xs = Pkcod ^ Rsum1 ^ Rsum2 ^ Control; Rsum = ((Rsum2 << 8) & 0xff00) | (Rsum1 & 0xff); if (Xs == Wfp[5]) { dpkinfo("<", -1, Wfp); Found = 1; Ptyp = 0xC0 & Control; if (Ptyp == 0) { Xack = Control & 7; Frmcmd = Control & 0x38; Rr = (Frmcmd == RR); printmsg(7, "Ckpt:Xack %d, Cmd %02x", Xack, Frmcmd); } else { Dpkt = 1; Rrseq = (Control >> 3) & 7; printmsg(7, "Dkpt:Rrseq %d, Control %02x", Rrseq, Control & 0xf0); } return 1; /* found a packet - we can leave happily */ } else { dpkinfo("Xsum<", -1, Wfp); Wfr = Rcv(Wfp, HDRSIZ); } } else { memcpy(Wfp, Wfp+1, HDRSIZ-1); Wfr = Rcv(Wfp+(HDRSIZ-1), 1); } } /* while Wfr == 0 */ return 0; } /* Waitframe */ /* * Writes: One data packet, from file opened as #1, to RS232 opened as #2. * Returns: Xfdone!=True after last packet sent. * Initial: Xfl%=Lof(#1), Xfp%=0, Xppt%=base packet pointer, * xpktsiz%, xpktcod%, xpktsizh%. * Current: Rseq%=last rcvd packet sequence number, Xseq%=last xmited. * Updates: Xseq%=xmited packet sequence number, Xfp%=xmited data pointer. */ Wfilepkt(file) { register unsigned int size; register unsigned int Xf1, Xsum; register int adjsiz; unsigned char *tXpd = Xppt + (8 * Xpktszh); extern long tell(); Xseq = (1+Xseq) & 7; Xph = Xppt + (Xseq * Xpktszh); Xpd = Xph + HDRSIZ; Xph[0] = DLE; Xph[1] = Xpktcod; size = read(file, tXpd, Xpktsiz); if (Debug > 1 && Debug < 7) { fprintf(stderr, "\r%ld ", tell(file)); fflush(stderr); } #ifdef DEBUGX fprintf(stdout, "\r%ld (%d)", tell(file), size); fflush(stdout); #endif if (size == Xpktsiz) { memcpy(Xpd, tXpd, size); Xctrl = DATAPK | (Xseq * 8) | Rseq; Xsum = Chk(Xpd, size, Xctrl); Xph[2] = Xsum; Xf1 = Xsum >> 8; Xph[3] = Xf1; Xph[4] = Xctrl; Xph[5] = Xpktcod ^ Xsum ^ Xf1 ^ Xctrl; Wchkwin(0); return 1; } else if (size > 0) { /* short packet */ adjsiz = Xpktsiz - size; if (adjsiz < 128) { Xpd[0] = adjsiz; memcpy(1+Xpd, tXpd, size); } else { Xpd[0] = (adjsiz & 0xff) | 0x80; Xpd[1] = (adjsiz >> 7); memcpy(2+Xpd, tXpd, size); } Xctrl = SHRTPK | (Xseq * 8) | Rseq; Xsum = Chk(Xpd, Xpktsiz, Xctrl); Xph[2] = Xsum; Xf1 = Xsum >> 8; Xph[3] = Xf1; Xph[4] = Xctrl; Xph[5] = Xpktcod ^ Xsum ^ Xf1 ^ Xctrl; Wchkwin(0); return 1; } else { /* empty framing packet for end of file */ if (Xpktsiz < 128) Xpd[0] = Xpktsiz; else { Xpd[0] = (Xpktsiz & 0x7f) | 0x80; Xpd[1] = (Xpktsiz >> 7); } Xctrl = SHRTPK | (Xseq*8) | Rseq; Xsum = Chk(Xpd, Xpktsiz, Xctrl); Xph[2] = Xsum; Xf1 = Xsum >> 8; Xph[3] = Xf1; Xph[4] = Xctrl; Xph[5] = Xpktcod ^ Xsum ^ Xf1 ^ Xctrl; #ifdef DEBUGX fprintf(stdout, "EOF\n"); fflush(stdout); #endif Wchkwin(1); return 0; } } /* Wfilepkt */ /* * This procedure sends data packets used for H,S,C type signals. * It differs from the other data packets in that there are no short * packets. Instead a zero follows each command string and a zero * must appear as the last byte in the packet. */ Wrqtpkt() /* Initial: Xrqp%=0, Wrklin$, Xfdone!=False. */ { register unsigned Xsum, Xf1, Xstl; Xstl = strlen(Wrklin); Xseq = (1+Xseq) & 7; Xph = Xppt + (Xseq*Xpktszh); Xpd = Xph + HDRSIZ; Xph[0] = DLE; Xph[1] = Xpktcod; memcpy(Xpd, Wrklin, Xpktsiz); if (Xstl < Xpktsiz) memset(Xpd+Xstl, 0, Xpktsiz-Xstl); Xctrl = DATAPK | (Xseq*8) | Rseq; Xsum = Chk(Xpd, Xpktsiz, Xctrl); Xph[2] = Xsum; Xf1 = Xsum >> 8; Xph[3] = Xf1; Xph[4] = Xctrl; Xph[5] = (Xpktcod ^ Xsum ^ Xf1 ^ Xctrl); Wchkwin(Xstl < Xpktsiz); Wrklin += Xpktsiz; return (Xstl >= Xpktsiz); } /* Wrqtpkt */ /* * This procedure sends RR's, RJ's, CLOSE, and INITA,B,C's. */ Wctlpkt(Wct) /* wct%=0 for RR, 1 for Rj, 2 for other. */ { unsigned char bfr[HDRSIZ]; unsigned Wc0, Wc1, Wcx; register count; register char *p; if (Wct==0) { printmsg(7, "RR %d", Rseq); Wcc = RR | Rseq; } else if (Wct == 1) { printmsg(7, "RJ %d", Rseq); Wcc = RJ | Rseq; } Wc1 = 0xAAAA-Wcc; Wc0 = Wc1 & 0xFF; Wc1 /= 256; Wcx = 9 ^ Wc0 ^ Wc1 ^ Wcc; bfr[0] = DLE; bfr[1] = 0x09; bfr[2] = Wc0; bfr[3] = Wc1; bfr[4] = Wcc; bfr[5] = Wcx; printmsg(8, "[0x09 %02x %02x %02x %02x]", bfr[2], bfr[3], bfr[4], bfr[5]); ttywrite(bfr, HDRSIZ); } /* Wctlpkt */ /* * This procedure waits to receive a data packet. It RR's them as soon * as it sees them. */ Waitdata(bfr) char *bfr; { register unsigned Wf, Dif, Dfc; for (Wf=1; Wf<=20; Wf++) { Waitframe(); if (Dpkt) { if (Rcv(Rcvbf, RPKTSIZ) != 0) printmsg(4, "Short packet"); else if ( ((1+Rseq) & 7) != Rrseq) { /* Might be a resent packet - if so, just reack it and * continue on our way. */ register short Win; register resent; Win = (Rseq-RWINSIZ) & 7; if (Win > Rrseq) resent = (Rrseq >= Win) || (Rrseq <= Rseq); else resent = (Rrseq >= Win) && (Rrseq <= Rseq); if (resent) { printmsg(4, "Resent %d", Rrseq); Wf = Rseq; Rseq = Rrseq; Wctlpkt(0); Rseq = Wf; continue; } printmsg(4, "Expected %d, got %d", (1+Rseq) & 7, Rrseq); Rr = 0; } else if (Rsum != Chk(Rcvbf, RPKTSIZ, Control)) printmsg(4, "Bad checksum"); else { Rseq = Rrseq; Wctlpkt(0); if (Ptyp == DATAPK) { Dfc = 0; Dif = RPKTSIZ; } else { Dif = Rcvbf[0]; if (Dif >= 128) { Dif = (Dif-128) + (Rcvbf[1]*128); Dfc = 2; } else Dfc = 1; Dif = RPKTSIZ-Dif; } if (Dif) memcpy(bfr, Rcvbf+Dfc, Dif); printmsg(6, "%d data bytes", Dif); return Dif; } } else printmsg(4, "Not a data packet"); if (!Rr) { /* wait a while for the sender to stop sending, * then throw away all input and reject the * packet we failed on */ sleep(5); flush(); Wctlpkt(1); } } logerror("Failed waiting for a data frame"); longjmp(Sjbuf, 1); } /* Waitdata */ /* * debugging printout of a packet for debugging */ dpkinfo(msg, pkno, pkt) char *msg; unsigned char *pkt; { unsigned long Xsum, Xcalc; unsigned Xs; register i; if (Debug < 8) return 0; Xs = pkt[1] ^ pkt[2] ^ pkt[3] ^ pkt[4]; Xsum = (pkt[3]<<8) | pkt[2]; Xcalc = Chk(pkt+HDRSIZ, Xpktsiz, (unsigned int)pkt[4]); fprintf(stderr, "%s %06lo %03o ", msg, 0xffff & Xcalc, 0xff & Xs); if (pkno >= 0) fprintf(stderr, "%d ( ", pkno); else fprintf(stderr, " ( ", pkno); for (i=0; i0 && ttystat() == 0; --i) sleep(1); Waitframe(); printmsg(10, "Rr %d, Xack %d, Xjr %d, Xseq %d, Found %d", Rr, Xack, Xjr, Xseq, Found); if (Found == 0 || Rr == 0) { if (retries++ > 10) { printmsg(4, "RJ %d couldn't resync", Xack); return 0; } Jr--; } else if (Xjr == Xseq) return 1; } return 0; } /* Wckack */ /* * * This procedure handles the windowing of sent data packets. * It sends as many packets as allowed before waiting for RR's. */ Wchkwin(synchronise) { register int retry; register naked=0; while (ttystat() || (UNACKED >= Xwinsiz)) if (!Wckack()) { logerror("Failed waiting for RR."); longjmp(Sjbuf, 1); } dpkinfo(">", Xseq, Xph); ttywrite(Xph, Xpktszh); if (synchronise) while (Xack != Xseq) if (!Wckack()) { logerror("Failed waiting for flushed RR."); longjmp(Sjbuf, 1); } } /* Wchkwin */ #if OS2|MSDOS Rcv(b, size) register int size; register unsigned char *b; { register c; register unsigned long timeout = clock() + (12*CLK_TCK); while (clock() < timeout) { if ((c=receive(1)) >= 0) { *b++ = c; if (--size < 1) return 0; } else if ((*cdf)() == 0) longjmp(Sjbuf, 1); } return 1; } /* Rcv */ #endif #if GEMDOS #include Rcv(b, size) register int size; register unsigned char *b; { register unsigned long timeout = clock()+(12*CLK_TCK); while (clock() < timeout) { if (ttystat()) { *b++ = ttyin(); if (--size < 1) return 0; } else if ((*cdf)()) Syield(); else longjmp(Sjbuf, 1); } return 1; } #endif