netwerk/base/src/NetworkActivityMonitor.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:62ea4514e8a7
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/. */
6
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"
15
16 using namespace mozilla::net;
17
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 }
29
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 }
39
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 }
49
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 }
62
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 }
76
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 }
90
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 }
110
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 }
130
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 }
150
151
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());
160
161 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
162 if (!obs)
163 return NS_ERROR_FAILURE;
164
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 };
176
177 NetworkActivityMonitor * NetworkActivityMonitor::gInstance = nullptr;
178
179 NetworkActivityMonitor::NetworkActivityMonitor()
180 : mLayerIdentity(PR_INVALID_IO_LAYER)
181 , mBlipInterval(PR_INTERVAL_NO_TIMEOUT)
182 {
183 MOZ_COUNT_CTOR(NetworkActivityMonitor);
184
185 NS_ASSERTION(gInstance==nullptr,
186 "multiple NetworkActivityMonitor instances!");
187 }
188
189 NetworkActivityMonitor::~NetworkActivityMonitor()
190 {
191 MOZ_COUNT_DTOR(NetworkActivityMonitor);
192 gInstance = nullptr;
193 }
194
195 nsresult
196 NetworkActivityMonitor::Init(int32_t blipInterval)
197 {
198 nsresult rv;
199
200 if (gInstance)
201 return NS_ERROR_ALREADY_INITIALIZED;
202
203 NetworkActivityMonitor * mon = new NetworkActivityMonitor();
204 rv = mon->Init_Internal(blipInterval);
205 if (NS_FAILED(rv)) {
206 delete mon;
207 return rv;
208 }
209
210 gInstance = mon;
211 return NS_OK;
212 }
213
214 nsresult
215 NetworkActivityMonitor::Shutdown()
216 {
217 if (!gInstance)
218 return NS_ERROR_NOT_INITIALIZED;
219
220 delete gInstance;
221 return NS_OK;
222 }
223
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;
238
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];
244
245 return NS_OK;
246 }
247
248 nsresult
249 NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd)
250 {
251 if (!gInstance)
252 return NS_OK;
253
254 PRFileDesc * layer;
255 PRStatus status;
256
257 layer = PR_CreateIOLayerStub(gInstance->mLayerIdentity,
258 &gInstance->mLayerMethods);
259 if (!layer) {
260 return NS_ERROR_FAILURE;
261 }
262
263 status = PR_PushIOLayer(fd, PR_NSPR_IO_LAYER, layer);
264
265 if (status == PR_FAILURE) {
266 PR_DELETE(layer);
267 return NS_ERROR_FAILURE;
268 }
269
270 return NS_OK;
271 }
272
273 nsresult
274 NetworkActivityMonitor::DataInOut(Direction direction)
275 {
276 NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
277
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 }
286
287 return NS_OK;
288 }
289
290 void
291 NetworkActivityMonitor::PostNotification(Direction direction)
292 {
293 nsRefPtr<nsIRunnable> ev = new NotifyNetworkActivity(direction);
294 NS_DispatchToMainThread(ev);
295 }

mercurial