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 --- |