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