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

int virtualbox_check_error(HRESULT rc, char* szFunction, char* szFile, int iLine) {
    HRESULT local_rc;
80
81
82
83
84
    char buf[256];
    IErrorInfo* pErrorInfo = NULL;
    BSTR strDescription;

    if (FAILED(rc)) {
85
86
87
88
89
90
91
92
93
        local_rc = GetErrorInfo(0, &pErrorInfo);
        if (FAILED(local_rc)) {
            fprintf(
                stderr,
                "%s Error: getting error info! rc = 0x%x\n",
                vboxwrapper_msg_prefix(buf, sizeof(buf)),
                rc
            );
        } else {
94
95
            fprintf(
                stderr,
96
                "%s Error in %s (%s:%d)\n",
97
                vboxwrapper_msg_prefix(buf, sizeof(buf)),
98
99
100
                szFunction,
                szFile,
                iLine
101
            );
102
103
104
105
106
107
108
109
110
111
112
            rc = pErrorInfo->GetDescription(&strDescription);
            if (SUCCEEDED(rc) && strDescription) {
                fprintf(
                    stderr,
                    "%s Error description: %S\n",
                    vboxwrapper_msg_prefix(buf, sizeof(buf)),
                    strDescription
                );
                SysFreeString(strDescription);
            }
            pErrorInfo->Release();
113
114
        }
    }
115
    return rc;
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
}


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


183
VBOX_VM::VBOX_VM() {
184
    VBOX_BASE::VBOX_BASE();
185
186

    m_pPrivate = new VBOX_PRIV();
187
188
}

189
VBOX_VM::~VBOX_VM() {
190
    VBOX_BASE::~VBOX_BASE();
191
192
193
194
195

    if (m_pPrivate) {
        delete m_pPrivate;
        m_pPrivate = NULL;
    }
196
197
}

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
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
251
252
253
254
255
256
257
258
259
int VBOX_VM::initialize() {
    int rc = BOINC_SUCCESS;
    string old_path;
    string new_path;
    string command;
    string output;
    APP_INIT_DATA aid;
    bool force_sandbox = false;
    char buf[256];

    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()))) {
            fprintf(
                stderr,
                "%s Failed to modify the search path.\n",
                vboxwrapper_msg_prefix(buf, sizeof(buf))
            );
        }
    }

    // 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()))) {
            fprintf(
                stderr,
                "%s Failed to modify the search path.\n",
                vboxwrapper_msg_prefix(buf, sizeof(buf))
            );
        }
    }

    // Instantiate the VirtualBox root object.
260
    rc = m_pPrivate->m_pVirtualBox.CreateInstance(CLSID_VirtualBox);
261
    if (FAILED(rc)) {
262
263
264
        fprintf(
            stderr,
            "%s Error creating VirtualBox instance! rc = 0x%x\n",
265
            vboxwrapper_msg_prefix(buf, sizeof(buf)),
266
267
268
269
270
271
            rc
        );
        return rc;
    }

    // Create the session object.
272
    rc = m_pPrivate->m_pSession.CreateInstance(CLSID_Session);
273
    if (FAILED(rc)) {
274
275
276
        fprintf(
            stderr,
            "%s Error creating Session instance! rc = 0x%x\n",
277
            vboxwrapper_msg_prefix(buf, sizeof(buf)),
278
279
280
281
282
283
284
285
            rc
        );
        return rc;
    }

    rc = get_version_information(virtualbox_version);
    if (rc) return rc;

286
    get_guest_additions(virtualbox_guest_additions);
287
288
289
290
291

    return rc;
}

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


322
    rc = pSession.CoCreateInstance(CLSID_Session);
323
    if (CHECK_ERROR(rc)) goto CLEANUP;
324
325


326
327
328
329
    // Reset VM name in case it was changed while deregistering a stale VM
    //
    vm_name = vm_master_name;

330
331
332
333
334
335
336
337
    fprintf(
        stderr,
        "%s Create VM. (%s, slot#%d) \n",
        vboxwrapper_msg_prefix(buf, sizeof(buf)),
        vm_name.c_str(),
        aid.slot
    );

338
339
340
341
342
343
344
345
346
347
348
349
350
351
    // Fixup chipset and drive controller information for known configurations
    //
    if (enable_isocontextualization) {
        if ("PIIX4" == vm_disk_controller_model) {
            fprintf(
                stderr,
                "%s Updating drive controller type and model for desired configuration.\n",
                vboxwrapper_msg_prefix(buf, sizeof(buf))
            );
            vm_disk_controller_type = "sata";
            vm_disk_controller_model = "IntelAHCI";
        }
    }

