1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - Virtual channels
4 Copyright (C) Erik Forsberg <forsberg@cendio.se> 2003
5 Copyright (C) Matthew Chapman 2003-2005
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include "rdesktop.h"
23
24 // FIXME: header mess
25 #if 0
26 #define CHANNEL_CHUNK_LENGTH 1600
27 #define CHANNEL_FLAG_FIRST 0x01
28 #define CHANNEL_FLAG_LAST 0x02
29 #define CHANNEL_FLAG_SHOW_PROTOCOL 0x10
30 #endif
31
32 /* FIXME: We should use the information in TAG_SRV_CHANNELS to map RDP5
33 channels to MCS channels.
34
35 The format of TAG_SRV_CHANNELS seems to be
36
37 global_channel_no (uint16le)
38 number_of_other_channels (uint16le)
39 ..followed by uint16les for the other channels.
40 */
41
42 VCHANNEL *
channel_register(RDPCLIENT * This,char * name,uint32 flags,void (* callback)(RDPCLIENT *,STREAM))43 channel_register(RDPCLIENT * This, char *name, uint32 flags, void (*callback) (RDPCLIENT *, STREAM))
44 {
45 VCHANNEL *channel;
46
47 if (!This->use_rdp5)
48 return NULL;
49
50 if (This->num_channels >= MAX_CHANNELS)
51 {
52 error("Channel table full, increase MAX_CHANNELS\n");
53 return NULL;
54 }
55
56 channel = &This->channels[This->num_channels];
57 channel->mcs_id = MCS_GLOBAL_CHANNEL + 1 + This->num_channels;
58 strncpy(channel->name, name, 8);
59 channel->flags = flags;
60 channel->process = callback;
61 This->num_channels++;
62 return channel;
63 }
64
65 STREAM
channel_init(RDPCLIENT * This,VCHANNEL * channel,uint32 length)66 channel_init(RDPCLIENT * This, VCHANNEL * channel, uint32 length)
67 {
68 STREAM s;
69
70 s = sec_init(This, This->encryption ? SEC_ENCRYPT : 0, length + 8);
71 s_push_layer(s, channel_hdr, 8);
72 return s;
73 }
74
75 void
channel_send(RDPCLIENT * This,STREAM s,VCHANNEL * channel)76 channel_send(RDPCLIENT * This, STREAM s, VCHANNEL * channel)
77 {
78 uint32 length, flags;
79 uint32 thislength, remaining;
80 uint8 *data;
81
82 /* first fragment sent in-place */
83 s_pop_layer(s, channel_hdr);
84 length = s->end - s->p - sizeof(CHANNEL_PDU_HEADER);
85
86 DEBUG_CHANNEL(("channel_send, length = %d\n", length));
87
88 thislength = MIN(length, CHANNEL_CHUNK_LENGTH);
89 /* Note: In the original clipboard implementation, this number was
90 1592, not 1600. However, I don't remember the reason and 1600 seems
91 to work so.. This applies only to *this* length, not the length of
92 continuation or ending packets. */
93 remaining = length - thislength;
94 flags = (remaining == 0) ? CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST : CHANNEL_FLAG_FIRST;
95 if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
96 flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
97
98 out_uint32_le(s, length);
99 out_uint32_le(s, flags);
100 data = s->end = s->p + thislength;
101 DEBUG_CHANNEL(("Sending %d bytes with FLAG_FIRST\n", thislength));
102 sec_send_to_channel(This, s, This->encryption ? SEC_ENCRYPT : 0, channel->mcs_id);
103
104 /* subsequent segments copied (otherwise would have to generate headers backwards) */
105 while (remaining > 0)
106 {
107 thislength = MIN(remaining, CHANNEL_CHUNK_LENGTH);
108 remaining -= thislength;
109 flags = (remaining == 0) ? CHANNEL_FLAG_LAST : 0;
110 if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
111 flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
112
113 DEBUG_CHANNEL(("Sending %d bytes with flags %d\n", thislength, flags));
114
115 s = sec_init(This, This->encryption ? SEC_ENCRYPT : 0, thislength + 8);
116 out_uint32_le(s, length);
117 out_uint32_le(s, flags);
118 out_uint8p(s, data, thislength);
119 s_mark_end(s);
120 sec_send_to_channel(This, s, This->encryption ? SEC_ENCRYPT : 0, channel->mcs_id);
121
122 data += thislength;
123 }
124 }
125
126 void
channel_process(RDPCLIENT * This,STREAM s,uint16 mcs_channel)127 channel_process(RDPCLIENT * This, STREAM s, uint16 mcs_channel)
128 {
129 uint32 length, flags;
130 uint32 thislength;
131 VCHANNEL *channel = NULL;
132 unsigned int i;
133 STREAM in;
134
135 for (i = 0; i < This->num_channels; i++)
136 {
137 channel = &This->channels[i];
138 if (channel->mcs_id == mcs_channel)
139 break;
140 }
141
142 if (i >= This->num_channels)
143 return;
144
145 in_uint32_le(s, length);
146 in_uint32_le(s, flags);
147 if ((flags & CHANNEL_FLAG_FIRST) && (flags & CHANNEL_FLAG_LAST))
148 {
149 /* single fragment - pass straight up */
150 channel->process(This, s);
151 }
152 else
153 {
154 /* add fragment to defragmentation buffer */
155 in = &channel->in;
156 if (flags & CHANNEL_FLAG_FIRST)
157 {
158 if (length > in->size)
159 {
160 in->data = (uint8 *) xrealloc(in->data, length);
161 in->size = length;
162 }
163 in->p = in->data;
164 }
165
166 thislength = MIN(s->end - s->p, in->data + in->size - in->p);
167 memcpy(in->p, s->p, thislength);
168 in->p += thislength;
169
170 if (flags & CHANNEL_FLAG_LAST)
171 {
172 in->end = in->p;
173 in->p = in->data;
174 channel->process(This, in);
175 }
176 }
177 }
178