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