vnc.c (57a6d6d538c596292003d131035dc4f7cb44474d) vnc.c (396f935a9aff3cefd288bdb2b20024fb9dcfa062)
1/*
2 * QEMU VNC display driver
3 *
4 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5 * Copyright (C) 2006 Fabrice Bellard
6 * Copyright (C) 2009 Red Hat, Inc
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy

--- 3549 unchanged lines hidden (view full) ---

3558 } else {
3559 inet->host = g_strndup(addrstr, hostlen);
3560 }
3561 /* plain VNC port is just an offset, for websocket
3562 * port is absolute */
3563 if (websocket) {
3564 if (g_str_equal(addrstr, "") ||
3565 g_str_equal(addrstr, "on")) {
1/*
2 * QEMU VNC display driver
3 *
4 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5 * Copyright (C) 2006 Fabrice Bellard
6 * Copyright (C) 2009 Red Hat, Inc
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy

--- 3549 unchanged lines hidden (view full) ---

3558 } else {
3559 inet->host = g_strndup(addrstr, hostlen);
3560 }
3561 /* plain VNC port is just an offset, for websocket
3562 * port is absolute */
3563 if (websocket) {
3564 if (g_str_equal(addrstr, "") ||
3565 g_str_equal(addrstr, "on")) {
3566 if (displaynum == -1) {
3567 error_setg(errp, "explicit websocket port is required");
3568 goto cleanup;
3569 }
3566 inet->port = g_strdup_printf(
3567 "%d", displaynum + 5700);
3568 if (to) {
3569 inet->has_to = true;
3570 inet->to = to + 5700;
3571 }
3572 } else {
3573 inet->port = g_strdup(port);

--- 30 unchanged lines hidden (view full) ---

3604 cleanup:
3605 if (ret < 0) {
3606 qapi_free_SocketAddress(addr);
3607 }
3608 return ret;
3609}
3610
3611static int vnc_display_get_addresses(QemuOpts *opts,
3570 inet->port = g_strdup_printf(
3571 "%d", displaynum + 5700);
3572 if (to) {
3573 inet->has_to = true;
3574 inet->to = to + 5700;
3575 }
3576 } else {
3577 inet->port = g_strdup(port);

--- 30 unchanged lines hidden (view full) ---

3608 cleanup:
3609 if (ret < 0) {
3610 qapi_free_SocketAddress(addr);
3611 }
3612 return ret;
3613}
3614
3615static int vnc_display_get_addresses(QemuOpts *opts,
3612 SocketAddress **retsaddr,
3613 SocketAddress **retwsaddr,
3616 SocketAddress ***retsaddr,
3617 size_t *retnsaddr,
3618 SocketAddress ***retwsaddr,
3619 size_t *retnwsaddr,
3614 Error **errp)
3615{
3616 SocketAddress *saddr = NULL;
3617 SocketAddress *wsaddr = NULL;
3620 Error **errp)
3621{
3622 SocketAddress *saddr = NULL;
3623 SocketAddress *wsaddr = NULL;
3618 const char *saddrstr = qemu_opt_get(opts, "vnc");
3619 const char *wsaddrstr = qemu_opt_get(opts, "websocket");
3624 QemuOptsIter addriter;
3625 const char *addr;
3620 int to = qemu_opt_get_number(opts, "to", 0);
3621 bool has_ipv4 = qemu_opt_get(opts, "ipv4");
3622 bool has_ipv6 = qemu_opt_get(opts, "ipv6");
3623 bool ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
3624 bool ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
3626 int to = qemu_opt_get_number(opts, "to", 0);
3627 bool has_ipv4 = qemu_opt_get(opts, "ipv4");
3628 bool has_ipv6 = qemu_opt_get(opts, "ipv6");
3629 bool ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
3630 bool ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
3631 size_t i;
3632 int displaynum = -1;
3633 int ret = -1;
3625
3634
3626 if (!saddrstr || strcmp(saddrstr, "none") == 0) {
3627 *retsaddr = NULL;
3628 *retwsaddr = NULL;
3629 return 0;
3630 }
3635 *retsaddr = NULL;
3636 *retnsaddr = 0;
3637 *retwsaddr = NULL;
3638 *retnwsaddr = 0;
3631
3639
3632 if (wsaddrstr &&
3640 addr = qemu_opt_get(opts, "vnc");
3641 if (addr == NULL || g_str_equal(addr, "none")) {
3642 ret = 0;
3643 goto cleanup;
3644 }
3645 if (qemu_opt_get(opts, "websocket") &&
3633 !qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
3634 error_setg(errp,
3635 "SHA1 hash support is required for websockets");
3646 !qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
3647 error_setg(errp,
3648 "SHA1 hash support is required for websockets");
3636 goto error;
3649 goto cleanup;
3637 }
3638
3650 }
3651
3639 int displaynum = vnc_display_get_address(saddrstr, false, 0, to,
3640 has_ipv4, has_ipv6,
3641 ipv4, ipv6,
3642 &saddr, errp);
3643 if (displaynum < 0) {
3644 goto error;
3652 qemu_opt_iter_init(&addriter, opts, "vnc");
3653 while ((addr = qemu_opt_iter_next(&addriter)) != NULL) {
3654 int rv;
3655 rv = vnc_display_get_address(addr, false, 0, to,
3656 has_ipv4, has_ipv6,
3657 ipv4, ipv6,
3658 &saddr, errp);
3659 if (rv < 0) {
3660 goto cleanup;
3661 }
3662 /* Historical compat - first listen address can be used
3663 * to set the default websocket port
3664 */
3665 if (displaynum == -1) {
3666 displaynum = rv;
3667 }
3668 *retsaddr = g_renew(SocketAddress *, *retsaddr, *retnsaddr + 1);
3669 (*retsaddr)[(*retnsaddr)++] = saddr;
3645 }
3670 }
3646 if (wsaddrstr) {
3647 if (vnc_display_get_address(wsaddrstr, true, displaynum, to,
3671
3672 /* If we had multiple primary displays, we don't do defaults
3673 * for websocket, and require explicit config instead. */
3674 if (*retnsaddr > 1) {
3675 displaynum = -1;
3676 }
3677
3678 qemu_opt_iter_init(&addriter, opts, "websocket");
3679 while ((addr = qemu_opt_iter_next(&addriter)) != NULL) {
3680 if (vnc_display_get_address(addr, true, displaynum, to,
3648 has_ipv4, has_ipv6,
3649 ipv4, ipv6,
3650 &wsaddr, errp) < 0) {
3681 has_ipv4, has_ipv6,
3682 ipv4, ipv6,
3683 &wsaddr, errp) < 0) {
3651 goto error;
3684 goto cleanup;
3652 }
3685 }
3653 if (saddr->type == SOCKET_ADDRESS_KIND_INET &&
3686
3687 /* Historical compat - if only a single listen address was
3688 * provided, then this is used to set the default listen
3689 * address for websocket too
3690 */
3691 if (*retnsaddr == 1 &&
3692 (*retsaddr)[0]->type == SOCKET_ADDRESS_KIND_INET &&
3654 wsaddr->type == SOCKET_ADDRESS_KIND_INET &&
3655 g_str_equal(wsaddr->u.inet.data->host, "") &&
3693 wsaddr->type == SOCKET_ADDRESS_KIND_INET &&
3694 g_str_equal(wsaddr->u.inet.data->host, "") &&
3656 !g_str_equal(saddr->u.inet.data->host, "")) {
3695 !g_str_equal((*retsaddr)[0]->u.inet.data->host, "")) {
3657 g_free(wsaddr->u.inet.data->host);
3696 g_free(wsaddr->u.inet.data->host);
3658 wsaddr->u.inet.data->host = g_strdup(saddr->u.inet.data->host);
3697 wsaddr->u.inet.data->host =
3698 g_strdup((*retsaddr)[0]->u.inet.data->host);
3659 }
3699 }
3700
3701 *retwsaddr = g_renew(SocketAddress *, *retwsaddr, *retnwsaddr + 1);
3702 (*retwsaddr)[(*retnwsaddr)++] = wsaddr;
3660 }
3703 }
3661 *retsaddr = saddr;
3662 *retwsaddr = wsaddr;
3663 return 0;
3664
3704
3665 error:
3666 qapi_free_SocketAddress(saddr);
3667 qapi_free_SocketAddress(wsaddr);
3668 return -1;
3705 ret = 0;
3706 cleanup:
3707 if (ret < 0) {
3708 for (i = 0; i < *retnsaddr; i++) {
3709 qapi_free_SocketAddress((*retsaddr)[i]);
3710 }
3711 g_free(*retsaddr);
3712 for (i = 0; i < *retnwsaddr; i++) {
3713 qapi_free_SocketAddress((*retwsaddr)[i]);
3714 }
3715 g_free(*retwsaddr);
3716 *retsaddr = *retwsaddr = NULL;
3717 *retnsaddr = *retnwsaddr = 0;
3718 }
3719 return ret;
3669}
3670
3671static int vnc_display_connect(VncDisplay *vd,
3720}
3721
3722static int vnc_display_connect(VncDisplay *vd,
3672 SocketAddress *saddr,
3673 SocketAddress *wsaddr,
3723 SocketAddress **saddr,
3724 size_t nsaddr,
3725 SocketAddress **wsaddr,
3726 size_t nwsaddr,
3674 Error **errp)
3675{
3676 /* connect to viewer */
3677 QIOChannelSocket *sioc = NULL;
3727 Error **errp)
3728{
3729 /* connect to viewer */
3730 QIOChannelSocket *sioc = NULL;
3678 if (wsaddr) {
3731 if (nwsaddr != 0) {
3679 error_setg(errp, "Cannot use websockets in reverse mode");
3680 return -1;
3681 }
3732 error_setg(errp, "Cannot use websockets in reverse mode");
3733 return -1;
3734 }
3682 vd->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
3735 if (nsaddr != 1) {
3736 error_setg(errp, "Expected a single address in reverse mode");
3737 return -1;
3738 }
3739 vd->is_unix = saddr[0]->type == SOCKET_ADDRESS_KIND_UNIX;
3683 sioc = qio_channel_socket_new();
3684 qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-reverse");
3740 sioc = qio_channel_socket_new();
3741 qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-reverse");
3685 if (qio_channel_socket_connect_sync(sioc, saddr, errp) < 0) {
3742 if (qio_channel_socket_connect_sync(sioc, saddr[0], errp) < 0) {
3686 return -1;
3687 }
3688 vnc_connect(vd, sioc, false, false);
3689 object_unref(OBJECT(sioc));
3690 return 0;
3691}
3692
3693

--- 4 unchanged lines hidden (view full) ---

3698 guint **lsock_tag,
3699 size_t *nlsock,
3700 Error **errp)
3701{
3702 QIODNSResolver *resolver = qio_dns_resolver_get_instance();
3703 SocketAddress **rawaddrs = NULL;
3704 size_t nrawaddrs = 0;
3705 Error *listenerr = NULL;
3743 return -1;
3744 }
3745 vnc_connect(vd, sioc, false, false);
3746 object_unref(OBJECT(sioc));
3747 return 0;
3748}
3749
3750

--- 4 unchanged lines hidden (view full) ---

3755 guint **lsock_tag,
3756 size_t *nlsock,
3757 Error **errp)
3758{
3759 QIODNSResolver *resolver = qio_dns_resolver_get_instance();
3760 SocketAddress **rawaddrs = NULL;
3761 size_t nrawaddrs = 0;
3762 Error *listenerr = NULL;
3763 bool listening = false;
3706 size_t i;
3707
3708 if (qio_dns_resolver_lookup_sync(resolver, addr, &nrawaddrs,
3709 &rawaddrs, errp) < 0) {
3710 return -1;
3711 }
3712
3713 for (i = 0; i < nrawaddrs; i++) {
3714 QIOChannelSocket *sioc = qio_channel_socket_new();
3715
3716 qio_channel_set_name(QIO_CHANNEL(sioc), name);
3717 if (qio_channel_socket_listen_sync(
3718 sioc, rawaddrs[i], listenerr == NULL ? &listenerr : NULL) < 0) {
3719 continue;
3720 }
3764 size_t i;
3765
3766 if (qio_dns_resolver_lookup_sync(resolver, addr, &nrawaddrs,
3767 &rawaddrs, errp) < 0) {
3768 return -1;
3769 }
3770
3771 for (i = 0; i < nrawaddrs; i++) {
3772 QIOChannelSocket *sioc = qio_channel_socket_new();
3773
3774 qio_channel_set_name(QIO_CHANNEL(sioc), name);
3775 if (qio_channel_socket_listen_sync(
3776 sioc, rawaddrs[i], listenerr == NULL ? &listenerr : NULL) < 0) {
3777 continue;
3778 }
3779 listening = true;
3721 (*nlsock)++;
3722 *lsock = g_renew(QIOChannelSocket *, *lsock, *nlsock);
3723 *lsock_tag = g_renew(guint, *lsock_tag, *nlsock);
3724
3725 (*lsock)[*nlsock - 1] = sioc;
3726 (*lsock_tag)[*nlsock - 1] = 0;
3727 }
3728
3729 for (i = 0; i < nrawaddrs; i++) {
3730 qapi_free_SocketAddress(rawaddrs[i]);
3731 }
3732 g_free(rawaddrs);
3733
3734 if (listenerr) {
3780 (*nlsock)++;
3781 *lsock = g_renew(QIOChannelSocket *, *lsock, *nlsock);
3782 *lsock_tag = g_renew(guint, *lsock_tag, *nlsock);
3783
3784 (*lsock)[*nlsock - 1] = sioc;
3785 (*lsock_tag)[*nlsock - 1] = 0;
3786 }
3787
3788 for (i = 0; i < nrawaddrs; i++) {
3789 qapi_free_SocketAddress(rawaddrs[i]);
3790 }
3791 g_free(rawaddrs);
3792
3793 if (listenerr) {
3735 if (*nlsock == 0) {
3794 if (!listening) {
3736 error_propagate(errp, listenerr);
3737 return -1;
3738 } else {
3739 error_free(listenerr);
3740 }
3741 }
3742
3743 for (i = 0; i < *nlsock; i++) {
3744 (*lsock_tag)[i] = qio_channel_add_watch(
3745 QIO_CHANNEL((*lsock)[i]),
3746 G_IO_IN, vnc_listen_io, vd, NULL);
3747 }
3748
3749 return 0;
3750}
3751
3752
3753static int vnc_display_listen(VncDisplay *vd,
3795 error_propagate(errp, listenerr);
3796 return -1;
3797 } else {
3798 error_free(listenerr);
3799 }
3800 }
3801
3802 for (i = 0; i < *nlsock; i++) {
3803 (*lsock_tag)[i] = qio_channel_add_watch(
3804 QIO_CHANNEL((*lsock)[i]),
3805 G_IO_IN, vnc_listen_io, vd, NULL);
3806 }
3807
3808 return 0;
3809}
3810
3811
3812static int vnc_display_listen(VncDisplay *vd,
3754 SocketAddress *saddr,
3755 SocketAddress *wsaddr,
3813 SocketAddress **saddr,
3814 size_t nsaddr,
3815 SocketAddress **wsaddr,
3816 size_t nwsaddr,
3756 Error **errp)
3757{
3817 Error **errp)
3818{
3758 vd->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
3819 size_t i;
3759
3820
3760 if (vnc_display_listen_addr(vd, saddr,
3761 "vnc-listen",
3762 &vd->lsock,
3763 &vd->lsock_tag,
3764 &vd->nlsock,
3765 errp) < 0) {
3766 return -1;
3821 for (i = 0; i < nsaddr; i++) {
3822 if (vnc_display_listen_addr(vd, saddr[i],
3823 "vnc-listen",
3824 &vd->lsock,
3825 &vd->lsock_tag,
3826 &vd->nlsock,
3827 errp) < 0) {
3828 return -1;
3829 }
3767 }
3830 }
3768 if (wsaddr &&
3769 vnc_display_listen_addr(vd, wsaddr,
3770 "vnc-ws-listen",
3771 &vd->lwebsock,
3772 &vd->lwebsock_tag,
3773 &vd->nlwebsock,
3774 errp) < 0) {
3775 return -1;
3831 for (i = 0; i < nwsaddr; i++) {
3832 if (vnc_display_listen_addr(vd, wsaddr[i],
3833 "vnc-ws-listen",
3834 &vd->lwebsock,
3835 &vd->lwebsock_tag,
3836 &vd->nlwebsock,
3837 errp) < 0) {
3838 return -1;
3839 }
3776 }
3777
3778 return 0;
3779}
3780
3781
3782void vnc_display_open(const char *id, Error **errp)
3783{
3784 VncDisplay *vd = vnc_display_find(id);
3785 QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
3840 }
3841
3842 return 0;
3843}
3844
3845
3846void vnc_display_open(const char *id, Error **errp)
3847{
3848 VncDisplay *vd = vnc_display_find(id);
3849 QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
3786 SocketAddress *saddr = NULL, *wsaddr = NULL;
3850 SocketAddress **saddr = NULL, **wsaddr = NULL;
3851 size_t nsaddr, nwsaddr;
3787 const char *share, *device_id;
3788 QemuConsole *con;
3789 bool password = false;
3790 bool reverse = false;
3791 const char *credid;
3792 bool sasl = false;
3793#ifdef CONFIG_VNC_SASL
3794 int saslErr;
3795#endif
3796 int acl = 0;
3797 int lock_key_sync = 1;
3798 int key_delay_ms;
3852 const char *share, *device_id;
3853 QemuConsole *con;
3854 bool password = false;
3855 bool reverse = false;
3856 const char *credid;
3857 bool sasl = false;
3858#ifdef CONFIG_VNC_SASL
3859 int saslErr;
3860#endif
3861 int acl = 0;
3862 int lock_key_sync = 1;
3863 int key_delay_ms;
3864 size_t i;
3799
3800 if (!vd) {
3801 error_setg(errp, "VNC display not active");
3802 return;
3803 }
3804 vnc_display_close(vd);
3805
3806 if (!opts) {
3807 return;
3808 }
3809
3865
3866 if (!vd) {
3867 error_setg(errp, "VNC display not active");
3868 return;
3869 }
3870 vnc_display_close(vd);
3871
3872 if (!opts) {
3873 return;
3874 }
3875
3810 if (vnc_display_get_addresses(opts, &saddr, &wsaddr, errp) < 0) {
3876 if (vnc_display_get_addresses(opts, &saddr, &nsaddr,
3877 &wsaddr, &nwsaddr, errp) < 0) {
3811 goto fail;
3812 }
3813
3814 if (saddr == NULL) {
3815 return;
3816 }
3817
3818 password = qemu_opt_get_bool(opts, "password", false);

--- 177 unchanged lines hidden (view full) ---

3996
3997 if (con != vd->dcl.con) {
3998 unregister_displaychangelistener(&vd->dcl);
3999 vd->dcl.con = con;
4000 register_displaychangelistener(&vd->dcl);
4001 }
4002
4003 if (reverse) {
3878 goto fail;
3879 }
3880
3881 if (saddr == NULL) {
3882 return;
3883 }
3884
3885 password = qemu_opt_get_bool(opts, "password", false);

--- 177 unchanged lines hidden (view full) ---

4063
4064 if (con != vd->dcl.con) {
4065 unregister_displaychangelistener(&vd->dcl);
4066 vd->dcl.con = con;
4067 register_displaychangelistener(&vd->dcl);
4068 }
4069
4070 if (reverse) {
4004 if (vnc_display_connect(vd, saddr, wsaddr, errp) < 0) {
4071 if (vnc_display_connect(vd, saddr, nsaddr, wsaddr, nwsaddr, errp) < 0) {
4005 goto fail;
4006 }
4007 } else {
4072 goto fail;
4073 }
4074 } else {
4008 if (vnc_display_listen(vd, saddr, wsaddr, errp) < 0) {
4075 if (vnc_display_listen(vd, saddr, nsaddr, wsaddr, nwsaddr, errp) < 0) {
4009 goto fail;
4010 }
4011 }
4012
4013 if (qemu_opt_get(opts, "to")) {
4014 vnc_display_print_local_addr(vd);
4015 }
4016
4076 goto fail;
4077 }
4078 }
4079
4080 if (qemu_opt_get(opts, "to")) {
4081 vnc_display_print_local_addr(vd);
4082 }
4083
4017 qapi_free_SocketAddress(saddr);
4018 qapi_free_SocketAddress(wsaddr);
4084 cleanup:
4085 for (i = 0; i < nsaddr; i++) {
4086 qapi_free_SocketAddress(saddr[i]);
4087 }
4088 for (i = 0; i < nwsaddr; i++) {
4089 qapi_free_SocketAddress(wsaddr[i]);
4090 }
4019 return;
4020
4021fail:
4022 vnc_display_close(vd);
4091 return;
4092
4093fail:
4094 vnc_display_close(vd);
4023 qapi_free_SocketAddress(saddr);
4024 qapi_free_SocketAddress(wsaddr);
4095 goto cleanup;
4025}
4026
4027void vnc_display_add_client(const char *id, int csock, bool skipauth)
4028{
4029 VncDisplay *vd = vnc_display_find(id);
4030 QIOChannelSocket *sioc;
4031
4032 if (!vd) {

--- 62 unchanged lines hidden ---
4096}
4097
4098void vnc_display_add_client(const char *id, int csock, bool skipauth)
4099{
4100 VncDisplay *vd = vnc_display_find(id);
4101 QIOChannelSocket *sioc;
4102
4103 if (!vd) {

--- 62 unchanged lines hidden ---