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