Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-core / tcp.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * Transmission Control Protocol (TCP)
4  *
5  * Copyright 2011 Vic Lee
6  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <errno.h>
26 #include <fcntl.h>
27
28 #ifndef _WIN32
29 #include <netdb.h>
30 #include <unistd.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
35 #include <net/if.h>
36
37 #ifdef __APPLE__
38 #ifndef TCP_KEEPIDLE
39 #define TCP_KEEPIDLE TCP_KEEPALIVE
40 #endif
41 #endif
42
43 #else
44 #define SHUT_RDWR SD_BOTH
45 #define close(_fd) closesocket(_fd)
46 #endif
47
48 #include <freerdp/utils/print.h>
49 #include <freerdp/utils/stream.h>
50 #include <freerdp/utils/memory.h>
51
52 #include "tcp.h"
53
54 void tcp_get_ip_address(rdpTcp * tcp)
55 {
56         uint8* ip;
57         socklen_t length;
58         struct sockaddr_in sockaddr;
59
60         length = sizeof(sockaddr);
61
62         if (getsockname(tcp->sockfd, (struct sockaddr*) &sockaddr, &length) == 0)
63         {
64                 ip = (uint8*) (&sockaddr.sin_addr);
65                 snprintf(tcp->ip_address, sizeof(tcp->ip_address),
66                          "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
67         }
68         else
69         {
70                 strncpy(tcp->ip_address, "127.0.0.1", sizeof(tcp->ip_address));
71         }
72
73         tcp->ip_address[sizeof(tcp->ip_address) - 1] = 0;
74
75         tcp->settings->ipv6 = 0;
76         tcp->settings->ip_address = xstrdup(tcp->ip_address);
77 }
78
79 void tcp_get_mac_address(rdpTcp * tcp)
80 {
81 #ifdef LINUX
82         uint8* mac;
83         struct ifreq if_req;
84         struct if_nameindex* ni;
85
86         ni = if_nameindex();
87         mac = tcp->mac_address;
88
89         while (ni->if_name != NULL)
90         {
91                 if (strcmp(ni->if_name, "lo") != 0)
92                         break;
93
94                 ni++;
95         }
96
97         strncpy(if_req.ifr_name, ni->if_name, IF_NAMESIZE);
98
99         if (ioctl(tcp->sockfd, SIOCGIFHWADDR, &if_req) != 0)
100         {
101                 printf("failed to obtain MAC address\n");
102                 return;
103         }
104
105         memmove((void*) mac, (void*) &if_req.ifr_ifru.ifru_hwaddr.sa_data[0], 6);
106 #endif
107
108         /* printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
109                 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); */
110 }
111
112 boolean tcp_connect(rdpTcp* tcp, const char* hostname, uint16 port)
113 {
114         int status;
115         char servname[10];
116         uint32 option_value;
117         socklen_t option_len;
118         struct addrinfo hints = { 0 };
119         struct addrinfo * res, * ai;
120
121         memset(&hints, 0, sizeof(struct addrinfo));
122         hints.ai_family = AF_UNSPEC;
123         hints.ai_socktype = SOCK_STREAM;
124
125         snprintf(servname, sizeof(servname), "%d", port);
126         status = getaddrinfo(hostname, servname, &hints, &res);
127
128         if (status != 0)
129         {
130                 printf("transport_connect: getaddrinfo (%s)\n", gai_strerror(status));
131                 return false;
132         }
133
134         tcp->sockfd = -1;
135         for (ai = res; ai; ai = ai->ai_next)
136         {
137                 tcp->sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
138
139                 if (tcp->sockfd < 0)
140                         continue;
141
142                 if (connect(tcp->sockfd, ai->ai_addr, ai->ai_addrlen) == 0)
143                 {
144                         printf("connected to %s:%s\n", hostname, servname);
145                         break;
146                 }
147
148                 close(tcp->sockfd);
149                 tcp->sockfd = -1;
150         }
151         freeaddrinfo(res);
152
153         if (tcp->sockfd == -1)
154         {
155                 printf("unable to connect to %s:%s\n", hostname, servname);
156                 return false;
157         }
158
159         tcp_get_ip_address(tcp);
160         tcp_get_mac_address(tcp);
161
162         option_value = 1;
163         option_len = sizeof(option_value);
164         setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len);
165
166         /* receive buffer must be a least 32 K */
167         if (getsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, &option_len) == 0)
168         {
169                 if (option_value < (1024 * 32))
170                 {
171                         option_value = 1024 * 32;
172                         option_len = sizeof(option_value);
173                         setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, option_len);
174                 }
175         }
176
177         tcp_set_keep_alive_mode(tcp);
178
179         return true;
180 }
181
182 int tcp_read(rdpTcp* tcp, uint8* data, int length)
183 {
184         int status;
185
186         status = recv(tcp->sockfd, data, length, 0);
187
188         if (status == 0)
189         {
190                 /* Peer disconnected. */
191                 return -1;
192         }
193         else if (status < 0)
194         {
195 #ifdef _WIN32
196                 int wsa_error = WSAGetLastError();
197
198                 /* No data available */
199                 if (wsa_error == WSAEWOULDBLOCK)
200                         return 0;
201
202                 printf("recv() error: %d\n", wsa_error);
203 #else
204                 /* No data available */
205                 if (errno == EAGAIN || errno == EWOULDBLOCK)
206                         return 0;
207
208                 perror("recv");
209 #endif
210                 return -1;
211         }
212
213         return status;
214 }
215
216 int tcp_write(rdpTcp* tcp, uint8* data, int length)
217 {
218         int status;
219
220         status = send(tcp->sockfd, data, length, MSG_NOSIGNAL);
221
222         if (status < 0)
223         {
224 #ifdef _WIN32
225                 int wsa_error = WSAGetLastError();
226
227                 /* No data available */
228                 if (wsa_error == WSAEWOULDBLOCK)
229                         status = 0;
230                 else 
231                         perror("send");
232 #else
233                 if (errno == EAGAIN || errno == EWOULDBLOCK)
234                         status = 0;
235                 else
236                         perror("send");
237 #endif
238         }
239
240         return status;
241 }
242
243 boolean tcp_disconnect(rdpTcp * tcp)
244 {
245         if (tcp->sockfd != -1)
246         {
247                 shutdown(tcp->sockfd, SHUT_RDWR);
248                 close(tcp->sockfd);
249                 tcp->sockfd = -1;
250         }
251
252         return true;
253 }
254
255 boolean tcp_set_blocking_mode(rdpTcp* tcp, boolean blocking)
256 {
257 #ifndef _WIN32
258         int flags;
259         flags = fcntl(tcp->sockfd, F_GETFL);
260
261         if (flags == -1)
262         {
263                 printf("tcp_set_blocking_mode: fcntl failed.\n");
264                 return false;
265         }
266
267         if (blocking == true)
268                 fcntl(tcp->sockfd, F_SETFL, flags & ~(O_NONBLOCK));
269         else
270                 fcntl(tcp->sockfd, F_SETFL, flags | O_NONBLOCK);
271 #else
272         u_long arg = blocking;
273         ioctlsocket(tcp->sockfd, FIONBIO, &arg);
274         tcp->wsa_event = WSACreateEvent();
275         WSAEventSelect(tcp->sockfd, tcp->wsa_event, FD_READ);
276 #endif
277
278         return true;
279 }
280
281 boolean tcp_set_keep_alive_mode(rdpTcp* tcp)
282 {
283 #ifndef _WIN32
284         uint32 option_value;
285         socklen_t option_len;
286
287         option_value = 1;
288         option_len = sizeof(option_value);
289
290         if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*) &option_value, option_len) < 0)
291         {
292                 perror("setsockopt() SOL_SOCKET, SO_KEEPALIVE:");
293                 return false;
294         }
295
296 #ifdef TCP_KEEPIDLE
297         option_value = 5;
298         option_len = sizeof(option_value);
299
300         if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &option_value, option_len) < 0)
301         {
302                 perror("setsockopt() IPPROTO_TCP, SO_KEEPIDLE:");
303                 return false;
304         }
305 #endif
306 #endif
307
308         return true;
309 }
310
311 rdpTcp* tcp_new(rdpSettings* settings)
312 {
313         rdpTcp* tcp;
314
315         tcp = (rdpTcp*) xzalloc(sizeof(rdpTcp));
316
317         if (tcp != NULL)
318         {
319                 tcp->sockfd = -1;
320                 tcp->settings = settings;
321         }
322
323         return tcp;
324 }
325
326 void tcp_free(rdpTcp* tcp)
327 {
328         if (tcp != NULL)
329         {
330                 xfree(tcp);
331         }
332 }