Backport of pre-connect Hyper-V code
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-core / transport.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * Network Transport Layer
4  *
5  * Copyright 2011 Vic Lee
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include "config.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <freerdp/utils/sleep.h>
25 #include <freerdp/utils/stream.h>
26 #include <freerdp/utils/memory.h>
27 #include <freerdp/utils/hexdump.h>
28
29 #include <time.h>
30 #include <errno.h>
31 #include <fcntl.h>
32
33 #ifndef _WIN32
34 #include <netdb.h>
35 #include <sys/socket.h>
36 #endif
37
38 #include "tpkt.h"
39 #include "fastpath.h"
40 #include "credssp.h"
41 #include "transport.h"
42
43 #define BUFFER_SIZE 16384
44
45 STREAM* transport_recv_stream_init(rdpTransport* transport, int size)
46 {
47         STREAM* s = transport->recv_stream;
48         stream_check_size(s, size);
49         stream_set_pos(s, 0);
50         return s;
51 }
52
53 STREAM* transport_send_stream_init(rdpTransport* transport, int size)
54 {
55         STREAM* s = transport->send_stream;
56         stream_check_size(s, size);
57         stream_set_pos(s, 0);
58         return s;
59 }
60
61 boolean transport_connect(rdpTransport* transport, const char* hostname, uint16 port)
62 {
63         return tcp_connect(transport->tcp, hostname, port);
64 }
65
66 void transport_attach(rdpTransport* transport, int sockfd)
67 {
68         transport->tcp->sockfd = sockfd;
69 }
70
71 boolean transport_disconnect(rdpTransport* transport)
72 {
73         if (transport->layer == TRANSPORT_LAYER_TLS)
74                 tls_disconnect(transport->tls);
75         return tcp_disconnect(transport->tcp);
76 }
77
78 boolean transport_connect_rdp(rdpTransport* transport)
79 {
80         /* RDP encryption */
81
82         return true;
83 }
84
85 boolean transport_connect_tls(rdpTransport* transport)
86 {
87         if (transport->tls == NULL)
88                 transport->tls = tls_new(transport->settings);
89
90         transport->layer = TRANSPORT_LAYER_TLS;
91         transport->tls->sockfd = transport->tcp->sockfd;
92
93         if (tls_connect(transport->tls) != true)
94                 return false;
95
96         return true;
97 }
98
99 boolean transport_connect_nla(rdpTransport* transport)
100 {
101         if (transport->tls == NULL)
102                 transport->tls = tls_new(transport->settings);
103
104         transport->layer = TRANSPORT_LAYER_TLS;
105         transport->tls->sockfd = transport->tcp->sockfd;
106
107         if (tls_connect(transport->tls) != true)
108                 return false;
109
110         /* Network Level Authentication */
111
112         if (transport->settings->authentication != true)
113                 return true;
114
115         if (transport->credssp == NULL)
116                 transport->credssp = credssp_new(transport);
117
118         if (credssp_authenticate(transport->credssp) < 0)
119         {
120                 printf("Authentication failure, check credentials.\n"
121                         "If credentials are valid, the NTLMSSP implementation may be to blame.\n");
122
123                 credssp_free(transport->credssp);
124                 return false;
125         }
126
127         credssp_free(transport->credssp);
128
129         return true;
130 }
131
132 boolean transport_accept_rdp(rdpTransport* transport)
133 {
134         /* RDP encryption */
135
136         return true;
137 }
138
139 boolean transport_accept_tls(rdpTransport* transport)
140 {
141         if (transport->tls == NULL)
142                 transport->tls = tls_new(transport->settings);
143
144         transport->layer = TRANSPORT_LAYER_TLS;
145         transport->tls->sockfd = transport->tcp->sockfd;
146
147         if (tls_accept(transport->tls, transport->settings->cert_file, transport->settings->privatekey_file) != true)
148                 return false;
149
150         return true;
151 }
152
153 boolean transport_accept_nla(rdpTransport* transport)
154 {
155         if (transport->tls == NULL)
156                 transport->tls = tls_new(transport->settings);
157
158         transport->layer = TRANSPORT_LAYER_TLS;
159         transport->tls->sockfd = transport->tcp->sockfd;
160
161         if (tls_accept(transport->tls, transport->settings->cert_file, transport->settings->privatekey_file) != true)
162                 return false;
163
164         /* Network Level Authentication */
165
166         if (transport->settings->authentication != true)
167                 return true;
168
169         /* Blocking here until NLA is complete */
170
171         return true;
172 }
173
174 int transport_read(rdpTransport* transport, STREAM* s)
175 {
176         int status = -1;
177
178         while (true)
179         {
180                 if (transport->layer == TRANSPORT_LAYER_TLS)
181                         status = tls_read(transport->tls, stream_get_tail(s), stream_get_left(s));
182                 else if (transport->layer == TRANSPORT_LAYER_TCP)
183                         status = tcp_read(transport->tcp, stream_get_tail(s), stream_get_left(s));
184
185                 if (status == 0 && transport->blocking)
186                 {
187                         freerdp_usleep(transport->usleep_interval);
188                         continue;
189                 }
190
191                 break;
192         }
193
194 #ifdef WITH_DEBUG_TRANSPORT
195         if (status > 0)
196         {
197                 printf("Local < Remote\n");
198                 freerdp_hexdump(s->data, status);
199         }
200 #endif
201
202         return status;
203 }
204
205 static int transport_read_nonblocking(rdpTransport* transport)
206 {
207         int status;
208
209         stream_check_size(transport->recv_buffer, 4096);
210         status = transport_read(transport, transport->recv_buffer);
211
212         if (status <= 0)
213                 return status;
214
215         stream_seek(transport->recv_buffer, status);
216
217         return status;
218 }
219
220 int transport_write(rdpTransport* transport, STREAM* s)
221 {
222         int status = -1;
223         int length;
224
225         length = stream_get_length(s);
226         stream_set_pos(s, 0);
227
228 #ifdef WITH_DEBUG_TRANSPORT
229         if (length > 0)
230         {
231                 printf("Local > Remote\n");
232                 freerdp_hexdump(s->data, length);
233         }
234 #endif
235
236         while (length > 0)
237         {
238                 if (transport->layer == TRANSPORT_LAYER_TLS)
239                         status = tls_write(transport->tls, stream_get_tail(s), length);
240                 else if (transport->layer == TRANSPORT_LAYER_TCP)
241                         status = tcp_write(transport->tcp, stream_get_tail(s), length);
242
243                 if (status < 0)
244                         break; /* error occurred */
245
246                 if (status == 0)
247                 {
248                         /* blocking while sending */
249                         freerdp_usleep(transport->usleep_interval);
250
251                         /* when sending is blocked in nonblocking mode, the receiving buffer should be checked */
252                         if (!transport->blocking)
253                         {
254                                 /* and in case we do have buffered some data, we set the event so next loop will get it */
255                                 if (transport_read_nonblocking(transport) > 0)
256                                         wait_obj_set(transport->recv_event);
257                         }
258                 }
259
260                 length -= status;
261                 stream_seek(s, status);
262         }
263
264         if (status < 0)
265         {
266                 /* A write error indicates that the peer has dropped the connection */
267                 transport->layer = TRANSPORT_LAYER_CLOSED;
268         }
269
270         return status;
271 }
272
273 void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount)
274 {
275         rfds[*rcount] = (void*)(long)(transport->tcp->sockfd);
276         (*rcount)++;
277         wait_obj_get_fds(transport->recv_event, rfds, rcount);
278 }
279
280 int transport_check_fds(rdpTransport* transport)
281 {
282         int pos;
283         int status;
284         uint16 length;
285         STREAM* received;
286
287         wait_obj_clear(transport->recv_event);
288
289         status = transport_read_nonblocking(transport);
290
291         if (status < 0)
292                 return status;
293
294         while ((pos = stream_get_pos(transport->recv_buffer)) > 0)
295         {
296                 stream_set_pos(transport->recv_buffer, 0);
297                 if (tpkt_verify_header(transport->recv_buffer)) /* TPKT */
298                 {
299                         /* Ensure the TPKT header is available. */
300                         if (pos <= 4)
301                         {
302                                 stream_set_pos(transport->recv_buffer, pos);
303                                 return 0;
304                         }
305                         length = tpkt_read_header(transport->recv_buffer);
306                 }
307                 else /* Fast Path */
308                 {
309                         /* Ensure the Fast Path header is available. */
310                         if (pos <= 2)
311                         {
312                                 stream_set_pos(transport->recv_buffer, pos);
313                                 return 0;
314                         }
315                         /* Fastpath header can be two or three bytes long. */
316                         length = fastpath_header_length(transport->recv_buffer);
317                         if (pos < length)
318                         {
319                                 stream_set_pos(transport->recv_buffer, pos);
320                                 return 0;
321                         }
322                         length = fastpath_read_header(NULL, transport->recv_buffer);
323                 }
324
325                 if (length == 0)
326                 {
327                         printf("transport_check_fds: protocol error, not a TPKT or Fast Path header.\n");
328                         freerdp_hexdump(stream_get_head(transport->recv_buffer), pos);
329                         return -1;
330                 }
331
332                 if (pos < length)
333                 {
334                         stream_set_pos(transport->recv_buffer, pos);
335                         return 0; /* Packet is not yet completely received. */
336                 }
337
338                 /*
339                  * A complete packet has been received. In case there are trailing data
340                  * for the next packet, we copy it to the new receive buffer.
341                  */
342                 received = transport->recv_buffer;
343                 transport->recv_buffer = stream_new(BUFFER_SIZE);
344
345                 if (pos > length)
346                 {
347                         stream_set_pos(received, length);
348                         stream_check_size(transport->recv_buffer, pos - length);
349                         stream_copy(transport->recv_buffer, received, pos - length);
350                 }
351
352                 stream_set_pos(received, length);
353                 stream_seal(received);
354                 stream_set_pos(received, 0);
355                 
356                 if (transport->recv_callback(transport, received, transport->recv_extra) == false)
357                         status = -1;
358         
359                 stream_free(received);
360
361                 if (status < 0)
362                         return status;
363         }
364
365         return 0;
366 }
367
368 boolean transport_set_blocking_mode(rdpTransport* transport, boolean blocking)
369 {
370         transport->blocking = blocking;
371         return tcp_set_blocking_mode(transport->tcp, blocking);
372 }
373
374 rdpTransport* transport_new(rdpSettings* settings)
375 {
376         rdpTransport* transport;
377
378         transport = (rdpTransport*) xzalloc(sizeof(rdpTransport));
379
380         if (transport != NULL)
381         {
382                 transport->tcp = tcp_new(settings);
383                 transport->settings = settings;
384
385                 /* a small 0.1ms delay when transport is blocking. */
386                 transport->usleep_interval = 100;
387
388                 /* receive buffer for non-blocking read. */
389                 transport->recv_buffer = stream_new(BUFFER_SIZE);
390                 transport->recv_event = wait_obj_new();
391
392                 /* buffers for blocking read/write */
393                 transport->recv_stream = stream_new(BUFFER_SIZE);
394                 transport->send_stream = stream_new(BUFFER_SIZE);
395
396                 transport->blocking = true;
397
398                 transport->layer = TRANSPORT_LAYER_TCP;
399         }
400
401         return transport;
402 }
403
404 void transport_free(rdpTransport* transport)
405 {
406         if (transport != NULL)
407         {
408                 stream_free(transport->recv_buffer);
409                 stream_free(transport->recv_stream);
410                 stream_free(transport->send_stream);
411                 wait_obj_free(transport->recv_event);
412                 if (transport->tls)
413                         tls_free(transport->tls);
414                 tcp_free(transport->tcp);
415                 xfree(transport);
416         }
417 }