netwerk/protocol/ftp/nsFtpControlConnection.cpp

changeset 0
6474c204b198
     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 +}

mercurial