Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(106)

Side by Side Diff: WebCore/platform/network/soup/SocketStreamHandleSoup.cpp

Issue 155079: WebSocket implementation in WebKit (Closed)
Patch Set: Rewrite to use SocketStreamHandle Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « WebCore/platform/network/soup/SocketStreamError.h ('k') | WebCore/websockets/WebSocket.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2009 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "SocketStreamHandle.h"
28
29 #include <errno.h>
30 #include <glib.h>
31 #include <netdb.h>
32 #include <sys/socket.h>
33 #include <sys/types.h>
34
35 #include <wtf/PassOwnPtr.h>
36
37 #include "CString.h"
38 #include "Logging.h"
39 #include "KURL.h"
40 #include "NotImplemented.h"
41 #include "SharedBuffer.h"
42 #include "SocketStreamError.h"
43 #include "SocketStreamHandleClient.h"
44
45 #undef LOG
46 #define LOG(channel, ...) do { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n "); } while (0);
47
48 namespace WebCore {
49
50 const int kSocketStreamHandleBufSize = 1024;
51
52 class SocketStreamHandleInternal {
53 public:
54 static PassOwnPtr<SocketStreamHandleInternal> create(SocketStreamHandle* han dle) { return new SocketStreamHandleInternal(handle); }
55 ~SocketStreamHandleInternal();
56
57 void connect(const KURL&);
58 int send(const char*, int);
59 void close();
60
61 static gboolean handleRead(GIOChannel* source, GIOCondition condition, gpoin ter data);
62 static gboolean handleWrite(GIOChannel* source, GIOCondition condition, gpoi nter data);
63 static gboolean handleError(GIOChannel* source, GIOCondition condition, gpoi nter data);
64 static gboolean handleClose(gpointer data);
65
66 private:
67 explicit SocketStreamHandleInternal(SocketStreamHandle*);
68
69 gboolean canReceive();
70 gboolean canSend();
71 gboolean didError(GIOCondition condition);
72 gboolean didClose();
73
74 SocketStreamHandle* m_handle;
75 struct addrinfo* m_addrinfo;
76 int m_sock;
77 GIOChannel* m_g_io;
78 guint m_in_watch;
79 guint m_out_watch;
80 guint m_err_watch;
81 Vector<char> m_send_buffer;
82 gchar m_read_buf[kSocketStreamHandleBufSize];
83 };
84
85 /* static */
86 gboolean SocketStreamHandleInternal::handleRead(GIOChannel* source, GIOCondition cdondition, gpointer data)
87 {
88 LOG(Network, "SocketStreamHandle handleRead");
89 SocketStreamHandleInternal* internal = reinterpret_cast<SocketStreamHandleIn ternal*>(data);
90 return internal->canReceive();
91 }
92
93 /* static */
94 gboolean SocketStreamHandleInternal::handleWrite(GIOChannel* source, GIOConditio n condition, gpointer data)
95 {
96 LOG(Network, "SocketStreamHandle handleWrite");
97 SocketStreamHandleInternal* internal = reinterpret_cast<SocketStreamHandleIn ternal*>(data);
98 return internal->canSend();
99 }
100
101 /* static */
102 gboolean SocketStreamHandleInternal::handleError(GIOChannel* source, GIOConditio n condition, gpointer data)
103 {
104 LOG(Network, "SocketStreamHandle handleError");
105 SocketStreamHandleInternal* internal = reinterpret_cast<SocketStreamHandleIn ternal*>(data);
106 return internal->didError(condition);
107 }
108
109 /* static */
110 gboolean SocketStreamHandleInternal::handleClose(gpointer data)
111 {
112 LOG(Network, "SocketStreamHandle handleClose");
113 SocketStreamHandleInternal* internal = reinterpret_cast<SocketStreamHandleIn ternal*>(data);
114 internal->didClose();
115 return FALSE;
116 }
117
118 SocketStreamHandleInternal::SocketStreamHandleInternal(SocketStreamHandle* handl e)
119 : m_handle(handle)
120 , m_addrinfo(NULL)
121 , m_sock(-1)
122 , m_g_io(NULL)
123 , m_in_watch(0)
124 , m_out_watch(0)
125 , m_err_watch(0)
126 {
127 LOG(Network, "new SocketStreamHandleInternal %p", this);
128 }
129
130 SocketStreamHandleInternal::~SocketStreamHandleInternal()
131 {
132 LOG(Network, "delete SocketStreamHandleInternal %p", this);
133 m_handle = NULL;
134 if (m_g_io) {
135 GError* gerr = NULL;
136 g_io_channel_shutdown(m_g_io, false, &gerr);
137 if (gerr) {
138 LOG(Network, "shutdown failed: %s", gerr->message);
139 g_error_free(gerr);
140 }
141 g_io_channel_unref(m_g_io);
142 m_g_io = NULL;
143 }
144 if (m_sock >= 0)
145 ::close(m_sock);
146 if (m_addrinfo)
147 freeaddrinfo(m_addrinfo);
148 }
149
150 void SocketStreamHandleInternal::connect(const KURL& url)
151 {
152 LOG(Network, "SocketStreamHandleInternal %p connect %s", this, url.prettyURL ().utf8().data());
153
154 struct addrinfo hints;
155 memset(&hints, 0, sizeof(hints));
156 hints.ai_family = AF_UNSPEC;
157 hints.ai_flags = AI_ADDRCONFIG;
158 hints.ai_socktype = SOCK_STREAM;
159
160 LOG(Network, "SocketStreamHandleInternal %p connect %s:%d", this, url.host() .utf8().data(), url.port());
161 int err = getaddrinfo(url.host().utf8().data(), String::number(url.port()).u tf8().data(), &hints, &m_addrinfo);
162 if (err) {
163 LOG(Network, "SocketStreamHandleInternal %p resolve error %s:%d", this, url.host().utf8().data(), url.port());
164 close();
165 return;
166 }
167 ASSERT(m_addrinfo);
168
169 if (m_handle->m_client)
170 m_handle->m_client->willOpenStream(m_handle, url);
171
172 struct addrinfo* rp;
173 for (rp = m_addrinfo; rp != NULL; rp = rp->ai_next) {
174 m_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
175 if (m_sock < 0) {
176 LOG(Network, "SocketStreamHandleInternal %p socket error %d", this, errno);
177 continue;
178 }
179 m_g_io = g_io_channel_unix_new(m_sock);
180 ASSERT(m_g_io);
181
182 GError* gerr = NULL;
183 GIOStatus status = g_io_channel_set_encoding(m_g_io, NULL, &gerr);
184 ASSERT(status == G_IO_STATUS_NORMAL);
185 ASSERT(!gerr);
186
187 g_io_channel_set_buffered(m_g_io, FALSE);
188
189 m_out_watch = g_io_add_watch(m_g_io, G_IO_OUT, &SocketStreamHandleIntern al::handleWrite, this);
190 m_err_watch = g_io_add_watch(m_g_io, static_cast<GIOCondition>(G_IO_ERR| G_IO_HUP), &SocketStreamHandleInternal::handleError, this);
191
192 status = g_io_channel_set_flags(m_g_io, G_IO_FLAG_NONBLOCK, &gerr);
193 ASSERT(status == G_IO_STATUS_NORMAL);
194 ASSERT(!gerr);
195
196 LOG(Network, "SocketStreamHandleInternal %p CONNECTING", this);
197 int err = ::connect(m_sock, rp->ai_addr, rp->ai_addrlen);
198 if (err == 0) {
199 LOG(Network, "SocketStreamHandleInternal %p connect ok", this);
200 m_handle->m_client->didOpen(m_handle);
201 return;
202 } else {
203 if (errno == EINPROGRESS)
204 return;
205 LOG(Network, "SocketStreamHandleInternal %p connect failed %d", this , errno);
206 m_out_watch = m_err_watch = 0;
207 g_io_channel_unref(m_g_io);
208 m_g_io = NULL;
209 ::close(m_sock);
210 m_sock = -1;
211 }
212 }
213 LOG(Network, "SocketStreamHandleInternal %p connect all failed", this);
214 close();
215 }
216
217 int SocketStreamHandleInternal::send(const char* buf, int size)
218 {
219 LOG(Network, "SocketStreamHandleInternal %p send %d bytes", this, size);
220 if (!m_g_io) {
221 LOG_ERROR("SocketStreamHandleInternal %p already closed", this);
222 return -1;
223 }
224 if (!m_send_buffer.isEmpty()) {
225 LOG(Network, "SocketStreamHandleInternal %p send has buffer %d", this, m _send_buffer.size());
226 return 0;
227 }
228
229 m_send_buffer.append(buf, size);
230 if (m_out_watch == 0)
231 m_out_watch = g_io_add_watch(m_g_io, G_IO_OUT, &SocketStreamHandleIntern al::handleWrite, this);
232 return size;
233 }
234
235 void SocketStreamHandleInternal::close()
236 {
237 LOG(Network, "SocketStreamHandleInternal %p close", this);
238 if (m_handle->m_state != Closed)
239 g_idle_add(&SocketStreamHandleInternal::handleClose, this);
240 }
241
242 gboolean SocketStreamHandleInternal::canReceive()
243 {
244 LOG(Network, "SocketStreamHandleInternal %p canReceive", this);
245 if (!m_g_io) {
246 LOG_ERROR("SocketStreamHandleInternal %p already closed", this);
247 return FALSE;
248 }
249 ASSERT(m_g_io);
250 gsize num_read;
251 GError* gerr = NULL;
252 GIOStatus status = g_io_channel_read_chars(m_g_io, m_read_buf, sizeof(m_read _buf), &num_read, &gerr);
253 if (status == G_IO_STATUS_AGAIN) {
254 LOG(Network, "SocketStreamHandleInternal %p read resource temporarily un available", this);
255 return TRUE;
256 }
257 if (status != G_IO_STATUS_NORMAL) {
258 LOG(Network, "SocketStreamHandleInternal %p read error %d %s", this, sta tus, gerr ? gerr->message : "");
259 if (gerr)
260 g_error_free(gerr);
261 return didError(G_IO_ERR);
262 }
263 ASSERT(!gerr);
264 ASSERT(num_read < kSocketStreamHandleBufSize);
265
266 gchar tmp_buf[kSocketStreamHandleBufSize + 1];
267 memcpy(tmp_buf, m_read_buf, num_read);
268 tmp_buf[num_read] = '\0';
269
270 LOG(Network, "SocketStreamHandleInternal %p read %s (%lu)", this, tmp_buf, n um_read);
271 if (m_handle && m_handle->m_client)
272 m_handle->m_client->didReceivedData(m_handle, m_read_buf, num_read);
273 return TRUE;
274 }
275
276 gboolean SocketStreamHandleInternal::canSend()
277 {
278 LOG(Network, "SocketStreamHandleInternal %p canSend", this);
279 if (!m_g_io) {
280 LOG_ERROR("SocketStreamHandleInternal %p already closed", this);
281 return FALSE;
282 }
283 ASSERT(m_g_io);
284 if (m_handle->m_state == Connecting) {
285 int optval;
286 socklen_t optlen = sizeof(optval);
287 int err = getsockopt(m_sock, SOL_SOCKET, SO_ERROR, (void*)(&optval), &op tlen);
288 if (err < 0 || optval != 0) {
289 // TODO(ukai): errno = EINPROGRESS or EALREADY?
290 LOG(Network, "SocketStreamHandleInternal %p async connect failed %d so_error=%d", this, errno, optval);
291 return didError(G_IO_ERR);
292 }
293 LOG(Network, "SocketStreamHandleInternal %p CONNECTED", this);
294 m_in_watch = g_io_add_watch(m_g_io, G_IO_IN, &SocketStreamHandleInternal ::handleRead, this);
295 m_handle->m_state = Open;
296 // TODO(ukai): proxy, ssl.
297 LOG(Network, "SocketStreamHandleInternal %p didOpen", m_handle->m_client );
298 if (m_handle->m_client)
299 m_handle->m_client->didOpen(m_handle);
300 }
301
302 if (m_handle->m_client)
303 m_handle->m_client->willSendData(m_handle, m_send_buffer.data(), m_send_ buffer.size());
304 gsize bytes_written;
305 GError* gerr = NULL;
306 GIOStatus status = g_io_channel_write_chars(m_g_io, m_send_buffer.data(), m_ send_buffer.size(), &bytes_written, &gerr);
307 if (status == G_IO_STATUS_AGAIN) {
308 LOG(Network, "SocketStreamHandleInternal %p write resource temporarily u navailable", this);
309 return TRUE;
310 }
311 if (status != G_IO_STATUS_NORMAL) {
312 LOG(Network, "SocketStreamHandleInternal %p write error %d %s", this, st atus, gerr ? gerr->message : "");
313 if (gerr)
314 g_error_free(gerr);
315 return didError(G_IO_ERR);
316 }
317 LOG(Network, "SocketStreamHandleInternal %p write %lu bytes", this, bytes_wr itten);
318 ASSERT(!gerr);
319
320 if (m_send_buffer.size() > bytes_written) {
321 LOG(Network, "SocketStreamHandleInternal %p send buf size %lu", this, m_ send_buffer.size() - bytes_written);
322 Vector<char> buf;
323 buf.append(m_send_buffer.data() + bytes_written,
324 m_send_buffer.size() - bytes_written);
325 m_send_buffer.swap(buf);
326 return TRUE;
327 }
328 // All bytes in m_send_buffer were sent.
329 LOG(Network, "SocketStreamHandleInternal %p no send buf", this);
330 m_send_buffer.clear();
331 m_out_watch = 0;
332 return FALSE;
333 }
334
335 gboolean SocketStreamHandleInternal::didError(GIOCondition condition)
336 {
337 LOG(Network, "SocketStreamHandleInternal %p error", this);
338 m_handle->m_state = Closed;
339 SocketStreamError err(condition);
340 if (m_handle->m_client)
341 m_handle->m_client->didFail(m_handle, err);
342 m_handle->m_client = NULL;
343 return FALSE;
344 }
345
346 gboolean SocketStreamHandleInternal::didClose()
347 {
348 LOG(Network, "SocketStreamHandleInternal %p close", this);
349 m_handle->m_state = Closed;
350 if (m_handle->m_client)
351 m_handle->m_client->didClose(m_handle);
352 m_handle->m_client = NULL;
353 return FALSE;
354 }
355
356 SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient * client)
357 : m_url(url)
358 {
359 setClient(client);
360 LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
361 internal = SocketStreamHandleInternal::create(this);
362 internal->connect(m_url);
363 }
364
365 SocketStreamHandle::~SocketStreamHandle()
366 {
367 LOG(Network, "SocketStreamHandle %p delete", this);
368 setClient(NULL);
369 internal.clear();
370 }
371
372 int SocketStreamHandle::platformSend(const char *buf, int len)
373 {
374 LOG(Network, "SocketStreamHandle %p platformSend %d", this, len);
375 if (internal.get())
376 return internal->send(buf, len);
377 return 0;
378 }
379
380 void SocketStreamHandle::platformClose()
381 {
382 LOG(Network, "SocketStreamHandle %p platformClose", this);
383 if (internal.get())
384 internal->close();
385 }
386
387 void SocketStreamHandle::didReceivedAuthenticationChallenge(const Authentication Challenge& challenge)
388 {
389 if (m_client)
390 m_client->didReceivedAuthenticationChallenge(this, challenge);
391 }
392
393 void SocketStreamHandle::receivedCredential(const AuthenticationChallenge& chall enge, const Credential& credential)
394 {
395 notImplemented();
396 }
397
398 void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const Authen ticationChallenge& challenge)
399 {
400 notImplemented();
401 }
402
403 void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge& cha llenge)
404 {
405 if (m_client)
406 m_client->receivedCancellation(this, challenge);
407 }
408
409 } // namespace WebCore
OLDNEW
« no previous file with comments | « WebCore/platform/network/soup/SocketStreamError.h ('k') | WebCore/websockets/WebSocket.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698