tlibventi: protocol support for blocks larger than 64k - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 33b446b8bbfea80552d462296d27ad4114fbd3fb
 (DIR) parent 9cac97f2c55efc9ffa9b3894127e049cc25852a3
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Mon, 25 May 2009 00:30:17 -0700
       
       libventi: protocol support for blocks larger than 64k
       
       Diffstat:
         M include/venti.h                     |       2 +-
         M man/man7/venti.7                    |      15 +++++++++++++++
         M src/libventi/client.c               |       4 ++++
         M src/libventi/fcall.c                |      33 +++++++++++++++++++++++++------
         M src/libventi/send.c                 |      47 ++++++++++++++++++++-----------
         M src/libventi/version.c              |       1 +
       
       6 files changed, 79 insertions(+), 23 deletions(-)
       ---
 (DIR) diff --git a/include/venti.h b/include/venti.h
       t@@ -292,7 +292,7 @@ struct VtFcall
                uint        nauth;                /* TauthX, RauthX */
                uchar        score[VtScoreSize];        /* Tread, Rwrite */
                uchar        blocktype;                /* Tread, Twrite */
       -        ushort        count;                /* Tread */
       +        uint        count;                /* Tread */
                Packet        *data;                /* Rread, Twrite */
        };
        
 (DIR) diff --git a/man/man7/venti.7 b/man/man7/venti.7
       t@@ -441,6 +441,21 @@ message ends a session.  There is no
        upon receiving the
        .BR VtTgoodbye
        message, the server terminates up the connection.
       +.PP
       +Version
       +.B 04
       +of the Venti protocol is similar to version
       +.B 02
       +(described above)
       +but has two changes to accomodates larger payloads.
       +First, it replaces the leading 2-byte packet size with
       +a 4-byte size.
       +Second, the
       +.I count
       +in the
       +.B VtTread
       +packet may be either 2 or 4 bytes;
       +the total packet length distinguishes the two cases.
        .SH SEE ALSO
        .IR venti (1),
        .IR venti (3),
 (DIR) diff --git a/src/libventi/client.c b/src/libventi/client.c
       t@@ -65,6 +65,10 @@ vtreadpacket(VtConn *z, uchar score[VtScoreSize], uint type, int n)
                if(memcmp(score, vtzeroscore, VtScoreSize) == 0)
                        return packetalloc();
        
       +        if(z->version[1] == '2' && n >= (1<<16)) {
       +                werrstr("read count too large for protocol");
       +                return nil;
       +        }
                memset(&tx, 0, sizeof tx);
                tx.msgtype = VtTread;
                tx.blocktype = type;
 (DIR) diff --git a/src/libventi/fcall.c b/src/libventi/fcall.c
       t@@ -5,7 +5,7 @@
        Packet*
        vtfcallpack(VtFcall *f)
        {
       -        uchar buf[4];
       +        uchar buf[10];
                Packet *p;
        
                p = packetalloc();
       t@@ -60,9 +60,17 @@ vtfcallpack(VtFcall *f)
                        if(~buf[0] == 0)
                                goto Err;
                        buf[1] = 0;
       -                buf[2] = f->count >> 8;
       -                buf[3] = f->count;
       -                packetappend(p, buf, 4);
       +                if(f->count >= (1<<16)) {
       +                        buf[2] = f->count >> 24;
       +                        buf[3] = f->count >> 16;
       +                        buf[4] = f->count >> 8;
       +                        buf[5] = f->count;
       +                        packetappend(p, buf, 6);
       +                } else {
       +                        buf[2] = f->count >> 8;
       +                        buf[3] = f->count;
       +                        packetappend(p, buf, 4);
       +                }
                        break;
        
                case VtRread:
       t@@ -163,12 +171,25 @@ vtfcallunpack(VtFcall *f, Packet *p)
        
                case VtTread:
                        if(packetconsume(p, f->score, VtScoreSize) < 0
       -                || packetconsume(p, buf, 4) < 0)
       +                || packetconsume(p, buf, 2) < 0)
                                goto Err;
                        f->blocktype = vtfromdisktype(buf[0]);
                        if(~f->blocktype == 0)
                                goto Err;
       -                f->count = (buf[2] << 8) | buf[3];
       +                switch(packetsize(p)) {
       +                default:
       +                        goto Err;
       +                case 2:
       +                        if(packetconsume(p, buf, 2) < 0)
       +                                goto Err;
       +                        f->count = (buf[2] << 8) | buf[3];
       +                        break;
       +                case 4:
       +                        if(packetconsume(p, buf, 4) < 0)
       +                                goto Err;
       +                        f->count = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
       +                        break;
       +                }
                        break;
        
                case VtRread:
 (DIR) diff --git a/src/libventi/send.c b/src/libventi/send.c
       t@@ -11,7 +11,7 @@ _vtsend(VtConn *z, Packet *p)
        {
                IOchunk ioc;
                int n, tot;
       -        uchar buf[2];
       +        uchar buf[4];
        
                if(z->state != VtStateConnected) {
                        werrstr("session not connected");
       t@@ -20,15 +20,24 @@ _vtsend(VtConn *z, Packet *p)
        
                /* add framing */
                n = packetsize(p);
       -        if(n >= (1<<16)) {
       -                werrstr("packet too large");
       -                packetfree(p);
       -                return -1;
       +        if(z->version[1] == '2') {
       +                if(n >= (1<<16)) {
       +                        werrstr("packet too large");
       +                        packetfree(p);
       +                        return -1;
       +                }
       +                buf[0] = n>>8;
       +                buf[1] = n;
       +                packetprefix(p, buf, 2);
       +                ventisendbytes += n+2;
       +        } else {
       +                buf[0] = n>>24;
       +                buf[1] = n>>16;
       +                buf[2] = n>>8;
       +                buf[3] = n;
       +                packetprefix(p, buf, 4);
       +                ventisendbytes += n+4;
                }
       -        buf[0] = n>>8;
       -        buf[1] = n;
       -        packetprefix(p, buf, 2);
       -        ventisendbytes += n+2;
                ventisendpackets++;
        
                tot = 0;
       t@@ -63,7 +72,7 @@ static Packet*
        _vtrecv(VtConn *z)
        {
                uchar buf[10], *b;
       -        int n;
       +        int n, need;
                Packet *p;
                int size, len;
        
       t@@ -75,11 +84,12 @@ _vtrecv(VtConn *z)
                p = z->part;
                /* get enough for head size */
                size = packetsize(p);
       -        while(size < 2) {
       -                b = packettrailer(p, 2);
       +        need = z->version[1] - '0';        // 2 or 4
       +        while(size < need) {
       +                b = packettrailer(p, need);
                        assert(b != nil);
                        if(0) fprint(2, "%d read hdr\n", getpid());
       -                n = read(z->infd, b, 2);
       +                n = read(z->infd, b, need);
                        if(0) fprint(2, "%d got %d (%r)\n", getpid(), n);
                        if(n==0 || (n<0 && !interrupted()))
                                goto Err;
       t@@ -87,10 +97,15 @@ _vtrecv(VtConn *z)
                        packettrim(p, 0, size);
                }
        
       -        if(packetconsume(p, buf, 2) < 0)
       +        if(packetconsume(p, buf, need) < 0)
                        goto Err;
       -        len = (buf[0] << 8) | buf[1];
       -        size -= 2;
       +        if(z->version[1] == '2') {
       +                len = (buf[0] << 8) | buf[1];
       +                size -= 2;
       +        } else {
       +                len = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
       +                size -= 4;
       +        }
        
                while(size < len) {
                        n = len - size;
 (DIR) diff --git a/src/libventi/version.c b/src/libventi/version.c
       t@@ -3,6 +3,7 @@
        #include <venti.h>
        
        static char *okvers[] = {
       +        "04",
                "02",
                nil,
        };