libfreerdp-utils: added snprintf wrapper for windows portability
[platform/upstream/freerdp.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 <netdb.h>
27 #include <fcntl.h>
28 #include <net/if.h>
29 #include <sys/ioctl.h>
30 #include <sys/socket.h>
31 #include <unistd.h>
32
33 #include <freerdp/utils/print.h>
34 #include <freerdp/utils/stream.h>
35 #include <freerdp/utils/memory.h>
36
37 #include "tcp.h"
38
39 void tcp_get_ip_address(rdpTcp * tcp)
40 {
41         uint8* ip;
42         socklen_t length;
43         struct sockaddr_in sockaddr;
44
45         length = sizeof(sockaddr);
46
47         if (getsockname(tcp->sockfd, (struct sockaddr*) &sockaddr, &length) == 0)
48         {
49                 ip = (uint8*) (&sockaddr.sin_addr);
50                 snprintf(tcp->ip_address, sizeof(tcp->ip_address),
51                          "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
52         }
53         else
54         {
55                 strncpy(tcp->ip_address, "127.0.0.1", sizeof(tcp->ip_address));
56         }
57
58         tcp->ip_address[sizeof(tcp->ip_address) - 1] = 0;
59
60         tcp->settings->ipv6 = 0;
61         tcp->settings->ip_address = tcp->ip_address;
62 }
63
64 void tcp_get_mac_address(rdpTcp * tcp)
65 {
66 #ifdef LINUX
67         uint8* mac;
68         struct ifreq if_req;
69         struct if_nameindex* ni;
70
71         ni = if_nameindex();
72         mac = tcp->mac_address;
73
74         while (ni->if_name != NULL)
75         {
76                 if (strcmp(ni->if_name, "lo") != 0)
77                         break;
78
79                 ni++;
80         }
81
82         strncpy(if_req.ifr_name, ni->if_name, IF_NAMESIZE);
83
84         if (ioctl(tcp->sockfd, SIOCGIFHWADDR, &if_req) != 0)
85         {
86                 printf("failed to obtain MAC address\n");
87                 return;
88         }
89
90         memmove((void*) mac, (void*) &if_req.ifr_ifru.ifru_hwaddr.sa_data[0], 6);
91 #endif
92
93         /* printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
94                 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); */
95 }
96
97 boolean tcp_connect(rdpTcp* tcp, const char* hostname, uint16 port)
98 {
99         int status;
100         int sockfd = -1;
101         char servname[10];
102         struct addrinfo hints = { 0 };
103         struct addrinfo * res, * ai;
104
105         hints.ai_family = AF_UNSPEC;
106         hints.ai_socktype = SOCK_STREAM;
107
108         snprintf(servname, sizeof(servname), "%d", port);
109         status = getaddrinfo(hostname, servname, &hints, &res);
110
111         if (status != 0)
112         {
113                 printf("transport_connect: getaddrinfo (%s)\n", gai_strerror(status));
114                 return False;
115         }
116
117         for (ai = res; ai; ai = ai->ai_next)
118         {
119                 sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
120
121                 if (sockfd < 0)
122                         continue;
123
124                 if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) == 0)
125                 {
126                         printf("connected to %s:%s\n", hostname, servname);
127                         break;
128                 }
129
130                 sockfd = -1;
131         }
132         freeaddrinfo(res);
133
134         if (sockfd == -1)
135         {
136                 printf("unable to connect to %s:%s\n", hostname, servname);
137                 return False;
138         }
139
140         tcp->sockfd = sockfd;
141         tcp_get_ip_address(tcp);
142         tcp_get_mac_address(tcp);
143
144         return True;
145 }
146
147 int tcp_read(rdpTcp* tcp, uint8* data, int length)
148 {
149         int status;
150
151         status = recv(tcp->sockfd, data, length, 0);
152
153         if (status < 0)
154         {
155                 if (errno == EAGAIN || errno == EWOULDBLOCK)
156                         return 0;
157
158                 perror("recv");
159                 return -1;
160         }
161
162         return status;
163 }
164
165 int tcp_write(rdpTcp* tcp, uint8* data, int length)
166 {
167         int status;
168
169         status = send(tcp->sockfd, data, length, MSG_NOSIGNAL);
170
171         if (status < 0)
172         {
173                 if (errno == EAGAIN || errno == EWOULDBLOCK)
174                         status = 0;
175                 else
176                         perror("send");
177         }
178
179         return status;
180 }
181
182 boolean tcp_disconnect(rdpTcp * tcp)
183 {
184         if (tcp->sockfd != -1)
185         {
186                 close(tcp->sockfd);
187                 tcp->sockfd = -1;
188         }
189
190         return True;
191 }
192
193 boolean tcp_set_blocking_mode(rdpTcp* tcp, boolean blocking)
194 {
195         int flags;
196         flags = fcntl(tcp->sockfd, F_GETFL);
197
198         if (flags == -1)
199         {
200                 printf("transport_configure_sockfd: fcntl failed.\n");
201                 return False;
202         }
203
204         if (blocking == True)
205         {
206                 /* blocking */
207                 fcntl(tcp->sockfd, F_SETFL, flags & ~(O_NONBLOCK));
208         }
209         else
210         {
211                 /* non-blocking */
212                 fcntl(tcp->sockfd, F_SETFL, flags | O_NONBLOCK);
213         }
214
215         return True;
216 }
217
218 rdpTcp* tcp_new(rdpSettings* settings)
219 {
220         rdpTcp* tcp = (rdpTcp*) xzalloc(sizeof(rdpTcp));
221
222         if (tcp != NULL)
223         {
224                 tcp->sockfd = -1;
225                 tcp->settings = settings;
226                 tcp->connect = tcp_connect;
227                 tcp->disconnect = tcp_disconnect;
228                 tcp->set_blocking_mode = tcp_set_blocking_mode;
229         }
230
231         return tcp;
232 }
233
234 void tcp_free(rdpTcp* tcp)
235 {
236         if (tcp != NULL)
237         {
238                 xfree(tcp);
239         }
240 }