Mercurial > pidgin.yaz
annotate src/network.c @ 12767:53218d758ba9
[gaim-migrate @ 15114]
Make the dns lookup for udp connecting asynchronous. Thomas pointed out that it should be instantaneous anyway because the SRV lookup that has just been done, but this'll avoid blocking if the SRV lookup failed or something.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Sun, 08 Jan 2006 22:09:28 +0000 |
parents | d5b8f4dc1622 |
children | 8e3b85fe4a55 |
rev | line source |
---|---|
8231 | 1 /** |
2 * @file network.c Network Implementation | |
3 * @ingroup core | |
4 * | |
5 * gaim | |
6 * | |
7 * Gaim is the legal property of its developers, whose names are too numerous | |
8 * to list here. Please refer to the COPYRIGHT file distributed with this | |
9 * source distribution. | |
10 * | |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 */ | |
25 | |
8245
91c6629b1ee8
[gaim-migrate @ 8968]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
8240
diff
changeset
|
26 #include "internal.h" |
8231 | 27 |
28 #include "debug.h" | |
29 #include "account.h" | |
30 #include "network.h" | |
31 #include "prefs.h" | |
11411 | 32 #include "stun.h" |
11195 | 33 #include "upnp.h" |
8231 | 34 |
11391 | 35 |
8838 | 36 const unsigned char * |
37 gaim_network_ip_atoi(const char *ip) | |
38 { | |
39 static unsigned char ret[4]; | |
8981 | 40 gchar *delimiter = "."; |
8838 | 41 gchar **split; |
42 int i; | |
43 | |
44 g_return_val_if_fail(ip != NULL, NULL); | |
45 | |
8981 | 46 split = g_strsplit(ip, delimiter, 4); |
8838 | 47 for (i = 0; split[i] != NULL; i++) |
48 ret[i] = atoi(split[i]); | |
49 g_strfreev(split); | |
50 | |
51 /* i should always be 4 */ | |
52 if (i != 4) | |
53 return NULL; | |
54 | |
55 return ret; | |
56 } | |
57 | |
8231 | 58 void |
8834 | 59 gaim_network_set_public_ip(const char *ip) |
8231 | 60 { |
61 g_return_if_fail(ip != NULL); | |
62 | |
8838 | 63 /* XXX - Ensure the IP address is valid */ |
64 | |
8231 | 65 gaim_prefs_set_string("/core/network/public_ip", ip); |
66 } | |
67 | |
68 const char * | |
8834 | 69 gaim_network_get_public_ip(void) |
8231 | 70 { |
71 const char *ip; | |
12686
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
72 GaimStunNatDiscovery *stun; |
11391 | 73 |
8231 | 74 ip = gaim_prefs_get_string("/core/network/public_ip"); |
75 | |
11411 | 76 if (ip == NULL || *ip == '\0') { |
77 /* Check if STUN discovery was already done */ | |
78 stun = gaim_stun_discover(NULL); | |
12686
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
79 if (stun != NULL && stun->status == GAIM_STUN_STATUS_DISCOVERED) |
11411 | 80 return stun->publicip; |
8231 | 81 return NULL; |
11411 | 82 } |
8231 | 83 |
84 return ip; | |
85 } | |
86 | |
87 static const char * | |
88 gaim_network_get_local_ip_from_fd(int fd) | |
89 { | |
90 struct sockaddr_in addr; | |
91 socklen_t len; | |
92 static char ip[16]; | |
93 const char *tmp; | |
94 | |
8840 | 95 g_return_val_if_fail(fd >= 0, NULL); |
8231 | 96 |
97 len = sizeof(addr); | |
98 if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) { | |
99 gaim_debug_warning("network", "getsockname: %s\n", strerror(errno)); | |
100 return NULL; | |
101 } | |
102 | |
103 tmp = inet_ntoa(addr.sin_addr); | |
104 strncpy(ip, tmp, sizeof(ip)); | |
8838 | 105 |
8231 | 106 return ip; |
107 } | |
108 | |
109 const char * | |
110 gaim_network_get_local_system_ip(int fd) | |
111 { | |
112 struct hostent *host; | |
113 char localhost[129]; | |
114 long unsigned add; | |
115 static char ip[46]; | |
116 const char *tmp = NULL; | |
117 | |
8840 | 118 if (fd >= 0) |
8231 | 119 tmp = gaim_network_get_local_ip_from_fd(fd); |
120 | |
121 if (tmp) | |
122 return tmp; | |
123 | |
124 if (gethostname(localhost, 128) < 0) | |
125 return NULL; | |
126 | |
127 if ((host = gethostbyname(localhost)) == NULL) | |
128 return NULL; | |
129 | |
130 memcpy(&add, host->h_addr_list[0], 4); | |
131 add = htonl(add); | |
132 | |
133 g_snprintf(ip, 16, "%lu.%lu.%lu.%lu", | |
134 ((add >> 24) & 255), | |
135 ((add >> 16) & 255), | |
136 ((add >> 8) & 255), | |
137 add & 255); | |
138 | |
139 return ip; | |
140 } | |
141 | |
142 const char * | |
8838 | 143 gaim_network_get_my_ip(int fd) |
8231 | 144 { |
12686
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
145 const char *ip = NULL; |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
146 GaimUPnPControlInfo* controlInfo = NULL; |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
147 GaimStunNatDiscovery *stun; |
8834 | 148 |
149 /* Check if the user specified an IP manually */ | |
150 if (!gaim_prefs_get_bool("/core/network/auto_ip")) { | |
151 ip = gaim_network_get_public_ip(); | |
152 if (ip != NULL) | |
153 return ip; | |
154 } | |
155 | |
11424 | 156 if (ip == NULL || *ip == '\0') { |
157 /* Check if STUN discovery was already done */ | |
158 stun = gaim_stun_discover(NULL); | |
12686
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
159 if (stun != NULL && stun->status == GAIM_STUN_STATUS_DISCOVERED) |
11424 | 160 return stun->publicip; |
161 } | |
162 | |
163 | |
12686
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
164 /* attempt to get the ip from a NAT device */ |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
165 if ((controlInfo = gaim_upnp_discover()) != NULL) { |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
166 ip = gaim_upnp_get_public_ip(controlInfo); |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
167 |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
168 g_free(controlInfo->controlURL); |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
169 g_free(controlInfo->serviceType); |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
170 g_free(controlInfo); |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
171 |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
172 if (ip != NULL) |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
173 return ip; |
5f65a0cca87c
[gaim-migrate @ 15029]
Richard Laager <rlaager@wiktel.com>
parents:
11424
diff
changeset
|
174 } |
11195 | 175 |
8834 | 176 /* Just fetch the IP of the local system */ |
177 return gaim_network_get_local_system_ip(fd); | |
8231 | 178 } |
179 | |
11391 | 180 |
8834 | 181 static int |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
182 gaim_network_do_listen(unsigned short port, int socket_type) |
8231 | 183 { |
9452 | 184 int listenfd = -1; |
8231 | 185 const int on = 1; |
12728
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
186 GaimUPnPControlInfo* controlInfo = NULL; |
9449 | 187 #if HAVE_GETADDRINFO |
188 int errnum; | |
189 struct addrinfo hints, *res, *next; | |
9456 | 190 char serv[6]; |
8231 | 191 |
9449 | 192 /* |
193 * Get a list of addresses on this machine. | |
194 */ | |
195 snprintf(serv, sizeof(serv), "%hu", port); | |
8231 | 196 memset(&hints, 0, sizeof(struct addrinfo)); |
197 hints.ai_flags = AI_PASSIVE; | |
198 hints.ai_family = AF_UNSPEC; | |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
199 hints.ai_socktype = socket_type; |
9449 | 200 errnum = getaddrinfo(NULL /* any IP */, serv, &hints, &res); |
201 if (errnum != 0) { | |
11221
5ed33bb06a84
[gaim-migrate @ 13353]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11215
diff
changeset
|
202 #ifndef _WIN32 |
9449 | 203 gaim_debug_warning("network", "getaddrinfo: %s\n", gai_strerror(errnum)); |
204 if (errnum == EAI_SYSTEM) | |
205 gaim_debug_warning("network", "getaddrinfo: system error: %s\n", strerror(errno)); | |
11221
5ed33bb06a84
[gaim-migrate @ 13353]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11215
diff
changeset
|
206 #else |
5ed33bb06a84
[gaim-migrate @ 13353]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11215
diff
changeset
|
207 gaim_debug_warning("network", "getaddrinfo: Error Code = %d\n", errnum); |
5ed33bb06a84
[gaim-migrate @ 13353]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11215
diff
changeset
|
208 #endif |
8231 | 209 return -1; |
210 } | |
9449 | 211 |
212 /* | |
213 * Go through the list of addresses and attempt to listen on | |
214 * one of them. | |
215 * XXX - Try IPv6 addresses first? | |
216 */ | |
217 for (next = res; next != NULL; next = next->ai_next) { | |
9455 | 218 listenfd = socket(next->ai_family, next->ai_socktype, next->ai_protocol); |
8231 | 219 if (listenfd < 0) |
220 continue; | |
9449 | 221 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) |
222 gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno)); | |
9455 | 223 if (bind(listenfd, next->ai_addr, next->ai_addrlen) == 0) |
8231 | 224 break; /* success */ |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
225 /* XXX - It is unclear to me (datallah) whether we need to be |
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
226 using a new socket each time */ |
8231 | 227 close(listenfd); |
9449 | 228 } |
8231 | 229 |
9449 | 230 freeaddrinfo(res); |
8231 | 231 |
9449 | 232 if (next == NULL) |
233 return -1; | |
8231 | 234 #else |
235 struct sockaddr_in sockin; | |
236 | |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
237 if ((listenfd = socket(AF_INET, socket_type, 0)) < 0) { |
8231 | 238 gaim_debug_warning("network", "socket: %s\n", strerror(errno)); |
239 return -1; | |
240 } | |
241 | |
9449 | 242 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) |
8231 | 243 gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno)); |
244 | |
245 memset(&sockin, 0, sizeof(struct sockaddr_in)); | |
9449 | 246 sockin.sin_family = PF_INET; |
8251 | 247 sockin.sin_port = htons(port); |
8231 | 248 |
249 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { | |
250 gaim_debug_warning("network", "bind: %s\n", strerror(errno)); | |
251 close(listenfd); | |
252 return -1; | |
253 } | |
254 #endif | |
255 | |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
256 if (socket_type == SOCK_STREAM && listen(listenfd, 4) != 0) { |
8231 | 257 gaim_debug_warning("network", "listen: %s\n", strerror(errno)); |
258 close(listenfd); | |
259 return -1; | |
260 } | |
261 fcntl(listenfd, F_SETFL, O_NONBLOCK); | |
262 | |
12728
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
263 if ((controlInfo = gaim_upnp_discover()) != NULL) { |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
264 char *type_desc = (socket_type == SOCK_STREAM) ? "TCP" : "UDP"; |
12728
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
265 if (!gaim_upnp_set_port_mapping(controlInfo, |
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
266 gaim_network_get_port_from_fd(listenfd), |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
267 type_desc)) { |
12728
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
268 gaim_upnp_remove_port_mapping(controlInfo, |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
269 gaim_network_get_port_from_fd(listenfd), |
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
270 type_desc); |
12728
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
271 gaim_upnp_set_port_mapping(controlInfo, |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
272 gaim_network_get_port_from_fd(listenfd), |
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
273 type_desc); |
11391 | 274 |
12728
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
275 } |
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
276 g_free(controlInfo->serviceType); |
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
277 g_free(controlInfo->controlURL); |
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
278 g_free(controlInfo); |
fb3b7466e3d2
[gaim-migrate @ 15072]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12686
diff
changeset
|
279 } |
11195 | 280 |
8231 | 281 gaim_debug_info("network", "Listening on port: %hu\n", gaim_network_get_port_from_fd(listenfd)); |
282 return listenfd; | |
283 } | |
284 | |
8834 | 285 int |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
286 gaim_network_listen(unsigned short port, int socket_type) |
8246 | 287 { |
8250 | 288 g_return_val_if_fail(port != 0, -1); |
289 | |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
290 return gaim_network_do_listen(port, socket_type); |
8246 | 291 } |
292 | |
8834 | 293 int |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
294 gaim_network_listen_range(unsigned short start, unsigned short end, |
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
295 int socket_type) |
8231 | 296 { |
8240 | 297 int ret = -1; |
8231 | 298 |
8250 | 299 if (gaim_prefs_get_bool("/core/network/ports_range_use")) { |
8239 | 300 start = gaim_prefs_get_int("/core/network/ports_range_start"); |
301 end = gaim_prefs_get_int("/core/network/ports_range_end"); | |
8250 | 302 } else { |
303 if (end < start) | |
304 end = start; | |
8239 | 305 } |
8231 | 306 |
307 for (; start <= end; start++) { | |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12728
diff
changeset
|
308 ret = gaim_network_do_listen(start, socket_type); |
8231 | 309 if (ret >= 0) |
310 break; | |
311 } | |
312 | |
313 return ret; | |
314 } | |
315 | |
8834 | 316 unsigned short |
317 gaim_network_get_port_from_fd(int fd) | |
8231 | 318 { |
319 struct sockaddr_in addr; | |
320 socklen_t len; | |
321 | |
9449 | 322 g_return_val_if_fail(fd >= 0, 0); |
8231 | 323 |
324 len = sizeof(addr); | |
325 if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) { | |
326 gaim_debug_warning("network", "getsockname: %s\n", strerror(errno)); | |
327 return 0; | |
328 } | |
329 | |
330 return ntohs(addr.sin_port); | |
331 } | |
332 | |
333 void | |
334 gaim_network_init(void) | |
335 { | |
336 gaim_prefs_add_none ("/core/network"); | |
337 gaim_prefs_add_bool ("/core/network/auto_ip", TRUE); | |
338 gaim_prefs_add_string("/core/network/public_ip", ""); | |
339 gaim_prefs_add_bool ("/core/network/ports_range_use", FALSE); | |
340 gaim_prefs_add_int ("/core/network/ports_range_start", 1024); | |
341 gaim_prefs_add_int ("/core/network/ports_range_end", 2048); | |
342 } |