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:
parent
e68fe81938
commit
a1ec5d9ad7
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user