COLO: fix setting checkpoint-delay not working properly
[qemu/ar7.git] / chardev / char-socket.c
blob4068dc5e523672bda7bcf3a379b6a640c44782a5
1 /*
2 * QEMU System Emulator
4 * Copyright (c) 2003-2008 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include "qemu/osdep.h"
25 #include "sysemu/char.h"
26 #include "io/channel-socket.h"
27 #include "io/channel-tls.h"
28 #include "qemu/error-report.h"
29 #include "qapi/error.h"
30 #include "qapi/clone-visitor.h"
32 #include "char-io.h"
34 /***********************************************************/
35 /* TCP Net console */
37 #define TCP_MAX_FDS 16
39 typedef struct {
40 Chardev parent;
41 QIOChannel *ioc; /* Client I/O channel */
42 QIOChannelSocket *sioc; /* Client master channel */
43 QIOChannelSocket *listen_ioc;
44 guint listen_tag;
45 QCryptoTLSCreds *tls_creds;
46 int connected;
47 int max_size;
48 int do_telnetopt;
49 int do_nodelay;
50 int is_unix;
51 int *read_msgfds;
52 size_t read_msgfds_num;
53 int *write_msgfds;
54 size_t write_msgfds_num;
56 SocketAddress *addr;
57 bool is_listen;
58 bool is_telnet;
60 guint reconnect_timer;
61 int64_t reconnect_time;
62 bool connect_err_reported;
63 } SocketChardev;
65 #define SOCKET_CHARDEV(obj) \
66 OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
68 static gboolean socket_reconnect_timeout(gpointer opaque);
70 static void qemu_chr_socket_restart_timer(Chardev *chr)
72 SocketChardev *s = SOCKET_CHARDEV(chr);
73 char *name;
75 assert(s->connected == 0);
76 s->reconnect_timer = g_timeout_add_seconds(s->reconnect_time,
77 socket_reconnect_timeout, chr);
78 name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label);
79 g_source_set_name_by_id(s->reconnect_timer, name);
80 g_free(name);
83 static void check_report_connect_error(Chardev *chr,
84 Error *err)
86 SocketChardev *s = SOCKET_CHARDEV(chr);
88 if (!s->connect_err_reported) {
89 error_report("Unable to connect character device %s: %s",
90 chr->label, error_get_pretty(err));
91 s->connect_err_reported = true;
93 qemu_chr_socket_restart_timer(chr);
96 static gboolean tcp_chr_accept(QIOChannel *chan,
97 GIOCondition cond,
98 void *opaque);
100 /* Called with chr_write_lock held. */
101 static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
103 SocketChardev *s = SOCKET_CHARDEV(chr);
105 if (s->connected) {
106 int ret = io_channel_send_full(s->ioc, buf, len,
107 s->write_msgfds,
108 s->write_msgfds_num);
110 /* free the written msgfds, no matter what */
111 if (s->write_msgfds_num) {
112 g_free(s->write_msgfds);
113 s->write_msgfds = 0;
114 s->write_msgfds_num = 0;
117 return ret;
118 } else {
119 /* XXX: indicate an error ? */
120 return len;
124 static int tcp_chr_read_poll(void *opaque)
126 Chardev *chr = CHARDEV(opaque);
127 SocketChardev *s = SOCKET_CHARDEV(opaque);
128 if (!s->connected) {
129 return 0;
131 s->max_size = qemu_chr_be_can_write(chr);
132 return s->max_size;
135 #define IAC 255
136 #define IAC_BREAK 243
137 static void tcp_chr_process_IAC_bytes(Chardev *chr,
138 SocketChardev *s,
139 uint8_t *buf, int *size)
141 /* Handle any telnet client's basic IAC options to satisfy char by
142 * char mode with no echo. All IAC options will be removed from
143 * the buf and the do_telnetopt variable will be used to track the
144 * state of the width of the IAC information.
146 * IAC commands come in sets of 3 bytes with the exception of the
147 * "IAC BREAK" command and the double IAC.
150 int i;
151 int j = 0;
153 for (i = 0; i < *size; i++) {
154 if (s->do_telnetopt > 1) {
155 if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
156 /* Double IAC means send an IAC */
157 if (j != i) {
158 buf[j] = buf[i];
160 j++;
161 s->do_telnetopt = 1;
162 } else {
163 if ((unsigned char)buf[i] == IAC_BREAK
164 && s->do_telnetopt == 2) {
165 /* Handle IAC break commands by sending a serial break */
166 qemu_chr_be_event(chr, CHR_EVENT_BREAK);
167 s->do_telnetopt++;
169 s->do_telnetopt++;
171 if (s->do_telnetopt >= 4) {
172 s->do_telnetopt = 1;
174 } else {
175 if ((unsigned char)buf[i] == IAC) {
176 s->do_telnetopt = 2;
177 } else {
178 if (j != i) {
179 buf[j] = buf[i];
181 j++;
185 *size = j;
188 static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
190 SocketChardev *s = SOCKET_CHARDEV(chr);
192 int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
194 assert(num <= TCP_MAX_FDS);
196 if (to_copy) {
197 int i;
199 memcpy(fds, s->read_msgfds, to_copy * sizeof(int));
201 /* Close unused fds */
202 for (i = to_copy; i < s->read_msgfds_num; i++) {
203 close(s->read_msgfds[i]);
206 g_free(s->read_msgfds);
207 s->read_msgfds = 0;
208 s->read_msgfds_num = 0;
211 return to_copy;
214 static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
216 SocketChardev *s = SOCKET_CHARDEV(chr);
218 /* clear old pending fd array */
219 g_free(s->write_msgfds);
220 s->write_msgfds = NULL;
221 s->write_msgfds_num = 0;
223 if (!s->connected ||
224 !qio_channel_has_feature(s->ioc,
225 QIO_CHANNEL_FEATURE_FD_PASS)) {
226 return -1;
229 if (num) {
230 s->write_msgfds = g_new(int, num);
231 memcpy(s->write_msgfds, fds, num * sizeof(int));
234 s->write_msgfds_num = num;
236 return 0;
239 static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
241 SocketChardev *s = SOCKET_CHARDEV(chr);
242 struct iovec iov = { .iov_base = buf, .iov_len = len };
243 int ret;
244 size_t i;
245 int *msgfds = NULL;
246 size_t msgfds_num = 0;
248 if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
249 ret = qio_channel_readv_full(s->ioc, &iov, 1,
250 &msgfds, &msgfds_num,
251 NULL);
252 } else {
253 ret = qio_channel_readv_full(s->ioc, &iov, 1,
254 NULL, NULL,
255 NULL);
258 if (ret == QIO_CHANNEL_ERR_BLOCK) {
259 errno = EAGAIN;
260 ret = -1;
261 } else if (ret == -1) {
262 errno = EIO;
265 if (msgfds_num) {
266 /* close and clean read_msgfds */
267 for (i = 0; i < s->read_msgfds_num; i++) {
268 close(s->read_msgfds[i]);
271 if (s->read_msgfds_num) {
272 g_free(s->read_msgfds);
275 s->read_msgfds = msgfds;
276 s->read_msgfds_num = msgfds_num;
279 for (i = 0; i < s->read_msgfds_num; i++) {
280 int fd = s->read_msgfds[i];
281 if (fd < 0) {
282 continue;
285 /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
286 qemu_set_block(fd);
288 #ifndef MSG_CMSG_CLOEXEC
289 qemu_set_cloexec(fd);
290 #endif
293 return ret;
296 static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
298 SocketChardev *s = SOCKET_CHARDEV(chr);
299 return qio_channel_create_watch(s->ioc, cond);
302 static void tcp_chr_free_connection(Chardev *chr)
304 SocketChardev *s = SOCKET_CHARDEV(chr);
305 int i;
307 if (!s->connected) {
308 return;
311 if (s->read_msgfds_num) {
312 for (i = 0; i < s->read_msgfds_num; i++) {
313 close(s->read_msgfds[i]);
315 g_free(s->read_msgfds);
316 s->read_msgfds = NULL;
317 s->read_msgfds_num = 0;
320 tcp_set_msgfds(chr, NULL, 0);
321 remove_fd_in_watch(chr);
322 object_unref(OBJECT(s->sioc));
323 s->sioc = NULL;
324 object_unref(OBJECT(s->ioc));
325 s->ioc = NULL;
326 g_free(chr->filename);
327 chr->filename = NULL;
328 s->connected = 0;
331 static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr,
332 bool is_listen, bool is_telnet)
334 switch (addr->type) {
335 case SOCKET_ADDRESS_KIND_INET:
336 return g_strdup_printf("%s%s:%s:%s%s", prefix,
337 is_telnet ? "telnet" : "tcp",
338 addr->u.inet.data->host,
339 addr->u.inet.data->port,
340 is_listen ? ",server" : "");
341 break;
342 case SOCKET_ADDRESS_KIND_UNIX:
343 return g_strdup_printf("%sunix:%s%s", prefix,
344 addr->u.q_unix.data->path,
345 is_listen ? ",server" : "");
346 break;
347 case SOCKET_ADDRESS_KIND_FD:
348 return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.data->str,
349 is_listen ? ",server" : "");
350 break;
351 default:
352 abort();
356 static void tcp_chr_disconnect(Chardev *chr)
358 SocketChardev *s = SOCKET_CHARDEV(chr);
360 if (!s->connected) {
361 return;
364 tcp_chr_free_connection(chr);
366 if (s->listen_ioc) {
367 s->listen_tag = qio_channel_add_watch(
368 QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
370 chr->filename = SocketAddress_to_str("disconnected:", s->addr,
371 s->is_listen, s->is_telnet);
372 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
373 if (s->reconnect_time) {
374 qemu_chr_socket_restart_timer(chr);
378 static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
380 Chardev *chr = CHARDEV(opaque);
381 SocketChardev *s = SOCKET_CHARDEV(opaque);
382 uint8_t buf[CHR_READ_BUF_LEN];
383 int len, size;
385 if (!s->connected || s->max_size <= 0) {
386 return TRUE;
388 len = sizeof(buf);
389 if (len > s->max_size) {
390 len = s->max_size;
392 size = tcp_chr_recv(chr, (void *)buf, len);
393 if (size == 0 || size == -1) {
394 /* connection closed */
395 tcp_chr_disconnect(chr);
396 } else if (size > 0) {
397 if (s->do_telnetopt) {
398 tcp_chr_process_IAC_bytes(chr, s, buf, &size);
400 if (size > 0) {
401 qemu_chr_be_write(chr, buf, size);
405 return TRUE;
408 static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
410 SocketChardev *s = SOCKET_CHARDEV(chr);
411 int size;
413 if (!s->connected) {
414 return 0;
417 size = tcp_chr_recv(chr, (void *) buf, len);
418 if (size == 0) {
419 /* connection closed */
420 tcp_chr_disconnect(chr);
423 return size;
426 static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
427 struct sockaddr_storage *ps, socklen_t ps_len,
428 bool is_listen, bool is_telnet)
430 char shost[NI_MAXHOST], sserv[NI_MAXSERV];
431 char phost[NI_MAXHOST], pserv[NI_MAXSERV];
432 const char *left = "", *right = "";
434 switch (ss->ss_family) {
435 #ifndef _WIN32
436 case AF_UNIX:
437 return g_strdup_printf("unix:%s%s",
438 ((struct sockaddr_un *)(ss))->sun_path,
439 is_listen ? ",server" : "");
440 #endif
441 case AF_INET6:
442 left = "[";
443 right = "]";
444 /* fall through */
445 case AF_INET:
446 getnameinfo((struct sockaddr *) ss, ss_len, shost, sizeof(shost),
447 sserv, sizeof(sserv), NI_NUMERICHOST | NI_NUMERICSERV);
448 getnameinfo((struct sockaddr *) ps, ps_len, phost, sizeof(phost),
449 pserv, sizeof(pserv), NI_NUMERICHOST | NI_NUMERICSERV);
450 return g_strdup_printf("%s:%s%s%s:%s%s <-> %s%s%s:%s",
451 is_telnet ? "telnet" : "tcp",
452 left, shost, right, sserv,
453 is_listen ? ",server" : "",
454 left, phost, right, pserv);
456 default:
457 return g_strdup_printf("unknown");
461 static void tcp_chr_connect(void *opaque)
463 Chardev *chr = CHARDEV(opaque);
464 SocketChardev *s = SOCKET_CHARDEV(opaque);
466 g_free(chr->filename);
467 chr->filename = sockaddr_to_str(
468 &s->sioc->localAddr, s->sioc->localAddrLen,
469 &s->sioc->remoteAddr, s->sioc->remoteAddrLen,
470 s->is_listen, s->is_telnet);
472 s->connected = 1;
473 if (s->ioc) {
474 chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
475 tcp_chr_read_poll,
476 tcp_chr_read,
477 chr, NULL);
479 qemu_chr_be_generic_open(chr);
482 static void tcp_chr_update_read_handler(Chardev *chr,
483 GMainContext *context)
485 SocketChardev *s = SOCKET_CHARDEV(chr);
487 if (!s->connected) {
488 return;
491 remove_fd_in_watch(chr);
492 if (s->ioc) {
493 chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
494 tcp_chr_read_poll,
495 tcp_chr_read, chr,
496 context);
500 typedef struct {
501 Chardev *chr;
502 char buf[12];
503 size_t buflen;
504 } TCPChardevTelnetInit;
506 static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
507 GIOCondition cond G_GNUC_UNUSED,
508 gpointer user_data)
510 TCPChardevTelnetInit *init = user_data;
511 ssize_t ret;
513 ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
514 if (ret < 0) {
515 if (ret == QIO_CHANNEL_ERR_BLOCK) {
516 ret = 0;
517 } else {
518 tcp_chr_disconnect(init->chr);
519 return FALSE;
522 init->buflen -= ret;
524 if (init->buflen == 0) {
525 tcp_chr_connect(init->chr);
526 return FALSE;
529 memmove(init->buf, init->buf + ret, init->buflen);
531 return TRUE;
534 static void tcp_chr_telnet_init(Chardev *chr)
536 SocketChardev *s = SOCKET_CHARDEV(chr);
537 TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1);
538 size_t n = 0;
540 init->chr = chr;
541 init->buflen = 12;
543 #define IACSET(x, a, b, c) \
544 do { \
545 x[n++] = a; \
546 x[n++] = b; \
547 x[n++] = c; \
548 } while (0)
550 /* Prep the telnet negotion to put telnet in binary,
551 * no echo, single char mode */
552 IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
553 IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
554 IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
555 IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
557 #undef IACSET
559 qio_channel_add_watch(
560 s->ioc, G_IO_OUT,
561 tcp_chr_telnet_init_io,
562 init, NULL);
566 static void tcp_chr_tls_handshake(QIOTask *task,
567 gpointer user_data)
569 Chardev *chr = user_data;
570 SocketChardev *s = user_data;
572 if (qio_task_propagate_error(task, NULL)) {
573 tcp_chr_disconnect(chr);
574 } else {
575 if (s->do_telnetopt) {
576 tcp_chr_telnet_init(chr);
577 } else {
578 tcp_chr_connect(chr);
584 static void tcp_chr_tls_init(Chardev *chr)
586 SocketChardev *s = SOCKET_CHARDEV(chr);
587 QIOChannelTLS *tioc;
588 Error *err = NULL;
589 gchar *name;
591 if (s->is_listen) {
592 tioc = qio_channel_tls_new_server(
593 s->ioc, s->tls_creds,
594 NULL, /* XXX Use an ACL */
595 &err);
596 } else {
597 tioc = qio_channel_tls_new_client(
598 s->ioc, s->tls_creds,
599 s->addr->u.inet.data->host,
600 &err);
602 if (tioc == NULL) {
603 error_free(err);
604 tcp_chr_disconnect(chr);
605 return;
607 name = g_strdup_printf("chardev-tls-%s-%s",
608 s->is_listen ? "server" : "client",
609 chr->label);
610 qio_channel_set_name(QIO_CHANNEL(tioc), name);
611 g_free(name);
612 object_unref(OBJECT(s->ioc));
613 s->ioc = QIO_CHANNEL(tioc);
615 qio_channel_tls_handshake(tioc,
616 tcp_chr_tls_handshake,
617 chr,
618 NULL);
622 static void tcp_chr_set_client_ioc_name(Chardev *chr,
623 QIOChannelSocket *sioc)
625 SocketChardev *s = SOCKET_CHARDEV(chr);
626 char *name;
627 name = g_strdup_printf("chardev-tcp-%s-%s",
628 s->is_listen ? "server" : "client",
629 chr->label);
630 qio_channel_set_name(QIO_CHANNEL(sioc), name);
631 g_free(name);
635 static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
637 SocketChardev *s = SOCKET_CHARDEV(chr);
639 if (s->ioc != NULL) {
640 return -1;
643 s->ioc = QIO_CHANNEL(sioc);
644 object_ref(OBJECT(sioc));
645 s->sioc = sioc;
646 object_ref(OBJECT(sioc));
648 qio_channel_set_blocking(s->ioc, false, NULL);
650 if (s->do_nodelay) {
651 qio_channel_set_delay(s->ioc, false);
653 if (s->listen_tag) {
654 g_source_remove(s->listen_tag);
655 s->listen_tag = 0;
658 if (s->tls_creds) {
659 tcp_chr_tls_init(chr);
660 } else {
661 if (s->do_telnetopt) {
662 tcp_chr_telnet_init(chr);
663 } else {
664 tcp_chr_connect(chr);
668 return 0;
672 static int tcp_chr_add_client(Chardev *chr, int fd)
674 int ret;
675 QIOChannelSocket *sioc;
677 sioc = qio_channel_socket_new_fd(fd, NULL);
678 if (!sioc) {
679 return -1;
681 tcp_chr_set_client_ioc_name(chr, sioc);
682 ret = tcp_chr_new_client(chr, sioc);
683 object_unref(OBJECT(sioc));
684 return ret;
687 static gboolean tcp_chr_accept(QIOChannel *channel,
688 GIOCondition cond,
689 void *opaque)
691 Chardev *chr = CHARDEV(opaque);
692 QIOChannelSocket *sioc;
694 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel),
695 NULL);
696 if (!sioc) {
697 return TRUE;
700 tcp_chr_new_client(chr, sioc);
702 object_unref(OBJECT(sioc));
704 return TRUE;
707 static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
709 SocketChardev *s = SOCKET_CHARDEV(chr);
710 QIOChannelSocket *sioc;
712 /* It can't wait on s->connected, since it is set asynchronously
713 * in TLS and telnet cases, only wait for an accepted socket */
714 while (!s->ioc) {
715 if (s->is_listen) {
716 error_report("QEMU waiting for connection on: %s",
717 chr->filename);
718 qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
719 tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
720 qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
721 } else {
722 sioc = qio_channel_socket_new();
723 tcp_chr_set_client_ioc_name(chr, sioc);
724 if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
725 object_unref(OBJECT(sioc));
726 return -1;
728 tcp_chr_new_client(chr, sioc);
729 object_unref(OBJECT(sioc));
733 return 0;
736 static void char_socket_finalize(Object *obj)
738 Chardev *chr = CHARDEV(obj);
739 SocketChardev *s = SOCKET_CHARDEV(obj);
741 tcp_chr_free_connection(chr);
743 if (s->reconnect_timer) {
744 g_source_remove(s->reconnect_timer);
745 s->reconnect_timer = 0;
747 qapi_free_SocketAddress(s->addr);
748 if (s->listen_tag) {
749 g_source_remove(s->listen_tag);
750 s->listen_tag = 0;
752 if (s->listen_ioc) {
753 object_unref(OBJECT(s->listen_ioc));
755 if (s->tls_creds) {
756 object_unref(OBJECT(s->tls_creds));
759 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
762 static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
764 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
765 Chardev *chr = CHARDEV(opaque);
766 SocketChardev *s = SOCKET_CHARDEV(chr);
767 Error *err = NULL;
769 if (qio_task_propagate_error(task, &err)) {
770 check_report_connect_error(chr, err);
771 error_free(err);
772 goto cleanup;
775 s->connect_err_reported = false;
776 tcp_chr_new_client(chr, sioc);
778 cleanup:
779 object_unref(OBJECT(sioc));
782 static gboolean socket_reconnect_timeout(gpointer opaque)
784 Chardev *chr = CHARDEV(opaque);
785 SocketChardev *s = SOCKET_CHARDEV(opaque);
786 QIOChannelSocket *sioc;
788 s->reconnect_timer = 0;
790 if (chr->be_open) {
791 return false;
794 sioc = qio_channel_socket_new();
795 tcp_chr_set_client_ioc_name(chr, sioc);
796 qio_channel_socket_connect_async(sioc, s->addr,
797 qemu_chr_socket_connected,
798 chr, NULL);
800 return false;
803 static void qmp_chardev_open_socket(Chardev *chr,
804 ChardevBackend *backend,
805 bool *be_opened,
806 Error **errp)
808 SocketChardev *s = SOCKET_CHARDEV(chr);
809 ChardevSocket *sock = backend->u.socket.data;
810 SocketAddress *addr = sock->addr;
811 bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
812 bool is_listen = sock->has_server ? sock->server : true;
813 bool is_telnet = sock->has_telnet ? sock->telnet : false;
814 bool is_waitconnect = sock->has_wait ? sock->wait : false;
815 int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
816 QIOChannelSocket *sioc = NULL;
818 s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
819 s->is_listen = is_listen;
820 s->is_telnet = is_telnet;
821 s->do_nodelay = do_nodelay;
822 if (sock->tls_creds) {
823 Object *creds;
824 creds = object_resolve_path_component(
825 object_get_objects_root(), sock->tls_creds);
826 if (!creds) {
827 error_setg(errp, "No TLS credentials with id '%s'",
828 sock->tls_creds);
829 goto error;
831 s->tls_creds = (QCryptoTLSCreds *)
832 object_dynamic_cast(creds,
833 TYPE_QCRYPTO_TLS_CREDS);
834 if (!s->tls_creds) {
835 error_setg(errp, "Object with id '%s' is not TLS credentials",
836 sock->tls_creds);
837 goto error;
839 object_ref(OBJECT(s->tls_creds));
840 if (is_listen) {
841 if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
842 error_setg(errp, "%s",
843 "Expected TLS credentials for server endpoint");
844 goto error;
846 } else {
847 if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
848 error_setg(errp, "%s",
849 "Expected TLS credentials for client endpoint");
850 goto error;
855 s->addr = QAPI_CLONE(SocketAddress, sock->addr);
857 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
858 if (s->is_unix) {
859 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
862 /* be isn't opened until we get a connection */
863 *be_opened = false;
865 chr->filename = SocketAddress_to_str("disconnected:",
866 addr, is_listen, is_telnet);
868 if (is_listen) {
869 if (is_telnet) {
870 s->do_telnetopt = 1;
872 } else if (reconnect > 0) {
873 s->reconnect_time = reconnect;
876 if (s->reconnect_time) {
877 sioc = qio_channel_socket_new();
878 tcp_chr_set_client_ioc_name(chr, sioc);
879 qio_channel_socket_connect_async(sioc, s->addr,
880 qemu_chr_socket_connected,
881 chr, NULL);
882 } else {
883 if (s->is_listen) {
884 char *name;
885 sioc = qio_channel_socket_new();
887 name = g_strdup_printf("chardev-tcp-listener-%s", chr->label);
888 qio_channel_set_name(QIO_CHANNEL(sioc), name);
889 g_free(name);
891 if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
892 goto error;
894 s->listen_ioc = sioc;
895 if (is_waitconnect &&
896 qemu_chr_wait_connected(chr, errp) < 0) {
897 return;
899 if (!s->ioc) {
900 s->listen_tag = qio_channel_add_watch(
901 QIO_CHANNEL(s->listen_ioc), G_IO_IN,
902 tcp_chr_accept, chr, NULL);
904 } else if (qemu_chr_wait_connected(chr, errp) < 0) {
905 goto error;
909 return;
911 error:
912 if (sioc) {
913 object_unref(OBJECT(sioc));
917 static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
918 Error **errp)
920 bool is_listen = qemu_opt_get_bool(opts, "server", false);
921 bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true);
922 bool is_telnet = qemu_opt_get_bool(opts, "telnet", false);
923 bool do_nodelay = !qemu_opt_get_bool(opts, "delay", true);
924 int64_t reconnect = qemu_opt_get_number(opts, "reconnect", 0);
925 const char *path = qemu_opt_get(opts, "path");
926 const char *host = qemu_opt_get(opts, "host");
927 const char *port = qemu_opt_get(opts, "port");
928 const char *tls_creds = qemu_opt_get(opts, "tls-creds");
929 SocketAddress *addr;
930 ChardevSocket *sock;
932 backend->type = CHARDEV_BACKEND_KIND_SOCKET;
933 if (!path) {
934 if (!host) {
935 error_setg(errp, "chardev: socket: no host given");
936 return;
938 if (!port) {
939 error_setg(errp, "chardev: socket: no port given");
940 return;
942 } else {
943 if (tls_creds) {
944 error_setg(errp, "TLS can only be used over TCP socket");
945 return;
949 sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
950 qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
952 sock->has_nodelay = true;
953 sock->nodelay = do_nodelay;
954 sock->has_server = true;
955 sock->server = is_listen;
956 sock->has_telnet = true;
957 sock->telnet = is_telnet;
958 sock->has_wait = true;
959 sock->wait = is_waitconnect;
960 sock->has_reconnect = true;
961 sock->reconnect = reconnect;
962 sock->tls_creds = g_strdup(tls_creds);
964 addr = g_new0(SocketAddress, 1);
965 if (path) {
966 UnixSocketAddress *q_unix;
967 addr->type = SOCKET_ADDRESS_KIND_UNIX;
968 q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
969 q_unix->path = g_strdup(path);
970 } else {
971 addr->type = SOCKET_ADDRESS_KIND_INET;
972 addr->u.inet.data = g_new(InetSocketAddress, 1);
973 *addr->u.inet.data = (InetSocketAddress) {
974 .host = g_strdup(host),
975 .port = g_strdup(port),
976 .has_to = qemu_opt_get(opts, "to"),
977 .to = qemu_opt_get_number(opts, "to", 0),
978 .has_ipv4 = qemu_opt_get(opts, "ipv4"),
979 .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
980 .has_ipv6 = qemu_opt_get(opts, "ipv6"),
981 .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
984 sock->addr = addr;
987 static void char_socket_class_init(ObjectClass *oc, void *data)
989 ChardevClass *cc = CHARDEV_CLASS(oc);
991 cc->parse = qemu_chr_parse_socket;
992 cc->open = qmp_chardev_open_socket;
993 cc->chr_wait_connected = tcp_chr_wait_connected;
994 cc->chr_write = tcp_chr_write;
995 cc->chr_sync_read = tcp_chr_sync_read;
996 cc->chr_disconnect = tcp_chr_disconnect;
997 cc->get_msgfds = tcp_get_msgfds;
998 cc->set_msgfds = tcp_set_msgfds;
999 cc->chr_add_client = tcp_chr_add_client;
1000 cc->chr_add_watch = tcp_chr_add_watch;
1001 cc->chr_update_read_handler = tcp_chr_update_read_handler;
1004 static const TypeInfo char_socket_type_info = {
1005 .name = TYPE_CHARDEV_SOCKET,
1006 .parent = TYPE_CHARDEV,
1007 .instance_size = sizeof(SocketChardev),
1008 .instance_finalize = char_socket_finalize,
1009 .class_init = char_socket_class_init,
1012 static void register_types(void)
1014 type_register_static(&char_socket_type_info);
1017 type_init(register_types);