Skip to content

Commit 087d426

Browse files
committed
Bug 786419 - Part 1 - Provide way to "set network offline" per app r=jduell
1 parent f9a4630 commit 087d426

18 files changed

+747
-9
lines changed

netwerk/base/public/nsIIOService.idl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,24 @@ interface nsIIOService : nsISupports
8888
*/
8989
attribute boolean offline;
9090

91+
/**
92+
* Set whether network appears to be offline for network connections from
93+
* a given appID.
94+
*
95+
* Calling this function may fire the "network:app-offline-status-changed"
96+
* notification, which is also sent to child processes containing this appId.
97+
* 'state' must one of nsIAppOfflineInfo::{ONLINE|OFFLINE|WIFI_ONLY}.
98+
*/
99+
void setAppOffline(in uint32_t appId, in long state);
100+
101+
/**
102+
* Returns true if given appId is currently not allowed to make network
103+
* connections. It will return true if the app is in the wifi-only state
104+
* and we are currently on a 3G connection.
105+
*/
106+
boolean isAppOffline(in uint32_t appId);
107+
108+
91109
/**
92110
* Checks if a port number is banned. This involves consulting a list of
93111
* unsafe ports, corresponding to network services that may be easily
@@ -117,6 +135,18 @@ interface nsIIOService : nsISupports
117135
ACString extractScheme(in AUTF8String urlString);
118136
};
119137

138+
[scriptable, uuid(4ac296a0-ca1b-44f4-8787-117a88cb70fb)]
139+
interface nsIAppOfflineInfo : nsISupports
140+
{
141+
readonly attribute unsigned long appId;
142+
143+
const long ONLINE = 1;
144+
const long OFFLINE = 2;
145+
const long WIFI_ONLY = 3;
146+
147+
readonly attribute long mode;
148+
};
149+
120150
%{C++
121151
/**
122152
* We send notifications through nsIObserverService with topic
@@ -136,4 +166,10 @@ interface nsIIOService : nsISupports
136166
#define NS_IOSERVICE_OFFLINE_STATUS_TOPIC "network:offline-status-changed"
137167
#define NS_IOSERVICE_OFFLINE "offline"
138168
#define NS_IOSERVICE_ONLINE "online"
169+
170+
/**
171+
* When network:app-offline-status-changed is fired,
172+
* the 'Subject' argument is a nsIOfflineAppInfo.
173+
*/
174+
#define NS_IOSERVICE_APP_OFFLINE_STATUS_TOPIC "network:app-offline-status-changed"
139175
%}

netwerk/base/src/OfflineObserver.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set sw=2 ts=8 et tw=80 : */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#include "OfflineObserver.h"
8+
#include "nsNetUtil.h"
9+
#include "nsIOService.h"
10+
#include "mozilla/net/NeckoCommon.h"
11+
#include "nsIObserverService.h"
12+
#include "nsThreadUtils.h"
13+
namespace mozilla {
14+
namespace net {
15+
16+
NS_IMPL_ISUPPORTS(OfflineObserver, nsIObserver)
17+
18+
void
19+
OfflineObserver::RegisterOfflineObserver()
20+
{
21+
if (NS_IsMainThread()) {
22+
RegisterOfflineObserverMainThread();
23+
} else {
24+
nsRefPtr<nsIRunnable> event =
25+
NS_NewRunnableMethod(this, &OfflineObserver::RegisterOfflineObserverMainThread);
26+
NS_DispatchToMainThread(event);
27+
}
28+
}
29+
30+
void
31+
OfflineObserver::RemoveOfflineObserver()
32+
{
33+
if (NS_IsMainThread()) {
34+
RemoveOfflineObserverMainThread();
35+
} else {
36+
nsRefPtr<nsIRunnable> event =
37+
NS_NewRunnableMethod(this, &OfflineObserver::RemoveOfflineObserverMainThread);
38+
NS_DispatchToMainThread(event);
39+
}
40+
}
41+
42+
void
43+
OfflineObserver::RegisterOfflineObserverMainThread()
44+
{
45+
nsCOMPtr<nsIObserverService> observerService =
46+
mozilla::services::GetObserverService();
47+
if (!observerService) {
48+
return;
49+
}
50+
nsresult rv = observerService->AddObserver(this,
51+
NS_IOSERVICE_APP_OFFLINE_STATUS_TOPIC, false);
52+
if (NS_FAILED(rv)) {
53+
NS_WARNING("Failed to register observer");
54+
}
55+
}
56+
57+
void
58+
OfflineObserver::RemoveOfflineObserverMainThread()
59+
{
60+
nsCOMPtr<nsIObserverService> observerService =
61+
mozilla::services::GetObserverService();
62+
if (observerService) {
63+
observerService->RemoveObserver(this, NS_IOSERVICE_APP_OFFLINE_STATUS_TOPIC);
64+
}
65+
}
66+
67+
OfflineObserver::OfflineObserver(DisconnectableParent * parent)
68+
{
69+
mParent = parent;
70+
RegisterOfflineObserver();
71+
}
72+
73+
void
74+
OfflineObserver::RemoveObserver()
75+
{
76+
RemoveOfflineObserver();
77+
mParent = nullptr;
78+
}
79+
80+
NS_IMETHODIMP
81+
OfflineObserver::Observe(nsISupports *aSubject,
82+
const char *aTopic,
83+
const char16_t *aData)
84+
{
85+
if (mParent &&
86+
!strcmp(aTopic, NS_IOSERVICE_APP_OFFLINE_STATUS_TOPIC)) {
87+
mParent->OfflineNotification(aSubject);
88+
}
89+
return NS_OK;
90+
}
91+
92+
uint32_t
93+
DisconnectableParent::GetAppId()
94+
{
95+
return NECKO_UNKNOWN_APP_ID;
96+
}
97+
98+
nsresult
99+
DisconnectableParent::OfflineNotification(nsISupports *aSubject)
100+
{
101+
nsCOMPtr<nsIAppOfflineInfo> info(do_QueryInterface(aSubject));
102+
if (!info) {
103+
return NS_ERROR_NOT_INITIALIZED;
104+
}
105+
106+
uint32_t targetAppId = NECKO_UNKNOWN_APP_ID;
107+
info->GetAppId(&targetAppId);
108+
109+
// Obtain App ID
110+
uint32_t appId = GetAppId();
111+
if (appId != targetAppId) {
112+
return NS_OK;
113+
}
114+
115+
// If the app is offline, close the socket
116+
if (NS_IsAppOffline(appId)) {
117+
OfflineDisconnect();
118+
}
119+
120+
return NS_OK;
121+
}
122+
123+
} // net namespace
124+
} // mozilla namespace

