1 #include "vnc.h"
2
3 #define SHORT(p) (((p)[0]<<8)|((p)[1]))
4 #define LONG(p) ((SHORT(p)<<16)|SHORT(p+2))
5
6 uchar zero[64];
7
8 Vnc*
vncinit(int fd,int cfd,Vnc * v)9 vncinit(int fd, int cfd, Vnc *v)
10 {
11 if(v == nil)
12 v = mallocz(sizeof(*v), 1);
13 Binit(&v->in, fd, OREAD);
14 Binit(&v->out, fd, OWRITE);
15 v->datafd = fd;
16 v->ctlfd = cfd;
17 return v;
18 }
19
20 void
vncterm(Vnc * v)21 vncterm(Vnc *v)
22 {
23 Bterm(&v->out);
24 Bterm(&v->in);
25 }
26
27 void
vncflush(Vnc * v)28 vncflush(Vnc *v)
29 {
30 if(Bflush(&v->out) < 0){
31 if(verbose > 1)
32 fprint(2, "hungup while sending flush: %r\n");
33 vnchungup(v);
34 }
35 }
36
37 uchar
vncrdchar(Vnc * v)38 vncrdchar(Vnc *v)
39 {
40 uchar buf[1];
41
42 vncrdbytes(v, buf, 1);
43 return buf[0];
44 }
45
46 ushort
vncrdshort(Vnc * v)47 vncrdshort(Vnc *v)
48 {
49 uchar buf[2];
50
51 vncrdbytes(v, buf, 2);
52 return SHORT(buf);
53 }
54
55 ulong
vncrdlong(Vnc * v)56 vncrdlong(Vnc *v)
57 {
58 uchar buf[4];
59
60 vncrdbytes(v, buf, 4);
61 return LONG(buf);
62 }
63
64 Point
vncrdpoint(Vnc * v)65 vncrdpoint(Vnc *v)
66 {
67 Point p;
68
69 p.x = vncrdshort(v);
70 p.y = vncrdshort(v);
71 return p;
72 }
73
74 Rectangle
vncrdrect(Vnc * v)75 vncrdrect(Vnc *v)
76 {
77 Rectangle r;
78
79 r.min.x = vncrdshort(v);
80 r.min.y = vncrdshort(v);
81 r.max.x = r.min.x + vncrdshort(v);
82 r.max.y = r.min.y + vncrdshort(v);
83 return r;
84 }
85
86 Rectangle
vncrdcorect(Vnc * v)87 vncrdcorect(Vnc *v)
88 {
89 Rectangle r;
90
91 r.min.x = vncrdchar(v);
92 r.min.y = vncrdchar(v);
93 r.max.x = r.min.x + vncrdchar(v);
94 r.max.y = r.min.y + vncrdchar(v);
95 return r;
96 }
97
98 void
vncrdbytes(Vnc * v,void * a,int n)99 vncrdbytes(Vnc *v, void *a, int n)
100 {
101 if(Bread(&v->in, a, n) != n){
102 if(verbose > 1)
103 fprint(2, "hungup while reading\n");
104 vnchungup(v);
105 }
106 }
107
108 Pixfmt
vncrdpixfmt(Vnc * v)109 vncrdpixfmt(Vnc *v)
110 {
111 Pixfmt fmt;
112 uchar pad[3];
113
114 fmt.bpp = vncrdchar(v);
115 fmt.depth = vncrdchar(v);
116 fmt.bigendian = vncrdchar(v);
117 fmt.truecolor = vncrdchar(v);
118 fmt.red.max = vncrdshort(v);
119 fmt.green.max = vncrdshort(v);
120 fmt.blue.max = vncrdshort(v);
121 fmt.red.shift = vncrdchar(v);
122 fmt.green.shift = vncrdchar(v);
123 fmt.blue.shift = vncrdchar(v);
124 vncrdbytes(v, pad, 3);
125 return fmt;
126 }
127
128 char*
vncrdstring(Vnc * v)129 vncrdstring(Vnc *v)
130 {
131 ulong len;
132 char *s;
133
134 len = vncrdlong(v);
135 s = malloc(len+1);
136 assert(s != nil);
137
138 vncrdbytes(v, s, len);
139 s[len] = '\0';
140 return s;
141 }
142
143 /*
144 * on the server side of the negotiation protocol, we read
145 * the client response and then run the negotiated function.
146 * in some cases (e.g., TLS) the negotiated function needs to
147 * use v->datafd directly and be sure that no data has been
148 * buffered away in the Bio. since we know the client is waiting
149 * for our response, it won't have sent any until we respond.
150 * thus we read the response with vncrdstringx, which goes
151 * behind bio's back.
152 */
153 char*
vncrdstringx(Vnc * v)154 vncrdstringx(Vnc *v)
155 {
156 char tmp[4];
157 char *s;
158 ulong len;
159
160 assert(Bbuffered(&v->in) == 0);
161 if(readn(v->datafd, tmp, 4) != 4){
162 fprint(2, "cannot rdstringx: %r");
163 vnchungup(v);
164 }
165 len = LONG(tmp);
166 s = malloc(len+1);
167 assert(s != nil);
168 if(readn(v->datafd, s, len) != len){
169 fprint(2, "cannot rdstringx len %lud: %r", len);
170 vnchungup(v);
171 }
172 s[len] = '\0';
173 return s;
174 }
175
176 void
vncwrstring(Vnc * v,char * s)177 vncwrstring(Vnc *v, char *s)
178 {
179 ulong len;
180
181 len = strlen(s);
182 vncwrlong(v, len);
183 vncwrbytes(v, s, len);
184 }
185
186 void
vncwrbytes(Vnc * v,void * a,int n)187 vncwrbytes(Vnc *v, void *a, int n)
188 {
189 if(Bwrite(&v->out, a, n) < 0){
190 if(verbose > 1)
191 fprint(2, "hungup while writing bytes\n");
192 vnchungup(v);
193 }
194 }
195
196 void
vncwrlong(Vnc * v,ulong u)197 vncwrlong(Vnc *v, ulong u)
198 {
199 uchar buf[4];
200
201 buf[0] = u>>24;
202 buf[1] = u>>16;
203 buf[2] = u>>8;
204 buf[3] = u;
205 vncwrbytes(v, buf, 4);
206 }
207
208 void
vncwrshort(Vnc * v,ushort u)209 vncwrshort(Vnc *v, ushort u)
210 {
211 uchar buf[2];
212
213 buf[0] = u>>8;
214 buf[1] = u;
215 vncwrbytes(v, buf, 2);
216 }
217
218 void
vncwrchar(Vnc * v,uchar c)219 vncwrchar(Vnc *v, uchar c)
220 {
221 vncwrbytes(v, &c, 1);
222 }
223
224 void
vncwrpixfmt(Vnc * v,Pixfmt * fmt)225 vncwrpixfmt(Vnc *v, Pixfmt *fmt)
226 {
227 vncwrchar(v, fmt->bpp);
228 vncwrchar(v, fmt->depth);
229 vncwrchar(v, fmt->bigendian);
230 vncwrchar(v, fmt->truecolor);
231 vncwrshort(v, fmt->red.max);
232 vncwrshort(v, fmt->green.max);
233 vncwrshort(v, fmt->blue.max);
234 vncwrchar(v, fmt->red.shift);
235 vncwrchar(v, fmt->green.shift);
236 vncwrchar(v, fmt->blue.shift);
237 vncwrbytes(v, zero, 3);
238 }
239
240 void
vncwrrect(Vnc * v,Rectangle r)241 vncwrrect(Vnc *v, Rectangle r)
242 {
243 vncwrshort(v, r.min.x);
244 vncwrshort(v, r.min.y);
245 vncwrshort(v, r.max.x-r.min.x);
246 vncwrshort(v, r.max.y-r.min.y);
247 }
248
249 void
vncwrpoint(Vnc * v,Point p)250 vncwrpoint(Vnc *v, Point p)
251 {
252 vncwrshort(v, p.x);
253 vncwrshort(v, p.y);
254 }
255
256 void
vnclock(Vnc * v)257 vnclock(Vnc *v)
258 {
259 qlock(v);
260 }
261
262 void
vncunlock(Vnc * v)263 vncunlock(Vnc *v)
264 {
265 qunlock(v);
266 }
267
268 void
hexdump(void * a,int n)269 hexdump(void *a, int n)
270 {
271 uchar *p, *ep;
272
273 p = a;
274 ep = p+n;
275
276 for(; p<ep; p++)
277 print("%.2ux ", *p);
278 print("\n");
279 }
280
281 void
vncgobble(Vnc * v,long n)282 vncgobble(Vnc *v, long n)
283 {
284 uchar buf[8192];
285 long m;
286
287 while(n > 0){
288 m = n;
289 if(m > sizeof(buf))
290 m = sizeof(buf);
291 vncrdbytes(v, buf, m);
292 n -= m;
293 }
294 }
295