vbox_mscom_impl.cpp 85.9 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
int VBOX_VM::initialize() {
    int rc = BOINC_SUCCESS;
    string old_path;
    string new_path;
202
    string version;
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
    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))
            );
        }
    }

258
259
260
261
262
263
    // 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();

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

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

288
    rc = get_version_information(version);
289
290
    if (rc) return rc;

291
292
293
294
    // Fix-up version string
    virtualbox_version = "VirtualBox COM Interface (Version: " + version + ")";

    // Get the guest addition information
295
    get_guest_additions(virtualbox_guest_additions);
296
297
298
299
300

    return rc;
}

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

    boinc_get_init_data_p(&aid);
    get_slot_directory(virtual_machine_slot_directory);


331
    rc = pSession.CoCreateInstance(CLSID_Session);
332
    if (CHECK_ERROR(rc)) goto CLEANUP;
333
334


335
336
337
338
    // Reset VM name in case it was changed while deregistering a stale VM
    //
    vm_name = vm_master_name;

339
340
341
342
343
344
345
346
    fprintf(
        stderr,
        "%s Create VM. (%s, slot#%d) \n",
        vboxwrapper_msg_prefix(buf, sizeof(buf)),
        vm_name.c_str(),
        aid.slot
    );

347
348
349
350
351
352
353
354
355
356
357
358
359
360
    // 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
361
    // Start the VM creation process
362
    //
363
    rc = m_pPrivate->m_pVirtualBox->CreateMachine(
364
        CComBSTR(string(virtual_machine_slot_directory + "\\" + vm_name + "\\" + vm_name + ".vbox").c_str()),
Rom Walton's avatar
Rom Walton committed
365
366
367
368
        CComBSTR(vm_name.c_str()),
        NULL,
        CComBSTR(os_name.c_str()),
        CComBSTR(""),
369
        &pMachineRO
Rom Walton's avatar
Rom Walton committed
370
    );
371
    if (CHECK_ERROR(rc)) goto CLEANUP;
372

Rom Walton's avatar
Rom Walton committed
373
374
375
376
377
378
    // 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.
379
    //
380
    rc = m_pPrivate->m_pVirtualBox->RegisterMachine(pMachineRO);
381
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
382
    
383
    rc = pMachineRO->LockMachine(pSession, LockType_Write);
384
    if (CHECK_ERROR(rc)) goto CLEANUP;
385

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

389
    rc = pMachine->get_BIOSSettings(&pBIOSSettings);
390
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
391

392
    rc = pMachine->get_BandwidthControl(&pBandwidthControl);
393
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
394

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

398
    rc = pMachine->GetNetworkAdapter(0, &pNetworkAdapter);
399
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
400
401

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

404
    rc = pMachine->get_AudioAdapter(&pAudioAdapter);
405
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
406
407

    // Set some properties
408
    //
409
    pMachine->put_Description(CComBSTR(vm_master_description.c_str()));
Rom Walton's avatar
Rom Walton committed
410
411

    // Tweak the VM's Memory Size
412
413
414
    //
    fprintf(
        stderr,
Rom Walton's avatar
Rom Walton committed
415
        "%s Setting Memory Size for VM. (%dMB)\n",
416
        vboxwrapper_msg_prefix(buf, sizeof(buf)),
Rom Walton's avatar
Rom Walton committed
417
        (int)memory_size_mb
418
    );
419
    rc = pMachine->put_MemorySize((int)(memory_size_mb));
420
    if (CHECK_ERROR(rc)) goto CLEANUP;
421

Rom Walton's avatar
Rom Walton committed
422
    // Tweak the VM's CPU Count
423
424
425
    //
    fprintf(
        stderr,
Rom Walton's avatar
Rom Walton committed
426
        "%s Setting CPU Count for VM. (%s)\n",
427
        vboxwrapper_msg_prefix(buf, sizeof(buf)),
Rom Walton's avatar
Rom Walton committed
428
        vm_cpu_count.c_str()
429
    );
430
    rc = pMachine->put_CPUCount((int)atoi(vm_cpu_count.c_str()));
431
    if (CHECK_ERROR(rc)) goto CLEANUP;
432
433
434
435
436
437
438
439

    // 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
440
    rc = pBIOSSettings->put_ACPIEnabled(TRUE);
441
    if (CHECK_ERROR(rc)) goto CLEANUP;
442

Rom Walton's avatar
Rom Walton committed
443
    rc = pBIOSSettings->put_IOAPICEnabled(TRUE);
444
    if (CHECK_ERROR(rc)) goto CLEANUP;
