2 * fbvnc - a small linux framebuffer vnc viewer
4 * Copyright (C) 2009-2010 Ali Gholami Rudi
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License, as published by the
8 * Free Software Foundation.
10 #include <arpa/inet.h>
15 #include <netinet/in.h>
22 #include <sys/socket.h>
24 #include <sys/types.h>
26 #include <linux/input.h>
32 #define MAXRES (1 << 21)
33 #define MIN(a, b) ((a) < (b) ? (a) : (b))
35 static int cols
, rows
;
36 static int mr
, mc
; /* mouse position */
38 static char buf
[MAXRES
];
40 int vnc_init(char *addr
, int port
)
42 struct sockaddr_in si
;
43 char vncver
[] = "RFB 003.003\n";
44 struct vnc_client_init clientinit
;
45 struct vnc_server_init serverinit
;
46 struct vnc_client_pixelfmt pixfmt_cmd
;
49 int connstat
= VNC_CONN_FAILED
;
51 si
.sin_family
= AF_INET
;
52 si
.sin_port
= htons(port
);
53 he
= gethostbyname(addr
);
55 si
.sin_addr
.s_addr
= *((unsigned long *)(he
->h_addr
));
56 } else if (inet_aton(addr
, &(si
.sin_addr
)) < 0) {
57 fprintf(stderr
, "cannot resolve hostname");
61 servsock
= socket(PF_INET
, SOCK_STREAM
, 0);
63 perror("Cannot create socket");
66 if (connect(servsock
, (void *) &si
, sizeof(si
)) < 0) {
67 perror("cannot connect");
71 write(servsock
, vncver
, 12);
72 read(servsock
, vncver
, 12);
74 read(servsock
, &connstat
, sizeof(connstat
));
76 switch (ntohl(connstat
)) {
78 puts("remote server says: connection failed");
84 puts("we don't support DES yet");
89 clientinit
.shared
= 1;
90 write(servsock
, &clientinit
, sizeof(clientinit
));
91 read(servsock
, &serverinit
, sizeof(serverinit
));
94 cols
= MIN(ntohs(serverinit
.w
), fb_cols());
95 rows
= MIN(ntohs(serverinit
.h
), fb_rows());
99 read(servsock
, buf
, ntohl(serverinit
.len
));
100 pixfmt_cmd
.type
= VNC_CLIENT_PIXFMT
;
101 pixfmt_cmd
.format
.bpp
= 8;
102 pixfmt_cmd
.format
.depth
= 8;
103 pixfmt_cmd
.format
.bigendian
= 0;
104 pixfmt_cmd
.format
.truecolor
= 1;
106 pixfmt_cmd
.format
.rmax
= htons(3);
107 pixfmt_cmd
.format
.gmax
= htons(7);
108 pixfmt_cmd
.format
.bmax
= htons(7);
109 pixfmt_cmd
.format
.rshl
= 0;
110 pixfmt_cmd
.format
.gshl
= 2;
111 pixfmt_cmd
.format
.bshl
= 5;
113 write(servsock
, &pixfmt_cmd
, sizeof(pixfmt_cmd
));
123 int vnc_refresh(int fd
, int inc
)
125 struct vnc_client_fbup fbup_req
;
126 fbup_req
.type
= VNC_CLIENT_FBUP
;
128 fbup_req
.x
= htons(0);
129 fbup_req
.y
= htons(0);
130 fbup_req
.w
= htons(cols
);
131 fbup_req
.h
= htons(rows
);
132 write(fd
, &fbup_req
, sizeof(fbup_req
));
136 static void drawfb(char *s
, int x
, int y
, int w
, int h
)
138 fbval_t slice
[1 << 14];
140 for (i
= 0; i
< h
; i
++) {
141 for (j
= 0; j
< w
; j
++) {
142 unsigned char *p
= (void *) &s
[i
* w
+ j
];
143 slice
[j
] = fb_color(*p
, *p
, *p
);
145 fb_set(y
+ i
, x
, slice
, w
);
149 int vnc_event(int fd
)
151 struct vnc_rect uprect
;
153 struct vnc_server_fbup
*fbup
= (void *) msg
;
154 struct vnc_server_cuttext
*cuttext
= (void *) msg
;
155 struct vnc_server_colormap
*colormap
= (void *) msg
;
159 if ((nr
= read(fd
, msg
, 1)) != 1)
163 case VNC_SERVER_FBUP
:
164 nr
= read(fd
, msg
+ 1, sizeof(*fbup
) - 1);
166 for (j
= 0; j
< n
; j
++) {
168 nr
= read(fd
, &uprect
, sizeof(uprect
));
169 if (nr
!= sizeof(uprect
))
175 if (x
>= cols
|| x
+ w
> cols
)
177 if (y
>= rows
|| y
+ h
> rows
)
179 for (i
= 0; i
< w
* h
; ) {
180 nr
= read(fd
, buf
+ i
, w
* h
- i
);
185 drawfb(buf
, x
, y
, w
, h
);
188 case VNC_SERVER_BELL
:
190 case VNC_SERVER_CUTTEXT
:
191 nr
= read(fd
, msg
+ 1, sizeof(*cuttext
) - 1);
192 nr
= read(fd
, buf
, cuttext
->len
);
194 case VNC_SERVER_COLORMAP
:
195 nr
= read(fd
, msg
+ 1, sizeof(*colormap
) - 1);
196 nr
= read(fd
, buf
, ntohs(colormap
->n
) * 3 * 2);
199 printf("unknown msg: %d\n", msg
[0]);
205 int rat_event(int fd
, int ratfd
)
208 struct vnc_client_ratevent me
= {VNC_CLIENT_RATEVENT
};
210 if (read(ratfd
, &ie
, sizeof(ie
)) != 3)
214 mc
= MAX(0, MIN(cols
- 1, mc
));
215 mr
= MAX(0, MIN(rows
- 1, mr
));
217 mask
|= VNC_BUTTON1_MASK
;
219 mask
|= VNC_BUTTON1_MASK
;
221 mask
|= VNC_BUTTON1_MASK
;
225 write(fd
, &me
, sizeof(me
));
229 static int press(int fd
, int key
, int down
)
231 struct vnc_client_keyevent ke
= {VNC_CLIENT_KEYEVENT
};
234 return write(fd
, &ke
, sizeof(ke
));
237 int kbd_event(int fd
, int kbdfd
)
243 if ((j
= read(kbdfd
, msg
, sizeof(msg
))) <= 0 )
245 for (i
= 0; i
< j
; i
++) {
264 k
= (unsigned char) msg
[i
];
266 if (isupper(k
) || strchr(":\"<>?{}|+_()*&^%$#@!~", k
))
268 if (k
>= 1 && k
<= 26) {
284 static void term_setup(struct termios
*ti
)
286 struct termios termios
;
287 char *hide
= "\x1b[?25l";
288 char *clear
= "\x1b[2J\x1b[H";
289 char *msg
= "\t\t\t*** fbvnc ***\r\n";
291 write(STDIN_FILENO
, hide
, strlen(hide
));
292 write(STDOUT_FILENO
, clear
, strlen(clear
));
293 write(STDOUT_FILENO
, msg
, strlen(msg
));
294 tcgetattr (0, &termios
);
297 tcsetattr(0, TCSANOW
, &termios
);
300 static void term_cleanup(struct termios
*ti
)
302 char *show
= "\x1b[?25h";
303 tcsetattr(0, TCSANOW
, ti
);
304 write(STDIN_FILENO
, show
, strlen(show
));
307 static void mainloop(int vnc_fd
, int kbd_fd
, int rat_fd
)
309 struct pollfd ufds
[3];
314 ufds
[0].events
= POLLIN
;
316 ufds
[1].events
= POLLIN
;
318 ufds
[2].events
= POLLIN
;
320 if (update
&& !pending
) {
321 if (vnc_refresh(vnc_fd
, 1) == -1)
326 err
= poll(ufds
, 3, 500);
327 if (err
== -1 && errno
!= EINTR
)
331 if (ufds
[0].revents
& POLLIN
) {
332 if (kbd_event(vnc_fd
, kbd_fd
) == -1)
336 if (ufds
[1].revents
& POLLIN
) {
337 if (vnc_event(vnc_fd
) == -1)
341 if (ufds
[2].revents
& POLLIN
) {
342 if (rat_event(vnc_fd
, rat_fd
) == -1)
349 int main(int argc
, char * argv
[])
352 char *host
= "127.0.0.1";
358 port
= atoi(argv
[2]);
359 if ((vnc_fd
= vnc_init(host
, port
)) == -1)
362 rat_fd
= open("/dev/input/mice", O_RDONLY
);
364 mainloop(vnc_fd
, 0, rat_fd
);