1 /* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "NetworkStateNotifier.h" 28 29 #include <wtf/MainThread.h> 30 #include <wtf/Vector.h> 31 32 #include <winsock2.h> 33 #include <iphlpapi.h> 34 35 namespace WebCore { 36 37 void NetworkStateNotifier::updateState() 38 { 39 // Assume that we're online until proven otherwise. 40 m_isOnLine = true; 41 42 Vector<char> buffer; 43 DWORD size = 0; 44 45 if (::GetAdaptersAddresses(AF_UNSPEC, 0, 0, 0, &size) != ERROR_BUFFER_OVERFLOW) 46 return; 47 48 buffer.resize(size); 49 PIP_ADAPTER_ADDRESSES addresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(buffer.data()); 50 51 if (::GetAdaptersAddresses(AF_UNSPEC, 0, 0, addresses, &size) != ERROR_SUCCESS) { 52 // We couldn't determine whether we're online or not, so assume that we are. 53 return; 54 } 55 56 for (; addresses; addresses = addresses->Next) { 57 if (addresses->IfType == MIB_IF_TYPE_LOOPBACK) 58 continue; 59 60 if (addresses->OperStatus != IfOperStatusUp) 61 continue; 62 63 // We found an interface that was up. 64 return; 65 } 66 67 // We didn't find any valid interfaces, so we must be offline. 68 m_isOnLine = false; 69 } 70 71 void NetworkStateNotifier::addressChanged() 72 { 73 bool oldOnLine = m_isOnLine; 74 75 updateState(); 76 77 if (m_isOnLine == oldOnLine) 78 return; 79 80 if (m_networkStateChangedFunction) 81 m_networkStateChangedFunction(); 82 } 83 84 void NetworkStateNotifier::callAddressChanged(void* context) 85 { 86 static_cast<NetworkStateNotifier*>(context)->addressChanged(); 87 } 88 89 void CALLBACK NetworkStateNotifier::addrChangeCallback(void* context, BOOLEAN timedOut) 90 { 91 // NotifyAddrChange only notifies us of a single address change. Now that we've been notified, 92 // we need to call it again so we'll get notified the *next* time. 93 static_cast<NetworkStateNotifier*>(context)->registerForAddressChange(); 94 95 callOnMainThread(callAddressChanged, context); 96 } 97 98 void NetworkStateNotifier::registerForAddressChange() 99 { 100 HANDLE handle; 101 ::NotifyAddrChange(&handle, &m_overlapped); 102 } 103 104 NetworkStateNotifier::NetworkStateNotifier() 105 : m_isOnLine(false) 106 , m_networkStateChangedFunction(0) 107 { 108 updateState(); 109 110 memset(&m_overlapped, 0, sizeof(m_overlapped)); 111 112 // FIXME: Check m_overlapped on WinCE. 113 #if !OS(WINCE) 114 m_overlapped.hEvent = ::CreateEvent(0, false, false, 0); 115 116 ::RegisterWaitForSingleObject(&m_waitHandle, m_overlapped.hEvent, addrChangeCallback, this, INFINITE, 0); 117 118 registerForAddressChange(); 119 #endif 120 } 121 122 } // namespace WebCore 123