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
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.
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.
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.
24 #define MAX_CHANNELS 6
25 #define CHANNEL_CHUNK_LENGTH 1600
26 #define CHANNEL_FLAG_FIRST 0x01
27 #define CHANNEL_FLAG_LAST 0x02
28 #define CHANNEL_FLAG_SHOW_PROTOCOL 0x10
30 extern BOOL g_use_rdp5
;
31 extern BOOL g_encryption
;
33 VCHANNEL g_channels
[MAX_CHANNELS
];
34 unsigned int g_num_channels
;
36 /* FIXME: We should use the information in TAG_SRV_CHANNELS to map RDP5
37 channels to MCS channels.
39 The format of TAG_SRV_CHANNELS seems to be
41 global_channel_no (uint16le)
42 number_of_other_channels (uint16le)
43 ..followed by uint16les for the other channels.
47 channel_register(char *name
, uint32 flags
, void (*callback
) (STREAM
))
54 if (g_num_channels
>= MAX_CHANNELS
)
56 error("Channel table full, increase MAX_CHANNELS\n");
60 channel
= &g_channels
[g_num_channels
];
61 channel
->mcs_id
= MCS_GLOBAL_CHANNEL
+ 1 + g_num_channels
;
62 strncpy(channel
->name
, name
, 8);
63 channel
->flags
= flags
;
64 channel
->process
= callback
;
70 channel_init(VCHANNEL
* channel
, uint32 length
)
74 s
= sec_init(g_encryption
? SEC_ENCRYPT
: 0, length
+ 8);
75 s_push_layer(s
, channel_hdr
, 8);
80 channel_send(STREAM s
, VCHANNEL
* channel
)
83 uint32 thislength
, remaining
;
86 /* first fragment sent in-place */
87 s_pop_layer(s
, channel_hdr
);
88 length
= s
->end
- s
->p
- 8;
90 DEBUG_CHANNEL(("channel_send, length = %d\n", length
));
92 thislength
= MIN(length
, CHANNEL_CHUNK_LENGTH
);
93 /* Note: In the original clipboard implementation, this number was
94 1592, not 1600. However, I don't remember the reason and 1600 seems
95 to work so.. This applies only to *this* length, not the length of
96 continuation or ending packets. */
97 remaining
= length
- thislength
;
98 flags
= (remaining
== 0) ? CHANNEL_FLAG_FIRST
| CHANNEL_FLAG_LAST
: CHANNEL_FLAG_FIRST
;
99 if (channel
->flags
& CHANNEL_OPTION_SHOW_PROTOCOL
)
100 flags
|= CHANNEL_FLAG_SHOW_PROTOCOL
;
102 out_uint32_le(s
, length
);
103 out_uint32_le(s
, flags
);
104 data
= s
->end
= s
->p
+ thislength
;
105 DEBUG_CHANNEL(("Sending %d bytes with FLAG_FIRST\n", thislength
));
106 sec_send_to_channel(s
, g_encryption
? SEC_ENCRYPT
: 0, channel
->mcs_id
);
108 /* subsequent segments copied (otherwise would have to generate headers backwards) */
109 while (remaining
> 0)
111 thislength
= MIN(remaining
, CHANNEL_CHUNK_LENGTH
);
112 remaining
-= thislength
;
113 flags
= (remaining
== 0) ? CHANNEL_FLAG_LAST
: 0;
114 if (channel
->flags
& CHANNEL_OPTION_SHOW_PROTOCOL
)
115 flags
|= CHANNEL_FLAG_SHOW_PROTOCOL
;
117 DEBUG_CHANNEL(("Sending %d bytes with flags %d\n", thislength
, flags
));
119 s
= sec_init(g_encryption
? SEC_ENCRYPT
: 0, thislength
+ 8);
120 out_uint32_le(s
, length
);
121 out_uint32_le(s
, flags
);
122 out_uint8p(s
, data
, thislength
);
124 sec_send_to_channel(s
, g_encryption
? SEC_ENCRYPT
: 0, channel
->mcs_id
);
131 channel_process(STREAM s
, uint16 mcs_channel
)
133 uint32 length
, flags
;
135 VCHANNEL
*channel
= NULL
;
139 for (i
= 0; i
< g_num_channels
; i
++)
141 channel
= &g_channels
[i
];
142 if (channel
->mcs_id
== mcs_channel
)
146 if (i
>= g_num_channels
)
149 in_uint32_le(s
, length
);
150 in_uint32_le(s
, flags
);
151 if ((flags
& CHANNEL_FLAG_FIRST
) && (flags
& CHANNEL_FLAG_LAST
))
153 /* single fragment - pass straight up */
158 /* add fragment to defragmentation buffer */
160 if (flags
& CHANNEL_FLAG_FIRST
)
162 if (length
> in
->size
)
164 in
->data
= (uint8
*) xrealloc(in
->data
, length
);
170 thislength
= MIN(s
->end
- s
->p
, in
->data
+ in
->size
- in
->p
);
171 memcpy(in
->p
, s
->p
, thislength
);
174 if (flags
& CHANNEL_FLAG_LAST
)
178 channel
->process(in
);