1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Protocol services - TCP layer
4 Copyright (C) Matthew Chapman 1999-2005
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.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 */
35 typedef int socklen_t
;
38 #define INADDR_NONE ((unsigned long) -1)
41 /* Initialise TCP transport data packet */
43 tcp_init(RDPCLIENT
* This
, uint32 maxlen
)
45 if (maxlen
> This
->tcp
.out
.size
)
49 p
= realloc(This
->tcp
.out
.data
, maxlen
);
53 This
->disconnect_reason
= 262;
57 This
->tcp
.out
.data
= (uint8
*)p
;
58 This
->tcp
.out
.size
= maxlen
;
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
;
66 /* Send TCP transport data packet */
68 tcp_send(RDPCLIENT
* This
, STREAM s
)
70 int length
= (int)(s
->end
- s
->data
);
74 OVERLAPPED overlapped
;
75 memset(&overlapped
, 0, sizeof(overlapped
));
77 while (total
< length
)
79 WriteFile((HANDLE
)This
->tcp
.sock
, s
->data
+ total
, length
- total
, NULL
, &overlapped
);
81 switch(WaitForSingleObjectEx((HANDLE
)This
->tcp
.sock
, INFINITE
, TRUE
))
87 /* Timeout or error */
90 This
->disconnect_reason
= 772;
92 /* Aborted, must disconnect ASAP */
93 case WAIT_IO_COMPLETION
:
94 CancelIo((HANDLE
)This
->tcp
.sock
);
98 /* Wait for completion. We could hang here, but we shouldn't */
99 if(!GetOverlappedResult((HANDLE
)This
->tcp
.sock
, &overlapped
, &sent
, TRUE
))
108 /* Receive a message on the TCP layer */
110 tcp_recv(RDPCLIENT
* This
, STREAM s
, uint32 length
)
112 unsigned int new_length
, end_offset
, p_offset
;
117 /* read into "new" stream */
118 if (length
> This
->tcp
.in
.size
)
120 void * p
= realloc(This
->tcp
.in
.data
, length
);
124 This
->disconnect_reason
= 262;
128 This
->tcp
.in
.data
= (uint8
*) p
;
129 This
->tcp
.in
.size
= length
;
131 This
->tcp
.in
.end
= This
->tcp
.in
.p
= This
->tcp
.in
.data
;
136 /* append to existing stream */
137 new_length
= (unsigned int)(s
->end
- s
->data
) + length
;
138 if (new_length
> s
->size
)
140 void * p
= realloc(s
->data
, new_length
);
144 This
->disconnect_reason
= 262;
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
;
159 OVERLAPPED overlapped
;
160 memset(&overlapped
, 0, sizeof(overlapped
));
162 if (!ui_select(This
, This
->tcp
.sock
))
166 ReadFile((HANDLE
)This
->tcp
.sock
, s
->end
, length
, NULL
, &overlapped
);
168 switch(WaitForSingleObjectEx((HANDLE
)This
->tcp
.sock
, INFINITE
, TRUE
))
174 /* Timeout or error */
177 This
->disconnect_reason
= 1028;
179 /* Aborted, must disconnect ASAP */
180 case WAIT_IO_COMPLETION
:
181 CancelIo((HANDLE
)This
->tcp
.sock
);
185 /* Wait for completion. We could hang here, but we shouldn't */
186 if(!GetOverlappedResult((HANDLE
)This
->tcp
.sock
, &overlapped
, &rcvd
, TRUE
))
191 error("Connection closed\n");
192 This
->disconnect_reason
= 2308;
203 /* Establish a connection on the TCP layer */
205 tcp_connect(RDPCLIENT
* This
, char *server
)
212 struct addrinfo hints
, *res
, *ressave
;
213 char tcp_port_rdp_s
[10];
215 snprintf(tcp_port_rdp_s
, 10, "%d", This
->tcp_port_rdp
);
217 memset(&hints
, 0, sizeof(struct addrinfo
));
218 hints
.ai_family
= AF_UNSPEC
;
219 hints
.ai_socktype
= SOCK_STREAM
;
221 if ((n
= getaddrinfo(server
, tcp_port_rdp_s
, &hints
, &res
)))
223 error("getaddrinfo: %s\n", gai_strerror(n
));
231 This
->tcp
.sock
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
232 if (!(This
->tcp
.sock
< 0))
234 if (connect(This
->tcp
.sock
, res
->ai_addr
, res
->ai_addrlen
) == 0)
236 close(This
->tcp
.sock
);
241 freeaddrinfo(ressave
);
243 if (This
->tcp
.sock
== -1)
245 error("%s: unable to connect\n", server
);
249 #else /* no IPv6 support */
251 struct hostent
*nslookup
;
252 struct sockaddr_in servaddr
;
254 if ((nslookup
= gethostbyname(server
)) != NULL
)
256 memcpy(&servaddr
.sin_addr
, nslookup
->h_addr
, sizeof(servaddr
.sin_addr
));
258 else if ((servaddr
.sin_addr
.s_addr
= inet_addr(server
)) == INADDR_NONE
)
260 error("%s: unable to resolve host\n", server
);
261 This
->disconnect_reason
= 260;
265 if ((This
->tcp
.sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0)
267 // error("socket: %s\n", strerror(errno)); // EOF
271 servaddr
.sin_family
= AF_INET
;
272 servaddr
.sin_port
= htons(This
->tcp_port_rdp
);
274 // TODO: apply connection timeout here
276 if (connect(This
->tcp
.sock
, (struct sockaddr
*) &servaddr
, sizeof(struct sockaddr
)) < 0)
278 // error("connect: %s\n", strerror(errno)); // EOF
279 This
->disconnect_reason
= 516;
280 closesocket(This
->tcp
.sock
);
286 setsockopt(This
->tcp
.sock
, IPPROTO_TCP
, TCP_NODELAY
, (void *) &true_value
, sizeof(true_value
));
288 This
->tcp
.in
.size
= 4096;
289 This
->tcp
.in
.data
= (uint8
*) malloc(This
->tcp
.in
.size
);
291 if(This
->tcp
.in
.data
== NULL
)
293 This
->disconnect_reason
= 262;
297 This
->tcp
.out
.size
= 4096;
298 This
->tcp
.out
.data
= (uint8
*) malloc(This
->tcp
.out
.size
);
300 if(This
->tcp
.out
.data
== NULL
)
302 This
->disconnect_reason
= 262;
309 /* Disconnect on the TCP layer */
311 tcp_disconnect(RDPCLIENT
* This
)
313 closesocket(This
->tcp
.sock
);
318 tcp_get_address(RDPCLIENT
* This
)
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)
326 unsigned char *ip
= (unsigned char *) &sockaddr
.sin_addr
;
327 sprintf(ipaddr
, "%d.%d.%d.%d", ip
[0], ip
[1], ip
[2], ip
[3]);
330 strcpy(ipaddr
, "127.0.0.1");
336 /* reset the state of the tcp layer */
337 /* Support for Session Directory */
339 tcp_reset_state(RDPCLIENT
* This
)
341 This
->tcp
.sock
= -1; /* reset socket */
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
;
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
;