Back to index

lightning-sunbird  0.9+nobinonly
nsSocketTransport2.h
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2002
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Darin Fisher <darin@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef nsSocketTransport2_h__
00039 #define nsSocketTransport2_h__
00040 
00041 #ifdef DEBUG_darinf
00042 #define ENABLE_SOCKET_TRACING
00043 #endif
00044 
00045 #include "nsSocketTransportService2.h"
00046 #include "nsString.h"
00047 #include "nsCOMPtr.h"
00048 #include "nsInt64.h"
00049 
00050 #include "nsISocketTransport.h"
00051 #include "nsIInterfaceRequestor.h"
00052 #include "nsIAsyncInputStream.h"
00053 #include "nsIAsyncOutputStream.h"
00054 #include "nsIDNSListener.h"
00055 #include "nsIDNSRecord.h"
00056 #include "nsICancelable.h"
00057 
00058 class nsSocketTransport;
00059 
00060 //-----------------------------------------------------------------------------
00061 
00062 // after this short interval, we will return to PR_Poll
00063 #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20)
00064 
00065 //-----------------------------------------------------------------------------
00066 
00067 class nsSocketInputStream : public nsIAsyncInputStream
00068 {
00069 public:
00070     NS_DECL_ISUPPORTS_INHERITED
00071     NS_DECL_NSIINPUTSTREAM
00072     NS_DECL_NSIASYNCINPUTSTREAM
00073 
00074     nsSocketInputStream(nsSocketTransport *);
00075     virtual ~nsSocketInputStream();
00076 
00077     PRBool   IsReferenced() { return mReaderRefCnt > 0; }
00078     nsresult Condition()    { return mCondition; }
00079     PRUint64 ByteCount()    { return mByteCount; }
00080 
00081     // called by the socket transport on the socket thread...
00082     void OnSocketReady(nsresult condition);
00083 
00084 private:
00085     nsSocketTransport               *mTransport;
00086     nsrefcnt                         mReaderRefCnt;
00087 
00088     // access to these is protected by mTransport->mLock
00089     nsresult                         mCondition;
00090     nsCOMPtr<nsIInputStreamCallback> mCallback;
00091     PRUint32                         mCallbackFlags;
00092     nsUint64                         mByteCount;
00093 };
00094 
00095 //-----------------------------------------------------------------------------
00096 
00097 class nsSocketOutputStream : public nsIAsyncOutputStream
00098 {
00099 public:
00100     NS_DECL_ISUPPORTS_INHERITED
00101     NS_DECL_NSIOUTPUTSTREAM
00102     NS_DECL_NSIASYNCOUTPUTSTREAM
00103 
00104     nsSocketOutputStream(nsSocketTransport *);
00105     virtual ~nsSocketOutputStream();
00106 
00107     PRBool   IsReferenced() { return mWriterRefCnt > 0; }
00108     nsresult Condition()    { return mCondition; }
00109     PRUint64 ByteCount()    { return mByteCount; }
00110 
00111     // called by the socket transport on the socket thread...
00112     void OnSocketReady(nsresult condition); 
00113 
00114 private:
00115     static NS_METHOD WriteFromSegments(nsIInputStream *, void *,
00116                                        const char *, PRUint32 offset,
00117                                        PRUint32 count, PRUint32 *countRead);
00118 
00119     nsSocketTransport                *mTransport;
00120     nsrefcnt                          mWriterRefCnt;
00121 
00122     // access to these is protected by mTransport->mLock
00123     nsresult                          mCondition;
00124     nsCOMPtr<nsIOutputStreamCallback> mCallback;
00125     PRUint32                          mCallbackFlags;
00126     nsUint64                          mByteCount;
00127 };
00128 
00129 //-----------------------------------------------------------------------------
00130 
00131 class nsSocketTransport : public nsASocketHandler
00132                         , public nsISocketTransport
00133                         , public nsIDNSListener
00134 {
00135 public:
00136     NS_DECL_ISUPPORTS
00137     NS_DECL_NSITRANSPORT
00138     NS_DECL_NSISOCKETTRANSPORT
00139     NS_DECL_NSIDNSLISTENER
00140 
00141     nsSocketTransport();
00142 
00143     // this method instructs the socket transport to open a socket of the
00144     // given type(s) to the given host or proxy.
00145     nsresult Init(const char **socketTypes, PRUint32 typeCount,
00146                   const nsACString &host, PRUint16 port,
00147                   nsIProxyInfo *proxyInfo);
00148 
00149     // this method instructs the socket transport to use an already connected
00150     // socket with the given address.
00151     nsresult InitWithConnectedSocket(PRFileDesc *socketFD,
00152                                      const PRNetAddr *addr);
00153 
00154     // nsASocketHandler methods:
00155     void OnSocketReady(PRFileDesc *, PRInt16 outFlags); 
00156     void OnSocketDetached(PRFileDesc *);
00157 
00158     // called when a socket event is handled
00159     void OnSocketEvent(PRUint32 type, nsresult status, nsISupports *param);
00160 
00161 protected:
00162 
00163     virtual ~nsSocketTransport();
00164 
00165 private:
00166 
00167     // event types
00168     enum {
00169         MSG_ENSURE_CONNECT,
00170         MSG_DNS_LOOKUP_COMPLETE,
00171         MSG_RETRY_INIT_SOCKET,
00172         MSG_TIMEOUT_CHANGED,
00173         MSG_INPUT_CLOSED,
00174         MSG_INPUT_PENDING,
00175         MSG_OUTPUT_CLOSED,
00176         MSG_OUTPUT_PENDING
00177     };
00178     nsresult PostEvent(PRUint32 type, nsresult status = NS_OK, nsISupports *param = nsnull);
00179 
00180     enum {
00181         STATE_CLOSED,
00182         STATE_IDLE,
00183         STATE_RESOLVING,
00184         STATE_CONNECTING,
00185         STATE_TRANSFERRING
00186     };
00187 
00188     //-------------------------------------------------------------------------
00189     // these members are "set" at initialization time and are never modified
00190     // afterwards.  this allows them to be safely accessed from any thread.
00191     //-------------------------------------------------------------------------
00192 
00193     // socket type info:
00194     char       **mTypes;
00195     PRUint32     mTypeCount;
00196     nsCString    mHost;
00197     nsCString    mProxyHost;
00198     PRUint16     mPort;
00199     PRUint16     mProxyPort;
00200     PRPackedBool mProxyTransparent;
00201     PRPackedBool mProxyTransparentResolvesHost;
00202 
00203     PRUint16         SocketPort() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; }
00204     const nsCString &SocketHost() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyHost : mHost; }
00205 
00206     //-------------------------------------------------------------------------
00207     // members accessible only on the socket transport thread:
00208     //  (the exception being initialization/shutdown time)
00209     //-------------------------------------------------------------------------
00210 
00211     // socket state vars:
00212     PRUint32     mState;     // STATE_??? flags
00213     PRPackedBool mAttached;
00214     PRPackedBool mInputClosed;
00215     PRPackedBool mOutputClosed;
00216 
00217     // this flag is used to determine if the results of a host lookup arrive
00218     // recursively or not.  this flag is not protected by any lock.
00219     PRPackedBool mResolving;
00220 
00221     nsCOMPtr<nsICancelable> mDNSRequest;
00222     nsCOMPtr<nsIDNSRecord>  mDNSRecord;
00223     PRNetAddr               mNetAddr;
00224 
00225     // socket methods (these can only be called on the socket thread):
00226 
00227     void     SendStatus(nsresult status);
00228     nsresult ResolveHost();
00229     nsresult BuildSocket(PRFileDesc *&, PRBool &, PRBool &); 
00230     nsresult InitiateSocket();
00231     PRBool   RecoverFromError();
00232 
00233     void OnMsgInputPending()
00234     {
00235         if (mState == STATE_TRANSFERRING)
00236             mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT);
00237     }
00238     void OnMsgOutputPending()
00239     {
00240         if (mState == STATE_TRANSFERRING)
00241             mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT);
00242     }
00243     void OnMsgInputClosed(nsresult reason);
00244     void OnMsgOutputClosed(nsresult reason);
00245 
00246     // called when the socket is connected
00247     void OnSocketConnected();
00248 
00249     //-------------------------------------------------------------------------
00250     // socket input/output objects.  these may be accessed on any thread with
00251     // the exception of some specific methods (XXX).
00252 
00253     PRLock     *mLock;  // protects members in this section
00254     PRFileDesc *mFD;
00255     nsrefcnt    mFDref;       // mFD is closed when mFDref goes to zero.
00256     PRBool      mFDconnected; // mFD is available to consumer when TRUE.
00257 
00258     nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
00259     nsCOMPtr<nsITransportEventSink> mEventSink;
00260     nsCOMPtr<nsISupports>           mSecInfo;
00261 
00262     nsSocketInputStream  mInput;
00263     nsSocketOutputStream mOutput;
00264 
00265     friend class nsSocketInputStream;
00266     friend class nsSocketOutputStream;
00267 
00268     // socket timeouts are not protected by any lock.
00269     PRUint16 mTimeouts[2];
00270 
00271     //
00272     // mFD access methods: called with mLock held.
00273     //
00274     PRFileDesc *GetFD_Locked();
00275     void        ReleaseFD_Locked(PRFileDesc *fd);
00276 
00277     //
00278     // stream state changes (called outside mLock):
00279     //
00280     void OnInputClosed(nsresult reason)
00281     {
00282         // no need to post an event if called on the socket thread
00283         if (PR_GetCurrentThread() == gSocketThread)
00284             OnMsgInputClosed(reason);
00285         else
00286             PostEvent(MSG_INPUT_CLOSED, reason);
00287     }
00288     void OnInputPending()
00289     {
00290         // no need to post an event if called on the socket thread
00291         if (PR_GetCurrentThread() == gSocketThread)
00292             OnMsgInputPending();
00293         else
00294             PostEvent(MSG_INPUT_PENDING);
00295     }
00296     void OnOutputClosed(nsresult reason)
00297     {
00298         // no need to post an event if called on the socket thread
00299         if (PR_GetCurrentThread() == gSocketThread)
00300             OnMsgOutputClosed(reason); // XXX need to not be inside lock!
00301         else
00302             PostEvent(MSG_OUTPUT_CLOSED, reason);
00303     }
00304     void OnOutputPending()
00305     {
00306         // no need to post an event if called on the socket thread
00307         if (PR_GetCurrentThread() == gSocketThread)
00308             OnMsgOutputPending();
00309         else
00310             PostEvent(MSG_OUTPUT_PENDING);
00311     }
00312 
00313 #ifdef ENABLE_SOCKET_TRACING
00314     void TraceInBuf(const char *buf, PRInt32 n);
00315     void TraceOutBuf(const char *buf, PRInt32 n);
00316 #endif
00317 };
00318 
00319 #endif // !nsSocketTransport_h__