1 #include "vnc.h"
2 #include "vncv.h"
3 #include <libsec.h>
4
5 char* encodings = "copyrect hextile corre rre raw mousewarp";
6 int bpp12;
7 int shared;
8 int verbose;
9 Vnc* vnc;
10 int mousefd;
11 int tls;
12
13 static int vncstart(Vnc*, int);
14
15 enum
16 {
17 NProcs = 4
18 };
19
20 static int pids[NProcs];
21 static char killkin[] = "die vnc kin";
22
23 /*
24 * called by any proc when exiting to tear everything down.
25 */
26 static void
shutdown(void)27 shutdown(void)
28 {
29 int i, pid;
30
31 hangup(vnc->ctlfd);
32 close(vnc->ctlfd);
33 vnc->ctlfd = -1;
34 close(vnc->datafd);
35 vnc->datafd = -1;
36
37 pid = getpid();
38 for(i = 0; i < NProcs; i++)
39 if(pids[i] != pid)
40 postnote(PNPROC, pids[i], killkin);
41 }
42
43 char*
netmkvncaddr(char * inserver)44 netmkvncaddr(char *inserver)
45 {
46 char *p, portstr[NETPATHLEN], *server;
47 int port;
48
49 server = strdup(inserver);
50 assert(server != nil);
51
52 port = 5900;
53 if(tls)
54 port = 35729;
55 if(p = strchr(server, ':')) {
56 *p++ = '\0';
57 port += atoi(p);
58 }
59
60 snprint(portstr, sizeof portstr, "%d", port);
61 p = netmkaddr(server, "tcp", portstr);
62 free(server);
63 return p;
64 }
65
66 void
vnchungup(Vnc *)67 vnchungup(Vnc*)
68 {
69 sysfatal("connection closed");
70 }
71
72 void
usage(void)73 usage(void)
74 {
75 fprint(2, "usage: vncv [-e encodings] [-k keypattern] [-csv] host[:n]\n");
76 exits("usage");
77 }
78
79 void
main(int argc,char ** argv)80 main(int argc, char **argv)
81 {
82 int p, fd, dfd, cfd, shared;
83 char *keypattern, *addr;
84 Point d;
85 TLSconn conn;
86
87 keypattern = nil;
88 shared = 0;
89 ARGBEGIN{
90 case 'c':
91 bpp12 = 1;
92 break;
93 case 'e':
94 encodings = EARGF(usage());
95 break;
96 case 's':
97 shared = 1;
98 break;
99 case 't':
100 tls = 1;
101 break;
102 case 'v':
103 verbose = 1;
104 break;
105 case 'k':
106 keypattern = EARGF(usage());
107 break;
108 default:
109 usage();
110 }ARGEND;
111
112 if(argc != 1)
113 usage();
114
115 addr = netmkvncaddr(argv[0]);
116 serveraddr = argv[0];
117 dfd = dial(addr, nil, nil, &cfd);
118 if(dfd < 0)
119 sysfatal("cannot dial %s: %r", addr);
120 if(tls){
121 dfd = tlsClient(dfd, &conn);
122 if(dfd < 0)
123 sysfatal("tlsClient: %r");
124 /* XXX check thumbprint */
125 }
126 vnc = vncinit(dfd, cfd, nil);
127
128 if(vnchandshake(vnc) < 0)
129 sysfatal("handshake failure: %r");
130 if(vncauth(vnc, keypattern) < 0)
131 sysfatal("authentication failure: %r");
132 if(vncstart(vnc, shared) < 0)
133 sysfatal("init failure: %r");
134
135 initdraw(0, 0, "vncv");
136 display->locking = 1;
137 unlockdisplay(display);
138
139 d = addpt(vnc->dim, Pt(2*Borderwidth, 2*Borderwidth));
140 if(verbose)
141 fprint(2, "screen size %P, desktop size %P\n", display->image->r.max, d);
142
143 choosecolor(vnc);
144 sendencodings(vnc);
145 initmouse();
146
147 rfork(RFREND);
148 atexit(shutdown);
149 pids[0] = getpid();
150
151 switch(p = rfork(RFPROC|RFMEM)){
152 case -1:
153 sysfatal("rfork: %r");
154 default:
155 break;
156 case 0:
157 atexit(shutdown);
158 readfromserver(vnc);
159 exits(nil);
160 }
161 pids[1] = p;
162
163 switch(p = rfork(RFPROC|RFMEM)){
164 case -1:
165 sysfatal("rfork: %r");
166 default:
167 break;
168 case 0:
169 atexit(shutdown);
170 checksnarf(vnc);
171 exits(nil);
172 }
173 pids[2] = p;
174
175 fd = open("/dev/label", OWRITE);
176 if(fd >= 0){
177 fprint(fd, "vnc %s", serveraddr);
178 close(fd);
179 }
180 if(access("/dev/snarf", AEXIST) >= 0){
181 switch(p = rfork(RFPROC|RFMEM)){
182 case -1:
183 sysfatal("rfork: %r");
184 default:
185 break;
186 case 0:
187 atexit(shutdown);
188 readkbd(vnc);
189 exits(nil);
190 }
191 }
192 pids[3] = p;
193
194 readmouse(vnc);
195 exits(nil);
196 }
197
198 static int
vncstart(Vnc * v,int shared)199 vncstart(Vnc *v, int shared)
200 {
201 vncwrchar(v, shared);
202 vncflush(v);
203 v->dim = vncrdpoint(v);
204 v->Pixfmt = vncrdpixfmt(v);
205 v->name = vncrdstring(v);
206 return 0;
207 }
208