1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099 |
- #define Image IMAGE
- #include "vnc.h"
- #include "vncs.h"
- #include "compat.h"
- #include <cursor.h>
- #include "screen.h"
- #include "kbd.h"
- #include <mp.h>
- #include <libsec.h>
- enum
- {
- MaxCorreDim = 48,
- MaxRreDim = 64,
- };
- extern Dev drawdevtab;
- extern Dev mousedevtab;
- extern Dev consdevtab;
- Dev *devtab[] =
- {
- &drawdevtab,
- &mousedevtab,
- &consdevtab,
- nil
- };
- int shared;
- int verbose = 0;
- static int worker = -1; /* pid of command we ran */
- static int srvfd;
- static int exportfd;
- static Vncs **vncpriv;
- static char *msgname[] = {
- [MPixFmt] = "MPixFmt",
- [MFixCmap] = "MFixCmap",
- [MSetEnc] = "MSetEnc",
- [MFrameReq] = "MFrameReq",
- [MKey] = "MKey",
- [MMouse] = "MMouse",
- [MCCut] = "MCCut",
- };
- static char *encname[] = {
- [EncRaw] = "raw",
- [EncCopyRect] = "copy rect",
- [EncRre] = "rre",
- [EncCorre] = "corre",
- [EncHextile] = "hextile",
- [EncZlib] = "zlib",
- [EncTight] = "zlibtight",
- [EncZHextile] = "zhextile",
- [EncMouseWarp] = "mousewarp",
- };
- static void shutdown_clients(Vncs *);
- /*
- * list head. used to hold the list, the lock, dim, and pixelfmt
- */
- Vnc clients;
- static void vnccsexiting(void);
- static int
- nbits(ulong mask)
- {
- int bit;
- if (mask == 0)
- sysfatal("nbits: invalid mask 0x%lx", mask);
- mask = ~mask;
- for (bit = 0; !(mask & 1); bit++)
- mask >>= 1;
- return bit;
- }
- struct _chan {
- uchar type;
- uchar nbits;
- Colorfmt * fmt;
- };
- #define SORT(x, y) if(x.fmt->shift < y.fmt->shift) do { chan = x; x = y; y = chan; } while(0)
- static ulong
- fmt2chan(Pixfmt * fmt)
- {
- struct _chan chans[4];
- struct _chan chan;
- int i, depth, n;
- ulong mask = 0xffffffff;
- Colorfmt xfmt;
- chans[0] = (struct _chan){CRed,0,&fmt->red};
- chans[1] = (struct _chan){CGreen,0,&fmt->green};
- chans[2] = (struct _chan){CBlue,0,&fmt->blue};
- SORT(chans[0], chans[1]);
- SORT(chans[0], chans[2]);
- SORT(chans[1], chans[2]);
- depth = 0;
- for(i = 0; i < 3; i++) {
- n = chans[i].nbits = nbits(chans[i].fmt->max);
- depth += n;
- mask &= ~(chans[i].fmt->max<<chans[i].fmt->shift);
- }
- if(fmt->bpp != depth && mask) {
- xfmt.shift = 0;
- while(!(mask & 1)) {
- xfmt.shift++;
- mask >>= 1;
- }
- xfmt.max = mask;
- chans[3] = (struct _chan){CIgnore, fmt->bpp-depth, &xfmt};
- SORT(chans[2], chans[3]);
- SORT(chans[1], chans[2]);
- SORT(chans[0], chans[1]);
- return (CHAN4(chans[0].type, chans[0].nbits,
- chans[1].type, chans[1].nbits,
- chans[2].type, chans[2].nbits,
- chans[3].type, chans[3].nbits));
- } else
- return (CHAN3(chans[0].type, chans[0].nbits,
- chans[1].type, chans[1].nbits,
- chans[2].type, chans[2].nbits));
- }
- #undef SORT
- static void
- chan2fmt(Pixfmt *fmt, ulong chan)
- {
- ulong c, rc, shift;
- shift = 0;
- for(rc = chan; rc; rc >>=8) {
- c = rc & 0xFF;
- switch(TYPE(c)){
- case CRed:
- fmt->red = (Colorfmt){(1<<NBITS(c))-1, shift};
- break;
- case CBlue:
- fmt->blue = (Colorfmt){(1<<NBITS(c))-1, shift};
- break;
- case CGreen:
- fmt->green = (Colorfmt){(1<<NBITS(c))-1, shift};
- break;
- }
- shift += NBITS(c);
- }
- }
- void
- srvchoosecolor(Vnc *v)
- {
- int bpp, depth;
- ulong chan;
- bpp = gscreen->depth;
- depth = gscreen->depth;
- chan = gscreen->chan;
- v->bpp = bpp;
- v->depth = depth;
- v->truecolor = 1;
- v->bigendian = 0;
- chan2fmt(v, chan);
- if(verbose)
- fprint(2, "%d bpp, %d depth, 0x%lx chan, %d truecolor, %d bigendian\n",
- v->bpp, v->depth, chan, v->truecolor, v->bigendian);
- vncwrpixfmt(v, &v->Pixfmt);
- vncflush(v);
- }
- void
- settranslation(Vncs * v)
- {
- ulong chan;
- chan = fmt2chan(&v->Pixfmt);
- if(verbose)
- fprint(2, "display chan 0x%lx, client chan 0x%lx\n", gscreen->chan, chan);
- v->clientimage = allocmemimage(Rpt(ZP, v->dim), chan);
- if(v->clientimage == nil)
- sysfatal("allocmemimage %r");
- if(verbose)
- fprint(2, "\ttranslating image format\n");
- }
- void
- senddim(Vnc *v)
- {
- v->dim = (Point){Dx(gscreen->r), Dy(gscreen->r)};
- vncwrpoint(v, v->dim);
- if(verbose)
- fprint(2, "screen is %d x %d %R\n", v->dim.x, v->dim.y, gscreen->r);
- }
- void flushmemscreen(Rectangle r)
- {
- Vncs *v;
- vnclock(&clients);
- for(v = (Vncs*)clients.next; v; v = (Vncs*)v->next)
- region_union(&v->updateregion, r, Rpt(ZP, v->dim));
- vncunlock(&clients);
- }
- // do lazy mouse warp. without it, we would cause
- // a warp message in each update.
- void
- mousewarpnote(Point p)
- {
- Vncs *v;
- vnclock(&clients);
- for(v = (Vncs*)clients.next; v; v = (Vncs*)v->next) {
- if(v->canwarp){
- vnclock(v);
- v->needwarp = 1;
- v->warppt = p;
- vncunlock(v);
- }
- }
- vncunlock(&clients);
- }
- static void
- sendcopyrect(Vncs *v, Rectangle r)
- {
- sendraw(v, r);
- }
- static int
- sendupdate(Vncs *v, int dowarp, Point warppt)
- {
- int nrects, i, snrects, docursor;
- Rectangle nr, cr;
- Region updateregion;
- vlong t1;
- drawlock();
- /* we make a snapshot so that new screen updates can overlap with us */
- region_init(&updateregion);
- region_copy(&updateregion, &v->updateregion);
- region_reset(&v->updateregion);
- docursor = 0;
- lock(&cursor);
- if(v->cursorver != cursorver || !eqpt(v->cursorpos, cursorpos)){
- docursor = 1;
- v->cursorver = cursorver;
- v->cursorpos = cursorpos;
- cr = cursorrect();
- }else
- cr = v->cursorr;
- unlock(&cursor);
- if(docursor)
- region_union(&updateregion, v->cursorr, Rpt(ZP, v->dim));
- for(i = 0; i < updateregion.nrects; i++){
- if(!docursor)
- docursor = rectXrect(v->cursorr, updateregion.rects[i]);
- memimagedraw(v->clientimage, updateregion.rects[i], gscreen, updateregion.rects[i].min, memopaque, ZP, S);
- }
- if(docursor){
- cursordraw(v->clientimage, cr);
- region_union(&updateregion, cr, Rpt(ZP, v->dim));
- v->cursorr = cr;
- }
- drawunlock();
- if(REGION_EMPTY(&updateregion) && dowarp == 0){
- region_reset(&updateregion);
- return 1;
- }
- if(v->preferredencoding == EncCorre) {
- nrects = 0;
- for(i = 0; i < updateregion.nrects; i++)
- nrects += rrerects(updateregion.rects[i], MaxCorreDim);
- } else if(v->preferredencoding == EncRre) {
- nrects = 0;
- for(i = 0; i < updateregion.nrects; i ++)
- nrects += rrerects(updateregion.rects[i], MaxRreDim);
- } else
- nrects = updateregion.nrects;
- if(verbose > 1)
- fprint(2, "sendupdate: %d rects, %d region rects..", nrects, updateregion.nrects);
- t1 = nsec();
- vncwrchar(v, MFrameUpdate);
- vncwrchar(v, 0);
- if(v->canwarp)
- vncwrshort(v, nrects+dowarp);
- else
- vncwrshort(v, nrects);
- snrects = 0;
- for(i = 0; i < updateregion.nrects; i++) {
- nr = updateregion.rects[i];
- switch(v->preferredencoding) {
- default:
- sysfatal("don't know about encoding %d\n", v->preferredencoding);
- break;
- case EncRaw:
- sendraw(v, nr);
- snrects++;
- break;
- case EncRre:
- snrects += sendrre(v, nr, MaxRreDim, 0);
- break;
- case EncCorre:
- snrects += sendrre(v, nr, MaxCorreDim, 1);
- break;
- case EncHextile:
- sendhextile(v, nr);
- snrects++;
- break;
- }
- }
- if(snrects != nrects)
- sysfatal("bad number of rectangles sent; %d expexted %d\n", snrects, nrects);
- region_reset(&updateregion);
- if(dowarp){
- // four shorts and an int (x, y, w, h, enctype)
- vncwrrect(v, rectaddpt(Rect(0,0,1,1), warppt));
- vncwrlong(v, EncMouseWarp);
- }
- if(verbose > 1)
- fprint(2, " in %lld msecs\n", (nsec()-t1)/(1000*1000LL));
- return 0;
- }
- static void
- vnc_update(Vncs *v)
- {
- char *buf;
- int n, notsent, needwarp;
- Point p;
- while(1) {
- vnclock(v);
- if( v->ndeadprocs )
- break;
- notsent = 1;
- if( v->updaterequested ) {
- v->updaterequested = 0;
- vncunlock(v);
- qlock(&snarf);
- if(v->snarfvers != snarf.vers) {
- n = snarf.n;
- buf = malloc(n);
- if(buf != nil)
- memmove(buf, snarf.buf, n);
- v->snarfvers = snarf.vers;
- qunlock(&snarf);
- if(buf != nil){
- vncwrchar(v, MSCut);
- vncwrbytes(v, "pad", 3);
- vncwrlong(v, n);
- vncwrbytes(v, buf, n);
- free(buf);
- }
- }else
- qunlock(&snarf);
- vnclock(v);
- needwarp = v->needwarp;
- v->needwarp = 0;
- p = v->warppt;
- vncunlock(v);
- notsent = sendupdate(v, needwarp, p);
- vnclock(v);
- v->updaterequested |= notsent;
- }
- vncunlock(v);
- vncflush(v);
- if(notsent)
- sleep(40);
- }
- vncunlock(v);
- vnchungup(v);
- }
- static int
- srvtlscrypt(Vnc *v)
- {
- int p[2], netfd;
- if(pipe(p) < 0){
- fprint(2, "pipe: %r\n");
- return -1;
- }
- netfd = v->datafd;
- switch(rfork(RFMEM|RFPROC|RFFDG|RFNOWAIT)){
- case -1:
- fprint(2, "fork: %r\n");
- return -1;
- case 0:
- dup(p[0], 0);
- dup(netfd, 1);
- close(v->ctlfd);
- close(netfd);
- close(p[0]);
- close(p[1]);
- execl("/bin/ntlssrv", "tlssrv", "-Dlvnc", "-k/tmp", nil);
- fprint(2, "exec: %r\n");
- _exits(nil);
- default:
- close(netfd);
- v->datafd = p[1];
- close(p[0]);
- Binit(&v->in, v->datafd, OREAD);
- Binit(&v->out, v->datafd, OWRITE);
- return 0;
- }
- }
- static int
- srvnocrypt(Vnc*)
- {
- return 0;
- }
- static int
- srvvncauth(Vnc *v)
- {
- return vncauth_srv(v);
- }
- static int
- srvnoauth(Vnc*)
- {
- return 0;
- }
- typedef struct Option Option;
- typedef struct Choice Choice;
- struct Choice {
- char *s;
- int (*fn)(Vnc*);
- };
- struct Option {
- char *s;
- int required;
- Choice *c;
- int nc;
- };
- static Choice srvcryptchoice[] = {
- "tlsv1", srvtlscrypt,
- // "none", srvnocrypt,
- };
- static Choice srvauthchoice[] = {
- "vnc", srvvncauth,
- // "none", srvnoauth,
- };
- static Option options[] = {
- "crypt", 1, srvcryptchoice, nelem(srvcryptchoice),
- "auth", 1, srvauthchoice, nelem(srvauthchoice),
- };
- static int
- vncnegotiate_srv(Vnc *v)
- {
- char opts[256], *eopts, *p, *resp;
- int i, j;
- for(i=0; i<nelem(options); i++){
- if(verbose)
- fprint(2, "%s...", options[i].s);
- eopts = opts+sizeof opts;
- p = seprint(opts, eopts, "%s", options[i].s);
- for(j=0; j<options[i].nc; j++)
- p = seprint(p, eopts, " %s", options[i].c[j].s);
- vncwrstring(v, opts);
- vncflush(v);
- resp = vncrdstringx(v);
- p = strchr(resp, ' ');
- if(p == nil){
- fprint(2, "malformed response in negotiation\n");
- free(resp);
- return -1;
- }
- *p++ = '\0';
- if(strcmp(resp, "error")==0){
- fprint(2, "negotiating %s: %s\n", options[i].s, p);
- if(options[i].required){
- free(resp);
- return -1;
- }
- }else if(strcmp(resp, options[i].s)==0){
- for(j=0; j<options[i].nc; i++)
- if(strcmp(options[i].c[j].s, p)==0)
- break;
- if(j==options[i].nc){
- fprint(2, "negotiating %s: unknown choice: %s\n",
- options[i].s, p);
- free(resp);
- return -1;
- }
- if(verbose)
- fprint(2, "(%s)...", p);
- if(options[i].c[j].fn(v) < 0){
- fprint(2, "%s %s failed: %r\n", resp, p);
- free(resp);
- return -1;
- }
- }else{
- p[-1] = ' ';
- fprint(2, "negotiating %s: bad response: %s\n", options[i].s, resp);
- free(resp);
- return -1;
- }
- free(resp);
- }
- vncwrstring(v, "start");
- if(verbose)
- fprint(2, "start...");
- vncflush(v);
- return 0;
- }
- static void
- vnc_srv(Vncs *v, int dfd, int cfd)
- {
- Rectangle r;
- char msg[12+1], *sn;
- uchar type, keydown;
- ushort n;
- ulong incremental, x, key;
- int y, buttons;
- if(verbose)
- fprint(2, "init...");
- vncinit(dfd, cfd, v);
- v->preferredencoding = -1;
- v->usecopyrect = 0;
- v->canwarp = 0;
- v->ndeadprocs = 0;
- v->nprocs = 1;
- if(verbose)
- fprint(2, "handshake...");
- if(vnchandshake_srv(v) < 0){
- if(verbose)
- fprint(2, "vnc handshake failed\n");
- vnchungup(v);
- }
- if(verbose)
- fprint(2, "auth...");
- if(vncauth_srv(v) < 0){
- if(verbose)
- fprint(2, "vnc authentication failed\n");
- vnchungup(v);
- }
- shared = vncrdchar(v);
- if(verbose)
- fprint(2, "client is %sshared\n", shared?"":"not ");
- if(!shared){
- shutdown_clients(v);
- }
- senddim(v);
- srvchoosecolor(v);
- vncwrlong(v, 14);
- vncwrbytes(v, "Plan9 Desktop", 14);
- vncflush(v);
- if(verbose)
- fprint(2, "handshaking done\n");
- /* start the update process */
- switch(rfork(RFPROC|RFMEM)){
- case -1:
- sysfatal("can't make update process: %r");
- default:
- break;
- case 0:
- v->nprocs++;
- *vncpriv = v;
- if(!atexit(vnccsexiting)){
- vnccsexiting();
- sysfatal("too many clients");
- }
- vnc_update(v);
- exits(nil);
- }
- region_init(&v->updateregion);
- for(;;){
- type = vncrdchar(v);
- switch(type){
- default:
- sysfatal("unknown vnc message type=%d\n", type);
- break;
- case MPixFmt:
- vncrdbytes(v, msg, 3);
- v->Pixfmt = vncrdpixfmt(v);
- settranslation(v);
- break;
- case MFixCmap:
- vncrdbytes(v, msg, 3);
- n = vncrdshort(v);
- vncgobble(v, n*6);
- break;
- case MSetEnc:
- vncrdchar(v);
- n = vncrdshort(v);
- while(n--){
- x = vncrdlong(v);
- if(x == EncCopyRect)
- v->usecopyrect = 1;
- else if (x == EncMouseWarp)
- v->canwarp = 1;
- else if(v->preferredencoding == -1)
- v->preferredencoding = x;
- }
- if(v->preferredencoding == -1)
- v->preferredencoding = EncRaw;
- if(verbose)
- fprint(2, "encoding is %s %s copyrect\n", encname[v->preferredencoding], v->usecopyrect?"with":"without");
- break;
- case MFrameReq:
- incremental = vncrdchar(v);
- r = vncrdrect(v);
- drawlock(); // must hold drawlock first
- vnclock(v);
- v->updaterequested = 1;
- if(!incremental)
- region_union(&v->updateregion, r, Rpt(ZP, v->dim));
- vncunlock(v);
- drawunlock();
- break;
- case MKey:
- keydown = vncrdchar(v);
- vncgobble(v, 2);
- key = vncrdlong(v);
- vncputc(!keydown, key);
- break;
- case MMouse:
- buttons = vncrdchar(v);
- x = vncrdshort(v);
- y = vncrdshort(v);
- mousetrack(x, y, buttons, nsec()/(1000*1000LL));
- break;
- case MCCut:
- vncrdbytes(v, msg, 3);
- x = vncrdlong(v);
- sn = malloc(x + 1);
- if(sn == nil)
- vncgobble(v, x);
- else{
- vncrdbytes(v, sn, x);
- sn[x] = '\0';
- setsnarf(sn, x, &v->snarfvers);
- }
- break;
- }
- }
- }
- void
- vnc_newclient(int dfd, int cfd)
- {
- Vncs * v;
- /* caller returns to listen */
- switch(rfork(RFPROC|RFMEM|RFNAMEG)){
- case -1:
- close(dfd);
- close(cfd);
- return;
- default:
- return;
- case 0:
- break;
- }
- v = mallocz(sizeof(Vncs), 1);
- vnclock(&clients);
- v->next = clients.next;
- clients.next = v;
- vncunlock(&clients);
- *vncpriv = v;
- if(!atexit(vnccsexiting)){
- vnccsexiting();
- sysfatal("too many clients");
- }
- vnc_srv(v, dfd, cfd);
- }
- /* here is where client procs exit.
- * vnclock(v) must not be held.
- */
- void
- vnchungup(Vnc *)
- {
- exits(nil);
- }
- static void
- vnccsexiting(void)
- {
- Vncs *v;
- Vnc **vp;
- v = *vncpriv;
- vnclock(&clients);
- for(vp = &clients.next; *vp != nil; vp = &(*vp)->next)
- if(*vp == v)
- break;
- /* check for shut down */
- if(*vp == nil){
- vncunlock(&clients);
- return;
- }
- /* wait for all of this client's procs to die */
- vnclock(v);
- if( ++v->ndeadprocs < v->nprocs ) {
- vncunlock(v);
- vncunlock(&clients);
- return;
- }
- *vp = v->next;
- vncunlock(&clients);
- region_reset(&v->updateregion);
- vncterm(v);
- close(v->ctlfd);
- close(v->datafd);
- freememimage(v->clientimage);
- free(v);
- }
- /*
- * kill all clients except nv.
- *
- * called by:
- * the listener before a non-shared client starts
- * shutdown
- */
- void static
- shutdown_clients(Vncs * nv)
- {
- Vncs *v;
- vnclock(&clients);
- for(v = (Vncs*)clients.next; v != nil; v = (Vncs*)v->next){
- if(v == nv)
- continue;
- if(v->ctlfd >= 0){
- hangup(v->ctlfd);
- close(v->ctlfd);
- v->ctlfd = -1;
- close(v->datafd);
- v->datafd = -1;
- }
- }
- vncunlock(&clients);
- }
- static char killkin[] = "die vnc kin";
- void
- killall(void)
- {
- int pid;
- postnote(PNGROUP, worker, "kill");
- close(srvfd);
- srvfd = -1;
- close(exportfd);
- exportfd = -1;
- pid = getpid();
- postnote(PNGROUP, pid, killkin);
- }
- /*
- * called by the exporter when unmounted
- * and the main listener when hung up.
- */
- void
- shutdown(void)
- {
- if(verbose)
- fprint(2, "vnc server shutdown\n");
- killall();
- }
- static void
- noteshut(void*, char *msg)
- {
- if(strcmp(msg, killkin) != 0)
- killall();
- noted(NDFLT);
- }
- /* try once if the user passed us the address, or hunt for one
- * explicit: tcp!*!5900
- * auto: /net | nil
- */
- int
- vncannounce(char *netmt, char * darg, char * adir, int bport)
- {
- int port, eport, fd;
- char portstr[NETPATHLEN];
- port = bport;
- eport = bport + 50;
- if( darg != nil && darg[0] == ':' ) {
- port = bport + strtol(&darg[1], nil, 10);
- eport = port;
- }
- for(; port <= eport; port++) {
- snprint(portstr, NETPATHLEN, "%s/tcp!*!%d", netmt, port);
- fd = announce(portstr, adir);
- if( fd >= 0 ) {
- fprint(2, "server started on display :%d\n", port-bport);
- return fd;
- }
- }
- return -1;
- }
- /* the user wants to kill the sever on a specified port
- */
- static void
- vnckillsrv(char * netroot, char * portstr, int bport)
- {
- int port, fd, lport;
- char * p;
- int fdir, i, tot, n;
- Dir *dir, * db;
- char buf[NETPATHLEN];
- port = atoi(portstr);
-
- port += bport;
- /* find the listener in /net/tcp/ */
- snprint(buf, sizeof buf, "%s/tcp", netroot);
- fdir = open(buf, OREAD);
- if(fdir < 0)
- return;
- tot = dirreadall(fdir, &dir);
- for(i = 0; i < tot; i++) {
- db = & dir[i];
- /* read in the local port number */
- sprint(buf, "%s/tcp/%s/local", netroot, db->name);
- fd = open(buf, OREAD);
- if(fd < 0)
- sysfatal("can't open file %s", buf);
- n = read(fd, buf, sizeof(buf));
- if(n < 0)
- sysfatal("can't read file %s", buf);
- buf[n-1] = 0;
- close(fd);
- p = strchr(buf, '!');
- if(p == 0)
- sysfatal("can't parse string %s", buf);
- lport = atoi(p+1);
- if(lport != port)
- continue;
- sprint(buf, "%s/tcp/%s/ctl", netroot, db->name);
- fd = open(buf, OWRITE);
- if( fd < 0 )
- sysfatal("can't open file %s", buf);
- if( write(fd, "hangup", 6) != 6 )
- sysfatal("can't write to file %s", buf);
- close(fd);
- break;
- }
- free(dir);
- close(fdir);
- }
- void
- usage(void)
- {
- fprint(2, "usage:\tvncs [-v] [-g widthXheight] [-d :display] [command [args ...]]\n");
- fprint(2, "\tvncs [-v] [-k :display]\n");
- exits("usage");
- }
- void
- main(int argc, char * argv[])
- {
- static char *defargv[] = { "/bin/rc", "-i", nil };
- char *addr, netmt[NETPATHLEN], adir[NETPATHLEN], ldir[NETPATHLEN], *p, *darg, *karg, *pem;
- int cfd, s, n, fd, w, h, vncport;
- TLSconn *conn;
- vncport = 5900;
- pem = nil;
- w = 1024;
- h = 768;
- addr = nil;
- darg = nil;
- karg = nil;
- setnetmtpt(netmt, NETPATHLEN, nil);
- ARGBEGIN{
- case 'c':
- pem = ARGF();
- if(pem == nil)
- usage();
- vncport = 35729; /* base port# for vnc/tls */
- break;
- case 'd':
- darg = ARGF();
- if(darg == nil || *darg != ':')
- usage();
- break;
- case 'g':
- p = ARGF();
- if(p == nil)
- usage();
- w = strtol(p, &p, 10);
- h = atoi(++p);
- break;
- case 'k':
- karg = ARGF();
- if(karg == nil || *karg != ':')
- usage();
- break;
- case 'v':
- verbose++;
- break;
- case 'x':
- p = ARGF();
- if(p == nil)
- usage();
- usage(); /* NO /net.alt LISTENERS */
- setnetmtpt(netmt, NETPATHLEN, p);
- break;
- default:
- usage();
- break;
- }ARGEND
-
- if(karg != nil){
- if(argc || darg != nil )
- usage();
- vnckillsrv(netmt, &karg[1], vncport);
- exits(nil);
- }
- if(argc == 0)
- argv = defargv;
- if(access(argv[0], AEXEC) < 0)
- sysfatal("can't exec %s: %r", argv[0]);
- /*
- * background the server
- */
- switch(rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG)){
- case -1:
- sysfatal("rfork: %r");
- default:
- exits(nil);
- case 0:
- break;
- }
- vncpriv = privalloc();
- if(vncpriv == nil)
- sysfatal("can't allocate private storage for vnc threads");
- initcompat();
- if(waserror())
- sysfatal("can't initialize screen: %s", up->error);
- fprint(2, "geometry is %dx%d\n", w, h);
- screeninit(w, h, "r5g6b5");
- poperror();
- /*
- * fork the plan 9 file system device slaves
- */
- n = exporter(devtab, &fd, &exportfd);
- /*
- * scummy: we have to rebuild all of /dev because the
- * underlying connection may go away, ripping out the old /dev/cons, etc.
- */
- unmount(nil, "/dev");
- bind("#c", "/dev", MREPL);
- /*
- * run the command
- */
- switch(worker = rfork(RFPROC|RFFDG|RFNOTEG|RFNAMEG|RFREND)){
- case -1:
- sysfatal("can't fork: %r");
- break;
- case 0:
- if(!mounter("/dev", MBEFORE, fd, n))
- exits("errors");
- close(exportfd);
- close(0);
- close(1);
- close(2);
- open("/dev/cons", OREAD);
- open("/dev/cons", OWRITE);
- open("/dev/cons", OWRITE);
- fprint(2, "execing %s...\n", argv[0]);
- exec(argv[0], argv);
- fprint(2, "can't exec %s: %r\n", argv[0]);
- _exits(0);
- default:
- close(fd);
- break;
- }
- /*
- * run the service
- */
- srvfd = vncannounce(netmt, darg, adir, vncport);
- if(srvfd < 0)
- sysfatal("announce %s: %r", addr);
- if(verbose)
- fprint(2, "announced %s\n", adir);
- atexit(shutdown);
- notify(noteshut);
- while(1){
- cfd = listen(adir, ldir);
- if(cfd < 0)
- break;
- if(verbose)
- fprint(2, "received call at %s\n", ldir);
- s = accept(cfd, ldir);
- if(pem != nil) {
- /* this code requires the user's own
- factotum running on the cpuserver
- */
- conn = (TLSconn*)mallocz(sizeof *conn, 1);
- conn->cert = readcert(pem, &conn->certlen);
- s = tlsServer(s, conn);
- if(conn->certlen)
- free(conn->cert);
- if(conn->sessionIDlen)
- free(conn->sessionID);
- free(conn);
- }
- if(s < 0){
- close(cfd);
- continue;
- }
- vnc_newclient(s, cfd);
- }
- exits(0);
- }
|