Rom Walton's avatar
Rom Walton committed
352
    // Start the VM creation process
353
    //
354
    rc = m_pPrivate->m_pVirtualBox->CreateMachine(
355
        CComBSTR(string(virtual_machine_slot_directory + "\\" + vm_name + "\\" + vm_name + ".vbox").c_str()),
Rom Walton's avatar
Rom Walton committed
356
357
358
359
        CComBSTR(vm_name.c_str()),
        NULL,
        CComBSTR(os_name.c_str()),
        CComBSTR(""),
360
        &pMachineRO
Rom Walton's avatar
Rom Walton committed
361
    );
362
    if (CHECK_ERROR(rc)) goto CLEANUP;
363

Rom Walton's avatar
Rom Walton committed
364
365
366
367
368
369
    // 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.
370
    //
371
    rc = m_pPrivate->m_pVirtualBox->RegisterMachine(pMachineRO);
372
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
373
    
374
    rc = pMachineRO->LockMachine(pSession, LockType_Write);
375
    if (CHECK_ERROR(rc)) goto CLEANUP;
376

377
    rc = pSession->get_Machine(&pMachine);
378
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
379

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

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

386
    rc = pMachine->get_VRDEServer(&pVRDEServer);
387
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
388

389
    rc = pMachine->GetNetworkAdapter(0, &pNetworkAdapter);
390
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
391
392

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

395
    rc = pMachine->get_AudioAdapter(&pAudioAdapter);
396
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
397
398

    // Set some properties
399
    //
400
    pMachine->put_Description(CComBSTR(vm_master_description.c_str()));
Rom Walton's avatar
Rom Walton committed
401
402

    // Tweak the VM's Memory Size
403
404
405
    //
    fprintf(
        stderr,
Rom Walton's avatar
Rom Walton committed
406
        "%s Setting Memory Size for VM. (%dMB)\n",
407
        vboxwrapper_msg_prefix(buf, sizeof(buf)),
Rom Walton's avatar
Rom Walton committed
408
        (int)memory_size_mb
409
    );
410
    rc = pMachine->put_MemorySize((int)(memory_size_mb));
411
    if (CHECK_ERROR(rc)) goto CLEANUP;
412

Rom Walton's avatar
Rom Walton committed
413
    // Tweak the VM's CPU Count
414
415
416
    //
    fprintf(
        stderr,
Rom Walton's avatar
Rom Walton committed
417
        "%s Setting CPU Count for VM. (%s)\n",
418
        vboxwrapper_msg_prefix(buf, sizeof(buf)),
Rom Walton's avatar
Rom Walton committed
419
        vm_cpu_count.c_str()
420
    );
421
    rc = pMachine->put_CPUCount((int)atoi(vm_cpu_count.c_str()));
422
    if (CHECK_ERROR(rc)) goto CLEANUP;
