Separated the RDP5 sending into its own protocol layer.
[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 int
137 tcp_connect(char *server, int port)
138 {
139         int true_value = 1;
140         int sock;
141
142 #ifdef IPv6
143
144         int n;
145         struct addrinfo hints, *res, *ressave;
146         char tcp_port_rdp_s[10];
147
148         snprintf(tcp_port_rdp_s, 10, "%d", tcp_port_rdp);
149
150         memset(&hints, 0, sizeof(struct addrinfo));
151         hints.ai_family = AF_UNSPEC;
152         hints.ai_socktype = SOCK_STREAM;
153
154         n = getaddrinfo(server, tcp_port_rdp_s, &hints, &res);
155
156         if (n < 0)
157         {
158                 error("getaddrinfo: %s\n", gai_strerror(n));
159                 return -1;
160         }
161
162         ressave = res;
163         sock = -1;
164         while (res)
165         {
166                 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
167                 if (!(sock < 0))
168                 {
169                         if (connect(sock, res->ai_addr, res->ai_addrlen) == 0)
170                                 break;
171                         close(sock);
172                         sock = -1;
173                 }
174                 res = res->ai_next;
175         }
176         freeaddrinfo(ressave);
177
178         if (sock == -1)
179         {
180                 error("%s: unable to connect\n", server);
181                 return -1;
182         }
183
184 #else /* no IPv6 support */
185
186         struct hostent *nslookup;
187         struct sockaddr_in servaddr;
188
189         if ((nslookup = gethostbyname(server)) != NULL)
190         {
191                 memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr));
192         }
193         else if ((servaddr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE)
194         {
195                 error("%s: unable to resolve host\n", server);
196                 return -1;
197         }
198
199         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
200         {
201                 error("socket: %s\n", strerror(errno));
202                 return -1;
203         }
204
205         servaddr.sin_family = AF_INET;
206         servaddr.sin_port = htons(port);
207
208         if (connect(sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0)
209         {
210                 error("connect: %s\n", strerror(errno));
211                 close(sock);
212                 return -1;
213         }
214
215 #endif /* IPv6 */
216
217         setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &true_value, sizeof(true_value));
218
219         in.size = 4096;
220         in.data = (uint8 *) xmalloc(in.size);
221
222         out.size = 4096;
223         out.data = (uint8 *) xmalloc(out.size);
224
225         return sock;
226 }
227
228 /* Establish a connection on the TCP layer */
229 BOOL
230 tcp_recv_connect(int server_sock)
231 {
232         struct sockaddr_in sin;
233         unsigned true_value = 1;
234         socklen_t len = sizeof(sin);
235         sock = accept(server_sock, (struct sockaddr *)&sin, &len);
236
237         if (sock == -1) {
238                 perror("accept()");
239                 exit(1);
240         }
241
242         setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &true_value, sizeof(true_value));
243
244         in.size = 4096;
245         in.data = (uint8 *) xmalloc(in.size);
246
247         out.size = 4096;
248         out.data = (uint8 *) xmalloc(out.size);
249
250         return True;
251 }
252
253 /* Disconnect on the TCP layer */
254 void
255 tcp_disconnect(void)
256 {
257         close(sock);
258 }
259
260 // hack? :-)
261 int tcp_get_socket(void)
262 {
263         return sock;
264 }