1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Protocol services - TCP layer
4    Copyright (C) Matthew Chapman 1999-2005
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20 
21 #if 0 // FIXME: header mess
22 #include <unistd.h>		/* select read write close */
23 #include <sys/socket.h>		/* socket connect setsockopt */
24 #include <sys/time.h>		/* timeval */
25 #include <netdb.h>		/* gethostbyname */
26 #include <netinet/in.h>		/* sockaddr_in */
27 #include <netinet/tcp.h>	/* TCP_NODELAY */
28 #include <arpa/inet.h>		/* inet_addr */
29 #include <errno.h>		/* errno */
30 #endif
31 
32 #include "rdesktop.h"
33 #include <winsock2.h>
34 
35 typedef int socklen_t;
36 
37 #ifndef INADDR_NONE
38 #define INADDR_NONE ((unsigned long) -1)
39 #endif
40 
41 /* Initialise TCP transport data packet */
42 STREAM
43 tcp_init(RDPCLIENT * This, uint32 maxlen)
44 {
45 	if (maxlen > This->tcp.out.size)
46 	{
47 		void * p;
48 
49 		p = realloc(This->tcp.out.data, maxlen);
50 
51 		if (p == NULL)
52 		{
53 			This->disconnect_reason = 262;
54 			return NULL;
55 		}
56 
57 		This->tcp.out.data = (uint8 *)p;
58 		This->tcp.out.size = maxlen;
59 	}
60 
61 	This->tcp.out.p = This->tcp.out.data;
62 	This->tcp.out.end = This->tcp.out.data + This->tcp.out.size;
63 	return &This->tcp.out;
64 }
65 
66 /* Send TCP transport data packet */
67 BOOL
68 tcp_send(RDPCLIENT * This, STREAM s)
69 {
70 	int length = (int)(s->end - s->data);
71 	int total = 0;
72 	DWORD sent;
73 
74 	OVERLAPPED overlapped;
75 	memset(&overlapped, 0, sizeof(overlapped));
76 
77 	while (total < length)
78 	{
79 		WriteFile((HANDLE)This->tcp.sock, s->data + total, length - total, NULL, &overlapped);
80 
81 		switch(WaitForSingleObjectEx((HANDLE)This->tcp.sock, INFINITE, TRUE))
82 		{
83 			/* Success */
84 		case WAIT_OBJECT_0:
85 			break;
86 
87 			/* Timeout or error */
88 		case WAIT_TIMEOUT:
89 		default:
90 			This->disconnect_reason = 772;
91 
92 			/* Aborted, must disconnect ASAP */
93 		case WAIT_IO_COMPLETION:
94 			CancelIo((HANDLE)This->tcp.sock);
95 			break;
96 		}
97 
98 		/* Wait for completion. We could hang here, but we shouldn't */
99 		if(!GetOverlappedResult((HANDLE)This->tcp.sock, &overlapped, &sent, TRUE))
100 			return False;
101 
102 		total += sent;
103 	}
104 
105 	return True;
106 }
107 
108 /* Receive a message on the TCP layer */
109 STREAM
110 tcp_recv(RDPCLIENT * This, STREAM s, uint32 length)
111 {
112 	unsigned int new_length, end_offset, p_offset;
113 	DWORD rcvd = 0;
114 
115 	if (s == NULL)
116 	{
117 		/* read into "new" stream */
118 		if (length > This->tcp.in.size)
119 		{
120 			void * p = realloc(This->tcp.in.data, length);
121 
122 			if(p == NULL)
123 			{
124 				This->disconnect_reason = 262;
125 				return NULL;
126 			}
127 
128 			This->tcp.in.data = (uint8 *) p;
129 			This->tcp.in.size = length;
130 		}
131 		This->tcp.in.end = This->tcp.in.p = This->tcp.in.data;
132 		s = &This->tcp.in;
133 	}
134 	else
135 	{
136 		/* append to existing stream */
137 		new_length = (unsigned int)(s->end - s->data) + length;
138 		if (new_length > s->size)
139 		{
140 			void * p = realloc(s->data, new_length);
141 
142 			if(p == NULL)
143 			{
144 				This->disconnect_reason = 262;
145 				return NULL;
146 			}
147 
148 			p_offset = (unsigned int)(s->p - s->data);
149 			end_offset = (unsigned int)(s->end - s->data);
150 			s->data = (uint8 *) p;
151 			s->size = new_length;
152 			s->p = s->data + p_offset;
153 			s->end = s->data + end_offset;
154 		}
155 	}
156 
157 	while (length > 0)
158 	{
159 		OVERLAPPED overlapped;
160 		memset(&overlapped, 0, sizeof(overlapped));
161 
162 		if (!ui_select(This, This->tcp.sock))
163 			/* User quit */
164 			return NULL;
165 
166 		ReadFile((HANDLE)This->tcp.sock, s->end, length, NULL, &overlapped);
167 
168 		switch(WaitForSingleObjectEx((HANDLE)This->tcp.sock, INFINITE, TRUE))
169 		{
170 			/* Success */
171 		case WAIT_OBJECT_0:
172 			break;
173 
174 			/* Timeout or error */
175 		case WAIT_TIMEOUT:
176 		default:
177 			This->disconnect_reason = 1028;
178 
179 			/* Aborted, must disconnect ASAP */
180 		case WAIT_IO_COMPLETION:
181 			CancelIo((HANDLE)This->tcp.sock);
182 			break;
183 		}
184 
185 		/* Wait for completion. We could hang here, but we shouldn't */
186 		if(!GetOverlappedResult((HANDLE)This->tcp.sock, &overlapped, &rcvd, TRUE))
187 			return False;
188 
189 		if (rcvd == 0)
190 		{
191 			error("Connection closed\n");
192 			This->disconnect_reason = 2308;
193 			return NULL;
194 		}
195 
196 		s->end += rcvd;
197 		length -= rcvd;
198 	}
199 
200 	return s;
201 }
202 
203 /* Establish a connection on the TCP layer */
204 BOOL
205 tcp_connect(RDPCLIENT * This, char *server)
206 {
207 	int true_value = 1;
208 
209 #ifdef IPv6
210 
211 	int n;
212 	struct addrinfo hints, *res, *ressave;
213 	char tcp_port_rdp_s[10];
214 
215 	snprintf(tcp_port_rdp_s, 10, "%d", This->tcp_port_rdp);
216 
217 	memset(&hints, 0, sizeof(struct addrinfo));
218 	hints.ai_family = AF_UNSPEC;
219 	hints.ai_socktype = SOCK_STREAM;
220 
221 	if ((n = getaddrinfo(server, tcp_port_rdp_s, &hints, &res)))
222 	{
223 		error("getaddrinfo: %s\n", gai_strerror(n));
224 		return False;
225 	}
226 
227 	ressave = res;
228 	This->tcp.sock = -1;
229 	while (res)
230 	{
231 		This->tcp.sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
232 		if (!(This->tcp.sock < 0))
233 		{
234 			if (connect(This->tcp.sock, res->ai_addr, res->ai_addrlen) == 0)
235 				break;
236 			close(This->tcp.sock);
237 			This->tcp.sock = -1;
238 		}
239 		res = res->ai_next;
240 	}
241 	freeaddrinfo(ressave);
242 
243 	if (This->tcp.sock == -1)
244 	{
245 		error("%s: unable to connect\n", server);
246 		return False;
247 	}
248 
249 #else /* no IPv6 support */
250 
251 	struct hostent *nslookup;
252 	struct sockaddr_in servaddr;
253 
254 	if ((nslookup = gethostbyname(server)) != NULL)
255 	{
256 		memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr));
257 	}
258 	else if ((servaddr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE)
259 	{
260 		error("%s: unable to resolve host\n", server);
261 		This->disconnect_reason = 260;
262 		return False;
263 	}
264 
265 	if ((This->tcp.sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
266 	{
267 		// error("socket: %s\n", strerror(errno)); // EOF
268 		return False;
269 	}
270 
271 	servaddr.sin_family = AF_INET;
272 	servaddr.sin_port = htons(This->tcp_port_rdp);
273 
274 	// TODO: apply connection timeout here
275 
276 	if (connect(This->tcp.sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0)
277 	{
278 		// error("connect: %s\n", strerror(errno)); // EOF
279 		This->disconnect_reason = 516;
280 		closesocket(This->tcp.sock);
281 		return False;
282 	}
283 
284 #endif /* IPv6 */
285 
286 	setsockopt(This->tcp.sock, IPPROTO_TCP, TCP_NODELAY, (void *) &true_value, sizeof(true_value));
287 
288 	This->tcp.in.size = 4096;
289 	This->tcp.in.data = (uint8 *) malloc(This->tcp.in.size);
290 
291 	if(This->tcp.in.data == NULL)
292 	{
293 		This->disconnect_reason = 262;
294 		return False;
295 	}
296 
297 	This->tcp.out.size = 4096;
298 	This->tcp.out.data = (uint8 *) malloc(This->tcp.out.size);
299 
300 	if(This->tcp.out.data == NULL)
301 	{
302 		This->disconnect_reason = 262;
303 		return False;
304 	}
305 
306 	return True;
307 }
308 
309 /* Disconnect on the TCP layer */
310 BOOL
311 tcp_disconnect(RDPCLIENT * This)
312 {
313 	closesocket(This->tcp.sock);
314 	return True;
315 }
316 
317 wchar_t *
318 tcp_get_address(RDPCLIENT * This)
319 {
320 #if 0
321 	static char ipaddr[32];
322 	struct sockaddr_in sockaddr;
323 	socklen_t len = sizeof(sockaddr);
324 	if (getsockname(This->tcp.sock, (struct sockaddr *) &sockaddr, &len) == 0)
325 	{
326 		unsigned char *ip = (unsigned char *) &sockaddr.sin_addr;
327 		sprintf(ipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
328 	}
329 	else
330 		strcpy(ipaddr, "127.0.0.1");
331 	return ipaddr;
332 #endif
333 	return NULL; // TODO
334 }
335 
336 /* reset the state of the tcp layer */
337 /* Support for Session Directory */
338 void
339 tcp_reset_state(RDPCLIENT * This)
340 {
341 	This->tcp.sock = -1;		/* reset socket */
342 
343 	/* Clear the incoming stream */
344 	if (This->tcp.in.data != NULL)
345 		free(This->tcp.in.data);
346 	This->tcp.in.p = NULL;
347 	This->tcp.in.end = NULL;
348 	This->tcp.in.data = NULL;
349 	This->tcp.in.size = 0;
350 	This->tcp.in.iso_hdr = NULL;
351 	This->tcp.in.mcs_hdr = NULL;
352 	This->tcp.in.sec_hdr = NULL;
353 	This->tcp.in.rdp_hdr = NULL;
354 	This->tcp.in.channel_hdr = NULL;
355 
356 	/* Clear the outgoing stream */
357 	if (This->tcp.out.data != NULL)
358 		free(This->tcp.out.data);
359 	This->tcp.out.p = NULL;
360 	This->tcp.out.end = NULL;
361 	This->tcp.out.data = NULL;
362 	This->tcp.out.size = 0;
363 	This->tcp.out.iso_hdr = NULL;
364 	This->tcp.out.mcs_hdr = NULL;
365 	This->tcp.out.sec_hdr = NULL;
366 	This->tcp.out.rdp_hdr = NULL;
367 	This->tcp.out.channel_hdr = NULL;
368 }
369