Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "vnc.h"

#define SHORT(p) (((p)[0]<<8)|((p)[1]))
#define LONG(p) ((SHORT(p)<<16)|SHORT(p+2))

uchar zero[64];

Vnc*
vncinit(int fd, int cfd, Vnc *v)
{
        if(v == nil)
                v = mallocz(sizeof(*v), 1);
        Binit(&v->in, fd, OREAD);
        Binit(&v->out, fd, OWRITE);
        v->datafd = fd;
        v->ctlfd = cfd;
        return v;
}

void
vncterm(Vnc *v)
{
        Bterm(&v->out);
        Bterm(&v->in);
}

void
vncflush(Vnc *v)
{
        if(Bflush(&v->out) < 0){
                if(verbose > 1)
                        fprint(2, "hungup while sending flush: %r\n");
                vnchungup(v);
        }
}

uchar
vncrdchar(Vnc *v)
{
        uchar buf[1];

        vncrdbytes(v, buf, 1);
        return buf[0];
}

ushort
vncrdshort(Vnc *v)
{
        uchar buf[2];

        vncrdbytes(v, buf, 2);
        return SHORT(buf);
}

ulong
vncrdlong(Vnc *v)
{
        uchar buf[4];

        vncrdbytes(v, buf, 4);
        return LONG(buf);
}

Point
vncrdpoint(Vnc *v)
{
        Point p;

        p.x = vncrdshort(v);
        p.y = vncrdshort(v);
        return p;
}

Rectangle
vncrdrect(Vnc *v)
{
        Rectangle r;

        r.min.x = vncrdshort(v);
        r.min.y = vncrdshort(v);
        r.max.x = r.min.x + vncrdshort(v);
        r.max.y = r.min.y + vncrdshort(v);
        return r;
}

Rectangle
vncrdcorect(Vnc *v)
{
        Rectangle r;

        r.min.x = vncrdchar(v);
        r.min.y = vncrdchar(v);
        r.max.x = r.min.x + vncrdchar(v);
        r.max.y = r.min.y + vncrdchar(v);
        return r;
}

void
vncrdbytes(Vnc *v, void *a, int n)
{
        if(Bread(&v->in, a, n) != n){
                if(verbose > 1)
                        fprint(2, "hungup while reading\n");
                vnchungup(v);
        }
}

Pixfmt
vncrdpixfmt(Vnc *v)
{
        Pixfmt fmt;
        uchar pad[3];

        fmt.bpp = vncrdchar(v);
        fmt.depth = vncrdchar(v);
        fmt.bigendian = vncrdchar(v);
        fmt.truecolor = vncrdchar(v);
        fmt.red.max = vncrdshort(v);
        fmt.green.max = vncrdshort(v);
        fmt.blue.max = vncrdshort(v);
        fmt.red.shift = vncrdchar(v);
        fmt.green.shift = vncrdchar(v);
        fmt.blue.shift = vncrdchar(v);
        vncrdbytes(v, pad, 3);
        return fmt;
}

char*
vncrdstring(Vnc *v)
{
        ulong len;
        char *s;

        len = vncrdlong(v);
        s = malloc(len+1);
        assert(s != nil);

        vncrdbytes(v, s, len);
        s[len] = '\0';
        return s;
}

/*
 * on the server side of the negotiation protocol, we read
 * the client response and then run the negotiated function.
 * in some cases (e.g., TLS) the negotiated function needs to
 * use v->datafd directly and be sure that no data has been
 * buffered away in the Bio.  since we know the client is waiting
 * for our response, it won't have sent any until we respond.
 * thus we read the response with vncrdstringx, which goes
 * behind bio's back.
 */
char*
vncrdstringx(Vnc *v)
{
        char tmp[4];
        char *s;
        ulong len;

        assert(Bbuffered(&v->in) == 0);
        if(readn(v->datafd, tmp, 4) != 4){
                fprint(2, "cannot rdstringx: %r");
                vnchungup(v);
        }
        len = LONG(tmp);
        s = malloc(len+1);
        assert(s != nil);
        if(readn(v->datafd, s, len) != len){
                fprint(2, "cannot rdstringx len %lud: %r", len);
                vnchungup(v);
        }
        s[len] = '\0';
        return s;
}

void
vncwrstring(Vnc *v, char *s)
{
        ulong len;

        len = strlen(s);
        vncwrlong(v, len);
        vncwrbytes(v, s, len);
}

void
vncwrbytes(Vnc *v, void *a, int n)
{
        if(Bwrite(&v->out, a, n) < 0){
                if(verbose > 1) 
                        fprint(2, "hungup while writing bytes\n");
                vnchungup(v);
        }
}

void
vncwrlong(Vnc *v, ulong u)
{
        uchar buf[4];

        buf[0] = u>>24;
        buf[1] = u>>16;
        buf[2] = u>>8;
        buf[3] = u;
        vncwrbytes(v, buf, 4);
}

void
vncwrshort(Vnc *v, ushort u)
{
        uchar buf[2];

        buf[0] = u>>8;
        buf[1] = u;
        vncwrbytes(v, buf, 2);
}

void
vncwrchar(Vnc *v, uchar c)
{
        vncwrbytes(v, &c, 1);
}

void
vncwrpixfmt(Vnc *v, Pixfmt *fmt)
{
        vncwrchar(v, fmt->bpp);
        vncwrchar(v, fmt->depth);
        vncwrchar(v, fmt->bigendian);
        vncwrchar(v, fmt->truecolor);
        vncwrshort(v, fmt->red.max);
        vncwrshort(v, fmt->green.max);
        vncwrshort(v, fmt->blue.max);
        vncwrchar(v, fmt->red.shift);
        vncwrchar(v, fmt->green.shift);
        vncwrchar(v, fmt->blue.shift);
        vncwrbytes(v, zero, 3);
}

void
vncwrrect(Vnc *v, Rectangle r)
{
        vncwrshort(v, r.min.x);
        vncwrshort(v, r.min.y);
        vncwrshort(v, r.max.x-r.min.x);
        vncwrshort(v, r.max.y-r.min.y);
}

void
vncwrpoint(Vnc *v, Point p)
{
        vncwrshort(v, p.x);
        vncwrshort(v, p.y);
}

void
vnclock(Vnc *v)
{
        qlock(v);
}

void
vncunlock(Vnc *v)
{
        qunlock(v);
}

void
hexdump(void *a, int n)
{
        uchar *p, *ep;

        p = a;
        ep = p+n;

        for(; p<ep; p++) 
                print("%.2ux ", *p);
        print("\n");
}

void
vncgobble(Vnc *v, long n)
{
        uchar buf[8192];
        long m;

        while(n > 0){
                m = n;
                if(m > sizeof(buf))
                        m = sizeof(buf);
                vncrdbytes(v, buf, m);
                n -= m;
        }
}