~ubuntu-branches/ubuntu/wily/freerdp/wily-proposed

« back to all changes in this revision

Viewing changes to channels/drdynvc/drdynvc_main.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt, Jeremy Bicha, Jean-Louis Dupond, Martin Pitt
  • Date: 2012-01-31 10:02:14 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120131100214-jaok3uwvni7sqxth
Tags: 1.0.0-0git1
Upload current Debian packaging git to get this rolling for precise.

[ Jeremy Bicha ]
* New upstream release. Closes: #647498.
* Updated symbols and bumped soname
* debian/control:
  - Added new build dependencies
  - Bump Standards-Version to 3.9.2
* debian/source/format: Set to 3.0 (quilt)
* debian/rules: Turn on strict symbols checking
* debian/watch: Watch github

[ Jean-Louis Dupond ]
* debian/control: Updated homepage
* debian/copyright: Reflect upstream switch to the Apache license

[ Martin Pitt ]
* debian/libfreerdp0.symbols: Fix version number, should
  be 1.0~beta5, not 1.0-beta5.
* debian/control: Add libavcodec-dev build dependency, upstream build system
  checks for that. Thanks Jean-Louis Dupond!

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
   Copyright (c) 2010 Jay Sorg
3
 
 
4
 
   Permission is hereby granted, free of charge, to any person obtaining a
5
 
   copy of this software and associated documentation files (the "Software"),
6
 
   to deal in the Software without restriction, including without limitation
7
 
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
 
   and/or sell copies of the Software, and to permit persons to whom the
9
 
   Software is furnished to do so, subject to the following conditions:
10
 
 
11
 
   The above copyright notice and this permission notice shall be included
12
 
   in all copies or substantial portions of the Software.
13
 
 
14
 
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
 
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
 
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
 
   DEALINGS IN THE SOFTWARE.
21
 
 
22
 
*/
 
1
/**
 
2
 * FreeRDP: A Remote Desktop Protocol client.
 
3
 * Dynamic Virtual Channel
 
4
 *
 
5
 * Copyright 2010-2011 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
 */
23
19
 
24
20
#include <stdio.h>
25
21
#include <stdlib.h>
26
22
#include <string.h>
27
 
#include <pthread.h>
28
 
#include <unistd.h>
29
 
#include <sys/time.h>
 
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>
 
28
 
 
29
#include "dvcman.h"
30
30
#include "drdynvc_types.h"
31
 
#include "wait_obj.h"
32
 
#include "dvcman.h"
33
31
#include "drdynvc_main.h"
34
32
 
35
33
#define CREATE_REQUEST_PDU     0x01
38
36
#define CLOSE_REQUEST_PDU      0x04
39
37
#define CAPABILITY_REQUEST_PDU 0x05
40
38
 
41
 
struct data_in_item
42
 
{
43
 
        struct data_in_item * next;
44
 
        char * data;
45
 
        int data_size;
46
 
};
47
 
 
48
39
struct drdynvc_plugin
49
40
{
50
 
        rdpChanPlugin chan_plugin;
 
41
        rdpSvcPlugin plugin;
51
42
 
52
 
        CHANNEL_ENTRY_POINTS ep;
53
 
        CHANNEL_DEF channel_def;
54
 
        uint32 open_handle;
55
 
        char * data_in;
56
 
        int data_in_size;
57
 
        int data_in_read;
58
 
        struct wait_obj * term_event;
59
 
        struct wait_obj * data_in_event;
60
 
        struct data_in_item * in_list_head;
61
 
        struct data_in_item * in_list_tail;
62
 
        /* for locking the linked list */
63
 
        pthread_mutex_t * in_mutex;
64
 
        int thread_status;
65
43
        int version;
66
44
        int PriorityCharge0;
67
45
        int PriorityCharge1;
68
46
        int PriorityCharge2;
69
47
        int PriorityCharge3;
70
48
 
71
 
        IWTSVirtualChannelManager * channel_mgr;
72
 
        char * dvc_data;
73
 
        uint32 dvc_data_pos;
74
 
        uint32 dvc_data_size;
 
49
        IWTSVirtualChannelManager* channel_mgr;
75
50
};
76
51
 
77
 
#if LOG_LEVEL > 10
78
 
void
79
 
hexdump(char* p, int len)
80
 
{
81
 
  unsigned char* line;
82
 
  int i;
83
 
  int thisline;
84
 
  int offset;
85
 
 
86
 
  line = (unsigned char*)p;
87
 
  offset = 0;
88
 
  while (offset < len)
89
 
  {
90
 
    printf("%04x ", offset);
91
 
    thisline = len - offset;
92
 
    if (thisline > 16)
93
 
    {
94
 
      thisline = 16;
95
 
    }
96
 
    for (i = 0; i < thisline; i++)
97
 
    {
98
 
      printf("%02x ", line[i]);
99
 
    }
100
 
    for (; i < 16; i++)
101
 
    {
102
 
      printf("   ");
103
 
    }
104
 
    for (i = 0; i < thisline; i++)
105
 
    {
106
 
      printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
107
 
    }
108
 
    printf("\n");
109
 
    offset += thisline;
110
 
    line += thisline;
111
 
  }
112
 
}
113
 
