From 7b55ece8e46d1590947382680f660d5e7c66d5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85strand?= Date: Thu, 2 Mar 2006 15:22:25 +0000 Subject: [PATCH] Added support for a new virtual channel, lspci, which makes it possible for the remote RDP server to enumerate the local PCI devices. git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@1052 423420c4-83ab-492f-b58f-81f9feb106b5 --- Makefile.in | 4 +- channels.c | 2 +- doc/lspci-channel.txt | 39 ++++++++++++++ doc/rdesktop.1 | 5 ++ proto.h | 4 ++ rdesktop.c | 120 ++++++++++++++++++++++++++++++++++++++++++ types.h | 2 + 7 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 doc/lspci-channel.txt diff --git a/Makefile.in b/Makefile.in index 4e6383a..2960469 100644 --- a/Makefile.in +++ b/Makefile.in @@ -25,7 +25,7 @@ LDVNC = @LDVNC@ VNCLINK = @VNCLINK@ SOUNDOBJ = @SOUNDOBJ@ -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 +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 lspci.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 @@ -82,7 +82,7 @@ proto: bitmap.c cache.c channels.c cliprdr.c disk.c mppc.c ewmhints.c \ iso.c licence.c mcs.c orders.c parallel.c printer.c printercache.c \ pstcache.c rdesktop.c rdp5.c rdp.c rdpdr.c rdpsnd.c rdpsnd_oss.c \ - secure.c serial.c tcp.c xclip.c xkeymap.c xwin.c >> proto.h + secure.c serial.c tcp.c xclip.c xkeymap.c xwin.c lspci.c >> proto.h cat proto.tail >> proto.h .PHONY: clean diff --git a/channels.c b/channels.c index 2c5b612..0cf83b9 100644 --- a/channels.c +++ b/channels.c @@ -21,7 +21,7 @@ #include "rdesktop.h" -#define MAX_CHANNELS 4 +#define MAX_CHANNELS 5 #define CHANNEL_CHUNK_LENGTH 1600 #define CHANNEL_FLAG_FIRST 0x01 #define CHANNEL_FLAG_LAST 0x02 diff --git a/doc/lspci-channel.txt b/doc/lspci-channel.txt new file mode 100644 index 0000000..7864517 --- /dev/null +++ b/doc/lspci-channel.txt @@ -0,0 +1,39 @@ + +Protocol overview +================= + +The lspci virtual channel makes it possible for the remote RDP server +to enumerate the local PCI devices. The protocol on this channel is +text based and line oriented: One single line per request or +response. UNIX-style LF line breaks are used. The maximum line length +is 1023, newline included. + +rdesktop acts as a server, with only one request: + + LSPCI + +The response is several lines with this syntax: + +,,,,,, + +After the last line, a line with a single dot is sent. + +Example: + +0300,102b,0525,102b,0338,04,00 +0401,8086,24d5,1028,0174,02,8f +. + + +Usage +===== + +To enable to lspci virtual channel, run rdesktop with "-r lspci". + + +References +========== + +http://www.microsoft.com/msj/1099/terminal/terminal.aspx +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/termserv/termserv/terminal_services_virtual_channels.asp + diff --git a/doc/rdesktop.1 b/doc/rdesktop.1 index 38f0f4d..6808865 100644 --- a/doc/rdesktop.1 +++ b/doc/rdesktop.1 @@ -186,6 +186,11 @@ Redirects sound generated on the server to the client. "remote" only has any effect when you connect to the console with the -0 option. (Requires Windows XP or newer). .TP +.BR "-r lspci" +Activates the lspci channel, which allows the server to enumerate the +clients PCI devices. See the file lspci-channel.txt in the +documentation for more information. +.TP .BR "-0" Attach to the console of the server (requires Windows Server 2003 or newer). diff --git a/proto.h b/proto.h index 94c90a6..4a1666a 100644 --- a/proto.h +++ b/proto.h @@ -117,6 +117,8 @@ void hexdump(unsigned char *p, unsigned int len); char *next_arg(char *src, char needle); void toupper_str(char *p); BOOL str_startswith(const char *s, const char *prefix); +BOOL str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data); +BOOL subprocess(char *const argv[], str_handle_lines_t linehandler, void *data); char *l_to_a(long N, int base); int load_licence(unsigned char **data); void save_licence(unsigned char *data, int length); @@ -269,6 +271,8 @@ void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy); void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy); void ui_begin_update(void); void ui_end_update(void); +/* lspci.c */ +BOOL lspci_init(void); /* *INDENT-OFF* */ #ifdef __cplusplus diff --git a/rdesktop.c b/rdesktop.c index 0a41838..c75d27a 100644 --- a/rdesktop.c +++ b/rdesktop.c @@ -86,6 +86,7 @@ BOOL g_hide_decorations = False; BOOL g_use_rdp5 = True; BOOL g_console_session = False; BOOL g_numlock_sync = False; +BOOL lspci_enabled = False; BOOL g_owncolmap = False; BOOL g_ownbackstore = True; /* We can't rely on external BackingStore */ uint32 g_embed_wnd; @@ -679,6 +680,10 @@ main(int argc, char *argv[]) { serial_enum_devices(&g_num_devices, optarg + 7); } + else if (str_startswith(optarg, "lspci")) + { + lspci_enabled = True; + } else if (str_startswith(optarg, "lptport")) { parallel_enum_devices(&g_num_devices, optarg + 7); @@ -804,6 +809,10 @@ main(int argc, char *argv[]) if (g_rdpsnd) rdpsnd_init(); #endif + + if (lspci_enabled) + lspci_init(); + rdpdr_init(); while (run_count < 2 && continue_connect) /* add support for Session Directory; only reconnect once */ @@ -1178,6 +1187,117 @@ str_startswith(const char *s, const char *prefix) } +/* Split input into lines, and call linehandler for each + line. Incomplete lines are saved in the rest variable, which should + initially point to NULL. When linehandler returns False, stop and + return False. Otherwise, return True. */ +BOOL +str_handle_lines(const char *input, char **rest, str_handle_lines_t linehandler, void *data) +{ + char *buf, *p; + char *oldrest; + size_t inputlen; + size_t buflen; + size_t restlen = 0; + BOOL ret = True; + + /* Copy data to buffer */ + inputlen = strlen(input); + if (*rest) + restlen = strlen(*rest); + buflen = restlen + inputlen + 1; + buf = (char *) xmalloc(buflen); + buf[0] = '\0'; + if (*rest) + STRNCPY(buf, *rest, buflen); + strncat(buf, input, inputlen); + p = buf; + + while (1) + { + char *newline = strchr(p, '\n'); + if (newline) + { + *newline = '\0'; + if (!linehandler(p, data)) + { + p = newline + 1; + ret = False; + break; + } + p = newline + 1; + } + else + { + break; + + } + } + + /* Save in rest */ + oldrest = *rest; + restlen = buf + buflen - p; + *rest = (char *) xmalloc(restlen); + STRNCPY((*rest), p, restlen); + xfree(oldrest); + + xfree(buf); + return ret; +} + +/* Execute the program specified by argv. For each line in + stdout/stderr output, call linehandler. Returns false on failure. */ +BOOL +subprocess(char *const argv[], str_handle_lines_t linehandler, void *data) +{ + pid_t child; + int fd[2]; + int n = 1; + char output[256]; + char *rest = NULL; + + if (pipe(fd) < 0) + { + perror("pipe"); + return False; + } + + if ((child = fork()) < 0) + { + perror("fork"); + return False; + } + + /* Child */ + if (child == 0) + { + /* Close read end */ + close(fd[0]); + + /* Redirect stdout and stderr to pipe */ + dup2(fd[1], 1); + dup2(fd[1], 2); + + /* Execute */ + execvp(argv[0], argv); + perror("Error executing child"); + _exit(128); + } + + /* Parent. Close write end. */ + close(fd[1]); + while (n > 0) + { + n = read(fd[0], output, 255); + output[n] = '\0'; + str_handle_lines(output, &rest, linehandler, data); + } + xfree(rest); + + return True; +} + + /* not all clibs got ltoa */ #define LTOA_BUFSIZE (sizeof(long) * 8 + 1) diff --git a/types.h b/types.h index 2c4625a..eed9d8a 100644 --- a/types.h +++ b/types.h @@ -264,3 +264,5 @@ typedef struct fileinfo uint32 info_class; } FILEINFO; + +typedef BOOL(*str_handle_lines_t) (const char *line, void *data);