/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** TheNetNode */ /* ***** ***** Portable */ /* ***** ***** Network */ /* ***** ***** Software */ /* */ /* File src/buffer.c (maintained by: DF6LN) */ /* */ /* This file is part of "TheNetNode" - Software Package */ /* */ /* Copyright (C) 1998 - 2008 NORD>| | -> hd ------->| |-----+ | * * +--------+ +--------+ | * * | | | |-------+ * * +--------+ +--------+ * * | | | | * * * \************************************************************************/ void inithd(LHEAD *hd) { hd->head = hd->tail = hd; } /************************************************************************/ /* Anfang des freien Speichers */ /*----------------------------------------------------------------------*/ static char huge * minmem(void) { return (RAMBOT); } /************************************************************************/ /* Ende des freien Speichers */ /*----------------------------------------------------------------------*/ static char huge * maxmem(void) { return (RAMTOP); } /************************************************************************/ /* Buffer-Verwaltung initialisieren. */ /*----------------------------------------------------------------------*/ void init_buffers(void) { MAX_BUFFER huge *actbp; ULONG n; nmblks = nmbfre = nmblks_max = 0; actbp = (MAX_BUFFER *)minmem(); n = (ULONG)((maxmem() - minmem()) / sizeof(MAX_BUFFER)); #ifdef __WIN32__ nmbfre_max = (unsigned short)n; #else nmbfre_max = n; #endif /* WIN32 */ while (n--) { #ifdef BUFFER_DEBUG ((MBHEAD *)actbp)->owner = ALLOC_LEHEAD; #endif dealoc((MBHEAD *)actbp++); } nmbfre_min = nmbfre; } /************************************************************************\ * * * action : Element aus Liste aushaengen. * * * * * * le ---+ * * vor | raus hinter * * +--------+ +-->+--------+ +--------+ * * ----->| |--------->| prevle |--------->| |-----> * * +--------+ +--------+ +--------+ * * <-----| |<---------| nextle |<---------| |<----- * * +--------+ +--------+ +--------+ * * | | | | | | * * * * * * \/ * * * * * * raus vor hinter * * +--------+ +--------+ +--------+ * * le --->| nextle | ----->| |----->| |-----> * * +--------+ +--------+ +--------+ * * | prevle | <-----| |<-----| |<----- * * +--------+ +--------+ +--------+ * * | | | | | | * * * * * ************************************************************************ * * * parameter : le - Zeiger auf auszuhaengendes Listenelement * * * * returns : le * * * \************************************************************************/ LEHEAD * ulink(LEHEAD *le) { le->prevle->nextle = le->nextle; /* Hinliste ohne le */ le->nextle->prevle = le->prevle; /* Rueckliste ohne le */ return (le); /* Zeiger auf das Element zurueck */ } /************************************************************************\ * * * action : Element in Liste einhaengen. * * * * * * neu vor hinter * * +--------+ +--------+ +--------+ * * new --->| nextle | pred --->| |----->| |-----> * * +--------+ +--------+ +--------+ * * | prevle | <-----| |<-----| |<----- * * +--------+ +--------+ +--------+ * * | | | | | | * * * * * * \/ * * * * * * new ---+ * * vor | neu hinter * * +--------+ +-->+--------+ +--------+ * * pred --->| |--------->| prevle |--------->| |-----> * * +--------+ +--------+ +--------+ * * <-----| |<---------| nextle |<---------| |<----- * * +--------+ +--------+ +--------+ * * | | | | | | * * * * * ************************************************************************ * * * parameter : new - Zeiger auf einzuhaengendes Listenelement * * pred - Zeiger auf Listenelement, hinter dem new * * eingehaengt werden soll * * * * returns : new * * * \************************************************************************/ LEHEAD * relink(LEHEAD *new, LEHEAD *pred) { new->nextle = pred->nextle; /* Vorzeiger im neuen Element */ new->prevle = pred; /* Rueckzeiger im neuen Element */ new->nextle->prevle = new; /* Rueckzeiger dahinter */ pred->nextle = new; /* Vorzeiger davor */ return (new); /* Zeiger auf neues Element */ } /************************************************************************\ * * * action : "allocate buffer" * * * * Leeren Buffer aus der Freiliste holen, Programmneustart * * wenn keine Buffer mehr in Freiliste. * * * ************************************************************************ * * * r/w globals : nmbfre - Anzahl der Buffer in Freiliste freel * * freel - verkettete Liste der freien Buffer * * * * locals : s.u. * * * * returns : Zeiger auf freien Buffer, fall vorhanden * * * \************************************************************************/ LEHEAD * #ifdef BUFFER_DEBUG allocb(int owner) #else allocb(void) #endif { LEHEAD *ret; /* Buffer Rueckgabewert */ nmbfre--; /* 1 Buffer weniger */ if (nmbfre < nmbfre_min) nmbfre_min = nmbfre; if (!nmbfre) /* wenn nicht genug frei */ { #ifdef BUFFER_DEBUG bufstat(); /* Buffernutzung protokollieren */ #endif HALT("allocb: no free buffers !"); /* dann Rechner neu starten.. */ } ret = ulink((LEHEAD *)freel.head); /* Buffer aus Liste aushaengen */ #ifdef BUFFER_DEBUG if (ret->owner != ALLOC_NO_OWNER) { bufstat(); /* Buffernutzung protokollieren */ HALT("allocb: buffer with owner in free-list !"); } ret->owner = (UBYTE)owner; #endif return (ret); /* Zeiger auf Freibuffer zurueck */ } /************************************************************************\ * * * "deallocate" * * * * Buffer, auf den bp zeigt, initialisieren als neuen Messagebufferhead * * (rwndmb()) und deallokieren, d.h. in die Freiliste freel einhaengen * * und den Freibufferzaehler nmbfre inkrementieren. * * * * * * +--------+ * * bp --->| | deallokieren * * +--------+ * * | | * * +--------+ * * | | * * * \************************************************************************/ void dealoc(MBHEAD *bp) { #ifdef INSANE_BUFFER_DEBUG MBPTRCHECK(bp); #endif bp->mbl.head = /* als Messagehead initialisieren */ bp->mbl.tail = /* Bufferlistenkopf */ &bp->mbl; /* initialisieren */ bp->mbpc = 0; /* Message leer */ bp->mbgc = 0; /* Rest initialisieren */ bp->mbbp = NULL; #ifdef BUFFER_DEBUG if (bp->owner != ALLOC_NO_OWNER) bp->owner = ALLOC_NO_OWNER; else HALT("dealoc: buffer with no owner !"); /* Rechner neu starten.. */ #endif rwndmb(bp); /* Buffer an Freiliste anhaengen */ relink((LEHEAD *)bp, (LEHEAD *)freel.tail); ++nmbfre; /* 1 Freibuffer mehr */ if (nmbfre > nmbfre_max) /* > nmbfre_max darf nicht sein! */ HALT("dealoc: more buffers free than allocated !"); /* neu starten */ } /************************************************************************\ * * * "deallocate message buffer" * * * * Einen kompletten Messagespeicher, auf dessen Kopf mbhd zeigt, * * deallokieren, d.h. sowohl den Messagebufferhead als auch alle an * * dessen Messagebufferliste haengende Datenbuffer deallokieren. * * * * * * +--------+ deallokieren * * mbhd -->| | * * +--------+ * * | | * * +--------+ +--------+ +--------+ * * a --->| |----->| |---> --->| |---> a * * + mbl + +--------+ ... +--------+ * * b <---| |<-----| |<--- <---| |<--- b * * +--------+ +--------+ +--------+ * * | | | | | | * * * \************************************************************************/ void dealmb(MBHEAD *mbhd) { MB *bp; /* Datenbufferzeiger */ #ifdef INSANE_BUFFER_DEBUG MBPTRCHECK(mbhd); #endif /* alle Datenbuffer */ while ((bp = (MB *)mbhd->mbl.head) != (MB *)&mbhd->mbl) dealoc((MBHEAD *)ulink((LEHEAD *)bp)); dealoc(mbhd); /* Am Ende den Kopf */ } /************************************************************************\ * * * "deallocate message list" * * * * Komplette Messageliste, auf deren Listenkopf mlp zeigt, deallokieren. * * D.h. alle Messagespeicher (jeweils Kopf und daran haengende * * Datenbuffer) deallokieren. * * * * * * +--------+ +--------+ +--------+ * * mlp --->| head |--->| |---> --->| |---> mlp * * +--------+ +--------+ ... +--------+ * * b <---| tail |<---| |<--- <---| |<--- b * * +--------+ +--------+ +--------+ * * | |---> \ | |---> \ * * + + | + + | * * | |<--- /| | |<--- /| * * +--------+ | +--------+ | * * | | | | | | * * | | * * deallokieren |------------------------| * * siehe unten dealmb() * * * \************************************************************************/ /*#include "coredump.c" */ void dealml(LEHEAD *mlp) { MBHEAD *bp; /* Zeiger auf Messagebufferhead */ #if 0 int i; for (bp = (MBHEAD *)mlp->nextle, i = 0; bp != (MBHEAD *)mlp; bp = (MBHEAD *)bp->nextmh) if (++i > 10000) { /* Fehler !!! */ coredump(); i = *((char *)NULL); /* Zugriff auf NULL-Pointer */ exit(-1); /* notfalls normaler exit */ } #endif LOOP /* fuer alle Messagebufferheads */ { /* in Messagespeicherliste : */ bp = (MBHEAD *)mlp->nextle; /* Zeiger auf naechsten Msgbhead */ if (mlp == (LEHEAD *)bp) /* Schwanz beisst Kopf -> fertig */ break; /* sonst Messagespeicher deallok. */ dealmb((MBHEAD *)ulink((LEHEAD *)bp)); } } /************************************************************************\ * * * action : "rewind message buffer" * * * * Message-Buffer (Kopf und Datenbufferliste) zuruecksetzen. * * Get-Counter auf 0 setzen, Buffer-Pointer so setzen, dass * * beim naechsten getchr() auf das das erste Datenbyte des * * ersten Datenbuffers zugegriffen wird. * * (Dies muss wie folgt geschehen, da der Get-Counter in * * jedem Fall auf 0 stehen muss und in getchr() auf % 32 * * fuer das Positionieren auf den naechsten Datenbuffer * * abgetestet wird.) * * * ************************************************************************ * * * parameter : mbhd - Zeiger auf Kopf des Message-Buffers * * * \************************************************************************/ void rwndmb(MBHEAD *mbhd) { #ifdef INSANE_BUFFER_DEBUG MBPTRCHECK(mbhd); #endif /* Kopf wie Datenbufferende */ mbhd->mbbp = (char *)(((MAX_BUFFER huge *)&(mbhd->mbl)) + 1); mbhd->mbgc = 0; /* Bufferanfang */ } /************************************************************************\ * * * action : "put character" * * * * Zeichen in Messagebuffer schreiben, Put-Counter erhoehen * * und Buffer-Pointer setzen. Ist der aktuelle Datenbuffer * * im Messagebuffer voll, dann neuen Datenbuffer allokieren * * und ans Datenbufferlistenende des Messagebuffers * * anhaengen. * * * ************************************************************************ * * * parameter : ch - in den Buffer zu schreibendes Zeichen * * mbhd - Zeiger auf den Messagebuffer-Kopf, in den ch * * zu schreiben ist * * * * r/o globals: - * * * * r/w globals: - * * * * locals : - * * * * returns : - * * * \************************************************************************/ void putchr(char ch, MBHEAD *mbhd) { #ifdef INSANE_BUFFER_DEBUG MBPTRCHECK(mbhd); #endif if (mbhd->mbpc++ % sizeof_MBDATA == 0) mbhd->mbbp = ((MB *)(relink((LEHEAD *)allocb(ALLOC_LEHEAD), (LEHEAD *)mbhd->mbl.tail)))->data; *mbhd->mbbp++ = ch; } /************************************************************************\ * * * action : "get character" * * * * Zeichen aus einem Messagebuffer holen. Datenbuffer-Poiner * * setzen und Get-Count erhoehen. Uebergang in der * * Datenbufferliste vom Ende eines Datenbuffers zum * * naechsten ausfuehren. * * * ************************************************************************ * * * parameter : mbhd - Zeiger auf Kopf des Messagebuffers, aus dem * * das Zeichen gelesen werden soll * * * * r/o globals: - * * * * r/w globals: - * * * * locals : - * * * * returns : aus dem Buffer gelesenes Zeichen * * * \************************************************************************/ #ifdef __WIN32__ unsigned char #else char #endif /* WIN32 */ getchr(MBHEAD *mbhd) { #ifdef INSANE_BUFFER_DEBUG MBPTRCHECK(mbhd); #endif if (mbhd->mbgc++ % sizeof_MBDATA == 0) mbhd->mbbp = ((MB *)((MAX_BUFFER huge *)(mbhd->mbbp) - 1))->nextmb->data; return (*mbhd->mbbp++); } #ifndef MC68K /************************************************************************ * Function : 16 Bits aus einem Buffer lesen * * Inputs : Zeiger auf den Buffer * * Returns : unsigned integer * * Operation : Liest 2 Bytes und vertauscht sie *----------------------------------------------------------------------*/ UWORD get16(MBHEAD *mbhd) { UWORD retval; #ifdef INSANE_BUFFER_DEBUG MBPTRCHECK(mbhd); #endif retval = ((UWORD)(getchr(mbhd)) << 8); retval |= (UWORD)getchr(mbhd); return (retval); } /************************************************************************ * Function : Schreibt ein Word in den Buffer * * Inputs : Der Wert (Word), Zeiger auf den Buffer * * Returns : nothing * * Operation : *----------------------------------------------------------------------*/ void put16(UWORD value, MBHEAD *mbhd) { #ifdef INSANE_BUFFER_DEBUG MBPTRCHECK(mbhd); #endif putchr((BYTE)((value >> 8) & 0xff), mbhd); putchr((BYTE)(value & 0xff), mbhd); } /************************************************************************ * Function : 32 Bits aus einem Buffer lesen * * Inputs : Zeiger auf den Buffer * * Returns : unsigned long integer * * Operation : Liest 2 Words und vertauscht sie *----------------------------------------------------------------------*/ ULONG get32(MBHEAD *mbhd) { ULONG retval; #ifdef INSANE_BUFFER_DEBUG MBPTRCHECK(mbhd); #endif retval = ((ULONG)(getchr(mbhd)) << 24); retval |= ((ULONG)(getchr(mbhd)) << 16); retval |= ((ULONG)(getchr(mbhd)) << 8); retval |= (ULONG)getchr(mbhd); return (retval); } /************************************************************************ * Function : Schreibt ein Long in den Buffer * * Inputs : Der Wert (Long), Zeiger auf den Buffer * * Returns : nothing * * Operation : *----------------------------------------------------------------------*/ void put32(ULONG value, MBHEAD *mbhd) { #ifdef INSANE_BUFFER_DEBUG MBPTRCHECK(mbhd); #endif putchr((BYTE)((value >> 24) & 0xff), mbhd); putchr((BYTE)((value >> 16) & 0xff), mbhd); putchr((BYTE)((value >> 8) & 0xff), mbhd); putchr((BYTE)(value & 0xff), mbhd); } #else UWORD get16(MBHEAD *mbhd) { UWORD retval; char *r = (UBYTE *)&retval; #if defined(BUFFER_DEBUG) && defined(__LINUX__) || defined(__WIN32__) MBPTRCHECK(mbhd); #endif *r++ = getchr(mbhd); *r = getchr(mbhd); return (retval); } void put16(UWORD value, MBHEAD *mbhd) { char *r = (UBYTE *)&value; #if defined(BUFFER_DEBUG) && defined(__LINUX__) || defined(__WIN32__) MBPTRCHECK(mbhd); #endif putchr(*r++, mbhd); putchr(*r, mbhd); } ULONG get32(MBHEAD *mbhd) { ULONG retval; char *r = (UBYTE *)&retval; #if defined(BUFFER_DEBUG) && defined(__LINUX__) || defined(__WIN32__) MBPTRCHECK(mbhd); #endif *r++ = getchr(mbhd); *r++ = getchr(mbhd); *r++ = getchr(mbhd); *r = getchr(mbhd); return (retval); } void put32(ULONG value, MBHEAD *mbhd) { char *r = (UBYTE *)&value; #if defined(BUFFER_DEBUG) && defined(__LINUX__) || defined(__WIN32__) MBPTRCHECK(mbhd); #endif putchr(*r++, mbhd); putchr(*r++, mbhd); putchr(*r++, mbhd); putchr(*r, mbhd); } #endif /************************************************************************\ * * * "split copy" * * * * Die Bytes aus dem Messagebuffer, auf dessen Kopf mbhd zeigt, in den * * Framebuffer, auf dessen Kopf fbp zeigt, kopieren. Es werden hoechstens * * max Bytes kopiert, hat die Message mehr Bytes, so wird ein neuer * * Messagebuffer angelegt, die restlichen Messagebytes werden in diesen * * Buffer kopiert, der neue Buffer wird hinter den alten Messagebuffer * * gehaengt, der Putcount des alten Buffers wird auf max gestellt, das * * "more follows"-Flag morflg des neuen Buffers wird geloescht, l2fflg * * wird uebertragen. * * * * Return : TRUE - der Messagebuffer wurde aufgesplittet * * FALSE - sonst * * * \************************************************************************/ BOOLEAN splcpy(WORD max, MBHEAD *fbp, MBHEAD *mbhd) { char huge *mbbpsa; /* Sicherung mbbp */ BOOLEAN split; /* TRUE: Split erfolgt */ WORD mbgcsa; /* Sicherung mbgc */ WORD mbgc2; /* mbgc alt -> mbpc alt */ WORD n; /* Zaehler */ MBHEAD *mbhd2; /* Kopfzeiger neuer Messagebuffer */ split = FALSE; /* zunaechst nichts gesplittet */ mbbpsa = mbhd->mbbp; /* Bufferpointer sichern */ mbgcsa = mbhd->mbgc; /* Getcounter sichern */ for (n = 0; mbhd->mbgc < mbhd->mbpc && n < max; ++n) putchr(getchr(mbhd), fbp); /* maximal max Bytes kopieren */ if (mbhd->mbgc < mbhd->mbpc) /* noch Bytes ueber -> Split ! */ { mbgc2 = mbhd->mbgc; /* Getcount fuer spaeter merken */ mbhd2 = (MBHEAD *)allocb(ALLOC_MBHEAD); /* neuen Buffer erzeugen */ while (mbhd->mbgc < mbhd->mbpc) /* die restlichen Bytes in diesen */ putchr(getchr(mbhd), mbhd2); /* Buffer kopieren */ rwndmb(mbhd2); /* neuen Buffer rewinden */ mbhd2->morflg = FALSE; /* noch dem neuen folgt keiner */ mbhd2->l2fflg = mbhd->l2fflg; /* Frameflag uebertragen */ mbhd2->repeated = 0; /* noch nicht erneut gesendet */ relink((LEHEAD *)mbhd2, (LEHEAD *)mbhd); /* neu. Buf. hinter alten haengen */ mbhd->mbpc = mbgc2; /* alter Buffer nur max Zeichen ! */ split = TRUE; /* wir mussten splitten */ } mbhd->mbbp = mbbpsa; /* Bufferpointer restaurieren */ mbhd->mbgc = mbgcsa; /* Getcount restaurieren */ return (split); /* Split oder nicht */ } #ifdef BUFFER_DEBUG /* Schreibt die aktuelle Buffer-Benutzung in eine Datei */ /* Wichtig: hier nichts benutzen, was irgendwie wieder */ /* neue Buffer belegen oder freigeben wuerde ! */ static void bufstat(void) { MAX_BUFFER huge *actbp; ULONG i, n; ULONG used[ALLOC_MAXELEMENTE + 1]; FILE *fp; if ((fp = fopen("buffer.log", "a+")) != NULL) { for (i = 0; i < ALLOC_MAXELEMENTE + 1; i++) used[i] = 0; actbp = (MAX_BUFFER *)RAMBOT; n = (ULONG)((RAMTOP - RAMBOT) / sizeof(MAX_BUFFER)); fprintf(fp, "\rTotal Buffers : %ld (%u free) at %u Bytes each\r", n, nmbfre_max, (unsigned int)sizeof(MAX_BUFFER)); while (n--) { if ((UBYTE) ((USRBLK *)actbp)->owner >= ALLOC_MAXELEMENTE) { used[ALLOC_MAXELEMENTE]++; fprintf(fp,"Wrong Owner: Buffer:%lu Owner:%d\r", n, (UBYTE) ((USRBLK *)actbp)->owner); } else used[(UBYTE) ((USRBLK *)actbp)->owner]++; actbp++; } fprintf(fp, "Free : by owner %lu, by counter %u\r", used[ALLOC_NO_OWNER], nmbfre); fprintf(fp, "LEHEAD : %lu\r", used[ALLOC_LEHEAD]); fprintf(fp, "MBHEAD : %lu\r", used[ALLOC_MBHEAD]); fprintf(fp, "USRBLK1: %lu\r", used[ALLOC_USRBLK1]); fprintf(fp, "USRBLK2: %lu\r", used[ALLOC_USRBLK2]); fprintf(fp, "L2LINK : %lu\r", used[ALLOC_L2LINK]); fprintf(fp, "MB : %lu\r", used[ALLOC_MB]); fprintf(fp, "MONBUF : %lu\r", used[ALLOC_MONBUF]); fprintf(fp, "CQBUF : %lu\r", used[ALLOC_CQBUF]); fprintf(fp, "IPROUTE: %lu\r", used[ALLOC_IP_ROUTE]); fprintf(fp, "ARPTAB : %lu\r", used[ALLOC_ARP_TAB]); fprintf(fp, "MHEARD : %lu\r", used[ALLOC_MHEARD]); fprintf(fp, "PACSAT : %lu\r", used[ALLOC_PACSATBLK]); #ifdef TCP_STACK fprintf(fp, "TCPSTA : %lu\r", used[ALLOC_TCPSTACK]); #endif /* TCP_STACK */ #ifdef L1TCPIP fprintf(fp, "TCPIP : %lu\r", used[ALLOC_L1TCPIP]); #endif /* L1TCPIP */ #ifdef L1HTTPD fprintf(fp, "HTTPDRX: %lu\r", used[ALLOC_L1HTTPD_RX]); fprintf(fp, "HTTPDTX: %lu\r", used[ALLOC_L1HTTPD_TX]); #endif /* L1HTTPD */ fprintf(fp, "INPOPT : %lu\r", used[ALLOC_INPOPT]); if (used[0] != 0L) fprintf(fp, "??? : %lu\r", used[0]); fprintf(fp, "Errors : %lu\r", used[ALLOC_MAXELEMENTE]); fclose(fp); } } #ifdef INSANE_BUFFER_DEBUG /************************************************************************/ /* Log-Funktion zum Debugging */ /************************************************************************/ static void TOLOG(const char *format, ...) { FILE *fp; va_list arg_ptr; struct timeval tv; static char str[30]; char *ptr; if ((fp = fopen("buffer.log", "a+")) != NULL) { gettimeofday(&tv, NULL); ptr = ctime(&tv.tv_sec); strcpy(str, &ptr[11]); fprintf(fp, "%s:", str); va_start(arg_ptr, format); vfprintf(fp, format, arg_ptr); va_end(arg_ptr); fprintf(fp, "\n"); fclose(fp); } } /************************************************************************\ * Prueft, ob der uebergebene Pointer im Bufferbereich liegt * \************************************************************************/ static void MBPTRCHECK(MBHEAD* checkme) { /* Ist der uebergebene Zeiger im gueltigen Bereich ? */ if (((char*)checkme < RAMBOT) || ((char*)checkme > RAMTOP)) { TOLOG("An error occured while accessing one of my buffers, the\r"); TOLOG("desired buffer at adress %p is outside of my allocted\r", checkme); TOLOG("memory range from %p to %p (%ld bytes) !\r", RAMBOT, RAMTOP, (RAMTOP - RAMBOT)); TOLOG("Here is the actual usage of the buffer system:\r"); bufstat(); TOLOG("I will crash now for conservation of the stack ...\r"); HALT("MBPTRCHECK: crash !\r"); } } #endif /* INSANE_BUFFER_DEBUG */ #endif /* BUFFER_DEBUG */ /* End of src/buffer.c */