#else
114
 
#define hexdump(p,len)
115
 
#endif
116
 
 
117
 
static int
118
 
set_variable_uint(uint32 val, char * data, uint32 * pos)
 
52
static int drdynvc_write_variable_uint(STREAM* stream, uint32 val)
119
53
{
120
54
        int cb;
121
55
 
122
56
        if (val <= 0xFF)
123
57
        {
124
58
                cb = 0;
125
 
                SET_UINT8(data, *pos, val);
126
 
                *pos += 1;
 
59
                stream_write_uint8(stream, val);
127
60
        }
128
61
        else if (val <= 0xFFFF)
129
62
        {
130
63
                cb = 1;
131
 
                SET_UINT16(data, *pos, val);
132
 
                *pos += 2;
 
64
                stream_write_uint16(stream, val);
133
65
        }
134
66
        else
135
67
        {
136
68
                cb = 3;
137
 
                SET_UINT32(data, *pos, val);
138
 
                *pos += 4;
 
69
                stream_write_uint32(stream, val);
139
70
        }
140
71
        return cb;
141
72
}
142
73
 
143
 
int
144
 
drdynvc_write_data(drdynvcPlugin * plugin, uint32 ChannelId, char * data, uint32 data_size)
 
74
int drdynvc_write_data(drdynvcPlugin* drdynvc, uint32 ChannelId, uint8* data, uint32 data_size)
145
75
{
146
 
        uint32 pos;
147
 
        uint32 t;
148
 
        int cbChId;
149
 
        int cbLen;
150
 
        char * out_data = NULL;
 
76
        STREAM* data_out;
 
77
        uint32 pos = 0;
 
78
        uint32 cbChId;
 
79
        uint32 cbLen;
 
80
        uint32 chunk_len;
151
81
        int error;
152
 
        uint32 data_pos;
153
 
 
154
 
        LLOGLN(10, ("drdynvc_write_data: ChannelId=%d size=%d", ChannelId, data_size));
155
 
 
156
 
        out_data = (char *) malloc(CHANNEL_CHUNK_LENGTH);
157
 
        memset(out_data, 0, CHANNEL_CHUNK_LENGTH);
158
 
        pos = 1;
159
 
        cbChId = set_variable_uint(ChannelId, out_data, &pos);
 
82
 
 
83
        DEBUG_DVC("ChannelId=%d size=%d", ChannelId, data_size);
 
84
 
 
85
        data_out = stream_new(CHANNEL_CHUNK_LENGTH);
 
86
        stream_set_pos(data_out, 1);
 
87
        cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
160
88
 
161
89
        if (data_size <= CHANNEL_CHUNK_LENGTH - pos)
162
90
        {
163
 
                SET_UINT8(out_data, 0, 0x30 | cbChId);
164
 
                memcpy(out_data + pos, data, data_size);
165
 
                hexdump(out_data, data_size + pos);
166
 
                error = plugin->ep.pVirtualChannelWrite(plugin->open_handle,
167
 
                        out_data, data_size + pos, out_data);
 
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);
168
97
        }
169
98
        else
170
99
        {
171
100
                /* Fragment the data */
172
 
                cbLen = set_variable_uint(data_size, out_data, &pos);
173
 
                SET_UINT8(out_data, 0, 0x20 | cbChId | (cbLen << 2));
174
 
                data_pos = CHANNEL_CHUNK_LENGTH - pos;
175
 
                memcpy(out_data + pos, data, data_pos);
176
 
                hexdump(out_data, CHANNEL_CHUNK_LENGTH);
177
 
                error = plugin->ep.pVirtualChannelWrite(plugin->open_handle,
178
 
                        out_data, CHANNEL_CHUNK_LENGTH, out_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);
 
108
                data += chunk_len;
 
109
                data_size -= chunk_len;
 
110
                error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
179
111
 
180
 
                while (error == CHANNEL_RC_OK && data_pos < data_size)
 
112
                while (error == CHANNEL_RC_OK && data_size > 0)
181
113
                {
182
 
                        out_data = (char *) malloc(CHANNEL_CHUNK_LENGTH);
183
 
                        memset(out_data, 0, CHANNEL_CHUNK_LENGTH);
184
 
                        pos = 1;
185
 
                        cbChId = set_variable_uint(ChannelId, out_data, &pos);
186
 
 
187
 
                        SET_UINT8(out_data, 0, 0x30 | cbChId);
188
 
                        t = data_size - data_pos;
189
 
                        if (t > CHANNEL_CHUNK_LENGTH - pos)
190
 
                                t = CHANNEL_CHUNK_LENGTH - pos;
191
 
                        memcpy(out_data + pos, data + data_pos, t);
192
 
                        data_pos += t;
193
 
                        hexdump(out_data, t + pos);
194
 
                        error = plugin->ep.pVirtualChannelWrite(plugin->open_handle,
195
 
                                out_data, t + pos, out_data);
 
114
                        data_out = stream_new(CHANNEL_CHUNK_LENGTH);
 
115
                        stream_set_pos(data_out, 1);
 
116
                        cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
 
117
 
 
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);
 
122
 
 
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);
 
