vbox_mscom_impl.cpp 80.4 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
void __stdcall virtualbox_com_raise_error(HRESULT rc, IErrorInfo* perrinfo) {
    HRESULT hr;
    CComPtr<IErrorInfo> pErrorInfo;
    CComBSTR strSource;
    CComBSTR strDescription;

    pErrorInfo.Attach(perrinfo);

    vboxlog_msg("COM Error 0x%x", rc);
    hr = pErrorInfo->GetSource(&strSource);
    if (SUCCEEDED(hr) && strSource) {
        vboxlog_msg("Error Source     : %S", strSource);
    }
    hr = pErrorInfo->GetDescription(&strDescription);
    if (SUCCEEDED(hr) && strDescription) {
        vboxlog_msg("Error Description: %S", strDescription);
    }

    DebugBreak();
}

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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188

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


189
VBOX_VM::VBOX_VM() {
190
191
192
193
    // Initialize COM Exception Trap
    //
    _set_com_error_handler(virtualbox_com_raise_error);

194
    m_pPrivate = new VBOX_PRIV();
195
196
}

197
VBOX_VM::~VBOX_VM() {
198
199
200
201
    if (m_pPrivate) {
        delete m_pPrivate;
        m_pPrivate = NULL;
    }
202
203
}

204
205
206
207
208
209
210
211
212
int VBOX_VM::initialize() {
    int rc = BOINC_SUCCESS;
    string old_path;
    string new_path;
    APP_INIT_DATA aid;
    bool force_sandbox = false;

    boinc_get_init_data_p(&aid);
    get_install_directory(virtualbox_install_directory);
213
    get_scratch_directory(virtualbox_scratch_directory);
214
215
216
217
218
219
220
221
222
223
224

    // 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()))) {
225
            vboxlog_msg("Failed to modify the search path");
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
        }
    }

    // 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()))) {
251
            vboxlog_msg("Failed to modify the search path");
252
253
254
        }
    }

255
256
257
258
259
260
    // 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();

261
    // Instantiate the VirtualBox root object.
262
    rc = m_pPrivate->m_pVirtualBox.CreateInstance(CLSID_VirtualBox);
263
    if (FAILED(rc)) {
264
        vboxlog_msg("Error creating VirtualBox instance! rc = 0x%x", rc);
265
266
267
268
        return rc;
    }

    // Create the session object.
269
    rc = m_pPrivate->m_pSession.CreateInstance(CLSID_Session);
270
    if (FAILED(rc)) {
271
        vboxlog_msg("Error creating Session instance! rc = 0x%x", rc);
272
273
274
        return rc;
    }

275
    rc = get_version_information(virtualbox_version_raw, virtualbox_version_display);
276
277
    if (rc) return rc;

278
    // Get the guest addition information
279
    get_guest_additions(virtualbox_guest_additions);
280
281
282
283
284

    return rc;
}

