added persistant bitmap chaching from Jeroen Meijer, slightly modified

git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@724 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
Jay Sorg 2004-06-27 17:51:54 +00:00
parent 4004b21d48
commit 7f836f0384
12 changed files with 688 additions and 77 deletions

View File

@ -15,7 +15,7 @@ datadir = $(prefix)/share/rdesktop
VERSION = 1.3.1
KEYMAP_PATH = $(datadir)/keymaps/
RDPOBJ = tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o
RDPOBJ = tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o pstcache.o
X11OBJ = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o
VNCOBJ = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o
CRYPTOBJ = crypto/rc4_enc.o crypto/rc4_skey.o crypto/md5_dgst.o crypto/sha1dgst.o crypto/bn_exp.o crypto/bn_mul.o crypto/bn_div.o crypto/bn_sqr.o crypto/bn_add.o crypto/bn_shift.o crypto/bn_asm.o crypto/bn_ctx.o crypto/bn_lib.o

73
cache.c
View File

@ -21,22 +21,59 @@
#include "rdesktop.h"
#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
#define TOUCH(id, idx) (g_bmpcache[id][idx].usage = ++g_stamp)
#define IS_PERSISTENT(id) (g_pstcache_fd[id] > 0)
extern int g_pstcache_fd[];
uint32 g_stamp;
int g_num_bitmaps_in_memory[3];
/* BITMAP CACHE */
static HBITMAP g_bmpcache[3][600];
static BMPCACHEENTRY g_bmpcache[3][0xa00];
/* Remove the least-recently used bitmap from the cache */
void
cache_remove_lru_bitmap(uint8 cache_id)
{
int i;
uint16 cache_idx = 0;
uint32 m = -1;
BMPCACHEENTRY *pbce;
for (i = 0; i < NUM_ELEMENTS(g_bmpcache[cache_id]); i++)
{
if (g_bmpcache[cache_id][i].bitmap && g_bmpcache[cache_id][i].usage < m)
{
cache_idx = i;
m = g_bmpcache[cache_id][i].usage;
}
}
pbce = &g_bmpcache[cache_id][cache_idx];
ui_destroy_bitmap(pbce->bitmap);
--g_num_bitmaps_in_memory[cache_id];
pbce->bitmap = 0;
pbce->usage = 0;
}
/* Retrieve a bitmap from the cache */
HBITMAP
cache_get_bitmap(uint8 cache_id, uint16 cache_idx)
{
HBITMAP bitmap;
HBITMAP *pbitmap;
if ((cache_id < NUM_ELEMENTS(g_bmpcache)) && (cache_idx < NUM_ELEMENTS(g_bmpcache[0])))
{
bitmap = g_bmpcache[cache_id][cache_idx];
if (bitmap != NULL)
return bitmap;
pbitmap = &g_bmpcache[cache_id][cache_idx].bitmap;
if ((*pbitmap != 0) || pstcache_load_bitmap(cache_id, cache_idx))
{
if (IS_PERSISTENT(cache_id))
TOUCH(cache_id, cache_idx);
return *pbitmap;
}
}
error("get bitmap %d:%d\n", cache_id, cache_idx);
@ -45,17 +82,25 @@ cache_get_bitmap(uint8 cache_id, uint16 cache_idx)
/* Store a bitmap in the cache */
void
cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap)
cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap, uint32 stamp)
{
HBITMAP old;
if ((cache_id < NUM_ELEMENTS(g_bmpcache)) && (cache_idx < NUM_ELEMENTS(g_bmpcache[0])))
{
old = g_bmpcache[cache_id][cache_idx];
old = g_bmpcache[cache_id][cache_idx].bitmap;
if (old != NULL)
{
ui_destroy_bitmap(old);
}
else
{
if (++g_num_bitmaps_in_memory[cache_id] > BMPCACHE2_C2_CELLS)
cache_remove_lru_bitmap(cache_id);
}
g_bmpcache[cache_id][cache_idx] = bitmap;
g_bmpcache[cache_id][cache_idx].bitmap = bitmap;
g_bmpcache[cache_id][cache_idx].usage = stamp;
}
else
{
@ -63,6 +108,18 @@ cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap)
}
}
/* Updates the persistent bitmap cache MRU information on exit */
void
cache_save_state(void)
{
int id, idx;
for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
if (IS_PERSISTENT(id))
for (idx = 0; idx < NUM_ELEMENTS(g_bmpcache[id]); idx++)
pstcache_touch_bitmap(id, idx, g_bmpcache[id][idx].usage);
}
/* FONT CACHE */
static FONTGLYPH g_fontcache[12][256];

