qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

channel-websock.c (43253B)


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