423
424
425
426
427
428
429
430

    // Tweak the VM's Chipset Options
    //
    fprintf(
        stderr,
        "%s Setting Chipset Options for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
Rom Walton's avatar
Rom Walton committed
431
    rc = pBIOSSettings->put_ACPIEnabled(TRUE);
432
    if (CHECK_ERROR(rc)) goto CLEANUP;
433

Rom Walton's avatar
Rom Walton committed
434
    rc = pBIOSSettings->put_IOAPICEnabled(TRUE);
435
    if (CHECK_ERROR(rc)) goto CLEANUP;
436
437
438
439
440
441
442
443

    // Tweak the VM's Boot Options
    //
    fprintf(
        stderr,
        "%s Setting Boot Options for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
444
    rc = pMachine->SetBootOrder(1, DeviceType_HardDisk);
445
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
446
    
447
    rc = pMachine->SetBootOrder(2, DeviceType_DVD);
448
    if (CHECK_ERROR(rc)) goto CLEANUP;
449

450
451
    pMachine->SetBootOrder(3, DeviceType_Null);
    pMachine->SetBootOrder(4, DeviceType_Null);
452
453
454

    // Tweak the VM's Network Configuration
    //
455
    if (enable_network) {
Rom Walton's avatar
Rom Walton committed
456
457
        fprintf(
            stderr,
458
459
            "%s Enabling VM Network Access.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
Rom Walton's avatar
Rom Walton committed
460
        );
461
        rc = pNetworkAdapter->put_Enabled(TRUE);
462
        if (CHECK_ERROR(rc)) goto CLEANUP;
463
464
465
466
467
468
469
    } else {
        fprintf(
            stderr,
            "%s Disabling VM Network Access.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
        rc = pNetworkAdapter->put_Enabled(FALSE);
470
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
471
472
    }

473
474
475
476
477
478
    if (network_bridged_mode) {
        fprintf(
            stderr,
            "%s Setting Network Configuration for Bridged Mode.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
Rom Walton's avatar
Rom Walton committed
479
        rc = pNetworkAdapter->put_AttachmentType(NetworkAttachmentType_Bridged);
480
        if (CHECK_ERROR(rc)) goto CLEANUP;
481
482
483
484
485
486
487
488

        get_default_network_interface(default_interface);
        fprintf(
            stderr,
            "%s Setting Bridged Interface. (%s)\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf)),
            default_interface.c_str()
        );
Rom Walton's avatar
Rom Walton committed
489
        rc = pNetworkAdapter->put_BridgedInterface(CComBSTR(CA2W(default_interface.c_str())));
490
        if (CHECK_ERROR(rc)) goto CLEANUP;
491
492
493
494
495
496
    } else {
        fprintf(
            stderr,
            "%s Setting Network Configuration for NAT.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
Rom Walton's avatar
Rom Walton committed
497
        rc = pNetworkAdapter->put_AttachmentType(NetworkAttachmentType_NAT);
498
        if (CHECK_ERROR(rc)) goto CLEANUP;
499

Rom Walton's avatar
Rom Walton committed
500
        rc = pNATEngine->put_DNSProxy(TRUE);
501
        if (CHECK_ERROR(rc)) goto CLEANUP;
502
503
504
505
506
507
508
509
510
    }

    // Tweak the VM's USB Configuration
    //
    fprintf(
        stderr,
        "%s Disabling USB Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
511
#ifdef _VIRTUALBOX43_
512
    rc = pMachine->GetUSBControllerCountByType(USBControllerType_OHCI, &lOHCICtrls);
Rom Walton's avatar
Rom Walton committed
513
    if (SUCCEEDED(rc) && lOHCICtrls) {
514
        pMachine->RemoveUSBController(CComBSTR("OHCI"));
Rom Walton's avatar
Rom Walton committed
515
    }
516
517
518
519
520
521
522
#endif
#ifdef _VIRTUALBOX42_
    rc = pMachine->get_USBController(&pUSBContoller);
    if (SUCCEEDED(rc)) {
        pUSBContoller->put_Enabled(FALSE);
    }
#endif
523
524
525
526
527
528
529
530

    // Tweak the VM's COM Port Support
    //
    fprintf(
        stderr,
        "%s Disabling COM Port Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
531
    rc = pMachine->GetSerialPort(0, &pSerialPort1);
Rom Walton's avatar
Rom Walton committed
532
    if (SUCCEEDED(rc)) {
533
        pSerialPort1->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
534
    }
535
    rc = pMachine->GetSerialPort(1, &pSerialPort2);
Rom Walton's avatar
Rom Walton committed
536
    if (SUCCEEDED(rc)) {
537
        pSerialPort2->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
538
    }
539
540
541
542
543
544
545
546

    // Tweak the VM's LPT Port Support
    //
    fprintf(
        stderr,
        "%s Disabling LPT Port Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
547
    rc = pMachine->GetParallelPort(0, &pParallelPort1);
Rom Walton's avatar
Rom Walton committed
548
    if (SUCCEEDED(rc)) {
549
        pParallelPort1->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
550
    }
551
    rc = pMachine->GetParallelPort(1, &pParallelPort2);
Rom Walton's avatar
Rom Walton committed
552
    if (SUCCEEDED(rc)) {
553
        pParallelPort2->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
554
    }
555
556
557
558
559
560
561
562

    // Tweak the VM's Audio Support
    //
    fprintf(
        stderr,
        "%s Disabling Audio Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
Rom Walton's avatar
Rom Walton committed
563
    pAudioAdapter->put_Enabled(FALSE);
564
565
566
567
568
569
570
571

    // Tweak the VM's Clipboard Support
    //
    fprintf(
        stderr,
        "%s Disabling Clipboard Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
572
    pMachine->put_ClipboardMode(ClipboardMode_Disabled);
573
574
575
576
577
578
579
580

    // Tweak the VM's Drag & Drop Support
    //
    fprintf(
        stderr,
        "%s Disabling Drag and Drop Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
581
    pMachine->put_DragAndDropMode(DragAndDropMode_Disabled);
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626

    // 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")) {
        fprintf(
            stderr,
            "%s Hardware acceleration CPU extensions not detected. Disabling VirtualBox hardware acceleration support.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
        disable_acceleration = true;
    }
    if (strstr(aid.host_info.p_features, "hypervisor")) {
        fprintf(
            stderr,
            "%s Running under Hypervisor. Disabling VirtualBox hardware acceleration support.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
        disable_acceleration = true;
    }
    if (is_boinc_client_version_newer(aid, 7, 2, 16)) {
        if (aid.vm_extensions_disabled) {
            fprintf(
                stderr,
                "%s Hardware acceleration failed with previous execution. Disabling VirtualBox hardware acceleration support.\n",
                vboxwrapper_msg_prefix(buf, sizeof(buf))
            );
            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.
            vboxwrapper_msg_prefix(buf, sizeof(buf));
            fprintf(
                stderr,
                "%s Legacy fallback configuration detected. Disabling VirtualBox hardware acceleration support.\n"
                "%s NOTE: Upgrading to BOINC 7.2.16 or better may re-enable hardware acceleration.\n",
                buf,
                buf
            );
            disable_acceleration = true;
        }
    }
Rom Walton's avatar
Rom Walton committed
627
628
629
630
631
632
633
634
635
636

    // 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) {
            fprintf(
                stderr,
                "%s Disabling hardware acceleration support for virtualization.\n",
                vboxwrapper_msg_prefix(buf, sizeof(buf))
            );
637
            rc = pMachine->SetHWVirtExProperty(HWVirtExPropertyType_Enabled, FALSE);
638
            if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
639
640
641
642
643
644
645
646
        }
    } else if (os_name.find("_64") != std::string::npos) {
        if (disable_acceleration) {
            fprintf(
                stderr,
                "%s ERROR: Invalid configuration.  VM type requires acceleration but the current configuration cannot support it.\n",
                vboxwrapper_msg_prefix(buf, sizeof(buf))
            );
647
648
            retval = ERR_INVALID_PARAM;
            goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
649
650
651
652
653
654
655
656
657
658
659
660
661
        }
    }

    // Add storage controller to VM
    // See: http://www.virtualbox.org/manual/ch08.html#vboxmanage-storagectl
    // See: http://www.virtualbox.org/manual/ch05.html#iocaching
    //
    fprintf(
        stderr,
        "%s Adding storage controller(s) to VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
    if (0 == stricmp(vm_disk_controller_type.c_str(), "ide")) {
662
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_IDE, &pDiskController);
663
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
664
665
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "sata")) {
666
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SATA, &pDiskController);
667
668
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
669
670
671
672
        pDiskController->put_UseHostIOCache(FALSE);
        pDiskController->put_PortCount(3);
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "sas")) {
673
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SAS, &pDiskController);
674
675
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
676
677
678
        pDiskController->put_UseHostIOCache(FALSE);
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "scsi")) {
679
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SCSI, &pDiskController);
680
681
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
682
        pDiskController->put_UseHostIOCache(FALSE);
683
684
    }

Rom Walton's avatar
Rom Walton committed
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
    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);
701
702
703
704
705
    }

    // Add storage controller for a floppy device if desired
    //
    if (enable_floppyio) {
706
        rc = pMachine->AddStorageController(CComBSTR("Floppy Controller"), StorageBus_Floppy, &pFloppyController);
707
        if (CHECK_ERROR(rc)) goto CLEANUP;
708
709
710
711
712
713
714
715
716
717
718
    }

    if (enable_isocontextualization) {
        // Add virtual ISO 9660 disk drive to VM
        //
        fprintf(
            stderr,
            "%s Adding virtual ISO 9660 disk drive to VM. (%s)\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf)),
            iso_image_filename.c_str()
        );
Rom Walton's avatar
Rom Walton committed
719
        CComPtr<IMedium> pISOImage;
720
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
721
            CComBSTR(string(virtual_machine_slot_directory + "\\" + iso_image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
722
723
            DeviceType_DVD,
            AccessMode_ReadOnly,
Rom Walton's avatar
Rom Walton committed
724
            TRUE,
Rom Walton's avatar
Rom Walton committed
725
726
            &pISOImage
        );
727
        if (CHECK_ERROR(rc)) goto CLEANUP;
728

729
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
730
731
732
733
734
735
            CComBSTR("Hard Disk Controller"),
            0,
            0,
            DeviceType_DVD,
            pISOImage
        );
736
        if (CHECK_ERROR(rc)) goto CLEANUP;
737
738
739
740
741
742
743
744

        // Add guest additions to the VM
        //
        fprintf(
            stderr,
            "%s Adding VirtualBox Guest Additions to VM.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
Rom Walton's avatar
Rom Walton committed
745
        CComPtr<IMedium> pGuestAdditionsImage;
746
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
Rom Walton's avatar
Rom Walton committed
747
748
749
750
751
752
            CComBSTR(virtualbox_guest_additions.c_str()),
            DeviceType_DVD,
            AccessMode_ReadOnly,
            FALSE,
            &pGuestAdditionsImage
        );
753
        if (CHECK_ERROR(rc)) goto CLEANUP;
754

755
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
756
757
758
759
760
761
            CComBSTR("Hard Disk Controller"),
            2,
            0,
            DeviceType_DVD,
            pGuestAdditionsImage
        );
762
        if (CHECK_ERROR(rc)) goto CLEANUP;
763
764
765
766
767
768
769
770
771
772

        // Add a virtual cache disk drive to VM
        //
        if (enable_cache_disk){
            fprintf(
                stderr,
                "%s Adding virtual cache disk drive to VM. (%s)\n",
                vboxwrapper_msg_prefix(buf, sizeof(buf)),
    		    cache_disk_filename.c_str()
            );
Rom Walton's avatar
Rom Walton committed
773
            CComPtr<IMedium> pCacheImage;
774
            rc = m_pPrivate->m_pVirtualBox->OpenMedium(
775
                CComBSTR(string(virtual_machine_slot_directory + "\\" + cache_disk_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
776
777
778
779
780
                DeviceType_HardDisk,
                AccessMode_ReadWrite,
                TRUE,
                &pCacheImage
            );
781
            if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
782

783
            rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
784
785
786
787
788
789
                CComBSTR("Hard Disk Controller"),
                1,
                0,
                DeviceType_HardDisk,
                pCacheImage
            );
790
            if (CHECK_ERROR(rc)) goto CLEANUP;
791
792
793
794
795
796
797
798
799
800
        }
    } else {
        // Adding virtual hard drive to VM
        //
        fprintf(
            stderr,
            "%s Adding virtual disk drive to VM. (%s)\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf)),
		    image_filename.c_str()
        );
Rom Walton's avatar
Rom Walton committed
801
        CComPtr<IMedium> pDiskImage;
802
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
803
            CComBSTR(string(virtual_machine_slot_directory + "\\" + image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
804
805
806
807
808
            DeviceType_HardDisk,
            AccessMode_ReadWrite,
            TRUE,
            &pDiskImage
        );
809
        if (CHECK_ERROR(rc)) goto CLEANUP;
810

811
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
812
813
814
815
816
817
            CComBSTR("Hard Disk Controller"),
            0,
            0,
            DeviceType_HardDisk,
            pDiskImage
        );
818
        if (CHECK_ERROR(rc)) goto CLEANUP;
819
820
821
822
823
824
825
826

        // Add guest additions to the VM
        //
        fprintf(
            stderr,
            "%s Adding VirtualBox Guest Additions to VM.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
Rom Walton's avatar
Rom Walton committed
827
        CComPtr<IMedium> pGuestAdditionsImage;
828
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
Rom Walton's avatar
Rom Walton committed
829
830
831
832
833
834
            CComBSTR(virtualbox_guest_additions.c_str()),
            DeviceType_DVD,
            AccessMode_ReadOnly,
            FALSE,
            &pGuestAdditionsImage
        );
835
        if (CHECK_ERROR(rc)) goto CLEANUP;
836

837
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
838
839
840
841
842
            CComBSTR("Hard Disk Controller"),
            1,
            0,
            DeviceType_DVD,
            pGuestAdditionsImage
843
        );
844
        if (CHECK_ERROR(rc)) goto CLEANUP;
845
846
847
848
849
850
851
852
853
    }

    // 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.
        //
854
        pFloppy = new FloppyIONS::FloppyIO(floppy_image_filename.c_str());
855
856
857
858
859
860
861
862
863
864
865
        if (!pFloppy->ready()) {
            vboxwrapper_msg_prefix(buf, sizeof(buf));
            fprintf(
                stderr,
                "%s Creating virtual floppy image failed.\n"
                "%s Error Code '%d' Error Message '%s'\n",
                buf,
                buf,
                pFloppy->error,
                pFloppy->errorStr.c_str()
            );
866
867
            retval = ERR_FWRITE;
            goto CLEANUP;
868
869
870
871
872
873
874
        }

        fprintf(
            stderr,
            "%s Adding virtual floppy disk drive to VM.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
Rom Walton's avatar
Rom Walton committed
875
        CComPtr<IMedium> pFloppyImage;
876
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
877
            CComBSTR(string(virtual_machine_slot_directory + "\\" + floppy_image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
878
879
880
881
882
            DeviceType_Floppy,
            AccessMode_ReadWrite,
            TRUE,
            &pFloppyImage
        );
883
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
884

885
886
        rc = pMachine->AttachDevice(
            CComBSTR("Floppy Controller"),
Rom Walton's avatar
Rom Walton committed
887
888
889
890
891
            0,
            0,
            DeviceType_Floppy,
            pFloppyImage
        );
892
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
893
    }
894

Rom Walton's avatar
Rom Walton committed
895
896
897
898
899
900
901
902
903
904
905
906
    // Add network bandwidth throttle group
    //
    fprintf(
        stderr,
        "%s Adding network bandwidth throttle group to VM. (Defaulting to 1024GB)\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
    rc = pBandwidthControl->CreateBandwidthGroup(
        CComBSTR(string(vm_name + "_net").c_str()),
        BandwidthGroupType_Network,
        (LONG64)1024*1024*1024*1024
    );
907
    if (CHECK_ERROR(rc)) goto CLEANUP;
908

909
    // Configure port forwarding
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
    //
    if (enable_network) {
        if (pf_guest_port) {
            PORT_FORWARD pf;
            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++) {
            PORT_FORWARD& pf = port_forwards[i];
            fprintf(
                stderr,
                "%s forwarding host port %d to guest port %d\n",
                vboxwrapper_msg_prefix(buf, sizeof(buf)),
                pf.host_port, pf.guest_port
            );

            // Add new firewall rule
            //
Rom Walton's avatar
Rom Walton committed
934
935
936
937
938
939
940
            rc = pNATEngine->AddRedirect(
                CComBSTR(""),
                NATProtocol_TCP,
                pf.is_remote?CComBSTR(""):CComBSTR("127.0.0.1"),
                pf.host_port,
                CComBSTR(""),
                pf.guest_port
941
            );
942
            if (CHECK_ERROR(rc)) goto CLEANUP;
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
        }
    }

    // If the VM wants to enable remote desktop for the VM do it here
    //
    if (enable_remotedesktop) {
        fprintf(
            stderr,
            "%s Enabling remote desktop for VM.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
        if (!is_extpack_installed()) {
            fprintf(
                stderr,
                "%s Required extension pack not installed, remote desktop not enabled.\n",
                vboxwrapper_msg_prefix(buf, sizeof(buf))
            );
        } else {
            retval = boinc_get_port(false, rd_host_port);
962
            if (retval) goto CLEANUP;
963
964

            sprintf(buf, "%d", rd_host_port);
Rom Walton's avatar
Rom Walton committed
965
966
967
968
969
970

            pVRDEServer->put_Enabled(TRUE);
            pVRDEServer->put_VRDEExtPack(CComBSTR(""));
            pVRDEServer->put_AuthLibrary(CComBSTR(""));
            pVRDEServer->put_AuthType(AuthType_Null);
            pVRDEServer->SetVRDEProperty(CComBSTR("TCP/Ports"), CComBSTR(buf));
971
972
973
974
975
976
977
978
979
980
981
        }
    }

    // Enable the shared folder if a shared folder is specified.
    //
    if (enable_shared_directory) {
        fprintf(
            stderr,
            "%s Enabling shared directory for VM.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
982
        rc = pMachine->CreateSharedFolder(
Rom Walton's avatar
Rom Walton committed
983
            CComBSTR("shared"),
984
            CComBSTR(string(virtual_machine_slot_directory + "\\shared").c_str()),
Rom Walton's avatar
Rom Walton committed
985
986
987
            TRUE,
            TRUE
        );
988
        if (CHECK_ERROR(rc)) goto CLEANUP;
989
990
    }

991
992
993
CLEANUP:
    if (pMachine) {
        pMachine->SaveSettings();
994
    }
995
996
    if (pSession) {
        pSession->UnlockMachine();
997
998
    }

Rom Walton's avatar
Rom Walton committed
999
    return retval;
1000
}
For faster browsing, not all history is shown. View entire blame