View File

@ -199,6 +199,15 @@ enum RDP_INPUT_DEVICE
#define TEXT2_VERTICAL 0x04
#define TEXT2_IMPLICIT_X 0x20
/* RDP bitmap cache (version 2) constants */
#define BMPCACHE2_C0_CELLS 0x78
#define BMPCACHE2_C1_CELLS 0x78
#define BMPCACHE2_C2_CELLS 0x150
#define BMPCACHE2_NUM_PSTCELLS 0x9f6
#define PDU_FLAG_FIRST 0x01
#define PDU_FLAG_LAST 0x02
/* RDP capabilities */
#define RDP_CAPSET_GENERAL 1 /* Maps to generalCapabilitySet in T.128 page 138 */
#define RDP_CAPLEN_GENERAL 0x18
@ -231,8 +240,9 @@ enum RDP_INPUT_DEVICE
#define RDP_CAPSET_COLCACHE 10
#define RDP_CAPLEN_COLCACHE 0x08
#define RDP_CAPSET_UNKNOWN 13
#define RDP_CAPLEN_UNKNOWN 0x9C
#define RDP_CAPSET_BMPCACHE2 19
#define RDP_CAPLEN_BMPCACHE2 0x28
#define BMPCACHE2_FLAG_PERSIST (1<<31)
#define RDP_SOURCE "MSTSC"

View File

@ -108,14 +108,21 @@ More than 8 bpp are only supported when connecting to Windows XP
limited by the server configuration.
.TP
.BR "-x <experience>"
Alters default bandwith performance behaviour for RDP5. By default only
Changes default bandwidth performance behaviour for RDP5. By default only
theming is enabled, and all other options are disabled (corresponding
to modem (56 Kbps)). Setting experience to b[roadband] enables menu
animations and full window dragging. Setting experience to l[an] will
also enable the desktop wallpaper. Setting experience to m[odem]
disables all (including theming). Experience can also be a hexidecimal
disables all (including themes). Experience can also be a hexidecimal
number containing the flags.
.TP
.BR "-P"
Enable caching of bitmaps to disk (persistent bitmap caching). This generally
improves performance (especially on low bandwidth connections) and reduces
network traffic at the cost of slightly longer startup and some disk space.
(10MB for 8-bit colour, 20MB for 15/16-bit colour and 30MB for 24-bit colour
sessions)
.TP
.BR "-r <device>"
Enable redirection of the specified device on the client, such
that it appears on the server. Note that the allowed

112
orders.c
View File

