qemu/io/channel-websock.c
<<
>>
Prefs
   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 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
 126typedef struct QIOChannelWebsockHeader QIOChannelWebsockHeader;
 127
 128struct 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
 144typedef struct QIOChannelWebsockHTTPHeader QIOChannelWebsockHTTPHeader;
 145
 146struct QIOChannelWebsockHTTPHeader {
 147    char *name;
 148    char *value;
 149};
 150
 151enum {
 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
 160static void GCC_FMT_ATTR(2, 3)
 161qio_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
 178static 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
 185static 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
 193enum {
 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
 202static size_t
 203qio_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
 321static const char *
 322qio_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
 338static 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
 379static 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
 484static 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
 529static 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
 569static 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
 610static 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
 655static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *, Error **);
 656
 657
 658static 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
 682static 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
 791static 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
 876QIOChannelWebsock *
 877qio_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
 895void 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
 917static 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
 934static 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
 975static 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
1006static 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
1012static void qio_channel_websock_set_watch(QIOChannelWebsock *ioc);
1013
1014static 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
1041static 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
1049static 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
1079static 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
1125static 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                                          Error **errp)
1131{
1132    QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
1133    ssize_t want = iov_size(iov, niov);
1134    ssize_t avail;
1135    ssize_t ret;
1136
1137    if (wioc->io_err) {
1138        error_propagate(errp, error_copy(wioc->io_err));
1139        return -1;
1140    }
1141
1142    if (wioc->io_eof) {
1143        error_setg(errp, "%s", "Broken pipe");
1144        return -1;
1145    }
1146
1147    avail = wioc->encoutput.offset >= QIO_CHANNEL_WEBSOCK_MAX_BUFFER ?
1148        0 : (QIO_CHANNEL_WEBSOCK_MAX_BUFFER - wioc->encoutput.offset);
1149    if (want > avail) {
1150        want = avail;
1151    }
1152
1153    if (want) {
1154        qio_channel_websock_encode(wioc,
1155                                   QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME,
1156                                   iov, niov, want);
1157    }
1158
1159    /* Even if want == 0, we'll try write_wire in case there's
1160     * pending data we could usefully flush out
1161     */
1162    ret = qio_channel_websock_write_wire(wioc, errp);
1163    if (ret < 0 &&
1164        ret != QIO_CHANNEL_ERR_BLOCK) {
1165        qio_channel_websock_unset_watch(wioc);
1166        return -1;
1167    }
1168
1169    qio_channel_websock_set_watch(wioc);
1170
1171    if (want == 0) {
1172        return QIO_CHANNEL_ERR_BLOCK;
1173    }
1174
1175    return want;
1176}
1177
1178static int qio_channel_websock_set_blocking(QIOChannel *ioc,
1179                                            bool enabled,
1180                                            Error **errp)
1181{
1182    QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
1183
1184    qio_channel_set_blocking(wioc->master, enabled, errp);
1185    return 0;
1186}
1187
1188static void qio_channel_websock_set_delay(QIOChannel *ioc,
1189                                          bool enabled)
1190{
1191    QIOChannelWebsock *tioc = QIO_CHANNEL_WEBSOCK(ioc);
1192
1193    qio_channel_set_delay(tioc->master, enabled);
1194}
1195
1196static void qio_channel_websock_set_cork(QIOChannel *ioc,
1197                                         bool enabled)
1198{
1199    QIOChannelWebsock *tioc = QIO_CHANNEL_WEBSOCK(ioc);
1200
1201    qio_channel_set_cork(tioc->master, enabled);
1202}
1203
1204static int qio_channel_websock_shutdown(QIOChannel *ioc,
1205                                        QIOChannelShutdown how,
1206                                        Error **errp)
1207{
1208    QIOChannelWebsock *tioc = QIO_CHANNEL_WEBSOCK(ioc);
1209
1210    return qio_channel_shutdown(tioc->master, how, errp);
1211}
1212
1213static int qio_channel_websock_close(QIOChannel *ioc,
1214                                     Error **errp)
1215{
1216    QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
1217
1218    trace_qio_channel_websock_close(ioc);
1219    return qio_channel_close(wioc->master, errp);
1220}
1221
1222typedef struct QIOChannelWebsockSource QIOChannelWebsockSource;
1223struct QIOChannelWebsockSource {
1224    GSource parent;
1225    QIOChannelWebsock *wioc;
1226    GIOCondition condition;
1227};
1228
1229static gboolean
1230qio_channel_websock_source_check(GSource *source)
1231{
1232    QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source;
1233    GIOCondition cond = 0;
1234
1235    if (wsource->wioc->rawinput.offset) {
1236        cond |= G_IO_IN;
1237    }
1238    if (wsource->wioc->encoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
1239        cond |= G_IO_OUT;
1240    }
1241    if (wsource->wioc->io_eof) {
1242        cond |= G_IO_HUP;
1243    }
1244    if (wsource->wioc->io_err) {
1245        cond |= G_IO_ERR;
1246    }
1247
1248    return cond & wsource->condition;
1249}
1250
1251static gboolean
1252qio_channel_websock_source_prepare(GSource *source,
1253                                   gint *timeout)
1254{
1255    *timeout = -1;
1256    return qio_channel_websock_source_check(source);
1257}
1258
1259static gboolean
1260qio_channel_websock_source_dispatch(GSource *source,
1261                                    GSourceFunc callback,
1262                                    gpointer user_data)
1263{
1264    QIOChannelFunc func = (QIOChannelFunc)callback;
1265    QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source;
1266
1267    return (*func)(QIO_CHANNEL(wsource->wioc),
1268                   qio_channel_websock_source_check(source),
1269                   user_data);
1270}
1271
1272static void
1273qio_channel_websock_source_finalize(GSource *source)
1274{
1275    QIOChannelWebsockSource *ssource = (QIOChannelWebsockSource *)source;
1276
1277    object_unref(OBJECT(ssource->wioc));
1278}
1279
1280GSourceFuncs qio_channel_websock_source_funcs = {
1281    qio_channel_websock_source_prepare,
1282    qio_channel_websock_source_check,
1283    qio_channel_websock_source_dispatch,
1284    qio_channel_websock_source_finalize
1285};
1286
1287static GSource *qio_channel_websock_create_watch(QIOChannel *ioc,
1288                                                 GIOCondition condition)
1289{
1290    QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
1291    QIOChannelWebsockSource *ssource;
1292    GSource *source;
1293
1294    source = g_source_new(&qio_channel_websock_source_funcs,
1295                          sizeof(QIOChannelWebsockSource));
1296    ssource = (QIOChannelWebsockSource *)source;
1297
1298    ssource->wioc = wioc;
1299    object_ref(OBJECT(wioc));
1300
1301    ssource->condition = condition;
1302
1303    qio_channel_websock_set_watch(wioc);
1304    return source;
1305}
1306
1307static void qio_channel_websock_class_init(ObjectClass *klass,
1308                                           void *class_data G_GNUC_UNUSED)
1309{
1310    QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
1311
1312    ioc_klass->io_writev = qio_channel_websock_writev;
1313    ioc_klass->io_readv = qio_channel_websock_readv;
1314    ioc_klass->io_set_blocking = qio_channel_websock_set_blocking;
1315    ioc_klass->io_set_cork = qio_channel_websock_set_cork;
1316    ioc_klass->io_set_delay = qio_channel_websock_set_delay;
1317    ioc_klass->io_close = qio_channel_websock_close;
1318    ioc_klass->io_shutdown = qio_channel_websock_shutdown;
1319    ioc_klass->io_create_watch = qio_channel_websock_create_watch;
1320}
1321
1322static const TypeInfo qio_channel_websock_info = {
1323    .parent = TYPE_QIO_CHANNEL,
1324    .name = TYPE_QIO_CHANNEL_WEBSOCK,
1325    .instance_size = sizeof(QIOChannelWebsock),
1326    .instance_finalize = qio_channel_websock_finalize,
1327    .class_init = qio_channel_websock_class_init,
1328};
1329
1330static void qio_channel_websock_register_types(void)
1331{
1332    type_register_static(&qio_channel_websock_info);
1333}
1334
1335type_init(qio_channel_websock_register_types);
1336