xref: /plan9/sys/src/cmd/vnc/vncv.c (revision 5e4924093ecb86f7174bf23023955abc83fb6962)
19a747e4fSDavid du Colombier #include "vnc.h"
29a747e4fSDavid du Colombier #include "vncv.h"
3f8e525acSDavid du Colombier #include <libsec.h>
49a747e4fSDavid du Colombier 
59a747e4fSDavid du Colombier char*	encodings = "copyrect hextile corre rre raw mousewarp";
69a747e4fSDavid du Colombier int		bpp12;
79a747e4fSDavid du Colombier int		shared;
89a747e4fSDavid du Colombier int		verbose;
99a747e4fSDavid du Colombier Vnc*		vnc;
109a747e4fSDavid du Colombier int		mousefd;
11f8e525acSDavid du Colombier int		tls;
129a747e4fSDavid du Colombier 
139a747e4fSDavid du Colombier static int	vncstart(Vnc*, int);
14f8e525acSDavid du Colombier 
159a747e4fSDavid du Colombier enum
169a747e4fSDavid du Colombier {
179a747e4fSDavid du Colombier 	NProcs	= 4
189a747e4fSDavid du Colombier };
199a747e4fSDavid du Colombier 
209a747e4fSDavid du Colombier static int pids[NProcs];
219a747e4fSDavid du Colombier static char killkin[] = "die vnc kin";
229a747e4fSDavid du Colombier 
239a747e4fSDavid du Colombier /*
249a747e4fSDavid du Colombier  * called by any proc when exiting to tear everything down.
259a747e4fSDavid du Colombier  */
269a747e4fSDavid du Colombier static void
shutdown(void)279a747e4fSDavid du Colombier shutdown(void)
289a747e4fSDavid du Colombier {
299a747e4fSDavid du Colombier 	int i, pid;
309a747e4fSDavid du Colombier 
319a747e4fSDavid du Colombier 	hangup(vnc->ctlfd);
329a747e4fSDavid du Colombier 	close(vnc->ctlfd);
339a747e4fSDavid du Colombier 	vnc->ctlfd = -1;
349a747e4fSDavid du Colombier 	close(vnc->datafd);
359a747e4fSDavid du Colombier 	vnc->datafd = -1;
369a747e4fSDavid du Colombier 
379a747e4fSDavid du Colombier 	pid = getpid();
389a747e4fSDavid du Colombier 	for(i = 0; i < NProcs; i++)
399a747e4fSDavid du Colombier 		if(pids[i] != pid)
409a747e4fSDavid du Colombier 			postnote(PNPROC, pids[i], killkin);
419a747e4fSDavid du Colombier }
429a747e4fSDavid du Colombier 
439a747e4fSDavid du Colombier char*
netmkvncaddr(char * inserver)449a747e4fSDavid du Colombier netmkvncaddr(char *inserver)
459a747e4fSDavid du Colombier {
469a747e4fSDavid du Colombier 	char *p, portstr[NETPATHLEN], *server;
479a747e4fSDavid du Colombier 	int port;
489a747e4fSDavid du Colombier 
499a747e4fSDavid du Colombier 	server = strdup(inserver);
509a747e4fSDavid du Colombier 	assert(server != nil);
519a747e4fSDavid du Colombier 
529a747e4fSDavid du Colombier 	port = 5900;
53f8e525acSDavid du Colombier 	if(tls)
54f8e525acSDavid du Colombier 		port = 35729;
559a747e4fSDavid du Colombier 	if(p = strchr(server, ':')) {
569a747e4fSDavid du Colombier 		*p++ = '\0';
579a747e4fSDavid du Colombier 		port += atoi(p);
589a747e4fSDavid du Colombier 	}
599a747e4fSDavid du Colombier 
609a747e4fSDavid du Colombier 	snprint(portstr, sizeof portstr, "%d", port);
61b7b24591SDavid du Colombier 	p = netmkaddr(server, "tcp", portstr);
629a747e4fSDavid du Colombier 	free(server);
639a747e4fSDavid du Colombier 	return p;
649a747e4fSDavid du Colombier }
659a747e4fSDavid du Colombier 
669a747e4fSDavid du Colombier void
vnchungup(Vnc *)679a747e4fSDavid du Colombier vnchungup(Vnc*)
689a747e4fSDavid du Colombier {
699a747e4fSDavid du Colombier 	sysfatal("connection closed");
709a747e4fSDavid du Colombier }
719a747e4fSDavid du Colombier 
729a747e4fSDavid du Colombier void
usage(void)739a747e4fSDavid du Colombier usage(void)
749a747e4fSDavid du Colombier {
75*5e492409SDavid du Colombier 	fprint(2, "usage: vncv [-e encodings] [-k keypattern] [-csv] host[:n]\n");
769a747e4fSDavid du Colombier 	exits("usage");
779a747e4fSDavid du Colombier }
789a747e4fSDavid du Colombier 
799a747e4fSDavid du Colombier void
main(int argc,char ** argv)809a747e4fSDavid du Colombier main(int argc, char **argv)
819a747e4fSDavid du Colombier {
82ebe1d0a8SDavid du Colombier 	int p, fd, dfd, cfd, shared;
83*5e492409SDavid du Colombier 	char *keypattern, *addr;
849a747e4fSDavid du Colombier 	Point d;
85f8e525acSDavid du Colombier 	TLSconn conn;
869a747e4fSDavid du Colombier 
87*5e492409SDavid du Colombier 	keypattern = nil;
889a747e4fSDavid du Colombier 	shared = 0;
899a747e4fSDavid du Colombier 	ARGBEGIN{
909a747e4fSDavid du Colombier 	case 'c':
919a747e4fSDavid du Colombier 		bpp12 = 1;
929a747e4fSDavid du Colombier 		break;
939a747e4fSDavid du Colombier 	case 'e':
94*5e492409SDavid du Colombier 		encodings = EARGF(usage());
959a747e4fSDavid du Colombier 		break;
969a747e4fSDavid du Colombier 	case 's':
979a747e4fSDavid du Colombier 		shared = 1;
989a747e4fSDavid du Colombier 		break;
99f8e525acSDavid du Colombier 	case 't':
100f8e525acSDavid du Colombier 		tls = 1;
101f8e525acSDavid du Colombier 		break;
1029a747e4fSDavid du Colombier 	case 'v':
1039a747e4fSDavid du Colombier 		verbose = 1;
1049a747e4fSDavid du Colombier 		break;
105*5e492409SDavid du Colombier 	case 'k':
106*5e492409SDavid du Colombier 		keypattern = EARGF(usage());
107*5e492409SDavid du Colombier 		break;
1089a747e4fSDavid du Colombier 	default:
1099a747e4fSDavid du Colombier 		usage();
1109a747e4fSDavid du Colombier 	}ARGEND;
1119a747e4fSDavid du Colombier 
1129a747e4fSDavid du Colombier 	if(argc != 1)
1139a747e4fSDavid du Colombier 		usage();
1149a747e4fSDavid du Colombier 
1159a747e4fSDavid du Colombier 	addr = netmkvncaddr(argv[0]);
116b7b24591SDavid du Colombier 	serveraddr = argv[0];
1179a747e4fSDavid du Colombier 	dfd = dial(addr, nil, nil, &cfd);
1189a747e4fSDavid du Colombier 	if(dfd < 0)
1199a747e4fSDavid du Colombier 		sysfatal("cannot dial %s: %r", addr);
120f8e525acSDavid du Colombier 	if(tls){
121f8e525acSDavid du Colombier 		dfd = tlsClient(dfd, &conn);
122f8e525acSDavid du Colombier 		if(dfd < 0)
123f8e525acSDavid du Colombier 			sysfatal("tlsClient: %r");
124f8e525acSDavid du Colombier 		/* XXX check thumbprint */
125f8e525acSDavid du Colombier 	}
1269a747e4fSDavid du Colombier 	vnc = vncinit(dfd, cfd, nil);
1279a747e4fSDavid du Colombier 
1289a747e4fSDavid du Colombier 	if(vnchandshake(vnc) < 0)
1299a747e4fSDavid du Colombier 		sysfatal("handshake failure: %r");
130*5e492409SDavid du Colombier 	if(vncauth(vnc, keypattern) < 0)
1319a747e4fSDavid du Colombier 		sysfatal("authentication failure: %r");
1329a747e4fSDavid du Colombier 	if(vncstart(vnc, shared) < 0)
1339a747e4fSDavid du Colombier 		sysfatal("init failure: %r");
1349a747e4fSDavid du Colombier 
1359a747e4fSDavid du Colombier 	initdraw(0, 0, "vncv");
1369a747e4fSDavid du Colombier 	display->locking = 1;
1379a747e4fSDavid du Colombier 	unlockdisplay(display);
1389a747e4fSDavid du Colombier 
1399a747e4fSDavid du Colombier 	d = addpt(vnc->dim, Pt(2*Borderwidth, 2*Borderwidth));
1409a747e4fSDavid du Colombier 	if(verbose)
1419a747e4fSDavid du Colombier 		fprint(2, "screen size %P, desktop size %P\n", display->image->r.max, d);
1429a747e4fSDavid du Colombier 
1439a747e4fSDavid du Colombier 	choosecolor(vnc);
1449a747e4fSDavid du Colombier 	sendencodings(vnc);
1459a747e4fSDavid du Colombier 	initmouse();
1469a747e4fSDavid du Colombier 
1479a747e4fSDavid du Colombier 	rfork(RFREND);
1489a747e4fSDavid du Colombier 	atexit(shutdown);
1499a747e4fSDavid du Colombier 	pids[0] = getpid();
1509a747e4fSDavid du Colombier 
1519a747e4fSDavid du Colombier 	switch(p = rfork(RFPROC|RFMEM)){
1529a747e4fSDavid du Colombier 	case -1:
1539a747e4fSDavid du Colombier 		sysfatal("rfork: %r");
1549a747e4fSDavid du Colombier 	default:
1559a747e4fSDavid du Colombier 		break;
1569a747e4fSDavid du Colombier 	case 0:
1579a747e4fSDavid du Colombier 		atexit(shutdown);
1589a747e4fSDavid du Colombier 		readfromserver(vnc);
1599a747e4fSDavid du Colombier 		exits(nil);
1609a747e4fSDavid du Colombier 	}
1619a747e4fSDavid du Colombier 	pids[1] = p;
1629a747e4fSDavid du Colombier 
1639a747e4fSDavid du Colombier 	switch(p = rfork(RFPROC|RFMEM)){
1649a747e4fSDavid du Colombier 	case -1:
1659a747e4fSDavid du Colombier 		sysfatal("rfork: %r");
1669a747e4fSDavid du Colombier 	default:
1679a747e4fSDavid du Colombier 		break;
1689a747e4fSDavid du Colombier 	case 0:
1699a747e4fSDavid du Colombier 		atexit(shutdown);
1709a747e4fSDavid du Colombier 		checksnarf(vnc);
1719a747e4fSDavid du Colombier 		exits(nil);
1729a747e4fSDavid du Colombier 	}
1739a747e4fSDavid du Colombier 	pids[2] = p;
1749a747e4fSDavid du Colombier 
175ebe1d0a8SDavid du Colombier 	fd = open("/dev/label", OWRITE);
176ebe1d0a8SDavid du Colombier 	if(fd >= 0){
177ebe1d0a8SDavid du Colombier 		fprint(fd, "vnc %s", serveraddr);
178ebe1d0a8SDavid du Colombier 		close(fd);
179ebe1d0a8SDavid du Colombier 	}
180f8e525acSDavid du Colombier 	if(access("/dev/snarf", AEXIST) >= 0){
1819a747e4fSDavid du Colombier 		switch(p = rfork(RFPROC|RFMEM)){
1829a747e4fSDavid du Colombier 		case -1:
1839a747e4fSDavid du Colombier 			sysfatal("rfork: %r");
1849a747e4fSDavid du Colombier 		default:
1859a747e4fSDavid du Colombier 			break;
1869a747e4fSDavid du Colombier 		case 0:
1879a747e4fSDavid du Colombier 			atexit(shutdown);
1889a747e4fSDavid du Colombier 			readkbd(vnc);
1899a747e4fSDavid du Colombier 			exits(nil);
1909a747e4fSDavid du Colombier 		}
1919a747e4fSDavid du Colombier 	}
1929a747e4fSDavid du Colombier 	pids[3] = p;
1939a747e4fSDavid du Colombier 
1949a747e4fSDavid du Colombier 	readmouse(vnc);
1959a747e4fSDavid du Colombier 	exits(nil);
1969a747e4fSDavid du Colombier }
1979a747e4fSDavid du Colombier 
1989a747e4fSDavid du Colombier static int
vncstart(Vnc * v,int shared)1999a747e4fSDavid du Colombier vncstart(Vnc *v, int shared)
2009a747e4fSDavid du Colombier {
2019a747e4fSDavid du Colombier 	vncwrchar(v, shared);
2029a747e4fSDavid du Colombier 	vncflush(v);
2039a747e4fSDavid du Colombier 	v->dim = vncrdpoint(v);
2049a747e4fSDavid du Colombier 	v->Pixfmt = vncrdpixfmt(v);
2059a747e4fSDavid du Colombier 	v->name = vncrdstring(v);
2069a747e4fSDavid du Colombier 	return 0;
2079a747e4fSDavid du Colombier }
208