@ -670,7 +670,7 @@ process_raw_bmpcache(STREAM s)
bitmap = ui_create_bitmap(width, height, inverted);
xfree(inverted);
cache_put_bitmap(cache_id, cache_idx, bitmap);
cache_put_bitmap(cache_id, cache_idx, bitmap, 0);
}
/* Process a bitmap cache order */
@ -695,7 +695,11 @@ process_bmpcache(STREAM s)
in_uint16_le(s, bufsize); /* bufsize */
in_uint16_le(s, cache_idx);
if (!g_use_rdp5)
if (g_use_rdp5)
{
size = bufsize;
}
else
{
/* Begin compressedBitmapData */
@ -706,10 +710,6 @@ process_bmpcache(STREAM s)
in_uint16_le(s, final_size);
}
else
{
size = bufsize;
}
in_uint8p(s, data, size);
DEBUG(("BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d,bpp=%d,size=%d,pad1=%d,bufsize=%d,pad2=%d,rs=%d,fs=%d)\n", width, height, cache_id, cache_idx, bpp, size, pad1, bufsize, pad2, row_size, final_size));
@ -719,7 +719,7 @@ process_bmpcache(STREAM s)
if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
{
bitmap = ui_create_bitmap(width, height, bmpdata);
cache_put_bitmap(cache_id, cache_idx, bitmap);
cache_put_bitmap(cache_id, cache_idx, bitmap, 0);
}
else
{
@ -729,6 +729,86 @@ process_bmpcache(STREAM s)
xfree(bmpdata);
}
/* Process a bitmap cache v2 order */
static void
process_bmpcache2(STREAM s, uint16 flags, BOOL compressed)
{
HBITMAP bitmap;
int y;
uint8 cache_id, cache_idx_low, width, height, Bpp;
uint16 cache_idx, bufsize;
uint8 *data, *bmpdata, *bitmap_id;
bitmap_id = NULL; /* prevent compiler warning */
cache_id = flags & ID_MASK;
Bpp = ((flags & MODE_MASK) >> MODE_SHIFT) - 2;
if (flags & PERSIST)
{
in_uint8p(s, bitmap_id, 8);
}
if (flags & SQUARE)
{
in_uint8(s, width);
height = width;
}
else
{
in_uint8(s, width);
in_uint8(s, height);
}
in_uint16_be(s, bufsize);
bufsize &= BUFSIZE_MASK;
in_uint8(s, cache_idx);
if (cache_idx & LONG_FORMAT)
{
in_uint8(s, cache_idx_low);
cache_idx = ((cache_idx ^ LONG_FORMAT) << 8) + cache_idx_low;
}
in_uint8p(s, data, bufsize);
DEBUG(("BMPCACHE2(compr=%d,flags=%x,cx=%d,cy=%d,id=%d,idx=%d,Bpp=%d,bs=%d)\n",
compressed, flags, width, height, cache_id, cache_idx, Bpp, bufsize));
bmpdata = (uint8 *) xmalloc(width * height * Bpp);
if (compressed)
{
if (!bitmap_decompress(bmpdata, width, height, data, bufsize, Bpp))
{
DEBUG(("Failed to decompress bitmap data\n"));
xfree(bmpdata);
return;
}
}
else
{
for (y = 0; y < height; y++)
memcpy(&bmpdata[(height - y - 1) * (width * Bpp)],
&data[y * (width * Bpp)], width * Bpp);
}
bitmap = ui_create_bitmap(width, height, bmpdata);
if (bitmap)
{
cache_put_bitmap(cache_id, cache_idx, bitmap, 0);
if (flags & PERSIST)
pstcache_put_bitmap(cache_id, cache_idx, bitmap_id, width, height,
width * height * Bpp, bmpdata);
}
else
{
DEBUG(("process_bmpcache2: ui_create_bitmap failed\n"));
}
xfree(bmpdata);
}
/* Process a colourmap cache order */
static void
process_colcache(STREAM s)
@ -796,12 +876,16 @@ process_fontcache(STREAM s)
static void
process_secondary_order(STREAM s)
{
uint16 length;
/* The length isn't calculated correctly by the server.
* For very compact orders the length becomes negative
* so a signed integer must be used. */
sint16 length;
uint16 flags;
uint8 type;
uint8 *next_order;
in_uint16_le(s, length);
in_uint8s(s, 2); /* flags */
in_uint16_le(s, (uint16) length);
in_uint16_le(s, flags); /* used by bmpcache2 */
in_uint8(s, type);
next_order = s->p + length + 7;
@ -824,6 +908,14 @@ process_secondary_order(STREAM s)
process_fontcache(s);
break;
case RDP_ORDER_RAW_BMPCACHE2:
process_bmpcache2(s, flags, False); /* uncompressed */
break;
case RDP_ORDER_BMPCACHE2:
process_bmpcache2(s, flags, True); /* compressed */
break;
default:
unimpl("secondary order %d\n", type);
}

View File

