Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsNetworkLinkService.h"
7 #include "nsCOMPtr.h"
8 #include "nsIObserverService.h"
9 #include "nsServiceManagerUtils.h"
10 #include "nsString.h"
11 #include "nsCRT.h"
13 #import <Cocoa/Cocoa.h>
14 #import <netinet/in.h>
16 NS_IMPL_ISUPPORTS(nsNetworkLinkService,
17 nsINetworkLinkService,
18 nsIObserver)
20 nsNetworkLinkService::nsNetworkLinkService()
21 : mLinkUp(true)
22 , mStatusKnown(false)
23 , mReachability(NULL)
24 , mCFRunLoop(NULL)
25 {
26 }
28 nsNetworkLinkService::~nsNetworkLinkService()
29 {
30 }
32 NS_IMETHODIMP
33 nsNetworkLinkService::GetIsLinkUp(bool *aIsUp)
34 {
35 *aIsUp = mLinkUp;
36 return NS_OK;
37 }
39 NS_IMETHODIMP
40 nsNetworkLinkService::GetLinkStatusKnown(bool *aIsUp)
41 {
42 *aIsUp = mStatusKnown;
43 return NS_OK;
44 }
46 NS_IMETHODIMP
47 nsNetworkLinkService::GetLinkType(uint32_t *aLinkType)
48 {
49 NS_ENSURE_ARG_POINTER(aLinkType);
51 // XXX This function has not yet been implemented for this platform
52 *aLinkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
53 return NS_OK;
54 }
56 NS_IMETHODIMP
57 nsNetworkLinkService::Observe(nsISupports *subject,
58 const char *topic,
59 const char16_t *data)
60 {
61 if (!strcmp(topic, "xpcom-shutdown")) {
62 Shutdown();
63 }
65 return NS_OK;
66 }
68 nsresult
69 nsNetworkLinkService::Init(void)
70 {
71 nsresult rv;
73 nsCOMPtr<nsIObserverService> observerService =
74 do_GetService("@mozilla.org/observer-service;1", &rv);
75 NS_ENSURE_SUCCESS(rv, rv);
77 rv = observerService->AddObserver(this, "xpcom-shutdown", false);
78 NS_ENSURE_SUCCESS(rv, rv);
80 // If the network reachability API can reach 0.0.0.0 without
81 // requiring a connection, there is a network interface available.
82 struct sockaddr_in addr;
83 bzero(&addr, sizeof(addr));
84 addr.sin_len = sizeof(addr);
85 addr.sin_family = AF_INET;
86 mReachability =
87 ::SCNetworkReachabilityCreateWithAddress(NULL,
88 (struct sockaddr *)&addr);
89 if (!mReachability) {
90 return NS_ERROR_NOT_AVAILABLE;
91 }
93 SCNetworkReachabilityContext context = {0, this, NULL, NULL, NULL};
94 if (!::SCNetworkReachabilitySetCallback(mReachability,
95 ReachabilityChanged,
96 &context)) {
97 NS_WARNING("SCNetworkReachabilitySetCallback failed.");
98 ::CFRelease(mReachability);
99 mReachability = NULL;
100 return NS_ERROR_NOT_AVAILABLE;
101 }
103 // Get the current run loop. This service is initialized at startup,
104 // so we shouldn't run in to any problems with modal dialog run loops.
105 mCFRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
106 if (!mCFRunLoop) {
107 NS_WARNING("Could not get current run loop.");
108 ::CFRelease(mReachability);
109 mReachability = NULL;
110 return NS_ERROR_NOT_AVAILABLE;
111 }
112 ::CFRetain(mCFRunLoop);
114 if (!::SCNetworkReachabilityScheduleWithRunLoop(mReachability, mCFRunLoop,
115 kCFRunLoopDefaultMode)) {
116 NS_WARNING("SCNetworkReachabilityScheduleWIthRunLoop failed.");
117 ::CFRelease(mReachability);
118 mReachability = NULL;
119 ::CFRelease(mCFRunLoop);
120 mCFRunLoop = NULL;
121 return NS_ERROR_NOT_AVAILABLE;
122 }
124 UpdateReachability();
126 return NS_OK;
127 }
129 nsresult
130 nsNetworkLinkService::Shutdown()
131 {
132 if (!::SCNetworkReachabilityUnscheduleFromRunLoop(mReachability,
133 mCFRunLoop,
134 kCFRunLoopDefaultMode)) {
135 NS_WARNING("SCNetworkReachabilityUnscheduleFromRunLoop failed.");
136 }
138 ::CFRelease(mReachability);
139 mReachability = NULL;
141 ::CFRelease(mCFRunLoop);
142 mCFRunLoop = NULL;
144 return NS_OK;
145 }
147 void
148 nsNetworkLinkService::UpdateReachability()
149 {
150 if (!mReachability) {
151 return;
152 }
154 SCNetworkConnectionFlags flags;
155 if (!::SCNetworkReachabilityGetFlags(mReachability, &flags)) {
156 mStatusKnown = false;
157 return;
158 }
160 bool reachable = (flags & kSCNetworkFlagsReachable) != 0;
161 bool needsConnection = (flags & kSCNetworkFlagsConnectionRequired) != 0;
163 mLinkUp = (reachable && !needsConnection);
164 mStatusKnown = true;
165 }
167 void
168 nsNetworkLinkService::SendEvent()
169 {
170 nsCOMPtr<nsIObserverService> observerService =
171 do_GetService("@mozilla.org/observer-service;1");
172 if (!observerService)
173 return;
175 const char *event;
176 if (!mStatusKnown)
177 event = NS_NETWORK_LINK_DATA_UNKNOWN;
178 else
179 event = mLinkUp ? NS_NETWORK_LINK_DATA_UP
180 : NS_NETWORK_LINK_DATA_DOWN;
182 observerService->NotifyObservers(static_cast<nsINetworkLinkService*>(this),
183 NS_NETWORK_LINK_TOPIC,
184 NS_ConvertASCIItoUTF16(event).get());
185 }
187 /* static */
188 void
189 nsNetworkLinkService::ReachabilityChanged(SCNetworkReachabilityRef target,
190 SCNetworkConnectionFlags flags,
191 void *info)
192 {
193 nsNetworkLinkService *service =
194 static_cast<nsNetworkLinkService*>(info);
196 service->UpdateReachability();
197 service->SendEvent();
198 }