~paulliu/ubuntu/quantal/freerdp/fixext

« back to all changes in this revision

Viewing changes to libfreerdp-core/tcp.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2012-01-31 10:02:14 UTC
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: package-import@ubuntu.com-20120131100214-zvig71djj2sqgq22
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#ifdef _WIN32
 
191
                int wsa_error = WSAGetLastError();
 
192
 
 
193
                /* No data available */
 
194
                if (wsa_error == WSAEWOULDBLOCK)
 
195
                        return 0;
 
196
 
 
197
                /* When peer disconnects we get status 0 with no error. */
 
198
                if (status < 0)
 
199
                        printf("recv() error: %d\n", wsa_error);
 
200
#else
 
201
                /* No data available */
 
202
                if (errno == EAGAIN || errno == EWOULDBLOCK)
 
203
                        return 0;
 
204
 
 
205
                /* When peer disconnects we get status 0 with no error. */
 
206
                if (status < 0)
 
207
                        perror("recv");
 
208
#endif
 
209
                return -1;
 
210
        }
 
211
 
 
212
        return status;
 
213
}
 
214
 
 
215
int tcp_write(rdpTcp* tcp, uint8* data, int length)
 
216
{
 
217
        int status;
 
218
 
 
219
        status = send(tcp->sockfd, data, length, MSG_NOSIGNAL);
 
220
 
 
221
        if (status < 0)
 
222
        {
 
223
                if (errno == EAGAIN || errno == EWOULDBLOCK)
 
224
                        status = 0;
 
225
                else
 
226
                        perror("send");
 
227
        }
 
228
 
 
229
        return status;
 
230
}
 
231
 
 
232
boolean tcp_disconnect(rdpTcp * tcp)
 
233
{
 
234
        if (tcp->sockfd != -1)
 
235
        {
 
236
                shutdown(tcp->sockfd, SHUT_RDWR);
 
237
                close(tcp->sockfd);
 
238
                tcp->sockfd = -1;
 
239
        }
 
240
 
 
241
        return true;
 
242
}
 
243
 
 
244
boolean tcp_set_blocking_mode(rdpTcp* tcp, boolean blocking)
 
245
{
 
246
#ifndef _WIN32
 
247
        int flags;
 
248
        flags = fcntl(tcp->sockfd, F_GETFL);
 
249
 
 
250
        if (flags == -1)
 
251
        {
 
252
                printf("tcp_set_blocking_mode: fcntl failed.\n");
 
253
                return false;
 
254
        }
 
255
 
 
256
        if (blocking == true)
 
257
                fcntl(tcp->sockfd, F_SETFL, flags & ~(O_NONBLOCK));
 
258
        else
 
259
                fcntl(tcp->sockfd, F_SETFL, flags | O_NONBLOCK);
 
260
#else
 
261
        u_long arg = blocking;
 
262
        ioctlsocket(tcp->sockfd, FIONBIO, &arg);
 
263
        tcp->wsa_event = WSACreateEvent();
 
264
        WSAEventSelect(tcp->sockfd, tcp->wsa_event, FD_READ);
 
265
#endif
 
266
 
 
267
        return true;
 
268
}
 
269
 
 
270
boolean tcp_set_keep_alive_mode(rdpTcp* tcp)
 
271
{
 
272
#ifndef _WIN32
 
273
        uint32 option_value;
 
274
        socklen_t option_len;
 
275
 
 
276
        option_value = 1;
 
277
        option_len = sizeof(option_value);
 
278
 
 
279
        if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*) &option_value, option_len) < 0)
 
280
        {
 
281
                perror("setsockopt() SOL_SOCKET, SO_KEEPALIVE:");
 
282
                return false;
 
283
        }
 
284
 
 
285
#ifdef TCP_KEEPIDLE
 
286
        option_value = 5;
 
287
        option_len = sizeof(option_value);
 
288
 
 
289
        if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &option_value, option_len) < 0)
 
290
        {
 
291
                perror("setsockopt() IPPROTO_TCP, SO_KEEPIDLE:");
 
292
                return false;
 
293
        }
 
294
#endif
 
295
#endif
 
296
 
 
297
        return true;
 
298
}
 
299
 
 
300
rdpTcp* tcp_new(rdpSettings* settings)
 
301
{
 
302
        rdpTcp* tcp;
 
303
 
 
304
        tcp = (rdpTcp*) xzalloc(sizeof(rdpTcp));
 
305
 
 
306
        if (tcp != NULL)
 
307
        {
 
308
                tcp->sockfd = -1;
 
309
                tcp->settings = settings;
 
310
        }
 
311
 
 
312
        return tcp;
 
313
}
 
314
 
 
315
void tcp_free(rdpTcp* tcp)
 
316
{
 
317
        if (tcp != NULL)
 
318
        {
 
319
                xfree(tcp);
 
320
        }
 
321
}