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