vncs.c 20 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  1. #define Image IMAGE
  2. #include "vnc.h"
  3. #include "vncs.h"
  4. #include "compat.h"
  5. #include <cursor.h>
  6. #include "screen.h"
  7. #include "kbd.h"
  8. #include <mp.h>
  9. #include <libsec.h>
  10. enum
  11. {
  12. MaxCorreDim = 48,
  13. MaxRreDim = 64,
  14. };
  15. extern Dev drawdevtab;
  16. extern Dev mousedevtab;
  17. extern Dev consdevtab;
  18. Dev *devtab[] =
  19. {
  20. &drawdevtab,
  21. &mousedevtab,
  22. &consdevtab,
  23. nil
  24. };
  25. int shared;
  26. int verbose = 0;
  27. static int worker = -1; /* pid of command we ran */
  28. static int srvfd;
  29. static int exportfd;
  30. static Vncs **vncpriv;
  31. static char *msgname[] = {
  32. [MPixFmt] = "MPixFmt",
  33. [MFixCmap] = "MFixCmap",
  34. [MSetEnc] = "MSetEnc",
  35. [MFrameReq] = "MFrameReq",
  36. [MKey] = "MKey",
  37. [MMouse] = "MMouse",
  38. [MCCut] = "MCCut",
  39. };
  40. static char *encname[] = {
  41. [EncRaw] = "raw",
  42. [EncCopyRect] = "copy rect",
  43. [EncRre] = "rre",
  44. [EncCorre] = "corre",
  45. [EncHextile] = "hextile",
  46. [EncZlib] = "zlib",
  47. [EncTight] = "zlibtight",
  48. [EncZHextile] = "zhextile",
  49. [EncMouseWarp] = "mousewarp",
  50. };
  51. static void shutdown_clients(Vncs *);
  52. /*
  53. * list head. used to hold the list, the lock, dim, and pixelfmt
  54. */
  55. Vnc clients;
  56. static void vnccsexiting(void);
  57. static int
  58. nbits(ulong mask)
  59. {
  60. int bit;
  61. if (mask == 0)
  62. sysfatal("nbits: invalid mask 0x%lx", mask);
  63. mask = ~mask;
  64. for (bit = 0; !(mask & 1); bit++)
  65. mask >>= 1;
  66. return bit;
  67. }
  68. struct _chan {
  69. uchar type;
  70. uchar nbits;
  71. Colorfmt * fmt;
  72. };
  73. #define SORT(x, y) if(x.fmt->shift < y.fmt->shift) do { chan = x; x = y; y = chan; } while(0)
  74. static ulong
  75. fmt2chan(Pixfmt * fmt)
  76. {
  77. struct _chan chans[4];
  78. struct _chan chan;
  79. int i, depth, n;
  80. ulong mask = 0xffffffff;
  81. Colorfmt xfmt;
  82. chans[0] = (struct _chan){CRed,0,&fmt->red};
  83. chans[1] = (struct _chan){CGreen,0,&fmt->green};
  84. chans[2] = (struct _chan){CBlue,0,&fmt->blue};
  85. SORT(chans[0], chans[1]);
  86. SORT(chans[0], chans[2]);
  87. SORT(chans[1], chans[2]);
  88. depth = 0;
  89. for(i = 0; i < 3; i++) {
  90. n = chans[i].nbits = nbits(chans[i].fmt->max);
  91. depth += n;
  92. mask &= ~(chans[i].fmt->max<<chans[i].fmt->shift);
  93. }
  94. if(fmt->bpp != depth && mask) {
  95. xfmt.shift = 0;
  96. while(!(mask & 1)) {
  97. xfmt.shift++;
  98. mask >>= 1;
  99. }
  100. xfmt.max = mask;
  101. chans[3] = (struct _chan){CIgnore, fmt->bpp-depth, &xfmt};
  102. SORT(chans[2], chans[3]);
  103. SORT(chans[1], chans[2]);
  104. SORT(chans[0], chans[1]);
  105. return (CHAN4(chans[0].type, chans[0].nbits,
  106. chans[1].type, chans[1].nbits,
  107. chans[2].type, chans[2].nbits,
  108. chans[3].type, chans[3].nbits));
  109. } else
  110. return (CHAN3(chans[0].type, chans[0].nbits,
  111. chans[1].type, chans[1].nbits,
  112. chans[2].type, chans[2].nbits));
  113. }
  114. #undef SORT
  115. static void
  116. chan2fmt(Pixfmt *fmt, ulong chan)
  117. {
  118. ulong c, rc, shift;
  119. shift = 0;
  120. for(rc = chan; rc; rc >>=8) {
  121. c = rc & 0xFF;
  122. switch(TYPE(c)){
  123. case CRed:
  124. fmt->red = (Colorfmt){(1<<NBITS(c))-1, shift};
  125. break;
  126. case CBlue:
  127. fmt->blue = (Colorfmt){(1<<NBITS(c))-1, shift};
  128. break;
  129. case CGreen:
  130. fmt->green = (Colorfmt){(1<<NBITS(c))-1, shift};
  131. break;
  132. }
  133. shift += NBITS(c);
  134. }
  135. }
  136. void
  137. srvchoosecolor(Vnc *v)
  138. {
  139. int bpp, depth;
  140. ulong chan;
  141. bpp = gscreen->depth;
  142. depth = gscreen->depth;
  143. chan = gscreen->chan;
  144. v->bpp = bpp;
  145. v->depth = depth;
  146. v->truecolor = 1;
  147. v->bigendian = 0;
  148. chan2fmt(v, chan);
  149. if(verbose)
  150. fprint(2, "%d bpp, %d depth, 0x%lx chan, %d truecolor, %d bigendian\n",
  151. v->bpp, v->depth, chan, v->truecolor, v->bigendian);
  152. vncwrpixfmt(v, &v->Pixfmt);
  153. vncflush(v);
  154. }
  155. void
  156. settranslation(Vncs * v)
  157. {
  158. ulong chan;
  159. chan = fmt2chan(&v->Pixfmt);
  160. if(verbose)
  161. fprint(2, "display chan 0x%lx, client chan 0x%lx\n", gscreen->chan, chan);
  162. v->clientimage = allocmemimage(Rpt(ZP, v->dim), chan);
  163. if(v->clientimage == nil)
  164. sysfatal("allocmemimage %r");
  165. if(verbose)
  166. fprint(2, "\ttranslating image format\n");
  167. }
  168. void
  169. senddim(Vnc *v)
  170. {
  171. v->dim = (Point){Dx(gscreen->r), Dy(gscreen->r)};
  172. vncwrpoint(v, v->dim);
  173. if(verbose)
  174. fprint(2, "screen is %d x %d %R\n", v->dim.x, v->dim.y, gscreen->r);
  175. }
  176. void flushmemscreen(Rectangle r)
  177. {
  178. Vncs *v;
  179. vnclock(&clients);
  180. for(v = (Vncs*)clients.next; v; v = (Vncs*)v->next)
  181. region_union(&v->updateregion, r, Rpt(ZP, v->dim));
  182. vncunlock(&clients);
  183. }
  184. // do lazy mouse warp. without it, we would cause
  185. // a warp message in each update.
  186. void
  187. mousewarpnote(Point p)
  188. {
  189. Vncs *v;
  190. vnclock(&clients);
  191. for(v = (Vncs*)clients.next; v; v = (Vncs*)v->next) {
  192. if(v->canwarp){
  193. vnclock(v);
  194. v->needwarp = 1;
  195. v->warppt = p;
  196. vncunlock(v);
  197. }
  198. }
  199. vncunlock(&clients);
  200. }
  201. static void
  202. sendcopyrect(Vncs *v, Rectangle r)
  203. {
  204. sendraw(v, r);
  205. }
  206. static int
  207. sendupdate(Vncs *v, int dowarp, Point warppt)
  208. {
  209. int nrects, i, snrects, docursor;
  210. Rectangle nr, cr;
  211. Region updateregion;
  212. vlong t1;
  213. drawlock();
  214. /* we make a snapshot so that new screen updates can overlap with us */
  215. region_init(&updateregion);
  216. region_copy(&updateregion, &v->updateregion);
  217. region_reset(&v->updateregion);
  218. docursor = 0;
  219. lock(&cursor);
  220. if(v->cursorver != cursorver || !eqpt(v->cursorpos, cursorpos)){
  221. docursor = 1;
  222. v->cursorver = cursorver;
  223. v->cursorpos = cursorpos;
  224. cr = cursorrect();
  225. }else
  226. cr = v->cursorr;
  227. unlock(&cursor);
  228. if(docursor)
  229. region_union(&updateregion, v->cursorr, Rpt(ZP, v->dim));
  230. for(i = 0; i < updateregion.nrects; i++){
  231. if(!docursor)
  232. docursor = rectXrect(v->cursorr, updateregion.rects[i]);
  233. memimagedraw(v->clientimage, updateregion.rects[i], gscreen, updateregion.rects[i].min, memopaque, ZP, S);
  234. }
  235. if(docursor){
  236. cursordraw(v->clientimage, cr);
  237. region_union(&updateregion, cr, Rpt(ZP, v->dim));
  238. v->cursorr = cr;
  239. }
  240. drawunlock();
  241. if(REGION_EMPTY(&updateregion) && dowarp == 0){
  242. region_reset(&updateregion);
  243. return 1;
  244. }
  245. if(v->preferredencoding == EncCorre) {
  246. nrects = 0;
  247. for(i = 0; i < updateregion.nrects; i++)
  248. nrects += rrerects(updateregion.rects[i], MaxCorreDim);
  249. } else if(v->preferredencoding == EncRre) {
  250. nrects = 0;
  251. for(i = 0; i < updateregion.nrects; i ++)
  252. nrects += rrerects(updateregion.rects[i], MaxRreDim);
  253. } else
  254. nrects = updateregion.nrects;
  255. if(verbose > 1)
  256. fprint(2, "sendupdate: %d rects, %d region rects..", nrects, updateregion.nrects);
  257. t1 = nsec();
  258. vncwrchar(v, MFrameUpdate);
  259. vncwrchar(v, 0);
  260. if(v->canwarp)
  261. vncwrshort(v, nrects+dowarp);
  262. else
  263. vncwrshort(v, nrects);
  264. snrects = 0;
  265. for(i = 0; i < updateregion.nrects; i++) {
  266. nr = updateregion.rects[i];
  267. switch(v->preferredencoding) {
  268. default:
  269. sysfatal("don't know about encoding %d\n", v->preferredencoding);
  270. break;
  271. case EncRaw:
  272. sendraw(v, nr);
  273. snrects++;
  274. break;
  275. case EncRre:
  276. snrects += sendrre(v, nr, MaxRreDim, 0);
  277. break;
  278. case EncCorre:
  279. snrects += sendrre(v, nr, MaxCorreDim, 1);
  280. break;
  281. case EncHextile:
  282. sendhextile(v, nr);
  283. snrects++;
  284. break;
  285. }
  286. }
  287. if(snrects != nrects)
  288. sysfatal("bad number of rectangles sent; %d expexted %d\n", snrects, nrects);
  289. region_reset(&updateregion);
  290. if(dowarp){
  291. // four shorts and an int (x, y, w, h, enctype)
  292. vncwrrect(v, rectaddpt(Rect(0,0,1,1), warppt));
  293. vncwrlong(v, EncMouseWarp);
  294. }
  295. if(verbose > 1)
  296. fprint(2, " in %lld msecs\n", (nsec()-t1)/(1000*1000LL));
  297. return 0;
  298. }
  299. static void
  300. vnc_update(Vncs *v)
  301. {
  302. char *buf;
  303. int n, notsent, needwarp;
  304. Point p;
  305. while(1) {
  306. vnclock(v);
  307. if( v->ndeadprocs )
  308. break;
  309. notsent = 1;
  310. if( v->updaterequested ) {
  311. v->updaterequested = 0;
  312. vncunlock(v);
  313. qlock(&snarf);
  314. if(v->snarfvers != snarf.vers) {
  315. n = snarf.n;
  316. buf = malloc(n);
  317. if(buf != nil)
  318. memmove(buf, snarf.buf, n);
  319. v->snarfvers = snarf.vers;
  320. qunlock(&snarf);
  321. if(buf != nil){
  322. vncwrchar(v, MSCut);
  323. vncwrbytes(v, "pad", 3);
  324. vncwrlong(v, n);
  325. vncwrbytes(v, buf, n);
  326. free(buf);
  327. }
  328. }else
  329. qunlock(&snarf);
  330. vnclock(v);
  331. needwarp = v->needwarp;
  332. v->needwarp = 0;
  333. p = v->warppt;
  334. vncunlock(v);
  335. notsent = sendupdate(v, needwarp, p);
  336. vnclock(v);
  337. v->updaterequested |= notsent;
  338. }
  339. vncunlock(v);
  340. vncflush(v);
  341. if(notsent)
  342. sleep(40);
  343. }
  344. vncunlock(v);
  345. vnchungup(v);
  346. }
  347. static int
  348. srvtlscrypt(Vnc *v)
  349. {
  350. int p[2], netfd;
  351. if(pipe(p) < 0){
  352. fprint(2, "pipe: %r\n");
  353. return -1;
  354. }
  355. netfd = v->datafd;
  356. switch(rfork(RFMEM|RFPROC|RFFDG|RFNOWAIT)){
  357. case -1:
  358. fprint(2, "fork: %r\n");
  359. return -1;
  360. case 0:
  361. dup(p[0], 0);
  362. dup(netfd, 1);
  363. close(v->ctlfd);
  364. close(netfd);
  365. close(p[0]);
  366. close(p[1]);
  367. execl("/bin/ntlssrv", "tlssrv", "-Dlvnc", "-k/tmp", nil);
  368. fprint(2, "exec: %r\n");
  369. _exits(nil);
  370. default:
  371. close(netfd);
  372. v->datafd = p[1];
  373. close(p[0]);
  374. Binit(&v->in, v->datafd, OREAD);
  375. Binit(&v->out, v->datafd, OWRITE);
  376. return 0;
  377. }
  378. }
  379. static int
  380. srvnocrypt(Vnc*)
  381. {
  382. return 0;
  383. }
  384. static int
  385. srvvncauth(Vnc *v)
  386. {
  387. return vncauth_srv(v);
  388. }
  389. static int
  390. srvnoauth(Vnc*)
  391. {
  392. return 0;
  393. }
  394. typedef struct Option Option;
  395. typedef struct Choice Choice;
  396. struct Choice {
  397. char *s;
  398. int (*fn)(Vnc*);
  399. };
  400. struct Option {
  401. char *s;
  402. int required;
  403. Choice *c;
  404. int nc;
  405. };
  406. static Choice srvcryptchoice[] = {
  407. "tlsv1", srvtlscrypt,
  408. // "none", srvnocrypt,
  409. };
  410. static Choice srvauthchoice[] = {
  411. "vnc", srvvncauth,
  412. // "none", srvnoauth,
  413. };
  414. static Option options[] = {
  415. "crypt", 1, srvcryptchoice, nelem(srvcryptchoice),
  416. "auth", 1, srvauthchoice, nelem(srvauthchoice),
  417. };
  418. static int
  419. vncnegotiate_srv(Vnc *v)
  420. {
  421. char opts[256], *eopts, *p, *resp;
  422. int i, j;
  423. for(i=0; i<nelem(options); i++){
  424. if(verbose)
  425. fprint(2, "%s...", options[i].s);
  426. eopts = opts+sizeof opts;
  427. p = seprint(opts, eopts, "%s", options[i].s);
  428. for(j=0; j<options[i].nc; j++)
  429. p = seprint(p, eopts, " %s", options[i].c[j].s);
  430. vncwrstring(v, opts);
  431. vncflush(v);
  432. resp = vncrdstringx(v);
  433. p = strchr(resp, ' ');
  434. if(p == nil){
  435. fprint(2, "malformed response in negotiation\n");
  436. free(resp);
  437. return -1;
  438. }
  439. *p++ = '\0';
  440. if(strcmp(resp, "error")==0){
  441. fprint(2, "negotiating %s: %s\n", options[i].s, p);
  442. if(options[i].required){
  443. free(resp);
  444. return -1;
  445. }
  446. }else if(strcmp(resp, options[i].s)==0){
  447. for(j=0; j<options[i].nc; i++)
  448. if(strcmp(options[i].c[j].s, p)==0)
  449. break;
  450. if(j==options[i].nc){
  451. fprint(2, "negotiating %s: unknown choice: %s\n",
  452. options[i].s, p);
  453. free(resp);
  454. return -1;
  455. }
  456. if(verbose)
  457. fprint(2, "(%s)...", p);
  458. if(options[i].c[j].fn(v) < 0){
  459. fprint(2, "%s %s failed: %r\n", resp, p);
  460. free(resp);
  461. return -1;
  462. }
  463. }else{
  464. p[-1] = ' ';
  465. fprint(2, "negotiating %s: bad response: %s\n", options[i].s, resp);
  466. free(resp);
  467. return -1;
  468. }
  469. free(resp);
  470. }
  471. vncwrstring(v, "start");
  472. if(verbose)
  473. fprint(2, "start...");
  474. vncflush(v);
  475. return 0;
  476. }
  477. static void
  478. vnc_srv(Vncs *v, int dfd, int cfd)
  479. {
  480. Rectangle r;
  481. char msg[12+1], *sn;
  482. uchar type, keydown;
  483. ushort n;
  484. ulong incremental, x, key;
  485. int y, buttons;
  486. if(verbose)
  487. fprint(2, "init...");
  488. vncinit(dfd, cfd, v);
  489. v->preferredencoding = -1;
  490. v->usecopyrect = 0;
  491. v->canwarp = 0;
  492. v->ndeadprocs = 0;
  493. v->nprocs = 1;
  494. if(verbose)
  495. fprint(2, "handshake...");
  496. if(vnchandshake_srv(v) < 0){
  497. if(verbose)
  498. fprint(2, "vnc handshake failed\n");
  499. vnchungup(v);
  500. }
  501. if(verbose)
  502. fprint(2, "auth...");
  503. if(vncauth_srv(v) < 0){
  504. if(verbose)
  505. fprint(2, "vnc authentication failed\n");
  506. vnchungup(v);
  507. }
  508. shared = vncrdchar(v);
  509. if(verbose)
  510. fprint(2, "client is %sshared\n", shared?"":"not ");
  511. if(!shared){
  512. shutdown_clients(v);
  513. }
  514. senddim(v);
  515. srvchoosecolor(v);
  516. vncwrlong(v, 14);
  517. vncwrbytes(v, "Plan9 Desktop", 14);
  518. vncflush(v);
  519. if(verbose)
  520. fprint(2, "handshaking done\n");
  521. /* start the update process */
  522. switch(rfork(RFPROC|RFMEM)){
  523. case -1:
  524. sysfatal("can't make update process: %r");
  525. default:
  526. break;
  527. case 0:
  528. v->nprocs++;
  529. *vncpriv = v;
  530. if(!atexit(vnccsexiting)){
  531. vnccsexiting();
  532. sysfatal("too many clients");
  533. }
  534. vnc_update(v);
  535. exits(nil);
  536. }
  537. region_init(&v->updateregion);
  538. for(;;){
  539. type = vncrdchar(v);
  540. switch(type){
  541. default:
  542. sysfatal("unknown vnc message type=%d\n", type);
  543. break;
  544. case MPixFmt:
  545. vncrdbytes(v, msg, 3);
  546. v->Pixfmt = vncrdpixfmt(v);
  547. settranslation(v);
  548. break;
  549. case MFixCmap:
  550. vncrdbytes(v, msg, 3);
  551. n = vncrdshort(v);
  552. vncgobble(v, n*6);
  553. break;
  554. case MSetEnc:
  555. vncrdchar(v);
  556. n = vncrdshort(v);
  557. while(n--){
  558. x = vncrdlong(v);
  559. if(x == EncCopyRect)
  560. v->usecopyrect = 1;
  561. else if (x == EncMouseWarp)
  562. v->canwarp = 1;
  563. else if(v->preferredencoding == -1)
  564. v->preferredencoding = x;
  565. }
  566. if(v->preferredencoding == -1)
  567. v->preferredencoding = EncRaw;
  568. if(verbose)
  569. fprint(2, "encoding is %s %s copyrect\n", encname[v->preferredencoding], v->usecopyrect?"with":"without");
  570. break;
  571. case MFrameReq:
  572. incremental = vncrdchar(v);
  573. r = vncrdrect(v);
  574. drawlock(); // must hold drawlock first
  575. vnclock(v);
  576. v->updaterequested = 1;
  577. if(!incremental)
  578. region_union(&v->updateregion, r, Rpt(ZP, v->dim));
  579. vncunlock(v);
  580. drawunlock();
  581. break;
  582. case MKey:
  583. keydown = vncrdchar(v);
  584. vncgobble(v, 2);
  585. key = vncrdlong(v);
  586. vncputc(!keydown, key);
  587. break;
  588. case MMouse:
  589. buttons = vncrdchar(v);
  590. x = vncrdshort(v);
  591. y = vncrdshort(v);
  592. mousetrack(x, y, buttons, nsec()/(1000*1000LL));
  593. break;
  594. case MCCut:
  595. vncrdbytes(v, msg, 3);
  596. x = vncrdlong(v);
  597. sn = malloc(x + 1);
  598. if(sn == nil)
  599. vncgobble(v, x);
  600. else{
  601. vncrdbytes(v, sn, x);
  602. sn[x] = '\0';
  603. setsnarf(sn, x, &v->snarfvers);
  604. }
  605. break;
  606. }
  607. }
  608. }
  609. void
  610. vnc_newclient(int dfd, int cfd)
  611. {
  612. Vncs * v;
  613. /* caller returns to listen */
  614. switch(rfork(RFPROC|RFMEM|RFNAMEG)){
  615. case -1:
  616. close(dfd);
  617. close(cfd);
  618. return;
  619. default:
  620. return;
  621. case 0:
  622. break;
  623. }
  624. v = mallocz(sizeof(Vncs), 1);
  625. vnclock(&clients);
  626. v->next = clients.next;
  627. clients.next = v;
  628. vncunlock(&clients);
  629. *vncpriv = v;
  630. if(!atexit(vnccsexiting)){
  631. vnccsexiting();
  632. sysfatal("too many clients");
  633. }
  634. vnc_srv(v, dfd, cfd);
  635. }
  636. /* here is where client procs exit.
  637. * vnclock(v) must not be held.
  638. */
  639. void
  640. vnchungup(Vnc *)
  641. {
  642. exits(nil);
  643. }
  644. static void
  645. vnccsexiting(void)
  646. {
  647. Vncs *v;
  648. Vnc **vp;
  649. v = *vncpriv;
  650. vnclock(&clients);
  651. for(vp = &clients.next; *vp != nil; vp = &(*vp)->next)
  652. if(*vp == v)
  653. break;
  654. /* check for shut down */
  655. if(*vp == nil){
  656. vncunlock(&clients);
  657. return;
  658. }
  659. /* wait for all of this client's procs to die */
  660. vnclock(v);
  661. if( ++v->ndeadprocs < v->nprocs ) {
  662. vncunlock(v);
  663. vncunlock(&clients);
  664. return;
  665. }
  666. *vp = v->next;
  667. vncunlock(&clients);
  668. region_reset(&v->updateregion);
  669. vncterm(v);
  670. close(v->ctlfd);
  671. close(v->datafd);
  672. freememimage(v->clientimage);
  673. free(v);
  674. }
  675. /*
  676. * kill all clients except nv.
  677. *
  678. * called by:
  679. * the listener before a non-shared client starts
  680. * shutdown
  681. */
  682. void static
  683. shutdown_clients(Vncs * nv)
  684. {
  685. Vncs *v;
  686. vnclock(&clients);
  687. for(v = (Vncs*)clients.next; v != nil; v = (Vncs*)v->next){
  688. if(v == nv)
  689. continue;
  690. if(v->ctlfd >= 0){
  691. hangup(v->ctlfd);
  692. close(v->ctlfd);
  693. v->ctlfd = -1;
  694. close(v->datafd);
  695. v->datafd = -1;
  696. }
  697. }
  698. vncunlock(&clients);
  699. }
  700. static char killkin[] = "die vnc kin";
  701. void
  702. killall(void)
  703. {
  704. int pid;
  705. postnote(PNGROUP, worker, "kill");
  706. close(srvfd);
  707. srvfd = -1;
  708. close(exportfd);
  709. exportfd = -1;
  710. pid = getpid();
  711. postnote(PNGROUP, pid, killkin);
  712. }
  713. /*
  714. * called by the exporter when unmounted
  715. * and the main listener when hung up.
  716. */
  717. void
  718. shutdown(void)
  719. {
  720. if(verbose)
  721. fprint(2, "vnc server shutdown\n");
  722. killall();
  723. }
  724. static void
  725. noteshut(void*, char *msg)
  726. {
  727. if(strcmp(msg, killkin) != 0)
  728. killall();
  729. noted(NDFLT);
  730. }
  731. /* try once if the user passed us the address, or hunt for one
  732. * explicit: tcp!*!5900
  733. * auto: /net | nil
  734. */
  735. int
  736. vncannounce(char *netmt, char * darg, char * adir, int bport)
  737. {
  738. int port, eport, fd;
  739. char portstr[NETPATHLEN];
  740. port = bport;
  741. eport = bport + 50;
  742. if( darg != nil && darg[0] == ':' ) {
  743. port = bport + strtol(&darg[1], nil, 10);
  744. eport = port;
  745. }
  746. for(; port <= eport; port++) {
  747. snprint(portstr, NETPATHLEN, "%s/tcp!*!%d", netmt, port);
  748. fd = announce(portstr, adir);
  749. if( fd >= 0 ) {
  750. fprint(2, "server started on display :%d\n", port-bport);
  751. return fd;
  752. }
  753. }
  754. return -1;
  755. }
  756. /* the user wants to kill the sever on a specified port
  757. */
  758. static void
  759. vnckillsrv(char * netroot, char * portstr, int bport)
  760. {
  761. int port, fd, lport;
  762. char * p;
  763. int fdir, i, tot, n;
  764. Dir *dir, * db;
  765. char buf[NETPATHLEN];
  766. port = atoi(portstr);
  767. port += bport;
  768. /* find the listener in /net/tcp/ */
  769. snprint(buf, sizeof buf, "%s/tcp", netroot);
  770. fdir = open(buf, OREAD);
  771. if(fdir < 0)
  772. return;
  773. tot = dirreadall(fdir, &dir);
  774. for(i = 0; i < tot; i++) {
  775. db = & dir[i];
  776. /* read in the local port number */
  777. sprint(buf, "%s/tcp/%s/local", netroot, db->name);
  778. fd = open(buf, OREAD);
  779. if(fd < 0)
  780. sysfatal("can't open file %s", buf);
  781. n = read(fd, buf, sizeof(buf));
  782. if(n < 0)
  783. sysfatal("can't read file %s", buf);
  784. buf[n-1] = 0;
  785. close(fd);
  786. p = strchr(buf, '!');
  787. if(p == 0)
  788. sysfatal("can't parse string %s", buf);
  789. lport = atoi(p+1);
  790. if(lport != port)
  791. continue;
  792. sprint(buf, "%s/tcp/%s/ctl", netroot, db->name);
  793. fd = open(buf, OWRITE);
  794. if( fd < 0 )
  795. sysfatal("can't open file %s", buf);
  796. if( write(fd, "hangup", 6) != 6 )
  797. sysfatal("can't write to file %s", buf);
  798. close(fd);
  799. break;
  800. }
  801. free(dir);
  802. close(fdir);
  803. }
  804. void
  805. usage(void)
  806. {
  807. fprint(2, "usage:\tvncs [-v] [-g widthXheight] [-d :display] [command [args ...]]\n");
  808. fprint(2, "\tvncs [-v] [-k :display]\n");
  809. exits("usage");
  810. }
  811. void
  812. main(int argc, char * argv[])
  813. {
  814. static char *defargv[] = { "/bin/rc", "-i", nil };
  815. char *addr, netmt[NETPATHLEN], adir[NETPATHLEN], ldir[NETPATHLEN], *p, *darg, *karg, *pem;
  816. int cfd, s, n, fd, w, h, vncport;
  817. TLSconn *conn;
  818. vncport = 5900;
  819. pem = nil;
  820. w = 1024;
  821. h = 768;
  822. addr = nil;
  823. darg = nil;
  824. karg = nil;
  825. setnetmtpt(netmt, NETPATHLEN, nil);
  826. ARGBEGIN{
  827. case 'c':
  828. pem = ARGF();
  829. if(pem == nil)
  830. usage();
  831. vncport = 35729; /* base port# for vnc/tls */
  832. break;
  833. case 'd':
  834. darg = ARGF();
  835. if(darg == nil || *darg != ':')
  836. usage();
  837. break;
  838. case 'g':
  839. p = ARGF();
  840. if(p == nil)
  841. usage();
  842. w = strtol(p, &p, 10);
  843. h = atoi(++p);
  844. break;
  845. case 'k':
  846. karg = ARGF();
  847. if(karg == nil || *karg != ':')
  848. usage();
  849. break;
  850. case 'v':
  851. verbose++;
  852. break;
  853. case 'x':
  854. p = ARGF();
  855. if(p == nil)
  856. usage();
  857. usage(); /* NO /net.alt LISTENERS */
  858. setnetmtpt(netmt, NETPATHLEN, p);
  859. break;
  860. default:
  861. usage();
  862. break;
  863. }ARGEND
  864. if(karg != nil){
  865. if(argc || darg != nil )
  866. usage();
  867. vnckillsrv(netmt, &karg[1], vncport);
  868. exits(nil);
  869. }
  870. if(argc == 0)
  871. argv = defargv;
  872. if(access(argv[0], AEXEC) < 0)
  873. sysfatal("can't exec %s: %r", argv[0]);
  874. /*
  875. * background the server
  876. */
  877. switch(rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG)){
  878. case -1:
  879. sysfatal("rfork: %r");
  880. default:
  881. exits(nil);
  882. case 0:
  883. break;
  884. }
  885. vncpriv = privalloc();
  886. if(vncpriv == nil)
  887. sysfatal("can't allocate private storage for vnc threads");
  888. initcompat();
  889. if(waserror())
  890. sysfatal("can't initialize screen: %s", up->error);
  891. fprint(2, "geometry is %dx%d\n", w, h);
  892. screeninit(w, h, "r5g6b5");
  893. poperror();
  894. /*
  895. * fork the plan 9 file system device slaves
  896. */
  897. n = exporter(devtab, &fd, &exportfd);
  898. /*
  899. * scummy: we have to rebuild all of /dev because the
  900. * underlying connection may go away, ripping out the old /dev/cons, etc.
  901. */
  902. unmount(nil, "/dev");
  903. bind("#c", "/dev", MREPL);
  904. /*
  905. * run the command
  906. */
  907. switch(worker = rfork(RFPROC|RFFDG|RFNOTEG|RFNAMEG|RFREND)){
  908. case -1:
  909. sysfatal("can't fork: %r");
  910. break;
  911. case 0:
  912. if(!mounter("/dev", MBEFORE, fd, n))
  913. exits("errors");
  914. close(exportfd);
  915. close(0);
  916. close(1);
  917. close(2);
  918. open("/dev/cons", OREAD);
  919. open("/dev/cons", OWRITE);
  920. open("/dev/cons", OWRITE);
  921. fprint(2, "execing %s...\n", argv[0]);
  922. exec(argv[0], argv);
  923. fprint(2, "can't exec %s: %r\n", argv[0]);
  924. _exits(0);
  925. default:
  926. close(fd);
  927. break;
  928. }
  929. /*
  930. * run the service
  931. */
  932. srvfd = vncannounce(netmt, darg, adir, vncport);
  933. if(srvfd < 0)
  934. sysfatal("announce %s: %r", addr);
  935. if(verbose)
  936. fprint(2, "announced %s\n", adir);
  937. atexit(shutdown);
  938. notify(noteshut);
  939. while(1){
  940. cfd = listen(adir, ldir);
  941. if(cfd < 0)
  942. break;
  943. if(verbose)
  944. fprint(2, "received call at %s\n", ldir);
  945. s = accept(cfd, ldir);
  946. if(pem != nil) {
  947. /* this code requires the user's own
  948. factotum running on the cpuserver
  949. */
  950. conn = (TLSconn*)mallocz(sizeof *conn, 1);
  951. conn->cert = readcert(pem, &conn->certlen);
  952. s = tlsServer(s, conn);
  953. if(conn->certlen)
  954. free(conn->cert);
  955. if(conn->sessionIDlen)
  956. free(conn->sessionID);
  957. free(conn);
  958. }
  959. if(s < 0){
  960. close(cfd);
  961. continue;
  962. }
  963. vnc_newclient(s, cfd);
  964. }
  965. exits(0);
  966. }