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 int num, 201 Error **errp) 202 { 203 int fd; 204 205 trace_qio_channel_socket_listen_sync(ioc, addr, num); 206 fd = socket_listen(addr, num, errp); 207 if (fd < 0) { 208 trace_qio_channel_socket_listen_fail(ioc); 209 return -1; 210 } 211 212 trace_qio_channel_socket_listen_complete(ioc, fd); 213 if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) { 214 close(fd); 215 return -1; 216 } 217 qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_LISTEN); 218 219 return 0; 220 } 221 222 223 static void qio_channel_socket_listen_worker(QIOTask *task, 224 gpointer opaque) 225 { 226 QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); 227 SocketAddress *addr = opaque; 228 Error *err = NULL; 229 230 qio_channel_socket_listen_sync(ioc, addr, 1, &err); 231 232 qio_task_set_error(task, err); 233 } 234 235 236 void qio_channel_socket_listen_async(QIOChannelSocket *ioc, 237 SocketAddress *addr, 238 QIOTaskFunc callback, 239 gpointer opaque, 240 GDestroyNotify destroy, 241 GMainContext *context) 242 { 243 QIOTask *task = qio_task_new( 244 OBJECT(ioc), callback, opaque, destroy); 245 SocketAddress *addrCopy; 246 247 addrCopy = QAPI_CLONE(SocketAddress, addr); 248 249 /* socket_listen() blocks in DNS lookups, so we must use a thread */ 250 trace_qio_channel_socket_listen_async(ioc, addr); 251 qio_task_run_in_thread(task, 252 qio_channel_socket_listen_worker, 253 addrCopy, 254 (GDestroyNotify)qapi_free_SocketAddress, 255 context); 256 } 257 258 259 int qio_channel_socket_dgram_sync(QIOChannelSocket *ioc, 260 SocketAddress *localAddr, 261 SocketAddress *remoteAddr, 262 Error **errp) 263 { 264 int fd; 265 266 trace_qio_channel_socket_dgram_sync(ioc, localAddr, remoteAddr); 267 fd = socket_dgram(remoteAddr, localAddr, errp); 268 if (fd < 0) { 269 trace_qio_channel_socket_dgram_fail(ioc); 270 return -1; 271 } 272 273 trace_qio_channel_socket_dgram_complete(ioc, fd); 274 if (qio_channel_socket_set_fd(ioc, fd, errp) < 0) { 275 close(fd); 276 return -1; 277 } 278 279 return 0; 280 } 281 282 283 struct QIOChannelSocketDGramWorkerData { 284 SocketAddress *localAddr; 285 SocketAddress *remoteAddr; 286 }; 287 288 289 static void qio_channel_socket_dgram_worker_free(gpointer opaque) 290 { 291 struct QIOChannelSocketDGramWorkerData *data = opaque; 292 qapi_free_SocketAddress(data->localAddr); 293 qapi_free_SocketAddress(data->remoteAddr); 294 g_free(data); 295 } 296 297 static void qio_channel_socket_dgram_worker(QIOTask *task, 298 gpointer opaque) 299 { 300 QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task)); 301 struct QIOChannelSocketDGramWorkerData *data = opaque; 302 Error *err = NULL; 303 304 /* socket_dgram() blocks in DNS lookups, so we must use a thread */ 305 qio_channel_socket_dgram_sync(ioc, data->localAddr, 306 data->remoteAddr, &err); 307 308 qio_task_set_error(task, err); 309 } 310 311 312 void qio_channel_socket_dgram_async(QIOChannelSocket *ioc, 313 SocketAddress *localAddr, 314 SocketAddress *remoteAddr, 315 QIOTaskFunc callback, 316 gpointer opaque, 317 GDestroyNotify destroy, 318 GMainContext *context) 319 { 320 QIOTask *task = qio_task_new( 321 OBJECT(ioc), callback, opaque, destroy); 322 struct QIOChannelSocketDGramWorkerData *data = g_new0( 323 struct QIOChannelSocketDGramWorkerData, 1); 324 325 data->localAddr = QAPI_CLONE(SocketAddress, localAddr); 326 data->remoteAddr = QAPI_CLONE(SocketAddress, remoteAddr); 327 328 trace_qio_channel_socket_dgram_async(ioc, localAddr, remoteAddr); 329 qio_task_run_in_thread(task, 330 qio_channel_socket_dgram_worker, 331 data, 332 qio_channel_socket_dgram_worker_free, 333 context); 334 } 335 336 337 QIOChannelSocket * 338 qio_channel_socket_accept(QIOChannelSocket *ioc, 339 Error **errp) 340 { 341 QIOChannelSocket *cioc; 342 343 cioc = qio_channel_socket_new(); 344 cioc->remoteAddrLen = sizeof(ioc->remoteAddr); 345 cioc->localAddrLen = sizeof(ioc->localAddr); 346 347 retry: 348 trace_qio_channel_socket_accept(ioc); 349 cioc->fd = qemu_accept(ioc->fd, (struct sockaddr *)&cioc->remoteAddr, 350 &cioc->remoteAddrLen); 351 if (cioc->fd < 0) { 352 if (errno == EINTR) { 353 goto retry; 354 } 355 error_setg_errno(errp, errno, "Unable to accept connection"); 356 trace_qio_channel_socket_accept_fail(ioc); 357 goto error; 358 } 359 360 if (getsockname(cioc->fd, (struct sockaddr *)&cioc->localAddr, 361 &cioc->localAddrLen) < 0) { 362 error_setg_errno(errp, errno, 363 "Unable to query local socket address"); 364 goto error; 365 } 366 367 #ifndef WIN32 368 if (cioc->localAddr.ss_family == AF_UNIX) { 369 QIOChannel *ioc_local = QIO_CHANNEL(cioc); 370 qio_channel_set_feature(ioc_local, QIO_CHANNEL_FEATURE_FD_PASS); 371 } 372 #endif /* WIN32 */ 373 374 trace_qio_channel_socket_accept_complete(ioc, cioc, cioc->fd); 375 return cioc; 376 377 error: 378 object_unref(OBJECT(cioc)); 379 return NULL; 380 } 381 382 static void qio_channel_socket_init(Object *obj) 383 { 384 QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj); 385 ioc->fd = -1; 386 } 387 388 static void qio_channel_socket_finalize(Object *obj) 389 { 390 QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(obj); 391 392 if (ioc->fd != -1) { 393 QIOChannel *ioc_local = QIO_CHANNEL(ioc); 394 if (qio_channel_has_feature(ioc_local, QIO_CHANNEL_FEATURE_LISTEN)) { 395 Error *err = NULL; 396 397 socket_listen_cleanup(ioc->fd, &err); 398 if (err) { 399 error_report_err(err); 400 err = NULL; 401 } 402 } 403 #ifdef WIN32 404 WSAEventSelect(ioc->fd, NULL, 0); 405 #endif 406 closesocket(ioc->fd); 407 ioc->fd = -1; 408 } 409 } 410 411 412 #ifndef WIN32 413 static void qio_channel_socket_copy_fds(struct msghdr *msg, 414 int **fds, size_t *nfds) 415 { 416 struct cmsghdr *cmsg; 417 418 *nfds = 0; 419 *fds = NULL; 420 421 for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { 422 int fd_size, i; 423 int gotfds; 424 425 if (cmsg->cmsg_len < CMSG_LEN(sizeof(int)) || 426 cmsg->cmsg_level != SOL_SOCKET || 427 cmsg->cmsg_type != SCM_RIGHTS) { 428 continue; 429 } 430 431 fd_size = cmsg->cmsg_len - CMSG_LEN(0); 432 433 if (!fd_size) { 434 continue; 435 } 436 437 gotfds = fd_size / sizeof(int); 438 *fds = g_renew(int, *fds, *nfds + gotfds); 439 memcpy(*fds + *nfds, CMSG_DATA(cmsg), fd_size); 440 441 for (i = 0; i < gotfds; i++) { 442 int fd = (*fds)[*nfds + i]; 443 if (fd < 0) { 444 continue; 445 } 446 447 /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */ 448 qemu_set_block(fd); 449 450 #ifndef MSG_CMSG_CLOEXEC 451 qemu_set_cloexec(fd); 452 #endif 453 } 454 *nfds += gotfds; 455 } 456 } 457 458 459 static ssize_t qio_channel_socket_readv(QIOChannel *ioc, 460 const struct iovec *iov, 461 size_t niov, 462 int **fds, 463 size_t *nfds, 464 Error **errp) 465 { 466 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 467 ssize_t ret; 468 struct msghdr msg = { NULL, }; 469 char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)]; 470 int sflags = 0; 471 472 memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)); 473 474 #ifdef MSG_CMSG_CLOEXEC 475 sflags |= MSG_CMSG_CLOEXEC; 476 #endif 477 478 msg.msg_iov = (struct iovec *)iov; 479 msg.msg_iovlen = niov; 480 if (fds && nfds) { 481 msg.msg_control = control; 482 msg.msg_controllen = sizeof(control); 483 } 484 485 retry: 486 ret = recvmsg(sioc->fd, &msg, sflags); 487 if (ret < 0) { 488 if (errno == EAGAIN) { 489 return QIO_CHANNEL_ERR_BLOCK; 490 } 491 if (errno == EINTR) { 492 goto retry; 493 } 494 495 error_setg_errno(errp, errno, 496 "Unable to read from socket"); 497 return -1; 498 } 499 500 if (fds && nfds) { 501 qio_channel_socket_copy_fds(&msg, fds, nfds); 502 } 503 504 return ret; 505 } 506 507 static ssize_t qio_channel_socket_writev(QIOChannel *ioc, 508 const struct iovec *iov, 509 size_t niov, 510 int *fds, 511 size_t nfds, 512 Error **errp) 513 { 514 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 515 ssize_t ret; 516 struct msghdr msg = { NULL, }; 517 char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)]; 518 size_t fdsize = sizeof(int) * nfds; 519 struct cmsghdr *cmsg; 520 521 memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)); 522 523 msg.msg_iov = (struct iovec *)iov; 524 msg.msg_iovlen = niov; 525 526 if (nfds) { 527 if (nfds > SOCKET_MAX_FDS) { 528 error_setg_errno(errp, EINVAL, 529 "Only %d FDs can be sent, got %zu", 530 SOCKET_MAX_FDS, nfds); 531 return -1; 532 } 533 534 msg.msg_control = control; 535 msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfds); 536 537 cmsg = CMSG_FIRSTHDR(&msg); 538 cmsg->cmsg_len = CMSG_LEN(fdsize); 539 cmsg->cmsg_level = SOL_SOCKET; 540 cmsg->cmsg_type = SCM_RIGHTS; 541 memcpy(CMSG_DATA(cmsg), fds, fdsize); 542 } 543 544 retry: 545 ret = sendmsg(sioc->fd, &msg, 0); 546 if (ret <= 0) { 547 if (errno == EAGAIN) { 548 return QIO_CHANNEL_ERR_BLOCK; 549 } 550 if (errno == EINTR) { 551 goto retry; 552 } 553 error_setg_errno(errp, errno, 554 "Unable to write to socket"); 555 return -1; 556 } 557 return ret; 558 } 559 #else /* WIN32 */ 560 static ssize_t qio_channel_socket_readv(QIOChannel *ioc, 561 const struct iovec *iov, 562 size_t niov, 563 int **fds, 564 size_t *nfds, 565 Error **errp) 566 { 567 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 568 ssize_t done = 0; 569 ssize_t i; 570 571 for (i = 0; i < niov; i++) { 572 ssize_t ret; 573 retry: 574 ret = recv(sioc->fd, 575 iov[i].iov_base, 576 iov[i].iov_len, 577 0); 578 if (ret < 0) { 579 if (errno == EAGAIN) { 580 if (done) { 581 return done; 582 } else { 583 return QIO_CHANNEL_ERR_BLOCK; 584 } 585 } else if (errno == EINTR) { 586 goto retry; 587 } else { 588 error_setg_errno(errp, errno, 589 "Unable to read from socket"); 590 return -1; 591 } 592 } 593 done += ret; 594 if (ret < iov[i].iov_len) { 595 return done; 596 } 597 } 598 599 return done; 600 } 601 602 static ssize_t qio_channel_socket_writev(QIOChannel *ioc, 603 const struct iovec *iov, 604 size_t niov, 605 int *fds, 606 size_t nfds, 607 Error **errp) 608 { 609 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 610 ssize_t done = 0; 611 ssize_t i; 612 613 for (i = 0; i < niov; i++) { 614 ssize_t ret; 615 retry: 616 ret = send(sioc->fd, 617 iov[i].iov_base, 618 iov[i].iov_len, 619 0); 620 if (ret < 0) { 621 if (errno == EAGAIN) { 622 if (done) { 623 return done; 624 } else { 625 return QIO_CHANNEL_ERR_BLOCK; 626 } 627 } else if (errno == EINTR) { 628 goto retry; 629 } else { 630 error_setg_errno(errp, errno, 631 "Unable to write to socket"); 632 return -1; 633 } 634 } 635 done += ret; 636 if (ret < iov[i].iov_len) { 637 return done; 638 } 639 } 640 641 return done; 642 } 643 #endif /* WIN32 */ 644 645 static int 646 qio_channel_socket_set_blocking(QIOChannel *ioc, 647 bool enabled, 648 Error **errp) 649 { 650 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 651 652 if (enabled) { 653 qemu_set_block(sioc->fd); 654 } else { 655 qemu_set_nonblock(sioc->fd); 656 } 657 return 0; 658 } 659 660 661 static void 662 qio_channel_socket_set_delay(QIOChannel *ioc, 663 bool enabled) 664 { 665 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 666 int v = enabled ? 0 : 1; 667 668 qemu_setsockopt(sioc->fd, 669 IPPROTO_TCP, TCP_NODELAY, 670 &v, sizeof(v)); 671 } 672 673 674 static void 675 qio_channel_socket_set_cork(QIOChannel *ioc, 676 bool enabled) 677 { 678 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 679 int v = enabled ? 1 : 0; 680 681 socket_set_cork(sioc->fd, v); 682 } 683 684 685 static int 686 qio_channel_socket_close(QIOChannel *ioc, 687 Error **errp) 688 { 689 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 690 int rc = 0; 691 692 if (sioc->fd != -1) { 693 #ifdef WIN32 694 WSAEventSelect(sioc->fd, NULL, 0); 695 #endif 696 if (qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_LISTEN)) { 697 socket_listen_cleanup(sioc->fd, errp); 698 } 699 700 if (closesocket(sioc->fd) < 0) { 701 sioc->fd = -1; 702 error_setg_errno(errp, errno, 703 "Unable to close socket"); 704 return -1; 705 } 706 sioc->fd = -1; 707 } 708 return rc; 709 } 710 711 static int 712 qio_channel_socket_shutdown(QIOChannel *ioc, 713 QIOChannelShutdown how, 714 Error **errp) 715 { 716 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 717 int sockhow; 718 719 switch (how) { 720 case QIO_CHANNEL_SHUTDOWN_READ: 721 sockhow = SHUT_RD; 722 break; 723 case QIO_CHANNEL_SHUTDOWN_WRITE: 724 sockhow = SHUT_WR; 725 break; 726 case QIO_CHANNEL_SHUTDOWN_BOTH: 727 default: 728 sockhow = SHUT_RDWR; 729 break; 730 } 731 732 if (shutdown(sioc->fd, sockhow) < 0) { 733 error_setg_errno(errp, errno, 734 "Unable to shutdown socket"); 735 return -1; 736 } 737 return 0; 738 } 739 740 static void qio_channel_socket_set_aio_fd_handler(QIOChannel *ioc, 741 AioContext *ctx, 742 IOHandler *io_read, 743 IOHandler *io_write, 744 void *opaque) 745 { 746 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 747 aio_set_fd_handler(ctx, sioc->fd, false, io_read, io_write, NULL, opaque); 748 } 749 750 static GSource *qio_channel_socket_create_watch(QIOChannel *ioc, 751 GIOCondition condition) 752 { 753 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc); 754 return qio_channel_create_socket_watch(ioc, 755 sioc->fd, 756 condition); 757 } 758 759 static void qio_channel_socket_class_init(ObjectClass *klass, 760 void *class_data G_GNUC_UNUSED) 761 { 762 QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); 763 764 ioc_klass->io_writev = qio_channel_socket_writev; 765 ioc_klass->io_readv = qio_channel_socket_readv; 766 ioc_klass->io_set_blocking = qio_channel_socket_set_blocking; 767 ioc_klass->io_close = qio_channel_socket_close; 768 ioc_klass->io_shutdown = qio_channel_socket_shutdown; 769 ioc_klass->io_set_cork = qio_channel_socket_set_cork; 770 ioc_klass->io_set_delay = qio_channel_socket_set_delay; 771 ioc_klass->io_create_watch = qio_channel_socket_create_watch; 772 ioc_klass->io_set_aio_fd_handler = qio_channel_socket_set_aio_fd_handler; 773 } 774 775 static const TypeInfo qio_channel_socket_info = { 776 .parent = TYPE_QIO_CHANNEL, 777 .name = TYPE_QIO_CHANNEL_SOCKET, 778 .instance_size = sizeof(QIOChannelSocket), 779 .instance_init = qio_channel_socket_init, 780 .instance_finalize = qio_channel_socket_finalize, 781 .class_init = qio_channel_socket_class_init, 782 }; 783 784 static void qio_channel_socket_register_types(void) 785 { 786 type_register_static(&qio_channel_socket_info); 787 } 788 789 type_init(qio_channel_socket_register_types); 790