vbox_mscom_impl.cpp 76.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 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 <http://www.gnu.org/licenses/>.

18
#ifdef _VIRTUALBOX_IMPORT_FUNCTIONS_
Rom Walton's avatar
Rom Walton committed
19

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
const char *MachineStateToName(MachineState State) 
{ 
    switch (State) 
    { 
        case MachineState_PoweredOff: 
            return "poweroff"; 
        case MachineState_Saved: 
            return "saved"; 
        case MachineState_Aborted: 
            return "aborted"; 
        case MachineState_Teleported: 
            return "teleported"; 
        case MachineState_Running: 
            return "running"; 
        case MachineState_Paused: 
            return "paused"; 
        case MachineState_Stuck: 
            return "gurumeditation"; 
        case MachineState_LiveSnapshotting: 
            return "livesnapshotting"; 
        case MachineState_Teleporting: 
            return "teleporting"; 
        case MachineState_Starting: 
            return "starting"; 
        case MachineState_Stopping: 
            return "stopping"; 
        case MachineState_Saving: 
            return "saving"; 
        case MachineState_Restoring: 
            return "restoring"; 
        case MachineState_TeleportingPausedVM: 
            return "teleportingpausedvm"; 
        case MachineState_TeleportingIn: 
            return "teleportingin"; 
        case MachineState_RestoringSnapshot: 
            return "restoringsnapshot"; 
        case MachineState_DeletingSnapshot: 
            return "deletingsnapshot"; 
        case MachineState_DeletingSnapshotOnline: 
            return "deletingsnapshotlive"; 
        case MachineState_DeletingSnapshotPaused: 
            return "deletingsnapshotlivepaused"; 
        case MachineState_SettingUp: 
            return "settingup"; 
        default: 
            break; 
    } 
    return "unknown"; 
} 


71
72
73
74
// Helper function to print MSCOM exception information set on the current
// thread after a failed MSCOM method call. This function will also print
// extended VirtualBox error info if it is available.
//
75
76
77
78
79
#define CHECK_ERROR(rc) \
    retval = virtualbox_check_error(rc, __FUNCTION__, __FILE__, __LINE__)

int virtualbox_check_error(HRESULT rc, char* szFunction, char* szFile, int iLine) {
    HRESULT local_rc;
80
81
    CComPtr<IErrorInfo> pErrorInfo;
    CComBSTR strDescription;
82
83

    if (FAILED(rc)) {
84
        local_rc = GetErrorInfo(0, &pErrorInfo);
85
86
        if (SUCCEEDED(local_rc)) {
            vboxlog_msg("Error in %s (%s:%d)", szFunction, szFile, iLine);
87
88
            rc = pErrorInfo->GetDescription(&strDescription);
            if (SUCCEEDED(rc) && strDescription) {
89
                vboxlog_msg("Error description: %S", strDescription);
90
            }
91
92
        } else {
            vboxlog_msg("Error: getting error info! rc = 0x%x", rc);
93
94
        }
    }
95
    return rc;
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
}


// We want to recurisively walk the snapshot tree so that we can get the most recent children first.
// We also want to skip whatever the most current snapshot is.
//
void TraverseSnapshots(std::string& current_snapshot_id, std::vector<std::string>& snapshots, ISnapshot* pSnapshot) {
    HRESULT rc;
    SAFEARRAY* pSnapshots = NULL;
    CComSafeArray<LPDISPATCH> aSnapshots;
    CComBSTR tmp;
    ULONG lCount;
    std::string snapshot_id;

    // Check to see if we have any children
    //
    rc = pSnapshot->GetChildrenCount(&lCount);
    if (SUCCEEDED(rc) && lCount) {
        rc = pSnapshot->get_Children(&pSnapshots);
        if (SUCCEEDED(rc)) {
            aSnapshots.Attach(pSnapshots);
            if (aSnapshots.GetCount() > 0) {
                for (int i = 0; i < (int)aSnapshots.GetCount(); i++) {
                    TraverseSnapshots(current_snapshot_id, snapshots, (ISnapshot*)(LPDISPATCH)aSnapshots[i]);
                }
            }
        }
    }

    // Check to see if we are the most recent snapshot.
    // if not, add the snapshot id to the list of snapshots to be deleted.
    //
    pSnapshot->get_Id(&tmp);
    if (SUCCEEDED(rc)) {
        snapshot_id = CW2A(tmp);
        if (current_snapshot_id == snapshot_id) {
            return;
        } else {
            snapshots.push_back(snapshot_id);
        }
    }
}


// We want to recurisively walk the medium tree so that we can get the most recent children first.
//
void TraverseMediums(std::vector<CComPtr<IMedium>>& mediums, IMedium* pMedium) {
    HRESULT rc;
    SAFEARRAY* pMediums = NULL;
    CComSafeArray<LPDISPATCH> aMediums;

    // Check to see if we have any children
    //
    rc = pMedium->get_Children(&pMediums);
    if (SUCCEEDED(rc)) {
        aMediums.Attach(pMediums);
        if (aMediums.GetCount() > 0) {
            for (int i = 0; i < (int)aMediums.GetCount(); i++) {
                TraverseMediums(mediums, (IMedium*)(LPDISPATCH)aMediums[i]);
            }
        }
    }

    mediums.push_back(CComPtr<IMedium>(pMedium));
}


