|
|
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.