1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/ftp/nsFtpControlConnection.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,188 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsIOService.h" 1.10 +#include "nsFtpControlConnection.h" 1.11 +#include "nsFtpProtocolHandler.h" 1.12 +#include "prlog.h" 1.13 +#include "nsIInputStream.h" 1.14 +#include "nsISocketTransportService.h" 1.15 +#include "nsISocketTransport.h" 1.16 +#include "nsThreadUtils.h" 1.17 +#include "nsIOutputStream.h" 1.18 +#include "nsNetCID.h" 1.19 +#include <algorithm> 1.20 + 1.21 +#if defined(PR_LOGGING) 1.22 +extern PRLogModuleInfo* gFTPLog; 1.23 +#endif 1.24 +#define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args) 1.25 +#define LOG_ALWAYS(args) PR_LOG(gFTPLog, PR_LOG_ALWAYS, args) 1.26 + 1.27 +// 1.28 +// nsFtpControlConnection implementation ... 1.29 +// 1.30 + 1.31 +NS_IMPL_ISUPPORTS(nsFtpControlConnection, nsIInputStreamCallback) 1.32 + 1.33 +NS_IMETHODIMP 1.34 +nsFtpControlConnection::OnInputStreamReady(nsIAsyncInputStream *stream) 1.35 +{ 1.36 + char data[4096]; 1.37 + 1.38 + // Consume data whether we have a listener or not. 1.39 + uint64_t avail64; 1.40 + uint32_t avail = 0; 1.41 + nsresult rv = stream->Available(&avail64); 1.42 + if (NS_SUCCEEDED(rv)) { 1.43 + avail = (uint32_t)std::min(avail64, (uint64_t)sizeof(data)); 1.44 + 1.45 + uint32_t n; 1.46 + rv = stream->Read(data, avail, &n); 1.47 + if (NS_SUCCEEDED(rv)) 1.48 + avail = n; 1.49 + } 1.50 + 1.51 + // It's important that we null out mListener before calling one of its 1.52 + // methods as it may call WaitData, which would queue up another read. 1.53 + 1.54 + nsRefPtr<nsFtpControlConnectionListener> listener; 1.55 + listener.swap(mListener); 1.56 + 1.57 + if (!listener) 1.58 + return NS_OK; 1.59 + 1.60 + if (NS_FAILED(rv)) { 1.61 + listener->OnControlError(rv); 1.62 + } else { 1.63 + listener->OnControlDataAvailable(data, avail); 1.64 + } 1.65 + 1.66 + return NS_OK; 1.67 +} 1.68 + 1.69 +nsFtpControlConnection::nsFtpControlConnection(const nsCSubstring& host, 1.70 + uint32_t port) 1.71 + : mServerType(0), mSessionId(gFtpHandler->GetSessionId()) 1.72 + , mUseUTF8(false), mHost(host), mPort(port) 1.73 +{ 1.74 + LOG_ALWAYS(("FTP:CC created @%p", this)); 1.75 +} 1.76 + 1.77 +nsFtpControlConnection::~nsFtpControlConnection() 1.78 +{ 1.79 + LOG_ALWAYS(("FTP:CC destroyed @%p", this)); 1.80 +} 1.81 + 1.82 +bool 1.83 +nsFtpControlConnection::IsAlive() 1.84 +{ 1.85 + if (!mSocket) 1.86 + return false; 1.87 + 1.88 + bool isAlive = false; 1.89 + mSocket->IsAlive(&isAlive); 1.90 + return isAlive; 1.91 +} 1.92 +nsresult 1.93 +nsFtpControlConnection::Connect(nsIProxyInfo* proxyInfo, 1.94 + nsITransportEventSink* eventSink) 1.95 +{ 1.96 + if (mSocket) 1.97 + return NS_OK; 1.98 + 1.99 + // build our own 1.100 + nsresult rv; 1.101 + nsCOMPtr<nsISocketTransportService> sts = 1.102 + do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 1.103 + if (NS_FAILED(rv)) 1.104 + return rv; 1.105 + 1.106 + rv = sts->CreateTransport(nullptr, 0, mHost, mPort, proxyInfo, 1.107 + getter_AddRefs(mSocket)); // the command transport 1.108 + if (NS_FAILED(rv)) 1.109 + return rv; 1.110 + 1.111 + mSocket->SetQoSBits(gFtpHandler->GetControlQoSBits()); 1.112 + 1.113 + // proxy transport events back to current thread 1.114 + if (eventSink) 1.115 + mSocket->SetEventSink(eventSink, NS_GetCurrentThread()); 1.116 + 1.117 + // open buffered, blocking output stream to socket. so long as commands 1.118 + // do not exceed 1024 bytes in length, the writing thread (the main thread) 1.119 + // will not block. this should be OK. 1.120 + rv = mSocket->OpenOutputStream(nsITransport::OPEN_BLOCKING, 1024, 1, 1.121 + getter_AddRefs(mSocketOutput)); 1.122 + if (NS_FAILED(rv)) 1.123 + return rv; 1.124 + 1.125 + // open buffered, non-blocking/asynchronous input stream to socket. 1.126 + nsCOMPtr<nsIInputStream> inStream; 1.127 + rv = mSocket->OpenInputStream(0, 1.128 + nsIOService::gDefaultSegmentSize, 1.129 + nsIOService::gDefaultSegmentCount, 1.130 + getter_AddRefs(inStream)); 1.131 + if (NS_SUCCEEDED(rv)) 1.132 + mSocketInput = do_QueryInterface(inStream); 1.133 + 1.134 + return rv; 1.135 +} 1.136 + 1.137 +nsresult 1.138 +nsFtpControlConnection::WaitData(nsFtpControlConnectionListener *listener) 1.139 +{ 1.140 + LOG(("FTP:(%p) wait data [listener=%p]\n", this, listener)); 1.141 + 1.142 + // If listener is null, then simply disconnect the listener. Otherwise, 1.143 + // ensure that we are listening. 1.144 + if (!listener) { 1.145 + mListener = nullptr; 1.146 + return NS_OK; 1.147 + } 1.148 + 1.149 + NS_ENSURE_STATE(mSocketInput); 1.150 + 1.151 + mListener = listener; 1.152 + return mSocketInput->AsyncWait(this, 0, 0, NS_GetCurrentThread()); 1.153 +} 1.154 + 1.155 +nsresult 1.156 +nsFtpControlConnection::Disconnect(nsresult status) 1.157 +{ 1.158 + if (!mSocket) 1.159 + return NS_OK; // already disconnected 1.160 + 1.161 + LOG_ALWAYS(("FTP:(%p) CC disconnecting (%x)", this, status)); 1.162 + 1.163 + if (NS_FAILED(status)) { 1.164 + // break cyclic reference! 1.165 + mSocket->Close(status); 1.166 + mSocket = 0; 1.167 + mSocketInput->AsyncWait(nullptr, 0, 0, nullptr); // clear any observer 1.168 + mSocketInput = nullptr; 1.169 + mSocketOutput = nullptr; 1.170 + } 1.171 + 1.172 + return NS_OK; 1.173 +} 1.174 + 1.175 +nsresult 1.176 +nsFtpControlConnection::Write(const nsCSubstring& command) 1.177 +{ 1.178 + NS_ENSURE_STATE(mSocketOutput); 1.179 + 1.180 + uint32_t len = command.Length(); 1.181 + uint32_t cnt; 1.182 + nsresult rv = mSocketOutput->Write(command.Data(), len, &cnt); 1.183 + 1.184 + if (NS_FAILED(rv)) 1.185 + return rv; 1.186 + 1.187 + if (len != cnt) 1.188 + return NS_ERROR_FAILURE; 1.189 + 1.190 + return NS_OK; 1.191 +}