1 /* 2 * QEMU I/O channels sockets driver 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 #include "qemu/osdep.h" 21 #include "qemu-common.h" 22 #include "qapi/error.h" 23 #include "qapi/qapi-visit-sockets.h" 24 #include "qemu/module.h" 25 #include "io/channel-socket.h" 26 #include "io/channel-watch.h" 27 #include "trace.h" 28 #include "qapi/clone-visitor.h" 29 30 #define SOCKET_MAX_FDS 16 31 32 SocketAddress * 33 qio_channel_socket_get_local_address(QIOChannelSocket *ioc, 34 Error **errp) 35 { 36 return socket_sockaddr_to_address(&ioc->localAddr, 37 ioc->localAddrLen, 38 errp); 39 } 40 41 SocketAddress * 42 qio_channel_socket_get_remote_address(QIOChannelSocket *ioc, 43 Error **errp) 44 { 45 return socket_sockaddr_to_address(&ioc->remoteAddr, 46 ioc->remoteAddrLen, 47 errp); 48 } 49 50 QIOChannelSocket * 51 qio_channel_socket_new(void) 52 { 53 QIOChannelSocket *sioc; 54 QIOChannel *ioc; 55 56 sioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET)); 57 sioc->fd = -1; 58 59 ioc = QIO_CHANNEL(sioc); 60 qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN); 61 62 #ifdef WIN32 63 ioc->event = CreateEvent(NULL, FALSE, FALSE, NULL); 64 #endif 65 66 trace_qio_channel_socket_new(sioc); 67 68 return sioc; 69 } 70 71 72 static int 73 qio_channel_socket_set_fd(QIOChannelSocket *sioc, 74 int fd, 75 Error **errp) 76 { 77 if (sioc->fd != -1) { 78 error_setg(errp, "Socket is already open"); 79 return -1; 80 } 81 82 sioc->fd = fd; 83 sioc->remoteAddrLen = sizeof(sioc->remoteAddr); 84 sioc->localAddrLen = sizeof(sioc->localAddr); 85 86 87 if (getpeername(fd, (struct sockaddr *)&sioc->remoteAddr, 88 &sioc->remoteAddrLen) < 0) { 89 if (errno == ENOTCONN) { 90 memset(&sioc->remoteAddr, 0, sizeof(sioc->remoteAddr)); 91 sioc->remoteAddrLen = sizeof(sioc->remoteAddr); 92 } else { 93 error_setg_errno(errp, errno, 94 "Unable to query remote socket address"); 95 goto error; 96 } 97 } 98 99 if (getsockname(fd, (struct sockaddr *)&sioc->localAddr, 100 &sioc->localAddrLen) < 0) { 101 error_setg_errno(errp, errno, 102 "Unable to query local socket address"); 103 goto error; 104 } 105 106 #ifndef WIN32 107 if (sioc->localAddr.ss_family == AF_UNIX) { 108 QIOChannel *ioc = QIO_CHANNEL(sioc); 109 qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS); 110 } 111 #endif /* WIN32 */ 112 113 return 0; 114 115 error: 116 sioc->fd = -1; /* Let the caller close FD on failure */ 117 return -1; 118 } 119 120 QIOChannelSocket * 121 qio_channel_socket_new_fd(int fd, 122 Error **errp) 123 { 124 QIOChannelSocket *ioc; 125 126 ioc = qio_channel_socket_new(); 127 if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) { 128 object_unref(OBJECT(ioc)); 129 return NULL; 130 } 131 132 trace_qio_channel_socket_new_fd(ioc, fd); 133 134 return ioc; 135 } 136 137 138 int qio_channel_socket_connect_sync(QIOChannelSocket *ioc, 139 SocketAddress *addr, 140 Error **errp) 141 { 142 int fd; 143 144 trace_qio_channel_socket_connect_sync(ioc, addr); 145 fd = socket_connect(addr, errp); 146 if (fd < 0) { 147 trace_qio_channel_socket_connect_fail(ioc); 148 return -1; 149 } 150 151 trace_qio_channel_socket_connect_complete(ioc, fd); 152 if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) { 153 close(fd); 154 return -1; 155 } 156 157 return 0; 158 } 159 160 161 static void qio_channel_socket_connect_worker(QIOTask *task, 162 gpointer opaque) 163 { 164 QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); 165 SocketAddress *addr = opaque; 166 Error *err = NULL; 167 168 qio_channel_socket_connect_sync(ioc, addr, &err); 169 170 qio_task_set_error(task, err); 171 } 172 173 174 void qio_channel_socket_connect_async(QIOChannelSocket *ioc, 175 SocketAddress *addr, 176 QIOTaskFunc callback, 177 gpointer opaque, 178 GDestroyNotify destroy, 179 GMainContext *context) 180 { 181 QIOTask *task = qio_task_new( 182 OBJECT(ioc), callback, opaque, destroy); 183 SocketAddress *addrCopy; 184 185 addrCopy = QAPI_CLONE(SocketAddress, addr); 186 187 /* socket_connect() does a non-blocking connect(), but it 188 * still blocks in DNS lookups, so we must use a thread */ 189 trace_qio_channel_socket_connect_async(ioc, addr); 190 qio_task_run_in_thread(task, 191 qio_channel_socket_connect_worker, 192 addrCopy, 193 (GDestroyNotify)qapi_free_SocketAddress, 194 context); 195 } 196 197 198 int qio_channel_socket_listen_sync(QIOChannelSocket *ioc, 199 SocketAddress *addr, 200 Error **errp) 201 { 202 int fd; 203 204 trace_qio_channel_socket_listen_sync(ioc, addr); 205 fd = socket_listen(addr, errp); 206 if (fd < 0) { 207 trace_qio_channel_socket_listen_fail(ioc); 208 return -1; 209 } 210 211 trace_qio_channel_socket_listen_complete(ioc, fd); 212 if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) { 213 close(fd); 214 return -1; 215 } 216 qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_LISTEN); 217 218 return 0; 219 } 220 221 222 static void qio_channel_socket_listen_worker(QIOTask *task, 223 gpointer opaque) 224 { 225 QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); 226 SocketAddress *addr = opaque; 227 Error *err = NULL; 228 229 qio_channel_socket_listen_sync(ioc, addr, &err); 230 231 qio_task_set_error(task, err); 232 } 233 234 235 void qio_channel_socket_listen_async(QIOChannelSocket *ioc, 236 SocketAddress *addr, 237 QIOTaskFunc callback, 238 gpointer opaque, 239 GDestroyNotify destroy, 240 GMainContext *context) 241 { 242 QIOTask *task = qio_task_new( 243 OBJECT(ioc), callback, opaque, destroy); 244 SocketAddress *addrCopy; 245 246 addrCopy = QAPI_CLONE(SocketAddress, addr); 247 248 /* socket_listen() blocks in DNS lookups, so we must use a thread */ 249 trace_qio_channel_socket_listen_async(ioc, addr); 250 qio_task_run_in_thread(task, 251 qio_channel_socket_listen_worker, 252 addrCopy, 253 (GDestroyNotify)qapi_free_SocketAddress, 254 context); 255 } 256 257 258 int qio_channel_socket_dgram_sync(QIOChannelSocket *ioc, 259 SocketAddress *localAddr, 260 SocketAddress *remoteAddr, 261 Error **errp) 262 { 263 int fd; 264 265 trace_qio_channel_socket_dgram_sync(ioc, localAddr, remoteAddr); 266 fd = socket_dgram(remoteAddr, localAddr, errp); 267 if (fd < 0) { 268 trace_qio_channel_socket_dgram_fail(ioc); 269 return -1; 270 } 271 272 trace_qio_channel_socket_dgram_complete(ioc, fd); 273 if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) { 274 close(fd); 275 return -1; 276 } 277 278 return 0; 279 } 280 281 282 struct QIOChannelSocketDGramWorkerData { 283 SocketAddress *localAddr; 284 SocketAddress *remoteAddr; 285 }; 286 287 288 static void qio_channel_socket_dgram_worker_free(gpointer opaque) 289 { 290 struct QIOChannelSocketDGramWorkerData *data = opaque; 291 qapi_free_SocketAddress(data->localAddr); 292 qapi_free_SocketAddress(data->remoteAddr); 293 g_free(data); 294 } 295 296 static void qio_channel_socket_dgram_worker(QIOTask *task, 297 gpointer opaque) 298 { 299 QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); 300 struct QIOChannelSocketDGramWorkerData *data = opaque; 301 Error *err = NULL; 302 303 /* socket_dgram() blocks in DNS lookups, so we must use a thread */ 304 qio_channel_socket_dgram_sync(ioc, data->localAddr, 305 data->remoteAddr, &err); 306 307 qio_task_set_error(task, err); 308 } 309 310 311 void qio_channel_socket_dgram_async(QIOChannelSocket *ioc, 312 SocketAddress *localAddr, 313 SocketAddress *remoteAddr, 314 QIOTaskFunc callback, 315 gpointer opaque, 316 GDestroyNotify destroy, 317 GMainContext *context) 318 { 319 QIOTask *task = qio_task_new( 320 OBJECT(ioc), callback, opaque, destroy); 321 struct QIOChannelSocketDGramWorkerData *data = g_new0( 322 struct QIOChannelSocketDGramWorkerData, 1); 323 324 data->localAddr = QAPI_CLONE(SocketAddress, localAddr); 325 data->remoteAddr = QAPI_CLONE(SocketAddress, remoteAddr); 326 327 trace_qio_channel_socket_dgram_async(ioc, localAddr, remoteAddr); 328 qio_task_run_in_thread(task, 329 qio_channel_socket_dgram_worker, 330 data, 331 qio_channel_socket_dgram_worker_free, 332 context); 333 } 334 335 336 QIOChannelSocket * 337 qio_channel_socket_accept(QIOChannelSocket *ioc, 338 Error **errp) 339 { 340 QIOChannelSocket *cioc; 341 342 cioc = qio_channel_socket_new(); 343 cioc->remoteAddrLen = sizeof(ioc->remoteAddr); 344 cioc->localAddrLen = sizeof(ioc->localAddr); 345 346 retry: 347 trace_qio_channel_socket_accept(ioc); 348 cioc->fd = qemu_accept(ioc->fd, (struct sockaddr *)&cioc->remoteAddr, 349 &cioc->remoteAddrLen); 350 if (cioc->fd < 0) { 351 if (errno == EINTR) { 352 goto retry; 353 } 354 error_setg_errno(errp, errno, "Unable to accept connection"); 355 trace_qio_channel_socket_accept_fail(ioc); 356 goto error; 357 } 358 359 if (getsockname(cioc->fd, (struct sockaddr *)&cioc->localAddr, 360 &cioc->localAddrLen) < 0) { 361 error_setg_errno(errp, errno, 362 "Unable to query local socket address"); 363 goto error; 364 } 365 366 #ifndef WIN32 367 if (cioc->localAddr.ss_family == AF_UNIX) { 368 QIOChannel *ioc_local = QIO_CHANNEL(cioc); 369 qio_channel_set_feature(ioc_local, QIO_CHANNEL_FEATURE_FD_PASS); 370 } 371 #endif /* WIN32 */ 372 373 trace_qio_channel_socket_accept_complete(ioc, cioc, cioc->fd); 374 return cioc; 375 376 error: 377 object_unref(OBJECT(cioc)); 378 return NULL; 379 } 380 381 static void qio_channel_socket_init(Object *obj) 382 { 383 QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj); 384 ioc->fd = -1; 385 } 386 387 static void qio_channel_socket_finalize(Object *obj) 388 { 389 QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj); 390 391 if (ioc->fd != -1) { 392 QIOChannel *ioc_local = QIO_CHANNEL(ioc); 393 if (qio_channel_has_feature(ioc_local, QIO_CHANNEL_FEATURE_LISTEN)) { 394 Error *err = NULL; 395 396 socket_listen_cleanup(ioc->fd, &err); 397 if (err) { 398 error_report_err(err); 399 err = NULL; 400 } 401 } 402 #ifdef WIN32 403 WSAEventSelect(ioc->fd, NULL, 0); 404 #endif 405 closesocket(ioc->fd); 406 ioc->fd = -1; 407 } 408 } 409 410 411 #ifndef WIN32 412 static void qio_channel_socket_copy_fds(struct msghdr *msg, 413 int **fds, size_t *nfds) 414 { 415 struct cmsghdr *cmsg; 416 417 *nfds = 0; 418 *fds = NULL; 419 420 for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { 421 int fd_size, i; 422 int gotfds; 423 424 if (cmsg->cmsg_len < CMSG_LEN(sizeof(int)) || 425 cmsg->cmsg_level != SOL_SOCKET || 426 cmsg->cmsg_type != SCM_RIGHTS) { 427 continue; 428 } 429 430 fd_size = cmsg->cmsg_len - CMSG_LEN(0); 431 432 if (!fd_size) { 433 continue; 434 } 435 436 gotfds = fd_size / sizeof(int); 437 *fds = g_renew(int, *fds, *nfds + gotfds); 438 memcpy(*fds + *nfds, CMSG_DATA(cmsg), fd_size); 439 440 for (i = 0; i < gotfds; i++) { 441 int fd = (*fds)[*nfds + i]; 442 if (fd < 0) { 443 continue; 444 } 445 446 /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */ 447 qemu_set_block(fd); 448 449 #ifndef MSG_CMSG_CLOEXEC 450 qemu_set_cloexec(fd); 451 #endif 452 } 453 *nfds += gotfds; 454 } 455 } 456 457 458 static ssize_t qio_channel_socket_readv(QIOChannel *ioc, 459 const struct iovec *iov, 460 size_t niov, 461 int **fds, 462 size_t *nfds, 463 Error **errp) 464 { 465 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 466 ssize_t ret; 467 struct msghdr msg = { NULL, }; 468 char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)]; 469 int sflags = 0; 470 471 memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)); 472 473 #ifdef MSG_CMSG_CLOEXEC 474 sflags |= MSG_CMSG_CLOEXEC; 475 #endif 476 477 msg.msg_iov = (struct iovec *)iov; 478 msg.msg_iovlen = niov; 479 if (fds && nfds) { 480 msg.msg_control = control; 481 msg.msg_controllen = sizeof(control); 482 } 483 484 retry: 485 ret = recvmsg(sioc->fd, &msg, sflags); 486 if (ret < 0) { 487 if (errno == EAGAIN) { 488 return QIO_CHANNEL_ERR_BLOCK; 489 } 490 if (errno == EINTR) { 491 goto retry; 492 } 493 494 error_setg_errno(errp, errno, 495 "Unable to read from socket"); 496 return -1; 497 } 498 499 if (fds && nfds) { 500 qio_channel_socket_copy_fds(&msg, fds, nfds); 501 } 502 503 return ret; 504 } 505 506 static ssize_t qio_channel_socket_writev(QIOChannel *ioc, 507 const struct iovec *iov, 508 size_t niov, 509 int *fds, 510 size_t nfds, 511 Error **errp) 512 { 513 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 514 ssize_t ret; 515 struct msghdr msg = { NULL, }; 516 char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)]; 517 size_t fdsize = sizeof(int) * nfds; 518 struct cmsghdr *cmsg; 519 520 memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)); 521 522 msg.msg_iov = (struct iovec *)iov; 523 msg.msg_iovlen = niov; 524 525 if (nfds) { 526 if (nfds > SOCKET_MAX_FDS) { 527 error_setg_errno(errp, EINVAL, 528 "Only %d FDs can be sent, got %zu", 529 SOCKET_MAX_FDS, nfds); 530 return -1; 531 } 532 533 msg.msg_control = control; 534 msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfds); 535 536 cmsg = CMSG_FIRSTHDR(&msg); 537 cmsg->cmsg_len = CMSG_LEN(fdsize); 538 cmsg->cmsg_level = SOL_SOCKET; 539 cmsg->cmsg_type = SCM_RIGHTS; 540 memcpy(CMSG_DATA(cmsg), fds, fdsize); 541 } 542 543 retry: 544 ret = sendmsg(sioc->fd, &msg, 0); 545 if (ret <= 0) { 546 if (errno == EAGAIN) { 547 return QIO_CHANNEL_ERR_BLOCK; 548 } 549 if (errno == EINTR) { 550 goto retry; 551 } 552 error_setg_errno(errp, errno, 553 "Unable to write to socket"); 554 return -1; 555 } 556 return ret; 557 } 558 #else /* WIN32 */ 559 static ssize_t qio_channel_socket_readv(QIOChannel *ioc, 560 const struct iovec *iov, 561 size_t niov, 562 int **fds, 563 size_t *nfds, 564 Error **errp) 565 { 566 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 567 ssize_t done = 0; 568 ssize_t i; 569 570 for (i = 0; i < niov; i++) { 571 ssize_t ret; 572 retry: 573 ret = recv(sioc->fd, 574 iov[i].iov_base, 575 iov[i].iov_len, 576 0); 577 if (ret < 0) { 578 if (errno == EAGAIN) { 579 if (done) { 580 return done; 581 } else { 582 return QIO_CHANNEL_ERR_BLOCK; 583 } 584 } else if (errno == EINTR) { 585 goto retry; 586 } else { 587 error_setg_errno(errp, errno, 588 "Unable to read from socket"); 589 return -1; 590 } 591 } 592 done += ret; 593 if (ret < iov[i].iov_len) { 594 return done; 595 } 596 } 597 598 return done; 599 } 600 601 static ssize_t qio_channel_socket_writev(QIOChannel *ioc, 602 const struct iovec *iov, 603 size_t niov, 604 int *fds, 605 size_t nfds, 606 Error **errp) 607 { 608 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 609 ssize_t done = 0; 610 ssize_t i; 611 612 for (i = 0; i < niov; i++) { 613 ssize_t ret; 614 retry: 615 ret = send(sioc->fd, 616 iov[i].iov_base, 617 iov[i].iov_len, 618 0); 619 if (ret < 0) { 620 if (errno == EAGAIN) { 621 if (done) { 622 return done; 623 } else { 624 return QIO_CHANNEL_ERR_BLOCK; 625 } 626 } else if (errno == EINTR) { 627 goto retry; 628 } else { 629 error_setg_errno(errp, errno, 630 "Unable to write to socket"); 631 return -1; 632 } 633 } 634 done += ret; 635 if (ret < iov[i].iov_len) { 636 return done; 637 } 638 } 639 640 return done; 641 } 642 #endif /* WIN32 */ 643 644 static int 645 qio_channel_socket_set_blocking(QIOChannel *ioc, 646 bool enabled, 647 Error **errp) 648 { 649 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 650 651 if (enabled) { 652 qemu_set_block(sioc->fd); 653 } else { 654 qemu_set_nonblock(sioc->fd); 655 } 656 return 0; 657 } 658 659 660 static void 661 qio_channel_socket_set_delay(QIOChannel *ioc, 662 bool enabled) 663 { 664 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 665 int v = enabled ? 0 : 1; 666 667 qemu_setsockopt(sioc->fd, 668 IPPROTO_TCP, TCP_NODELAY, 669 &v, sizeof(v)); 670 } 671 672 673 static void 674 qio_channel_socket_set_cork(QIOChannel *ioc, 675 bool enabled) 676 { 677 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 678 int v = enabled ? 1 : 0; 679 680 socket_set_cork(sioc->fd, v); 681 } 682 683 684 static int 685 qio_channel_socket_close(QIOChannel *ioc, 686 Error **errp) 687 { 688 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 689 int rc = 0; 690 691 if (sioc->fd != -1) { 692 #ifdef WIN32 693 WSAEventSelect(sioc->fd, NULL, 0); 694 #endif 695 if (qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_LISTEN)) { 696 socket_listen_cleanup(sioc->fd, errp); 697 } 698 699 if (closesocket(sioc->fd) < 0) { 700 sioc->fd = -1; 701 error_setg_errno(errp, errno, 702 "Unable to close socket"); 703 return -1; 704 } 705 sioc->fd = -1; 706 } 707 return rc; 708 } 709 710 static int 711 qio_channel_socket_shutdown(QIOChannel *ioc, 712 QIOChannelShutdown how, 713 Error **errp) 714 { 715 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 716 int sockhow; 717 718 switch (how) { 719 case QIO_CHANNEL_SHUTDOWN_READ: 720 sockhow = SHUT_RD; 721 break; 722 case QIO_CHANNEL_SHUTDOWN_WRITE: 723 sockhow = SHUT_WR; 724 break; 725 case QIO_CHANNEL_SHUTDOWN_BOTH: 726 default: 727 sockhow = SHUT_RDWR; 728 break; 729 } 730 731 if (shutdown(sioc->fd, sockhow) < 0) { 732 error_setg_errno(errp, errno, 733 "Unable to shutdown socket"); 734 return -1; 735 } 736 return 0; 737 } 738 739 static void qio_channel_socket_set_aio_fd_handler(QIOChannel *ioc, 740 AioContext *ctx, 741 IOHandler *io_read, 742 IOHandler *io_write, 743 void *opaque) 744 { 745 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 746 aio_set_fd_handler(ctx, sioc->fd, false, io_read, io_write, NULL, opaque); 747 } 748 749 static GSource *qio_channel_socket_create_watch(QIOChannel *ioc, 750 GIOCondition condition) 751 { 752 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 753 return qio_channel_create_socket_watch(ioc, 754 sioc->fd, 755 condition); 756 } 757 758 static void qio_channel_socket_class_init(ObjectClass *klass, 759 void *class_data G_GNUC_UNUSED) 760 { 761 QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); 762 763 ioc_klass->io_writev = qio_channel_socket_writev; 764 ioc_klass->io_readv = qio_channel_socket_readv; 765 ioc_klass->io_set_blocking = qio_channel_socket_set_blocking; 766 ioc_klass->io_close = qio_channel_socket_close; 767 ioc_klass->io_shutdown = qio_channel_socket_shutdown; 768 ioc_klass->io_set_cork = qio_channel_socket_set_cork; 769 ioc_klass->io_set_delay = qio_channel_socket_set_delay; 770 ioc_klass->io_create_watch = qio_channel_socket_create_watch; 771 ioc_klass->io_set_aio_fd_handler = qio_channel_socket_set_aio_fd_handler; 772 } 773 774 static const TypeInfo qio_channel_socket_info = { 775 .parent = TYPE_QIO_CHANNEL, 776 .name = TYPE_QIO_CHANNEL_SOCKET, 777 .instance_size = sizeof(QIOChannelSocket), 778 .instance_init = qio_channel_socket_init, 779 .instance_finalize = qio_channel_socket_finalize, 780 .class_init = qio_channel_socket_class_init, 781 }; 782 783 static void qio_channel_socket_register_types(void) 784 { 785 type_register_static(&qio_channel_socket_info); 786 } 787 788 type_init(qio_channel_socket_register_types); 789