vncs.c 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  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. /* remove self from client list if there */
  277. qlock(&clients);
  278. for(l=&clients.head; *l; l=&(*l)->next)
  279. if(*l == v){
  280. *l = v->next;
  281. break;
  282. }
  283. qunlock(&clients);
  284. /* if last proc, free v */
  285. vnclock(v);
  286. if(++v->ndead < v->nproc){
  287. vncunlock(v);
  288. return;
  289. }
  290. freerlist(&v->rlist);
  291. vncterm(v);
  292. if(v->ctlfd >= 0)
  293. close(v->ctlfd);
  294. if(v->datafd >= 0)
  295. close(v->datafd);
  296. if(v->image)
  297. freememimage(v->image);
  298. free(v);
  299. }
  300. static void
  301. exiting(void)
  302. {
  303. vncclose(*vncpriv);
  304. }
  305. void
  306. vnchungup(Vnc *v)
  307. {
  308. if(verbose)
  309. fprint(2, "%V: hangup\n", (Vncs*)v);
  310. exits(0); /* atexit and exiting() will take care of everything */
  311. }
  312. /*
  313. * Kill all clients except safe.
  314. * Used to start a non-shared client and at shutdown.
  315. */
  316. static void
  317. killclients(Vncs *safe)
  318. {
  319. Vncs *v;
  320. qlock(&clients);
  321. for(v=clients.head; v; v=v->next){
  322. if(v == safe)
  323. continue;
  324. if(v->ctlfd >= 0){
  325. hangup(v->ctlfd);
  326. close(v->ctlfd);
  327. v->ctlfd = -1;
  328. close(v->datafd);
  329. v->datafd = -1;
  330. }
  331. }
  332. qunlock(&clients);
  333. }
  334. /*
  335. * Kill the executing command and then kill everyone else.
  336. * Called to close up shop at the end of the day
  337. * and also if we get an unexpected note.
  338. */
  339. static char killkin[] = "die vnc kin";
  340. static void
  341. killall(void)
  342. {
  343. postnote(PNGROUP, cmdpid, "hangup");
  344. close(srvfd);
  345. srvfd = -1;
  346. close(exportfd);
  347. exportfd = -1;
  348. postnote(PNGROUP, getpid(), killkin);
  349. }
  350. void
  351. shutdown(void)
  352. {
  353. if(verbose)
  354. fprint(2, "vnc server shutdown\n");
  355. killall();
  356. }
  357. static void
  358. noteshutdown(void*, char *msg)
  359. {
  360. if(strcmp(msg, killkin) == 0) /* already shutting down */
  361. noted(NDFLT);
  362. killall();
  363. noted(NDFLT);
  364. }
  365. /*
  366. * Kill a specific instance of a server.
  367. */
  368. static void
  369. vnckill(char *net, int display, int baseport)
  370. {
  371. int fd, i, n, port;
  372. char buf[NETPATHLEN], *p;
  373. for(i=0;; i++){
  374. snprint(buf, sizeof buf, "%s/tcp/%d/local", net, i);
  375. if((fd = open(buf, OREAD)) < 0)
  376. sysfatal("did not find display");
  377. n = read(fd, buf, sizeof buf-1);
  378. close(fd);
  379. if(n <= 0)
  380. continue;
  381. buf[n] = 0;
  382. p = strchr(buf, '!');
  383. if(p == 0)
  384. continue;
  385. port = atoi(p+1);
  386. if(port != display+baseport)
  387. continue;
  388. snprint(buf, sizeof buf, "%s/tcp/%d/ctl", net, i);
  389. fd = open(buf, OWRITE);
  390. if(fd < 0)
  391. sysfatal("cannot open %s: %r", buf);
  392. if(write(fd, "hangup", 6) != 6)
  393. sysfatal("cannot hangup %s: %r", buf);
  394. close(fd);
  395. break;
  396. }
  397. }
  398. /*
  399. * Look for a port on which to announce.
  400. * If display != -1, we only try that one.
  401. * Otherwise we hunt.
  402. *
  403. * Returns the announce fd.
  404. */
  405. static int
  406. vncannounce(char *net, int display, char *adir, int base)
  407. {
  408. int port, eport, fd;
  409. char addr[NETPATHLEN];
  410. if(display == -1){
  411. port = base;
  412. eport = base+50;
  413. }else{
  414. port = base+display;
  415. eport = port;
  416. }
  417. for(; port<=eport; port++){
  418. snprint(addr, sizeof addr, "%s/tcp!*!%d", net, port);
  419. if((fd = announce(addr, adir)) >= 0){
  420. fprint(2, "server started on display :%d\n", port-base);
  421. return fd;
  422. }
  423. }
  424. if(display == -1)
  425. fprint(2, "could not find any ports to announce\n");
  426. else
  427. fprint(2, "announce: %r\n");
  428. return -1;
  429. }
  430. /*
  431. * Handle a new connection.
  432. */
  433. static void clientreadproc(Vncs*);
  434. static void clientwriteproc(Vncs*);
  435. static void chan2fmt(Pixfmt*, ulong);
  436. static ulong fmt2chan(Pixfmt*);
  437. static void
  438. vncaccept(Vncs *v)
  439. {
  440. char buf[32];
  441. int fd;
  442. TLSconn conn;
  443. /* caller returns to listen */
  444. switch(rfork(RFPROC|RFMEM|RFNAMEG)){
  445. case -1:
  446. fprint(2, "%V: fork failed: %r\n", v);
  447. vncclose(v);
  448. return;
  449. default:
  450. return;
  451. case 0:
  452. break;
  453. }
  454. *vncpriv = v;
  455. if(!atexit(exiting)){
  456. fprint(2, "%V: could not register atexit handler: %r; hanging up\n", v);
  457. exiting();
  458. exits(nil);
  459. }
  460. if(cert != nil){
  461. memset(&conn, 0, sizeof conn);
  462. conn.cert = readcert(cert, &conn.certlen);
  463. if(conn.cert == nil){
  464. fprint(2, "%V: could not read cert %s: %r; hanging up\n", v, cert);
  465. exits(nil);
  466. }
  467. fd = tlsServer(v->datafd, &conn);
  468. if(fd < 0){
  469. fprint(2, "%V: tlsServer: %r; hanging up\n", v);
  470. free(conn.cert);
  471. if(conn.sessionID)
  472. free(conn.sessionID);
  473. exits(nil);
  474. }
  475. close(v->datafd);
  476. v->datafd = fd;
  477. free(conn.cert);
  478. free(conn.sessionID);
  479. }
  480. vncinit(v->datafd, v->ctlfd, v);
  481. if(verbose)
  482. fprint(2, "%V: handshake\n", v);
  483. if(vncsrvhandshake(v) < 0){
  484. fprint(2, "%V: handshake failed; hanging up\n", v);
  485. exits(0);
  486. }
  487. if(verbose)
  488. fprint(2, "%V: auth\n", v);
  489. if(vncsrvauth(v) < 0){
  490. fprint(2, "%V: auth failed; hanging up\n", v);
  491. exits(0);
  492. }
  493. shared = vncrdchar(v);
  494. if(verbose)
  495. fprint(2, "%V: %sshared\n", v, shared ? "" : "not ");
  496. if(!shared)
  497. killclients(v);
  498. v->dim = (Point){Dx(gscreen->r), Dy(gscreen->r)};
  499. vncwrpoint(v, v->dim);
  500. if(verbose)
  501. fprint(2, "%V: send screen size %P (rect %R)\n", v, v->dim, gscreen->r);
  502. v->bpp = gscreen->depth;
  503. v->depth = gscreen->depth;
  504. v->truecolor = 1;
  505. v->bigendian = 0;
  506. chan2fmt(v, gscreen->chan);
  507. if(verbose)
  508. fprint(2, "%V: bpp=%d, depth=%d, chan=%s\n", v,
  509. v->bpp, v->depth, chantostr(buf, gscreen->chan));
  510. vncwrpixfmt(v, v);
  511. vncwrlong(v, 14);
  512. vncwrbytes(v, "Plan9 Desktop", 14);
  513. vncflush(v);
  514. if(verbose)
  515. fprint(2, "%V: handshaking done\n", v);
  516. switch(rfork(RFPROC|RFMEM)){
  517. case -1:
  518. fprint(2, "%V: cannot fork: %r; hanging up\n", v);
  519. vnchungup(v);
  520. default:
  521. clientreadproc(v);
  522. exits(nil);
  523. case 0:
  524. *vncpriv = v;
  525. v->nproc++;
  526. if(atexit(exiting) == 0){
  527. exiting();
  528. fprint(2, "%V: could not register atexit handler: %r; hanging up\n", v);
  529. exits(nil);
  530. }
  531. clientwriteproc(v);
  532. exits(nil);
  533. }
  534. }
  535. static void
  536. vncname(char *fmt, ...)
  537. {
  538. int fd;
  539. char name[64], buf[32];
  540. va_list arg;
  541. va_start(arg, fmt);
  542. vsnprint(name, sizeof name, fmt, arg);
  543. va_end(arg);
  544. sprint(buf, "/proc/%d/args", getpid());
  545. if((fd = open(buf, OWRITE)) >= 0){
  546. write(fd, name, strlen(name));
  547. close(fd);
  548. }
  549. }
  550. /*
  551. * Set the pixel format being sent. Can only happen once.
  552. * (Maybe a client would send this again if the screen changed
  553. * underneath it? If we want to support this we need a way to
  554. * make sure the current image is no longer in use, so we can free it.
  555. */
  556. static void
  557. setpixelfmt(Vncs *v)
  558. {
  559. ulong chan;
  560. vncgobble(v, 3);
  561. v->Pixfmt = vncrdpixfmt(v);
  562. chan = fmt2chan(v);
  563. if(chan == 0){
  564. fprint(2, "%V: bad pixel format; hanging up\n", v);
  565. vnchungup(v);
  566. }
  567. v->imagechan = chan;
  568. }
  569. /*
  570. * Set the preferred encoding list. Can only happen once.
  571. * If we want to support changing this more than once then
  572. * we need to put a lock around the encoding functions
  573. * so as not to conflict with updateimage.
  574. */
  575. static void
  576. setencoding(Vncs *v)
  577. {
  578. int n, x;
  579. vncrdchar(v);
  580. n = vncrdshort(v);
  581. while(n-- > 0){
  582. x = vncrdlong(v);
  583. switch(x){
  584. case EncCopyRect:
  585. v->copyrect = 1;
  586. continue;
  587. case EncMouseWarp:
  588. v->canwarp = 1;
  589. continue;
  590. }
  591. if(v->countrect != nil)
  592. continue;
  593. switch(x){
  594. case EncRaw:
  595. v->encname = "raw";
  596. v->countrect = countraw;
  597. v->sendrect = sendraw;
  598. break;
  599. case EncRre:
  600. v->encname = "rre";
  601. v->countrect = countrre;
  602. v->sendrect = sendrre;
  603. break;
  604. case EncCorre:
  605. v->encname = "corre";
  606. v->countrect = countcorre;
  607. v->sendrect = sendcorre;
  608. break;
  609. case EncHextile:
  610. v->encname = "hextile";
  611. v->countrect = counthextile;
  612. v->sendrect = sendhextile;
  613. break;
  614. }
  615. }
  616. if(v->countrect == nil){
  617. v->encname = "raw";
  618. v->countrect = countraw;
  619. v->sendrect = sendraw;
  620. }
  621. if(verbose)
  622. fprint(2, "Encoding with %s%s%s\n", v->encname,
  623. v->copyrect ? ", copyrect" : "",
  624. v->canwarp ? ", canwarp" : "");
  625. }
  626. /*
  627. * Continually read updates from one client.
  628. */
  629. static void
  630. clientreadproc(Vncs *v)
  631. {
  632. int incremental, key, keydown, buttons, type, x, y, n;
  633. char *buf;
  634. Rectangle r;
  635. vncname("read %V", v);
  636. for(;;){
  637. type = vncrdchar(v);
  638. switch(type){
  639. default:
  640. fprint(2, "%V: unknown vnc message type %d; hanging up\n", v, type);
  641. vnchungup(v);
  642. /* set pixel format */
  643. case MPixFmt:
  644. setpixelfmt(v);
  645. break;
  646. /* ignore color map changes */
  647. case MFixCmap:
  648. vncgobble(v, 3);
  649. n = vncrdshort(v);
  650. vncgobble(v, n*6);
  651. break;
  652. /* set encoding list */
  653. case MSetEnc:
  654. setencoding(v);
  655. break;
  656. /* request image update in rectangle */
  657. case MFrameReq:
  658. incremental = vncrdchar(v);
  659. r = vncrdrect(v);
  660. if(incremental){
  661. vnclock(v);
  662. v->updaterequest = 1;
  663. vncunlock(v);
  664. }else{
  665. drawlock(); /* protects rlist */
  666. vnclock(v); /* protects updaterequest */
  667. v->updaterequest = 1;
  668. addtorlist(&v->rlist, r);
  669. vncunlock(v);
  670. drawunlock();
  671. }
  672. break;
  673. /* send keystroke */
  674. case MKey:
  675. keydown = vncrdchar(v);
  676. vncgobble(v, 2);
  677. key = vncrdlong(v);
  678. vncputc(!keydown, key);
  679. break;
  680. /* send mouse event */
  681. case MMouse:
  682. buttons = vncrdchar(v);
  683. x = vncrdshort(v);
  684. y = vncrdshort(v);
  685. mousetrack(x, y, buttons, nsec()/(1000*1000LL));
  686. break;
  687. /* send cut text */
  688. case MCCut:
  689. vncgobble(v, 3);
  690. n = vncrdlong(v);
  691. buf = malloc(n+1);
  692. if(buf){
  693. vncrdbytes(v, buf, n);
  694. buf[n] = 0;
  695. vnclock(v); /* for snarfvers */
  696. setsnarf(buf, n, &v->snarfvers);
  697. vncunlock(v);
  698. }else
  699. vncgobble(v, n);
  700. break;
  701. }
  702. }
  703. }
  704. static int
  705. nbits(ulong mask)
  706. {
  707. int n;
  708. n = 0;
  709. for(; mask; mask>>=1)
  710. n += mask&1;
  711. return n;
  712. }
  713. typedef struct Col Col;
  714. struct Col {
  715. int type;
  716. int nbits;
  717. int shift;
  718. };
  719. static ulong
  720. fmt2chan(Pixfmt *fmt)
  721. {
  722. Col c[4], t;
  723. int i, j, depth, n, nc;
  724. ulong mask, u;
  725. /* unpack the Pixfmt channels */
  726. c[0] = (Col){CRed, nbits(fmt->red.max), fmt->red.shift};
  727. c[1] = (Col){CGreen, nbits(fmt->green.max), fmt->green.shift};
  728. c[2] = (Col){CBlue, nbits(fmt->blue.max), fmt->blue.shift};
  729. nc = 3;
  730. /* add an ignore channel if necessary */
  731. depth = c[0].nbits+c[1].nbits+c[2].nbits;
  732. if(fmt->bpp != depth){
  733. /* BUG: assumes only one run of ignored bits */
  734. if(fmt->bpp == 32)
  735. mask = ~0;
  736. else
  737. mask = (1<<fmt->bpp)-1;
  738. mask ^= fmt->red.max << fmt->red.shift;
  739. mask ^= fmt->green.max << fmt->green.shift;
  740. mask ^= fmt->blue.max << fmt->blue.shift;
  741. if(mask == 0)
  742. abort();
  743. n = 0;
  744. for(; !(mask&1); mask>>=1)
  745. n++;
  746. c[3] = (Col){CIgnore, nbits(mask), n};
  747. nc++;
  748. }
  749. /* sort the channels, largest shift (leftmost bits) first */
  750. for(i=1; i<nc; i++)
  751. for(j=i; j>0; j--)
  752. if(c[j].shift > c[j-1].shift){
  753. t = c[j];
  754. c[j] = c[j-1];
  755. c[j-1] = t;
  756. }
  757. /* build the channel descriptor */
  758. u = 0;
  759. for(i=0; i<nc; i++){
  760. u <<= 8;
  761. u |= CHAN1(c[i].type, c[i].nbits);
  762. }
  763. return u;
  764. }
  765. static void
  766. chan2fmt(Pixfmt *fmt, ulong chan)
  767. {
  768. ulong c, rc, shift;
  769. shift = 0;
  770. for(rc = chan; rc; rc >>=8){
  771. c = rc & 0xFF;
  772. switch(TYPE(c)){
  773. case CRed:
  774. fmt->red = (Colorfmt){(1<<NBITS(c))-1, shift};
  775. break;
  776. case CBlue:
  777. fmt->blue = (Colorfmt){(1<<NBITS(c))-1, shift};
  778. break;
  779. case CGreen:
  780. fmt->green = (Colorfmt){(1<<NBITS(c))-1, shift};
  781. break;
  782. }
  783. shift += NBITS(c);
  784. }
  785. }
  786. /*
  787. * Note that r has changed on the screen.
  788. * Updating the rlists is okay because they are protected by drawlock.
  789. */
  790. void
  791. flushmemscreen(Rectangle r)
  792. {
  793. Vncs *v;
  794. if(!rectclip(&r, gscreen->r))
  795. return;
  796. qlock(&clients);
  797. for(v=clients.head; v; v=v->next)
  798. addtorlist(&v->rlist, r);
  799. qunlock(&clients);
  800. }
  801. /*
  802. * Queue a mouse warp note for the next update to each client.
  803. */
  804. void
  805. mousewarpnote(Point p)
  806. {
  807. Vncs *v;
  808. qlock(&clients);
  809. for(v=clients.head; v; v=v->next){
  810. if(v->canwarp){
  811. vnclock(v);
  812. v->needwarp = 1;
  813. v->warppt = p;
  814. vncunlock(v);
  815. }
  816. }
  817. qunlock(&clients);
  818. }
  819. /*
  820. * Send a client his changed screen image.
  821. * v is locked on entrance, locked on exit, but released during.
  822. */
  823. static int
  824. updateimage(Vncs *v)
  825. {
  826. int i, ncount, nsend, docursor, needwarp;
  827. vlong ooffset;
  828. Point warppt;
  829. Rectangle cr;
  830. Rlist rlist;
  831. vlong t1;
  832. int (*count)(Vncs*, Rectangle);
  833. int (*send)(Vncs*, Rectangle);
  834. if(v->image == nil)
  835. return 0;
  836. /* warping info and unlock v so that updates can proceed */
  837. needwarp = v->canwarp && v->needwarp;
  838. warppt = v->warppt;
  839. v->needwarp = 0;
  840. vncunlock(v);
  841. /* copy the screen bits and then unlock the screen so updates can proceed */
  842. drawlock();
  843. rlist = v->rlist;
  844. memset(&v->rlist, 0, sizeof v->rlist);
  845. /* if the cursor has moved or changed shape, we need to redraw its square */
  846. lock(&cursor);
  847. if(v->cursorver != cursorver || !eqpt(v->cursorpos, cursorpos)){
  848. docursor = 1;
  849. v->cursorver = cursorver;
  850. v->cursorpos = cursorpos;
  851. cr = cursorrect();
  852. }else{
  853. docursor = 0;
  854. cr = v->cursorr;
  855. }
  856. unlock(&cursor);
  857. if(docursor){
  858. addtorlist(&rlist, v->cursorr);
  859. if(!rectclip(&cr, gscreen->r))
  860. cr.max = cr.min;
  861. addtorlist(&rlist, cr);
  862. }
  863. /* copy changed screen parts, also check for parts overlapping cursor location */
  864. for(i=0; i<rlist.nrect; i++){
  865. if(!docursor)
  866. docursor = rectXrect(v->cursorr, rlist.rect[i]);
  867. memimagedraw(v->image, rlist.rect[i], gscreen, rlist.rect[i].min, memopaque, ZP, S);
  868. }
  869. if(docursor){
  870. cursordraw(v->image, cr);
  871. addtorlist(&rlist, v->cursorr);
  872. v->cursorr = cr;
  873. }
  874. drawunlock();
  875. ooffset = Boffset(&v->out);
  876. /* no more locks are held; talk to the client */
  877. if(rlist.nrect == 0 && needwarp == 0){
  878. vnclock(v);
  879. return 0;
  880. }
  881. count = v->countrect;
  882. send = v->sendrect;
  883. if(count == nil || send == nil){
  884. count = countraw;
  885. send = sendraw;
  886. }
  887. ncount = 0;
  888. for(i=0; i<rlist.nrect; i++)
  889. ncount += (*count)(v, rlist.rect[i]);
  890. if(verbose > 1)
  891. fprint(2, "sendupdate: rlist.nrect=%d, ncount=%d", rlist.nrect, ncount);
  892. t1 = nsec();
  893. vncwrchar(v, MFrameUpdate);
  894. vncwrchar(v, 0);
  895. vncwrshort(v, ncount+needwarp);
  896. nsend = 0;
  897. for(i=0; i<rlist.nrect; i++)
  898. nsend += (*send)(v, rlist.rect[i]);
  899. if(ncount != nsend){
  900. fprint(2, "%V: ncount=%d, nsend=%d; hanging up\n", v, ncount, nsend);
  901. vnchungup(v);
  902. }
  903. if(needwarp){
  904. vncwrrect(v, Rect(warppt.x, warppt.y, warppt.x+1, warppt.y+1));
  905. vncwrlong(v, EncMouseWarp);
  906. }
  907. t1 = nsec() - t1;
  908. if(verbose > 1)
  909. fprint(2, " in %lldms, %lld bytes\n", t1/1000000, Boffset(&v->out) - ooffset);
  910. freerlist(&rlist);
  911. vnclock(v);
  912. return 1;
  913. }
  914. /*
  915. * Update the snarf buffer if it has changed.
  916. */
  917. static void
  918. updatesnarf(Vncs *v)
  919. {
  920. char *buf;
  921. int len;
  922. if(v->snarfvers == snarf.vers)
  923. return;
  924. vncunlock(v);
  925. qlock(&snarf);
  926. len = snarf.n;
  927. buf = malloc(len);
  928. if(buf == nil){
  929. qunlock(&snarf);
  930. vnclock(v);
  931. return;
  932. }
  933. memmove(buf, snarf.buf, len);
  934. v->snarfvers = snarf.vers;
  935. qunlock(&snarf);
  936. vncwrchar(v, MSCut);
  937. vncwrbytes(v, "pad", 3);
  938. vncwrlong(v, len);
  939. vncwrbytes(v, buf, len);
  940. free(buf);
  941. vnclock(v);
  942. }
  943. /*
  944. * Continually update one client.
  945. */
  946. static void
  947. clientwriteproc(Vncs *v)
  948. {
  949. char buf[32], buf2[32];
  950. int sent;
  951. vncname("write %V", v);
  952. for(;;){
  953. vnclock(v);
  954. if(v->ndead)
  955. break;
  956. if((v->image == nil && v->imagechan!=0)
  957. || (v->image && v->image->chan != v->imagechan)){
  958. if(v->image)
  959. freememimage(v->image);
  960. v->image = allocmemimage(Rpt(ZP, v->dim), v->imagechan);
  961. if(v->image == nil){
  962. fprint(2, "%V: allocmemimage: %r; hanging up\n", v);
  963. vnchungup(v);
  964. }
  965. if(verbose)
  966. fprint(2, "%V: translating image from chan=%s to chan=%s\n",
  967. v, chantostr(buf, gscreen->chan), chantostr(buf2, v->imagechan));
  968. }
  969. sent = 0;
  970. if(v->updaterequest){
  971. v->updaterequest = 0;
  972. updatesnarf(v);
  973. sent = updateimage(v);
  974. if(!sent)
  975. v->updaterequest = 1;
  976. }
  977. vncunlock(v);
  978. vncflush(v);
  979. if(!sent)
  980. sleep(sleeptime);
  981. }
  982. vncunlock(v);
  983. vnchungup(v);
  984. }