Back to index

lightning-sunbird  0.9+nobinonly
nsFtpControlConnection.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
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 
00039 #include "nsFTPChannel.h"
00040 #include "nsFtpControlConnection.h"
00041 #include "prlog.h"
00042 #include "nsIPipe.h"
00043 #include "nsIInputStream.h"
00044 #include "nsISocketTransportService.h"
00045 #include "nsISocketTransport.h"
00046 #include "nsNetUtil.h"
00047 #include "nsEventQueueUtils.h"
00048 #include "nsCRT.h"
00049 
00050 
00051 #if defined(PR_LOGGING)
00052 extern PRLogModuleInfo* gFTPLog;
00053 #define LOG(args)         PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
00054 #define LOG_ALWAYS(args)  PR_LOG(gFTPLog, PR_LOG_ALWAYS, args)
00055 #else
00056 #define LOG(args)
00057 #define LOG_ALWAYS(args)
00058 #endif
00059 
00060 
00061 static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
00062 
00063 //
00064 // nsFtpControlConnection implementation ...
00065 //
00066 
00067 NS_IMPL_THREADSAFE_ISUPPORTS2(nsFtpControlConnection, 
00068                               nsIStreamListener, 
00069                               nsIRequestObserver)
00070 
00071 nsFtpControlConnection::nsFtpControlConnection(const char* host, PRUint32 port)
00072     : mServerType(0), mPort(port)
00073 {
00074     LOG_ALWAYS(("(%x) nsFtpControlConnection created", this));
00075 
00076     mHost.Assign(host);
00077 }
00078 
00079 nsFtpControlConnection::~nsFtpControlConnection() 
00080 {
00081     LOG_ALWAYS(("(%x) nsFtpControlConnection destroyed", this));
00082 }
00083 
00084 PRBool
00085 nsFtpControlConnection::IsAlive()
00086 {
00087     if (!mCPipe) 
00088         return PR_FALSE;
00089 
00090     PRBool isAlive = PR_FALSE;
00091     mCPipe->IsAlive(&isAlive);
00092     return isAlive;
00093 }
00094 nsresult 
00095 nsFtpControlConnection::Connect(nsIProxyInfo* proxyInfo,
00096                                 nsITransportEventSink* eventSink)
00097 {
00098     nsresult rv;
00099 
00100     if (!mCPipe) {
00101         // build our own
00102         nsCOMPtr<nsISocketTransportService> sts =
00103                 do_GetService(kSocketTransportServiceCID, &rv);
00104 
00105         rv = sts->CreateTransport(nsnull, 0, mHost, mPort, proxyInfo,
00106                                   getter_AddRefs(mCPipe)); // the command transport
00107         if (NS_FAILED(rv)) return rv;
00108 
00109         // proxy transport events back to current thread
00110         if (eventSink) {
00111             nsCOMPtr<nsIEventQueue> eventQ;
00112             rv = NS_GetCurrentEventQ(getter_AddRefs(eventQ));
00113             if (NS_SUCCEEDED(rv))
00114                 mCPipe->SetEventSink(eventSink, eventQ);
00115         }
00116 
00117         // open buffered, blocking output stream to socket.  so long as commands
00118         // do not exceed 1024 bytes in length, the writing thread (the main thread)
00119         // will not block.  this should be OK.
00120         rv = mCPipe->OpenOutputStream(nsITransport::OPEN_BLOCKING, 1024, 1,
00121                                       getter_AddRefs(mOutStream));
00122         if (NS_FAILED(rv)) return rv;
00123 
00124         // open buffered, non-blocking/asynchronous input stream to socket.
00125         nsCOMPtr<nsIInputStream> inStream;
00126         rv = mCPipe->OpenInputStream(0,
00127                                      FTP_COMMAND_CHANNEL_SEG_SIZE, 
00128                                      FTP_COMMAND_CHANNEL_SEG_COUNT,
00129                                      getter_AddRefs(inStream));
00130         if (NS_FAILED(rv)) return rv;
00131 
00132         nsCOMPtr<nsIInputStreamPump> pump;
00133         rv = NS_NewInputStreamPump(getter_AddRefs(pump), inStream);
00134         if (NS_FAILED(rv)) return rv;
00135 
00136         // get the ball rolling by reading on the control socket.
00137         rv = pump->AsyncRead(NS_STATIC_CAST(nsIStreamListener*, this), nsnull);
00138         if (NS_FAILED(rv)) return rv;
00139 
00140         // cyclic reference!
00141         mReadRequest = pump;
00142     }
00143     return NS_OK;
00144 }
00145 
00146 nsresult 
00147 nsFtpControlConnection::Disconnect(nsresult status)
00148 {
00149     if (!mCPipe) return NS_ERROR_FAILURE;
00150     
00151     LOG_ALWAYS(("(%x) nsFtpControlConnection disconnecting (%x)", this, status));
00152 
00153     if (NS_FAILED(status)) {
00154         // break cyclic reference!
00155         mOutStream = 0;
00156         mReadRequest->Cancel(status);
00157         mReadRequest = 0;
00158         mCPipe->Close(status);
00159         mCPipe = 0;
00160     }
00161 
00162     return NS_OK;
00163 }
00164 
00165 nsresult 
00166 nsFtpControlConnection::Write(nsCString& command, PRBool suspend)
00167 {
00168     if (!mCPipe)
00169         return NS_ERROR_FAILURE;
00170 
00171     PRUint32 len = command.Length();
00172     PRUint32 cnt;
00173     nsresult rv = mOutStream->Write(command.get(), len, &cnt);
00174 
00175     if (NS_FAILED(rv))
00176         return rv;
00177 
00178     if (len != cnt)
00179         return NS_ERROR_FAILURE;
00180     
00181     if (suspend)
00182         return NS_OK;
00183 
00184     return NS_OK;
00185 }
00186 
00187 NS_IMETHODIMP
00188 nsFtpControlConnection::OnStartRequest(nsIRequest *request, nsISupports *aContext)
00189 {
00190     if (!mCPipe)
00191         return NS_OK;
00192 
00193     if (!mListener)
00194         return NS_OK;
00195     
00196     // In case our listener tries to remove itself via SetStreamListener(nsnull),
00197     // we need to keep an extra reference to it on the stack.
00198     nsCOMPtr<nsIStreamListener> deathGrip = mListener;
00199     return mListener->OnStartRequest(request, aContext);
00200 }
00201 
00202 NS_IMETHODIMP
00203 nsFtpControlConnection::OnStopRequest(nsIRequest *request, nsISupports *aContext,
00204                                       nsresult aStatus)
00205 {
00206     if (!mCPipe) 
00207         return NS_OK;
00208 
00209     if (!mListener)
00210         return NS_OK;
00211 
00212     // In case our listener tries to remove itself via SetStreamListener(nsnull),
00213     // we need to keep an extra reference to it on the stack.
00214     nsCOMPtr<nsIStreamListener> deathGrip = mListener;
00215     return mListener->OnStopRequest(request, aContext, aStatus);
00216 }
00217 
00218 NS_IMETHODIMP
00219 nsFtpControlConnection::OnDataAvailable(nsIRequest *request,
00220                                         nsISupports *aContext,
00221                                         nsIInputStream *aInStream,
00222                                         PRUint32 aOffset, 
00223                                         PRUint32 aCount)
00224 {
00225     if (!mCPipe) 
00226         return NS_OK;
00227     
00228     if (!mListener)
00229         return NS_OK;
00230 
00231     // In case our listener tries to remove itself via SetStreamListener(nsnull),
00232     // we need to keep an extra reference to it on the stack.
00233     nsCOMPtr<nsIStreamListener> deathGrip = mListener;
00234     return mListener->OnDataAvailable(request, aContext, aInStream,
00235                                       aOffset,  aCount);
00236 }