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