xref: /qemu/io/channel-socket.c (revision 3fa27a9a)
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     if (ioc->fd != -1) {
404 #ifdef WIN32
405         WSAEventSelect(ioc->fd, NULL, 0);
406 #endif
407         closesocket(ioc->fd);
408         ioc->fd = -1;
409     }
410 }
411 
412 
413 #ifndef WIN32
414 static void qio_channel_socket_copy_fds(struct msghdr *msg,
415                                         int **fds, size_t *nfds)
416 {
417     struct cmsghdr *cmsg;
418 
419     *nfds = 0;
420     *fds = NULL;
421 
422     for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
423         int fd_size, i;
424         int gotfds;
425 
426         if (cmsg->cmsg_len < CMSG_LEN(sizeof(int)) ||
427             cmsg->cmsg_level != SOL_SOCKET ||
428             cmsg->cmsg_type != SCM_RIGHTS) {
429             continue;
430         }
431 
432         fd_size = cmsg->cmsg_len - CMSG_LEN(0);
433 
434         if (!fd_size) {
435             continue;
436         }
437 
438         gotfds = fd_size / sizeof(int);
439         *fds = g_renew(int, *fds, *nfds + gotfds);
440         memcpy(*fds + *nfds, CMSG_DATA(cmsg), fd_size);
441 
442         for (i = 0; i < gotfds; i++) {
443             int fd = (*fds)[*nfds + i];
444             if (fd < 0) {
445                 continue;
446             }
447 
448             /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
449             qemu_set_block(fd);
450 
451 #ifndef MSG_CMSG_CLOEXEC
452             qemu_set_cloexec(fd);
453 #endif
454         }
455         *nfds += gotfds;
456     }
457 }
458 
459 
460 static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
461                                         const struct iovec *iov,
462                                         size_t niov,
463                                         int **fds,
464                                         size_t *nfds,
465                                         Error **errp)
466 {
467     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
468     ssize_t ret;
469     struct msghdr msg = { NULL, };
470     char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)];
471     int sflags = 0;
472 
473     memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS));
474 
475 #ifdef MSG_CMSG_CLOEXEC
476     sflags |= MSG_CMSG_CLOEXEC;
477 #endif
478 
479     msg.msg_iov = (struct iovec *)iov;
480     msg.msg_iovlen = niov;
481     if (fds && nfds) {
482         msg.msg_control = control;
483         msg.msg_controllen = sizeof(control);
484     }
485 
486  retry:
487     ret = recvmsg(sioc->fd, &msg, sflags);
488     if (ret < 0) {
489         if (errno == EAGAIN) {
490             return QIO_CHANNEL_ERR_BLOCK;
491         }
492         if (errno == EINTR) {
493             goto retry;
494         }
495 
496         error_setg_errno(errp, errno,
497                          "Unable to read from socket");
498         return -1;
499     }
500 
501     if (fds && nfds) {
502         qio_channel_socket_copy_fds(&msg, fds, nfds);
503     }
504 
505     return ret;
506 }
507 
508 static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
509                                          const struct iovec *iov,
510                                          size_t niov,
511                                          int *fds,
512                                          size_t nfds,
513                                          Error **errp)
514 {
515     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
516     ssize_t ret;
517     struct msghdr msg = { NULL, };
518     char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)];
519     size_t fdsize = sizeof(int) * nfds;
520     struct cmsghdr *cmsg;
521 
522     memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS));
523 
524     msg.msg_iov = (struct iovec *)iov;
525     msg.msg_iovlen = niov;
526 
527     if (nfds) {
528         if (nfds > SOCKET_MAX_FDS) {
529             error_setg_errno(errp, EINVAL,
530                              "Only %d FDs can be sent, got %zu",
531                              SOCKET_MAX_FDS, nfds);
532             return -1;
533         }
534 
535         msg.msg_control = control;
536         msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfds);
537 
538         cmsg = CMSG_FIRSTHDR(&msg);
539         cmsg->cmsg_len = CMSG_LEN(fdsize);
540         cmsg->cmsg_level = SOL_SOCKET;
541         cmsg->cmsg_type = SCM_RIGHTS;
542         memcpy(CMSG_DATA(cmsg), fds, fdsize);
543     }
544 
545  retry:
546     ret = sendmsg(sioc->fd, &msg, 0);
547     if (ret <= 0) {
548         if (errno == EAGAIN) {
549             return QIO_CHANNEL_ERR_BLOCK;
550         }
551         if (errno == EINTR) {
552             goto retry;
553         }
554         error_setg_errno(errp, errno,
555                          "Unable to write to socket");
556         return -1;
557     }
558     return ret;
559 }
560 #else /* WIN32 */
561 static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
562                                         const struct iovec *iov,
563                                         size_t niov,
564                                         int **fds,
565                                         size_t *nfds,
566                                         Error **errp)
567 {
568     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
569     ssize_t done = 0;
570     ssize_t i;
571 
572     for (i = 0; i < niov; i++) {
573         ssize_t ret;
574     retry:
575         ret = recv(sioc->fd,
576                    iov[i].iov_base,
577                    iov[i].iov_len,
578                    0);
579         if (ret < 0) {
580             if (errno == EAGAIN) {
581                 if (done) {
582                     return done;
583                 } else {
584                     return QIO_CHANNEL_ERR_BLOCK;
585                 }
586             } else if (errno == EINTR) {
587                 goto retry;
588             } else {
589                 error_setg_errno(errp, errno,
590                                  "Unable to read from socket");
591                 return -1;
592             }
593         }
594         done += ret;
595         if (ret < iov[i].iov_len) {
596             return done;
597         }
598     }
599 
600     return done;
601 }
602 
603 static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
604                                          const struct iovec *iov,
605                                          size_t niov,
606                                          int *fds,
607                                          size_t nfds,
608                                          Error **errp)
609 {
610     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
611     ssize_t done = 0;
612     ssize_t i;
613 
614     for (i = 0; i < niov; i++) {
615         ssize_t ret;
616     retry:
617         ret = send(sioc->fd,
618                    iov[i].iov_base,
619                    iov[i].iov_len,
620                    0);
621         if (ret < 0) {
622             if (errno == EAGAIN) {
623                 if (done) {
624                     return done;
625                 } else {
626                     return QIO_CHANNEL_ERR_BLOCK;
627                 }
628             } else if (errno == EINTR) {
629                 goto retry;
630             } else {
631                 error_setg_errno(errp, errno,
632                                  "Unable to write to socket");
633                 return -1;
634             }
635         }
636         done += ret;
637         if (ret < iov[i].iov_len) {
638             return done;
639         }
640     }
641 
642     return done;
643 }
644 #endif /* WIN32 */
645 
646 static int
647 qio_channel_socket_set_blocking(QIOChannel *ioc,
648                                 bool enabled,
649                                 Error **errp)
650 {
651     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
652 
653     if (enabled) {
654         qemu_set_block(sioc->fd);
655     } else {
656         qemu_set_nonblock(sioc->fd);
657 #ifdef WIN32
658         WSAEventSelect(sioc->fd, ioc->event,
659                        FD_READ | FD_ACCEPT | FD_CLOSE |
660                        FD_CONNECT | FD_WRITE | FD_OOB);
661 #endif
662     }
663     return 0;
664 }
665 
666 
667 static void
668 qio_channel_socket_set_delay(QIOChannel *ioc,
669                              bool enabled)
670 {
671     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
672     int v = enabled ? 0 : 1;
673 
674     qemu_setsockopt(sioc->fd,
675                     IPPROTO_TCP, TCP_NODELAY,
676                     &v, sizeof(v));
677 }
678 
679 
680 static void
681 qio_channel_socket_set_cork(QIOChannel *ioc,
682                             bool enabled)
683 {
684     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
685     int v = enabled ? 1 : 0;
686 
687     socket_set_cork(sioc->fd, v);
688 }
689 
690 
691 static int
692 qio_channel_socket_close(QIOChannel *ioc,
693                          Error **errp)
694 {
695     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
696 
697     if (sioc->fd != -1) {
698 #ifdef WIN32
699         WSAEventSelect(sioc->fd, NULL, 0);
700 #endif
701         if (closesocket(sioc->fd) < 0) {
702             sioc->fd = -1;
703             error_setg_errno(errp, errno,
704                              "Unable to close socket");
705             return -1;
706         }
707         sioc->fd = -1;
708     }
709     return 0;
710 }
711 
712 static int
713 qio_channel_socket_shutdown(QIOChannel *ioc,
714                             QIOChannelShutdown how,
715                             Error **errp)
716 {
717     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
718     int sockhow;
719 
720     switch (how) {
721     case QIO_CHANNEL_SHUTDOWN_READ:
722         sockhow = SHUT_RD;
723         break;
724     case QIO_CHANNEL_SHUTDOWN_WRITE:
725         sockhow = SHUT_WR;
726         break;
727     case QIO_CHANNEL_SHUTDOWN_BOTH:
728     default:
729         sockhow = SHUT_RDWR;
730         break;
731     }
732 
733     if (shutdown(sioc->fd, sockhow) < 0) {
734         error_setg_errno(errp, errno,
735                          "Unable to shutdown socket");
736         return -1;
737     }
738     return 0;
739 }
740 
741 static GSource *qio_channel_socket_create_watch(QIOChannel *ioc,
742                                                 GIOCondition condition)
743 {
744     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
745     return qio_channel_create_socket_watch(ioc,
746                                            sioc->fd,
747                                            condition);
748 }
749 
750 static void qio_channel_socket_class_init(ObjectClass *klass,
751                                           void *class_data G_GNUC_UNUSED)
752 {
753     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
754 
755     ioc_klass->io_writev = qio_channel_socket_writev;
756     ioc_klass->io_readv = qio_channel_socket_readv;
757     ioc_klass->io_set_blocking = qio_channel_socket_set_blocking;
758     ioc_klass->io_close = qio_channel_socket_close;
759     ioc_klass->io_shutdown = qio_channel_socket_shutdown;
760     ioc_klass->io_set_cork = qio_channel_socket_set_cork;
761     ioc_klass->io_set_delay = qio_channel_socket_set_delay;
762     ioc_klass->io_create_watch = qio_channel_socket_create_watch;
763 }
764 
765 static const TypeInfo qio_channel_socket_info = {
766     .parent = TYPE_QIO_CHANNEL,
767     .name = TYPE_QIO_CHANNEL_SOCKET,
768     .instance_size = sizeof(QIOChannelSocket),
769     .instance_init = qio_channel_socket_init,
770     .instance_finalize = qio_channel_socket_finalize,
771     .class_init = qio_channel_socket_class_init,
772 };
773 
774 static void qio_channel_socket_register_types(void)
775 {
776     type_register_static(&qio_channel_socket_info);
777 }
778 
779 type_init(qio_channel_socket_register_types);
780