Mercurial > pidgin
annotate libgaim/network.c @ 14780:ec9cc2219e55
[gaim-migrate @ 17544]
Robustify the wingaim network managers stuff.
Apparently if people disable certain windows services the networks lookup fails and the "wait for changes" function returns immediately.
This will make wingaim not go ape when this is the case.
committer: Tailor Script <tailor@pidgin.im>
| author | Daniel Atallah <daniel.atallah@gmail.com> |
|---|---|
| date | Thu, 19 Oct 2006 03:23:01 +0000 |
| parents | 182f77347680 |
| children | 2727e465602f |
| rev | line source |
|---|---|
| 14192 | 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 | |
| 26 #include "internal.h" | |
| 27 | |
| 28 #ifndef _WIN32 | |
| 29 #include <net/if.h> | |
| 30 #include <sys/ioctl.h> | |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
31 #else |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
32 #include <nspapi.h> |
| 14192 | 33 #endif |
| 34 | |
| 35 /* Solaris */ | |
| 36 #if defined (__SVR4) && defined (__sun) | |
| 37 #include <sys/sockio.h> | |
| 38 #endif | |
| 39 | |
| 40 #include "debug.h" | |
| 41 #include "account.h" | |
| 42 #include "network.h" | |
| 43 #include "prefs.h" | |
| 44 #include "stun.h" | |
| 45 #include "upnp.h" | |
| 46 | |
| 14696 | 47 #ifdef HAVE_LIBNM |
| 48 #include <libnm_glib.h> | |
| 49 | |
| 50 libnm_glib_ctx *nm_context = NULL; | |
| 51 guint nm_callback_idx = 0; | |
| 52 | |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
53 #elif defined _WIN32 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
54 static int current_network_count; |
| 14696 | 55 #endif |
| 56 | |
| 14267 | 57 struct _GaimNetworkListenData { |
| 14192 | 58 int listenfd; |
| 59 int socket_type; | |
| 60 gboolean retry; | |
| 61 gboolean adding; | |
| 62 GaimNetworkListenCallback cb; | |
| 63 gpointer cb_data; | |
| 14267 | 64 }; |
| 14192 | 65 |
| 14696 | 66 #ifdef HAVE_LIBNM |
| 67 void nm_callback_func(libnm_glib_ctx* ctx, gpointer user_data); | |
| 68 #endif | |
| 69 | |
| 14192 | 70 const unsigned char * |
| 71 gaim_network_ip_atoi(const char *ip) | |
| 72 { | |
| 73 static unsigned char ret[4]; | |
| 74 gchar *delimiter = "."; | |
| 75 gchar **split; | |
| 76 int i; | |
| 77 | |
| 78 g_return_val_if_fail(ip != NULL, NULL); | |
| 79 | |
| 80 split = g_strsplit(ip, delimiter, 4); | |
| 81 for (i = 0; split[i] != NULL; i++) | |
| 82 ret[i] = atoi(split[i]); | |
| 83 g_strfreev(split); | |
| 84 | |
| 85 /* i should always be 4 */ | |
| 86 if (i != 4) | |
| 87 return NULL; | |
| 88 | |
| 89 return ret; | |
| 90 } | |
| 91 | |
| 92 void | |
| 93 gaim_network_set_public_ip(const char *ip) | |
| 94 { | |
| 95 g_return_if_fail(ip != NULL); | |
| 96 | |
| 97 /* XXX - Ensure the IP address is valid */ | |
| 98 | |
| 99 gaim_prefs_set_string("/core/network/public_ip", ip); | |
| 100 } | |
| 101 | |
| 102 const char * | |
| 103 gaim_network_get_public_ip(void) | |
| 104 { | |
| 105 return gaim_prefs_get_string("/core/network/public_ip"); | |
| 106 } | |
| 107 | |
| 108 const char * | |
| 109 gaim_network_get_local_system_ip(int fd) | |
| 110 { | |
| 111 char buffer[1024]; | |
| 112 static char ip[16]; | |
| 113 char *tmp; | |
| 114 struct ifconf ifc; | |
| 115 struct ifreq *ifr; | |
| 116 struct sockaddr_in *sinptr; | |
| 117 guint32 lhost = htonl(127 * 256 * 256 * 256 + 1); | |
| 118 long unsigned int add; | |
| 119 int source = fd; | |
| 120 | |
| 121 if (fd < 0) | |
| 122 source = socket(PF_INET,SOCK_STREAM, 0); | |
| 123 | |
| 124 ifc.ifc_len = sizeof(buffer); | |
| 125 ifc.ifc_req = (struct ifreq *)buffer; | |
| 126 ioctl(source, SIOCGIFCONF, &ifc); | |
| 127 | |
| 128 if (fd < 0) | |
| 129 close(source); | |
| 130 | |
| 131 tmp = buffer; | |
| 132 while (tmp < buffer + ifc.ifc_len) | |
| 133 { | |
| 134 ifr = (struct ifreq *)tmp; | |
| 135 tmp += sizeof(struct ifreq); | |
| 136 | |
| 137 if (ifr->ifr_addr.sa_family == AF_INET) | |
| 138 { | |
| 139 sinptr = (struct sockaddr_in *)&ifr->ifr_addr; | |
| 140 if (sinptr->sin_addr.s_addr != lhost) | |
| 141 { | |
| 142 add = ntohl(sinptr->sin_addr.s_addr); | |
| 143 g_snprintf(ip, 16, "%lu.%lu.%lu.%lu", | |
| 144 ((add >> 24) & 255), | |
| 145 ((add >> 16) & 255), | |
| 146 ((add >> 8) & 255), | |
| 147 add & 255); | |
| 148 | |
| 149 return ip; | |
| 150 } | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 return "0.0.0.0"; | |
| 155 } | |
| 156 | |
| 157 const char * | |
| 158 gaim_network_get_my_ip(int fd) | |
| 159 { | |
| 160 const char *ip = NULL; | |
| 161 GaimStunNatDiscovery *stun; | |
| 162 | |
| 163 /* Check if the user specified an IP manually */ | |
| 164 if (!gaim_prefs_get_bool("/core/network/auto_ip")) { | |
| 165 ip = gaim_network_get_public_ip(); | |
| 166 if ((ip != NULL) && (*ip != '\0')) | |
| 167 return ip; | |
| 168 } | |
| 169 | |
| 170 /* Check if STUN discovery was already done */ | |
| 171 stun = gaim_stun_discover(NULL); | |
| 172 if ((stun != NULL) && (stun->status == GAIM_STUN_STATUS_DISCOVERED)) | |
| 173 return stun->publicip; | |
| 174 | |
| 175 /* Attempt to get the IP from a NAT device using UPnP */ | |
| 176 ip = gaim_upnp_get_public_ip(); | |
| 177 if (ip != NULL) | |
| 178 return ip; | |
| 179 | |
| 180 /* Just fetch the IP of the local system */ | |
| 181 return gaim_network_get_local_system_ip(fd); | |
| 182 } | |
| 183 | |
| 184 | |
| 185 static void | |
| 186 gaim_network_set_upnp_port_mapping_cb(gboolean success, gpointer data) | |
| 187 { | |
| 14267 | 188 GaimNetworkListenData *listen_data; |
| 189 | |
| 190 listen_data = data; | |
| 191 /* TODO: Once we're keeping track of upnp requests... */ | |
| 192 /* listen_data->pnp_data = NULL; */ | |
| 14192 | 193 |
| 194 if (!success) { | |
| 195 gaim_debug_info("network", "Couldn't create UPnP mapping\n"); | |
| 14267 | 196 if (listen_data->retry) { |
| 197 listen_data->retry = FALSE; | |
| 198 listen_data->adding = FALSE; | |
| 199 /* TODO: Need to keep track of this return value! */ | |
| 14192 | 200 gaim_upnp_remove_port_mapping( |
| 14267 | 201 gaim_network_get_port_from_fd(listen_data->listenfd), |
| 202 (listen_data->socket_type == SOCK_STREAM) ? "TCP" : "UDP", | |
| 203 gaim_network_set_upnp_port_mapping_cb, listen_data); | |
| 14192 | 204 return; |
| 205 } | |
| 14267 | 206 } else if (!listen_data->adding) { |
| 14192 | 207 /* We've tried successfully to remove the port mapping. |
| 208 * Try to add it again */ | |
| 14267 | 209 listen_data->adding = TRUE; |
| 210 /* TODO: Need to keep track of this return value! */ | |
| 14192 | 211 gaim_upnp_set_port_mapping( |
| 14267 | 212 gaim_network_get_port_from_fd(listen_data->listenfd), |
| 213 (listen_data->socket_type == SOCK_STREAM) ? "TCP" : "UDP", | |
| 214 gaim_network_set_upnp_port_mapping_cb, listen_data); | |
| 14192 | 215 return; |
| 216 } | |
| 217 | |
| 14267 | 218 if (listen_data->cb) |
| 219 listen_data->cb(listen_data->listenfd, listen_data->cb_data); | |
| 14192 | 220 |
| 14267 | 221 gaim_network_listen_cancel(listen_data); |
| 14192 | 222 } |
| 223 | |
| 224 | |
| 14267 | 225 static GaimNetworkListenData * |
| 14192 | 226 gaim_network_do_listen(unsigned short port, int socket_type, GaimNetworkListenCallback cb, gpointer cb_data) |
| 227 { | |
| 228 int listenfd = -1; | |
| 229 const int on = 1; | |
| 14267 | 230 GaimNetworkListenData *listen_data; |
| 14192 | 231 #ifdef HAVE_GETADDRINFO |
| 232 int errnum; | |
| 233 struct addrinfo hints, *res, *next; | |
| 234 char serv[6]; | |
| 235 | |
| 236 /* | |
| 237 * Get a list of addresses on this machine. | |
| 238 */ | |
| 239 snprintf(serv, sizeof(serv), "%hu", port); | |
| 240 memset(&hints, 0, sizeof(struct addrinfo)); | |
| 241 hints.ai_flags = AI_PASSIVE; | |
| 242 hints.ai_family = AF_UNSPEC; | |
| 243 hints.ai_socktype = socket_type; | |
| 244 errnum = getaddrinfo(NULL /* any IP */, serv, &hints, &res); | |
| 245 if (errnum != 0) { | |
| 246 #ifndef _WIN32 | |
| 247 gaim_debug_warning("network", "getaddrinfo: %s\n", gai_strerror(errnum)); | |
| 248 if (errnum == EAI_SYSTEM) | |
| 249 gaim_debug_warning("network", "getaddrinfo: system error: %s\n", strerror(errno)); | |
| 250 #else | |
| 251 gaim_debug_warning("network", "getaddrinfo: Error Code = %d\n", errnum); | |
| 252 #endif | |
| 14267 | 253 return NULL; |
| 14192 | 254 } |
| 255 | |
| 256 /* | |
| 257 * Go through the list of addresses and attempt to listen on | |
| 258 * one of them. | |
| 259 * XXX - Try IPv6 addresses first? | |
| 260 */ | |
| 261 for (next = res; next != NULL; next = next->ai_next) { | |
| 262 listenfd = socket(next->ai_family, next->ai_socktype, next->ai_protocol); | |
| 263 if (listenfd < 0) | |
| 264 continue; | |
| 265 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) | |
| 266 gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno)); | |
| 267 if (bind(listenfd, next->ai_addr, next->ai_addrlen) == 0) | |
| 268 break; /* success */ | |
| 269 /* XXX - It is unclear to me (datallah) whether we need to be | |
| 270 using a new socket each time */ | |
| 271 close(listenfd); | |
| 272 } | |
| 273 | |
| 274 freeaddrinfo(res); | |
| 275 | |
| 276 if (next == NULL) | |
| 14267 | 277 return NULL; |
| 14192 | 278 #else |
| 279 struct sockaddr_in sockin; | |
| 280 | |
| 281 if ((listenfd = socket(AF_INET, socket_type, 0)) < 0) { | |
| 282 gaim_debug_warning("network", "socket: %s\n", strerror(errno)); | |
| 14267 | 283 return NULL; |
| 14192 | 284 } |
| 285 | |
| 286 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) | |
| 287 gaim_debug_warning("network", "setsockopt: %s\n", strerror(errno)); | |
| 288 | |
| 289 memset(&sockin, 0, sizeof(struct sockaddr_in)); | |
| 290 sockin.sin_family = PF_INET; | |
| 291 sockin.sin_port = htons(port); | |
| 292 | |
| 293 if (bind(listenfd, (struct sockaddr *)&sockin, sizeof(struct sockaddr_in)) != 0) { | |
| 294 gaim_debug_warning("network", "bind: %s\n", strerror(errno)); | |
| 295 close(listenfd); | |
| 14267 | 296 return NULL; |
| 14192 | 297 } |
| 298 #endif | |
| 299 | |
| 300 if (socket_type == SOCK_STREAM && listen(listenfd, 4) != 0) { | |
| 301 gaim_debug_warning("network", "listen: %s\n", strerror(errno)); | |
| 302 close(listenfd); | |
| 14267 | 303 return NULL; |
| 14192 | 304 } |
| 305 fcntl(listenfd, F_SETFL, O_NONBLOCK); | |
| 306 | |
| 307 gaim_debug_info("network", "Listening on port: %hu\n", gaim_network_get_port_from_fd(listenfd)); | |
| 308 | |
| 14267 | 309 listen_data = g_new0(GaimNetworkListenData, 1); |
| 310 listen_data->listenfd = listenfd; | |
| 311 listen_data->adding = TRUE; | |
| 312 listen_data->retry = TRUE; | |
| 313 listen_data->cb = cb; | |
| 314 listen_data->cb_data = cb_data; | |
| 14192 | 315 |
| 14267 | 316 /* TODO: Need to keep track of this return value! */ |
| 14192 | 317 gaim_upnp_set_port_mapping( |
| 318 gaim_network_get_port_from_fd(listenfd), | |
| 319 (socket_type == SOCK_STREAM) ? "TCP" : "UDP", | |
| 14267 | 320 gaim_network_set_upnp_port_mapping_cb, listen_data); |
| 14192 | 321 |
| 14267 | 322 return listen_data; |
| 14192 | 323 } |
| 324 | |
| 14267 | 325 GaimNetworkListenData * |
| 14192 | 326 gaim_network_listen(unsigned short port, int socket_type, |
| 327 GaimNetworkListenCallback cb, gpointer cb_data) | |
| 328 { | |
| 14267 | 329 g_return_val_if_fail(port != 0, NULL); |
| 14192 | 330 |
| 331 return gaim_network_do_listen(port, socket_type, cb, cb_data); | |
| 332 } | |
| 333 | |
| 14267 | 334 GaimNetworkListenData * |
| 14192 | 335 gaim_network_listen_range(unsigned short start, unsigned short end, |
| 336 int socket_type, GaimNetworkListenCallback cb, gpointer cb_data) | |
| 337 { | |
| 14267 | 338 GaimNetworkListenData *ret = NULL; |
| 14192 | 339 |
| 340 if (gaim_prefs_get_bool("/core/network/ports_range_use")) { | |
| 341 start = gaim_prefs_get_int("/core/network/ports_range_start"); | |
| 342 end = gaim_prefs_get_int("/core/network/ports_range_end"); | |
| 343 } else { | |
| 344 if (end < start) | |
| 345 end = start; | |
| 346 } | |
| 347 | |
| 348 for (; start <= end; start++) { | |
| 349 ret = gaim_network_do_listen(start, socket_type, cb, cb_data); | |
| 14267 | 350 if (ret != NULL) |
| 14192 | 351 break; |
| 352 } | |
| 353 | |
| 354 return ret; | |
| 355 } | |
| 356 | |
| 14267 | 357 void gaim_network_listen_cancel(GaimNetworkListenData *listen_data) |
| 358 { | |
| 359 g_free(listen_data); | |
| 360 } | |
| 361 | |
| 14192 | 362 unsigned short |
| 363 gaim_network_get_port_from_fd(int fd) | |
| 364 { | |
| 365 struct sockaddr_in addr; | |
| 366 socklen_t len; | |
| 367 | |
| 368 g_return_val_if_fail(fd >= 0, 0); | |
| 369 | |
| 370 len = sizeof(addr); | |
| 371 if (getsockname(fd, (struct sockaddr *) &addr, &len) == -1) { | |
| 372 gaim_debug_warning("network", "getsockname: %s\n", strerror(errno)); | |
| 373 return 0; | |
| 374 } | |
| 375 | |
| 376 return ntohs(addr.sin_port); | |
| 377 } | |
| 378 | |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
379 #ifdef _WIN32 |
|
14780
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
380 static gint |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
381 wgaim_get_connected_network_count(void) |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
382 { |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
383 guint net_cnt = 0; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
384 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
385 WSAQUERYSET qs; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
386 HANDLE h; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
387 int retval; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
388 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
389 memset(&qs, 0, sizeof(WSAQUERYSET)); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
390 qs.dwSize = sizeof(WSAQUERYSET); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
391 qs.dwNameSpace = NS_ALL; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
392 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
393 retval = WSALookupServiceBegin(&qs, LUP_RETURN_ALL, &h); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
394 if (retval != ERROR_SUCCESS) { |
|
14776
a87c53e7b1e2
[gaim-migrate @ 17540]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14722
diff
changeset
|
395 int errorid = WSAGetLastError(); |
|
a87c53e7b1e2
[gaim-migrate @ 17540]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14722
diff
changeset
|
396 gchar *msg = g_win32_error_message(errorid); |
|
a87c53e7b1e2
[gaim-migrate @ 17540]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14722
diff
changeset
|
397 gaim_debug_warning("network", "Couldn't look up connected networks. %s (%d).\n", msg, errorid); |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
398 g_free(msg); |
|
14776
a87c53e7b1e2
[gaim-migrate @ 17540]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14722
diff
changeset
|
399 |
|
14780
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
400 return -1; |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
401 } else { |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
402 char buf[1024]; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
403 WSAQUERYSET *res = (LPWSAQUERYSET) buf; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
404 DWORD size = sizeof(buf); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
405 while (WSALookupServiceNext(h, 0, &size, res) == ERROR_SUCCESS) { |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
406 net_cnt++; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
407 gaim_debug_info("network", "found network '%s'\n", |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
408 res->lpszServiceInstanceName ? res->lpszServiceInstanceName : "(NULL)"); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
409 size = sizeof(buf); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
410 } |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
411 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
412 WSALookupServiceEnd(h); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
413 } |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
414 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
415 return net_cnt; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
416 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
417 } |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
418 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
419 static gboolean wgaim_network_change_thread_cb(gpointer data) |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
420 { |
|
14780
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
421 gint new_count; |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
422 GaimConnectionUiOps *ui_ops = gaim_connections_get_ui_ops(); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
423 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
424 new_count = wgaim_get_connected_network_count(); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
425 |
|
14780
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
426 if (new_count < 0) |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
427 return FALSE; |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
428 |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
429 gaim_debug_info("network", "Received Network Change Notification. Current network count is %d, previous count was %d.\n", new_count, current_network_count); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
430 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
431 if (new_count > 0) { |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
432 ui_ops->network_connected(); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
433 } else if (new_count == 0 && current_network_count > 0) { |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
434 ui_ops->network_disconnected(); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
435 } |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
436 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
437 current_network_count = new_count; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
438 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
439 return FALSE; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
440 } |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
441 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
442 static gpointer wgaim_network_change_thread(gpointer data) |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
443 { |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
444 HANDLE h; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
445 WSAQUERYSET qs; |
|
14780
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
446 time_t last_trigger = time(NULL); |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
447 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
448 int WSAAPI (*MyWSANSPIoctl) ( |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
449 HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer, |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
450 DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
451 LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion) = NULL; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
452 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
453 MyWSANSPIoctl = (void*) wgaim_find_and_loadproc("ws2_32.dll", "WSANSPIoctl"); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
454 if (!MyWSANSPIoctl) { |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
455 gaim_debug_error("network", "Couldn't load WSANSPIoctl from ws2_32.dll.\n"); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
456 g_thread_exit(NULL); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
457 return NULL; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
458 } |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
459 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
460 while (TRUE) { |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
461 int retval; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
462 DWORD retLen = 0; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
463 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
464 memset(&qs, 0, sizeof(WSAQUERYSET)); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
465 qs.dwSize = sizeof(WSAQUERYSET); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
466 qs.dwNameSpace = NS_ALL; |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
467 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
468 retval = WSALookupServiceBegin(&qs, LUP_RETURN_ALL, &h); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
469 |
|
14780
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
470 /* Make sure at least 30 seconds have elapsed since the last |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
471 * notification so we don't peg the cpu if this keeps changing. */ |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
472 if ((time(NULL) - last_trigger) < 30) |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
473 Sleep(30000); |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
474 |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
475 last_trigger = time(NULL); |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
476 |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
477 /* This will block until there is a network change */ |
|
14776
a87c53e7b1e2
[gaim-migrate @ 17540]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14722
diff
changeset
|
478 retval = MyWSANSPIoctl(h, SIO_NSP_NOTIFY_CHANGE, NULL, 0, NULL, 0, &retLen, NULL); |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
479 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
480 retval = WSALookupServiceEnd(h); |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
481 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
482 g_idle_add(wgaim_network_change_thread_cb, NULL); |
|
14780
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
483 |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
484 } |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
485 } |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
486 #endif |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
487 |
| 14696 | 488 gboolean |
| 489 gaim_network_is_available(void) | |
| 490 { | |
| 491 #ifdef HAVE_LIBNM | |
| 492 /* Try NetworkManager first, maybe we'll get lucky */ | |
| 493 int libnm_retval = -1; | |
| 494 | |
| 495 if (nm_context) | |
| 496 { | |
| 497 if ((libnm_retval = libnm_glib_get_network_state(nm_context)) == LIBNM_NO_NETWORK_CONNECTION) | |
| 498 { | |
| 499 gaim_debug_warning("network", "NetworkManager not active or reports no connection (retval = %i)\n", libnm_retval); | |
| 500 return FALSE; | |
| 501 } | |
| 502 if (libnm_retval == LIBNM_ACTIVE_NETWORK_CONNECTION) return TRUE; | |
| 503 } | |
|
14777
182f77347680
[gaim-migrate @ 17541]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14776
diff
changeset
|
504 #elif defined _WIN32 |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
505 return (current_network_count > 0); |
| 14696 | 506 #endif |
| 507 return TRUE; | |
| 508 } | |
| 509 | |
| 510 #ifdef HAVE_LIBNM | |
| 511 void | |
| 512 nm_callback_func(libnm_glib_ctx* ctx, gpointer user_data) | |
| 513 { | |
| 514 GList *l; | |
| 515 GaimAccount *account; | |
| 516 static libnm_glib_state prev = LIBNM_NO_DBUS; | |
| 517 libnm_glib_state current; | |
| 518 GaimConnectionUiOps *ui_ops = gaim_connections_get_ui_ops(); | |
| 519 | |
| 520 current = libnm_glib_get_network_state(ctx); | |
| 521 gaim_debug_info("network","Entering nm_callback_func!\n"); | |
| 522 | |
| 523 switch(current) | |
| 524 { | |
| 525 case LIBNM_ACTIVE_NETWORK_CONNECTION: | |
| 526 ui_ops->network_connected(); | |
| 527 prev = current; | |
| 528 break; | |
| 529 case LIBNM_NO_NETWORK_CONNECTION: | |
| 530 if (prev != LIBNM_ACTIVE_NETWORK_CONNECTION) | |
| 531 break; | |
| 532 ui_ops->network_disconnected(); | |
| 533 prev = current; | |
| 534 break; | |
| 535 case LIBNM_NO_DBUS: | |
| 536 case LIBNM_NO_NETWORKMANAGER: | |
| 537 case LIBNM_INVALID_CONTEXT: | |
| 538 default: | |
| 539 break; | |
| 540 } | |
| 541 } | |
| 542 #endif | |
| 543 | |
| 14192 | 544 void |
| 545 gaim_network_init(void) | |
| 546 { | |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
547 #ifdef _WIN32 |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
548 GError *err = NULL; |
|
14780
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
549 gint cnt = wgaim_get_connected_network_count(); |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
550 |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
551 if (cnt < 0) /* Assume there is a network */ |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
552 current_network_count = 1; |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
553 /* Don't listen for network changes if we can't tell anyway */ |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
554 else |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
555 { |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
556 current_network_count = cnt; |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
557 if (!g_thread_create(wgaim_network_change_thread, NULL, FALSE, &err)) |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
558 gaim_debug_error("network", "Couldn't create Network Monitor thread: %s\n", err ? err->message : ""); |
|
ec9cc2219e55
[gaim-migrate @ 17544]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14777
diff
changeset
|
559 } |
|
14722
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
560 #endif |
|
51685370de57
[gaim-migrate @ 17476]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14696
diff
changeset
|
561 |
| 14192 | 562 gaim_prefs_add_none ("/core/network"); |
| 563 gaim_prefs_add_bool ("/core/network/auto_ip", TRUE); | |
| 564 gaim_prefs_add_string("/core/network/public_ip", ""); | |
| 565 gaim_prefs_add_bool ("/core/network/ports_range_use", FALSE); | |
| 566 gaim_prefs_add_int ("/core/network/ports_range_start", 1024); | |
| 567 gaim_prefs_add_int ("/core/network/ports_range_end", 2048); | |
| 568 | |
| 569 gaim_upnp_discover(NULL, NULL); | |
| 14696 | 570 |
| 571 #ifdef HAVE_LIBNM | |
| 572 nm_context = libnm_glib_init(); | |
| 573 if(nm_context) | |
| 574 nm_callback_idx = libnm_glib_register_callback(nm_context, nm_callback_func, NULL, g_main_context_default()); | |
| 575 #endif | |
| 14192 | 576 } |
| 14696 | 577 |
| 578 void | |
| 579 gaim_network_uninit(void) | |
| 580 { | |
| 581 #ifdef HAVE_LIBNM | |
| 582 /* FIXME: If anyone can think of a more clever way to shut down libnm without | |
| 583 * using a global variable + this function, please do. */ | |
| 584 if(nm_context && nm_callback_idx) | |
| 585 libnm_glib_unregister_callback(nm_context, nm_callback_idx); | |
| 586 | |
| 587 if(nm_context) | |
| 588 libnm_glib_shutdown(nm_context); | |
| 589 #endif | |
| 590 } |
