Pull in even more rdesktop source.
[rdpsrv] / tcp.c
1 /*
2    rdesktop: A Remote Desktop Protocol client.
3    Protocol services - TCP layer
4    Copyright (C) Matthew Chapman 1999-2002
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
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <unistd.h>             /* select read write close */
22 #include <sys/socket.h>         /* socket connect setsockopt */
23 #include <sys/time.h>           /* timeval */
24 #include <netdb.h>              /* gethostbyname */
25 #include <netinet/in.h>         /* sockaddr_in */
26 #include <netinet/tcp.h>        /* TCP_NODELAY */
27 #include <arpa/inet.h>          /* inet_addr */
28 #include <errno.h>              /* errno */
29 #include "rdesktop.h"
30
31 #ifndef INADDR_NONE
32 #define INADDR_NONE ((unsigned long) -1)
33 #endif
34
35 static int sock;
36 static struct stream in;
37 static struct stream out;
38 extern int tcp_port_rdp;
39
40 /* Initialise TCP transport data packet */
41 STREAM
42 tcp_init(uint32 maxlen)
43 {
44         if (maxlen > out.size)
45         {
46                 out.data = (uint8 *) xrealloc(out.data, maxlen);
47                 out.size = maxlen;
48         }
49
50         out.p = out.data;
51         out.end = out.data + out.size;
52         return &out;
53 }
54
55 /* Send TCP transport data packet */
56 void
57 tcp_send(STREAM s)
58 {
59         int length = s->end - s->data;
60         int sent, total = 0;
61
62         while (total < length)
63         {
64                 sent = send(sock, s->data + total, length - total, 0);
65                 if (sent <= 0)
66                 {
67                         error("send: %s\n", strerror(errno));
68                         return;
69                 }
70
71                 total += sent;
72         }
73 }
74
75 /* Receive a message on the TCP layer */
76 STREAM
77 tcp_recv(STREAM s, uint32 length)
78 {
79         unsigned int new_length, end_offset, p_offset;
80         int rcvd = 0;
81
82         if (s == NULL)
83         {
84                 /* read into "new" stream */
85                 if (length > in.size)
86                 {
87                         in.data = (uint8 *) xrealloc(in.data, length);
88                         in.size = length;
89                 }
90                 in.end = in.p = in.data;
91                 s = &in;
92         }
93         else
94         {
95                 /* append to existing stream */
96                 new_length = (s->end - s->data) + length;
97                 if (new_length > s->size)
98                 {
99                         p_offset = s->p - s->data;
100                         end_offset = s->end - s->data;
101                         s->data = (uint8 *) xrealloc(s->data, new_length);
102                         s->size = new_length;
103                         s->p = s->data + p_offset;
104                         s->end = s->data + end_offset;
105                 }
106         }
107
108         while (length > 0)
109         {
110 #if 0
111                 if (!ui_select(sock))
112                         /* User quit */
113                         return NULL;
114 #endif
115
116                 rcvd = recv(sock, s->end, length, 0);
117                 if (rcvd < 0)
118                 {
119                         error("recv: %s\n", strerror(errno));
120                         return NULL;
121                 }
122                 else if (rcvd == 0)
123                 {
124                         error("Connection closed\n");
125                         return NULL;
126                 }
127
128                 s->end += rcvd;
129                 length -= rcvd;
130         }
131
132         return s;
133 }
134
135 /* Establish a connection on the TCP layer */
136 BOOL
137 tcp_connect(char *server)
138 {
139         int true_value = 1;
140
141 #ifdef IPv6
142
143         int n;
144         struct addrinfo hints, *res, *ressave;
145         char tcp_port_rdp_s[10];
146
147         snprintf(tcp_port_rdp_s, 10, "%d", tcp_port_rdp);
148
149         memset(&hints, 0, sizeof(struct addrinfo));
150         hints.ai_family = AF_UNSPEC;
151         hints.ai_socktype = SOCK_STREAM;
152
153         n = getaddrinfo(server, tcp_port_rdp_s, &hints, &res);
154
155         if (n < 0)
156         {
157                 error("getaddrinfo: %s\n", gai_strerror(n));
158                 return False;
159         }
160
161         ressave = res;
162         sock = -1;
163         while (res)
164         {
165                 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
166                 if (!(sock < 0))
167                 {
168                         if (connect(sock, res->ai_addr, res->ai_addrlen) == 0)
169                                 break;
170                         close(sock);
171                         sock = -1;
172                 }
173                 res = res->ai_next;
174         }
175         freeaddrinfo(ressave);
176
177         if (sock == -1)
178         {
179                 error("%s: unable to connect\n", server);
180                 return False;
181         }
182
183 #else /* no IPv6 support */
184
185         struct hostent *nslookup;
186         struct sockaddr_in servaddr;
187
188         if ((nslookup = gethostbyname(server)) != NULL)
189         {
190                 memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr));
191         }
192         else if ((servaddr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE)
193         {
194                 error("%s: unable to resolve host\n", server);
195                 return False;
196         }
197
198         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
199         {
200                 error("socket: %s\n", strerror(errno));
201                 return False;
202         }
203
204         servaddr.sin_family = AF_INET;
205         servaddr.sin_port = htons(tcp_port_rdp);
206
207         if (connect(sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0)
208         {
209                 error("connect: %s\n", strerror(errno));
210                 close(sock);
211                 return False;
212         }
213
214 #endif /* IPv6 */
215
216         setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &true_value, sizeof(true_value));
217
218         in.size = 4096;
219         in.data = (uint8 *) xmalloc(in.size);
220
221         out.size = 4096;
222         out.data = (uint8 *) xmalloc(out.size);
223
224         return True;
225 }
226
227 /* Disconnect on the TCP layer */
228 void
229 tcp_disconnect(void)
230 {
231         close(sock);
232 }