vncs.c 21 KB

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