README 18.1 KB
Newer Older
dscho's avatar
dscho committed
1
LibVNCServer: a library for easy implementation of a RDP/VNC server.
2 3 4
Copyright (C) 2001-2003 Johannes E. Schindelin

If you already used LibVNCServer, you probably want to read NEWS.
dscho's avatar
dscho committed
5

6 7 8
What is it?
-----------

dscho's avatar
dscho committed
9
VNC is a set of programs using the RFB (Remote Frame Buffer) protocol. They
dscho's avatar
dscho committed
10 11 12
are designed to "export" a frame buffer via net (if you don't know VNC, I
suggest you read "Basics" below). It is already in wide use for
administration, but it is not that easy to program a server yourself.
13 14 15

This has been changed by LibVNCServer.

dscho's avatar
dscho committed
16 17 18 19 20 21 22
There are two examples included:
 - example, a shared scribble sheet
 - pnmshow, a program to show PNMs (pictures) over the net.

The examples are not too well documented, but easy straight forward and a
good starting point.

23 24 25 26
Try example: it outputs on which port it listens (default: 5900), so it is
display 0. To view, call
	vncviewer :0
You should see a sheet with a gradient and "Hello World!" written on it. Try
dscho's avatar
dscho committed
27 28 29
to paint something. Note that everytime you click, there is some bigger blot,
whereas when you drag the mouse while clicked you draw a line. The size of the
blot depends on the mouse button you click. Open a second vncviewer with
30 31 32 33 34 35
the same parameters and watch it as you paint in the other window. This also
works over internet. You just have to know either the name or the IP of your
machine. Then it is
	vncviewer machine.where.example.runs.com:0
or similar for the remote client. Now you are ready to type something. Be sure
that your mouse sits still, because everytime the mouse moves, the cursor is
dscho's avatar
dscho committed
36 37 38 39 40
reset to the position of the pointer! If you are done with that demo, press
the down or up arrows. If your viewer supports it, then the dimensions of the
sheet change. Just press Escape in the viewer. Note that the server still
runs, even if you closed both windows. When you reconnect now, everything you
painted and wrote is still there. You can press "Page Up" for a blank page.
41 42 43 44 45 46 47

The demo pnmshow is much simpler: you either provide a filename as argument
or pipe a file through stdin. Note that the file has to be a raw pnm/ppm file,
i.e. a truecolour graphics. Only the Escape key is implemented. This may be
the best starting point if you want to learn how to use LibVNCServer. You
are confronted with the fact that the bytes per pixel can only be 8, 16 or 32.

dscho's avatar
dscho committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
Projects using it
----------------------------------------

VNC for KDE
http://www.tjansen.de/krfb

GemsVNC
http://www.elilabs.com/~rj/gemsvnc/

VNC for Netware
http://forge.novell.com/modules/xfmod/project/?vncnw

RDesktop
http://rdesktop.sourceforge.net

Mail me, if your application is missing!

dscho's avatar
dscho committed
65 66 67 68
How to use
----------

To make a server, you just have to initialise a server structure using the
69 70
function rfbDefaultScreenInit, like
  rfbScreenInfoPtr rfbScreen =
71
    rfbGetScreen(argc,argv,width,height,8,3,bpp);
72 73 74 75
where byte per pixel should be 1, 2 or 4. If performance doesn't matter,
you may try bpp=3 (internally one cannot use native data types in this
case; if you want to use this, look at pnmshow24).

dscho's avatar
dscho committed
76

dscho's avatar
dscho committed
77 78 79
You then can set hooks and io functions (see below) or other
options (see below).

80 81 82
And you allocate the frame buffer like this:
    rfbScreen->frameBuffer = (char*)malloc(width*height*bpp);

dscho's avatar
dscho committed
83 84
After that, you initialize the server, like
  rfbInitServer(rfbScreen);
dscho's avatar
dscho committed
85 86

You can use a blocking event loop, a background (pthread based) event loop,
dscho's avatar
dscho committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
or implement your own using the rfbProcessEvents function.

Making it interactive
---------------------

Input is handled by IO functions (see below).

Whenever you change something in the frame buffer, call rfbMarkRectAsModified.
You should make sure that the cursor is not drawn before drawing yourself
by calling rfbUndrawCursor. You can also draw the cursor using rfbDrawCursor,
but it hardly seems necessary. For cursor details, see below.

Utility functions
-----------------

Whenever you draw something, you have to call
 rfbMarkRectAsModified(screen,x1,y1,x2,y2).
This tells LibVNCServer to send updates to all connected clients.

Before you draw something, be sure to call
107
 rfbUndrawCursor(screen).
