1/*
2 * Copyright (C) 2009, 2011 Google Inc.  All rights reserved.
3 * Copyright (C) 2012 Samsung Electronics Ltd. 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#if USE(SOUP)
36
37#include "URL.h"
38#include "Logging.h"
39#include "NotImplemented.h"
40#include "SocketStreamError.h"
41#include "SocketStreamHandleClient.h"
42
43#include <gio/gio.h>
44#include <glib.h>
45
46#include <wtf/Vector.h>
47#include <wtf/gobject/GUniquePtr.h>
48#include <wtf/text/CString.h>
49
50#define READ_BUFFER_SIZE 1024
51
52namespace WebCore {
53
54// These functions immediately call the similarly named SocketStreamHandle methods.
55static void connectedCallback(GSocketClient*, GAsyncResult*, void*);
56static void readReadyCallback(GInputStream*, GAsyncResult*, void*);
57static gboolean writeReadyCallback(GPollableOutputStream*, void*);
58
59// Having a list of active handles means that we do not have to worry about WebCore
60// reference counting in GLib callbacks. Once the handle is off the active handles list
61// we just ignore it in the callback. We avoid a lot of extra checks and tricky
62// situations this way.
63static HashMap<void*, SocketStreamHandle*> gActiveHandles;
64COMPILE_ASSERT(HashTraits<SocketStreamHandle*>::emptyValueIsZero, emptyMapValue_is_0);
65
66static SocketStreamHandle* getHandleFromId(void* id)
67{
68    return gActiveHandles.get(id);
69}
70
71static void deactivateHandle(SocketStreamHandle* handle)
72{
73    gActiveHandles.remove(handle->id());
74}
75
76static void* activateHandle(SocketStreamHandle* handle)
77{
78    // The first id cannot be 0, because it conflicts with the HashMap emptyValue.
79    static gint currentHandleId = 1;
80    void* id = GINT_TO_POINTER(currentHandleId++);
81    gActiveHandles.set(id, handle);
82    return id;
83}
84
85SocketStreamHandle::SocketStreamHandle(const URL& url, SocketStreamHandleClient* client)
86    : SocketStreamHandleBase(url, client)
87{
88    LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
89    unsigned int port = url.hasPort() ? url.port() : (url.protocolIs("wss") ? 443 : 80);
90
91    m_id = activateHandle(this);
92    GRefPtr<GSocketClient> socketClient = adoptGRef(g_socket_client_new());
93    if (url.protocolIs("wss"))
94        g_socket_client_set_tls(socketClient.get(), TRUE);
95    g_socket_client_connect_to_host_async(socketClient.get(), url.host().utf8().data(), port, 0,
96        reinterpret_cast<GAsyncReadyCallback>(connectedCallback), m_id);
97}
98
99SocketStreamHandle::SocketStreamHandle(GSocketConnection* socketConnection, SocketStreamHandleClient* client)
100    : SocketStreamHandleBase(URL(), client)
101{
102    LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
103    m_id = activateHandle(this);
104    connected(socketConnection, 0);
105}
106
107SocketStreamHandle::~SocketStreamHandle()
108{
109    LOG(Network, "SocketStreamHandle %p delete", this);
110    // If for some reason we were destroyed without closing, ensure that we are deactivated.
111    deactivateHandle(this);
112    setClient(0);
113}
114
115void SocketStreamHandle::connected(GSocketConnection* socketConnection, GError* error)
116{
117    if (error) {
118        m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
119        return;
120    }
121
122    m_socketConnection = socketConnection;
123    m_outputStream = G_POLLABLE_OUTPUT_STREAM(g_io_stream_get_output_stream(G_IO_STREAM(m_socketConnection.get())));
124    m_inputStream = g_io_stream_get_input_stream(G_IO_STREAM(m_socketConnection.get()));
125
126    m_readBuffer = std::make_unique<char[]>(READ_BUFFER_SIZE);
127    g_input_stream_read_async(m_inputStream.get(), m_readBuffer.get(), READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
128        reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), m_id);
129
130    m_state = Open;
131    m_client->didOpenSocketStream(this);
132}
133
134void SocketStreamHandle::readBytes(signed long bytesRead, GError* error)
135{
136    if (error) {
137        m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
138        return;
139    }
140
141    if (!bytesRead) {
142        close();
143        return;
144    }
145
146    // The client can close the handle, potentially removing the last reference.
147    RefPtr<SocketStreamHandle> protect(this);
148    m_client->didReceiveSocketStreamData(this, m_readBuffer.get(), bytesRead);
149    if (m_inputStream) // The client may have closed the connection.
150        g_input_stream_read_async(m_inputStream.get(), m_readBuffer.get(), READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
151            reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), m_id);
152}
153
154void SocketStreamHandle::writeReady()
155{
156    // We no longer have buffered data, so stop waiting for the socket to be writable.
157    if (!bufferedAmount()) {
158        stopWaitingForSocketWritability();
159        return;
160    }
161
162    sendPendingData();
163}
164
165int SocketStreamHandle::platformSend(const char* data, int length)
166{
167    LOG(Network, "SocketStreamHandle %p platformSend", this);
168    if (!m_outputStream || !data)
169        return 0;
170
171    GUniqueOutPtr<GError> error;
172    gssize written = g_pollable_output_stream_write_nonblocking(m_outputStream.get(), data, length, 0, &error.outPtr());
173    if (error) {
174        if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
175            beginWaitingForSocketWritability();
176        else
177            m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
178        return 0;
179    }
180
181    // If we did not send all the bytes we were given, we know that
182    // SocketStreamHandleBase will need to send more in the future.
183    if (written < length)
184        beginWaitingForSocketWritability();
185
186    return written;
187}
188
189void SocketStreamHandle::platformClose()
190{
191    LOG(Network, "SocketStreamHandle %p platformClose", this);
192    // We remove this handle from the active handles list first, to disable all callbacks.
193    deactivateHandle(this);
194    stopWaitingForSocketWritability();
195
196    if (m_socketConnection) {
197        GUniqueOutPtr<GError> error;
198        g_io_stream_close(G_IO_STREAM(m_socketConnection.get()), 0, &error.outPtr());
199        if (error)
200            m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
201        m_socketConnection = 0;
202    }
203
204    m_outputStream = 0;
205    m_inputStream = 0;
206    m_readBuffer = nullptr;
207
208    m_client->didCloseSocketStream(this);
209}
210
211void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&)
212{
213    notImplemented();
214}
215
216void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&)
217{
218    notImplemented();
219}
220
221void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
222{
223    notImplemented();
224}
225
226void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
227{
228    notImplemented();
229}
230
231void SocketStreamHandle::receivedRequestToPerformDefaultHandling(const AuthenticationChallenge&)
232{
233    notImplemented();
234}
235
236void SocketStreamHandle::receivedChallengeRejection(const AuthenticationChallenge&)
237{
238    notImplemented();
239}
240
241void SocketStreamHandle::beginWaitingForSocketWritability()
242{
243    if (m_writeReadySource) // Already waiting.
244        return;
245
246    m_writeReadySource = adoptGRef(g_pollable_output_stream_create_source(m_outputStream.get(), 0));
247    g_source_set_callback(m_writeReadySource.get(), reinterpret_cast<GSourceFunc>(writeReadyCallback), m_id, 0);
248    g_source_attach(m_writeReadySource.get(), 0);
249}
250
251void SocketStreamHandle::stopWaitingForSocketWritability()
252{
253    if (!m_writeReadySource) // Not waiting.
254        return;
255
256    g_source_remove(g_source_get_id(m_writeReadySource.get()));
257    m_writeReadySource = 0;
258}
259
260static void connectedCallback(GSocketClient* client, GAsyncResult* result, void* id)
261{
262    // Always finish the connection, even if this SocketStreamHandle was deactivated earlier.
263    GUniqueOutPtr<GError> error;
264    GSocketConnection* socketConnection = g_socket_client_connect_to_host_finish(client, result, &error.outPtr());
265
266    // The SocketStreamHandle has been deactivated, so just close the connection, ignoring errors.
267    SocketStreamHandle* handle = getHandleFromId(id);
268    if (!handle) {
269        if (socketConnection)
270            g_io_stream_close(G_IO_STREAM(socketConnection), 0, 0);
271        return;
272    }
273
274    handle->connected(socketConnection, error.get());
275}
276
277static void readReadyCallback(GInputStream* stream, GAsyncResult* result, void* id)
278{
279    // Always finish the read, even if this SocketStreamHandle was deactivated earlier.
280    GUniqueOutPtr<GError> error;
281    gssize bytesRead = g_input_stream_read_finish(stream, result, &error.outPtr());
282
283    SocketStreamHandle* handle = getHandleFromId(id);
284    if (!handle)
285        return;
286
287    handle->readBytes(bytesRead, error.get());
288}
289
290static gboolean writeReadyCallback(GPollableOutputStream*, void* id)
291{
292    SocketStreamHandle* handle = getHandleFromId(id);
293    if (!handle)
294        return FALSE;
295
296    handle->writeReady();
297    return TRUE;
298}
299
300} // namespace WebCore
301
302#endif
303