DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (c68fe15a81fc)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "nsIOService.h"
#include "nsFtpControlConnection.h"
#include "nsFtpProtocolHandler.h"
#include "mozilla/Logging.h"
#include "nsIInputStream.h"
#include "nsIInputStream.h"
#include "nsISocketTransportService.h"
#include "nsISocketTransport.h"
#include "nsThreadUtils.h"
#include "nsNetCID.h"
#include "nsTArray.h"
#include "nsTArray.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 ...
// nsFtpControlConnection implementation ...
//

NS_IMPL_ISUPPORTS(nsFtpControlConnection, nsIInputStreamCallback)

NS_IMETHODIMP
NS_IMETHODIMP
nsFtpControlConnection::OnInputStreamReady(nsIAsyncInputStream* stream) {
  char data[4096];

  // Consume data whether we have a listener or not.
  uint64_t avail64;
  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);
  listener.swap(mListener);

  if (!listener) return NS_OK;

  if (NS_FAILED(rv)) {
    listener->OnControlError(rv);
  } else {
  } else {
    listener->OnControlDataAvailable(data, avail);
  }


  return NS_OK;
  return NS_OK;
}

nsFtpControlConnection::nsFtpControlConnection(const nsACString& host,
nsFtpControlConnection::nsFtpControlConnection(const nsACString& host,
                                               uint32_t port)
    : mServerType(0),
      mSuspendedWrite(0),
      mSessionId(gFtpHandler->GetSessionId()),
      mUseUTF8(false),
      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() {
bool nsFtpControlConnection::IsAlive() {
  if (!mSocket) return false;

  bool isAlive = false;
  mSocket->IsAlive(&isAlive);
  return isAlive;
  return isAlive;
}
nsresult nsFtpControlConnection::Connect(nsIProxyInfo* proxyInfo,
                                         nsITransportEventSink* eventSink) {
  if (mSocket) return NS_OK;

  // build our own
  nsresult rv;
  nsresult rv;
  nsCOMPtr<nsISocketTransportService> sts =
      do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
  if (NS_FAILED(rv)) return rv;

  rv = sts->CreateTransport(nsTArray<nsCString>(), mHost, mPort, proxyInfo,
  rv = sts->CreateTransport(nsTArray<nsCString>(), 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, GetCurrentThreadEventTarget());

  // open buffered, blocking output stream to socket.  so long as commands
  // 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.
  // 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);
  if (NS_SUCCEEDED(rv)) mSocketInput = do_QueryInterface(inStream);

  return rv;
}

nsresult nsFtpControlConnection::WaitData(
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, GetCurrentThreadEventTarget());
  return mSocketInput->AsyncWait(this, 0, 0, GetCurrentThreadEventTarget());
}

nsresult nsFtpControlConnection::Disconnect(nsresult status) {
  if (!mSocket) return NS_OK;  // already disconnected


  LOG_INFO(("FTP:(%p) CC disconnecting (%" PRIx32 ")", this,
            static_cast<uint32_t>(status)));

  if (NS_FAILED(status)) {
    // break cyclic reference!
    mSocket->Close(status);
    mSocket->Close(status);
    mSocket = nullptr;
    mSocketInput->AsyncWait(nullptr, 0, 0, nullptr);  // clear any observer
    mSocketInput = nullptr;
    mSocketOutput = nullptr;
    mSocketOutput = nullptr;
  }

  return NS_OK;
}


nsresult nsFtpControlConnection::Write(const nsACString& command) {
  NS_ENSURE_STATE(mSocketOutput);

  uint32_t len = command.Length();
  uint32_t cnt;
  uint32_t cnt;
  nsresult rv = mSocketOutput->Write(command.Data(), len, &cnt);

  if (NS_FAILED(rv)) return rv;

  if (len != cnt) return NS_ERROR_FAILURE;
  if (len != cnt) return NS_ERROR_FAILURE;

  return NS_OK;
}