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