127
                        data += chunk_len;
 
128
                        data_size -= chunk_len;
 
129
                        error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
196
130
                }
197
131
        }
198
132
        if (error != CHANNEL_RC_OK)
199
133
        {
200
 
                if (out_data)
201
 
                        free(out_data);
202
 
                LLOGLN(0, ("drdynvc_write_data: "
203
 
                        "VirtualChannelWrite "
204
 
                        "failed %d", error));
205
 
                return 1;
206
 
        }
207
 
        return 0;
208
 
}
209
 
 
210
 
/* called by main thread
211
 
   add item to linked list and inform worker thread that there is data */
212
 
static void
213
 
signal_data_in(drdynvcPlugin * plugin)
214
 
{
215
 
        struct data_in_item * item;
216
 
 
217
 
        item = (struct data_in_item *) malloc(sizeof(struct data_in_item));
218
 
        item->next = 0;
219
 
        item->data = plugin->data_in;
220
 
        plugin->data_in = 0;
221
 
        item->data_size = plugin->data_in_size;
222
 
        plugin->data_in_size = 0;
223
 
        pthread_mutex_lock(plugin->in_mutex);
224
 
        if (plugin->in_list_tail == 0)
225
 
        {
226
 
                plugin->in_list_head = item;
227
 
                plugin->in_list_tail = item;
228
 
        }
229
 
        else
230
 
        {
231
 
                plugin->in_list_tail->next = item;
232
 
                plugin->in_list_tail = item;
233
 
        }
234
 
        pthread_mutex_unlock(plugin->in_mutex);
235
 
        wait_obj_set(plugin->data_in_event);
236
 
}
237
 
 
238
 
static int
239
 
process_CAPABILITY_REQUEST_PDU(drdynvcPlugin * plugin, int Sp, int cbChId,
240
 
        char * data, int data_size)
241
 
{
242
 
        int error;
243
 
        int size;
244
 
        char * out_data;
245
 
 
246
 
        LLOGLN(10, ("process_CAPABILITY_REQUEST_PDU:"));
247
 
        plugin->version = GET_UINT16(data, 2);
248
 
        if (plugin->version == 2)
249
 
        {
250
 
                plugin->PriorityCharge0 = GET_UINT16(data, 4);
251
 
                plugin->PriorityCharge1 = GET_UINT16(data, 6);
252
 
                plugin->PriorityCharge2 = GET_UINT16(data, 8);
253
 
                plugin->PriorityCharge3 = GET_UINT16(data, 10);
254
 
        }
255
 
        size = 4;
256
 
        out_data = (char *) malloc(size);
257
 
        SET_UINT16(out_data, 0, 0x0050); /* Cmd+Sp+cbChId+Pad. Note: MSTSC sends 0x005c */
258
 
        SET_UINT16(out_data, 2, plugin->version);
259
 
        hexdump(out_data, 4);
260
 
        error = plugin->ep.pVirtualChannelWrite(plugin->open_handle,
261
 
        out_data, size, out_data);
262
 
        if (error != CHANNEL_RC_OK)
263
 
        {
264
 
                LLOGLN(0, ("process_CAPABILITY_REQUEST_PDU: "
265
 
                        "VirtualChannelWrite "
266
 
                        "failed %d", error));
267
 
                return 1;
268
 
        }
269
 
        return 0;
270
 
}
271
 
 
272
 
static uint32
273
 
get_variable_uint(int cbLen, char * data, int * pos)
 
134
                DEBUG_WARN("VirtualChannelWrite failed %d", error);
 
135
                return 1;
 
136
        }
 
137
        return 0;
 
138
}
 
139
 
 
140
int drdynvc_push_event(drdynvcPlugin* drdynvc, RDP_EVENT* event)
 
141
{
 
142
        int error;
 
143
 
 
144
        error = svc_plugin_send_event((rdpSvcPlugin*)drdynvc, event);
 
145
        if (error != CHANNEL_RC_OK)
 
146
        {
 
147
                DEBUG_WARN("pVirtualChannelEventPush failed %d", error);
 
148
                return 1;
 
149
        }
 
150
        return 0;
 
151
}
 
