/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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;} voidvncterm(Vnc *v){ Bterm(&v->out); Bterm(&v->in);} voidvncflush(Vnc *v){ if(Bflush(&v->out) < 0){ if(verbose > 1) fprint(2, "hungup while sending flush: %r\n"); vnchungup(v); }} ucharvncrdchar(Vnc *v){ uchar buf[1]; vncrdbytes(v, buf, 1); return buf[0];} ushortvncrdshort(Vnc *v){ uchar buf[2]; vncrdbytes(v, buf, 2); return SHORT(buf);} ulongvncrdlong(Vnc *v){ uchar buf[4]; vncrdbytes(v, buf, 4); return LONG(buf);} Pointvncrdpoint(Vnc *v){ Point p; p.x = vncrdshort(v); p.y = vncrdshort(v); return p;} Rectanglevncrdrect(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;} Rectanglevncrdcorect(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;} voidvncrdbytes(Vnc *v, void *a, int n){ if(Bread(&v->in, a, n) != n){ if(verbose > 1) fprint(2, "hungup while reading\n"); vnchungup(v); }} Pixfmtvncrdpixfmt(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;} voidvncwrstring(Vnc *v, char *s){ ulong len; len = strlen(s); vncwrlong(v, len); vncwrbytes(v, s, len);} voidvncwrbytes(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); }} voidvncwrlong(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);} voidvncwrshort(Vnc *v, ushort u){ uchar buf[2]; buf[0] = u>>8; buf[1] = u; vncwrbytes(v, buf, 2);} voidvncwrchar(Vnc *v, uchar c){ vncwrbytes(v, &c, 1);} voidvncwrpixfmt(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);} voidvncwrrect(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);} voidvncwrpoint(Vnc *v, Point p){ vncwrshort(v, p.x); vncwrshort(v, p.y);} voidvnclock(Vnc *v){ qlock(v);} voidvncunlock(Vnc *v){ qunlock(v);} voidhexdump(void *a, int n){ uchar *p, *ep; p = a; ep = p+n; for(; p<ep; p++) print("%.2ux ", *p); print("\n");} voidvncgobble(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; }}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#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;
}
}