Back to index

lightning-sunbird  0.9+nobinonly
nsTransportUtils.cpp
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 IBM Corporation.
00017  * Portions created by IBM Corporation are Copyright (C) 2003
00018  * IBM Corporation. All Rights Reserved.
00019  *
00020  * Contributor(s):
00021  *   IBM Corp.
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "nsTransportUtils.h"
00038 #include "nsITransport.h"
00039 #include "nsIEventTarget.h"
00040 #include "nsProxyRelease.h"
00041 #include "nsAutoLock.h"
00042 #include "nsCOMPtr.h"
00043 #include "plevent.h"
00044 
00045 //-----------------------------------------------------------------------------
00046 
00047 class nsTransportStatusEvent;
00048 
00049 class nsTransportEventSinkProxy : public nsITransportEventSink
00050 {
00051 public:
00052     NS_DECL_ISUPPORTS
00053     NS_DECL_NSITRANSPORTEVENTSINK
00054 
00055     nsTransportEventSinkProxy(nsITransportEventSink *sink,
00056                               nsIEventTarget *target,
00057                               PRBool coalesceAll)
00058         : mSink(sink)
00059         , mTarget(target)
00060         , mLock(PR_NewLock())
00061         , mLastEvent(nsnull)
00062         , mCoalesceAll(coalesceAll)
00063     {
00064         NS_ADDREF(mSink);
00065     }
00066 
00067     virtual ~nsTransportEventSinkProxy()
00068     {
00069         if (mLock)
00070             PR_DestroyLock(mLock);
00071     
00072         // our reference to mSink could be the last, so be sure to release
00073         // it on the target thread.  otherwise, we could get into trouble.
00074         NS_ProxyRelease(mTarget, mSink);
00075     }
00076 
00077     nsITransportEventSink           *mSink;
00078     nsCOMPtr<nsIEventTarget>         mTarget;
00079     PRLock                          *mLock;
00080     nsTransportStatusEvent          *mLastEvent;
00081     PRBool                           mCoalesceAll;
00082 };
00083 
00084 class nsTransportStatusEvent : public PLEvent
00085 {
00086 public:
00087     nsTransportStatusEvent(nsTransportEventSinkProxy *proxy,
00088                            nsITransport *transport,
00089                            nsresult status,
00090                            PRUint64 progress,
00091                            PRUint64 progressMax)
00092         : mTransport(transport)
00093         , mStatus(status)
00094         , mProgress(progress)
00095         , mProgressMax(progressMax)
00096     {
00097         NS_ADDREF(proxy); 
00098         PL_InitEvent(this, proxy, HandleEvent, DestroyEvent);
00099     }
00100 
00101    ~nsTransportStatusEvent()
00102     {
00103         nsTransportEventSinkProxy *proxy =
00104                 (nsTransportEventSinkProxy *) owner;
00105         NS_RELEASE(proxy);
00106     }
00107 
00108     PR_STATIC_CALLBACK(void*) HandleEvent(PLEvent *event)
00109     {
00110         nsTransportStatusEvent *self = (nsTransportStatusEvent *) event;
00111         nsTransportEventSinkProxy *proxy = (nsTransportEventSinkProxy *) event->owner;
00112 
00113         // since this event is being handled, we need to clear the proxy's ref.
00114         // if not coalescing all, then last event may not equal self!
00115         {
00116             nsAutoLock lock(proxy->mLock);
00117             if (proxy->mLastEvent == self)
00118                 proxy->mLastEvent = nsnull;
00119         }
00120 
00121         proxy->mSink->OnTransportStatus(self->mTransport,
00122                                         self->mStatus,
00123                                         self->mProgress,
00124                                         self->mProgressMax);
00125         return nsnull;
00126     }
00127 
00128     PR_STATIC_CALLBACK(void) DestroyEvent(PLEvent *event)
00129     {
00130         delete (nsTransportStatusEvent *) event;
00131     }
00132 
00133     // parameters to OnTransportStatus
00134     nsCOMPtr<nsITransport> mTransport;
00135     nsresult               mStatus;
00136     PRUint64               mProgress;
00137     PRUint64               mProgressMax;
00138 };
00139 
00140 NS_IMPL_THREADSAFE_ISUPPORTS1(nsTransportEventSinkProxy, nsITransportEventSink)
00141 
00142 NS_IMETHODIMP
00143 nsTransportEventSinkProxy::OnTransportStatus(nsITransport *transport,
00144                                              nsresult status,
00145                                              PRUint64 progress,
00146                                              PRUint64 progressMax)
00147 {
00148     nsresult rv = NS_OK;
00149     PLEvent *event;
00150     {
00151         nsAutoLock lock(mLock);
00152 
00153         // try to coalesce events! ;-)
00154         if (mLastEvent && (mCoalesceAll || mLastEvent->mStatus == status)) {
00155             mLastEvent->mStatus = status;
00156             mLastEvent->mProgress = progress;
00157             mLastEvent->mProgressMax = progressMax;
00158             event = nsnull;
00159         }
00160         else {
00161             event = new nsTransportStatusEvent(this, transport, status,
00162                                                progress, progressMax);
00163             if (!event)
00164                 rv = NS_ERROR_OUT_OF_MEMORY;
00165             mLastEvent = (nsTransportStatusEvent *) event;
00166         }
00167     }
00168     if (event) {
00169         rv = mTarget->PostEvent(event);
00170         if (NS_FAILED(rv)) {
00171             NS_WARNING("unable to post transport status event");
00172             PL_DestroyEvent(event);
00173 
00174             nsAutoLock lock(mLock); // cleanup.. don't reference anymore!
00175             mLastEvent = nsnull;
00176         }
00177     }
00178     return rv;
00179 }
00180 
00181 //-----------------------------------------------------------------------------
00182 
00183 nsresult
00184 net_NewTransportEventSinkProxy(nsITransportEventSink **result,
00185                                nsITransportEventSink *sink,
00186                                nsIEventTarget *target,
00187                                PRBool coalesceAll)
00188 {
00189     *result = new nsTransportEventSinkProxy(sink, target, coalesceAll);
00190     if (!*result)
00191         return NS_ERROR_OUT_OF_MEMORY;
00192     NS_ADDREF(*result);
00193     return NS_OK;
00194 }