vncs.c 20 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  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. extern Dev drawdevtab;
  11. extern Dev mousedevtab;
  12. extern Dev consdevtab;
  13. Dev *devtab[] =
  14. {
  15. &drawdevtab,
  16. &mousedevtab,
  17. &consdevtab,
  18. nil
  19. };
  20. static char *msgname[] = {
  21. [MPixFmt] = "MPixFmt",
  22. [MFixCmap] = "MFixCmap",
  23. [MSetEnc] = "MSetEnc",
  24. [MFrameReq] = "MFrameReq",
  25. [MKey] = "MKey",
  26. [MMouse] = "MMouse",
  27. [MCCut] = "MCCut",
  28. };
  29. static char *encname[] = {
  30. [EncRaw] = "raw",
  31. [EncCopyRect] = "copy rect",
  32. [EncRre] = "rre",
  33. [EncCorre] = "corre",
  34. [EncHextile] = "hextile",
  35. [EncZlib] = "zlib",
  36. [EncTight] = "zlibtight",
  37. [EncZHextile] = "zhextile",
  38. [EncMouseWarp] = "mousewarp",
  39. };
  40. /*
  41. * list head. used to hold the list, the lock, dim, and pixelfmt
  42. */
  43. struct {
  44. QLock;
  45. Vncs *head;
  46. } clients;
  47. int shared;
  48. int sleeptime = 5;
  49. int verbose = 0;
  50. char *cert;
  51. char *pixchan = "r5g6b5";
  52. static int cmdpid;
  53. static int srvfd;
  54. static int exportfd;
  55. static Vncs **vncpriv;
  56. static int parsedisplay(char*);
  57. static void vnckill(char*, int, int);
  58. static int vncannounce(char *net, int display, char *adir, int base);
  59. static void noteshutdown(void*, char*);
  60. static void vncaccept(Vncs*);
  61. static int vncsfmt(Fmt*);
  62. static void getremote(char*, char*);
  63. static void vncname(char*, ...);
  64. #pragma varargck argpos vncname 1
  65. #pragma varargck type "V" Vncs*
  66. void
  67. usage(void)
  68. {
  69. fprint(2, "usage: vncs [-v] [-c cert] [-d :display] [-g widthXheight] [-p pixelfmt] [cmd [args]...]\n");
  70. fprint(2, "\tto kill a server: vncs [-v] -k :display\n");
  71. exits("usage");
  72. }
  73. void
  74. main(int argc, char **argv)
  75. {
  76. int altnet, baseport, cfd, display, exnum, fd, h, killing, w;
  77. char adir[NETPATHLEN], ldir[NETPATHLEN];
  78. char net[NETPATHLEN], *p;
  79. char *rc[] = { "/bin/rc", "-i", nil };
  80. Vncs *v;
  81. fmtinstall('V', vncsfmt);
  82. display = -1;
  83. killing = 0;
  84. altnet = 0;
  85. w = 1024;
  86. h = 768;
  87. baseport = 5900;
  88. setnetmtpt(net, sizeof net, nil);
  89. ARGBEGIN{
  90. default:
  91. usage();
  92. case 'c':
  93. cert = EARGF(usage());
  94. baseport = 35729;
  95. break;
  96. case 'd':
  97. if(display != -1)
  98. usage();
  99. display = parsedisplay(EARGF(usage()));
  100. break;
  101. case 'g':
  102. p = EARGF(usage());
  103. w = strtol(p, &p, 10);
  104. if(*p != 'x' && *p != 'X' && *p != ' ' && *p != ' ')
  105. usage();
  106. h = strtol(p+1, &p, 10);
  107. if(*p != 0)
  108. usage();
  109. break;
  110. case 'k':
  111. if(display != -1)
  112. usage();
  113. display = parsedisplay(EARGF(usage()));
  114. killing = 1;
  115. break;
  116. case 'p':
  117. pixchan = EARGF(usage());
  118. break;
  119. /* DEBUGGING
  120. case 's':
  121. sleeptime = atoi(EARGF(usage()));
  122. break;
  123. */
  124. case 'v':
  125. verbose++;
  126. break;
  127. case 'x':
  128. p = EARGF(usage());
  129. setnetmtpt(net, sizeof net, p);
  130. altnet = 1;
  131. break;
  132. }ARGEND
  133. if(killing){
  134. vnckill(net, display, baseport);
  135. exits(nil);
  136. }
  137. if(altnet && !cert)
  138. sysfatal("announcing on alternate network requires TLS (-c)");
  139. if(argc == 0)
  140. argv = rc;
  141. /* easy exit */
  142. if(access(argv[0], AEXEC) < 0)
  143. sysfatal("access %s for exec: %r", argv[0]);
  144. /* background ourselves */
  145. switch(rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG)){
  146. case -1:
  147. sysfatal("rfork: %r");
  148. default:
  149. exits(nil);
  150. case 0:
  151. break;
  152. }
  153. vncpriv = privalloc();
  154. if(vncpriv == nil)
  155. sysfatal("privalloc: %r");
  156. /* start screen */
  157. initcompat();
  158. if(waserror())
  159. sysfatal("screeninit %dx%d %s: %s\n", w, h, pixchan, up->error);
  160. if(verbose)
  161. fprint(2, "geometry is %dx%d\n", w, h);
  162. screeninit(w, h, pixchan);
  163. poperror();
  164. /* start file system device slaves */
  165. exnum = exporter(devtab, &fd, &exportfd);
  166. /* rebuild /dev because the underlying connection might go away (ick) */
  167. unmount(nil, "/dev");
  168. bind("#c", "/dev", MREPL);
  169. /* run the command */
  170. switch(cmdpid = rfork(RFPROC|RFFDG|RFNOTEG|RFNAMEG|RFREND)){
  171. case -1:
  172. sysfatal("rfork: %r");
  173. break;
  174. case 0:
  175. if(mounter("/dev", MBEFORE, fd, exnum) < 0)
  176. sysfatal("mounter: %r");
  177. close(exportfd);
  178. close(0);
  179. close(1);
  180. close(2);
  181. open("/dev/cons", OREAD);
  182. open("/dev/cons", OWRITE);
  183. open("/dev/cons", OWRITE);
  184. exec(argv[0], argv);
  185. fprint(2, "exec %s: %r\n", argv[0]);
  186. _exits(nil);
  187. default:
  188. close(fd);
  189. break;
  190. }
  191. /* run the service */
  192. srvfd = vncannounce(net, display, adir, baseport);
  193. if(srvfd < 0)
  194. sysfatal("announce failed");
  195. if(verbose)
  196. fprint(2, "announced in %s\n", adir);
  197. atexit(shutdown);
  198. notify(noteshutdown);
  199. for(;;){
  200. vncname("listener");
  201. cfd = listen(adir, ldir);
  202. if(cfd < 0)
  203. break;
  204. if(verbose)
  205. fprint(2, "call in %s\n", ldir);
  206. fd = accept(cfd, ldir);
  207. if(fd < 0){
  208. close(cfd);
  209. continue;
  210. }
  211. v = mallocz(sizeof(Vncs), 1);
  212. if(v == nil){
  213. close(cfd);
  214. close(fd);
  215. continue;
  216. }
  217. v->ctlfd = cfd;
  218. v->datafd = fd;
  219. v->nproc = 1;
  220. v->ndead = 0;
  221. getremote(ldir, v->remote);
  222. strcpy(v->netpath, ldir);
  223. qlock(&clients);
  224. v->next = clients.head;
  225. clients.head = v;
  226. qunlock(&clients);
  227. vncaccept(v);
  228. }
  229. exits(0);
  230. }
  231. static int
  232. parsedisplay(char *p)
  233. {
  234. int n;
  235. if(*p != ':')
  236. usage();
  237. if(*p == 0)
  238. usage();
  239. n = strtol(p+1, &p, 10);
  240. if(*p != 0)
  241. usage();
  242. return n;
  243. }
  244. static void
  245. getremote(char *ldir, char *remote)
  246. {
  247. char buf[NETPATHLEN];
  248. int fd, n;
  249. snprint(buf, sizeof buf, "%s/remote", ldir);
  250. strcpy(remote, "<none>");
  251. if((fd = open(buf, OREAD)) < 0)
  252. return;
  253. n = readn(fd, remote, NETPATHLEN-1);
  254. close(fd);
  255. if(n < 0)
  256. return;
  257. remote[n] = 0;
  258. if(n>0 && remote[n-1] == '\n')
  259. remote[n-1] = 0;
  260. }
  261. static int
  262. vncsfmt(Fmt *fmt)
  263. {
  264. Vncs *v;
  265. v = va_arg(fmt->args, Vncs*);
  266. return fmtprint(fmt, "[%d] %s %s", getpid(), v->remote, v->netpath);
  267. }
  268. /*
  269. * We register exiting as an atexit handler in each proc, so that
  270. * client procs need merely exit when something goes wrong.
  271. */
  272. static void
  273. vncclose(Vncs *v)
  274. {
  275. Vncs **l;
  276. v = *vncpriv;
  277. /* remove self from client list if there */
  278. qlock(&clients);
  279. for(l=&clients.head; *l; l=&(*l)->next)
  280. if(*l == v){
  281. *l = v->next;
  282. break;
  283. }
  284. qunlock(&clients);
  285. /* if last proc, free v */
  286. vnclock(v);
  287. if(++v->ndead < v->nproc){
  288. vncunlock(v);
  289. return;
  290. }
  291. freerlist(&v->rlist);
  292. vncterm(v);
  293. if(v->ctlfd >= 0)
  294. close(v->ctlfd);
  295. if(v->datafd >= 0)
  296. close(v->datafd);
  297. if(v->image)
  298. freememimage(v->image);
  299. free(v);
  300. }
  301. static void
  302. exiting(void)
  303. {
  304. vncclose(*vncpriv);
  305. }
  306. void
  307. vnchungup(Vnc *v)
  308. {
  309. if(verbose)
  310. fprint(2, "%V: hangup\n", (Vncs*)v);
  311. exits(0); /* atexit and exiting() will take care of everything */
  312. }
  313. /*
  314. * Kill all clients except safe.
  315. * Used to start a non-shared client and at shutdown.
  316. */
  317. static void
  318. killclients(Vncs *safe)
  319. {
  320. Vncs *v;
  321. qlock(&clients);
  322. for(v=clients.head; v; v=v->next){
  323. if(v == safe)
  324. continue;
  325. if(v->ctlfd >= 0){
  326. hangup(v->ctlfd);
  327. close(v->ctlfd);
  328. v->ctlfd = -1;
  329. close(v->datafd);
  330. v->datafd = -1;
  331. }
  332. }
  333. qunlock(&clients);
  334. }
  335. /*
  336. * Kill the executing command and then kill everyone else.
  337. * Called to close up shop at the end of the day
  338. * and also if we get an unexpected note.
  339. */
  340. static char killkin[] = "die vnc kin";
  341. static void
  342. killall(void)
  343. {
  344. postnote(PNGROUP, cmdpid, "hangup");
  345. close(srvfd);
  346. srvfd = -1;
  347. close(exportfd);
  348. exportfd = -1;
  349. postnote(PNGROUP, getpid(), killkin);
  350. }
  351. void
  352. shutdown(void)
  353. {
  354. if(verbose)
  355. fprint(2, "vnc server shutdown\n");
  356. killall();
  357. }
  358. static void
  359. noteshutdown(void*, char *msg)
  360. {
  361. if(strcmp(msg, killkin) == 0) /* already shutting down */
  362. noted(NDFLT);
  363. killall();
  364. noted(NDFLT);
  365. }
  366. /*
  367. * Kill a specific instance of a server.
  368. */
  369. static void
  370. vnckill(char *net, int display, int baseport)
  371. {
  372. int fd, i, n, port;
  373. char buf[NETPATHLEN], *p;
  374. for(i=0;; i++){
  375. snprint(buf, sizeof buf, "%s/tcp/%d/local", net, i);
  376. if((fd = open(buf, OREAD)) < 0)
  377. sysfatal("did not find display");
  378. n = read(fd, buf, sizeof buf-1);
  379. close(fd);
  380. if(n <= 0)
  381. continue;
  382. buf[n] = 0;
  383. p = strchr(buf, '!');
  384. if(p == 0)
  385. continue;
  386. port = atoi(p+1);
  387. if(port != display+baseport)
  388. continue;
  389. snprint(buf, sizeof buf, "%s/tcp/%d/ctl", net, i);
  390. fd = open(buf, OWRITE);
  391. if(fd < 0)
  392. sysfatal("cannot open %s: %r", buf);
  393. if(write(fd, "hangup", 6) != 6)
  394. sysfatal("cannot hangup %s: %r", buf);
  395. close(fd);
  396. break;
  397. }
  398. }
  399. /*
  400. * Look for a port on which to announce.
  401. * If display != -1, we only try that one.
  402. * Otherwise we hunt.
  403. *
  404. * Returns the announce fd.
  405. */
  406. static int
  407. vncannounce(char *net, int display, char *adir, int base)
  408. {
  409. int port, eport, fd;
  410. char addr[NETPATHLEN];
  411. if(display == -1){
  412. port = base;
  413. eport = base+50;
  414. }else{
  415. port = base+display;
  416. eport = port;
  417. }
  418. for(; port<=eport; port++){
  419. snprint(addr, sizeof addr, "%s/tcp!*!%d", net, port);
  420. if((fd = announce(addr, adir)) >= 0){
  421. fprint(2, "server started on display :%d\n", port-base);
  422. return fd;
  423. }
  424. }
  425. if(display == -1)
  426. fprint(2, "could not find any ports to announce\n");
  427. else
  428. fprint(2, "announce: %r\n");
  429. return -1;
  430. }
  431. /*
  432. * Handle a new connection.
  433. */
  434. static void clientreadproc(Vncs*);
  435. static void clientwriteproc(Vncs*);
  436. static void chan2fmt(Pixfmt*, ulong);
  437. static ulong fmt2chan(Pixfmt*);
  438. static void
  439. vncaccept(Vncs *v)
  440. {
  441. char buf[32];
  442. int fd;
  443. TLSconn conn;
  444. /* caller returns to listen */
  445. switch(rfork(RFPROC|RFMEM|RFNAMEG)){
  446. case -1:
  447. fprint(2, "%V: fork failed: %r\n", v);
  448. vncclose(v);
  449. return;
  450. default:
  451. return;
  452. case 0:
  453. break;
  454. }
  455. *vncpriv = v;
  456. if(!atexit(exiting)){
  457. fprint(2, "%V: could not register atexit handler: %r; hanging up\n", v);
  458. exiting();
  459. exits(nil);
  460. }
  461. if(cert != nil){
  462. memset(&conn, 0, sizeof conn);
  463. conn.cert = readcert(cert, &conn.certlen);
  464. if(conn.cert == nil){
  465. fprint(2, "%V: could not read cert %s: %r; hanging up\n", v, cert);
  466. exits(nil);
  467. }
  468. fd = tlsServer(v->datafd, &conn);
  469. if(fd < 0){
  470. fprint(2, "%V: tlsServer: %r; hanging up\n", v);
  471. free(conn.cert);
  472. if(conn.sessionID)
  473. free(conn.sessionID);
  474. exits(nil);
  475. }
  476. close(v->datafd);
  477. v->datafd = fd;
  478. free(conn.cert);
  479. free(conn.sessionID);
  480. }
  481. vncinit(v->datafd, v->ctlfd, v);
  482. if(verbose)
  483. fprint(2, "%V: handshake\n", v);
  484. if(vncsrvhandshake(v) < 0){
  485. fprint(2, "%V: handshake failed; hanging up\n", v);
  486. exits(0);
  487. }
  488. if(verbose)
  489. fprint(2, "%V: auth\n", v);
  490. if(vncsrvauth(v) < 0){
  491. fprint(2, "%V: auth failed; hanging up\n", v);
  492. exits(0);
  493. }
  494. shared = vncrdchar(v);
  495. if(verbose)
  496. fprint(2, "%V: %sshared\n", v, shared ? "" : "not ");
  497. if(!shared)
  498. killclients(v);
  499. v->dim = (Point){Dx(gscreen->r), Dy(gscreen->r)};
  500. vncwrpoint(v, v->dim);
  501. if(verbose)
  502. fprint(2, "%V: send screen size %P (rect %R)\n", v, v->dim, gscreen->r);
  503. v->bpp = gscreen->depth;
  504. v->depth = gscreen->depth;
  505. v->truecolor = 1;
  506. v->bigendian = 0;
  507. chan2fmt(v, gscreen->chan);
  508. if(verbose)
  509. fprint(2, "%V: bpp=%d, depth=%d, chan=%s\n", v,
  510. v->bpp, v->depth, chantostr(buf, gscreen->chan));
  511. vncwrpixfmt(v, v);
  512. vncwrlong(v, 14);
  513. vncwrbytes(v, "Plan9 Desktop", 14);
  514. vncflush(v);
  515. if(verbose)
  516. fprint(2, "%V: handshaking done\n", v);
  517. switch(rfork(RFPROC|RFMEM)){
  518. case -1:
  519. fprint(2, "%V: cannot fork: %r; hanging up\n", v);
  520. vnchungup(v);
  521. default:
  522. clientreadproc(v);
  523. exits(nil);
  524. case 0:
  525. *vncpriv = v;
  526. v->nproc++;
  527. if(atexit(exiting) == 0){
  528. exiting();
  529. fprint(2, "%V: could not register atexit handler: %r; hanging up\n", v);
  530. exits(nil);
  531. }
  532. clientwriteproc(v);
  533. exits(nil);
  534. }
  535. }
  536. static void
  537. vncname(char *fmt, ...)
  538. {
  539. int fd;
  540. char name[64], buf[32];
  541. va_list arg;
  542. va_start(arg, fmt);
  543. vsnprint(name, sizeof name, fmt, arg);
  544. va_end(arg);
  545. sprint(buf, "/proc/%d/args", getpid());
  546. if((fd = open(buf, OWRITE)) >= 0){
  547. write(fd, name, strlen(name));
  548. close(fd);
  549. }
  550. }
  551. /*
  552. * Set the pixel format being sent. Can only happen once.
  553. * (Maybe a client would send this again if the screen changed
  554. * underneath it? If we want to support this we need a way to
  555. * make sure the current image is no longer in use, so we can free it.
  556. */
  557. static void
  558. setpixelfmt(Vncs *v)
  559. {
  560. char buf[32], buf2[32];
  561. ulong chan;
  562. if(v->image)
  563. fprint(2, "%V: client already has image (leaking memory!)\n", v);
  564. vncgobble(v, 3);
  565. v->Pixfmt = vncrdpixfmt(v);
  566. chan = fmt2chan(v);
  567. if(chan == 0){
  568. fprint(2, "%V: bad pixel format; hanging up\n", v);
  569. vnchungup(v);
  570. }
  571. v->image = allocmemimage(Rpt(ZP, v->dim), chan);
  572. if(v->image == nil){
  573. fprint(2, "%V: allocmemimage: %r; hanging up\n", v);
  574. vnchungup(v);
  575. }
  576. if(verbose)fprint(2, "v %R g %R\n", v->image->r, gscreen->r);
  577. if(verbose)
  578. fprint(2, "%V: translating image from chan=%s to chan=%s\n",
  579. v, chantostr(buf, gscreen->chan), chantostr(buf2, chan));
  580. }
  581. /*
  582. * Set the preferred encoding list. Can only happen once.
  583. * If we want to support changing this more than once then
  584. * we need to put a lock around the encoding functions
  585. * so as not to conflict with updateimage.
  586. */
  587. static void
  588. setencoding(Vncs *v)
  589. {
  590. int n, x;
  591. vncrdchar(v);
  592. n = vncrdshort(v);
  593. while(n-- > 0){
  594. x = vncrdlong(v);
  595. switch(x){
  596. case EncCopyRect:
  597. v->copyrect = 1;
  598. continue;
  599. case EncMouseWarp:
  600. v->canwarp = 1;
  601. continue;
  602. }
  603. if(v->countrect != nil)
  604. continue;
  605. switch(x){
  606. case EncRaw:
  607. v->encname = "raw";
  608. v->countrect = countraw;
  609. v->sendrect = sendraw;
  610. break;
  611. case EncRre:
  612. v->encname = "rre";
  613. v->countrect = countrre;
  614. v->sendrect = sendrre;
  615. break;
  616. case EncCorre:
  617. v->encname = "corre";
  618. v->countrect = countcorre;
  619. v->sendrect = sendcorre;
  620. break;
  621. case EncHextile:
  622. v->encname = "hextile";
  623. v->countrect = counthextile;
  624. v->sendrect = sendhextile;
  625. break;
  626. }
  627. }
  628. if(v->countrect == nil){
  629. v->encname = "raw";
  630. v->countrect = countraw;
  631. v->sendrect = sendraw;
  632. }
  633. if(verbose)
  634. fprint(2, "Encoding with %s%s%s\n", v->encname,
  635. v->copyrect ? ", copyrect" : "",
  636. v->canwarp ? ", canwarp" : "");
  637. }
  638. /*
  639. * Continually read updates from one client.
  640. */
  641. static void
  642. clientreadproc(Vncs *v)
  643. {
  644. int incremental, key, keydown, buttons, type, x, y, n;
  645. char *buf;
  646. Rectangle r;
  647. vncname("read %V", v);
  648. for(;;){
  649. type = vncrdchar(v);
  650. switch(type){
  651. default:
  652. fprint(2, "%V: unknown vnc message type %d; hanging up\n", v, type);
  653. vnchungup(v);
  654. /* set pixel format */
  655. case MPixFmt:
  656. setpixelfmt(v);
  657. break;
  658. /* ignore color map changes */
  659. case MFixCmap:
  660. vncgobble(v, 3);
  661. n = vncrdshort(v);
  662. vncgobble(v, n*6);
  663. break;
  664. /* set encoding list */
  665. case MSetEnc:
  666. setencoding(v);
  667. break;
  668. /* request image update in rectangle */
  669. case MFrameReq:
  670. incremental = vncrdchar(v);
  671. r = vncrdrect(v);
  672. if(incremental){
  673. vnclock(v);
  674. v->updaterequest = 1;
  675. vncunlock(v);
  676. }else{
  677. drawlock(); /* protects rlist */
  678. vnclock(v); /* protects updaterequest */
  679. v->updaterequest = 1;
  680. addtorlist(&v->rlist, r);
  681. vncunlock(v);
  682. drawunlock();
  683. }
  684. break;
  685. /* send keystroke */
  686. case MKey:
  687. keydown = vncrdchar(v);
  688. vncgobble(v, 2);
  689. key = vncrdlong(v);
  690. vncputc(!keydown, key);
  691. break;
  692. /* send mouse event */
  693. case MMouse:
  694. buttons = vncrdchar(v);
  695. x = vncrdshort(v);
  696. y = vncrdshort(v);
  697. mousetrack(x, y, buttons, nsec()/(1000*1000LL));
  698. break;
  699. /* send cut text */
  700. case MCCut:
  701. vncgobble(v, 3);
  702. n = vncrdlong(v);
  703. buf = malloc(n+1);
  704. if(buf){
  705. vncrdbytes(v, buf, n);
  706. buf[n] = 0;
  707. vnclock(v); /* for snarfvers */
  708. setsnarf(buf, n, &v->snarfvers);
  709. vncunlock(v);
  710. }else
  711. vncgobble(v, n);
  712. break;
  713. }
  714. }
  715. }
  716. static int
  717. nbits(ulong mask)
  718. {
  719. int n;
  720. n = 0;
  721. for(; mask; mask>>=1)
  722. n += mask&1;
  723. return n;
  724. }
  725. typedef struct Col Col;
  726. struct Col {
  727. int type;
  728. int nbits;
  729. int shift;
  730. };
  731. static ulong
  732. fmt2chan(Pixfmt *fmt)
  733. {
  734. Col c[4], t;
  735. int i, j, depth, n, nc;
  736. ulong mask, u;
  737. /* unpack the Pixfmt channels */
  738. c[0] = (Col){CRed, nbits(fmt->red.max), fmt->red.shift};
  739. c[1] = (Col){CGreen, nbits(fmt->green.max), fmt->green.shift};
  740. c[2] = (Col){CBlue, nbits(fmt->blue.max), fmt->blue.shift};
  741. nc = 3;
  742. /* add an ignore channel if necessary */
  743. depth = c[0].nbits+c[1].nbits+c[2].nbits;
  744. if(fmt->bpp != depth){
  745. /* BUG: assumes only one run of ignored bits */
  746. if(fmt->bpp == 32)
  747. mask = ~0;
  748. else
  749. mask = (1<<fmt->bpp)-1;
  750. mask ^= fmt->red.max << fmt->red.shift;
  751. mask ^= fmt->green.max << fmt->green.shift;
  752. mask ^= fmt->blue.max << fmt->blue.shift;
  753. if(mask == 0)
  754. abort();
  755. n = 0;
  756. for(; !(mask&1); mask>>=1)
  757. n++;
  758. c[3] = (Col){CIgnore, nbits(mask), n};
  759. nc++;
  760. }
  761. /* sort the channels, largest shift (leftmost bits) first */
  762. for(i=1; i<nc; i++)
  763. for(j=i; j>0; j--)
  764. if(c[j].shift > c[j-1].shift){
  765. t = c[j];
  766. c[j] = c[j-1];
  767. c[j-1] = t;
  768. }
  769. /* build the channel descriptor */
  770. u = 0;
  771. for(i=0; i<nc; i++){
  772. u <<= 8;
  773. u |= CHAN1(c[i].type, c[i].nbits);
  774. }
  775. return u;
  776. }
  777. static void
  778. chan2fmt(Pixfmt *fmt, ulong chan)
  779. {
  780. ulong c, rc, shift;
  781. shift = 0;
  782. for(rc = chan; rc; rc >>=8){
  783. c = rc & 0xFF;
  784. switch(TYPE(c)){
  785. case CRed:
  786. fmt->red = (Colorfmt){(1<<NBITS(c))-1, shift};
  787. break;
  788. case CBlue:
  789. fmt->blue = (Colorfmt){(1<<NBITS(c))-1, shift};
  790. break;
  791. case CGreen:
  792. fmt->green = (Colorfmt){(1<<NBITS(c))-1, shift};
  793. break;
  794. }
  795. shift += NBITS(c);
  796. }
  797. }
  798. /*
  799. * Note that r has changed on the screen.
  800. * Updating the rlists is okay because they are protected by drawlock.
  801. */
  802. void
  803. flushmemscreen(Rectangle r)
  804. {
  805. Vncs *v;
  806. if(!rectclip(&r, gscreen->r))
  807. return;
  808. qlock(&clients);
  809. for(v=clients.head; v; v=v->next)
  810. addtorlist(&v->rlist, r);
  811. qunlock(&clients);
  812. }
  813. /*
  814. * Queue a mouse warp note for the next update to each client.
  815. */
  816. void
  817. mousewarpnote(Point p)
  818. {
  819. Vncs *v;
  820. qlock(&clients);
  821. for(v=clients.head; v; v=v->next){
  822. if(v->canwarp){
  823. vnclock(v);
  824. v->needwarp = 1;
  825. v->warppt = p;
  826. vncunlock(v);
  827. }
  828. }
  829. qunlock(&clients);
  830. }
  831. /*
  832. * Send a client his changed screen image.
  833. * v is locked on entrance, locked on exit, but released during.
  834. */
  835. static int
  836. updateimage(Vncs *v)
  837. {
  838. int i, ncount, nsend, docursor, needwarp;
  839. vlong ooffset;
  840. Point warppt;
  841. Rectangle cr;
  842. Rlist rlist;
  843. vlong t1;
  844. int (*count)(Vncs*, Rectangle);
  845. int (*send)(Vncs*, Rectangle);
  846. /* warping info and unlock v so that updates can proceed */
  847. needwarp = v->canwarp && v->needwarp;
  848. warppt = v->warppt;
  849. v->needwarp = 0;
  850. vncunlock(v);
  851. /* copy the screen bits and then unlock the screen so updates can proceed */
  852. drawlock();
  853. rlist = v->rlist;
  854. memset(&v->rlist, 0, sizeof v->rlist);
  855. /* if the cursor has moved or changed shape, we need to redraw its square */
  856. lock(&cursor);
  857. if(v->cursorver != cursorver || !eqpt(v->cursorpos, cursorpos)){
  858. docursor = 1;
  859. v->cursorver = cursorver;
  860. v->cursorpos = cursorpos;
  861. cr = cursorrect();
  862. }else{
  863. docursor = 0;
  864. cr = v->cursorr;
  865. }
  866. unlock(&cursor);
  867. if(docursor){
  868. addtorlist(&rlist, v->cursorr);
  869. if(!rectclip(&cr, gscreen->r))
  870. cr.max = cr.min;
  871. addtorlist(&rlist, cr);
  872. }
  873. /* copy changed screen parts, also check for parts overlapping cursor location */
  874. for(i=0; i<rlist.nrect; i++){
  875. if(!docursor)
  876. docursor = rectXrect(v->cursorr, rlist.rect[i]);
  877. memimagedraw(v->image, rlist.rect[i], gscreen, rlist.rect[i].min, memopaque, ZP, S);
  878. }
  879. if(docursor){
  880. cursordraw(v->image, cr);
  881. addtorlist(&rlist, v->cursorr);
  882. v->cursorr = cr;
  883. }
  884. drawunlock();
  885. ooffset = Boffset(&v->out);
  886. /* no more locks are held; talk to the client */
  887. if(rlist.nrect == 0 && needwarp == 0){
  888. vnclock(v);
  889. return 0;
  890. }
  891. count = v->countrect;
  892. send = v->sendrect;
  893. if(count == nil || send == nil){
  894. count = countraw;
  895. send = sendraw;
  896. }
  897. ncount = 0;
  898. for(i=0; i<rlist.nrect; i++)
  899. ncount += (*count)(v, rlist.rect[i]);
  900. if(verbose > 1)
  901. fprint(2, "sendupdate: rlist.nrect=%d, ncount=%d", rlist.nrect, ncount);
  902. t1 = nsec();
  903. vncwrchar(v, MFrameUpdate);
  904. vncwrchar(v, 0);
  905. vncwrshort(v, ncount+needwarp);
  906. nsend = 0;
  907. for(i=0; i<rlist.nrect; i++)
  908. nsend += (*send)(v, rlist.rect[i]);
  909. if(ncount != nsend){
  910. fprint(2, "%V: ncount=%d, nsend=%d; hanging up\n", v, ncount, nsend);
  911. vnchungup(v);
  912. }
  913. if(needwarp){
  914. vncwrrect(v, Rect(warppt.x, warppt.y, warppt.x+1, warppt.y+1));
  915. vncwrlong(v, EncMouseWarp);
  916. }
  917. t1 = nsec() - t1;
  918. if(verbose > 1)
  919. fprint(2, " in %lldms, %lld bytes\n", t1/1000000, Boffset(&v->out) - ooffset);
  920. freerlist(&rlist);
  921. vnclock(v);
  922. return 1;
  923. }
  924. /*
  925. * Update the snarf buffer if it has changed.
  926. */
  927. static void
  928. updatesnarf(Vncs *v)
  929. {
  930. char *buf;
  931. int len;
  932. if(v->snarfvers == snarf.vers)
  933. return;
  934. vncunlock(v);
  935. qlock(&snarf);
  936. len = snarf.n;
  937. buf = malloc(len);
  938. if(buf == nil){
  939. qunlock(&snarf);
  940. vnclock(v);
  941. return;
  942. }
  943. memmove(buf, snarf.buf, len);
  944. v->snarfvers = snarf.vers;
  945. qunlock(&snarf);
  946. vncwrchar(v, MSCut);
  947. vncwrbytes(v, "pad", 3);
  948. vncwrlong(v, len);
  949. vncwrbytes(v, buf, len);
  950. free(buf);
  951. vnclock(v);
  952. }
  953. /*
  954. * Continually update one client.
  955. */
  956. static void
  957. clientwriteproc(Vncs *v)
  958. {
  959. int sent;
  960. vncname("write %V", v);
  961. for(;;){
  962. vnclock(v);
  963. if(v->ndead)
  964. break;
  965. sent = 0;
  966. if(v->updaterequest){
  967. v->updaterequest = 0;
  968. updatesnarf(v);
  969. sent = updateimage(v);
  970. if(!sent)
  971. v->updaterequest = 1;
  972. }
  973. vncunlock(v);
  974. vncflush(v);
  975. if(!sent)
  976. sleep(sleeptime);
  977. }
  978. vncunlock(v);
  979. vnchungup(v);
  980. }