dscho's avatar
dscho committed
108 109 110 111 112 113
This tells LibVNCServer to hide the cursor.
Remark: There are vncviewers out there, which know a cursor encoding, so
that network traffic is low, and also the cursor doesn't need to be
drawn the cursor everytime an update is sent. LibVNCServer handles
all the details. Just set the cursor and don't bother any more.

114 115
To set the mouse coordinates (or emulate mouse clicks), call
  defaultPtrAddEvent(buttonMask,x,y,cl);
dscho's avatar
dscho committed
116 117
IMPORTANT: do this at the end of your function, because this actually draws
the cursor if no cursor encoding is active.
118

dscho's avatar
dscho committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132
What is the difference between rfbScreenInfoPtr and rfbClientPtr?
-----------------------------------------------------------------

The rfbScreenInfoPtr is a pointer to a rfbScreenInfo structure, which
holds information about the server, like pixel format, io functions,
frame buffer etc.

The rfbClientPtr is a pointer to an rfbClientRec structure, which holds
information about a client, like pixel format, socket of the
connection, etc.

A server can have several clients, but needn't have any. So, if you
have a server and three clients are connected, you have one instance
of a rfbScreenInfo and three instances of rfbClientRec's.
dscho's avatar
dscho committed
133

dscho's avatar
dscho committed
134 135 136 137 138
The rfbClientRec structure holds a member
  rfbScreenInfoPtr screen
which points to the server and a member
  rfbClientPtr next
to the next client.
139

dscho's avatar
dscho committed
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
The rfbScreenInfo structure holds a member
  rfbClientPtr rfbClientHead
which points to the first client.

So, to access the server from the client structure, you use client->screen.
To access all clients from a server, get screen->rfbClientHead and
iterate using client->next.

If you change client settings, be sure to use the provided iterator
 rfbGetClientIterator(rfbScreen)
with
 rfbClientIteratorNext(iterator)
and
 rfbReleaseClientIterator
to prevent thread clashes.

Other options
-------------

These options have to be set between rfbGetScreen and rfbInitServer.

If you already have a socket to talk to, just set rfbScreen->inetdSock
(originally this is for inetd handling, but why not use it for your purpose?).

To also start an HTTP server (running on port 5800+display_number), you have
165 166 167 168 169 170
to set rfbScreen->httpdDir to a directory containing vncviewer.jar and
index.vnc (like the included "classes" directory).

Hooks and IO functions
----------------------

dscho's avatar
dscho committed
171 172 173
There exist the following IO functions as members of rfbScreen:
kbdAddEvent, kbdReleaseAllKeys, ptrAddEvent and setXCutText

174
kbdAddEvent(rfbBool down,rfbKeySym key,rfbClientPtr cl)
dscho's avatar
dscho committed
175 176 177 178 179
  is called when a key is pressed.
kbdReleaseAllKeys(rfbClientPtr cl)
  is not called at all (maybe in the future).
ptrAddEvent(int buttonMask,int x,int y,rfbClientPtr cl)
  is called when the mouse moves or a button is pressed.
180 181 182
  WARNING: if you want to have proper cursor handling, call
	defaultPtrAddEvent(buttonMask,x,y,cl)
  in your own function. This sets the coordinates of the cursor.
dscho's avatar
dscho committed
183 184 185
setXCutText(char* str,int len,rfbClientPtr cl)
  is called when the selection changes.

dscho's avatar
dscho committed
186
There are only two hooks:
dscho's avatar
dscho committed
187 188
newClientHook(rfbClientPtr cl)
  is called when a new client has connected.
dscho's avatar
dscho committed
189 190
displayHook
  is called just before a frame buffer update is sent.
dscho's avatar
dscho committed
191

192
You can also override the following methods:
dscho's avatar
dscho committed
193 194
getCursorPtr(rfbClientPtr cl)
  This could be used to make an animated cursor (if you really want ...)
195 196 197
setTranslateFunction(rfbClientPtr cl)
  If you insist on colour maps or something more obscure, you have to
  implement this. Default is a trueColour mapping.
198 199 200 201

Cursor handling
---------------

dscho's avatar
dscho committed
202 203 204 205 206
The screen holds a pointer
 rfbCursorPtr cursor
to the current cursor. Whenever you set it, remember that any dynamically
created cursor (like return value from rfbMakeXCursor) is not free'd!

207 208 209 210 211
The rfbCursor structure consists mainly of a mask and a source. The mask
describes, which pixels are drawn for the cursor (a cursor needn't be
rectangular). The source describes, which colour those pixels should have.

