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