2 * FreeRDP: A Remote Desktop Protocol client.
3 * Dynamic Virtual Channel
5 * Copyright 2010-2011 Vic Lee
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
23 #include <freerdp/constants.h>
24 #include <freerdp/utils/memory.h>
25 #include <freerdp/utils/stream.h>
26 #include <freerdp/utils/svc_plugin.h>
27 #include <freerdp/utils/wait_obj.h>
30 #include "drdynvc_types.h"
31 #include "drdynvc_main.h"
33 #define CREATE_REQUEST_PDU 0x01
34 #define DATA_FIRST_PDU 0x02
36 #define CLOSE_REQUEST_PDU 0x04
37 #define CAPABILITY_REQUEST_PDU 0x05
49 IWTSVirtualChannelManager* channel_mgr;
52 static int drdynvc_write_variable_uint(STREAM* stream, uint32 val)
59 stream_write_uint8(stream, val);
61 else if (val <= 0xFFFF)
64 stream_write_uint16(stream, val);
69 stream_write_uint32(stream, val);
74 int drdynvc_write_data(drdynvcPlugin* drdynvc, uint32 ChannelId, uint8* data, uint32 data_size)
83 DEBUG_DVC("ChannelId=%d size=%d", ChannelId, data_size);
85 data_out = stream_new(CHANNEL_CHUNK_LENGTH);
86 stream_set_pos(data_out, 1);
87 cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
89 if (data_size <= CHANNEL_CHUNK_LENGTH - pos)
91 pos = stream_get_pos(data_out);
92 stream_set_pos(data_out, 0);
93 stream_write_uint8(data_out, 0x30 | cbChId);
94 stream_set_pos(data_out, pos);
95 stream_write(data_out, data, data_size);
96 error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
100 /* Fragment the data */
101 cbLen = drdynvc_write_variable_uint(data_out, data_size);
102 pos = stream_get_pos(data_out);
103 stream_set_pos(data_out, 0);
104 stream_write_uint8(data_out, 0x20 | cbChId | (cbLen << 2));
105 stream_set_pos(data_out, pos);
106 chunk_len = CHANNEL_CHUNK_LENGTH - pos;
107 stream_write(data_out, data, chunk_len);
109 data_size -= chunk_len;
110 error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
112 while (error == CHANNEL_RC_OK && data_size > 0)
114 data_out = stream_new(CHANNEL_CHUNK_LENGTH);
115 stream_set_pos(data_out, 1);
116 cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
118 pos = stream_get_pos(data_out);
119 stream_set_pos(data_out, 0);
120 stream_write_uint8(data_out, 0x30 | cbChId);
121 stream_set_pos(data_out, pos);
123 chunk_len = data_size;
124 if (chunk_len > CHANNEL_CHUNK_LENGTH - pos)
125 chunk_len = CHANNEL_CHUNK_LENGTH - pos;
126 stream_write(data_out, data, chunk_len);
128 data_size -= chunk_len;
129 error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
132 if (error != CHANNEL_RC_OK)
134 DEBUG_WARN("VirtualChannelWrite failed %d", error);
140 int drdynvc_push_event(drdynvcPlugin* drdynvc, RDP_EVENT* event)
144 error = svc_plugin_send_event((rdpSvcPlugin*)drdynvc, event);
145 if (error != CHANNEL_RC_OK)
147 DEBUG_WARN("pVirtualChannelEventPush failed %d", error);
153 static int drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
158 DEBUG_DVC("Sp=%d cbChId=%d", Sp, cbChId);
159 stream_seek(s, 1); /* pad */
160 stream_read_uint16(s, drdynvc->version);
161 if (drdynvc->version == 2)
163 stream_read_uint16(s, drdynvc->PriorityCharge0);
164 stream_read_uint16(s, drdynvc->PriorityCharge1);
165 stream_read_uint16(s, drdynvc->PriorityCharge2);
166 stream_read_uint16(s, drdynvc->PriorityCharge3);
168 data_out = stream_new(4);
169 stream_write_uint16(data_out, 0x0050); /* Cmd+Sp+cbChId+Pad. Note: MSTSC sends 0x005c */
170 stream_write_uint16(data_out, drdynvc->version);
171 error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
172 if (error != CHANNEL_RC_OK)
174 DEBUG_WARN("VirtualChannelWrite failed %d", error);
180 static uint32 drdynvc_read_variable_uint(STREAM* stream, int cbLen)
187 stream_read_uint8(stream, val);
190 stream_read_uint16(stream, val);
193 stream_read_uint32(stream, val);
199 static int drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
206 ChannelId = drdynvc_read_variable_uint(s, cbChId);
207 pos = stream_get_pos(s);
208 DEBUG_DVC("ChannelId=%d ChannelName=%s", ChannelId, stream_get_tail(s));
210 error = dvcman_create_channel(drdynvc->channel_mgr, ChannelId, (char*)stream_get_tail(s));
212 data_out = stream_new(pos + 4);
213 stream_write_uint8(data_out, 0x10 | cbChId);
214 stream_set_pos(s, 1);
215 stream_copy(data_out, s, pos - 1);
219 DEBUG_DVC("channel created");
220 stream_write_uint32(data_out, 0);
224 DEBUG_DVC("no listener");
225 stream_write_uint32(data_out, (uint32)(-1));
228 error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
229 if (error != CHANNEL_RC_OK)
231 DEBUG_WARN("VirtualChannelWrite failed %d", error);
237 static int drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
243 ChannelId = drdynvc_read_variable_uint(s, cbChId);
244 Length = drdynvc_read_variable_uint(s, Sp);
245 DEBUG_DVC("ChannelId=%d Length=%d", ChannelId, Length);
247 error = dvcman_receive_channel_data_first(drdynvc->channel_mgr, ChannelId, Length);
251 return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
252 stream_get_tail(s), stream_get_left(s));
255 static int drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
259 ChannelId = drdynvc_read_variable_uint(s, cbChId);
260 DEBUG_DVC("ChannelId=%d", ChannelId);
262 return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
263 stream_get_tail(s), stream_get_left(s));
266 static int drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
270 ChannelId = drdynvc_read_variable_uint(s, cbChId);
271 DEBUG_DVC("ChannelId=%d", ChannelId);
272 dvcman_close_channel(drdynvc->channel_mgr, ChannelId);
277 static void drdynvc_process_receive(rdpSvcPlugin* plugin, STREAM* s)
279 drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
285 stream_read_uint8(s, value);
286 Cmd = (value & 0xf0) >> 4;
287 Sp = (value & 0x0c) >> 2;
288 cbChId = (value & 0x03) >> 0;
290 DEBUG_DVC("Cmd=0x%x", Cmd);
294 case CAPABILITY_REQUEST_PDU:
295 drdynvc_process_capability_request(drdynvc, Sp, cbChId, s);
297 case CREATE_REQUEST_PDU:
298 drdynvc_process_create_request(drdynvc, Sp, cbChId, s);
301 drdynvc_process_data_first(drdynvc, Sp, cbChId, s);
304 drdynvc_process_data(drdynvc, Sp, cbChId, s);
306 case CLOSE_REQUEST_PDU:
307 drdynvc_process_close_request(drdynvc, Sp, cbChId, s);
310 DEBUG_WARN("unknown drdynvc cmd 0x%x", Cmd);
317 static void drdynvc_process_connect(rdpSvcPlugin* plugin)
319 drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
321 DEBUG_DVC("connecting");
323 drdynvc->channel_mgr = dvcman_new(drdynvc);
324 dvcman_load_plugin(drdynvc->channel_mgr, svc_plugin_get_data(plugin));
325 dvcman_init(drdynvc->channel_mgr);
328 static void drdynvc_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
330 freerdp_event_free(event);
333 static void drdynvc_process_terminate(rdpSvcPlugin* plugin)
335 drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
337 DEBUG_DVC("terminating");
339 if (drdynvc->channel_mgr != NULL)
340 dvcman_free(drdynvc->channel_mgr);
344 DEFINE_SVC_PLUGIN(drdynvc, "drdynvc",
345 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
346 CHANNEL_OPTION_COMPRESS_RDP)