@ -46,7 +46,9 @@ enum RDP_SECONDARY_ORDER_TYPE
RDP_ORDER_RAW_BMPCACHE = 0,
RDP_ORDER_COLCACHE = 1,
RDP_ORDER_BMPCACHE = 2,
RDP_ORDER_FONTCACHE = 3
RDP_ORDER_FONTCACHE = 3,
RDP_ORDER_RAW_BMPCACHE2 = 4,
RDP_ORDER_BMPCACHE2 = 5
};
typedef struct _DESTBLT_ORDER
@ -252,6 +254,18 @@ typedef struct _RDP_BMPCACHE_ORDER
}
RDP_BMPCACHE_ORDER;
/* RDP_BMPCACHE2_ORDER */
#define ID_MASK 0x0007
#define MODE_MASK 0x0038
#define SQUARE 0x0080
#define PERSIST 0x0100
#define FLAG_51_UNKNOWN 0x0800
#define MODE_SHIFT 3
#define LONG_FORMAT 0x80
#define BUFSIZE_MASK 0x3FFF /* or 0x1FFF? */
#define MAX_GLYPH 32
typedef struct _RDP_FONT_GLYPH

17
proto.h
View File

@ -2,7 +2,8 @@
BOOL bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp);
/* cache.c */
HBITMAP cache_get_bitmap(uint8 cache_id, uint16 cache_idx);
void cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap);
void cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap, uint32 stamp);
void cache_save_state(void);
FONTGLYPH *cache_get_font(uint8 font, uint16 character);
void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width,
uint16 height, HGLYPH pixmap);
@ -60,6 +61,13 @@ int printer_enum_devices(uint32 * id, char *optarg);
/* printercache.c */
int printercache_load_blob(char *printer_name, uint8 ** data);
void printercache_process(STREAM s);
/* pstcache.c */
void pstcache_touch_bitmap(uint8 id, uint16 idx, uint32 stamp);
BOOL pstcache_load_bitmap(uint8 id, uint16 idx);
BOOL pstcache_put_bitmap(uint8 id, uint16 idx, uint8 *bmp_id, uint16 wd,
uint16 ht, uint16 len, uint8 *data);
int pstcache_enumerate(uint8 id, uint8 *list);
BOOL pstcache_init(uint8 id);
/* rdesktop.c */
int main(int argc, char *argv[]);
void generate_random(uint8 * random);
@ -75,6 +83,13 @@ void toupper_str(char *p);
char *l_to_a(long N, int base);
int load_licence(unsigned char **data);
void save_licence(unsigned char *data, int length);
BOOL rd_pstcache_mkdir(void);
int rd_open_file(char *filename);
void rd_close_file(int fd);
int rd_read_file(int fd, void *ptr, int len);
int rd_write_file(int fd, void* ptr, int len);
int rd_lseek_file(int fd, int offset);
BOOL rd_lock_file(int fd, int start, int len);
/* rdp5.c */
void rdp5_process(STREAM s, BOOL encryption);
/* rdp.c */

194
pstcache.c Normal file
View File

