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