1 /* 2 * QEMU I/O channels driver websockets 3 * 4 * Copyright (c) 2015 Red Hat, Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qapi/error.h" 23 #include "qemu/bswap.h" 24 #include "io/channel-websock.h" 25 #include "crypto/hash.h" 26 #include "trace.h" 27 #include "qemu/iov.h" 28 #include "qemu/module.h" 29 30 /* Max amount to allow in rawinput/encoutput buffers */ 31 #define QIO_CHANNEL_WEBSOCK_MAX_BUFFER 8192 32 33 #define QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN 24 34 #define QIO_CHANNEL_WEBSOCK_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 35 #define QIO_CHANNEL_WEBSOCK_GUID_LEN strlen(QIO_CHANNEL_WEBSOCK_GUID) 36 37 #define QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL "sec-websocket-protocol" 38 #define QIO_CHANNEL_WEBSOCK_HEADER_VERSION "sec-websocket-version" 39 #define QIO_CHANNEL_WEBSOCK_HEADER_KEY "sec-websocket-key" 40 #define QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE "upgrade" 41 #define QIO_CHANNEL_WEBSOCK_HEADER_HOST "host" 42 #define QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION "connection" 43 44 #define QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY "binary" 45 #define QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE "Upgrade" 46 #define QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET "websocket" 47 48 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ 49 "Server: QEMU VNC\r\n" \ 50 "Date: %s\r\n" 51 52 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK \ 53 "HTTP/1.1 101 Switching Protocols\r\n" \ 54 QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ 55 "Upgrade: websocket\r\n" \ 56 "Connection: Upgrade\r\n" \ 57 "Sec-WebSocket-Accept: %s\r\n" \ 58 "Sec-WebSocket-Protocol: binary\r\n" \ 59 "\r\n" 60 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_NOT_FOUND \ 61 "HTTP/1.1 404 Not Found\r\n" \ 62 QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ 63 "Connection: close\r\n" \ 64 "\r\n" 65 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST \ 66 "HTTP/1.1 400 Bad Request\r\n" \ 67 QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ 68 "Connection: close\r\n" \ 69 "Sec-WebSocket-Version: " \ 70 QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION \ 71 "\r\n" 72 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR \ 73 "HTTP/1.1 500 Internal Server Error\r\n" \ 74 QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ 75 "Connection: close\r\n" \ 76 "\r\n" 77 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE \ 78 "HTTP/1.1 403 Request Entity Too Large\r\n" \ 79 QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ 80 "Connection: close\r\n" \ 81 "\r\n" 82 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM "\r\n" 83 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_END "\r\n\r\n" 84 #define QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION "13" 85 #define QIO_CHANNEL_WEBSOCK_HTTP_METHOD "GET" 86 #define QIO_CHANNEL_WEBSOCK_HTTP_PATH "/" 87 #define QIO_CHANNEL_WEBSOCK_HTTP_VERSION "HTTP/1.1" 88 89 /* The websockets packet header is variable length 90 * depending on the size of the payload... */ 91 92 /* ...length when using 7-bit payload length */ 93 #define QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT 6 94 /* ...length when using 16-bit payload length */ 95 #define QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT 8 96 /* ...length when using 64-bit payload length */ 97 #define QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT 14 98 99 /* Length of the optional data mask field in header */ 100 #define QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK 4 101 102 /* Maximum length that can fit in 7-bit payload size */ 103 #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT 126 104 /* Maximum length that can fit in 16-bit payload size */ 105 #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_16_BIT 65536 106 107 /* Magic 7-bit length to indicate use of 16-bit payload length */ 108 #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT 126 109 /* Magic 7-bit length to indicate use of 64-bit payload length */ 110 #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT 127 111 112 /* Bitmasks for accessing header fields */ 113 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN 0x80 114 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE 0x0f 115 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK 0x80 116 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN 0x7f 117 #define QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK 0x8 118 119 typedef struct QIOChannelWebsockHeader QIOChannelWebsockHeader; 120 121 struct QEMU_PACKED QIOChannelWebsockHeader { 122 unsigned char b0; 123 unsigned char b1; 124 union { 125 struct QEMU_PACKED { 126 uint16_t l16; 127 QIOChannelWebsockMask m16; 128 } s16; 129 struct QEMU_PACKED { 130 uint64_t l64; 131 QIOChannelWebsockMask m64; 132 } s64; 133 QIOChannelWebsockMask m; 134 } u; 135 }; 136 137 typedef struct QIOChannelWebsockHTTPHeader QIOChannelWebsockHTTPHeader; 138 139 struct QIOChannelWebsockHTTPHeader { 140 char *name; 141 char *value; 142 }; 143 144 enum { 145 QIO_CHANNEL_WEBSOCK_OPCODE_CONTINUATION = 0x0, 146 QIO_CHANNEL_WEBSOCK_OPCODE_TEXT_FRAME = 0x1, 147 QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME = 0x2, 148 QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE = 0x8, 149 QIO_CHANNEL_WEBSOCK_OPCODE_PING = 0x9, 150 QIO_CHANNEL_WEBSOCK_OPCODE_PONG = 0xA 151 }; 152 153 static void GCC_FMT_ATTR(2, 3) 154 qio_channel_websock_handshake_send_res(QIOChannelWebsock *ioc, 155 const char *resmsg, 156 ...) 157 { 158 va_list vargs; 159 char *response; 160 size_t responselen; 161 162 va_start(vargs, resmsg); 163 response = g_strdup_vprintf(resmsg, vargs); 164 responselen = strlen(response); 165 buffer_reserve(&ioc->encoutput, responselen); 166 buffer_append(&ioc->encoutput, response, responselen); 167 g_free(response); 168 va_end(vargs); 169 } 170 171 static gchar *qio_channel_websock_date_str(void) 172 { 173 struct tm tm; 174 time_t now = time(NULL); 175 char datebuf[128]; 176 177 gmtime_r(&now, &tm); 178 179 strftime(datebuf, sizeof(datebuf), "%a, %d %b %Y %H:%M:%S GMT", &tm); 180 181 return g_strdup(datebuf); 182 } 183 184 static void qio_channel_websock_handshake_send_res_err(QIOChannelWebsock *ioc, 185 const char *resdata) 186 { 187 char *date = qio_channel_websock_date_str(); 188 qio_channel_websock_handshake_send_res(ioc, resdata, date); 189 g_free(date); 190 } 191 192 enum { 193 QIO_CHANNEL_WEBSOCK_STATUS_NORMAL = 1000, 194 QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR = 1002, 195 QIO_CHANNEL_WEBSOCK_STATUS_INVALID_DATA = 1003, 196 QIO_CHANNEL_WEBSOCK_STATUS_POLICY = 1008, 197 QIO_CHANNEL_WEBSOCK_STATUS_TOO_LARGE = 1009, 198 QIO_CHANNEL_WEBSOCK_STATUS_SERVER_ERR = 1011, 199 }; 200 201 static size_t 202 qio_channel_websock_extract_headers(QIOChannelWebsock *ioc, 203 char *buffer, 204 QIOChannelWebsockHTTPHeader *hdrs, 205 size_t nhdrsalloc, 206 Error **errp) 207 { 208 char *nl, *sep, *tmp; 209 size_t nhdrs = 0; 210 211 /* 212 * First parse the HTTP protocol greeting of format: 213 * 214 * $METHOD $PATH $VERSION 215 * 216 * e.g. 217 * 218 * GET / HTTP/1.1 219 */ 220 221 nl = strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); 222 if (!nl) { 223 error_setg(errp, "Missing HTTP header delimiter"); 224 goto bad_request; 225 } 226 *nl = '\0'; 227 trace_qio_channel_websock_http_greeting(ioc, buffer); 228 229 tmp = strchr(buffer, ' '); 230 if (!tmp) { 231 error_setg(errp, "Missing HTTP path delimiter"); 232 return 0; 233 } 234 *tmp = '\0'; 235 236 if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_METHOD)) { 237 error_setg(errp, "Unsupported HTTP method %s", buffer); 238 goto bad_request; 239 } 240 241 buffer = tmp + 1; 242 tmp = strchr(buffer, ' '); 243 if (!tmp) { 244 error_setg(errp, "Missing HTTP version delimiter"); 245 goto bad_request; 246 } 247 *tmp = '\0'; 248 249 if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_PATH)) { 250 qio_channel_websock_handshake_send_res_err( 251 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_NOT_FOUND); 252 error_setg(errp, "Unexpected HTTP path %s", buffer); 253 return 0; 254 } 255 256 buffer = tmp + 1; 257 258 if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_VERSION)) { 259 error_setg(errp, "Unsupported HTTP version %s", buffer); 260 goto bad_request; 261 } 262 263 buffer = nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); 264 265 /* 266 * Now parse all the header fields of format 267 * 268 * $NAME: $VALUE 269 * 270 * e.g. 271 * 272 * Cache-control: no-cache 273 */ 274 do { 275 QIOChannelWebsockHTTPHeader *hdr; 276 277 nl = strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); 278 if (nl) { 279 *nl = '\0'; 280 } 281 282 sep = strchr(buffer, ':'); 283 if (!sep) { 284 error_setg(errp, "Malformed HTTP header"); 285 goto bad_request; 286 } 287 *sep = '\0'; 288 sep++; 289 while (*sep == ' ') { 290 sep++; 291 } 292 293 if (nhdrs >= nhdrsalloc) { 294 error_setg(errp, "Too many HTTP headers"); 295 goto bad_request; 296 } 297 298 hdr = &hdrs[nhdrs++]; 299 hdr->name = buffer; 300 hdr->value = sep; 301 302 /* Canonicalize header name for easier identification later */ 303 for (tmp = hdr->name; *tmp; tmp++) { 304 *tmp = g_ascii_tolower(*tmp); 305 } 306 307 if (nl) { 308 buffer = nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); 309 } 310 } while (nl != NULL); 311 312 return nhdrs; 313 314 bad_request: 315 qio_channel_websock_handshake_send_res_err( 316 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST); 317 return 0; 318 } 319 320 static const char * 321 qio_channel_websock_find_header(QIOChannelWebsockHTTPHeader *hdrs, 322 size_t nhdrs, 323 const char *name) 324 { 325 size_t i; 326 327 for (i = 0; i < nhdrs; i++) { 328 if (g_str_equal(hdrs[i].name, name)) { 329 return hdrs[i].value; 330 } 331 } 332 333 return NULL; 334 } 335 336 337 static void qio_channel_websock_handshake_send_res_ok(QIOChannelWebsock *ioc, 338 const char *key, 339 Error **errp) 340 { 341 char combined_key[QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 342 QIO_CHANNEL_WEBSOCK_GUID_LEN + 1]; 343 char *accept = NULL; 344 char *date = NULL; 345 346 g_strlcpy(combined_key, key, QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 1); 347 g_strlcat(combined_key, QIO_CHANNEL_WEBSOCK_GUID, 348 QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 349 QIO_CHANNEL_WEBSOCK_GUID_LEN + 1); 350 351 /* hash and encode it */ 352 if (qcrypto_hash_base64(QCRYPTO_HASH_ALG_SHA1, 353 combined_key, 354 QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 355 QIO_CHANNEL_WEBSOCK_GUID_LEN, 356 &accept, 357 errp) < 0) { 358 qio_channel_websock_handshake_send_res_err( 359 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR); 360 return; 361 } 362 363 date = qio_channel_websock_date_str(); 364 qio_channel_websock_handshake_send_res( 365 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK, date, accept); 366 367 g_free(date); 368 g_free(accept); 369 } 370 371 static void qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, 372 char *buffer, 373 Error **errp) 374 { 375 QIOChannelWebsockHTTPHeader hdrs[32]; 376 size_t nhdrs = G_N_ELEMENTS(hdrs); 377 const char *protocols = NULL, *version = NULL, *key = NULL, 378 *host = NULL, *connection = NULL, *upgrade = NULL; 379 char **connectionv; 380 bool upgraded = false; 381 size_t i; 382 383 nhdrs = qio_channel_websock_extract_headers(ioc, buffer, hdrs, nhdrs, errp); 384 if (!nhdrs) { 385 return; 386 } 387 388 protocols = qio_channel_websock_find_header( 389 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL); 390 if (!protocols) { 391 error_setg(errp, "Missing websocket protocol header data"); 392 goto bad_request; 393 } 394 395 version = qio_channel_websock_find_header( 396 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_VERSION); 397 if (!version) { 398 error_setg(errp, "Missing websocket version header data"); 399 goto bad_request; 400 } 401 402 key = qio_channel_websock_find_header( 403 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_KEY); 404 if (!key) { 405 error_setg(errp, "Missing websocket key header data"); 406 goto bad_request; 407 } 408 409 host = qio_channel_websock_find_header( 410 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_HOST); 411 if (!host) { 412 error_setg(errp, "Missing websocket host header data"); 413 goto bad_request; 414 } 415 416 connection = qio_channel_websock_find_header( 417 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION); 418 if (!connection) { 419 error_setg(errp, "Missing websocket connection header data"); 420 goto bad_request; 421 } 422 423 upgrade = qio_channel_websock_find_header( 424 hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE); 425 if (!upgrade) { 426 error_setg(errp, "Missing websocket upgrade header data"); 427 goto bad_request; 428 } 429 430 trace_qio_channel_websock_http_request(ioc, protocols, version, 431 host, connection, upgrade, key); 432 433 if (!g_strrstr(protocols, QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY)) { 434 error_setg(errp, "No '%s' protocol is supported by client '%s'", 435 QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY, protocols); 436 goto bad_request; 437 } 438 439 if (!g_str_equal(version, QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION)) { 440 error_setg(errp, "Version '%s' is not supported by client '%s'", 441 QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION, version); 442 goto bad_request; 443 } 444 445 if (strlen(key) != QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN) { 446 error_setg(errp, "Key length '%zu' was not as expected '%d'", 447 strlen(key), QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN); 448 goto bad_request; 449 } 450 451 connectionv = g_strsplit(connection, ",", 0); 452 for (i = 0; connectionv != NULL && connectionv[i] != NULL; i++) { 453 g_strstrip(connectionv[i]); 454 if (strcasecmp(connectionv[i], 455 QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE) == 0) { 456 upgraded = true; 457 } 458 } 459 g_strfreev(connectionv); 460 if (!upgraded) { 461 error_setg(errp, "No connection upgrade requested '%s'", connection); 462 goto bad_request; 463 } 464 465 if (strcasecmp(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET) != 0) { 466 error_setg(errp, "Incorrect upgrade method '%s'", upgrade); 467 goto bad_request; 468 } 469 470 qio_channel_websock_handshake_send_res_ok(ioc, key, errp); 471 return; 472 473 bad_request: 474 qio_channel_websock_handshake_send_res_err( 475 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST); 476 } 477 478 static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc, 479 Error **errp) 480 { 481 char *handshake_end; 482 ssize_t ret; 483 /* Typical HTTP headers from novnc are 512 bytes, so limiting 484 * total header size to 4096 is easily enough. */ 485 size_t want = 4096 - ioc->encinput.offset; 486 buffer_reserve(&ioc->encinput, want); 487 ret = qio_channel_read(ioc->master, 488 (char *)buffer_end(&ioc->encinput), want, errp); 489 if (ret < 0) { 490 return -1; 491 } 492 ioc->encinput.offset += ret; 493 494 handshake_end = g_strstr_len((char *)ioc->encinput.buffer, 495 ioc->encinput.offset, 496 QIO_CHANNEL_WEBSOCK_HANDSHAKE_END); 497 if (!handshake_end) { 498 if (ioc->encinput.offset >= 4096) { 499 qio_channel_websock_handshake_send_res_err( 500 ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE); 501 error_setg(errp, 502 "End of headers not found in first 4096 bytes"); 503 return 1; 504 } else if (ret == 0) { 505 error_setg(errp, 506 "End of headers not found before connection closed"); 507 return -1; 508 } 509 return 0; 510 } 511 *handshake_end = '\0'; 512 513 qio_channel_websock_handshake_process(ioc, 514 (char *)ioc->encinput.buffer, 515 errp); 516 517 buffer_advance(&ioc->encinput, 518 handshake_end - (char *)ioc->encinput.buffer + 519 strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_END)); 520 return 1; 521 } 522 523 static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc, 524 GIOCondition condition, 525 gpointer user_data) 526 { 527 QIOTask *task = user_data; 528 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK( 529 qio_task_get_source(task)); 530 Error *err = NULL; 531 ssize_t ret; 532 533 ret = qio_channel_write(wioc->master, 534 (char *)wioc->encoutput.buffer, 535 wioc->encoutput.offset, 536 &err); 537 538 if (ret < 0) { 539 trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); 540 qio_task_set_error(task, err); 541 qio_task_complete(task); 542 return FALSE; 543 } 544 545 buffer_advance(&wioc->encoutput, ret); 546 if (wioc->encoutput.offset == 0) { 547 if (wioc->io_err) { 548 trace_qio_channel_websock_handshake_fail( 549 ioc, error_get_pretty(wioc->io_err)); 550 qio_task_set_error(task, wioc->io_err); 551 wioc->io_err = NULL; 552 qio_task_complete(task); 553 } else { 554 trace_qio_channel_websock_handshake_complete(ioc); 555 qio_task_complete(task); 556 } 557 return FALSE; 558 } 559 trace_qio_channel_websock_handshake_pending(ioc, G_IO_OUT); 560 return TRUE; 561 } 562 563 static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc, 564 GIOCondition condition, 565 gpointer user_data) 566 { 567 QIOTask *task = user_data; 568 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK( 569 qio_task_get_source(task)); 570 Error *err = NULL; 571 int ret; 572 573 ret = qio_channel_websock_handshake_read(wioc, &err); 574 if (ret < 0) { 575 /* 576 * We only take this path on a fatal I/O error reading from 577 * client connection, as most of the time we have an 578 * HTTP 4xx err response to send instead 579 */ 580 trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err)); 581 qio_task_set_error(task, err); 582 qio_task_complete(task); 583 return FALSE; 584 } 585 if (ret == 0) { 586 trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN); 587 /* need more data still */ 588 return TRUE; 589 } 590 591 error_propagate(&wioc->io_err, err); 592 593 trace_qio_channel_websock_handshake_reply(ioc); 594 qio_channel_add_watch( 595 wioc->master, 596 G_IO_OUT, 597 qio_channel_websock_handshake_send, 598 task, 599 NULL); 600 return FALSE; 601 } 602 603 604 static 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 649 static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *, Error **); 650 651 652 static 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 676 static 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 785 static 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 870 QIOChannelWebsock * 871 qio_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 889 void 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 911 static 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 928 static 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 969 static 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 1000 static 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 1006 static void qio_channel_websock_set_watch(QIOChannelWebsock *ioc); 1007 1008 static 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 1035 static 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 1043 static 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 1073 static 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 1119 static 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 1172 static 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 1182 static 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 1190 static 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 1198 static 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 1207 static 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 1216 typedef struct QIOChannelWebsockSource QIOChannelWebsockSource; 1217 struct QIOChannelWebsockSource { 1218 GSource parent; 1219 QIOChannelWebsock *wioc; 1220 GIOCondition condition; 1221 }; 1222 1223 static gboolean 1224 qio_channel_websock_source_check(GSource *source) 1225 { 1226 QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; 1227 GIOCondition cond = 0; 1228 1229 if (wsource->wioc->rawinput.offset) { 1230 cond |= G_IO_IN; 1231 } 1232 if (wsource->wioc->encoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { 1233 cond |= G_IO_OUT; 1234 } 1235 if (wsource->wioc->io_eof) { 1236 cond |= G_IO_HUP; 1237 } 1238 if (wsource->wioc->io_err) { 1239 cond |= G_IO_ERR; 1240 } 1241 1242 return cond & wsource->condition; 1243 } 1244 1245 static gboolean 1246 qio_channel_websock_source_prepare(GSource *source, 1247 gint *timeout) 1248 { 1249 *timeout = -1; 1250 return qio_channel_websock_source_check(source); 1251 } 1252 1253 static gboolean 1254 qio_channel_websock_source_dispatch(GSource *source, 1255 GSourceFunc callback, 1256 gpointer user_data) 1257 { 1258 QIOChannelFunc func = (QIOChannelFunc)callback; 1259 QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; 1260 1261 return (*func)(QIO_CHANNEL(wsource->wioc), 1262 qio_channel_websock_source_check(source), 1263 user_data); 1264 } 1265 1266 static void 1267 qio_channel_websock_source_finalize(GSource *source) 1268 { 1269 QIOChannelWebsockSource *ssource = (QIOChannelWebsockSource *)source; 1270 1271 object_unref(OBJECT(ssource->wioc)); 1272 } 1273 1274 GSourceFuncs qio_channel_websock_source_funcs = { 1275 qio_channel_websock_source_prepare, 1276 qio_channel_websock_source_check, 1277 qio_channel_websock_source_dispatch, 1278 qio_channel_websock_source_finalize 1279 }; 1280 1281 static GSource *qio_channel_websock_create_watch(QIOChannel *ioc, 1282 GIOCondition condition) 1283 { 1284 QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); 1285 QIOChannelWebsockSource *ssource; 1286 GSource *source; 1287 1288 source = g_source_new(&qio_channel_websock_source_funcs, 1289 sizeof(QIOChannelWebsockSource)); 1290 ssource = (QIOChannelWebsockSource *)source; 1291 1292 ssource->wioc = wioc; 1293 object_ref(OBJECT(wioc)); 1294 1295 ssource->condition = condition; 1296 1297 qio_channel_websock_set_watch(wioc); 1298 return source; 1299 } 1300 1301 static void qio_channel_websock_class_init(ObjectClass *klass, 1302 void *class_data G_GNUC_UNUSED) 1303 { 1304 QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); 1305 1306 ioc_klass->io_writev = qio_channel_websock_writev; 1307 ioc_klass->io_readv = qio_channel_websock_readv; 1308 ioc_klass->io_set_blocking = qio_channel_websock_set_blocking; 1309 ioc_klass->io_set_cork = qio_channel_websock_set_cork; 1310 ioc_klass->io_set_delay = qio_channel_websock_set_delay; 1311 ioc_klass->io_close = qio_channel_websock_close; 1312 ioc_klass->io_shutdown = qio_channel_websock_shutdown; 1313 ioc_klass->io_create_watch = qio_channel_websock_create_watch; 1314 } 1315 1316 static const TypeInfo qio_channel_websock_info = { 1317 .parent = TYPE_QIO_CHANNEL, 1318 .name = TYPE_QIO_CHANNEL_WEBSOCK, 1319 .instance_size = sizeof(QIOChannelWebsock), 1320 .instance_finalize = qio_channel_websock_finalize, 1321 .class_init = qio_channel_websock_class_init, 1322 }; 1323 1324 static void qio_channel_websock_register_types(void) 1325 { 1326 type_register_static(&qio_channel_websock_info); 1327 } 1328 1329 type_init(qio_channel_websock_register_types); 1330