1/*
2 * Copyright (C) 2010 Nokia Inc. All rights reserved.
3 * Copyright (C) 2009 Google Inc.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "config.h"
33#include "SocketStreamHandle.h"
34
35#include "KURL.h"
36#include "Logging.h"
37#include "NotImplemented.h"
38#include "SocketStreamError.h"
39#include "SocketStreamHandleClient.h"
40#include "SocketStreamHandlePrivate.h"
41
42namespace WebCore {
43
44SocketStreamHandlePrivate::SocketStreamHandlePrivate(SocketStreamHandle* streamHandle, const KURL& url)
45{
46    m_streamHandle = streamHandle;
47    m_socket = 0;
48    bool isSecure = url.protocolIs("wss");
49
50    if (isSecure) {
51#ifndef QT_NO_OPENSSL
52        m_socket = new QSslSocket(this);
53#endif
54    } else
55        m_socket = new QTcpSocket(this);
56
57    if (!m_socket)
58        return;
59
60    initConnections();
61
62    unsigned int port = url.hasPort() ? url.port() : (isSecure ? 443 : 80);
63
64    QString host = url.host();
65    if (isSecure) {
66#ifndef QT_NO_OPENSSL
67        static_cast<QSslSocket*>(m_socket)->connectToHostEncrypted(host, port);
68#endif
69    } else
70        m_socket->connectToHost(host, port);
71}
72
73SocketStreamHandlePrivate::SocketStreamHandlePrivate(SocketStreamHandle* streamHandle, QTcpSocket* socket)
74{
75    m_streamHandle = streamHandle;
76    m_socket = socket;
77    initConnections();
78}
79
80SocketStreamHandlePrivate::~SocketStreamHandlePrivate()
81{
82    Q_ASSERT(!(m_socket && m_socket->state() == QAbstractSocket::ConnectedState));
83}
84
85void SocketStreamHandlePrivate::initConnections()
86{
87    connect(m_socket, SIGNAL(connected()), this, SLOT(socketConnected()));
88    connect(m_socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()));
89    connect(m_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
90    connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
91#ifndef QT_NO_OPENSSL
92    if (qobject_cast<QSslSocket*>(m_socket))
93        connect(m_socket, SIGNAL(sslErrors(const QList<QSslError>&)), this, SLOT(socketSslErrors(const QList<QSslError>&)));
94#endif
95
96    // Check for missed signals and call the slots asynchronously to allow a client to be set first.
97    if (m_socket->state() >= QAbstractSocket::ConnectedState)
98        QMetaObject::invokeMethod(this, "socketConnected", Qt::QueuedConnection);
99    if (m_socket->bytesAvailable())
100        QMetaObject::invokeMethod(this, "socketReadyRead", Qt::QueuedConnection);
101}
102
103void SocketStreamHandlePrivate::socketConnected()
104{
105    if (m_streamHandle && m_streamHandle->client()) {
106        m_streamHandle->m_state = SocketStreamHandleBase::Open;
107        m_streamHandle->client()->didOpenSocketStream(m_streamHandle);
108    }
109}
110
111void SocketStreamHandlePrivate::socketReadyRead()
112{
113    if (m_streamHandle && m_streamHandle->client()) {
114        QByteArray data = m_socket->read(m_socket->bytesAvailable());
115        m_streamHandle->client()->didReceiveSocketStreamData(m_streamHandle, data.constData(), data.size());
116    }
117}
118
119int SocketStreamHandlePrivate::send(const char* data, int len)
120{
121    if (!m_socket || m_socket->state() != QAbstractSocket::ConnectedState)
122        return 0;
123    quint64 sentSize = m_socket->write(data, len);
124    QMetaObject::invokeMethod(this, "socketSentData", Qt::QueuedConnection);
125    return sentSize;
126}
127
128void SocketStreamHandlePrivate::close()
129{
130    if (m_streamHandle && m_streamHandle->m_state == SocketStreamHandleBase::Connecting) {
131        m_socket->abort();
132        m_streamHandle->client()->didCloseSocketStream(m_streamHandle);
133        return;
134    }
135    if (m_socket && m_socket->state() == QAbstractSocket::ConnectedState)
136        m_socket->close();
137}
138
139void SocketStreamHandlePrivate::socketSentData()
140{
141    if (m_streamHandle)
142        m_streamHandle->sendPendingData();
143}
144
145void SocketStreamHandlePrivate::socketClosed()
146{
147    QMetaObject::invokeMethod(this, "socketClosedCallback", Qt::QueuedConnection);
148}
149
150void SocketStreamHandlePrivate::socketError(QAbstractSocket::SocketError error)
151{
152    QMetaObject::invokeMethod(this, "socketErrorCallback", Qt::QueuedConnection, Q_ARG(int, error));
153}
154
155void SocketStreamHandlePrivate::socketClosedCallback()
156{
157    if (m_streamHandle && m_streamHandle->client()) {
158        SocketStreamHandle* streamHandle = m_streamHandle;
159        m_streamHandle = 0;
160        // This following call deletes _this_. Nothing should be after it.
161        streamHandle->client()->didCloseSocketStream(streamHandle);
162    }
163}
164
165void SocketStreamHandlePrivate::socketErrorCallback(int error)
166{
167    // FIXME - in the future, we might not want to treat all errors as fatal.
168    if (m_streamHandle && m_streamHandle->client()) {
169        SocketStreamHandle* streamHandle = m_streamHandle;
170        m_streamHandle = 0;
171
172        streamHandle->client()->didFailSocketStream(streamHandle, SocketStreamError(error, m_socket->errorString()));
173
174        // This following call deletes _this_. Nothing should be after it.
175        streamHandle->client()->didCloseSocketStream(streamHandle);
176    }
177}
178
179#ifndef QT_NO_OPENSSL
180void SocketStreamHandlePrivate::socketSslErrors(const QList<QSslError>& error)
181{
182    QMetaObject::invokeMethod(this, "socketErrorCallback", Qt::QueuedConnection, Q_ARG(int, error[0].error()));
183}
184#endif
185
186SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client)
187    : SocketStreamHandleBase(url, client)
188{
189    LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
190    m_p = new SocketStreamHandlePrivate(this, url);
191}
192
193SocketStreamHandle::SocketStreamHandle(QTcpSocket* socket, SocketStreamHandleClient* client)
194    : SocketStreamHandleBase(KURL(), client)
195{
196    LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
197    m_p = new SocketStreamHandlePrivate(this, socket);
198    if (socket->isOpen())
199        m_state = Open;
200}
201
202SocketStreamHandle::~SocketStreamHandle()
203{
204    LOG(Network, "SocketStreamHandle %p delete", this);
205    setClient(0);
206    delete m_p;
207}
208
209int SocketStreamHandle::platformSend(const char* data, int len)
210{
211    LOG(Network, "SocketStreamHandle %p platformSend", this);
212    return m_p->send(data, len);
213}
214
215void SocketStreamHandle::platformClose()
216{
217    LOG(Network, "SocketStreamHandle %p platformClose", this);
218    m_p->close();
219}
220
221void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&)
222{
223    notImplemented();
224}
225
226void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&)
227{
228    notImplemented();
229}
230
231void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
232{
233    notImplemented();
234}
235
236void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
237{
238    notImplemented();
239}
240
241} // namespace WebCore
242
243#include "moc_SocketStreamHandlePrivate.cpp"
244