int VBOX_VM::create_vm() {
Rom Walton's avatar
Rom Walton committed
285
286
287
    int retval = ERR_EXEC;
    HRESULT rc;
    char buf[256];
288
    APP_INIT_DATA aid;
Rom Walton's avatar
Rom Walton committed
289
    CComBSTR vm_machine_uuid;
290
    CComPtr<IMachine> pMachineRO;
291
292
    CComPtr<IMachine> pMachine;
    CComPtr<ISession> pSession;
Rom Walton's avatar
Rom Walton committed
293
294
295
    CComPtr<IBIOSSettings> pBIOSSettings;
    CComPtr<INetworkAdapter> pNetworkAdapter;
    CComPtr<INATEngine> pNATEngine;
296
    CComPtr<IUSBController> pUSBContoller;
297
298
299
300
    CComPtr<ISerialPort> pSerialPort1;
    CComPtr<ISerialPort> pSerialPort2;
    CComPtr<IParallelPort> pParallelPort1;
    CComPtr<IParallelPort> pParallelPort2;
Rom Walton's avatar
Rom Walton committed
301
302
303
304
305
306
    CComPtr<IAudioAdapter> pAudioAdapter;
    CComPtr<IStorageController> pDiskController;
    CComPtr<IStorageController> pFloppyController;
    CComPtr<IBandwidthControl> pBandwidthControl;
    CComPtr<IVRDEServer> pVRDEServer;
    ULONG lOHCICtrls = 0;
307
    bool disable_acceleration = false;
Rom Walton's avatar
Rom Walton committed
308
309
    string virtual_machine_slot_directory;
    string default_interface;
310
311
312
313
314

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


315
    rc = pSession.CoCreateInstance(CLSID_Session);
316
    if (CHECK_ERROR(rc)) goto CLEANUP;
317
318


319
320
321
    vboxlog_msg("Create VM. (%s, slot#%d)", vm_master_name.c_str(), aid.slot);


322
323
324
325
326
327
328
329
    // 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) {
330
            vboxlog_msg("Updating drive controller type and model for desired configuration.");
331
332
333
334
335
            vm_disk_controller_type = "sata";
            vm_disk_controller_model = "IntelAHCI";
        }
    }

Rom Walton's avatar
Rom Walton committed
336
    // Start the VM creation process
337
    //
338
    rc = m_pPrivate->m_pVirtualBox->CreateMachine(
339
        CComBSTR(string(virtual_machine_slot_directory + "\\" + vm_name + "\\" + vm_name + ".vbox").c_str()),
Rom Walton's avatar
Rom Walton committed
340
341
342
343
        CComBSTR(vm_name.c_str()),
        NULL,
        CComBSTR(os_name.c_str()),
        CComBSTR(""),
344
        &pMachineRO
Rom Walton's avatar
Rom Walton committed
345
    );
346
    if (CHECK_ERROR(rc)) goto CLEANUP;
347

Rom Walton's avatar
Rom Walton committed
348
349
350
351
352
353
    // 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.
354
    //
355
    rc = m_pPrivate->m_pVirtualBox->RegisterMachine(pMachineRO);
356
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
357
    
358
    rc = pMachineRO->LockMachine(pSession, LockType_Write);
359
    if (CHECK_ERROR(rc)) goto CLEANUP;
360

361
    rc = pSession->get_Machine(&pMachine);
362
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
363

364
    rc = pMachine->get_BIOSSettings(&pBIOSSettings);
365
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
366

367
    rc = pMachine->get_BandwidthControl(&pBandwidthControl);
368
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
369

370
    rc = pMachine->get_VRDEServer(&pVRDEServer);
371
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
372

373
    rc = pMachine->GetNetworkAdapter(0, &pNetworkAdapter);
374
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
375
376

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

379
    rc = pMachine->get_AudioAdapter(&pAudioAdapter);
380
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
381
382

    // Set some properties
383
    //
384
    pMachine->put_Description(CComBSTR(vm_master_description.c_str()));
Rom Walton's avatar
Rom Walton committed
385
386

    // Tweak the VM's Memory Size
387
    //
388
    vboxlog_msg("Setting Memory Size for VM. (%dMB)", (int)memory_size_mb);
389
    rc = pMachine->put_MemorySize((int)(memory_size_mb));
390
    if (CHECK_ERROR(rc)) goto CLEANUP;
391

Rom Walton's avatar
Rom Walton committed
392
    // Tweak the VM's CPU Count
393
    //
394
    vboxlog_msg("Setting CPU Count for VM. (%s)", vm_cpu_count.c_str());
395
    rc = pMachine->put_CPUCount((int)atoi(vm_cpu_count.c_str()));
396
    if (CHECK_ERROR(rc)) goto CLEANUP;
397
398
399

    // Tweak the VM's Chipset Options
    //
400
    vboxlog_msg("Setting Chipset Options for VM.");