445
446
447
448
449
450
451
452

    // Tweak the VM's Boot Options
    //
    fprintf(
        stderr,
        "%s Setting Boot Options for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
453
    rc = pMachine->SetBootOrder(1, DeviceType_HardDisk);
454
    if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
455
    
456
    rc = pMachine->SetBootOrder(2, DeviceType_DVD);
457
    if (CHECK_ERROR(rc)) goto CLEANUP;
458

459
460
    pMachine->SetBootOrder(3, DeviceType_Null);
    pMachine->SetBootOrder(4, DeviceType_Null);
461
462
463

    // Tweak the VM's Network Configuration
    //
464
    if (enable_network) {
Rom Walton's avatar
Rom Walton committed
465
466
        fprintf(
            stderr,
467
468
            "%s Enabling VM Network Access.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
Rom Walton's avatar
Rom Walton committed
469
        );
470
        rc = pNetworkAdapter->put_Enabled(TRUE);
471
        if (CHECK_ERROR(rc)) goto CLEANUP;
472
473
474
475
476
477
478
    } else {
        fprintf(
            stderr,
            "%s Disabling VM Network Access.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
        rc = pNetworkAdapter->put_Enabled(FALSE);
479
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
480
481
    }

482
483
484
485
486
487
    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
488
        rc = pNetworkAdapter->put_AttachmentType(NetworkAttachmentType_Bridged);
489
        if (CHECK_ERROR(rc)) goto CLEANUP;
490
491
492
493
494
495
496
497

        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
498
        rc = pNetworkAdapter->put_BridgedInterface(CComBSTR(CA2W(default_interface.c_str())));
499
        if (CHECK_ERROR(rc)) goto CLEANUP;
500
501
502
503
504
505
    } else {
        fprintf(
            stderr,
            "%s Setting Network Configuration for NAT.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
Rom Walton's avatar
Rom Walton committed
506
        rc = pNetworkAdapter->put_AttachmentType(NetworkAttachmentType_NAT);
507
        if (CHECK_ERROR(rc)) goto CLEANUP;
508

Rom Walton's avatar
Rom Walton committed
509
        rc = pNATEngine->put_DNSProxy(TRUE);
510
        if (CHECK_ERROR(rc)) goto CLEANUP;
511
512
513
514
515
516
517
518
519
    }

    // Tweak the VM's USB Configuration
    //
    fprintf(
        stderr,
        "%s Disabling USB Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
520
#ifdef _VIRTUALBOX43_
521
    rc = pMachine->GetUSBControllerCountByType(USBControllerType_OHCI, &lOHCICtrls);
Rom Walton's avatar
Rom Walton committed
522
    if (SUCCEEDED(rc) && lOHCICtrls) {
523
        pMachine->RemoveUSBController(CComBSTR("OHCI"));
Rom Walton's avatar
Rom Walton committed
524
    }
525
526
527
528
529
530
531
#endif
#ifdef _VIRTUALBOX42_
    rc = pMachine->get_USBController(&pUSBContoller);
    if (SUCCEEDED(rc)) {
        pUSBContoller->put_Enabled(FALSE);
    }
#endif
532
533
534
535
536
537
538
539

    // Tweak the VM's COM Port Support
    //
    fprintf(
        stderr,
        "%s Disabling COM Port Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
540
    rc = pMachine->GetSerialPort(0, &pSerialPort1);
Rom Walton's avatar
Rom Walton committed
541
    if (SUCCEEDED(rc)) {
542
        pSerialPort1->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
543
    }
544
    rc = pMachine->GetSerialPort(1, &pSerialPort2);
Rom Walton's avatar
Rom Walton committed
545
    if (SUCCEEDED(rc)) {
546
        pSerialPort2->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
547
    }
548
549
550
551
552
553
554
555

    // Tweak the VM's LPT Port Support
    //
    fprintf(
        stderr,
        "%s Disabling LPT Port Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
556
    rc = pMachine->GetParallelPort(0, &pParallelPort1);
Rom Walton's avatar
Rom Walton committed
557
    if (SUCCEEDED(rc)) {
558
        pParallelPort1->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
559
    }
560
    rc = pMachine->GetParallelPort(1, &pParallelPort2);
Rom Walton's avatar
Rom Walton committed
561
    if (SUCCEEDED(rc)) {
562
        pParallelPort2->put_Enabled(FALSE);
Rom Walton's avatar
Rom Walton committed
563
    }
564
565
566
567
568
569
570
571

    // 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
572
    pAudioAdapter->put_Enabled(FALSE);
573
574
575
576
577
578
579
580

    // Tweak the VM's Clipboard Support
    //
    fprintf(
        stderr,
        "%s Disabling Clipboard Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
581
    pMachine->put_ClipboardMode(ClipboardMode_Disabled);
582
583
584
585
586
587
588
589

    // Tweak the VM's Drag & Drop Support
    //
    fprintf(
        stderr,
        "%s Disabling Drag and Drop Support for VM.\n",
        vboxwrapper_msg_prefix(buf, sizeof(buf))
    );
590
    pMachine->put_DragAndDropMode(DragAndDropMode_Disabled);
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
627
628
629
630
631
632
633
634
635

    // 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
636
637
638
639
640
641
642
643
644
645

    // 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))
            );
646
            rc = pMachine->SetHWVirtExProperty(HWVirtExPropertyType_Enabled, FALSE);
647
            if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
648
649
650
651
652
653
654
655
        }
    } 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))
            );
