LCOV - code coverage report
Current view: directory - netwerk/base/src - nsSocketTransport2.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 854 646 75.6 %
Date: 2012-06-02 Functions: 89 68 76.4 %

       1                 : /* vim:set ts=4 sw=4 et cindent: */
       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                 :  *   Malcolm Smith <malsmith@cs.rmit.edu.au>
      25                 :  *   Andreas Otte <andreas.otte@debitel.net>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #ifdef MOZ_LOGGING
      42                 : #define FORCE_PR_LOG
      43                 : #endif
      44                 : 
      45                 : #include "nsSocketTransport2.h"
      46                 : #include "nsAtomicRefcnt.h"
      47                 : #include "nsIOService.h"
      48                 : #include "nsStreamUtils.h"
      49                 : #include "nsNetSegmentUtils.h"
      50                 : #include "nsNetAddr.h"
      51                 : #include "nsTransportUtils.h"
      52                 : #include "nsProxyInfo.h"
      53                 : #include "nsNetCID.h"
      54                 : #include "nsAutoPtr.h"
      55                 : #include "nsCOMPtr.h"
      56                 : #include "netCore.h"
      57                 : #include "prmem.h"
      58                 : #include "plstr.h"
      59                 : #include "prnetdb.h"
      60                 : #include "prerror.h"
      61                 : #include "prerr.h"
      62                 : 
      63                 : #include "nsIServiceManager.h"
      64                 : #include "nsISocketProviderService.h"
      65                 : #include "nsISocketProvider.h"
      66                 : #include "nsISSLSocketControl.h"
      67                 : #include "nsINSSErrorsService.h"
      68                 : #include "nsIPipe.h"
      69                 : #include "nsIProgrammingLanguage.h"
      70                 : #include "nsIClassInfoImpl.h"
      71                 : 
      72                 : #if defined(XP_WIN) || defined(MOZ_PLATFORM_MAEMO)
      73                 : #include "nsNativeConnectionHelper.h"
      74                 : #endif
      75                 : 
      76                 : using namespace mozilla;
      77                 : 
      78                 : //-----------------------------------------------------------------------------
      79                 : 
      80                 : static NS_DEFINE_CID(kSocketProviderServiceCID, NS_SOCKETPROVIDERSERVICE_CID);
      81                 : static NS_DEFINE_CID(kDNSServiceCID, NS_DNSSERVICE_CID);
      82                 : 
      83                 : //-----------------------------------------------------------------------------
      84                 : 
      85                 : class nsSocketEvent : public nsRunnable
      86           70592 : {
      87                 : public:
      88           17648 :     nsSocketEvent(nsSocketTransport *transport, PRUint32 type,
      89                 :                   nsresult status = NS_OK, nsISupports *param = nsnull)
      90                 :         : mTransport(transport)
      91                 :         , mType(type)
      92                 :         , mStatus(status)
      93           17648 :         , mParam(param)
      94           17648 :     {}
      95                 : 
      96           17648 :     NS_IMETHOD Run()
      97                 :     {
      98           17648 :         mTransport->OnSocketEvent(mType, mStatus, mParam);
      99           17648 :         return NS_OK;
     100                 :     }
     101                 : 
     102                 : private:
     103                 :     nsRefPtr<nsSocketTransport> mTransport;
     104                 : 
     105                 :     PRUint32              mType;
     106                 :     nsresult              mStatus;
     107                 :     nsCOMPtr<nsISupports> mParam;
     108                 : };
     109                 : 
     110                 : //-----------------------------------------------------------------------------
     111                 : 
     112                 : //#define TEST_CONNECT_ERRORS
     113                 : #ifdef TEST_CONNECT_ERRORS
     114                 : #include <stdlib.h>
     115                 : static PRErrorCode RandomizeConnectError(PRErrorCode code)
     116                 : {
     117                 :     //
     118                 :     // To test out these errors, load http://www.yahoo.com/.  It should load
     119                 :     // correctly despite the random occurrence of these errors.
     120                 :     //
     121                 :     int n = rand();
     122                 :     if (n > RAND_MAX/2) {
     123                 :         struct {
     124                 :             PRErrorCode err_code;
     125                 :             const char *err_name;
     126                 :         } 
     127                 :         errors[] = {
     128                 :             //
     129                 :             // These errors should be recoverable provided there is another
     130                 :             // IP address in mDNSRecord.
     131                 :             //
     132                 :             { PR_CONNECT_REFUSED_ERROR, "PR_CONNECT_REFUSED_ERROR" },
     133                 :             { PR_CONNECT_TIMEOUT_ERROR, "PR_CONNECT_TIMEOUT_ERROR" },
     134                 :             //
     135                 :             // This error will cause this socket transport to error out;
     136                 :             // however, if the consumer is HTTP, then the HTTP transaction
     137                 :             // should be restarted when this error occurs.
     138                 :             //
     139                 :             { PR_CONNECT_RESET_ERROR, "PR_CONNECT_RESET_ERROR" },
     140                 :         };
     141                 :         n = n % (sizeof(errors)/sizeof(errors[0]));
     142                 :         code = errors[n].err_code;
     143                 :         SOCKET_LOG(("simulating NSPR error %d [%s]\n", code, errors[n].err_name));
     144                 :     }
     145                 :     return code;
     146                 : }
     147                 : #endif
     148                 : 
     149                 : //-----------------------------------------------------------------------------
     150                 : 
     151                 : static bool
     152               0 : IsNSSErrorCode(PRErrorCode code)
     153                 : {
     154                 :   return 
     155                 :     ((code >= nsINSSErrorsService::NSS_SEC_ERROR_BASE) && 
     156                 :       (code < nsINSSErrorsService::NSS_SEC_ERROR_LIMIT))
     157                 :     ||
     158                 :     ((code >= nsINSSErrorsService::NSS_SSL_ERROR_BASE) && 
     159               0 :       (code < nsINSSErrorsService::NSS_SSL_ERROR_LIMIT));
     160                 : }
     161                 : 
     162                 : // this logic is duplicated from the implementation of
     163                 : // nsINSSErrorsService::getXPCOMFromNSSError
     164                 : // It might have been better to implement that interface here...
     165                 : static nsresult
     166               0 : GetXPCOMFromNSSError(PRErrorCode code)
     167                 : {
     168               0 :     return NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_SECURITY, -1 * code);
     169                 : }
     170                 : 
     171                 : static nsresult
     172             139 : ErrorAccordingToNSPR(PRErrorCode errorCode)
     173                 : {
     174             139 :     nsresult rv = NS_ERROR_FAILURE;
     175             139 :     switch (errorCode) {
     176                 :     case PR_WOULD_BLOCK_ERROR:
     177               0 :         rv = NS_BASE_STREAM_WOULD_BLOCK;
     178               0 :         break;
     179                 :     case PR_CONNECT_ABORTED_ERROR:
     180                 :     case PR_CONNECT_RESET_ERROR:
     181               3 :         rv = NS_ERROR_NET_RESET;
     182               3 :         break;
     183                 :     case PR_END_OF_FILE_ERROR: // XXX document this correlation
     184               0 :         rv = NS_ERROR_NET_INTERRUPT;
     185               0 :         break;
     186                 :     case PR_CONNECT_REFUSED_ERROR:
     187                 :     case PR_NETWORK_UNREACHABLE_ERROR: // XXX need new nsresult for this!
     188                 :     case PR_HOST_UNREACHABLE_ERROR:    // XXX and this!
     189                 :     case PR_ADDRESS_NOT_AVAILABLE_ERROR:
     190                 :     // Treat EACCES as a soft error since (at least on Linux) connect() returns
     191                 :     // EACCES when an IPv6 connection is blocked by a firewall. See bug 270784.
     192                 :     case PR_ADDRESS_NOT_SUPPORTED_ERROR:
     193                 :     case PR_NO_ACCESS_RIGHTS_ERROR:
     194             136 :         rv = NS_ERROR_CONNECTION_REFUSED;
     195             136 :         break;
     196                 :     case PR_IO_TIMEOUT_ERROR:
     197                 :     case PR_CONNECT_TIMEOUT_ERROR:
     198               0 :         rv = NS_ERROR_NET_TIMEOUT;
     199               0 :         break;
     200                 :     default:
     201               0 :         if (IsNSSErrorCode(errorCode))
     202               0 :             rv = GetXPCOMFromNSSError(errorCode);
     203               0 :         break;
     204                 :     }
     205             139 :     SOCKET_LOG(("ErrorAccordingToNSPR [in=%d out=%x]\n", errorCode, rv));
     206             139 :     return rv;
     207                 : }
     208                 : 
     209                 : //-----------------------------------------------------------------------------
     210                 : // socket input stream impl 
     211                 : //-----------------------------------------------------------------------------
     212                 : 
     213            5883 : nsSocketInputStream::nsSocketInputStream(nsSocketTransport *trans)
     214                 :     : mTransport(trans)
     215                 :     , mReaderRefCnt(0)
     216                 :     , mCondition(NS_OK)
     217                 :     , mCallbackFlags(0)
     218            5883 :     , mByteCount(0)
     219                 : {
     220            5883 : }
     221                 : 
     222            5882 : nsSocketInputStream::~nsSocketInputStream()
     223                 : {
     224           11764 : }
     225                 : 
     226                 : // called on the socket transport thread...
     227                 : //
     228                 : //   condition : failure code if socket has been closed
     229                 : //
     230                 : void
     231           20764 : nsSocketInputStream::OnSocketReady(nsresult condition)
     232                 : {
     233           20764 :     SOCKET_LOG(("nsSocketInputStream::OnSocketReady [this=%x cond=%x]\n",
     234                 :         this, condition));
     235                 : 
     236           20764 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
     237                 : 
     238           41528 :     nsCOMPtr<nsIInputStreamCallback> callback;
     239                 :     {
     240           41528 :         MutexAutoLock lock(mTransport->mLock);
     241                 : 
     242                 :         // update condition, but be careful not to erase an already
     243                 :         // existing error condition.
     244           20764 :         if (NS_SUCCEEDED(mCondition))
     245           12150 :             mCondition = condition;
     246                 : 
     247                 :         // ignore event if only waiting for closure and not closed.
     248           20764 :         if (NS_FAILED(mCondition) || !(mCallbackFlags & WAIT_CLOSURE_ONLY)) {
     249           20738 :             callback = mCallback;
     250           20738 :             mCallback = nsnull;
     251           20738 :             mCallbackFlags = 0;
     252                 :         }
     253                 :     }
     254                 : 
     255           20764 :     if (callback)
     256            9217 :         callback->OnInputStreamReady(this);
     257           20764 : }
     258                 : 
     259           17716 : NS_IMPL_QUERY_INTERFACE2(nsSocketInputStream,
     260                 :                          nsIInputStream,
     261                 :                          nsIAsyncInputStream)
     262                 : 
     263                 : NS_IMETHODIMP_(nsrefcnt)
     264           26574 : nsSocketInputStream::AddRef()
     265                 : {
     266           26574 :     NS_AtomicIncrementRefcnt(mReaderRefCnt);
     267           26574 :     return mTransport->AddRef();
     268                 : }
     269                 : 
     270                 : NS_IMETHODIMP_(nsrefcnt)
     271           26574 : nsSocketInputStream::Release()
     272                 : {
     273           26574 :     if (NS_AtomicDecrementRefcnt(mReaderRefCnt) == 0)
     274            5882 :         Close();
     275           26574 :     return mTransport->Release();
     276                 : }
     277                 : 
     278                 : NS_IMETHODIMP
     279            5882 : nsSocketInputStream::Close()
     280                 : {
     281            5882 :     return CloseWithStatus(NS_BASE_STREAM_CLOSED);
     282                 : }
     283                 : 
     284                 : NS_IMETHODIMP
     285               6 : nsSocketInputStream::Available(PRUint32 *avail)
     286                 : {
     287               6 :     SOCKET_LOG(("nsSocketInputStream::Available [this=%x]\n", this));
     288                 : 
     289               6 :     *avail = 0;
     290                 : 
     291                 :     PRFileDesc *fd;
     292                 :     {
     293              12 :         MutexAutoLock lock(mTransport->mLock);
     294                 : 
     295               6 :         if (NS_FAILED(mCondition))
     296               0 :             return mCondition;
     297                 : 
     298               6 :         fd = mTransport->GetFD_Locked();
     299               6 :         if (!fd)
     300               0 :             return NS_OK;
     301                 :     }
     302                 : 
     303                 :     // cannot hold lock while calling NSPR.  (worried about the fact that PSM
     304                 :     // synchronously proxies notifications over to the UI thread, which could
     305                 :     // mistakenly try to re-enter this code.)
     306               6 :     PRInt32 n = PR_Available(fd);
     307                 : 
     308                 :     // PSM does not implement PR_Available() so do a best approximation of it
     309                 :     // with MSG_PEEK
     310               6 :     if ((n == -1) && (PR_GetError() == PR_NOT_IMPLEMENTED_ERROR)) {
     311                 :         char c;
     312                 : 
     313               4 :         n = PR_Recv(fd, &c, 1, PR_MSG_PEEK, 0);
     314               4 :         SOCKET_LOG(("nsSocketInputStream::Available [this=%x] "
     315                 :                     "using PEEK backup n=%d]\n", this, n));
     316                 :     }
     317                 : 
     318                 :     nsresult rv;
     319                 :     {
     320              12 :         MutexAutoLock lock(mTransport->mLock);
     321                 : 
     322               6 :         mTransport->ReleaseFD_Locked(fd);
     323                 : 
     324               6 :         if (n >= 0)
     325               2 :             *avail = n;
     326                 :         else {
     327               4 :             PRErrorCode code = PR_GetError();
     328               4 :             if (code == PR_WOULD_BLOCK_ERROR)
     329               4 :                 return NS_OK;
     330               0 :             mCondition = ErrorAccordingToNSPR(code);
     331                 :         }
     332               8 :         rv = mCondition;
     333                 :     }
     334               2 :     if (NS_FAILED(rv))
     335               0 :         mTransport->OnInputClosed(rv);
     336               2 :     return rv;
     337                 : }
     338                 : 
     339                 : NS_IMETHODIMP
     340           18590 : nsSocketInputStream::Read(char *buf, PRUint32 count, PRUint32 *countRead)
     341                 : {
     342           18590 :     SOCKET_LOG(("nsSocketInputStream::Read [this=%x count=%u]\n", this, count));
     343                 : 
     344           18590 :     *countRead = 0;
     345                 : 
     346                 :     PRFileDesc *fd;
     347                 :     {
     348           37180 :         MutexAutoLock lock(mTransport->mLock);
     349                 : 
     350           18590 :         if (NS_FAILED(mCondition))
     351               2 :             return (mCondition == NS_BASE_STREAM_CLOSED) ? NS_OK : mCondition;
     352                 : 
     353           18588 :         fd = mTransport->GetFD_Locked();
     354           18588 :         if (!fd)
     355              36 :             return NS_BASE_STREAM_WOULD_BLOCK;
     356                 :     }
     357                 : 
     358           18552 :     SOCKET_LOG(("  calling PR_Read [count=%u]\n", count));
     359                 : 
     360                 :     // cannot hold lock while calling NSPR.  (worried about the fact that PSM
     361                 :     // synchronously proxies notifications over to the UI thread, which could
     362                 :     // mistakenly try to re-enter this code.)
     363           18552 :     PRInt32 n = PR_Read(fd, buf, count);
     364                 : 
     365           18552 :     SOCKET_LOG(("  PR_Read returned [n=%d]\n", n));
     366                 : 
     367                 :     nsresult rv;
     368                 :     {
     369           37104 :         MutexAutoLock lock(mTransport->mLock);
     370                 : 
     371                 : #ifdef ENABLE_SOCKET_TRACING
     372                 :         if (n > 0)
     373                 :             mTransport->TraceInBuf(buf, n);
     374                 : #endif
     375                 : 
     376           18552 :         mTransport->ReleaseFD_Locked(fd);
     377                 : 
     378           18552 :         if (n > 0)
     379            9349 :             mByteCount += (*countRead = n);
     380            9203 :         else if (n < 0) {
     381            6347 :             PRErrorCode code = PR_GetError();
     382            6347 :             if (code == PR_WOULD_BLOCK_ERROR)
     383            6347 :                 return NS_BASE_STREAM_WOULD_BLOCK;
     384               0 :             mCondition = ErrorAccordingToNSPR(code);
     385                 :         }
     386           30757 :         rv = mCondition;
     387                 :     }
     388           12205 :     if (NS_FAILED(rv))
     389               0 :         mTransport->OnInputClosed(rv);
     390                 : 
     391                 :     // only send this notification if we have indeed read some data.
     392                 :     // see bug 196827 for an example of why this is important.
     393           12205 :     if (n > 0)
     394            9349 :         mTransport->SendStatus(nsISocketTransport::STATUS_RECEIVING_FROM);
     395           12205 :     return rv;
     396                 : }
     397                 : 
     398                 : NS_IMETHODIMP
     399               0 : nsSocketInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
     400                 :                                   PRUint32 count, PRUint32 *countRead)
     401                 : {
     402                 :     // socket stream is unbuffered
     403               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     404                 : }
     405                 : 
     406                 : NS_IMETHODIMP
     407               0 : nsSocketInputStream::IsNonBlocking(bool *nonblocking)
     408                 : {
     409               0 :     *nonblocking = true;
     410               0 :     return NS_OK;
     411                 : }
     412                 : 
     413                 : NS_IMETHODIMP
     414           11926 : nsSocketInputStream::CloseWithStatus(nsresult reason)
     415                 : {
     416           11926 :     SOCKET_LOG(("nsSocketInputStream::CloseWithStatus [this=%x reason=%x]\n", this, reason));
     417                 : 
     418                 :     // may be called from any thread
     419                 :  
     420                 :     nsresult rv;
     421                 :     {
     422           23852 :         MutexAutoLock lock(mTransport->mLock);
     423                 : 
     424           11926 :         if (NS_SUCCEEDED(mCondition))
     425            8581 :             rv = mCondition = reason;
     426                 :         else
     427            3345 :             rv = NS_OK;
     428                 :     }
     429           11926 :     if (NS_FAILED(rv))
     430            5739 :         mTransport->OnInputClosed(rv);
     431           11926 :     return NS_OK;
     432                 : }
     433                 : 
     434                 : NS_IMETHODIMP
     435            9253 : nsSocketInputStream::AsyncWait(nsIInputStreamCallback *callback,
     436                 :                                PRUint32 flags,
     437                 :                                PRUint32 amount,
     438                 :                                nsIEventTarget *target)
     439                 : {
     440            9253 :     SOCKET_LOG(("nsSocketInputStream::AsyncWait [this=%x]\n", this));
     441                 : 
     442                 :     // This variable will be non-null when we want to call the callback
     443                 :     // directly from this function, but outside the lock.
     444                 :     // (different from callback when target is not null)
     445           18506 :     nsCOMPtr<nsIInputStreamCallback> directCallback;
     446                 :     {
     447           18506 :         MutexAutoLock lock(mTransport->mLock);
     448                 : 
     449            9253 :         if (callback && target) {
     450                 :             //
     451                 :             // build event proxy
     452                 :             //
     453                 :             // failure to create an event proxy (most likely out of memory)
     454                 :             // shouldn't alter the state of the transport.
     455                 :             //
     456               0 :             nsCOMPtr<nsIInputStreamCallback> temp;
     457               0 :             nsresult rv = NS_NewInputStreamReadyEvent(getter_AddRefs(temp),
     458               0 :                                                       callback, target);
     459               0 :             if (NS_FAILED(rv)) return rv;
     460               0 :             mCallback = temp;
     461                 :         }
     462                 :         else
     463            9253 :             mCallback = callback;
     464                 : 
     465            9253 :         if (NS_FAILED(mCondition))
     466               0 :             directCallback.swap(mCallback);
     467                 :         else
     468            9253 :             mCallbackFlags = flags;
     469                 :     }
     470            9253 :     if (directCallback)
     471               0 :         directCallback->OnInputStreamReady(this);
     472                 :     else
     473            9253 :         mTransport->OnInputPending();
     474                 : 
     475            9253 :     return NS_OK;
     476                 : }
     477                 : 
     478                 : //-----------------------------------------------------------------------------
     479                 : // socket output stream impl 
     480                 : //-----------------------------------------------------------------------------
     481                 : 
     482            5883 : nsSocketOutputStream::nsSocketOutputStream(nsSocketTransport *trans)
     483                 :     : mTransport(trans)
     484                 :     , mWriterRefCnt(0)
     485                 :     , mCondition(NS_OK)
     486                 :     , mCallbackFlags(0)
     487            5883 :     , mByteCount(0)
     488                 : {
     489            5883 : }
     490                 : 
     491            5882 : nsSocketOutputStream::~nsSocketOutputStream()
     492                 : {
     493           11764 : }
     494                 : 
     495                 : // called on the socket transport thread...
     496                 : //
     497                 : //   condition : failure code if socket has been closed
     498                 : //
     499                 : void
     500           20903 : nsSocketOutputStream::OnSocketReady(nsresult condition)
     501                 : {
     502           20903 :     SOCKET_LOG(("nsSocketOutputStream::OnSocketReady [this=%x cond=%x]\n",
     503                 :         this, condition));
     504                 : 
     505           20903 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
     506                 : 
     507           41806 :     nsCOMPtr<nsIOutputStreamCallback> callback;
     508                 :     {
     509           41806 :         MutexAutoLock lock(mTransport->mLock);
     510                 : 
     511                 :         // update condition, but be careful not to erase an already
     512                 :         // existing error condition.
     513           20903 :         if (NS_SUCCEEDED(mCondition))
     514           15127 :             mCondition = condition;
     515                 : 
     516                 :         // ignore event if only waiting for closure and not closed.
     517           20903 :         if (NS_FAILED(mCondition) || !(mCallbackFlags & WAIT_CLOSURE_ONLY)) {
     518           11684 :             callback = mCallback;
     519           11684 :             mCallback = nsnull;
     520           11684 :             mCallbackFlags = 0;
     521                 :         }
     522                 :     }
     523                 : 
     524           20903 :     if (callback)
     525            5911 :         callback->OnOutputStreamReady(this);
     526           20903 : }
     527                 : 
     528           17718 : NS_IMPL_QUERY_INTERFACE2(nsSocketOutputStream,
     529                 :                          nsIOutputStream,
     530                 :                          nsIAsyncOutputStream)
     531                 : 
     532                 : NS_IMETHODIMP_(nsrefcnt)
     533           26577 : nsSocketOutputStream::AddRef()
     534                 : {
     535           26577 :     NS_AtomicIncrementRefcnt(mWriterRefCnt);
     536           26577 :     return mTransport->AddRef();
     537                 : }
     538                 : 
     539                 : NS_IMETHODIMP_(nsrefcnt)
     540           26575 : nsSocketOutputStream::Release()
     541                 : {
     542           26575 :     if (NS_AtomicDecrementRefcnt(mWriterRefCnt) == 0)
     543            5882 :         Close();
     544           26575 :     return mTransport->Release();
     545                 : }
     546                 : 
     547                 : NS_IMETHODIMP
     548            5882 : nsSocketOutputStream::Close()
     549                 : {
     550            5882 :     return CloseWithStatus(NS_BASE_STREAM_CLOSED);
     551                 : }
     552                 : 
     553                 : NS_IMETHODIMP
     554               0 : nsSocketOutputStream::Flush()
     555                 : {
     556               0 :     return NS_OK;
     557                 : }
     558                 : 
     559                 : NS_IMETHODIMP
     560            9520 : nsSocketOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *countWritten)
     561                 : {
     562            9520 :     SOCKET_LOG(("nsSocketOutputStream::Write [this=%x count=%u]\n", this, count));
     563                 : 
     564            9520 :     *countWritten = 0;
     565                 : 
     566                 :     // A write of 0 bytes can be used to force the initial SSL handshake.
     567            9520 :     if (count == 0 && mByteCount)
     568               0 :         return NS_OK;
     569                 : 
     570                 :     PRFileDesc *fd;
     571                 :     {
     572           19040 :         MutexAutoLock lock(mTransport->mLock);
     573                 : 
     574            9520 :         if (NS_FAILED(mCondition))
     575             145 :             return mCondition;
     576                 :         
     577            9375 :         fd = mTransport->GetFD_Locked();
     578            9375 :         if (!fd)
     579               0 :             return NS_BASE_STREAM_WOULD_BLOCK;
     580                 :     }
     581                 : 
     582            9375 :     SOCKET_LOG(("  calling PR_Write [count=%u]\n", count));
     583                 : 
     584                 :     // cannot hold lock while calling NSPR.  (worried about the fact that PSM
     585                 :     // synchronously proxies notifications over to the UI thread, which could
     586                 :     // mistakenly try to re-enter this code.)
     587            9375 :     PRInt32 n = PR_Write(fd, buf, count);
     588                 : 
     589            9375 :     SOCKET_LOG(("  PR_Write returned [n=%d]\n", n));
     590                 : 
     591                 :     nsresult rv;
     592                 :     {
     593           18750 :         MutexAutoLock lock(mTransport->mLock);
     594                 : 
     595                 : #ifdef ENABLE_SOCKET_TRACING
     596                 :     if (n > 0)
     597                 :         mTransport->TraceOutBuf(buf, n);
     598                 : #endif
     599                 : 
     600            9375 :         mTransport->ReleaseFD_Locked(fd);
     601                 : 
     602            9375 :         if (n > 0)
     603            9344 :             mByteCount += (*countWritten = n);
     604              31 :         else if (n < 0) {
     605              27 :             PRErrorCode code = PR_GetError();
     606              27 :             if (code == PR_WOULD_BLOCK_ERROR)
     607              24 :                 return NS_BASE_STREAM_WOULD_BLOCK;
     608               3 :             mCondition = ErrorAccordingToNSPR(code);
     609                 :         }
     610           18726 :         rv = mCondition;
     611                 :     }
     612            9351 :     if (NS_FAILED(rv))
     613               3 :         mTransport->OnOutputClosed(rv);
     614                 : 
     615                 :     // only send this notification if we have indeed written some data.
     616                 :     // see bug 196827 for an example of why this is important.
     617            9351 :     if (n > 0)
     618            9344 :         mTransport->SendStatus(nsISocketTransport::STATUS_SENDING_TO);
     619            9351 :     return rv;
     620                 : }
     621                 : 
     622                 : NS_IMETHODIMP
     623               0 : nsSocketOutputStream::WriteSegments(nsReadSegmentFun reader, void *closure,
     624                 :                                     PRUint32 count, PRUint32 *countRead)
     625                 : {
     626                 :     // socket stream is unbuffered
     627               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     628                 : }
     629                 : 
     630                 : NS_METHOD
     631               0 : nsSocketOutputStream::WriteFromSegments(nsIInputStream *input,
     632                 :                                         void *closure,
     633                 :                                         const char *fromSegment,
     634                 :                                         PRUint32 offset,
     635                 :                                         PRUint32 count,
     636                 :                                         PRUint32 *countRead)
     637                 : {
     638               0 :     nsSocketOutputStream *self = (nsSocketOutputStream *) closure;
     639               0 :     return self->Write(fromSegment, count, countRead);
     640                 : }
     641                 : 
     642                 : NS_IMETHODIMP
     643               0 : nsSocketOutputStream::WriteFrom(nsIInputStream *stream, PRUint32 count, PRUint32 *countRead)
     644                 : {
     645               0 :     return stream->ReadSegments(WriteFromSegments, this, count, countRead);
     646                 : }
     647                 : 
     648                 : NS_IMETHODIMP
     649               0 : nsSocketOutputStream::IsNonBlocking(bool *nonblocking)
     650                 : {
     651               0 :     *nonblocking = true;
     652               0 :     return NS_OK;
     653                 : }
     654                 : 
     655                 : NS_IMETHODIMP
     656           11926 : nsSocketOutputStream::CloseWithStatus(nsresult reason)
     657                 : {
     658           11926 :     SOCKET_LOG(("nsSocketOutputStream::CloseWithStatus [this=%x reason=%x]\n", this, reason));
     659                 : 
     660                 :     // may be called from any thread
     661                 :  
     662                 :     nsresult rv;
     663                 :     {
     664           23852 :         MutexAutoLock lock(mTransport->mLock);
     665                 : 
     666           11926 :         if (NS_SUCCEEDED(mCondition))
     667            8631 :             rv = mCondition = reason;
     668                 :         else
     669            3295 :             rv = NS_OK;
     670                 :     }
     671           11926 :     if (NS_FAILED(rv))
     672            5733 :         mTransport->OnOutputClosed(rv);
     673           11926 :     return NS_OK;
     674                 : }
     675                 : 
     676                 : NS_IMETHODIMP
     677           12235 : nsSocketOutputStream::AsyncWait(nsIOutputStreamCallback *callback,
     678                 :                                 PRUint32 flags,
     679                 :                                 PRUint32 amount,
     680                 :                                 nsIEventTarget *target)
     681                 : {
     682           12235 :     SOCKET_LOG(("nsSocketOutputStream::AsyncWait [this=%x]\n", this));
     683                 : 
     684                 :     {
     685           24470 :         MutexAutoLock lock(mTransport->mLock);
     686                 : 
     687           12235 :         if (callback && target) {
     688                 :             //
     689                 :             // build event proxy
     690                 :             //
     691                 :             // failure to create an event proxy (most likely out of memory)
     692                 :             // shouldn't alter the state of the transport.
     693                 :             //
     694               0 :             nsCOMPtr<nsIOutputStreamCallback> temp;
     695               0 :             nsresult rv = NS_NewOutputStreamReadyEvent(getter_AddRefs(temp),
     696               0 :                                                        callback, target);
     697               0 :             if (NS_FAILED(rv)) return rv;
     698               0 :             mCallback = temp;
     699                 :         }
     700                 :         else
     701           12235 :             mCallback = callback;
     702                 : 
     703           24470 :         mCallbackFlags = flags;
     704                 :     }
     705           12235 :     mTransport->OnOutputPending();
     706           12235 :     return NS_OK;
     707                 : }
     708                 : 
     709                 : //-----------------------------------------------------------------------------
     710                 : // socket transport impl
     711                 : //-----------------------------------------------------------------------------
     712                 : 
     713            5883 : nsSocketTransport::nsSocketTransport()
     714                 :     : mTypes(nsnull)
     715                 :     , mTypeCount(0)
     716                 :     , mPort(0)
     717                 :     , mProxyPort(0)
     718                 :     , mProxyTransparent(false)
     719                 :     , mProxyTransparentResolvesHost(false)
     720                 :     , mConnectionFlags(0)
     721                 :     , mState(STATE_CLOSED)
     722                 :     , mAttached(false)
     723                 :     , mInputClosed(true)
     724                 :     , mOutputClosed(true)
     725                 :     , mResolving(false)
     726                 :     , mNetAddrIsSet(false)
     727                 :     , mLock("nsSocketTransport.mLock")
     728                 :     , mFD(nsnull)
     729                 :     , mFDref(0)
     730                 :     , mFDconnected(false)
     731                 :     , mInput(this)
     732                 :     , mOutput(this)
     733            5883 :     , mQoSBits(0x00)
     734                 : {
     735            5883 :     SOCKET_LOG(("creating nsSocketTransport @%x\n", this));
     736                 : 
     737            5883 :     NS_ADDREF(gSocketTransportService);
     738                 : 
     739            5883 :     mTimeouts[TIMEOUT_CONNECT]    = PR_UINT16_MAX; // no timeout
     740            5883 :     mTimeouts[TIMEOUT_READ_WRITE] = PR_UINT16_MAX; // no timeout
     741            5883 : }
     742                 : 
     743           17646 : nsSocketTransport::~nsSocketTransport()
     744                 : {
     745            5882 :     SOCKET_LOG(("destroying nsSocketTransport @%x\n", this));
     746                 : 
     747                 :     // cleanup socket type info
     748            5882 :     if (mTypes) {
     749                 :         PRUint32 i;
     750               8 :         for (i=0; i<mTypeCount; ++i)
     751               4 :             PL_strfree(mTypes[i]);
     752               4 :         free(mTypes);
     753                 :     }
     754                 :  
     755            5882 :     nsSocketTransportService *serv = gSocketTransportService;
     756            5882 :     NS_RELEASE(serv); // nulls argument
     757           23528 : }
     758                 : 
     759                 : nsresult
     760            3013 : nsSocketTransport::Init(const char **types, PRUint32 typeCount,
     761                 :                         const nsACString &host, PRUint16 port,
     762                 :                         nsIProxyInfo *givenProxyInfo)
     763                 : {
     764            6026 :     nsCOMPtr<nsProxyInfo> proxyInfo;
     765            3013 :     if (givenProxyInfo) {
     766              27 :         proxyInfo = do_QueryInterface(givenProxyInfo);
     767              27 :         NS_ENSURE_ARG(proxyInfo);
     768                 :     }
     769                 : 
     770                 :     // init socket type info
     771                 : 
     772            3013 :     mPort = port;
     773            3013 :     mHost = host;
     774                 : 
     775            3013 :     const char *proxyType = nsnull;
     776            3013 :     if (proxyInfo) {
     777              27 :         mProxyPort = proxyInfo->Port();
     778              27 :         mProxyHost = proxyInfo->Host();
     779                 :         // grab proxy type (looking for "socks" for example)
     780              27 :         proxyType = proxyInfo->Type();
     781              27 :         if (proxyType && (strcmp(proxyType, "http") == 0 ||
     782               0 :                           strcmp(proxyType, "direct") == 0 ||
     783               0 :                           strcmp(proxyType, "unknown") == 0))
     784              27 :             proxyType = nsnull;
     785                 :     }
     786                 : 
     787            3013 :     SOCKET_LOG(("nsSocketTransport::Init [this=%x host=%s:%hu proxy=%s:%hu]\n",
     788                 :         this, mHost.get(), mPort, mProxyHost.get(), mProxyPort));
     789                 : 
     790                 :     // include proxy type as a socket type if proxy type is not "http"
     791            3013 :     mTypeCount = typeCount + (proxyType != nsnull);
     792            3013 :     if (!mTypeCount)
     793            3009 :         return NS_OK;
     794                 : 
     795                 :     // if we have socket types, then the socket provider service had
     796                 :     // better exist!
     797                 :     nsresult rv;
     798                 :     nsCOMPtr<nsISocketProviderService> spserv =
     799               8 :         do_GetService(kSocketProviderServiceCID, &rv);
     800               4 :     if (NS_FAILED(rv)) return rv;
     801                 : 
     802               4 :     mTypes = (char **) malloc(mTypeCount * sizeof(char *));
     803               4 :     if (!mTypes)
     804               0 :         return NS_ERROR_OUT_OF_MEMORY;
     805                 : 
     806                 :     // now verify that each socket type has a registered socket provider.
     807               8 :     for (PRUint32 i = 0, type = 0; i < mTypeCount; ++i) {
     808                 :         // store socket types
     809               4 :         if (i == 0 && proxyType)
     810               0 :             mTypes[i] = PL_strdup(proxyType);
     811                 :         else
     812               4 :             mTypes[i] = PL_strdup(types[type++]);
     813                 : 
     814               4 :         if (!mTypes[i]) {
     815               0 :             mTypeCount = i;
     816               0 :             return NS_ERROR_OUT_OF_MEMORY;
     817                 :         }
     818               8 :         nsCOMPtr<nsISocketProvider> provider;
     819               4 :         rv = spserv->GetSocketProvider(mTypes[i], getter_AddRefs(provider));
     820               4 :         if (NS_FAILED(rv)) {
     821               0 :             NS_WARNING("no registered socket provider");
     822               0 :             return rv;
     823                 :         }
     824                 : 
     825                 :         // note if socket type corresponds to a transparent proxy
     826                 :         // XXX don't hardcode SOCKS here (use proxy info's flags instead).
     827               8 :         if ((strcmp(mTypes[i], "socks") == 0) ||
     828               4 :             (strcmp(mTypes[i], "socks4") == 0)) {
     829               0 :             mProxyTransparent = true;
     830                 : 
     831               0 :             if (proxyInfo->Flags() & nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST) {
     832                 :                 // we want the SOCKS layer to send the hostname
     833                 :                 // and port to the proxy and let it do the DNS.
     834               0 :                 mProxyTransparentResolvesHost = true;
     835                 :             }
     836                 :         }
     837                 :     }
     838                 : 
     839               4 :     return NS_OK;
     840                 : }
     841                 : 
     842                 : nsresult
     843            2870 : nsSocketTransport::InitWithConnectedSocket(PRFileDesc *fd, const PRNetAddr *addr)
     844                 : {
     845            2870 :     NS_ASSERTION(!mFD, "already initialized");
     846                 : 
     847                 :     char buf[64];
     848            2870 :     PR_NetAddrToString(addr, buf, sizeof(buf));
     849            2870 :     mHost.Assign(buf);
     850                 : 
     851                 :     PRUint16 port;
     852            2870 :     if (addr->raw.family == PR_AF_INET)
     853            2870 :         port = addr->inet.port;
     854                 :     else
     855               0 :         port = addr->ipv6.port;
     856            2870 :     mPort = PR_ntohs(port);
     857                 : 
     858            2870 :     memcpy(&mNetAddr, addr, sizeof(PRNetAddr));
     859                 : 
     860            2870 :     mPollFlags = (PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT);
     861            2870 :     mPollTimeout = mTimeouts[TIMEOUT_READ_WRITE];
     862            2870 :     mState = STATE_TRANSFERRING;
     863            2870 :     mNetAddrIsSet = true;
     864                 : 
     865            2870 :     mFD = fd;
     866            2870 :     mFDref = 1;
     867            2870 :     mFDconnected = 1;
     868                 : 
     869                 :     // make sure new socket is non-blocking
     870                 :     PRSocketOptionData opt;
     871            2870 :     opt.option = PR_SockOpt_Nonblocking;
     872            2870 :     opt.value.non_blocking = true;
     873            2870 :     PR_SetSocketOption(mFD, &opt);
     874                 : 
     875            2870 :     SOCKET_LOG(("nsSocketTransport::InitWithConnectedSocket [this=%p addr=%s:%hu]\n",
     876                 :         this, mHost.get(), mPort));
     877                 : 
     878                 :     // jump to InitiateSocket to get ourselves attached to the STS poll list.
     879            2870 :     return PostEvent(MSG_RETRY_INIT_SOCKET);
     880                 : }
     881                 : 
     882                 : nsresult
     883           17648 : nsSocketTransport::PostEvent(PRUint32 type, nsresult status, nsISupports *param)
     884                 : {
     885           17648 :     SOCKET_LOG(("nsSocketTransport::PostEvent [this=%p type=%u status=%x param=%p]\n",
     886                 :         this, type, status, param));
     887                 : 
     888           35296 :     nsCOMPtr<nsIRunnable> event = new nsSocketEvent(this, type, status, param);
     889           17648 :     if (!event)
     890               0 :         return NS_ERROR_OUT_OF_MEMORY;
     891                 : 
     892           17648 :     return gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL);
     893                 : }
     894                 : 
     895                 : void
     896           30595 : nsSocketTransport::SendStatus(nsresult status)
     897                 : {
     898           30595 :     SOCKET_LOG(("nsSocketTransport::SendStatus [this=%x status=%x]\n", this, status));
     899                 : 
     900           61190 :     nsCOMPtr<nsITransportEventSink> sink;
     901                 :     PRUint64 progress;
     902                 :     {
     903           61190 :         MutexAutoLock lock(mLock);
     904           30595 :         sink = mEventSink;
     905           30595 :         switch (status) {
     906                 :         case STATUS_SENDING_TO:
     907            9344 :             progress = mOutput.ByteCount();
     908            9344 :             break;
     909                 :         case STATUS_RECEIVING_FROM:
     910            9349 :             progress = mInput.ByteCount();
     911            9349 :             break;
     912                 :         default:
     913           11902 :             progress = 0;
     914           11902 :             break;
     915                 :         }
     916                 :     }
     917           30595 :     if (sink)
     918           20313 :         sink->OnTransportStatus(this, status, progress, LL_MAXUINT);
     919           30595 : }
     920                 : 
     921                 : nsresult
     922            3013 : nsSocketTransport::ResolveHost()
     923                 : {
     924            3013 :     SOCKET_LOG(("nsSocketTransport::ResolveHost [this=%x]\n", this));
     925                 : 
     926                 :     nsresult rv;
     927                 : 
     928            3013 :     if (!mProxyHost.IsEmpty()) {
     929              27 :         if (!mProxyTransparent || mProxyTransparentResolvesHost) {
     930                 :             // When not resolving mHost locally, we still want to ensure that
     931                 :             // it only contains valid characters.  See bug 304904 for details.
     932              27 :             if (!net_IsValidHostName(mHost))
     933               0 :                 return NS_ERROR_UNKNOWN_HOST;
     934                 :         }
     935              27 :         if (mProxyTransparentResolvesHost) {
     936                 :             // Name resolution is done on the server side.  Just pretend
     937                 :             // client resolution is complete, this will get picked up later.
     938                 :             // since we don't need to do DNS now, we bypass the resolving
     939                 :             // step by initializing mNetAddr to an empty address, but we
     940                 :             // must keep the port. The SOCKS IO layer will use the hostname
     941                 :             // we send it when it's created, rather than the empty address
     942                 :             // we send with the connect call.
     943               0 :             mState = STATE_RESOLVING;
     944               0 :             PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, SocketPort(), &mNetAddr);
     945               0 :             return PostEvent(MSG_DNS_LOOKUP_COMPLETE, NS_OK, nsnull);
     946                 :         }
     947                 :     }
     948                 : 
     949            6026 :     nsCOMPtr<nsIDNSService> dns = do_GetService(kDNSServiceCID, &rv);
     950            3013 :     if (NS_FAILED(rv)) return rv;
     951                 : 
     952            3013 :     mResolving = true;
     953                 : 
     954            3013 :     PRUint32 dnsFlags = 0;
     955            3013 :     if (mConnectionFlags & nsSocketTransport::BYPASS_CACHE)
     956            1923 :         dnsFlags = nsIDNSService::RESOLVE_BYPASS_CACHE;
     957            3013 :     if (mConnectionFlags & nsSocketTransport::DISABLE_IPV6)
     958               0 :         dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
     959                 : 
     960            3013 :     SendStatus(STATUS_RESOLVING);
     961            6026 :     rv = dns->AsyncResolve(SocketHost(), dnsFlags, this, nsnull,
     962            6026 :                            getter_AddRefs(mDNSRequest));
     963            3013 :     if (NS_SUCCEEDED(rv)) {
     964            3013 :         SOCKET_LOG(("  advancing to STATE_RESOLVING\n"));
     965            3013 :         mState = STATE_RESOLVING;
     966                 :     }
     967            3013 :     return rv;
     968                 : }
     969                 : 
     970                 : nsresult
     971            3006 : nsSocketTransport::BuildSocket(PRFileDesc *&fd, bool &proxyTransparent, bool &usingSSL)
     972                 : {
     973            3006 :     SOCKET_LOG(("nsSocketTransport::BuildSocket [this=%x]\n", this));
     974                 : 
     975                 :     nsresult rv;
     976                 : 
     977            3006 :     proxyTransparent = false;
     978            3006 :     usingSSL = false;
     979                 : 
     980            3006 :     if (mTypeCount == 0) {
     981            3002 :         fd = PR_OpenTCPSocket(mNetAddr.raw.family);
     982            3002 :         rv = fd ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     983                 :     }
     984                 :     else {
     985               4 :         fd = nsnull;
     986                 : 
     987                 :         nsCOMPtr<nsISocketProviderService> spserv =
     988               8 :             do_GetService(kSocketProviderServiceCID, &rv);
     989               4 :         if (NS_FAILED(rv)) return rv;
     990                 : 
     991               4 :         const char *host       = mHost.get();
     992               4 :         PRInt32     port       = (PRInt32) mPort;
     993               4 :         const char *proxyHost  = mProxyHost.IsEmpty() ? nsnull : mProxyHost.get();
     994               4 :         PRInt32     proxyPort  = (PRInt32) mProxyPort;
     995               4 :         PRUint32    proxyFlags = 0;
     996                 : 
     997                 :         PRUint32 i;
     998               8 :         for (i=0; i<mTypeCount; ++i) {
     999               8 :             nsCOMPtr<nsISocketProvider> provider;
    1000                 : 
    1001               4 :             SOCKET_LOG(("  pushing io layer [%u:%s]\n", i, mTypes[i]));
    1002                 : 
    1003               4 :             rv = spserv->GetSocketProvider(mTypes[i], getter_AddRefs(provider));
    1004               4 :             if (NS_FAILED(rv))
    1005                 :                 break;
    1006                 : 
    1007               4 :             if (mProxyTransparentResolvesHost)
    1008               0 :                 proxyFlags |= nsISocketProvider::PROXY_RESOLVES_HOST;
    1009                 :             
    1010               4 :             if (mConnectionFlags & nsISocketTransport::ANONYMOUS_CONNECT)
    1011               0 :                 proxyFlags |= nsISocketProvider::ANONYMOUS_CONNECT;
    1012                 : 
    1013               8 :             nsCOMPtr<nsISupports> secinfo;
    1014               4 :             if (i == 0) {
    1015                 :                 // if this is the first type, we'll want the 
    1016                 :                 // service to allocate a new socket
    1017               4 :                 rv = provider->NewSocket(mNetAddr.raw.family,
    1018                 :                                          host, port, proxyHost, proxyPort,
    1019                 :                                          proxyFlags, &fd,
    1020               4 :                                          getter_AddRefs(secinfo));
    1021                 : 
    1022               4 :                 if (NS_SUCCEEDED(rv) && !fd) {
    1023               0 :                     NS_NOTREACHED("NewSocket succeeded but failed to create a PRFileDesc");
    1024               0 :                     rv = NS_ERROR_UNEXPECTED;
    1025                 :                 }
    1026                 :             }
    1027                 :             else {
    1028                 :                 // the socket has already been allocated, 
    1029                 :                 // so we just want the service to add itself
    1030                 :                 // to the stack (such as pushing an io layer)
    1031               0 :                 rv = provider->AddToSocket(mNetAddr.raw.family,
    1032                 :                                            host, port, proxyHost, proxyPort,
    1033                 :                                            proxyFlags, fd,
    1034               0 :                                            getter_AddRefs(secinfo));
    1035                 :             }
    1036                 :             // proxyFlags = 0; not used below this point...
    1037               4 :             if (NS_FAILED(rv))
    1038                 :                 break;
    1039                 : 
    1040                 :             // if the service was ssl or starttls, we want to hold onto the socket info
    1041               4 :             bool isSSL = (strcmp(mTypes[i], "ssl") == 0);
    1042               4 :             if (isSSL || (strcmp(mTypes[i], "starttls") == 0)) {
    1043                 :                 // remember security info and give notification callbacks to PSM...
    1044               8 :                 nsCOMPtr<nsIInterfaceRequestor> callbacks;
    1045                 :                 {
    1046               8 :                     MutexAutoLock lock(mLock);
    1047               4 :                     mSecInfo = secinfo;
    1048               4 :                     callbacks = mCallbacks;
    1049               4 :                     SOCKET_LOG(("  [secinfo=%x callbacks=%x]\n", mSecInfo.get(), mCallbacks.get()));
    1050                 :                 }
    1051                 :                 // don't call into PSM while holding mLock!!
    1052               8 :                 nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(secinfo));
    1053               4 :                 if (secCtrl)
    1054               4 :                     secCtrl->SetNotificationCallbacks(callbacks);
    1055                 :                 // remember if socket type is SSL so we can ProxyStartSSL if need be.
    1056               8 :                 usingSSL = isSSL;
    1057                 :             }
    1058               0 :             else if ((strcmp(mTypes[i], "socks") == 0) ||
    1059               0 :                      (strcmp(mTypes[i], "socks4") == 0)) {
    1060                 :                 // since socks is transparent, any layers above
    1061                 :                 // it do not have to worry about proxy stuff
    1062               0 :                 proxyHost = nsnull;
    1063               0 :                 proxyPort = -1;
    1064               0 :                 proxyTransparent = true;
    1065                 :             }
    1066                 :         }
    1067                 : 
    1068               4 :         if (NS_FAILED(rv)) {
    1069               0 :             SOCKET_LOG(("  error pushing io layer [%u:%s rv=%x]\n", i, mTypes[i], rv));
    1070               0 :             if (fd)
    1071               0 :                 PR_Close(fd);
    1072                 :         }
    1073                 :     }
    1074                 : 
    1075            3006 :     return rv;
    1076                 : }
    1077                 : 
    1078                 : nsresult
    1079            5876 : nsSocketTransport::InitiateSocket()
    1080                 : {
    1081            5876 :     SOCKET_LOG(("nsSocketTransport::InitiateSocket [this=%x]\n", this));
    1082                 : 
    1083                 :     nsresult rv;
    1084                 : 
    1085                 :     //
    1086                 :     // find out if it is going to be ok to attach another socket to the STS.
    1087                 :     // if not then we have to wait for the STS to tell us that it is ok.
    1088                 :     // the notification is asynchronous, which means that when we could be
    1089                 :     // in a race to call AttachSocket once notified.  for this reason, when
    1090                 :     // we get notified, we just re-enter this function.  as a result, we are
    1091                 :     // sure to ask again before calling AttachSocket.  in this way we deal
    1092                 :     // with the race condition.  though it isn't the most elegant solution,
    1093                 :     // it is far simpler than trying to build a system that would guarantee
    1094                 :     // FIFO ordering (which wouldn't even be that valuable IMO).  see bug
    1095                 :     // 194402 for more info.
    1096                 :     //
    1097            5876 :     if (!gSocketTransportService->CanAttachSocket()) {
    1098                 :         nsCOMPtr<nsIRunnable> event =
    1099               0 :                 new nsSocketEvent(this, MSG_RETRY_INIT_SOCKET);
    1100               0 :         if (!event)
    1101               0 :             return NS_ERROR_OUT_OF_MEMORY;
    1102               0 :         return gSocketTransportService->NotifyWhenCanAttachSocket(event);
    1103                 :     }
    1104                 : 
    1105                 :     //
    1106                 :     // if we already have a connected socket, then just attach and return.
    1107                 :     //
    1108            5876 :     if (mFD) {
    1109            2870 :         rv = gSocketTransportService->AttachSocket(mFD, this);
    1110            2870 :         if (NS_SUCCEEDED(rv))
    1111            2870 :             mAttached = true;
    1112            2870 :         return rv;
    1113                 :     }
    1114                 : 
    1115                 :     //
    1116                 :     // create new socket fd, push io layers, etc.
    1117                 :     //
    1118                 :     PRFileDesc *fd;
    1119                 :     bool proxyTransparent;
    1120                 :     bool usingSSL;
    1121                 : 
    1122            3006 :     rv = BuildSocket(fd, proxyTransparent, usingSSL);
    1123            3006 :     if (NS_FAILED(rv)) {
    1124               0 :         SOCKET_LOG(("  BuildSocket failed [rv=%x]\n", rv));
    1125               0 :         return rv;
    1126                 :     }
    1127                 : 
    1128                 :     PRStatus status;
    1129                 : 
    1130                 :     // Make the socket non-blocking...
    1131                 :     PRSocketOptionData opt;
    1132            3006 :     opt.option = PR_SockOpt_Nonblocking;
    1133            3006 :     opt.value.non_blocking = true;
    1134            3006 :     status = PR_SetSocketOption(fd, &opt);
    1135            3006 :     NS_ASSERTION(status == PR_SUCCESS, "unable to make socket non-blocking");
    1136                 : 
    1137                 :     // disable the nagle algorithm - if we rely on it to coalesce writes into
    1138                 :     // full packets the final packet of a multi segment POST/PUT or pipeline
    1139                 :     // sequence is delayed a full rtt
    1140            3006 :     opt.option = PR_SockOpt_NoDelay;
    1141            3006 :     opt.value.no_delay = true;
    1142            3006 :     PR_SetSocketOption(fd, &opt);
    1143                 : 
    1144                 :     // if the network.tcp.sendbuffer preference is set, use it to size SO_SNDBUF
    1145                 :     // The Windows default of 8KB is too small and as of vista sp1, autotuning
    1146                 :     // only applies to receive window
    1147                 :     PRInt32 sndBufferSize;
    1148            3006 :     gSocketTransportService->GetSendBufferSize(&sndBufferSize);
    1149            3006 :     if (sndBufferSize > 0) {
    1150               0 :         opt.option = PR_SockOpt_SendBufferSize;
    1151               0 :         opt.value.send_buffer_size = sndBufferSize;
    1152               0 :         PR_SetSocketOption(fd, &opt);
    1153                 :     }
    1154                 : 
    1155            3006 :     if (mQoSBits) {
    1156               0 :         opt.option = PR_SockOpt_IpTypeOfService;
    1157               0 :         opt.value.tos = mQoSBits;
    1158               0 :         PR_SetSocketOption(fd, &opt);
    1159                 :     }
    1160                 : 
    1161                 :     // inform socket transport about this newly created socket...
    1162            3006 :     rv = gSocketTransportService->AttachSocket(fd, this);
    1163            3006 :     if (NS_FAILED(rv)) {
    1164               0 :         PR_Close(fd);
    1165               0 :         return rv;
    1166                 :     }
    1167            3006 :     mAttached = true;
    1168                 : 
    1169                 :     // assign mFD so that we can properly handle OnSocketDetached before we've
    1170                 :     // established a connection.
    1171                 :     {
    1172            6012 :         MutexAutoLock lock(mLock);
    1173            3006 :         mFD = fd;
    1174            3006 :         mFDref = 1;
    1175            3006 :         mFDconnected = false;
    1176                 :     }
    1177                 : 
    1178            3006 :     SOCKET_LOG(("  advancing to STATE_CONNECTING\n"));
    1179            3006 :     mState = STATE_CONNECTING;
    1180            3006 :     mPollTimeout = mTimeouts[TIMEOUT_CONNECT];
    1181            3006 :     SendStatus(STATUS_CONNECTING_TO);
    1182                 : 
    1183                 : #if defined(PR_LOGGING)
    1184            3006 :     if (SOCKET_LOG_ENABLED()) {
    1185                 :         char buf[64];
    1186               0 :         PR_NetAddrToString(&mNetAddr, buf, sizeof(buf));
    1187               0 :         SOCKET_LOG(("  trying address: %s\n", buf));
    1188                 :     }
    1189                 : #endif
    1190                 : 
    1191                 :     // 
    1192                 :     // Initiate the connect() to the host...  
    1193                 :     //
    1194            3006 :     status = PR_Connect(fd, &mNetAddr, NS_SOCKET_CONNECT_TIMEOUT);
    1195            3006 :     if (status == PR_SUCCESS) {
    1196                 :         // 
    1197                 :         // we are connected!
    1198                 :         //
    1199               0 :         OnSocketConnected();
    1200                 :     }
    1201                 :     else {
    1202            3006 :         PRErrorCode code = PR_GetError();
    1203                 : #if defined(TEST_CONNECT_ERRORS)
    1204                 :         code = RandomizeConnectError(code);
    1205                 : #endif
    1206                 :         //
    1207                 :         // If the PR_Connect(...) would block, then poll for a connection.
    1208                 :         //
    1209            3006 :         if ((PR_WOULD_BLOCK_ERROR == code) || (PR_IN_PROGRESS_ERROR == code))
    1210            3006 :             mPollFlags = (PR_POLL_EXCEPT | PR_POLL_WRITE);
    1211                 :         //
    1212                 :         // If the socket is already connected, then return success...
    1213                 :         //
    1214               0 :         else if (PR_IS_CONNECTED_ERROR == code) {
    1215                 :             //
    1216                 :             // we are connected!
    1217                 :             //
    1218               0 :             OnSocketConnected();
    1219                 : 
    1220               0 :             if (mSecInfo && !mProxyHost.IsEmpty() && proxyTransparent && usingSSL) {
    1221                 :                 // if the connection phase is finished, and the ssl layer has
    1222                 :                 // been pushed, and we were proxying (transparently; ie. nothing
    1223                 :                 // has to happen in the protocol layer above us), it's time for
    1224                 :                 // the ssl to start doing it's thing.
    1225                 :                 nsCOMPtr<nsISSLSocketControl> secCtrl =
    1226               0 :                     do_QueryInterface(mSecInfo);
    1227               0 :                 if (secCtrl) {
    1228               0 :                     SOCKET_LOG(("  calling ProxyStartSSL()\n"));
    1229               0 :                     secCtrl->ProxyStartSSL();
    1230                 :                 }
    1231                 :                 // XXX what if we were forced to poll on the socket for a successful
    1232                 :                 // connection... wouldn't we need to call ProxyStartSSL after a call
    1233                 :                 // to PR_ConnectContinue indicates that we are connected?
    1234                 :                 //
    1235                 :                 // XXX this appears to be what the old socket transport did.  why
    1236                 :                 // isn't this broken?
    1237                 :             }
    1238                 :         }
    1239                 :         //
    1240                 :         // A SOCKS request was rejected; get the actual error code from
    1241                 :         // the OS error
    1242                 :         //
    1243               0 :         else if (PR_UNKNOWN_ERROR == code &&
    1244                 :                  mProxyTransparent &&
    1245               0 :                  !mProxyHost.IsEmpty()) {
    1246               0 :             code = PR_GetOSError();
    1247               0 :             rv = ErrorAccordingToNSPR(code);
    1248                 :         }
    1249                 :         //
    1250                 :         // The connection was refused...
    1251                 :         //
    1252                 :         else {
    1253               0 :             rv = ErrorAccordingToNSPR(code);
    1254               0 :             if ((rv == NS_ERROR_CONNECTION_REFUSED) && !mProxyHost.IsEmpty())
    1255               0 :                 rv = NS_ERROR_PROXY_CONNECTION_REFUSED;
    1256                 :         }
    1257                 :     }
    1258            3006 :     return rv;
    1259                 : }
    1260                 : 
    1261                 : bool
    1262            5883 : nsSocketTransport::RecoverFromError()
    1263                 : {
    1264            5883 :     NS_ASSERTION(NS_FAILED(mCondition), "there should be something wrong");
    1265                 : 
    1266            5883 :     SOCKET_LOG(("nsSocketTransport::RecoverFromError [this=%x state=%x cond=%x]\n",
    1267                 :         this, mState, mCondition));
    1268                 : 
    1269                 :     // can only recover from errors in these states
    1270            5883 :     if (mState != STATE_RESOLVING && mState != STATE_CONNECTING)
    1271            5740 :         return false;
    1272                 : 
    1273                 :     nsresult rv;
    1274                 : 
    1275                 :     // OK to check this outside mLock
    1276             143 :     NS_ASSERTION(!mFDconnected, "socket should not be connected");
    1277                 : 
    1278                 :     // can only recover from these errors
    1279             143 :     if (mCondition != NS_ERROR_CONNECTION_REFUSED &&
    1280                 :         mCondition != NS_ERROR_PROXY_CONNECTION_REFUSED &&
    1281                 :         mCondition != NS_ERROR_NET_TIMEOUT &&
    1282                 :         mCondition != NS_ERROR_UNKNOWN_HOST &&
    1283                 :         mCondition != NS_ERROR_UNKNOWN_PROXY_HOST)
    1284               0 :         return false;
    1285                 : 
    1286             143 :     bool tryAgain = false;
    1287                 : 
    1288             143 :     if (mConnectionFlags & DISABLE_IPV6 &&
    1289                 :         mCondition == NS_ERROR_UNKNOWN_HOST &&
    1290                 :         mState == STATE_RESOLVING &&
    1291               0 :         !mProxyTransparentResolvesHost) {
    1292               0 :         SOCKET_LOG(("  trying lookup again with both ipv4/ipv6 enabled\n"));
    1293               0 :         mConnectionFlags &= ~DISABLE_IPV6;
    1294               0 :         tryAgain = true;
    1295                 :     }
    1296                 : 
    1297                 :     // try next ip address only if past the resolver stage...
    1298             143 :     if (mState == STATE_CONNECTING && mDNSRecord) {
    1299             136 :         mDNSRecord->ReportUnusable(SocketPort());
    1300                 :         
    1301             136 :         nsresult rv = mDNSRecord->GetNextAddr(SocketPort(), &mNetAddr);
    1302             136 :         if (NS_SUCCEEDED(rv)) {
    1303               0 :             SOCKET_LOG(("  trying again with next ip address\n"));
    1304               0 :             tryAgain = true;
    1305                 :         }
    1306             136 :         else if (mConnectionFlags & DISABLE_IPV6) {
    1307                 :             // Drop state to closed.  This will trigger new round of DNS
    1308                 :             // resolving bellow.
    1309                 :             // XXX Here should idealy be set now non-existing flag DISABLE_IPV4
    1310               0 :             SOCKET_LOG(("  failed to connect all ipv4 hosts,"
    1311                 :                         " trying lookup/connect again with both ipv4/ipv6\n"));
    1312               0 :             mState = STATE_CLOSED;
    1313               0 :             mConnectionFlags &= ~DISABLE_IPV6;
    1314               0 :             tryAgain = true;
    1315                 :         }
    1316                 :     }
    1317                 : 
    1318                 : #if defined(XP_WIN) || defined(MOZ_PLATFORM_MAEMO)
    1319                 :     // If not trying next address, try to make a connection using dialup. 
    1320                 :     // Retry if that connection is made.
    1321                 :     if (!tryAgain) {
    1322                 :         bool autodialEnabled;
    1323                 :         gSocketTransportService->GetAutodialEnabled(&autodialEnabled);
    1324                 :         if (autodialEnabled) {
    1325                 :           tryAgain = nsNativeConnectionHelper::OnConnectionFailed(
    1326                 :                        NS_ConvertUTF8toUTF16(SocketHost()).get());
    1327                 :             }
    1328                 :     }
    1329                 : #endif
    1330                 : 
    1331                 :     // prepare to try again.
    1332             143 :     if (tryAgain) {
    1333                 :         PRUint32 msg;
    1334                 : 
    1335               0 :         if (mState == STATE_CONNECTING) {
    1336               0 :             mState = STATE_RESOLVING;
    1337               0 :             msg = MSG_DNS_LOOKUP_COMPLETE;
    1338                 :         }
    1339                 :         else {
    1340               0 :             mState = STATE_CLOSED;
    1341               0 :             msg = MSG_ENSURE_CONNECT;
    1342                 :         }
    1343                 : 
    1344               0 :         rv = PostEvent(msg, NS_OK);
    1345               0 :         if (NS_FAILED(rv))
    1346               0 :             tryAgain = false;
    1347                 :     }
    1348                 : 
    1349             143 :     return tryAgain;
    1350                 : }
    1351                 : 
    1352                 : // called on the socket thread only
    1353                 : void
    1354            5739 : nsSocketTransport::OnMsgInputClosed(nsresult reason)
    1355                 : {
    1356            5739 :     SOCKET_LOG(("nsSocketTransport::OnMsgInputClosed [this=%x reason=%x]\n",
    1357                 :         this, reason));
    1358                 : 
    1359            5739 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
    1360                 : 
    1361            5739 :     mInputClosed = true;
    1362                 :     // check if event should affect entire transport
    1363            5739 :     if (NS_FAILED(reason) && (reason != NS_BASE_STREAM_CLOSED))
    1364            2835 :         mCondition = reason;                // XXX except if NS_FAILED(mCondition), right??
    1365            2904 :     else if (mOutputClosed)
    1366              36 :         mCondition = NS_BASE_STREAM_CLOSED; // XXX except if NS_FAILED(mCondition), right??
    1367                 :     else {
    1368            2868 :         if (mState == STATE_TRANSFERRING)
    1369            2868 :             mPollFlags &= ~PR_POLL_READ;
    1370            2868 :         mInput.OnSocketReady(reason);
    1371                 :     }
    1372            5739 : }
    1373                 : 
    1374                 : // called on the socket thread only
    1375                 : void
    1376            5736 : nsSocketTransport::OnMsgOutputClosed(nsresult reason)
    1377                 : {
    1378            5736 :     SOCKET_LOG(("nsSocketTransport::OnMsgOutputClosed [this=%x reason=%x]\n",
    1379                 :         this, reason));
    1380                 : 
    1381            5736 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
    1382                 : 
    1383            5736 :     mOutputClosed = true;
    1384                 :     // check if event should affect entire transport
    1385            5736 :     if (NS_FAILED(reason) && (reason != NS_BASE_STREAM_CLOSED))
    1386            2838 :         mCondition = reason;                // XXX except if NS_FAILED(mCondition), right??
    1387            2898 :     else if (mInputClosed)
    1388            2865 :         mCondition = NS_BASE_STREAM_CLOSED; // XXX except if NS_FAILED(mCondition), right??
    1389                 :     else {
    1390              33 :         if (mState == STATE_TRANSFERRING)
    1391              33 :             mPollFlags &= ~PR_POLL_WRITE;
    1392              33 :         mOutput.OnSocketReady(reason);
    1393                 :     }
    1394            5736 : }
    1395                 : 
    1396                 : void
    1397            2870 : nsSocketTransport::OnSocketConnected()
    1398                 : {
    1399            2870 :     SOCKET_LOG(("  advancing to STATE_TRANSFERRING\n"));
    1400                 : 
    1401            2870 :     mPollFlags = (PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT);
    1402            2870 :     mPollTimeout = mTimeouts[TIMEOUT_READ_WRITE];
    1403            2870 :     mState = STATE_TRANSFERRING;
    1404                 : 
    1405                 :     // Set the mNetAddrIsSet flag only when state has reached TRANSFERRING
    1406                 :     // because we need to make sure its value does not change due to failover
    1407            2870 :     mNetAddrIsSet = true;
    1408                 : 
    1409                 :     // assign mFD (must do this within the transport lock), but take care not
    1410                 :     // to trample over mFDref if mFD is already set.
    1411                 :     {
    1412            5740 :         MutexAutoLock lock(mLock);
    1413            2870 :         NS_ASSERTION(mFD, "no socket");
    1414            2870 :         NS_ASSERTION(mFDref == 1, "wrong socket ref count");
    1415            2870 :         mFDconnected = true;
    1416                 :     }
    1417                 : 
    1418            2870 :     SendStatus(STATUS_CONNECTED_TO);
    1419            2870 : }
    1420                 : 
    1421                 : PRFileDesc *
    1422           30908 : nsSocketTransport::GetFD_Locked()
    1423                 : {
    1424                 :     // mFD is not available to the streams while disconnected.
    1425           30908 :     if (!mFDconnected)
    1426              39 :         return nsnull;
    1427                 : 
    1428           30869 :     if (mFD)
    1429           30869 :         mFDref++;
    1430                 : 
    1431           30869 :     return mFD;
    1432                 : }
    1433                 : 
    1434                 : void
    1435           36745 : nsSocketTransport::ReleaseFD_Locked(PRFileDesc *fd)
    1436                 : {
    1437           36745 :     NS_ASSERTION(mFD == fd, "wrong fd");
    1438                 : 
    1439           36745 :     if (--mFDref == 0) {
    1440            5876 :         SOCKET_LOG(("nsSocketTransport: calling PR_Close [this=%x]\n", this));
    1441            5876 :         PR_Close(mFD);
    1442            5876 :         mFD = nsnull;
    1443                 :     }
    1444           36745 : }
    1445                 : 
    1446                 : //-----------------------------------------------------------------------------
    1447                 : // socket event handler impl
    1448                 : 
    1449                 : void
    1450           17648 : nsSocketTransport::OnSocketEvent(PRUint32 type, nsresult status, nsISupports *param)
    1451                 : {
    1452           17648 :     SOCKET_LOG(("nsSocketTransport::OnSocketEvent [this=%p type=%u status=%x param=%p]\n",
    1453                 :         this, type, status, param));
    1454                 : 
    1455           17648 :     if (NS_FAILED(mCondition)) {
    1456                 :         // block event since we're apparently already dead.
    1457               7 :         SOCKET_LOG(("  blocking event [condition=%x]\n", mCondition));
    1458                 :         //
    1459                 :         // notify input/output streams in case either has a pending notify.
    1460                 :         //
    1461               7 :         mInput.OnSocketReady(mCondition);
    1462               7 :         mOutput.OnSocketReady(mCondition);
    1463               7 :         return;
    1464                 :     }
    1465                 : 
    1466           17641 :     switch (type) {
    1467                 :     case MSG_ENSURE_CONNECT:
    1468           11758 :         SOCKET_LOG(("  MSG_ENSURE_CONNECT\n"));
    1469                 :         //
    1470                 :         // ensure that we have created a socket, attached it, and have a
    1471                 :         // connection.
    1472                 :         //
    1473           11758 :         if (mState == STATE_CLOSED)
    1474            3013 :             mCondition = ResolveHost();
    1475                 :         else
    1476            8745 :             SOCKET_LOG(("  ignoring redundant event\n"));
    1477           11758 :         break;
    1478                 : 
    1479                 :     case MSG_DNS_LOOKUP_COMPLETE:
    1480            3013 :         if (mDNSRequest)  // only send this if we actually resolved anything
    1481            3013 :             SendStatus(STATUS_RESOLVED);
    1482                 : 
    1483            3013 :         SOCKET_LOG(("  MSG_DNS_LOOKUP_COMPLETE\n"));
    1484            3013 :         mDNSRequest = 0;
    1485            3013 :         if (param) {
    1486            3006 :             mDNSRecord = static_cast<nsIDNSRecord *>(param);
    1487            3006 :             mDNSRecord->GetNextAddr(SocketPort(), &mNetAddr);
    1488                 :         }
    1489                 :         // status contains DNS lookup status
    1490            3013 :         if (NS_FAILED(status)) {
    1491                 :             // When using a HTTP proxy, NS_ERROR_UNKNOWN_HOST means the HTTP 
    1492                 :             // proxy host is not found, so we fixup the error code.
    1493                 :             // For SOCKS proxies (mProxyTransparent == true), the socket 
    1494                 :             // transport resolves the real host here, so there's no fixup 
    1495                 :             // (see bug 226943).
    1496              14 :             if ((status == NS_ERROR_UNKNOWN_HOST) && !mProxyTransparent &&
    1497               7 :                 !mProxyHost.IsEmpty())
    1498               2 :                 mCondition = NS_ERROR_UNKNOWN_PROXY_HOST;
    1499                 :             else
    1500               5 :                 mCondition = status;
    1501                 :         }
    1502            3006 :         else if (mState == STATE_RESOLVING)
    1503            3006 :             mCondition = InitiateSocket();
    1504            3013 :         break;
    1505                 : 
    1506                 :     case MSG_RETRY_INIT_SOCKET:
    1507            2870 :         mCondition = InitiateSocket();
    1508            2870 :         break;
    1509                 : 
    1510                 :     case MSG_INPUT_CLOSED:
    1511               0 :         SOCKET_LOG(("  MSG_INPUT_CLOSED\n"));
    1512               0 :         OnMsgInputClosed(status);
    1513               0 :         break;
    1514                 : 
    1515                 :     case MSG_INPUT_PENDING:
    1516               0 :         SOCKET_LOG(("  MSG_INPUT_PENDING\n"));
    1517               0 :         OnMsgInputPending();
    1518               0 :         break;
    1519                 : 
    1520                 :     case MSG_OUTPUT_CLOSED:
    1521               0 :         SOCKET_LOG(("  MSG_OUTPUT_CLOSED\n"));
    1522               0 :         OnMsgOutputClosed(status);
    1523               0 :         break;
    1524                 : 
    1525                 :     case MSG_OUTPUT_PENDING:
    1526               0 :         SOCKET_LOG(("  MSG_OUTPUT_PENDING\n"));
    1527               0 :         OnMsgOutputPending();
    1528               0 :         break;
    1529                 :     case MSG_TIMEOUT_CHANGED:
    1530               0 :         SOCKET_LOG(("  MSG_TIMEOUT_CHANGED\n"));
    1531                 :         mPollTimeout = mTimeouts[(mState == STATE_TRANSFERRING)
    1532               0 :           ? TIMEOUT_READ_WRITE : TIMEOUT_CONNECT];
    1533               0 :         break;
    1534                 :     default:
    1535               0 :         SOCKET_LOG(("  unhandled event!\n"));
    1536                 :     }
    1537                 :     
    1538           17641 :     if (NS_FAILED(mCondition)) {
    1539               7 :         SOCKET_LOG(("  after event [this=%x cond=%x]\n", this, mCondition));
    1540               7 :         if (!mAttached) // need to process this error ourselves...
    1541               7 :             OnSocketDetached(nsnull);
    1542                 :     }
    1543           17634 :     else if (mPollFlags == PR_POLL_EXCEPT)
    1544               0 :         mPollFlags = 0; // make idle
    1545                 : }
    1546                 : 
    1547                 : //-----------------------------------------------------------------------------
    1548                 : // socket handler impl
    1549                 : 
    1550                 : void
    1551           29887 : nsSocketTransport::OnSocketReady(PRFileDesc *fd, PRInt16 outFlags)
    1552                 : {
    1553           29887 :     SOCKET_LOG(("nsSocketTransport::OnSocketReady [this=%x outFlags=%hd]\n",
    1554                 :         this, outFlags));
    1555                 : 
    1556           29887 :     if (outFlags == -1) {
    1557               0 :         SOCKET_LOG(("socket timeout expired\n"));
    1558               0 :         mCondition = NS_ERROR_NET_TIMEOUT;
    1559               0 :         return;
    1560                 :     }
    1561                 : 
    1562           29887 :     if (mState == STATE_TRANSFERRING) {
    1563                 :         // if waiting to write and socket is writable or hit an exception.
    1564           26881 :         if ((mPollFlags & PR_POLL_WRITE) && (outFlags & ~PR_POLL_READ)) {
    1565                 :             // assume that we won't need to poll any longer (the stream will
    1566                 :             // request that we poll again if it is still pending).
    1567           14980 :             mPollFlags &= ~PR_POLL_WRITE;
    1568           14980 :             mOutput.OnSocketReady(NS_OK);
    1569                 :         }
    1570                 :         // if waiting to read and socket is readable or hit an exception.
    1571           26881 :         if ((mPollFlags & PR_POLL_READ) && (outFlags & ~PR_POLL_WRITE)) {
    1572                 :             // assume that we won't need to poll any longer (the stream will
    1573                 :             // request that we poll again if it is still pending).
    1574           12006 :             mPollFlags &= ~PR_POLL_READ;
    1575           12006 :             mInput.OnSocketReady(NS_OK);
    1576                 :         }
    1577                 :         // Update poll timeout in case it was changed
    1578           26881 :         mPollTimeout = mTimeouts[TIMEOUT_READ_WRITE];
    1579                 :     }
    1580            3006 :     else if (mState == STATE_CONNECTING) {
    1581            3006 :         PRStatus status = PR_ConnectContinue(fd, outFlags);
    1582            3006 :         if (status == PR_SUCCESS) {
    1583                 :             //
    1584                 :             // we are connected!
    1585                 :             //
    1586            2870 :             OnSocketConnected();
    1587                 :         }
    1588                 :         else {
    1589             136 :             PRErrorCode code = PR_GetError();
    1590                 : #if defined(TEST_CONNECT_ERRORS)
    1591                 :             code = RandomizeConnectError(code);
    1592                 : #endif
    1593                 :             //
    1594                 :             // If the connect is still not ready, then continue polling...
    1595                 :             //
    1596             136 :             if ((PR_WOULD_BLOCK_ERROR == code) || (PR_IN_PROGRESS_ERROR == code)) {
    1597                 :                 // Set up the select flags for connect...
    1598               0 :                 mPollFlags = (PR_POLL_EXCEPT | PR_POLL_WRITE);
    1599                 :                 // Update poll timeout in case it was changed
    1600               0 :                 mPollTimeout = mTimeouts[TIMEOUT_CONNECT];
    1601                 :             }
    1602                 :             //
    1603                 :             // The SOCKS proxy rejected our request. Find out why.
    1604                 :             //
    1605             136 :             else if (PR_UNKNOWN_ERROR == code &&
    1606                 :                      mProxyTransparent &&
    1607               0 :                      !mProxyHost.IsEmpty()) {
    1608               0 :                 code = PR_GetOSError();
    1609               0 :                 mCondition = ErrorAccordingToNSPR(code);
    1610                 :             }
    1611                 :             else {
    1612                 :                 //
    1613                 :                 // else, the connection failed...
    1614                 :                 //
    1615             136 :                 mCondition = ErrorAccordingToNSPR(code);
    1616             136 :                 if ((mCondition == NS_ERROR_CONNECTION_REFUSED) && !mProxyHost.IsEmpty())
    1617               0 :                     mCondition = NS_ERROR_PROXY_CONNECTION_REFUSED;
    1618             136 :                 SOCKET_LOG(("  connection failed! [reason=%x]\n", mCondition));
    1619                 :             }
    1620                 :         }
    1621                 :     }
    1622                 :     else {
    1623               0 :         NS_ERROR("unexpected socket state");
    1624               0 :         mCondition = NS_ERROR_UNEXPECTED;
    1625                 :     }
    1626                 : 
    1627           29887 :     if (mPollFlags == PR_POLL_EXCEPT)
    1628            9101 :         mPollFlags = 0; // make idle
    1629                 : }
    1630                 : 
    1631                 : // called on the socket thread only
    1632                 : void
    1633            5883 : nsSocketTransport::OnSocketDetached(PRFileDesc *fd)
    1634                 : {
    1635            5883 :     SOCKET_LOG(("nsSocketTransport::OnSocketDetached [this=%x cond=%x]\n",
    1636                 :         this, mCondition));
    1637                 : 
    1638            5883 :     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
    1639                 : 
    1640                 :     // if we didn't initiate this detach, then be sure to pass an error
    1641                 :     // condition up to our consumers.  (e.g., STS is shutting down.)
    1642            5883 :     if (NS_SUCCEEDED(mCondition))
    1643               1 :         mCondition = NS_ERROR_ABORT;
    1644                 : 
    1645            5883 :     if (RecoverFromError())
    1646               0 :         mCondition = NS_OK;
    1647                 :     else {
    1648            5883 :         mState = STATE_CLOSED;
    1649                 : 
    1650                 :         // make sure there isn't any pending DNS request
    1651            5883 :         if (mDNSRequest) {
    1652               0 :             mDNSRequest->Cancel(NS_ERROR_ABORT);
    1653               0 :             mDNSRequest = 0;
    1654                 :         }
    1655                 : 
    1656                 :         //
    1657                 :         // notify input/output streams
    1658                 :         //
    1659            5883 :         mInput.OnSocketReady(mCondition);
    1660            5883 :         mOutput.OnSocketReady(mCondition);
    1661                 :     }
    1662                 : 
    1663                 :     // break any potential reference cycle between the security info object
    1664                 :     // and ourselves by resetting its notification callbacks object.  see
    1665                 :     // bug 285991 for details.
    1666           11766 :     nsCOMPtr<nsISSLSocketControl> secCtrl = do_QueryInterface(mSecInfo);
    1667            5883 :     if (secCtrl)
    1668               4 :         secCtrl->SetNotificationCallbacks(nsnull);
    1669                 : 
    1670                 :     // finally, release our reference to the socket (must do this within
    1671                 :     // the transport lock) possibly closing the socket. Also release our
    1672                 :     // listeners to break potential refcount cycles.
    1673                 : 
    1674                 :     // We should be careful not to release mEventSink and mCallbacks while
    1675                 :     // we're locked, because releasing it might require acquiring the lock
    1676                 :     // again, so we just null out mEventSink and mCallbacks while we're
    1677                 :     // holding the lock, and let the stack based objects' destuctors take
    1678                 :     // care of destroying it if needed.
    1679           11766 :     nsCOMPtr<nsIInterfaceRequestor> ourCallbacks;
    1680           11766 :     nsCOMPtr<nsITransportEventSink> ourEventSink;
    1681                 :     {
    1682           11766 :         MutexAutoLock lock(mLock);
    1683            5883 :         if (mFD) {
    1684            5876 :             ReleaseFD_Locked(mFD);
    1685                 :             // flag mFD as unusable; this prevents other consumers from 
    1686                 :             // acquiring a reference to mFD.
    1687            5876 :             mFDconnected = false;
    1688                 :         }
    1689                 : 
    1690                 :         // We must release mCallbacks and mEventSink to avoid memory leak
    1691                 :         // but only when RecoverFromError() above failed. Otherwise we lose
    1692                 :         // link with UI and security callbacks on next connection attempt 
    1693                 :         // round. That would lead e.g. to a broken certificate exception page.
    1694            5883 :         if (NS_FAILED(mCondition)) {
    1695            5883 :             mCallbacks.swap(ourCallbacks);
    1696            5883 :             mEventSink.swap(ourEventSink);
    1697                 :         }
    1698                 :     }
    1699            5883 : }
    1700                 : 
    1701                 : //-----------------------------------------------------------------------------
    1702                 : // xpcom api
    1703                 : 
    1704          313570 : NS_IMPL_THREADSAFE_ISUPPORTS4(nsSocketTransport,
    1705                 :                               nsISocketTransport,
    1706                 :                               nsITransport,
    1707                 :                               nsIDNSListener,
    1708                 :                               nsIClassInfo)
    1709            2907 : NS_IMPL_CI_INTERFACE_GETTER3(nsSocketTransport,
    1710                 :                              nsISocketTransport,
    1711                 :                              nsITransport,
    1712            2907 :                              nsIDNSListener)
    1713                 : 
    1714                 : NS_IMETHODIMP
    1715            5882 : nsSocketTransport::OpenInputStream(PRUint32 flags,
    1716                 :                                    PRUint32 segsize,
    1717                 :                                    PRUint32 segcount,
    1718                 :                                    nsIInputStream **result)
    1719                 : {
    1720            5882 :     SOCKET_LOG(("nsSocketTransport::OpenInputStream [this=%x flags=%x]\n",
    1721                 :         this, flags));
    1722                 : 
    1723            5882 :     NS_ENSURE_TRUE(!mInput.IsReferenced(), NS_ERROR_UNEXPECTED);
    1724                 : 
    1725                 :     nsresult rv;
    1726           11764 :     nsCOMPtr<nsIAsyncInputStream> pipeIn;
    1727                 : 
    1728            5882 :     if (!(flags & OPEN_UNBUFFERED) || (flags & OPEN_BLOCKING)) {
    1729                 :         // XXX if the caller wants blocking, then the caller also gets buffered!
    1730                 :         //bool openBuffered = !(flags & OPEN_UNBUFFERED);
    1731            2906 :         bool openBlocking =  (flags & OPEN_BLOCKING);
    1732                 : 
    1733            2906 :         net_ResolveSegmentParams(segsize, segcount);
    1734                 : 
    1735                 :         // create a pipe
    1736            5812 :         nsCOMPtr<nsIAsyncOutputStream> pipeOut;
    1737            2906 :         rv = NS_NewPipe2(getter_AddRefs(pipeIn), getter_AddRefs(pipeOut),
    1738            2906 :                          !openBlocking, true, segsize, segcount);
    1739            2906 :         if (NS_FAILED(rv)) return rv;
    1740                 : 
    1741                 :         // async copy from socket to pipe
    1742                 :         rv = NS_AsyncCopy(&mInput, pipeOut, gSocketTransportService,
    1743            2906 :                           NS_ASYNCCOPY_VIA_WRITESEGMENTS, segsize);
    1744            2906 :         if (NS_FAILED(rv)) return rv;
    1745                 : 
    1746            5812 :         *result = pipeIn;
    1747                 :     }
    1748                 :     else
    1749            2976 :         *result = &mInput;
    1750                 : 
    1751                 :     // flag input stream as open
    1752            5882 :     mInputClosed = false;
    1753                 : 
    1754            5882 :     rv = PostEvent(MSG_ENSURE_CONNECT);
    1755            5882 :     if (NS_FAILED(rv)) return rv;
    1756                 : 
    1757            5882 :     NS_ADDREF(*result);
    1758            5882 :     return NS_OK;
    1759                 : }
    1760                 : 
    1761                 : NS_IMETHODIMP
    1762            5883 : nsSocketTransport::OpenOutputStream(PRUint32 flags,
    1763                 :                                     PRUint32 segsize,
    1764                 :                                     PRUint32 segcount,
    1765                 :                                     nsIOutputStream **result)
    1766                 : {
    1767            5883 :     SOCKET_LOG(("nsSocketTransport::OpenOutputStream [this=%x flags=%x]\n",
    1768                 :         this, flags));
    1769                 : 
    1770            5883 :     NS_ENSURE_TRUE(!mOutput.IsReferenced(), NS_ERROR_UNEXPECTED);
    1771                 : 
    1772                 :     nsresult rv;
    1773           11766 :     nsCOMPtr<nsIAsyncOutputStream> pipeOut;
    1774            5883 :     if (!(flags & OPEN_UNBUFFERED) || (flags & OPEN_BLOCKING)) {
    1775                 :         // XXX if the caller wants blocking, then the caller also gets buffered!
    1776                 :         //bool openBuffered = !(flags & OPEN_UNBUFFERED);
    1777            2907 :         bool openBlocking =  (flags & OPEN_BLOCKING);
    1778                 : 
    1779            2907 :         net_ResolveSegmentParams(segsize, segcount);
    1780                 : 
    1781                 :         // create a pipe
    1782            5814 :         nsCOMPtr<nsIAsyncInputStream> pipeIn;
    1783            2907 :         rv = NS_NewPipe2(getter_AddRefs(pipeIn), getter_AddRefs(pipeOut),
    1784            2907 :                          true, !openBlocking, segsize, segcount);
    1785            2907 :         if (NS_FAILED(rv)) return rv;
    1786                 : 
    1787                 :         // async copy from socket to pipe
    1788                 :         rv = NS_AsyncCopy(pipeIn, &mOutput, gSocketTransportService,
    1789            2907 :                           NS_ASYNCCOPY_VIA_READSEGMENTS, segsize);
    1790            2907 :         if (NS_FAILED(rv)) return rv;
    1791                 : 
    1792            5814 :         *result = pipeOut;
    1793                 :     }
    1794                 :     else
    1795            2976 :         *result = &mOutput;
    1796                 : 
    1797                 :     // flag output stream as open
    1798            5883 :     mOutputClosed = false;
    1799                 : 
    1800            5883 :     rv = PostEvent(MSG_ENSURE_CONNECT);
    1801            5883 :     if (NS_FAILED(rv)) return rv;
    1802                 : 
    1803            5883 :     NS_ADDREF(*result);
    1804            5883 :     return NS_OK;
    1805                 : }
    1806                 : 
    1807                 : NS_IMETHODIMP
    1808            3138 : nsSocketTransport::Close(nsresult reason)
    1809                 : {
    1810            3138 :     if (NS_SUCCEEDED(reason))
    1811               1 :         reason = NS_BASE_STREAM_CLOSED;
    1812                 : 
    1813            3138 :     mInput.CloseWithStatus(reason);
    1814            3138 :     mOutput.CloseWithStatus(reason);
    1815            3138 :     return NS_OK;
    1816                 : }
    1817                 : 
    1818                 : NS_IMETHODIMP
    1819            2995 : nsSocketTransport::GetSecurityInfo(nsISupports **secinfo)
    1820                 : {
    1821            5990 :     MutexAutoLock lock(mLock);
    1822            2995 :     NS_IF_ADDREF(*secinfo = mSecInfo);
    1823            2995 :     return NS_OK;
    1824                 : }
    1825                 : 
    1826                 : NS_IMETHODIMP
    1827               0 : nsSocketTransport::GetSecurityCallbacks(nsIInterfaceRequestor **callbacks)
    1828                 : {
    1829               0 :     MutexAutoLock lock(mLock);
    1830               0 :     NS_IF_ADDREF(*callbacks = mCallbacks);
    1831               0 :     return NS_OK;
    1832                 : }
    1833                 : 
    1834                 : NS_IMETHODIMP
    1835            9089 : nsSocketTransport::SetSecurityCallbacks(nsIInterfaceRequestor *callbacks)
    1836                 : {
    1837           18178 :     nsCOMPtr<nsISupports> secinfo;
    1838                 :     {
    1839           18178 :         MutexAutoLock lock(mLock);
    1840            9089 :         mCallbacks = callbacks;
    1841            9089 :         SOCKET_LOG(("Reset callbacks for secinfo=%p callbacks=%p\n",
    1842                 :                     mSecInfo.get(), mCallbacks.get()));
    1843                 : 
    1844            9089 :         secinfo = mSecInfo;
    1845                 :     }
    1846                 : 
    1847                 :     // don't call into PSM while holding mLock!!
    1848           18178 :     nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(secinfo));
    1849            9089 :     if (secCtrl)
    1850               8 :         secCtrl->SetNotificationCallbacks(callbacks);
    1851                 : 
    1852            9089 :     return NS_OK;
    1853                 : }
    1854                 : 
    1855                 : NS_IMETHODIMP
    1856            9089 : nsSocketTransport::SetEventSink(nsITransportEventSink *sink,
    1857                 :                                 nsIEventTarget *target)
    1858                 : {
    1859           18178 :     nsCOMPtr<nsITransportEventSink> temp;
    1860            9089 :     if (target) {
    1861               0 :         nsresult rv = net_NewTransportEventSinkProxy(getter_AddRefs(temp),
    1862               0 :                                                      sink, target);
    1863               0 :         if (NS_FAILED(rv))
    1864               0 :             return rv;
    1865               0 :         sink = temp.get();
    1866                 :     }
    1867                 : 
    1868           18178 :     MutexAutoLock lock(mLock);
    1869            9089 :     mEventSink = sink;
    1870            9089 :     return NS_OK;
    1871                 : }
    1872                 : 
    1873                 : NS_IMETHODIMP
    1874               6 : nsSocketTransport::IsAlive(bool *result)
    1875                 : {
    1876               6 :     *result = false;
    1877                 : 
    1878                 :     PRFileDesc *fd;
    1879                 :     {
    1880              12 :         MutexAutoLock lock(mLock);
    1881               6 :         if (NS_FAILED(mCondition))
    1882               0 :             return NS_OK;
    1883               6 :         fd = GetFD_Locked();
    1884               6 :         if (!fd)
    1885               0 :             return NS_OK;
    1886                 :     }
    1887                 : 
    1888                 :     // XXX do some idle-time based checks??
    1889                 : 
    1890                 :     char c;
    1891               6 :     PRInt32 rval = PR_Recv(fd, &c, 1, PR_MSG_PEEK, 0);
    1892                 : 
    1893               6 :     if ((rval > 0) || (rval < 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR))
    1894               6 :         *result = true;
    1895                 : 
    1896                 :     {
    1897              12 :         MutexAutoLock lock(mLock);
    1898               6 :         ReleaseFD_Locked(fd);
    1899                 :     }
    1900               6 :     return NS_OK;
    1901                 : }
    1902                 : 
    1903                 : NS_IMETHODIMP
    1904            2865 : nsSocketTransport::GetHost(nsACString &host)
    1905                 : {
    1906            2865 :     host = SocketHost();
    1907            2865 :     return NS_OK;
    1908                 : }
    1909                 : 
    1910                 : NS_IMETHODIMP
    1911            5730 : nsSocketTransport::GetPort(PRInt32 *port)
    1912                 : {
    1913            5730 :     *port = (PRInt32) SocketPort();
    1914            5730 :     return NS_OK;
    1915                 : }
    1916                 : 
    1917                 : NS_IMETHODIMP
    1918            2937 : nsSocketTransport::GetPeerAddr(PRNetAddr *addr)
    1919                 : {
    1920                 :     // once we are in the connected state, mNetAddr will not change.
    1921                 :     // so if we can verify that we are in the connected state, then
    1922                 :     // we can freely access mNetAddr from any thread without being
    1923                 :     // inside a critical section.
    1924                 : 
    1925            2937 :     if (!mNetAddrIsSet) {
    1926               0 :         SOCKET_LOG(("nsSocketTransport::GetPeerAddr [this=%p state=%d] "
    1927                 :                     "NOT_AVAILABLE because not yet connected.", this, mState));
    1928               0 :         return NS_ERROR_NOT_AVAILABLE;
    1929                 :     }
    1930                 : 
    1931            2937 :     memcpy(addr, &mNetAddr, sizeof(mNetAddr));
    1932            2937 :     return NS_OK;
    1933                 : }
    1934                 : 
    1935                 : NS_IMETHODIMP
    1936            2933 : nsSocketTransport::GetSelfAddr(PRNetAddr *addr)
    1937                 : {
    1938                 :     // we must not call any PR methods on our file descriptor
    1939                 :     // while holding mLock since those methods might re-enter
    1940                 :     // socket transport code.
    1941                 : 
    1942                 :     PRFileDesc *fd;
    1943                 :     {
    1944            5866 :         MutexAutoLock lock(mLock);
    1945            2933 :         fd = GetFD_Locked();
    1946                 :     }
    1947                 : 
    1948            2933 :     if (!fd)
    1949               3 :         return NS_ERROR_NOT_CONNECTED;
    1950                 : 
    1951                 :     nsresult rv =
    1952            2930 :         (PR_GetSockName(fd, addr) == PR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
    1953                 : 
    1954                 :     {
    1955            5860 :         MutexAutoLock lock(mLock);
    1956            2930 :         ReleaseFD_Locked(fd);
    1957                 :     }
    1958                 : 
    1959            2930 :     return rv;
    1960                 : }
    1961                 : 
    1962                 : /* nsINetAddr getScriptablePeerAddr (); */
    1963                 : NS_IMETHODIMP
    1964               2 : nsSocketTransport::GetScriptablePeerAddr(nsINetAddr * *addr NS_OUTPARAM)
    1965                 : {
    1966                 :     PRNetAddr rawAddr;
    1967                 : 
    1968                 :     nsresult rv;
    1969               2 :     rv = GetPeerAddr(&rawAddr);
    1970               2 :     if (NS_FAILED(rv))
    1971               0 :         return rv;
    1972                 : 
    1973               2 :     NS_ADDREF(*addr = new nsNetAddr(&rawAddr));
    1974                 : 
    1975               2 :     return NS_OK;
    1976                 : }
    1977                 : 
    1978                 : /* nsINetAddr getScriptableSelfAddr (); */
    1979                 : NS_IMETHODIMP
    1980               2 : nsSocketTransport::GetScriptableSelfAddr(nsINetAddr * *addr NS_OUTPARAM)
    1981                 : {
    1982                 :     PRNetAddr rawAddr;
    1983                 : 
    1984                 :     nsresult rv;
    1985               2 :     rv = GetSelfAddr(&rawAddr);
    1986               2 :     if (NS_FAILED(rv))
    1987               0 :         return rv;
    1988                 : 
    1989               2 :     NS_ADDREF(*addr = new nsNetAddr(&rawAddr));
    1990                 : 
    1991               2 :     return NS_OK;
    1992                 : }
    1993                 : 
    1994                 : NS_IMETHODIMP
    1995               0 : nsSocketTransport::GetTimeout(PRUint32 type, PRUint32 *value)
    1996                 : {
    1997               0 :     NS_ENSURE_ARG_MAX(type, nsISocketTransport::TIMEOUT_READ_WRITE);
    1998               0 :     *value = (PRUint32) mTimeouts[type];
    1999               0 :     return NS_OK;
    2000                 : }
    2001                 : 
    2002                 : NS_IMETHODIMP
    2003               0 : nsSocketTransport::SetTimeout(PRUint32 type, PRUint32 value)
    2004                 : {
    2005               0 :     NS_ENSURE_ARG_MAX(type, nsISocketTransport::TIMEOUT_READ_WRITE);
    2006                 :     // truncate overly large timeout values.
    2007               0 :     mTimeouts[type] = (PRUint16) NS_MIN(value, PR_UINT16_MAX);
    2008               0 :     PostEvent(MSG_TIMEOUT_CHANGED);
    2009               0 :     return NS_OK;
    2010                 : }
    2011                 : 
    2012                 : NS_IMETHODIMP
    2013            2976 : nsSocketTransport::SetQoSBits(PRUint8 aQoSBits)
    2014                 : {
    2015                 :     // Don't do any checking here of bits.  Why?  Because as of RFC-4594
    2016                 :     // several different Class Selector and Assured Forwarding values
    2017                 :     // have been defined, but that isn't to say more won't be added later.
    2018                 :     // In that case, any checking would be an impediment to interoperating
    2019                 :     // with newer QoS definitions.
    2020                 : 
    2021            2976 :     mQoSBits = aQoSBits;
    2022            2976 :     return NS_OK;
    2023                 : }
    2024                 : 
    2025                 : NS_IMETHODIMP
    2026               0 : nsSocketTransport::GetQoSBits(PRUint8 *aQoSBits)
    2027                 : {
    2028               0 :     *aQoSBits = mQoSBits;
    2029               0 :     return NS_OK;
    2030                 : }
    2031                 : 
    2032                 : NS_IMETHODIMP
    2033            3013 : nsSocketTransport::OnLookupComplete(nsICancelable *request,
    2034                 :                                     nsIDNSRecord  *rec,
    2035                 :                                     nsresult       status)
    2036                 : {
    2037                 :     // flag host lookup complete for the benefit of the ResolveHost method.
    2038            3013 :     mResolving = false;
    2039                 : 
    2040            3013 :     nsresult rv = PostEvent(MSG_DNS_LOOKUP_COMPLETE, status, rec);
    2041                 : 
    2042                 :     // if posting a message fails, then we should assume that the socket
    2043                 :     // transport has been shutdown.  this should never happen!  if it does
    2044                 :     // it means that the socket transport service was shutdown before the
    2045                 :     // DNS service.
    2046            3013 :     if (NS_FAILED(rv))
    2047               0 :         NS_WARNING("unable to post DNS lookup complete message");
    2048                 : 
    2049            3013 :     return NS_OK;
    2050                 : }
    2051                 : 
    2052                 : NS_IMETHODIMP
    2053            2907 : nsSocketTransport::GetInterfaces(PRUint32 *count, nsIID * **array)
    2054                 : {
    2055            2907 :     return NS_CI_INTERFACE_GETTER_NAME(nsSocketTransport)(count, array);
    2056                 : }
    2057                 : 
    2058                 : NS_IMETHODIMP
    2059            2907 : nsSocketTransport::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
    2060                 : {
    2061            2907 :     *_retval = nsnull;
    2062            2907 :     return NS_OK;
    2063                 : }
    2064                 : 
    2065                 : NS_IMETHODIMP
    2066               0 : nsSocketTransport::GetContractID(char * *aContractID)
    2067                 : {
    2068               0 :     *aContractID = nsnull;
    2069               0 :     return NS_OK;
    2070                 : }
    2071                 : 
    2072                 : NS_IMETHODIMP
    2073               0 : nsSocketTransport::GetClassDescription(char * *aClassDescription)
    2074                 : {
    2075               0 :     *aClassDescription = nsnull;
    2076               0 :     return NS_OK;
    2077                 : }
    2078                 : 
    2079                 : NS_IMETHODIMP
    2080               0 : nsSocketTransport::GetClassID(nsCID * *aClassID)
    2081                 : {
    2082               0 :     *aClassID = nsnull;
    2083               0 :     return NS_OK;
    2084                 : }
    2085                 : 
    2086                 : NS_IMETHODIMP
    2087               0 : nsSocketTransport::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
    2088                 : {
    2089               0 :     *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
    2090               0 :     return NS_OK;
    2091                 : }
    2092                 : 
    2093                 : NS_IMETHODIMP
    2094            2908 : nsSocketTransport::GetFlags(PRUint32 *aFlags)
    2095                 : {
    2096            2908 :     *aFlags = nsIClassInfo::THREADSAFE;
    2097            2908 :     return NS_OK;
    2098                 : }
    2099                 : 
    2100                 : NS_IMETHODIMP
    2101               0 : nsSocketTransport::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
    2102                 : {
    2103               0 :     return NS_ERROR_NOT_AVAILABLE;
    2104                 : }
    2105                 : 
    2106                 : 
    2107                 : NS_IMETHODIMP
    2108               0 : nsSocketTransport::GetConnectionFlags(PRUint32 *value)
    2109                 : {
    2110               0 :     *value = mConnectionFlags;
    2111               0 :     return NS_OK;
    2112                 : }
    2113                 : 
    2114                 : NS_IMETHODIMP
    2115            2976 : nsSocketTransport::SetConnectionFlags(PRUint32 value)
    2116                 : {
    2117            2976 :     mConnectionFlags = value;
    2118            2976 :     return NS_OK;
    2119                 : }
    2120                 : 
    2121                 : 
    2122                 : #ifdef ENABLE_SOCKET_TRACING
    2123                 : 
    2124                 : #include <stdio.h>
    2125                 : #include <ctype.h>
    2126                 : #include "prenv.h"
    2127                 : 
    2128                 : static void
    2129                 : DumpBytesToFile(const char *path, const char *header, const char *buf, PRInt32 n)
    2130                 : {
    2131                 :     FILE *fp = fopen(path, "a");
    2132                 : 
    2133                 :     fprintf(fp, "\n%s [%d bytes]\n", header, n);
    2134                 : 
    2135                 :     const unsigned char *p;
    2136                 :     while (n) {
    2137                 :         p = (const unsigned char *) buf;
    2138                 : 
    2139                 :         PRInt32 i, row_max = NS_MIN(16, n);
    2140                 : 
    2141                 :         for (i = 0; i < row_max; ++i)
    2142                 :             fprintf(fp, "%02x  ", *p++);
    2143                 :         for (i = row_max; i < 16; ++i)
    2144                 :             fprintf(fp, "    ");
    2145                 : 
    2146                 :         p = (const unsigned char *) buf;
    2147                 :         for (i = 0; i < row_max; ++i, ++p) {
    2148                 :             if (isprint(*p))
    2149                 :                 fprintf(fp, "%c", *p);
    2150                 :             else
    2151                 :                 fprintf(fp, ".");
    2152                 :         }
    2153                 : 
    2154                 :         fprintf(fp, "\n");
    2155                 :         buf += row_max;
    2156                 :         n -= row_max;
    2157                 :     }
    2158                 : 
    2159                 :     fprintf(fp, "\n");
    2160                 :     fclose(fp);
    2161                 : }
    2162                 : 
    2163                 : void
    2164                 : nsSocketTransport::TraceInBuf(const char *buf, PRInt32 n)
    2165                 : {
    2166                 :     char *val = PR_GetEnv("NECKO_SOCKET_TRACE_LOG");
    2167                 :     if (!val || !*val)
    2168                 :         return;
    2169                 : 
    2170                 :     nsCAutoString header;
    2171                 :     header.Assign(NS_LITERAL_CSTRING("Reading from: ") + mHost);
    2172                 :     header.Append(':');
    2173                 :     header.AppendInt(mPort);
    2174                 : 
    2175                 :     DumpBytesToFile(val, header.get(), buf, n);
    2176                 : }
    2177                 : 
    2178                 : void
    2179                 : nsSocketTransport::TraceOutBuf(const char *buf, PRInt32 n)
    2180                 : {
    2181                 :     char *val = PR_GetEnv("NECKO_SOCKET_TRACE_LOG");
    2182                 :     if (!val || !*val)
    2183                 :         return;
    2184                 : 
    2185                 :     nsCAutoString header;
    2186                 :     header.Assign(NS_LITERAL_CSTRING("Writing to: ") + mHost);
    2187                 :     header.Append(':');
    2188                 :     header.AppendInt(mPort);
    2189                 : 
    2190                 :     DumpBytesToFile(val, header.get(), buf, n);
    2191                 : }
    2192                 : 
    2193                 : #endif

Generated by: LCOV version 1.7