1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/base/src/NetworkActivityMonitor.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,295 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "NetworkActivityMonitor.h" 1.11 +#include "prmem.h" 1.12 +#include "nsIObserverService.h" 1.13 +#include "nsPISocketTransportService.h" 1.14 +#include "nsSocketTransportService2.h" 1.15 +#include "nsThreadUtils.h" 1.16 +#include "mozilla/Services.h" 1.17 +#include "prerror.h" 1.18 + 1.19 +using namespace mozilla::net; 1.20 + 1.21 +static PRStatus 1.22 +nsNetMon_Connect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) 1.23 +{ 1.24 + PRStatus ret; 1.25 + PRErrorCode code; 1.26 + ret = fd->lower->methods->connect(fd->lower, addr, timeout); 1.27 + if (ret == PR_SUCCESS || (code = PR_GetError()) == PR_WOULD_BLOCK_ERROR || 1.28 + code == PR_IN_PROGRESS_ERROR) 1.29 + NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload); 1.30 + return ret; 1.31 +} 1.32 + 1.33 +static int32_t 1.34 +nsNetMon_Read(PRFileDesc *fd, void *buf, int32_t len) 1.35 +{ 1.36 + int32_t ret; 1.37 + ret = fd->lower->methods->read(fd->lower, buf, len); 1.38 + if (ret >= 0) 1.39 + NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload); 1.40 + return ret; 1.41 +} 1.42 + 1.43 +static int32_t 1.44 +nsNetMon_Write(PRFileDesc *fd, const void *buf, int32_t len) 1.45 +{ 1.46 + int32_t ret; 1.47 + ret = fd->lower->methods->write(fd->lower, buf, len); 1.48 + if (ret > 0) 1.49 + NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload); 1.50 + return ret; 1.51 +} 1.52 + 1.53 +static int32_t 1.54 +nsNetMon_Writev(PRFileDesc *fd, 1.55 + const PRIOVec *iov, 1.56 + int32_t size, 1.57 + PRIntervalTime timeout) 1.58 +{ 1.59 + int32_t ret; 1.60 + ret = fd->lower->methods->writev(fd->lower, iov, size, timeout); 1.61 + if (ret > 0) 1.62 + NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload); 1.63 + return ret; 1.64 +} 1.65 + 1.66 +static int32_t 1.67 +nsNetMon_Recv(PRFileDesc *fd, 1.68 + void *buf, 1.69 + int32_t amount, 1.70 + int flags, 1.71 + PRIntervalTime timeout) 1.72 +{ 1.73 + int32_t ret; 1.74 + ret = fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout); 1.75 + if (ret >= 0) 1.76 + NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload); 1.77 + return ret; 1.78 +} 1.79 + 1.80 +static int32_t 1.81 +nsNetMon_Send(PRFileDesc *fd, 1.82 + const void *buf, 1.83 + int32_t amount, 1.84 + int flags, 1.85 + PRIntervalTime timeout) 1.86 +{ 1.87 + int32_t ret; 1.88 + ret = fd->lower->methods->send(fd->lower, buf, amount, flags, timeout); 1.89 + if (ret > 0) 1.90 + NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload); 1.91 + return ret; 1.92 +} 1.93 + 1.94 +static int32_t 1.95 +nsNetMon_RecvFrom(PRFileDesc *fd, 1.96 + void *buf, 1.97 + int32_t amount, 1.98 + int flags, 1.99 + PRNetAddr *addr, 1.100 + PRIntervalTime timeout) 1.101 +{ 1.102 + int32_t ret; 1.103 + ret = fd->lower->methods->recvfrom(fd->lower, 1.104 + buf, 1.105 + amount, 1.106 + flags, 1.107 + addr, 1.108 + timeout); 1.109 + if (ret >= 0) 1.110 + NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload); 1.111 + return ret; 1.112 +} 1.113 + 1.114 +static int32_t 1.115 +nsNetMon_SendTo(PRFileDesc *fd, 1.116 + const void *buf, 1.117 + int32_t amount, 1.118 + int flags, 1.119 + const PRNetAddr *addr, 1.120 + PRIntervalTime timeout) 1.121 +{ 1.122 + int32_t ret; 1.123 + ret = fd->lower->methods->sendto(fd->lower, 1.124 + buf, 1.125 + amount, 1.126 + flags, 1.127 + addr, 1.128 + timeout); 1.129 + if (ret > 0) 1.130 + NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kUpload); 1.131 + return ret; 1.132 +} 1.133 + 1.134 +static int32_t 1.135 +nsNetMon_AcceptRead(PRFileDesc *listenSock, 1.136 + PRFileDesc **acceptedSock, 1.137 + PRNetAddr **peerAddr, 1.138 + void *buf, 1.139 + int32_t amount, 1.140 + PRIntervalTime timeout) 1.141 +{ 1.142 + int32_t ret; 1.143 + ret = listenSock->lower->methods->acceptread(listenSock->lower, 1.144 + acceptedSock, 1.145 + peerAddr, 1.146 + buf, 1.147 + amount, 1.148 + timeout); 1.149 + if (ret > 0) 1.150 + NetworkActivityMonitor::DataInOut(NetworkActivityMonitor::kDownload); 1.151 + return ret; 1.152 +} 1.153 + 1.154 + 1.155 +class NotifyNetworkActivity : public nsRunnable { 1.156 +public: 1.157 + NotifyNetworkActivity(NetworkActivityMonitor::Direction aDirection) 1.158 + : mDirection(aDirection) 1.159 + {} 1.160 + NS_IMETHOD Run() 1.161 + { 1.162 + MOZ_ASSERT(NS_IsMainThread()); 1.163 + 1.164 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.165 + if (!obs) 1.166 + return NS_ERROR_FAILURE; 1.167 + 1.168 + obs->NotifyObservers(nullptr, 1.169 + mDirection == NetworkActivityMonitor::kUpload 1.170 + ? NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC 1.171 + : NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC, 1.172 + nullptr); 1.173 + return NS_OK; 1.174 + } 1.175 +private: 1.176 + nsCOMPtr<nsIObserverService> mObs; 1.177 + NetworkActivityMonitor::Direction mDirection; 1.178 +}; 1.179 + 1.180 +NetworkActivityMonitor * NetworkActivityMonitor::gInstance = nullptr; 1.181 + 1.182 +NetworkActivityMonitor::NetworkActivityMonitor() 1.183 + : mLayerIdentity(PR_INVALID_IO_LAYER) 1.184 + , mBlipInterval(PR_INTERVAL_NO_TIMEOUT) 1.185 +{ 1.186 + MOZ_COUNT_CTOR(NetworkActivityMonitor); 1.187 + 1.188 + NS_ASSERTION(gInstance==nullptr, 1.189 + "multiple NetworkActivityMonitor instances!"); 1.190 +} 1.191 + 1.192 +NetworkActivityMonitor::~NetworkActivityMonitor() 1.193 +{ 1.194 + MOZ_COUNT_DTOR(NetworkActivityMonitor); 1.195 + gInstance = nullptr; 1.196 +} 1.197 + 1.198 +nsresult 1.199 +NetworkActivityMonitor::Init(int32_t blipInterval) 1.200 +{ 1.201 + nsresult rv; 1.202 + 1.203 + if (gInstance) 1.204 + return NS_ERROR_ALREADY_INITIALIZED; 1.205 + 1.206 + NetworkActivityMonitor * mon = new NetworkActivityMonitor(); 1.207 + rv = mon->Init_Internal(blipInterval); 1.208 + if (NS_FAILED(rv)) { 1.209 + delete mon; 1.210 + return rv; 1.211 + } 1.212 + 1.213 + gInstance = mon; 1.214 + return NS_OK; 1.215 +} 1.216 + 1.217 +nsresult 1.218 +NetworkActivityMonitor::Shutdown() 1.219 +{ 1.220 + if (!gInstance) 1.221 + return NS_ERROR_NOT_INITIALIZED; 1.222 + 1.223 + delete gInstance; 1.224 + return NS_OK; 1.225 +} 1.226 + 1.227 +nsresult 1.228 +NetworkActivityMonitor::Init_Internal(int32_t blipInterval) 1.229 +{ 1.230 + mLayerIdentity = PR_GetUniqueIdentity("network activity monitor layer"); 1.231 + mLayerMethods = *PR_GetDefaultIOMethods(); 1.232 + mLayerMethods.connect = nsNetMon_Connect; 1.233 + mLayerMethods.read = nsNetMon_Read; 1.234 + mLayerMethods.write = nsNetMon_Write; 1.235 + mLayerMethods.writev = nsNetMon_Writev; 1.236 + mLayerMethods.recv = nsNetMon_Recv; 1.237 + mLayerMethods.send = nsNetMon_Send; 1.238 + mLayerMethods.recvfrom = nsNetMon_RecvFrom; 1.239 + mLayerMethods.sendto = nsNetMon_SendTo; 1.240 + mLayerMethods.acceptread = nsNetMon_AcceptRead; 1.241 + 1.242 + mBlipInterval = PR_MillisecondsToInterval(blipInterval); 1.243 + // Set the last notification times to time that has just expired, so any 1.244 + // activity even right now will trigger notification. 1.245 + mLastNotificationTime[kUpload] = PR_IntervalNow() - mBlipInterval; 1.246 + mLastNotificationTime[kDownload] = mLastNotificationTime[kUpload]; 1.247 + 1.248 + return NS_OK; 1.249 +} 1.250 + 1.251 +nsresult 1.252 +NetworkActivityMonitor::AttachIOLayer(PRFileDesc *fd) 1.253 +{ 1.254 + if (!gInstance) 1.255 + return NS_OK; 1.256 + 1.257 + PRFileDesc * layer; 1.258 + PRStatus status; 1.259 + 1.260 + layer = PR_CreateIOLayerStub(gInstance->mLayerIdentity, 1.261 + &gInstance->mLayerMethods); 1.262 + if (!layer) { 1.263 + return NS_ERROR_FAILURE; 1.264 + } 1.265 + 1.266 + status = PR_PushIOLayer(fd, PR_NSPR_IO_LAYER, layer); 1.267 + 1.268 + if (status == PR_FAILURE) { 1.269 + PR_DELETE(layer); 1.270 + return NS_ERROR_FAILURE; 1.271 + } 1.272 + 1.273 + return NS_OK; 1.274 +} 1.275 + 1.276 +nsresult 1.277 +NetworkActivityMonitor::DataInOut(Direction direction) 1.278 +{ 1.279 + NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); 1.280 + 1.281 + if (gInstance) { 1.282 + PRIntervalTime now = PR_IntervalNow(); 1.283 + if ((now - gInstance->mLastNotificationTime[direction]) > 1.284 + gInstance->mBlipInterval) { 1.285 + gInstance->mLastNotificationTime[direction] = now; 1.286 + gInstance->PostNotification(direction); 1.287 + } 1.288 + } 1.289 + 1.290 + return NS_OK; 1.291 +} 1.292 + 1.293 +void 1.294 +NetworkActivityMonitor::PostNotification(Direction direction) 1.295 +{ 1.296 + nsRefPtr<nsIRunnable> ev = new NotifyNetworkActivity(direction); 1.297 + NS_DispatchToMainThread(ev); 1.298 +}