ia64/xen-unstable

view tools/ioemu/vnc.c @ 12789:c7f4a89eb054

Fix numpad handling in QEMU's VNC server. The keymaps that we have include
information on which keys change depending upon the numlock setting, but
this isn't being used. By forcing numlock on and off as necessary, when
receiving these keysyms through the VNC connection, we ensure that the
server's numlock status is the same as the client's.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Mon Dec 04 17:52:33 2006 +0000 (2006-12-04)
parents 582d21e2d3cd
children ede2f5280810
line source
1 /*
2 * QEMU VNC display driver
3 *
4 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5 * Copyright (C) 2006 Fabrice Bellard
6 * Copyright (C) 2006 Christian Limpach <Christian.Limpach@xensource.com>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
27 #include "vl.h"
28 #include "qemu_socket.h"
29 #include <assert.h>
31 /* The refresh interval starts at BASE. If we scan the buffer and
32 find no change, we increase by INC, up to MAX. If the mouse moves
33 or we get a keypress, the interval is set back to BASE. If we find
34 an update, halve the interval.
36 All times in milliseconds. */
37 #define VNC_REFRESH_INTERVAL_BASE 30
38 #define VNC_REFRESH_INTERVAL_INC 50
39 #define VNC_REFRESH_INTERVAL_MAX 2000
41 /* Wait at most one second between updates, so that we can detect a
42 minimised vncviewer reasonably quickly. */
43 #define VNC_MAX_UPDATE_INTERVAL 5000
45 #include "vnc_keysym.h"
46 #include "keymaps.c"
47 #include "d3des.h"
49 #define XK_MISCELLANY
50 #define XK_LATIN1
51 #include <X11/keysymdef.h>
53 typedef struct Buffer
54 {
55 size_t capacity;
56 size_t offset;
57 char *buffer;
58 } Buffer;
60 typedef struct VncState VncState;
62 typedef int VncReadEvent(VncState *vs, char *data, size_t len);
64 typedef void VncWritePixels(VncState *vs, void *data, int size);
66 typedef void VncSendHextileTile(VncState *vs,
67 int x, int y, int w, int h,
68 uint32_t *last_bg,
69 uint32_t *last_fg,
70 int *has_bg, int *has_fg);
72 #if 0
73 #define VNC_MAX_WIDTH 2048
74 #define VNC_MAX_HEIGHT 2048
75 #define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
76 #endif
78 struct VncState
79 {
80 QEMUTimer *timer;
81 int timer_interval;
82 int64_t last_update_time;
83 int lsock;
84 int csock;
85 DisplayState *ds;
86 int width;
87 int height;
88 uint64_t *dirty_row; /* screen regions which are possibly dirty */
89 int dirty_pixel_shift;
90 uint64_t *update_row; /* outstanding updates */
91 int has_update; /* there's outstanding updates in the
92 * visible area */
93 char *old_data;
94 int depth; /* internal VNC frame buffer byte per pixel */
95 int has_resize;
96 int has_hextile;
97 Buffer output;
98 Buffer input;
99 kbd_layout_t *kbd_layout;
100 /* current output mode information */
101 VncWritePixels *write_pixels;
102 VncSendHextileTile *send_hextile_tile;
103 int pix_bpp, pix_big_endian;
104 int red_shift, red_max, red_shift1;
105 int green_shift, green_max, green_shift1;
106 int blue_shift, blue_max, blue_shift1;
108 VncReadEvent *read_handler;
109 size_t read_handler_expect;
111 int visible_x;
112 int visible_y;
113 int visible_w;
114 int visible_h;
116 int ctl_keys; /* Ctrl+Alt starts calibration */
117 int shift_keys; /* Shift / CapsLock keys */
118 int numlock;
119 };
121 #define DIRTY_PIXEL_BITS 64
122 #define X2DP_DOWN(vs, x) ((x) >> (vs)->dirty_pixel_shift)
123 #define X2DP_UP(vs, x) \
124 (((x) + (1ULL << (vs)->dirty_pixel_shift) - 1) >> (vs)->dirty_pixel_shift)
125 #define DP2X(vs, x) ((x) << (vs)->dirty_pixel_shift)
127 /* TODO
128 1) Get the queue working for IO.
129 2) there is some weirdness when using the -S option (the screen is grey
130 and not totally invalidated
131 */
133 static void vnc_write(VncState *vs, const void *data, size_t len);
134 static void vnc_write_u32(VncState *vs, uint32_t value);
135 static void vnc_write_s32(VncState *vs, int32_t value);
136 static void vnc_write_u16(VncState *vs, uint16_t value);
137 static void vnc_write_u8(VncState *vs, uint8_t value);
138 static void vnc_flush(VncState *vs);
139 static void _vnc_update_client(void *opaque);
140 static void vnc_update_client(void *opaque);
141 static void vnc_client_read(void *opaque);
142 static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h);
143 static int make_challenge(char *random, int size);
144 static void set_seed(unsigned int *seedp);
145 static void get_random(int len, unsigned char *buf);
147 #if 0
148 static inline void vnc_set_bit(uint32_t *d, int k)
149 {
150 d[k >> 5] |= 1 << (k & 0x1f);
151 }
153 static inline void vnc_clear_bit(uint32_t *d, int k)
154 {
155 d[k >> 5] &= ~(1 << (k & 0x1f));
156 }
158 static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
159 {
160 int j;
162 j = 0;
163 while (n >= 32) {
164 d[j++] = -1;
165 n -= 32;
166 }
167 if (n > 0)
168 d[j++] = (1 << n) - 1;
169 while (j < nb_words)
170 d[j++] = 0;
171 }
173 static inline int vnc_get_bit(const uint32_t *d, int k)
174 {
175 return (d[k >> 5] >> (k & 0x1f)) & 1;
176 }
178 static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
179 int nb_words)
180 {
181 int i;
182 for(i = 0; i < nb_words; i++) {
183 if ((d1[i] & d2[i]) != 0)
184 return 1;
185 }
186 return 0;
187 }
188 #endif
190 static void set_bits_in_row(VncState *vs, uint64_t *row,
191 int x, int y, int w, int h)
192 {
193 int x1, x2;
194 uint64_t mask;
196 if (w == 0)
197 return;
199 x1 = X2DP_DOWN(vs, x);
200 x2 = X2DP_UP(vs, x + w);
202 if (X2DP_UP(vs, w) != DIRTY_PIXEL_BITS)
203 mask = ((1ULL << (x2 - x1)) - 1) << x1;
204 else
205 mask = ~(0ULL);
207 h += y;
208 if (h > vs->ds->height)
209 h = vs->ds->height;
210 for (; y < h; y++)
211 row[y] |= mask;
212 }
214 static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
215 {
216 VncState *vs = ds->opaque;
218 set_bits_in_row(vs, vs->dirty_row, x, y, w, h);
219 }
221 static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
222 int32_t encoding)
223 {
224 vnc_write_u16(vs, x);
225 vnc_write_u16(vs, y);
226 vnc_write_u16(vs, w);
227 vnc_write_u16(vs, h);
229 vnc_write_s32(vs, encoding);
230 }
232 static void vnc_dpy_resize(DisplayState *ds, int w, int h)
233 {
234 VncState *vs = ds->opaque;
235 int o;
237 ds->data = realloc(ds->data, w * h * vs->depth);
238 vs->old_data = realloc(vs->old_data, w * h * vs->depth);
239 vs->dirty_row = realloc(vs->dirty_row, h * sizeof(vs->dirty_row[0]));
240 vs->update_row = realloc(vs->update_row, h * sizeof(vs->dirty_row[0]));
242 if (ds->data == NULL || vs->old_data == NULL ||
243 vs->dirty_row == NULL || vs->update_row == NULL) {
244 fprintf(stderr, "vnc: memory allocation failed\n");
245 exit(1);
246 }
248 if (ds->depth != vs->depth * 8) {
249 ds->depth = vs->depth * 8;
250 set_color_table(ds);
251 }
252 ds->width = w;
253 ds->height = h;
254 ds->linesize = w * vs->depth;
255 if (vs->csock != -1 && vs->has_resize) {
256 vnc_write_u8(vs, 0); /* msg id */
257 vnc_write_u8(vs, 0);
258 vnc_write_u16(vs, 1); /* number of rects */
259 vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223);
260 vnc_flush(vs);
261 vs->width = ds->width;
262 vs->height = ds->height;
263 }
264 vs->dirty_pixel_shift = 0;
265 for (o = DIRTY_PIXEL_BITS; o < ds->width; o *= 2)
266 vs->dirty_pixel_shift++;
267 framebuffer_set_updated(vs, 0, 0, ds->width, ds->height);
268 }
270 /* fastest code */
271 static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
272 {
273 vnc_write(vs, pixels, size);
274 }
276 /* slowest but generic code. */
277 static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
278 {
279 unsigned int r, g, b;
281 r = (v >> vs->red_shift1) & vs->red_max;
282 g = (v >> vs->green_shift1) & vs->green_max;
283 b = (v >> vs->blue_shift1) & vs->blue_max;
284 v = (r << vs->red_shift) |
285 (g << vs->green_shift) |
286 (b << vs->blue_shift);
287 switch(vs->pix_bpp) {
288 case 1:
289 buf[0] = v;
290 break;
291 case 2:
292 if (vs->pix_big_endian) {
293 buf[0] = v >> 8;
294 buf[1] = v;
295 } else {
296 buf[1] = v >> 8;
297 buf[0] = v;
298 }
299 break;
300 default:
301 case 4:
302 if (vs->pix_big_endian) {
303 buf[0] = v >> 24;
304 buf[1] = v >> 16;
305 buf[2] = v >> 8;
306 buf[3] = v;
307 } else {
308 buf[3] = v >> 24;
309 buf[2] = v >> 16;
310 buf[1] = v >> 8;
311 buf[0] = v;
312 }
313 break;
314 }
315 }
317 static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
318 {
319 uint32_t *pixels = pixels1;
320 uint8_t buf[4];
321 int n, i;
323 n = size >> 2;
324 for(i = 0; i < n; i++) {
325 vnc_convert_pixel(vs, buf, pixels[i]);
326 vnc_write(vs, buf, vs->pix_bpp);
327 }
328 }
330 static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
331 {
332 int i;
333 char *row;
335 vnc_framebuffer_update(vs, x, y, w, h, 0);
337 row = vs->ds->data + y * vs->ds->linesize + x * vs->depth;
338 for (i = 0; i < h; i++) {
339 vs->write_pixels(vs, row, w * vs->depth);
340 row += vs->ds->linesize;
341 }
342 }
344 static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
345 {
346 ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
347 ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
348 }
350 #define BPP 8
351 #include "vnchextile.h"
352 #undef BPP
354 #define BPP 16
355 #include "vnchextile.h"
356 #undef BPP
358 #define BPP 32
359 #include "vnchextile.h"
360 #undef BPP
362 #define GENERIC
363 #define BPP 32
364 #include "vnchextile.h"
365 #undef BPP
366 #undef GENERIC
368 static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
369 {
370 int i, j;
371 int has_fg, has_bg;
372 uint32_t last_fg32, last_bg32;
374 vnc_framebuffer_update(vs, x, y, w, h, 5);
376 has_fg = has_bg = 0;
377 for (j = y; j < (y + h); j += 16) {
378 for (i = x; i < (x + w); i += 16) {
379 vs->send_hextile_tile(vs, i, j,
380 MIN(16, x + w - i), MIN(16, y + h - j),
381 &last_bg32, &last_fg32, &has_bg, &has_fg);
382 }
383 }
384 }
386 static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
387 {
388 if (vs->has_hextile)
389 send_framebuffer_update_hextile(vs, x, y, w, h);
390 else
391 send_framebuffer_update_raw(vs, x, y, w, h);
392 }
394 static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
395 {
396 int src, dst;
397 char *src_row;
398 char *dst_row;
399 char *old_row;
400 int y = 0;
401 int pitch = ds->linesize;
402 VncState *vs = ds->opaque;
403 int updating_client = 1;
405 if (src_x < vs->visible_x || src_y < vs->visible_y ||
406 dst_x < vs->visible_x || dst_y < vs->visible_y ||
407 (src_x + w) > (vs->visible_x + vs->visible_w) ||
408 (src_y + h) > (vs->visible_y + vs->visible_h) ||
409 (dst_x + w) > (vs->visible_x + vs->visible_w) ||
410 (dst_y + h) > (vs->visible_y + vs->visible_h))
411 updating_client = 0;
413 if (updating_client)
414 _vnc_update_client(vs);
416 if (dst_y > src_y) {
417 y = h - 1;
418 pitch = -pitch;
419 }
421 src = (ds->linesize * (src_y + y) + vs->depth * src_x);
422 dst = (ds->linesize * (dst_y + y) + vs->depth * dst_x);
424 src_row = ds->data + src;
425 dst_row = ds->data + dst;
426 old_row = vs->old_data + dst;
428 for (y = 0; y < h; y++) {
429 memmove(old_row, src_row, w * vs->depth);
430 memmove(dst_row, src_row, w * vs->depth);
431 src_row += pitch;
432 dst_row += pitch;
433 old_row += pitch;
434 }
436 if (updating_client && vs->csock != -1 && !vs->has_update) {
437 vnc_write_u8(vs, 0); /* msg id */
438 vnc_write_u8(vs, 0);
439 vnc_write_u16(vs, 1); /* number of rects */
440 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, 1);
441 vnc_write_u16(vs, src_x);
442 vnc_write_u16(vs, src_y);
443 vnc_flush(vs);
444 } else
445 framebuffer_set_updated(vs, dst_x, dst_y, w, h);
446 }
448 static int find_update_height(VncState *vs, int y, int maxy, int last_x, int x)
449 {
450 int h;
452 for (h = 1; y + h < maxy; h++) {
453 int tmp_x;
454 if (!(vs->update_row[y + h] & (1ULL << last_x)))
455 break;
456 for (tmp_x = last_x; tmp_x < x; tmp_x++)
457 vs->update_row[y + h] &= ~(1ULL << tmp_x);
458 }
460 return h;
461 }
463 static void _vnc_update_client(void *opaque)
464 {
465 VncState *vs = opaque;
466 int64_t now;
467 int y;
468 char *row;
469 char *old_row;
470 uint64_t width_mask;
471 int n_rectangles;
472 int saved_offset;
473 int maxx, maxy;
474 int tile_bytes = vs->depth * DP2X(vs, 1);
476 if (vs->csock == -1)
477 return;
479 now = qemu_get_clock(rt_clock);
481 if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))
482 width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;
483 else
484 width_mask = ~(0ULL);
486 /* Walk through the dirty map and eliminate tiles that really
487 aren't dirty */
488 row = vs->ds->data;
489 old_row = vs->old_data;
491 for (y = 0; y < vs->ds->height; y++) {
492 if (vs->dirty_row[y] & width_mask) {
493 int x;
494 char *ptr, *old_ptr;
496 ptr = row;
497 old_ptr = old_row;
499 for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) {
500 if (vs->dirty_row[y] & (1ULL << x)) {
501 if (memcmp(old_ptr, ptr, tile_bytes)) {
502 vs->has_update = 1;
503 vs->update_row[y] |= (1ULL << x);
504 memcpy(old_ptr, ptr, tile_bytes);
505 }
506 vs->dirty_row[y] &= ~(1ULL << x);
507 }
509 ptr += tile_bytes;
510 old_ptr += tile_bytes;
511 }
512 }
514 row += vs->ds->linesize;
515 old_row += vs->ds->linesize;
516 }
518 if (!vs->has_update || vs->visible_y >= vs->ds->height ||
519 vs->visible_x >= vs->ds->width)
520 goto backoff;
522 /* Count rectangles */
523 n_rectangles = 0;
524 vnc_write_u8(vs, 0); /* msg id */
525 vnc_write_u8(vs, 0);
526 saved_offset = vs->output.offset;
527 vnc_write_u16(vs, 0);
529 maxy = vs->visible_y + vs->visible_h;
530 if (maxy > vs->ds->height)
531 maxy = vs->ds->height;
532 maxx = vs->visible_x + vs->visible_w;
533 if (maxx > vs->ds->width)
534 maxx = vs->ds->width;
536 for (y = vs->visible_y; y < maxy; y++) {
537 int x;
538 int last_x = -1;
539 for (x = X2DP_DOWN(vs, vs->visible_x);
540 x < X2DP_UP(vs, maxx); x++) {
541 if (vs->update_row[y] & (1ULL << x)) {
542 if (last_x == -1)
543 last_x = x;
544 vs->update_row[y] &= ~(1ULL << x);
545 } else {
546 if (last_x != -1) {
547 int h = find_update_height(vs, y, maxy, last_x, x);
548 if (h != 0) {
549 send_framebuffer_update(vs, DP2X(vs, last_x), y,
550 DP2X(vs, (x - last_x)), h);
551 n_rectangles++;
552 }
553 }
554 last_x = -1;
555 }
556 }
557 if (last_x != -1) {
558 int h = find_update_height(vs, y, maxy, last_x, x);
559 if (h != 0) {
560 send_framebuffer_update(vs, DP2X(vs, last_x), y,
561 DP2X(vs, (x - last_x)), h);
562 n_rectangles++;
563 }
564 }
565 }
566 vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
567 vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
569 if (n_rectangles == 0)
570 goto backoff;
572 vs->has_update = 0;
573 vnc_flush(vs);
574 vs->last_update_time = now;
576 vs->timer_interval /= 2;
577 if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE)
578 vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
580 return;
582 backoff:
583 /* No update -> back off a bit */
584 vs->timer_interval += VNC_REFRESH_INTERVAL_INC;
585 if (vs->timer_interval > VNC_REFRESH_INTERVAL_MAX) {
586 vs->timer_interval = VNC_REFRESH_INTERVAL_MAX;
587 if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) {
588 /* Send a null update. If the client is no longer
589 interested (e.g. minimised) it'll ignore this, and we
590 can stop scanning the buffer until it sends another
591 update request. */
592 /* It turns out that there's a bug in realvncviewer 4.1.2
593 which means that if you send a proper null update (with
594 no update rectangles), it gets a bit out of sync and
595 never sends any further requests, regardless of whether
596 it needs one or not. Fix this by sending a single 1x1
597 update rectangle instead. */
598 vnc_write_u8(vs, 0);
599 vnc_write_u8(vs, 0);
600 vnc_write_u16(vs, 1);
601 send_framebuffer_update(vs, 0, 0, 1, 1);
602 vnc_flush(vs);
603 vs->last_update_time = now;
604 return;
605 }
606 }
607 qemu_mod_timer(vs->timer, now + vs->timer_interval);
608 return;
609 }
611 static void vnc_update_client(void *opaque)
612 {
613 VncState *vs = opaque;
615 vs->ds->dpy_refresh(vs->ds);
616 _vnc_update_client(vs);
617 }
619 static void vnc_timer_init(VncState *vs)
620 {
621 if (vs->timer == NULL) {
622 vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
623 vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
624 }
625 }
627 static void vnc_dpy_refresh(DisplayState *ds)
628 {
629 vga_hw_update();
630 }
632 static int vnc_listen_poll(void *opaque)
633 {
634 VncState *vs = opaque;
635 if (vs->csock == -1)
636 return 1;
637 return 0;
638 }
640 static void buffer_reserve(Buffer *buffer, size_t len)
641 {
642 if ((buffer->capacity - buffer->offset) < len) {
643 buffer->capacity += (len + 1024);
644 buffer->buffer = realloc(buffer->buffer, buffer->capacity);
645 if (buffer->buffer == NULL) {
646 fprintf(stderr, "vnc: out of memory\n");
647 exit(1);
648 }
649 }
650 }
652 static int buffer_empty(Buffer *buffer)
653 {
654 return buffer->offset == 0;
655 }
657 static char *buffer_end(Buffer *buffer)
658 {
659 return buffer->buffer + buffer->offset;
660 }
662 static void buffer_reset(Buffer *buffer)
663 {
664 buffer->offset = 0;
665 }
667 static void buffer_append(Buffer *buffer, const void *data, size_t len)
668 {
669 memcpy(buffer->buffer + buffer->offset, data, len);
670 buffer->offset += len;
671 }
673 static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
674 {
675 if (ret == 0 || ret == -1) {
676 if (ret == -1 && (last_errno == EINTR || last_errno == EAGAIN))
677 return 0;
679 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
680 closesocket(vs->csock);
681 vs->csock = -1;
682 buffer_reset(&vs->input);
683 buffer_reset(&vs->output);
684 return 0;
685 }
686 return ret;
687 }
689 static void vnc_client_error(VncState *vs)
690 {
691 vnc_client_io_error(vs, -1, EINVAL);
692 }
694 static void vnc_client_write(void *opaque)
695 {
696 long ret;
697 VncState *vs = opaque;
699 ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
700 ret = vnc_client_io_error(vs, ret, socket_error());
701 if (!ret)
702 return;
704 memmove(vs->output.buffer, vs->output.buffer + ret,
705 vs->output.offset - ret);
706 vs->output.offset -= ret;
708 if (vs->output.offset == 0)
709 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
710 }
712 static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
713 {
714 vs->read_handler = func;
715 vs->read_handler_expect = expecting;
716 }
718 static void vnc_client_read(void *opaque)
719 {
720 VncState *vs = opaque;
721 long ret;
723 buffer_reserve(&vs->input, 4096);
725 ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
726 ret = vnc_client_io_error(vs, ret, socket_error());
727 if (!ret)
728 return;
730 vs->input.offset += ret;
732 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
733 size_t len = vs->read_handler_expect;
734 int ret;
736 ret = vs->read_handler(vs, vs->input.buffer, len);
737 if (vs->csock == -1)
738 return;
740 if (!ret) {
741 memmove(vs->input.buffer, vs->input.buffer + len,
742 vs->input.offset - len);
743 vs->input.offset -= len;
744 } else {
745 assert(ret > vs->read_handler_expect);
746 vs->read_handler_expect = ret;
747 }
748 }
749 }
751 static void vnc_write(VncState *vs, const void *data, size_t len)
752 {
753 buffer_reserve(&vs->output, len);
755 if (buffer_empty(&vs->output))
756 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read,
757 vnc_client_write, vs);
759 buffer_append(&vs->output, data, len);
760 }
762 static void vnc_write_s32(VncState *vs, int32_t value)
763 {
764 vnc_write_u32(vs, *(uint32_t *)&value);
765 }
767 static void vnc_write_u32(VncState *vs, uint32_t value)
768 {
769 uint8_t buf[4];
771 buf[0] = (value >> 24) & 0xFF;
772 buf[1] = (value >> 16) & 0xFF;
773 buf[2] = (value >> 8) & 0xFF;
774 buf[3] = value & 0xFF;
776 vnc_write(vs, buf, 4);
777 }
779 static void vnc_write_u16(VncState *vs, uint16_t value)
780 {
781 char buf[2];
783 buf[0] = (value >> 8) & 0xFF;
784 buf[1] = value & 0xFF;
786 vnc_write(vs, buf, 2);
787 }
789 static void vnc_write_u8(VncState *vs, uint8_t value)
790 {
791 vnc_write(vs, (char *)&value, 1);
792 }
794 static void vnc_flush(VncState *vs)
795 {
796 if (vs->output.offset)
797 vnc_client_write(vs);
798 }
800 static uint8_t read_u8(char *data, size_t offset)
801 {
802 return data[offset];
803 }
805 static uint16_t read_u16(char *data, size_t offset)
806 {
807 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
808 }
810 static int32_t read_s32(char *data, size_t offset)
811 {
812 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
813 (data[offset + 2] << 8) | data[offset + 3]);
814 }
816 static uint32_t read_u32(char *data, size_t offset)
817 {
818 return ((data[offset] << 24) | (data[offset + 1] << 16) |
819 (data[offset + 2] << 8) | data[offset + 3]);
820 }
822 static void client_cut_text(VncState *vs, size_t len, char *text)
823 {
824 }
826 static void pointer_event(VncState *vs, int button_mask, int x, int y)
827 {
828 int buttons = 0;
829 int dz = 0;
831 if (button_mask & 0x01)
832 buttons |= MOUSE_EVENT_LBUTTON;
833 if (button_mask & 0x02)
834 buttons |= MOUSE_EVENT_MBUTTON;
835 if (button_mask & 0x04)
836 buttons |= MOUSE_EVENT_RBUTTON;
837 if (button_mask & 0x08)
838 dz = -1;
839 if (button_mask & 0x10)
840 dz = 1;
842 if (kbd_mouse_is_absolute()) {
843 kbd_mouse_event(x * 0x7FFF / vs->ds->width,
844 y * 0x7FFF / vs->ds->height,
845 dz, buttons);
846 } else {
847 static int last_x = -1;
848 static int last_y = -1;
850 if (last_x != -1)
851 kbd_mouse_event(x - last_x, y - last_y, dz, buttons);
853 last_x = x;
854 last_y = y;
855 }
856 }
858 static void press_key(VncState *vs, int keycode)
859 {
860 kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) & 0x7f);
861 kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) | 0x80);
862 }
864 static void do_key_event(VncState *vs, int down, uint32_t sym)
865 {
866 sym &= 0xFFFF;
868 if (is_graphic_console()) {
869 int keycode;
870 int numlock;
872 keycode = keysym2scancode(vs->kbd_layout, sym);
873 numlock = keysym2numlock(vs->kbd_layout, sym);
875 /* If the numlock state needs to change then simulate an additional
876 keypress before sending this one. This will happen if the user
877 toggles numlock away from the VNC window.
878 */
879 if (numlock == 1) {
880 if (!vs->numlock) {
881 vs->numlock = 1;
882 press_key(vs, XK_Num_Lock);
883 }
884 }
885 else if (numlock == -1) {
886 if (vs->numlock) {
887 vs->numlock = 0;
888 press_key(vs, XK_Num_Lock);
889 }
890 }
892 if (keycode & 0x80)
893 kbd_put_keycode(0xe0);
894 if (down)
895 kbd_put_keycode(keycode & 0x7f);
896 else
897 kbd_put_keycode(keycode | 0x80);
898 } else if (down) {
899 int qemu_keysym = 0;
901 if (sym <= 128) { /* normal ascii */
902 int shifted = vs->shift_keys == 1 || vs->shift_keys == 2;
903 qemu_keysym = sym;
904 if (sym >= 'a' && sym <= 'z' && shifted)
905 qemu_keysym -= 'a' - 'A';
906 } else {
907 switch (sym) {
908 case XK_Up: qemu_keysym = QEMU_KEY_UP; break;
909 case XK_Down: qemu_keysym = QEMU_KEY_DOWN; break;
910 case XK_Left: qemu_keysym = QEMU_KEY_LEFT; break;
911 case XK_Right: qemu_keysym = QEMU_KEY_RIGHT; break;
912 case XK_Home: qemu_keysym = QEMU_KEY_HOME; break;
913 case XK_End: qemu_keysym = QEMU_KEY_END; break;
914 case XK_Page_Up: qemu_keysym = QEMU_KEY_PAGEUP; break;
915 case XK_Page_Down: qemu_keysym = QEMU_KEY_PAGEDOWN; break;
916 case XK_BackSpace: qemu_keysym = QEMU_KEY_BACKSPACE; break;
917 case XK_Delete: qemu_keysym = QEMU_KEY_DELETE; break;
918 case XK_Return:
919 case XK_Linefeed: qemu_keysym = sym; break;
920 default: break;
921 }
922 }
923 if (qemu_keysym != 0)
924 kbd_put_keysym(qemu_keysym);
925 }
927 if (down) {
928 switch (sym) {
929 case XK_Control_L:
930 vs->ctl_keys |= 1;
931 break;
933 case XK_Alt_L:
934 vs->ctl_keys |= 2;
935 break;
937 case XK_Shift_L:
938 vs->shift_keys |= 1;
939 break;
941 default:
942 break;
943 }
944 } else {
945 switch (sym) {
946 case XK_Control_L:
947 vs->ctl_keys &= ~1;
948 break;
950 case XK_Alt_L:
951 vs->ctl_keys &= ~2;
952 break;
954 case XK_Shift_L:
955 vs->shift_keys &= ~1;
956 break;
958 case XK_Caps_Lock:
959 vs->shift_keys ^= 2;
960 break;
962 case XK_Num_Lock:
963 vs->numlock = !vs->numlock;
964 break;
966 case XK_1 ... XK_9:
967 if ((vs->ctl_keys & 3) != 3)
968 break;
970 console_select(sym - XK_1);
971 if (is_graphic_console()) {
972 /* tell the vga console to redisplay itself */
973 vga_hw_invalidate();
974 vnc_dpy_update(vs->ds, 0, 0, vs->ds->width, vs->ds->height);
975 }
976 break;
977 }
978 }
979 }
981 static void key_event(VncState *vs, int down, uint32_t sym)
982 {
983 if (sym >= 'A' && sym <= 'Z')
984 sym = sym - 'A' + 'a';
985 do_key_event(vs, down, sym);
986 }
988 static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h)
989 {
991 set_bits_in_row(vs, vs->update_row, x, y, w, h);
993 vs->has_update = 1;
994 }
996 static void framebuffer_update_request(VncState *vs, int incremental,
997 int x_position, int y_position,
998 int w, int h)
999 {
1000 if (!incremental)
1001 framebuffer_set_updated(vs, x_position, y_position, w, h);
1002 vs->visible_x = x_position;
1003 vs->visible_y = y_position;
1004 vs->visible_w = w;
1005 vs->visible_h = h;
1007 qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock));
1010 static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1012 int i;
1014 vs->has_hextile = 0;
1015 vs->has_resize = 0;
1016 vs->ds->dpy_copy = NULL;
1018 for (i = n_encodings - 1; i >= 0; i--) {
1019 switch (encodings[i]) {
1020 case 0: /* Raw */
1021 vs->has_hextile = 0;
1022 break;
1023 case 1: /* CopyRect */
1024 vs->ds->dpy_copy = vnc_copy;
1025 break;
1026 case 5: /* Hextile */
1027 vs->has_hextile = 1;
1028 break;
1029 case -223: /* DesktopResize */
1030 vs->has_resize = 1;
1031 break;
1032 default:
1033 break;
1038 static int compute_nbits(unsigned int val)
1040 int n;
1041 n = 0;
1042 while (val != 0) {
1043 n++;
1044 val >>= 1;
1046 return n;
1049 static void set_pixel_format(VncState *vs,
1050 int bits_per_pixel, int depth,
1051 int big_endian_flag, int true_color_flag,
1052 int red_max, int green_max, int blue_max,
1053 int red_shift, int green_shift, int blue_shift)
1055 int host_big_endian_flag;
1057 #ifdef WORDS_BIGENDIAN
1058 host_big_endian_flag = 1;
1059 #else
1060 host_big_endian_flag = 0;
1061 #endif
1062 if (!true_color_flag) {
1063 fail:
1064 vnc_client_error(vs);
1065 return;
1067 if (bits_per_pixel == 32 &&
1068 host_big_endian_flag == big_endian_flag &&
1069 red_max == 0xff && green_max == 0xff && blue_max == 0xff &&
1070 red_shift == 16 && green_shift == 8 && blue_shift == 0) {
1071 vs->depth = 4;
1072 vs->write_pixels = vnc_write_pixels_copy;
1073 vs->send_hextile_tile = send_hextile_tile_32;
1074 } else
1075 if (bits_per_pixel == 16 &&
1076 host_big_endian_flag == big_endian_flag &&
1077 red_max == 31 && green_max == 63 && blue_max == 31 &&
1078 red_shift == 11 && green_shift == 5 && blue_shift == 0) {
1079 vs->depth = 2;
1080 vs->write_pixels = vnc_write_pixels_copy;
1081 vs->send_hextile_tile = send_hextile_tile_16;
1082 } else
1083 if (bits_per_pixel == 8 &&
1084 red_max == 7 && green_max == 7 && blue_max == 3 &&
1085 red_shift == 5 && green_shift == 2 && blue_shift == 0) {
1086 vs->depth = 1;
1087 vs->write_pixels = vnc_write_pixels_copy;
1088 vs->send_hextile_tile = send_hextile_tile_8;
1089 } else
1091 /* generic and slower case */
1092 if (bits_per_pixel != 8 &&
1093 bits_per_pixel != 16 &&
1094 bits_per_pixel != 32)
1095 goto fail;
1096 vs->depth = 4;
1097 vs->red_shift = red_shift;
1098 vs->red_max = red_max;
1099 vs->red_shift1 = 24 - compute_nbits(red_max);
1100 vs->green_shift = green_shift;
1101 vs->green_max = green_max;
1102 vs->green_shift1 = 16 - compute_nbits(green_max);
1103 vs->blue_shift = blue_shift;
1104 vs->blue_max = blue_max;
1105 vs->blue_shift1 = 8 - compute_nbits(blue_max);
1106 vs->pix_bpp = bits_per_pixel / 8;
1107 vs->pix_big_endian = big_endian_flag;
1108 vs->write_pixels = vnc_write_pixels_generic;
1109 vs->send_hextile_tile = send_hextile_tile_generic;
1112 vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height);
1114 vga_hw_invalidate();
1115 vga_hw_update();
1118 static int protocol_client_msg(VncState *vs, char *data, size_t len)
1120 int i;
1121 uint16_t limit;
1122 int64_t now;
1124 switch (data[0]) {
1125 case 0:
1126 if (len == 1)
1127 return 20;
1129 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
1130 read_u8(data, 6), read_u8(data, 7),
1131 read_u16(data, 8), read_u16(data, 10),
1132 read_u16(data, 12), read_u8(data, 14),
1133 read_u8(data, 15), read_u8(data, 16));
1134 break;
1135 case 2:
1136 if (len == 1)
1137 return 4;
1139 if (len == 4) {
1140 uint16_t v;
1141 v = read_u16(data, 2);
1142 if (v)
1143 return 4 + v * 4;
1146 limit = read_u16(data, 2);
1147 for (i = 0; i < limit; i++) {
1148 int32_t val = read_s32(data, 4 + (i * 4));
1149 memcpy(data + 4 + (i * 4), &val, sizeof(val));
1152 set_encodings(vs, (int32_t *)(data + 4), limit);
1153 break;
1154 case 3:
1155 if (len == 1)
1156 return 10;
1158 framebuffer_update_request(vs,
1159 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
1160 read_u16(data, 6), read_u16(data, 8));
1161 break;
1162 case 4:
1163 if (len == 1)
1164 return 8;
1166 vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
1167 qemu_advance_timer(vs->timer,
1168 qemu_get_clock(rt_clock) + vs->timer_interval);
1169 key_event(vs, read_u8(data, 1), read_u32(data, 4));
1170 break;
1171 case 5:
1172 if (len == 1)
1173 return 6;
1175 vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
1176 qemu_advance_timer(vs->timer,
1177 qemu_get_clock(rt_clock) + vs->timer_interval);
1178 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
1179 break;
1180 case 6:
1181 if (len == 1)
1182 return 8;
1184 if (len == 8) {
1185 uint32_t v;
1186 v = read_u32(data, 4);
1187 if (v)
1188 return 8 + v;
1191 client_cut_text(vs, read_u32(data, 4), data + 8);
1192 break;
1193 default:
1194 printf("Msg: %d\n", data[0]);
1195 vnc_client_error(vs);
1196 break;
1199 vnc_read_when(vs, protocol_client_msg, 1);
1200 return 0;
1203 static int protocol_client_init(VncState *vs, char *data, size_t len)
1205 size_t l;
1206 char pad[3] = { 0, 0, 0 };
1208 vga_hw_update();
1210 vs->width = vs->ds->width;
1211 vs->height = vs->ds->height;
1212 vnc_write_u16(vs, vs->ds->width);
1213 vnc_write_u16(vs, vs->ds->height);
1215 vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */
1216 vnc_write_u8(vs, vs->depth * 8); /* depth */
1217 #ifdef WORDS_BIGENDIAN
1218 vnc_write_u8(vs, 1); /* big-endian-flag */
1219 #else
1220 vnc_write_u8(vs, 0); /* big-endian-flag */
1221 #endif
1222 vnc_write_u8(vs, 1); /* true-color-flag */
1223 if (vs->depth == 4) {
1224 vnc_write_u16(vs, 0xFF); /* red-max */
1225 vnc_write_u16(vs, 0xFF); /* green-max */
1226 vnc_write_u16(vs, 0xFF); /* blue-max */
1227 vnc_write_u8(vs, 16); /* red-shift */
1228 vnc_write_u8(vs, 8); /* green-shift */
1229 vnc_write_u8(vs, 0); /* blue-shift */
1230 vs->send_hextile_tile = send_hextile_tile_32;
1231 } else if (vs->depth == 2) {
1232 vnc_write_u16(vs, 31); /* red-max */
1233 vnc_write_u16(vs, 63); /* green-max */
1234 vnc_write_u16(vs, 31); /* blue-max */
1235 vnc_write_u8(vs, 11); /* red-shift */
1236 vnc_write_u8(vs, 5); /* green-shift */
1237 vnc_write_u8(vs, 0); /* blue-shift */
1238 vs->send_hextile_tile = send_hextile_tile_16;
1239 } else if (vs->depth == 1) {
1240 /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */
1241 vnc_write_u16(vs, 7); /* red-max */
1242 vnc_write_u16(vs, 7); /* green-max */
1243 vnc_write_u16(vs, 3); /* blue-max */
1244 vnc_write_u8(vs, 5); /* red-shift */
1245 vnc_write_u8(vs, 2); /* green-shift */
1246 vnc_write_u8(vs, 0); /* blue-shift */
1247 vs->send_hextile_tile = send_hextile_tile_8;
1249 vs->write_pixels = vnc_write_pixels_copy;
1251 vnc_write(vs, pad, 3); /* padding */
1253 l = strlen(domain_name);
1254 vnc_write_u32(vs, l);
1255 vnc_write(vs, domain_name, l);
1257 vnc_flush(vs);
1259 vnc_read_when(vs, protocol_client_msg, 1);
1261 return 0;
1264 static int protocol_response(VncState *vs, char *client_response, size_t len)
1266 extern char vncpasswd[64];
1267 extern unsigned char challenge[AUTHCHALLENGESIZE];
1268 unsigned char cryptchallenge[AUTHCHALLENGESIZE];
1269 unsigned char key[8];
1270 int passwdlen, i, j;
1272 memcpy(cryptchallenge, challenge, AUTHCHALLENGESIZE);
1274 /* Calculate the sent challenge */
1275 passwdlen = strlen(vncpasswd);
1276 for (i=0; i<8; i++)
1277 key[i] = i<passwdlen ? vncpasswd[i] : 0;
1278 deskey(key, EN0);
1279 for (j = 0; j < AUTHCHALLENGESIZE; j += 8)
1280 des(cryptchallenge+j, cryptchallenge+j);
1282 /* Check the actual response */
1283 if (memcmp(cryptchallenge, client_response, AUTHCHALLENGESIZE) != 0) {
1284 /* password error */
1285 vnc_write_u32(vs, 1);
1286 vnc_write_u32(vs, 22);
1287 vnc_write(vs, "Authentication failure", 22);
1288 vnc_flush(vs);
1289 fprintf(stderr, "VNC Password error.\n");
1290 vnc_client_error(vs);
1291 return 0;
1294 vnc_write_u32(vs, 0);
1295 vnc_flush(vs);
1297 vnc_read_when(vs, protocol_client_init, 1);
1299 return 0;
1302 static int protocol_version(VncState *vs, char *version, size_t len)
1304 extern char vncpasswd[64];
1305 extern unsigned char challenge[AUTHCHALLENGESIZE];
1306 char local[13];
1307 int support, maj, min;
1309 memcpy(local, version, 12);
1310 local[12] = 0;
1312 /* protocol version check */
1313 if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) {
1314 fprintf(stderr, "Protocol version error.\n");
1315 vnc_client_error(vs);
1316 return 0;
1320 support = 0;
1321 if (maj = 3) {
1322 if (min == 3 || min ==4) {
1323 support = 1;
1327 if (! support) {
1328 fprintf(stderr, "Client uses unsupported protocol version %d.%d.\n",
1329 maj, min);
1330 vnc_client_error(vs);
1331 return 0;
1334 if (*vncpasswd == '\0') {
1335 /* AuthType is None */
1336 vnc_write_u32(vs, 1);
1337 vnc_flush(vs);
1338 vnc_read_when(vs, protocol_client_init, 1);
1339 } else {
1340 /* AuthType is VncAuth */
1341 vnc_write_u32(vs, 2);
1343 /* Challenge-Responce authentication */
1344 /* Send Challenge */
1345 make_challenge(challenge, AUTHCHALLENGESIZE);
1346 vnc_write(vs, challenge, AUTHCHALLENGESIZE);
1347 vnc_flush(vs);
1348 vnc_read_when(vs, protocol_response, AUTHCHALLENGESIZE);
1351 return 0;
1354 static void vnc_listen_read(void *opaque)
1356 VncState *vs = opaque;
1357 struct sockaddr_in addr;
1358 socklen_t addrlen = sizeof(addr);
1360 vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
1361 if (vs->csock != -1) {
1362 socket_set_nonblock(vs->csock);
1363 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque);
1364 vnc_write(vs, "RFB 003.003\n", 12);
1365 vnc_flush(vs);
1366 vnc_read_when(vs, protocol_version, 12);
1367 framebuffer_set_updated(vs, 0, 0, vs->ds->width, vs->ds->height);
1368 vs->has_resize = 0;
1369 vs->has_hextile = 0;
1370 vs->ds->dpy_copy = NULL;
1371 vnc_timer_init(vs);
1375 int vnc_display_init(DisplayState *ds, int display, int find_unused, struct sockaddr_in *addr)
1377 int reuse_addr, ret;
1378 VncState *vs;
1380 vs = qemu_mallocz(sizeof(VncState));
1381 if (!vs)
1382 exit(1);
1384 ds->opaque = vs;
1386 vs->lsock = -1;
1387 vs->csock = -1;
1388 vs->depth = 4;
1389 vs->numlock = 0;
1391 vs->ds = ds;
1393 if (!keyboard_layout)
1394 keyboard_layout = "en-us";
1396 vs->kbd_layout = init_keyboard_layout(keyboard_layout);
1397 if (!vs->kbd_layout)
1398 exit(1);
1400 vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
1401 if (vs->lsock == -1) {
1402 fprintf(stderr, "Could not create socket\n");
1403 exit(1);
1406 reuse_addr = 1;
1407 ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
1408 (const char *)&reuse_addr, sizeof(reuse_addr));
1409 if (ret == -1) {
1410 fprintf(stderr, "setsockopt() failed\n");
1411 exit(1);
1414 retry:
1415 addr->sin_family = AF_INET;
1416 addr->sin_port = htons(5900 + display);
1418 if (bind(vs->lsock, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) == -1) {
1419 if (find_unused && errno == EADDRINUSE) {
1420 display++;
1421 goto retry;
1423 fprintf(stderr, "bind() failed\n");
1424 exit(1);
1427 if (listen(vs->lsock, 1) == -1) {
1428 fprintf(stderr, "listen() failed\n");
1429 exit(1);
1432 ret = qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read,
1433 NULL, vs);
1434 if (ret == -1)
1435 exit(1);
1437 vs->ds->data = NULL;
1438 vs->ds->dpy_update = vnc_dpy_update;
1439 vs->ds->dpy_resize = vnc_dpy_resize;
1440 vs->ds->dpy_refresh = vnc_dpy_refresh;
1442 vnc_dpy_resize(vs->ds, 640, 400);
1444 return display;
1447 int vnc_start_viewer(int port)
1449 int pid;
1450 char s[16];
1452 sprintf(s, ":%d", port);
1454 switch (pid = fork()) {
1455 case -1:
1456 fprintf(stderr, "vncviewer failed fork\n");
1457 exit(1);
1459 case 0: /* child */
1460 execlp("vncviewer", "vncviewer", s, NULL);
1461 fprintf(stderr, "vncviewer execlp failed\n");
1462 exit(1);
1464 default:
1465 return pid;
1469 unsigned int seed;
1471 static int make_challenge(char *random, int size)
1474 set_seed(&seed);
1475 get_random(size, random);
1477 return 0;
1480 static void set_seed(unsigned int *seedp)
1482 *seedp += (unsigned int)(time(NULL)+getpid()+getpid()*987654+rand());
1483 srand(*seedp);
1485 return;
1488 static void get_random(int len, unsigned char *buf)
1490 int i;
1492 for (i=0; i<len; i++)
1493 buf[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
1495 return;