vbox_mscom_impl.cpp 76.9 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
    m_pPrivate = new VBOX_PRIV();
165
166
}

167
VBOX_VM::~VBOX_VM() {
168
169
170
171
    if (m_pPrivate) {
        delete m_pPrivate;
        m_pPrivate = NULL;
    }
172
173
}

174
175
176
177
int VBOX_VM::initialize() {
    int rc = BOINC_SUCCESS;
    string old_path;
    string new_path;
178
    string version;
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
    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()))) {
195
            vboxlog_msg("Failed to modify the search path");
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
        }
    }

    // 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()))) {
221
            vboxlog_msg("Failed to modify the search path");
222
223
224
        }
    }

225
226
227
228
229
230
    // 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();

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

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

245
    rc = get_version_information(version);
246
247
    if (rc) return rc;

248
249
250
251
    // Fix-up version string
    virtualbox_version = "VirtualBox COM Interface (Version: " + version + ")";

    // Get the guest addition information
252
    get_guest_additions(virtualbox_guest_additions);
253
254
255
256
257

    return rc;
}

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


288
    rc = pSession.CoCreateInstance(CLSID_Session);
289
    if (CHECK_ERROR(rc)) goto CLEANUP;
290
291


292
293
294
    vboxlog_msg("Create VM. (%s, slot#%d)", vm_master_name.c_str(), aid.slot);


295
296
297
298
299
300
301
302
    // 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) {
303
            vboxlog_msg("Updating drive controller type and model for desired configuration.");
304
305
306
307
308
            vm_disk_controller_type = "sata";
            vm_disk_controller_model = "IntelAHCI";
        }
    }

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

Rom Walton's avatar
Rom Walton committed
321
322
323
324
325
326
    // 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.
327
    //
328
    rc = m_pPrivate->m_pVirtualBox->RegisterMachine(pMachineRO);
329
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
330
    
331
    rc = pMachineRO->LockMachine(pSession, LockType_Write);
332
    if (CHECK_ERROR(rc)) goto CLEANUP;
333

334
    rc = pSession->get_Machine(&pMachine);
335
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
336

337
    rc = pMachine->get_BIOSSettings(&pBIOSSettings);
338
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
339

340
    rc = pMachine->get_BandwidthControl(&pBandwidthControl);
341
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
342

343
    rc = pMachine->get_VRDEServer(&pVRDEServer);
344
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
345

346
    rc = pMachine->GetNetworkAdapter(0, &pNetworkAdapter);
347
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
348
349

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

352
    rc = pMachine->get_AudioAdapter(&pAudioAdapter);
353
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
354
355

    // Set some properties
356
    //
357
    pMachine->put_Description(CComBSTR(vm_master_description.c_str()));
Rom Walton's avatar
Rom Walton committed
358
359

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

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

    // Tweak the VM's Chipset Options
    //
373
    vboxlog_msg("Setting Chipset Options for VM.");
Rom Walton's avatar
Rom Walton committed
374
    rc = pBIOSSettings->put_ACPIEnabled(TRUE);
375
    if (CHECK_ERROR(rc)) goto CLEANUP;
376

Rom Walton's avatar
Rom Walton committed
377
    rc = pBIOSSettings->put_IOAPICEnabled(TRUE);
378
    if (CHECK_ERROR(rc)) goto CLEANUP;
379
380
381

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

389
390
    pMachine->SetBootOrder(3, DeviceType_Null);
    pMachine->SetBootOrder(4, DeviceType_Null);
391
392
393

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

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

        get_default_network_interface(default_interface);
410
411

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

Rom Walton's avatar
Rom Walton committed
419
        rc = pNATEngine->put_DNSProxy(TRUE);
420
        if (CHECK_ERROR(rc)) goto CLEANUP;
421
422
423
424
    }

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

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

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

    // Tweak the VM's Audio Support
    //
465
    vboxlog_msg("Disabling Audio Support for VM.");
Rom Walton's avatar
Rom Walton committed
466
    pAudioAdapter->put_Enabled(FALSE);
