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 (sizeof(QIO_CHANNEL_WEBSOCK_GUID) - 1) 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 G_GNUC_PRINTF(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 g_autoptr(GDateTime) now = g_date_time_new_now_utc(); 181 182 return g_date_time_format(now, "%a, %d %b %Y %H:%M:%S GMT"); 183 } 184 185 static 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 193 enum { 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 202 static size_t 203 qio_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 321 static const char * 322 qio_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 338 static void qio_channel_websock_handshake_send_res_ok(QIOChannelWebsock *ioc, 339 const char *key, 340 const bool use_protocols, 341 Error **errp) 342 { 343 char combined_key[QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 344 QIO_CHANNEL_WEBSOCK_GUID_LEN + 1]; 345 char *accept = NULL; 346 char *date = NULL; 347 348 g_strlcpy(combined_key, key, QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 1); 349 g_strlcat(combined_key, QIO_CHANNEL_WEBSOCK_GUID, 350 QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 351 QIO_CHANNEL_WEBSOCK_GUID_LEN + 1); 352 353 /* hash and encode it */ 354 if (qcrypto_hash_base64(QCRYPTO_HASH_ALGO_SHA1, 355 combined_key, 356 QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 357 QIO_CHANNEL_WEBSOCK_GUID_LEN, 358 &accept, 359 errp) < 0) { 360 qio_channel_websock_handshake_send_res_err( 361 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR); 362 return; 363 } 364 365 date = qio_channel_websock_date_str(); 366 if (use_protocols) { 367 qio_channel_websock_handshake_send_res( 368 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_WITH_PROTO_RES_OK, 369 date, accept); 370 } else { 371 qio_channel_websock_handshake_send_res( 372 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK, date, accept); 373 } 374 375 g_free(date); 376 g_free(accept); 377 } 378 379 static void qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, 380 char *buffer, 381 Error **errp) 382 { 383 QIOChannelWebsockHTTPHeader hdrs[32]; 384 size_t nhdrs = G_N_ELEMENTS(hdrs); 385 const char *protocols = NULL, *version = NULL, *key = NULL, 386 *host = NULL, *connection = NULL, *upgrade = NULL; 387 char **connectionv; 388 bool upgraded = false; 389 size_t i; 390 391 nhdrs = qio_channel_websock_extract_headers(ioc, buffer, hdrs, nhdrs, errp); 392 if (!nhdrs) { 393 return; 394 } 395 396 protocols = qio_channel_websock_find_header( 397 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL); 398 399 version = qio_channel_websock_find_header( 400 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_VERSION); 401 if (!version) { 402 error_setg(errp, "Missing websocket version header data"); 403 goto bad_request; 404 } 405 406 key = qio_channel_websock_find_header( 407 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_KEY); 408 if (!key) { 409 error_setg(errp, "Missing websocket key header data"); 410 goto bad_request; 411 } 412 413 host = qio_channel_websock_find_header( 414 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_HOST); 415 if (!host) { 416 error_setg(errp, "Missing websocket host header data"); 417 goto bad_request; 418 } 419 420 connection = qio_channel_websock_find_header( 421 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION); 422 if (!connection) { 423 error_setg(errp, "Missing websocket connection header data"); 424 goto bad_request; 425 } 426 427 upgrade = qio_channel_websock_find_header( 428 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE); 429 if (!upgrade) { 430 error_setg(errp, "Missing websocket upgrade header data"); 431 goto bad_request; 432 } 433 434 trace_qio_channel_websock_http_request(ioc, protocols, version, 435 host, connection, upgrade, key); 436 437 if (protocols) { 438 if (!g_strrstr(protocols, QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY)) { 439 error_setg(errp, "No '%s' protocol is supported by client '%s'", 440 QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY, protocols); 441 goto bad_request; 442 } 443 } 444 445 if (!g_str_equal(version, QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION)) { 446 error_setg(errp, "Version '%s' is not supported by client '%s'", 447 QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION, version); 448 goto bad_request; 449 } 450 451 if (strlen(key) != QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN) { 452 error_setg(errp, "Key length '%zu' was not as expected '%d'", 453 strlen(key), QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN); 454 goto bad_request; 455 } 456 457 connectionv = g_strsplit(connection, ",", 0); 458 for (i = 0; connectionv != NULL && connectionv[i] != NULL; i++) { 459 g_strstrip(connectionv[i]); 460 if (strcasecmp(connectionv[i], 461 QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE) == 0) { 462 upgraded = true; 463 } 464 } 465 g_strfreev(connectionv); 466 if (!upgraded) { 467 error_setg(errp, "No connection upgrade requested '%s'", connection); 468 goto bad_request; 469 } 470 471 if (strcasecmp(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET) != 0) { 472 error_setg(errp, "Incorrect upgrade method '%s'", upgrade); 473 goto bad_request; 474 } 475 476 qio_channel_websock_handshake_send_res_ok(ioc, key, !!protocols, errp); 477 return; 478 479 bad_request: 480 qio_channel_websock_handshake_send_res_err( 481 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST); 482 } 483 484 static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc, 485 Error **errp) 486 { 487 char *handshake_end; 488 ssize_t ret; 489 /* Typical HTTP headers from novnc are 512 bytes, so limiting 490 * total header size to 4096 is easily enough. */ 491 size_t want = 4096 - ioc->encinput.offset; 492 buffer_reserve(&ioc->encinput, want); 493 ret = qio_channel_read(ioc->master, 494 (char *)buffer_end(&ioc->encinput), want, errp); 495 if (ret < 0) { 496 return -1; 497 } 498 ioc->encinput.offset += ret; 499 500 handshake_end = g_strstr_len((char *)ioc->encinput.buffer, 501 ioc->encinput.offset, 502 QIO_CHANNEL_WEBSOCK_HANDSHAKE_END); 503 if (!handshake_end) { 504 if (ioc->encinput.offset >= 4096) { 505 qio_channel_websock_handshake_send_res_err( 506 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE); 507 error_setg(errp, 508 "End of headers not found in first 4096 bytes"); 509 return 1; 510 } else if (ret == 0) { 511 error_setg(errp, 512 "End of headers not found before connection closed"); 513 return -1; 514 } 515 return 0; 516 } 517 *handshake_end = '\0'; 518 519 qio_channel_websock_handshake_process(ioc, 520 (char *)ioc->encinput.buffer, 521 errp); 522 523 buffer_advance(&ioc->encinput, 524 handshake_end - (char *)ioc->encinput.buffer + 525 strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_END)); 526 return 1; 527 } 528 529 static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc, 530 GIOCondition condition, 531 gpointer user_data) 532 { 533 QIOTask *task = user_data; 534 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK( 535 qio_task_get_source(task)); 536 Error *err = NULL; 537 ssize_t ret; 538 539 ret = qio_channel_write(wioc->master, 540 (char *)wioc->encoutput.buffer, 541 wioc->encoutput.offset, 542 &err); 543 544 if (ret < 0) { 545 trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); 546 qio_task_set_error(task, err); 547 qio_task_complete(task); 548 return FALSE; 549 } 550 551 buffer_advance(&wioc->encoutput, ret); 552 if (wioc->encoutput.offset == 0) { 553 if (wioc->io_err) { 554 trace_qio_channel_websock_handshake_fail( 555 ioc, error_get_pretty(wioc->io_err)); 556 qio_task_set_error(task, wioc->io_err); 557 wioc->io_err = NULL; 558 qio_task_complete(task); 559 } else { 560 trace_qio_channel_websock_handshake_complete(ioc); 561 qio_task_complete(task); 562 } 563 return FALSE; 564 } 565 trace_qio_channel_websock_handshake_pending(ioc, G_IO_OUT); 566 return TRUE; 567 } 568 569 static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, 570 GIOCondition condition, 571 gpointer user_data) 572 { 573 QIOTask *task = user_data; 574 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK( 575 qio_task_get_source(task)); 576 Error *err = NULL; 577 int ret; 578 579 ret = qio_channel_websock_handshake_read(wioc, &err); 580 if (ret < 0) { 581 /* 582 * We only take this path on a fatal I/O error reading from 583 * client connection, as most of the time we have an 584 * HTTP 4xx err response to send instead 585 */ 586 trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); 587 qio_task_set_error(task, err); 588 qio_task_complete(task); 589 return FALSE; 590 } 591 if (ret == 0) { 592 trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN); 593 /* need more data still */ 594 return TRUE; 595 } 596 597 error_propagate(&wioc->io_err, err); 598 599 trace_qio_channel_websock_handshake_reply(ioc); 600 qio_channel_add_watch( 601 wioc->master, 602 G_IO_OUT, 603 qio_channel_websock_handshake_send, 604 task, 605 NULL); 606 return FALSE; 607 } 608 609 610 static void qio_channel_websock_encode(QIOChannelWebsock *ioc, 611 uint8_t opcode, 612 const struct iovec *iov, 613 size_t niov, 614 size_t size) 615 { 616 size_t header_size; 617 size_t i; 618 union { 619 char buf[QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT]; 620 QIOChannelWebsockHeader ws; 621 } header; 622 623 assert(size <= iov_size(iov, niov)); 624 625 header.ws.b0 = QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN | 626 (opcode & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE); 627 if (size < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT) { 628 header.ws.b1 = (uint8_t)size; 629 header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT; 630 } else if (size < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_16_BIT) { 631 header.ws.b1 = QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT; 632 header.ws.u.s16.l16 = cpu_to_be16((uint16_t)size); 633 header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT; 634 } else { 635 header.ws.b1 = QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT; 636 header.ws.u.s64.l64 = cpu_to_be64(size); 637 header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT; 638 } 639 header_size -= QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK; 640 641 trace_qio_channel_websock_encode(ioc, opcode, header_size, size); 642 buffer_reserve(&ioc->encoutput, header_size + size); 643 buffer_append(&ioc->encoutput, header.buf, header_size); 644 for (i = 0; i < niov && size != 0; i++) { 645 size_t want = iov[i].iov_len; 646 if (want > size) { 647 want = size; 648 } 649 buffer_append(&ioc->encoutput, iov[i].iov_base, want); 650 size -= want; 651 } 652 } 653 654 655 static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *, Error **); 656 657 658 static void qio_channel_websock_write_close(QIOChannelWebsock *ioc, 659 uint16_t code, const char *reason) 660 { 661 struct iovec iov[2] = { 662 { .iov_base = &code, .iov_len = sizeof(code) }, 663 }; 664 size_t niov = 1; 665 size_t size = iov[0].iov_len; 666 667 cpu_to_be16s(&code); 668 669 if (reason) { 670 iov[1].iov_base = (void *)reason; 671 iov[1].iov_len = strlen(reason); 672 size += iov[1].iov_len; 673 niov++; 674 } 675 qio_channel_websock_encode(ioc, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, 676 iov, niov, size); 677 qio_channel_websock_write_wire(ioc, NULL); 678 qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); 679 } 680 681 682 static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, 683 Error **errp) 684 { 685 unsigned char opcode, fin, has_mask; 686 size_t header_size; 687 size_t payload_len; 688 QIOChannelWebsockHeader *header = 689 (QIOChannelWebsockHeader *)ioc->encinput.buffer; 690 691 if (ioc->payload_remain) { 692 error_setg(errp, 693 "Decoding header but %zu bytes of payload remain", 694 ioc->payload_remain); 695 qio_channel_websock_write_close( 696 ioc, QIO_CHANNEL_WEBSOCK_STATUS_SERVER_ERR, 697 "internal server error"); 698 return -1; 699 } 700 if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT) { 701 /* header not complete */ 702 return QIO_CHANNEL_ERR_BLOCK; 703 } 704 705 fin = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN; 706 opcode = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE; 707 has_mask = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK; 708 payload_len = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN; 709 710 /* Save or restore opcode. */ 711 if (opcode) { 712 ioc->opcode = opcode; 713 } else { 714 opcode = ioc->opcode; 715 } 716 717 trace_qio_channel_websock_header_partial_decode(ioc, payload_len, 718 fin, opcode, (int)has_mask); 719 720 if (opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { 721 /* disconnect */ 722 return 0; 723 } 724 725 /* Websocket frame sanity check: 726 * * Fragmentation is only supported for binary frames. 727 * * All frames sent by a client MUST be masked. 728 * * Only binary and ping/pong encoding is supported. 729 */ 730 if (!fin) { 731 if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { 732 error_setg(errp, "only binary websocket frames may be fragmented"); 733 qio_channel_websock_write_close( 734 ioc, QIO_CHANNEL_WEBSOCK_STATUS_POLICY , 735 "only binary frames may be fragmented"); 736 return -1; 737 } 738 } else { 739 if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME && 740 opcode != QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE && 741 opcode != QIO_CHANNEL_WEBSOCK_OPCODE_PING && 742 opcode != QIO_CHANNEL_WEBSOCK_OPCODE_PONG) { 743 error_setg(errp, "unsupported opcode: 0x%04x; only binary, close, " 744 "ping, and pong websocket frames are supported", opcode); 745 qio_channel_websock_write_close( 746 ioc, QIO_CHANNEL_WEBSOCK_STATUS_INVALID_DATA , 747 "only binary, close, ping, and pong frames are supported"); 748 return -1; 749 } 750 } 751 if (!has_mask) { 752 error_setg(errp, "client websocket frames must be masked"); 753 qio_channel_websock_write_close( 754 ioc, QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR, 755 "client frames must be masked"); 756 return -1; 757 } 758 759 if (payload_len < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT) { 760 ioc->payload_remain = payload_len; 761 header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT; 762 ioc->mask = header->u.m; 763 } else if (opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) { 764 error_setg(errp, "websocket control frame is too large"); 765 qio_channel_websock_write_close( 766 ioc, QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR, 767 "control frame is too large"); 768 return -1; 769 } else if (payload_len == QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT && 770 ioc->encinput.offset >= QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT) { 771 ioc->payload_remain = be16_to_cpu(header->u.s16.l16); 772 header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT; 773 ioc->mask = header->u.s16.m16; 774 } else if (payload_len == QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT && 775 ioc->encinput.offset >= QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT) { 776 ioc->payload_remain = be64_to_cpu(header->u.s64.l64); 777 header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT; 778 ioc->mask = header->u.s64.m64; 779 } else { 780 /* header not complete */ 781 return QIO_CHANNEL_ERR_BLOCK; 782 } 783 784 trace_qio_channel_websock_header_full_decode( 785 ioc, header_size, ioc->payload_remain, ioc->mask.u); 786 buffer_advance(&ioc->encinput, header_size); 787 return 0; 788 } 789 790 791 static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, 792 Error **errp) 793 { 794 size_t i; 795 size_t payload_len = 0; 796 uint32_t *payload32; 797 798 if (ioc->payload_remain) { 799 /* If we aren't at the end of the payload, then drop 800 * off the last bytes, so we're always multiple of 4 801 * for purpose of unmasking, except at end of payload 802 */ 803 if (ioc->encinput.offset < ioc->payload_remain) { 804 /* Wait for the entire payload before processing control frames 805 * because the payload will most likely be echoed back. */ 806 if (ioc->opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) { 807 return QIO_CHANNEL_ERR_BLOCK; 808 } 809 payload_len = ioc->encinput.offset - (ioc->encinput.offset % 4); 810 } else { 811 payload_len = ioc->payload_remain; 812 } 813 if (payload_len == 0) { 814 return QIO_CHANNEL_ERR_BLOCK; 815 } 816 817 ioc->payload_remain -= payload_len; 818 819 /* unmask frame */ 820 /* process 1 frame (32 bit op) */ 821 payload32 = (uint32_t *)ioc->encinput.buffer; 822 for (i = 0; i < payload_len / 4; i++) { 823 payload32[i] ^= ioc->mask.u; 824 } 825 /* process the remaining bytes (if any) */ 826 for (i *= 4; i < payload_len; i++) { 827 ioc->encinput.buffer[i] ^= ioc->mask.c[i % 4]; 828 } 829 } 830 831 trace_qio_channel_websock_payload_decode( 832 ioc, ioc->opcode, ioc->payload_remain); 833 834 if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { 835 if (payload_len) { 836 /* binary frames are passed on */ 837 buffer_reserve(&ioc->rawinput, payload_len); 838 buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); 839 } 840 } else if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { 841 /* close frames are echoed back */ 842 error_setg(errp, "websocket closed by peer"); 843 if (payload_len) { 844 /* echo client status */ 845 struct iovec iov = { .iov_base = ioc->encinput.buffer, 846 .iov_len = ioc->encinput.offset }; 847 qio_channel_websock_encode(ioc, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, 848 &iov, 1, iov.iov_len); 849 qio_channel_websock_write_wire(ioc, NULL); 850 qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); 851 } else { 852 /* send our own status */ 853 qio_channel_websock_write_close( 854 ioc, QIO_CHANNEL_WEBSOCK_STATUS_NORMAL, "peer requested close"); 855 } 856 return -1; 857 } else if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_PING) { 858 /* ping frames produce an immediate reply, as long as we've not still 859 * got a previous pong queued, in which case we drop the new pong */ 860 if (ioc->pong_remain == 0) { 861 struct iovec iov = { .iov_base = ioc->encinput.buffer, 862 .iov_len = ioc->encinput.offset }; 863 qio_channel_websock_encode(ioc, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, 864 &iov, 1, iov.iov_len); 865 ioc->pong_remain = ioc->encoutput.offset; 866 } 867 } /* pong frames are ignored */ 868 869 if (payload_len) { 870 buffer_advance(&ioc->encinput, payload_len); 871 } 872 return 0; 873 } 874 875 876 QIOChannelWebsock * 877 qio_channel_websock_new_server(QIOChannel *master) 878 { 879 QIOChannelWebsock *wioc; 880 QIOChannel *ioc; 881 882 wioc = QIO_CHANNEL_WEBSOCK(object_new(TYPE_QIO_CHANNEL_WEBSOCK)); 883 ioc = QIO_CHANNEL(wioc); 884 885 wioc->master = master; 886 ioc->follow_coroutine_ctx = master->follow_coroutine_ctx; 887 if (qio_channel_has_feature(master, QIO_CHANNEL_FEATURE_SHUTDOWN)) { 888 qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN); 889 } 890 object_ref(OBJECT(master)); 891 892 trace_qio_channel_websock_new_server(wioc, master); 893 return wioc; 894 } 895 896 void qio_channel_websock_handshake(QIOChannelWebsock *ioc, 897 QIOTaskFunc func, 898 gpointer opaque, 899 GDestroyNotify destroy) 900 { 901 QIOTask *task; 902 903 task = qio_task_new(OBJECT(ioc), 904 func, 905 opaque, 906 destroy); 907 908 trace_qio_channel_websock_handshake_start(ioc); 909 trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN); 910 qio_channel_add_watch(ioc->master, 911 G_IO_IN, 912 qio_channel_websock_handshake_io, 913 task, 914 NULL); 915 } 916 917 918 static void qio_channel_websock_finalize(Object *obj) 919 { 920 QIOChannelWebsock *ioc = QIO_CHANNEL_WEBSOCK(obj); 921 922 buffer_free(&ioc->encinput); 923 buffer_free(&ioc->encoutput); 924 buffer_free(&ioc->rawinput); 925 object_unref(OBJECT(ioc->master)); 926 if (ioc->io_tag) { 927 g_source_remove(ioc->io_tag); 928 } 929 if (ioc->io_err) { 930 error_free(ioc->io_err); 931 } 932 } 933 934 935 static ssize_t qio_channel_websock_read_wire(QIOChannelWebsock *ioc, 936 Error **errp) 937 { 938 ssize_t ret; 939 940 if (ioc->encinput.offset < 4096) { 941 size_t want = 4096 - ioc->encinput.offset; 942 943 buffer_reserve(&ioc->encinput, want); 944 ret = qio_channel_read(ioc->master, 945 (char *)ioc->encinput.buffer + 946 ioc->encinput.offset, 947 want, 948 errp); 949 if (ret < 0) { 950 return ret; 951 } 952 if (ret == 0 && ioc->encinput.offset == 0) { 953 ioc->io_eof = TRUE; 954 return 0; 955 } 956 ioc->encinput.offset += ret; 957 } 958 959 while (ioc->encinput.offset != 0) { 960 if (ioc->payload_remain == 0) { 961 ret = qio_channel_websock_decode_header(ioc, errp); 962 if (ret < 0) { 963 return ret; 964 } 965 } 966 967 ret = qio_channel_websock_decode_payload(ioc, errp); 968 if (ret < 0) { 969 return ret; 970 } 971 } 972 return 1; 973 } 974 975 976 static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *ioc, 977 Error **errp) 978 { 979 ssize_t ret; 980 ssize_t done = 0; 981 982 while (ioc->encoutput.offset > 0) { 983 ret = qio_channel_write(ioc->master, 984 (char *)ioc->encoutput.buffer, 985 ioc->encoutput.offset, 986 errp); 987 if (ret < 0) { 988 if (ret == QIO_CHANNEL_ERR_BLOCK && 989 done > 0) { 990 return done; 991 } else { 992 return ret; 993 } 994 } 995 buffer_advance(&ioc->encoutput, ret); 996 done += ret; 997 if (ioc->pong_remain < ret) { 998 ioc->pong_remain = 0; 999 } else { 1000 ioc->pong_remain -= ret; 1001 } 1002 } 1003 return done; 1004 } 1005 1006 1007 static void qio_channel_websock_flush_free(gpointer user_data) 1008 { 1009 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(user_data); 1010 object_unref(OBJECT(wioc)); 1011 } 1012 1013 static void qio_channel_websock_set_watch(QIOChannelWebsock *ioc); 1014 1015 static gboolean qio_channel_websock_flush(QIOChannel *ioc, 1016 GIOCondition condition, 1017 gpointer user_data) 1018 { 1019 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(user_data); 1020 ssize_t ret; 1021 1022 if (condition & G_IO_OUT) { 1023 ret = qio_channel_websock_write_wire(wioc, &wioc->io_err); 1024 if (ret < 0) { 1025 goto cleanup; 1026 } 1027 } 1028 1029 if (condition & G_IO_IN) { 1030 ret = qio_channel_websock_read_wire(wioc, &wioc->io_err); 1031 if (ret < 0) { 1032 goto cleanup; 1033 } 1034 } 1035 1036 cleanup: 1037 qio_channel_websock_set_watch(wioc); 1038 return FALSE; 1039 } 1040 1041 1042 static void qio_channel_websock_unset_watch(QIOChannelWebsock *ioc) 1043 { 1044 if (ioc->io_tag) { 1045 g_source_remove(ioc->io_tag); 1046 ioc->io_tag = 0; 1047 } 1048 } 1049 1050 static void qio_channel_websock_set_watch(QIOChannelWebsock *ioc) 1051 { 1052 GIOCondition cond = 0; 1053 1054 qio_channel_websock_unset_watch(ioc); 1055 1056 if (ioc->io_err) { 1057 return; 1058 } 1059 1060 if (ioc->encoutput.offset) { 1061 cond |= G_IO_OUT; 1062 } 1063 if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER && 1064 !ioc->io_eof) { 1065 cond |= G_IO_IN; 1066 } 1067 1068 if (cond) { 1069 object_ref(OBJECT(ioc)); 1070 ioc->io_tag = 1071 qio_channel_add_watch(ioc->master, 1072 cond, 1073 qio_channel_websock_flush, 1074 ioc, 1075 qio_channel_websock_flush_free); 1076 } 1077 } 1078 1079 1080 static ssize_t qio_channel_websock_readv(QIOChannel *ioc, 1081 const struct iovec *iov, 1082 size_t niov, 1083 int **fds, 1084 size_t *nfds, 1085 int flags, 1086 Error **errp) 1087 { 1088 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); 1089 size_t i; 1090 ssize_t got = 0; 1091 ssize_t ret; 1092 1093 if (wioc->io_err) { 1094 error_propagate(errp, error_copy(wioc->io_err)); 1095 return -1; 1096 } 1097 1098 if (!wioc->rawinput.offset) { 1099 ret = qio_channel_websock_read_wire(QIO_CHANNEL_WEBSOCK(ioc), errp); 1100 if (ret < 0) { 1101 return ret; 1102 } 1103 } 1104 1105 for (i = 0 ; i < niov ; i++) { 1106 size_t want = iov[i].iov_len; 1107 if (want > (wioc->rawinput.offset - got)) { 1108 want = (wioc->rawinput.offset - got); 1109 } 1110 1111 memcpy(iov[i].iov_base, 1112 wioc->rawinput.buffer + got, 1113 want); 1114 got += want; 1115 1116 if (want < iov[i].iov_len) { 1117 break; 1118 } 1119 } 1120 1121 buffer_advance(&wioc->rawinput, got); 1122 qio_channel_websock_set_watch(wioc); 1123 return got; 1124 } 1125 1126 1127 static ssize_t qio_channel_websock_writev(QIOChannel *ioc, 1128 const struct iovec *iov, 1129 size_t niov, 1130 int *fds, 1131 size_t nfds, 1132 int flags, 1133 Error **errp) 1134 { 1135 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); 1136 ssize_t want = iov_size(iov, niov); 1137 ssize_t avail; 1138 ssize_t ret; 1139 1140 if (wioc->io_err) { 1141 error_propagate(errp, error_copy(wioc->io_err)); 1142 return -1; 1143 } 1144 1145 if (wioc->io_eof) { 1146 error_setg(errp, "%s", "Broken pipe"); 1147 return -1; 1148 } 1149 1150 avail = wioc->encoutput.offset >= QIO_CHANNEL_WEBSOCK_MAX_BUFFER ? 1151 0 : (QIO_CHANNEL_WEBSOCK_MAX_BUFFER - wioc->encoutput.offset); 1152 if (want > avail) { 1153 want = avail; 1154 } 1155 1156 if (want) { 1157 qio_channel_websock_encode(wioc, 1158 QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, 1159 iov, niov, want); 1160 } 1161 1162 /* Even if want == 0, we'll try write_wire in case there's 1163 * pending data we could usefully flush out 1164 */ 1165 ret = qio_channel_websock_write_wire(wioc, errp); 1166 if (ret < 0 && 1167 ret != QIO_CHANNEL_ERR_BLOCK) { 1168 qio_channel_websock_unset_watch(wioc); 1169 return -1; 1170 } 1171 1172 qio_channel_websock_set_watch(wioc); 1173 1174 if (want == 0) { 1175 return QIO_CHANNEL_ERR_BLOCK; 1176 } 1177 1178 return want; 1179 } 1180 1181 static int qio_channel_websock_set_blocking(QIOChannel *ioc, 1182 bool enabled, 1183 Error **errp) 1184 { 1185 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); 1186 1187 qio_channel_set_blocking(wioc->master, enabled, errp); 1188 return 0; 1189 } 1190 1191 static void qio_channel_websock_set_delay(QIOChannel *ioc, 1192 bool enabled) 1193 { 1194 QIOChannelWebsock *tioc = QIO_CHANNEL_WEBSOCK(ioc); 1195 1196 qio_channel_set_delay(tioc->master, enabled); 1197 } 1198 1199 static void qio_channel_websock_set_cork(QIOChannel *ioc, 1200 bool enabled) 1201 { 1202 QIOChannelWebsock *tioc = QIO_CHANNEL_WEBSOCK(ioc); 1203 1204 qio_channel_set_cork(tioc->master, enabled); 1205 } 1206 1207 static int qio_channel_websock_shutdown(QIOChannel *ioc, 1208 QIOChannelShutdown how, 1209 Error **errp) 1210 { 1211 QIOChannelWebsock *tioc = QIO_CHANNEL_WEBSOCK(ioc); 1212 1213 return qio_channel_shutdown(tioc->master, how, errp); 1214 } 1215 1216 static int qio_channel_websock_close(QIOChannel *ioc, 1217 Error **errp) 1218 { 1219 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); 1220 1221 trace_qio_channel_websock_close(ioc); 1222 return qio_channel_close(wioc->master, errp); 1223 } 1224 1225 typedef struct QIOChannelWebsockSource QIOChannelWebsockSource; 1226 struct QIOChannelWebsockSource { 1227 GSource parent; 1228 QIOChannelWebsock *wioc; 1229 GIOCondition condition; 1230 }; 1231 1232 static gboolean 1233 qio_channel_websock_source_check(GSource *source) 1234 { 1235 QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; 1236 GIOCondition cond = 0; 1237 1238 if (wsource->wioc->rawinput.offset) { 1239 cond |= G_IO_IN; 1240 } 1241 if (wsource->wioc->encoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { 1242 cond |= G_IO_OUT; 1243 } 1244 if (wsource->wioc->io_eof) { 1245 cond |= G_IO_HUP; 1246 } 1247 if (wsource->wioc->io_err) { 1248 cond |= G_IO_ERR; 1249 } 1250 1251 return cond & wsource->condition; 1252 } 1253 1254 static gboolean 1255 qio_channel_websock_source_prepare(GSource *source, 1256 gint *timeout) 1257 { 1258 *timeout = -1; 1259 return qio_channel_websock_source_check(source); 1260 } 1261 1262 static gboolean 1263 qio_channel_websock_source_dispatch(GSource *source, 1264 GSourceFunc callback, 1265 gpointer user_data) 1266 { 1267 QIOChannelFunc func = (QIOChannelFunc)callback; 1268 QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; 1269 1270 return (*func)(QIO_CHANNEL(wsource->wioc), 1271 qio_channel_websock_source_check(source), 1272 user_data); 1273 } 1274 1275 static void 1276 qio_channel_websock_source_finalize(GSource *source) 1277 { 1278 QIOChannelWebsockSource *ssource = (QIOChannelWebsockSource *)source; 1279 1280 object_unref(OBJECT(ssource->wioc)); 1281 } 1282 1283 GSourceFuncs qio_channel_websock_source_funcs = { 1284 qio_channel_websock_source_prepare, 1285 qio_channel_websock_source_check, 1286 qio_channel_websock_source_dispatch, 1287 qio_channel_websock_source_finalize 1288 }; 1289 1290 static GSource *qio_channel_websock_create_watch(QIOChannel *ioc, 1291 GIOCondition condition) 1292 { 1293 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); 1294 QIOChannelWebsockSource *ssource; 1295 GSource *source; 1296 1297 source = g_source_new(&qio_channel_websock_source_funcs, 1298 sizeof(QIOChannelWebsockSource)); 1299 ssource = (QIOChannelWebsockSource *)source; 1300 1301 ssource->wioc = wioc; 1302 object_ref(OBJECT(wioc)); 1303 1304 ssource->condition = condition; 1305 1306 qio_channel_websock_set_watch(wioc); 1307 return source; 1308 } 1309 1310 static void qio_channel_websock_class_init(ObjectClass *klass, 1311 void *class_data G_GNUC_UNUSED) 1312 { 1313 QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); 1314 1315 ioc_klass->io_writev = qio_channel_websock_writev; 1316 ioc_klass->io_readv = qio_channel_websock_readv; 1317 ioc_klass->io_set_blocking = qio_channel_websock_set_blocking; 1318 ioc_klass->io_set_cork = qio_channel_websock_set_cork; 1319 ioc_klass->io_set_delay = qio_channel_websock_set_delay; 1320 ioc_klass->io_close = qio_channel_websock_close; 1321 ioc_klass->io_shutdown = qio_channel_websock_shutdown; 1322 ioc_klass->io_create_watch = qio_channel_websock_create_watch; 1323 } 1324 1325 static const TypeInfo qio_channel_websock_info = { 1326 .parent = TYPE_QIO_CHANNEL, 1327 .name = TYPE_QIO_CHANNEL_WEBSOCK, 1328 .instance_size = sizeof(QIOChannelWebsock), 1329 .instance_finalize = qio_channel_websock_finalize, 1330 .class_init = qio_channel_websock_class_init, 1331 }; 1332 1333 static void qio_channel_websock_register_types(void) 1334 { 1335 type_register_static(&qio_channel_websock_info); 1336 } 1337 1338 type_init(qio_channel_websock_register_types); 1339