163
VBOX_VM::VBOX_VM() {
164
    VBOX_BASE::VBOX_BASE();
165
166

    m_pPrivate = new VBOX_PRIV();
167
168
}

169
VBOX_VM::~VBOX_VM() {
170
    VBOX_BASE::~VBOX_BASE();
171
172
173
174
175

    if (m_pPrivate) {
        delete m_pPrivate;
        m_pPrivate = NULL;
    }
176
177
}

178
179
180
181
int VBOX_VM::initialize() {
    int rc = BOINC_SUCCESS;
    string old_path;
    string new_path;
182
    string version;
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
    APP_INIT_DATA aid;
    bool force_sandbox = false;

    boinc_get_init_data_p(&aid);
    get_install_directory(virtualbox_install_directory);

    // Prep the environment so we can execute the vboxmanage application
    //
    // TODO: Fix for non-Windows environments if we ever find another platform
    // where vboxmanage is not already in the search path
    if (!virtualbox_install_directory.empty())
    {
        old_path = getenv("PATH");
        new_path = virtualbox_install_directory + ";" + old_path;

        if (!SetEnvironmentVariable("PATH", const_cast<char*>(new_path.c_str()))) {
199
            vboxlog_msg("Failed to modify the search path");
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
        }
    }

    // Determine the VirtualBox home directory.  Overwrite as needed.
    //
    if (getenv("VBOX_USER_HOME")) {
        virtualbox_home_directory = getenv("VBOX_USER_HOME");
    } else {
        // If the override environment variable isn't specified then
        // it is based of the current users HOME directory.
        virtualbox_home_directory = getenv("USERPROFILE");
        virtualbox_home_directory += "/.VirtualBox";
    }

    // Set the location in which the VirtualBox Configuration files can be
    // stored for this instance.
    if (aid.using_sandbox || force_sandbox) {
        virtualbox_home_directory = aid.project_dir;
        virtualbox_home_directory += "/../virtualbox";

        if (!boinc_file_exists(virtualbox_home_directory.c_str())) {
            boinc_mkdir(virtualbox_home_directory.c_str());
        }

        if (!SetEnvironmentVariable("VBOX_USER_HOME", const_cast<char*>(virtualbox_home_directory.c_str()))) {
225
            vboxlog_msg("Failed to modify the search path");
226
227
228
        }
    }

229
230
231
232
233
234
    // Launch vboxsvc manually so that the DCOM subsystem won't be able too.  Our version
    // will have permission and direction to write its state information to the BOINC
    // data directory.
    //
    launch_vboxsvc();

235
    // Instantiate the VirtualBox root object.
236
    rc = m_pPrivate->m_pVirtualBox.CreateInstance(CLSID_VirtualBox);
237
    if (FAILED(rc)) {
238
        vboxlog_msg("Error creating VirtualBox instance! rc = 0x%x", rc);
239
240
241
242
        return rc;
    }

    // Create the session object.
243
    rc = m_pPrivate->m_pSession.CreateInstance(CLSID_Session);
244
    if (FAILED(rc)) {
245
        vboxlog_msg("Error creating Session instance! rc = 0x%x", rc);
246
247
248
        return rc;
    }

249
    rc = get_version_information(version);
250
251
    if (rc) return rc;

252
253
254
255
    // Fix-up version string
    virtualbox_version = "VirtualBox COM Interface (Version: " + version + ")";

    // Get the guest addition information
256
    get_guest_additions(virtualbox_guest_additions);
257
258
259
260
261

    return rc;
}