Rom Walton's avatar
Rom Walton committed
401
    rc = pBIOSSettings->put_ACPIEnabled(TRUE);
402
    if (CHECK_ERROR(rc)) goto CLEANUP;
403

Rom Walton's avatar
Rom Walton committed
404
    rc = pBIOSSettings->put_IOAPICEnabled(TRUE);
405
    if (CHECK_ERROR(rc)) goto CLEANUP;
406
407
408

    // Tweak the VM's Boot Options
    //
409
    vboxlog_msg("Setting Boot Options for VM.");
410
    rc = pMachine->SetBootOrder(1, DeviceType_HardDisk);
411
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
412
    
413
    rc = pMachine->SetBootOrder(2, DeviceType_DVD);
414
    if (CHECK_ERROR(rc)) goto CLEANUP;
415

416
417
    pMachine->SetBootOrder(3, DeviceType_Null);
    pMachine->SetBootOrder(4, DeviceType_Null);
418
419
420

    // Tweak the VM's Network Configuration
    //
421
    if (enable_network) {
422
        vboxlog_msg("Enabling VM Network Access.");
423
        rc = pNetworkAdapter->put_Enabled(TRUE);
424
        if (CHECK_ERROR(rc)) goto CLEANUP;
425
    } else {
426
        vboxlog_msg("Disabling VM Network Access.");
427
        rc = pNetworkAdapter->put_Enabled(FALSE);
428
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
429
430
    }

431
    if (network_bridged_mode) {
432
        vboxlog_msg("Setting Network Configuration for Bridged Mode.");
Rom Walton's avatar
Rom Walton committed
433
        rc = pNetworkAdapter->put_AttachmentType(NetworkAttachmentType_Bridged);
434
        if (CHECK_ERROR(rc)) goto CLEANUP;
435
436

        get_default_network_interface(default_interface);
437
438

        vboxlog_msg("Setting Bridged Interface. (%s)", default_interface.c_str());
Rom Walton's avatar
Rom Walton committed
439
        rc = pNetworkAdapter->put_BridgedInterface(CComBSTR(CA2W(default_interface.c_str())));
440
        if (CHECK_ERROR(rc)) goto CLEANUP;
441
    } else {
442
        vboxlog_msg("Setting Network Configuration for NAT.");
Rom Walton's avatar
Rom Walton committed
443
        rc = pNetworkAdapter->put_AttachmentType(NetworkAttachmentType_NAT);
444
        if (CHECK_ERROR(rc)) goto CLEANUP;
445

Rom Walton's avatar
Rom Walton committed
446
        rc = pNATEngine->put_DNSProxy(TRUE);
447
        if (CHECK_ERROR(rc)) goto CLEANUP;
448
449
450
451
    }

    // Tweak the VM's USB Configuration
    //
452
    vboxlog_msg("Disabling USB Support for VM.");
453
454
455
456
457
#ifdef _VIRTUALBOX42_
    rc = pMachine->get_USBController(&pUSBContoller);
    if (SUCCEEDED(rc)) {
        pUSBContoller->put_Enabled(FALSE);
    }
458
459
460
461
462
#else
    rc = pMachine->GetUSBControllerCountByType(USBControllerType_OHCI, &lOHCICtrls);
    if (SUCCEEDED(rc) && lOHCICtrls) {
        pMachine->RemoveUSBController(CComBSTR("OHCI"));
    }
463
#endif
464
465
466

    // Tweak the VM's COM Port Support
    //
467
    vboxlog_msg("Disabling COM Port Support for VM.");
468
    rc = pMachine->GetSerialPort(0, &pSerialPort1);
Rom Walton's avatar
Rom Walton committed
469
    if (SUCCEEDED(rc)) {
470
        pSerialPort1->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
471
    }
472
    rc = pMachine->GetSerialPort(1, &pSerialPort2);
Rom Walton's avatar
Rom Walton committed
473
    if (SUCCEEDED(rc)) {
474
        pSerialPort2->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
475
    }