656
657
            retval = ERR_INVALID_PARAM;
            goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
658
659
660
661
662
663
664
665
666
667
668
669
670
        }
    }

    // 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")) {
671
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_IDE, &pDiskController);
672
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
673
674
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "sata")) {
675
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SATA, &pDiskController);
676
677
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
678
679
680
681
        pDiskController->put_UseHostIOCache(FALSE);
        pDiskController->put_PortCount(3);
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "sas")) {
682
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SAS, &pDiskController);
683
684
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
685
686
687
        pDiskController->put_UseHostIOCache(FALSE);
    }
    if (0 == stricmp(vm_disk_controller_type.c_str(), "scsi")) {
688
        rc = pMachine->AddStorageController(CComBSTR("Hard Disk Controller"), StorageBus_SCSI, &pDiskController);
689
690
        if (CHECK_ERROR(rc)) goto CLEANUP;

Rom Walton's avatar
Rom Walton committed
691
        pDiskController->put_UseHostIOCache(FALSE);
692
693
    }

Rom Walton's avatar
Rom Walton committed
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
    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);
710
711
712
713
714
    }

    // Add storage controller for a floppy device if desired
    //
    if (enable_floppyio) {
715
        rc = pMachine->AddStorageController(CComBSTR("Floppy Controller"), StorageBus_Floppy, &pFloppyController);
716
        if (CHECK_ERROR(rc)) goto CLEANUP;
717
718
719
720
721
722
723
724
725
726
727
    }

    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
728
        CComPtr<IMedium> pISOImage;
729
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
730
            CComBSTR(string(virtual_machine_slot_directory + "\\" + iso_image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
731
732
            DeviceType_DVD,
            AccessMode_ReadOnly,
Rom Walton's avatar
Rom Walton committed
733
            TRUE,
Rom Walton's avatar
Rom Walton committed
734
735
            &pISOImage
        );
736
        if (CHECK_ERROR(rc)) goto CLEANUP;
737

738
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
739
740
741
742
743
744
            CComBSTR("Hard Disk Controller"),
            0,
            0,
            DeviceType_DVD,
            pISOImage
        );
745
        if (CHECK_ERROR(rc)) goto CLEANUP;
746
747
748
749
750
751
752
753

        // 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
754
        CComPtr<IMedium> pGuestAdditionsImage;
755
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
Rom Walton's avatar
Rom Walton committed
756
757
758
759
760
761
            CComBSTR(virtualbox_guest_additions.c_str()),
            DeviceType_DVD,
            AccessMode_ReadOnly,
            FALSE,
            &pGuestAdditionsImage
        );
762
        if (CHECK_ERROR(rc)) goto CLEANUP;
763

764
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
765
766
767
768
769
770
            CComBSTR("Hard Disk Controller"),
            2,
            0,
            DeviceType_DVD,
            pGuestAdditionsImage
        );
771
        if (CHECK_ERROR(rc)) goto CLEANUP;
772
773
774
775
776
777
778
779
780
781

        // 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
782
            CComPtr<IMedium> pCacheImage;
783
            rc = m_pPrivate->m_pVirtualBox->OpenMedium(
784
                CComBSTR(string(virtual_machine_slot_directory + "\\" + cache_disk_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
785
786
787
788
789
                DeviceType_HardDisk,
                AccessMode_ReadWrite,
                TRUE,
                &pCacheImage
            );
790
            if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
791

792
            rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
793
794
795
796
797
798
                CComBSTR("Hard Disk Controller"),
                1,
                0,
                DeviceType_HardDisk,
                pCacheImage
            );
799
            if (CHECK_ERROR(rc)) goto CLEANUP;
800
801
802
803
804
805
806
807
808
809
        }
    } 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
810
        CComPtr<IMedium> pDiskImage;
