Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <venti.h>
4 #include <libsec.h>
6 typedef struct Mem Mem;
7 typedef struct Frag Frag;
9 enum {
10 BigMemSize = MaxFragSize,
11 SmallMemSize = BigMemSize/8,
12 NLocalFrag = 2,
13 };
15 /* position to carve out of a Mem */
16 enum {
17 PFront,
18 PMiddle,
19 PEnd,
20 };
22 struct Mem
23 {
24 Lock lk;
25 int ref;
26 uchar *bp;
27 uchar *ep;
28 uchar *rp;
29 uchar *wp;
30 Mem *next;
31 };
33 enum {
34 FragLocalFree,
35 FragLocalAlloc,
36 FragGlobal,
37 };
39 struct Frag
40 {
41 int state;
42 Mem *mem;
43 uchar *rp;
44 uchar *wp;
45 Frag *next;
46 void (*free)(void*);
47 void *a;
48 };
50 struct Packet
51 {
52 int size;
53 int asize; /* allocated memory - greater than size unless foreign frags */
55 Packet *next;
57 Frag *first;
58 Frag *last;
60 Frag local[NLocalFrag];
61 };
63 static Frag *fragalloc(Packet*, int n, int pos, Frag *next);
64 static Frag *fragdup(Packet*, Frag*);
65 static void fragfree(Frag*);
67 static Mem *memalloc(int, int);
68 static void memfree(Mem*);
69 static int memhead(Mem *m, uchar *rp, int n);
70 static int memtail(Mem *m, uchar *wp, int n);
72 static char EPacketSize[] = "bad packet size";
73 static char EPacketOffset[] = "bad packet offset";
74 static char EBadSize[] = "bad size";
76 static struct {
77 Lock lk;
78 Packet *packet;
79 int npacket;
80 Frag *frag;
81 int nfrag;
82 Mem *bigmem;
83 int nbigmem;
84 Mem *smallmem;
85 int nsmallmem;
86 } freelist;
88 #define FRAGSIZE(f) ((f)->wp - (f)->rp)
89 #define FRAGASIZE(f) ((f)->mem ? (f)->mem->ep - (f)->mem->bp : 0)
91 #define NOTFREE(p) assert((p)->size>=0)
93 Packet *
94 packetalloc(void)
95 {
96 Packet *p;
98 lock(&freelist.lk);
99 p = freelist.packet;
100 if(p != nil)
101 freelist.packet = p->next;
102 else
103 freelist.npacket++;
104 unlock(&freelist.lk);
106 if(p == nil)
107 p = vtbrk(sizeof(Packet));
108 else
109 assert(p->size == -1);
110 p->size = 0;
111 p->asize = 0;
112 p->first = nil;
113 p->last = nil;
114 p->next = nil;
116 if(1)fprint(2, "packetalloc %p from %08lux %08lux %08lux\n", p, *((uint*)&p+2), *((uint*)&p+3), *((uint*)&p+4));
118 return p;
121 void
122 packetfree(Packet *p)
124 Frag *f, *ff;
126 if(1)fprint(2, "packetfree %p from %08lux\n", p, getcallerpc(&p));
128 if(p == nil)
129 return;
131 NOTFREE(p);
132 p->size = -1;
134 for(f=p->first; f!=nil; f=ff) {
135 ff = f->next;
136 fragfree(f);
138 p->first = nil;
139 p->last = nil;
141 lock(&freelist.lk);
142 p->next = freelist.packet;
143 freelist.packet = p;
144 unlock(&freelist.lk);
147 Packet *
148 packetdup(Packet *p, int offset, int n)
150 Frag *f, *ff;
151 Packet *pp;
153 NOTFREE(p);
154 if(offset < 0 || n < 0 || offset+n > p->size) {
155 werrstr(EBadSize);
156 return nil;
159 pp = packetalloc();
160 if(n == 0)
161 return pp;
163 pp->size = n;
165 /* skip offset */
166 for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
167 offset -= FRAGSIZE(f);
169 /* first frag */
170 ff = fragdup(pp, f);
171 ff->rp += offset;
172 pp->first = ff;
173 n -= FRAGSIZE(ff);
174 pp->asize += FRAGASIZE(ff);
176 /* the remaining */
177 while(n > 0) {
178 f = f->next;
179 ff->next = fragdup(pp, f);
180 ff = ff->next;
181 n -= FRAGSIZE(ff);
182 pp->asize += FRAGASIZE(ff);
185 /* fix up last frag: note n <= 0 */
186 ff->wp += n;
187 ff->next = nil;
188 pp->last = ff;
190 return pp;
193 Packet *
194 packetsplit(Packet *p, int n)
196 Packet *pp;
197 Frag *f, *ff;
199 NOTFREE(p);
200 if(n < 0 || n > p->size) {
201 werrstr(EPacketSize);
202 return nil;
205 pp = packetalloc();
206 if(n == 0)
207 return pp;
209 pp->size = n;
210 p->size -= n;
211 ff = nil;
212 for(f=p->first; n > 0 && n >= FRAGSIZE(f); f=f->next) {
213 n -= FRAGSIZE(f);
214 p->asize -= FRAGASIZE(f);
215 pp->asize += FRAGASIZE(f);
216 ff = f;
219 /* split shared frag */
220 if(n > 0) {
221 ff = f;
222 f = fragdup(pp, ff);
223 pp->asize += FRAGASIZE(ff);
224 ff->next = nil;
225 ff->wp = ff->rp + n;
226 f->rp += n;
229 pp->first = p->first;
230 pp->last = ff;
231 p->first = f;
232 return pp;
235 int
236 packetconsume(Packet *p, uchar *buf, int n)
238 NOTFREE(p);
239 if(buf && packetcopy(p, buf, 0, n) < 0)
240 return 0;
241 return packettrim(p, n, p->size-n);
244 int
245 packettrim(Packet *p, int offset, int n)
247 Frag *f, *ff;
249 NOTFREE(p);
250 if(offset < 0 || offset > p->size) {
251 werrstr(EPacketOffset);
252 return -1;
255 if(n < 0 || offset + n > p->size) {
256 werrstr(EPacketOffset);
257 return -1;
260 p->size = n;
262 /* easy case */
263 if(n == 0) {
264 for(f=p->first; f != nil; f=ff) {
265 ff = f->next;
266 fragfree(f);
268 p->first = p->last = nil;
269 p->asize = 0;
270 return 0;
273 /* free before offset */
274 for(f=p->first; offset >= FRAGSIZE(f); f=ff) {
275 p->asize -= FRAGASIZE(f);
276 offset -= FRAGSIZE(f);
277 ff = f->next;
278 fragfree(f);
281 /* adjust frag */
282 f->rp += offset;
283 p->first = f;
285 /* skip middle */
286 for(; n > 0 && n > FRAGSIZE(f); f=f->next)
287 n -= FRAGSIZE(f);
289 /* adjust end */
290 f->wp = f->rp + n;
291 p->last = f;
292 ff = f->next;
293 f->next = nil;
295 /* free after */
296 for(f=ff; f != nil; f=ff) {
297 p->asize -= FRAGASIZE(f);
298 ff = f->next;
299 fragfree(f);
301 return 0;
304 uchar *
305 packetheader(Packet *p, int n)
307 Frag *f;
308 Mem *m;
310 NOTFREE(p);
311 if(n <= 0 || n > MaxFragSize) {
312 werrstr(EPacketSize);
313 return nil;
316 p->size += n;
318 /* try and fix in current frag */
319 f = p->first;
320 if(f != nil) {
321 m = f->mem;
322 if(n <= f->rp - m->bp)
323 if(m->ref == 1 || memhead(m, f->rp, n) >= 0) {
324 f->rp -= n;
325 return f->rp;
329 /* add frag to front */
330 f = fragalloc(p, n, PEnd, p->first);
331 p->asize += FRAGASIZE(f);
332 if(p->first == nil)
333 p->last = f;
334 p->first = f;
335 return f->rp;
338 uchar *
339 packettrailer(Packet *p, int n)
341 Mem *m;
342 Frag *f;
344 NOTFREE(p);
345 if(n <= 0 || n > MaxFragSize) {
346 werrstr(EPacketSize);
347 return nil;
350 p->size += n;
352 /* try and fix in current frag */
353 if(p->first != nil) {
354 f = p->last;
355 m = f->mem;
356 if(n <= m->ep - f->wp)
357 if(m->ref == 1 || memtail(m, f->wp, n) >= 0) {
358 f->wp += n;
359 return f->wp - n;
363 /* add frag to end */
364 f = fragalloc(p, n, (p->first == nil)?PMiddle:PFront, nil);
365 p->asize += FRAGASIZE(f);
366 if(p->first == nil)
367 p->first = f;
368 else
369 p->last->next = f;
370 p->last = f;
371 return f->rp;
374 int
375 packetprefix(Packet *p, uchar *buf, int n)
377 Frag *f;
378 int nn;
379 Mem *m;
381 NOTFREE(p);
382 if(n <= 0)
383 return 0;
385 p->size += n;
387 /* try and fix in current frag */
388 f = p->first;
389 if(f != nil) {
390 m = f->mem;
391 nn = f->rp - m->bp;
392 if(nn > n)
393 nn = n;
394 if(m->ref == 1 || memhead(m, f->rp, nn) >= 0) {
395 f->rp -= nn;
396 n -= nn;
397 memmove(f->rp, buf+n, nn);
401 while(n > 0) {
402 nn = n;
403 if(nn > MaxFragSize)
404 nn = MaxFragSize;
405 f = fragalloc(p, nn, PEnd, p->first);
406 p->asize += FRAGASIZE(f);
407 if(p->first == nil)
408 p->last = f;
409 p->first = f;
410 n -= nn;
411 memmove(f->rp, buf+n, nn);
413 return 0;
416 int
417 packetappend(Packet *p, uchar *buf, int n)
419 Frag *f;
420 int nn;
421 Mem *m;
423 NOTFREE(p);
424 if(n <= 0)
425 return 0;
427 p->size += n;
428 /* try and fix in current frag */
429 if(p->first != nil) {
430 f = p->last;
431 m = f->mem;
432 nn = m->ep - f->wp;
433 if(nn > n)
434 nn = n;
435 if(m->ref == 1 || memtail(m, f->wp, nn) >= 0) {
436 memmove(f->wp, buf, nn);
437 f->wp += nn;
438 buf += nn;
439 n -= nn;
443 while(n > 0) {
444 nn = n;
445 if(nn > MaxFragSize)
446 nn = MaxFragSize;
447 f = fragalloc(p, nn, (p->first == nil)?PMiddle:PFront, nil);
448 p->asize += FRAGASIZE(f);
449 if(p->first == nil)
450 p->first = f;
451 else
452 p->last->next = f;
453 p->last = f;
454 memmove(f->rp, buf, nn);
455 buf += nn;
456 n -= nn;
458 return 0;
461 int
462 packetconcat(Packet *p, Packet *pp)
464 NOTFREE(p);
465 NOTFREE(pp);
466 if(pp->size == 0)
467 return 0;
468 p->size += pp->size;
469 p->asize += pp->asize;
471 if(p->first != nil)
472 p->last->next = pp->first;
473 else
474 p->first = pp->first;
475 p->last = pp->last;
476 pp->size = 0;
477 pp->asize = 0;
478 pp->first = nil;
479 pp->last = nil;
480 return 0;
483 uchar *
484 packetpeek(Packet *p, uchar *buf, int offset, int n)
486 Frag *f;
487 int nn;
488 uchar *b;
490 NOTFREE(p);
491 if(n == 0)
492 return buf;
494 if(offset < 0 || offset >= p->size) {
495 werrstr(EPacketOffset);
496 return nil;
499 if(n < 0 || offset + n > p->size) {
500 werrstr(EPacketSize);
501 return nil;
504 /* skip up to offset */
505 for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
506 offset -= FRAGSIZE(f);
508 /* easy case */
509 if(offset + n <= FRAGSIZE(f))
510 return f->rp + offset;
512 for(b=buf; n>0; n -= nn) {
513 nn = FRAGSIZE(f) - offset;
514 if(nn > n)
515 nn = n;
516 memmove(b, f->rp+offset, nn);
517 offset = 0;
518 f = f->next;
519 b += nn;
522 return buf;
525 int
526 packetcopy(Packet *p, uchar *buf, int offset, int n)
528 uchar *b;
530 NOTFREE(p);
531 b = packetpeek(p, buf, offset, n);
532 if(b == nil)
533 return -1;
534 if(b != buf)
535 memmove(buf, b, n);
536 return 0;
539 int
540 packetfragments(Packet *p, IOchunk *io, int nio, int offset)
542 Frag *f;
543 int size;
544 IOchunk *eio;
546 NOTFREE(p);
547 if(p->size == 0 || nio <= 0)
548 return 0;
550 if(offset < 0 || offset > p->size) {
551 werrstr(EPacketOffset);
552 return -1;
555 for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
556 offset -= FRAGSIZE(f);
558 size = 0;
559 eio = io + nio;
560 for(; f != nil && io < eio; f=f->next) {
561 io->addr = f->rp + offset;
562 io->len = f->wp - (f->rp + offset);
563 offset = 0;
564 size += io->len;
565 io++;
568 return size;
571 void
572 packetstats(void)
574 Packet *p;
575 Frag *f;
576 Mem *m;
578 int np, nf, nsm, nbm;
580 lock(&freelist.lk);
581 np = 0;
582 for(p=freelist.packet; p; p=p->next)
583 np++;
584 nf = 0;
585 for(f=freelist.frag; f; f=f->next)
586 nf++;
587 nsm = 0;
588 for(m=freelist.smallmem; m; m=m->next)
589 nsm++;
590 nbm = 0;
591 for(m=freelist.bigmem; m; m=m->next)
592 nbm++;
594 fprint(2, "packet: %d/%d frag: %d/%d small mem: %d/%d big mem: %d/%d\n",
595 np, freelist.npacket,
596 nf, freelist.nfrag,
597 nsm, freelist.nsmallmem,
598 nbm, freelist.nbigmem);
600 unlock(&freelist.lk);
604 uint
605 packetsize(Packet *p)
607 NOTFREE(p);
608 if(0) {
609 Frag *f;
610 int size = 0;
612 for(f=p->first; f; f=f->next)
613 size += FRAGSIZE(f);
614 if(size != p->size)
615 fprint(2, "packetsize %d %d\n", size, p->size);
616 assert(size == p->size);
618 return p->size;
621 uint
622 packetasize(Packet *p)
624 NOTFREE(p);
625 if(0) {
626 Frag *f;
627 int asize = 0;
629 for(f=p->first; f; f=f->next)
630 asize += FRAGASIZE(f);
631 if(asize != p->asize)
632 fprint(2, "packetasize %d %d\n", asize, p->asize);
633 assert(asize == p->asize);
635 return p->asize;
638 void
639 packetsha1(Packet *p, uchar digest[VtScoreSize])
641 DigestState ds;
642 Frag *f;
643 int size;
645 NOTFREE(p);
646 memset(&ds, 0, sizeof ds);
647 size = p->size;
648 for(f=p->first; f; f=f->next) {
649 sha1(f->rp, FRAGSIZE(f), nil, &ds);
650 size -= FRAGSIZE(f);
652 assert(size == 0);
653 sha1(nil, 0, digest, &ds);
656 int
657 packetcmp(Packet *pkt0, Packet *pkt1)
659 Frag *f0, *f1;
660 int n0, n1, x;
662 NOTFREE(pkt0);
663 NOTFREE(pkt1);
664 f0 = pkt0->first;
665 f1 = pkt1->first;
667 if(f0 == nil)
668 return (f1 == nil)?0:-1;
669 if(f1 == nil)
670 return 1;
671 n0 = FRAGSIZE(f0);
672 n1 = FRAGSIZE(f1);
674 for(;;) {
675 if(n0 < n1) {
676 x = memcmp(f0->wp - n0, f1->wp - n1, n0);
677 if(x != 0)
678 return x;
679 n1 -= n0;
680 f0 = f0->next;
681 if(f0 == nil)
682 return -1;
683 n0 = FRAGSIZE(f0);
684 } else if (n0 > n1) {
685 x = memcmp(f0->wp - n0, f1->wp - n1, n1);
686 if(x != 0)
687 return x;
688 n0 -= n1;
689 f1 = f1->next;
690 if(f1 == nil)
691 return 1;
692 n1 = FRAGSIZE(f1);
693 } else { /* n0 == n1 */
694 x = memcmp(f0->wp - n0, f1->wp - n1, n0);
695 if(x != 0)
696 return x;
697 f0 = f0->next;
698 f1 = f1->next;
699 if(f0 == nil)
700 return (f1 == nil)?0:-1;
701 if(f1 == nil)
702 return 1;
703 n0 = FRAGSIZE(f0);
704 n1 = FRAGSIZE(f1);
707 return 0; /* for ken */
711 static Frag *
712 fragalloc(Packet *p, int n, int pos, Frag *next)
714 Frag *f, *ef;
715 Mem *m;
717 /* look for local frag */
718 f = &p->local[0];
719 ef = &p->local[NLocalFrag];
720 for(;f<ef; f++) {
721 if(f->state == FragLocalFree) {
722 f->state = FragLocalAlloc;
723 goto Found;
726 lock(&freelist.lk);
727 f = freelist.frag;
728 if(f != nil)
729 freelist.frag = f->next;
730 else
731 freelist.nfrag++;
732 unlock(&freelist.lk);
734 if(f == nil) {
735 f = vtbrk(sizeof(Frag));
736 f->state = FragGlobal;
739 Found:
740 f->next = next;
742 if(n == 0){
743 f->mem = 0;
744 f->rp = 0;
745 f->wp = 0;
746 return f;
749 if(pos == PEnd && next == nil)
750 pos = PMiddle;
751 m = memalloc(n, pos);
752 f->mem = m;
753 f->rp = m->rp;
754 f->wp = m->wp;
755 return f;
758 Packet*
759 packetforeign(uchar *buf, int n, void (*free)(void *a), void *a)
761 Packet *p;
762 Frag *f;
764 p = packetalloc();
765 f = fragalloc(p, 0, 0, nil);
766 f->free = free;
767 f->a = a;
768 f->next = nil;
769 f->rp = buf;
770 f->wp = buf+n;
772 p->first = f;
773 p->size = n;
774 return p;
777 static Frag *
778 fragdup(Packet *p, Frag *f)
780 Frag *ff;
781 Mem *m;
783 m = f->mem;
785 /*
786 * m->rp && m->wp can be out of date when ref == 1
787 * also, potentially reclaims space from previous frags
788 */
789 if(m && m->ref == 1) {
790 m->rp = f->rp;
791 m->wp = f->wp;
794 ff = fragalloc(p, 0, 0, nil);
795 *ff = *f;
796 if(m){
797 lock(&m->lk);
798 m->ref++;
799 unlock(&m->lk);
801 return ff;
805 static void
806 fragfree(Frag *f)
808 if(f->mem == nil){
809 if(f->free)
810 (*f->free)(f->a);
811 }else{
812 memfree(f->mem);
813 f->mem = 0;
816 if(f->state == FragLocalAlloc) {
817 f->state = FragLocalFree;
818 return;
821 lock(&freelist.lk);
822 f->next = freelist.frag;
823 freelist.frag = f;
824 unlock(&freelist.lk);
827 static Mem *
828 memalloc(int n, int pos)
830 Mem *m;
831 int nn;
833 if(n < 0 || n > MaxFragSize) {
834 werrstr(EPacketSize);
835 return 0;
837 if(n <= SmallMemSize) {
838 lock(&freelist.lk);
839 m = freelist.smallmem;
840 if(m != nil)
841 freelist.smallmem = m->next;
842 else
843 freelist.nsmallmem++;
844 unlock(&freelist.lk);
845 nn = SmallMemSize;
846 } else {
847 lock(&freelist.lk);
848 m = freelist.bigmem;
849 if(m != nil)
850 freelist.bigmem = m->next;
851 else
852 freelist.nbigmem++;
853 unlock(&freelist.lk);
854 nn = BigMemSize;
857 if(m == nil) {
858 m = vtbrk(sizeof(Mem));
859 m->bp = vtbrk(nn);
860 m->ep = m->bp + nn;
862 assert(m->ref == 0);
863 m->ref = 1;
865 switch(pos) {
866 default:
867 assert(0);
868 case PFront:
869 m->rp = m->bp;
870 break;
871 case PMiddle:
872 /* leave a little bit at end */
873 m->rp = m->ep - n - 32;
874 break;
875 case PEnd:
876 m->rp = m->ep - n;
877 break;
879 /* check we did not blow it */
880 if(m->rp < m->bp)
881 m->rp = m->bp;
882 m->wp = m->rp + n;
883 assert(m->rp >= m->bp && m->wp <= m->ep);
884 return m;
887 static void
888 memfree(Mem *m)
890 lock(&m->lk);
891 m->ref--;
892 if(m->ref > 0) {
893 unlock(&m->lk);
894 return;
896 unlock(&m->lk);
897 assert(m->ref == 0);
899 switch(m->ep - m->bp) {
900 default:
901 assert(0);
902 case SmallMemSize:
903 lock(&freelist.lk);
904 m->next = freelist.smallmem;
905 freelist.smallmem = m;
906 unlock(&freelist.lk);
907 break;
908 case BigMemSize:
909 lock(&freelist.lk);
910 m->next = freelist.bigmem;
911 freelist.bigmem = m;
912 unlock(&freelist.lk);
913 break;
917 static int
918 memhead(Mem *m, uchar *rp, int n)
920 lock(&m->lk);
921 if(m->rp != rp) {
922 unlock(&m->lk);
923 return -1;
925 m->rp -= n;
926 unlock(&m->lk);
927 return 0;
930 static int
931 memtail(Mem *m, uchar *wp, int n)
933 lock(&m->lk);
934 if(m->wp != wp) {
935 unlock(&m->lk);
936 return -1;
938 m->wp += n;
939 unlock(&m->lk);
940 return 0;