123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsIOService.h"
- #include "nsFtpControlConnection.h"
- #include "nsFtpProtocolHandler.h"
- #include "mozilla/Logging.h"
- #include "nsIInputStream.h"
- #include "nsISocketTransportService.h"
- #include "nsISocketTransport.h"
- #include "nsThreadUtils.h"
- #include "nsIOutputStream.h"
- #include "nsNetCID.h"
- #include <algorithm>
- using namespace mozilla;
- using namespace mozilla::net;
- extern LazyLogModule gFTPLog;
- #define LOG(args) MOZ_LOG(gFTPLog, mozilla::LogLevel::Debug, args)
- #define LOG_INFO(args) MOZ_LOG(gFTPLog, mozilla::LogLevel::Info, args)
- //
- // nsFtpControlConnection implementation ...
- //
- NS_IMPL_ISUPPORTS(nsFtpControlConnection, nsIInputStreamCallback)
- NS_IMETHODIMP
- nsFtpControlConnection::OnInputStreamReady(nsIAsyncInputStream *stream)
- {
- char data[4096];
- // Consume data whether we have a listener or not.
- uint64_t avail64;
- uint32_t avail = 0;
- nsresult rv = stream->Available(&avail64);
- if (NS_SUCCEEDED(rv)) {
- avail = (uint32_t)std::min(avail64, (uint64_t)sizeof(data));
- uint32_t n;
- rv = stream->Read(data, avail, &n);
- if (NS_SUCCEEDED(rv))
- avail = n;
- }
- // It's important that we null out mListener before calling one of its
- // methods as it may call WaitData, which would queue up another read.
- RefPtr<nsFtpControlConnectionListener> listener;
- listener.swap(mListener);
- if (!listener)
- return NS_OK;
- if (NS_FAILED(rv)) {
- listener->OnControlError(rv);
- } else {
- listener->OnControlDataAvailable(data, avail);
- }
- return NS_OK;
- }
- nsFtpControlConnection::nsFtpControlConnection(const nsCSubstring& host,
- uint32_t port)
- : mServerType(0), mSessionId(gFtpHandler->GetSessionId())
- , mUseUTF8(false), mHost(host), mPort(port)
- {
- LOG_INFO(("FTP:CC created @%p", this));
- }
- nsFtpControlConnection::~nsFtpControlConnection()
- {
- LOG_INFO(("FTP:CC destroyed @%p", this));
- }
- bool
- nsFtpControlConnection::IsAlive()
- {
- if (!mSocket)
- return false;
- bool isAlive = false;
- mSocket->IsAlive(&isAlive);
- return isAlive;
- }
- nsresult
- nsFtpControlConnection::Connect(nsIProxyInfo* proxyInfo,
- nsITransportEventSink* eventSink)
- {
- if (mSocket)
- return NS_OK;
- // build our own
- nsresult rv;
- nsCOMPtr<nsISocketTransportService> sts =
- do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
- if (NS_FAILED(rv))
- return rv;
- rv = sts->CreateTransport(nullptr, 0, mHost, mPort, proxyInfo,
- getter_AddRefs(mSocket)); // the command transport
- if (NS_FAILED(rv))
- return rv;
- mSocket->SetQoSBits(gFtpHandler->GetControlQoSBits());
- // proxy transport events back to current thread
- if (eventSink)
- mSocket->SetEventSink(eventSink, NS_GetCurrentThread());
- // open buffered, blocking output stream to socket. so long as commands
- // do not exceed 1024 bytes in length, the writing thread (the main thread)
- // will not block. this should be OK.
- rv = mSocket->OpenOutputStream(nsITransport::OPEN_BLOCKING, 1024, 1,
- getter_AddRefs(mSocketOutput));
- if (NS_FAILED(rv))
- return rv;
- // open buffered, non-blocking/asynchronous input stream to socket.
- nsCOMPtr<nsIInputStream> inStream;
- rv = mSocket->OpenInputStream(0,
- nsIOService::gDefaultSegmentSize,
- nsIOService::gDefaultSegmentCount,
- getter_AddRefs(inStream));
- if (NS_SUCCEEDED(rv))
- mSocketInput = do_QueryInterface(inStream);
-
- return rv;
- }
- nsresult
- nsFtpControlConnection::WaitData(nsFtpControlConnectionListener *listener)
- {
- LOG(("FTP:(%p) wait data [listener=%p]\n", this, listener));
- // If listener is null, then simply disconnect the listener. Otherwise,
- // ensure that we are listening.
- if (!listener) {
- mListener = nullptr;
- return NS_OK;
- }
- NS_ENSURE_STATE(mSocketInput);
- mListener = listener;
- return mSocketInput->AsyncWait(this, 0, 0, NS_GetCurrentThread());
- }
- nsresult
- nsFtpControlConnection::Disconnect(nsresult status)
- {
- if (!mSocket)
- return NS_OK; // already disconnected
-
- LOG_INFO(("FTP:(%p) CC disconnecting (%x)", this, status));
- if (NS_FAILED(status)) {
- // break cyclic reference!
- mSocket->Close(status);
- mSocket = nullptr;
- mSocketInput->AsyncWait(nullptr, 0, 0, nullptr); // clear any observer
- mSocketInput = nullptr;
- mSocketOutput = nullptr;
- }
- return NS_OK;
- }
- nsresult
- nsFtpControlConnection::Write(const nsCSubstring& command)
- {
- NS_ENSURE_STATE(mSocketOutput);
- uint32_t len = command.Length();
- uint32_t cnt;
- nsresult rv = mSocketOutput->Write(command.Data(), len, &cnt);
- if (NS_FAILED(rv))
- return rv;
- if (len != cnt)
- return NS_ERROR_FAILURE;
-
- return NS_OK;
- }
|