152
 
 
153
static int drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
 
154
{
 
155
        STREAM* data_out;
 
156
        int error;
 
157
 
 
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)
 
162
        {
 
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);
 
167
        }
 
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)
 
173
        {
 
174
                DEBUG_WARN("VirtualChannelWrite failed %d", error);
 
175
                return 1;
 
176
        }
 
177
        return 0;
 
178
}
 
179
 
 
180
static uint32 drdynvc_read_variable_uint(STREAM* stream, int cbLen)
274
181
{
275
182
        uint32 val;
276
183
 
277
184
        switch (cbLen)
278
185
        {
279
186
                case 0:
280
 
                        val = (uint32) GET_UINT8(data, *pos);
281
 
                        *pos += 1;
 
187
                        stream_read_uint8(stream, val);
282
188
                        break;
283
189
                case 1:
284
 
                        val = (uint32) GET_UINT16(data, *pos);
285
 
                        *pos += 2;
 
190
                        stream_read_uint16(stream, val);
286
191
                        break;
287
192
                default:
288
 
                        val = (uint32) GET_UINT32(data, *pos);
289
 
                        *pos += 4;
 
193
                        stream_read_uint32(stream, val);
290
194
                        break;
291
195
        }
292
196
        return val;
293
197
}
294
198
 
295
 
static int
296
 
process_CREATE_REQUEST_PDU(drdynvcPlugin * plugin, int Sp, int cbChId,
297
 
        char * data, int data_size)
 
199
static int drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
298
200
{
 
201
        STREAM* data_out;
299
202
        int pos;
300
203
        int error;
301
 
        int size;
302
 
        char * out_data;
303
204
        uint32 ChannelId;
304
205
 
305
 
        pos = 1;
306
 
        ChannelId = get_variable_uint(cbChId, data, &pos);
307
 
        LLOGLN(10, ("process_CREATE_REQUEST_PDU: ChannelId=%d ChannelName=%s", ChannelId, data + pos));
308
 
 
309
 
        size = pos + 4;
310
 
        out_data = (char *) malloc(size);
311
 
        SET_UINT8(out_data, 0, 0x10 | cbChId);
312
 
        memcpy(out_data + 1, data + 1, pos - 1);
 
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));
 
209
 
 
210
        error = dvcman_create_channel(drdynvc->channel_mgr, ChannelId, (char*)stream_get_tail(s));
 
211
 
 
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);
313
216
        
314
 
        error = dvcman_create_channel(plugin->channel_mgr, ChannelId, data + pos);
315
217
        if (error == 0)
316
218
        {
317
 
                LLOGLN(10, ("process_CREATE_REQUEST_PDU: channel created"));
318
 
                SET_UINT32(out_data, pos, 0);
 
219
                DEBUG_DVC("channel created");
 
220
                stream_write_uint32(data_out, 0);
319
221
        }
320
222
        else
321
223
        {
322
 
                LLOGLN(10, ("process_CREATE_REQUEST_PDU: no listener"));
323
 
                SET_UINT32(out_data, pos, (uint32)(-1));
 
224
                DEBUG_DVC("no listener");
 
225
                stream_write_uint32(data_out, (uint32)(-1));
324
226
        }
325
 
        hexdump(out_data, size);
326
 
        error = plugin->ep.pVirtualChannelWrite(plugin->open_handle,
327
 
        out_data, size, out_data);
 
227
 
 
228
        error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
328
229
        if (error != CHANNEL_RC_OK)
329
230
        {
330
 
                LLOGLN(0, ("process_CREATE_REQUEST_PDU: "
331
 
                        "VirtualChannelWrite "
332
 
                        "failed %d", error));
 
231
                DEBUG_WARN("VirtualChannelWrite failed %d", error);
333
232
                return 1;
334
233
        }
335
234
        return 0;
336
235
}
337
236
 
338
 
static int
339
 
process_DATA(drdynvcPlugin * plugin, uint32 ChannelId,
340
 
        char * data, int data_size)
341
 
