1/*
2 * Copyright (C) 2009, 2011, 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "platform/network/SocketStreamHandle.h"
33
34#include "platform/Logging.h"
35#include "platform/network/SocketStreamError.h"
36#include "platform/network/SocketStreamHandleClient.h"
37#include "platform/network/SocketStreamHandleInternal.h"
38#include "public/platform/Platform.h"
39#include "public/platform/WebData.h"
40#include "public/platform/WebSocketStreamError.h"
41#include "public/platform/WebSocketStreamHandle.h"
42#include "wtf/PassOwnPtr.h"
43
44namespace blink {
45
46static const unsigned bufferSize = 100 * 1024 * 1024;
47
48SocketStreamHandleInternal::SocketStreamHandleInternal(SocketStreamHandle* handle)
49    : m_handle(handle)
50    , m_socket(adoptPtr(blink::Platform::current()->createSocketStreamHandle()))
51    , m_maxPendingSendAllowed(0)
52    , m_pendingAmountSent(0)
53{
54}
55
56SocketStreamHandleInternal::~SocketStreamHandleInternal()
57{
58#if !ENABLE(OILPAN)
59    m_handle = nullptr;
60#endif
61}
62
63void SocketStreamHandleInternal::connect(const KURL& url)
64{
65    WTF_LOG(Network, "SocketStreamHandleInternal %p connect()", this);
66
67    ASSERT(m_socket);
68    m_socket->connect(url, this);
69}
70
71int SocketStreamHandleInternal::send(const char* data, int len)
72{
73    WTF_LOG(Network, "SocketStreamHandleInternal %p send() len=%d", this, len);
74    // FIXME: |m_socket| should not be null here, but it seems that there is the
75    // case. We should figure out such a path and fix it rather than checking
76    // null here.
77    if (!m_socket) {
78        WTF_LOG(Network, "SocketStreamHandleInternal %p send() m_socket is NULL", this);
79        return 0;
80    }
81    if (m_pendingAmountSent + len > m_maxPendingSendAllowed)
82        len = m_maxPendingSendAllowed - m_pendingAmountSent;
83
84    if (len <= 0)
85        return len;
86    blink::WebData webdata(data, len);
87    if (m_socket->send(webdata)) {
88        m_pendingAmountSent += len;
89        WTF_LOG(Network, "SocketStreamHandleInternal %p send() Sent %d bytes", this, len);
90        return len;
91    }
92    WTF_LOG(Network, "SocketStreamHandleInternal %p send() m_socket->send() failed", this);
93    return 0;
94}
95
96void SocketStreamHandleInternal::close()
97{
98    WTF_LOG(Network, "SocketStreamHandleInternal %p close()", this);
99    if (m_socket)
100        m_socket->close();
101}
102
103void SocketStreamHandleInternal::didOpenStream(blink::WebSocketStreamHandle* socketHandle, int maxPendingSendAllowed)
104{
105    WTF_LOG(Network, "SocketStreamHandleInternal %p didOpenStream() maxPendingSendAllowed=%d", this, maxPendingSendAllowed);
106    ASSERT(maxPendingSendAllowed > 0);
107    if (m_handle && m_socket) {
108        ASSERT(socketHandle == m_socket.get());
109        m_maxPendingSendAllowed = maxPendingSendAllowed;
110        m_handle->m_state = SocketStreamHandle::Open;
111        if (m_handle->m_client) {
112            m_handle->m_client->didOpenSocketStream(m_handle);
113            return;
114        }
115    }
116    WTF_LOG(Network, "SocketStreamHandleInternal %p didOpenStream() m_handle or m_socket is NULL", this);
117}
118
119void SocketStreamHandleInternal::didSendData(blink::WebSocketStreamHandle* socketHandle, int amountSent)
120{
121    WTF_LOG(Network, "SocketStreamHandleInternal %p didSendData() amountSent=%d", this, amountSent);
122    ASSERT(amountSent > 0);
123    if (m_handle && m_socket) {
124        ASSERT(socketHandle == m_socket.get());
125        m_pendingAmountSent -= amountSent;
126        ASSERT(m_pendingAmountSent >= 0);
127        m_handle->sendPendingData();
128    }
129}
130
131void SocketStreamHandleInternal::didReceiveData(blink::WebSocketStreamHandle* socketHandle, const blink::WebData& data)
132{
133    WTF_LOG(Network, "SocketStreamHandleInternal %p didReceiveData() Received %lu bytes", this, static_cast<unsigned long>(data.size()));
134    if (m_handle && m_socket) {
135        ASSERT(socketHandle == m_socket.get());
136        if (m_handle->m_client)
137            m_handle->m_client->didReceiveSocketStreamData(m_handle, data.data(), data.size());
138    }
139}
140
141void SocketStreamHandleInternal::didClose(blink::WebSocketStreamHandle* socketHandle)
142{
143    WTF_LOG(Network, "SocketStreamHandleInternal %p didClose()", this);
144    if (m_handle && m_socket) {
145        ASSERT(socketHandle == m_socket.get());
146        m_socket.clear();
147        SocketStreamHandle* h = m_handle;
148        m_handle = nullptr;
149        if (h->m_client)
150            h->m_client->didCloseSocketStream(h);
151    }
152}
153
154void SocketStreamHandleInternal::didFail(blink::WebSocketStreamHandle* socketHandle, const blink::WebSocketStreamError& err)
155{
156    WTF_LOG(Network, "SocketStreamHandleInternal %p didFail()", this);
157    if (m_handle && m_socket) {
158        ASSERT(socketHandle == m_socket.get());
159        if (m_handle->m_client)
160            m_handle->m_client->didFailSocketStream(m_handle, *(PassRefPtr<SocketStreamError>(err)));
161    }
162}
163
164void SocketStreamHandleInternal::trace(Visitor* visitor)
165{
166    visitor->trace(m_handle);
167}
168
169// SocketStreamHandle ----------------------------------------------------------
170
171SocketStreamHandle::SocketStreamHandle(SocketStreamHandleClient* client)
172    : m_client(client)
173    , m_state(Connecting)
174{
175    m_internal = SocketStreamHandleInternal::create(this);
176}
177
178void SocketStreamHandle::connect(const KURL& url)
179{
180    m_internal->connect(url);
181}
182
183SocketStreamHandle::~SocketStreamHandle()
184{
185#if !ENABLE(OILPAN)
186    setClient(0);
187#endif
188}
189
190SocketStreamHandle::SocketStreamState SocketStreamHandle::state() const
191{
192    return m_state;
193}
194
195bool SocketStreamHandle::send(const char* data, int length)
196{
197    if (m_state == Connecting || m_state == Closing)
198        return false;
199    if (!m_buffer.isEmpty()) {
200        if (m_buffer.size() + length > bufferSize) {
201            // FIXME: report error to indicate that buffer has no more space.
202            return false;
203        }
204        m_buffer.append(data, length);
205        return true;
206    }
207    int bytesWritten = 0;
208    if (m_state == Open)
209        bytesWritten = sendInternal(data, length);
210    if (bytesWritten < 0)
211        return false;
212    if (m_client)
213        m_client->didConsumeBufferedAmount(this, bytesWritten);
214    if (m_buffer.size() + length - bytesWritten > bufferSize) {
215        // FIXME: report error to indicate that buffer has no more space.
216        return false;
217    }
218    if (bytesWritten < length) {
219        m_buffer.append(data + bytesWritten, length - bytesWritten);
220    }
221    return true;
222}
223
224void SocketStreamHandle::close()
225{
226    if (m_state == Closed)
227        return;
228    m_state = Closing;
229    if (!m_buffer.isEmpty())
230        return;
231    disconnect();
232}
233
234void SocketStreamHandle::disconnect()
235{
236    closeInternal();
237    m_state = Closed;
238}
239
240void SocketStreamHandle::setClient(SocketStreamHandleClient* client)
241{
242    ASSERT(!client || (!m_client && m_state == Connecting));
243    m_client = client;
244}
245
246bool SocketStreamHandle::sendPendingData()
247{
248    if (m_state != Open && m_state != Closing)
249        return false;
250    if (m_buffer.isEmpty()) {
251        if (m_state == Open)
252            return false;
253        if (m_state == Closing) {
254            disconnect();
255            return false;
256        }
257    }
258    bool pending;
259    do {
260        int bytesWritten = sendInternal(m_buffer.firstBlockData(), m_buffer.firstBlockSize());
261        pending = bytesWritten != static_cast<int>(m_buffer.firstBlockSize());
262        if (bytesWritten <= 0)
263            return false;
264        ASSERT(m_buffer.size() - bytesWritten <= bufferSize);
265        m_buffer.consume(bytesWritten);
266        // FIXME: place didConsumeBufferedAmount out of do-while.
267        if (m_client)
268            m_client->didConsumeBufferedAmount(this, bytesWritten);
269    } while (!pending && !m_buffer.isEmpty());
270    return true;
271}
272
273int SocketStreamHandle::sendInternal(const char* buf, int len)
274{
275    if (!m_internal)
276        return 0;
277    return m_internal->send(buf, len);
278}
279
280void SocketStreamHandle::closeInternal()
281{
282    if (m_internal)
283        m_internal->close();
284}
285
286void SocketStreamHandle::trace(Visitor* visitor)
287{
288    visitor->trace(m_client);
289    visitor->trace(m_internal);
290}
291
292} // namespace blink
293