chardev: honour the reconnect setting in tcp_chr_wait_connected
[qemu/ar7.git] / chardev / char-socket.c
blob7db20ff0a0266586a7501d6a69071a1efb8bb170
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.
25 #include "qemu/osdep.h"
26 #include "chardev/char.h"
27 #include "io/channel-socket.h"
28 #include "io/channel-tls.h"
29 #include "io/channel-websock.h"
30 #include "io/net-listener.h"
31 #include "qemu/error-report.h"
32 #include "qemu/option.h"
33 #include "qapi/error.h"
34 #include "qapi/clone-visitor.h"
35 #include "qapi/qapi-visit-sockets.h"
37 #include "chardev/char-io.h"
39 /***********************************************************/
40 /* TCP Net console */
42 #define TCP_MAX_FDS 16
44 typedef struct {
45 char buf[21];
46 size_t buflen;
47 } TCPChardevTelnetInit;
49 typedef enum {
50 TCP_CHARDEV_STATE_DISCONNECTED,
51 TCP_CHARDEV_STATE_CONNECTING,
52 TCP_CHARDEV_STATE_CONNECTED,
53 } TCPChardevState;
55 typedef struct {
56 Chardev parent;
57 QIOChannel *ioc; /* Client I/O channel */
58 QIOChannelSocket *sioc; /* Client master channel */
59 QIONetListener *listener;
60 GSource *hup_source;
61 QCryptoTLSCreds *tls_creds;
62 TCPChardevState state;
63 int max_size;
64 int do_telnetopt;
65 int do_nodelay;
66 int *read_msgfds;
67 size_t read_msgfds_num;
68 int *write_msgfds;
69 size_t write_msgfds_num;
71 SocketAddress *addr;
72 bool is_listen;
73 bool is_telnet;
74 bool is_tn3270;
75 GSource *telnet_source;
76 TCPChardevTelnetInit *telnet_init;
78 bool is_websock;
80 GSource *reconnect_timer;
81 int64_t reconnect_time;
82 bool connect_err_reported;
83 } SocketChardev;
85 #define SOCKET_CHARDEV(obj) \
86 OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
88 static gboolean socket_reconnect_timeout(gpointer opaque);
89 static void tcp_chr_telnet_init(Chardev *chr);
91 static void tcp_chr_change_state(SocketChardev *s, TCPChardevState state)
93 switch (state) {
94 case TCP_CHARDEV_STATE_DISCONNECTED:
95 break;
96 case TCP_CHARDEV_STATE_CONNECTING:
97 assert(s->state == TCP_CHARDEV_STATE_DISCONNECTED);
98 break;
99 case TCP_CHARDEV_STATE_CONNECTED:
100 assert(s->state == TCP_CHARDEV_STATE_CONNECTING);
101 break;
103 s->state = state;
106 static void tcp_chr_reconn_timer_cancel(SocketChardev *s)
108 if (s->reconnect_timer) {
109 g_source_destroy(s->reconnect_timer);
110 g_source_unref(s->reconnect_timer);
111 s->reconnect_timer = NULL;
115 static void qemu_chr_socket_restart_timer(Chardev *chr)
117 SocketChardev *s = SOCKET_CHARDEV(chr);
118 char *name;
120 assert(s->state == TCP_CHARDEV_STATE_DISCONNECTED);
121 name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label);
122 s->reconnect_timer = qemu_chr_timeout_add_ms(chr,
123 s->reconnect_time * 1000,
124 socket_reconnect_timeout,
125 chr);
126 g_source_set_name(s->reconnect_timer, name);
127 g_free(name);
130 static void check_report_connect_error(Chardev *chr,
131 Error *err)
133 SocketChardev *s = SOCKET_CHARDEV(chr);
135 if (!s->connect_err_reported) {
136 error_report("Unable to connect character device %s: %s",
137 chr->label, error_get_pretty(err));
138 s->connect_err_reported = true;
140 qemu_chr_socket_restart_timer(chr);
143 static void tcp_chr_accept(QIONetListener *listener,
144 QIOChannelSocket *cioc,
145 void *opaque);
147 static int tcp_chr_read_poll(void *opaque);
148 static void tcp_chr_disconnect(Chardev *chr);
150 /* Called with chr_write_lock held. */
151 static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
153 SocketChardev *s = SOCKET_CHARDEV(chr);
155 if (s->state == TCP_CHARDEV_STATE_CONNECTED) {
156 int ret = io_channel_send_full(s->ioc, buf, len,
157 s->write_msgfds,
158 s->write_msgfds_num);
160 /* free the written msgfds in any cases
161 * other than ret < 0 && errno == EAGAIN
163 if (!(ret < 0 && EAGAIN == errno)
164 && s->write_msgfds_num) {
165 g_free(s->write_msgfds);
166 s->write_msgfds = 0;
167 s->write_msgfds_num = 0;
170 if (ret < 0 && errno != EAGAIN) {
171 if (tcp_chr_read_poll(chr) <= 0) {
172 tcp_chr_disconnect(chr);
173 return len;
174 } /* else let the read handler finish it properly */
177 return ret;
178 } else {
179 /* XXX: indicate an error ? */
180 return len;
184 static int tcp_chr_read_poll(void *opaque)
186 Chardev *chr = CHARDEV(opaque);
187 SocketChardev *s = SOCKET_CHARDEV(opaque);
188 if (s->state != TCP_CHARDEV_STATE_CONNECTED) {
189 return 0;
191 s->max_size = qemu_chr_be_can_write(chr);
192 return s->max_size;
195 static void tcp_chr_process_IAC_bytes(Chardev *chr,
196 SocketChardev *s,
197 uint8_t *buf, int *size)
199 /* Handle any telnet or tn3270 client's basic IAC options.
200 * For telnet options, it satisfies char by char mode with no echo.
201 * For tn3270 options, it satisfies binary mode with EOR.
202 * All IAC options will be removed from the buf and the do_opt
203 * pointer will be used to track the state of the width of the
204 * IAC information.
206 * RFC854: "All TELNET commands consist of at least a two byte sequence.
207 * The commands dealing with option negotiation are three byte sequences,
208 * the third byte being the code for the option referenced."
209 * "IAC BREAK", "IAC IP", "IAC NOP" and the double IAC are two bytes.
210 * "IAC SB", "IAC SE" and "IAC EOR" are saved to split up data boundary
211 * for tn3270.
212 * NOP, Break and Interrupt Process(IP) might be encountered during a TN3270
213 * session, and NOP and IP need to be done later.
216 int i;
217 int j = 0;
219 for (i = 0; i < *size; i++) {
220 if (s->do_telnetopt > 1) {
221 if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
222 /* Double IAC means send an IAC */
223 if (j != i) {
224 buf[j] = buf[i];
226 j++;
227 s->do_telnetopt = 1;
228 } else {
229 if ((unsigned char)buf[i] == IAC_BREAK
230 && s->do_telnetopt == 2) {
231 /* Handle IAC break commands by sending a serial break */
232 qemu_chr_be_event(chr, CHR_EVENT_BREAK);
233 s->do_telnetopt++;
234 } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_EOR
235 || (unsigned char)buf[i] == IAC_SB
236 || (unsigned char)buf[i] == IAC_SE)
237 && s->do_telnetopt == 2) {
238 buf[j++] = IAC;
239 buf[j++] = buf[i];
240 s->do_telnetopt++;
241 } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_IP
242 || (unsigned char)buf[i] == IAC_NOP)
243 && s->do_telnetopt == 2) {
244 /* TODO: IP and NOP need to be implemented later. */
245 s->do_telnetopt++;
247 s->do_telnetopt++;
249 if (s->do_telnetopt >= 4) {
250 s->do_telnetopt = 1;
252 } else {
253 if ((unsigned char)buf[i] == IAC) {
254 s->do_telnetopt = 2;
255 } else {
256 if (j != i) {
257 buf[j] = buf[i];
259 j++;
263 *size = j;
266 static int tcp_get_msgfds(Chardev *chr, int *fds, int num)
268 SocketChardev *s = SOCKET_CHARDEV(chr);
270 int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
272 assert(num <= TCP_MAX_FDS);
274 if (to_copy) {
275 int i;
277 memcpy(fds, s->read_msgfds, to_copy * sizeof(int));
279 /* Close unused fds */
280 for (i = to_copy; i < s->read_msgfds_num; i++) {
281 close(s->read_msgfds[i]);
284 g_free(s->read_msgfds);
285 s->read_msgfds = 0;
286 s->read_msgfds_num = 0;
289 return to_copy;
292 static int tcp_set_msgfds(Chardev *chr, int *fds, int num)
294 SocketChardev *s = SOCKET_CHARDEV(chr);
296 /* clear old pending fd array */
297 g_free(s->write_msgfds);
298 s->write_msgfds = NULL;
299 s->write_msgfds_num = 0;
301 if ((s->state != TCP_CHARDEV_STATE_CONNECTED) ||
302 !qio_channel_has_feature(s->ioc,
303 QIO_CHANNEL_FEATURE_FD_PASS)) {
304 return -1;
307 if (num) {
308 s->write_msgfds = g_new(int, num);
309 memcpy(s->write_msgfds, fds, num * sizeof(int));
312 s->write_msgfds_num = num;
314 return 0;
317 static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
319 SocketChardev *s = SOCKET_CHARDEV(chr);
320 struct iovec iov = { .iov_base = buf, .iov_len = len };
321 int ret;
322 size_t i;
323 int *msgfds = NULL;
324 size_t msgfds_num = 0;
326 if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
327 ret = qio_channel_readv_full(s->ioc, &iov, 1,
328 &msgfds, &msgfds_num,
329 NULL);
330 } else {
331 ret = qio_channel_readv_full(s->ioc, &iov, 1,
332 NULL, NULL,
333 NULL);
336 if (ret == QIO_CHANNEL_ERR_BLOCK) {
337 errno = EAGAIN;
338 ret = -1;
339 } else if (ret == -1) {
340 errno = EIO;
343 if (msgfds_num) {
344 /* close and clean read_msgfds */
345 for (i = 0; i < s->read_msgfds_num; i++) {
346 close(s->read_msgfds[i]);
349 if (s->read_msgfds_num) {
350 g_free(s->read_msgfds);
353 s->read_msgfds = msgfds;
354 s->read_msgfds_num = msgfds_num;
357 for (i = 0; i < s->read_msgfds_num; i++) {
358 int fd = s->read_msgfds[i];
359 if (fd < 0) {
360 continue;
363 /* O_NONBLOCK is preserved across SCM_RIGHTS so reset it */
364 qemu_set_block(fd);
366 #ifndef MSG_CMSG_CLOEXEC
367 qemu_set_cloexec(fd);
368 #endif
371 return ret;
374 static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
376 SocketChardev *s = SOCKET_CHARDEV(chr);
377 return qio_channel_create_watch(s->ioc, cond);
380 static void remove_hup_source(SocketChardev *s)
382 if (s->hup_source != NULL) {
383 g_source_destroy(s->hup_source);
384 g_source_unref(s->hup_source);
385 s->hup_source = NULL;
389 static void tcp_chr_free_connection(Chardev *chr)
391 SocketChardev *s = SOCKET_CHARDEV(chr);
392 int i;
394 if (s->read_msgfds_num) {
395 for (i = 0; i < s->read_msgfds_num; i++) {
396 close(s->read_msgfds[i]);
398 g_free(s->read_msgfds);
399 s->read_msgfds = NULL;
400 s->read_msgfds_num = 0;
403 remove_hup_source(s);
405 tcp_set_msgfds(chr, NULL, 0);
406 remove_fd_in_watch(chr);
407 object_unref(OBJECT(s->sioc));
408 s->sioc = NULL;
409 object_unref(OBJECT(s->ioc));
410 s->ioc = NULL;
411 g_free(chr->filename);
412 chr->filename = NULL;
413 tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
416 static const char *qemu_chr_socket_protocol(SocketChardev *s)
418 if (s->is_telnet) {
419 return "telnet";
421 return s->is_websock ? "websocket" : "tcp";
424 static char *qemu_chr_socket_address(SocketChardev *s, const char *prefix)
426 switch (s->addr->type) {
427 case SOCKET_ADDRESS_TYPE_INET:
428 return g_strdup_printf("%s%s:%s:%s%s", prefix,
429 qemu_chr_socket_protocol(s),
430 s->addr->u.inet.host,
431 s->addr->u.inet.port,
432 s->is_listen ? ",server" : "");
433 break;
434 case SOCKET_ADDRESS_TYPE_UNIX:
435 return g_strdup_printf("%sunix:%s%s", prefix,
436 s->addr->u.q_unix.path,
437 s->is_listen ? ",server" : "");
438 break;
439 case SOCKET_ADDRESS_TYPE_FD:
440 return g_strdup_printf("%sfd:%s%s", prefix, s->addr->u.fd.str,
441 s->is_listen ? ",server" : "");
442 break;
443 case SOCKET_ADDRESS_TYPE_VSOCK:
444 return g_strdup_printf("%svsock:%s:%s", prefix,
445 s->addr->u.vsock.cid,
446 s->addr->u.vsock.port);
447 default:
448 abort();
452 static void update_disconnected_filename(SocketChardev *s)
454 Chardev *chr = CHARDEV(s);
456 g_free(chr->filename);
457 if (s->addr) {
458 chr->filename = qemu_chr_socket_address(s, "disconnected:");
459 } else {
460 chr->filename = g_strdup("disconnected:socket");
464 /* NB may be called even if tcp_chr_connect has not been
465 * reached, due to TLS or telnet initialization failure,
466 * so can *not* assume s->state == TCP_CHARDEV_STATE_CONNECTED
468 static void tcp_chr_disconnect(Chardev *chr)
470 SocketChardev *s = SOCKET_CHARDEV(chr);
471 bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
473 tcp_chr_free_connection(chr);
475 if (s->listener) {
476 qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
477 chr, NULL, chr->gcontext);
479 update_disconnected_filename(s);
480 if (emit_close) {
481 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
483 if (s->reconnect_time) {
484 qemu_chr_socket_restart_timer(chr);
488 static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
490 Chardev *chr = CHARDEV(opaque);
491 SocketChardev *s = SOCKET_CHARDEV(opaque);
492 uint8_t buf[CHR_READ_BUF_LEN];
493 int len, size;
495 if ((s->state != TCP_CHARDEV_STATE_CONNECTED) ||
496 s->max_size <= 0) {
497 return TRUE;
499 len = sizeof(buf);
500 if (len > s->max_size) {
501 len = s->max_size;
503 size = tcp_chr_recv(chr, (void *)buf, len);
504 if (size == 0 || (size == -1 && errno != EAGAIN)) {
505 /* connection closed */
506 tcp_chr_disconnect(chr);
507 } else if (size > 0) {
508 if (s->do_telnetopt) {
509 tcp_chr_process_IAC_bytes(chr, s, buf, &size);
511 if (size > 0) {
512 qemu_chr_be_write(chr, buf, size);
516 return TRUE;
519 static gboolean tcp_chr_hup(QIOChannel *channel,
520 GIOCondition cond,
521 void *opaque)
523 Chardev *chr = CHARDEV(opaque);
524 tcp_chr_disconnect(chr);
525 return G_SOURCE_REMOVE;
528 static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
530 SocketChardev *s = SOCKET_CHARDEV(chr);
531 int size;
533 if (s->state != TCP_CHARDEV_STATE_CONNECTED) {
534 return 0;
537 qio_channel_set_blocking(s->ioc, true, NULL);
538 size = tcp_chr_recv(chr, (void *) buf, len);
539 qio_channel_set_blocking(s->ioc, false, NULL);
540 if (size == 0) {
541 /* connection closed */
542 tcp_chr_disconnect(chr);
545 return size;
548 static char *qemu_chr_compute_filename(SocketChardev *s)
550 struct sockaddr_storage *ss = &s->sioc->localAddr;
551 struct sockaddr_storage *ps = &s->sioc->remoteAddr;
552 socklen_t ss_len = s->sioc->localAddrLen;
553 socklen_t ps_len = s->sioc->remoteAddrLen;
554 char shost[NI_MAXHOST], sserv[NI_MAXSERV];
555 char phost[NI_MAXHOST], pserv[NI_MAXSERV];
556 const char *left = "", *right = "";
558 switch (ss->ss_family) {
559 #ifndef _WIN32
560 case AF_UNIX:
561 return g_strdup_printf("unix:%s%s",
562 ((struct sockaddr_un *)(ss))->sun_path,
563 s->is_listen ? ",server" : "");
564 #endif
565 case AF_INET6:
566 left = "[";
567 right = "]";
568 /* fall through */
569 case AF_INET:
570 getnameinfo((struct sockaddr *) ss, ss_len, shost, sizeof(shost),
571 sserv, sizeof(sserv), NI_NUMERICHOST | NI_NUMERICSERV);
572 getnameinfo((struct sockaddr *) ps, ps_len, phost, sizeof(phost),
573 pserv, sizeof(pserv), NI_NUMERICHOST | NI_NUMERICSERV);
574 return g_strdup_printf("%s:%s%s%s:%s%s <-> %s%s%s:%s",
575 qemu_chr_socket_protocol(s),
576 left, shost, right, sserv,
577 s->is_listen ? ",server" : "",
578 left, phost, right, pserv);
580 default:
581 return g_strdup_printf("unknown");
585 static void update_ioc_handlers(SocketChardev *s)
587 Chardev *chr = CHARDEV(s);
589 if (s->state != TCP_CHARDEV_STATE_CONNECTED) {
590 return;
593 remove_fd_in_watch(chr);
594 chr->gsource = io_add_watch_poll(chr, s->ioc,
595 tcp_chr_read_poll,
596 tcp_chr_read, chr,
597 chr->gcontext);
599 remove_hup_source(s);
600 s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP);
601 g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup,
602 chr, NULL);
603 g_source_attach(s->hup_source, chr->gcontext);
606 static void tcp_chr_connect(void *opaque)
608 Chardev *chr = CHARDEV(opaque);
609 SocketChardev *s = SOCKET_CHARDEV(opaque);
611 g_free(chr->filename);
612 chr->filename = qemu_chr_compute_filename(s);
614 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTED);
615 update_ioc_handlers(s);
616 qemu_chr_be_event(chr, CHR_EVENT_OPENED);
619 static void tcp_chr_telnet_destroy(SocketChardev *s)
621 if (s->telnet_source) {
622 g_source_destroy(s->telnet_source);
623 g_source_unref(s->telnet_source);
624 s->telnet_source = NULL;
628 static void tcp_chr_update_read_handler(Chardev *chr)
630 SocketChardev *s = SOCKET_CHARDEV(chr);
632 if (s->listener) {
634 * It's possible that chardev context is changed in
635 * qemu_chr_be_update_read_handlers(). Reset it for QIO net
636 * listener if there is.
638 qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
639 chr, NULL, chr->gcontext);
642 if (s->telnet_source) {
643 tcp_chr_telnet_init(CHARDEV(s));
646 update_ioc_handlers(s);
649 static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
650 GIOCondition cond G_GNUC_UNUSED,
651 gpointer user_data)
653 SocketChardev *s = user_data;
654 Chardev *chr = CHARDEV(s);
655 TCPChardevTelnetInit *init = s->telnet_init;
656 ssize_t ret;
658 assert(init);
660 ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
661 if (ret < 0) {
662 if (ret == QIO_CHANNEL_ERR_BLOCK) {
663 ret = 0;
664 } else {
665 tcp_chr_disconnect(chr);
666 goto end;
669 init->buflen -= ret;
671 if (init->buflen == 0) {
672 tcp_chr_connect(chr);
673 goto end;
676 memmove(init->buf, init->buf + ret, init->buflen);
678 return G_SOURCE_CONTINUE;
680 end:
681 g_free(s->telnet_init);
682 s->telnet_init = NULL;
683 g_source_unref(s->telnet_source);
684 s->telnet_source = NULL;
685 return G_SOURCE_REMOVE;
688 static void tcp_chr_telnet_init(Chardev *chr)
690 SocketChardev *s = SOCKET_CHARDEV(chr);
691 TCPChardevTelnetInit *init;
692 size_t n = 0;
694 /* Destroy existing task */
695 tcp_chr_telnet_destroy(s);
697 if (s->telnet_init) {
698 /* We are possibly during a handshake already */
699 goto cont;
702 s->telnet_init = g_new0(TCPChardevTelnetInit, 1);
703 init = s->telnet_init;
705 #define IACSET(x, a, b, c) \
706 do { \
707 x[n++] = a; \
708 x[n++] = b; \
709 x[n++] = c; \
710 } while (0)
712 if (!s->is_tn3270) {
713 init->buflen = 12;
714 /* Prep the telnet negotion to put telnet in binary,
715 * no echo, single char mode */
716 IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
717 IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
718 IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
719 IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
720 } else {
721 init->buflen = 21;
722 /* Prep the TN3270 negotion based on RFC1576 */
723 IACSET(init->buf, 0xff, 0xfd, 0x19); /* IAC DO EOR */
724 IACSET(init->buf, 0xff, 0xfb, 0x19); /* IAC WILL EOR */
725 IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO BINARY */
726 IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL BINARY */
727 IACSET(init->buf, 0xff, 0xfd, 0x18); /* IAC DO TERMINAL TYPE */
728 IACSET(init->buf, 0xff, 0xfa, 0x18); /* IAC SB TERMINAL TYPE */
729 IACSET(init->buf, 0x01, 0xff, 0xf0); /* SEND IAC SE */
732 #undef IACSET
734 cont:
735 s->telnet_source = qio_channel_add_watch_source(s->ioc, G_IO_OUT,
736 tcp_chr_telnet_init_io,
737 s, NULL,
738 chr->gcontext);
742 static void tcp_chr_websock_handshake(QIOTask *task, gpointer user_data)
744 Chardev *chr = user_data;
745 SocketChardev *s = user_data;
747 if (qio_task_propagate_error(task, NULL)) {
748 tcp_chr_disconnect(chr);
749 } else {
750 if (s->do_telnetopt) {
751 tcp_chr_telnet_init(chr);
752 } else {
753 tcp_chr_connect(chr);
759 static void tcp_chr_websock_init(Chardev *chr)
761 SocketChardev *s = SOCKET_CHARDEV(chr);
762 QIOChannelWebsock *wioc = NULL;
763 gchar *name;
765 wioc = qio_channel_websock_new_server(s->ioc);
767 name = g_strdup_printf("chardev-websocket-server-%s", chr->label);
768 qio_channel_set_name(QIO_CHANNEL(wioc), name);
769 g_free(name);
770 object_unref(OBJECT(s->ioc));
771 s->ioc = QIO_CHANNEL(wioc);
773 qio_channel_websock_handshake(wioc, tcp_chr_websock_handshake, chr, NULL);
777 static void tcp_chr_tls_handshake(QIOTask *task,
778 gpointer user_data)
780 Chardev *chr = user_data;
781 SocketChardev *s = user_data;
783 if (qio_task_propagate_error(task, NULL)) {
784 tcp_chr_disconnect(chr);
785 } else {
786 if (s->is_websock) {
787 tcp_chr_websock_init(chr);
788 } else if (s->do_telnetopt) {
789 tcp_chr_telnet_init(chr);
790 } else {
791 tcp_chr_connect(chr);
797 static void tcp_chr_tls_init(Chardev *chr)
799 SocketChardev *s = SOCKET_CHARDEV(chr);
800 QIOChannelTLS *tioc;
801 Error *err = NULL;
802 gchar *name;
804 if (s->is_listen) {
805 tioc = qio_channel_tls_new_server(
806 s->ioc, s->tls_creds,
807 NULL, /* XXX Use an ACL */
808 &err);
809 } else {
810 tioc = qio_channel_tls_new_client(
811 s->ioc, s->tls_creds,
812 s->addr->u.inet.host,
813 &err);
815 if (tioc == NULL) {
816 error_free(err);
817 tcp_chr_disconnect(chr);
818 return;
820 name = g_strdup_printf("chardev-tls-%s-%s",
821 s->is_listen ? "server" : "client",
822 chr->label);
823 qio_channel_set_name(QIO_CHANNEL(tioc), name);
824 g_free(name);
825 object_unref(OBJECT(s->ioc));
826 s->ioc = QIO_CHANNEL(tioc);
828 qio_channel_tls_handshake(tioc,
829 tcp_chr_tls_handshake,
830 chr,
831 NULL,
832 chr->gcontext);
836 static void tcp_chr_set_client_ioc_name(Chardev *chr,
837 QIOChannelSocket *sioc)
839 SocketChardev *s = SOCKET_CHARDEV(chr);
840 char *name;
841 name = g_strdup_printf("chardev-tcp-%s-%s",
842 s->is_listen ? "server" : "client",
843 chr->label);
844 qio_channel_set_name(QIO_CHANNEL(sioc), name);
845 g_free(name);
849 static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc)
851 SocketChardev *s = SOCKET_CHARDEV(chr);
853 if (s->state != TCP_CHARDEV_STATE_CONNECTING) {
854 return -1;
857 s->ioc = QIO_CHANNEL(sioc);
858 object_ref(OBJECT(sioc));
859 s->sioc = sioc;
860 object_ref(OBJECT(sioc));
862 qio_channel_set_blocking(s->ioc, false, NULL);
864 if (s->do_nodelay) {
865 qio_channel_set_delay(s->ioc, false);
867 if (s->listener) {
868 qio_net_listener_set_client_func_full(s->listener, NULL, NULL,
869 NULL, chr->gcontext);
872 if (s->tls_creds) {
873 tcp_chr_tls_init(chr);
874 } else if (s->is_websock) {
875 tcp_chr_websock_init(chr);
876 } else if (s->do_telnetopt) {
877 tcp_chr_telnet_init(chr);
878 } else {
879 tcp_chr_connect(chr);
882 return 0;
886 static int tcp_chr_add_client(Chardev *chr, int fd)
888 int ret;
889 QIOChannelSocket *sioc;
890 SocketChardev *s = SOCKET_CHARDEV(chr);
892 if (s->state != TCP_CHARDEV_STATE_DISCONNECTED) {
893 return -1;
896 sioc = qio_channel_socket_new_fd(fd, NULL);
897 if (!sioc) {
898 return -1;
900 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
901 tcp_chr_set_client_ioc_name(chr, sioc);
902 ret = tcp_chr_new_client(chr, sioc);
903 object_unref(OBJECT(sioc));
904 return ret;
907 static void tcp_chr_accept(QIONetListener *listener,
908 QIOChannelSocket *cioc,
909 void *opaque)
911 Chardev *chr = CHARDEV(opaque);
912 SocketChardev *s = SOCKET_CHARDEV(chr);
914 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
915 tcp_chr_set_client_ioc_name(chr, cioc);
916 tcp_chr_new_client(chr, cioc);
920 static int tcp_chr_connect_client_sync(Chardev *chr, Error **errp)
922 SocketChardev *s = SOCKET_CHARDEV(chr);
923 QIOChannelSocket *sioc = qio_channel_socket_new();
924 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
925 tcp_chr_set_client_ioc_name(chr, sioc);
926 if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
927 tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
928 object_unref(OBJECT(sioc));
929 return -1;
931 tcp_chr_new_client(chr, sioc);
932 object_unref(OBJECT(sioc));
933 return 0;
937 static void tcp_chr_accept_server_sync(Chardev *chr)
939 SocketChardev *s = SOCKET_CHARDEV(chr);
940 QIOChannelSocket *sioc;
941 info_report("QEMU waiting for connection on: %s",
942 chr->filename);
943 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
944 sioc = qio_net_listener_wait_client(s->listener);
945 tcp_chr_set_client_ioc_name(chr, sioc);
946 tcp_chr_new_client(chr, sioc);
947 object_unref(OBJECT(sioc));
951 static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
953 SocketChardev *s = SOCKET_CHARDEV(chr);
954 /* It can't wait on s->connected, since it is set asynchronously
955 * in TLS and telnet cases, only wait for an accepted socket */
956 while (!s->ioc) {
957 if (s->is_listen) {
958 tcp_chr_accept_server_sync(chr);
959 } else {
960 Error *err = NULL;
961 if (tcp_chr_connect_client_sync(chr, &err) < 0) {
962 if (s->reconnect_time) {
963 error_free(err);
964 g_usleep(s->reconnect_time * 1000ULL * 1000ULL);
965 } else {
966 error_propagate(errp, err);
967 return -1;
973 return 0;
976 static void char_socket_finalize(Object *obj)
978 Chardev *chr = CHARDEV(obj);
979 SocketChardev *s = SOCKET_CHARDEV(obj);
981 tcp_chr_free_connection(chr);
982 tcp_chr_reconn_timer_cancel(s);
983 qapi_free_SocketAddress(s->addr);
984 tcp_chr_telnet_destroy(s);
985 g_free(s->telnet_init);
986 if (s->listener) {
987 qio_net_listener_set_client_func_full(s->listener, NULL, NULL,
988 NULL, chr->gcontext);
989 object_unref(OBJECT(s->listener));
991 if (s->tls_creds) {
992 object_unref(OBJECT(s->tls_creds));
995 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
998 static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
1000 QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
1001 Chardev *chr = CHARDEV(opaque);
1002 SocketChardev *s = SOCKET_CHARDEV(chr);
1003 Error *err = NULL;
1005 if (qio_task_propagate_error(task, &err)) {
1006 tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
1007 check_report_connect_error(chr, err);
1008 error_free(err);
1009 goto cleanup;
1012 s->connect_err_reported = false;
1013 tcp_chr_new_client(chr, sioc);
1015 cleanup:
1016 object_unref(OBJECT(sioc));
1019 static void tcp_chr_connect_client_async(Chardev *chr)
1021 SocketChardev *s = SOCKET_CHARDEV(chr);
1022 QIOChannelSocket *sioc;
1024 tcp_chr_change_state(s, TCP_CHARDEV_STATE_CONNECTING);
1025 sioc = qio_channel_socket_new();
1026 tcp_chr_set_client_ioc_name(chr, sioc);
1027 qio_channel_socket_connect_async(sioc, s->addr,
1028 qemu_chr_socket_connected,
1029 chr, NULL, chr->gcontext);
1032 static gboolean socket_reconnect_timeout(gpointer opaque)
1034 Chardev *chr = CHARDEV(opaque);
1035 SocketChardev *s = SOCKET_CHARDEV(opaque);
1037 g_source_unref(s->reconnect_timer);
1038 s->reconnect_timer = NULL;
1040 if (chr->be_open) {
1041 return false;
1044 tcp_chr_connect_client_async(chr);
1046 return false;
1050 static int qmp_chardev_open_socket_server(Chardev *chr,
1051 bool is_telnet,
1052 bool is_waitconnect,
1053 Error **errp)
1055 SocketChardev *s = SOCKET_CHARDEV(chr);
1056 char *name;
1057 if (is_telnet) {
1058 s->do_telnetopt = 1;
1060 s->listener = qio_net_listener_new();
1062 name = g_strdup_printf("chardev-tcp-listener-%s", chr->label);
1063 qio_net_listener_set_name(s->listener, name);
1064 g_free(name);
1066 if (qio_net_listener_open_sync(s->listener, s->addr, errp) < 0) {
1067 object_unref(OBJECT(s->listener));
1068 s->listener = NULL;
1069 return -1;
1072 qapi_free_SocketAddress(s->addr);
1073 s->addr = socket_local_address(s->listener->sioc[0]->fd, errp);
1074 update_disconnected_filename(s);
1076 if (is_waitconnect) {
1077 tcp_chr_accept_server_sync(chr);
1078 } else {
1079 qio_net_listener_set_client_func_full(s->listener,
1080 tcp_chr_accept,
1081 chr, NULL,
1082 chr->gcontext);
1085 return 0;
1089 static int qmp_chardev_open_socket_client(Chardev *chr,
1090 int64_t reconnect,
1091 Error **errp)
1093 SocketChardev *s = SOCKET_CHARDEV(chr);
1095 if (reconnect > 0) {
1096 s->reconnect_time = reconnect;
1097 tcp_chr_connect_client_async(chr);
1098 return 0;
1099 } else {
1100 return tcp_chr_connect_client_sync(chr, errp);
1105 static bool qmp_chardev_validate_socket(ChardevSocket *sock,
1106 SocketAddress *addr,
1107 Error **errp)
1109 /* Validate any options which have a dependency on address type */
1110 switch (addr->type) {
1111 case SOCKET_ADDRESS_TYPE_FD:
1112 if (sock->has_reconnect) {
1113 error_setg(errp,
1114 "'reconnect' option is incompatible with "
1115 "'fd' address type");
1116 return false;
1118 if (sock->has_tls_creds &&
1119 !(sock->has_server && sock->server)) {
1120 error_setg(errp,
1121 "'tls_creds' option is incompatible with "
1122 "'fd' address type as client");
1123 return false;
1125 break;
1127 case SOCKET_ADDRESS_TYPE_UNIX:
1128 if (sock->has_tls_creds) {
1129 error_setg(errp,
1130 "'tls_creds' option is incompatible with "
1131 "'unix' address type");
1132 return false;
1134 break;
1136 case SOCKET_ADDRESS_TYPE_INET:
1137 break;
1139 case SOCKET_ADDRESS_TYPE_VSOCK:
1140 if (sock->has_tls_creds) {
1141 error_setg(errp,
1142 "'tls_creds' option is incompatible with "
1143 "'vsock' address type");
1144 return false;
1147 default:
1148 break;
1151 /* Validate any options which have a dependancy on client vs server */
1152 if (!sock->has_server || sock->server) {
1153 if (sock->has_reconnect) {
1154 error_setg(errp,
1155 "'reconnect' option is incompatible with "
1156 "socket in server listen mode");
1157 return false;
1159 } else {
1160 if (sock->has_websocket && sock->websocket) {
1161 error_setg(errp, "%s", "Websocket client is not implemented");
1162 return false;
1164 if (sock->has_wait) {
1165 error_setg(errp, "%s",
1166 "'wait' option is incompatible with "
1167 "socket in client connect mode");
1168 return false;
1172 return true;
1176 static void qmp_chardev_open_socket(Chardev *chr,
1177 ChardevBackend *backend,
1178 bool *be_opened,
1179 Error **errp)
1181 SocketChardev *s = SOCKET_CHARDEV(chr);
1182 ChardevSocket *sock = backend->u.socket.data;
1183 bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
1184 bool is_listen = sock->has_server ? sock->server : true;
1185 bool is_telnet = sock->has_telnet ? sock->telnet : false;
1186 bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false;
1187 bool is_waitconnect = sock->has_wait ? sock->wait : false;
1188 bool is_websock = sock->has_websocket ? sock->websocket : false;
1189 int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
1190 SocketAddress *addr;
1192 s->is_listen = is_listen;
1193 s->is_telnet = is_telnet;
1194 s->is_tn3270 = is_tn3270;
1195 s->is_websock = is_websock;
1196 s->do_nodelay = do_nodelay;
1197 if (sock->tls_creds) {
1198 Object *creds;
1199 creds = object_resolve_path_component(
1200 object_get_objects_root(), sock->tls_creds);
1201 if (!creds) {
1202 error_setg(errp, "No TLS credentials with id '%s'",
1203 sock->tls_creds);
1204 return;
1206 s->tls_creds = (QCryptoTLSCreds *)
1207 object_dynamic_cast(creds,
1208 TYPE_QCRYPTO_TLS_CREDS);
1209 if (!s->tls_creds) {
1210 error_setg(errp, "Object with id '%s' is not TLS credentials",
1211 sock->tls_creds);
1212 return;
1214 object_ref(OBJECT(s->tls_creds));
1215 if (is_listen) {
1216 if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
1217 error_setg(errp, "%s",
1218 "Expected TLS credentials for server endpoint");
1219 return;
1221 } else {
1222 if (s->tls_creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
1223 error_setg(errp, "%s",
1224 "Expected TLS credentials for client endpoint");
1225 return;
1230 s->addr = addr = socket_address_flatten(sock->addr);
1232 if (!qmp_chardev_validate_socket(sock, addr, errp)) {
1233 return;
1236 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
1237 /* TODO SOCKET_ADDRESS_FD where fd has AF_UNIX */
1238 if (addr->type == SOCKET_ADDRESS_TYPE_UNIX) {
1239 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
1242 /* be isn't opened until we get a connection */
1243 *be_opened = false;
1245 update_disconnected_filename(s);
1247 if (s->is_listen) {
1248 if (qmp_chardev_open_socket_server(chr, is_telnet || is_tn3270,
1249 is_waitconnect, errp) < 0) {
1250 return;
1252 } else {
1253 if (qmp_chardev_open_socket_client(chr, reconnect, errp) < 0) {
1254 return;
1259 static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
1260 Error **errp)
1262 const char *path = qemu_opt_get(opts, "path");
1263 const char *host = qemu_opt_get(opts, "host");
1264 const char *port = qemu_opt_get(opts, "port");
1265 const char *fd = qemu_opt_get(opts, "fd");
1266 SocketAddressLegacy *addr;
1267 ChardevSocket *sock;
1269 if ((!!path + !!fd + !!host) != 1) {
1270 error_setg(errp,
1271 "Exactly one of 'path', 'fd' or 'host' required");
1272 return;
1275 if (host && !port) {
1276 error_setg(errp, "chardev: socket: no port given");
1277 return;
1280 backend->type = CHARDEV_BACKEND_KIND_SOCKET;
1281 sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
1282 qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
1284 sock->has_nodelay = qemu_opt_get(opts, "delay");
1285 sock->nodelay = !qemu_opt_get_bool(opts, "delay", true);
1287 * We have different default to QMP for 'server', hence
1288 * we can't just check for existence of 'server'
1290 sock->has_server = true;
1291 sock->server = qemu_opt_get_bool(opts, "server", false);
1292 sock->has_telnet = qemu_opt_get(opts, "telnet");
1293 sock->telnet = qemu_opt_get_bool(opts, "telnet", false);
1294 sock->has_tn3270 = qemu_opt_get(opts, "tn3270");
1295 sock->tn3270 = qemu_opt_get_bool(opts, "tn3270", false);
1296 sock->has_websocket = qemu_opt_get(opts, "websocket");
1297 sock->websocket = qemu_opt_get_bool(opts, "websocket", false);
1299 * We have different default to QMP for 'wait' when 'server'
1300 * is set, hence we can't just check for existence of 'wait'
1302 sock->has_wait = qemu_opt_find(opts, "wait") || sock->server;
1303 sock->wait = qemu_opt_get_bool(opts, "wait", true);
1304 sock->has_reconnect = qemu_opt_find(opts, "reconnect");
1305 sock->reconnect = qemu_opt_get_number(opts, "reconnect", 0);
1306 sock->has_tls_creds = qemu_opt_get(opts, "tls-creds");
1307 sock->tls_creds = g_strdup(qemu_opt_get(opts, "tls-creds"));
1309 addr = g_new0(SocketAddressLegacy, 1);
1310 if (path) {
1311 UnixSocketAddress *q_unix;
1312 addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX;
1313 q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
1314 q_unix->path = g_strdup(path);
1315 } else if (host) {
1316 addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
1317 addr->u.inet.data = g_new(InetSocketAddress, 1);
1318 *addr->u.inet.data = (InetSocketAddress) {
1319 .host = g_strdup(host),
1320 .port = g_strdup(port),
1321 .has_to = qemu_opt_get(opts, "to"),
1322 .to = qemu_opt_get_number(opts, "to", 0),
1323 .has_ipv4 = qemu_opt_get(opts, "ipv4"),
1324 .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0),
1325 .has_ipv6 = qemu_opt_get(opts, "ipv6"),
1326 .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
1328 } else if (fd) {
1329 addr->type = SOCKET_ADDRESS_LEGACY_KIND_FD;
1330 addr->u.fd.data = g_new(String, 1);
1331 addr->u.fd.data->str = g_strdup(fd);
1332 } else {
1333 g_assert_not_reached();
1335 sock->addr = addr;
1338 static void
1339 char_socket_get_addr(Object *obj, Visitor *v, const char *name,
1340 void *opaque, Error **errp)
1342 SocketChardev *s = SOCKET_CHARDEV(obj);
1344 visit_type_SocketAddress(v, name, &s->addr, errp);
1347 static bool
1348 char_socket_get_connected(Object *obj, Error **errp)
1350 SocketChardev *s = SOCKET_CHARDEV(obj);
1352 return s->state == TCP_CHARDEV_STATE_CONNECTED;
1355 static void char_socket_class_init(ObjectClass *oc, void *data)
1357 ChardevClass *cc = CHARDEV_CLASS(oc);
1359 cc->parse = qemu_chr_parse_socket;
1360 cc->open = qmp_chardev_open_socket;
1361 cc->chr_wait_connected = tcp_chr_wait_connected;
1362 cc->chr_write = tcp_chr_write;
1363 cc->chr_sync_read = tcp_chr_sync_read;
1364 cc->chr_disconnect = tcp_chr_disconnect;
1365 cc->get_msgfds = tcp_get_msgfds;
1366 cc->set_msgfds = tcp_set_msgfds;
1367 cc->chr_add_client = tcp_chr_add_client;
1368 cc->chr_add_watch = tcp_chr_add_watch;
1369 cc->chr_update_read_handler = tcp_chr_update_read_handler;
1371 object_class_property_add(oc, "addr", "SocketAddress",
1372 char_socket_get_addr, NULL,
1373 NULL, NULL, &error_abort);
1375 object_class_property_add_bool(oc, "connected", char_socket_get_connected,
1376 NULL, &error_abort);
1379 static const TypeInfo char_socket_type_info = {
1380 .name = TYPE_CHARDEV_SOCKET,
1381 .parent = TYPE_CHARDEV,
1382 .instance_size = sizeof(SocketChardev),
1383 .instance_finalize = char_socket_finalize,
1384 .class_init = char_socket_class_init,
1387 static void register_types(void)
1389 type_register_static(&char_socket_type_info);
1392 type_init(register_types);