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: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 *
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/. */
7 #include "NetworkActivityMonitor.h"
8 #include "prmem.h"
9 #include "nsIObserverService.h"
10 #include "nsPISocketTransportService.h"
11 #include "nsSocketTransportService2.h"
12 #include "nsThreadUtils.h"
13 #include "mozilla/Services.h"
14 #include "prerror.h"
16 using namespace mozilla::net;
18 static PRStatus
19 nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
20 {
21 PRStatus ret;
22 PRErrorCode code;
23 ret = fd->lower->methods->connect(fd->lower, addr, timeout);
24 if (ret == PR_SUCCESS || (code = PR_GetError()) == PR_WOULD_BLOCK_ERROR ||
25 code == PR_IN_PROGRESS_ERROR)
26 NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
27 return ret;
28 }
30 static int32_t
31 nsNetMon_Read(PRFileDesc *fd, void *buf, int32_t len)
32 {
33 int32_t ret;
34 ret = fd->lower->methods->read(fd->lower, buf, len);
35 if (ret >= 0)
36 NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
37 return ret;
38 }
40 static int32_t
41 nsNetMon_Write(PRFileDesc *fd, const void *buf, int32_t len)
42 {
43 int32_t ret;
44 ret = fd->lower->methods->write(fd->lower, buf, len);
45 if (ret > 0)
46 NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
47 return ret;
48 }
50 static int32_t
51 nsNetMon_Writev(PRFileDesc *fd,
52 const PRIOVec *iov,
53 int32_t size,
54 PRIntervalTime timeout)
55 {
56 int32_t ret;
57 ret = fd->lower->methods->writev(fd->lower, iov, size, timeout);
58 if (ret > 0)
59 NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
60 return ret;
61 }
63 static int32_t
64 nsNetMon_Recv(PRFileDesc *fd,
65 void *buf,
66 int32_t amount,
67 int flags,
68 PRIntervalTime timeout)
69 {
70 int32_t ret;
71 ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
72 if (ret >= 0)
73 NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
74 return ret;
75 }
77 static int32_t
78 nsNetMon_Send(PRFileDesc *fd,
79 const void *buf,
80 int32_t amount,
81 int flags,
82 PRIntervalTime timeout)
83 {
84 int32_t ret;
85 ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
86 if (ret > 0)
87 NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
88 return ret;
89 }
91 static int32_t
92 nsNetMon_RecvFrom(PRFileDesc *fd,
93 void *buf,
94 int32_t amount,
95 int flags,
96 PRNetAddr *addr,
97 PRIntervalTime timeout)
98 {
99 int32_t ret;
100 ret = fd->lower->methods->recvfrom(fd->lower,
101 buf,
102 amount,
103 flags,
104 addr,
105 timeout);
106 if (ret >= 0)
107 NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
108 return ret;
109 }
111 static int32_t
112 nsNetMon_SendTo(PRFileDesc *fd,
113 const void *buf,
114 int32_t amount,
115 int flags,
116 const PRNetAddr *addr,
117 PRIntervalTime timeout)
118 {
119 int32_t ret;
120 ret = fd->lower->methods->sendto(fd->lower,
121 buf,
122 amount,
123 flags,
124 addr,
125 timeout);
126 if (ret > 0)
127 NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload);
128 return ret;
129 }
131 static int32_t
132 nsNetMon_AcceptRead(PRFileDesc *listenSock,
133 PRFileDesc **acceptedSock,
134 PRNetAddr **peerAddr,
135 void *buf,
136 int32_t amount,
137 PRIntervalTime timeout)
138 {
139 int32_t ret;
140 ret = listenSock->lower->methods->acceptread(listenSock->lower,
141 acceptedSock,
142 peerAddr,
143 buf,
144 amount,
145 timeout);
146 if (ret > 0)
147 NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload);
148 return ret;
149 }
152 class NotifyNetworkActivity : public nsRunnable {
153 public:
154 NotifyNetworkActivity(NetworkActivityMonitor::Direction aDirection)
155 : mDirection(aDirection)
156 {}
157 NS_IMETHOD Run()
158 {
159 MOZ_ASSERT(NS_IsMainThread());
161 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
162 if (!obs)
163 return NS_ERROR_FAILURE;
165 obs->NotifyObservers(nullptr,
166 mDirection == NetworkActivityMonitor::kUpload
167 ? NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC
168 : NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC,
169 nullptr);
170 return NS_OK;
171 }
172 private:
173 nsCOMPtr<nsIObserverService> mObs;
174 NetworkActivityMonitor::Direction mDirection;
175 };
177 NetworkActivityMonitor * NetworkActivityMonitor::gInstance = nullptr;
179 NetworkActivityMonitor::NetworkActivityMonitor()
180 : mLayerIdentity(PR_INVALID_IO_LAYER)
181 , mBlipInterval(PR_INTERVAL_NO_TIMEOUT)
182 {
183 MOZ_COUNT_CTOR(NetworkActivityMonitor);
185 NS_ASSERTION(gInstance==nullptr,
186 "multiple NetworkActivityMonitor instances!");
187 }
189 NetworkActivityMonitor::~NetworkActivityMonitor()
190 {
191 MOZ_COUNT_DTOR(NetworkActivityMonitor);
192 gInstance = nullptr;
193 }
195 nsresult
196 NetworkActivityMonitor::Init(int32_t blipInterval)
197 {
198 nsresult rv;
200 if (gInstance)
201 return NS_ERROR_ALREADY_INITIALIZED;
203 NetworkActivityMonitor * mon = new NetworkActivityMonitor();
204 rv = mon->Init_Internal(blipInterval);
205 if (NS_FAILED(rv)) {
206 delete mon;
207 return rv;
208 }
210 gInstance = mon;
211 return NS_OK;
212 }
214 nsresult
215 NetworkActivityMonitor::Shutdown()
216 {
217 if (!gInstance)
218 return NS_ERROR_NOT_INITIALIZED;
220 delete gInstance;
221 return NS_OK;
222 }
224 nsresult
225 NetworkActivityMonitor::Init_Internal(int32_t blipInterval)
226 {
227 mLayerIdentity = PR_GetUniqueIdentity("network activity monitor layer");
228 mLayerMethods = *PR_GetDefaultIOMethods();
229 mLayerMethods.connect = nsNetMon_Connect;
230 mLayerMethods.read = nsNetMon_Read;
231 mLayerMethods.write = nsNetMon_Write;
232 mLayerMethods.writev = nsNetMon_Writev;
233 mLayerMethods.recv = nsNetMon_Recv;
234 mLayerMethods.send = nsNetMon_Send;
235 mLayerMethods.recvfrom = nsNetMon_RecvFrom;
236 mLayerMethods.sendto = nsNetMon_SendTo;
237 mLayerMethods.acceptread = nsNetMon_AcceptRead;
239 mBlipInterval = PR_MillisecondsToInterval(blipInterval);
240 // Set the last notification times to time that has just expired, so any
241 // activity even right now will trigger notification.
242 mLastNotificationTime[kUpload] = PR_IntervalNow() - mBlipInterval;
243 mLastNotificationTime[kDownload] = mLastNotificationTime[kUpload];
245 return NS_OK;
246 }
248 nsresult
249 NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
250 {
251 if (!gInstance)
252 return NS_OK;
254 PRFileDesc * layer;
255 PRStatus status;
257 layer = PR_CreateIOLayerStub(gInstance->mLayerIdentity,
258 &gInstance->mLayerMethods);
259 if (!layer) {
260 return NS_ERROR_FAILURE;
261 }
263 status = PR_PushIOLayer(fd, PR_NSPR_IO_LAYER, layer);
265 if (status == PR_FAILURE) {
266 PR_DELETE(layer);
267 return NS_ERROR_FAILURE;
268 }
270 return NS_OK;
271 }
273 nsresult
274 NetworkActivityMonitor::DataInOut(Direction direction)
275 {
276 NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
278 if (gInstance) {
279 PRIntervalTime now = PR_IntervalNow();
280 if ((now - gInstance->mLastNotificationTime[direction]) >
281 gInstance->mBlipInterval) {
282 gInstance->mLastNotificationTime[direction] = now;
283 gInstance->PostNotification(direction);
284 }
285 }
287 return NS_OK;
288 }
290 void
291 NetworkActivityMonitor::PostNotification(Direction direction)
292 {
293 nsRefPtr<nsIRunnable> ev = new NotifyNetworkActivity(direction);
294 NS_DispatchToMainThread(ev);
295 }