The standard is an XCursor: a cursor with a foreground and a background
dscho's avatar
dscho committed
212 213 214 215 216
colour (stored in backRed,backGreen,backBlue and the same for foreground
in a range from 0-0xffff). Therefore, the arrays "mask" and "source"
contain pixels as single bits stored in bytes in MSB order. The rows are
padded, such that each row begins with a new byte (i.e. a 10x4
cursor's mask has 2x4 bytes, because 2 bytes are needed to hold 10 bits).
217

dscho's avatar
dscho committed
218
It is however very easy to make a cursor like this:
219 220 221 222 223 224 225 226 227 228 229 230

char* cur="    "
          " xx "
	  " x  "
	  "    ";
char* mask="xxxx"
           "xxxx"
	   "xxxx"
	   "xxx ";
rfbCursorPtr c=rfbMakeXCursor(4,4,cur,mask);

You can even set "mask" to NULL in this call and LibVNCServer will calculate
dscho's avatar
dscho committed
231
a mask for you (dynamically, so you have to free it yourself).
232 233

There is also an array named "richSource" for colourful cursors. They have
dscho's avatar
dscho committed
234 235
the same format as the frameBuffer (i.e. if the server is 32 bit,
a 10x4 cursor has 4x10x4 bytes).
236

dscho's avatar
dscho committed
237 238 239 240 241 242
History
-------

LibVNCServer is based on Tridia VNC and OSXvnc, which in turn are based on
the original code from ORL/AT&T.

dscho's avatar
dscho committed
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
When I began hacking with computers, my first interest was speed. So, when I
got around assembler, I programmed the floppy to do much of the work, because
it's clock rate was higher than that of my C64. This was my first experience
with client/server techniques.

When I came around Xwindows (much later), I was at once intrigued by the
elegance of such connectedness between the different computers. I used it
a lot - not the least priority lay on games. However, when I tried it over
modem from home, it was no longer that much fun.

When I started working with ASP (Application Service Provider) programs, I
tumbled across Tarantella and Citrix. Being a security fanatic, the idea of
running a server on windows didn't appeal to me, so Citrix went down the
basket. However, Tarantella has it's own problems (security as well as the
high price). But at the same time somebody told me about this "great little
administrator's tool" named VNC. Being used to windows programs' sizes, the
surprise was reciprocal inverse to the size of VNC!

At the same time, the program "rdesktop" (a native Linux client for the
Terminal Services of Windows servers) came to my attention. There where even
works under way to make a protocol converter "rdp2vnc" out of this. However,
my primary goal was a slow connection and rdp2vnc could only speak RRE
encoding, which is not that funny with just 5kB/s. Tim Edmonds, the original
author of rdp2vnc, suggested that I adapt it to Hextile Encoding, which is
better. I first tried that, but had no success at all (crunchy pictures).

Also, I liked the idea of an HTTP server included and possibly other
encodings like the Tight Encodings from Const Kaplinsky. So I started looking
for libraries implementing a VNC server where I could steal what I can't make.
I found some programs based on the demo server from AT&T, which was also the
basis for rdp2vnc (can only speak Raw and RRE encoding). There were some
rumors that GGI has a VNC backend, but I didn't find any code, so probably
there wasn't a working version anyway.

All of a sudden, everything changed: I read on freshmeat that "OSXvnc" was
released. I looked at the code and it was not much of a problem to work out
a simple server - using every functionality there is in Xvnc. It became clear
to me that I *had* to build a library out of it, so everybody can use it.
Every change, every new feature can propagate to every user of it.

It also makes everything easier:
 You don't care about the cursor, once set (or use the standard cursor).
You don't care about those sockets. You don't care about encodings.
You just change your frame buffer and inform the library about it. Every once
in a while you call rfbProcessEvents and that's it.

Basics
------

VNC (Virtual network computing) works like this: You set up a server and can
connect to it via vncviewers. The communication uses a protocol named RFB
(Remote Frame Buffer). If the server supports HTTP, you can also connect
using a java enabled browser. In this case, the server sends back a
vncviewer applet with the correct settings.

There exist several encodings for VNC, which are used to compress the regions
which have changed before they are sent to the client. A client need not be
able to understand every encoding, but at least Raw encoding. Which encoding
it understands is negotiated by the RFB protocol.

The following encodings are known to me:
Raw, RRE, CoRRE, Hextile, CopyRect from the original AT&T code and
Tight, ZLib, LastRect, XCursor, RichCursor from Const Kaplinsky et al.

If you are using a modem, you want to try the "new" encodings. Especially
with my 56k modem I like ZLib or Tight with Quality 0. In my tests, it even
beats Tarantella.

There is the possibility to set a password, which is also negotiated by the
RFB protocol, but IT IS NOT SECURE. Anybody sniffing your net can get the
password. You really should tunnel through SSH.
dscho's avatar
dscho committed
314

