libpurple/network.c

branch
next.minor
changeset 25855
f2aac5656e7d
parent 24999
84d597b7e7c6
parent 25326
c4f4b222dbac
child 25911
f22097dc8413
equal deleted inserted replaced
25854:56a02cb817d9 25855:f2aac5656e7d
69 static NMState nm_state = NM_STATE_UNKNOWN; 69 static NMState nm_state = NM_STATE_UNKNOWN;
70 static gboolean have_nm_state = FALSE; 70 static gboolean have_nm_state = FALSE;
71 71
72 #elif defined _WIN32 72 #elif defined _WIN32
73 static int current_network_count; 73 static int current_network_count;
74
75 /* Mutex for the other global vars */
76 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
77 static gboolean network_initialized;
78 static HANDLE network_change_handle;
74 #endif 79 #endif
75 80
76 struct _PurpleNetworkListenData { 81 struct _PurpleNetworkListenData {
77 int listenfd; 82 int listenfd;
78 int socket_type; 83 int socket_type;
537 return FALSE; 542 return FALSE;
538 } 543 }
539 544
540 static gpointer wpurple_network_change_thread(gpointer data) 545 static gpointer wpurple_network_change_thread(gpointer data)
541 { 546 {
542 HANDLE h;
543 WSAQUERYSET qs; 547 WSAQUERYSET qs;
548 WSAEVENT *nla_event;
544 time_t last_trigger = time(NULL); 549 time_t last_trigger = time(NULL);
545 550
546 int (WSAAPI *MyWSANSPIoctl) ( 551 int (WSAAPI *MyWSANSPIoctl) (
547 HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer, 552 HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer,
548 DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, 553 DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
551 if (!(MyWSANSPIoctl = (void*) wpurple_find_and_loadproc("ws2_32.dll", "WSANSPIoctl"))) { 556 if (!(MyWSANSPIoctl = (void*) wpurple_find_and_loadproc("ws2_32.dll", "WSANSPIoctl"))) {
552 g_thread_exit(NULL); 557 g_thread_exit(NULL);
553 return NULL; 558 return NULL;
554 } 559 }
555 560
561 if ((nla_event = WSACreateEvent()) == WSA_INVALID_EVENT) {
562 int errorid = WSAGetLastError();
563 gchar *msg = g_win32_error_message(errorid);
564 purple_debug_warning("network", "Couldn't create WSA event. "
565 "Message: %s (%d).\n", msg, errorid);
566 g_free(msg);
567 g_thread_exit(NULL);
568 return NULL;
569 }
570
556 while (TRUE) { 571 while (TRUE) {
557 int retval; 572 int retval;
558 DWORD retLen = 0; 573 DWORD retLen = 0;
574 WSACOMPLETION completion;
575 WSAOVERLAPPED overlapped;
576
577 g_static_mutex_lock(&mutex);
578 if (network_initialized == FALSE) {
579 /* purple_network_uninit has been called */
580 WSACloseEvent(nla_event);
581 g_static_mutex_unlock(&mutex);
582 g_thread_exit(NULL);
583 return NULL;
584 }
559 585
560 memset(&qs, 0, sizeof(WSAQUERYSET)); 586 memset(&qs, 0, sizeof(WSAQUERYSET));
561 qs.dwSize = sizeof(WSAQUERYSET); 587 qs.dwSize = sizeof(WSAQUERYSET);
562 qs.dwNameSpace = NS_NLA; 588 qs.dwNameSpace = NS_NLA;
563 if (WSALookupServiceBegin(&qs, 0, &h) == SOCKET_ERROR) { 589 if (WSALookupServiceBegin(&qs, 0, &network_change_handle) == SOCKET_ERROR) {
564 int errorid = WSAGetLastError(); 590 int errorid = WSAGetLastError();
565 gchar *msg = g_win32_error_message(errorid); 591 gchar *msg = g_win32_error_message(errorid);
566 purple_debug_warning("network", "Couldn't retrieve NLA SP lookup handle. " 592 purple_debug_warning("network", "Couldn't retrieve NLA SP lookup handle. "
567 "NLA service is probably not running. Message: %s (%d).\n", 593 "NLA service is probably not running. Message: %s (%d).\n",
568 msg, errorid); 594 msg, errorid);
569 g_free(msg); 595 g_free(msg);
596 WSACloseEvent(nla_event);
597 g_static_mutex_unlock(&mutex);
570 g_thread_exit(NULL); 598 g_thread_exit(NULL);
571 return NULL; 599 return NULL;
572 } 600 }
601 g_static_mutex_unlock(&mutex);
573 602
574 /* Make sure at least 30 seconds have elapsed since the last 603 /* Make sure at least 30 seconds have elapsed since the last
575 * notification so we don't peg the cpu if this keeps changing. */ 604 * notification so we don't peg the cpu if this keeps changing. */
576 if ((time(NULL) - last_trigger) < 30) 605 if ((time(NULL) - last_trigger) < 30)
577 Sleep(30000); 606 Sleep(30000);
578 607
579 last_trigger = time(NULL); 608 last_trigger = time(NULL);
580 609
581 /* This will block until there is a network change */ 610 memset(&completion, 0, sizeof(WSACOMPLETION));
582 if (MyWSANSPIoctl(h, SIO_NSP_NOTIFY_CHANGE, NULL, 0, NULL, 0, &retLen, NULL) == SOCKET_ERROR) { 611 completion.Type = NSP_NOTIFY_EVENT;
612 overlapped.hEvent = nla_event;
613 completion.Parameters.Event.lpOverlapped = &overlapped;
614
615 if (MyWSANSPIoctl(network_change_handle, SIO_NSP_NOTIFY_CHANGE, NULL, 0, NULL, 0, &retLen, &completion) == SOCKET_ERROR) {
583 int errorid = WSAGetLastError(); 616 int errorid = WSAGetLastError();
584 gchar *msg = g_win32_error_message(errorid); 617 /* WSA_IO_PENDING indicates successful async notification will happen */
585 purple_debug_warning("network", "Unable to wait for changes. Message: %s (%d).\n", 618 if (errorid != WSA_IO_PENDING) {
586 msg, errorid); 619 gchar *msg = g_win32_error_message(errorid);
587 g_free(msg); 620 purple_debug_warning("network", "Unable to wait for changes. Message: %s (%d).\n",
588 } 621 msg, errorid);
589 622 g_free(msg);
590 retval = WSALookupServiceEnd(h); 623 }
624 }
625
626 /* This will block until NLA notifies us */
627 retval = WaitForSingleObjectEx(nla_event, WSA_INFINITE, TRUE);
628
629 g_static_mutex_lock(&mutex);
630 if (network_initialized == FALSE) {
631 /* Time to die */
632 WSACloseEvent(nla_event);
633 g_static_mutex_unlock(&mutex);
634 g_thread_exit(NULL);
635 return NULL;
636 }
637
638 retval = WSALookupServiceEnd(network_change_handle);
639 network_change_handle = NULL;
640 WSAResetEvent(nla_event);
641 g_static_mutex_unlock(&mutex);
591 642
592 purple_timeout_add(0, wpurple_network_change_thread_cb, NULL); 643 purple_timeout_add(0, wpurple_network_change_thread_cb, NULL);
593
594 } 644 }
595 645
596 g_thread_exit(NULL); 646 g_thread_exit(NULL);
597 return NULL; 647 return NULL;
598 } 648 }
727 #endif 777 #endif
728 #ifdef _WIN32 778 #ifdef _WIN32
729 GError *err = NULL; 779 GError *err = NULL;
730 gint cnt = wpurple_get_connected_network_count(); 780 gint cnt = wpurple_get_connected_network_count();
731 781
782 network_initialized = TRUE;
732 if (cnt < 0) /* Assume there is a network */ 783 if (cnt < 0) /* Assume there is a network */
733 current_network_count = 1; 784 current_network_count = 1;
734 /* Don't listen for network changes if we can't tell anyway */ 785 /* Don't listen for network changes if we can't tell anyway */
735 else 786 else
736 { 787 {
795 } 846 }
796 if (nm_conn) 847 if (nm_conn)
797 dbus_g_connection_unref(nm_conn); 848 dbus_g_connection_unref(nm_conn);
798 #endif 849 #endif
799 850
851 #ifdef _WIN32
852 g_static_mutex_lock(&mutex);
853 network_initialized = FALSE;
854 if (network_change_handle != NULL) {
855 int retval;
856 /* Trigger the NLA thread to stop waiting for network changes. Not
857 * doing this can cause hangs on WSACleanup. */
858 purple_debug_warning("network", "Terminating the NLA thread\n");
859 if ((retval = WSALookupServiceEnd(network_change_handle)) == SOCKET_ERROR) {
860 int errorid = WSAGetLastError();
861 gchar *msg = g_win32_error_message(errorid);
862 purple_debug_warning("network", "Unable to kill NLA thread. Message: %s (%d).\n",
863 msg, errorid);
864 g_free(msg);
865 }
866 }
867 g_static_mutex_unlock(&mutex);
868
869 #endif
800 purple_signal_unregister(purple_network_get_handle(), 870 purple_signal_unregister(purple_network_get_handle(),
801 "network-configuration-changed"); 871 "network-configuration-changed");
802 } 872 }

mercurial