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