xref: /openbmc/qemu/io/channel-websock.c (revision 8301ea44)
1 /*
2  * QEMU I/O channels driver websockets
3  *
4  * Copyright (c) 2015 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "qemu/osdep.h"
22 #include "qapi/error.h"
23 #include "qemu/bswap.h"
24 #include "io/channel-websock.h"
25 #include "crypto/hash.h"
26 #include "trace.h"
27 
28 #include <time.h>
29 
30 
31 /* Max amount to allow in rawinput/rawoutput buffers */
32 #define QIO_CHANNEL_WEBSOCK_MAX_BUFFER 8192
33 
34 #define QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN 24
35 #define QIO_CHANNEL_WEBSOCK_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
36 #define QIO_CHANNEL_WEBSOCK_GUID_LEN strlen(QIO_CHANNEL_WEBSOCK_GUID)
37 
38 #define QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL "sec-websocket-protocol"
39 #define QIO_CHANNEL_WEBSOCK_HEADER_VERSION "sec-websocket-version"
40 #define QIO_CHANNEL_WEBSOCK_HEADER_KEY "sec-websocket-key"
41 #define QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE "upgrade"
42 #define QIO_CHANNEL_WEBSOCK_HEADER_HOST "host"
43 #define QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION "connection"
44 
45 #define QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY "binary"
46 #define QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE "Upgrade"
47 #define QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET "websocket"
48 
49 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \
50     "Server: QEMU VNC\r\n"                       \
51     "Date: %s\r\n"
52 
53 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK    \
54     "HTTP/1.1 101 Switching Protocols\r\n"      \
55     QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON    \
56     "Upgrade: websocket\r\n"                    \
57     "Connection: Upgrade\r\n"                   \
58     "Sec-WebSocket-Accept: %s\r\n"              \
59     "Sec-WebSocket-Protocol: binary\r\n"        \
60     "\r\n"
61 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_NOT_FOUND \
62     "HTTP/1.1 404 Not Found\r\n"                    \
63     QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON        \
64     "Connection: close\r\n"                         \
65     "\r\n"
66 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST \
67     "HTTP/1.1 400 Bad Request\r\n"                    \
68     QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON          \
69     "Connection: close\r\n"                           \
70     "Sec-WebSocket-Version: "                         \
71     QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION             \
72     "\r\n"
73 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR \
74     "HTTP/1.1 500 Internal Server Error\r\n"         \
75     QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON         \
76     "Connection: close\r\n"                          \
77     "\r\n"
78 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE  \
79     "HTTP/1.1 403 Request Entity Too Large\r\n"      \
80     QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON         \
81     "Connection: close\r\n"                          \
82     "\r\n"
83 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM "\r\n"
84 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_END "\r\n\r\n"
85 #define QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION "13"
86 #define QIO_CHANNEL_WEBSOCK_HTTP_METHOD "GET"
87 #define QIO_CHANNEL_WEBSOCK_HTTP_PATH "/"
88 #define QIO_CHANNEL_WEBSOCK_HTTP_VERSION "HTTP/1.1"
89 
90 /* The websockets packet header is variable length
91  * depending on the size of the payload... */
92 
93 /* ...length when using 7-bit payload length */
94 #define QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT 6
95 /* ...length when using 16-bit payload length */
96 #define QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT 8
97 /* ...length when using 64-bit payload length */
98 #define QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT 14
99 
100 /* Length of the optional data mask field in header */
101 #define QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK 4
102 
103 /* Maximum length that can fit in 7-bit payload size */
104 #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT 126
105 /* Maximum length that can fit in 16-bit payload size */
106 #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_16_BIT 65536
107 
108 /* Magic 7-bit length to indicate use of 16-bit payload length */
109 #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT 126
110 /* Magic 7-bit length to indicate use of 64-bit payload length */
111 #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT 127
112 
113 /* Bitmasks for accessing header fields */
114 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN 0x80
115 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE 0x0f
116 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK 0x80
117 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN 0x7f
118 #define QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK 0x8
119 
120 typedef struct QIOChannelWebsockHeader QIOChannelWebsockHeader;
121 
122 struct QEMU_PACKED QIOChannelWebsockHeader {
123     unsigned char b0;
124     unsigned char b1;
125     union {
126         struct QEMU_PACKED {
127             uint16_t l16;
128             QIOChannelWebsockMask m16;
129         } s16;
130         struct QEMU_PACKED {
131             uint64_t l64;
132             QIOChannelWebsockMask m64;
133         } s64;
134         QIOChannelWebsockMask m;
135     } u;
136 };
137 
138 typedef struct QIOChannelWebsockHTTPHeader QIOChannelWebsockHTTPHeader;
139 
140 struct QIOChannelWebsockHTTPHeader {
141     char *name;
142     char *value;
143 };
144 
145 enum {
146     QIO_CHANNEL_WEBSOCK_OPCODE_CONTINUATION = 0x0,
147     QIO_CHANNEL_WEBSOCK_OPCODE_TEXT_FRAME = 0x1,
148     QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME = 0x2,
149     QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE = 0x8,
150     QIO_CHANNEL_WEBSOCK_OPCODE_PING = 0x9,
151     QIO_CHANNEL_WEBSOCK_OPCODE_PONG = 0xA
152 };
153 
154 static void qio_channel_websock_handshake_send_res(QIOChannelWebsock *ioc,
155                                                    const char *resmsg,
156                                                    ...)
157 {
158     va_list vargs;
159     char *response;
160     size_t responselen;
161 
162     va_start(vargs, resmsg);
163     response = g_strdup_vprintf(resmsg, vargs);
164     responselen = strlen(response);
165     buffer_reserve(&ioc->encoutput, responselen);
166     buffer_append(&ioc->encoutput, response, responselen);
167     va_end(vargs);
168 }
169 
170 static gchar *qio_channel_websock_date_str(void)
171 {
172     struct tm tm;
173     time_t now = time(NULL);
174     char datebuf[128];
175 
176     gmtime_r(&now, &tm);
177 
178     strftime(datebuf, sizeof(datebuf), "%a, %d %b %Y %H:%M:%S GMT", &tm);
179 
180     return g_strdup(datebuf);
181 }
182 
183 static void qio_channel_websock_handshake_send_res_err(QIOChannelWebsock *ioc,
184                                                        const char *resdata)
185 {
186     char *date = qio_channel_websock_date_str();
187     qio_channel_websock_handshake_send_res(ioc, resdata, date);
188     g_free(date);
189 }
190 
191 enum {
192     QIO_CHANNEL_WEBSOCK_STATUS_NORMAL = 1000,
193     QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR = 1002,
194     QIO_CHANNEL_WEBSOCK_STATUS_INVALID_DATA = 1003,
195     QIO_CHANNEL_WEBSOCK_STATUS_POLICY = 1008,
196     QIO_CHANNEL_WEBSOCK_STATUS_TOO_LARGE = 1009,
197     QIO_CHANNEL_WEBSOCK_STATUS_SERVER_ERR = 1011,
198 };
199 
200 static size_t
201 qio_channel_websock_extract_headers(QIOChannelWebsock *ioc,
202                                     char *buffer,
203                                     QIOChannelWebsockHTTPHeader *hdrs,
204                                     size_t nhdrsalloc,
205                                     Error **errp)
206 {
207     char *nl, *sep, *tmp;
208     size_t nhdrs = 0;
209 
210     /*
211      * First parse the HTTP protocol greeting of format:
212      *
213      *   $METHOD $PATH $VERSION
214      *
215      * e.g.
216      *
217      *   GET / HTTP/1.1
218      */
219 
220     nl = strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
221     if (!nl) {
222         error_setg(errp, "Missing HTTP header delimiter");
223         goto bad_request;
224     }
225     *nl = '\0';
226 
227     tmp = strchr(buffer, ' ');
228     if (!tmp) {
229         error_setg(errp, "Missing HTTP path delimiter");
230         return 0;
231     }
232     *tmp = '\0';
233 
234     if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_METHOD)) {
235         error_setg(errp, "Unsupported HTTP method %s", buffer);
236         goto bad_request;
237     }
238 
239     buffer = tmp + 1;
240     tmp = strchr(buffer, ' ');
241     if (!tmp) {
242         error_setg(errp, "Missing HTTP version delimiter");
243         goto bad_request;
244     }
245     *tmp = '\0';
246 
247     if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_PATH)) {
248         qio_channel_websock_handshake_send_res_err(
249             ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_NOT_FOUND);
250         error_setg(errp, "Unexpected HTTP path %s", buffer);
251         return 0;
252     }
253 
254     buffer = tmp + 1;
255 
256     if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_VERSION)) {
257         error_setg(errp, "Unsupported HTTP version %s", buffer);
258         goto bad_request;
259     }
260 
261     buffer = nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
262 
263     /*
264      * Now parse all the header fields of format
265      *
266      *   $NAME: $VALUE
267      *
268      * e.g.
269      *
270      *   Cache-control: no-cache
271      */
272     do {
273         QIOChannelWebsockHTTPHeader *hdr;
274 
275         nl = strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
276         if (nl) {
277             *nl = '\0';
278         }
279 
280         sep = strchr(buffer, ':');
281         if (!sep) {
282             error_setg(errp, "Malformed HTTP header");
283             goto bad_request;
284         }
285         *sep = '\0';
286         sep++;
287         while (*sep == ' ') {
288             sep++;
289         }
290 
291         if (nhdrs >= nhdrsalloc) {
292             error_setg(errp, "Too many HTTP headers");
293             goto bad_request;
294         }
295 
296         hdr = &hdrs[nhdrs++];
297         hdr->name = buffer;
298         hdr->value = sep;
299 
300         /* Canonicalize header name for easier identification later */
301         for (tmp = hdr->name; *tmp; tmp++) {
302             *tmp = g_ascii_tolower(*tmp);
303         }
304 
305         if (nl) {
306             buffer = nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
307         }
308     } while (nl != NULL);
309 
310     return nhdrs;
311 
312  bad_request:
313     qio_channel_websock_handshake_send_res_err(
314         ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST);
315     return 0;
316 }
317 
318 static const char *
319 qio_channel_websock_find_header(QIOChannelWebsockHTTPHeader *hdrs,
320                                 size_t nhdrs,
321                                 const char *name)
322 {
323     size_t i;
324 
325     for (i = 0; i < nhdrs; i++) {
326         if (g_str_equal(hdrs[i].name, name)) {
327             return hdrs[i].value;
328         }
329     }
330 
331     return NULL;
332 }
333 
334 
335 static void qio_channel_websock_handshake_send_res_ok(QIOChannelWebsock *ioc,
336                                                       const char *key,
337                                                       Error **errp)
338 {
339     char combined_key[QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN +
340                       QIO_CHANNEL_WEBSOCK_GUID_LEN + 1];
341     char *accept = NULL;
342     char *date = qio_channel_websock_date_str();
343 
344     g_strlcpy(combined_key, key, QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 1);
345     g_strlcat(combined_key, QIO_CHANNEL_WEBSOCK_GUID,
346               QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN +
347               QIO_CHANNEL_WEBSOCK_GUID_LEN + 1);
348 
349     /* hash and encode it */
350     if (qcrypto_hash_base64(QCRYPTO_HASH_ALG_SHA1,
351                             combined_key,
352                             QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN +
353                             QIO_CHANNEL_WEBSOCK_GUID_LEN,
354                             &accept,
355                             errp) < 0) {
356         qio_channel_websock_handshake_send_res_err(
357             ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR);
358         return;
359     }
360 
361     qio_channel_websock_handshake_send_res(
362         ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK, date, accept);
363 
364     g_free(date);
365     g_free(accept);
366 }
367 
368 static void qio_channel_websock_handshake_process(QIOChannelWebsock *ioc,
369                                                   char *buffer,
370                                                   Error **errp)
371 {
372     QIOChannelWebsockHTTPHeader hdrs[32];
373     size_t nhdrs = G_N_ELEMENTS(hdrs);
374     const char *protocols = NULL, *version = NULL, *key = NULL,
375         *host = NULL, *connection = NULL, *upgrade = NULL;
376 
377     nhdrs = qio_channel_websock_extract_headers(ioc, buffer, hdrs, nhdrs, errp);
378     if (!nhdrs) {
379         return;
380     }
381 
382     protocols = qio_channel_websock_find_header(
383         hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL);
384     if (!protocols) {
385         error_setg(errp, "Missing websocket protocol header data");
386         goto bad_request;
387     }
388 
389     version = qio_channel_websock_find_header(
390         hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_VERSION);
391     if (!version) {
392         error_setg(errp, "Missing websocket version header data");
393         goto bad_request;
394     }
395 
396     key = qio_channel_websock_find_header(
397         hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_KEY);
398     if (!key) {
399         error_setg(errp, "Missing websocket key header data");
400         goto bad_request;
401     }
402 
403     host = qio_channel_websock_find_header(
404         hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_HOST);
405     if (!host) {
406         error_setg(errp, "Missing websocket host header data");
407         goto bad_request;
408     }
409 
410     connection = qio_channel_websock_find_header(
411         hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION);
412     if (!connection) {
413         error_setg(errp, "Missing websocket connection header data");
414         goto bad_request;
415     }
416 
417     upgrade = qio_channel_websock_find_header(
418         hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE);
419     if (!upgrade) {
420         error_setg(errp, "Missing websocket upgrade header data");
421         goto bad_request;
422     }
423 
424     if (!g_strrstr(protocols, QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY)) {
425         error_setg(errp, "No '%s' protocol is supported by client '%s'",
426                    QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY, protocols);
427         goto bad_request;
428     }
429 
430     if (!g_str_equal(version, QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION)) {
431         error_setg(errp, "Version '%s' is not supported by client '%s'",
432                    QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION, version);
433         goto bad_request;
434     }
435 
436     if (strlen(key) != QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN) {
437         error_setg(errp, "Key length '%zu' was not as expected '%d'",
438                    strlen(key), QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN);
439         goto bad_request;
440     }
441 
442     if (strcasecmp(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE) != 0) {
443         error_setg(errp, "No connection upgrade requested '%s'", connection);
444         goto bad_request;
445     }
446 
447     if (strcasecmp(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET) != 0) {
448         error_setg(errp, "Incorrect upgrade method '%s'", upgrade);
449         goto bad_request;
450     }
451 
452     qio_channel_websock_handshake_send_res_ok(ioc, key, errp);
453     return;
454 
455  bad_request:
456     qio_channel_websock_handshake_send_res_err(
457         ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST);
458 }
459 
460 static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc,
461                                               Error **errp)
462 {
463     char *handshake_end;
464     ssize_t ret;
465     /* Typical HTTP headers from novnc are 512 bytes, so limiting
466      * total header size to 4096 is easily enough. */
467     size_t want = 4096 - ioc->encinput.offset;
468     buffer_reserve(&ioc->encinput, want);
469     ret = qio_channel_read(ioc->master,
470                            (char *)buffer_end(&ioc->encinput), want, errp);
471     if (ret < 0) {
472         return -1;
473     }
474     ioc->encinput.offset += ret;
475 
476     handshake_end = g_strstr_len((char *)ioc->encinput.buffer,
477                                  ioc->encinput.offset,
478                                  QIO_CHANNEL_WEBSOCK_HANDSHAKE_END);
479     if (!handshake_end) {
480         if (ioc->encinput.offset >= 4096) {
481             qio_channel_websock_handshake_send_res_err(
482                 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE);
483             error_setg(errp,
484                        "End of headers not found in first 4096 bytes");
485             return 1;
486         } else {
487             return 0;
488         }
489     }
490     *handshake_end = '\0';
491 
492     qio_channel_websock_handshake_process(ioc,
493                                           (char *)ioc->encinput.buffer,
494                                           errp);
495 
496     buffer_advance(&ioc->encinput,
497                    handshake_end - (char *)ioc->encinput.buffer +
498                    strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_END));
499     return 1;
500 }
501 
502 static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc,
503                                                    GIOCondition condition,
504                                                    gpointer user_data)
505 {
506     QIOTask *task = user_data;
507     QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(
508         qio_task_get_source(task));
509     Error *err = NULL;
510     ssize_t ret;
511 
512     ret = qio_channel_write(wioc->master,
513                             (char *)wioc->encoutput.buffer,
514                             wioc->encoutput.offset,
515                             &err);
516 
517     if (ret < 0) {
518         trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err));
519         qio_task_set_error(task, err);
520         qio_task_complete(task);
521         return FALSE;
522     }
523 
524     buffer_advance(&wioc->encoutput, ret);
525     if (wioc->encoutput.offset == 0) {
526         if (wioc->io_err) {
527             trace_qio_channel_websock_handshake_fail(
528                 ioc, error_get_pretty(wioc->io_err));
529             qio_task_set_error(task, wioc->io_err);
530             wioc->io_err = NULL;
531             qio_task_complete(task);
532         } else {
533             trace_qio_channel_websock_handshake_complete(ioc);
534             qio_task_complete(task);
535         }
536         return FALSE;
537     }
538     trace_qio_channel_websock_handshake_pending(ioc, G_IO_OUT);
539     return TRUE;
540 }
541 
542 static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc,
543                                                  GIOCondition condition,
544                                                  gpointer user_data)
545 {
546     QIOTask *task = user_data;
547     QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(
548         qio_task_get_source(task));
549     Error *err = NULL;
550     int ret;
551 
552     ret = qio_channel_websock_handshake_read(wioc, &err);
553     if (ret < 0) {
554         /*
555          * We only take this path on a fatal I/O error reading from
556          * client connection, as most of the time we have an
557          * HTTP 4xx err response to send instead
558          */
559         trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err));
560         qio_task_set_error(task, err);
561         qio_task_complete(task);
562         return FALSE;
563     }
564     if (ret == 0) {
565         trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN);
566         /* need more data still */
567         return TRUE;
568     }
569 
570     if (err) {
571         error_propagate(&wioc->io_err, err);
572     }
573 
574     trace_qio_channel_websock_handshake_reply(ioc);
575     qio_channel_add_watch(
576         wioc->master,
577         G_IO_OUT,
578         qio_channel_websock_handshake_send,
579         task,
580         NULL);
581     return FALSE;
582 }
583 
584 
585 static void qio_channel_websock_encode_buffer(QIOChannelWebsock *ioc,
586                                               Buffer *output,
587                                               uint8_t opcode, Buffer *buffer)
588 {
589     size_t header_size;
590     union {
591         char buf[QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT];
592         QIOChannelWebsockHeader ws;
593     } header;
594 
595     header.ws.b0 = QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN |
596         (opcode & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE);
597     if (buffer->offset < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT) {
598         header.ws.b1 = (uint8_t)buffer->offset;
599         header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT;
600     } else if (buffer->offset <
601                QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_16_BIT) {
602         header.ws.b1 = QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT;
603         header.ws.u.s16.l16 = cpu_to_be16((uint16_t)buffer->offset);
604         header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT;
605     } else {
606         header.ws.b1 = QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT;
607         header.ws.u.s64.l64 = cpu_to_be64(buffer->offset);
608         header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT;
609     }
610     header_size -= QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK;
611 
612     trace_qio_channel_websock_encode(ioc, opcode, header_size, buffer->offset);
613     buffer_reserve(output, header_size + buffer->offset);
614     buffer_append(output, header.buf, header_size);
615     buffer_append(output, buffer->buffer, buffer->offset);
616 }
617 
618 
619 static void qio_channel_websock_encode(QIOChannelWebsock *ioc)
620 {
621     if (!ioc->rawoutput.offset) {
622         return;
623     }
624     qio_channel_websock_encode_buffer(
625         ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME,
626         &ioc->rawoutput);
627     buffer_reset(&ioc->rawoutput);
628 }
629 
630 
631 static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *, Error **);
632 
633 
634 static void qio_channel_websock_write_close(QIOChannelWebsock *ioc,
635                                             uint16_t code, const char *reason)
636 {
637     buffer_reserve(&ioc->rawoutput, 2 + (reason ? strlen(reason) : 0));
638     *(uint16_t *)(ioc->rawoutput.buffer + ioc->rawoutput.offset) =
639         cpu_to_be16(code);
640     ioc->rawoutput.offset += 2;
641     if (reason) {
642         buffer_append(&ioc->rawoutput, reason, strlen(reason));
643     }
644     qio_channel_websock_encode_buffer(
645         ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE,
646         &ioc->rawoutput);
647     buffer_reset(&ioc->rawoutput);
648     qio_channel_websock_write_wire(ioc, NULL);
649     qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
650 }
651 
652 
653 static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc,
654                                              Error **errp)
655 {
656     unsigned char opcode, fin, has_mask;
657     size_t header_size;
658     size_t payload_len;
659     QIOChannelWebsockHeader *header =
660         (QIOChannelWebsockHeader *)ioc->encinput.buffer;
661 
662     if (ioc->payload_remain) {
663         error_setg(errp,
664                    "Decoding header but %zu bytes of payload remain",
665                    ioc->payload_remain);
666         qio_channel_websock_write_close(
667             ioc, QIO_CHANNEL_WEBSOCK_STATUS_SERVER_ERR,
668             "internal server error");
669         return -1;
670     }
671     if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT) {
672         /* header not complete */
673         return QIO_CHANNEL_ERR_BLOCK;
674     }
675 
676     fin = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN;
677     opcode = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE;
678     has_mask = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK;
679     payload_len = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN;
680 
681     /* Save or restore opcode. */
682     if (opcode) {
683         ioc->opcode = opcode;
684     } else {
685         opcode = ioc->opcode;
686     }
687 
688     trace_qio_channel_websock_header_partial_decode(ioc, payload_len,
689                                                     fin, opcode, (int)has_mask);
690 
691     if (opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) {
692         /* disconnect */
693         return 0;
694     }
695 
696     /* Websocket frame sanity check:
697      * * Fragmentation is only supported for binary frames.
698      * * All frames sent by a client MUST be masked.
699      * * Only binary and ping/pong encoding is supported.
700      */
701     if (!fin) {
702         if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) {
703             error_setg(errp, "only binary websocket frames may be fragmented");
704             qio_channel_websock_write_close(
705                 ioc, QIO_CHANNEL_WEBSOCK_STATUS_POLICY ,
706                 "only binary frames may be fragmented");
707             return -1;
708         }
709     } else {
710         if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME &&
711             opcode != QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE &&
712             opcode != QIO_CHANNEL_WEBSOCK_OPCODE_PING &&
713             opcode != QIO_CHANNEL_WEBSOCK_OPCODE_PONG) {
714             error_setg(errp, "unsupported opcode: %#04x; only binary, close, "
715                        "ping, and pong websocket frames are supported", opcode);
716             qio_channel_websock_write_close(
717                 ioc, QIO_CHANNEL_WEBSOCK_STATUS_INVALID_DATA ,
718                 "only binary, close, ping, and pong frames are supported");
719             return -1;
720         }
721     }
722     if (!has_mask) {
723         error_setg(errp, "client websocket frames must be masked");
724         qio_channel_websock_write_close(
725             ioc, QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR,
726             "client frames must be masked");
727         return -1;
728     }
729 
730     if (payload_len < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT) {
731         ioc->payload_remain = payload_len;
732         header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT;
733         ioc->mask = header->u.m;
734     } else if (opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) {
735         error_setg(errp, "websocket control frame is too large");
736         qio_channel_websock_write_close(
737             ioc, QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR,
738             "control frame is too large");
739         return -1;
740     } else if (payload_len == QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT &&
741                ioc->encinput.offset >= QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT) {
742         ioc->payload_remain = be16_to_cpu(header->u.s16.l16);
743         header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT;
744         ioc->mask = header->u.s16.m16;
745     } else if (payload_len == QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT &&
746                ioc->encinput.offset >= QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT) {
747         ioc->payload_remain = be64_to_cpu(header->u.s64.l64);
748         header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT;
749         ioc->mask = header->u.s64.m64;
750     } else {
751         /* header not complete */
752         return QIO_CHANNEL_ERR_BLOCK;
753     }
754 
755     trace_qio_channel_websock_header_full_decode(
756         ioc, header_size, ioc->payload_remain, ioc->mask.u);
757     buffer_advance(&ioc->encinput, header_size);
758     return 0;
759 }
760 
761 
762 static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc,
763                                               Error **errp)
764 {
765     size_t i;
766     size_t payload_len = 0;
767     uint32_t *payload32;
768 
769     if (ioc->payload_remain) {
770         /* If we aren't at the end of the payload, then drop
771          * off the last bytes, so we're always multiple of 4
772          * for purpose of unmasking, except at end of payload
773          */
774         if (ioc->encinput.offset < ioc->payload_remain) {
775             /* Wait for the entire payload before processing control frames
776              * because the payload will most likely be echoed back. */
777             if (ioc->opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) {
778                 return QIO_CHANNEL_ERR_BLOCK;
779             }
780             payload_len = ioc->encinput.offset - (ioc->encinput.offset % 4);
781         } else {
782             payload_len = ioc->payload_remain;
783         }
784         if (payload_len == 0) {
785             return QIO_CHANNEL_ERR_BLOCK;
786         }
787 
788         ioc->payload_remain -= payload_len;
789 
790         /* unmask frame */
791         /* process 1 frame (32 bit op) */
792         payload32 = (uint32_t *)ioc->encinput.buffer;
793         for (i = 0; i < payload_len / 4; i++) {
794             payload32[i] ^= ioc->mask.u;
795         }
796         /* process the remaining bytes (if any) */
797         for (i *= 4; i < payload_len; i++) {
798             ioc->encinput.buffer[i] ^= ioc->mask.c[i % 4];
799         }
800     }
801 
802     trace_qio_channel_websock_payload_decode(
803         ioc, ioc->opcode, ioc->payload_remain);
804 
805     if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) {
806         if (payload_len) {
807             /* binary frames are passed on */
808             buffer_reserve(&ioc->rawinput, payload_len);
809             buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len);
810         }
811     } else if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) {
812         /* close frames are echoed back */
813         error_setg(errp, "websocket closed by peer");
814         if (payload_len) {
815             /* echo client status */
816             qio_channel_websock_encode_buffer(
817                 ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE,
818                 &ioc->encinput);
819             qio_channel_websock_write_wire(ioc, NULL);
820             qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
821         } else {
822             /* send our own status */
823             qio_channel_websock_write_close(
824                 ioc, QIO_CHANNEL_WEBSOCK_STATUS_NORMAL, "peer requested close");
825         }
826         return -1;
827     } else if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_PING) {
828         /* ping frames produce an immediate reply */
829         buffer_reset(&ioc->ping_reply);
830         qio_channel_websock_encode_buffer(
831             ioc, &ioc->ping_reply, QIO_CHANNEL_WEBSOCK_OPCODE_PONG,
832             &ioc->encinput);
833     }   /* pong frames are ignored */
834 
835     if (payload_len) {
836         buffer_advance(&ioc->encinput, payload_len);
837     }
838     return 0;
839 }
840 
841 
842 QIOChannelWebsock *
843 qio_channel_websock_new_server(QIOChannel *master)
844 {
845     QIOChannelWebsock *wioc;
846     QIOChannel *ioc;
847 
848     wioc = QIO_CHANNEL_WEBSOCK(object_new(TYPE_QIO_CHANNEL_WEBSOCK));
849     ioc = QIO_CHANNEL(wioc);
850 
851     wioc->master = master;
852     if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) {
853         qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
854     }
855     object_ref(OBJECT(master));
856 
857     trace_qio_channel_websock_new_server(wioc, master);
858     return wioc;
859 }
860 
861 void qio_channel_websock_handshake(QIOChannelWebsock *ioc,
862                                    QIOTaskFunc func,
863                                    gpointer opaque,
864                                    GDestroyNotify destroy)
865 {
866     QIOTask *task;
867 
868     task = qio_task_new(OBJECT(ioc),
869                         func,
870                         opaque,
871                         destroy);
872 
873     trace_qio_channel_websock_handshake_start(ioc);
874     trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN);
875     qio_channel_add_watch(ioc->master,
876                           G_IO_IN,
877                           qio_channel_websock_handshake_io,
878                           task,
879                           NULL);
880 }
881 
882 
883 static void qio_channel_websock_finalize(Object *obj)
884 {
885     QIOChannelWebsock *ioc = QIO_CHANNEL_WEBSOCK(obj);
886 
887     buffer_free(&ioc->encinput);
888     buffer_free(&ioc->encoutput);
889     buffer_free(&ioc->rawinput);
890     buffer_free(&ioc->rawoutput);
891     buffer_free(&ioc->ping_reply);
892     object_unref(OBJECT(ioc->master));
893     if (ioc->io_tag) {
894         g_source_remove(ioc->io_tag);
895     }
896     if (ioc->io_err) {
897         error_free(ioc->io_err);
898     }
899 }
900 
901 
902 static ssize_t qio_channel_websock_read_wire(QIOChannelWebsock *ioc,
903                                              Error **errp)
904 {
905     ssize_t ret;
906 
907     if (ioc->encinput.offset < 4096) {
908         size_t want = 4096 - ioc->encinput.offset;
909 
910         buffer_reserve(&ioc->encinput, want);
911         ret = qio_channel_read(ioc->master,
912                                (char *)ioc->encinput.buffer +
913                                ioc->encinput.offset,
914                                want,
915                                errp);
916         if (ret < 0) {
917             return ret;
918         }
919         if (ret == 0 && ioc->encinput.offset == 0) {
920             ioc->io_eof = TRUE;
921             return 0;
922         }
923         ioc->encinput.offset += ret;
924     }
925 
926     while (ioc->encinput.offset != 0) {
927         if (ioc->payload_remain == 0) {
928             ret = qio_channel_websock_decode_header(ioc, errp);
929             if (ret < 0) {
930                 return ret;
931             }
932         }
933 
934         ret = qio_channel_websock_decode_payload(ioc, errp);
935         if (ret < 0) {
936             return ret;
937         }
938     }
939     return 1;
940 }
941 
942 
943 static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *ioc,
944                                               Error **errp)
945 {
946     ssize_t ret;
947     ssize_t done = 0;
948 
949     /* ping replies take priority over binary data */
950     if (!ioc->ping_reply.offset) {
951         qio_channel_websock_encode(ioc);
952     } else if (!ioc->encoutput.offset) {
953         buffer_move_empty(&ioc->encoutput, &ioc->ping_reply);
954     }
955 
956     while (ioc->encoutput.offset > 0) {
957         ret = qio_channel_write(ioc->master,
958                                 (char *)ioc->encoutput.buffer,
959                                 ioc->encoutput.offset,
960                                 errp);
961         if (ret < 0) {
962             if (ret == QIO_CHANNEL_ERR_BLOCK &&
963                 done > 0) {
964                 return done;
965             } else {
966                 return ret;
967             }
968         }
969         buffer_advance(&ioc->encoutput, ret);
970         done += ret;
971     }
972     return done;
973 }
974 
975 
976 static void qio_channel_websock_flush_free(gpointer user_data)
977 {
978     QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(user_data);
979     object_unref(OBJECT(wioc));
980 }
981 
982 static void qio_channel_websock_set_watch(QIOChannelWebsock *ioc);
983 
984 static gboolean qio_channel_websock_flush(QIOChannel *ioc,
985                                           GIOCondition condition,
986                                           gpointer user_data)
987 {
988     QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(user_data);
989     ssize_t ret;
990 
991     if (condition & G_IO_OUT) {
992         ret = qio_channel_websock_write_wire(wioc, &wioc->io_err);
993         if (ret < 0) {
994             goto cleanup;
995         }
996     }
997 
998     if (condition & G_IO_IN) {
999         ret = qio_channel_websock_read_wire(wioc, &wioc->io_err);
1000         if (ret < 0) {
1001             goto cleanup;
1002         }
1003     }
1004 
1005  cleanup:
1006     qio_channel_websock_set_watch(wioc);
1007     return FALSE;
1008 }
1009 
1010 
1011 static void qio_channel_websock_unset_watch(QIOChannelWebsock *ioc)
1012 {
1013     if (ioc->io_tag) {
1014         g_source_remove(ioc->io_tag);
1015         ioc->io_tag = 0;
1016     }
1017 }
1018 
1019 static void qio_channel_websock_set_watch(QIOChannelWebsock *ioc)
1020 {
1021     GIOCondition cond = 0;
1022 
1023     qio_channel_websock_unset_watch(ioc);
1024 
1025     if (ioc->io_err) {
1026         return;
1027     }
1028 
1029     if (ioc->encoutput.offset || ioc->ping_reply.offset) {
1030         cond |= G_IO_OUT;
1031     }
1032     if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER &&
1033         !ioc->io_eof) {
1034         cond |= G_IO_IN;
1035     }
1036 
1037     if (cond) {
1038         object_ref(OBJECT(ioc));
1039         ioc->io_tag =
1040             qio_channel_add_watch(ioc->master,
1041                                   cond,
1042                                   qio_channel_websock_flush,
1043                                   ioc,
1044                                   qio_channel_websock_flush_free);
1045     }
1046 }
1047 
1048 
1049 static ssize_t qio_channel_websock_readv(QIOChannel *ioc,
1050                                          const struct iovec *iov,
1051                                          size_t niov,
1052                                          int **fds,
1053                                          size_t *nfds,
1054                                          Error **errp)
1055 {
1056     QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
1057     size_t i;
1058     ssize_t got = 0;
1059     ssize_t ret;
1060 
1061     if (wioc->io_err) {
1062         error_propagate(errp, error_copy(wioc->io_err));
1063         return -1;
1064     }
1065 
1066     if (!wioc->rawinput.offset) {
1067         ret = qio_channel_websock_read_wire(QIO_CHANNEL_WEBSOCK(ioc), errp);
1068         if (ret < 0) {
1069             return ret;
1070         }
1071     }
1072 
1073     for (i = 0 ; i < niov ; i++) {
1074         size_t want = iov[i].iov_len;
1075         if (want > (wioc->rawinput.offset - got)) {
1076             want = (wioc->rawinput.offset - got);
1077         }
1078 
1079         memcpy(iov[i].iov_base,
1080                wioc->rawinput.buffer + got,
1081                want);
1082         got += want;
1083 
1084         if (want < iov[i].iov_len) {
1085             break;
1086         }
1087     }
1088 
1089     buffer_advance(&wioc->rawinput, got);
1090     qio_channel_websock_set_watch(wioc);
1091     return got;
1092 }
1093 
1094 
1095 static ssize_t qio_channel_websock_writev(QIOChannel *ioc,
1096                                           const struct iovec *iov,
1097                                           size_t niov,
1098                                           int *fds,
1099                                           size_t nfds,
1100                                           Error **errp)
1101 {
1102     QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
1103     size_t i;
1104     ssize_t done = 0;
1105     ssize_t ret;
1106 
1107     if (wioc->io_err) {
1108         error_propagate(errp, error_copy(wioc->io_err));
1109         return -1;
1110     }
1111 
1112     if (wioc->io_eof) {
1113         error_setg(errp, "%s", "Broken pipe");
1114         return -1;
1115     }
1116 
1117     for (i = 0; i < niov; i++) {
1118         size_t want = iov[i].iov_len;
1119         if ((want + wioc->rawoutput.offset) > QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
1120             want = (QIO_CHANNEL_WEBSOCK_MAX_BUFFER - wioc->rawoutput.offset);
1121         }
1122         if (want == 0) {
1123             goto done;
1124         }
1125 
1126         buffer_reserve(&wioc->rawoutput, want);
1127         buffer_append(&wioc->rawoutput, iov[i].iov_base, want);
1128         done += want;
1129         if (want < iov[i].iov_len) {
1130             break;
1131         }
1132     }
1133 
1134  done:
1135     ret = qio_channel_websock_write_wire(wioc, errp);
1136     if (ret < 0 &&
1137         ret != QIO_CHANNEL_ERR_BLOCK) {
1138         qio_channel_websock_unset_watch(wioc);
1139         return -1;
1140     }
1141 
1142     qio_channel_websock_set_watch(wioc);
1143 
1144     if (done == 0) {
1145         return QIO_CHANNEL_ERR_BLOCK;
1146     }
1147 
1148     return done;
1149 }
1150 
1151 static int qio_channel_websock_set_blocking(QIOChannel *ioc,
1152                                             bool enabled,
1153                                             Error **errp)
1154 {
1155     QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
1156 
1157     qio_channel_set_blocking(wioc->master, enabled, errp);
1158     return 0;
1159 }
1160 
1161 static void qio_channel_websock_set_delay(QIOChannel *ioc,
1162                                           bool enabled)
1163 {
1164     QIOChannelWebsock *tioc = QIO_CHANNEL_WEBSOCK(ioc);
1165 
1166     qio_channel_set_delay(tioc->master, enabled);
1167 }
1168 
1169 static void qio_channel_websock_set_cork(QIOChannel *ioc,
1170                                          bool enabled)
1171 {
1172     QIOChannelWebsock *tioc = QIO_CHANNEL_WEBSOCK(ioc);
1173 
1174     qio_channel_set_cork(tioc->master, enabled);
1175 }
1176 
1177 static int qio_channel_websock_shutdown(QIOChannel *ioc,
1178                                         QIOChannelShutdown how,
1179                                         Error **errp)
1180 {
1181     QIOChannelWebsock *tioc = QIO_CHANNEL_WEBSOCK(ioc);
1182 
1183     return qio_channel_shutdown(tioc->master, how, errp);
1184 }
1185 
1186 static int qio_channel_websock_close(QIOChannel *ioc,
1187                                      Error **errp)
1188 {
1189     QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
1190 
1191     trace_qio_channel_websock_close(ioc);
1192     return qio_channel_close(wioc->master, errp);
1193 }
1194 
1195 typedef struct QIOChannelWebsockSource QIOChannelWebsockSource;
1196 struct QIOChannelWebsockSource {
1197     GSource parent;
1198     QIOChannelWebsock *wioc;
1199     GIOCondition condition;
1200 };
1201 
1202 static gboolean
1203 qio_channel_websock_source_check(GSource *source)
1204 {
1205     QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source;
1206     GIOCondition cond = 0;
1207 
1208     if (wsource->wioc->rawinput.offset || wsource->wioc->io_eof) {
1209         cond |= G_IO_IN;
1210     }
1211     if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
1212         cond |= G_IO_OUT;
1213     }
1214 
1215     return cond & wsource->condition;
1216 }
1217 
1218 static gboolean
1219 qio_channel_websock_source_prepare(GSource *source,
1220                                    gint *timeout)
1221 {
1222     *timeout = -1;
1223     return qio_channel_websock_source_check(source);
1224 }
1225 
1226 static gboolean
1227 qio_channel_websock_source_dispatch(GSource *source,
1228                                     GSourceFunc callback,
1229                                     gpointer user_data)
1230 {
1231     QIOChannelFunc func = (QIOChannelFunc)callback;
1232     QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source;
1233 
1234     return (*func)(QIO_CHANNEL(wsource->wioc),
1235                    qio_channel_websock_source_check(source),
1236                    user_data);
1237 }
1238 
1239 static void
1240 qio_channel_websock_source_finalize(GSource *source)
1241 {
1242     QIOChannelWebsockSource *ssource = (QIOChannelWebsockSource *)source;
1243 
1244     object_unref(OBJECT(ssource->wioc));
1245 }
1246 
1247 GSourceFuncs qio_channel_websock_source_funcs = {
1248     qio_channel_websock_source_prepare,
1249     qio_channel_websock_source_check,
1250     qio_channel_websock_source_dispatch,
1251     qio_channel_websock_source_finalize
1252 };
1253 
1254 static GSource *qio_channel_websock_create_watch(QIOChannel *ioc,
1255                                                  GIOCondition condition)
1256 {
1257     QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
1258     QIOChannelWebsockSource *ssource;
1259     GSource *source;
1260 
1261     source = g_source_new(&qio_channel_websock_source_funcs,
1262                           sizeof(QIOChannelWebsockSource));
1263     ssource = (QIOChannelWebsockSource *)source;
1264 
1265     ssource->wioc = wioc;
1266     object_ref(OBJECT(wioc));
1267 
1268     ssource->condition = condition;
1269 
1270     qio_channel_websock_set_watch(wioc);
1271     return source;
1272 }
1273 
1274 static void qio_channel_websock_class_init(ObjectClass *klass,
1275                                            void *class_data G_GNUC_UNUSED)
1276 {
1277     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
1278 
1279     ioc_klass->io_writev = qio_channel_websock_writev;
1280     ioc_klass->io_readv = qio_channel_websock_readv;
1281     ioc_klass->io_set_blocking = qio_channel_websock_set_blocking;
1282     ioc_klass->io_set_cork = qio_channel_websock_set_cork;
1283     ioc_klass->io_set_delay = qio_channel_websock_set_delay;
1284     ioc_klass->io_close = qio_channel_websock_close;
1285     ioc_klass->io_shutdown = qio_channel_websock_shutdown;
1286     ioc_klass->io_create_watch = qio_channel_websock_create_watch;
1287 }
1288 
1289 static const TypeInfo qio_channel_websock_info = {
1290     .parent = TYPE_QIO_CHANNEL,
1291     .name = TYPE_QIO_CHANNEL_WEBSOCK,
1292     .instance_size = sizeof(QIOChannelWebsock),
1293     .instance_finalize = qio_channel_websock_finalize,
1294     .class_init = qio_channel_websock_class_init,
1295 };
1296 
1297 static void qio_channel_websock_register_types(void)
1298 {
1299     type_register_static(&qio_channel_websock_info);
1300 }
1301 
1302 type_init(qio_channel_websock_register_types);
1303