{
342
 
        int error = 0;
343
 
 
344
 
        if (plugin->dvc_data)
345
 
        {
346
 
                /* Fragmented data */
347
 
                if (plugin->dvc_data_pos + (uint32) data_size > plugin->dvc_data_size)
348
 
                {
349
 
                        LLOGLN(0, ("process_DATA: data exceeding declared length!"));
350
 
                        free(plugin->dvc_data);
351
 
                        plugin->dvc_data = NULL;
352
 
                        return 1;
353
 
                }
354
 
                memcpy(plugin->dvc_data + plugin->dvc_data_pos, data, data_size);
355
 
                plugin->dvc_data_pos += (uint32) data_size;
356
 
                if (plugin->dvc_data_pos >= plugin->dvc_data_size)
357
 
                {
358
 
                        error = dvcman_receive_channel_data(plugin->channel_mgr,
359
 
                                ChannelId, plugin->dvc_data, plugin->dvc_data_size);
360
 
                        free(plugin->dvc_data);
361
 
                        plugin->dvc_data = NULL;
362
 
                }
363
 
        }
364
 
        else
365
 
        {
366
 
                error = dvcman_receive_channel_data(plugin->channel_mgr,
367
 
                        ChannelId, data, (uint32) data_size);
368
 
        }
369
 
        return error;
370
 
}
371
 
 
372
 
static int
373
 
process_DATA_FIRST_PDU(drdynvcPlugin * plugin, int Sp, int cbChId,
374
 
        char * data, int data_size)
375
 
{
376
 
        int pos;
 
237
static int drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
 
238
{
377
239
        uint32 ChannelId;
378
240
        uint32 Length;
379
 
 
380
 
        pos = 1;
381
 
        ChannelId = get_variable_uint(cbChId, data, &pos);
382
 
        Length = get_variable_uint(Sp, data, &pos);
383
 
        LLOGLN(10, ("process_DATA_FIRST_PDU: ChannelId=%d Length=%d", ChannelId, Length));
384
 
 
385
 
        if (plugin->dvc_data)
386
 
                free(plugin->dvc_data);
387
 
        plugin->dvc_data = (char *) malloc(Length);
388
 
        memset(plugin->dvc_data, 0, Length);
389
 
        plugin->dvc_data_pos = 0;
390
 
        plugin->dvc_data_size = Length;
391
 
 
392
 
        return process_DATA(plugin, ChannelId, data + pos, data_size - pos);
393
 
}
394
 
 
395
 
static int
396
 
process_DATA_PDU(drdynvcPlugin * plugin, int Sp, int cbChId,
397
 
        char * data, int data_size)
398
 
{
399
 
        int pos;
400
 
        uint32 ChannelId;
401
 
 
402
 
        pos = 1;
403
 
        ChannelId = get_variable_uint(cbChId, data, &pos);
404
 
        LLOGLN(10, ("process_DATA_PDU: ChannelId=%d", ChannelId));
405
 
 
406
 
        return process_DATA(plugin, ChannelId, data + pos, data_size - pos);
407
 
}
408
 
 
409
 
static int
410
 
process_CLOSE_REQUEST_PDU(drdynvcPlugin * plugin, int Sp, int cbChId,
411
 
        char * data, int data_size)
412
 
{
413
 
        int pos;
414
 
        uint32 ChannelId;
415
 
 
416
 
        pos = 1;
417
 
        ChannelId = get_variable_uint(cbChId, data, &pos);
418
 
        LLOGLN(10, ("process_CLOSE_REQUEST_PDU: ChannelId=%d", ChannelId));
419
 
        dvcman_close_channel(plugin->channel_mgr, ChannelId);
 
241
        int error;
 
242
 
 
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);
 
246
 
 
247
        error = dvcman_receive_channel_data_first(drdynvc->channel_mgr, ChannelId, Length);
 
248
        if (error)
 
249
                return error;
 
250
 
 
251
        return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
 
252
                stream_get_tail(s), stream_get_left(s));
 
253
}
 
254
 
 
255
static int drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
 
256
{
 
257
        uint32 ChannelId;
 
258
 
 
259
        ChannelId = drdynvc_read_variable_uint(s, cbChId);
 
260
        DEBUG_DVC("ChannelId=%d", ChannelId);
 
261
 
 
262
        return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
 
263
                stream_get_tail(s), stream_get_left(s));
 
264
}
 
265
 
 
266
static int drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, STREAM* s)
 
267
{
 
268
        uint32 ChannelId;
 
269
 
 
270
        ChannelId = drdynvc_read_variable_uint(s, cbChId);
 
271
        DEBUG_DVC("ChannelId=%d", ChannelId);
 
272
        dvcman_close_channel(drdynvc->channel_mgr, ChannelId);
420
273
 
421
274
        return 0;
422
275
}
423
276
 
424
 
static int
425
 
thread_process_message(drdynvcPlugin * plugin, char * data, int data_size)
 