476
477
478

    // Tweak the VM's LPT Port Support
    //
479
    vboxlog_msg("Disabling LPT Port Support for VM.");
480
    rc = pMachine->GetParallelPort(0, &pParallelPort1);
Rom Walton's avatar
Rom Walton committed
481
    if (SUCCEEDED(rc)) {
482
        pParallelPort1->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
483
    }
484
    rc = pMachine->GetParallelPort(1, &pParallelPort2);
Rom Walton's avatar
Rom Walton committed
485
    if (SUCCEEDED(rc)) {
486
        pParallelPort2->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
487
    }
488
489
490

    // Tweak the VM's Audio Support
    //
491
    vboxlog_msg("Disabling Audio Support for VM.");
Rom Walton's avatar
Rom Walton committed
492
    pAudioAdapter->put_Enabled(FALSE);
493
494
495

    // Tweak the VM's Clipboard Support
    //
496
    vboxlog_msg("Disabling Clipboard Support for VM.");
497
    pMachine->put_ClipboardMode(ClipboardMode_Disabled);
498
499
500

    // Tweak the VM's Drag & Drop Support
    //
501
    vboxlog_msg("Disabling Drag and Drop Support for VM.");
502
#if defined(_VIRTUALBOX42_) || defined (_VIRTUALBOX43_)
503
    pMachine->put_DragAndDropMode(DragAndDropMode_Disabled);
504
505
506
#else
    pMachine->put_DnDMode(DnDMode_Disabled);
#endif
507
508
509
510
511
512

    // 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")) {
513
        vboxlog_msg("Hardware acceleration CPU extensions not detected. Disabling VirtualBox hardware acceleration support.");
514
515
516
        disable_acceleration = true;
    }
    if (strstr(aid.host_info.p_features, "hypervisor")) {
517
        vboxlog_msg("Running under Hypervisor. Disabling VirtualBox hardware acceleration support.");
518
519
520
521
        disable_acceleration = true;
    }
    if (is_boinc_client_version_newer(aid, 7, 2, 16)) {
        if (aid.vm_extensions_disabled) {
522
            vboxlog_msg("Hardware acceleration failed with previous execution. Disabling VirtualBox hardware acceleration support.");
523
524
525
526
527
528
            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.
529
530
            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.");
531
            disable_acceleration = true;
532
533
        }
    }
Rom Walton's avatar
Rom Walton committed
534
535
536
537
538

    // 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) {
539
            vboxlog_msg("Disabling hardware acceleration support for virtualization.");
540
            rc = pMachine->SetHWVirtExProperty(HWVirtExPropertyType_Enabled, FALSE);
541
            if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
542
543
544
        }
    } else if (os_name.find("_64") != std::string::npos) {
        if (disable_acceleration) {
545
            vboxlog_msg("ERROR: Invalid configuration.  VM type requires acceleration but the current configuration cannot support it.");
546
547
            retval = ERR_INVALID_PARAM;
            goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
548
549
550
551
552
553
554
        }
    }

    // Add storage controller to VM
    // See: http://www.virtualbox.org/manual/ch08.html#vboxmanage-storagectl
    // See: http://www.virtualbox.org/manual/ch05.html#iocaching
    //
555
    vboxlog_msg("Adding storage controller(s) to VM.");
Rom Walton's avatar
Rom Walton committed
556
    if (0 == stricmp(vm_disk_controller_type.c_str(), "ide")) {
557
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_IDE, &pDiskController);
558
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
559
560
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "sata")) {
561
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SATA, &pDiskController);
562
563
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
564
565
566
567
        pDiskController->put_UseHostIOCache(FALSE);
        pDiskController->put_PortCount(3);
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "sas")) {
568
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SAS, &pDiskController);
569
570
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
571
572
573
        pDiskController->put_UseHostIOCache(FALSE);
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "scsi")) {
574
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SCSI, &pDiskController);
575
576
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
577
        pDiskController->put_UseHostIOCache(FALSE);
