vbox_mscom_impl.cpp 77.1 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
#ifdef _VIRTUALBOX43_
432
    rc = pMachine->GetUSBControllerCountByType(USBControllerType_OHCI, &lOHCICtrls);
Rom Walton's avatar
Rom Walton committed
433
    if (SUCCEEDED(rc) && lOHCICtrls) {
434
        pMachine->RemoveUSBController(CComBSTR("OHCI"));
Rom Walton's avatar
Rom Walton committed
435
    }
436
437
438
439
440
441
442
#endif
#ifdef _VIRTUALBOX42_
    rc = pMachine->get_USBController(&pUSBContoller);
    if (SUCCEEDED(rc)) {
        pUSBContoller->put_Enabled(FALSE);
    }
#endif
443
444
445

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


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


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

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

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

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

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

872

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

876
877
878

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

879

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

886
            rc = pMachineRO->LockMachine(pSession, LockType_Write);
887
            if (CHECK_ERROR(rc)) goto CLEANUP;
888
889

            rc = pSession->get_Console(&pConsole);
890
            if (CHECK_ERROR(rc)) goto CLEANUP;
891
892

            rc = pSession->get_Machine(&pMachine);
893
            if (CHECK_ERROR(rc)) goto CLEANUP;
894

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

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

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

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

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

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

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

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

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

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

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