LCOV - code coverage report
Current view: directory - netwerk/base/src - nsSocketTransportService2.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 372 279 75.0 %
Date: 2012-06-02 Functions: 36 31 86.1 %

       1                 : // vim:set sw=4 sts=4 et cin:
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2002
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Darin Fisher <darin@netscape.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #ifdef MOZ_LOGGING
      40                 : #define FORCE_PR_LOG
      41                 : #endif
      42                 : 
      43                 : #include "nsSocketTransportService2.h"
      44                 : #include "nsSocketTransport2.h"
      45                 : #include "nsReadableUtils.h"
      46                 : #include "nsNetError.h"
      47                 : #include "prnetdb.h"
      48                 : #include "prerror.h"
      49                 : #include "plstr.h"
      50                 : #include "nsIPrefService.h"
      51                 : #include "nsIPrefBranch.h"
      52                 : #include "nsServiceManagerUtils.h"
      53                 : #include "nsIOService.h"
      54                 : 
      55                 : #include "mozilla/FunctionTimer.h"
      56                 : 
      57                 : // XXX: There is no good header file to put these in. :(
      58                 : namespace mozilla { namespace psm {
      59                 : 
      60                 : void InitializeSSLServerCertVerificationThreads();
      61                 : void StopSSLServerCertVerificationThreads();
      62                 : 
      63                 : } } // namespace mozilla::psm
      64                 : 
      65                 : using namespace mozilla;
      66                 : 
      67                 : #if defined(PR_LOGGING)
      68                 : PRLogModuleInfo *gSocketTransportLog = nsnull;
      69                 : #endif
      70                 : 
      71                 : nsSocketTransportService *gSocketTransportService = nsnull;
      72                 : PRThread                 *gSocketThread           = nsnull;
      73                 : 
      74                 : #define SEND_BUFFER_PREF "network.tcp.sendbuffer"
      75                 : #define SOCKET_LIMIT_TARGET 550U
      76                 : #define SOCKET_LIMIT_MIN     50U
      77                 : 
      78                 : PRUint32 nsSocketTransportService::gMaxCount;
      79                 : PRCallOnceType nsSocketTransportService::gMaxCountInitOnce;
      80                 : 
      81                 : //-----------------------------------------------------------------------------
      82                 : // ctor/dtor (called on the main/UI thread by the service manager)
      83                 : 
      84            1419 : nsSocketTransportService::nsSocketTransportService()
      85                 :     : mThread(nsnull)
      86                 :     , mThreadEvent(nsnull)
      87                 :     , mAutodialEnabled(false)
      88                 :     , mLock("nsSocketTransportService::mLock")
      89                 :     , mInitialized(false)
      90                 :     , mShuttingDown(false)
      91                 :     , mActiveListSize(SOCKET_LIMIT_MIN)
      92                 :     , mIdleListSize(SOCKET_LIMIT_MIN)
      93                 :     , mActiveCount(0)
      94                 :     , mIdleCount(0)
      95                 :     , mSendBufferSize(0)
      96            1419 :     , mProbedMaxCount(false)
      97                 : {
      98                 : #if defined(PR_LOGGING)
      99            1419 :     gSocketTransportLog = PR_NewLogModule("nsSocketTransport");
     100                 : #endif
     101                 : 
     102            1419 :     NS_ASSERTION(NS_IsMainThread(), "wrong thread");
     103                 : 
     104            1419 :     PR_CallOnce(&gMaxCountInitOnce, DiscoverMaxCount);
     105                 :     mActiveList = (SocketContext *)
     106            1419 :         moz_xmalloc(sizeof(SocketContext) * mActiveListSize);
     107                 :     mIdleList = (SocketContext *)
     108            1419 :         moz_xmalloc(sizeof(SocketContext) * mIdleListSize);
     109                 :     mPollList = (PRPollDesc *)
     110            1419 :         moz_xmalloc(sizeof(PRPollDesc) * (mActiveListSize + 1));
     111                 : 
     112            1419 :     NS_ASSERTION(!gSocketTransportService, "must not instantiate twice");
     113            1419 :     gSocketTransportService = this;
     114            1419 : }
     115                 : 
     116            4245 : nsSocketTransportService::~nsSocketTransportService()
     117                 : {
     118            1415 :     NS_ASSERTION(NS_IsMainThread(), "wrong thread");
     119            1415 :     NS_ASSERTION(!mInitialized, "not shutdown properly");
     120                 :     
     121            1415 :     if (mThreadEvent)
     122            1415 :         PR_DestroyPollableEvent(mThreadEvent);
     123                 : 
     124            1415 :     moz_free(mActiveList);
     125            1415 :     moz_free(mIdleList);
     126            1415 :     moz_free(mPollList);
     127            1415 :     gSocketTransportService = nsnull;
     128            5660 : }
     129                 : 
     130                 : //-----------------------------------------------------------------------------
     131                 : // event queue (any thread)
     132                 : 
     133                 : already_AddRefed<nsIThread>
     134           49891 : nsSocketTransportService::GetThreadSafely()
     135                 : {
     136           99782 :     MutexAutoLock lock(mLock);
     137           49891 :     nsIThread* result = mThread;
     138           49891 :     NS_IF_ADDREF(result);
     139           49891 :     return result;
     140                 : }
     141                 : 
     142                 : NS_IMETHODIMP
     143           49887 : nsSocketTransportService::Dispatch(nsIRunnable *event, PRUint32 flags)
     144                 : {
     145           49887 :     SOCKET_LOG(("STS dispatch [%p]\n", event));
     146                 : 
     147           99774 :     nsCOMPtr<nsIThread> thread = GetThreadSafely();
     148           49887 :     NS_ENSURE_TRUE(thread, NS_ERROR_NOT_INITIALIZED);
     149           49887 :     nsresult rv = thread->Dispatch(event, flags);
     150           49887 :     if (rv == NS_ERROR_UNEXPECTED) {
     151                 :         // Thread is no longer accepting events. We must have just shut it
     152                 :         // down on the main thread. Pretend we never saw it.
     153               0 :         rv = NS_ERROR_NOT_INITIALIZED;
     154                 :     }
     155           49887 :     return rv;
     156                 : }
     157                 : 
     158                 : NS_IMETHODIMP
     159               4 : nsSocketTransportService::IsOnCurrentThread(bool *result)
     160                 : {
     161               8 :     nsCOMPtr<nsIThread> thread = GetThreadSafely();
     162               4 :     NS_ENSURE_TRUE(thread, NS_ERROR_NOT_INITIALIZED);
     163               4 :     return thread->IsOnCurrentThread(result);
     164                 : }
     165                 : 
     166                 : //-----------------------------------------------------------------------------
     167                 : // socket api (socket thread only)
     168                 : 
     169                 : NS_IMETHODIMP
     170               0 : nsSocketTransportService::NotifyWhenCanAttachSocket(nsIRunnable *event)
     171                 : {
     172               0 :     SOCKET_LOG(("nsSocketTransportService::NotifyWhenCanAttachSocket\n"));
     173                 : 
     174               0 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
     175                 : 
     176               0 :     if (CanAttachSocket()) {
     177               0 :         return Dispatch(event, NS_DISPATCH_NORMAL);
     178                 :     }
     179                 : 
     180               0 :     mPendingSocketQ.PutEvent(event);
     181               0 :     return NS_OK;
     182                 : }
     183                 : 
     184                 : NS_IMETHODIMP
     185            6296 : nsSocketTransportService::AttachSocket(PRFileDesc *fd, nsASocketHandler *handler)
     186                 : {
     187            6296 :     SOCKET_LOG(("nsSocketTransportService::AttachSocket [handler=%x]\n", handler));
     188                 : 
     189            6296 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
     190                 : 
     191            6296 :     if (!CanAttachSocket()) {
     192               0 :         return NS_ERROR_NOT_AVAILABLE;
     193                 :     }
     194                 : 
     195                 :     SocketContext sock;
     196            6296 :     sock.mFD = fd;
     197            6296 :     sock.mHandler = handler;
     198            6296 :     sock.mElapsedTime = 0;
     199                 : 
     200            6296 :     nsresult rv = AddToIdleList(&sock);
     201            6296 :     if (NS_SUCCEEDED(rv))
     202            6296 :         NS_ADDREF(handler);
     203            6296 :     return rv;
     204                 : }
     205                 : 
     206                 : nsresult
     207            6296 : nsSocketTransportService::DetachSocket(SocketContext *listHead, SocketContext *sock)
     208                 : {
     209            6296 :     SOCKET_LOG(("nsSocketTransportService::DetachSocket [handler=%x]\n", sock->mHandler));
     210            6296 :     NS_ABORT_IF_FALSE((listHead == mActiveList) || (listHead == mIdleList),
     211                 :                       "DetachSocket invalid head");
     212                 : 
     213                 :     // inform the handler that this socket is going away
     214            6296 :     sock->mHandler->OnSocketDetached(sock->mFD);
     215                 : 
     216                 :     // cleanup
     217            6296 :     sock->mFD = nsnull;
     218            6296 :     NS_RELEASE(sock->mHandler);
     219                 : 
     220            6296 :     if (listHead == mActiveList)
     221            3413 :         RemoveFromPollList(sock);
     222                 :     else
     223            2883 :         RemoveFromIdleList(sock);
     224                 : 
     225                 :     // NOTE: sock is now an invalid pointer
     226                 :     
     227                 :     //
     228                 :     // notify the first element on the pending socket queue...
     229                 :     //
     230           12592 :     nsCOMPtr<nsIRunnable> event;
     231            6296 :     if (mPendingSocketQ.GetPendingEvent(getter_AddRefs(event))) {
     232                 :         // move event from pending queue to dispatch queue
     233               0 :         return Dispatch(event, NS_DISPATCH_NORMAL);
     234                 :     }
     235            6296 :     return NS_OK;
     236                 : }
     237                 : 
     238                 : nsresult
     239            9154 : nsSocketTransportService::AddToPollList(SocketContext *sock)
     240                 : {
     241            9154 :     NS_ABORT_IF_FALSE(!(((PRUint32)(sock - mActiveList)) < mActiveListSize),
     242                 :                       "AddToPollList Socket Already Active");
     243                 : 
     244            9154 :     SOCKET_LOG(("nsSocketTransportService::AddToPollList [handler=%x]\n", sock->mHandler));
     245            9154 :     if (mActiveCount == mActiveListSize) {
     246               0 :         SOCKET_LOG(("  Active List size of %d met\n", mActiveCount));
     247               0 :         if (!GrowActiveList()) {
     248               0 :             NS_ERROR("too many active sockets");
     249               0 :             return NS_ERROR_OUT_OF_MEMORY;
     250                 :         }
     251                 :     }
     252                 :     
     253            9154 :     mActiveList[mActiveCount] = *sock;
     254            9154 :     mActiveCount++;
     255                 : 
     256            9154 :     mPollList[mActiveCount].fd = sock->mFD;
     257            9154 :     mPollList[mActiveCount].in_flags = sock->mHandler->mPollFlags;
     258            9154 :     mPollList[mActiveCount].out_flags = 0;
     259                 : 
     260            9154 :     SOCKET_LOG(("  active=%u idle=%u\n", mActiveCount, mIdleCount));
     261            9154 :     return NS_OK;
     262                 : }
     263                 : 
     264                 : void
     265            9154 : nsSocketTransportService::RemoveFromPollList(SocketContext *sock)
     266                 : {
     267            9154 :     SOCKET_LOG(("nsSocketTransportService::RemoveFromPollList [handler=%x]\n", sock->mHandler));
     268                 : 
     269            9154 :     PRUint32 index = sock - mActiveList;
     270            9154 :     NS_ABORT_IF_FALSE(index < mActiveListSize, "invalid index");
     271                 : 
     272            9154 :     SOCKET_LOG(("  index=%u mActiveCount=%u\n", index, mActiveCount));
     273                 : 
     274            9154 :     if (index != mActiveCount-1) {
     275            2919 :         mActiveList[index] = mActiveList[mActiveCount-1];
     276            2919 :         mPollList[index+1] = mPollList[mActiveCount];
     277                 :     }
     278            9154 :     mActiveCount--;
     279                 : 
     280            9154 :     SOCKET_LOG(("  active=%u idle=%u\n", mActiveCount, mIdleCount));
     281            9154 : }
     282                 : 
     283                 : nsresult
     284           12037 : nsSocketTransportService::AddToIdleList(SocketContext *sock)
     285                 : {
     286           12037 :     NS_ABORT_IF_FALSE(!(((PRUint32)(sock - mIdleList)) < mIdleListSize),
     287                 :                       "AddToIdlelList Socket Already Idle");
     288                 : 
     289           12037 :     SOCKET_LOG(("nsSocketTransportService::AddToIdleList [handler=%x]\n", sock->mHandler));
     290           12037 :     if (mIdleCount == mIdleListSize) {
     291               0 :         SOCKET_LOG(("  Idle List size of %d met\n", mIdleCount));
     292               0 :         if (!GrowIdleList()) {
     293               0 :             NS_ERROR("too many idle sockets");
     294               0 :             return NS_ERROR_OUT_OF_MEMORY;
     295                 :         }
     296                 :     }
     297                 : 
     298           12037 :     mIdleList[mIdleCount] = *sock;
     299           12037 :     mIdleCount++;
     300                 : 
     301           12037 :     SOCKET_LOG(("  active=%u idle=%u\n", mActiveCount, mIdleCount));
     302           12037 :     return NS_OK;
     303                 : }
     304                 : 
     305                 : void
     306           12037 : nsSocketTransportService::RemoveFromIdleList(SocketContext *sock)
     307                 : {
     308           12037 :     SOCKET_LOG(("nsSocketTransportService::RemoveFromIdleList [handler=%x]\n", sock->mHandler));
     309                 : 
     310           12037 :     PRUint32 index = sock - mIdleList;
     311           12037 :     NS_ASSERTION(index < mIdleListSize, "invalid index in idle list");
     312                 : 
     313           12037 :     if (index != mIdleCount-1)
     314            1251 :         mIdleList[index] = mIdleList[mIdleCount-1];
     315           12037 :     mIdleCount--;
     316                 : 
     317           12037 :     SOCKET_LOG(("  active=%u idle=%u\n", mActiveCount, mIdleCount));
     318           12037 : }
     319                 : 
     320                 : void
     321            5741 : nsSocketTransportService::MoveToIdleList(SocketContext *sock)
     322                 : {
     323            5741 :     nsresult rv = AddToIdleList(sock);
     324            5741 :     if (NS_FAILED(rv))
     325               0 :         DetachSocket(mActiveList, sock);
     326                 :     else
     327            5741 :         RemoveFromPollList(sock);
     328            5741 : }
     329                 : 
     330                 : void
     331            9154 : nsSocketTransportService::MoveToPollList(SocketContext *sock)
     332                 : {
     333            9154 :     nsresult rv = AddToPollList(sock);
     334            9154 :     if (NS_FAILED(rv))
     335               0 :         DetachSocket(mIdleList, sock);
     336                 :     else
     337            9154 :         RemoveFromIdleList(sock);
     338            9154 : }
     339                 : 
     340                 : bool
     341               0 : nsSocketTransportService::GrowActiveList()
     342                 : {
     343               0 :     PRInt32 toAdd = gMaxCount - mActiveListSize;
     344               0 :     if (toAdd > 100)
     345               0 :         toAdd = 100;
     346               0 :     if (toAdd < 1)
     347               0 :         return false;
     348                 :     
     349               0 :     mActiveListSize += toAdd;
     350                 :     mActiveList = (SocketContext *)
     351               0 :         moz_xrealloc(mActiveList, sizeof(SocketContext) * mActiveListSize);
     352                 :     mPollList = (PRPollDesc *)
     353               0 :         moz_xrealloc(mPollList, sizeof(PRPollDesc) * (mActiveListSize + 1));
     354               0 :     return true;
     355                 : }
     356                 : 
     357                 : bool
     358               0 : nsSocketTransportService::GrowIdleList()
     359                 : {
     360               0 :     PRInt32 toAdd = gMaxCount - mIdleListSize;
     361               0 :     if (toAdd > 100)
     362               0 :         toAdd = 100;
     363               0 :     if (toAdd < 1)
     364               0 :         return false;
     365                 : 
     366               0 :     mIdleListSize += toAdd;
     367                 :     mIdleList = (SocketContext *)
     368               0 :         moz_xrealloc(mIdleList, sizeof(SocketContext) * mIdleListSize);
     369               0 :     return true;
     370                 : }
     371                 : 
     372                 : PRIntervalTime
     373           61371 : nsSocketTransportService::PollTimeout()
     374                 : {
     375           61371 :     if (mActiveCount == 0)
     376            3667 :         return NS_SOCKET_POLL_TIMEOUT;
     377                 : 
     378                 :     // compute minimum time before any socket timeout expires.
     379           57704 :     PRUint32 minR = PR_UINT16_MAX;
     380          199531 :     for (PRUint32 i=0; i<mActiveCount; ++i) {
     381          141827 :         const SocketContext &s = mActiveList[i];
     382                 :         // mPollTimeout could be less than mElapsedTime if setTimeout
     383                 :         // was called with a value smaller than mElapsedTime.
     384                 :         PRUint32 r = (s.mElapsedTime < s.mHandler->mPollTimeout)
     385                 :           ? s.mHandler->mPollTimeout - s.mElapsedTime
     386          141827 :           : 0;
     387          141827 :         if (r < minR)
     388               0 :             minR = r;
     389                 :     }
     390           57704 :     SOCKET_LOG(("poll timeout: %lu\n", minR));
     391           57704 :     return PR_SecondsToInterval(minR);
     392                 : }
     393                 : 
     394                 : PRInt32
     395           61371 : nsSocketTransportService::Poll(bool wait, PRUint32 *interval)
     396                 : {
     397                 :     PRPollDesc *pollList;
     398                 :     PRUint32 pollCount;
     399                 :     PRIntervalTime pollTimeout;
     400                 : 
     401           61371 :     if (mPollList[0].fd) {
     402           61371 :         mPollList[0].out_flags = 0;
     403           61371 :         pollList = mPollList;
     404           61371 :         pollCount = mActiveCount + 1;
     405           61371 :         pollTimeout = PollTimeout();
     406                 :     }
     407                 :     else {
     408                 :         // no pollable event, so busy wait...
     409               0 :         pollCount = mActiveCount;
     410               0 :         if (pollCount)
     411               0 :             pollList = &mPollList[1];
     412                 :         else
     413               0 :             pollList = nsnull;
     414               0 :         pollTimeout = PR_MillisecondsToInterval(25);
     415                 :     }
     416                 : 
     417           61371 :     if (!wait)
     418           15049 :         pollTimeout = PR_INTERVAL_NO_WAIT;
     419                 : 
     420           61371 :     PRIntervalTime ts = PR_IntervalNow();
     421                 : 
     422           61371 :     SOCKET_LOG(("    timeout = %i milliseconds\n",
     423                 :          PR_IntervalToMilliseconds(pollTimeout)));
     424           61371 :     PRInt32 rv = PR_Poll(pollList, pollCount, pollTimeout);
     425                 : 
     426           61371 :     PRIntervalTime passedInterval = PR_IntervalNow() - ts;
     427                 : 
     428           61371 :     SOCKET_LOG(("    ...returned after %i milliseconds\n",
     429                 :          PR_IntervalToMilliseconds(passedInterval))); 
     430                 : 
     431           61371 :     *interval = PR_IntervalToSeconds(passedInterval);
     432           61371 :     return rv;
     433                 : }
     434                 : 
     435                 : //-----------------------------------------------------------------------------
     436                 : // xpcom api
     437                 : 
     438          514412 : NS_IMPL_THREADSAFE_ISUPPORTS6(nsSocketTransportService,
     439                 :                               nsISocketTransportService,
     440                 :                               nsIEventTarget,
     441                 :                               nsIThreadObserver,
     442                 :                               nsIRunnable,
     443                 :                               nsPISocketTransportService,
     444                 :                               nsIObserver)
     445                 : 
     446                 : // called from main thread only
     447                 : NS_IMETHODIMP
     448            2845 : nsSocketTransportService::Init()
     449                 : {
     450                 :     NS_TIME_FUNCTION;
     451                 : 
     452            2845 :     if (!NS_IsMainThread()) {
     453               0 :         NS_ERROR("wrong thread");
     454               0 :         return NS_ERROR_UNEXPECTED;
     455                 :     }
     456                 : 
     457            2845 :     if (mInitialized)
     458            1419 :         return NS_OK;
     459                 : 
     460            1426 :     if (mShuttingDown)
     461               0 :         return NS_ERROR_UNEXPECTED;
     462                 : 
     463                 :     // Don't initialize inside the offline mode
     464            1426 :     if (gIOService->IsOffline() && !gIOService->IsComingOnline())
     465               0 :         return NS_ERROR_OFFLINE;
     466                 : 
     467            1426 :     if (!mThreadEvent) {
     468            1419 :         mThreadEvent = PR_NewPollableEvent();
     469                 :         //
     470                 :         // NOTE: per bug 190000, this failure could be caused by Zone-Alarm
     471                 :         // or similar software.
     472                 :         //
     473                 :         // NOTE: per bug 191739, this failure could also be caused by lack
     474                 :         // of a loopback device on Windows and OS/2 platforms (NSPR creates
     475                 :         // a loopback socket pair on these platforms to implement a pollable
     476                 :         // event object).  if we can't create a pollable event, then we'll
     477                 :         // have to "busy wait" to implement the socket event queue :-(
     478                 :         //
     479            1419 :         if (!mThreadEvent) {
     480               0 :             NS_WARNING("running socket transport thread without a pollable event");
     481               0 :             SOCKET_LOG(("running socket transport thread without a pollable event"));
     482                 :         }
     483                 :     }
     484                 :     
     485                 :     NS_TIME_FUNCTION_MARK("Created thread");
     486                 : 
     487            2852 :     nsCOMPtr<nsIThread> thread;
     488            1426 :     nsresult rv = NS_NewThread(getter_AddRefs(thread), this);
     489            1426 :     if (NS_FAILED(rv)) return rv;
     490                 :     
     491                 :     {
     492            2852 :         MutexAutoLock lock(mLock);
     493                 :         // Install our mThread, protecting against concurrent readers
     494            1426 :         thread.swap(mThread);
     495                 :     }
     496                 : 
     497            2852 :     nsCOMPtr<nsIPrefBranch> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
     498            1426 :     if (tmpPrefService) 
     499            1426 :         tmpPrefService->AddObserver(SEND_BUFFER_PREF, this, false);
     500            1426 :     UpdatePrefs();
     501                 : 
     502                 :     NS_TIME_FUNCTION_MARK("UpdatePrefs");
     503                 : 
     504            1426 :     mInitialized = true;
     505            1426 :     return NS_OK;
     506                 : }
     507                 : 
     508                 : // called from main thread only
     509                 : NS_IMETHODIMP
     510            1426 : nsSocketTransportService::Shutdown()
     511                 : {
     512            1426 :     SOCKET_LOG(("nsSocketTransportService::Shutdown\n"));
     513                 : 
     514            1426 :     NS_ENSURE_STATE(NS_IsMainThread());
     515                 : 
     516            1426 :     if (!mInitialized)
     517               0 :         return NS_OK;
     518                 : 
     519            1426 :     if (mShuttingDown)
     520               0 :         return NS_ERROR_UNEXPECTED;
     521                 : 
     522                 :     {
     523            2852 :         MutexAutoLock lock(mLock);
     524                 : 
     525                 :         // signal the socket thread to shutdown
     526            1426 :         mShuttingDown = true;
     527                 : 
     528            1426 :         if (mThreadEvent)
     529            1426 :             PR_SetPollableEvent(mThreadEvent);
     530                 :         // else wait for Poll timeout
     531                 :     }
     532                 : 
     533                 :     // join with thread
     534            1426 :     mThread->Shutdown();
     535                 :     {
     536            2852 :         MutexAutoLock lock(mLock);
     537                 :         // Drop our reference to mThread and make sure that any concurrent
     538                 :         // readers are excluded
     539            1426 :         mThread = nsnull;
     540                 :     }
     541                 : 
     542            2852 :     nsCOMPtr<nsIPrefBranch> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
     543            1426 :     if (tmpPrefService) 
     544            1426 :         tmpPrefService->RemoveObserver(SEND_BUFFER_PREF, this);
     545                 : 
     546            1426 :     mInitialized = false;
     547            1426 :     mShuttingDown = false;
     548                 : 
     549            1426 :     return NS_OK;
     550                 : }
     551                 : 
     552                 : NS_IMETHODIMP
     553            3014 : nsSocketTransportService::CreateTransport(const char **types,
     554                 :                                           PRUint32 typeCount,
     555                 :                                           const nsACString &host,
     556                 :                                           PRInt32 port,
     557                 :                                           nsIProxyInfo *proxyInfo,
     558                 :                                           nsISocketTransport **result)
     559                 : {
     560            3014 :     NS_ENSURE_TRUE(mInitialized, NS_ERROR_OFFLINE);
     561            3014 :     NS_ENSURE_TRUE(port >= 0 && port <= 0xFFFF, NS_ERROR_ILLEGAL_VALUE);
     562                 : 
     563            3013 :     nsSocketTransport *trans = new nsSocketTransport();
     564            3013 :     if (!trans)
     565               0 :         return NS_ERROR_OUT_OF_MEMORY;
     566            3013 :     NS_ADDREF(trans);
     567                 : 
     568            3013 :     nsresult rv = trans->Init(types, typeCount, host, port, proxyInfo);
     569            3013 :     if (NS_FAILED(rv)) {
     570               0 :         NS_RELEASE(trans);
     571               0 :         return rv;
     572                 :     }
     573                 : 
     574            3013 :     *result = trans;
     575            3013 :     return NS_OK;
     576                 : }
     577                 : 
     578                 : NS_IMETHODIMP
     579               0 : nsSocketTransportService::GetAutodialEnabled(bool *value)
     580                 : {
     581               0 :     *value = mAutodialEnabled;
     582               0 :     return NS_OK;
     583                 : }
     584                 : 
     585                 : NS_IMETHODIMP
     586            1426 : nsSocketTransportService::SetAutodialEnabled(bool value)
     587                 : {
     588            1426 :     mAutodialEnabled = value;
     589            1426 :     return NS_OK;
     590                 : }
     591                 : 
     592                 : NS_IMETHODIMP
     593           50981 : nsSocketTransportService::OnDispatchedEvent(nsIThreadInternal *thread)
     594                 : {
     595          101962 :     MutexAutoLock lock(mLock);
     596           50981 :     if (mThreadEvent)
     597           50981 :         PR_SetPollableEvent(mThreadEvent);
     598           50981 :     return NS_OK;
     599                 : }
     600                 : 
     601                 : NS_IMETHODIMP
     602           54371 : nsSocketTransportService::OnProcessNextEvent(nsIThreadInternal *thread,
     603                 :                                              bool mayWait, PRUint32 depth)
     604                 : {
     605           54371 :     return NS_OK;
     606                 : }
     607                 : 
     608                 : NS_IMETHODIMP
     609           54371 : nsSocketTransportService::AfterProcessNextEvent(nsIThreadInternal* thread,
     610                 :                                                 PRUint32 depth)
     611                 : {
     612           54371 :     return NS_OK;
     613                 : }
     614                 : 
     615                 : NS_IMETHODIMP
     616            1426 : nsSocketTransportService::Run()
     617                 : {
     618            1426 :     SOCKET_LOG(("STS thread init\n"));
     619                 : 
     620            1426 :     psm::InitializeSSLServerCertVerificationThreads();
     621                 : 
     622            1426 :     gSocketThread = PR_GetCurrentThread();
     623                 : 
     624                 :     // add thread event to poll list (mThreadEvent may be NULL)
     625            1426 :     mPollList[0].fd = mThreadEvent;
     626            1426 :     mPollList[0].in_flags = PR_POLL_READ;
     627            1426 :     mPollList[0].out_flags = 0;
     628                 : 
     629            1426 :     nsIThread *thread = NS_GetCurrentThread();
     630                 : 
     631                 :     // hook ourselves up to observe event processing for this thread
     632            2852 :     nsCOMPtr<nsIThreadInternal> threadInt = do_QueryInterface(thread);
     633            1426 :     threadInt->SetObserver(this);
     634                 : 
     635                 :     // make sure the pseudo random number generator is seeded on this thread
     636            1426 :     srand(PR_Now());
     637                 : 
     638           44905 :     for (;;) {
     639           46331 :         bool pendingEvents = false;
     640           46331 :         thread->HasPendingEvents(&pendingEvents);
     641                 : 
     642           61371 :         do {
     643                 :             // If there are pending events for this thread then
     644                 :             // DoPollIteration() should service the network without blocking.
     645           61371 :             DoPollIteration(!pendingEvents);
     646                 :             
     647                 :             // If nothing was pending before the poll, it might be now
     648           61371 :             if (!pendingEvents)
     649           46322 :                 thread->HasPendingEvents(&pendingEvents);
     650                 : 
     651           61371 :             if (pendingEvents) {
     652           50888 :                 NS_ProcessNextEvent(thread);
     653           50888 :                 pendingEvents = false;
     654           50888 :                 thread->HasPendingEvents(&pendingEvents);
     655                 :             }
     656                 :         } while (pendingEvents);
     657                 : 
     658                 :         // now that our event queue is empty, check to see if we should exit
     659                 :         {
     660           92662 :             MutexAutoLock lock(mLock);
     661           46331 :             if (mShuttingDown)
     662                 :                 break;
     663                 :         }
     664                 :     }
     665                 : 
     666            1426 :     SOCKET_LOG(("STS shutting down thread\n"));
     667                 : 
     668                 :     // detach any sockets
     669                 :     PRInt32 i;
     670            1438 :     for (i=mActiveCount-1; i>=0; --i)
     671              12 :         DetachSocket(mActiveList, &mActiveList[i]);
     672            1427 :     for (i=mIdleCount-1; i>=0; --i)
     673               1 :         DetachSocket(mIdleList, &mIdleList[i]);
     674                 : 
     675                 :     // Final pass over the event queue. This makes sure that events posted by
     676                 :     // socket detach handlers get processed.
     677            1426 :     NS_ProcessPendingEvents(thread);
     678                 : 
     679            1426 :     gSocketThread = nsnull;
     680                 : 
     681            1426 :     psm::StopSSLServerCertVerificationThreads();
     682                 : 
     683            1426 :     SOCKET_LOG(("STS thread exit\n"));
     684            1426 :     return NS_OK;
     685                 : }
     686                 : 
     687                 : nsresult
     688           61371 : nsSocketTransportService::DoPollIteration(bool wait)
     689                 : {
     690           61371 :     SOCKET_LOG(("STS poll iter [%d]\n", wait));
     691                 : 
     692                 :     PRInt32 i, count;
     693                 : 
     694                 :     //
     695                 :     // poll loop
     696                 :     //
     697                 :     // walk active list backwards to see if any sockets should actually be
     698                 :     // idle, then walk the idle list backwards to see if any idle sockets
     699                 :     // should become active.  take care to check only idle sockets that
     700                 :     // were idle to begin with ;-)
     701                 :     //
     702           61371 :     count = mIdleCount;
     703          203039 :     for (i=mActiveCount-1; i>=0; --i) {
     704                 :         //---
     705          141668 :         SOCKET_LOG(("  active [%u] { handler=%x condition=%x pollflags=%hu }\n", i,
     706                 :             mActiveList[i].mHandler,
     707                 :             mActiveList[i].mHandler->mCondition,
     708                 :             mActiveList[i].mHandler->mPollFlags));
     709                 :         //---
     710          141668 :         if (NS_FAILED(mActiveList[i].mHandler->mCondition))
     711            3254 :             DetachSocket(mActiveList, &mActiveList[i]);
     712                 :         else {
     713          138414 :             PRUint16 in_flags = mActiveList[i].mHandler->mPollFlags;
     714          138414 :             if (in_flags == 0)
     715            5741 :                 MoveToIdleList(&mActiveList[i]);
     716                 :             else {
     717                 :                 // update poll flags
     718          132673 :                 mPollList[i+1].in_flags = in_flags;
     719          132673 :                 mPollList[i+1].out_flags = 0;
     720                 :             }
     721                 :         }
     722                 :     }
     723           91000 :     for (i=count-1; i>=0; --i) {
     724                 :         //---
     725           29629 :         SOCKET_LOG(("  idle [%u] { handler=%x condition=%x pollflags=%hu }\n", i,
     726                 :             mIdleList[i].mHandler,
     727                 :             mIdleList[i].mHandler->mCondition,
     728                 :             mIdleList[i].mHandler->mPollFlags));
     729                 :         //---
     730           29629 :         if (NS_FAILED(mIdleList[i].mHandler->mCondition))
     731            2882 :             DetachSocket(mIdleList, &mIdleList[i]);
     732           26747 :         else if (mIdleList[i].mHandler->mPollFlags != 0)
     733            9154 :             MoveToPollList(&mIdleList[i]);
     734                 :     }
     735                 : 
     736           61371 :     SOCKET_LOG(("  calling PR_Poll [active=%u idle=%u]\n", mActiveCount, mIdleCount));
     737                 : 
     738                 : #if defined(XP_WIN)
     739                 :     // 30 active connections is the historic limit before firefox 7's 256. A few
     740                 :     //  windows systems have troubles with the higher limit, so actively probe a
     741                 :     // limit the first time we exceed 30.
     742                 :     if ((mActiveCount > 30) && !mProbedMaxCount)
     743                 :         ProbeMaxCount();
     744                 : #endif
     745                 : 
     746                 :     // Measures seconds spent while blocked on PR_Poll
     747                 :     PRUint32 pollInterval;
     748                 : 
     749           61371 :     PRInt32 n = Poll(wait, &pollInterval);
     750           61371 :     if (n < 0) {
     751               0 :         SOCKET_LOG(("  PR_Poll error [%d]\n", PR_GetError()));
     752                 :     }
     753                 :     else {
     754                 :         //
     755                 :         // service "active" sockets...
     756                 :         //
     757          203198 :         for (i=0; i<PRInt32(mActiveCount); ++i) {
     758          141827 :             PRPollDesc &desc = mPollList[i+1];
     759          141827 :             SocketContext &s = mActiveList[i];
     760          141827 :             if (n > 0 && desc.out_flags != 0) {
     761           32757 :                 s.mElapsedTime = 0;
     762           32757 :                 s.mHandler->OnSocketReady(desc.fd, desc.out_flags);
     763                 :             }
     764                 :             // check for timeout errors unless disabled...
     765          109070 :             else if (s.mHandler->mPollTimeout != PR_UINT16_MAX) {
     766                 :                 // update elapsed time counter
     767               0 :                 if (NS_UNLIKELY(pollInterval > (PR_UINT16_MAX - s.mElapsedTime)))
     768               0 :                     s.mElapsedTime = PR_UINT16_MAX;
     769                 :                 else
     770               0 :                     s.mElapsedTime += PRUint16(pollInterval);
     771                 :                 // check for timeout expiration 
     772               0 :                 if (s.mElapsedTime >= s.mHandler->mPollTimeout) {
     773               0 :                     s.mElapsedTime = 0;
     774               0 :                     s.mHandler->OnSocketReady(desc.fd, -1);
     775                 :                 }
     776                 :             }
     777                 :         }
     778                 : 
     779                 :         //
     780                 :         // check for "dead" sockets and remove them (need to do this in
     781                 :         // reverse order obviously).
     782                 :         //
     783          203198 :         for (i=mActiveCount-1; i>=0; --i) {
     784          141827 :             if (NS_FAILED(mActiveList[i].mHandler->mCondition))
     785             147 :                 DetachSocket(mActiveList, &mActiveList[i]);
     786                 :         }
     787                 : 
     788           61371 :         if (n != 0 && mPollList[0].out_flags == PR_POLL_READ) {
     789                 :             // acknowledge pollable event (wait should not block)
     790           44755 :             if (PR_WaitForPollableEvent(mThreadEvent) != PR_SUCCESS) {
     791                 :                 // On Windows, the TCP loopback connection in the
     792                 :                 // pollable event may become broken when a laptop
     793                 :                 // switches between wired and wireless networks or
     794                 :                 // wakes up from hibernation.  We try to create a
     795                 :                 // new pollable event.  If that fails, we fall back
     796                 :                 // on "busy wait".
     797                 :                 {
     798               0 :                     MutexAutoLock lock(mLock);
     799               0 :                     PR_DestroyPollableEvent(mThreadEvent);
     800               0 :                     mThreadEvent = PR_NewPollableEvent();
     801                 :                 }
     802               0 :                 if (!mThreadEvent) {
     803                 :                     NS_WARNING("running socket transport thread without "
     804               0 :                                "a pollable event");
     805               0 :                     SOCKET_LOG(("running socket transport thread without "
     806                 :                          "a pollable event"));
     807                 :                 }
     808               0 :                 mPollList[0].fd = mThreadEvent;
     809                 :                 // mPollList[0].in_flags was already set to PR_POLL_READ
     810                 :                 // in Run().
     811               0 :                 mPollList[0].out_flags = 0;
     812                 :             }
     813                 :         }
     814                 :     }
     815                 : 
     816           61371 :     return NS_OK;
     817                 : }
     818                 : 
     819                 : nsresult
     820            1426 : nsSocketTransportService::UpdatePrefs()
     821                 : {
     822            1426 :     mSendBufferSize = 0;
     823                 :     
     824            2852 :     nsCOMPtr<nsIPrefBranch> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
     825            1426 :     if (tmpPrefService) {
     826                 :         PRInt32 bufferSize;
     827            1426 :         nsresult rv = tmpPrefService->GetIntPref(SEND_BUFFER_PREF, &bufferSize);
     828            1426 :         if (NS_SUCCEEDED(rv) && bufferSize > 0)
     829               0 :             mSendBufferSize = bufferSize;
     830                 :     }
     831                 :     
     832            1426 :     return NS_OK;
     833                 : }
     834                 : 
     835                 : NS_IMETHODIMP
     836               0 : nsSocketTransportService::Observe(nsISupports *subject,
     837                 :                                   const char *topic,
     838                 :                                   const PRUnichar *data)
     839                 : {
     840               0 :     if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
     841               0 :         UpdatePrefs();
     842                 :     }
     843               0 :     return NS_OK;
     844                 : }
     845                 : 
     846                 : NS_IMETHODIMP
     847            3006 : nsSocketTransportService::GetSendBufferSize(PRInt32 *value)
     848                 : {
     849            3006 :     *value = mSendBufferSize;
     850            3006 :     return NS_OK;
     851                 : }
     852                 : 
     853                 : 
     854                 : /// ugly OS specific includes are placed at the bottom of the src for clarity
     855                 : 
     856                 : #if defined(XP_WIN)
     857                 : #include <windows.h>
     858                 : #elif defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX)
     859                 : #include <sys/resource.h>
     860                 : #endif
     861                 : 
     862                 : // Right now the only need to do this is on windows.
     863                 : #if defined(XP_WIN)
     864                 : void
     865                 : nsSocketTransportService::ProbeMaxCount()
     866                 : {
     867                 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
     868                 : 
     869                 :     if (mProbedMaxCount)
     870                 :         return;
     871                 :     mProbedMaxCount = true;
     872                 : 
     873                 :     PRInt32 startedMaxCount = gMaxCount;
     874                 : 
     875                 :     // Allocate and test a PR_Poll up to the gMaxCount number of unconnected
     876                 :     // sockets. See bug 692260 - windows should be able to handle 1000 sockets
     877                 :     // in select() without a problem, but LSPs have been known to balk at lower
     878                 :     // numbers. (64 in the bug).
     879                 : 
     880                 :     // Allocate
     881                 :     struct PRPollDesc pfd[SOCKET_LIMIT_TARGET];
     882                 :     PRUint32 numAllocated = 0;
     883                 : 
     884                 :     for (PRUint32 index = 0 ; index < gMaxCount; ++index) {
     885                 :         pfd[index].in_flags = PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT;
     886                 :         pfd[index].out_flags = 0;
     887                 :         pfd[index].fd =  PR_OpenTCPSocket(PR_AF_INET);
     888                 :         if (!pfd[index].fd) {
     889                 :             SOCKET_LOG(("Socket Limit Test index %d failed\n", index));
     890                 :             if (index < SOCKET_LIMIT_MIN)
     891                 :                 gMaxCount = SOCKET_LIMIT_MIN;
     892                 :             else
     893                 :                 gMaxCount = index;
     894                 :             break;
     895                 :         }
     896                 :         ++numAllocated;
     897                 :     }
     898                 : 
     899                 :     // Test
     900                 :     PR_STATIC_ASSERT(SOCKET_LIMIT_MIN >= 32U);
     901                 :     while (gMaxCount <= numAllocated) {
     902                 :         PRInt32 rv = PR_Poll(pfd, gMaxCount, PR_MillisecondsToInterval(0));
     903                 :         
     904                 :         SOCKET_LOG(("Socket Limit Test poll() size=%d rv=%d\n",
     905                 :                     gMaxCount, rv));
     906                 : 
     907                 :         if (rv >= 0)
     908                 :             break;
     909                 : 
     910                 :         SOCKET_LOG(("Socket Limit Test poll confirmationSize=%d rv=%d error=%d\n",
     911                 :                     gMaxCount, rv, PR_GetError()));
     912                 : 
     913                 :         gMaxCount -= 32;
     914                 :         if (gMaxCount <= SOCKET_LIMIT_MIN) {
     915                 :             gMaxCount = SOCKET_LIMIT_MIN;
     916                 :             break;
     917                 :         }
     918                 :     }
     919                 : 
     920                 :     // Free
     921                 :     for (PRUint32 index = 0 ; index < numAllocated; ++index)
     922                 :         if (pfd[index].fd)
     923                 :             PR_Close(pfd[index].fd);
     924                 : 
     925                 :     SOCKET_LOG(("Socket Limit Test max was confirmed at %d\n", gMaxCount));
     926                 : }
     927                 : #endif // windows
     928                 : 
     929                 : PRStatus
     930            1419 : nsSocketTransportService::DiscoverMaxCount()
     931                 : {
     932            1419 :     gMaxCount = SOCKET_LIMIT_MIN;
     933                 : 
     934                 : #if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX)
     935                 :     // On unix and os x network sockets and file
     936                 :     // descriptors are the same. OS X comes defaulted at 256,
     937                 :     // most linux at 1000. We can reliably use [sg]rlimit to
     938                 :     // query that and raise it. We will try to raise it 250 past
     939                 :     // our target number of SOCKET_LIMIT_TARGET so that some descriptors
     940                 :     // are still available for other things.
     941                 : 
     942                 :     struct rlimit rlimitData;
     943            1419 :     if (getrlimit(RLIMIT_NOFILE, &rlimitData) == -1)
     944               0 :         return PR_SUCCESS;
     945            1419 :     if (rlimitData.rlim_cur >=  SOCKET_LIMIT_TARGET + 250) {
     946            1419 :         gMaxCount = SOCKET_LIMIT_TARGET;
     947            1419 :         return PR_SUCCESS;
     948                 :     }
     949                 : 
     950               0 :     PRInt32 maxallowed = rlimitData.rlim_max;
     951               0 :     if (maxallowed == -1) {                       /* no limit */
     952               0 :         maxallowed = SOCKET_LIMIT_TARGET + 250;
     953               0 :     } else if ((PRUint32)maxallowed < SOCKET_LIMIT_MIN + 250) {
     954               0 :         return PR_SUCCESS;
     955               0 :     } else if ((PRUint32)maxallowed > SOCKET_LIMIT_TARGET + 250) {
     956               0 :         maxallowed = SOCKET_LIMIT_TARGET + 250;
     957                 :     }
     958                 : 
     959               0 :     rlimitData.rlim_cur = maxallowed;
     960               0 :     setrlimit(RLIMIT_NOFILE, &rlimitData);
     961               0 :     if (getrlimit(RLIMIT_NOFILE, &rlimitData) != -1)
     962               0 :         if (rlimitData.rlim_cur > SOCKET_LIMIT_MIN + 250)
     963               0 :             gMaxCount = rlimitData.rlim_cur - 250;
     964                 : 
     965                 : #elif defined(XP_WIN) && !defined(WIN_CE)
     966                 :     // >= XP is confirmed to have at least 1000
     967                 :     gMaxCount = SOCKET_LIMIT_TARGET;
     968                 : #else
     969                 :     // other platforms are harder to test - so leave at safe legacy value
     970                 : #endif
     971                 : 
     972               0 :     return PR_SUCCESS;
     973                 : }

Generated by: LCOV version 1.7