vbox_mscom_impl.cpp 79.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2010-2012 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.

18
#ifdef _VIRTUALBOX_IMPORT_FUNCTIONS_
Rom Walton's avatar
Rom Walton committed
19

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
const char *MachineStateToName(MachineState State) 
{ 
    switch (State) 
    { 
        case MachineState_PoweredOff: 
            return "poweroff"; 
        case MachineState_Saved: 
            return "saved"; 
        case MachineState_Aborted: 
            return "aborted"; 
        case MachineState_Teleported: 
            return "teleported"; 
        case MachineState_Running: 
            return "running"; 
        case MachineState_Paused: 
            return "paused"; 
        case MachineState_Stuck: 
            return "gurumeditation"; 
        case MachineState_LiveSnapshotting: 
            return "livesnapshotting"; 
        case MachineState_Teleporting: 
            return "teleporting"; 
        case MachineState_Starting: 
            return "starting"; 
        case MachineState_Stopping: 
            return "stopping"; 
        case MachineState_Saving: 
            return "saving"; 
        case MachineState_Restoring: 
            return "restoring"; 
        case MachineState_TeleportingPausedVM: 
            return "teleportingpausedvm"; 
        case MachineState_TeleportingIn: 
            return "teleportingin"; 
        case MachineState_RestoringSnapshot: 
            return "restoringsnapshot"; 
        case MachineState_DeletingSnapshot: 
            return "deletingsnapshot"; 
        case MachineState_DeletingSnapshotOnline: 
            return "deletingsnapshotlive"; 
        case MachineState_DeletingSnapshotPaused: 
            return "deletingsnapshotlivepaused"; 
        case MachineState_SettingUp: 
            return "settingup"; 
        default: 
            break; 
    } 
    return "unknown"; 
} 


71
72
73
74
// Helper function to print MSCOM exception information set on the current
// thread after a failed MSCOM method call. This function will also print
// extended VirtualBox error info if it is available.
//
75
76
77
78
#define CHECK_ERROR(rc) \
    retval = virtualbox_check_error(rc, __FUNCTION__, __FILE__, __LINE__)

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

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

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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
int VBOX_VM::initialize() {
    int rc = BOINC_SUCCESS;
    string old_path;
    string new_path;
208
    string version;
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
    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()))) {
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(version);
276
277
    if (rc) return rc;

278
279
280
281
    // Fix-up version string
    virtualbox_version = "VirtualBox COM Interface (Version: " + version + ")";

    // Get the guest addition information
282
    get_guest_additions(virtualbox_guest_additions);
283
284
285
286
287

    return rc;
}

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


318
    rc = pSession.CoCreateInstance(CLSID_Session);
319
    if (CHECK_ERROR(rc)) goto CLEANUP;
320
321


322
323
324
    vboxlog_msg("Create VM. (%s, slot#%d)", vm_master_name.c_str(), aid.slot);


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

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

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

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

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

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

373
    rc = pMachine->get_VRDEServer(&pVRDEServer);
374
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
375

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

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

382
    rc = pMachine->get_AudioAdapter(&pAudioAdapter);
383
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
384
385

    // Set some properties
386
    //
387
    pMachine->put_Description(CComBSTR(vm_master_description.c_str()));
Rom Walton's avatar
Rom Walton committed
388
389

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

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

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

Rom Walton's avatar
Rom Walton committed
407
    rc = pBIOSSettings->put_IOAPICEnabled(TRUE);
408
    if (CHECK_ERROR(rc)) goto CLEANUP;
409
410
411

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

419
420
    pMachine->SetBootOrder(3, DeviceType_Null);
    pMachine->SetBootOrder(4, DeviceType_Null);
421
422
423

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

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

        get_default_network_interface(default_interface);
440
441

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

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

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

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

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

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

    // Tweak the VM's Clipboard Support
    //
499
    vboxlog_msg("Disabling Clipboard Support for VM.");
500
    pMachine->put_ClipboardMode(ClipboardMode_Disabled);
501
502
503

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

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

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

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

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

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

Rom Walton's avatar
Rom Walton committed
580
        pDiskController->put_UseHostIOCache(FALSE);
581
582
    }

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

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

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

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

        // Add guest additions to the VM
        //
633
634
635
636
637
638
639
640
641
642
643
        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;
644

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

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

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

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

        // Add guest additions to the VM
        //
703
704
705
706
707
708
709
710
711
712
713
        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;
714

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

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

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

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

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

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

            vboxlog_msg("forwarding host port %d to guest port %d", pf.host_port, pf.guest_port);
790
791
792

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

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

            sprintf(buf, "%d", rd_host_port);
Rom Walton's avatar
Rom Walton committed
816
817
818
819
820
821

            pVRDEServer->put_Enabled(TRUE);
            pVRDEServer->put_VRDEExtPack(CComBSTR(""));
            pVRDEServer->put_AuthLibrary(CComBSTR(""));
            pVRDEServer->put_AuthType(AuthType_Null);
            pVRDEServer->SetVRDEProperty(CComBSTR("TCP/Ports"), CComBSTR(buf));
822
823
824
        }
    }

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

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

851

852
853
854
CLEANUP:
    if (pMachine) {
        pMachine->SaveSettings();
855
    }
856
857
    if (pSession) {
        pSession->UnlockMachine();
858
859
    }

Rom Walton's avatar
Rom Walton committed
860
    return retval;
861
862
863
}

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


874
875
876
    vboxlog_msg("Register VM. (%s, slot#%d)", vm_master_name.c_str(), aid.slot);


877
878
879
880
    // Reset VM name in case it was changed while deregistering a stale VM
    //
    vm_name = vm_master_name;

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

887
    rc = m_pPrivate->m_pVirtualBox->RegisterMachine(pMachine);
888
    if (CHECK_ERROR(rc)) goto CLEANUP;
889

890
CLEANUP:
Rom Walton's avatar
Rom Walton committed
891
    return retval;
892
893
894
}

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

918

919
    boinc_get_init_data_p(&aid);
920
921
    get_slot_directory(virtual_machine_slot_directory);

922
923
924

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

925

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

932
            rc = pMachineRO->LockMachine(pSession, LockType_Write);
933
            if (CHECK_ERROR(rc)) goto CLEANUP;
934
935

            rc = pSession->get_Console(&pConsole);
936
            if (CHECK_ERROR(rc)) goto CLEANUP;
937
938

            rc = pSession->get_Machine(&pMachine);
939
            if (CHECK_ERROR(rc)) goto CLEANUP;
940

941
942
943
944
945
946
947
948
949
950
951
952
953
954

            // 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 {
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