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