123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107 |
- #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, ffd, 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:
- /* On a cpuserver, we need to use bootes factotum
- * to talk to the auth server.
- */
- ffd = open("/srv/factotum", ORDWR);
- if(ffd < 0)
- sysfatal("can't open bootes factotum: %r\n");
- mount(ffd, -1, "/mnt", MBEFORE, "");
- 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);
- }
|