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
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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
32 /* FIXME: We should use the information in TAG_SRV_CHANNELS to map RDP5
33 channels to MCS channels.
35 The format of TAG_SRV_CHANNELS seems to be
37 global_channel_no (uint16le)
38 number_of_other_channels (uint16le)
39 ..followed by uint16les for the other channels.
43 channel_register(RDPCLIENT
* This
, char *name
, uint32 flags
, void (*callback
) (RDPCLIENT
*, STREAM
))
50 if (This
->num_channels
>= MAX_CHANNELS
)
52 error("Channel table full, increase MAX_CHANNELS\n");
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
;
66 channel_init(RDPCLIENT
* This
, VCHANNEL
* channel
, uint32 length
)
70 s
= sec_init(This
, This
->encryption
? SEC_ENCRYPT
: 0, length
+ 8);
71 s_push_layer(s
, channel_hdr
, 8);
76 channel_send(RDPCLIENT
* This
, STREAM s
, VCHANNEL
* channel
)
79 uint32 thislength
, remaining
;
82 /* first fragment sent in-place */
83 s_pop_layer(s
, channel_hdr
);
84 length
= s
->end
- s
->p
- sizeof(CHANNEL_PDU_HEADER
);
86 DEBUG_CHANNEL(("channel_send, length = %d\n", length
));
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
;
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
);
104 /* subsequent segments copied (otherwise would have to generate headers backwards) */
105 while (remaining
> 0)
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
;
113 DEBUG_CHANNEL(("Sending %d bytes with flags %d\n", thislength
, flags
));
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
);
120 sec_send_to_channel(This
, s
, This
->encryption
? SEC_ENCRYPT
: 0, channel
->mcs_id
);
127 channel_process(RDPCLIENT
* This
, STREAM s
, uint16 mcs_channel
)
129 uint32 length
, flags
;
131 VCHANNEL
*channel
= NULL
;
135 for (i
= 0; i
< This
->num_channels
; i
++)
137 channel
= &This
->channels
[i
];
138 if (channel
->mcs_id
== mcs_channel
)
142 if (i
>= This
->num_channels
)
145 in_uint32_le(s
, length
);
146 in_uint32_le(s
, flags
);
147 if ((flags
& CHANNEL_FLAG_FIRST
) && (flags
& CHANNEL_FLAG_LAST
))
149 /* single fragment - pass straight up */
150 channel
->process(This
, s
);
154 /* add fragment to defragmentation buffer */
156 if (flags
& CHANNEL_FLAG_FIRST
)
158 if (length
> in
->size
)
160 in
->data
= (uint8
*) xrealloc(in
->data
, length
);
166 thislength
= MIN(s
->end
- s
->p
, in
->data
+ in
->size
- in
->p
);
167 memcpy(in
->p
, s
->p
, thislength
);
170 if (flags
& CHANNEL_FLAG_LAST
)
174 channel
->process(This
, in
);