578
579
    }

Rom Walton's avatar
Rom Walton committed
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
    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);
596
597
598
599
600
    }

    // Add storage controller for a floppy device if desired
    //
    if (enable_floppyio) {
601
        rc = pMachine->AddStorageController(CComBSTR("Floppy Controller"), StorageBus_Floppy, &pFloppyController);
602
        if (CHECK_ERROR(rc)) goto CLEANUP;
603
604
605
606
607
    }

    if (enable_isocontextualization) {
        // Add virtual ISO 9660 disk drive to VM
        //
608
        vboxlog_msg("Adding virtual ISO 9660 disk drive to VM. (%s)", iso_image_filename.c_str());
Rom Walton's avatar
Rom Walton committed
609
        CComPtr<IMedium> pISOImage;
610
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
611
            CComBSTR(string(virtual_machine_slot_directory + "\\" + iso_image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
612
613
            DeviceType_DVD,
            AccessMode_ReadOnly,
Rom Walton's avatar
Rom Walton committed
614
            TRUE,
Rom Walton's avatar
Rom Walton committed
615
616
            &pISOImage
        );
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"),
            0,
            0,
            DeviceType_DVD,
            pISOImage
        );
626
        if (CHECK_ERROR(rc)) goto CLEANUP;
627
628
629

        // Add guest additions to the VM
        //
630
631
632
633
634
635
636
637
638
639
640
        if (virtualbox_guest_additions.size()) {
            vboxlog_msg("Adding VirtualBox Guest Additions to VM.");
            CComPtr<IMedium> pGuestAdditionsImage;
            rc = m_pPrivate->m_pVirtualBox->OpenMedium(
                CComBSTR(virtualbox_guest_additions.c_str()),
                DeviceType_DVD,
                AccessMode_ReadOnly,
                FALSE,
                &pGuestAdditionsImage
            );
            if (CHECK_ERROR(rc)) goto CLEANUP;
641

642
643
644
645
646
647
648
649
650
            rc = pMachine->AttachDevice(
                CComBSTR("Hard Disk Controller"),
                2,
                0,
                DeviceType_DVD,
                pGuestAdditionsImage
            );
            if (CHECK_ERROR(rc)) goto CLEANUP;
        }
651
652
653
654

        // Add a virtual cache disk drive to VM
        //
        if (enable_cache_disk){
655
            vboxlog_msg("Adding virtual cache disk drive to VM. (%s)", cache_disk_filename.c_str());
Rom Walton's avatar
Rom Walton committed
656
            CComPtr<IMedium> pCacheImage;
657
            rc = m_pPrivate->m_pVirtualBox->OpenMedium(
658
                CComBSTR(string(virtual_machine_slot_directory + "\\" + cache_disk_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
659
660
661
662
663
                DeviceType_HardDisk,
                AccessMode_ReadWrite,
                TRUE,
                &pCacheImage
            );
664
            if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
665

666
            rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
667
668
669
670
671
672
                CComBSTR("Hard Disk Controller"),
                1,
                0,
                DeviceType_HardDisk,
                pCacheImage
            );
673
            if (CHECK_ERROR(rc)) goto CLEANUP;
674
675
676
677
        }
    } else {
        // Adding virtual hard drive to VM
        //
678
        vboxlog_msg("Adding virtual disk drive to VM. (%s)", image_filename.c_str());
Rom Walton's avatar
Rom Walton committed
679
        CComPtr<IMedium> pDiskImage;
680
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
681
            CComBSTR(string(virtual_machine_slot_directory + "\\" + image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
682
683
684
685
686
            DeviceType_HardDisk,
            AccessMode_ReadWrite,
            TRUE,
            &pDiskImage
        );
687
        if (CHECK_ERROR(rc)) goto CLEANUP;
688

689
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
690
691
692
693
694
695
            CComBSTR("Hard Disk Controller"),
            0,
            0,
            DeviceType_HardDisk,
            pDiskImage
        );
696
        if (CHECK_ERROR(rc)) goto CLEANUP;
697
698
699

        // Add guest additions to the VM
        //
700
701
702
703
704
705
706
707
708
709
710
        if (virtualbox_guest_additions.size()) {
            vboxlog_msg("Adding VirtualBox Guest Additions to VM.");
            CComPtr<IMedium> pGuestAdditionsImage;
            rc = m_pPrivate->m_pVirtualBox->OpenMedium(
                CComBSTR(virtualbox_guest_additions.c_str()),
                DeviceType_DVD,
                AccessMode_ReadOnly,
                FALSE,
                &pGuestAdditionsImage
            );
            if (CHECK_ERROR(rc)) goto CLEANUP;
711

712
713
714
715
716
717
718
719
720
            rc = pMachine->AttachDevice(
                CComBSTR("Hard Disk Controller"),
                1,
                0,
                DeviceType_DVD,
                pGuestAdditionsImage
            );
            if (CHECK_ERROR(rc)) goto CLEANUP;
        }
721
722
723
724
725
726
727
728
729
    }

    // 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.
        //
730
        pFloppy = new FloppyIONS::FloppyIO(floppy_image_filename.c_str());
731
        if (!pFloppy->ready()) {
732
733
            vboxlog_msg("Creating virtual floppy image failed.");
            vboxlog_msg("Error Code '%d' Error Message '%s'", pFloppy->error, pFloppy->errorStr.c_str());
734
735
            retval = ERR_FWRITE;
            goto CLEANUP;
736
737
        }

738
        vboxlog_msg("Adding virtual floppy disk drive to VM.");
Rom Walton's avatar
Rom Walton committed
739
        CComPtr<IMedium> pFloppyImage;
740
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
741
            CComBSTR(string(virtual_machine_slot_directory + "\\" + floppy_image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
742
743
744
745
746
            DeviceType_Floppy,
            AccessMode_ReadWrite,
            TRUE,
            &pFloppyImage
        );
747
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
748

749
750
        rc = pMachine->AttachDevice(
            CComBSTR("Floppy Controller"),
Rom Walton's avatar
Rom Walton committed
751
752
753
754
755
            0,
            0,
            DeviceType_Floppy,
            pFloppyImage
        );
756
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
757
    }
758

Rom Walton's avatar
Rom Walton committed
759
760
    // Add network bandwidth throttle group
    //
761
    vboxlog_msg("Adding network bandwidth throttle group to VM. (Defaulting to 1024GB)");
Rom Walton's avatar
Rom Walton committed
762
763
764
765
766
    rc = pBandwidthControl->CreateBandwidthGroup(
        CComBSTR(string(vm_name + "_net").c_str()),
        BandwidthGroupType_Network,
        (LONG64)1024*1024*1024*1024
    );
767
    if (CHECK_ERROR(rc)) goto CLEANUP;
768

769
    // Configure port forwarding
770
771
772
    //
    if (enable_network) {
        if (pf_guest_port) {
773
            VBOX_PORT_FORWARD pf;
774
775
776
777
778
779
780
781
782
783
            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++) {
784
785
786
            VBOX_PORT_FORWARD& pf = port_forwards[i];

            vboxlog_msg("forwarding host port %d to guest port %d", pf.host_port, pf.guest_port);
787
788
789

            // Add new firewall rule
            //
Rom Walton's avatar
Rom Walton committed
790
791
792
793
794
795
796
            rc = pNATEngine->AddRedirect(
                CComBSTR(""),
                NATProtocol_TCP,
                pf.is_remote?CComBSTR(""):CComBSTR("127.0.0.1"),
                pf.host_port,
                CComBSTR(""),
                pf.guest_port
797
            );
798
            if (CHECK_ERROR(rc)) goto CLEANUP;
799
800
801
802
803
804
        }
    }

    // If the VM wants to enable remote desktop for the VM do it here
    //
    if (enable_remotedesktop) {
805
        vboxlog_msg("Enabling remote desktop for VM.");
806
        if (!is_extpack_installed()) {
807
            vboxlog_msg("Required extension pack not installed, remote desktop not enabled.");
808
809
        } else {
            retval = boinc_get_port(false, rd_host_port);
810
            if (retval) goto CLEANUP;
811
812

            sprintf(buf, "%d", rd_host_port);
Rom Walton's avatar
Rom Walton committed
813
814
815
816
817
818

            pVRDEServer->put_Enabled(TRUE);
            pVRDEServer->put_VRDEExtPack(CComBSTR(""));
            pVRDEServer->put_AuthLibrary(CComBSTR(""));
            pVRDEServer->put_AuthType(AuthType_Null);
            pVRDEServer->SetVRDEProperty(CComBSTR("TCP/Ports"), CComBSTR(buf));
819
820
821
        }
    }

822
    // Enable the shared folders if a shared folder is specified.
823
824
    //
    if (enable_shared_directory) {
825
        vboxlog_msg("Enabling shared directory for VM.");
826
        rc = pMachine->CreateSharedFolder(
Rom Walton's avatar
Rom Walton committed
827
            CComBSTR("shared"),
828
            CComBSTR(string(virtual_machine_slot_directory + "\\shared").c_str()),
Rom Walton's avatar
Rom Walton committed
829
830
831
            TRUE,
            TRUE
        );
832
        if (CHECK_ERROR(rc)) goto CLEANUP;
833
    }
834

835
836
837
    // Enable the scratch folder if a scratch folder is specified.
    //
    if (enable_scratch_directory) {
838
839
840
841
842
843
844
845
        vboxlog_msg("Enabling scratch shared directory for VM.");
        rc = pMachine->CreateSharedFolder(
            CComBSTR("scratch"),
            CComBSTR(virtualbox_scratch_directory.c_str()),
            TRUE,
            TRUE
        );
        if (CHECK_ERROR(rc)) goto CLEANUP;
846
847
    }

848

849
850
851
CLEANUP:
    if (pMachine) {
        pMachine->SaveSettings();
852
    }
853
854
    if (pSession) {
        pSession->UnlockMachine();
855
856
    }

Rom Walton's avatar
Rom Walton committed
857
    return retval;
858
859
860
}

