vbox_mscom_impl.cpp 77.3 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
#define CHECK_ERROR(rc) \
    retval = virtualbox_check_error(rc, __FUNCTION__, __FILE__, __LINE__)

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

    if (FAILED(rc)) {
85
        vboxlog_msg("Error 0x%x in %s (%s:%d)", rc, szFunction, szFile, iLine);
86
87
88
89
        hr = ::GetErrorInfo(0, &pErrorInfo);
        if (SUCCEEDED(hr) && pErrorInfo) {
            hr = pErrorInfo->GetSource(&strSource);
            if (SUCCEEDED(hr) && strSource) {
90
91
                vboxlog_msg("Error Source     : %S", strSource);
            }
92
93
            hr = pErrorInfo->GetDescription(&strDescription);
            if (SUCCEEDED(hr) && strDescription) {
94
                vboxlog_msg("Error Description: %S", strDescription);
95
            }
96
        } else {
97
            vboxlog_msg("Error: Getting Error Info! hr = 0x%x", hr);
98
99
        }
    }
100
    return rc;
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
163
164
165
166
167
}


// 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));
}


168
VBOX_VM::VBOX_VM() {
169
    m_pPrivate = new VBOX_PRIV();
170
171
}

172
VBOX_VM::~VBOX_VM() {
173
174
175
176
    if (m_pPrivate) {
        delete m_pPrivate;
        m_pPrivate = NULL;
    }
177
178
}

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

    // 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()))) {
226
            vboxlog_msg("Failed to modify the search path");
227
228
229
        }
    }

230
231
232
233
234
235
    // 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();

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

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

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

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

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

    return rc;
}

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        get_default_network_interface(default_interface);
415
416

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

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

    // Tweak the VM's USB Configuration
    //
430
    vboxlog_msg("Disabling USB Support for VM.");
431
432
433
434
435
#ifdef _VIRTUALBOX42_
    rc = pMachine->get_USBController(&pUSBContoller);
    if (SUCCEEDED(rc)) {
        pUSBContoller->put_Enabled(FALSE);
    }
436
437
438
439
440
#else
    rc = pMachine->GetUSBControllerCountByType(USBControllerType_OHCI, &lOHCICtrls);
    if (SUCCEEDED(rc) && lOHCICtrls) {
        pMachine->RemoveUSBController(CComBSTR("OHCI"));
    }
441
#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
#if defined(_VIRTUALBOX42_) || defined (_VIRTUALBOX43_)
481
    pMachine->put_DragAndDropMode(DragAndDropMode_Disabled);
482
483
484
#else
    pMachine->put_DnDMode(DnDMode_Disabled);
#endif
485
486
487
488
489
490

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

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

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

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

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

Rom Walton's avatar
Rom Walton committed
555
        pDiskController->put_UseHostIOCache(FALSE);
556
557
    }

Rom Walton's avatar
Rom Walton committed
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
    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);
574
575
576
577
578
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            vboxlog_msg("forwarding host port %d to guest port %d", pf.host_port, pf.guest_port);
761
762
763

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

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

            sprintf(buf, "%d", rd_host_port);
Rom Walton's avatar
Rom Walton committed
787
788
789
790
791
792

            pVRDEServer->put_Enabled(TRUE);
            pVRDEServer->put_VRDEExtPack(CComBSTR(""));
            pVRDEServer->put_AuthLibrary(CComBSTR(""));
            pVRDEServer->put_AuthType(AuthType_Null);
            pVRDEServer->SetVRDEProperty(CComBSTR("TCP/Ports"), CComBSTR(buf));
793
794
795
796
797
798
        }
    }

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

809
810
811
CLEANUP:
    if (pMachine) {
        pMachine->SaveSettings();
812
    }
813
814
    if (pSession) {
        pSession->UnlockMachine();
815
816
    }

Rom Walton's avatar
Rom Walton committed
817
    return retval;
818
819
820
}

