vbox_mscom_impl.cpp 76.7 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
506
        }
    }
Rom Walton's avatar
Rom Walton committed
507
508
509
510
511

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

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

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

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

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

Rom Walton's avatar
Rom Walton committed
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
    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);
569
570
571
572
573
    }

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

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

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

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

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

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

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

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

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

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

    // 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.
        //
699
        pFloppy = new FloppyIONS::FloppyIO(floppy_image_filename.c_str());
700
        if (!pFloppy->ready()) {
701
702
            vboxlog_msg("Creating virtual floppy image failed.");
            vboxlog_msg("Error Code '%d' Error Message '%s'", pFloppy->error, pFloppy->errorStr.c_str());
703
704
            retval = ERR_FWRITE;
            goto CLEANUP;
705
706
        }

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

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

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

738
    // Configure port forwarding
739
740
741
    //
    if (enable_network) {
        if (pf_guest_port) {
742
            VBOX_PORT_FORWARD pf;
743
744
745
746
747
748
749
750
751
752
            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++) {
753
754
755
            VBOX_PORT_FORWARD& pf = port_forwards[i];

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

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

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

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

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

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

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

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

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


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


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

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

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

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

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

870

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

874
875
876

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

877

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

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

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

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

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

            // 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 {
907
                        CHECK_ERROR(rc);
908
909
910
911
912
                    }
                }
            }

            // Close Hard Disk, DVD, and floppy mediums
913
            //
914
           vboxlog_msg("Removing virtual disk drive(s) from VM.");
915
            rc = pMachine->get_MediumAttachments(&pMediumAttachments);
916
            if (SUCCEEDED(rc)) {
917
918
919
920
                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);
921
922
923
924
925
                    if (SUCCEEDED(rc) && 
                       ((DeviceType_HardDisk == device_type) ||
                        (DeviceType_DVD == device_type) ||
                        (DeviceType_Floppy == device_type))
                    ) {
926
927
928
                        CComPtr<IMedium> pMedium;
                        CComBSTR strController;

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

                        pMediumAttachment->get_Device(&lDevice);
                        pMediumAttachment->get_Port(&lPort);
                        pMediumAttachment->get_Medium(&pMedium);
938
                        
939
940
941
942
943
                        // 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));
                        }
944
                        
945
                        rc = pMachine->DetachDevice(strController, lPort, lDevice);
946
                        CHECK_ERROR(rc);
947
                    }
948
                }
949
950
951
952
            }

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

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

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

972
973
974
975
976
977
978
979
            // 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
            //
980
            rc = pSession->UnlockMachine();
981
            CHECK_ERROR(rc);
982
983
984
985
        }

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

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