int VBOX_VM::register_vm() {
861
862
    int retval = ERR_EXEC;
    HRESULT rc;
863
864
    string virtual_machine_slot_directory;
    APP_INIT_DATA aid;
865
    CComPtr<IMachine> pMachine;
866
867
868
869
870

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


871
872
873
    vboxlog_msg("Register VM. (%s, slot#%d)", vm_master_name.c_str(), aid.slot);


874
875
876
877
    // Reset VM name in case it was changed while deregistering a stale VM
    //
    vm_name = vm_master_name;

878
    rc = m_pPrivate->m_pVirtualBox->OpenMachine(
879
        CComBSTR(string(virtual_machine_slot_directory + "\\" + vm_name + "\\" + vm_name + ".vbox").c_str()),
880
881
        &pMachine
    );
882
    if (CHECK_ERROR(rc)) goto CLEANUP;
883

884
    rc = m_pPrivate->m_pVirtualBox->RegisterMachine(pMachine);
885
    if (CHECK_ERROR(rc)) goto CLEANUP;
886

887
CLEANUP:
Rom Walton's avatar
Rom Walton committed
888
    return retval;
889
890
891
}

int VBOX_VM::deregister_vm(bool delete_media) {
892
893
    int retval = ERR_EXEC;
    HRESULT rc;
894
895
896
897
898
899
    SAFEARRAY* pHardDisks = NULL;
    SAFEARRAY* pEmptyHardDisks = NULL;
    SAFEARRAY* pMediumAttachments = NULL;
    CComSafeArray<LPDISPATCH> aMediumAttachments;
    CComSafeArray<LPDISPATCH> aHardDisks;
    CComPtr<ISession> pSession;
900
    CComPtr<IConsole> pConsole;
901
    CComPtr<IMachine> pMachineRO;
902
    CComPtr<IMachine> pMachine;
903
    CComPtr<IProgress> pProgress;
904
    CComPtr<IBandwidthControl> pBandwidthControl;
905
906
907
908
    CComPtr<ISnapshot> pRootSnapshot;
    std::vector<CComPtr<IMedium>> clean_mediums;
    std::vector<CComPtr<IMedium>> mediums;
    std::vector<std::string> snapshots;
909
910
911
    DeviceType device_type; 
    LONG lDevice;
    LONG lPort;
912
    string virtual_machine_slot_directory;
913
    APP_INIT_DATA aid;
914

915

916
    boinc_get_init_data_p(&aid);
917
918
    get_slot_directory(virtual_machine_slot_directory);

919
920
921

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

922

923
    rc = m_pPrivate->m_pVirtualBox->FindMachine(CComBSTR(vm_name.c_str()), &pMachineRO);
924
    if (SUCCEEDED(rc)) {
925
926
        if (delete_media) {
            rc = pSession.CoCreateInstance(CLSID_Session);
927
            if (CHECK_ERROR(rc)) goto CLEANUP;
928

929
            rc = pMachineRO->LockMachine(pSession, LockType_Write);
930
            if (CHECK_ERROR(rc)) goto CLEANUP;
931
932

            rc = pSession->get_Console(&pConsole);
933
            if (CHECK_ERROR(rc)) goto CLEANUP;
934
935

            rc = pSession->get_Machine(&pMachine);
936
            if (CHECK_ERROR(rc)) goto CLEANUP;
937

938
939
940
941
942
943
944
945
946
947

            // 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;
948
949
950
#ifdef _VIRTUALBOX50_
                    rc = pMachine->DeleteSnapshot(CComBSTR(snapshots[i].c_str()), &pProgress);
#else
951
                    rc = pConsole->DeleteSnapshot(CComBSTR(snapshots[i].c_str()), &pProgress);
952
#endif
953
954
955
                    if (SUCCEEDED(rc)) {
                        pProgress->WaitForCompletion(-1);
                    } else {
956
                        CHECK_ERROR(rc);
957
958
959
960
961
                    }
                }
            }

            // Close Hard Disk, DVD, and floppy mediums
962
            //
963
           vboxlog_msg("Removing virtual disk drive(s) from VM.");
964
            rc = pMachine->get_MediumAttachments(&pMediumAttachments);
965
            if (SUCCEEDED(rc)) {
966
967
968
969
                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);
970
971
972
973
974
                    if (SUCCEEDED(rc) && 
                       ((DeviceType_HardDisk == device_type) ||
                        (DeviceType_DVD == device_type) ||
                        (DeviceType_Floppy == device_type))
                    ) {
975
976
977
                        CComPtr<IMedium> pMedium;
                        CComBSTR strController;

978
                        if ((DeviceType_HardDisk == device_type) || (DeviceType_DVD == device_type)) {
979
980
981
982
983
984
985
986
                            strController = "Hard Disk Controller";
                        } else {
                            strController = "Floppy Controller";
                        }

                        pMediumAttachment->get_Device(&lDevice);
                        pMediumAttachment->get_Port(&lPort);
                        pMediumAttachment->get_Medium(&pMedium);
987
                        
988
989
990
991
992
                        // 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));
                        }
993
                        
994
                        rc = pMachine->DetachDevice(strController, lPort, lDevice);
995
                        CHECK_ERROR(rc);
996
                    }
997
                }
998
999
1000
            }

            // Delete network bandwidth throttle group