@ -0,0 +1,194 @@
/*
rdesktop: A Remote Desktop Protocol client.
Persistent Bitmap Cache routines
Copyright (C) Jeroen Meijer 2004
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rdesktop.h"
#define MAX_CELL_SIZE 0x1000 /* pixels */
#define IS_PERSISTENT(id) (g_pstcache_fd[id] > 0)
extern int g_server_bpp;
extern uint32 g_stamp;
extern BOOL g_bitmap_cache;
extern BOOL g_bitmap_cache_persist_enable;
extern BOOL g_bitmap_cache_precache;
int g_pstcache_fd[8];
int g_pstcache_Bpp;
BOOL g_pstcache_enumerated = False;
uint8 zero_id[] = {0, 0, 0, 0, 0, 0, 0, 0};
/* Update usage info for a bitmap */
void
pstcache_touch_bitmap(uint8 cache_id, uint16 cache_idx, uint32 stamp)
{
int fd;
if (!IS_PERSISTENT(cache_id))
return;
fd = g_pstcache_fd[cache_id];
rd_lseek_file(fd, 12 + cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
rd_write_file(fd, &stamp, sizeof(stamp));
}
/* Load a bitmap from the persistent cache */
BOOL
pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx)
{
uint8 *celldata;
int fd;
CELLHEADER cellhdr;
HBITMAP bitmap;
if (!(g_bitmap_cache_persist_enable && IS_PERSISTENT(cache_id)))
return False;
fd = g_pstcache_fd[cache_id];
rd_lseek_file(fd, cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
rd_read_file(fd, &cellhdr, sizeof(CELLHEADER));
celldata = (uint8 *)xmalloc(cellhdr.length);
rd_read_file(fd, celldata, cellhdr.length);
DEBUG(("Loading bitmap from disk (%d:%d)\n", cache_id, cache_idx));
bitmap = ui_create_bitmap(cellhdr.width, cellhdr.height, celldata);
cache_put_bitmap(cache_id, cache_idx, bitmap, cellhdr.stamp);
xfree(celldata);
return True;
}
/* Store a bitmap in the persistent cache */
BOOL
pstcache_put_bitmap(uint8 cache_id, uint16 cache_idx, uint8 *bitmap_id,
uint16 width, uint16 height, uint16 length, uint8 *data)
{
int fd;
CELLHEADER cellhdr;
if (!IS_PERSISTENT(cache_id))
return False;
memcpy(cellhdr.bitmap_id, bitmap_id, sizeof(BITMAP_ID));
cellhdr.width = width;
cellhdr.height = height;
cellhdr.length = length;
cellhdr.stamp = 0;
fd = g_pstcache_fd[cache_id];
rd_lseek_file(fd, cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
rd_write_file(fd, &cellhdr, sizeof(CELLHEADER));
rd_write_file(fd, data, length);
return True;
}
/* list the bitmaps from the persistent cache file */
int
pstcache_enumerate(uint8 cache_id, uint8 *idlist)
{
int fd, n, c = 0;
CELLHEADER cellhdr;
if (!(g_bitmap_cache && g_bitmap_cache_persist_enable && IS_PERSISTENT(cache_id)))
return 0;
/* The server disconnects if the bitmap cache content is sent more than once */
if (g_pstcache_enumerated)
return 0;
DEBUG(("pstcache enumeration... "));
for (n = 0; n < BMPCACHE2_NUM_PSTCELLS; n++)
{
fd = g_pstcache_fd[cache_id];
rd_lseek_file(fd, n * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
if (rd_read_file(fd, &cellhdr, sizeof(CELLHEADER)) <= 0)
break;
if (memcmp(cellhdr.bitmap_id, zero_id, sizeof(BITMAP_ID)) != 0)
{
memcpy(idlist + n * sizeof(BITMAP_ID), cellhdr.bitmap_id,
sizeof(BITMAP_ID));
if (cellhdr.stamp)
{
/* Pre-caching is not possible with 8bpp because a colourmap
* is needed to load them */
if (g_bitmap_cache_precache && (g_server_bpp > 8))
{
if (pstcache_load_bitmap(cache_id, n))
c++;
}
g_stamp = MAX(g_stamp, cellhdr.stamp);
}
}
else
{
break;
}
}
DEBUG(("%d bitmaps in persistent cache, %d bitmaps loaded in memory\n", n, c));
g_pstcache_enumerated = True;
return n;
}
/* initialise the persistent bitmap cache */
BOOL
pstcache_init(uint8 cache_id)
{
int fd;
char filename[256];
if (g_pstcache_enumerated)
return True;
g_pstcache_fd[cache_id] = 0;
if (!(g_bitmap_cache && g_bitmap_cache_persist_enable))
return False;
if (!rd_pstcache_mkdir())
{
DEBUG(("failed to get/make cache directory!\n"));
return False;
}
g_pstcache_Bpp = (g_server_bpp + 7) / 8;
sprintf(filename, "cache/pstcache_%d_%d", cache_id, g_pstcache_Bpp);
DEBUG(("persistent bitmap cache file: %s\n", filename));
fd = rd_open_file(filename);
if (fd == -1)
return False;
if (!rd_lock_file(fd, 0, 0))
{
warning("Persistent bitmap caching is disabled. (The file is already in use)\n");
rd_close_file(fd);
return False;
}
g_pstcache_fd[cache_id] = fd;
return True;
}

View File

@ -59,6 +59,8 @@ int g_win_button_size = 0; /* If zero, disable single app mode */
BOOL g_bitmap_compression = True;
BOOL g_sendmotion = True;
BOOL g_bitmap_cache = True;
BOOL g_bitmap_cache_persist_enable = False;
BOOL g_bitmap_cache_precache = True;
BOOL g_encryption = True;
BOOL packet_encryption = True;
BOOL g_desktop_save = True;
@ -124,8 +126,8 @@ usage(char *program)
fprintf(stderr, " -N: enable numlock syncronization\n");
fprintf(stderr, " -X: embed into another window with a given id.\n");
fprintf(stderr, " -a: connection colour depth\n");
fprintf(stderr,
" -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex number)\n");
fprintf(stderr, " -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex nr.)\n");
fprintf(stderr, " -P: use persistent bitmap caching\n");
fprintf(stderr, " -r: enable specified device redirection (this flag can be repeated)\n");
fprintf(stderr,
" '-r comport:COM1=/dev/ttyS0': enable serial redirection of /dev/ttyS0 to COM1\n");
@ -364,7 +366,8 @@ main(int argc, char *argv[])
#define VNCOPT
#endif
while ((c = getopt(argc, argv, VNCOPT "u:d:s:c:p:n:k:g:fbBeEmCDKS:T:NX:a:x:r:045h?")) != -1)
while ((c = getopt(argc, argv,
VNCOPT "u:d:s:c:p:n:k:g:fbBeEmCDKS:T:NX:a:x:Pr:045h?")) != -1)
{
switch (c)
{
@ -547,6 +550,10 @@ main(int argc, char *argv[])
}
break;
case 'P':
g_bitmap_cache_persist_enable = True;
break;
case 'r':
if (strncmp("sound", optarg, 5) == 0)
@ -713,6 +720,7 @@ main(int argc, char *argv[])
}
DEBUG(("Disconnecting...\n"));
cache_save_state();
rdp_disconnect();
ui_deinit();
@ -1121,3 +1129,95 @@ save_licence(unsigned char *data, int length)
xfree(tmppath);
xfree(path);
}
/* Create the bitmap cache directory */
BOOL
rd_pstcache_mkdir(void)
{
char *home;
char bmpcache_dir[256];
home = getenv("HOME");
if (home == NULL)
return False;
sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
{
perror(bmpcache_dir);
return False;
}
sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
{
perror(bmpcache_dir);
return False;
}
return True;
}
/* open a file in the .rdesktop directory */
int
rd_open_file(char *filename)
{
char *home;
char fn[256];
int fd;
home = getenv("HOME");
if (home == NULL)
return -1;
sprintf(fn, "%s/.rdesktop/%s", home, filename);
fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1)
perror(fn);
return fd;
}
/* close file */
void
rd_close_file(int fd)
{
close(fd);
}
/* read from file*/
int
rd_read_file(int fd, void *ptr, int len)
{
return read(fd, ptr, len);
}
/* write to file */
int
rd_write_file(int fd, void* ptr, int len)
{
return write(fd, ptr, len);
}
/* move file pointer */
int
rd_lseek_file(int fd, int offset)
{
return lseek(fd, offset, SEEK_SET);
}
/* do a write lock on a file */
BOOL
rd_lock_file(int fd, int start, int len)
{
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = start;
lock.l_len = len;
if (fcntl(fd, F_SETLK, &lock) == -1)
return False;
return True;
}

184
rdp.c
View File

@ -34,6 +34,7 @@ extern int g_server_bpp;
extern int g_width;
extern int g_height;
extern BOOL g_bitmap_cache;
extern BOOL g_bitmap_cache_persist_enable;
uint8 *g_next_packet;
uint32 g_rdp_shareid;
@ -366,6 +367,51 @@ rdp_send_input(uint32 time, uint16 message_type, uint16 device_flags, uint16 par
rdp_send_data(s, RDP_DATA_PDU_INPUT);
}
/* Inform the server on the contents of the persistent bitmap cache */
static void
rdp_enum_bmpcache2(void)
{
STREAM s;
uint8 idlist[BMPCACHE2_NUM_PSTCELLS * sizeof(BITMAP_ID)];
uint32 nids, offset, count, flags;
offset = 0;
nids = pstcache_enumerate(2, idlist);
while (offset < nids)
{
count = MIN(nids - offset, 169);
s = rdp_init_data(24 + count * sizeof(BITMAP_ID));
flags = 0;
if (offset == 0)
flags |= PDU_FLAG_FIRST;
if (nids - offset <= 169)
flags |= PDU_FLAG_LAST;
/* header */
out_uint32_le(s, 0);
out_uint16_le(s, count);
out_uint16_le(s, 0);
out_uint16_le(s, 0);
out_uint16_le(s, 0);
out_uint16_le(s, 0);
out_uint16_le(s, nids);
out_uint32_le(s, 0);
out_uint32_le(s, flags);
/* list */
out_uint8a(s, idlist + offset * sizeof(BITMAP_ID),
count * sizeof(BITMAP_ID));
s_mark_end(s);
rdp_send_data(s, 0x2b);
offset += 169;
}
}
/* Send an (empty) font information PDU */
static void
rdp_send_fonts(uint16 seq)
@ -486,6 +532,30 @@ rdp_out_bmpcache_caps(STREAM s)
out_uint16_le(s, 0x1000 * Bpp); /* max cell size */
}
/* Output bitmap cache v2 capability set */
static void
rdp_out_bmpcache2_caps(STREAM s)
{
out_uint16_le(s, RDP_CAPSET_BMPCACHE2);
out_uint16_le(s, RDP_CAPLEN_BMPCACHE2);
out_uint16_le(s, g_bitmap_cache_persist_enable ? 1 : 0); /* version */
out_uint16_le(s, 0x0300); /* flags? number of caches? */
out_uint32_le(s, BMPCACHE2_C0_CELLS);
out_uint32_le(s, BMPCACHE2_C1_CELLS);
if (pstcache_init(2))
{
out_uint32_le(s, BMPCACHE2_NUM_PSTCELLS | BMPCACHE2_FLAG_PERSIST);
}
else
{
out_uint32_le(s, BMPCACHE2_C2_CELLS);
}
out_uint8s(s, 20); /* other bitmap caches not used */
}
/* Output control capability set */
static void
rdp_out_control_caps(STREAM s)
@ -545,36 +615,41 @@ rdp_out_colcache_caps(STREAM s)
out_uint16(s, 0); /* pad */
}
static uint8 canned_caps[] = {
0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x08, 0x00, 0x01,
0x00, 0x00, 0x00, 0x0E, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
0x10, 0x00, 0x34, 0x00, 0xFE,
0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x08, 0x00,
0xFE, 0x00, 0x08, 0x00, 0xFE,
0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00, 0xFE, 0x00, 0x40, 0x00,
0xFE, 0x00, 0x80, 0x00, 0xFE,
0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01,
0x02, 0x00, 0x00, 0x00
static uint8 caps_0x0d[] = {
0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
/* Output unknown capability sets (number 13, 12, 14 and 16) */
static void
rdp_out_unknown_caps(STREAM s)
{
out_uint16_le(s, RDP_CAPSET_UNKNOWN);
out_uint16_le(s, 0x58);
static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
out_uint8p(s, canned_caps, RDP_CAPLEN_UNKNOWN - 4);
static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
static uint8 caps_0x10[] = {
0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
};
/* Output unknown capability sets */
static void
rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 *caps)
{
out_uint16_le(s, id);
out_uint16_le(s, length);
out_uint8p(s, caps, length - 4);
}
#define RDP5_FLAG 0x0030
@ -588,7 +663,9 @@ rdp_send_confirm_active(void)
RDP_CAPLEN_GENERAL + RDP_CAPLEN_BITMAP + RDP_CAPLEN_ORDER +
RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE +
RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE + RDP_CAPLEN_UNKNOWN + 4 /* w2k fix, why? */ ;
RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE +
0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
4 /* w2k fix, why? */ ;
s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE));
@ -608,14 +685,18 @@ rdp_send_confirm_active(void)
rdp_out_general_caps(s);
rdp_out_bitmap_caps(s);
rdp_out_order_caps(s);
rdp_out_bmpcache_caps(s);
g_use_rdp5 ? rdp_out_bmpcache2_caps(s) : rdp_out_bmpcache_caps(s);
rdp_out_colcache_caps(s);
rdp_out_activate_caps(s);
rdp_out_control_caps(s);
rdp_out_pointer_caps(s);
rdp_out_share_caps(s);
rdp_out_unknown_caps(s);
rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* international? */
rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c);
rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e);
rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* glyph cache? */
s_mark_end(s);
sec_send(s, sec_flags);
}
@ -659,33 +740,31 @@ rdp_process_bitmap_caps(STREAM s)
if (g_width != width || g_height != height)
{
warning("screen size changed from %dx%d to %dx%d\n", g_width, g_height,
width, height);
width, height);
g_width = width;
g_height = height;
ui_resize_window();
}
}
/* Respond to a demand active PDU */
static void
process_demand_active(STREAM s)
/* Process server capabilities */
void
rdp_process_server_caps(STREAM s, uint16 length)
{
int n;
uint8 type, *next;
uint16 len_src_descriptor, len_combined_caps, num_capsets, capset_type, capset_length;
uint8 *next, *start;
uint16 ncapsets, capset_type, capset_length;
in_uint32_le(s, g_rdp_shareid);
in_uint16_le(s, len_src_descriptor);
in_uint16_le(s, len_combined_caps);
in_uint8s(s, len_src_descriptor);
start = s->p;
in_uint16_le(s, num_capsets);
in_uint16_le(s, ncapsets);
in_uint8s(s, 2); /* pad */
DEBUG(("DEMAND_ACTIVE(id=0x%x,num_caps=%d)\n", g_rdp_shareid, num_capsets));
for (n = 0; n < num_capsets; n++)
for (n = 0; n < ncapsets; n++)
{
if (s->p > start + length)
return;
in_uint16_le(s, capset_type);
in_uint16_le(s, capset_length);
@ -704,6 +783,22 @@ process_demand_active(STREAM s)
s->p = next;
}
}
/* Respond to a demand active PDU */
static void
process_demand_active(STREAM s)
{
uint8 type;
uint16 len_src_descriptor, len_combined_caps;
in_uint32_le(s, g_rdp_shareid);
in_uint16_le(s, len_src_descriptor);
in_uint16_le(s, len_combined_caps);
in_uint8s(s, len_src_descriptor);
DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid));
rdp_process_server_caps(s, len_combined_caps);
rdp_send_confirm_active();
rdp_send_synchronise();
@ -716,6 +811,7 @@ process_demand_active(STREAM s)
if (g_use_rdp5)
{
rdp_enum_bmpcache2();
rdp_send_fonts(3);
}
else

