From fea602b6e67164078386f09ba248e0b5d3655efa Mon Sep 17 00:00:00 2001 From: Rom Walton Date: Thu, 12 Jan 2012 15:54:28 +0000 Subject: [PATCH] - VBOX: Enable remote desktop functionality for a VM that has specified in its vbox_job.xml file. NOTE: It does require the VirtualBox extension pack, but that is freely available on the VirtualBox download page. samples/vboxwrapper vbox.cpp, .h vboxwrapper.cpp, .h svn path=/trunk/boinc/; revision=25034 --- checkin_notes | 11 ++ samples/vboxwrapper/vbox.cpp | 109 ++++++++----- samples/vboxwrapper/vbox.h | 231 ++++++++++++++-------------- samples/vboxwrapper/vboxwrapper.cpp | 33 ++++ samples/vboxwrapper/vboxwrapper.h | 1 + 5 files changed, 237 insertions(+), 148 deletions(-) diff --git a/checkin_notes b/checkin_notes index e4ead81faf..c19768c15b 100644 --- a/checkin_notes +++ b/checkin_notes @@ -391,3 +391,14 @@ David 12 Jan 2012 boinc_db.inc user/ lammps.php + +Rom 12 Jan 2012 + - VBOX: Enable remote desktop functionality for a VM that has + specified in its vbox_job.xml file. + + NOTE: It does require the VirtualBox extension pack, but that + is freely available on the VirtualBox download page. + + samples/vboxwrapper + vbox.cpp, .h + vboxwrapper.cpp, .h diff --git a/samples/vboxwrapper/vbox.cpp b/samples/vboxwrapper/vbox.cpp index 0b4151c79c..ae1d3c420f 100644 --- a/samples/vboxwrapper/vbox.cpp +++ b/samples/vboxwrapper/vbox.cpp @@ -648,6 +648,35 @@ int VBOX_VM::get_port_forwarding_port() { return 0; } +int VBOX_VM::get_remote_desktop_port() { + struct sockaddr_in addr; + BOINC_SOCKLEN_T addrsize; + int sock; + int retval; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(0); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + addrsize = sizeof(addr); + + retval = boinc_socket(sock); + if (retval) return retval; + + retval = bind(sock, (struct sockaddr *)&addr, addrsize); + if (retval < 0) { + boinc_close_socket(sock); + return ERR_BIND; + } + + getsockname(sock, (struct sockaddr *)&addr, &addrsize); + rd_host_port = addr.sin_port; + + boinc_close_socket(sock); + return 0; +} + int VBOX_VM::register_vm() { string command; string output; @@ -839,18 +868,55 @@ int VBOX_VM::register_vm() { // if (enable_network) { set_network_access(true); + + // If the VM wants to open up a port through the VirtualBox virtual + // network firewall/nat do that here. + // + if (pf_guest_port) { + if (!pf_host_port) { + retval = get_port_forwarding_port(); + if (retval) return retval; + } + + fprintf( + stderr, + "%s Enabling virtual machine firewall rules.\n", + boinc_msg_prefix(buf, sizeof(buf)) + ); + + // Add new firewall rule + // + sprintf(buf, "vboxwrapper,tcp,127.0.0.1,%d,,%d", pf_host_port, pf_guest_port); + command = "modifyvm \"" + vm_name + "\" "; + command += "--natpf1 \"" + string(buf) + "\" "; + + retval = vbm_popen(command, output, "add updated port forwarding rule"); + if(retval) return retval; + } } - // If the app wants to open up a port through the VirtualBox virtual - // network firewall/nat do that here. + // If the VM wants to enable remote desktop for the VM do it here // - if (pf_guest_port) { - if (!pf_host_port) { - retval = get_port_forwarding_port(); - if (retval) return retval; - } - retval = register_vm_firewall_rules(); + if (enable_remotedesktop) { + retval = get_remote_desktop_port(); if (retval) return retval; + + fprintf( + stderr, + "%s Enabling remote desktop for virtual machine.\n", + boinc_msg_prefix(buf, sizeof(buf)) + ); + + sprintf(buf, "%d", rd_host_port); + command = "modifyvm \"" + vm_name + "\" "; + command += "--vrde on "; + command += "--vrdeextpack default "; + command += "--vrdeauthlibrary default "; + command += "--vrdeauthtype null "; + command += "--vrdeport " + string(buf) + " "; + + retval = vbm_popen(command, output, "remote desktop"); + if(retval) return retval; } // Enable the shared folder if a shared folder is specified. @@ -872,33 +938,6 @@ int VBOX_VM::register_vm() { return 0; } -int VBOX_VM::register_vm_firewall_rules() { - string command; - string output; - string virtual_machine_slot_directory; - char buf[256]; - int retval; - - get_slot_directory(virtual_machine_slot_directory); - - fprintf( - stderr, - "%s Registering virtual machine firewall rules.\n", - boinc_msg_prefix(buf, sizeof(buf)) - ); - - // Add new firewall rule - // - sprintf(buf, "vboxwrapper,tcp,127.0.0.1,%d,,%d", pf_host_port, pf_guest_port); - command = "modifyvm \"" + vm_name + "\" "; - command += "--natpf1 \"" + string(buf) + "\" "; - - retval = vbm_popen(command, output, "add updated port forwarding rule"); - if(retval) return retval; - - return 0; -} - int VBOX_VM::deregister_vm() { string command; string output; diff --git a/samples/vboxwrapper/vbox.h b/samples/vboxwrapper/vbox.h index 98c743549a..3cb28fa16f 100644 --- a/samples/vboxwrapper/vbox.h +++ b/samples/vboxwrapper/vbox.h @@ -1,114 +1,119 @@ -// This file is part of BOINC. -// http://boinc.berkeley.edu +// This file is part of BOINC. +// http://boinc.berkeley.edu // Copyright (C) 2010-2012 University of California -// -// BOINC is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// BOINC is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with BOINC. If not, see . - - -// Provide cross-platform interfaces for making changes to VirtualBox - -#ifndef _VBOX_H_ -#define _VBOX_H_ - -// raw floppy drive device -class FloppyIO; - -// represents a VirtualBox VM -struct VBOX_VM { - VBOX_VM(); - ~VBOX_VM(); - - // Floppy IO abstraction - FloppyIO* pFloppy; - - // name of the OS the VM runs - std::string os_name; - // size of the memory allocation for the VM, in megabytes - std::string memory_size_mb; - // name of the virtual machine disk image file - std::string image_filename; - // name of the virtual machine floppy disk image file - std::string floppy_image_filename; - // unique name for the VM - std::string vm_name; - // required CPU core count - std::string vm_cpu_count; - // maximum amount of wall-clock time this VM is allowed to run before - // considering itself done. - double job_duration; - // is the VM suspended? - bool suspended; - // is network access temporarily suspended? - bool network_suspended; - // is VM even online? - bool online; - // Has the VM crashed? - bool crashed; - // whether to use CERN specific data structures - bool enable_cern_dataformat; - // whether to use shared directory infrastructure at all - bool enable_shared_directory; - // whether to use floppy io infrastructure at all - bool enable_floppyio; - // whether we were instructed to only register the VM. - // useful for debugging VMs. - bool register_only; - // whether to allow network access at all - bool enable_network; - // the following for optional port forwarding - int pf_host_port; - // specified in config file - int pf_guest_port; - // specified in config file - - int run(); - int stop(); - int pause(); - int resume(); - void cleanup(); - void poll(bool log_state = true); - bool is_running(); - bool is_paused(); - - int register_vm(); - int register_vm_firewall_rules(); - bool is_hdd_registered(); - bool is_registered(); - int deregister_stale_vm(); - int deregister_vm(); - int start(); - int set_network_access(bool enabled); - int set_cpu_usage_fraction(double); - int set_network_max_bytes_sec(double); - int get_process_id(int& process_id); - int get_network_bytes_sent(double& sent); - int get_network_bytes_received(double& received); - int get_system_log(std::string& log); - int get_vm_log(std::string& log); - int read_floppy(std::string& data); - int write_floppy(std::string& data); - int get_port_forwarding_port(); - - int initialize(); - int get_install_directory(std::string& dir); - int get_slot_directory(std::string& dir); - int vbm_popen( - std::string& command, std::string& output, const char* item, bool log_error = true, bool retry_failures = true - ); - int vbm_popen_raw( - std::string& command, std::string& output - ); -}; - -#endif +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + + +// Provide cross-platform interfaces for making changes to VirtualBox + +#ifndef _VBOX_H_ +#define _VBOX_H_ + +// raw floppy drive device +class FloppyIO; + +// represents a VirtualBox VM +struct VBOX_VM { + VBOX_VM(); + ~VBOX_VM(); + + // Floppy IO abstraction + FloppyIO* pFloppy; + + // name of the OS the VM runs + std::string os_name; + // size of the memory allocation for the VM, in megabytes + std::string memory_size_mb; + // name of the virtual machine disk image file + std::string image_filename; + // name of the virtual machine floppy disk image file + std::string floppy_image_filename; + // unique name for the VM + std::string vm_name; + // required CPU core count + std::string vm_cpu_count; + // maximum amount of wall-clock time this VM is allowed to run before + // considering itself done. + double job_duration; + // is the VM suspended? + bool suspended; + // is network access temporarily suspended? + bool network_suspended; + // is VM even online? + bool online; + // Has the VM crashed? + bool crashed; + // whether to use CERN specific data structures + bool enable_cern_dataformat; + // whether to use shared directory infrastructure at all + bool enable_shared_directory; + // whether to use floppy io infrastructure at all + bool enable_floppyio; + // whether to enable remote desktop functionality + bool enable_remotedesktop; + // whether we were instructed to only register the VM. + // useful for debugging VMs. + bool register_only; + // whether to allow network access at all + bool enable_network; + // the following for optional port forwarding + int pf_host_port; + // specified in config file + int pf_guest_port; + // specified in config file + // the following for optional remote desktop + int rd_host_port; + // dynamically assigned + + int run(); + int stop(); + int pause(); + int resume(); + void cleanup(); + void poll(bool log_state = true); + bool is_running(); + bool is_paused(); + + int register_vm(); + bool is_hdd_registered(); + bool is_registered(); + int deregister_stale_vm(); + int deregister_vm(); + int start(); + int set_network_access(bool enabled); + int set_cpu_usage_fraction(double); + int set_network_max_bytes_sec(double); + int get_process_id(int& process_id); + int get_network_bytes_sent(double& sent); + int get_network_bytes_received(double& received); + int get_system_log(std::string& log); + int get_vm_log(std::string& log); + int read_floppy(std::string& data); + int write_floppy(std::string& data); + int get_port_forwarding_port(); + int get_remote_desktop_port(); + + int initialize(); + int get_install_directory(std::string& dir); + int get_slot_directory(std::string& dir); + int vbm_popen( + std::string& command, std::string& output, const char* item, bool log_error = true, bool retry_failures = true + ); + int vbm_popen_raw( + std::string& command, std::string& output + ); +}; + +#endif diff --git a/samples/vboxwrapper/vboxwrapper.cpp b/samples/vboxwrapper/vboxwrapper.cpp index 8c2dbe7239..2124dee983 100644 --- a/samples/vboxwrapper/vboxwrapper.cpp +++ b/samples/vboxwrapper/vboxwrapper.cpp @@ -109,6 +109,7 @@ int parse_job_file(VBOX_VM& vm) { else if (xp.parse_bool("enable_network", vm.enable_network)) continue; else if (xp.parse_bool("enable_shared_directory", vm.enable_shared_directory)) continue; else if (xp.parse_bool("enable_floppyio", vm.enable_floppyio)) continue; + else if (xp.parse_bool("enable_remotedesktop", vm.enable_remotedesktop)) continue; else if (xp.parse_int("pf_guest_port", vm.pf_guest_port)) continue; else if (xp.parse_int("pf_host_port", vm.pf_host_port)) continue; fprintf(stderr, "%s parse_job_file(): unexpected tag %s\n", @@ -238,6 +239,37 @@ void set_port_forwarding_info(APP_INIT_DATA& /* aid */, VBOX_VM& vm) { } } +// set remote desktop information if needed +// +void set_remote_desktop_info(APP_INIT_DATA& /* aid */, VBOX_VM& vm) { + char buf[256]; + + if (vm.rd_host_port) { + fprintf( + stderr, + "%s remote desktop enabled on port '%d'.\n", + boinc_msg_prefix(buf, sizeof(buf)), vm.rd_host_port + ); + + // Write info to disk + // + MIOFILE mf; + FILE* f = boinc_fopen(REMOTEDESKTOP_FILENAME, "w"); + mf.init_file(f); + + mf.printf( + "\n" + " \n" + " %d\n" + " \n" + "\n", + vm.rd_host_port + ); + + fclose(f); + } +} + int main(int argc, char** argv) { int retval; BOINC_OPTIONS boinc_options; @@ -446,6 +478,7 @@ int main(int argc, char** argv) { set_floppy_image(aid, vm); set_port_forwarding_info(aid, vm); + set_remote_desktop_info(aid, vm); set_throttles(aid, vm); while (1) { diff --git a/samples/vboxwrapper/vboxwrapper.h b/samples/vboxwrapper/vboxwrapper.h index c951ee7edd..14b1cbe802 100644 --- a/samples/vboxwrapper/vboxwrapper.h +++ b/samples/vboxwrapper/vboxwrapper.h @@ -29,6 +29,7 @@ #define JOB_FILENAME "vbox_job.xml" #define CHECKPOINT_FILENAME "vbox_checkpoint.txt" #define PORTFORWARD_FILENAME "vbox_port_forward.xml" +#define REMOTEDESKTOP_FILENAME "vbox_remote_desktop.xml" #define POLL_PERIOD 1.0 #endif