int VBOX_VM::register_vm() {
821
822
    int retval = ERR_EXEC;
    HRESULT rc;
823
824
    string virtual_machine_slot_directory;
    APP_INIT_DATA aid;
825
    CComPtr<IMachine> pMachine;
826
827
828
829
830

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


831
832
833
    vboxlog_msg("Register VM. (%s, slot#%d)", vm_master_name.c_str(), aid.slot);


834
835
836
837
    // Reset VM name in case it was changed while deregistering a stale VM
    //
    vm_name = vm_master_name;

838
    rc = m_pPrivate->m_pVirtualBox->OpenMachine(
839
        CComBSTR(string(virtual_machine_slot_directory + "\\" + vm_name + "\\" + vm_name + ".vbox").c_str()),
840
841
        &pMachine
    );
842
    if (CHECK_ERROR(rc)) goto CLEANUP;
843

844
    rc = m_pPrivate->m_pVirtualBox->RegisterMachine(pMachine);
845
    if (CHECK_ERROR(rc)) goto CLEANUP;
846

847
CLEANUP:
Rom Walton's avatar
Rom Walton committed
848
    return retval;
849
850
851
}

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

875

876
    boinc_get_init_data_p(&aid);
877
878
    get_slot_directory(virtual_machine_slot_directory);

879
880
881

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

882

883
    rc = m_pPrivate->m_pVirtualBox->FindMachine(CComBSTR(vm_name.c_str()), &pMachineRO);
884
    if (SUCCEEDED(rc)) {
885
886
        if (delete_media) {
            rc = pSession.CoCreateInstance(CLSID_Session);
887
            if (CHECK_ERROR(rc)) goto CLEANUP;
888

889
            rc = pMachineRO->LockMachine(pSession, LockType_Write);
890
            if (CHECK_ERROR(rc)) goto CLEANUP;
891
892

            rc = pSession->get_Console(&pConsole);
893
            if (CHECK_ERROR(rc)) goto CLEANUP;
894
895

            rc = pSession->get_Machine(&pMachine);
896
            if (CHECK_ERROR(rc)) goto CLEANUP;
897

898
899
900
901
902
903
904
905
906
907
908
909
910
911

            // 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 {
912
                        CHECK_ERROR(rc);
913
914
915
916
917
                    }
                }
            }

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

934
                        if ((DeviceType_HardDisk == device_type) || (DeviceType_DVD == device_type)) {
935
936
937
938
939
940
941
942
                            strController = "Hard Disk Controller";
                        } else {
                            strController = "Floppy Controller";
                        }

                        pMediumAttachment->get_Device(&lDevice);
                        pMediumAttachment->get_Port(&lPort);
                        pMediumAttachment->get_Medium(&pMedium);
943
                        
944
945
946
947
948
                        // 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));
                        }
949
                        
950
                        rc = pMachine->DetachDevice(strController, lPort, lDevice);
951
                        CHECK_ERROR(rc);
952
                    }
953
                }
954
955
956
957
            }

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

            // Delete its storage controller(s)
            //
966
            vboxlog_msg("Removing storage controller(s) from VM.");
967
968
969
970
971
            pMachine->RemoveStorageController(CComBSTR("Hard Disk Controller"));
            if (enable_floppyio) {
                pMachine->RemoveStorageController(CComBSTR("Floppy Controller"));
            }

972
973
            // Save the VM Settings so the state is stored
            //
974
            rc = pMachine->SaveSettings();
975
            CHECK_ERROR(rc);
976

977
978
979
980
981
982
983
984
            // 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
            //
985
            rc = pSession->UnlockMachine();
986
            CHECK_ERROR(rc);
987
988
989
990
        }

        // Next, delete VM
        //
991
        vboxlog_msg("Removing VM from VirtualBox.");
992
993
994
995
        rc = pMachineRO->Unregister(CleanupMode_Full, &pHardDisks);
        if (SUCCEEDED(rc)) {

            // We only want to close(remove from media registry) the hard disks
996
997
            // instead of deleting them, order them by most recent image first
            // and then walk back to the root.
998
999
1000
            //
            aHardDisks.Attach(pHardDisks);
            for (int i = 0; i < (int)aHardDisks.GetCount(); i++) {
For faster browsing, not all history is shown. View entire blame