Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-channels / wtsvc.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
3  * Server Virtual Channel Interface
4  *
5  * Copyright 2011-2012 Vic Lee
6  *
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
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  */
19
20 #include "config.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <freerdp/constants.h>
25 #include <freerdp/utils/memory.h>
26
27 #include "wtsvc.h"
28
29 typedef struct wts_data_item
30 {
31         uint16 channel_id;
32         uint8* buffer;
33         uint32 length;
34 } wts_data_item;
35
36 static void wts_data_item_free(wts_data_item* item)
37 {
38         xfree(item->buffer);
39         xfree(item);
40 }
41
42 static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, uint8* data, int size, int flags, int total_size)
43 {
44         wts_data_item* item;
45
46         if (flags & CHANNEL_FLAG_FIRST)
47         {
48                 stream_set_pos(channel->receive_data, 0);
49         }
50
51         stream_check_size(channel->receive_data, size);
52         stream_write(channel->receive_data, data, size);
53
54         if (flags & CHANNEL_FLAG_LAST)
55         {
56                 if (stream_get_length(channel->receive_data) != total_size)
57                 {
58                         printf("WTSProcessChannelData: read error\n");
59                 }
60                 if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_DVC)
61                 {
62                         /* TODO: Receive DVC channel data */
63                 }
64                 else
65                 {
66                         item = xnew(wts_data_item);
67                         item->length = stream_get_length(channel->receive_data);
68                         item->buffer = xmalloc(item->length);
69                         memcpy(item->buffer, stream_get_head(channel->receive_data), item->length);
70
71                         freerdp_mutex_lock(channel->mutex);
72                         list_enqueue(channel->receive_queue, item);
73                         freerdp_mutex_unlock(channel->mutex);
74
75                         wait_obj_set(channel->receive_event);
76                 }
77                 stream_set_pos(channel->receive_data, 0);
78         }
79 }
80
81 static int WTSReceiveChannelData(freerdp_peer* client, int channelId, uint8* data, int size, int flags, int total_size)
82 {
83         int i;
84         boolean result = false;
85         rdpPeerChannel* channel;
86
87         for (i = 0; i < client->settings->num_channels; i++)
88         {
89                 if (client->settings->channels[i].channel_id == channelId)
90                         break;
91         }
92         if (i < client->settings->num_channels)
93         {
94                 channel = (rdpPeerChannel*) client->settings->channels[i].handle;
95                 if (channel != NULL)
96                 {
97                         WTSProcessChannelData(channel, channelId, data, size, flags, total_size);
98                         result = true;
99                 }
100         }
101
102         return result;
103 }
104
105 WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client)
106 {
107         WTSVirtualChannelManager* vcm;
108
109         vcm = xnew(WTSVirtualChannelManager);
110         if (vcm != NULL)
111         {
112                 vcm->client = client;
113                 vcm->send_event = wait_obj_new();
114                 vcm->send_queue = list_new();
115                 vcm->mutex = freerdp_mutex_new();
116
117                 client->ReceiveChannelData = WTSReceiveChannelData;
118         }
119
120         return vcm;
121 }
122
123 void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm)
124 {
125         wts_data_item* item;
126
127         if (vcm != NULL)
128         {
129                 if (vcm->drdynvc_channel != NULL)
130                 {
131                         WTSVirtualChannelClose(vcm->drdynvc_channel);
132                         vcm->drdynvc_channel = NULL;
133                 }
134
135                 wait_obj_free(vcm->send_event);
136                 while ((item = (wts_data_item*) list_dequeue(vcm->send_queue)) != NULL)
137                 {
138                         wts_data_item_free(item);
139                 }
140                 list_free(vcm->send_queue);
141                 freerdp_mutex_free(vcm->mutex);
142                 xfree(vcm);
143         }
144 }
145
146 void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm,
147         void** fds, int* fds_count)
148 {
149         wait_obj_get_fds(vcm->send_event, fds, fds_count);
150 }
151
152 boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm)
153 {
154         boolean result = true;
155         wts_data_item* item;
156
157         wait_obj_clear(vcm->send_event);
158
159         freerdp_mutex_lock(vcm->mutex);
160         while ((item = (wts_data_item*) list_dequeue(vcm->send_queue)) != NULL)
161         {
162                 if (vcm->client->SendChannelData(vcm->client, item->channel_id, item->buffer, item->length) == false)
163                 {
164                         result = false;
165                 }
166                 wts_data_item_free(item);
167                 if (result == false)
168                         break;
169         }
170         freerdp_mutex_unlock(vcm->mutex);
171
172         return result;
173 }
174
175 void* WTSVirtualChannelOpenEx(
176         /* __in */ WTSVirtualChannelManager* vcm,
177         /* __in */ const char* pVirtualName,
178         /* __in */ uint32 flags)
179 {
180         int i;
181         int len;
182         rdpPeerChannel* channel;
183         const char* channel_name;
184         freerdp_peer* client = vcm->client;
185
186         channel_name = ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0 ? "drdynvc" : pVirtualName);
187
188         len = strlen(channel_name);
189         if (len > 8)
190                 return NULL;
191
192         for (i = 0; i < client->settings->num_channels; i++)
193         {
194                 if (client->settings->channels[i].joined &&
195                         strncmp(client->settings->channels[i].name, channel_name, len) == 0)
196                 {
197                         break;
198                 }
199         }
200         if (i >= client->settings->num_channels)
201                 return NULL;
202
203         channel = (rdpPeerChannel*) client->settings->channels[i].handle;
204         if (channel == NULL)
205         {
206                 channel = xnew(rdpPeerChannel);
207                 channel->vcm = vcm;
208                 channel->client = client;
209                 channel->channel_id = client->settings->channels[i].channel_id;
210                 channel->index = i;
211                 channel->receive_data = stream_new(client->settings->vc_chunk_size);
212                 if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0)
213                 {
214                         channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC;
215                         vcm->drdynvc_channel = channel;
216                 }
217                 else
218                 {
219                         channel->channel_type = RDP_PEER_CHANNEL_TYPE_SVC;
220                         channel->receive_event = wait_obj_new();
221                         channel->receive_queue = list_new();
222                         channel->mutex = freerdp_mutex_new();
223                 }
224
225                 client->settings->channels[i].handle = channel;
226         }
227         if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_DVC)
228         {
229                 /* TODO: do DVC channel initialization here using pVirtualName */
230                 /* A sub-channel should be created and returned, instead of using the main drdynvc channel */
231                 /* Set channel->index to num_channels */
232         }
233
234         return channel;
235 }
236
237 boolean WTSVirtualChannelQuery(
238         /* __in */  void* hChannelHandle,
239         /* __in */  WTS_VIRTUAL_CLASS WtsVirtualClass,
240         /* __out */ void** ppBuffer,
241         /* __out */ uint32* pBytesReturned)
242 {
243         void* fds[10];
244         int fds_count = 0;
245         boolean result = false;
246         rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
247
248         switch (WtsVirtualClass)
249         {
250                 case WTSVirtualFileHandle:
251                         wait_obj_get_fds(channel->receive_event, fds, &fds_count);
252                         *ppBuffer = xmalloc(sizeof(void*));
253                         memcpy(*ppBuffer, &fds[0], sizeof(void*));
254                         *pBytesReturned = sizeof(void*);
255                         result = true;
256                         break;
257
258                 default:
259                         break;
260         }
261         return result;
262 }
263
264 void WTSFreeMemory(
265         /* __in */ void* pMemory)
266 {
267         xfree(pMemory);
268 }
269
270 boolean WTSVirtualChannelRead(
271         /* __in */  void* hChannelHandle,
272         /* __in */  uint32 TimeOut,
273         /* __out */ uint8* Buffer,
274         /* __in */  uint32 BufferSize,
275         /* __out */ uint32* pBytesRead)
276 {
277         wts_data_item* item;
278         rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
279
280         item = (wts_data_item*) list_peek(channel->receive_queue);
281         if (item == NULL)
282         {
283                 wait_obj_clear(channel->receive_event);
284                 *pBytesRead = 0;
285                 return true;
286         }
287         *pBytesRead = item->length;
288         if (item->length > BufferSize)
289                 return false;
290
291         /* remove the first element (same as what we just peek) */
292         freerdp_mutex_lock(channel->mutex);
293         list_dequeue(channel->receive_queue);
294         if (channel->receive_queue->head == NULL)
295                 wait_obj_clear(channel->receive_event);
296         freerdp_mutex_unlock(channel->mutex);
297
298         memcpy(Buffer, item->buffer, item->length);
299
300         return true;
301 }
302
303 boolean WTSVirtualChannelWrite(
304         /* __in */  void* hChannelHandle,
305         /* __in */  uint8* Buffer,
306         /* __in */  uint32 Length,
307         /* __out */ uint32* pBytesWritten)
308 {
309         uint32 written = 0;
310         wts_data_item* item;
311         boolean result = false;
312         rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
313         WTSVirtualChannelManager* vcm = channel->vcm;
314
315         if (channel == NULL)
316                 return false;
317
318         if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
319         {
320                 item = xnew(wts_data_item);
321                 item->channel_id = channel->channel_id;
322                 item->buffer = xmalloc(Length);
323                 item->length = Length;
324                 memcpy(item->buffer, Buffer, Length);
325
326                 freerdp_mutex_lock(vcm->mutex);
327                 list_enqueue(vcm->send_queue, item);
328                 freerdp_mutex_unlock(vcm->mutex);
329
330                 wait_obj_set(vcm->send_event);
331
332                 written = Length;
333                 result = true;
334         }
335         else
336         {
337                 /* TODO: Send to DVC channel */
338         }
339
340         if (pBytesWritten != NULL)
341                 *pBytesWritten = written;
342         return result;
343 }
344
345 boolean WTSVirtualChannelClose(
346         /* __in */ void* hChannelHandle)
347 {
348         wts_data_item* item;
349         rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
350
351         if (channel != NULL)
352         {
353                 if (channel->index < channel->client->settings->num_channels)
354                         channel->client->settings->channels[channel->index].handle = NULL;
355                 stream_free(channel->receive_data);
356                 if (channel->receive_event)
357                         wait_obj_free(channel->receive_event);
358                 if (channel->receive_queue)
359                 {
360                         while ((item = (wts_data_item*) list_dequeue(channel->receive_queue)) != NULL)
361                         {
362                                 wts_data_item_free(item);
363                         }
364                         list_free(channel->receive_queue);
365                 }
366                 if (channel->mutex)
367                         freerdp_mutex_free(channel->mutex);
368                 xfree(channel);
369         }
370
371         return true;
372 }