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#include <time.h>
  30
  31
  32/* Max amount to allow in rawinput/encoutput buffers */
  33#define QIO_CHANNEL_WEBSOCK_MAX_BUFFER 8192
  34
  35#define QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN 24
  36#define QIO_CHANNEL_WEBSOCK_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
  37#define QIO_CHANNEL_WEBSOCK_GUID_LEN strlen(QIO_CHANNEL_WEBSOCK_GUID)
  38
  39#define QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL "sec-websocket-protocol"
  40#define QIO_CHANNEL_WEBSOCK_HEADER_VERSION "sec-websocket-version"
  41#define QIO_CHANNEL_WEBSOCK_HEADER_KEY "sec-websocket-key"
  42#define QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE "upgrade"
  43#define QIO_CHANNEL_WEBSOCK_HEADER_HOST "host"
  44#define QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION "connection"
  45
  46#define QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY "binary"
  47#define QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE "Upgrade"
  48#define QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET "websocket"
  49
  50#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \
  51    "Server: QEMU VNC\r\n"                       \
  52    "Date: %s\r\n"
  53
  54#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK    \
  55    "HTTP/1.1 101 Switching Protocols\r\n"      \
  56    QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON    \
  57    "Upgrade: websocket\r\n"                    \
  58    "Connection: Upgrade\r\n"                   \
  59    "Sec-WebSocket-Accept: %s\r\n"              \
  60    "Sec-WebSocket-Protocol: binary\r\n"        \
  61    "\r\n"
  62#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_NOT_FOUND \
  63    "HTTP/1.1 404 Not Found\r\n"                    \
  64    QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON        \
  65    "Connection: close\r\n"                         \
  66    "\r\n"
  67#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST \
  68    "HTTP/1.1 400 Bad Request\r\n"                    \
  69    QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON          \
  70    "Connection: close\r\n"                           \
  71    "Sec-WebSocket-Version: "                         \
  72    QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION             \
  73    "\r\n"
  74#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR \
  75    "HTTP/1.1 500 Internal Server Error\r\n"         \
  76    QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON         \
  77    "Connection: close\r\n"                          \
  78    "\r\n"
  79#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE  \
  80    "HTTP/1.1 403 Request Entity Too Large\r\n"      \
  81    QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON         \
  82    "Connection: close\r\n"                          \
  83    "\r\n"
  84#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM "\r\n"
  85#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_END "\r\n\r\n"
  86#define QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION "13"
  87#define QIO_CHANNEL_WEBSOCK_HTTP_METHOD "GET"
  88#define QIO_CHANNEL_WEBSOCK_HTTP_PATH "/"
  89#define QIO_CHANNEL_WEBSOCK_HTTP_VERSION "HTTP/1.1"
  90
  91/* The websockets packet header is variable length
  92 * depending on the size of the payload... */
  93
  94/* ...length when using 7-bit payload length */
  95#define QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT 6
  96/* ...length when using 16-bit payload length */
  97#define QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT 8
  98/* ...length when using 64-bit payload length */
  99#define QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT 14
 100
 101/* Length of the optional data mask field in header */
 102#define QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK 4
 103
 104/* Maximum length that can fit in 7-bit payload size */
 105#define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT 126
 106/* Maximum length that can fit in 16-bit payload size */
 107#define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_16_BIT 65536
 108
 109/* Magic 7-bit length to indicate use of 16-bit payload length */
 110#define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT 126
 111/* Magic 7-bit length to indicate use of 64-bit payload length */
 112#define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT 127
 113
 114/* Bitmasks for accessing header fields */
 115#define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN 0x80
 116#define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE 0x0f
 117#define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK 0x80
 118#define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN 0x7f
 119#define QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK 0x8
 120
 121typedef struct QIOChannelWebsockHeader QIOChannelWebsockHeader;
 122
 123struct QEMU_PACKED QIOChannelWebsockHeader {
 124    unsigned char b0;
 125    unsigned char b1;
 126    union {
 127        struct QEMU_PACKED {
 128            uint16_t l16;
 129            QIOChannelWebsockMask m16;
 130        } s16;
 131        struct QEMU_PACKED {
 132            uint64_t l64;
 133            QIOChannelWebsockMask m64;
 134        } s64;
 135        QIOChannelWebsockMask m;
 136    } u;
 137};
 138
 139typedef struct QIOChannelWebsockHTTPHeader QIOChannelWebsockHTTPHeader;
 140
 141struct QIOChannelWebsockHTTPHeader {
 142    char *name;
 143    char *value;
 144};
 145
 146enum {
 147    QIO_CHANNEL_WEBSOCK_OPCODE_CONTINUATION = 0x0,
 148    QIO_CHANNEL_WEBSOCK_OPCODE_TEXT_FRAME = 0x1,
 149    QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME = 0x2,
 150    QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE = 0x8,
 151    QIO_CHANNEL_WEBSOCK_OPCODE_PING = 0x9,
 152    QIO_CHANNEL_WEBSOCK_OPCODE_PONG = 0xA
 153};
 154
 155static void GCC_FMT_ATTR(2, 3)
 156qio_channel_websock_handshake_send_res(QIOChannelWebsock *ioc,
 157                                       const char *resmsg,
 158                                       ...)
 159{
 160    va_list vargs;
 161    char *response;
 162    size_t responselen;
 163
 164    va_start(vargs, resmsg);
 165    response = g_strdup_vprintf(resmsg, vargs);
 166    responselen = strlen(response);
 167    buffer_reserve(&ioc->encoutput, responselen);
 168    buffer_append(&ioc->encoutput, response, responselen);
 169    va_end(vargs);
 170}
 171
 172static gchar *qio_channel_websock_date_str(void)
 173{
 174    struct tm tm;
 175    time_t now = time(NULL);
 176    char datebuf[128];
 177
 178    gmtime_r(&now, &tm);
 179
 180    strftime(datebuf, sizeof(datebuf), "%a, %d %b %Y %H:%M:%S GMT", &tm);
 181
 182    return g_strdup(datebuf);
 183}
 184
 185static void qio_channel_websock_handshake_send_res_err(QIOChannelWebsock *ioc,
 186                                                       const char *resdata)
 187{
 188    char *date = qio_channel_websock_date_str();
 189    qio_channel_websock_handshake_send_res(ioc, resdata, date);
 190    g_free(date);
 191}
 192
 193enum {
 194    QIO_CHANNEL_WEBSOCK_STATUS_NORMAL = 1000,
 195    QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR = 1002,
 196    QIO_CHANNEL_WEBSOCK_STATUS_INVALID_DATA = 1003,
 197    QIO_CHANNEL_WEBSOCK_STATUS_POLICY = 1008,
 198    QIO_CHANNEL_WEBSOCK_STATUS_TOO_LARGE = 1009,
 199    QIO_CHANNEL_WEBSOCK_STATUS_SERVER_ERR = 1011,
 200};
 201
 202static size_t
 203qio_channel_websock_extract_headers(QIOChannelWebsock *ioc,
 204                                    char *buffer,
 205                                    QIOChannelWebsockHTTPHeader *hdrs,
 206                                    size_t nhdrsalloc,
 207                                    Error **errp)
 208{
 209    char *nl, *sep, *tmp;
 210    size_t nhdrs = 0;
 211
 212    /*
 213     * First parse the HTTP protocol greeting of format:
 214     *
 215     *   $METHOD $PATH $VERSION
 216     *
 217     * e.g.
 218     *
 219     *   GET / HTTP/1.1
 220     */
 221
 222    nl = strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
 223    if (!nl) {
 224        error_setg(errp, "Missing HTTP header delimiter");
 225        goto bad_request;
 226    }
 227    *nl = '\0';
 228    trace_qio_channel_websock_http_greeting(ioc, buffer);
 229
 230    tmp = strchr(buffer, ' ');
 231    if (!tmp) {
 232        error_setg(errp, "Missing HTTP path delimiter");
 233        return 0;
 234    }
 235    *tmp = '\0';
 236
 237    if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_METHOD)) {
 238        error_setg(errp, "Unsupported HTTP method %s", buffer);
 239        goto bad_request;
 240    }
 241
 242    buffer = tmp + 1;
 243    tmp = strchr(buffer, ' ');
 244    if (!tmp) {
 245        error_setg(errp, "Missing HTTP version delimiter");
 246        goto bad_request;
 247    }
 248    *tmp = '\0';
 249
 250    if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_PATH)) {
 251        qio_channel_websock_handshake_send_res_err(
 252            ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_NOT_FOUND);
 253        error_setg(errp, "Unexpected HTTP path %s", buffer);
 254        return 0;
 255    }
 256
 257    buffer = tmp + 1;
 258
 259    if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_VERSION)) {
 260        error_setg(errp, "Unsupported HTTP version %s", buffer);
 261        goto bad_request;
 262    }
 263
 264    buffer = nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
 265
 266    /*
 267     * Now parse all the header fields of format
 268     *
 269     *   $NAME: $VALUE
 270     *
 271     * e.g.
 272     *
 273     *   Cache-control: no-cache
 274     */
 275    do {
 276        QIOChannelWebsockHTTPHeader *hdr;
 277
 278        nl = strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
 279        if (nl) {
 280            *nl = '\0';
 281        }
 282
 283        sep = strchr(buffer, ':');
 284        if (!sep) {
 285            error_setg(errp, "Malformed HTTP header");
 286            goto bad_request;
 287        }
 288        *sep = '\0';
 289        sep++;
 290        while (*sep == ' ') {
 291            sep++;
 292        }
 293
 294        if (nhdrs >= nhdrsalloc) {
 295            error_setg(errp, "Too many HTTP headers");
 296            goto bad_request;
 297        }
 298
 299        hdr = &hdrs[nhdrs++];
 300        hdr->name = buffer;
 301        hdr->value = sep;
 302
 303        /* Canonicalize header name for easier identification later */
 304        for (tmp = hdr->name; *tmp; tmp++) {
 305            *tmp = g_ascii_tolower(*tmp);
 306        }
 307
 308        if (nl) {
 309            buffer = nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
 310        }
 311    } while (nl != NULL);
 312
 313    return nhdrs;
 314
 315 bad_request:
 316    qio_channel_websock_handshake_send_res_err(
 317        ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST);
 318    return 0;
 319}
 320
 321static const char *
 322qio_channel_websock_find_header(QIOChannelWebsockHTTPHeader *hdrs,
 323                                size_t nhdrs,
 324                                const char *name)
 325{
 326    size_t i;
 327
 328    for (i = 0; i < nhdrs; i++) {
 329        if (g_str_equal(hdrs[i].name, name)) {
 330            return hdrs[i].value;
 331        }
 332    }
 333
 334    return NULL;
 335}
 336
 337
 338static void qio_channel_websock_handshake_send_res_ok(QIOChannelWebsock *ioc,
 339                                                      const char *key,
 340                                                      Error **errp)
 341{
 342    char combined_key[QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN +
 343                      QIO_CHANNEL_WEBSOCK_GUID_LEN + 1];
 344    char *accept = NULL;
 345    char *date = NULL;
 346
 347    g_strlcpy(combined_key, key, QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 1);
 348    g_strlcat(combined_key, QIO_CHANNEL_WEBSOCK_GUID,
 349              QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN +
 350              QIO_CHANNEL_WEBSOCK_GUID_LEN + 1);
 351
 352    /* hash and encode it */
 353    if (qcrypto_hash_base64(QCRYPTO_HASH_ALG_SHA1,
 354                            combined_key,
 355                            QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN +
 356                            QIO_CHANNEL_WEBSOCK_GUID_LEN,
 357                            &accept,
 358                            errp) < 0) {
 359        qio_channel_websock_handshake_send_res_err(
 360            ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR);
 361        return;
 362    }
 363
 364    date = qio_channel_websock_date_str();
 365    qio_channel_websock_handshake_send_res(
 366        ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK, date, accept);
 367
 368    g_free(date);
 369    g_free(accept);
 370}
 371
 372static void qio_channel_websock_handshake_process(QIOChannelWebsock *ioc,
 373                                                  char *buffer,
 374                                                  Error **errp)
 375{
 376    QIOChannelWebsockHTTPHeader hdrs[32];
 377    size_t nhdrs = G_N_ELEMENTS(hdrs);
 378    const char *protocols = NULL, *version = NULL, *key = NULL,
 379        *host = NULL, *connection = NULL, *upgrade = NULL;
 380    char **connectionv;
 381    bool upgraded = false;
 382    size_t i;
 383
 384    nhdrs = qio_channel_websock_extract_headers(ioc, buffer, hdrs, nhdrs, errp);
 385    if (!nhdrs) {
 386        return;
 387    }
 388
 389    protocols = qio_channel_websock_find_header(
 390        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL);
 391    if (!protocols) {
 392        error_setg(errp, "Missing websocket protocol header data");
 393        goto bad_request;
 394    }
 395
 396    version = qio_channel_websock_find_header(
 397        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_VERSION);
 398    if (!version) {
 399        error_setg(errp, "Missing websocket version header data");
 400        goto bad_request;
 401    }
 402
 403    key = qio_channel_websock_find_header(
 404        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_KEY);
 405    if (!key) {
 406        error_setg(errp, "Missing websocket key header data");
 407        goto bad_request;
 408    }
 409
 410    host = qio_channel_websock_find_header(
 411        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_HOST);
 412    if (!host) {
 413        error_setg(errp, "Missing websocket host header data");
 414        goto bad_request;
 415    }
 416
 417    connection = qio_channel_websock_find_header(
 418        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION);
 419    if (!connection) {
 420        error_setg(errp, "Missing websocket connection header data");
 421        goto bad_request;
 422    }
 423
 424    upgrade = qio_channel_websock_find_header(
 425        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE);
 426    if (!upgrade) {
 427        error_setg(errp, "Missing websocket upgrade header data");
 428        goto bad_request;
 429    }
 430
 431    trace_qio_channel_websock_http_request(ioc, protocols, version,
 432                                           host, connection, upgrade, key);
 433
 434    if (!g_strrstr(protocols, QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY)) {
 435        error_setg(errp, "No '%s' protocol is supported by client '%s'",
 436                   QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY, protocols);
 437        goto bad_request;
 438    }
 439
 440    if (!g_str_equal(version, QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION)) {
 441        error_setg(errp, "Version '%s' is not supported by client '%s'",
 442                   QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION, version);
 443        goto bad_request;
 444    }
 445
 446    if (strlen(key) != QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN) {
 447        error_setg(errp, "Key length '%zu' was not as expected '%d'",
 448                   strlen(key), QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN);
 449        goto bad_request;
 450    }
 451
 452    connectionv = g_strsplit(connection, ",", 0);
 453    for (i = 0; connectionv != NULL && connectionv[i] != NULL; i++) {
 454        g_strstrip(connectionv[i]);
 455        if (strcasecmp(connectionv[i],
 456                       QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE) == 0) {
 457            upgraded = true;
 458        }
 459    }
 460    g_strfreev(connectionv);
 461    if (!upgraded) {
 462        error_setg(errp, "No connection upgrade requested '%s'", connection);
 463        goto bad_request;
 464    }
 465
 466    if (strcasecmp(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET) != 0) {
 467        error_setg(errp, "Incorrect upgrade method '%s'", upgrade);
 468        goto bad_request;
 469    }
 470
 471    qio_channel_websock_handshake_send_res_ok(ioc, key, errp);
 472    return;
 473
 474 bad_request:
 475    qio_channel_websock_handshake_send_res_err(
 476        ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST);
 477}
 478
 479static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc,
 480                                              Error **errp)
 481{
 482    char *handshake_end;
 483    ssize_t ret;
 484    /* Typical HTTP headers from novnc are 512 bytes, so limiting
 485     * total header size to 4096 is easily enough. */
 486    size_t want = 4096 - ioc->encinput.offset;
 487    buffer_reserve(&ioc->encinput, want);
 488    ret = qio_channel_read(ioc->master,
 489                           (char *)buffer_end(&ioc->encinput), want, errp);
 490    if (ret < 0) {
 491        return -1;
 492    }
 493    ioc->encinput.offset += ret;
 494
 495    handshake_end = g_strstr_len((char *)ioc->encinput.buffer,
 496                                 ioc->encinput.offset,
 497                                 QIO_CHANNEL_WEBSOCK_HANDSHAKE_END);
 498    if (!handshake_end) {
 499        if (ioc->encinput.offset >= 4096) {
 500            qio_channel_websock_handshake_send_res_err(
 501                ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE);
 502            error_setg(errp,
 503                       "End of headers not found in first 4096 bytes");
 504            return 1;
 505        } else {
 506            return 0;
 507        }
 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    if (err) {
 590        error_propagate(&wioc->io_err, err);
 591    }
 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 || wsource->wioc->io_eof) {
1230        cond |= G_IO_IN;
1231    }
1232    if (wsource->wioc->encoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
1233        cond |= G_IO_OUT;
1234    }
1235
1236    return cond & wsource->condition;
1237}
1238
1239static gboolean
1240qio_channel_websock_source_prepare(GSource *source,
1241                                   gint *timeout)
1242{
1243    *timeout = -1;
1244    return qio_channel_websock_source_check(source);
1245}
1246
1247static gboolean
1248qio_channel_websock_source_dispatch(GSource *source,
1249                                    GSourceFunc callback,
1250                                    gpointer user_data)
1251{
1252    QIOChannelFunc func = (QIOChannelFunc)callback;
1253    QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source;
1254
1255    return (*func)(QIO_CHANNEL(wsource->wioc),
1256                   qio_channel_websock_source_check(source),
1257                   user_data);
1258}
1259
1260static void
1261qio_channel_websock_source_finalize(GSource *source)
1262{
1263    QIOChannelWebsockSource *ssource = (QIOChannelWebsockSource *)source;
1264
1265    object_unref(OBJECT(ssource->wioc));
1266}
1267
1268GSourceFuncs qio_channel_websock_source_funcs = {
1269    qio_channel_websock_source_prepare,
1270    qio_channel_websock_source_check,
1271    qio_channel_websock_source_dispatch,
1272    qio_channel_websock_source_finalize
1273};
1274
1275static GSource *qio_channel_websock_create_watch(QIOChannel *ioc,
1276                                                 GIOCondition condition)
1277{
1278    QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
1279    QIOChannelWebsockSource *ssource;
1280    GSource *source;
1281
1282    source = g_source_new(&qio_channel_websock_source_funcs,
1283                          sizeof(QIOChannelWebsockSource));
1284    ssource = (QIOChannelWebsockSource *)source;
1285
1286    ssource->wioc = wioc;
1287    object_ref(OBJECT(wioc));
1288
1289    ssource->condition = condition;
1290
1291    qio_channel_websock_set_watch(wioc);
1292    return source;
1293}
1294
1295static void qio_channel_websock_class_init(ObjectClass *klass,
1296                                           void *class_data G_GNUC_UNUSED)
1297{
1298    QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
1299
1300    ioc_klass->io_writev = qio_channel_websock_writev;
1301    ioc_klass->io_readv = qio_channel_websock_readv;
1302    ioc_klass->io_set_blocking = qio_channel_websock_set_blocking;
1303    ioc_klass->io_set_cork = qio_channel_websock_set_cork;
1304    ioc_klass->io_set_delay = qio_channel_websock_set_delay;
1305    ioc_klass->io_close = qio_channel_websock_close;
1306    ioc_klass->io_shutdown = qio_channel_websock_shutdown;
1307    ioc_klass->io_create_watch = qio_channel_websock_create_watch;
1308}
1309
1310static const TypeInfo qio_channel_websock_info = {
1311    .parent = TYPE_QIO_CHANNEL,
1312    .name = TYPE_QIO_CHANNEL_WEBSOCK,
1313    .instance_size = sizeof(QIOChannelWebsock),
1314    .instance_finalize = qio_channel_websock_finalize,
1315    .class_init = qio_channel_websock_class_init,
1316};
1317
1318static void qio_channel_websock_register_types(void)
1319{
1320    type_register_static(&qio_channel_websock_info);
1321}
1322
1323type_init(qio_channel_websock_register_types);
1324