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