@ -70,8 +70,8 @@ static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
[ VNC_SHARE_MODE_EXCLUSIVE ] = " exclusive " ,
[ VNC_SHARE_MODE_DISCONNECTED ] = " disconnected " ,
} ;
fprintf ( stderr , " %s/%d : %s -> %s \n " , __func__ ,
vs - > csock , mn [ vs - > share_mode ] , mn [ mode ] ) ;
fprintf ( stderr , " %s/%p : %s -> %s \n " , __func__ ,
vs - > ioc , mn [ vs - > share_mode ] , mn [ mode ] ) ;
# endif
switch ( vs - > share_mode ) {
@ -105,108 +105,65 @@ static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
}
}
static char * addr_to_string ( const char * format ,
struct sockaddr_storage * sa ,
socklen_t salen ) {
char * addr ;
char host [ NI_MAXHOST ] ;
char serv [ NI_MAXSERV ] ;
int err ;
size_t addrlen ;
if ( ( err = getnameinfo ( ( struct sockaddr * ) sa , salen ,
host , sizeof ( host ) ,
serv , sizeof ( serv ) ,
NI_NUMERICHOST | NI_NUMERICSERV ) ) ! = 0 ) {
VNC_DEBUG ( " Cannot resolve address %d: %s \n " ,
err , gai_strerror ( err ) ) ;
return NULL ;
}
/* Enough for the existing format + the 2 vars we're
* substituting in . */
addrlen = strlen ( format ) + strlen ( host ) + strlen ( serv ) ;
addr = g_malloc ( addrlen + 1 ) ;
snprintf ( addr , addrlen , format , host , serv ) ;
addr [ addrlen ] = ' \0 ' ;
return addr ;
}
char * vnc_socket_local_addr ( const char * format , int fd ) {
struct sockaddr_storage sa ;
socklen_t salen ;
salen = sizeof ( sa ) ;
if ( getsockname ( fd , ( struct sockaddr * ) & sa , & salen ) < 0 )
return NULL ;
return addr_to_string ( format , & sa , salen ) ;
}
char * vnc_socket_remote_addr ( const char * format , int fd ) {
struct sockaddr_storage sa ;
socklen_t salen ;
salen = sizeof ( sa ) ;
if ( getpeername ( fd , ( struct sockaddr * ) & sa , & salen ) < 0 )
return NULL ;
return addr_to_string ( format , & sa , salen ) ;
}
static void vnc_init_basic_info ( struct sockaddr_storage * sa ,
socklen_t salen ,
static void vnc_init_basic_info ( SocketAddress * addr ,
VncBasicInfo * info ,
Error * * errp )
{
char host [ NI_MAXHOST ] ;
char serv [ NI_MAXSERV ] ;
int err ;
switch ( addr - > type ) {
case SOCKET_ADDRESS_KIND_INET :
info - > host = g_strdup ( addr - > u . inet - > host ) ;
info - > service = g_strdup ( addr - > u . inet - > port ) ;
if ( addr - > u . inet - > ipv6 ) {
info - > family = NETWORK_ADDRESS_FAMILY_IPV6 ;
} else {
info - > family = NETWORK_ADDRESS_FAMILY_IPV4 ;
}
break ;
if ( ( err = getnameinfo ( ( struct sockaddr * ) sa , salen ,
host , sizeof ( host ) ,
serv , sizeof ( serv ) ,
NI_NUMERICHOST | NI_NUMERICSERV ) ) ! = 0 ) {
error_setg ( errp , " Cannot resolve address: %s " ,
gai_strerror ( err ) ) ;
return ;
case SOCKET_ADDRESS_KIND_UNIX :
info - > host = g_strdup ( " " ) ;
info - > service = g_strdup ( addr - > u . q_unix - > path ) ;
info - > family = NETWORK_ADDRESS_FAMILY_UNIX ;
break ;
default :
error_setg ( errp , " Unsupported socket kind %d " ,
addr - > type ) ;
break ;
}
info - > host = g_strdup ( host ) ;
info - > service = g_strdup ( serv ) ;
info - > family = inet_netfamily ( sa - > ss_family ) ;
return ;
}
static void vnc_init_basic_info_from_server_addr ( int fd , VncBasicInfo * info ,
static void vnc_init_basic_info_from_server_addr ( QIOChannelSocket * ioc ,
VncBasicInfo * info ,
Error * * errp )
{
struct sockaddr_storage sa ;
socklen_t salen ;
SocketAddress * addr = NULL ;
salen = sizeof ( sa ) ;
if ( getsockname ( fd , ( struct sockaddr * ) & sa , & salen ) < 0 ) {
error_setg_errno ( errp , errno , " getsockname failed " ) ;
addr = qio_channel_socket_get_local_address ( ioc , errp ) ;
if ( ! addr ) {
return ;
}
vnc_init_basic_info ( & sa , salen , info , errp ) ;
vnc_init_basic_info ( addr , info , errp ) ;
qapi_free_SocketAddress ( addr ) ;
}
static void vnc_init_basic_info_from_remote_addr ( int fd , VncBasicInfo * info ,
static void vnc_init_basic_info_from_remote_addr ( QIOChannelSocket * ioc ,
VncBasicInfo * info ,
Error * * errp )
{
struct sockaddr_storage sa ;
socklen_t salen ;
SocketAddress * addr = NULL ;
salen = sizeof ( sa ) ;
if ( getpeername ( fd , ( struct sockaddr * ) & sa , & salen ) < 0 ) {
error_setg_errno ( errp , errno , " getpeername failed " ) ;
addr = qio_channel_socket_get_remote_address ( ioc , errp ) ;
if ( ! addr ) {
return ;
}
vnc_init_basic_info ( & sa , salen , info , errp ) ;
vnc_init_basic_info ( addr , info , errp ) ;
qapi_free_SocketAddress ( addr ) ;
}
static const char * vnc_auth_name ( VncDisplay * vd ) {
@ -300,7 +257,7 @@ static void vnc_client_cache_addr(VncState *client)
Error * err = NULL ;
client - > info = g_malloc0 ( sizeof ( * client - > info ) ) ;
vnc_init_basic_info_from_remote_addr ( client - > c sock ,
vnc_init_basic_info_from_remote_addr ( client - > si oc ,
qapi_VncClientInfo_base ( client - > info ) ,
& err ) ;
if ( err ) {
@ -343,27 +300,20 @@ static void vnc_qmp_event(VncState *vs, QAPIEvent event)
static VncClientInfo * qmp_query_vnc_client ( const VncState * client )
{
struct sockaddr_storage sa ;
socklen_t salen = sizeof ( sa ) ;
char host [ NI_MAXHOST ] ;
char serv [ NI_MAXSERV ] ;
VncClientInfo * info ;
Error * err = NULL ;
if ( getpeername ( client - > csock , ( struct sockaddr * ) & sa , & salen ) < 0 ) {
return NULL ;
}
info = g_malloc0 ( sizeof ( * info ) ) ;
if ( getnameinfo ( ( struct sockaddr * ) & sa , salen ,
host , sizeof ( host ) ,
serv , sizeof ( serv ) ,
NI_NUMERICHOST | NI_NUMERICSERV ) < 0 ) {
vnc_init_basic_info_from_remote_addr ( client - > sioc ,
qapi_VncClientInfo_base ( info ) ,
& err ) ;
if ( err ) {
error_free ( err ) ;
qapi_free_VncClientInfo ( info ) ;
return NULL ;
}
info = g_malloc0 ( sizeof ( * info ) ) ;
info - > host = g_strdup ( host ) ;
info - > service = g_strdup ( serv ) ;
info - > family = inet_netfamily ( sa . ss_family ) ;
info - > websocket = client - > websocket ;
if ( client - > tls ) {
@ -413,81 +363,89 @@ VncInfo *qmp_query_vnc(Error **errp)
{
VncInfo * info = g_malloc0 ( sizeof ( * info ) ) ;
VncDisplay * vd = vnc_display_find ( NULL ) ;
SocketAddress * addr = NULL ;
if ( vd = = NULL | | ! vd - > enabled ) {
info - > enabled = false ;
} else {
struct sockaddr_storage sa ;
socklen_t salen = sizeof ( sa ) ;
char host [ NI_MAXHOST ] ;
char serv [ NI_MAXSERV ] ;
info - > enabled = true ;
/* for compatibility with the original command */
info - > has_clients = true ;
info - > clients = qmp_query_client_list ( vd ) ;
if ( vd - > lsock = = - 1 ) {
if ( vd - > lsock = = NULL ) {
return info ;
}
if ( getsockname ( vd - > lsock , ( struct sockaddr * ) & sa ,
& salen ) = = - 1 ) {
error_setg ( errp , QERR_UNDEFINED_ERROR ) ;
addr = qio_channel_socket_get_local_address ( vd - > lsock , errp ) ;
if ( ! addr ) {
goto out_error ;
}
if ( getnameinfo ( ( struct sockaddr * ) & sa , salen ,
host , sizeof ( host ) ,
serv , sizeof ( serv ) ,
NI_NUMERICHOST | NI_NUMERICSERV ) < 0 ) {
error_setg ( errp , QERR_UNDEFINED_ERROR ) ;
switch ( addr - > type ) {
case SOCKET_ADDRESS_KIND_INET :
info - > host = g_strdup ( addr - > u . inet - > host ) ;
info - > service = g_strdup ( addr - > u . inet - > port ) ;
if ( addr - > u . inet - > ipv6 ) {
info - > family = NETWORK_ADDRESS_FAMILY_IPV6 ;
} else {
info - > family = NETWORK_ADDRESS_FAMILY_IPV4 ;
}
break ;
case SOCKET_ADDRESS_KIND_UNIX :
info - > host = g_strdup ( " " ) ;
info - > service = g_strdup ( addr - > u . q_unix - > path ) ;
info - > family = NETWORK_ADDRESS_FAMILY_UNIX ;
break ;
default :
error_setg ( errp , " Unsupported socket kind %d " ,
addr - > type ) ;
goto out_error ;
}
info - > has_host = true ;
info - > host = g_strdup ( host ) ;
info - > has_service = true ;
info - > service = g_strdup ( serv ) ;
info - > has_family = true ;
info - > family = inet_netfamily ( sa . ss_family ) ;
info - > has_auth = true ;
info - > auth = g_strdup ( vnc_auth_name ( vd ) ) ;
}
qapi_free_SocketAddress ( addr ) ;
return info ;
out_error :
qapi_free_SocketAddress ( addr ) ;
qapi_free_VncInfo ( info ) ;
return NULL ;
}
static VncBasicInfoList * qmp_query_server_entry ( int socket ,
static VncBasicInfoList * qmp_query_server_entry ( QIOChannelSocket * ioc ,
bool websocket ,
VncBasicInfoList * prev )
{
VncBasicInfoList * list ;
VncBasicInfo * info ;
struct sockaddr_storage sa ;
socklen_t salen = sizeof ( sa ) ;
char host [ NI_MAXHOST ] ;
char serv [ NI_MAXSERV ] ;
if ( getsockname ( socket , ( struct sockaddr * ) & sa , & salen ) < 0 | |
getnameinfo ( ( struct sockaddr * ) & sa , salen ,
host , sizeof ( host ) , serv , sizeof ( serv ) ,
NI_NUMERICHOST | NI_NUMERICSERV ) < 0 ) {
Error * err = NULL ;
SocketAddress * addr ;
addr = qio_channel_socket_get_local_address ( ioc , & err ) ;
if ( ! addr ) {
error_free ( err ) ;
return prev ;
}
info = g_new0 ( VncBasicInfo , 1 ) ;
info - > host = g_strdup ( host ) ;
info - > service = g_strdup ( serv ) ;
info - > family = inet_netfamily ( sa . ss_family ) ;
vnc_init_basic_info ( addr , info , & err ) ;
qapi_free_SocketAddress ( addr ) ;
if ( err ) {
qapi_free_VncBasicInfo ( info ) ;
error_free ( err ) ;
return prev ;
}
info - > websocket = websocket ;
list = g_new0 ( VncBasicInfoList , 1 ) ;
@ -581,13 +539,13 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
info - > has_display = true ;
info - > display = g_strdup ( dev - > id ) ;
}
if ( vd - > lsock ! = - 1 ) {
info - > server = qmp_query_server_entry ( vd - > lsock , false ,
info - > server ) ;
if ( vd - > lsock ! = NULL ) {
info - > server = qmp_query_server_entry (
vd - > lsock , false , info - > server ) ;
}
if ( vd - > lwebsock ! = - 1 ) {
info - > server = qmp_query_server_entry ( vd - > lwebsock , true ,
info - > server ) ;
if ( vd - > lwebsock ! = NULL ) {
info - > server = qmp_query_server_entry (
vd - > lwebsock , true , info - > server ) ;
}
item = g_new0 ( VncInfo2List , 1 ) ;
@ -673,7 +631,7 @@ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
static void vnc_desktop_resize ( VncState * vs )
{
if ( vs - > csock = = - 1 | | ! vnc_has_feature ( vs , VNC_FEATURE_RESIZE ) ) {
if ( vs - > ioc = = NULL | | ! vnc_has_feature ( vs , VNC_FEATURE_RESIZE ) ) {
return ;
}
if ( vs - > client_width = = pixman_image_get_width ( vs - > vd - > server ) & &
@ -1066,7 +1024,7 @@ static int find_and_clear_dirty_height(VncState *vs,
static int vnc_update_client ( VncState * vs , int has_dirty , bool sync )
{
vs - > has_dirty + = has_dirty ;
if ( vs - > need_update & & vs - > csock ! = - 1 ) {
if ( vs - > need_update & & vs - > ioc ! = NULL ) {
VncDisplay * vd = vs - > vd ;
VncJob * job ;
int y ;
@ -1130,7 +1088,7 @@ static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
return n ;
}
if ( vs - > csock = = - 1 ) {
if ( vs - > disconnecting ) {
vnc_disconnect_finish ( vs ) ;
} else if ( sync ) {
vnc_jobs_join ( vs ) ;
@ -1212,12 +1170,15 @@ static void audio_del(VncState *vs)
static void vnc_disconnect_start ( VncState * vs )
{
if ( vs - > csock = = - 1 )
if ( vs - > disconnecting ) {
return ;
}
vnc_set_share_mode ( vs , VNC_SHARE_MODE_DISCONNECTED ) ;
qemu_set_fd_handler ( vs - > csock , NULL , NULL , NULL ) ;
closesocket ( vs - > csock ) ;
vs - > csock = - 1 ;
if ( vs - > ioc_tag ) {
g_source_remove ( vs - > ioc_tag ) ;
}
qio_channel_close ( vs - > ioc , NULL ) ;
vs - > disconnecting = TRUE ;
}
void vnc_disconnect_finish ( VncState * vs )
@ -1270,29 +1231,29 @@ void vnc_disconnect_finish(VncState *vs)
g_free ( vs - > lossy_rect [ i ] ) ;
}
g_free ( vs - > lossy_rect ) ;
object_unref ( OBJECT ( vs - > ioc ) ) ;
vs - > ioc = NULL ;
object_unref ( OBJECT ( vs - > sioc ) ) ;
vs - > sioc = NULL ;
g_free ( vs ) ;
}
ssize_t vnc_client_io_error ( VncState * vs , ssize_t ret , int last_errno )
ssize_t vnc_client_io_error ( VncState * vs , ssize_t ret , Error * * errp )
{
if ( ret = = 0 | | ret = = - 1 ) {
if ( ret = = - 1 ) {
switch ( last_errno ) {
case EINTR :
case EAGAIN :
# ifdef _WIN32
case WSAEWOULDBLOCK :
# endif
return 0 ;
default :
break ;
}
if ( ret < = 0 ) {
if ( ret = = 0 ) {
VNC_DEBUG ( " Closing down client sock: EOF \n " ) ;
} else if ( ret ! = QIO_CHANNEL_ERR_BLOCK ) {
VNC_DEBUG ( " Closing down client sock: ret %d (%s) \n " ,
ret , errp ? error_get_pretty ( * errp ) : " Unknown " ) ;
}
VNC_DEBUG ( " Closing down client sock: ret %zd, errno %d \n " ,
ret , ret < 0 ? last_errno : 0 ) ;
vnc_disconnect_start ( vs ) ;
if ( errp ) {
error_free ( * errp ) ;
* errp = NULL ;
}
return 0 ;
}
return ret ;
@ -1309,13 +1270,12 @@ void vnc_client_error(VncState *vs)
ssize_t vnc_tls_pull ( char * buf , size_t len , void * opaque )
{
VncState * vs = opaque ;
ssize_t ret ;
retry :
ret = qemu_recv ( vs - > csock , buf , len , 0 ) ;
ssize_t ret = qio_channel_read ( vs - > ioc , buf , len , NULL ) ;
if ( ret < 0 ) {
if ( errno = = EINTR ) {
goto retry ;
if ( ret = = QIO_CHANNEL_ERR_BLOCK ) {
errno = EAGAIN ;
} else {
errno = EIO ;
}
return - 1 ;
}
@ -1326,13 +1286,12 @@ ssize_t vnc_tls_pull(char *buf, size_t len, void *opaque)
ssize_t vnc_tls_push ( const char * buf , size_t len , void * opaque )
{
VncState * vs = opaque ;
ssize_t ret ;
retry :
ret = send ( vs - > csock , buf , len , 0 ) ;
ssize_t ret = qio_channel_write ( vs - > ioc , buf , len , NULL ) ;
if ( ret < 0 ) {
if ( errno = = EINTR ) {
goto retry ;
if ( ret = = QIO_CHANNEL_ERR_BLOCK ) {
errno = EAGAIN ;
} else {
errno = EIO ;
}
return - 1 ;
}
@ -1357,21 +1316,25 @@ ssize_t vnc_tls_push(const char *buf, size_t len, void *opaque)
*/
ssize_t vnc_client_write_buf ( VncState * vs , const uint8_t * data , size_t datalen )
{
Error * err = NULL ;
ssize_t ret ;
int err = 0 ;
if ( vs - > tls ) {
ret = qcrypto_tls_session_write ( vs - > tls , ( const char * ) data , datalen ) ;
if ( ret < 0 ) {
err = errno ;
if ( errno = = EAGAIN ) {
ret = QIO_CHANNEL_ERR_BLOCK ;
} else {
ret = - 1 ;
error_setg_errno ( & err , errno , " %s " ,
" Cannot write to TLS socket " ) ;
}
}
} else {
ret = send ( vs - > csock , ( const void * ) data , datalen , 0 ) ;
if ( ret < 0 ) {
err = socket_error ( ) ;
}
ret = qio_channel_write (
vs - > ioc , ( const char * ) data , datalen , & err ) ;
}
VNC_DEBUG ( " Wrote wire %p %zd -> %ld \n " , data , datalen , ret ) ;
return vnc_client_io_error ( vs , ret , err ) ;
return vnc_client_io_error ( vs , ret , & err ) ;
}
@ -1409,7 +1372,11 @@ static ssize_t vnc_client_write_plain(VncState *vs)
buffer_advance ( & vs - > output , ret ) ;
if ( vs - > output . offset = = 0 ) {
qemu_set_fd_handler ( vs - > csock , vnc_client_read , NULL , vs ) ;
if ( vs - > ioc_tag ) {
g_source_remove ( vs - > ioc_tag ) ;
}
vs - > ioc_tag = qio_channel_add_watch (
vs - > ioc , G_IO_IN , vnc_client_io , vs , NULL ) ;
}
return ret ;
@ -1421,10 +1388,8 @@ static ssize_t vnc_client_write_plain(VncState *vs)
* the client socket . Will delegate actual work according to whether
* SASL SSF layers are enabled ( thus requiring encryption calls )
*/
static void vnc_client_write_locked ( void * opaque )
static void vnc_client_write_locked ( VncState * vs )
{
VncState * vs = opaque ;
# ifdef CONFIG_VNC_SASL
if ( vs - > sasl . conn & &
vs - > sasl . runSSF & &
@ -1441,15 +1406,18 @@ static void vnc_client_write_locked(void *opaque)
}
}
void vnc_client_write ( void * opaque )
static void vnc_client_write ( VncState * vs )
{
VncState * vs = opaque ;
vnc_lock_output ( vs ) ;
if ( vs - > output . offset | | vs - > ws_output . offset ) {
vnc_client_write_locked ( opaque ) ;
} else if ( vs - > csock ! = - 1 ) {
qemu_set_fd_handler ( vs - > csock , vnc_client_read , NULL , vs ) ;
vnc_client_write_locked ( vs ) ;
} else if ( vs - > ioc ! = NULL ) {
if ( vs - > ioc_tag ) {
g_source_remove ( vs - > ioc_tag ) ;
}
vs - > ioc_tag = qio_channel_add_watch (
vs - > ioc , G_IO_IN , vnc_client_io , vs , NULL ) ;
}
vnc_unlock_output ( vs ) ;
}
@ -1479,20 +1447,24 @@ void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
ssize_t vnc_client_read_buf ( VncState * vs , uint8_t * data , size_t datalen )
{
ssize_t ret ;
int err = - 1 ;
Error * err = NULL ;
if ( vs - > tls ) {
ret = qcrypto_tls_session_read ( vs - > tls , ( char * ) data , datalen ) ;
if ( ret < 0 ) {
err = errno ;
if ( errno = = EAGAIN ) {
ret = QIO_CHANNEL_ERR_BLOCK ;
} else {
ret = - 1 ;
error_setg_errno ( & err , errno , " %s " ,
" Cannot read from TLS socket " ) ;
}
}
} else {
ret = qemu_recv ( vs - > csock , data , datalen , 0 ) ;
if ( ret < 0 ) {
err = socket_error ( ) ;
}
ret = qio_channel_read (
vs - > ioc , ( char * ) data , datalen , & err ) ;
}
VNC_DEBUG ( " Read wire %p %zd -> %ld \n " , data , datalen , ret ) ;
return vnc_client_io_error ( vs , ret , err ) ;
return vnc_client_io_error ( vs , ret , & err ) ;
}
@ -1529,9 +1501,8 @@ static void vnc_jobs_bh(void *opaque)
* the client socket . Will delegate actual work according to whether
* SASL SSF layers are enabled ( thus requiring decryption calls )
*/
void vnc_client_read ( void * opaque )
static void vnc_client_read ( VncState * vs )
{
VncState * vs = opaque ;
ssize_t ret ;
# ifdef CONFIG_VNC_SASL
@ -1552,8 +1523,9 @@ void vnc_client_read(void *opaque)
ret = vnc_client_read_plain ( vs ) ;
}
if ( ! ret ) {
if ( vs - > csock = = - 1 )
if ( vs - > disconnecting ) {
vnc_disconnect_finish ( vs ) ;
}
return ;
}
@ -1562,7 +1534,7 @@ void vnc_client_read(void *opaque)
int ret ;
ret = vs - > read_handler ( vs , vs - > input . buffer , len ) ;
if ( vs - > csock = = - 1 ) {
if ( vs - > disconnecting ) {
vnc_disconnect_finish ( vs ) ;
return ;
}
@ -1575,12 +1547,30 @@ void vnc_client_read(void *opaque)
}
}
gboolean vnc_client_io ( QIOChannel * ioc G_GNUC_UNUSED ,
GIOCondition condition , void * opaque )
{
VncState * vs = opaque ;
if ( condition & G_IO_IN ) {
vnc_client_read ( vs ) ;
}
if ( condition & G_IO_OUT ) {
vnc_client_write ( vs ) ;
}
return TRUE ;
}
void vnc_write ( VncState * vs , const void * data , size_t len )
{
buffer_reserve ( & vs - > output , len ) ;
if ( vs - > csock ! = - 1 & & buffer_empty ( & vs - > output ) ) {
qemu_set_fd_handler ( vs - > csock , vnc_client_read , vnc_client_write , vs ) ;
if ( vs - > ioc ! = NULL & & buffer_empty ( & vs - > output ) ) {
if ( vs - > ioc_tag ) {
g_source_remove ( vs - > ioc_tag ) ;
}
vs - > ioc_tag = qio_channel_add_watch (
vs - > ioc , G_IO_IN | G_IO_OUT , vnc_client_io , vs , NULL ) ;
}
buffer_append ( & vs - > output , data , len ) ;
@ -1621,8 +1611,7 @@ void vnc_write_u8(VncState *vs, uint8_t value)
void vnc_flush ( VncState * vs )
{
vnc_lock_output ( vs ) ;
if ( vs - > csock ! = - 1 & & ( vs - > output . offset | |
vs - > ws_output . offset ) ) {
if ( vs - > ioc ! = NULL & & ( vs - > output . offset | | vs - > ws_output . offset ) ) {
vnc_client_write_locked ( vs ) ;
}
vnc_unlock_output ( vs ) ;
@ -3006,34 +2995,37 @@ static void vnc_refresh(DisplayChangeListener *dcl)
}
}
static void vnc_connect ( VncDisplay * vd , int csock ,
static void vnc_connect ( VncDisplay * vd , QIOChannelSocket * sioc ,
bool skipauth , bool websocket )
{
VncState * vs = g_new0 ( VncState , 1 ) ;
int i ;
vs - > csock = csock ;
vs - > sioc = sioc ;
object_ref ( OBJECT ( vs - > sioc ) ) ;
vs - > ioc = QIO_CHANNEL ( sioc ) ;
object_ref ( OBJECT ( vs - > ioc ) ) ;
vs - > vd = vd ;
buffer_init ( & vs - > input , " vnc-input/%d " , csock ) ;
buffer_init ( & vs - > output , " vnc-output/%d " , c sock ) ;
buffer_init ( & vs - > ws_input , " vnc-ws_input/%d " , c sock ) ;
buffer_init ( & vs - > ws_output , " vnc-ws_output/%d " , c sock ) ;
buffer_init ( & vs - > jobs_buffer , " vnc-jobs_buffer/%d " , c sock ) ;
buffer_init ( & vs - > input , " vnc-input/%p " , si oc ) ;
buffer_init ( & vs - > output , " vnc-output/%p " , si oc ) ;
buffer_init ( & vs - > ws_input , " vnc-ws_input/%p " , si oc ) ;
buffer_init ( & vs - > ws_output , " vnc-ws_output/%p " , si oc ) ;
buffer_init ( & vs - > jobs_buffer , " vnc-jobs_buffer/%p " , si oc ) ;
buffer_init ( & vs - > tight . tight , " vnc-tight/%d " , c sock ) ;
buffer_init ( & vs - > tight . zlib , " vnc-tight-zlib/%d " , c sock ) ;
buffer_init ( & vs - > tight . gradient , " vnc-tight-gradient/%d " , c sock ) ;
buffer_init ( & vs - > tight . tight , " vnc-tight/%p " , si oc ) ;
buffer_init ( & vs - > tight . zlib , " vnc-tight-zlib/%p " , si oc ) ;
buffer_init ( & vs - > tight . gradient , " vnc-tight-gradient/%p " , si oc ) ;
# ifdef CONFIG_VNC_JPEG
buffer_init ( & vs - > tight . jpeg , " vnc-tight-jpeg/%d " , c sock ) ;
buffer_init ( & vs - > tight . jpeg , " vnc-tight-jpeg/%p " , si oc ) ;
# endif
# ifdef CONFIG_VNC_PNG
buffer_init ( & vs - > tight . png , " vnc-tight-png/%d " , c sock ) ;
buffer_init ( & vs - > tight . png , " vnc-tight-png/%p " , si oc ) ;
# endif
buffer_init ( & vs - > zlib . zlib , " vnc-zlib/%d " , c sock ) ;
buffer_init ( & vs - > zrle . zrle , " vnc-zrle/%d " , c sock ) ;
buffer_init ( & vs - > zrle . fb , " vnc-zrle-fb/%d " , c sock ) ;
buffer_init ( & vs - > zrle . zlib , " vnc-zrle-zlib/%d " , c sock ) ;
buffer_init ( & vs - > zlib . zlib , " vnc-zlib/%p " , si oc ) ;
buffer_init ( & vs - > zrle . zrle , " vnc-zrle/%p " , si oc ) ;
buffer_init ( & vs - > zrle . fb , " vnc-zrle-fb/%p " , si oc ) ;
buffer_init ( & vs - > zrle . zlib , " vnc-zrle-zlib/%p " , si oc ) ;
if ( skipauth ) {
vs - > auth = VNC_AUTH_NONE ;
@ -3047,27 +3039,29 @@ static void vnc_connect(VncDisplay *vd, int csock,
vs - > subauth = vd - > subauth ;
}
}
VNC_DEBUG ( " Client sock=%d ws=%d auth=%d subauth=%d \n " ,
c sock , websocket , vs - > auth , vs - > subauth ) ;
VNC_DEBUG ( " Client sioc=%p ws=%d auth=%d subauth=%d \n " ,
si oc , websocket , vs - > auth , vs - > subauth ) ;
vs - > lossy_rect = g_malloc0 ( VNC_STAT_ROWS * sizeof ( * vs - > lossy_rect ) ) ;
for ( i = 0 ; i < VNC_STAT_ROWS ; + + i ) {
vs - > lossy_rect [ i ] = g_new0 ( uint8_t , VNC_STAT_COLS ) ;
}
VNC_DEBUG ( " New client on socket %d \n " , csock ) ;
VNC_DEBUG ( " New client on socket %p \n " , vs - > sioc ) ;
update_displaychangelistener ( & vd - > dcl , VNC_REFRESH_INTERVAL_BASE ) ;
qemu_set_nonblock ( vs - > csock ) ;
qio_channel_set_blocking ( vs - > ioc , false , NULL ) ;
if ( websocket ) {
vs - > websocket = 1 ;
if ( vd - > ws_tls ) {
qemu_set_fd_handler ( vs - > csock , vncws_tls_handshake_io , NULL , vs ) ;
vs - > ioc_tag = qio_channel_add_watch (
vs - > ioc , G_IO_IN , vncws_tls_handshake_io , vs , NULL ) ;
} else {
qemu_set_fd_handler ( vs - > csock , vncws_handshake_read , NULL , vs ) ;
vs - > ioc_tag = qio_channel_add_watch (
vs - > ioc , G_IO_IN , vncws_handshake_io , vs , NULL ) ;
}
} else
{
qemu_set_fd_handler ( vs - > csock , vnc_client_read , NULL , vs ) ;
} else {
vs - > ioc_tag = qio_channel_add_watch (
vs - > ioc , G_IO_IN , vnc_client_io , vs , NULL ) ;
}
vnc_client_cache_addr ( vs ) ;
@ -3125,35 +3119,28 @@ void vnc_init_state(VncState *vs)
/* vs might be free()ed here */
}
static void vnc_listen_read ( void * opaque , bool websocket )
static gboolean vnc_listen_io ( QIOChannel * ioc ,
GIOCondition condition ,
void * opaque )
{
VncDisplay * vs = opaque ;
struct sockaddr_in addr ;
socklen_t addrlen = sizeof ( addr ) ;
int csock ;
QIOChannelSocket * sioc = NULL ;
Error * err = NULL ;
/* Catch-up */
graphic_hw_update ( vs - > dcl . con ) ;
if ( websocket ) {
csock = qemu_accept ( vs - > lwebsock , ( struct sockaddr * ) & addr , & addrlen ) ;
sioc = qio_channel_socket_accept ( QIO_CHANNEL_SOCKET ( ioc ) , & err ) ;
if ( sioc ! = NULL ) {
qio_channel_set_delay ( QIO_CHANNEL ( sioc ) , false ) ;
vnc_connect ( vs , sioc , false ,
ioc ! = QIO_CHANNEL ( vs - > lsock ) ) ;
object_unref ( OBJECT ( sioc ) ) ;
} else {
csock = qemu_accept ( vs - > lsock , ( struct sockaddr * ) & addr , & addrlen ) ;
}
if ( csock ! = - 1 ) {
socket_set_nodelay ( csock ) ;
vnc_connect ( vs , csock , false , websocket ) ;
/* client probably closed connection before we got there */
error_free ( err ) ;
}
}
static void vnc_listen_regular_read ( void * opaque )
{
vnc_listen_read ( opaque , false ) ;
}
static void vnc_listen_websocket_read ( void * opaque )
{
vnc_listen_read ( opaque , true ) ;
return TRUE ;
}
static const DisplayChangeListenerOps dcl_ops = {
@ -3179,9 +3166,6 @@ void vnc_display_init(const char *id)
vs - > id = strdup ( id ) ;
QTAILQ_INSERT_TAIL ( & vnc_displays , vs , next ) ;
vs - > lsock = - 1 ;
vs - > lwebsock = - 1 ;
QTAILQ_INIT ( & vs - > clients ) ;
vs - > expires = TIME_MAX ;
@ -3209,16 +3193,20 @@ static void vnc_display_close(VncDisplay *vs)
return ;
vs - > enabled = false ;
vs - > is_unix = false ;
if ( vs - > lsock ! = - 1 ) {
qemu_set_fd_handler ( vs - > lsock , NULL , NULL , NULL ) ;
close ( vs - > lsock ) ;
vs - > lsock = - 1 ;
if ( vs - > lsock ! = NULL ) {
if ( vs - > lsock_tag ) {
g_source_remove ( vs - > lsock_tag ) ;
}
object_unref ( OBJECT ( vs - > lsock ) ) ;
vs - > lsock = NULL ;
}
vs - > ws_enabled = false ;
if ( vs - > lwebsock ! = - 1 ) {
qemu_set_fd_handler ( vs - > lwebsock , NULL , NULL , NULL ) ;
close ( vs - > lwebsock ) ;
vs - > lwebsock = - 1 ;
if ( vs - > lwebsock ! = NULL ) {
if ( vs - > lwebsock_tag ) {
g_source_remove ( vs - > lwebsock_tag ) ;
}
object_unref ( OBJECT ( vs - > lwebsock ) ) ;
vs - > lwebsock = NULL ;
}
vs - > auth = VNC_AUTH_INVALID ;
vs - > subauth = VNC_AUTH_INVALID ;
@ -3263,9 +3251,25 @@ int vnc_display_pw_expire(const char *id, time_t expires)
char * vnc_display_local_addr ( const char * id )
{
VncDisplay * vs = vnc_display_find ( id ) ;
SocketAddress * addr ;
char * ret ;
Error * err = NULL ;
assert ( vs ) ;
return vnc_socket_local_addr ( " %s:%s " , vs - > lsock ) ;
addr = qio_channel_socket_get_local_address ( vs - > lsock , & err ) ;
if ( ! addr ) {
return NULL ;
}
if ( addr - > type ! = SOCKET_ADDRESS_KIND_INET ) {
qapi_free_SocketAddress ( addr ) ;
return NULL ;
}
ret = g_strdup_printf ( " %s;%s " , addr - > u . inet - > host , addr - > u . inet - > port ) ;
qapi_free_SocketAddress ( addr ) ;
return ret ;
}
static QemuOptsList qemu_vnc_opts = {
@ -3826,41 +3830,45 @@ void vnc_display_open(const char *id, Error **errp)
if ( reverse ) {
/* connect to viewer */
int csock ;
vs - > lsock = - 1 ;
vs - > lwebsock = - 1 ;
QIOChannelSocket * sioc = NULL ;
vs - > lsock = NULL ;
vs - > lwebsock = NULL ;
if ( vs - > ws_enabled ) {
error_setg ( errp , " Cannot use websockets in reverse mode " ) ;
goto fail ;
}
csock = socket_connect ( saddr , errp , NULL , NULL ) ;
if ( csock < 0 ) {
vs - > is_unix = saddr - > type = = SOCKET_ADDRESS_KIND_UNIX ;
sioc = qio_channel_socket_new ( ) ;
if ( qio_channel_socket_connect_sync ( sioc , saddr , errp ) < 0 ) {
goto fail ;
}
vs - > is_unix = saddr - > type = = SOCKET_ADDRESS_KIND_UNIX ;
vnc_connect ( vs , csock , false , false ) ;
vnc_connect ( vs , sioc , false , false ) ;
object_unref ( OBJECT ( sioc ) ) ;
} else {
/* listen for connects */
vs - > lsock = socket_listen ( saddr , errp ) ;
if ( vs - > lsock < 0 ) {
vs - > lsock = qio_channel_socket_new ( ) ;
if ( qio_channel_socket_listen_sync ( vs - > lsock , saddr , errp ) < 0 ) {
goto fail ;
}
vs - > is_unix = saddr - > type = = SOCKET_ADDRESS_KIND_UNIX ;
vs - > enabled = true ;
if ( vs - > ws_enabled ) {
vs - > lwebsock = socket_listen ( wsaddr , errp ) ;
if ( vs - > lwebsock < 0 ) {
if ( vs - > lsock ! = - 1 ) {
close ( vs - > lsock ) ;
vs - > lsock = - 1 ;
}
vs - > lwebsock = qio_channel_socket_new ( ) ;
if ( qio_channel_socket_listen_sync ( vs - > lwebsock ,
wsaddr , errp ) < 0 ) {
object_unref ( OBJECT ( vs - > lsock ) ) ;
vs - > lsock = NULL ;
goto fail ;
}
}
vs - > enabled = true ;
qemu_set_fd_handler ( vs - > lsock , vnc_listen_regular_read , NULL , vs ) ;
vs - > lsock_tag = qio_channel_add_watch (
QIO_CHANNEL ( vs - > lsock ) ,
G_IO_IN , vnc_listen_io , vs , NULL ) ;
if ( vs - > ws_enabled ) {
qemu_set_fd_handler ( vs - > lwebsock , vnc_listen_websocket_read ,
NULL , vs ) ;
vs - > lwebsock_tag = qio_channel_add_watch (
QIO_CHANNEL ( vs - > lwebsock ) ,
G_IO_IN , vnc_listen_io , vs , NULL ) ;
}
}
@ -3878,11 +3886,17 @@ fail:
void vnc_display_add_client ( const char * id , int csock , bool skipauth )
{
VncDisplay * vs = vnc_display_find ( id ) ;
QIOChannelSocket * sioc ;
if ( ! vs ) {
return ;
}
vnc_connect ( vs , csock , skipauth , false ) ;
sioc = qio_channel_socket_new_fd ( csock , NULL ) ;
if ( sioc ) {
vnc_connect ( vs , sioc , skipauth , false ) ;
object_unref ( OBJECT ( sioc ) ) ;
}
}
static void vnc_auto_assign_id ( QemuOptsList * olist , QemuOpts * opts )