int VBOX_VM::create_vm() {
Rom Walton's avatar
Rom Walton committed
262
263
264
    int retval = ERR_EXEC;
    HRESULT rc;
    char buf[256];
265
    APP_INIT_DATA aid;
Rom Walton's avatar
Rom Walton committed
266
    CComBSTR vm_machine_uuid;
267
    CComPtr<IMachine> pMachineRO;
268
269
    CComPtr<IMachine> pMachine;
    CComPtr<ISession> pSession;
Rom Walton's avatar
Rom Walton committed
270
271
272
    CComPtr<IBIOSSettings> pBIOSSettings;
    CComPtr<INetworkAdapter> pNetworkAdapter;
    CComPtr<INATEngine> pNATEngine;
273
    CComPtr<IUSBController> pUSBContoller;
274
275
276
277
    CComPtr<ISerialPort> pSerialPort1;
    CComPtr<ISerialPort> pSerialPort2;
    CComPtr<IParallelPort> pParallelPort1;
    CComPtr<IParallelPort> pParallelPort2;
Rom Walton's avatar
Rom Walton committed
278
279
280
281
282
283
    CComPtr<IAudioAdapter> pAudioAdapter;
    CComPtr<IStorageController> pDiskController;
    CComPtr<IStorageController> pFloppyController;
    CComPtr<IBandwidthControl> pBandwidthControl;
    CComPtr<IVRDEServer> pVRDEServer;
    ULONG lOHCICtrls = 0;
284
    bool disable_acceleration = false;
Rom Walton's avatar
Rom Walton committed
285
286
    string virtual_machine_slot_directory;
    string default_interface;
287
288
289
290
291

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


292
    rc = pSession.CoCreateInstance(CLSID_Session);
293
    if (CHECK_ERROR(rc)) goto CLEANUP;
294
295


296
297
298
    vboxlog_msg("Create VM. (%s, slot#%d)", vm_master_name.c_str(), aid.slot);


299
300
301
302
303
304
305
306
    // Reset VM name in case it was changed while deregistering a stale VM
    //
    vm_name = vm_master_name;

    // Fixup chipset and drive controller information for known configurations
    //
    if (enable_isocontextualization) {
        if ("PIIX4" == vm_disk_controller_model) {
307
            vboxlog_msg("Updating drive controller type and model for desired configuration.");
308
309
310
311
312
            vm_disk_controller_type = "sata";
            vm_disk_controller_model = "IntelAHCI";
        }
    }

Rom Walton's avatar
Rom Walton committed
313
    // Start the VM creation process
314
    //
315
    rc = m_pPrivate->m_pVirtualBox->CreateMachine(
316
        CComBSTR(string(virtual_machine_slot_directory + "\\" + vm_name + "\\" + vm_name + ".vbox").c_str()),
Rom Walton's avatar
Rom Walton committed
317
318
319
320
        CComBSTR(vm_name.c_str()),
        NULL,
        CComBSTR(os_name.c_str()),
        CComBSTR(""),
321
        &pMachineRO
Rom Walton's avatar
Rom Walton committed
322
    );
323
    if (CHECK_ERROR(rc)) goto CLEANUP;
324

Rom Walton's avatar
Rom Walton committed
325
326
327
328
329
330
    // Register the VM. Note that this call also saves the VM config
    // to disk. It is also possible to save the VM settings but not
    // register the VM.
    //
    // Also note that due to current VirtualBox limitations, the machine
    // must be registered *before* we can attach hard disks to it.
331
    //
332
    rc = m_pPrivate->m_pVirtualBox->RegisterMachine(pMachineRO);
333
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
334
    
335
    rc = pMachineRO->LockMachine(pSession, LockType_Write);
336
    if (CHECK_ERROR(rc)) goto CLEANUP;
337

338
    rc = pSession->get_Machine(&pMachine);
339
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
340

341
    rc = pMachine->get_BIOSSettings(&pBIOSSettings);
342
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
343

344
    rc = pMachine->get_BandwidthControl(&pBandwidthControl);
345
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
346

347
    rc = pMachine->get_VRDEServer(&pVRDEServer);
348
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
349

350
    rc = pMachine->GetNetworkAdapter(0, &pNetworkAdapter);
351
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
352
353

    rc = pNetworkAdapter->get_NATEngine(&pNATEngine);
354
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
355

356
    rc = pMachine->get_AudioAdapter(&pAudioAdapter);
357
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
358
359

    // Set some properties
360
    //
361
    pMachine->put_Description(CComBSTR(vm_master_description.c_str()));
Rom Walton's avatar
Rom Walton committed
362
363

    // Tweak the VM's Memory Size
364
    //
365
    vboxlog_msg("Setting Memory Size for VM. (%dMB)", (int)memory_size_mb);
366
    rc = pMachine->put_MemorySize((int)(memory_size_mb));
367
    if (CHECK_ERROR(rc)) goto CLEANUP;
368

Rom Walton's avatar
Rom Walton committed
369
    // Tweak the VM's CPU Count
370
    //
371
    vboxlog_msg("Setting CPU Count for VM. (%s)", vm_cpu_count.c_str());
372
    rc = pMachine->put_CPUCount((int)atoi(vm_cpu_count.c_str()));
373
    if (CHECK_ERROR(rc)) goto CLEANUP;
374
375
376

    // Tweak the VM's Chipset Options
    //
377
    vboxlog_msg("Setting Chipset Options for VM.");
Rom Walton's avatar
Rom Walton committed
378
    rc = pBIOSSettings->put_ACPIEnabled(TRUE);
379
    if (CHECK_ERROR(rc)) goto CLEANUP;
380

Rom Walton's avatar
Rom Walton committed
381
    rc = pBIOSSettings->put_IOAPICEnabled(TRUE);
382
    if (CHECK_ERROR(rc)) goto CLEANUP;
383
384
385

    // Tweak the VM's Boot Options
    //
386
    vboxlog_msg("Setting Boot Options for VM.");
387
    rc = pMachine->SetBootOrder(1, DeviceType_HardDisk);
388
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
389
    
390
    rc = pMachine->SetBootOrder(2, DeviceType_DVD);
391
    if (CHECK_ERROR(rc)) goto CLEANUP;
392

393
394
    pMachine->SetBootOrder(3, DeviceType_Null);
    pMachine->SetBootOrder(4, DeviceType_Null);
395
396
397

    // Tweak the VM's Network Configuration
    //
398
    if (enable_network) {
399
        vboxlog_msg("Enabling VM Network Access.");
400
        rc = pNetworkAdapter->put_Enabled(TRUE);
401
        if (CHECK_ERROR(rc)) goto CLEANUP;
402
    } else {
403
        vboxlog_msg("Disabling VM Network Access.");
404
        rc = pNetworkAdapter->put_Enabled(FALSE);
405
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
406
407
    }

408
    if (network_bridged_mode) {
409
        vboxlog_msg("Setting Network Configuration for Bridged Mode.");
Rom Walton's avatar
Rom Walton committed
410
        rc = pNetworkAdapter->put_AttachmentType(NetworkAttachmentType_Bridged);
411
        if (CHECK_ERROR(rc)) goto CLEANUP;
412
413

        get_default_network_interface(default_interface);
414
415

        vboxlog_msg("Setting Bridged Interface. (%s)", default_interface.c_str());
Rom Walton's avatar
Rom Walton committed
416
        rc = pNetworkAdapter->put_BridgedInterface(CComBSTR(CA2W(default_interface.c_str())));
417
        if (CHECK_ERROR(rc)) goto CLEANUP;
418
    } else {
419
        vboxlog_msg("Setting Network Configuration for NAT.");
Rom Walton's avatar
Rom Walton committed
420
        rc = pNetworkAdapter->put_AttachmentType(NetworkAttachmentType_NAT);
421
        if (CHECK_ERROR(rc)) goto CLEANUP;
422

Rom Walton's avatar
Rom Walton committed
423
        rc = pNATEngine->put_DNSProxy(TRUE);
424
        if (CHECK_ERROR(rc)) goto CLEANUP;
425
426
427
428
    }

    // Tweak the VM's USB Configuration
    //
429
    vboxlog_msg("Disabling USB Support for VM.");
430
#ifdef _VIRTUALBOX43_
431
    rc = pMachine->GetUSBControllerCountByType(USBControllerType_OHCI, &lOHCICtrls);
Rom Walton's avatar
Rom Walton committed
432
    if (SUCCEEDED(rc) && lOHCICtrls) {
433
        pMachine->RemoveUSBController(CComBSTR("OHCI"));
Rom Walton's avatar
Rom Walton committed
434
    }
435
436
437
438
439
440
441
#endif
#ifdef _VIRTUALBOX42_
    rc = pMachine->get_USBController(&pUSBContoller);
    if (SUCCEEDED(rc)) {
        pUSBContoller->put_Enabled(FALSE);
    }
#endif
442
443
444

    // Tweak the VM's COM Port Support
    //
445
    vboxlog_msg("Disabling COM Port Support for VM.");
446
    rc = pMachine->GetSerialPort(0, &pSerialPort1);
Rom Walton's avatar
Rom Walton committed
447
    if (SUCCEEDED(rc)) {
448
        pSerialPort1->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
449
    }
450
    rc = pMachine->GetSerialPort(1, &pSerialPort2);
Rom Walton's avatar
Rom Walton committed
451
    if (SUCCEEDED(rc)) {
452
        pSerialPort2->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
453
    }
454
455
456

    // Tweak the VM's LPT Port Support
    //
457
    vboxlog_msg("Disabling LPT Port Support for VM.");
458
    rc = pMachine->GetParallelPort(0, &pParallelPort1);
Rom Walton's avatar
Rom Walton committed
459
    if (SUCCEEDED(rc)) {
460
        pParallelPort1->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
461
    }
462
    rc = pMachine->GetParallelPort(1, &pParallelPort2);
Rom Walton's avatar
Rom Walton committed
463
    if (SUCCEEDED(rc)) {
464
        pParallelPort2->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
465
    }
466
467
468

    // Tweak the VM's Audio Support
    //
469
    vboxlog_msg("Disabling Audio Support for VM.");
Rom Walton's avatar
Rom Walton committed
470
    pAudioAdapter->put_Enabled(FALSE);
471
472
473

    // Tweak the VM's Clipboard Support
    //
474
    vboxlog_msg("Disabling Clipboard Support for VM.");
475
    pMachine->put_ClipboardMode(ClipboardMode_Disabled);
476
477
478

    // Tweak the VM's Drag & Drop Support
    //
479
    vboxlog_msg("Disabling Drag and Drop Support for VM.");
480
    pMachine->put_DragAndDropMode(DragAndDropMode_Disabled);
481
482
483
484
485
486

    // Check to see if the processor supports hardware acceleration for virtualization
    // If it doesn't, disable the use of it in VirtualBox. Multi-core jobs require hardware
    // acceleration and actually override this setting.
    //
    if (!strstr(aid.host_info.p_features, "vmx") && !strstr(aid.host_info.p_features, "svm")) {
487
        vboxlog_msg("Hardware acceleration CPU extensions not detected. Disabling VirtualBox hardware acceleration support.");
488
489
490
        disable_acceleration = true;
    }
    if (strstr(aid.host_info.p_features, "hypervisor")) {
491
        vboxlog_msg("Running under Hypervisor. Disabling VirtualBox hardware acceleration support.");
492
493
494
495
        disable_acceleration = true;
    }
    if (is_boinc_client_version_newer(aid, 7, 2, 16)) {
        if (aid.vm_extensions_disabled) {
496
            vboxlog_msg("Hardware acceleration failed with previous execution. Disabling VirtualBox hardware acceleration support.");
497
498
499
500
501
502
            disable_acceleration = true;
        }
    } else {
        if (vm_cpu_count == "1") {
            // Keep this around for older clients.  Removing this for older clients might
            // lead to a machine that will only return crashed VM reports.
503
504
            vboxlog_msg("Legacy fallback configuration detected. Disabling VirtualBox hardware acceleration support.");
            vboxlog_msg("NOTE: Upgrading to BOINC 7.2.16 or better may re-enable hardware acceleration.");
505
            disable_acceleration = true;
506
507
        }
    }
Rom Walton's avatar
Rom Walton committed
508
509
510
511
512

    // Only allow disabling of hardware acceleration on 32-bit VM types, 64-bit VM types require it.
    //
    if (os_name.find("_64") == std::string::npos) {
        if (disable_acceleration) {
513
            vboxlog_msg("Disabling hardware acceleration support for virtualization.");
514
            rc = pMachine->SetHWVirtExProperty(HWVirtExPropertyType_Enabled, FALSE);
515
            if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
516
517
518
        }
    } else if (os_name.find("_64") != std::string::npos) {
        if (disable_acceleration) {
519
            vboxlog_msg("ERROR: Invalid configuration.  VM type requires acceleration but the current configuration cannot support it.");
520
521
            retval = ERR_INVALID_PARAM;
            goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
522
523
524
525
526
527
528
        }
    }

    // Add storage controller to VM
    // See: http://www.virtualbox.org/manual/ch08.html#vboxmanage-storagectl
    // See: http://www.virtualbox.org/manual/ch05.html#iocaching
    //
529
    vboxlog_msg("Adding storage controller(s) to VM.");
Rom Walton's avatar
Rom Walton committed
530
    if (0 == stricmp(vm_disk_controller_type.c_str(), "ide")) {
531
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_IDE, &pDiskController);
532
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
533
534
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "sata")) {
535
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SATA, &pDiskController);
536
537
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
538
539
540
541
        pDiskController->put_UseHostIOCache(FALSE);
        pDiskController->put_PortCount(3);
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "sas")) {
542
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SAS, &pDiskController);
543
544
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
545
546
547
        pDiskController->put_UseHostIOCache(FALSE);
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "scsi")) {
548
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SCSI, &pDiskController);
549
550
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
551
        pDiskController->put_UseHostIOCache(FALSE);
