2
* Copyright (C) 2009, 2011 Google Inc. All rights reserved.
3
* Copyright (C) 2012 Samsung Electronics Ltd. All Rights Reserved.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are
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
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.
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.
33
#include "SocketStreamHandle.h"
37
#include "NotImplemented.h"
38
#include "SocketStreamError.h"
39
#include "SocketStreamHandleClient.h"
44
#include <wtf/NotFound.h>
45
#include <wtf/Vector.h>
46
#include <wtf/gobject/GOwnPtr.h>
47
#include <wtf/text/CString.h>
49
#define READ_BUFFER_SIZE 1024
53
// These functions immediately call the similarly named SocketStreamHandle methods.
54
static void connectedCallback(GSocketClient*, GAsyncResult*, void*);
55
static void readReadyCallback(GInputStream*, GAsyncResult*, void*);
56
static gboolean writeReadyCallback(GPollableOutputStream*, void*);
58
// Having a list of active handles means that we do not have to worry about WebCore
59
// reference counting in GLib callbacks. Once the handle is off the active handles list
60
// we just ignore it in the callback. We avoid a lot of extra checks and tricky
61
// situations this way.
62
static HashMap<void*, SocketStreamHandle*> gActiveHandles;
63
static SocketStreamHandle* getHandleFromId(void* id)
65
if (!gActiveHandles.contains(id))
67
return gActiveHandles.get(id);
70
static void deactivateHandle(SocketStreamHandle* handle)
72
gActiveHandles.remove(handle->id());
75
static void* activateHandle(SocketStreamHandle* handle)
77
// The first id cannot be 0, because it conflicts with the HashMap emptyValue.
78
static gint currentHandleId = 1;
79
void* id = GINT_TO_POINTER(currentHandleId++);
80
gActiveHandles.set(id, handle);
84
SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client)
85
: SocketStreamHandleBase(url, client)
88
LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
89
unsigned int port = url.hasPort() ? url.port() : (url.protocolIs("wss") ? 443 : 80);
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);
99
SocketStreamHandle::SocketStreamHandle(GSocketConnection* socketConnection, SocketStreamHandleClient* client)
100
: SocketStreamHandleBase(KURL(), client)
103
LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
104
m_id = activateHandle(this);
105
connected(socketConnection, 0);
108
SocketStreamHandle::~SocketStreamHandle()
110
LOG(Network, "SocketStreamHandle %p delete", this);
111
// If for some reason we were destroyed without closing, ensure that we are deactivated.
112
deactivateHandle(this);
116
void SocketStreamHandle::connected(GSocketConnection* socketConnection, GError* error)
119
m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
123
m_socketConnection = socketConnection;
124
m_outputStream = G_POLLABLE_OUTPUT_STREAM(g_io_stream_get_output_stream(G_IO_STREAM(m_socketConnection.get())));
125
m_inputStream = g_io_stream_get_input_stream(G_IO_STREAM(m_socketConnection.get()));
127
m_readBuffer = new char[READ_BUFFER_SIZE];
128
g_input_stream_read_async(m_inputStream.get(), m_readBuffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
129
reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), m_id);
132
m_client->didOpenSocketStream(this);
135
void SocketStreamHandle::readBytes(signed long bytesRead, GError* error)
138
m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
147
// The client can close the handle, potentially removing the last reference.
148
RefPtr<SocketStreamHandle> protect(this);
149
m_client->didReceiveSocketStreamData(this, m_readBuffer, bytesRead);
150
if (m_inputStream) // The client may have closed the connection.
151
g_input_stream_read_async(m_inputStream.get(), m_readBuffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
152
reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), m_id);
155
void SocketStreamHandle::writeReady()
157
// We no longer have buffered data, so stop waiting for the socket to be writable.
158
if (!bufferedAmount()) {
159
stopWaitingForSocketWritability();
166
int SocketStreamHandle::platformSend(const char* data, int length)
168
LOG(Network, "SocketStreamHandle %p platformSend", this);
169
if (!m_outputStream || !data)
172
GOwnPtr<GError> error;
173
gssize written = g_pollable_output_stream_write_nonblocking(m_outputStream.get(), data, length, 0, &error.outPtr());
175
if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
176
beginWaitingForSocketWritability();
178
m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
182
// If we did not send all the bytes we were given, we know that
183
// SocketStreamHandleBase will need to send more in the future.
184
if (written < length)
185
beginWaitingForSocketWritability();
190
void SocketStreamHandle::platformClose()
192
LOG(Network, "SocketStreamHandle %p platformClose", this);
193
// We remove this handle from the active handles list first, to disable all callbacks.
194
deactivateHandle(this);
195
stopWaitingForSocketWritability();
197
if (m_socketConnection) {
198
GOwnPtr<GError> error;
199
g_io_stream_close(G_IO_STREAM(m_socketConnection.get()), 0, &error.outPtr());
201
m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
202
m_socketConnection = 0;
210
m_client->didCloseSocketStream(this);
213
void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&)
218
void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&)
223
void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
228
void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
233
void SocketStreamHandle::beginWaitingForSocketWritability()
235
if (m_writeReadySource) // Already waiting.
238
m_writeReadySource = adoptGRef(g_pollable_output_stream_create_source(m_outputStream.get(), 0));
239
g_source_set_callback(m_writeReadySource.get(), reinterpret_cast<GSourceFunc>(writeReadyCallback), m_id, 0);
240
g_source_attach(m_writeReadySource.get(), 0);
243
void SocketStreamHandle::stopWaitingForSocketWritability()
245
if (!m_writeReadySource) // Not waiting.
248
g_source_remove(g_source_get_id(m_writeReadySource.get()));
249
m_writeReadySource = 0;
252
static void connectedCallback(GSocketClient* client, GAsyncResult* result, void* id)
254
// Always finish the connection, even if this SocketStreamHandle was deactivated earlier.
255
GOwnPtr<GError> error;
256
GSocketConnection* socketConnection = g_socket_client_connect_to_host_finish(client, result, &error.outPtr());
258
// The SocketStreamHandle has been deactivated, so just close the connection, ignoring errors.
259
SocketStreamHandle* handle = getHandleFromId(id);
261
if (socketConnection)
262
g_io_stream_close(G_IO_STREAM(socketConnection), 0, 0);
266
handle->connected(socketConnection, error.get());
269
static void readReadyCallback(GInputStream* stream, GAsyncResult* result, void* id)
271
// Always finish the read, even if this SocketStreamHandle was deactivated earlier.
272
GOwnPtr<GError> error;
273
gssize bytesRead = g_input_stream_read_finish(stream, result, &error.outPtr());
275
SocketStreamHandle* handle = getHandleFromId(id);
279
handle->readBytes(bytesRead, error.get());
282
static gboolean writeReadyCallback(GPollableOutputStream*, void* id)
284
SocketStreamHandle* handle = getHandleFromId(id);
288
handle->writeReady();
292
} // namespace WebCore