277
static void drdynvc_process_receive(rdpSvcPlugin* plugin, STREAM* s)
426
278
{
 
279
        drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
427
280
        int value;
428
281
        int Cmd;
429
282
        int Sp;
430
283
        int cbChId;
431
 
        int rv;
432
284
 
433
 
        rv = 0;
434
 
        value = GET_UINT8(data, 0);
 
285
        stream_read_uint8(s, value);
435
286
        Cmd = (value & 0xf0) >> 4;
436
287
        Sp = (value & 0x0c) >> 2;
437
288
        cbChId = (value & 0x03) >> 0;
438
 
        LLOGLN(10, ("thread_process_message: data_size %d cmd 0x%x", data_size, Cmd));
439
 
        hexdump(data, data_size);
 
289
 
 
290
        DEBUG_DVC("Cmd=0x%x", Cmd);
 
291
 
440
292
        switch (Cmd)
441
293
        {
442
294
                case CAPABILITY_REQUEST_PDU:
443
 
                        rv = process_CAPABILITY_REQUEST_PDU(plugin, Sp, cbChId, data, data_size);
 
295
                        drdynvc_process_capability_request(drdynvc, Sp, cbChId, s);
444
296
                        break;
445
297
                case CREATE_REQUEST_PDU:
446
 
                        rv = process_CREATE_REQUEST_PDU(plugin, Sp, cbChId, data, data_size);
 
298
                        drdynvc_process_create_request(drdynvc, Sp, cbChId, s);
447
299
                        break;
448
300
                case DATA_FIRST_PDU:
449
 
                        rv = process_DATA_FIRST_PDU(plugin, Sp, cbChId, data, data_size);
 
301
                        drdynvc_process_data_first(drdynvc, Sp, cbChId, s);
450
302
                        break;
451
303
                case DATA_PDU:
452
 
                        rv = process_DATA_PDU(plugin, Sp, cbChId, data, data_size);
 
304
                        drdynvc_process_data(drdynvc, Sp, cbChId, s);
453
305
                        break;
454
306
                case CLOSE_REQUEST_PDU:
455
 
                        rv = process_CLOSE_REQUEST_PDU(plugin, Sp, cbChId, data, data_size);
 
307
                        drdynvc_process_close_request(drdynvc, Sp, cbChId, s);
456
308
                        break;
457
309
                default:
458
 
                        LLOGLN(0, ("thread_process_message: unknown drdynvc cmd 0x%x", Cmd));
459
 
                        break;
460
 
        }
461
 
        return rv;
462
 
}
463
 
 
464
 
/* process the linked list of data that has come in */
465
 
static int
466
 
thread_process_data_in(drdynvcPlugin * plugin)
467
 
{
468
 
        char * data;
469
 
        int data_size;
470
 
        struct data_in_item * item;
471
 
 
472
 
        while (1)
473
 
        {
474
 
                if (wait_obj_is_set(plugin->term_event))
475
 
                {
476
 
                        break;
477
 
                }
478
 
                pthread_mutex_lock(plugin->in_mutex);
479
 
                if (plugin->in_list_head == 0)
480
 
                {
481
 
                        pthread_mutex_unlock(plugin->in_mutex);
482
 
                        break;
483
 
                }
484
 
                data = plugin->in_list_head->data;
485
 
                data_size = plugin->in_list_head->data_size;
486
 
                item = plugin->in_list_head;
487
 
                plugin->in_list_head = plugin->in_list_head->next;
488
 
                if (plugin->in_list_head == 0)
489
 
                {
490
 
                        plugin->in_list_tail = 0;
491
 
                }
492
 
                pthread_mutex_unlock(plugin->in_mutex);
493
 
                if (data != 0)
494
 
                {
495
 
                        thread_process_message(plugin, data, data_size);
496
 
                        free(data);
497
 
                }
498
 
                if (item != 0)
499
 
                {
500
 
                        free(item);
501
 
                }
502
 
        }
503
 
        return 0;
504
 
}
505
 
 
506
 
static void *
507
 
thread_func(void * arg)
508
 
{
509
 
        drdynvcPlugin * plugin;
510
 
        struct wait_obj * listobj[2];
511
 
        int numobj;
512
 
        int timeout;
513
 
 
514
 
        plugin = (drdynvcPlugin *) arg;
515
 
 
516
 
        plugin->thread_status = 1;
517
 
        LLOGLN(10, ("thread_func: in"));
518
 
        while (1)
519
 
        {
520
 
                listobj[0] = plugin->term_event;
521
 
                listobj[1] = plugin->data_in_event;
522
 
                numobj = 2;
523
 
                timeout = -1;
524
 
                wait_obj_select(listobj, numobj, NULL, 0, timeout);
525
 
                if (wait_obj_is_set(plugin->term_event))
526
 
                {
527
 
                        break;
528
 
                }
529
 
                if (wait_obj_is_set(plugin->data_in_event))
530
 
                {
531
 
                        wait_obj_clear(plugin->data_in_event);
532
 
                        /* process data in */
533
 
                        thread_process_data_in(plugin);
534
 
                }
535
 
        }
536
 
        LLOGLN(10, ("thread_func: out"));
537
 
        plugin->thread_status = -1;
538
 
        return 0;
539
 
}
540
 
 
541
 
static void
542
 