315 316 317 318 319 320 321 322 323 324
Windows or: why do you do that to me?
--------------------------------------------

If you love products from Redmod, you better skip this paragraph.
I am always amazed how people react whenever Microsoft(tm) puts in some
features into their products which were around for a long time. Especially
reporters seem to not know dick about what they are reporting about! But
what is everytime annoying again, is that they don't do it right. Every
concept has it's new name (remember what enumerators used to be until
Mickeysoft(tm) claimed that enumerators are what we thought were iterators.
dscho's avatar
dscho committed
325
Yeah right, enumerators are also containers. They are not separated. Muddy.)
326 327 328 329 330 331 332 333 334 335 336 337

There are three packages you want to get hold of: zlib, jpeg and pthreads.
The latter is not strictly necessary, but when you put something like this
into your source:

#define MUTEX(s)
	struct {
		int something;
		MUTEX(latex);
	}

Microsoft's C++ compiler doesn't do it. It complains that this is an error.
dscho's avatar
dscho committed
338 339
This, however, is how I implemented mutexes in case you don't need pthreads,
and so don't need the mutex.
340 341 342 343 344 345

You can find the packages at
http://www.gimp.org/win32/extralibs-dev-20001007.zip

Thanks go to all the GIMP team!

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
What are those other targets in the Makefile?
---------------------------------------------

OSXvnc-server is the original OSXvnc adapted to use the library, which was in
turn adapted from OSXvnc. As you easily can see, the OSX dependend part is
minimal.

storepasswd is the original program to save a vnc style password in a file.
Unfortunately, authentication as every vncviewer speaks it means the server
has to know the plain password. You really should tunnel via ssh or use
your own PasswordCheck to build a PIN/TAN system.

sratest is a test unit. Run it to assert correct behaviour of sraRegion. I
wrote this to test my iterator implementation.

blooptest is a test of pthreads. It is just the example, but with a background
loop to hunt down thread lockups.

pnmshow24 is like pnmshow, but it uses 3 bytes/pixel internally, which is not
as efficient as 4 bytes/pixel for translation, because there is no native data
type of that size, so you have to memcpy pixels and be real cautious with
endianness. Anyway, it works.

fontsel is a test for rfbSelectBox and rfbLoadConsoleFont. If you have Linux
console fonts, you can browse them via VNC. Directory browsing not implemented
yet :-(

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
Why I don't feel bad about GPL
------------------------------

At the beginning of this projects I would have liked to make it a BSD
license. However, it is based on plenty of GPL'ed code, so it has to be
a GPL. I hear BeeGee complaining: "but that's invasive, every derivative
work, even just linking, makes my software GPL!"

Yeah. That's right. It is because there are nasty jarheads out there who
would take anybody's work and claim it their own, selling it for much too
much money, stealing freedom and innovation from others, saying they were
the maintainers of innovation, lying, making money with that.

The people at AT&T worked really well to produce something as clean and lean
as VNC. The managers decided that for their fame, they would release the
program for free. But not only that! They realized that by releasing also
the code for free, VNC would become an evolving little child, conquering
new worlds, making it's parents very proud. As well they can be! To protect
this innovation, they decided to make it GPL, not BSD. The principal
difference is: You can make closed source programs deriving from BSD, not
from GPL. You have to give proper credit with both.

Now, why not BSD? Well, imagine your child being some famous actor. Along
comes a manager who exploits your child exclusively, that is: nobody else
can profit from the child, it itself included. Got it?

What reason do you have now to use this library commercially?

Several: You don't have to give away your product. Then you have effectively
circumvented the GPL, because you have the benefits of other's work and you
don't give back anything and you will be in hell for that. In fact, this
library, as my other projects, is a payback for all the free software I can
use (and sometimes, make better). For example, just now, I am using XEmacs
dscho's avatar
dscho committed
406
on top of XFree86, all running under Linux.
407 408 409 410 411 412 413 414 415 416 417

Better: Use a concept like MySQL. This is free software, however, they make
money with it. If you want something implemented, you have the choice:
Ask them to do it (and pay a fair price), or do it yourself, normally giving
back your enhancements to the free world of computing.

Learn from it: If you like the style this is written, learn how to imitate
it. If you don't like the style, learn how to avoid those things you don't
like. I learnt so much, just from looking at code like Linux, XEmacs,
LilyPond, STL, etc.

dscho's avatar
dscho committed
418 419
License
-------
dscho's avatar
dscho committed
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.dfdf

435 436
Contact
-------
dscho's avatar
dscho committed
437

438
To contact me, mail me: Johannes dot Schindelin at gmx dot de
439