First implementation of MCS_CONNECT_RESPONSE (send error for now)
[rdpsrv] / channels.c
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
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
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "rdesktop.h"
23
24 #define MAX_CHANNELS                    4
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
29
30 extern BOOL g_use_rdp5;
31 extern BOOL g_encryption;
32
33 VCHANNEL g_channels[MAX_CHANNELS];
34 unsigned int g_num_channels;
35
36 /* FIXME: We should use the information in TAG_SRV_CHANNELS to map RDP5
37    channels to MCS channels.
38
39    The format of TAG_SRV_CHANNELS seems to be
40
41    global_channel_no (uint16le)
42    number_of_other_channels (uint16le)
43    ..followed by uint16les for the other channels.
44 */
45
46 VCHANNEL *
47 channel_register(char *name, uint32 flags, void (*callback) (STREAM))
48 {
49         VCHANNEL *channel;
50
51         if (g_num_channels >= MAX_CHANNELS)
52         {
53                 error("Channel table full, increase MAX_CHANNELS\n");
54                 return NULL;
55         }
56
57         channel = &g_channels[g_num_channels];
58         channel->mcs_id = MCS_GLOBAL_CHANNEL + 1 + g_num_channels;
59         strncpy(channel->name, name, 8);
60         channel->flags = flags;
61         channel->process = callback;
62         g_num_channels++;
63         return channel;
64 }
65
66 STREAM
67 channel_init(VCHANNEL * channel, uint32 length)
68 {
69         STREAM s;
70
71         s = sec_init(/*g_encryption ? SEC_ENCRYPT :*/ 0, length + 8);
72         s_push_layer(s, channel_hdr, 8);
73         return s;
74 }
75
76 void
77 channel_send(STREAM s, VCHANNEL * channel)
78 {
79         uint32 length, flags;
80         uint32 thislength, remaining;
81         uint8 *data;
82
83         /* first fragment sent in-place */
84         s_pop_layer(s, channel_hdr);
85         length = s->end - s->p - 8;
86
87         DEBUG_CLIPBOARD(("channel_send, length = %d\n", length));
88
89         thislength = MIN(length, CHANNEL_CHUNK_LENGTH);
90 /* Note: In the original clipboard implementation, this number was
91    1592, not 1600. However, I don't remember the reason and 1600 seems
92    to work so.. This applies only to *this* length, not the length of
93    continuation or ending packets. */
94         remaining = length - thislength;
95         flags = (remaining == 0) ? CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST : CHANNEL_FLAG_FIRST;
96         if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
97                 flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
98
99         out_uint32_le(s, length);
100         out_uint32_le(s, flags);
101         data = s->end = s->p + thislength;
102         DEBUG_CLIPBOARD(("Sending %d bytes with FLAG_FIRST\n", thislength));
103         sec_send_to_channel(s, /*g_encryption ? SEC_ENCRYPT :*/ 0, channel->mcs_id);
104
105         /* subsequent segments copied (otherwise would have to generate headers backwards) */
106         while (remaining > 0)
107         {
108                 thislength = MIN(remaining, CHANNEL_CHUNK_LENGTH);
109                 remaining -= thislength;
110                 flags = (remaining == 0) ? CHANNEL_FLAG_LAST : 0;
111                 if (channel->flags & CHANNEL_OPTION_SHOW_PROTOCOL)
112                         flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
113
114                 DEBUG_CLIPBOARD(("Sending %d bytes with flags %d\n", thislength, flags));
115
116                 s = sec_init(/*g_encryption ? SEC_ENCRYPT : */0, thislength + 8);
117                 out_uint32_le(s, length);
118                 out_uint32_le(s, flags);
119                 out_uint8p(s, data, thislength);
120                 s_mark_end(s);
121                 sec_send_to_channel(s, /*g_encryption ? SEC_ENCRYPT : */0, channel->mcs_id);
122
123                 data += thislength;
124         }
125 }
126
127 void
128 channel_process(STREAM s, uint16 mcs_channel)
129 {
130         uint32 length, flags;
131         uint32 thislength;
132         VCHANNEL *channel = NULL;
133         unsigned int i;
134         STREAM in;
135
136         for (i = 0; i < g_num_channels; i++)
137         {
138                 channel = &g_channels[i];
139                 if (channel->mcs_id == mcs_channel)
140                         break;
141         }
142
143         if (i >= g_num_channels)
144                 return;
145
146         in_uint32_le(s, length);
147         in_uint32_le(s, flags);
148         if ((flags & CHANNEL_FLAG_FIRST) && (flags & CHANNEL_FLAG_LAST))
149         {
150                 /* single fragment - pass straight up */
151                 channel->process(s);
152         }
153         else
154         {
155                 /* add fragment to defragmentation buffer */
156                 in = &channel->in;
157                 if (flags & CHANNEL_FLAG_FIRST)
158                 {
159                         if (length > in->size)
160                         {
161                                 in->data = xrealloc(in->data, length);
162                                 in->size = length;
163                         }
164                         in->p = in->data;
165                 }
166
167                 thislength = MIN(s->end - s->p, in->data + in->size - in->p);
168                 memcpy(in->p, s->p, thislength);
169                 in->p += thislength;
170
171                 if (flags & CHANNEL_FLAG_LAST)
172                 {
173                         in->end = in->p;
174                         in->p = in->data;
175                         channel->process(in);
176                 }
177         }
178 }