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