552
553
    }

Rom Walton's avatar
Rom Walton committed
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
    if (0 == stricmp(vm_disk_controller_model.c_str(), "lsilogic")) {
        pDiskController->put_ControllerType(StorageControllerType_LsiLogic);
    } else if (0 == stricmp(vm_disk_controller_model.c_str(), "buslogic")) {
        pDiskController->put_ControllerType(StorageControllerType_BusLogic);
    } else if (0 == stricmp(vm_disk_controller_model.c_str(), "intelahci")) {
        pDiskController->put_ControllerType(StorageControllerType_IntelAhci);
    } else if (0 == stricmp(vm_disk_controller_model.c_str(), "piix3")) {
        pDiskController->put_ControllerType(StorageControllerType_PIIX3);
    } else if (0 == stricmp(vm_disk_controller_model.c_str(), "piix4")) {
        pDiskController->put_ControllerType(StorageControllerType_PIIX4);
    } else if (0 == stricmp(vm_disk_controller_model.c_str(), "ich6")) {
        pDiskController->put_ControllerType(StorageControllerType_ICH6);
    } else if (0 == stricmp(vm_disk_controller_model.c_str(), "i82078")) {
        pDiskController->put_ControllerType(StorageControllerType_I82078);
    } else if (0 == stricmp(vm_disk_controller_model.c_str(), "lsilogicsas")) {
        pDiskController->put_ControllerType(StorageControllerType_LsiLogicSas);
570
571
572
573
574
    }

    // Add storage controller for a floppy device if desired
    //
    if (enable_floppyio) {
575
        rc = pMachine->AddStorageController(CComBSTR("Floppy Controller"), StorageBus_Floppy, &pFloppyController);
576
        if (CHECK_ERROR(rc)) goto CLEANUP;
577
578
579
580
581
    }

    if (enable_isocontextualization) {
        // Add virtual ISO 9660 disk drive to VM
        //
582
        vboxlog_msg("Adding virtual ISO 9660 disk drive to VM. (%s)", iso_image_filename.c_str());
Rom Walton's avatar
Rom Walton committed
583
        CComPtr<IMedium> pISOImage;
584
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
585
            CComBSTR(string(virtual_machine_slot_directory + "\\" + iso_image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
586
587
            DeviceType_DVD,
            AccessMode_ReadOnly,
Rom Walton's avatar
Rom Walton committed
588
            TRUE,
Rom Walton's avatar
Rom Walton committed
589
590
            &pISOImage
        );
591
        if (CHECK_ERROR(rc)) goto CLEANUP;
592

593
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
594
595
596
597
598
599
            CComBSTR("Hard Disk Controller"),
            0,
            0,
            DeviceType_DVD,
            pISOImage
        );
600
        if (CHECK_ERROR(rc)) goto CLEANUP;
601
602
603

        // Add guest additions to the VM
        //
604
        vboxlog_msg("Adding VirtualBox Guest Additions to VM.");
Rom Walton's avatar
Rom Walton committed
605
        CComPtr<IMedium> pGuestAdditionsImage;
606
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
Rom Walton's avatar
Rom Walton committed
607
608
609
610
611
612
            CComBSTR(virtualbox_guest_additions.c_str()),
            DeviceType_DVD,
            AccessMode_ReadOnly,
            FALSE,
            &pGuestAdditionsImage
        );
