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
213
214
215
216
217
218
219
220
221
222
223
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);

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

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

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

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

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

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

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

    return rc;
}

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        get_default_network_interface(default_interface);
436
437

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        // Add guest additions to the VM
        //
629
630
631
632
633
634
635
636
637
638
639
        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;
640

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

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

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

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

        // Add guest additions to the VM
        //
699
700
701
702
703
704
705
706
707
708
709
        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;
710

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

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

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

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

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

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

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

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

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

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

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

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

834
835
836
    // Enable the scratch folder if a scratch folder is specified.
    //
    if (enable_scratch_directory) {
837
838
839
840
841
842
843
844
        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;
845
846
    }

847

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

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

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


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


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

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

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

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

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

914

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

918
919
920

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

921

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

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

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

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

937
938
939
940
941
942
943
944
945
946

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

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

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

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

            // Delete network bandwidth throttle group
            //
For faster browsing, not all history is shown. View entire blame