OpenEventProcessReceived(uint32 openHandle, void * pData, uint32 dataLength,
543
 
        uint32 totalLength, uint32 dataFlags)
544
 
{
545
 
        drdynvcPlugin * plugin;
546
 
 
547
 
        plugin = (drdynvcPlugin *) chan_plugin_find_by_open_handle(openHandle);
548
 
 
549
 
        LLOGLN(10, ("OpenEventProcessReceived: receive openHandle %d dataLength %d "
550
 
                "totalLength %d dataFlags %d",
551
 
                openHandle, dataLength, totalLength, dataFlags));
552
 
        if (dataFlags & CHANNEL_FLAG_FIRST)
553
 
        {
554
 
                plugin->data_in_read = 0;
555
 
                if (plugin->data_in != 0)
556
 
                {
557
 
                        free(plugin->data_in);
558
 
                }
559
 
                plugin->data_in = (char *) malloc(totalLength);
560
 
                plugin->data_in_size = totalLength;
561
 
        }
562
 
        memcpy(plugin->data_in + plugin->data_in_read, pData, dataLength);
563
 
        plugin->data_in_read += dataLength;
564
 
        if (dataFlags & CHANNEL_FLAG_LAST)
565
 
        {
566
 
                if (plugin->data_in_read != plugin->data_in_size)
567
 
                {
568
 
                        LLOGLN(0, ("OpenEventProcessReceived: read error"));
569
 
                }
570
 
                signal_data_in(plugin);
571
 
        }
572
 
}
573
 
 
574
 
static void
575
 
OpenEvent(uint32 openHandle, uint32 event, void * pData, uint32 dataLength,
576
 
        uint32 totalLength, uint32 dataFlags)
577
 
{
578
 
        LLOGLN(10, ("OpenEvent: event %d", event));
579
 
        switch (event)
580
 
        {
581
 
                case CHANNEL_EVENT_DATA_RECEIVED:
582
 
                        OpenEventProcessReceived(openHandle, pData, dataLength,
583
 
                                totalLength, dataFlags);
584
 
                        break;
585
 
                case CHANNEL_EVENT_WRITE_COMPLETE:
586
 
                        free(pData);
587
 
                        break;
588
 
        }
589
 
}
590
 
 
591
 
static void
592
 
InitEventProcessConnected(void * pInitHandle, void * pData, uint32 dataLength)
593
 
{
594
 
        drdynvcPlugin * plugin;
595
 
        uint32 error;
596
 
        pthread_t thread;
597
 
 
598
 
        plugin = (drdynvcPlugin *) chan_plugin_find_by_init_handle(pInitHandle);
599
 
        if (plugin == NULL)
600
 
        {
601
 
                LLOGLN(0, ("InitEventProcessConnected: error no match"));
602
 
                return;
603
 
        }
604
 
 
605
 
        error = plugin->ep.pVirtualChannelOpen(pInitHandle, &(plugin->open_handle),
606
 
                plugin->channel_def.name, OpenEvent);
607
 
        if (error != CHANNEL_RC_OK)
608
 
        {
609
 
                LLOGLN(0, ("InitEventProcessConnected: Open failed"));
610
 
                return;
611
 
        }
612
 
        chan_plugin_register_open_handle((rdpChanPlugin *) plugin, plugin->open_handle);
613
 
 
614
 
        dvcman_initialize(plugin->channel_mgr);
615
 
 
616
 
        pthread_create(&thread, 0, thread_func, plugin);
617
 
        pthread_detach(thread);
618
 
}
619
 
 
620
 
static void
621
 
InitEventProcessTerminated(void * pInitHandle)
622
 
{
623
 
        drdynvcPlugin * plugin;
624
 
        int index;
625
 
        struct data_in_item * in_item;
626
 
 
627
 
        plugin = (drdynvcPlugin *) chan_plugin_find_by_init_handle(pInitHandle);
628
 
        if (plugin == NULL)
629
 
        {
630
 
                LLOGLN(0, ("InitEventProcessConnected: error no match"));
631
 
                return;
632
 
        }
633
 
 
634
 
        wait_obj_set(plugin->term_event);
635
 
        index = 0;
636
 
        while ((plugin->thread_status > 0) && (index < 100))
637
 
        {
638
 
                index++;
639
 
                usleep(250 * 1000);
640
 
        }
641
 
        wait_obj_free(plugin->term_event);
642
 
        wait_obj_free(plugin->data_in_event);
643
 
 
644
 
        pthread_mutex_destroy(plugin->in_mutex);
645
 
        free(plugin->in_mutex);
646
 
 
647
 
        /* free the un-processed in/out queue */
648
 
        while (plugin->in_list_head != 0)
649
 
        {
650
 
                in_item = plugin->in_list_head;
651
 
                plugin->in_list_head = in_item->next;
652
 
                free(in_item->data);
653
 
                free(in_item);
654
 
        }
655
 
 
656
 
        dvcman_free(plugin->channel_mgr);
657
 
        if (plugin->dvc_data)
658
 
        {
659
 
                free(plugin->dvc_data);
660
 
                plugin->dvc_data = NULL;
661
 
        }
662
 
 
663
 
        chan_plugin_uninit((rdpChanPlugin *) plugin);
664
 
        free(plugin);
665
 
}
666
 
 
667
 