613
        if (CHECK_ERROR(rc)) goto CLEANUP;
614

615
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
616
617
618
619
620
621
            CComBSTR("Hard Disk Controller"),
            2,
            0,
            DeviceType_DVD,
            pGuestAdditionsImage
        );
622
        if (CHECK_ERROR(rc)) goto CLEANUP;
623
624
625
626

        // Add a virtual cache disk drive to VM
        //
        if (enable_cache_disk){
627
            vboxlog_msg("Adding virtual cache disk drive to VM. (%s)", cache_disk_filename.c_str());
Rom Walton's avatar
Rom Walton committed
628
            CComPtr<IMedium> pCacheImage;
629
            rc = m_pPrivate->m_pVirtualBox->OpenMedium(
630
                CComBSTR(string(virtual_machine_slot_directory + "\\" + cache_disk_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
631
632
633
634
635
                DeviceType_HardDisk,
                AccessMode_ReadWrite,
                TRUE,
                &pCacheImage
            );
636
            if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
637

638
            rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
639
640
641
642
643
644
                CComBSTR("Hard Disk Controller"),
                1,
                0,
                DeviceType_HardDisk,
                pCacheImage
            );
645
            if (CHECK_ERROR(rc)) goto CLEANUP;
646
647
648
649
        }
    } else {
        // Adding virtual hard drive to VM
        //
650
        vboxlog_msg("Adding virtual disk drive to VM. (%s)", image_filename.c_str());
Rom Walton's avatar
Rom Walton committed
651
        CComPtr<IMedium> pDiskImage;
652
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
653
            CComBSTR(string(virtual_machine_slot_directory + "\\" + image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
654
655
656
657
658
            DeviceType_HardDisk,
            AccessMode_ReadWrite,
            TRUE,
            &pDiskImage
        );
659
        if (CHECK_ERROR(rc)) goto CLEANUP;
660

661
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
662
663
664
665
666
667
            CComBSTR("Hard Disk Controller"),
            0,
            0,
            DeviceType_HardDisk,
            pDiskImage
        );
668
        if (CHECK_ERROR(rc)) goto CLEANUP;
669
670
671

        // Add guest additions to the VM
        //
672
        vboxlog_msg("Adding VirtualBox Guest Additions to VM.");
Rom Walton's avatar
Rom Walton committed
673
        CComPtr<IMedium> pGuestAdditionsImage;
674
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
Rom Walton's avatar
Rom Walton committed
675
676
677
678
679
680
            CComBSTR(virtualbox_guest_additions.c_str()),
            DeviceType_DVD,
            AccessMode_ReadOnly,
            FALSE,
            &pGuestAdditionsImage
        );