811
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
812
            CComBSTR(string(virtual_machine_slot_directory + "\\" + image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
813
814
815
816
817
            DeviceType_HardDisk,
            AccessMode_ReadWrite,
            TRUE,
            &pDiskImage
        );
818
        if (CHECK_ERROR(rc)) goto CLEANUP;
819

820
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
821
822
823
824
825
826
            CComBSTR("Hard Disk Controller"),
            0,
            0,
            DeviceType_HardDisk,
            pDiskImage
        );
827
        if (CHECK_ERROR(rc)) goto CLEANUP;
828
829
830
831
832
833
834
835

        // 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
836
        CComPtr<IMedium> pGuestAdditionsImage;
837
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
Rom Walton's avatar
Rom Walton committed
838
839
840
841
842
843
            CComBSTR(virtualbox_guest_additions.c_str()),
            DeviceType_DVD,
            AccessMode_ReadOnly,
            FALSE,
            &pGuestAdditionsImage
        );
844
        if (CHECK_ERROR(rc)) goto CLEANUP;
845

846
        rc = pMachine->AttachDevice(
Rom Walton's avatar
Rom Walton committed
847
848
849
850
851
            CComBSTR("Hard Disk Controller"),
            1,
            0,
            DeviceType_DVD,
            pGuestAdditionsImage
852
        );
853
        if (CHECK_ERROR(rc)) goto CLEANUP;
854
855
856
857
858
859
860
861
862
    }

    // 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.
        //
863
        pFloppy = new FloppyIONS::FloppyIO(floppy_image_filename.c_str());
864
865
866
867
868
869
870
871
872
873
874
        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()
            );
875
876
            retval = ERR_FWRITE;
            goto CLEANUP;
877
878
879
880
881
882
883
        }

        fprintf(
            stderr,
            "%s Adding virtual floppy disk drive to VM.\n",
            vboxwrapper_msg_prefix(buf, sizeof(buf))
        );
Rom Walton's avatar
Rom Walton committed
884
        CComPtr<IMedium> pFloppyImage;
885
        rc = m_pPrivate->m_pVirtualBox->OpenMedium(
886
            CComBSTR(string(virtual_machine_slot_directory + "\\" + floppy_image_filename).c_str()),
Rom Walton's avatar
Rom Walton committed
887
888
889
890
891
            DeviceType_Floppy,
            AccessMode_ReadWrite,
            TRUE,
            &pFloppyImage
        );
892
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
893

894
895
        rc = pMachine->AttachDevice(
            CComBSTR("Floppy Controller"),
Rom Walton's avatar
Rom Walton committed
896
897
898
899
900
            0,
            0,
            DeviceType_Floppy,
            pFloppyImage
        );
901
        if (CHECK_ERROR(rc)) goto CLEANUP;
Rom Walton's avatar
Rom Walton committed
902
    }
903

Rom Walton's avatar
Rom Walton committed
904
905
906
907
908
909
910
911
912
913
914
915
    // 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
    );
916
    if (CHECK_ERROR(rc)) goto CLEANUP;
917

918
    // Configure port forwarding
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
    //
    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
943
944
945
946
947
948
949
            rc = pNATEngine->AddRedirect(
                CComBSTR(""),
                NATProtocol_TCP,
                pf.is_remote?CComBSTR(""):CComBSTR("127.0.0.1"),
                pf.host_port,
                CComBSTR(""),
                pf.guest_port
950
            );
951
            if (CHECK_ERROR(rc)) goto CLEANUP;
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
        }
    }

    // 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);
971
            if (retval) goto CLEANUP;
972
973

            sprintf(buf, "%d", rd_host_port);
Rom Walton's avatar
Rom Walton committed
974
975
976
977
978
979

            pVRDEServer->put_Enabled(TRUE);
            pVRDEServer->put_VRDEExtPack(CComBSTR(""));
            pVRDEServer->put_AuthLibrary(CComBSTR(""));
            pVRDEServer->put_AuthType(AuthType_Null);
            pVRDEServer->SetVRDEProperty(CComBSTR("TCP/Ports"), CComBSTR(buf));
980
981
982
983
984
985
986
987
988
989
990
        }
    }

    // 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))
        );
991
        rc = pMachine->CreateSharedFolder(
Rom Walton's avatar
Rom Walton committed
992
            CComBSTR("shared"),
993
            CComBSTR(string(virtual_machine_slot_directory + "\\shared").c_str()),
Rom Walton's avatar
Rom Walton committed
994
995
996
            TRUE,
            TRUE
        );
997
        if (CHECK_ERROR(rc)) goto CLEANUP;
998
999
    }

1000
CLEANUP:
For faster browsing, not all history is shown. View entire blame