/* * Private function name: vnc_refresh_screen * Since version: 0.4.1(-3) * Description: Function to send the key to VNC window to refresh the screen * Arguments: @server [string]: server string to connect to * @port [string]: string version of port value to connect to * @scancode [int]: scancode to be sent to the guest's VNC window * Returns: 0 on success, -errno otherwise */ int vnc_refresh_screen(char *server, char *port, int scancode) { int sfd; tServerFBParams params; DPRINTF("%s: Server is %s, port is %s, scancode is %d\n", VNCFUNC, server, port, scancode); DPRINTF("%s: server is %s, port is %s\n", VNCFUNC, server, port); sfd = vnc_connect(server, port, 1); if (sfd < 0) { int err = errno; DPRINTF("%s: VNC Connection failed with error code %d (%s)\n", VNCFUNC, err, strerror(err)); close(sfd); return -err; } params = vnc_read_server_init(sfd); DPRINTF("%s: Sending key press emulation for key %d\n", VNCFUNC, scancode); if (scancode > -1) vnc_send_key(sfd, scancode, 1, 0); DPRINTF("%s: Requesting framebuffer update\n", VNCFUNC); vnc_send_framebuffer_update_request(sfd, 1, params); shutdown(sfd, SHUT_RDWR); close(sfd); DPRINTF("%s: Closed descriptor #%d\n", VNCFUNC, sfd); return 0; }
/* * Private function name: vnc_send_keys * Since version: 0.4.2 * Description: Function to send the key to VNC window * Arguments: @server [string]: server string to specify VNC server * @port [string]: string version of port value to connect to * @keys [string]: string to be send to the guest's VNC window * Returns: 0 on success, -errno otherwise */ int vnc_send_keys(char *server, char *port, char *keys) { int sfd; int i, skip_next; tServerFBParams params; DPRINTF("%s: server is %s, port is %s, keys are '%s'\n", VNCFUNC, server, port, keys); sfd = vnc_connect(server, port, 1); if (sfd < 0) { int err = errno; DPRINTF("%s: VNC Connection failed with error code %d (%s)\n", VNCFUNC, err, strerror(err)); close(sfd); return -err; } params = vnc_read_server_init(sfd); skip_next = 0; DPRINTF("%s: About to process key sequence '%s' (%d keys)\n", VNCFUNC, keys, (int)strlen(keys)); for (i = 0; i < strlen(keys); i++) { DPRINTF("%s: Processing key %d: %d [0x%02x]\n", VNCFUNC, i, keys[i], keys[i]); if (skip_next) { skip_next = 0; continue; } /* Handling for escape characters */ if ((keys[i] == '\\') && (strlen(keys) > i + 1)) { if (keys[i + 1] == 'n') keys[i] = 13; if (keys[i + 1] == 'r') keys[i] = 10; skip_next = 1; } DPRINTF("%s: Sending key press emulation for key %d\n", VNCFUNC, keys[i]); vnc_send_key(sfd, keys[i], skip_next, 0); DPRINTF("%s: Requesting framebuffer update\n", VNCFUNC); vnc_send_framebuffer_update_request(sfd, 1, params); DPRINTF("%s: Sending key release emulation for key %d\n", VNCFUNC, keys[i]); vnc_send_key(sfd, keys[i], skip_next, 1); /* Sleep for 50 ms, required to make VNC server accept the keystroke emulation */ usleep(50000); } DPRINTF("%s: All %d keys sent\n", VNCFUNC, (int)strlen(keys)); while (socket_has_data(sfd, 500000, 0) == 1) socket_read(sfd, -1); shutdown(sfd, SHUT_RDWR); close(sfd); DPRINTF("%s: Closed descriptor #%d\n", VNCFUNC, sfd); return 0; }
/* * Private function name: vnc_send_pointer_event * Since version: 0.4.2 * Description: Function to send the mouse pointer event/click to VNC window * Arguments: @server [string]: server string to specify VNC server * @port [string]: string version of port value to connect to * @pos_x [int]: position on x-axis of the VNC window * @pos_y [int]: position on y-axis of the VNC window * @clicked [int]: mask of what buttons were clicked * @release [boolean]: release the buttons once clicked * Returns: 0 on success, -errno otherwise */ int vnc_send_pointer_event(char *server, char *port, int pos_x, int pos_y, int clicked, int release) { int sfd; tServerFBParams params; DPRINTF("%s: Server is %s, port is %s, x is %d, y is %d, clicked is %d, release is %d\n", VNCFUNC, server, port, pos_x, pos_y, clicked, release); sfd = vnc_connect(server, port, 0); if (sfd < 0) { int err = errno; DPRINTF("%s: VNC Connection failed with error code %d (%s)\n", VNCFUNC, err, strerror(err)); close(sfd); return -err; } params = vnc_read_server_init(sfd); if (((pos_x > params.width) || (pos_y < 0)) || ((pos_y > params.height) || (pos_y < 0))) { DPRINTF("%s: Required positions out of range (width = %d, height = %d, x = %d, y = %d) for '%s'\n", VNCFUNC, params.width, params.height, pos_x, pos_y, params.desktopName); return -EINVAL; } socket_read(sfd, -1); vnc_set_pixel_format(sfd, params); vnc_set_encoding(sfd); socket_read(sfd, -1); usleep(50000); /* Following paragraph moves mouse pointer to [0, 0] (left upper corner) */ vnc_send_client_pointer(sfd, 0, 0x7FFF, 0x7FFF); socket_read(sfd, -1); vnc_send_client_pointer(sfd, 0, 0, 0); socket_read(sfd, -1); vnc_send_client_pointer(sfd, clicked, (pos_x / 2), (params.height - pos_y) / 2); socket_read(sfd, -1); vnc_send_client_pointer(sfd, 0, (pos_x / 2), ((params.height - pos_y) / 2)); socket_read(sfd, -1); if (release) { vnc_send_client_pointer(sfd, clicked, (pos_x / 2), (params.height - pos_y) / 2); socket_read(sfd, -1); vnc_send_client_pointer(sfd, 0, (pos_x / 2), (params.height - pos_y) / 2); socket_read(sfd, -1); } shutdown(sfd, SHUT_RDWR); close(sfd); DPRINTF("%s: Closed descriptor #%d\n", VNCFUNC, sfd); return 0; }
/* * Private function name: vnc_get_bitmap * Since version: 0.4.5 * Description: Function to get the bitmap from the VNC window * Arguments: @server [string]: server string to specify VNC server * @port [string]: string version of port value to connect to * @fn [string]: string version of filename * Returns: 0 on success, -errno otherwise */ int vnc_get_bitmap(char *server, char *port, char *fn) { int sfd; long pattern_size; tServerFBParams params; char file[] = "/tmp/libvirt-php-tmp-XXXXXX"; if (mkstemp(file) == 0) return -ENOENT; if (fn == NULL) return -ENOENT; sfd = vnc_connect(server, port, 1); if (sfd < 0) { int err = errno; DPRINTF("%s: VNC Connection failed with error code %d (%s)\n", VNCFUNC, err, strerror(err)); close(sfd); return -err; } params = vnc_read_server_init(sfd); pattern_size = params.width * params.height * (params.bpp / 8); DPRINTF("%s: %ld\n", VNCFUNC, pattern_size); vnc_set_pixel_format(sfd, params); vnc_set_encoding(sfd); DPRINTF("%s: Requesting framebuffer update\n", VNCFUNC); vnc_send_framebuffer_update_request(sfd, 1, params); while (socket_has_data(sfd, 50000, 0) == 0) { continue; } socket_read_and_save(sfd, file, pattern_size); shutdown(sfd, SHUT_RDWR); close(sfd); vnc_raw_to_bmp(file, fn, params.width, params.height); unlink(file); DPRINTF("%s: Closed descriptor #%d\n", VNCFUNC, sfd); return 0; }
/* * Private function name: vnc_get_dimensions * Since version: 0.4.3 * Description: Function to get the dimensions of VNC window * Arguments: @server [string]: server string to specify VNC server * @port [string]: string version of port value to connect to * @width [out int]: pointer to integer to carry width argument * @height [out int]: pointer to integer to carry height argument * Returns: 0 on success, -errno otherwise */ int vnc_get_dimensions(char *server, char *port, int *width, int *height) { int sfd; tServerFBParams params; if (!width && !height) { DPRINTF("%s: Neither width or height output value not defined\n", VNCFUNC); return -EINVAL; } DPRINTF("%s: server is %s, port is %s\n", VNCFUNC, server, port); sfd = vnc_connect(server, port, 1); if (sfd < 0) { int err = errno; DPRINTF("%s: VNC Connection failed with error code %d (%s)\n", VNCFUNC, err, strerror(err)); close(sfd); return -err; } params = vnc_read_server_init(sfd); if (width) { *width = params.width; DPRINTF("%s: Output parameter of width set to %d\n", VNCFUNC, *width); } if (height) { *height = params.height; DPRINTF("%s: Output parameter of height set to %d\n", VNCFUNC, *height); } while (socket_has_data(sfd, 500000, 0) == 1) socket_read(sfd, -1); shutdown(sfd, SHUT_RDWR); close(sfd); DPRINTF("%s: Closed descriptor #%d\n", VNCFUNC, sfd); return 0; }
static void* vnc_worker_thread( void *obj ) { filter_t* p_filter = (filter_t*)obj; filter_sys_t *p_sys = p_filter->p_sys; vlc_thread_t update_thread; int canc = vlc_savecancel (); msg_Dbg( p_filter, "VNC worker thread started" ); int fd = vnc_connect( p_filter ); if( fd == -1 ) { msg_Err( p_filter, "Error occurred while handshaking VNC host" ); return NULL; } /* Create an empty picture for VNC the data */ picture_t *pic = picture_New( VLC_CODEC_YUVA, p_sys->i_vnc_width, p_sys->i_vnc_height, 1, 1 ); if( likely(pic != NULL) ) { vlc_mutex_lock( &p_sys->lock ); p_sys->i_socket = fd; p_sys->p_pic = pic; vlc_mutex_unlock( &p_sys->lock ); } else { net_Close( fd ); return NULL; } write_update_request( p_filter, false ); /* create the update request thread */ bool polling = var_InheritBool( p_filter, RMTOSD_CFG "vnc-polling" ); if( polling && vlc_clone( &update_thread, update_request_thread, p_filter, VLC_THREAD_PRIORITY_LOW ) ) { msg_Err( p_filter, "cannot spawn VNC update request thread" ); polling = false; } vlc_cleanup_push( polling ? update_thread_cleanup : dummy_cleanup, &update_thread ); /* connection is initialized, now read and handle server messages */ for( ;; ) { rfbServerToClientMsg msg; int i_msgSize; memset( &msg, 0, sizeof(msg) ); vlc_restorecancel (canc); if( !read_exact(p_filter, fd, &msg, 1 ) ) { msg_Err( p_filter, "Error while waiting for next server message"); break; } switch (msg.type) { case rfbFramebufferUpdate: i_msgSize = sz_rfbFramebufferUpdateMsg; break; case rfbSetColourMapEntries: i_msgSize = sz_rfbSetColourMapEntriesMsg; break; case rfbBell: i_msgSize = sz_rfbBellMsg; break; case rfbServerCutText: i_msgSize = sz_rfbServerCutTextMsg; break; case rfbReSizeFrameBuffer: i_msgSize = sz_rfbReSizeFrameBufferMsg; break; default: i_msgSize = 0; msg_Err( p_filter, "Invalid message %u received", msg.type ); break; } if( i_msgSize <= 0 ) break; if( --i_msgSize > 0 ) { if ( !read_exact( p_filter, fd, ((char *)&msg) + 1, i_msgSize ) ) { msg_Err( p_filter, "Error while reading message of type %u", msg.type ); break; } } canc = vlc_savecancel (); process_server_message( p_filter, &msg); } vlc_cleanup_pop(); if( polling ) update_thread_cleanup( &update_thread ); msg_Dbg( p_filter, "VNC message reader thread ended" ); vlc_restorecancel (canc); return NULL; }