netwerk/base/src/NetworkActivityMonitor.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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 }

mercurial