Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/ftp/nsFtpControlConnection.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "nsIOService.h"
7
#include "nsFtpControlConnection.h"
8
#include "nsFtpProtocolHandler.h"
9
#include "mozilla/Logging.h"
10
#include "nsIInputStream.h"
11
#include "nsISocketTransportService.h"
12
#include "nsISocketTransport.h"
13
#include "nsThreadUtils.h"
14
#include "nsIOutputStream.h"
15
#include "nsNetCID.h"
16
#include <algorithm>
17
18
using namespace mozilla;
19
using namespace mozilla::net;
20
21
extern LazyLogModule gFTPLog;
22
0
#define LOG(args)         MOZ_LOG(gFTPLog, mozilla::LogLevel::Debug, args)
23
0
#define LOG_INFO(args)  MOZ_LOG(gFTPLog, mozilla::LogLevel::Info, args)
24
25
//
26
// nsFtpControlConnection implementation ...
27
//
28
29
NS_IMPL_ISUPPORTS(nsFtpControlConnection, nsIInputStreamCallback)
30
31
NS_IMETHODIMP
32
nsFtpControlConnection::OnInputStreamReady(nsIAsyncInputStream *stream)
33
0
{
34
0
    char data[4096];
35
0
36
0
    // Consume data whether we have a listener or not.
37
0
    uint64_t avail64;
38
0
    uint32_t avail = 0;
39
0
    nsresult rv = stream->Available(&avail64);
40
0
    if (NS_SUCCEEDED(rv)) {
41
0
        avail = (uint32_t)std::min(avail64, (uint64_t)sizeof(data));
42
0
43
0
        uint32_t n;
44
0
        rv = stream->Read(data, avail, &n);
45
0
        if (NS_SUCCEEDED(rv))
46
0
            avail = n;
47
0
    }
48
0
49
0
    // It's important that we null out mListener before calling one of its
50
0
    // methods as it may call WaitData, which would queue up another read.
51
0
52
0
    RefPtr<nsFtpControlConnectionListener> listener;
53
0
    listener.swap(mListener);
54
0
55
0
    if (!listener)
56
0
        return NS_OK;
57
0
58
0
    if (NS_FAILED(rv)) {
59
0
        listener->OnControlError(rv);
60
0
    } else {
61
0
        listener->OnControlDataAvailable(data, avail);
62
0
    }
63
0
64
0
    return NS_OK;
65
0
}
66
67
nsFtpControlConnection::nsFtpControlConnection(const nsACString& host,
68
                                               uint32_t port)
69
    : mServerType(0)
70
    , mSuspendedWrite(0)
71
    , mSessionId(gFtpHandler->GetSessionId())
72
    , mUseUTF8(false)
73
    , mHost(host)
74
    , mPort(port)
75
0
{
76
0
    LOG_INFO(("FTP:CC created @%p", this));
77
0
}
78
79
nsFtpControlConnection::~nsFtpControlConnection()
80
0
{
81
0
    LOG_INFO(("FTP:CC destroyed @%p", this));
82
0
}
83
84
bool
85
nsFtpControlConnection::IsAlive()
86
0
{
87
0
    if (!mSocket)
88
0
        return false;
89
0
90
0
    bool isAlive = false;
91
0
    mSocket->IsAlive(&isAlive);
92
0
    return isAlive;
93
0
}
94
nsresult
95
nsFtpControlConnection::Connect(nsIProxyInfo* proxyInfo,
96
                                nsITransportEventSink* eventSink)
97
0
{
98
0
    if (mSocket)
99
0
        return NS_OK;
100
0
101
0
    // build our own
102
0
    nsresult rv;
103
0
    nsCOMPtr<nsISocketTransportService> sts =
104
0
            do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
105
0
    if (NS_FAILED(rv))
106
0
        return rv;
107
0
108
0
    rv = sts->CreateTransport(nullptr, 0, mHost, mPort, proxyInfo,
109
0
                              getter_AddRefs(mSocket)); // the command transport
110
0
    if (NS_FAILED(rv))
111
0
        return rv;
112
0
113
0
    mSocket->SetQoSBits(gFtpHandler->GetControlQoSBits());
114
0
115
0
    // proxy transport events back to current thread
116
0
    if (eventSink)
117
0
        mSocket->SetEventSink(eventSink, GetCurrentThreadEventTarget());
118
0
119
0
    // open buffered, blocking output stream to socket.  so long as commands
120
0
    // do not exceed 1024 bytes in length, the writing thread (the main thread)
121
0
    // will not block.  this should be OK.
122
0
    rv = mSocket->OpenOutputStream(nsITransport::OPEN_BLOCKING, 1024, 1,
123
0
                                   getter_AddRefs(mSocketOutput));
124
0
    if (NS_FAILED(rv))
125
0
        return rv;
126
0
127
0
    // open buffered, non-blocking/asynchronous input stream to socket.
128
0
    nsCOMPtr<nsIInputStream> inStream;
129
0
    rv = mSocket->OpenInputStream(0,
130
0
                                  nsIOService::gDefaultSegmentSize,
131
0
                                  nsIOService::gDefaultSegmentCount,
132
0
                                  getter_AddRefs(inStream));
133
0
    if (NS_SUCCEEDED(rv))
134
0
        mSocketInput = do_QueryInterface(inStream);
135
0
136
0
    return rv;
137
0
}
138
139
nsresult
140
nsFtpControlConnection::WaitData(nsFtpControlConnectionListener *listener)
141
0
{
142
0
    LOG(("FTP:(%p) wait data [listener=%p]\n", this, listener));
143
0
144
0
    // If listener is null, then simply disconnect the listener.  Otherwise,
145
0
    // ensure that we are listening.
146
0
    if (!listener) {
147
0
        mListener = nullptr;
148
0
        return NS_OK;
149
0
    }
150
0
151
0
    NS_ENSURE_STATE(mSocketInput);
152
0
153
0
    mListener = listener;
154
0
    return mSocketInput->AsyncWait(this, 0, 0, GetCurrentThreadEventTarget());
155
0
}
156
157
nsresult
158
nsFtpControlConnection::Disconnect(nsresult status)
159
0
{
160
0
    if (!mSocket)
161
0
        return NS_OK;  // already disconnected
162
0
163
0
    LOG_INFO(("FTP:(%p) CC disconnecting (%" PRIx32 ")", this,
164
0
              static_cast<uint32_t>(status)));
165
0
166
0
    if (NS_FAILED(status)) {
167
0
        // break cyclic reference!
168
0
        mSocket->Close(status);
169
0
        mSocket = nullptr;
170
0
        mSocketInput->AsyncWait(nullptr, 0, 0, nullptr);  // clear any observer
171
0
        mSocketInput = nullptr;
172
0
        mSocketOutput = nullptr;
173
0
    }
174
0
175
0
    return NS_OK;
176
0
}
177
178
nsresult
179
nsFtpControlConnection::Write(const nsACString& command)
180
0
{
181
0
    NS_ENSURE_STATE(mSocketOutput);
182
0
183
0
    uint32_t len = command.Length();
184
0
    uint32_t cnt;
185
0
    nsresult rv = mSocketOutput->Write(command.Data(), len, &cnt);
186
0
187
0
    if (NS_FAILED(rv))
188
0
        return rv;
189
0
190
0
    if (len != cnt)
191
0
        return NS_ERROR_FAILURE;
192
0
193
0
    return NS_OK;
194
0
}