681
        if (CHECK_ERROR(rc)) goto CLEANUP;
682

683
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
684
685
686
687
688
            CComBSTR("Hard Disk Controller"),
            1,
            0,
            DeviceType_DVD,
            pGuestAdditionsImage
689
        );
690
        if (CHECK_ERROR(rc)) goto CLEANUP;
691
692
693
694
695
696
697
698
699
    }

    // Adding virtual floppy disk drive to VM
    //
    if (enable_floppyio) {
        // Put in place the FloppyIO abstraction
        //
        // NOTE: This creates the floppy.img file at runtime for use by the VM.
        //
700
        pFloppy = new FloppyIONS::FloppyIO(floppy_image_filename.c_str());
701
        if (!pFloppy->ready()) {
702
703
            vboxlog_msg("Creating virtual floppy image failed.");
            vboxlog_msg("Error Code '%d' Error Message '%s'", pFloppy->error, pFloppy->errorStr.c_str());
704
705
            retval = ERR_FWRITE;
            goto CLEANUP;
706
707
        }

708
        vboxlog_msg("Adding virtual floppy disk drive to VM.");
Rom Walton's avatar
Rom Walton committed
709
        CComPtr<IMedium> pFloppyImage;
710
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
711
            CComBSTR(string(virtual_machine_slot_directory + "\\" + floppy_image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
712
713
714
715
716
            DeviceType_Floppy,
            AccessMode_ReadWrite,
            TRUE,
            &pFloppyImage
        );
717
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
718

719
720
        rc = pMachine->AttachDevice(
            CComBSTR("Floppy Controller"),
Rom Walton's avatar
Rom Walton committed
721
722
723
724
725
            0,
            0,
            DeviceType_Floppy,
            pFloppyImage
        );
726
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
727
    }
728

Rom Walton's avatar
Rom Walton committed
729
730
    // Add network bandwidth throttle group
    //
731
    vboxlog_msg("Adding network bandwidth throttle group to VM. (Defaulting to 1024GB)");
Rom Walton's avatar
Rom Walton committed
732
733
734
735
736
    rc = pBandwidthControl->CreateBandwidthGroup(
        CComBSTR(string(vm_name + "_net").c_str()),
        BandwidthGroupType_Network,
        (LONG64)1024*1024*1024*1024
    );
737
    if (CHECK_ERROR(rc)) goto CLEANUP;
738

739
    // Configure port forwarding
740
741
742
    //
    if (enable_network) {
        if (pf_guest_port) {
743
            VBOX_PORT_FORWARD pf;
744
745
746
747
748
749
750
751
752
753
            pf.guest_port = pf_guest_port;
            pf.host_port = pf_host_port;
            if (!pf_host_port) {
                retval = boinc_get_port(false, pf.host_port);
                if (retval) return retval;
                pf_host_port = pf.host_port;
            }
            port_forwards.push_back(pf);
        }
        for (unsigned int i=0; i<port_forwards.size(); i++) {
754
755
756
            VBOX_PORT_FORWARD& pf = port_forwards[i];

            vboxlog_msg("forwarding host port %d to guest port %d", pf.host_port, pf.guest_port);
757
758
759

            // Add new firewall rule
            //
Rom Walton's avatar
Rom Walton committed
760
761
762
763
764
765
766
            rc = pNATEngine->AddRedirect(
                CComBSTR(""),
                NATProtocol_TCP,
                pf.is_remote?CComBSTR(""):CComBSTR("127.0.0.1"),
                pf.host_port,
                CComBSTR(""),
                pf.guest_port
767
            );
768
            if (CHECK_ERROR(rc)) goto CLEANUP;
769
770
771
772
773
774
        }
    }

    // If the VM wants to enable remote desktop for the VM do it here
    //
    if (enable_remotedesktop) {
775
        vboxlog_msg("Enabling remote desktop for VM.");
776
        if (!is_extpack_installed()) {
777
            vboxlog_msg("Required extension pack not installed, remote desktop not enabled.");
778
779
        } else {
            retval = boinc_get_port(false, rd_host_port);
780
            if (retval) goto CLEANUP;
781
782

            sprintf(buf, "%d", rd_host_port);
Rom Walton's avatar
Rom Walton committed
783
784
785
786
787
788

            pVRDEServer->put_Enabled(TRUE);
            pVRDEServer->put_VRDEExtPack(CComBSTR(""));
            pVRDEServer->put_AuthLibrary(CComBSTR(""));
            pVRDEServer->put_AuthType(AuthType_Null);
            pVRDEServer->SetVRDEProperty(CComBSTR("TCP/Ports"), CComBSTR(buf));
789
790
791
792
793
794
        }
    }

    // Enable the shared folder if a shared folder is specified.
    //
    if (enable_shared_directory) {
795
        vboxlog_msg("Enabling shared directory for VM.");
796
        rc = pMachine->CreateSharedFolder(
Rom Walton's avatar
Rom Walton committed
797
            CComBSTR("shared"),
798
            CComBSTR(string(virtual_machine_slot_directory + "\\shared").c_str()),
Rom Walton's avatar
Rom Walton committed
799
800
801
            TRUE,
            TRUE
        );
802
        if (CHECK_ERROR(rc)) goto CLEANUP;
803
804
    }

805
806
807
CLEANUP:
    if (pMachine) {
        pMachine->SaveSettings();
808
    }
809
810
    if (pSession) {
        pSession->UnlockMachine();
811
812
    }

Rom Walton's avatar
Rom Walton committed
813
    return retval;
814
815
816
}

