new venti library.
This commit is contained in:
parent
9df487d720
commit
056fe1ba7f
28 changed files with 4635 additions and 0 deletions
560
src/libventi/cache.c
Normal file
560
src/libventi/cache.c
Normal file
|
|
@ -0,0 +1,560 @@
|
||||||
|
/*
|
||||||
|
* Memory-only VtBlock cache.
|
||||||
|
*
|
||||||
|
* The cached Venti blocks are in the hash chains.
|
||||||
|
* The cached local blocks are only in the blocks array.
|
||||||
|
* The free blocks are in the heap, which is supposed to
|
||||||
|
* be indexed by second-to-last use but actually
|
||||||
|
* appears to be last use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
int nread, ncopy, nwrite;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BioLocal = 1,
|
||||||
|
BioVenti,
|
||||||
|
BioReading,
|
||||||
|
BioWriting,
|
||||||
|
BioEmpty,
|
||||||
|
BioVentiError,
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
BadHeap = ~0,
|
||||||
|
};
|
||||||
|
struct VtCache
|
||||||
|
{
|
||||||
|
QLock lk;
|
||||||
|
VtConn *z;
|
||||||
|
u32int blocksize;
|
||||||
|
u32int now; /* ticks for usage time stamps */
|
||||||
|
VtBlock **hash; /* hash table for finding addresses */
|
||||||
|
int nhash;
|
||||||
|
VtBlock **heap; /* heap for finding victims */
|
||||||
|
int nheap;
|
||||||
|
VtBlock *block; /* all allocated blocks */
|
||||||
|
int nblock;
|
||||||
|
uchar *mem; /* memory for all blocks and data */
|
||||||
|
int mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cachecheck(VtCache*);
|
||||||
|
|
||||||
|
VtCache*
|
||||||
|
vtcachealloc(VtConn *z, int blocksize, ulong nblock, int mode)
|
||||||
|
{
|
||||||
|
uchar *p;
|
||||||
|
VtCache *c;
|
||||||
|
int i;
|
||||||
|
VtBlock *b;
|
||||||
|
|
||||||
|
c = vtmallocz(sizeof(VtCache));
|
||||||
|
|
||||||
|
c->z = z;
|
||||||
|
c->blocksize = (blocksize + 127) & ~127;
|
||||||
|
c->nblock = nblock;
|
||||||
|
|
||||||
|
c->nhash = nblock;
|
||||||
|
c->hash = vtmallocz(nblock*sizeof(VtBlock*));
|
||||||
|
c->heap = vtmallocz(nblock*sizeof(VtBlock*));
|
||||||
|
c->block = vtmallocz(nblock*sizeof(VtBlock));
|
||||||
|
c->mem = vtmallocz(nblock*c->blocksize);
|
||||||
|
c->mode = mode;
|
||||||
|
|
||||||
|
p = c->mem;
|
||||||
|
for(i=0; i<nblock; i++){
|
||||||
|
b = &c->block[i];
|
||||||
|
b->addr = NilBlock;
|
||||||
|
b->c = c;
|
||||||
|
b->data = p;
|
||||||
|
b->heap = i;
|
||||||
|
c->heap[i] = b;
|
||||||
|
p += c->blocksize;
|
||||||
|
}
|
||||||
|
c->nheap = nblock;
|
||||||
|
cachecheck(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vtcachefree(VtCache *c)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
qlock(&c->lk);
|
||||||
|
|
||||||
|
cachecheck(c);
|
||||||
|
for(i=0; i<c->nblock; i++)
|
||||||
|
assert(c->block[i].ref == 0);
|
||||||
|
|
||||||
|
vtfree(c->hash);
|
||||||
|
vtfree(c->heap);
|
||||||
|
vtfree(c->block);
|
||||||
|
vtfree(c->mem);
|
||||||
|
vtfree(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vtcachedump(VtCache *c)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
VtBlock *b;
|
||||||
|
|
||||||
|
for(i=0; i<c->nblock; i++){
|
||||||
|
b = &c->block[i];
|
||||||
|
print("cache block %d: type %d score %V iostate %d addr %d ref %d nlock %d\n",
|
||||||
|
i, b->type, b->score, b->iostate, b->addr, b->ref, b->nlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cachecheck(VtCache *c)
|
||||||
|
{
|
||||||
|
u32int size, now;
|
||||||
|
int i, k, refed;
|
||||||
|
VtBlock *b;
|
||||||
|
|
||||||
|
size = c->blocksize;
|
||||||
|
now = c->now;
|
||||||
|
|
||||||
|
for(i = 0; i < c->nheap; i++){
|
||||||
|
if(c->heap[i]->heap != i)
|
||||||
|
sysfatal("mis-heaped at %d: %d", i, c->heap[i]->heap);
|
||||||
|
if(i > 0 && c->heap[(i - 1) >> 1]->used - now > c->heap[i]->used - now)
|
||||||
|
sysfatal("bad heap ordering");
|
||||||
|
k = (i << 1) + 1;
|
||||||
|
if(k < c->nheap && c->heap[i]->used - now > c->heap[k]->used - now)
|
||||||
|
sysfatal("bad heap ordering");
|
||||||
|
k++;
|
||||||
|
if(k < c->nheap && c->heap[i]->used - now > c->heap[k]->used - now)
|
||||||
|
sysfatal("bad heap ordering");
|
||||||
|
}
|
||||||
|
|
||||||
|
refed = 0;
|
||||||
|
for(i = 0; i < c->nblock; i++){
|
||||||
|
b = &c->block[i];
|
||||||
|
if(b->data != &c->mem[i * size])
|
||||||
|
sysfatal("mis-blocked at %d", i);
|
||||||
|
if(b->ref && b->heap == BadHeap)
|
||||||
|
refed++;
|
||||||
|
else if(b->addr != NilBlock)
|
||||||
|
refed++;
|
||||||
|
}
|
||||||
|
if(c->nheap + refed != c->nblock){
|
||||||
|
fprint(2, "cachecheck: nheap %d refed %d nblocks %d\n", c->nheap, refed, c->nblock);
|
||||||
|
//vtcachedump(c);
|
||||||
|
}
|
||||||
|
assert(c->nheap + refed == c->nblock);
|
||||||
|
refed = 0;
|
||||||
|
for(i = 0; i < c->nblock; i++){
|
||||||
|
b = &c->block[i];
|
||||||
|
if(b->ref){
|
||||||
|
if(1)fprint(2, "a=%ud %V ref=%d\n", b->addr, b->score, b->ref);
|
||||||
|
refed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(refed > 0)fprint(2, "cachecheck: in used %d\n", refed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
upheap(int i, VtBlock *b)
|
||||||
|
{
|
||||||
|
VtBlock *bb;
|
||||||
|
u32int now;
|
||||||
|
int p;
|
||||||
|
VtCache *c;
|
||||||
|
|
||||||
|
c = b->c;
|
||||||
|
now = c->now;
|
||||||
|
for(; i != 0; i = p){
|
||||||
|
p = (i - 1) >> 1;
|
||||||
|
bb = c->heap[p];
|
||||||
|
if(b->used - now >= bb->used - now)
|
||||||
|
break;
|
||||||
|
c->heap[i] = bb;
|
||||||
|
bb->heap = i;
|
||||||
|
}
|
||||||
|
c->heap[i] = b;
|
||||||
|
b->heap = i;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
downheap(int i, VtBlock *b)
|
||||||
|
{
|
||||||
|
VtBlock *bb;
|
||||||
|
u32int now;
|
||||||
|
int k;
|
||||||
|
VtCache *c;
|
||||||
|
|
||||||
|
c = b->c;
|
||||||
|
now = c->now;
|
||||||
|
for(; ; i = k){
|
||||||
|
k = (i << 1) + 1;
|
||||||
|
if(k >= c->nheap)
|
||||||
|
break;
|
||||||
|
if(k + 1 < c->nheap && c->heap[k]->used - now > c->heap[k + 1]->used - now)
|
||||||
|
k++;
|
||||||
|
bb = c->heap[k];
|
||||||
|
if(b->used - now <= bb->used - now)
|
||||||
|
break;
|
||||||
|
c->heap[i] = bb;
|
||||||
|
bb->heap = i;
|
||||||
|
}
|
||||||
|
c->heap[i] = b;
|
||||||
|
b->heap = i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a block from the heap.
|
||||||
|
* Called with c->lk held.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
heapdel(VtBlock *b)
|
||||||
|
{
|
||||||
|
int i, si;
|
||||||
|
VtCache *c;
|
||||||
|
|
||||||
|
c = b->c;
|
||||||
|
|
||||||
|
si = b->heap;
|
||||||
|
if(si == BadHeap)
|
||||||
|
return;
|
||||||
|
b->heap = BadHeap;
|
||||||
|
c->nheap--;
|
||||||
|
if(si == c->nheap)
|
||||||
|
return;
|
||||||
|
b = c->heap[c->nheap];
|
||||||
|
i = upheap(si, b);
|
||||||
|
if(i == si)
|
||||||
|
downheap(i, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a block into the heap.
|
||||||
|
* Called with c->lk held.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
heapins(VtBlock *b)
|
||||||
|
{
|
||||||
|
assert(b->heap == BadHeap);
|
||||||
|
upheap(b->c->nheap++, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* locate the vtBlock with the oldest second to last use.
|
||||||
|
* remove it from the heap, and fix up the heap.
|
||||||
|
*/
|
||||||
|
/* called with c->lk held */
|
||||||
|
static VtBlock*
|
||||||
|
vtcachebumpblock(VtCache *c)
|
||||||
|
{
|
||||||
|
VtBlock *b;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* locate the vtBlock with the oldest second to last use.
|
||||||
|
* remove it from the heap, and fix up the heap.
|
||||||
|
*/
|
||||||
|
if(c->nheap == 0){
|
||||||
|
vtcachedump(c);
|
||||||
|
abort();
|
||||||
|
sysfatal("vtcachebumpblock: no free blocks in vtCache");
|
||||||
|
}
|
||||||
|
b = c->heap[0];
|
||||||
|
heapdel(b);
|
||||||
|
|
||||||
|
assert(b->heap == BadHeap);
|
||||||
|
assert(b->ref == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* unchain the vtBlock from hash chain if any
|
||||||
|
*/
|
||||||
|
if(b->prev){
|
||||||
|
*(b->prev) = b->next;
|
||||||
|
if(b->next)
|
||||||
|
b->next->prev = b->prev;
|
||||||
|
b->prev = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(0)fprint(2, "droping %x:%V\n", b->addr, b->score);
|
||||||
|
/* set vtBlock to a reasonable state */
|
||||||
|
b->ref = 1;
|
||||||
|
b->iostate = BioEmpty;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fetch a local block from the memory cache.
|
||||||
|
* if it's not there, load it, bumping some other Block.
|
||||||
|
* if we're out of free blocks, we're screwed.
|
||||||
|
*/
|
||||||
|
VtBlock*
|
||||||
|
vtcachelocal(VtCache *c, u32int addr, int type)
|
||||||
|
{
|
||||||
|
VtBlock *b;
|
||||||
|
|
||||||
|
if(addr >= c->nblock)
|
||||||
|
sysfatal("vtcachelocal: asked for block #%ud; only %d blocks\n",
|
||||||
|
addr, c->nblock);
|
||||||
|
|
||||||
|
b = &c->block[addr];
|
||||||
|
if(b->addr == NilBlock || b->iostate != BioLocal)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
sysfatal("vtcachelocal: block is not local");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b->type != type)
|
||||||
|
{
|
||||||
|
print("%d != %d\n", b->type, type);
|
||||||
|
abort();
|
||||||
|
sysfatal("vtcachelocal: block has wrong type %d != %d", b->type, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
qlock(&c->lk);
|
||||||
|
b->ref++;
|
||||||
|
qunlock(&c->lk);
|
||||||
|
|
||||||
|
qlock(&b->lk);
|
||||||
|
b->nlock = 1;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
VtBlock*
|
||||||
|
vtcacheallocblock(VtCache *c, int type)
|
||||||
|
{
|
||||||
|
VtBlock *b;
|
||||||
|
|
||||||
|
if(type >= VtMaxType)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
qlock(&c->lk);
|
||||||
|
b = vtcachebumpblock(c);
|
||||||
|
b->iostate = BioLocal;
|
||||||
|
b->type = type;
|
||||||
|
b->addr = b - c->block;
|
||||||
|
vtzeroextend(type, b->data, 0, c->blocksize);
|
||||||
|
vtlocaltoglobal(b->addr, b->score);
|
||||||
|
qunlock(&c->lk);
|
||||||
|
|
||||||
|
qlock(&b->lk);
|
||||||
|
b->nlock = 1;
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fetch a global (Venti) block from the memory cache.
|
||||||
|
* if it's not there, load it, bumping some other block.
|
||||||
|
*/
|
||||||
|
VtBlock*
|
||||||
|
vtcacheglobal(VtCache *c, uchar score[VtScoreSize], int type)
|
||||||
|
{
|
||||||
|
VtBlock *b;
|
||||||
|
ulong h;
|
||||||
|
int n;
|
||||||
|
u32int addr;
|
||||||
|
|
||||||
|
addr = vtglobaltolocal(score);
|
||||||
|
if(addr != NilBlock)
|
||||||
|
return vtcachelocal(c, addr, type);
|
||||||
|
|
||||||
|
h = (u32int)(score[0]|(score[1]<<8)|(score[2]<<16)|(score[3]<<24)) % c->nhash;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* look for the block in the cache
|
||||||
|
*/
|
||||||
|
qlock(&c->lk);
|
||||||
|
for(b = c->hash[h]; b != nil; b = b->next){
|
||||||
|
if(b->addr != NilBlock || memcmp(b->score, score, VtScoreSize) != 0 || b->type != type)
|
||||||
|
continue;
|
||||||
|
heapdel(b);
|
||||||
|
b->ref++;
|
||||||
|
qunlock(&c->lk);
|
||||||
|
qlock(&b->lk);
|
||||||
|
b->nlock = 1;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* not found
|
||||||
|
*/
|
||||||
|
b = vtcachebumpblock(c);
|
||||||
|
b->addr = NilBlock;
|
||||||
|
b->type = type;
|
||||||
|
memmove(b->score, score, VtScoreSize);
|
||||||
|
/* chain onto correct hash */
|
||||||
|
b->next = c->hash[h];
|
||||||
|
c->hash[h] = b;
|
||||||
|
if(b->next != nil)
|
||||||
|
b->next->prev = &b->next;
|
||||||
|
b->prev = &c->hash[h];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock b before unlocking c, so that others wait while we read.
|
||||||
|
*
|
||||||
|
* You might think there is a race between this qlock(b) before qunlock(c)
|
||||||
|
* and the qlock(c) while holding a qlock(b) in vtblockwrite. However,
|
||||||
|
* the block here can never be the block in a vtblockwrite, so we're safe.
|
||||||
|
* We're certainly living on the edge.
|
||||||
|
*/
|
||||||
|
qlock(&b->lk);
|
||||||
|
b->nlock = 1;
|
||||||
|
qunlock(&c->lk);
|
||||||
|
|
||||||
|
n = vtread(c->z, score, type, b->data, c->blocksize);
|
||||||
|
if(n < 0){
|
||||||
|
fprint(2, "vtread: %r\n");
|
||||||
|
b->iostate = BioVentiError;
|
||||||
|
vtblockput(b);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
vtzeroextend(type, b->data, n, c->blocksize);
|
||||||
|
b->iostate = BioVenti;
|
||||||
|
b->nlock = 1;
|
||||||
|
b->decrypted = 0;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The thread that has locked b may refer to it by
|
||||||
|
* multiple names. Nlock counts the number of
|
||||||
|
* references the locking thread holds. It will call
|
||||||
|
* vtblockput once per reference.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
vtblockduplock(VtBlock *b)
|
||||||
|
{
|
||||||
|
assert(b->nlock > 0);
|
||||||
|
b->nlock++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we're done with the block.
|
||||||
|
* unlock it. can't use it after calling this.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
vtblockput(VtBlock* b)
|
||||||
|
{
|
||||||
|
VtCache *c;
|
||||||
|
|
||||||
|
if(b == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(0)fprint(2, "vtblockput: %d: %x %d %d\n", getpid(), b->addr, c->nheap, b->iostate);
|
||||||
|
|
||||||
|
if(--b->nlock > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* b->nlock should probably stay at zero while
|
||||||
|
* the vtBlock is unlocked, but diskThread and vtSleep
|
||||||
|
* conspire to assume that they can just qlock(&b->lk); vtblockput(b),
|
||||||
|
* so we have to keep b->nlock set to 1 even
|
||||||
|
* when the vtBlock is unlocked.
|
||||||
|
*/
|
||||||
|
assert(b->nlock == 0);
|
||||||
|
b->nlock = 1;
|
||||||
|
|
||||||
|
qunlock(&b->lk);
|
||||||
|
c = b->c;
|
||||||
|
qlock(&c->lk);
|
||||||
|
|
||||||
|
if(--b->ref > 0){
|
||||||
|
qunlock(&c->lk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(b->ref == 0);
|
||||||
|
switch(b->iostate){
|
||||||
|
case BioVenti:
|
||||||
|
//if(b->addr != NilBlock) print("blockput %d\n", b->addr);
|
||||||
|
b->used = c->now++;
|
||||||
|
case BioVentiError:
|
||||||
|
heapins(b);
|
||||||
|
break;
|
||||||
|
case BioLocal:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
qunlock(&c->lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtblockwrite(VtBlock *b)
|
||||||
|
{
|
||||||
|
uchar score[VtScoreSize];
|
||||||
|
VtCache *c;
|
||||||
|
uint h;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if(b->iostate != BioLocal){
|
||||||
|
abort();
|
||||||
|
sysfatal("vtBlockWrite: not a local block");
|
||||||
|
}
|
||||||
|
|
||||||
|
c = b->c;
|
||||||
|
n = vtzerotruncate(b->type, b->data, c->blocksize);
|
||||||
|
if(vtwrite(c->z, score, b->type, b->data, n) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memmove(b->score, score, VtScoreSize);
|
||||||
|
|
||||||
|
qlock(&c->lk);
|
||||||
|
b->iostate = BioVenti;
|
||||||
|
h = (u32int)(score[0]|(score[1]<<8)|(score[2]<<16)|(score[3]<<24)) % c->nhash;
|
||||||
|
b->next = c->hash[h];
|
||||||
|
c->hash[h] = b;
|
||||||
|
if(b->next != nil)
|
||||||
|
b->next->prev = &b->next;
|
||||||
|
b->prev = &c->hash[h];
|
||||||
|
qunlock(&c->lk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
vtcacheblocksize(VtCache *c)
|
||||||
|
{
|
||||||
|
return c->blocksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
VtBlock*
|
||||||
|
vtblockcopy(VtBlock *b)
|
||||||
|
{
|
||||||
|
VtBlock *bb;
|
||||||
|
|
||||||
|
ncopy++;
|
||||||
|
bb = vtcacheallocblock(b->c, b->type);
|
||||||
|
if(bb == nil){
|
||||||
|
vtblockput(b);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
memmove(bb->data, b->data, b->c->blocksize);
|
||||||
|
vtblockput(b);
|
||||||
|
return bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vtlocaltoglobal(u32int addr, uchar score[VtScoreSize])
|
||||||
|
{
|
||||||
|
memset(score, 0, 16);
|
||||||
|
score[16] = addr>>24;
|
||||||
|
score[17] = addr>>16;
|
||||||
|
score[18] = addr>>8;
|
||||||
|
score[19] = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u32int
|
||||||
|
vtglobaltolocal(uchar score[VtScoreSize])
|
||||||
|
{
|
||||||
|
static uchar zero[16];
|
||||||
|
if(memcmp(score, zero, 16) != 0)
|
||||||
|
return NilBlock;
|
||||||
|
return (score[16]<<24)|(score[17]<<16)|(score[18]<<8)|score[19];
|
||||||
|
}
|
||||||
151
src/libventi/client.c
Normal file
151
src/libventi/client.c
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
vtfcallrpc(VtConn *z, VtFcall *ou, VtFcall *in)
|
||||||
|
{
|
||||||
|
Packet *p;
|
||||||
|
|
||||||
|
p = vtfcallpack(ou);
|
||||||
|
if(p == nil)
|
||||||
|
return -1;
|
||||||
|
if((p = vtrpc(z, p)) == nil)
|
||||||
|
return -1;
|
||||||
|
if(vtfcallunpack(in, p) < 0){
|
||||||
|
packetfree(p);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(in->type == VtRerror){
|
||||||
|
werrstr(in->error);
|
||||||
|
vtfcallclear(in);
|
||||||
|
packetfree(p);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(in->type != ou->type+1){
|
||||||
|
werrstr("type mismatch: sent %c%d got %c%d",
|
||||||
|
"TR"[ou->type&1], ou->type>>1,
|
||||||
|
"TR"[in->type&1], in->type>>1);
|
||||||
|
vtfcallclear(in);
|
||||||
|
packetfree(p);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
packetfree(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vthello(VtConn *z)
|
||||||
|
{
|
||||||
|
VtFcall tx, rx;
|
||||||
|
|
||||||
|
memset(&tx, 0, sizeof tx);
|
||||||
|
tx.type = VtThello;
|
||||||
|
tx.version = z->version;
|
||||||
|
tx.uid = z->uid;
|
||||||
|
if(tx.uid == nil)
|
||||||
|
tx.uid = "anonymous";
|
||||||
|
if(vtfcallrpc(z, &tx, &rx) < 0)
|
||||||
|
return -1;
|
||||||
|
z->sid = rx.sid;
|
||||||
|
rx.sid = 0;
|
||||||
|
vtfcallclear(&rx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet*
|
||||||
|
vtreadpacket(VtConn *z, uchar score[VtScoreSize], uint type, int n)
|
||||||
|
{
|
||||||
|
VtFcall tx, rx;
|
||||||
|
|
||||||
|
memset(&tx, 0, sizeof tx);
|
||||||
|
tx.type = VtTread;
|
||||||
|
tx.dtype = type;
|
||||||
|
tx.count = n;
|
||||||
|
memmove(tx.score, score, VtScoreSize);
|
||||||
|
if(vtfcallrpc(z, &tx, &rx) < 0)
|
||||||
|
return nil;
|
||||||
|
if(packetsize(rx.data) > n){
|
||||||
|
werrstr("read returned too much data");
|
||||||
|
packetfree(rx.data);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
packetsha1(rx.data, tx.score);
|
||||||
|
if(memcmp(score, tx.score, VtScoreSize) != 0){
|
||||||
|
werrstr("read asked for %V got %V", score, tx.score);
|
||||||
|
packetfree(rx.data);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rx.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtread(VtConn *z, uchar score[VtScoreSize], uint type, uchar *buf, int n)
|
||||||
|
{
|
||||||
|
int nn;
|
||||||
|
Packet *p;
|
||||||
|
|
||||||
|
if((p = vtreadpacket(z, score, type, n)) == nil)
|
||||||
|
return -1;
|
||||||
|
nn = packetsize(p);
|
||||||
|
if(packetconsume(p, buf, nn) < 0)
|
||||||
|
abort();
|
||||||
|
return nn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtwritepacket(VtConn *z, uchar score[VtScoreSize], uint type, Packet *p)
|
||||||
|
{
|
||||||
|
VtFcall tx, rx;
|
||||||
|
|
||||||
|
tx.type = VtTwrite;
|
||||||
|
tx.dtype = type;
|
||||||
|
tx.data = p;
|
||||||
|
packetsha1(p, score);
|
||||||
|
if(vtfcallrpc(z, &tx, &rx) < 0)
|
||||||
|
return -1;
|
||||||
|
if(memcmp(score, rx.score, VtScoreSize) != 0){
|
||||||
|
werrstr("sha1 hash mismatch: want %V got %V", score, rx.score);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtwrite(VtConn *z, uchar score[VtScoreSize], uint type, uchar *buf, int n)
|
||||||
|
{
|
||||||
|
Packet *p;
|
||||||
|
|
||||||
|
p = packetforeign(buf, n, nil, nil);
|
||||||
|
return vtwritepacket(z, score, type, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtsync(VtConn *z)
|
||||||
|
{
|
||||||
|
VtFcall tx, rx;
|
||||||
|
|
||||||
|
tx.type = VtTsync;
|
||||||
|
return vtfcallrpc(z, &tx, &rx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtping(VtConn *z)
|
||||||
|
{
|
||||||
|
VtFcall tx, rx;
|
||||||
|
|
||||||
|
tx.type = VtTping;
|
||||||
|
return vtfcallrpc(z, &tx, &rx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtconnect(VtConn *z)
|
||||||
|
{
|
||||||
|
if(vtversion(z) < 0)
|
||||||
|
return -1;
|
||||||
|
if(vthello(z) < 0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
36
src/libventi/conn.c
Normal file
36
src/libventi/conn.c
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
VtConn*
|
||||||
|
vtconn(int infd, int outfd)
|
||||||
|
{
|
||||||
|
VtConn *z;
|
||||||
|
|
||||||
|
z = vtmallocz(sizeof(VtConn));
|
||||||
|
z->tagrend.l = &z->lk;
|
||||||
|
z->rpcfork.l = &z->lk;
|
||||||
|
z->infd = infd;
|
||||||
|
z->outfd = outfd;
|
||||||
|
z->part = packetalloc();
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vtfreeconn(VtConn *z)
|
||||||
|
{
|
||||||
|
vthangup(z);
|
||||||
|
qlock(&z->lk);
|
||||||
|
for(;;){
|
||||||
|
if(z->readq)
|
||||||
|
_vtqhangup(z->readq);
|
||||||
|
else if(z->writeq)
|
||||||
|
_vtqhangup(z->writeq);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
rsleep(&z->rpcfork);
|
||||||
|
}
|
||||||
|
packetfree(z->part);
|
||||||
|
vtfree(z);
|
||||||
|
}
|
||||||
15
src/libventi/cvt.h
Normal file
15
src/libventi/cvt.h
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* integer conversion routines
|
||||||
|
*/
|
||||||
|
#define U8GET(p) ((p)[0])
|
||||||
|
#define U16GET(p) (((p)[0]<<8)|(p)[1])
|
||||||
|
#define U32GET(p) ((u32int)(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3]))
|
||||||
|
#define U48GET(p) (((vlong)U16GET(p)<<32)|(vlong)U32GET((p)+2))
|
||||||
|
#define U64GET(p) (((vlong)U32GET(p)<<32)|(vlong)U32GET((p)+4))
|
||||||
|
|
||||||
|
#define U8PUT(p,v) (p)[0]=(v)
|
||||||
|
#define U16PUT(p,v) (p)[0]=(v)>>8;(p)[1]=(v)
|
||||||
|
#define U32PUT(p,v) (p)[0]=(v)>>24;(p)[1]=(v)>>16;(p)[2]=(v)>>8;(p)[3]=(v)
|
||||||
|
#define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
|
||||||
|
#define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
|
||||||
|
|
||||||
17
src/libventi/debug.c
Normal file
17
src/libventi/debug.c
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
vtdebug(VtConn *z, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
if(z->debug == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
vfprint(2, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
}
|
||||||
|
|
||||||
21
src/libventi/dial.c
Normal file
21
src/libventi/dial.c
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
VtConn*
|
||||||
|
vtdial(char *addr)
|
||||||
|
{
|
||||||
|
char *na;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if(addr == nil)
|
||||||
|
addr = getenv("venti");
|
||||||
|
if(addr == nil)
|
||||||
|
addr = "$venti";
|
||||||
|
|
||||||
|
na = netmkaddr(addr, "net", "venti");
|
||||||
|
if((fd = dial(na, nil, nil, nil)) < 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return vtconn(fd, fd);
|
||||||
|
}
|
||||||
78
src/libventi/dtype.c
Normal file
78
src/libventi/dtype.c
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OVtErrType, /* illegal */
|
||||||
|
|
||||||
|
OVtRootType,
|
||||||
|
OVtDirType,
|
||||||
|
OVtPointerType0,
|
||||||
|
OVtPointerType1,
|
||||||
|
OVtPointerType2,
|
||||||
|
OVtPointerType3,
|
||||||
|
OVtPointerType4,
|
||||||
|
OVtPointerType5,
|
||||||
|
OVtPointerType6,
|
||||||
|
OVtPointerType7, /* not used */
|
||||||
|
OVtPointerType8, /* not used */
|
||||||
|
OVtPointerType9, /* not used */
|
||||||
|
OVtDataType,
|
||||||
|
|
||||||
|
OVtMaxType
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
uint todisk[] = {
|
||||||
|
OVtDataType,
|
||||||
|
OVtPointerType0,
|
||||||
|
OVtPointerType1,
|
||||||
|
OVtPointerType2,
|
||||||
|
OVtPointerType3,
|
||||||
|
OVtPointerType4,
|
||||||
|
OVtPointerType5,
|
||||||
|
OVtPointerType6,
|
||||||
|
OVtDirType,
|
||||||
|
OVtPointerType0,
|
||||||
|
OVtPointerType1,
|
||||||
|
OVtPointerType2,
|
||||||
|
OVtPointerType3,
|
||||||
|
OVtPointerType4,
|
||||||
|
OVtPointerType5,
|
||||||
|
OVtPointerType6,
|
||||||
|
OVtRootType,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint fromdisk[] = {
|
||||||
|
~0,
|
||||||
|
VtRootType,
|
||||||
|
VtDirType,
|
||||||
|
VtDirType+1,
|
||||||
|
VtDirType+2,
|
||||||
|
VtDirType+3,
|
||||||
|
VtDirType+4,
|
||||||
|
VtDirType+5,
|
||||||
|
VtDirType+6,
|
||||||
|
VtDirType+7,
|
||||||
|
~0,
|
||||||
|
~0,
|
||||||
|
~0,
|
||||||
|
VtDataType,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint
|
||||||
|
vttodisktype(uint n)
|
||||||
|
{
|
||||||
|
if(n >= nelem(todisk))
|
||||||
|
return ~0;
|
||||||
|
return todisk[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
vtfromdisktype(uint n)
|
||||||
|
{
|
||||||
|
if(n >= nelem(fromdisk))
|
||||||
|
return ~0;
|
||||||
|
return fromdisk[n];
|
||||||
|
}
|
||||||
|
|
||||||
85
src/libventi/entry.c
Normal file
85
src/libventi/entry.c
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
#include "cvt.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
checksize(int n)
|
||||||
|
{
|
||||||
|
if(n < 256 || n > VtMaxLumpSize) {
|
||||||
|
werrstr("bad block size");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vtentrypack(VtEntry *e, uchar *p, int index)
|
||||||
|
{
|
||||||
|
ulong t32;
|
||||||
|
int flags;
|
||||||
|
uchar *op;
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
p += index * VtEntrySize;
|
||||||
|
op = p;
|
||||||
|
|
||||||
|
U32PUT(p, e->gen);
|
||||||
|
p += 4;
|
||||||
|
U16PUT(p, e->psize);
|
||||||
|
p += 2;
|
||||||
|
U16PUT(p, e->dsize);
|
||||||
|
p += 2;
|
||||||
|
depth = e->type&VtTypeDepthMask;
|
||||||
|
flags = (e->flags&~(VtEntryDir|VtEntryDepthShift));
|
||||||
|
flags |= depth << VtEntryDepthShift;
|
||||||
|
if(e->type - depth == VtEntryDir)
|
||||||
|
flags |= VtEntryDir;
|
||||||
|
U8PUT(p, flags);
|
||||||
|
p++;
|
||||||
|
memset(p, 0, 5);
|
||||||
|
p += 5;
|
||||||
|
U48PUT(p, e->size, t32);
|
||||||
|
p += 6;
|
||||||
|
memmove(p, e->score, VtScoreSize);
|
||||||
|
p += VtScoreSize;
|
||||||
|
|
||||||
|
assert(p-op == VtEntrySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtentryunpack(VtEntry *e, uchar *p, int index)
|
||||||
|
{
|
||||||
|
uchar *op;
|
||||||
|
|
||||||
|
p += index * VtEntrySize;
|
||||||
|
op = p;
|
||||||
|
|
||||||
|
e->gen = U32GET(p);
|
||||||
|
p += 4;
|
||||||
|
e->psize = U16GET(p);
|
||||||
|
p += 2;
|
||||||
|
e->dsize = U16GET(p);
|
||||||
|
p += 2;
|
||||||
|
e->flags = U8GET(p);
|
||||||
|
e->type = (e->flags&VtEntryDir) ? VtDirType : VtDataType;
|
||||||
|
e->type += (e->flags & VtEntryDepthMask) >> VtEntryDepthShift;
|
||||||
|
e->flags &= ~(VtEntryDir|VtEntryDepthMask);
|
||||||
|
p++;
|
||||||
|
p += 5;
|
||||||
|
e->size = U48GET(p);
|
||||||
|
p += 6;
|
||||||
|
memmove(e->score, p, VtScoreSize);
|
||||||
|
p += VtScoreSize;
|
||||||
|
|
||||||
|
assert(p-op == VtEntrySize);
|
||||||
|
|
||||||
|
if(!(e->flags & VtEntryActive))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(checksize(e->psize) < 0 || checksize(e->dsize) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
230
src/libventi/fcall.c
Normal file
230
src/libventi/fcall.c
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
Packet*
|
||||||
|
vtfcallpack(VtFcall *f)
|
||||||
|
{
|
||||||
|
uchar buf[4];
|
||||||
|
Packet *p;
|
||||||
|
|
||||||
|
p = packetalloc();
|
||||||
|
|
||||||
|
buf[0] = f->type;
|
||||||
|
buf[1] = f->tag;
|
||||||
|
packetappend(p, buf, 2);
|
||||||
|
|
||||||
|
switch(f->type){
|
||||||
|
default:
|
||||||
|
werrstr("vtfcallpack: unknown packet type %d", f->type);
|
||||||
|
goto Err;
|
||||||
|
|
||||||
|
case VtRerror:
|
||||||
|
if(vtputstring(p, f->error) < 0)
|
||||||
|
goto Err;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtTping:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtRping:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtThello:
|
||||||
|
if(vtputstring(p, f->version) < 0
|
||||||
|
|| vtputstring(p, f->uid) < 0)
|
||||||
|
goto Err;
|
||||||
|
buf[0] = f->strength;
|
||||||
|
buf[1] = f->ncrypto;
|
||||||
|
packetappend(p, buf, 2);
|
||||||
|
packetappend(p, f->crypto, f->ncrypto);
|
||||||
|
buf[0] = f->ncodec;
|
||||||
|
packetappend(p, buf, 1);
|
||||||
|
packetappend(p, f->codec, f->ncodec);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtRhello:
|
||||||
|
if(vtputstring(p, f->sid) < 0)
|
||||||
|
goto Err;
|
||||||
|
buf[0] = f->rcrypto;
|
||||||
|
buf[1] = f->rcodec;
|
||||||
|
packetappend(p, buf, 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtTgoodbye:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtTread:
|
||||||
|
packetappend(p, f->score, VtScoreSize);
|
||||||
|
buf[0] = vttodisktype(f->dtype);
|
||||||
|
if(~buf[0] == 0)
|
||||||
|
goto Err;
|
||||||
|
buf[1] = 0;
|
||||||
|
buf[2] = f->count >> 8;
|
||||||
|
buf[3] = f->count;
|
||||||
|
packetappend(p, buf, 4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtRread:
|
||||||
|
packetconcat(p, f->data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtTwrite:
|
||||||
|
buf[0] = vttodisktype(f->dtype);
|
||||||
|
if(~buf[0] == 0)
|
||||||
|
goto Err;
|
||||||
|
buf[1] = 0;
|
||||||
|
buf[2] = 0;
|
||||||
|
buf[3] = 0;
|
||||||
|
packetappend(p, buf, 4);
|
||||||
|
packetconcat(p, f->data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtRwrite:
|
||||||
|
packetappend(p, f->score, VtScoreSize);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtTsync:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtRsync:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
|
||||||
|
Err:
|
||||||
|
packetfree(p);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtfcallunpack(VtFcall *f, Packet *p)
|
||||||
|
{
|
||||||
|
uchar buf[4];
|
||||||
|
|
||||||
|
memset(f, 0, sizeof *f);
|
||||||
|
|
||||||
|
if(packetconsume(p, buf, 2) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
f->type = buf[0];
|
||||||
|
f->tag = buf[1];
|
||||||
|
|
||||||
|
switch(f->type){
|
||||||
|
default:
|
||||||
|
werrstr("vtfcallunpack: unknown bad packet type %d", f->type);
|
||||||
|
vtfcallclear(f);
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
case VtRerror:
|
||||||
|
if(vtgetstring(p, &f->error) < 0)
|
||||||
|
goto Err;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtTping:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtRping:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtThello:
|
||||||
|
if(vtgetstring(p, &f->version) < 0
|
||||||
|
|| vtgetstring(p, &f->uid) < 0
|
||||||
|
|| packetconsume(p, buf, 2) < 0)
|
||||||
|
goto Err;
|
||||||
|
f->strength = buf[0];
|
||||||
|
f->ncrypto = buf[1];
|
||||||
|
if(f->ncrypto){
|
||||||
|
f->crypto = vtmalloc(f->ncrypto);
|
||||||
|
if(packetconsume(p, buf, f->ncrypto) < 0)
|
||||||
|
goto Err;
|
||||||
|
}
|
||||||
|
if(packetconsume(p, buf, 1) < 0)
|
||||||
|
goto Err;
|
||||||
|
f->ncodec = buf[0];
|
||||||
|
if(f->ncodec){
|
||||||
|
f->codec = vtmalloc(f->ncodec);
|
||||||
|
if(packetconsume(p, buf, f->ncodec) < 0)
|
||||||
|
goto Err;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtRhello:
|
||||||
|
if(vtgetstring(p, &f->sid) < 0
|
||||||
|
|| packetconsume(p, buf, 2) < 0)
|
||||||
|
goto Err;
|
||||||
|
f->rcrypto = buf[0];
|
||||||
|
f->rcodec = buf[1];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtTgoodbye:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtTread:
|
||||||
|
if(packetconsume(p, f->score, VtScoreSize) < 0
|
||||||
|
|| packetconsume(p, buf, 4) < 0)
|
||||||
|
goto Err;
|
||||||
|
f->dtype = vtfromdisktype(buf[0]);
|
||||||
|
if(~f->dtype == 0)
|
||||||
|
goto Err;
|
||||||
|
f->count = (buf[2] << 8) | buf[3];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtRread:
|
||||||
|
f->data = packetalloc();
|
||||||
|
packetconcat(f->data, p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtTwrite:
|
||||||
|
if(packetconsume(p, buf, 4) < 0)
|
||||||
|
goto Err;
|
||||||
|
f->dtype = vtfromdisktype(buf[0]);
|
||||||
|
if(~f->dtype == 0)
|
||||||
|
goto Err;
|
||||||
|
f->data = packetalloc();
|
||||||
|
packetconcat(f->data, p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtRwrite:
|
||||||
|
if(packetconsume(p, f->score, VtScoreSize) < 0)
|
||||||
|
goto Err;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtTsync:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VtRsync:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(packetsize(p) != 0)
|
||||||
|
goto Err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Err:
|
||||||
|
werrstr("bad packet");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vtfcallclear(VtFcall *f)
|
||||||
|
{
|
||||||
|
vtfree(f->error);
|
||||||
|
f->error = nil;
|
||||||
|
vtfree(f->uid);
|
||||||
|
f->uid = nil;
|
||||||
|
vtfree(f->sid);
|
||||||
|
f->sid = nil;
|
||||||
|
vtfree(f->version);
|
||||||
|
f->version = nil;
|
||||||
|
vtfree(f->crypto);
|
||||||
|
f->crypto = nil;
|
||||||
|
vtfree(f->codec);
|
||||||
|
f->codec = nil;
|
||||||
|
vtfree(f->auth);
|
||||||
|
f->auth = nil;
|
||||||
|
packetfree(f->data);
|
||||||
|
f->auth = nil;
|
||||||
|
}
|
||||||
55
src/libventi/fcallfmt.c
Normal file
55
src/libventi/fcallfmt.c
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
vtfcallfmt(Fmt *f)
|
||||||
|
{
|
||||||
|
VtFcall *t;
|
||||||
|
|
||||||
|
t = va_arg(f->args, VtFcall*);
|
||||||
|
if(t == nil){
|
||||||
|
fmtprint(f, "<nil fcall>");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
switch(t->type){
|
||||||
|
default:
|
||||||
|
return fmtprint(f, "%c%d tag %ud", "TR"[t->type&1], t->type>>1, t->tag);
|
||||||
|
case VtRerror:
|
||||||
|
return fmtprint(f, "Rerror tag %ud error %s", t->tag, t->error);
|
||||||
|
case VtTping:
|
||||||
|
return fmtprint(f, "Tping tag %ud", t->tag);
|
||||||
|
case VtRping:
|
||||||
|
return fmtprint(f, "Rping tag %ud", t->tag);
|
||||||
|
case VtThello:
|
||||||
|
return fmtprint(f, "Thello tag %ud vers %s uid %s strength %d crypto %d:%.*H codec %d:%.*H", t->tag,
|
||||||
|
t->version, t->uid, t->strength, t->ncrypto, t->ncrypto, t->crypto,
|
||||||
|
t->ncodec, t->ncodec, t->codec);
|
||||||
|
case VtRhello:
|
||||||
|
return fmtprint(f, "Rhello tag %ud sid %s rcrypto %d rcodec %d", t->tag, t->sid, t->rcrypto, t->rcodec);
|
||||||
|
case VtTgoodbye:
|
||||||
|
return fmtprint(f, "Tgoodbye tag %ud", t->tag);
|
||||||
|
case VtRgoodbye:
|
||||||
|
return fmtprint(f, "Rgoodbye tag %ud", t->tag);
|
||||||
|
case VtTauth0:
|
||||||
|
return fmtprint(f, "Tauth0 tag %ud auth %.*H", t->tag, t->nauth, t->auth);
|
||||||
|
case VtRauth0:
|
||||||
|
return fmtprint(f, "Rauth0 tag %ud auth %.*H", t->tag, t->nauth, t->auth);
|
||||||
|
case VtTauth1:
|
||||||
|
return fmtprint(f, "Tauth1 tag %ud auth %.*H", t->tag, t->nauth, t->auth);
|
||||||
|
case VtRauth1:
|
||||||
|
return fmtprint(f, "Rauth1 tag %ud auth %.*H", t->tag, t->nauth, t->auth);
|
||||||
|
case VtTread:
|
||||||
|
return fmtprint(f, "Tread tag %ud score %V dtype %d count %d", t->tag, t->score, t->dtype, t->count);
|
||||||
|
case VtRread:
|
||||||
|
return fmtprint(f, "Rread tag %ud count %d", t->tag, packetsize(t->data));
|
||||||
|
case VtTwrite:
|
||||||
|
return fmtprint(f, "Twrite tag %ud dtype %d count %d", t->tag, t->dtype, packetsize(t->data));
|
||||||
|
case VtRwrite:
|
||||||
|
return fmtprint(f, "Rwrite tag %ud score %V", t->tag, t->score);
|
||||||
|
case VtTsync:
|
||||||
|
return fmtprint(f, "Tsync tag %ud", t->tag);
|
||||||
|
case VtRsync:
|
||||||
|
return fmtprint(f, "Rsync tag %ud", t->tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
1264
src/libventi/file.c
Normal file
1264
src/libventi/file.c
Normal file
File diff suppressed because it is too large
Load diff
22
src/libventi/hangup.c
Normal file
22
src/libventi/hangup.c
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
vthangup(VtConn *z)
|
||||||
|
{
|
||||||
|
qlock(&z->lk);
|
||||||
|
z->state = VtStateClosed;
|
||||||
|
if(z->infd >= 0)
|
||||||
|
close(z->infd);
|
||||||
|
if(z->outfd >= 0 && z->outfd != z->infd)
|
||||||
|
close(z->outfd);
|
||||||
|
z->infd = -1;
|
||||||
|
z->outfd = -1;
|
||||||
|
if(z->writeq)
|
||||||
|
_vtqhangup(z->writeq);
|
||||||
|
if(z->readq)
|
||||||
|
_vtqhangup(z->readq);
|
||||||
|
qunlock(&z->lk);
|
||||||
|
}
|
||||||
87
src/libventi/mem.c
Normal file
87
src/libventi/mem.c
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IdealAlignment = 32,
|
||||||
|
ChunkSize = 128*1024,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
vtfree(void *p)
|
||||||
|
{
|
||||||
|
if(p == 0)
|
||||||
|
return;
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
vtmalloc(int size)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
p = malloc(size);
|
||||||
|
if(p == 0)
|
||||||
|
sysfatal("vtmalloc: out of memory");
|
||||||
|
setmalloctag(p, getcallerpc(&size));
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
vtmallocz(int size)
|
||||||
|
{
|
||||||
|
void *p = vtmalloc(size);
|
||||||
|
memset(p, 0, size);
|
||||||
|
setmalloctag(p, getcallerpc(&size));
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
vtrealloc(void *p, int size)
|
||||||
|
{
|
||||||
|
if(p == nil)
|
||||||
|
return vtmalloc(size);
|
||||||
|
p = realloc(p, size);
|
||||||
|
if(p == 0)
|
||||||
|
sysfatal("vtMemRealloc: out of memory");
|
||||||
|
setrealloctag(p, getcallerpc(&size));
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
vtbrk(int n)
|
||||||
|
{
|
||||||
|
static Lock lk;
|
||||||
|
static uchar *buf;
|
||||||
|
static int nbuf;
|
||||||
|
static int nchunk;
|
||||||
|
int align, pad;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if(n >= IdealAlignment)
|
||||||
|
align = IdealAlignment;
|
||||||
|
else if(n > 8)
|
||||||
|
align = 8;
|
||||||
|
else
|
||||||
|
align = 4;
|
||||||
|
|
||||||
|
lock(&lk);
|
||||||
|
pad = (align - (ulong)buf) & (align-1);
|
||||||
|
if(n + pad > nbuf) {
|
||||||
|
buf = vtmallocz(ChunkSize);
|
||||||
|
nbuf = ChunkSize;
|
||||||
|
pad = (align - (ulong)buf) & (align-1);
|
||||||
|
nchunk++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(n + pad <= nbuf);
|
||||||
|
|
||||||
|
p = buf + pad;
|
||||||
|
buf += pad + n;
|
||||||
|
nbuf -= pad + n;
|
||||||
|
unlock(&lk);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
42
src/libventi/mkfile
Normal file
42
src/libventi/mkfile
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
PLAN9=../..
|
||||||
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
|
LIB=libventi.a
|
||||||
|
|
||||||
|
OFILES=\
|
||||||
|
cache.$O\
|
||||||
|
client.$O\
|
||||||
|
conn.$O\
|
||||||
|
dial.$O\
|
||||||
|
debug.$O\
|
||||||
|
dtype.$O\
|
||||||
|
entry.$O\
|
||||||
|
fcall.$O\
|
||||||
|
fcallfmt.$O\
|
||||||
|
file.$O\
|
||||||
|
hangup.$O\
|
||||||
|
mem.$O\
|
||||||
|
packet.$O\
|
||||||
|
queue.$O\
|
||||||
|
root.$O\
|
||||||
|
rpc.$O\
|
||||||
|
scorefmt.$O\
|
||||||
|
send.$O\
|
||||||
|
server.$O\
|
||||||
|
srvhello.$O\
|
||||||
|
strdup.$O\
|
||||||
|
string.$O\
|
||||||
|
version.$O\
|
||||||
|
zero.$O\
|
||||||
|
zeroscore.$O\
|
||||||
|
|
||||||
|
HFILES=\
|
||||||
|
$PLAN9/include/venti.h\
|
||||||
|
|
||||||
|
<$PLAN9/src/mksyslib
|
||||||
|
|
||||||
|
send.$O: queue.h
|
||||||
|
server.$O: queue.h
|
||||||
|
queue.$O: queue.h
|
||||||
|
|
||||||
|
|
||||||
941
src/libventi/packet.c
Normal file
941
src/libventi/packet.c
Normal file
|
|
@ -0,0 +1,941 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
#include <libsec.h>
|
||||||
|
|
||||||
|
typedef struct Mem Mem;
|
||||||
|
typedef struct Frag Frag;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BigMemSize = MaxFragSize,
|
||||||
|
SmallMemSize = BigMemSize/8,
|
||||||
|
NLocalFrag = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* position to carve out of a Mem */
|
||||||
|
enum {
|
||||||
|
PFront,
|
||||||
|
PMiddle,
|
||||||
|
PEnd,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Mem
|
||||||
|
{
|
||||||
|
Lock lk;
|
||||||
|
int ref;
|
||||||
|
uchar *bp;
|
||||||
|
uchar *ep;
|
||||||
|
uchar *rp;
|
||||||
|
uchar *wp;
|
||||||
|
Mem *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FragLocalFree,
|
||||||
|
FragLocalAlloc,
|
||||||
|
FragGlobal,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Frag
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
Mem *mem;
|
||||||
|
uchar *rp;
|
||||||
|
uchar *wp;
|
||||||
|
Frag *next;
|
||||||
|
void (*free)(void*);
|
||||||
|
void *a;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Packet
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
int asize; /* allocated memory - greater than size unless foreign frags */
|
||||||
|
|
||||||
|
Packet *next;
|
||||||
|
|
||||||
|
Frag *first;
|
||||||
|
Frag *last;
|
||||||
|
|
||||||
|
Frag local[NLocalFrag];
|
||||||
|
};
|
||||||
|
|
||||||
|
static Frag *fragalloc(Packet*, int n, int pos, Frag *next);
|
||||||
|
static Frag *fragdup(Packet*, Frag*);
|
||||||
|
static void fragfree(Frag*);
|
||||||
|
|
||||||
|
static Mem *memalloc(int, int);
|
||||||
|
static void memfree(Mem*);
|
||||||
|
static int memhead(Mem *m, uchar *rp, int n);
|
||||||
|
static int memtail(Mem *m, uchar *wp, int n);
|
||||||
|
|
||||||
|
static char EPacketSize[] = "bad packet size";
|
||||||
|
static char EPacketOffset[] = "bad packet offset";
|
||||||
|
static char EBadSize[] = "bad size";
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
Lock lk;
|
||||||
|
Packet *packet;
|
||||||
|
int npacket;
|
||||||
|
Frag *frag;
|
||||||
|
int nfrag;
|
||||||
|
Mem *bigmem;
|
||||||
|
int nbigmem;
|
||||||
|
Mem *smallmem;
|
||||||
|
int nsmallmem;
|
||||||
|
} freelist;
|
||||||
|
|
||||||
|
#define FRAGSIZE(f) ((f)->wp - (f)->rp)
|
||||||
|
#define FRAGASIZE(f) ((f)->mem ? (f)->mem->ep - (f)->mem->bp : 0)
|
||||||
|
|
||||||
|
#define NOTFREE(p) assert((p)->size>=0)
|
||||||
|
|
||||||
|
Packet *
|
||||||
|
packetalloc(void)
|
||||||
|
{
|
||||||
|
Packet *p;
|
||||||
|
|
||||||
|
lock(&freelist.lk);
|
||||||
|
p = freelist.packet;
|
||||||
|
if(p != nil)
|
||||||
|
freelist.packet = p->next;
|
||||||
|
else
|
||||||
|
freelist.npacket++;
|
||||||
|
unlock(&freelist.lk);
|
||||||
|
|
||||||
|
if(p == nil)
|
||||||
|
p = vtbrk(sizeof(Packet));
|
||||||
|
else
|
||||||
|
assert(p->size == -1);
|
||||||
|
p->size = 0;
|
||||||
|
p->asize = 0;
|
||||||
|
p->first = nil;
|
||||||
|
p->last = nil;
|
||||||
|
p->next = nil;
|
||||||
|
|
||||||
|
if(1)fprint(2, "packetalloc %p from %08lux %08lux %08lux\n", p, *((uint*)&p+2), *((uint*)&p+3), *((uint*)&p+4));
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
packetfree(Packet *p)
|
||||||
|
{
|
||||||
|
Frag *f, *ff;
|
||||||
|
|
||||||
|
if(1)fprint(2, "packetfree %p from %08lux\n", p, getcallerpc(&p));
|
||||||
|
|
||||||
|
if(p == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
p->size = -1;
|
||||||
|
|
||||||
|
for(f=p->first; f!=nil; f=ff) {
|
||||||
|
ff = f->next;
|
||||||
|
fragfree(f);
|
||||||
|
}
|
||||||
|
p->first = nil;
|
||||||
|
p->last = nil;
|
||||||
|
|
||||||
|
lock(&freelist.lk);
|
||||||
|
p->next = freelist.packet;
|
||||||
|
freelist.packet = p;
|
||||||
|
unlock(&freelist.lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet *
|
||||||
|
packetdup(Packet *p, int offset, int n)
|
||||||
|
{
|
||||||
|
Frag *f, *ff;
|
||||||
|
Packet *pp;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
if(offset < 0 || n < 0 || offset+n > p->size) {
|
||||||
|
werrstr(EBadSize);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
pp = packetalloc();
|
||||||
|
if(n == 0)
|
||||||
|
return pp;
|
||||||
|
|
||||||
|
pp->size = n;
|
||||||
|
|
||||||
|
/* skip offset */
|
||||||
|
for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
|
||||||
|
offset -= FRAGSIZE(f);
|
||||||
|
|
||||||
|
/* first frag */
|
||||||
|
ff = fragdup(pp, f);
|
||||||
|
ff->rp += offset;
|
||||||
|
pp->first = ff;
|
||||||
|
n -= FRAGSIZE(ff);
|
||||||
|
pp->asize += FRAGASIZE(ff);
|
||||||
|
|
||||||
|
/* the remaining */
|
||||||
|
while(n > 0) {
|
||||||
|
f = f->next;
|
||||||
|
ff->next = fragdup(pp, f);
|
||||||
|
ff = ff->next;
|
||||||
|
n -= FRAGSIZE(ff);
|
||||||
|
pp->asize += FRAGASIZE(ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fix up last frag: note n <= 0 */
|
||||||
|
ff->wp += n;
|
||||||
|
ff->next = nil;
|
||||||
|
pp->last = ff;
|
||||||
|
|
||||||
|
return pp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet *
|
||||||
|
packetsplit(Packet *p, int n)
|
||||||
|
{
|
||||||
|
Packet *pp;
|
||||||
|
Frag *f, *ff;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
if(n < 0 || n > p->size) {
|
||||||
|
werrstr(EPacketSize);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
pp = packetalloc();
|
||||||
|
if(n == 0)
|
||||||
|
return pp;
|
||||||
|
|
||||||
|
pp->size = n;
|
||||||
|
p->size -= n;
|
||||||
|
ff = nil;
|
||||||
|
for(f=p->first; n > 0 && n >= FRAGSIZE(f); f=f->next) {
|
||||||
|
n -= FRAGSIZE(f);
|
||||||
|
p->asize -= FRAGASIZE(f);
|
||||||
|
pp->asize += FRAGASIZE(f);
|
||||||
|
ff = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* split shared frag */
|
||||||
|
if(n > 0) {
|
||||||
|
ff = f;
|
||||||
|
f = fragdup(pp, ff);
|
||||||
|
pp->asize += FRAGASIZE(ff);
|
||||||
|
ff->next = nil;
|
||||||
|
ff->wp = ff->rp + n;
|
||||||
|
f->rp += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
pp->first = p->first;
|
||||||
|
pp->last = ff;
|
||||||
|
p->first = f;
|
||||||
|
return pp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
packetconsume(Packet *p, uchar *buf, int n)
|
||||||
|
{
|
||||||
|
NOTFREE(p);
|
||||||
|
if(buf && packetcopy(p, buf, 0, n) < 0)
|
||||||
|
return 0;
|
||||||
|
return packettrim(p, n, p->size-n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
packettrim(Packet *p, int offset, int n)
|
||||||
|
{
|
||||||
|
Frag *f, *ff;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
if(offset < 0 || offset > p->size) {
|
||||||
|
werrstr(EPacketOffset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n < 0 || offset + n > p->size) {
|
||||||
|
werrstr(EPacketOffset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->size = n;
|
||||||
|
|
||||||
|
/* easy case */
|
||||||
|
if(n == 0) {
|
||||||
|
for(f=p->first; f != nil; f=ff) {
|
||||||
|
ff = f->next;
|
||||||
|
fragfree(f);
|
||||||
|
}
|
||||||
|
p->first = p->last = nil;
|
||||||
|
p->asize = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free before offset */
|
||||||
|
for(f=p->first; offset >= FRAGSIZE(f); f=ff) {
|
||||||
|
p->asize -= FRAGASIZE(f);
|
||||||
|
offset -= FRAGSIZE(f);
|
||||||
|
ff = f->next;
|
||||||
|
fragfree(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust frag */
|
||||||
|
f->rp += offset;
|
||||||
|
p->first = f;
|
||||||
|
|
||||||
|
/* skip middle */
|
||||||
|
for(; n > 0 && n > FRAGSIZE(f); f=f->next)
|
||||||
|
n -= FRAGSIZE(f);
|
||||||
|
|
||||||
|
/* adjust end */
|
||||||
|
f->wp = f->rp + n;
|
||||||
|
p->last = f;
|
||||||
|
ff = f->next;
|
||||||
|
f->next = nil;
|
||||||
|
|
||||||
|
/* free after */
|
||||||
|
for(f=ff; f != nil; f=ff) {
|
||||||
|
p->asize -= FRAGASIZE(f);
|
||||||
|
ff = f->next;
|
||||||
|
fragfree(f);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar *
|
||||||
|
packetheader(Packet *p, int n)
|
||||||
|
{
|
||||||
|
Frag *f;
|
||||||
|
Mem *m;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
if(n <= 0 || n > MaxFragSize) {
|
||||||
|
werrstr(EPacketSize);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->size += n;
|
||||||
|
|
||||||
|
/* try and fix in current frag */
|
||||||
|
f = p->first;
|
||||||
|
if(f != nil) {
|
||||||
|
m = f->mem;
|
||||||
|
if(n <= f->rp - m->bp)
|
||||||
|
if(m->ref == 1 || memhead(m, f->rp, n) >= 0) {
|
||||||
|
f->rp -= n;
|
||||||
|
return f->rp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add frag to front */
|
||||||
|
f = fragalloc(p, n, PEnd, p->first);
|
||||||
|
p->asize += FRAGASIZE(f);
|
||||||
|
if(p->first == nil)
|
||||||
|
p->last = f;
|
||||||
|
p->first = f;
|
||||||
|
return f->rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar *
|
||||||
|
packettrailer(Packet *p, int n)
|
||||||
|
{
|
||||||
|
Mem *m;
|
||||||
|
Frag *f;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
if(n <= 0 || n > MaxFragSize) {
|
||||||
|
werrstr(EPacketSize);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->size += n;
|
||||||
|
|
||||||
|
/* try and fix in current frag */
|
||||||
|
if(p->first != nil) {
|
||||||
|
f = p->last;
|
||||||
|
m = f->mem;
|
||||||
|
if(n <= m->ep - f->wp)
|
||||||
|
if(m->ref == 1 || memtail(m, f->wp, n) >= 0) {
|
||||||
|
f->wp += n;
|
||||||
|
return f->wp - n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add frag to end */
|
||||||
|
f = fragalloc(p, n, (p->first == nil)?PMiddle:PFront, nil);
|
||||||
|
p->asize += FRAGASIZE(f);
|
||||||
|
if(p->first == nil)
|
||||||
|
p->first = f;
|
||||||
|
else
|
||||||
|
p->last->next = f;
|
||||||
|
p->last = f;
|
||||||
|
return f->rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
packetprefix(Packet *p, uchar *buf, int n)
|
||||||
|
{
|
||||||
|
Frag *f;
|
||||||
|
int nn;
|
||||||
|
Mem *m;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
if(n <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p->size += n;
|
||||||
|
|
||||||
|
/* try and fix in current frag */
|
||||||
|
f = p->first;
|
||||||
|
if(f != nil) {
|
||||||
|
m = f->mem;
|
||||||
|
nn = f->rp - m->bp;
|
||||||
|
if(nn > n)
|
||||||
|
nn = n;
|
||||||
|
if(m->ref == 1 || memhead(m, f->rp, nn) >= 0) {
|
||||||
|
f->rp -= nn;
|
||||||
|
n -= nn;
|
||||||
|
memmove(f->rp, buf+n, nn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(n > 0) {
|
||||||
|
nn = n;
|
||||||
|
if(nn > MaxFragSize)
|
||||||
|
nn = MaxFragSize;
|
||||||
|
f = fragalloc(p, nn, PEnd, p->first);
|
||||||
|
p->asize += FRAGASIZE(f);
|
||||||
|
if(p->first == nil)
|
||||||
|
p->last = f;
|
||||||
|
p->first = f;
|
||||||
|
n -= nn;
|
||||||
|
memmove(f->rp, buf+n, nn);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
packetappend(Packet *p, uchar *buf, int n)
|
||||||
|
{
|
||||||
|
Frag *f;
|
||||||
|
int nn;
|
||||||
|
Mem *m;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
if(n <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p->size += n;
|
||||||
|
/* try and fix in current frag */
|
||||||
|
if(p->first != nil) {
|
||||||
|
f = p->last;
|
||||||
|
m = f->mem;
|
||||||
|
nn = m->ep - f->wp;
|
||||||
|
if(nn > n)
|
||||||
|
nn = n;
|
||||||
|
if(m->ref == 1 || memtail(m, f->wp, nn) >= 0) {
|
||||||
|
memmove(f->wp, buf, nn);
|
||||||
|
f->wp += nn;
|
||||||
|
buf += nn;
|
||||||
|
n -= nn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(n > 0) {
|
||||||
|
nn = n;
|
||||||
|
if(nn > MaxFragSize)
|
||||||
|
nn = MaxFragSize;
|
||||||
|
f = fragalloc(p, nn, (p->first == nil)?PMiddle:PFront, nil);
|
||||||
|
p->asize += FRAGASIZE(f);
|
||||||
|
if(p->first == nil)
|
||||||
|
p->first = f;
|
||||||
|
else
|
||||||
|
p->last->next = f;
|
||||||
|
p->last = f;
|
||||||
|
memmove(f->rp, buf, nn);
|
||||||
|
buf += nn;
|
||||||
|
n -= nn;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
packetconcat(Packet *p, Packet *pp)
|
||||||
|
{
|
||||||
|
NOTFREE(p);
|
||||||
|
NOTFREE(pp);
|
||||||
|
if(pp->size == 0)
|
||||||
|
return 0;
|
||||||
|
p->size += pp->size;
|
||||||
|
p->asize += pp->asize;
|
||||||
|
|
||||||
|
if(p->first != nil)
|
||||||
|
p->last->next = pp->first;
|
||||||
|
else
|
||||||
|
p->first = pp->first;
|
||||||
|
p->last = pp->last;
|
||||||
|
pp->size = 0;
|
||||||
|
pp->asize = 0;
|
||||||
|
pp->first = nil;
|
||||||
|
pp->last = nil;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar *
|
||||||
|
packetpeek(Packet *p, uchar *buf, int offset, int n)
|
||||||
|
{
|
||||||
|
Frag *f;
|
||||||
|
int nn;
|
||||||
|
uchar *b;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
if(n == 0)
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
if(offset < 0 || offset >= p->size) {
|
||||||
|
werrstr(EPacketOffset);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n < 0 || offset + n > p->size) {
|
||||||
|
werrstr(EPacketSize);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip up to offset */
|
||||||
|
for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
|
||||||
|
offset -= FRAGSIZE(f);
|
||||||
|
|
||||||
|
/* easy case */
|
||||||
|
if(offset + n <= FRAGSIZE(f))
|
||||||
|
return f->rp + offset;
|
||||||
|
|
||||||
|
for(b=buf; n>0; n -= nn) {
|
||||||
|
nn = FRAGSIZE(f) - offset;
|
||||||
|
if(nn > n)
|
||||||
|
nn = n;
|
||||||
|
memmove(b, f->rp+offset, nn);
|
||||||
|
offset = 0;
|
||||||
|
f = f->next;
|
||||||
|
b += nn;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
packetcopy(Packet *p, uchar *buf, int offset, int n)
|
||||||
|
{
|
||||||
|
uchar *b;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
b = packetpeek(p, buf, offset, n);
|
||||||
|
if(b == nil)
|
||||||
|
return -1;
|
||||||
|
if(b != buf)
|
||||||
|
memmove(buf, b, n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
packetfragments(Packet *p, IOchunk *io, int nio, int offset)
|
||||||
|
{
|
||||||
|
Frag *f;
|
||||||
|
int size;
|
||||||
|
IOchunk *eio;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
if(p->size == 0 || nio <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(offset < 0 || offset > p->size) {
|
||||||
|
werrstr(EPacketOffset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
|
||||||
|
offset -= FRAGSIZE(f);
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
eio = io + nio;
|
||||||
|
for(; f != nil && io < eio; f=f->next) {
|
||||||
|
io->addr = f->rp + offset;
|
||||||
|
io->len = f->wp - (f->rp + offset);
|
||||||
|
offset = 0;
|
||||||
|
size += io->len;
|
||||||
|
io++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
packetstats(void)
|
||||||
|
{
|
||||||
|
Packet *p;
|
||||||
|
Frag *f;
|
||||||
|
Mem *m;
|
||||||
|
|
||||||
|
int np, nf, nsm, nbm;
|
||||||
|
|
||||||
|
lock(&freelist.lk);
|
||||||
|
np = 0;
|
||||||
|
for(p=freelist.packet; p; p=p->next)
|
||||||
|
np++;
|
||||||
|
nf = 0;
|
||||||
|
for(f=freelist.frag; f; f=f->next)
|
||||||
|
nf++;
|
||||||
|
nsm = 0;
|
||||||
|
for(m=freelist.smallmem; m; m=m->next)
|
||||||
|
nsm++;
|
||||||
|
nbm = 0;
|
||||||
|
for(m=freelist.bigmem; m; m=m->next)
|
||||||
|
nbm++;
|
||||||
|
|
||||||
|
fprint(2, "packet: %d/%d frag: %d/%d small mem: %d/%d big mem: %d/%d\n",
|
||||||
|
np, freelist.npacket,
|
||||||
|
nf, freelist.nfrag,
|
||||||
|
nsm, freelist.nsmallmem,
|
||||||
|
nbm, freelist.nbigmem);
|
||||||
|
|
||||||
|
unlock(&freelist.lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint
|
||||||
|
packetsize(Packet *p)
|
||||||
|
{
|
||||||
|
NOTFREE(p);
|
||||||
|
if(0) {
|
||||||
|
Frag *f;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
for(f=p->first; f; f=f->next)
|
||||||
|
size += FRAGSIZE(f);
|
||||||
|
if(size != p->size)
|
||||||
|
fprint(2, "packetsize %d %d\n", size, p->size);
|
||||||
|
assert(size == p->size);
|
||||||
|
}
|
||||||
|
return p->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
packetasize(Packet *p)
|
||||||
|
{
|
||||||
|
NOTFREE(p);
|
||||||
|
if(0) {
|
||||||
|
Frag *f;
|
||||||
|
int asize = 0;
|
||||||
|
|
||||||
|
for(f=p->first; f; f=f->next)
|
||||||
|
asize += FRAGASIZE(f);
|
||||||
|
if(asize != p->asize)
|
||||||
|
fprint(2, "packetasize %d %d\n", asize, p->asize);
|
||||||
|
assert(asize == p->asize);
|
||||||
|
}
|
||||||
|
return p->asize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
packetsha1(Packet *p, uchar digest[VtScoreSize])
|
||||||
|
{
|
||||||
|
DigestState ds;
|
||||||
|
Frag *f;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
NOTFREE(p);
|
||||||
|
memset(&ds, 0, sizeof ds);
|
||||||
|
size = p->size;
|
||||||
|
for(f=p->first; f; f=f->next) {
|
||||||
|
sha1(f->rp, FRAGSIZE(f), nil, &ds);
|
||||||
|
size -= FRAGSIZE(f);
|
||||||
|
}
|
||||||
|
assert(size == 0);
|
||||||
|
sha1(nil, 0, digest, &ds);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
packetcmp(Packet *pkt0, Packet *pkt1)
|
||||||
|
{
|
||||||
|
Frag *f0, *f1;
|
||||||
|
int n0, n1, x;
|
||||||
|
|
||||||
|
NOTFREE(pkt0);
|
||||||
|
NOTFREE(pkt1);
|
||||||
|
f0 = pkt0->first;
|
||||||
|
f1 = pkt1->first;
|
||||||
|
|
||||||
|
if(f0 == nil)
|
||||||
|
return (f1 == nil)?0:-1;
|
||||||
|
if(f1 == nil)
|
||||||
|
return 1;
|
||||||
|
n0 = FRAGSIZE(f0);
|
||||||
|
n1 = FRAGSIZE(f1);
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
if(n0 < n1) {
|
||||||
|
x = memcmp(f0->wp - n0, f1->wp - n1, n0);
|
||||||
|
if(x != 0)
|
||||||
|
return x;
|
||||||
|
n1 -= n0;
|
||||||
|
f0 = f0->next;
|
||||||
|
if(f0 == nil)
|
||||||
|
return -1;
|
||||||
|
n0 = FRAGSIZE(f0);
|
||||||
|
} else if (n0 > n1) {
|
||||||
|
x = memcmp(f0->wp - n0, f1->wp - n1, n1);
|
||||||
|
if(x != 0)
|
||||||
|
return x;
|
||||||
|
n0 -= n1;
|
||||||
|
f1 = f1->next;
|
||||||
|
if(f1 == nil)
|
||||||
|
return 1;
|
||||||
|
n1 = FRAGSIZE(f1);
|
||||||
|
} else { /* n0 == n1 */
|
||||||
|
x = memcmp(f0->wp - n0, f1->wp - n1, n0);
|
||||||
|
if(x != 0)
|
||||||
|
return x;
|
||||||
|
f0 = f0->next;
|
||||||
|
f1 = f1->next;
|
||||||
|
if(f0 == nil)
|
||||||
|
return (f1 == nil)?0:-1;
|
||||||
|
if(f1 == nil)
|
||||||
|
return 1;
|
||||||
|
n0 = FRAGSIZE(f0);
|
||||||
|
n1 = FRAGSIZE(f1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0; /* for ken */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Frag *
|
||||||
|
fragalloc(Packet *p, int n, int pos, Frag *next)
|
||||||
|
{
|
||||||
|
Frag *f, *ef;
|
||||||
|
Mem *m;
|
||||||
|
|
||||||
|
/* look for local frag */
|
||||||
|
f = &p->local[0];
|
||||||
|
ef = &p->local[NLocalFrag];
|
||||||
|
for(;f<ef; f++) {
|
||||||
|
if(f->state == FragLocalFree) {
|
||||||
|
f->state = FragLocalAlloc;
|
||||||
|
goto Found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lock(&freelist.lk);
|
||||||
|
f = freelist.frag;
|
||||||
|
if(f != nil)
|
||||||
|
freelist.frag = f->next;
|
||||||
|
else
|
||||||
|
freelist.nfrag++;
|
||||||
|
unlock(&freelist.lk);
|
||||||
|
|
||||||
|
if(f == nil) {
|
||||||
|
f = vtbrk(sizeof(Frag));
|
||||||
|
f->state = FragGlobal;
|
||||||
|
}
|
||||||
|
|
||||||
|
Found:
|
||||||
|
f->next = next;
|
||||||
|
|
||||||
|
if(n == 0){
|
||||||
|
f->mem = 0;
|
||||||
|
f->rp = 0;
|
||||||
|
f->wp = 0;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pos == PEnd && next == nil)
|
||||||
|
pos = PMiddle;
|
||||||
|
m = memalloc(n, pos);
|
||||||
|
f->mem = m;
|
||||||
|
f->rp = m->rp;
|
||||||
|
f->wp = m->wp;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet*
|
||||||
|
packetforeign(uchar *buf, int n, void (*free)(void *a), void *a)
|
||||||
|
{
|
||||||
|
Packet *p;
|
||||||
|
Frag *f;
|
||||||
|
|
||||||
|
p = packetalloc();
|
||||||
|
f = fragalloc(p, 0, 0, nil);
|
||||||
|
f->free = free;
|
||||||
|
f->a = a;
|
||||||
|
f->next = nil;
|
||||||
|
f->rp = buf;
|
||||||
|
f->wp = buf+n;
|
||||||
|
|
||||||
|
p->first = f;
|
||||||
|
p->size = n;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Frag *
|
||||||
|
fragdup(Packet *p, Frag *f)
|
||||||
|
{
|
||||||
|
Frag *ff;
|
||||||
|
Mem *m;
|
||||||
|
|
||||||
|
m = f->mem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* m->rp && m->wp can be out of date when ref == 1
|
||||||
|
* also, potentially reclaims space from previous frags
|
||||||
|
*/
|
||||||
|
if(m && m->ref == 1) {
|
||||||
|
m->rp = f->rp;
|
||||||
|
m->wp = f->wp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ff = fragalloc(p, 0, 0, nil);
|
||||||
|
*ff = *f;
|
||||||
|
if(m){
|
||||||
|
lock(&m->lk);
|
||||||
|
m->ref++;
|
||||||
|
unlock(&m->lk);
|
||||||
|
}
|
||||||
|
return ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
fragfree(Frag *f)
|
||||||
|
{
|
||||||
|
if(f->mem == nil){
|
||||||
|
if(f->free)
|
||||||
|
(*f->free)(f->a);
|
||||||
|
}else{
|
||||||
|
memfree(f->mem);
|
||||||
|
f->mem = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(f->state == FragLocalAlloc) {
|
||||||
|
f->state = FragLocalFree;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock(&freelist.lk);
|
||||||
|
f->next = freelist.frag;
|
||||||
|
freelist.frag = f;
|
||||||
|
unlock(&freelist.lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Mem *
|
||||||
|
memalloc(int n, int pos)
|
||||||
|
{
|
||||||
|
Mem *m;
|
||||||
|
int nn;
|
||||||
|
|
||||||
|
if(n < 0 || n > MaxFragSize) {
|
||||||
|
werrstr(EPacketSize);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(n <= SmallMemSize) {
|
||||||
|
lock(&freelist.lk);
|
||||||
|
m = freelist.smallmem;
|
||||||
|
if(m != nil)
|
||||||
|
freelist.smallmem = m->next;
|
||||||
|
else
|
||||||
|
freelist.nsmallmem++;
|
||||||
|
unlock(&freelist.lk);
|
||||||
|
nn = SmallMemSize;
|
||||||
|
} else {
|
||||||
|
lock(&freelist.lk);
|
||||||
|
m = freelist.bigmem;
|
||||||
|
if(m != nil)
|
||||||
|
freelist.bigmem = m->next;
|
||||||
|
else
|
||||||
|
freelist.nbigmem++;
|
||||||
|
unlock(&freelist.lk);
|
||||||
|
nn = BigMemSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m == nil) {
|
||||||
|
m = vtbrk(sizeof(Mem));
|
||||||
|
m->bp = vtbrk(nn);
|
||||||
|
m->ep = m->bp + nn;
|
||||||
|
}
|
||||||
|
assert(m->ref == 0);
|
||||||
|
m->ref = 1;
|
||||||
|
|
||||||
|
switch(pos) {
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
case PFront:
|
||||||
|
m->rp = m->bp;
|
||||||
|
break;
|
||||||
|
case PMiddle:
|
||||||
|
/* leave a little bit at end */
|
||||||
|
m->rp = m->ep - n - 32;
|
||||||
|
break;
|
||||||
|
case PEnd:
|
||||||
|
m->rp = m->ep - n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* check we did not blow it */
|
||||||
|
if(m->rp < m->bp)
|
||||||
|
m->rp = m->bp;
|
||||||
|
m->wp = m->rp + n;
|
||||||
|
assert(m->rp >= m->bp && m->wp <= m->ep);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
memfree(Mem *m)
|
||||||
|
{
|
||||||
|
lock(&m->lk);
|
||||||
|
m->ref--;
|
||||||
|
if(m->ref > 0) {
|
||||||
|
unlock(&m->lk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unlock(&m->lk);
|
||||||
|
assert(m->ref == 0);
|
||||||
|
|
||||||
|
switch(m->ep - m->bp) {
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
case SmallMemSize:
|
||||||
|
lock(&freelist.lk);
|
||||||
|
m->next = freelist.smallmem;
|
||||||
|
freelist.smallmem = m;
|
||||||
|
unlock(&freelist.lk);
|
||||||
|
break;
|
||||||
|
case BigMemSize:
|
||||||
|
lock(&freelist.lk);
|
||||||
|
m->next = freelist.bigmem;
|
||||||
|
freelist.bigmem = m;
|
||||||
|
unlock(&freelist.lk);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
memhead(Mem *m, uchar *rp, int n)
|
||||||
|
{
|
||||||
|
lock(&m->lk);
|
||||||
|
if(m->rp != rp) {
|
||||||
|
unlock(&m->lk);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
m->rp -= n;
|
||||||
|
unlock(&m->lk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
memtail(Mem *m, uchar *wp, int n)
|
||||||
|
{
|
||||||
|
lock(&m->lk);
|
||||||
|
if(m->wp != wp) {
|
||||||
|
unlock(&m->lk);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
m->wp += n;
|
||||||
|
unlock(&m->lk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
103
src/libventi/queue.c
Normal file
103
src/libventi/queue.c
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
typedef struct Qel Qel;
|
||||||
|
struct Qel
|
||||||
|
{
|
||||||
|
Qel *next;
|
||||||
|
void *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Queue
|
||||||
|
{
|
||||||
|
int hungup;
|
||||||
|
QLock lk;
|
||||||
|
Rendez r;
|
||||||
|
Qel *head;
|
||||||
|
Qel *tail;
|
||||||
|
};
|
||||||
|
|
||||||
|
Queue*
|
||||||
|
_vtqalloc(void)
|
||||||
|
{
|
||||||
|
Queue *q;
|
||||||
|
|
||||||
|
q = vtmallocz(sizeof(Queue));
|
||||||
|
q->r.l = &q->lk;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_vtqsend(Queue *q, void *p)
|
||||||
|
{
|
||||||
|
Qel *e;
|
||||||
|
|
||||||
|
e = vtmalloc(sizeof(Qel));
|
||||||
|
qlock(&q->lk);
|
||||||
|
if(q->hungup){
|
||||||
|
werrstr("hungup queue");
|
||||||
|
qunlock(&q->lk);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
e->p = p;
|
||||||
|
e->next = nil;
|
||||||
|
if(q->head == nil)
|
||||||
|
q->head = e;
|
||||||
|
else
|
||||||
|
q->tail->next = e;
|
||||||
|
q->tail = e;
|
||||||
|
rwakeup(&q->r);
|
||||||
|
qunlock(&q->lk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
_vtqrecv(Queue *q)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
Qel *e;
|
||||||
|
|
||||||
|
qlock(&q->lk);
|
||||||
|
while(q->head == nil && !q->hungup)
|
||||||
|
rsleep(&q->r);
|
||||||
|
if(q->hungup){
|
||||||
|
qunlock(&q->lk);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
e = q->head;
|
||||||
|
q->head = e->next;
|
||||||
|
qunlock(&q->lk);
|
||||||
|
p = e->p;
|
||||||
|
vtfree(e);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
_vtnbqrecv(Queue *q)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
Qel *e;
|
||||||
|
|
||||||
|
qlock(&q->lk);
|
||||||
|
if(q->head == nil){
|
||||||
|
qunlock(&q->lk);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
e = q->head;
|
||||||
|
q->head = e->next;
|
||||||
|
qunlock(&q->lk);
|
||||||
|
p = e->p;
|
||||||
|
vtfree(e);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_vtqhangup(Queue *q)
|
||||||
|
{
|
||||||
|
qlock(&q->lk);
|
||||||
|
q->hungup = 1;
|
||||||
|
rwakeupall(&q->r);
|
||||||
|
qunlock(&q->lk);
|
||||||
|
}
|
||||||
6
src/libventi/queue.h
Normal file
6
src/libventi/queue.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
typedef struct Queue Queue;
|
||||||
|
Queue *_vtqalloc(void);
|
||||||
|
int _vtqsend(Queue*, void*);
|
||||||
|
void *_vtqrecv(Queue*);
|
||||||
|
void _vtqhangup(Queue*);
|
||||||
|
void *_vtnbqrecv(Queue*);
|
||||||
67
src/libventi/root.c
Normal file
67
src/libventi/root.c
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
#include "cvt.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
checksize(int n)
|
||||||
|
{
|
||||||
|
if(n < 256 || n > VtMaxLumpSize) {
|
||||||
|
werrstr("bad block size");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vtrootpack(VtRoot *r, uchar *p)
|
||||||
|
{
|
||||||
|
uchar *op = p;
|
||||||
|
|
||||||
|
U16PUT(p, VtRootVersion);
|
||||||
|
p += 2;
|
||||||
|
memmove(p, r->name, sizeof(r->name));
|
||||||
|
p += sizeof(r->name);
|
||||||
|
memmove(p, r->type, sizeof(r->type));
|
||||||
|
p += sizeof(r->type);
|
||||||
|
memmove(p, r->score, VtScoreSize);
|
||||||
|
p += VtScoreSize;
|
||||||
|
U16PUT(p, r->blocksize);
|
||||||
|
p += 2;
|
||||||
|
memmove(p, r->prev, VtScoreSize);
|
||||||
|
p += VtScoreSize;
|
||||||
|
|
||||||
|
assert(p-op == VtRootSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtrootunpack(VtRoot *r, uchar *p)
|
||||||
|
{
|
||||||
|
uchar *op = p;
|
||||||
|
uint vers;
|
||||||
|
memset(r, 0, sizeof(*r));
|
||||||
|
|
||||||
|
vers = U16GET(p);
|
||||||
|
if(vers != VtRootVersion) {
|
||||||
|
werrstr("unknown root version");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
p += 2;
|
||||||
|
memmove(r->name, p, sizeof(r->name));
|
||||||
|
r->name[sizeof(r->name)-1] = 0;
|
||||||
|
p += sizeof(r->name);
|
||||||
|
memmove(r->type, p, sizeof(r->type));
|
||||||
|
r->type[sizeof(r->type)-1] = 0;
|
||||||
|
p += sizeof(r->type);
|
||||||
|
memmove(r->score, p, VtScoreSize);
|
||||||
|
p += VtScoreSize;
|
||||||
|
r->blocksize = U16GET(p);
|
||||||
|
if(checksize(r->blocksize) < 0)
|
||||||
|
return -1;
|
||||||
|
p += 2;
|
||||||
|
memmove(r->prev, p, VtScoreSize);
|
||||||
|
p += VtScoreSize;
|
||||||
|
|
||||||
|
assert(p-op == VtRootSize);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
155
src/libventi/rpc.c
Normal file
155
src/libventi/rpc.c
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* Multiplexed Venti client. It would be nice if we
|
||||||
|
* could turn this into a generic library routine rather
|
||||||
|
* than keep it Venti specific. A user-level 9P client
|
||||||
|
* could use something like this too.
|
||||||
|
*
|
||||||
|
* This is a little more complicated than it might be
|
||||||
|
* because we want it to work well within and without libthread.
|
||||||
|
*
|
||||||
|
* The mux code is inspired by tra's, which is inspired by the Plan 9 kernel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
typedef struct Rwait Rwait;
|
||||||
|
struct Rwait
|
||||||
|
{
|
||||||
|
Rendez r;
|
||||||
|
Packet *p;
|
||||||
|
int done;
|
||||||
|
int sleeping;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int gettag(VtConn*, Rwait*);
|
||||||
|
static void puttag(VtConn*, Rwait*, int);
|
||||||
|
static void muxrpc(VtConn*, Packet*);
|
||||||
|
Packet *vtrpc(VtConn*, Packet*);
|
||||||
|
|
||||||
|
Packet*
|
||||||
|
vtrpc(VtConn *z, Packet *p)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uchar tag, buf[2], *top;
|
||||||
|
Rwait *r;
|
||||||
|
|
||||||
|
/* must malloc because stack could be private */
|
||||||
|
r = vtmallocz(sizeof(Rwait));
|
||||||
|
|
||||||
|
qlock(&z->lk);
|
||||||
|
r->r.l = &z->lk;
|
||||||
|
tag = gettag(z, r);
|
||||||
|
|
||||||
|
/* slam tag into packet */
|
||||||
|
top = packetpeek(p, buf, 0, 2);
|
||||||
|
if(top == nil){
|
||||||
|
packetfree(p);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(top == buf){
|
||||||
|
werrstr("first two bytes must be in same packet fragment");
|
||||||
|
packetfree(p);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
top[1] = tag;
|
||||||
|
qunlock(&z->lk);
|
||||||
|
if(vtsend(z, p) < 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
qlock(&z->lk);
|
||||||
|
/* wait for the muxer to give us our packet */
|
||||||
|
r->sleeping = 1;
|
||||||
|
z->nsleep++;
|
||||||
|
while(z->muxer && !r->done)
|
||||||
|
rsleep(&r->r);
|
||||||
|
z->nsleep--;
|
||||||
|
r->sleeping = 0;
|
||||||
|
|
||||||
|
/* if not done, there's no muxer: start muxing */
|
||||||
|
if(!r->done){
|
||||||
|
if(z->muxer)
|
||||||
|
abort();
|
||||||
|
z->muxer = 1;
|
||||||
|
while(!r->done){
|
||||||
|
qunlock(&z->lk);
|
||||||
|
if((p = vtrecv(z)) == nil){
|
||||||
|
z->muxer = 0;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
qlock(&z->lk);
|
||||||
|
muxrpc(z, p);
|
||||||
|
}
|
||||||
|
z->muxer = 0;
|
||||||
|
/* if there is anyone else sleeping, wake them to mux */
|
||||||
|
if(z->nsleep){
|
||||||
|
for(i=0; i<256; i++)
|
||||||
|
if(z->wait[i] != nil && ((Rwait*)z->wait[i])->sleeping)
|
||||||
|
break;
|
||||||
|
if(i==256)
|
||||||
|
fprint(2, "libventi: nsleep botch\n");
|
||||||
|
else
|
||||||
|
rwakeup(&((Rwait*)z->wait[i])->r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p = r->p;
|
||||||
|
puttag(z, r, tag);
|
||||||
|
vtfree(r);
|
||||||
|
qunlock(&z->lk);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gettag(VtConn *z, Rwait *r)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
Again:
|
||||||
|
while(z->ntag == 256)
|
||||||
|
rsleep(&z->tagrend);
|
||||||
|
for(i=0; i<256; i++)
|
||||||
|
if(z->wait[i] == 0){
|
||||||
|
z->ntag++;
|
||||||
|
z->wait[i] = r;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
fprint(2, "libventi: ntag botch\n");
|
||||||
|
goto Again;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
puttag(VtConn *z, Rwait *r, int tag)
|
||||||
|
{
|
||||||
|
assert(z->wait[tag] == r);
|
||||||
|
z->wait[tag] = nil;
|
||||||
|
z->ntag--;
|
||||||
|
rwakeup(&z->tagrend);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
muxrpc(VtConn *z, Packet *p)
|
||||||
|
{
|
||||||
|
uchar tag, buf[2], *top;
|
||||||
|
Rwait *r;
|
||||||
|
|
||||||
|
if((top = packetpeek(p, buf, 0, 2)) == nil){
|
||||||
|
fprint(2, "libventi: short packet in vtrpc\n");
|
||||||
|
packetfree(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = top[1];
|
||||||
|
if((r = z->wait[tag]) == nil){
|
||||||
|
fprint(2, "libventi: unexpected packet tag %d in vtrpc\n", tag);
|
||||||
|
abort();
|
||||||
|
packetfree(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->p = p;
|
||||||
|
r->done = 1;
|
||||||
|
rwakeup(&r->r);
|
||||||
|
}
|
||||||
|
|
||||||
18
src/libventi/scorefmt.c
Normal file
18
src/libventi/scorefmt.c
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
vtscorefmt(Fmt *f)
|
||||||
|
{
|
||||||
|
uchar *v;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
v = va_arg(f->args, uchar*);
|
||||||
|
if(v == nil)
|
||||||
|
fmtprint(f, "*");
|
||||||
|
else
|
||||||
|
for(i = 0; i < VtScoreSize; i++)
|
||||||
|
fmtprint(f, "%2.2ux", v[i]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
212
src/libventi/send.c
Normal file
212
src/libventi/send.c
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
_vtsend(VtConn *z, Packet *p)
|
||||||
|
{
|
||||||
|
IOchunk ioc;
|
||||||
|
int n;
|
||||||
|
uchar buf[2];
|
||||||
|
|
||||||
|
if(z->state != VtStateConnected) {
|
||||||
|
werrstr("session not connected");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add framing */
|
||||||
|
n = packetsize(p);
|
||||||
|
if(n >= (1<<16)) {
|
||||||
|
werrstr("packet too large");
|
||||||
|
packetfree(p);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf[0] = n>>8;
|
||||||
|
buf[1] = n;
|
||||||
|
packetprefix(p, buf, 2);
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
n = packetfragments(p, &ioc, 1, 0);
|
||||||
|
if(n == 0)
|
||||||
|
break;
|
||||||
|
if(write(z->outfd, ioc.addr, ioc.len) < ioc.len){
|
||||||
|
packetfree(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
packetconsume(p, nil, ioc.len);
|
||||||
|
}
|
||||||
|
packetfree(p);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Packet*
|
||||||
|
_vtrecv(VtConn *z)
|
||||||
|
{
|
||||||
|
uchar buf[10], *b;
|
||||||
|
int n;
|
||||||
|
Packet *p;
|
||||||
|
int size, len;
|
||||||
|
|
||||||
|
if(z->state != VtStateConnected) {
|
||||||
|
werrstr("session not connected");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = z->part;
|
||||||
|
/* get enough for head size */
|
||||||
|
size = packetsize(p);
|
||||||
|
while(size < 2) {
|
||||||
|
b = packettrailer(p, MaxFragSize);
|
||||||
|
assert(b != nil);
|
||||||
|
n = read(z->infd, b, MaxFragSize);
|
||||||
|
if(n <= 0)
|
||||||
|
goto Err;
|
||||||
|
size += n;
|
||||||
|
packettrim(p, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(packetconsume(p, buf, 2) < 0)
|
||||||
|
goto Err;
|
||||||
|
len = (buf[0] << 8) | buf[1];
|
||||||
|
size -= 2;
|
||||||
|
|
||||||
|
while(size < len) {
|
||||||
|
n = len - size;
|
||||||
|
if(n > MaxFragSize)
|
||||||
|
n = MaxFragSize;
|
||||||
|
b = packettrailer(p, n);
|
||||||
|
if(readn(z->infd, b, n) != n)
|
||||||
|
goto Err;
|
||||||
|
size += n;
|
||||||
|
}
|
||||||
|
p = packetsplit(p, len);
|
||||||
|
return p;
|
||||||
|
Err:
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If you fork off two procs running vtrecvproc and vtsendproc,
|
||||||
|
* then vtrecv/vtsend (and thus vtrpc) will never block except on
|
||||||
|
* rendevouses, which is nice when it's running in one thread of many.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
vtrecvproc(void *v)
|
||||||
|
{
|
||||||
|
Packet *p;
|
||||||
|
VtConn *z;
|
||||||
|
Queue *q;
|
||||||
|
|
||||||
|
z = v;
|
||||||
|
q = _vtqalloc();
|
||||||
|
|
||||||
|
qlock(&z->lk);
|
||||||
|
z->readq = q;
|
||||||
|
qlock(&z->inlk);
|
||||||
|
rwakeup(&z->rpcfork);
|
||||||
|
qunlock(&z->lk);
|
||||||
|
|
||||||
|
while((p = _vtrecv(z)) != nil)
|
||||||
|
if(_vtqsend(q, p) < 0){
|
||||||
|
packetfree(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
qunlock(&z->inlk);
|
||||||
|
qlock(&z->lk);
|
||||||
|
_vtqhangup(q);
|
||||||
|
while((p = _vtnbqrecv(q)) != nil)
|
||||||
|
packetfree(p);
|
||||||
|
vtfree(q);
|
||||||
|
z->readq = nil;
|
||||||
|
rwakeup(&z->rpcfork);
|
||||||
|
qunlock(&z->lk);
|
||||||
|
vthangup(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vtsendproc(void *v)
|
||||||
|
{
|
||||||
|
Queue *q;
|
||||||
|
Packet *p;
|
||||||
|
VtConn *z;
|
||||||
|
|
||||||
|
z = v;
|
||||||
|
q = _vtqalloc();
|
||||||
|
|
||||||
|
qlock(&z->lk);
|
||||||
|
z->writeq = q;
|
||||||
|
qlock(&z->outlk);
|
||||||
|
rwakeup(&z->rpcfork);
|
||||||
|
qunlock(&z->lk);
|
||||||
|
|
||||||
|
while((p = _vtqrecv(q)) != nil)
|
||||||
|
if(_vtsend(z, p) < 0)
|
||||||
|
break;
|
||||||
|
qunlock(&z->outlk);
|
||||||
|
qlock(&z->lk);
|
||||||
|
_vtqhangup(q);
|
||||||
|
while((p = _vtnbqrecv(q)) != nil)
|
||||||
|
packetfree(p);
|
||||||
|
vtfree(q);
|
||||||
|
z->writeq = nil;
|
||||||
|
rwakeup(&z->rpcfork);
|
||||||
|
qunlock(&z->lk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet*
|
||||||
|
vtrecv(VtConn *z)
|
||||||
|
{
|
||||||
|
Packet *p;
|
||||||
|
|
||||||
|
qlock(&z->lk);
|
||||||
|
if(z->state != VtStateConnected){
|
||||||
|
werrstr("not connected");
|
||||||
|
qunlock(&z->lk);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(z->readq){
|
||||||
|
qunlock(&z->lk);
|
||||||
|
return _vtqrecv(z->readq);
|
||||||
|
}
|
||||||
|
|
||||||
|
qlock(&z->inlk);
|
||||||
|
qunlock(&z->lk);
|
||||||
|
p = _vtrecv(z);
|
||||||
|
qunlock(&z->inlk);
|
||||||
|
if(!p)
|
||||||
|
vthangup(z);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtsend(VtConn *z, Packet *p)
|
||||||
|
{
|
||||||
|
qlock(&z->lk);
|
||||||
|
if(z->state != VtStateConnected){
|
||||||
|
packetfree(p);
|
||||||
|
werrstr("not connected");
|
||||||
|
qunlock(&z->lk);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(z->writeq){
|
||||||
|
qunlock(&z->lk);
|
||||||
|
if(_vtqsend(z->writeq, p) < 0){
|
||||||
|
packetfree(p);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qlock(&z->outlk);
|
||||||
|
qunlock(&z->lk);
|
||||||
|
if(_vtsend(z, p) < 0){
|
||||||
|
qunlock(&z->outlk);
|
||||||
|
vthangup(z);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
qunlock(&z->outlk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
172
src/libventi/server.c
Normal file
172
src/libventi/server.c
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STACK = 8192,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct VtSconn VtSconn;
|
||||||
|
struct VtSconn
|
||||||
|
{
|
||||||
|
int ctl;
|
||||||
|
char dir[NETPATHLEN];
|
||||||
|
VtSrv *srv;
|
||||||
|
VtConn *c;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VtSrv
|
||||||
|
{
|
||||||
|
int afd;
|
||||||
|
int dead;
|
||||||
|
char adir[NETPATHLEN];
|
||||||
|
Queue *q; /* Queue(VtReq*) */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void listenproc(void*);
|
||||||
|
static void connproc(void*);
|
||||||
|
|
||||||
|
VtSrv*
|
||||||
|
vtlisten(char *addr)
|
||||||
|
{
|
||||||
|
VtSrv *s;
|
||||||
|
|
||||||
|
s = vtmallocz(sizeof(VtSrv));
|
||||||
|
s->afd = announce(addr, s->adir);
|
||||||
|
if(s->afd < 0){
|
||||||
|
free(s);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
s->q = _vtqalloc();
|
||||||
|
proccreate(listenproc, s, STACK);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
listenproc(void *v)
|
||||||
|
{
|
||||||
|
int ctl;
|
||||||
|
char dir[NETPATHLEN];
|
||||||
|
VtSrv *srv;
|
||||||
|
VtSconn *sc;
|
||||||
|
|
||||||
|
srv = v;
|
||||||
|
for(;;){
|
||||||
|
ctl = listen(srv->adir, dir);
|
||||||
|
if(ctl < 0){
|
||||||
|
srv->dead = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sc = vtmallocz(sizeof(VtSconn));
|
||||||
|
sc->ctl = ctl;
|
||||||
|
sc->srv = srv;
|
||||||
|
strcpy(sc->dir, dir);
|
||||||
|
proccreate(connproc, sc, STACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hangup
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
connproc(void *v)
|
||||||
|
{
|
||||||
|
VtSconn *sc;
|
||||||
|
VtConn *c;
|
||||||
|
Packet *p;
|
||||||
|
VtReq *r;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
r = nil;
|
||||||
|
c = nil;
|
||||||
|
sc = v;
|
||||||
|
fprint(2, "new call %s on %d\n", sc->dir, sc->ctl);
|
||||||
|
fd = accept(sc->ctl, sc->dir);
|
||||||
|
close(sc->ctl);
|
||||||
|
if(fd < 0){
|
||||||
|
fprint(2, "accept %s: %r\n", sc->dir);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = vtconn(fd, fd);
|
||||||
|
sc->c = c;
|
||||||
|
if(vtversion(c) < 0){
|
||||||
|
fprint(2, "vtversion %s: %r\n", sc->dir);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(vtsrvhello(c) < 0){
|
||||||
|
fprint(2, "vtsrvhello %s: %r\n", sc->dir);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprint(2, "new proc %s\n", sc->dir);
|
||||||
|
proccreate(vtsendproc, c, STACK);
|
||||||
|
qlock(&c->lk);
|
||||||
|
while(!c->writeq)
|
||||||
|
rsleep(&c->rpcfork);
|
||||||
|
qunlock(&c->lk);
|
||||||
|
|
||||||
|
while((p = vtrecv(c)) != nil){
|
||||||
|
r = vtmallocz(sizeof(VtReq));
|
||||||
|
if(vtfcallunpack(&r->tx, p) < 0){
|
||||||
|
packetfree(p);
|
||||||
|
fprint(2, "bad packet on %s: %r\n", sc->dir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
packetfree(p);
|
||||||
|
if(r->tx.type == VtTgoodbye)
|
||||||
|
break;
|
||||||
|
r->rx.tag = r->tx.tag;
|
||||||
|
r->sc = sc;
|
||||||
|
if(_vtqsend(sc->srv->q, r) < 0){
|
||||||
|
fprint(2, "hungup queue\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprint(2, "eof on %s\n", sc->dir);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if(r){
|
||||||
|
vtfcallclear(&r->tx);
|
||||||
|
vtfree(r);
|
||||||
|
}
|
||||||
|
if(c)
|
||||||
|
vtfreeconn(c);
|
||||||
|
fprint(2, "freed %s\n", sc->dir);
|
||||||
|
vtfree(sc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VtReq*
|
||||||
|
vtgetreq(VtSrv *srv)
|
||||||
|
{
|
||||||
|
return _vtqrecv(srv->q);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vtrespond(VtReq *r)
|
||||||
|
{
|
||||||
|
Packet *p;
|
||||||
|
VtSconn *sc;
|
||||||
|
|
||||||
|
sc = r->sc;
|
||||||
|
if(r->rx.tag != r->tx.tag)
|
||||||
|
abort();
|
||||||
|
if(r->rx.type != r->tx.type+1 && r->rx.type != VtRerror)
|
||||||
|
abort();
|
||||||
|
if((p = vtfcallpack(&r->rx)) == nil){
|
||||||
|
fprint(2, "fcallpack on %s: %r\n", sc->dir);
|
||||||
|
packetfree(p);
|
||||||
|
vtfcallclear(&r->rx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vtsend(sc->c, p);
|
||||||
|
vtfcallclear(&r->tx);
|
||||||
|
vtfcallclear(&r->rx);
|
||||||
|
vtfree(r);
|
||||||
|
}
|
||||||
|
|
||||||
50
src/libventi/srvhello.c
Normal file
50
src/libventi/srvhello.c
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
vtsrvhello(VtConn *z)
|
||||||
|
{
|
||||||
|
VtFcall tx, rx;
|
||||||
|
Packet *p;
|
||||||
|
|
||||||
|
if((p = vtrecv(z)) == nil)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(vtfcallunpack(&tx, p) < 0){
|
||||||
|
packetfree(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
packetfree(p);
|
||||||
|
|
||||||
|
if(tx.type != VtThello){
|
||||||
|
vtfcallclear(&tx);
|
||||||
|
werrstr("bad packet type %d; want Thello %d", tx.type, VtThello);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(tx.tag != 0){
|
||||||
|
vtfcallclear(&tx);
|
||||||
|
werrstr("bad tag in hello");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(strcmp(tx.version, z->version) != 0){
|
||||||
|
vtfcallclear(&tx);
|
||||||
|
werrstr("bad version in hello");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
vtfree(z->uid);
|
||||||
|
z->uid = tx.uid;
|
||||||
|
tx.uid = nil;
|
||||||
|
vtfcallclear(&tx);
|
||||||
|
|
||||||
|
memset(&rx, 0, sizeof rx);
|
||||||
|
rx.type = VtRhello;
|
||||||
|
rx.tag = tx.tag;
|
||||||
|
rx.sid = "anonymous";
|
||||||
|
if((p = vtfcallpack(&rx)) == nil)
|
||||||
|
return 0;
|
||||||
|
if(vtsend(z, p) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
18
src/libventi/strdup.c
Normal file
18
src/libventi/strdup.c
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
char*
|
||||||
|
vtstrdup(char *s)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char *ss;
|
||||||
|
|
||||||
|
if(s == nil)
|
||||||
|
return nil;
|
||||||
|
n = strlen(s) + 1;
|
||||||
|
ss = vtmalloc(n);
|
||||||
|
memmove(ss, s, n);
|
||||||
|
return ss;
|
||||||
|
}
|
||||||
|
|
||||||
50
src/libventi/string.c
Normal file
50
src/libventi/string.c
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
vtputstring(Packet *p, char *s)
|
||||||
|
{
|
||||||
|
uchar buf[2];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if(s == nil){
|
||||||
|
werrstr("null string in packet");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = strlen(s);
|
||||||
|
if(n > VtMaxStringSize){
|
||||||
|
werrstr("string too long in packet");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf[0] = n>>8;
|
||||||
|
buf[1] = n;
|
||||||
|
packetappend(p, buf, 2);
|
||||||
|
packetappend(p, (uchar*)s, n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtgetstring(Packet *p, char **ps)
|
||||||
|
{
|
||||||
|
uchar buf[2];
|
||||||
|
int n;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if(packetconsume(p, buf, 2) < 0)
|
||||||
|
return -1;
|
||||||
|
n = (buf[0]<<8) + buf[1];
|
||||||
|
if(n > VtMaxStringSize) {
|
||||||
|
werrstr("string too long in packet");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
s = vtmalloc(n+1);
|
||||||
|
if(packetconsume(p, (uchar*)s, n) < 0){
|
||||||
|
vtfree(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
s[n] = 0;
|
||||||
|
*ps = s;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
115
src/libventi/version.c
Normal file
115
src/libventi/version.c
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
static char *okvers[] = {
|
||||||
|
"02",
|
||||||
|
nil,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
static char EBigString[] = "string too long";
|
||||||
|
static char EBigPacket[] = "packet too long";
|
||||||
|
static char ENullString[] = "missing string";
|
||||||
|
*/
|
||||||
|
static char EBadVersion[] = "bad format in version string";
|
||||||
|
|
||||||
|
static int
|
||||||
|
vtreadversion(VtConn *z, char *q, char *v, int nv)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
if(nv <= 1){
|
||||||
|
werrstr("version too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = read(z->infd, v, 1);
|
||||||
|
if(n <= 0){
|
||||||
|
if(n == 0)
|
||||||
|
werrstr("unexpected eof");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(*v == '\n'){
|
||||||
|
*v = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if((uchar)*v < ' ' || (uchar)*v > 0x7f || (*q && *v != *q)){
|
||||||
|
werrstr(EBadVersion);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
v++;
|
||||||
|
nv--;
|
||||||
|
if(*q)
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vtversion(VtConn *z)
|
||||||
|
{
|
||||||
|
char buf[VtMaxStringSize], *p, *ep, *prefix, *pp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
qlock(&z->lk);
|
||||||
|
if(z->state != VtStateAlloc){
|
||||||
|
werrstr("bad session state");
|
||||||
|
qunlock(&z->lk);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qlock(&z->inlk);
|
||||||
|
qlock(&z->outlk);
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
ep = buf + sizeof buf;
|
||||||
|
prefix = "venti-";
|
||||||
|
p = seprint(p, ep, "%s", prefix);
|
||||||
|
p += strlen(p);
|
||||||
|
for(i=0; okvers[i]; i++)
|
||||||
|
p = seprint(p, ep, "%s%s", i ? ":" : "", okvers[i]);
|
||||||
|
p = seprint(p, ep, "-libventi\n");
|
||||||
|
assert(p-buf < sizeof buf);
|
||||||
|
|
||||||
|
if(write(z->outfd, buf, p-buf) != p-buf)
|
||||||
|
goto Err;
|
||||||
|
vtdebug(z, "version string out: %s", buf);
|
||||||
|
|
||||||
|
if(vtreadversion(z, prefix, buf, sizeof buf) < 0)
|
||||||
|
goto Err;
|
||||||
|
vtdebug(z, "version string in: %s", buf);
|
||||||
|
|
||||||
|
p = buf+strlen(prefix);
|
||||||
|
for(;;){
|
||||||
|
pp = strpbrk(p, ":-");
|
||||||
|
for(i=0; okvers[i]; i++)
|
||||||
|
if(strlen(okvers[i]) == pp-p && memcmp(okvers[i], p, pp-p) == 0){
|
||||||
|
*pp = 0;
|
||||||
|
z->version = vtstrdup(p);
|
||||||
|
goto Okay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
werrstr("unable to negotiate version");
|
||||||
|
goto Err;
|
||||||
|
|
||||||
|
Okay:
|
||||||
|
z->state = VtStateConnected;
|
||||||
|
qunlock(&z->inlk);
|
||||||
|
qunlock(&z->outlk);
|
||||||
|
qunlock(&z->lk);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Err:
|
||||||
|
if(z->infd >= 0)
|
||||||
|
close(z->infd);
|
||||||
|
if(z->outfd >= 0 && z->outfd != z->infd)
|
||||||
|
close(z->outfd);
|
||||||
|
z->infd = -1;
|
||||||
|
z->outfd = -1;
|
||||||
|
z->state = VtStateClosed;
|
||||||
|
qunlock(&z->inlk);
|
||||||
|
qunlock(&z->outlk);
|
||||||
|
qunlock(&z->lk);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
55
src/libventi/zero.c
Normal file
55
src/libventi/zero.c
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
vtzeroextend(int type, uchar *buf, uint n, uint nn)
|
||||||
|
{
|
||||||
|
uchar *p, *ep;
|
||||||
|
|
||||||
|
switch(type&7) {
|
||||||
|
case 0:
|
||||||
|
memset(buf+n, 0, nn-n);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
p = buf + (n/VtScoreSize)*VtScoreSize;
|
||||||
|
ep = buf + (nn/VtScoreSize)*VtScoreSize;
|
||||||
|
while(p < ep) {
|
||||||
|
memmove(p, vtzeroscore, VtScoreSize);
|
||||||
|
p += VtScoreSize;
|
||||||
|
}
|
||||||
|
memset(p, 0, buf+nn-p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
vtzerotruncate(int type, uchar *buf, uint n)
|
||||||
|
{
|
||||||
|
uchar *p;
|
||||||
|
|
||||||
|
if(type == VtRootType){
|
||||||
|
if(n < VtRootSize)
|
||||||
|
return n;
|
||||||
|
return VtRootSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(type&7){
|
||||||
|
case 0:
|
||||||
|
for(p = buf + n; p > buf; p--) {
|
||||||
|
if(p[-1] != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return p - buf;
|
||||||
|
default:
|
||||||
|
/* ignore slop at end of block */
|
||||||
|
p = buf + (n/VtScoreSize)*VtScoreSize;
|
||||||
|
|
||||||
|
while(p > buf) {
|
||||||
|
if(memcmp(p - VtScoreSize, vtzeroscore, VtScoreSize) != 0)
|
||||||
|
break;
|
||||||
|
p -= VtScoreSize;
|
||||||
|
}
|
||||||
|
return p - buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/libventi/zeroscore.c
Normal file
10
src/libventi/zeroscore.c
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <venti.h>
|
||||||
|
|
||||||
|
/* score of a zero length block */
|
||||||
|
uchar vtzeroscore[VtScoreSize] = {
|
||||||
|
0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
|
||||||
|
0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09
|
||||||
|
};
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue