char-socket: update local address after listen
[qemu.git] / chardev / char-socket.c
blobf24961ad1611dcffbb4b35d63e94e357b8dba975
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 *read_msgfds;
51 size_t read_msgfds_num;
52 int *write_msgfds;
53 size_t write_msgfds_num;
55 SocketAddress *addr;
56 bool is_listen;
57 bool is_telnet;
59 guint reconnect_timer;
60 int64_t reconnect_time;
61 bool connect_err_reported;
62 } SocketChardev;
64 #define SOCKET_CHARDEV(obj) \
65 OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
67 static gboolean socket_reconnect_timeout(gpointer opaque);
69 static void qemu_chr_socket_restart_timer(Chardev *chr)
71 SocketChardev *s = SOCKET_CHARDEV(chr);
72 char *name;
74 assert(s->connected == 0);
75 s->reconnect_timer = g_timeout_add_seconds(s->reconnect_time,
76 socket_reconnect_timeout, chr);
77 name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label);
78 g_source_set_name_by_id(s->reconnect_timer, name);
79 g_free(name);
82 static void check_report_connect_error(Chardev *chr,
83 Error *err)
85 SocketChardev *s = SOCKET_CHARDEV(chr);
87 if (!s->connect_err_reported) {
88 error_report("Unable to connect character device %s: %s",
89 chr->label, error_get_pretty(err));
90 s->connect_err_reported = true;
92 qemu_chr_socket_restart_timer(chr);
95 static gboolean tcp_chr_accept(QIOChannel *chan,
96 GIOCondition cond,
97 void *opaque);
99 static int tcp_chr_read_poll(void *opaque);
100 static void tcp_chr_disconnect(Chardev *chr);
102 /* Called with chr_write_lock held. */
103 static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
105 SocketChardev *s = SOCKET_CHARDEV(chr);
107 if (s->connected) {
108 int ret = io_channel_send_full(s->ioc, buf, len,
109 s->write_msgfds,
110 s->write_msgfds_num);
112 /* free the written msgfds, no matter what */
113 if (s->write_msgfds_num) {
114 g_free(s->write_msgfds);
115 s->write_msgfds = 0;
116 s->write_msgfds_num = 0;
119 if (ret < 0 && errno != EAGAIN) {
120 if (tcp_chr_read_poll(chr) <= 0) {
121 tcp_chr_disconnect(chr);
122 return len;
123 } /* else let the read handler finish it properly */
126 return ret;
127 } else {
128 /* XXX: indicate an error ? */
129 return len;
133 static int tcp_chr_read_poll(void *opaque)
135 Chardev *chr = CHARDEV(opaque);
136 SocketChardev *s = SOCKET_CHARDEV(opaque);
137 if (!s->connected) {
138 return 0;
140 s->max_size = qemu_chr_be_can_write(chr);
141 return s->max_size;
144 #define IAC 255
145 #define IAC_BREAK 243
146 static void tcp_chr_process_IAC_bytes(Chardev *chr,
147 SocketChardev *s,
148 uint8_t *buf, int *size)
150 /* Handle any telnet client's basic IAC options to satisfy char by
151 * char mode with no echo. All IAC options will be removed from
152 * the buf and the do_telnetopt variable will be used to track the
153 * state of the width of the IAC information.
155 * IAC commands come in sets of 3 bytes with the exception of the
156 * "IAC BREAK" command and the double IAC.
159 int i;
160 int j = 0;
162 for (i = 0; i < *size; i++) {
163 if (s->do_telnetopt > 1) {
164 if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
165 /* Double IAC means send an IAC */
166 if (j != i) {
167 buf[j] = buf[i];
169 j++;
170 s->do_telnetopt = 1;
171 } else {
172 if ((unsigned char)buf[i] == IAC_BREAK
173 && s->do_telnetopt == 2) {
174 /* Handle IAC break commands by sending a serial break */
175 qemu_chr_be_event(chr, CHR_EVENT_BREAK);
176 s->do_telnetopt++;
178 s->do_telnetopt++;
180 if (s->do_telnetopt >= 4) {
181 s->do_telnetopt = 1;
183 } else {
184 if ((unsigned char)buf[i] == IAC) {
185 s->do_telnetopt = 2;
186 } else {
187 if (j != i) {
188 buf[j] = buf[i];
190 j++;
194 *size = j;
197 static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
199 SocketChardev *s = SOCKET_CHARDEV(chr);
201 int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
203 assert(num <= TCP_MAX_FDS);
205 if (to_copy) {
206 int i;
208 memcpy(fds, s->read_msgfds, to_copy * sizeof(int));
210 /* Close unused fds */
211 for (i = to_copy; i < s->read_msgfds_num; i++) {
212 close(s->read_msgfds[i]);
215 g_free(s->read_msgfds);
216 s->read_msgfds = 0;
217 s->read_msgfds_num = 0;
220 return to_copy;
223 static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
225 SocketChardev *s = SOCKET_CHARDEV(chr);
227 /* clear old pending fd array */
228 g_free(s->write_msgfds);
229 s->write_msgfds = NULL;
230 s->write_msgfds_num = 0;
232 if (!s->connected ||
233 !qio_channel_has_feature(s->ioc,
234 QIO_CHANNEL_FEATURE_FD_PASS)) {
235 return -1;
238 if (num) {
239 s->write_msgfds = g_new(int, num);
240 memcpy(s->write_msgfds, fds, num * sizeof(int));
243 s->write_msgfds_num = num;
245 return 0;
248 static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
250 SocketChardev *s = SOCKET_CHARDEV(chr);
251 struct iovec iov = { .iov_base = buf, .iov_len = len };
252 int ret;
253 size_t i;
254 int *msgfds = NULL;
255 size_t msgfds_num = 0;
257 if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
258 ret = qio_channel_readv_full(s->ioc, &iov, 1,
259 &msgfds, &msgfds_num,
260 NULL);
261 } else {
262 ret = qio_channel_readv_full(s->ioc, &iov, 1,
263 NULL, NULL,
264 NULL);
267 if (ret == QIO_CHANNEL_ERR_BLOCK) {
268 errno = EAGAIN;
269 ret = -1;
270 } else if (ret == -1) {
271 errno = EIO;
274 if (msgfds_num) {
275 /* close and clean read_msgfds */
276 for (i = 0; i < s->read_msgfds_num; i++) {
277 close(s->read_msgfds[i]);
280 if (s->read_msgfds_num) {
281 g_free(s->read_msgfds);
284 s->read_msgfds = msgfds;
285 s->read_msgfds_num = msgfds_num;
288 for (i = 0; i < s->read_msgfds_num; i++) {
289 int fd = s->read_msgfds[i];
290 if (fd < 0) {
291 continue;
294 /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
295 qemu_set_block(fd);
297 #ifndef MSG_CMSG_CLOEXEC
298 qemu_set_cloexec(fd);
299 #endif
302 return ret;
305 static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
307 SocketChardev *s = SOCKET_CHARDEV(chr);
308 return qio_channel_create_watch(s->ioc, cond);
311 static void tcp_chr_free_connection(Chardev *chr)
313 SocketChardev *s = SOCKET_CHARDEV(chr);
314 int i;
316 if (!s->connected) {
317 return;
320 if (s->read_msgfds_num) {
321 for (i = 0; i < s->read_msgfds_num; i++) {
322 close(s->read_msgfds[i]);
324 g_free(s->read_msgfds);
325 s->read_msgfds = NULL;
326 s->read_msgfds_num = 0;
329 tcp_set_msgfds(chr, NULL, 0);
330 remove_fd_in_watch(chr, NULL);
331 object_unref(OBJECT(s->sioc));
332 s->sioc = NULL;
333 object_unref(OBJECT(s->ioc));
334 s->ioc = NULL;
335 g_free(chr->filename);
336 chr->filename = NULL;
337 s->connected = 0;
340 static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr,
341 bool is_listen, bool is_telnet)
343 switch (addr->type) {
344 case SOCKET_ADDRESS_KIND_INET:
345 return g_strdup_printf("%s%s:%s:%s%s", prefix,
346 is_telnet ? "telnet" : "tcp",
347 addr->u.inet.data->host,
348 addr->u.inet.data->port,
349 is_listen ? ",server" : "");
350 break;
351 case SOCKET_ADDRESS_KIND_UNIX:
352 return g_strdup_printf("%sunix:%s%s", prefix,
353 addr->u.q_unix.data->path,
354 is_listen ? ",server" : "");
355 break;
356 case SOCKET_ADDRESS_KIND_FD:
357 return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.data->str,
358 is_listen ? ",server" : "");
359 break;
360 case SOCKET_ADDRESS_KIND_VSOCK:
361 return g_strdup_printf("%svsock:%s:%s", prefix,
362 addr->u.vsock.data->cid,
363 addr->u.vsock.data->port);
364 default:
365 abort();
369 static void update_disconnected_filename(SocketChardev *s)
371 Chardev *chr = CHARDEV(s);
373 g_free(chr->filename);
374 chr->filename = SocketAddress_to_str("disconnected:", s->addr,
375 s->is_listen, s->is_telnet);
378 static void tcp_chr_disconnect(Chardev *chr)
380 SocketChardev *s = SOCKET_CHARDEV(chr);
382 if (!s->connected) {
383 return;
386 tcp_chr_free_connection(chr);
388 if (s->listen_ioc) {
389 s->listen_tag = qio_channel_add_watch(
390 QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
392 update_disconnected_filename(s);
393 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
394 if (s->reconnect_time) {
395 qemu_chr_socket_restart_timer(chr);
399 static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
401 Chardev *chr = CHARDEV(opaque);
402 SocketChardev *s = SOCKET_CHARDEV(opaque);
403 uint8_t buf[CHR_READ_BUF_LEN];
404 int len, size;
406 if (!s->connected || s->max_size <= 0) {
407 return TRUE;
409 len = sizeof(buf);
410 if (len > s->max_size) {
411 len = s->max_size;
413 size = tcp_chr_recv(chr, (void *)buf, len);
414 if (size == 0 || size == -1) {
415 /* connection closed */
416 tcp_chr_disconnect(chr);
417 } else if (size > 0) {
418 if (s->do_telnetopt) {
419 tcp_chr_process_IAC_bytes(chr, s, buf, &size);
421 if (size > 0) {
422 qemu_chr_be_write(chr, buf, size);
426 return TRUE;
429 static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
431 SocketChardev *s = SOCKET_CHARDEV(chr);
432 int size;
434 if (!s->connected) {
435 return 0;
438 size = tcp_chr_recv(chr, (void *) buf, len);
439 if (size == 0) {
440 /* connection closed */
441 tcp_chr_disconnect(chr);
444 return size;
447 static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
448 struct sockaddr_storage *ps, socklen_t ps_len,
449 bool is_listen, bool is_telnet)
451 char shost[NI_MAXHOST], sserv[NI_MAXSERV];
452 char phost[NI_MAXHOST], pserv[NI_MAXSERV];
453 const char *left = "", *right = "";
455 switch (ss->ss_family) {
456 #ifndef _WIN32
457 case AF_UNIX:
458 return g_strdup_printf("unix:%s%s",
459 ((struct sockaddr_un *)(ss))->sun_path,
460 is_listen ? ",server" : "");
461 #endif
462 case AF_INET6:
463 left = "[";
464 right = "]";
465 /* fall through */
466 case AF_INET:
467 getnameinfo((struct sockaddr *) ss, ss_len, shost, sizeof(shost),
468 sserv, sizeof(sserv), NI_NUMERICHOST | NI_NUMERICSERV);
469 getnameinfo((struct sockaddr *) ps, ps_len, phost, sizeof(phost),
470 pserv, sizeof(pserv), NI_NUMERICHOST | NI_NUMERICSERV);
471 return g_strdup_printf("%s:%s%s%s:%s%s <-> %s%s%s:%s",
472 is_telnet ? "telnet" : "tcp",
473 left, shost, right, sserv,
474 is_listen ? ",server" : "",
475 left, phost, right, pserv);
477 default:
478 return g_strdup_printf("unknown");
482 static void tcp_chr_connect(void *opaque)
484 Chardev *chr = CHARDEV(opaque);
485 SocketChardev *s = SOCKET_CHARDEV(opaque);
487 g_free(chr->filename);
488 chr->filename = sockaddr_to_str(
489 &s->sioc->localAddr, s->sioc->localAddrLen,
490 &s->sioc->remoteAddr, s->sioc->remoteAddrLen,
491 s->is_listen, s->is_telnet);
493 s->connected = 1;
494 if (s->ioc) {
495 chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
496 tcp_chr_read_poll,
497 tcp_chr_read,
498 chr, NULL);
500 qemu_chr_be_event(chr, CHR_EVENT_OPENED);
503 static void tcp_chr_update_read_handler(Chardev *chr,
504 GMainContext *context)
506 SocketChardev *s = SOCKET_CHARDEV(chr);
508 if (!s->connected) {
509 return;
512 remove_fd_in_watch(chr, NULL);
513 if (s->ioc) {
514 chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
515 tcp_chr_read_poll,
516 tcp_chr_read, chr,
517 context);
521 typedef struct {
522 Chardev *chr;
523 char buf[12];
524 size_t buflen;
525 } TCPChardevTelnetInit;
527 static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
528 GIOCondition cond G_GNUC_UNUSED,
529 gpointer user_data)
531 TCPChardevTelnetInit *init = user_data;
532 ssize_t ret;
534 ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
535 if (ret < 0) {
536 if (ret == QIO_CHANNEL_ERR_BLOCK) {
537 ret = 0;
538 } else {
539 tcp_chr_disconnect(init->chr);
540 return FALSE;
543 init->buflen -= ret;
545 if (init->buflen == 0) {
546 tcp_chr_connect(init->chr);
547 return FALSE;
550 memmove(init->buf, init->buf + ret, init->buflen);
552 return TRUE;
555 static void tcp_chr_telnet_init(Chardev *chr)
557 SocketChardev *s = SOCKET_CHARDEV(chr);
558 TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1);
559 size_t n = 0;
561 init->chr = chr;
562 init->buflen = 12;
564 #define IACSET(x, a, b, c) \
565 do { \
566 x[n++] = a; \
567 x[n++] = b; \
568 x[n++] = c; \
569 } while (0)
571 /* Prep the telnet negotion to put telnet in binary,
572 * no echo, single char mode */
573 IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
574 IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
575 IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
576 IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
578 #undef IACSET
580 qio_channel_add_watch(
581 s->ioc, G_IO_OUT,
582 tcp_chr_telnet_init_io,
583 init, NULL);
587 static void tcp_chr_tls_handshake(QIOTask *task,
588 gpointer user_data)
590 Chardev *chr = user_data;
591 SocketChardev *s = user_data;
593 if (qio_task_propagate_error(task, NULL)) {
594 tcp_chr_disconnect(chr);
595 } else {
596 if (s->do_telnetopt) {
597 tcp_chr_telnet_init(chr);
598 } else {
599 tcp_chr_connect(chr);
605 static void tcp_chr_tls_init(Chardev *chr)
607 SocketChardev *s = SOCKET_CHARDEV(chr);
608 QIOChannelTLS *tioc;
609 Error *err = NULL;
610 gchar *name;
612 if (s->is_listen) {
613 tioc = qio_channel_tls_new_server(
614 s->ioc, s->tls_creds,
615 NULL, /* XXX Use an ACL */
616 &err);
617 } else {
618 tioc = qio_channel_tls_new_client(
619 s->ioc, s->tls_creds,
620 s->addr->u.inet.data->host,
621 &err);
623 if (tioc == NULL) {
624 error_free(err);
625 tcp_chr_disconnect(chr);
626 return;
628 name = g_strdup_printf("chardev-tls-%s-%s",
629 s->is_listen ? "server" : "client",
630 chr->label);
631 qio_channel_set_name(QIO_CHANNEL(tioc), name);
632 g_free(name);
633 object_unref(OBJECT(s->ioc));
634 s->ioc = QIO_CHANNEL(tioc);
636 qio_channel_tls_handshake(tioc,
637 tcp_chr_tls_handshake,
638 chr,
639 NULL);
643 static void tcp_chr_set_client_ioc_name(Chardev *chr,
644 QIOChannelSocket *sioc)
646 SocketChardev *s = SOCKET_CHARDEV(chr);
647 char *name;
648 name = g_strdup_printf("chardev-tcp-%s-%s",
649 s->is_listen ? "server" : "client",
650 chr->label);
651 qio_channel_set_name(QIO_CHANNEL(sioc), name);
652 g_free(name);
656 static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
658 SocketChardev *s = SOCKET_CHARDEV(chr);
660 if (s->ioc != NULL) {
661 return -1;
664 s->ioc = QIO_CHANNEL(sioc);
665 object_ref(OBJECT(sioc));
666 s->sioc = sioc;
667 object_ref(OBJECT(sioc));
669 qio_channel_set_blocking(s->ioc, false, NULL);
671 if (s->do_nodelay) {
672 qio_channel_set_delay(s->ioc, false);
674 if (s->listen_tag) {
675 g_source_remove(s->listen_tag);
676 s->listen_tag = 0;
679 if (s->tls_creds) {
680 tcp_chr_tls_init(chr);
681 } else {
682 if (s->do_telnetopt) {
683 tcp_chr_telnet_init(chr);
684 } else {
685 tcp_chr_connect(chr);
689 return 0;
693 static int tcp_chr_add_client(Chardev *chr, int fd)
695 int ret;
696 QIOChannelSocket *sioc;
698 sioc = qio_channel_socket_new_fd(fd, NULL);
699 if (!sioc) {
700 return -1;
702 tcp_chr_set_client_ioc_name(chr, sioc);
703 ret = tcp_chr_new_client(chr, sioc);
704 object_unref(OBJECT(sioc));
705 return ret;
708 static gboolean tcp_chr_accept(QIOChannel *channel,
709 GIOCondition cond,
710 void *opaque)
712 Chardev *chr = CHARDEV(opaque);
713 QIOChannelSocket *sioc;
715 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel),
716 NULL);
717 if (!sioc) {
718 return TRUE;
721 tcp_chr_new_client(chr, sioc);
723 object_unref(OBJECT(sioc));
725 return TRUE;
728 static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
730 SocketChardev *s = SOCKET_CHARDEV(chr);
731 QIOChannelSocket *sioc;
733 /* It can't wait on s->connected, since it is set asynchronously
734 * in TLS and telnet cases, only wait for an accepted socket */
735 while (!s->ioc) {
736 if (s->is_listen) {
737 error_report("QEMU waiting for connection on: %s",
738 chr->filename);
739 qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
740 tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
741 qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
742 } else {
743 sioc = qio_channel_socket_new();
744 tcp_chr_set_client_ioc_name(chr, sioc);
745 if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
746 object_unref(OBJECT(sioc));
747 return -1;
749 tcp_chr_new_client(chr, sioc);
750 object_unref(OBJECT(sioc));
754 return 0;
757 static void char_socket_finalize(Object *obj)
759 Chardev *chr = CHARDEV(obj);
760 SocketChardev *s = SOCKET_CHARDEV(obj);
762 tcp_chr_free_connection(chr);
764 if (s->reconnect_timer) {
765 g_source_remove(s->reconnect_timer);
766 s->reconnect_timer = 0;
768 qapi_free_SocketAddress(s->addr);
769 if (s->listen_tag) {
770 g_source_remove(s->listen_tag);
771 s->listen_tag = 0;
773 if (s->listen_ioc) {
774 object_unref(OBJECT(s->listen_ioc));
776 if (s->tls_creds) {
777 object_unref(OBJECT(s->tls_creds));
780 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
783 static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
785 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
786 Chardev *chr = CHARDEV(opaque);
787 SocketChardev *s = SOCKET_CHARDEV(chr);
788 Error *err = NULL;
790 if (qio_task_propagate_error(task, &err)) {
791 check_report_connect_error(chr, err);
792 error_free(err);
793 goto cleanup;
796 s->connect_err_reported = false;
797 tcp_chr_new_client(chr, sioc);
799 cleanup:
800 object_unref(OBJECT(sioc));
803 static gboolean socket_reconnect_timeout(gpointer opaque)
805 Chardev *chr = CHARDEV(opaque);
806 SocketChardev *s = SOCKET_CHARDEV(opaque);
807 QIOChannelSocket *sioc;
809 s->reconnect_timer = 0;
811 if (chr->be_open) {
812 return false;
815 sioc = qio_channel_socket_new();
816 tcp_chr_set_client_ioc_name(chr, sioc);
817 qio_channel_socket_connect_async(sioc, s->addr,
818 qemu_chr_socket_connected,
819 chr, NULL);
821 return false;
824 static void qmp_chardev_open_socket(Chardev *chr,
825 ChardevBackend *backend,
826 bool *be_opened,
827 Error **errp)
829 SocketChardev *s = SOCKET_CHARDEV(chr);
830 ChardevSocket *sock = backend->u.socket.data;
831 SocketAddress *addr = sock->addr;
832 bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
833 bool is_listen = sock->has_server ? sock->server : true;
834 bool is_telnet = sock->has_telnet ? sock->telnet : false;
835 bool is_waitconnect = sock->has_wait ? sock->wait : false;
836 int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
837 QIOChannelSocket *sioc = NULL;
839 s->is_listen = is_listen;
840 s->is_telnet = is_telnet;
841 s->do_nodelay = do_nodelay;
842 if (sock->tls_creds) {
843 Object *creds;
844 creds = object_resolve_path_component(
845 object_get_objects_root(), sock->tls_creds);
846 if (!creds) {
847 error_setg(errp, "No TLS credentials with id '%s'",
848 sock->tls_creds);
849 goto error;
851 s->tls_creds = (QCryptoTLSCreds *)
852 object_dynamic_cast(creds,
853 TYPE_QCRYPTO_TLS_CREDS);
854 if (!s->tls_creds) {
855 error_setg(errp, "Object with id '%s' is not TLS credentials",
856 sock->tls_creds);
857 goto error;
859 object_ref(OBJECT(s->tls_creds));
860 if (is_listen) {
861 if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
862 error_setg(errp, "%s",
863 "Expected TLS credentials for server endpoint");
864 goto error;
866 } else {
867 if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
868 error_setg(errp, "%s",
869 "Expected TLS credentials for client endpoint");
870 goto error;
875 s->addr = QAPI_CLONE(SocketAddress, sock->addr);
877 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
878 /* TODO SOCKET_ADDRESS_FD where fd has AF_UNIX */
879 if (addr->type == SOCKET_ADDRESS_KIND_UNIX) {
880 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
883 /* be isn't opened until we get a connection */
884 *be_opened = false;
886 update_disconnected_filename(s);
888 if (is_listen) {
889 if (is_telnet) {
890 s->do_telnetopt = 1;
892 } else if (reconnect > 0) {
893 s->reconnect_time = reconnect;
896 if (s->reconnect_time) {
897 sioc = qio_channel_socket_new();
898 tcp_chr_set_client_ioc_name(chr, sioc);
899 qio_channel_socket_connect_async(sioc, s->addr,
900 qemu_chr_socket_connected,
901 chr, NULL);
902 } else {
903 if (s->is_listen) {
904 char *name;
905 sioc = qio_channel_socket_new();
907 name = g_strdup_printf("chardev-tcp-listener-%s", chr->label);
908 qio_channel_set_name(QIO_CHANNEL(sioc), name);
909 g_free(name);
911 if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
912 goto error;
915 qapi_free_SocketAddress(s->addr);
916 s->addr = socket_local_address(sioc->fd, errp);
917 update_disconnected_filename(s);
919 s->listen_ioc = sioc;
920 if (is_waitconnect &&
921 qemu_chr_wait_connected(chr, errp) < 0) {
922 return;
924 if (!s->ioc) {
925 s->listen_tag = qio_channel_add_watch(
926 QIO_CHANNEL(s->listen_ioc), G_IO_IN,
927 tcp_chr_accept, chr, NULL);
929 } else if (qemu_chr_wait_connected(chr, errp) < 0) {
930 goto error;
934 return;
936 error:
937 if (sioc) {
938 object_unref(OBJECT(sioc));
942 static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
943 Error **errp)
945 bool is_listen = qemu_opt_get_bool(opts, "server", false);
946 bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true);
947 bool is_telnet = qemu_opt_get_bool(opts, "telnet", false);
948 bool do_nodelay = !qemu_opt_get_bool(opts, "delay", true);
949 int64_t reconnect = qemu_opt_get_number(opts, "reconnect", 0);
950 const char *path = qemu_opt_get(opts, "path");
951 const char *host = qemu_opt_get(opts, "host");
952 const char *port = qemu_opt_get(opts, "port");
953 const char *tls_creds = qemu_opt_get(opts, "tls-creds");
954 SocketAddress *addr;
955 ChardevSocket *sock;
957 backend->type = CHARDEV_BACKEND_KIND_SOCKET;
958 if (!path) {
959 if (!host) {
960 error_setg(errp, "chardev: socket: no host given");
961 return;
963 if (!port) {
964 error_setg(errp, "chardev: socket: no port given");
965 return;
967 } else {
968 if (tls_creds) {
969 error_setg(errp, "TLS can only be used over TCP socket");
970 return;
974 sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
975 qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
977 sock->has_nodelay = true;
978 sock->nodelay = do_nodelay;
979 sock->has_server = true;
980 sock->server = is_listen;
981 sock->has_telnet = true;
982 sock->telnet = is_telnet;
983 sock->has_wait = true;
984 sock->wait = is_waitconnect;
985 sock->has_reconnect = true;
986 sock->reconnect = reconnect;
987 sock->tls_creds = g_strdup(tls_creds);
989 addr = g_new0(SocketAddress, 1);
990 if (path) {
991 UnixSocketAddress *q_unix;
992 addr->type = SOCKET_ADDRESS_KIND_UNIX;
993 q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
994 q_unix->path = g_strdup(path);
995 } else {
996 addr->type = SOCKET_ADDRESS_KIND_INET;
997 addr->u.inet.data = g_new(InetSocketAddress, 1);
998 *addr->u.inet.data = (InetSocketAddress) {
999 .host = g_strdup(host),
1000 .port = g_strdup(port),
1001 .has_to = qemu_opt_get(opts, "to"),
1002 .to = qemu_opt_get_number(opts, "to", 0),
1003 .has_ipv4 = qemu_opt_get(opts, "ipv4"),
1004 .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
1005 .has_ipv6 = qemu_opt_get(opts, "ipv6"),
1006 .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
1009 sock->addr = addr;
1012 static void char_socket_class_init(ObjectClass *oc, void *data)
1014 ChardevClass *cc = CHARDEV_CLASS(oc);
1016 cc->parse = qemu_chr_parse_socket;
1017 cc->open = qmp_chardev_open_socket;
1018 cc->chr_wait_connected = tcp_chr_wait_connected;
1019 cc->chr_write = tcp_chr_write;
1020 cc->chr_sync_read = tcp_chr_sync_read;
1021 cc->chr_disconnect = tcp_chr_disconnect;
1022 cc->get_msgfds = tcp_get_msgfds;
1023 cc->set_msgfds = tcp_set_msgfds;
1024 cc->chr_add_client = tcp_chr_add_client;
1025 cc->chr_add_watch = tcp_chr_add_watch;
1026 cc->chr_update_read_handler = tcp_chr_update_read_handler;
1029 static const TypeInfo char_socket_type_info = {
1030 .name = TYPE_CHARDEV_SOCKET,
1031 .parent = TYPE_CHARDEV,
1032 .instance_size = sizeof(SocketChardev),
1033 .instance_finalize = char_socket_finalize,
1034 .class_init = char_socket_class_init,
1037 static void register_types(void)
1039 type_register_static(&char_socket_type_info);
1042 type_init(register_types);