diff --git a/src/protocols/rdp/Makefile.am b/src/protocols/rdp/Makefile.am index 0ac074a2..0d07a747 100644 --- a/src/protocols/rdp/Makefile.am +++ b/src/protocols/rdp/Makefile.am @@ -46,9 +46,10 @@ libguac_client_rdp_la_SOURCES = \ unicode.c \ user.c -guacai_sources = \ - guac_ai/ai_service.c \ - ptr_string.c +guacai_sources = \ + guac_ai/ai_messages.c \ + guac_ai/ai_service.c \ + ptr_string.c guacsvc_sources = \ guac_svc/svc_service.c \ @@ -74,6 +75,7 @@ guacdr_sources = \ noinst_HEADERS = \ compat/client-cliprdr.h \ compat/rail.h \ + guac_ai/ai_messages.h \ guac_ai/ai_service.h \ guac_rdpdr/rdpdr_fs_messages.h \ guac_rdpdr/rdpdr_fs_messages_dir_info.h \ diff --git a/src/protocols/rdp/guac_ai/ai_messages.c b/src/protocols/rdp/guac_ai/ai_messages.c new file mode 100644 index 00000000..c799a448 --- /dev/null +++ b/src/protocols/rdp/guac_ai/ai_messages.c @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "config.h" + +#include "ai_messages.h" +#include "rdp.h" + +#include + +#include +#include +#include +#include + +#ifdef ENABLE_WINPR +#include +#else +#include "compat/winpr-stream.h" +#endif + +void guac_rdp_ai_process_version(guac_client* client, + IWTSVirtualChannel* channel, wStream* stream) { + + UINT32 version; + Stream_Read_UINT32(stream, version); + + /* Warn if server's version number is incorrect */ + if (version != 1) + guac_client_log(client, GUAC_LOG_WARNING, + "Server reports AUDIO_INPUT version %i, not 1", version); + + /* Build response version PDU */ + wStream* response = Stream_New(NULL, 5); + Stream_Write_UINT8(response, GUAC_RDP_MSG_SNDIN_VERSION); /* MessageId */ + Stream_Write_UINT32(response, 1); /* Version */ + + /* Send response */ + channel->Write(channel, (UINT32) Stream_GetPosition(response), + Stream_Buffer(response), NULL); + Stream_Free(response, TRUE); + +} + +void guac_rdp_ai_process_formats(guac_client* client, + IWTSVirtualChannel* channel, wStream* stream) { + + /* STUB */ + guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: formats"); + +} + +void guac_rdp_ai_process_open(guac_client* client, + IWTSVirtualChannel* channel, wStream* stream) { + + /* STUB */ + guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: open"); + +} + +void guac_rdp_ai_process_formatchange(guac_client* client, + IWTSVirtualChannel* channel, wStream* stream) { + + /* STUB */ + guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: formatchange"); + +} + diff --git a/src/protocols/rdp/guac_ai/ai_messages.h b/src/protocols/rdp/guac_ai/ai_messages.h new file mode 100644 index 00000000..96282e57 --- /dev/null +++ b/src/protocols/rdp/guac_ai/ai_messages.h @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef GUAC_RDP_AI_MESSAGES_H +#define GUAC_RDP_AI_MESSAGES_H + +#include "config.h" + +#include +#include + +#ifdef ENABLE_WINPR +#include +#else +#include "compat/winpr-stream.h" +#endif + +/** + * The message ID associated with the AUDIO_INPUT Version PDU. The Version PDU + * is sent by both the client and the server to indicate their version of the + * AUDIO_INPUT channel protocol (which must always be 1). + */ +#define GUAC_RDP_MSG_SNDIN_VERSION 0x01 + +/** + * The message ID associated with the AUDIO_INPUT Sound Formats PDU. The + * Sound Formats PDU is sent by the client and the server to indicate the + * formats of audio supported. + */ +#define GUAC_RDP_MSG_SNDIN_FORMATS 0x02 + +/** + * The message ID associated with the AUDIO_INPUT Open PDU. The Open PDU is + * sent by the server to inform the client that the AUDIO_INPUT channel is + * now open. + */ +#define GUAC_RDP_MSG_SNDIN_OPEN 0x03 + +/** + * The message ID associated with the AUDIO_INPUT Open Reply PDU. The Open + * Reply PDU is sent by the client (after sending a Format Change PDU) to + * acknowledge that the AUDIO_INPUT channel is open. + */ +#define GUAC_RDP_MSG_SNDIN_OPEN_REPLY 0x04 + +/** + * The message ID associated with the AUDIO_INPUT Incoming Data PDU. The + * Incoming Data PDU is sent by the client to inform the server of incoming + * sound format or audio data. + */ +#define GUAC_RDP_MSG_SNDIN_DATA_INCOMING 0x05 + +/** + * The message ID associated with the AUDIO_INPUT Data PDU. The Data PDU is + * sent by the client and contains audio data read from the microphone. + */ +#define GUAC_RDP_MSG_SNDIN_DATA 0x06 + +/** + * The message ID associated with the AUDIO_INPUT Format Change PDU. The Format + * Change PDU is sent by the client to acknowledge the current sound format, or + * by the server to request a different sound format. + */ +#define GUAC_RDP_MSG_SNDIN_FORMATCHANGE 0x07 + +/** + * Processes a Version PDU received from the RDP server. The Version PDU is + * sent by the server to indicate its version of the AUDIO_INPUT channel + * protocol (which must always be 1). + * + * @param client + * The guac_client associated with the current RDP connection. + * + * @param channel + * The IWTSVirtualChannel instance associated with the connected + * AUDIO_INPUT channel. + * + * @param stream + * The received PDU, with the read position just after the message ID field + * common to all AUDIO_INPUT PDUs. + */ +void guac_rdp_ai_process_version(guac_client* client, + IWTSVirtualChannel* channel, wStream* stream); + +/** + * Processes a Sound Formats PDU received from the RDP server. The Sound + * Formats PDU is sent by the server to indicate the formats of audio + * supported. + * + * @param client + * The guac_client associated with the current RDP connection. + * + * @param channel + * The IWTSVirtualChannel instance associated with the connected + * AUDIO_INPUT channel. + * + * @param stream + * The received PDU, with the read position just after the message ID field + * common to all AUDIO_INPUT PDUs. + */ +void guac_rdp_ai_process_formats(guac_client* client, + IWTSVirtualChannel* channel, wStream* stream); + +/** + * Processes a Open PDU received from the RDP server. The Open PDU is sent by + * the server to inform the client that the AUDIO_INPUT channel is now open. + * + * @param client + * The guac_client associated with the current RDP connection. + * + * @param channel + * The IWTSVirtualChannel instance associated with the connected + * AUDIO_INPUT channel. + * + * @param stream + * The received PDU, with the read position just after the message ID field + * common to all AUDIO_INPUT PDUs. + */ +void guac_rdp_ai_process_open(guac_client* client, + IWTSVirtualChannel* channel, wStream* stream); + +/** + * Processes a Format Change PDU received from the RDP server. The Format + * Change PDU is sent by the server to request a different sound format. + * + * @param client + * The guac_client associated with the current RDP connection. + * + * @param channel + * The IWTSVirtualChannel instance associated with the connected + * AUDIO_INPUT channel. + * + * @param stream + * The received PDU, with the read position just after the message ID field + * common to all AUDIO_INPUT PDUs. + */ +void guac_rdp_ai_process_formatchange(guac_client* client, + IWTSVirtualChannel* channel, wStream* stream); + +#endif + diff --git a/src/protocols/rdp/guac_ai/ai_service.c b/src/protocols/rdp/guac_ai/ai_service.c index e822f90e..d6538bcd 100644 --- a/src/protocols/rdp/guac_ai/ai_service.c +++ b/src/protocols/rdp/guac_ai/ai_service.c @@ -19,6 +19,7 @@ #include "config.h" +#include "ai_messages.h" #include "ai_service.h" #include "ptr_string.h" #include "rdp.h" @@ -47,18 +48,49 @@ * The guac_client associated with RDP connection having the AUDIO_INPUT * connection along which the given data was received. * + * @param channel + * A reference to the IWTSVirtualChannel instance along which responses + * should be sent. + * * @param stream * The data received along the AUDIO_INPUT channel. */ -static void guac_rdp_ai_handle_data(guac_client* client, wStream* stream) { +static void guac_rdp_ai_handle_data(guac_client* client, + IWTSVirtualChannel* channel, wStream* stream) { /* Read message ID from received PDU */ BYTE message_id; Stream_Read_UINT8(stream, message_id); - /* STUB */ - guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT data received: 0x%x", - message_id); + /* Invoke appropriate message processor based on ID */ + switch (message_id) { + + /* Version PDU */ + case GUAC_RDP_MSG_SNDIN_VERSION: + guac_rdp_ai_process_version(client, channel, stream); + break; + + /* Sound Formats PDU */ + case GUAC_RDP_MSG_SNDIN_FORMATS: + guac_rdp_ai_process_formats(client, channel, stream); + break; + + /* Open PDU */ + case GUAC_RDP_MSG_SNDIN_OPEN: + guac_rdp_ai_process_open(client, channel, stream); + break; + + /* Format Change PDU */ + case GUAC_RDP_MSG_SNDIN_FORMATCHANGE: + guac_rdp_ai_process_formatchange(client, channel, stream); + break; + + /* Log unknown message IDs */ + default: + guac_client_log(client, GUAC_LOG_DEBUG, + "Unknown AUDIO_INPUT message ID: 0x%x", message_id); + + } } @@ -85,10 +117,11 @@ static int guac_rdp_ai_data(IWTSVirtualChannelCallback* channel_callback, guac_rdp_ai_channel_callback* ai_channel_callback = (guac_rdp_ai_channel_callback*) channel_callback; + IWTSVirtualChannel* channel = ai_channel_callback->channel; /* Invoke generalized (API-independent) data handler */ wStream* stream = Stream_New(buffer, size); - guac_rdp_ai_handle_data(ai_channel_callback->client, stream); + guac_rdp_ai_handle_data(ai_channel_callback->client, channel, stream); Stream_Free(stream, FALSE); return 0; @@ -114,9 +147,10 @@ static int guac_rdp_ai_data(IWTSVirtualChannelCallback* channel_callback, guac_rdp_ai_channel_callback* ai_channel_callback = (guac_rdp_ai_channel_callback*) channel_callback; + IWTSVirtualChannel* channel = ai_channel_callback->channel; /* Invoke generalized (API-independent) data handler */ - guac_rdp_ai_handle_data(ai_channel_callback->client, stream); + guac_rdp_ai_handle_data(ai_channel_callback->client, channel, stream); return 0; @@ -197,6 +231,7 @@ static int guac_rdp_ai_new_connection( /* Init listener callback with data from plugin */ ai_channel_callback->client = ai_listener_callback->client; + ai_channel_callback->channel = channel; ai_channel_callback->parent.OnDataReceived = guac_rdp_ai_data; ai_channel_callback->parent.OnClose = guac_rdp_ai_close; diff --git a/src/protocols/rdp/guac_ai/ai_service.h b/src/protocols/rdp/guac_ai/ai_service.h index 4377812a..28f2227e 100644 --- a/src/protocols/rdp/guac_ai/ai_service.h +++ b/src/protocols/rdp/guac_ai/ai_service.h @@ -63,6 +63,12 @@ typedef struct guac_rdp_ai_channel_callback { */ IWTSVirtualChannelCallback parent; + /** + * The actual virtual channel instance along which the AUDIO_INPUT plugin + * should send any responses. + */ + IWTSVirtualChannel* channel; + /** * The guac_client instance associated with the RDP connection using the * AUDIO_INPUT plugin.