|
|
1.1 ! root 1: /* ! 2: * P A C K E T ! 3: * ! 4: * Utilities for working with "packets". These are groups of (stream) data ! 5: * blocks terminated by a delimiter. When these blocks are removed from a ! 6: * queue, they are kept as a chain of blocks, without the final M_DELIM, and ! 7: * are referred to as a dequeued packet. ! 8: * ! 9: * ! 10: * Written by Kurt Gollhardt (Nirvonics, Inc.) ! 11: * Last update Wed Feb 12 21:24:10 1986 ! 12: * ! 13: */ ! 14: ! 15: #include "../h/param.h" ! 16: #include "../h/stream.h" ! 17: ! 18: #define PKT_COMPLETE 0 ! 19: #define PKT_PARTIAL 1 ! 20: ! 21: ! 22: /* ! 23: * This routine does all the work for a server on a queue using packets. ! 24: * Arguments provide routines to do the application-specific operations: ! 25: * 'blocked' is called with a pointer to the queue; ! 26: * it should return non-zero if the location which the first ! 27: * packet on the queue would be sent to is full. If it does ! 28: * return non-zero, it must ensure that this queue will be ! 29: * re-enabled when the blocking condition goes away. ! 30: * 'allow_partial' is called with a pointer to the queue; ! 31: * it should return non-zero if this queue is allowed to receive ! 32: * partial packets at any time. (Any queue may be given partial ! 33: * packets if not doing so would cause a deadlock.) ! 34: * 'process' is called with a pointer to the queue, a dequeued ! 35: * packet (struct block *), and a flag which is non-zero if ! 36: * this is a partial packet. ! 37: */ ! 38: packet_srvp(q, delim_count, blocked, allow_partial, process, other) ! 39: register struct queue *q; /* queue being serviced */ ! 40: int *delim_count; /* ptr to count of delims on queue */ ! 41: int (*blocked)(); /* routine to see if a queue blocks */ ! 42: int (*allow_partial)(); /* routine to say if partial pkts ok */ ! 43: int (*process)(); /* routine to process a packet */ ! 44: int (*other)(); /* routine to handle misc blocks */ ! 45: { ! 46: register struct block *bp, *first_bp, *prev_bp; ! 47: register int processed = 0; ! 48: static check_other(); ! 49: ! 50: check_other(q, other); ! 51: while (*delim_count > 0) { ! 52: if ((*blocked) (q)) ! 53: return; ! 54: if ((bp = getq(q))->type == M_DELIM) ! 55: first_bp = NULL; ! 56: else { ! 57: first_bp = prev_bp = bp; ! 58: while ((bp = getq(q))->type != M_DELIM) ! 59: prev_bp = bp; ! 60: prev_bp->next = NULL; ! 61: } ! 62: freeb(bp); ! 63: (*process) (q, first_bp, PKT_COMPLETE); ! 64: --*delim_count; ! 65: ++processed; ! 66: check_other(q, other); ! 67: } ! 68: ! 69: if (q->first != NULL) { ! 70: if ((*allow_partial) (q) || /* Huge partial packet */ ! 71: ((q->flag & QWANTW) && processed == 0)) { ! 72: if ((*blocked) (q)) ! 73: return; ! 74: first_bp = q->first; ! 75: while (getq(q)) ! 76: ; ! 77: (*process) (q, first_bp, PKT_PARTIAL); ! 78: } else ! 79: q->flag |= QWANTR; ! 80: } ! 81: } ! 82: ! 83: static check_other(q, other) ! 84: register struct queue *q; ! 85: int (*other)(); ! 86: { ! 87: register struct block *bp; ! 88: ! 89: while (q->first && q->first->type != M_DATA && q->first->type != M_DELIM) { ! 90: bp = getq(q); ! 91: if (other) ! 92: (*other)(q, bp); ! 93: else ! 94: freeb(bp); ! 95: } ! 96: } ! 97: ! 98: ! 99: /* ! 100: * This routine does all the work for a put routine on a queue using packets. ! 101: * Arguments provide routines to do the application-specific operations: ! 102: * 'ioctl' (optional) is called with a pointer to the queue, and a pointer ! 103: * to an M_IOCTL block. ! 104: * 'other' (optional) is called with a pointer to the queue, and a pointer ! 105: * to a block of type other than M_DATA, M_DELIM, or M_IOCTL. ! 106: */ ! 107: packet_putp(q, bp, delim_count, ioctl, other) ! 108: register struct queue *q; /* queue being put onto */ ! 109: register struct block *bp; /* block being put on */ ! 110: int *delim_count; /* ptr to count of delims on queue */ ! 111: int (*ioctl)(); /* routine to handle an ioctl */ ! 112: int (*other)(); /* routine to handle misc blocks */ ! 113: { ! 114: register int ps, (*func)(); ! 115: ! 116: switch (bp->type) { ! 117: case M_DATA: ! 118: putq(q, bp); ! 119: return; ! 120: case M_DELIM: ! 121: ps = spl6(); ! 122: putq(q, bp); ! 123: ++*delim_count; ! 124: qenable(q); ! 125: splx(ps); ! 126: return; ! 127: case M_IOCTL: ! 128: func = ioctl; ! 129: break; ! 130: default: ! 131: func = other; ! 132: } ! 133: ! 134: if (func) ! 135: (*func) (q, bp); ! 136: else if (q->next) ! 137: (*q->next->qinfo->putp) (q->next, bp); ! 138: else ! 139: freeb(bp); ! 140: } ! 141: ! 142: ! 143: #define BLEN(bp) ((bp)->wptr - (bp)->rptr) ! 144: #define BSZ(bp) ((bp)->lim - (bp)->base) ! 145: #undef MIN ! 146: #define MIN(a,b) ((a) > (b) ? (b) : (a)) ! 147: ! 148: /* ! 149: * This routine takes a dequeued packet and a length. ! 150: * It makes sure that the specified length of data appears in the first ! 151: * block of the packet, if possible. ! 152: */ ! 153: struct block *packet_pullup(bp, len) ! 154: register struct block *bp; /* the dequeued packet */ ! 155: unsigned len; /* desired length */ ! 156: /* returns the new packet (the old one is invalid) */ ! 157: { ! 158: register struct block *nbp; ! 159: register unsigned count; ! 160: ! 161: ! 162: if (bp == NULL) ! 163: goto bad; ! 164: if (BLEN(bp) >= len) ! 165: return bp; ! 166: ! 167: nbp = allocb(len); ! 168: if (nbp == NULL || BSZ(nbp) < len) { ! 169: free_blocks(bp); ! 170: goto cleanup; ! 171: } ! 172: nbp->next = bp; ! 173: ! 174: while (bp && bp->type == M_DATA) { ! 175: count = BSZ(nbp) - BLEN(nbp); /* space left in new block */ ! 176: count = MIN(count, len); /* clip to desired length */ ! 177: count = MIN(count, BLEN(bp)); /* clip to length of this block */ ! 178: bcopy(bp->rptr, nbp->wptr, count); ! 179: len -= count; ! 180: bp->rptr += count; ! 181: nbp->wptr += count; ! 182: if (BLEN(bp) > 0) ! 183: break; ! 184: nbp->next = bp->next; ! 185: freeb(bp); ! 186: bp = nbp->next; ! 187: } ! 188: ! 189: if (len == 0) ! 190: return nbp; ! 191: ! 192: cleanup: ! 193: free_blocks(nbp); ! 194: bad: ! 195: printf("packet_pullup bad\n"); ! 196: return NULL; ! 197: } ! 198: ! 199: ! 200: /* ! 201: * Free space taken by a dequeued packet. ! 202: */ ! 203: free_blocks(bp) ! 204: register struct block *bp; /* dequeued packet */ ! 205: { ! 206: register struct block *nbp; ! 207: ! 208: while (bp) { ! 209: nbp = bp->next; ! 210: freeb(bp); ! 211: bp = nbp; ! 212: } ! 213: } ! 214: ! 215: ! 216: /* ! 217: * This routine puts blocks from a dequeued packet onto a queue's successor. ! 218: */ ! 219: packet_put(q, bp) ! 220: register struct queue *q; /* Note that we put to q->next */ ! 221: register struct block *bp; ! 222: { ! 223: register struct block *bnext; ! 224: ! 225: while (bp != NULL) { ! 226: bnext = bp->next; ! 227: if (bp->rptr >= bp->wptr) ! 228: freeb(bp); ! 229: else ! 230: (*q->next->qinfo->putp) (q->next, bp); ! 231: bp = bnext; ! 232: } ! 233: if (q->flag & QDELIM) ! 234: putctl(q->next, M_DELIM); ! 235: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.