22
types.h
View File

@ -119,6 +119,28 @@ typedef struct _VCHANNEL
}
VCHANNEL;
typedef struct _BMPCACHEENTRY
{
HBITMAP bitmap;
uint32 usage;
}
BMPCACHEENTRY;
/* PSTCACHE */
typedef uint8 BITMAP_ID[8];
/* Header for an entry in the persistent bitmap cache file */
typedef struct _PSTCACHE_CELLHEADER
{
BITMAP_ID bitmap_id;
uint8 width, height;
uint16 length;
uint32 stamp;
}
CELLHEADER;
#define MAX_CBSIZE 256
/* RDPSND */

14
xwin.c
View File

@ -47,6 +47,8 @@ extern uint32 g_embed_wnd;
BOOL g_enable_compose = False;
BOOL g_Unobscured; /* used for screenblt */
static GC g_gc = NULL;
static GC g_create_bitmap_gc = NULL;
static GC g_create_glyph_gc = NULL;
static Visual *g_visual;
static int g_depth;
static int g_bpp;
@ -969,6 +971,9 @@ ui_create_window(void)
if (g_gc == NULL)
g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
if (g_create_bitmap_gc == NULL)
g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
if ((g_ownbackstore) && (g_backstore == 0))
{
g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
@ -1481,7 +1486,7 @@ ui_create_bitmap(int width, int height, uint8 * data)
image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
(char *) tdata, width, height, bitmap_pad, 0);
XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
XFree(image);
if (tdata != data)
@ -1539,12 +1544,12 @@ ui_create_glyph(int width, int height, uint8 * data)
XImage *image;
Pixmap bitmap;
int scanline;
GC gc;
scanline = (width + 7) / 8;
bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
gc = XCreateGC(g_display, bitmap, 0, NULL);
if (g_create_glyph_gc == 0)
g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
width, height, 8, scanline);
@ -1552,10 +1557,9 @@ ui_create_glyph(int width, int height, uint8 * data)
image->bitmap_bit_order = MSBFirst;
XInitImage(image);
XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
XFree(image);
XFreeGC(g_display, gc);
return (HGLYPH) bitmap;
}