netwerk/base/src/OfflineObserver.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set sw=2 ts=8 et tw=80 : */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#ifndef nsOfflineObserver_h__
8+
#define nsOfflineObserver_h__
9+
10+
#include "nsIObserver.h"
11+
12+
namespace mozilla {
13+
namespace net {
14+
15+
/**
16+
* Parents should extend this class and have a nsRefPtr<OfflineObserver> member.
17+
* The constructor should initialize the member to new OfflineObserver(this)
18+
* and the destructor should call RemoveObserver on the member.
19+
*
20+
* GetAppId and OfflineDisconnect are called from the default implementation
21+
* of OfflineNotification. These should be overridden by classes that don't
22+
* provide an implementation of OfflineNotification.
23+
*/
24+
class DisconnectableParent
25+
{
26+
public:
27+
// This is called on the main thread, by the OfflineObserver.
28+
// aSubject is of type nsAppOfflineInfo and contains appId and offline mode.
29+
virtual nsresult OfflineNotification(nsISupports *aSubject);
30+
31+
// GetAppId returns the appId for the app associated with the parent
32+
virtual uint32_t GetAppId();
33+
34+
// OfflineDisconnect cancels all existing connections in the parent when
35+
// the app becomes offline.
36+
virtual void OfflineDisconnect() { }
37+
};
38+
39+
/**
40+
* This class observes the "network:app-offline-status-changed" topic and calls
41+
* OfflineNotification on the DisconnectableParent with the subject.
42+
*/
43+
class OfflineObserver
44+
: public nsIObserver
45+
{
46+
NS_DECL_THREADSAFE_ISUPPORTS
47+
NS_DECL_NSIOBSERVER
48+
public:
49+
// A nsRefPtr to this object should be kept by the disconnectable parent.
50+
51+
OfflineObserver(DisconnectableParent * parent);
52+
// This method needs to be called in the destructor of the parent
53+
// It removes the observer from the nsObserverService list, and it clears
54+
// the pointer it holds to the disconnectable parent.
55+
void RemoveObserver();
56+
private:
57+
58+
// These methods are called to register and unregister the observer.
59+
// If they are called on the main thread they register the observer right
60+
// away, otherwise they dispatch and event to the main thread
61+
void RegisterOfflineObserver();
62+
void RemoveOfflineObserver();
63+
void RegisterOfflineObserverMainThread();
64+
void RemoveOfflineObserverMainThread();
65+
private:
66+
virtual ~OfflineObserver() { }
67+
DisconnectableParent * mParent;
68+
};
69+
70+
} // net namespace
71+
} // mozilla namespace
72+
73+
#endif // nsOfflineObserver_h__

netwerk/base/src/moz.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ EXPORTS.mozilla.net += [
1717
'ChannelDiverterParent.h',
1818
'Dashboard.h',
1919
'DashboardTypes.h',
20+
'OfflineObserver.h',
2021
]
2122

2223
UNIFIED_SOURCES += [
@@ -85,6 +86,7 @@ SOURCES += [
8586
'nsAsyncRedirectVerifyHelper.cpp',
8687
'nsSocketTransport2.cpp',
8788
'nsSocketTransportService2.cpp',
89+
'OfflineObserver.cpp',
8890
]
8991

9092
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':

0 commit comments

Comments
 (0)