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