[NTDLL]
[reactos.git] / base / applications / mstsc / tcp.c
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
22 #include <precomp.h>
23
24 #ifdef _WIN32
25 #define socklen_t int
26 #define TCP_CLOSE(_sck) closesocket(_sck)
27 #define TCP_STRERROR "tcp error"
28 #define TCP_SLEEP(_n) Sleep(_n)
29 #define TCP_BLOCKS (WSAGetLastError() == WSAEWOULDBLOCK)
30 #else /* _WIN32 */
31 #define TCP_CLOSE(_sck) close(_sck)
32 #define TCP_STRERROR strerror(errno)
33 #define TCP_SLEEP(_n) sleep(_n)
34 #define TCP_BLOCKS (errno == EWOULDBLOCK)
35 #endif /* _WIN32 */
36
37 #ifndef INADDR_NONE
38 #define INADDR_NONE ((unsigned long) -1)
39 #endif
40
41 static int sock;
42 static struct stream in;
43 static struct stream out;
44 int g_tcp_port_rdp = TCP_PORT_RDP;
45
46 /* Initialise TCP transport data packet */
47 STREAM
48 tcp_init(uint32 maxlen)
49 {
50 if (maxlen > out.size)
51 {
52 out.data = (uint8 *) xrealloc(out.data, maxlen);
53 out.size = maxlen;
54 }
55
56 out.p = out.data;
57 out.end = out.data + out.size;
58 return &out;
59 }
60
61 /* Send TCP transport data packet */
62 void
63 tcp_send(STREAM s)
64 {
65 int length = s->end - s->data;
66 int sent, total = 0;
67
68 while (total < length)
69 {
70 sent = send(sock, (char *)s->data + total, length - total, 0);
71 if (sent <= 0)
72 {
73 if (sent == -1 && TCP_BLOCKS)
74 {
75 TCP_SLEEP(0);
76 sent = 0;
77 }
78 else
79 {
80 error("send: %s\n", TCP_STRERROR);
81 return;
82 }
83 }
84 total += sent;
85 }
86 }
87
88 /* Receive a message on the TCP layer */
89 STREAM
90 tcp_recv(STREAM s, uint32 length)
91 {
92 unsigned int new_length, end_offset, p_offset;
93 int rcvd = 0;
94
95 if (s == NULL)
96 {
97 /* read into "new" stream */
98 if (length > in.size)
99 {
100 in.data = (uint8 *) xrealloc(in.data, length);
101 in.size = length;
102 }
103 in.end = in.p = in.data;
104 s = &in;
105 }
106 else
107 {
108 /* append to existing stream */
109 new_length = (s->end - s->data) + length;
110 if (new_length > s->size)
111 {
112 p_offset = s->p - s->data;
113 end_offset = s->end - s->data;
114 s->data = (uint8 *) xrealloc(s->data, new_length);
115 s->size = new_length;
116 s->p = s->data + p_offset;
117 s->end = s->data + end_offset;
118 }
119 }
120
121 while (length > 0)
122 {
123 if (!ui_select(sock))
124 /* User quit */
125 return NULL;
126
127 rcvd = recv(sock, (char *)s->end, length, 0);
128 if (rcvd < 0)
129 {
130 if (rcvd == -1 && TCP_BLOCKS)
131 {
132 TCP_SLEEP(0);
133 rcvd = 0;
134 }
135 else
136 {
137 error("recv: %s\n", TCP_STRERROR);
138 return NULL;
139 }
140 }
141 else if (rcvd == 0)
142 {
143 error("Connection closed\n");
144 return NULL;
145 }
146
147 s->end += rcvd;
148 length -= rcvd;
149 }
150
151 return s;
152 }
153
154 /* Establish a connection on the TCP layer */
155 BOOL
156 tcp_connect(char *server)
157 {
158 int true_value = 1;
159
160 #ifdef IPv6
161
162 int n;
163 struct addrinfo hints, *res, *ressave;
164 char tcp_port_rdp_s[10];
165
166 snprintf(tcp_port_rdp_s, 10, "%d", g_tcp_port_rdp);
167
168 memset(&hints, 0, sizeof(struct addrinfo));
169 hints.ai_family = AF_UNSPEC;
170 hints.ai_socktype = SOCK_STREAM;
171
172 if ((n = getaddrinfo(server, tcp_port_rdp_s, &hints, &res)))
173 {
174 error("getaddrinfo: %s\n", gai_strerror(n));
175 return False;
176 }
177
178 ressave = res;
179 sock = -1;
180 while (res)
181 {
182 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
183 if (!(sock < 0))
184 {
185 if (connect(sock, res->ai_addr, res->ai_addrlen) == 0)
186 break;
187 TCP_CLOSE(sock);
188 sock = -1;
189 }
190 res = res->ai_next;
191 }
192 freeaddrinfo(ressave);
193
194 if (sock == -1)
195 {
196 error("%s: unable to connect\n", server);
197 return False;
198 }
199
200 #else /* no IPv6 support */
201
202 struct hostent *nslookup;
203 struct sockaddr_in servaddr;
204
205 if ((nslookup = gethostbyname(server)) != NULL)
206 {
207 memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr));
208 }
209 else if ((servaddr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE)
210 {
211 error("%s: unable to resolve host\n", server);
212 return False;
213 }
214
215 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
216 {
217 error("socket: %s\n", TCP_STRERROR);
218 return False;
219 }
220
221 servaddr.sin_family = AF_INET;
222 servaddr.sin_port = htons((uint16) g_tcp_port_rdp);
223
224 if (connect(sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0)
225 {
226 error("connect: %s\n", TCP_STRERROR);
227 TCP_CLOSE(sock);
228 return False;
229 }
230
231 #endif /* IPv6 */
232
233 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &true_value, sizeof(true_value));
234
235 in.size = 4096;
236 in.data = (uint8 *) xmalloc(in.size);
237
238 out.size = 4096;
239 out.data = (uint8 *) xmalloc(out.size);
240
241 return True;
242 }
243
244 /* Disconnect on the TCP layer */
245 void
246 tcp_disconnect(void)
247 {
248 TCP_CLOSE(sock);
249 }
250
251 char *
252 tcp_get_address()
253 {
254 static char ipaddr[32];
255 struct sockaddr_in sockaddr;
256 socklen_t len = sizeof(sockaddr);
257 if (getsockname(sock, (struct sockaddr *) &sockaddr, &len) == 0)
258 {
259 unsigned char *ip = (unsigned char *) &sockaddr.sin_addr;
260 sprintf(ipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
261 }
262 else
263 strcpy(ipaddr, "127.0.0.1");
264 return ipaddr;
265 }
266
267 /* reset the state of the tcp layer */
268 /* Support for Session Directory */
269 void
270 tcp_reset_state(void)
271 {
272 sock = -1; /* reset socket */
273
274 /* Clear the incoming stream */
275 if (in.data != NULL)
276 xfree(in.data);
277 in.p = NULL;
278 in.end = NULL;
279 in.data = NULL;
280 in.size = 0;
281 in.iso_hdr = NULL;
282 in.mcs_hdr = NULL;
283 in.sec_hdr = NULL;
284 in.rdp_hdr = NULL;
285 in.channel_hdr = NULL;
286
287 /* Clear the outgoing stream */
288 if (out.data != NULL)
289 xfree(out.data);
290 out.p = NULL;
291 out.end = NULL;
292 out.data = NULL;
293 out.size = 0;
294 out.iso_hdr = NULL;
295 out.mcs_hdr = NULL;
296 out.sec_hdr = NULL;
297 out.rdp_hdr = NULL;
298 out.channel_hdr = NULL;
299 }