int VBOX_VM::register_vm() {
817
818
    int retval = ERR_EXEC;
    HRESULT rc;
819
820
    string virtual_machine_slot_directory;
    APP_INIT_DATA aid;
821
    CComPtr<IMachine> pMachine;
822
823
824
825
826

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


827
828
829
    vboxlog_msg("Register VM. (%s, slot#%d)", vm_master_name.c_str(), aid.slot);


830
831
832
833
    // Reset VM name in case it was changed while deregistering a stale VM
    //
    vm_name = vm_master_name;

834
    rc = m_pPrivate->m_pVirtualBox->OpenMachine(
835
        CComBSTR(string(virtual_machine_slot_directory + "\\" + vm_name + "\\" + vm_name + ".vbox").c_str()),
836
837
        &pMachine
    );
838
    if (CHECK_ERROR(rc)) goto CLEANUP;
839

840
    rc = m_pPrivate->m_pVirtualBox->RegisterMachine(pMachine);
841
    if (CHECK_ERROR(rc)) goto CLEANUP;
842

843
CLEANUP:
Rom Walton's avatar
Rom Walton committed
844
    return retval;
845
846
847
}

int VBOX_VM::deregister_vm(bool delete_media) {
848
849
    int retval = ERR_EXEC;
    HRESULT rc;
850
851
852
853
854
855
    SAFEARRAY* pHardDisks = NULL;
    SAFEARRAY* pEmptyHardDisks = NULL;
    SAFEARRAY* pMediumAttachments = NULL;
    CComSafeArray<LPDISPATCH> aMediumAttachments;
    CComSafeArray<LPDISPATCH> aHardDisks;
    CComPtr<ISession> pSession;
856
    CComPtr<IConsole> pConsole;
857
    CComPtr<IMachine> pMachineRO;
858
    CComPtr<IMachine> pMachine;
859
    CComPtr<IProgress> pProgress;
860
    CComPtr<IBandwidthControl> pBandwidthControl;
861
862
863
864
    CComPtr<ISnapshot> pRootSnapshot;
    std::vector<CComPtr<IMedium>> clean_mediums;
    std::vector<CComPtr<IMedium>> mediums;
    std::vector<std::string> snapshots;
865
866
867
    DeviceType device_type; 
    LONG lDevice;
    LONG lPort;
868
    string virtual_machine_slot_directory;
869
    APP_INIT_DATA aid;
870

871

872
    boinc_get_init_data_p(&aid);
873
874
    get_slot_directory(virtual_machine_slot_directory);

875
876
877

    vboxlog_msg("Deregistering VM. (%s, slot#%d)", vm_name.c_str(), aid.slot);

878

879
    rc = m_pPrivate->m_pVirtualBox->FindMachine(CComBSTR(vm_name.c_str()), &pMachineRO);
880
    if (SUCCEEDED(rc)) {
881
882
        if (delete_media) {
            rc = pSession.CoCreateInstance(CLSID_Session);
883
            CHECK_ERROR(rc);
884

885
            rc = pMachineRO->LockMachine(pSession, LockType_Write);
886
887
888
889
890
891
892
            CHECK_ERROR(rc);

            rc = pSession->get_Console(&pConsole);
            CHECK_ERROR(rc);

            rc = pSession->get_Machine(&pMachine);
            CHECK_ERROR(rc);
893

894
895
896
897
898
899
900
901
902
903
904
905
906
907

            // Delete snapshots
            //
            rc = pMachine->FindSnapshot(CComBSTR(""), &pRootSnapshot);
            if (SUCCEEDED(rc) && pRootSnapshot) {
                TraverseSnapshots(string(""), snapshots, pRootSnapshot);
            }
            if (snapshots.size()) {
                for (size_t i = 0; i < snapshots.size(); i++) {
                    CComPtr<IProgress> pProgress;
                    rc = pConsole->DeleteSnapshot(CComBSTR(snapshots[i].c_str()), &pProgress);
                    if (SUCCEEDED(rc)) {
                        pProgress->WaitForCompletion(-1);
                    } else {
908
                        CHECK_ERROR(rc);
909
910
911
912
913
                    }
                }
            }

            // Close Hard Disk, DVD, and floppy mediums
914
            //
915
           vboxlog_msg("Removing virtual disk drive(s) from VM.");
916
            rc = pMachine->get_MediumAttachments(&pMediumAttachments);
917
            if (SUCCEEDED(rc)) {
918
919
920
921
                aMediumAttachments.Attach(pMediumAttachments);
                for (int i = 0; i < (int)aMediumAttachments.GetCount(); i++) {
                    CComPtr<IMediumAttachment> pMediumAttachment((IMediumAttachment*)(LPDISPATCH)aMediumAttachments[i]);
                    rc = pMediumAttachment->get_Type(&device_type);
922
923
924
925
926
                    if (SUCCEEDED(rc) && 
                       ((DeviceType_HardDisk == device_type) ||
                        (DeviceType_DVD == device_type) ||
                        (DeviceType_Floppy == device_type))
                    ) {
927
928
929
                        CComPtr<IMedium> pMedium;
                        CComBSTR strController;

930
                        if ((DeviceType_HardDisk == device_type) || (DeviceType_DVD == device_type)) {
931
932
933
934
935
936
937
938
                            strController = "Hard Disk Controller";
                        } else {
                            strController = "Floppy Controller";
                        }

                        pMediumAttachment->get_Device(&lDevice);
                        pMediumAttachment->get_Port(&lPort);
                        pMediumAttachment->get_Medium(&pMedium);
939
                        
940
941
942
943
944
                        // If the device in question is a DVD/CD-ROM drive, the medium may have been ejected.
                        // If so, pMedium will be NULL.
                        if (pMedium) {
                            mediums.push_back(CComPtr<IMedium>(pMedium));
                        }
945
                        
946
                        rc = pMachine->DetachDevice(strController, lPort, lDevice);
947
                        CHECK_ERROR(rc);
948
                    }
949
                }
950
951
952
953
            }

            // Delete network bandwidth throttle group
            //
954
            vboxlog_msg("Removing network bandwidth throttle group from VM.");
955
956
957
958
959
960
961
            rc = pMachine->get_BandwidthControl(&pBandwidthControl);
            if (SUCCEEDED(rc)) {
                pBandwidthControl->DeleteBandwidthGroup(CComBSTR(string(vm_name + "_net").c_str()));
            }

            // Delete its storage controller(s)
            //
962
            vboxlog_msg("Removing storage controller(s) from VM.");
963
964
965
966
967
            pMachine->RemoveStorageController(CComBSTR("Hard Disk Controller"));
            if (enable_floppyio) {
                pMachine->RemoveStorageController(CComBSTR("Floppy Controller"));
            }

968
969
            // Save the VM Settings so the state is stored
            //
970
            rc = pMachine->SaveSettings();
971
            CHECK_ERROR(rc);
972

973
974
975
976
977
978
979
980
            // Now it should be safe to close down the mediums we detached.
            //
            for (int i = 0; i < (int)mediums.size(); i++) {
                mediums[i]->Close();
            }

            // Now free the session lock
            //
981
            rc = pSession->UnlockMachine();
982
            CHECK_ERROR(rc);
983
984
985
986
        }

        // Next, delete VM
        //
987
        vboxlog_msg("Removing VM from VirtualBox.");
988
989
990
991
        rc = pMachineRO->Unregister(CleanupMode_Full, &pHardDisks);
        if (SUCCEEDED(rc)) {

            // We only want to close(remove from media registry) the hard disks
992
993
            // instead of deleting them, order them by most recent image first
            // and then walk back to the root.
994
995
996
997
            //
            aHardDisks.Attach(pHardDisks);
            for (int i = 0; i < (int)aHardDisks.GetCount(); i++) {
                CComPtr<IMedium> pMedium((IMedium*)(LPDISPATCH)aHardDisks[i]);
998
999
1000
                TraverseMediums(mediums, pMedium);
            }
            for (int i = 0; i < (int)mediums.size(); i++) {
For faster browsing, not all history is shown. View entire blame