vncs.c 21 KB

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