467
468
469

    // Tweak the VM's Clipboard Support
    //
470
    vboxlog_msg("Disabling Clipboard Support for VM.");
471
    pMachine->put_ClipboardMode(ClipboardMode_Disabled);
472
473
474

    // Tweak the VM's Drag & Drop Support
    //
475
    vboxlog_msg("Disabling Drag and Drop Support for VM.");
476
    pMachine->put_DragAndDropMode(DragAndDropMode_Disabled);
477
478
479
480
481
482

    // 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")) {
483
        vboxlog_msg("Hardware acceleration CPU extensions not detected. Disabling VirtualBox hardware acceleration support.");
484
485
486
        disable_acceleration = true;
    }
    if (strstr(aid.host_info.p_features, "hypervisor")) {
487
        vboxlog_msg("Running under Hypervisor. Disabling VirtualBox hardware acceleration support.");
488
489
490
491
        disable_acceleration = true;
    }
    if (is_boinc_client_version_newer(aid, 7, 2, 16)) {
        if (aid.vm_extensions_disabled) {
492
            vboxlog_msg("Hardware acceleration failed with previous execution. Disabling VirtualBox hardware acceleration support.");
493
494
495
496
497
498
            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.
499
500
            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.");
501
            disable_acceleration = true;
502
503
        }
    }
Rom Walton's avatar
Rom Walton committed
504
505
506
507
508

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

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

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

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

Rom Walton's avatar
Rom Walton committed
547
        pDiskController->put_UseHostIOCache(FALSE);
548
549
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            vboxlog_msg("forwarding host port %d to guest port %d", pf.host_port, pf.guest_port);
753
754
755

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

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

            sprintf(buf, "%d", rd_host_port);
Rom Walton's avatar
Rom Walton committed
779
780
781
782
783
784

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

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

801
802
803
CLEANUP:
    if (pMachine) {
        pMachine->SaveSettings();
804
    }
805
806
    if (pSession) {
        pSession->UnlockMachine();
807
808
    }

Rom Walton's avatar
Rom Walton committed
809
    return retval;
810
811
812
}

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


823
824
825
    vboxlog_msg("Register VM. (%s, slot#%d)", vm_master_name.c_str(), aid.slot);


826
827
828
829
    // Reset VM name in case it was changed while deregistering a stale VM
    //
    vm_name = vm_master_name;

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

836
    rc = m_pPrivate->m_pVirtualBox->RegisterMachine(pMachine);
837
    if (CHECK_ERROR(rc)) goto CLEANUP;
838

839
CLEANUP:
Rom Walton's avatar
Rom Walton committed
840
    return retval;
841
842
843
}

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

867

868
    boinc_get_init_data_p(&aid);
869
870
    get_slot_directory(virtual_machine_slot_directory);

871
872
873

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

874

875
    rc = m_pPrivate->m_pVirtualBox->FindMachine(CComBSTR(vm_name.c_str()), &pMachineRO);
876
    if (SUCCEEDED(rc)) {
877
878
        if (delete_media) {
            rc = pSession.CoCreateInstance(CLSID_Session);
879
            if (CHECK_ERROR(rc)) goto CLEANUP;
880

881
            rc = pMachineRO->LockMachine(pSession, LockType_Write);
882
            if (CHECK_ERROR(rc)) goto CLEANUP;
883
884

            rc = pSession->get_Console(&pConsole);
885
            if (CHECK_ERROR(rc)) goto CLEANUP;
886
887

            rc = pSession->get_Machine(&pMachine);
888
            if (CHECK_ERROR(rc)) goto CLEANUP;
889

890
891
892
893
894
895
896
897
898
899
900
901
902
903

            // 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 {
904
                        CHECK_ERROR(rc);
905
906
907
908
909
                    }
                }
            }

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

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

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

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

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

964
965
            // Save the VM Settings so the state is stored
            //
966
            rc = pMachine->SaveSettings();
967
            CHECK_ERROR(rc);
968

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

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

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

For faster browsing, not all history is shown. View entire blame