static void
668
 
InitEvent(void * pInitHandle, uint32 event, void * pData, uint32 dataLength)
669
 
{
670
 
        LLOGLN(10, ("InitEvent: event %d", event));
671
 
        switch (event)
672
 
        {
673
 
                case CHANNEL_EVENT_CONNECTED:
674
 
                        InitEventProcessConnected(pInitHandle, pData, dataLength);
675
 
                        break;
676
 
                case CHANNEL_EVENT_DISCONNECTED:
677
 
                        break;
678
 
                case CHANNEL_EVENT_TERMINATED:
679
 
                        InitEventProcessTerminated(pInitHandle);
680
 
                        break;
681
 
        }
682
 
}
683
 
 
684
 
int
685
 
VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
686
 
{
687
 
        drdynvcPlugin * plugin;
688
 
        RD_PLUGIN_DATA * data;
689
 
 
690
 
        LLOGLN(10, ("VirtualChannelEntry:"));
691
 
 
692
 
        plugin = (drdynvcPlugin *) malloc(sizeof(drdynvcPlugin));
693
 
        memset(plugin, 0, sizeof(drdynvcPlugin));
694
 
 
695
 
        chan_plugin_init((rdpChanPlugin *) plugin);
696
 
 
697
 
        plugin->data_in_size = 0;
698
 
        plugin->data_in = 0;
699
 
        plugin->ep = *pEntryPoints;
700
 
        memset(&(plugin->channel_def), 0, sizeof(plugin->channel_def));
701
 
        plugin->channel_def.options = CHANNEL_OPTION_INITIALIZED |
702
 
                CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
703
 
        strcpy(plugin->channel_def.name, "drdynvc");
704
 
        plugin->in_mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
705
 
        pthread_mutex_init(plugin->in_mutex, 0);
706
 
        plugin->in_list_head = 0;
707
 
        plugin->in_list_tail = 0;
708
 
        plugin->term_event = wait_obj_new("freerdprdrynvcterm");
709
 
        plugin->data_in_event = wait_obj_new("freerdpdrdynvcdatain");
710
 
        plugin->thread_status = 0;
711
 
        plugin->ep.pVirtualChannelInit(&plugin->chan_plugin.init_handle, &plugin->channel_def, 1,
712
 
                VIRTUAL_CHANNEL_VERSION_WIN2000, InitEvent);
713
 
 
714
 
        plugin->channel_mgr = dvcman_new(plugin);
715
 
 
716
 
        if (pEntryPoints->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_EX))
717
 
        {
718
 
                data = (RD_PLUGIN_DATA *) (((PCHANNEL_ENTRY_POINTS_EX)pEntryPoints)->pExtendedData);
719
 
                while (data && data->size > 0)
720
 
                {
721
 
                        dvcman_load_plugin(plugin->channel_mgr, (char*)data->data[0]);
722
 
                        data = (RD_PLUGIN_DATA *) (((void *) data) + data->size);
723
 
                }
724
 
        }
725
 
 
726
 
        return 1;
727
 
}
 
310
                        DEBUG_WARN("unknown drdynvc cmd 0x%x", Cmd);
 
311
                        break;
 
312
        }
 
313
 
 
314
        stream_free(s);
 
315
}
 
316
 
 
317
static void drdynvc_process_connect(rdpSvcPlugin* plugin)
 
318
{
 
319
        drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
 
320
 
 
321
        DEBUG_DVC("connecting");
 
322
 
 
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);
 
326
}
 
327
 
 
328
static void drdynvc_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
 
329
{
 
330
        freerdp_event_free(event);
 
331
}
 
332
 
 
333
static void drdynvc_process_terminate(rdpSvcPlugin* plugin)
 
334
{
 
335
        drdynvcPlugin* drdynvc = (drdynvcPlugin*)plugin;
 
336
 
 
337
        DEBUG_DVC("terminating");
 
338
 
 
339
        if (drdynvc->channel_mgr != NULL)
 
340
                dvcman_free(drdynvc->channel_mgr);
 
341
        xfree(drdynvc);
 
342
}
 
343
 
 
344
DEFINE_SVC_PLUGIN(drdynvc, "drdynvc",
 
345
        CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
 
346
        CHANNEL_OPTION_COMPRESS_RDP)