tcx: remove page24 and cpage from tcx24_update_display()
[qemu/kevin.git] / chardev / char-socket.c
blob36ab0d633a7cfcc5a973096d218870d09194ad54
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 tcp_chr_disconnect(Chardev *chr)
371 SocketChardev *s = SOCKET_CHARDEV(chr);
373 if (!s->connected) {
374 return;
377 tcp_chr_free_connection(chr);
379 if (s->listen_ioc) {
380 s->listen_tag = qio_channel_add_watch(
381 QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
383 chr->filename = SocketAddress_to_str("disconnected:", s->addr,
384 s->is_listen, s->is_telnet);
385 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
386 if (s->reconnect_time) {
387 qemu_chr_socket_restart_timer(chr);
391 static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
393 Chardev *chr = CHARDEV(opaque);
394 SocketChardev *s = SOCKET_CHARDEV(opaque);
395 uint8_t buf[CHR_READ_BUF_LEN];
396 int len, size;
398 if (!s->connected || s->max_size <= 0) {
399 return TRUE;
401 len = sizeof(buf);
402 if (len > s->max_size) {
403 len = s->max_size;
405 size = tcp_chr_recv(chr, (void *)buf, len);
406 if (size == 0 || size == -1) {
407 /* connection closed */
408 tcp_chr_disconnect(chr);
409 } else if (size > 0) {
410 if (s->do_telnetopt) {
411 tcp_chr_process_IAC_bytes(chr, s, buf, &size);
413 if (size > 0) {
414 qemu_chr_be_write(chr, buf, size);
418 return TRUE;
421 static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
423 SocketChardev *s = SOCKET_CHARDEV(chr);
424 int size;
426 if (!s->connected) {
427 return 0;
430 size = tcp_chr_recv(chr, (void *) buf, len);
431 if (size == 0) {
432 /* connection closed */
433 tcp_chr_disconnect(chr);
436 return size;
439 static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
440 struct sockaddr_storage *ps, socklen_t ps_len,
441 bool is_listen, bool is_telnet)
443 char shost[NI_MAXHOST], sserv[NI_MAXSERV];
444 char phost[NI_MAXHOST], pserv[NI_MAXSERV];
445 const char *left = "", *right = "";
447 switch (ss->ss_family) {
448 #ifndef _WIN32
449 case AF_UNIX:
450 return g_strdup_printf("unix:%s%s",
451 ((struct sockaddr_un *)(ss))->sun_path,
452 is_listen ? ",server" : "");
453 #endif
454 case AF_INET6:
455 left = "[";
456 right = "]";
457 /* fall through */
458 case AF_INET:
459 getnameinfo((struct sockaddr *) ss, ss_len, shost, sizeof(shost),
460 sserv, sizeof(sserv), NI_NUMERICHOST | NI_NUMERICSERV);
461 getnameinfo((struct sockaddr *) ps, ps_len, phost, sizeof(phost),
462 pserv, sizeof(pserv), NI_NUMERICHOST | NI_NUMERICSERV);
463 return g_strdup_printf("%s:%s%s%s:%s%s <-> %s%s%s:%s",
464 is_telnet ? "telnet" : "tcp",
465 left, shost, right, sserv,
466 is_listen ? ",server" : "",
467 left, phost, right, pserv);
469 default:
470 return g_strdup_printf("unknown");
474 static void tcp_chr_connect(void *opaque)
476 Chardev *chr = CHARDEV(opaque);
477 SocketChardev *s = SOCKET_CHARDEV(opaque);
479 g_free(chr->filename);
480 chr->filename = sockaddr_to_str(
481 &s->sioc->localAddr, s->sioc->localAddrLen,
482 &s->sioc->remoteAddr, s->sioc->remoteAddrLen,
483 s->is_listen, s->is_telnet);
485 s->connected = 1;
486 if (s->ioc) {
487 chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
488 tcp_chr_read_poll,
489 tcp_chr_read,
490 chr, NULL);
492 qemu_chr_be_generic_open(chr);
495 static void tcp_chr_update_read_handler(Chardev *chr,
496 GMainContext *context)
498 SocketChardev *s = SOCKET_CHARDEV(chr);
500 if (!s->connected) {
501 return;
504 remove_fd_in_watch(chr, NULL);
505 if (s->ioc) {
506 chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
507 tcp_chr_read_poll,
508 tcp_chr_read, chr,
509 context);
513 typedef struct {
514 Chardev *chr;
515 char buf[12];
516 size_t buflen;
517 } TCPChardevTelnetInit;
519 static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
520 GIOCondition cond G_GNUC_UNUSED,
521 gpointer user_data)
523 TCPChardevTelnetInit *init = user_data;
524 ssize_t ret;
526 ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
527 if (ret < 0) {
528 if (ret == QIO_CHANNEL_ERR_BLOCK) {
529 ret = 0;
530 } else {
531 tcp_chr_disconnect(init->chr);
532 return FALSE;
535 init->buflen -= ret;
537 if (init->buflen == 0) {
538 tcp_chr_connect(init->chr);
539 return FALSE;
542 memmove(init->buf, init->buf + ret, init->buflen);
544 return TRUE;
547 static void tcp_chr_telnet_init(Chardev *chr)
549 SocketChardev *s = SOCKET_CHARDEV(chr);
550 TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1);
551 size_t n = 0;
553 init->chr = chr;
554 init->buflen = 12;
556 #define IACSET(x, a, b, c) \
557 do { \
558 x[n++] = a; \
559 x[n++] = b; \
560 x[n++] = c; \
561 } while (0)
563 /* Prep the telnet negotion to put telnet in binary,
564 * no echo, single char mode */
565 IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
566 IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
567 IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
568 IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
570 #undef IACSET
572 qio_channel_add_watch(
573 s->ioc, G_IO_OUT,
574 tcp_chr_telnet_init_io,
575 init, NULL);
579 static void tcp_chr_tls_handshake(QIOTask *task,
580 gpointer user_data)
582 Chardev *chr = user_data;
583 SocketChardev *s = user_data;
585 if (qio_task_propagate_error(task, NULL)) {
586 tcp_chr_disconnect(chr);
587 } else {
588 if (s->do_telnetopt) {
589 tcp_chr_telnet_init(chr);
590 } else {
591 tcp_chr_connect(chr);
597 static void tcp_chr_tls_init(Chardev *chr)
599 SocketChardev *s = SOCKET_CHARDEV(chr);
600 QIOChannelTLS *tioc;
601 Error *err = NULL;
602 gchar *name;
604 if (s->is_listen) {
605 tioc = qio_channel_tls_new_server(
606 s->ioc, s->tls_creds,
607 NULL, /* XXX Use an ACL */
608 &err);
609 } else {
610 tioc = qio_channel_tls_new_client(
611 s->ioc, s->tls_creds,
612 s->addr->u.inet.data->host,
613 &err);
615 if (tioc == NULL) {
616 error_free(err);
617 tcp_chr_disconnect(chr);
618 return;
620 name = g_strdup_printf("chardev-tls-%s-%s",
621 s->is_listen ? "server" : "client",
622 chr->label);
623 qio_channel_set_name(QIO_CHANNEL(tioc), name);
624 g_free(name);
625 object_unref(OBJECT(s->ioc));
626 s->ioc = QIO_CHANNEL(tioc);
628 qio_channel_tls_handshake(tioc,
629 tcp_chr_tls_handshake,
630 chr,
631 NULL);
635 static void tcp_chr_set_client_ioc_name(Chardev *chr,
636 QIOChannelSocket *sioc)
638 SocketChardev *s = SOCKET_CHARDEV(chr);
639 char *name;
640 name = g_strdup_printf("chardev-tcp-%s-%s",
641 s->is_listen ? "server" : "client",
642 chr->label);
643 qio_channel_set_name(QIO_CHANNEL(sioc), name);
644 g_free(name);
648 static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
650 SocketChardev *s = SOCKET_CHARDEV(chr);
652 if (s->ioc != NULL) {
653 return -1;
656 s->ioc = QIO_CHANNEL(sioc);
657 object_ref(OBJECT(sioc));
658 s->sioc = sioc;
659 object_ref(OBJECT(sioc));
661 qio_channel_set_blocking(s->ioc, false, NULL);
663 if (s->do_nodelay) {
664 qio_channel_set_delay(s->ioc, false);
666 if (s->listen_tag) {
667 g_source_remove(s->listen_tag);
668 s->listen_tag = 0;
671 if (s->tls_creds) {
672 tcp_chr_tls_init(chr);
673 } else {
674 if (s->do_telnetopt) {
675 tcp_chr_telnet_init(chr);
676 } else {
677 tcp_chr_connect(chr);
681 return 0;
685 static int tcp_chr_add_client(Chardev *chr, int fd)
687 int ret;
688 QIOChannelSocket *sioc;
690 sioc = qio_channel_socket_new_fd(fd, NULL);
691 if (!sioc) {
692 return -1;
694 tcp_chr_set_client_ioc_name(chr, sioc);
695 ret = tcp_chr_new_client(chr, sioc);
696 object_unref(OBJECT(sioc));
697 return ret;
700 static gboolean tcp_chr_accept(QIOChannel *channel,
701 GIOCondition cond,
702 void *opaque)
704 Chardev *chr = CHARDEV(opaque);
705 QIOChannelSocket *sioc;
707 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel),
708 NULL);
709 if (!sioc) {
710 return TRUE;
713 tcp_chr_new_client(chr, sioc);
715 object_unref(OBJECT(sioc));
717 return TRUE;
720 static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
722 SocketChardev *s = SOCKET_CHARDEV(chr);
723 QIOChannelSocket *sioc;
725 /* It can't wait on s->connected, since it is set asynchronously
726 * in TLS and telnet cases, only wait for an accepted socket */
727 while (!s->ioc) {
728 if (s->is_listen) {
729 error_report("QEMU waiting for connection on: %s",
730 chr->filename);
731 qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
732 tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
733 qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
734 } else {
735 sioc = qio_channel_socket_new();
736 tcp_chr_set_client_ioc_name(chr, sioc);
737 if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
738 object_unref(OBJECT(sioc));
739 return -1;
741 tcp_chr_new_client(chr, sioc);
742 object_unref(OBJECT(sioc));
746 return 0;
749 static void char_socket_finalize(Object *obj)
751 Chardev *chr = CHARDEV(obj);
752 SocketChardev *s = SOCKET_CHARDEV(obj);
754 tcp_chr_free_connection(chr);
756 if (s->reconnect_timer) {
757 g_source_remove(s->reconnect_timer);
758 s->reconnect_timer = 0;
760 qapi_free_SocketAddress(s->addr);
761 if (s->listen_tag) {
762 g_source_remove(s->listen_tag);
763 s->listen_tag = 0;
765 if (s->listen_ioc) {
766 object_unref(OBJECT(s->listen_ioc));
768 if (s->tls_creds) {
769 object_unref(OBJECT(s->tls_creds));
772 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
775 static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
777 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
778 Chardev *chr = CHARDEV(opaque);
779 SocketChardev *s = SOCKET_CHARDEV(chr);
780 Error *err = NULL;
782 if (qio_task_propagate_error(task, &err)) {
783 check_report_connect_error(chr, err);
784 error_free(err);
785 goto cleanup;
788 s->connect_err_reported = false;
789 tcp_chr_new_client(chr, sioc);
791 cleanup:
792 object_unref(OBJECT(sioc));
795 static gboolean socket_reconnect_timeout(gpointer opaque)
797 Chardev *chr = CHARDEV(opaque);
798 SocketChardev *s = SOCKET_CHARDEV(opaque);
799 QIOChannelSocket *sioc;
801 s->reconnect_timer = 0;
803 if (chr->be_open) {
804 return false;
807 sioc = qio_channel_socket_new();
808 tcp_chr_set_client_ioc_name(chr, sioc);
809 qio_channel_socket_connect_async(sioc, s->addr,
810 qemu_chr_socket_connected,
811 chr, NULL);
813 return false;
816 static void qmp_chardev_open_socket(Chardev *chr,
817 ChardevBackend *backend,
818 bool *be_opened,
819 Error **errp)
821 SocketChardev *s = SOCKET_CHARDEV(chr);
822 ChardevSocket *sock = backend->u.socket.data;
823 SocketAddress *addr = sock->addr;
824 bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
825 bool is_listen = sock->has_server ? sock->server : true;
826 bool is_telnet = sock->has_telnet ? sock->telnet : false;
827 bool is_waitconnect = sock->has_wait ? sock->wait : false;
828 int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
829 QIOChannelSocket *sioc = NULL;
831 s->is_listen = is_listen;
832 s->is_telnet = is_telnet;
833 s->do_nodelay = do_nodelay;
834 if (sock->tls_creds) {
835 Object *creds;
836 creds = object_resolve_path_component(
837 object_get_objects_root(), sock->tls_creds);
838 if (!creds) {
839 error_setg(errp, "No TLS credentials with id '%s'",
840 sock->tls_creds);
841 goto error;
843 s->tls_creds = (QCryptoTLSCreds *)
844 object_dynamic_cast(creds,
845 TYPE_QCRYPTO_TLS_CREDS);
846 if (!s->tls_creds) {
847 error_setg(errp, "Object with id '%s' is not TLS credentials",
848 sock->tls_creds);
849 goto error;
851 object_ref(OBJECT(s->tls_creds));
852 if (is_listen) {
853 if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
854 error_setg(errp, "%s",
855 "Expected TLS credentials for server endpoint");
856 goto error;
858 } else {
859 if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
860 error_setg(errp, "%s",
861 "Expected TLS credentials for client endpoint");
862 goto error;
867 s->addr = QAPI_CLONE(SocketAddress, sock->addr);
869 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
870 /* TODO SOCKET_ADDRESS_FD where fd has AF_UNIX */
871 if (addr->type == SOCKET_ADDRESS_KIND_UNIX) {
872 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
875 /* be isn't opened until we get a connection */
876 *be_opened = false;
878 chr->filename = SocketAddress_to_str("disconnected:",
879 addr, is_listen, is_telnet);
881 if (is_listen) {
882 if (is_telnet) {
883 s->do_telnetopt = 1;
885 } else if (reconnect > 0) {
886 s->reconnect_time = reconnect;
889 if (s->reconnect_time) {
890 sioc = qio_channel_socket_new();
891 tcp_chr_set_client_ioc_name(chr, sioc);
892 qio_channel_socket_connect_async(sioc, s->addr,
893 qemu_chr_socket_connected,
894 chr, NULL);
895 } else {
896 if (s->is_listen) {
897 char *name;
898 sioc = qio_channel_socket_new();
900 name = g_strdup_printf("chardev-tcp-listener-%s", chr->label);
901 qio_channel_set_name(QIO_CHANNEL(sioc), name);
902 g_free(name);
904 if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
905 goto error;
907 s->listen_ioc = sioc;
908 if (is_waitconnect &&
909 qemu_chr_wait_connected(chr, errp) < 0) {
910 return;
912 if (!s->ioc) {
913 s->listen_tag = qio_channel_add_watch(
914 QIO_CHANNEL(s->listen_ioc), G_IO_IN,
915 tcp_chr_accept, chr, NULL);
917 } else if (qemu_chr_wait_connected(chr, errp) < 0) {
918 goto error;
922 return;
924 error:
925 if (sioc) {
926 object_unref(OBJECT(sioc));
930 static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
931 Error **errp)
933 bool is_listen = qemu_opt_get_bool(opts, "server", false);
934 bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true);
935 bool is_telnet = qemu_opt_get_bool(opts, "telnet", false);
936 bool do_nodelay = !qemu_opt_get_bool(opts, "delay", true);
937 int64_t reconnect = qemu_opt_get_number(opts, "reconnect", 0);
938 const char *path = qemu_opt_get(opts, "path");
939 const char *host = qemu_opt_get(opts, "host");
940 const char *port = qemu_opt_get(opts, "port");
941 const char *tls_creds = qemu_opt_get(opts, "tls-creds");
942 SocketAddress *addr;
943 ChardevSocket *sock;
945 backend->type = CHARDEV_BACKEND_KIND_SOCKET;
946 if (!path) {
947 if (!host) {
948 error_setg(errp, "chardev: socket: no host given");
949 return;
951 if (!port) {
952 error_setg(errp, "chardev: socket: no port given");
953 return;
955 } else {
956 if (tls_creds) {
957 error_setg(errp, "TLS can only be used over TCP socket");
958 return;
962 sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
963 qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
965 sock->has_nodelay = true;
966 sock->nodelay = do_nodelay;
967 sock->has_server = true;
968 sock->server = is_listen;
969 sock->has_telnet = true;
970 sock->telnet = is_telnet;
971 sock->has_wait = true;
972 sock->wait = is_waitconnect;
973 sock->has_reconnect = true;
974 sock->reconnect = reconnect;
975 sock->tls_creds = g_strdup(tls_creds);
977 addr = g_new0(SocketAddress, 1);
978 if (path) {
979 UnixSocketAddress *q_unix;
980 addr->type = SOCKET_ADDRESS_KIND_UNIX;
981 q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
982 q_unix->path = g_strdup(path);
983 } else {
984 addr->type = SOCKET_ADDRESS_KIND_INET;
985 addr->u.inet.data = g_new(InetSocketAddress, 1);
986 *addr->u.inet.data = (InetSocketAddress) {
987 .host = g_strdup(host),
988 .port = g_strdup(port),
989 .has_to = qemu_opt_get(opts, "to"),
990 .to = qemu_opt_get_number(opts, "to", 0),
991 .has_ipv4 = qemu_opt_get(opts, "ipv4"),
992 .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
993 .has_ipv6 = qemu_opt_get(opts, "ipv6"),
994 .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
997 sock->addr = addr;
1000 static void char_socket_class_init(ObjectClass *oc, void *data)
1002 ChardevClass *cc = CHARDEV_CLASS(oc);
1004 cc->parse = qemu_chr_parse_socket;
1005 cc->open = qmp_chardev_open_socket;
1006 cc->chr_wait_connected = tcp_chr_wait_connected;
1007 cc->chr_write = tcp_chr_write;
1008 cc->chr_sync_read = tcp_chr_sync_read;
1009 cc->chr_disconnect = tcp_chr_disconnect;
1010 cc->get_msgfds = tcp_get_msgfds;
1011 cc->set_msgfds = tcp_set_msgfds;
1012 cc->chr_add_client = tcp_chr_add_client;
1013 cc->chr_add_watch = tcp_chr_add_watch;
1014 cc->chr_update_read_handler = tcp_chr_update_read_handler;
1017 static const TypeInfo char_socket_type_info = {
1018 .name = TYPE_CHARDEV_SOCKET,
1019 .parent = TYPE_CHARDEV,
1020 .instance_size = sizeof(SocketChardev),
1021 .instance_finalize = char_socket_finalize,
1022 .class_init = char_socket_class_init,
1025 static void register_types(void)
1027 type_register_static(&char_socket_type_info);
1030 type_init(register_types);