GUACAMOLE-445: Implement per-device announce stream, set it up with device initalization, and collect them all during the annonuce process.

This commit is contained in:
Nick Couchman 2018-03-24 16:22:55 -04:00
parent e68fe81938
commit a1ec5d9ad7
5 changed files with 99 additions and 63 deletions

View File

@ -29,6 +29,7 @@
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
#include <guacamole/socket.h> #include <guacamole/socket.h>
#include <guacamole/unicode.h>
#ifdef ENABLE_WINPR #ifdef ENABLE_WINPR
#include <winpr/stream.h> #include <winpr/stream.h>
@ -36,21 +37,6 @@
#include "compat/winpr-stream.h" #include "compat/winpr-stream.h"
#endif #endif
static void guac_rdpdr_device_fs_announce_handler(guac_rdpdr_device* device,
wStream* output_stream, int device_id) {
/* Filesystem header */
guac_client_log(device->rdpdr->client, GUAC_LOG_INFO, "Sending filesystem");
Stream_Write_UINT32(output_stream, RDPDR_DTYP_FILESYSTEM);
Stream_Write_UINT32(output_stream, device_id);
Stream_Write(output_stream, "GUAC\0\0\0\0", 8); /* DOS name */
/* Filesystem data */
Stream_Write_UINT32(output_stream, GUAC_FILESYSTEM_NAME_LENGTH);
Stream_Write(output_stream, GUAC_FILESYSTEM_NAME, GUAC_FILESYSTEM_NAME_LENGTH);
}
static void guac_rdpdr_device_fs_iorequest_handler(guac_rdpdr_device* device, static void guac_rdpdr_device_fs_iorequest_handler(guac_rdpdr_device* device,
wStream* input_stream, int file_id, int completion_id, int major_func, int minor_func) { wStream* input_stream, int file_id, int completion_id, int major_func, int minor_func) {
@ -128,6 +114,9 @@ static void guac_rdpdr_device_fs_iorequest_handler(guac_rdpdr_device* device,
} }
static void guac_rdpdr_device_fs_free_handler(guac_rdpdr_device* device) { static void guac_rdpdr_device_fs_free_handler(guac_rdpdr_device* device) {
Stream_Free(device->device_announce, 1);
} }
void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr) { void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr) {
@ -143,9 +132,21 @@ void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr) {
device->rdpdr = rdpdr; device->rdpdr = rdpdr;
device->device_id = id; device->device_id = id;
device->device_name = "Guacamole Filesystem"; device->device_name = "Guacamole Filesystem";
int device_name_len = guac_utf8_strlen(device->device_name);
device->device_type = RDPDR_DTYP_FILESYSTEM;
device->dos_name = "GUACFS\0\0";
/* Set up the device announcement */
device->device_announce_len = 20 + device_name_len;
device->device_announce = Stream_New(NULL, device->device_announce_len);
Stream_Write_UINT32(device->device_announce, device->device_type);
Stream_Write_UINT32(device->device_announce, device->device_id);
Stream_Write(device->device_announce, device->dos_name, 8);
Stream_Write_UINT32(device->device_announce, device_name_len);
Stream_Write(device->device_announce, device->device_name, device_name_len);
/* Set handlers */ /* Set handlers */
device->announce_handler = guac_rdpdr_device_fs_announce_handler;
device->iorequest_handler = guac_rdpdr_device_fs_iorequest_handler; device->iorequest_handler = guac_rdpdr_device_fs_iorequest_handler;
device->free_handler = guac_rdpdr_device_fs_free_handler; device->free_handler = guac_rdpdr_device_fs_free_handler;

View File

@ -22,9 +22,11 @@
#include "rdp.h" #include "rdp.h"
#include "rdpdr_messages.h" #include "rdpdr_messages.h"
#include "rdpdr_service.h" #include "rdpdr_service.h"
#include "unicode.h"
#include <freerdp/utils/svc_plugin.h> #include <freerdp/utils/svc_plugin.h>
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/unicode.h>
#ifdef ENABLE_WINPR #ifdef ENABLE_WINPR
#include <winpr/stream.h> #include <winpr/stream.h>
@ -122,20 +124,29 @@ static void guac_rdpdr_send_client_capability(guac_rdpdrPlugin* rdpdr) {
static void guac_rdpdr_send_client_device_list_announce_request(guac_rdpdrPlugin* rdpdr) { static void guac_rdpdr_send_client_device_list_announce_request(guac_rdpdrPlugin* rdpdr) {
int i; /* Calculate number of bytes needed for the stream */
wStream* output_stream = Stream_New(NULL, 256); int streamBytes = 16;
for (int i=0; i < rdpdr->devices_registered; i++)
streamBytes += rdpdr->devices[i].device_announce_len;
/* Allocate the stream */
wStream* output_stream = Stream_New(NULL, streamBytes);
/* Write header */ /* Write header */
Stream_Write_UINT16(output_stream, RDPDR_CTYP_CORE); Stream_Write_UINT16(output_stream, RDPDR_CTYP_CORE);
Stream_Write_UINT16(output_stream, PAKID_CORE_DEVICELIST_ANNOUNCE); Stream_Write_UINT16(output_stream, PAKID_CORE_DEVICELIST_ANNOUNCE);
/* List devices */ /* Get the stream for each of the devices. */
Stream_Write_UINT32(output_stream, rdpdr->devices_registered); Stream_Write_UINT32(output_stream, rdpdr->devices_registered);
for (i=0; i<rdpdr->devices_registered; i++) { for (int i=0; i<rdpdr->devices_registered; i++) {
guac_rdpdr_device* device = &(rdpdr->devices[i]);
device->announce_handler(device, output_stream, i); Stream_Write(output_stream,
Stream_Buffer(rdpdr->devices[i].device_announce),
rdpdr->devices[i].device_announce_len);
guac_client_log(rdpdr->client, GUAC_LOG_INFO, "Registered device %i (%s)", guac_client_log(rdpdr->client, GUAC_LOG_INFO, "Registered device %i (%s)",
device->device_id, device->device_name); rdpdr->devices[i].device_id, rdpdr->devices[i].device_name);
} }
svc_plugin_send((rdpSvcPlugin*) rdpdr, output_stream); svc_plugin_send((rdpSvcPlugin*) rdpdr, output_stream);

View File

@ -133,38 +133,6 @@ void guac_rdpdr_process_print_job_close(guac_rdpdr_device* device,
} }
static void guac_rdpdr_device_printer_announce_handler(guac_rdpdr_device* device,
wStream* output_stream, int device_id) {
/* Printer header */
guac_client_log(device->rdpdr->client, GUAC_LOG_INFO, "Sending printer");
Stream_Write_UINT32(output_stream, RDPDR_DTYP_PRINT);
Stream_Write_UINT32(output_stream, device_id);
Stream_Write(output_stream, "PRN1\0\0\0\0", 8); /* DOS name */
/* Printer data */
int settings_length = guac_utf8_strlen(device->device_name);
int printer_name_length = (settings_length + 1) * 2;
char printer_name[printer_name_length];
guac_rdp_utf8_to_utf16((const unsigned char*)device->device_name,
settings_length, printer_name, printer_name_length);
printer_name[printer_name_length - 2] = '\0';
printer_name[printer_name_length - 1] = '\0';
Stream_Write_UINT32(output_stream, 24 + GUAC_PRINTER_DRIVER_LENGTH + printer_name_length);
Stream_Write_UINT32(output_stream,
RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER
| RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER);
Stream_Write_UINT32(output_stream, 0); /* reserved - must be 0 */
Stream_Write_UINT32(output_stream, 0); /* PnPName length (PnPName is ultimately ignored) */
Stream_Write_UINT32(output_stream, GUAC_PRINTER_DRIVER_LENGTH); /* DriverName length */
Stream_Write_UINT32(output_stream, printer_name_length); /* PrinterName length */
Stream_Write_UINT32(output_stream, 0); /* CachedFields length */
Stream_Write(output_stream, GUAC_PRINTER_DRIVER, GUAC_PRINTER_DRIVER_LENGTH);
Stream_Write(output_stream, printer_name, printer_name_length);
}
static void guac_rdpdr_device_printer_iorequest_handler(guac_rdpdr_device* device, static void guac_rdpdr_device_printer_iorequest_handler(guac_rdpdr_device* device,
wStream* input_stream, int file_id, int completion_id, int major_func, int minor_func) { wStream* input_stream, int file_id, int completion_id, int major_func, int minor_func) {
@ -196,7 +164,9 @@ static void guac_rdpdr_device_printer_iorequest_handler(guac_rdpdr_device* devic
} }
static void guac_rdpdr_device_printer_free_handler(guac_rdpdr_device* device) { static void guac_rdpdr_device_printer_free_handler(guac_rdpdr_device* device) {
/* Do nothing */
Stream_Free(device->device_announce, 1);
} }
void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name) { void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name) {
@ -210,9 +180,41 @@ void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name) {
device->rdpdr = rdpdr; device->rdpdr = rdpdr;
device->device_id = id; device->device_id = id;
device->device_name = printer_name; device->device_name = printer_name;
int device_name_len = guac_utf8_strlen(device->device_name);
device->device_type = RDPDR_DTYP_PRINT;
device->dos_name = "PRN1\0\0\0\0";
/* Set up device announce stream */
int prt_name_len = (device_name_len + 1) * 2;
device->device_announce_len = 44 + prt_name_len
+ GUAC_PRINTER_DRIVER_LENGTH;
device->device_announce = Stream_New(NULL, device->device_announce_len);
/* Write common information. */
Stream_Write_UINT32(device->device_announce, device->device_type);
Stream_Write_UINT32(device->device_announce, device->device_id);
Stream_Write(device->device_announce, device->dos_name, 8);
/* DeviceDataLength */
Stream_Write_UINT32(device->device_announce, 24 + prt_name_len + GUAC_PRINTER_DRIVER_LENGTH);
/* Begin printer-specific information */
Stream_Write_UINT32(device->device_announce,
RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER
| RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER); /* Printer flags */
Stream_Write_UINT32(device->device_announce, 0); /* Reserved - must be 0. */
Stream_Write_UINT32(device->device_announce, 0); /* PnPName Length - ignored. */
Stream_Write_UINT32(device->device_announce, GUAC_PRINTER_DRIVER_LENGTH);
Stream_Write_UINT32(device->device_announce, prt_name_len);
Stream_Write_UINT32(device->device_announce, 0); /* CachedFields length. */
Stream_Write(device->device_announce, GUAC_PRINTER_DRIVER, GUAC_PRINTER_DRIVER_LENGTH);
guac_rdp_utf8_to_utf16((const unsigned char*) device->device_name,
device_name_len + 1, (char*) Stream_Pointer(device->device_announce),
prt_name_len);
Stream_Seek(device->device_announce, prt_name_len);
/* Set handlers */ /* Set handlers */
device->announce_handler = guac_rdpdr_device_printer_announce_handler;
device->iorequest_handler = guac_rdpdr_device_printer_iorequest_handler; device->iorequest_handler = guac_rdpdr_device_printer_iorequest_handler;
device->free_handler = guac_rdpdr_device_printer_free_handler; device->free_handler = guac_rdpdr_device_printer_free_handler;

View File

@ -34,6 +34,13 @@
/** /**
* Registers a new printer device within the RDPDR plugin. This must be done * Registers a new printer device within the RDPDR plugin. This must be done
* before RDPDR connection finishes. * before RDPDR connection finishes.
*
* @param rdpdr
* The RDP device redirection plugin where the device is registered.
*
* @param printer_name
* The name of the printer that will be registered with the RDP
* connection and passed through to the server.
*/ */
void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name); void guac_rdpdr_register_printer(guac_rdpdrPlugin* rdpdr, char* printer_name);

View File

@ -74,15 +74,30 @@ struct guac_rdpdr_device {
int device_id; int device_id;
/** /**
* An arbitrary device name, used for logging purposes only. * Device name, used for logging and for passthrough to the
* server.
*/ */
const char* device_name; const char* device_name;
/** /**
* Handler which will be called when the RDPDR plugin is forming the client * The type of RDPDR device that this represents.
* device announce list.
*/ */
guac_rdpdr_device_announce_handler* announce_handler; uint32_t device_type;
/**
* The DOS name of the device. Max 8 bytes, including terminator.
*/
const char *dos_name;
/**
* The stream that stores the RDPDR device announcement for this device.
*/
wStream* device_announce;
/**
* The length of the device_announce wStream.
*/
int device_announce_len;
/** /**
* Handler which should be called for every I/O request received. * Handler which should be called for every I/O request received.
@ -90,7 +105,7 @@ struct guac_rdpdr_device {
guac_rdpdr_device_iorequest_handler* iorequest_handler; guac_rdpdr_device_iorequest_handler* iorequest_handler;
/** /**
* Handlel which should be called when the device is being free'd. * Handler which should be called when the device is being freed.
*/ */
guac_rdpdr_device_free_handler* free_handler; guac_rdpdr_device_free_handler* free_handler;
@ -154,7 +169,7 @@ void guac_rdpdr_process_terminate(rdpSvcPlugin* plugin);
void guac_rdpdr_process_event(rdpSvcPlugin* plugin, wMessage* event); void guac_rdpdr_process_event(rdpSvcPlugin* plugin, wMessage* event);
/** /**
* Creates a new stream which contains the ommon DR_DEVICE_IOCOMPLETION header * Creates a new stream which contains the common DR_DEVICE_IOCOMPLETION header
* used for virtually all responses. * used for virtually all responses.
*/ */
wStream* guac_rdpdr_new_io_completion(guac_rdpdr_device* device, wStream* guac_rdpdr_new_io_completion(guac_rdpdr_device* device,