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