VirtualBox

source: vbox/trunk/src/VBox/Main/HostImpl.cpp@ 633

Last change on this file since 633 was 606, checked in by vboxsync, 18 years ago

Initial darwin port. (Not tested on linux yet.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.4 KB
Line 
1/** @file
2 * VirtualBox COM class implementation
3 */
4
5/*
6 * Copyright (C) 2006 InnoTek Systemberatung GmbH
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License as published by the Free Software Foundation,
12 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
13 * distribution. VirtualBox OSE is distributed in the hope that it will
14 * be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * If you received this file as part of a commercial VirtualBox
17 * distribution, then only the terms of your commercial VirtualBox
18 * license agreement apply instead of the previous paragraph.
19 */
20
21#ifdef __LINUX__
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <sys/ioctl.h>
26#include <fcntl.h>
27#include <mntent.h>
28/* bird: This is a hack to work around conflicts between these linux kernel headers
29 * and the GLIBC tcpip headers. They have different declarations of the 4
30 * standard byte order functions. */
31#define _LINUX_BYTEORDER_GENERIC_H
32#include <linux/cdrom.h>
33#include <errno.h>
34#endif /* __LINUX __ */
35
36#ifdef __WIN__
37#define _WIN32_DCOM
38#include <windows.h>
39#include <shellapi.h>
40#define INITGUID
41#include <guiddef.h>
42#include <devguid.h>
43#include <objbase.h>
44#include <setupapi.h>
45#include <shlobj.h>
46#include <cfgmgr32.h>
47#endif /* __WIN__ */
48
49
50
51#include "HostImpl.h"
52#include "HostDVDDriveImpl.h"
53#include "HostFloppyDriveImpl.h"
54#include "HostUSBDeviceImpl.h"
55#include "USBControllerImpl.h"
56#include "USBDeviceFilterImpl.h"
57#include "USBProxyService.h"
58#include "VirtualBoxImpl.h"
59#include "MachineImpl.h"
60#include "Logging.h"
61
62#ifdef __WIN__
63#include "HostNetworkInterfaceImpl.h"
64#endif
65
66#include <VBox/usb.h>
67#include <VBox/err.h>
68#include <iprt/string.h>
69#include <iprt/system.h>
70#include <iprt/time.h>
71#include <iprt/param.h>
72
73#include <stdio.h>
74
75#include <algorithm>
76
77// constructor / destructor
78/////////////////////////////////////////////////////////////////////////////
79
80HRESULT Host::FinalConstruct()
81{
82 return S_OK;
83}
84
85void Host::FinalRelease()
86{
87 if (isReady())
88 uninit();
89}
90
91// public initializer/uninitializer for internal purposes only
92/////////////////////////////////////////////////////////////////////////////
93
94/**
95 * Initializes the host object.
96 *
97 * @returns COM result indicator
98 * @param parent handle of our parent object
99 */
100HRESULT Host::init (VirtualBox *parent)
101{
102 LogFlowMember(("Host::init(): isReady=%d\n", isReady()));
103
104 ComAssertRet (parent, E_INVALIDARG);
105
106 AutoLock lock(this);
107 ComAssertRet (!isReady(), E_UNEXPECTED);
108
109 mParent = parent;
110
111#if defined (__LINUX__) && defined (VBOX_WITH_USB)
112 mUSBProxyService = new USBProxyServiceLinux (this);
113#elif defined (__WIN__) && defined (VBOX_WITH_USB)
114 mUSBProxyService = new USBProxyServiceWin32 (this);
115#else
116 mUSBProxyService = new USBProxyService (this);
117#endif
118 /** @todo handle !mUSBProxySerivce->isActive() and mUSBProxyService->getLastError()
119 * and somehow report or whatever that the proxy failed to startup.
120 * Also, there might be init order issues... */
121
122 setReady(true);
123 return S_OK;
124}
125
126/**
127 * Uninitializes the host object and sets the ready flag to FALSE.
128 * Called either from FinalRelease() or by the parent when it gets destroyed.
129 */
130void Host::uninit()
131{
132 LogFlowMember(("Host::uninit(): isReady=%d\n", isReady()));
133
134 AssertReturn (isReady(), (void) 0);
135
136 // uninit all USB device filters still referenced by clients
137 uninitDependentChildren();
138
139 delete mUSBProxyService;
140 mUSBProxyService = NULL;
141
142 mUSBDeviceFilters.clear();
143 mUSBDevices.clear();
144
145 setReady (FALSE);
146}
147
148// IHost properties
149/////////////////////////////////////////////////////////////////////////////
150
151/**
152 * Returns a list of host DVD drives.
153 *
154 * @returns COM status code
155 * @param drives address of result pointer
156 */
157STDMETHODIMP Host::COMGETTER(DVDDrives) (IHostDVDDriveCollection **drives)
158{
159 if (!drives)
160 return E_POINTER;
161 AutoLock lock(this);
162 CHECK_READY();
163 std::list <ComObjPtr <HostDVDDrive> > list;
164
165#if defined(__WIN__)
166 int sz = GetLogicalDriveStrings(0, NULL);
167 TCHAR *hostDrives = new TCHAR[sz+1];
168 GetLogicalDriveStrings(sz, hostDrives);
169 wchar_t driveName[3] = { '?', ':', '\0' };
170 TCHAR *p = hostDrives;
171 do
172 {
173 if (GetDriveType(p) == DRIVE_CDROM)
174 {
175 driveName[0] = *p;
176 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
177 hostDVDDriveObj.createObject();
178 hostDVDDriveObj->init (Bstr (driveName));
179 list.push_back (hostDVDDriveObj);
180 }
181 p += _tcslen(p) + 1;
182 }
183 while (*p);
184 delete[] hostDrives;
185#elif defined(__LINUX__)
186 // On Linux, the situation is much more complex. There is no simple API so
187 // we will take a more creative approach. As there is only a heuristical
188 // approach on Linux, we'll allow the user to specify a list of host CDROMs
189 // using and an environment variable.
190 // The general strategy is to try some known device names and see of they
191 // exist. At last, we'll enumerate the /etc/fstab file (luckily there's an
192 // API to parse it) for CDROM devices. Ok, let's start!
193
194 if (getenv("VBOX_CDROM"))
195 {
196 char *cdromEnv = strdupa(getenv("VBOX_CDROM"));
197 char *cdromDrive;
198 cdromDrive = strtok(cdromEnv, ":");
199 while (cdromDrive)
200 {
201 if (validateDevice(cdromDrive, true))
202 {
203 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
204 hostDVDDriveObj.createObject();
205 hostDVDDriveObj->init (Bstr (cdromDrive));
206 list.push_back (hostDVDDriveObj);
207 }
208 cdromDrive = strtok(NULL, ":");
209 }
210 }
211 else
212 {
213 // this is a good guess usually
214 if (validateDevice("/dev/cdrom", true))
215 {
216 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
217 hostDVDDriveObj.createObject();
218 hostDVDDriveObj->init (Bstr ("/dev/cdrom"));
219 list.push_back (hostDVDDriveObj);
220 }
221
222 // check the mounted drives
223 parseMountTable((char*)"/etc/mtab", list);
224
225 // check the drives that can be mounted
226 parseMountTable((char*)"/etc/fstab", list);
227 }
228#else
229 /* PORTME */
230#endif
231
232 ComObjPtr<HostDVDDriveCollection> collection;
233 collection.createObject();
234 collection->init (list);
235 collection.queryInterfaceTo(drives);
236 return S_OK;
237}
238
239/**
240 * Returns a list of host floppy drives.
241 *
242 * @returns COM status code
243 * @param drives address of result pointer
244 */
245STDMETHODIMP Host::COMGETTER(FloppyDrives) (IHostFloppyDriveCollection **drives)
246{
247 if (!drives)
248 return E_POINTER;
249 AutoLock lock(this);
250 CHECK_READY();
251
252 std::list <ComObjPtr <HostFloppyDrive> > list;
253
254#ifdef __WIN__
255 int sz = GetLogicalDriveStrings(0, NULL);
256 TCHAR *hostDrives = new TCHAR[sz+1];
257 GetLogicalDriveStrings(sz, hostDrives);
258 wchar_t driveName[3] = { '?', ':', '\0' };
259 TCHAR *p = hostDrives;
260 do
261 {
262 if (GetDriveType(p) == DRIVE_REMOVABLE)
263 {
264 driveName[0] = *p;
265 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
266 hostFloppyDriveObj.createObject();
267 hostFloppyDriveObj->init (Bstr (driveName));
268 list.push_back (hostFloppyDriveObj);
269 }
270 p += _tcslen(p) + 1;
271 }
272 while (*p);
273 delete[] hostDrives;
274#elif defined(__LINUX__)
275 // As with the CDROMs, on Linux we have to take a multi-level approach
276 // involving parsing the mount tables. As this is not bulletproof, we'll
277 // give the user the chance to override the detection by an environment
278 // variable and skip the detection.
279
280 if (getenv("VBOX_FLOPPY"))
281 {
282 char *floppyEnv = getenv("VBOX_FLOPPY");
283 char *floppyDrive;
284 floppyDrive = strtok(floppyEnv, ":");
285 while (floppyDrive)
286 {
287 // check if this is an acceptable device
288 if (validateDevice(floppyDrive, false))
289 {
290 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
291 hostFloppyDriveObj.createObject();
292 hostFloppyDriveObj->init (Bstr (floppyDrive));
293 list.push_back (hostFloppyDriveObj);
294 }
295 floppyDrive = strtok(NULL, ":");
296 }
297 }
298 else
299 {
300 // we assume that a floppy is always /dev/fd[x] with x from 0 to 7
301 char devName[10];
302 for (int i = 0; i <= 7; i++)
303 {
304 sprintf(devName, "/dev/fd%d", i);
305 if (validateDevice(devName, false))
306 {
307 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
308 hostFloppyDriveObj.createObject();
309 hostFloppyDriveObj->init (Bstr (devName));
310 list.push_back (hostFloppyDriveObj);
311 }
312 }
313 }
314#else
315 /* PORTME */
316#endif
317
318 ComObjPtr<HostFloppyDriveCollection> collection;
319 collection.createObject();
320 collection->init (list);
321 collection.queryInterfaceTo(drives);
322 return S_OK;
323}
324
325#ifdef __WIN__
326
327static bool IsTAPDevice(const char *guid)
328{
329 HKEY hNetcard;
330 LONG status;
331 DWORD len;
332 int i = 0;
333 bool ret = false;
334
335 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &hNetcard);
336 if (status != ERROR_SUCCESS)
337 return false;
338
339 while(true)
340 {
341 char szEnumName[256];
342 char szNetCfgInstanceId[256];
343 DWORD dwKeyType;
344 HKEY hNetCardGUID;
345
346 len = sizeof(szEnumName);
347 status = RegEnumKeyExA(hNetcard, i, szEnumName, &len, NULL, NULL, NULL, NULL);
348 if (status != ERROR_SUCCESS)
349 break;
350
351 status = RegOpenKeyExA(hNetcard, szEnumName, 0, KEY_READ, &hNetCardGUID);
352 if (status == ERROR_SUCCESS)
353 {
354 len = sizeof (szNetCfgInstanceId);
355 status = RegQueryValueExA(hNetCardGUID, "NetCfgInstanceId", NULL, &dwKeyType, (LPBYTE)szNetCfgInstanceId, &len);
356 if (status == ERROR_SUCCESS && dwKeyType == REG_SZ)
357 {
358 char szNetProductName[256];
359 char szNetProviderName[256];
360
361 szNetProductName[0] = 0;
362 len = sizeof(szNetProductName);
363 status = RegQueryValueExA(hNetCardGUID, "ProductName", NULL, &dwKeyType, (LPBYTE)szNetProductName, &len);
364
365 szNetProviderName[0] = 0;
366 len = sizeof(szNetProviderName);
367 status = RegQueryValueExA(hNetCardGUID, "ProviderName", NULL, &dwKeyType, (LPBYTE)szNetProviderName, &len);
368
369 if ( !strcmp(szNetCfgInstanceId, guid)
370 && !strcmp(szNetProductName, "VirtualBox TAP Adapter")
371 && !strcmp(szNetProviderName, "InnoTek Systemberatung GmbH"))
372 {
373 ret = true;
374 RegCloseKey(hNetCardGUID);
375 break;
376 }
377 }
378 RegCloseKey(hNetCardGUID);
379 }
380 ++i;
381 }
382
383 RegCloseKey (hNetcard);
384 return ret;
385}
386
387/**
388 * Returns a list of host network interfaces.
389 *
390 * @returns COM status code
391 * @param drives address of result pointer
392 */
393STDMETHODIMP Host::COMGETTER(NetworkInterfaces) (IHostNetworkInterfaceCollection **networkInterfaces)
394{
395 if (!networkInterfaces)
396 return E_POINTER;
397 AutoLock lock(this);
398 CHECK_READY();
399
400 std::list <ComObjPtr <HostNetworkInterface> > list;
401
402 HKEY hCtrlNet;
403 LONG status;
404 DWORD len;
405 int i = 0;
406 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
407 "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
408 0, KEY_READ, &hCtrlNet);
409 if (status != ERROR_SUCCESS)
410 return setError(E_FAIL, tr("Could not open registry key"));
411
412 while (true)
413 {
414 char szNetworkGUID[256];
415 HKEY hConnection;
416 char szNetworkConnection[256];
417
418 len = sizeof (szNetworkGUID);
419 status = RegEnumKeyExA(hCtrlNet, i, szNetworkGUID, &len, NULL, NULL, NULL, NULL);
420 if (status != ERROR_SUCCESS)
421 break;
422
423 RTStrPrintf(szNetworkConnection, sizeof(szNetworkConnection), "%s\\Connection", szNetworkGUID);
424 status = RegOpenKeyExA(hCtrlNet, szNetworkConnection, 0, KEY_READ, &hConnection);
425 if (status == ERROR_SUCCESS)
426 {
427 DWORD dwKeyType;
428
429 len = sizeof (szNetworkConnection);
430 status = RegQueryValueExA(hConnection, "Name", NULL, &dwKeyType, (LPBYTE)szNetworkConnection, &len);
431 if (status == ERROR_SUCCESS && dwKeyType == REG_SZ)
432 {
433 if (IsTAPDevice(szNetworkGUID))
434 {
435 /* create a new object and add it to the list */
436 ComObjPtr<HostNetworkInterface> networkInterfaceObj;
437 networkInterfaceObj.createObject();
438 /* remove the curly bracket at the end */
439 szNetworkGUID[strlen(szNetworkGUID) - 1] = '\0';
440 if (SUCCEEDED(networkInterfaceObj->init(Bstr(szNetworkConnection), Guid(szNetworkGUID + 1))))
441 list.push_back(networkInterfaceObj);
442 }
443 }
444 RegCloseKey (hConnection);
445 }
446 ++i;
447 }
448 RegCloseKey (hCtrlNet);
449
450 ComObjPtr<HostNetworkInterfaceCollection> collection;
451 collection.createObject();
452 collection->init(list);
453 collection.queryInterfaceTo(networkInterfaces);
454 return S_OK;
455}
456#endif /* __WIN__ */
457
458STDMETHODIMP Host::COMGETTER(USBDevices)(IHostUSBDeviceCollection **aUSBDevices)
459{
460 if (!aUSBDevices)
461 return E_POINTER;
462
463 AutoLock alock (this);
464 CHECK_READY();
465
466 ComObjPtr <HostUSBDeviceCollection> collection;
467 collection.createObject();
468 collection->init (mUSBDevices);
469 collection.queryInterfaceTo (aUSBDevices);
470 return S_OK;
471}
472
473STDMETHODIMP Host::COMGETTER(USBDeviceFilters) (IHostUSBDeviceFilterCollection ** aUSBDeviceFilters)
474{
475 if (!aUSBDeviceFilters)
476 return E_POINTER;
477
478 AutoLock alock (this);
479 CHECK_READY();
480
481 ComObjPtr <HostUSBDeviceFilterCollection> collection;
482 collection.createObject();
483 collection->init (mUSBDeviceFilters);
484 collection.queryInterfaceTo (aUSBDeviceFilters);
485 return S_OK;
486}
487
488/**
489 * Returns the number of installed logical processors
490 *
491 * @returns COM status code
492 * @param count address of result variable
493 */
494STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *count)
495{
496 if (!count)
497 return E_POINTER;
498 AutoLock lock(this);
499 CHECK_READY();
500 *count = RTSystemProcessorGetCount();
501 return S_OK;
502}
503
504/**
505 * Returns the (approximate) speed of the host CPU in MHz
506 *
507 * @returns COM status code
508 * @param speed address of result variable
509 */
510STDMETHODIMP Host::COMGETTER(ProcessorSpeed)(ULONG *speed)
511{
512 if (!speed)
513 return E_POINTER;
514 AutoLock lock(this);
515 CHECK_READY();
516 /** @todo Add a runtime function for this which uses GIP. */
517 return S_OK;
518}
519/**
520 * Returns a description string for the host CPU
521 *
522 * @returns COM status code
523 * @param description address of result variable
524 */
525STDMETHODIMP Host::COMGETTER(ProcessorDescription)(BSTR *description)
526{
527 if (!description)
528 return E_POINTER;
529 AutoLock lock(this);
530 CHECK_READY();
531 /** @todo */
532 return S_OK;
533}
534
535
536/**
537 * Returns the amount of installed system memory in megabytes
538 *
539 * @returns COM status code
540 * @param size address of result variable
541 */
542STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *size)
543{
544 if (!size)
545 return E_POINTER;
546 AutoLock lock(this);
547 CHECK_READY();
548 /** @todo */
549 return S_OK;
550}
551
552/**
553 * Returns the current system memory free space in megabytes
554 *
555 * @returns COM status code
556 * @param available address of result variable
557 */
558STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *available)
559{
560 if (!available)
561 return E_POINTER;
562 AutoLock lock(this);
563 CHECK_READY();
564 /** @todo */
565 return S_OK;
566}
567
568/**
569 * Returns the name string of the host operating system
570 *
571 * @returns COM status code
572 * @param os address of result variable
573 */
574STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *os)
575{
576 if (!os)
577 return E_POINTER;
578 AutoLock lock(this);
579 CHECK_READY();
580 /** @todo */
581 return S_OK;
582}
583
584/**
585 * Returns the version string of the host operating system
586 *
587 * @returns COM status code
588 * @param os address of result variable
589 */
590STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *version)
591{
592 if (!version)
593 return E_POINTER;
594 AutoLock lock(this);
595 CHECK_READY();
596 /** @todo */
597 return S_OK;
598}
599
600/**
601 * Returns the current host time in milliseconds since 1970-01-01 UTC.
602 *
603 * @returns COM status code
604 * @param time address of result variable
605 */
606STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
607{
608 if (!aUTCTime)
609 return E_POINTER;
610 AutoLock lock(this);
611 CHECK_READY();
612 RTTIMESPEC now;
613 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
614 return S_OK;
615}
616
617// IHost methods
618////////////////////////////////////////////////////////////////////////////////
619
620#ifdef __WIN__
621
622struct NetworkInterfaceHelperClientData
623{
624 SVCHlpMsg::Code msgCode;
625 /* for SVCHlpMsg::CreateHostNetworkInterface */
626 Bstr name;
627 ComObjPtr <HostNetworkInterface> iface;
628 /* for SVCHlpMsg::RemoveHostNetworkInterface */
629 Guid guid;
630};
631
632STDMETHODIMP
633Host::CreateHostNetworkInterface (INPTR BSTR aName,
634 IHostNetworkInterface **aHostNetworkInterface,
635 IProgress **aProgress)
636{
637 if (!aName)
638 return E_INVALIDARG;
639 if (!aHostNetworkInterface)
640 return E_POINTER;
641 if (!aProgress)
642 return E_POINTER;
643
644 AutoLock lock (this);
645 CHECK_READY();
646
647 HRESULT rc = S_OK;
648
649 /* first check whether an interface with the given name already exists */
650 {
651 ComPtr <IHostNetworkInterfaceCollection> coll;
652 rc = COMGETTER(NetworkInterfaces) (coll.asOutParam());
653 CheckComRCReturnRC (rc);
654 ComPtr <IHostNetworkInterface> iface;
655 if (SUCCEEDED (coll->FindByName (aName, iface.asOutParam())))
656 return setError (E_FAIL,
657 tr ("Host network interface '%ls' already exists"), aName);
658 }
659
660 /* create a progress object */
661 ComObjPtr <Progress> progress;
662 progress.createObject();
663 rc = progress->init (mParent, (IHost *) this,
664 Bstr (tr ("Creating host network interface")),
665 FALSE /* aCancelable */);
666 CheckComRCReturnRC (rc);
667 progress.queryInterfaceTo (aProgress);
668
669 /* create a new uninitialized host interface object */
670 ComObjPtr <HostNetworkInterface> iface;
671 iface.createObject();
672 iface.queryInterfaceTo (aHostNetworkInterface);
673
674 /* create the networkInterfaceHelperClient() argument */
675 std::auto_ptr <NetworkInterfaceHelperClientData>
676 d (new NetworkInterfaceHelperClientData());
677 AssertReturn (d.get(), E_OUTOFMEMORY);
678
679 d->msgCode = SVCHlpMsg::CreateHostNetworkInterface;
680 d->name = aName;
681 d->iface = iface;
682
683 rc = mParent->startSVCHelperClient (
684 true /* aPrivileged */,
685 networkInterfaceHelperClient,
686 static_cast <void *> (d.get()),
687 progress);
688
689 if (SUCCEEDED (rc))
690 {
691 /* d is now owned by networkInterfaceHelperClient(), so release it */
692 d.release();
693 }
694
695 return rc;
696}
697
698STDMETHODIMP
699Host::RemoveHostNetworkInterface (INPTR GUIDPARAM aId,
700 IHostNetworkInterface **aHostNetworkInterface,
701 IProgress **aProgress)
702{
703 if (!aHostNetworkInterface)
704 return E_POINTER;
705 if (!aProgress)
706 return E_POINTER;
707
708 AutoLock lock (this);
709 CHECK_READY();
710
711 HRESULT rc = S_OK;
712
713 /* first check whether an interface with the given name already exists */
714 {
715 ComPtr <IHostNetworkInterfaceCollection> coll;
716 rc = COMGETTER(NetworkInterfaces) (coll.asOutParam());
717 CheckComRCReturnRC (rc);
718 ComPtr <IHostNetworkInterface> iface;
719 if (FAILED (coll->FindById (aId, iface.asOutParam())))
720 return setError (E_FAIL,
721 tr ("Host network interface with UUID {%Vuuid} does not exist"),
722 Guid (aId).raw());
723
724 /* return the object to be removed to the caller */
725 iface.queryInterfaceTo (aHostNetworkInterface);
726 }
727
728 /* create a progress object */
729 ComObjPtr <Progress> progress;
730 progress.createObject();
731 rc = progress->init (mParent, (IHost *) this,
732 Bstr (tr ("Removing host network interface")),
733 FALSE /* aCancelable */);
734 CheckComRCReturnRC (rc);
735 progress.queryInterfaceTo (aProgress);
736
737 /* create the networkInterfaceHelperClient() argument */
738 std::auto_ptr <NetworkInterfaceHelperClientData>
739 d (new NetworkInterfaceHelperClientData());
740 AssertReturn (d.get(), E_OUTOFMEMORY);
741
742 d->msgCode = SVCHlpMsg::RemoveHostNetworkInterface;
743 d->guid = aId;
744
745 rc = mParent->startSVCHelperClient (
746 true /* aPrivileged */,
747 networkInterfaceHelperClient,
748 static_cast <void *> (d.get()),
749 progress);
750
751 if (SUCCEEDED (rc))
752 {
753 /* d is now owned by networkInterfaceHelperClient(), so release it */
754 d.release();
755 }
756
757 return rc;
758}
759
760#endif /* __WIN__ */
761
762STDMETHODIMP Host::CreateUSBDeviceFilter (INPTR BSTR aName, IHostUSBDeviceFilter **aFilter)
763{
764 if (!aFilter)
765 return E_POINTER;
766
767 if (!aName || *aName == 0)
768 return E_INVALIDARG;
769
770 AutoLock lock (this);
771 CHECK_READY();
772
773 ComObjPtr <HostUSBDeviceFilter> filter;
774 filter.createObject();
775 HRESULT rc = filter->init (this, aName);
776 ComAssertComRCRet (rc, rc);
777 rc = filter.queryInterfaceTo (aFilter);
778 AssertComRCReturn (rc, rc);
779 return S_OK;
780}
781
782STDMETHODIMP Host::InsertUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter *aFilter)
783{
784 if (!aFilter)
785 return E_INVALIDARG;
786
787 AutoLock alock (this);
788 CHECK_READY();
789
790 ComObjPtr <HostUSBDeviceFilter> filter = getDependentChild (aFilter);
791 if (!filter)
792 return setError (E_INVALIDARG,
793 tr ("The given USB device filter is not created within "
794 "this VirtualBox instance"));
795
796 if (filter->mInList)
797 return setError (E_INVALIDARG,
798 tr ("The given USB device filter is already in the list"));
799
800 // iterate to the position...
801 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
802 std::advance (it, aPosition);
803 // ...and insert
804 mUSBDeviceFilters.insert (it, filter);
805 filter->mInList = true;
806
807 // notify the proxy (only when the filter is active)
808 if (filter->data().mActive)
809 {
810 ComAssertRet (filter->id() == NULL, E_FAIL);
811 filter->id() =
812 mUSBProxyService->insertFilter (ComPtr <IUSBDeviceFilter> (aFilter));
813 }
814
815 // save the global settings
816 alock.unlock();
817 return mParent->saveSettings();
818}
819
820STDMETHODIMP Host::RemoveUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter **aFilter)
821{
822 if (!aFilter)
823 return E_POINTER;
824
825 AutoLock alock (this);
826 CHECK_READY();
827
828 if (!mUSBDeviceFilters.size())
829 return setError (E_INVALIDARG,
830 tr ("The USB device filter list is empty"));
831
832 if (aPosition >= mUSBDeviceFilters.size())
833 return setError (E_INVALIDARG,
834 tr ("Invalid position: %lu (must be in range [0, %lu])"),
835 aPosition, mUSBDeviceFilters.size() - 1);
836
837 ComObjPtr <HostUSBDeviceFilter> filter;
838 {
839 // iterate to the position...
840 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
841 std::advance (it, aPosition);
842 // ...get an element from there...
843 filter = *it;
844 // ...and remove
845 filter->mInList = false;
846 mUSBDeviceFilters.erase (it);
847 }
848
849 filter.queryInterfaceTo (aFilter);
850
851 // notify the proxy (only when the filter is active)
852 if (filter->data().mActive)
853 {
854 ComAssertRet (filter->id() != NULL, E_FAIL);
855 mUSBProxyService->removeFilter (filter->id());
856 filter->id() = NULL;
857 }
858
859 // save the global settings
860 alock.unlock();
861 return mParent->saveSettings();
862}
863
864// public methods only for internal purposes
865////////////////////////////////////////////////////////////////////////////////
866
867/**
868 * Called by setter methods of all USB device filters.
869 */
870HRESULT Host::onUSBDeviceFilterChange (HostUSBDeviceFilter *aFilter,
871 BOOL aActiveChanged /* = FALSE */)
872{
873 AutoLock alock (this);
874 CHECK_READY();
875
876 if (aFilter->mInList)
877 {
878 if (aActiveChanged)
879 {
880 // insert/remove the filter from the proxy
881 if (aFilter->data().mActive)
882 {
883 ComAssertRet (aFilter->id() == NULL, E_FAIL);
884 aFilter->id() =
885 mUSBProxyService->insertFilter (ComPtr <IUSBDeviceFilter> (aFilter));
886 }
887 else
888 {
889 ComAssertRet (aFilter->id() != NULL, E_FAIL);
890 mUSBProxyService->removeFilter (aFilter->id());
891 aFilter->id() = NULL;
892 }
893 }
894 else
895 {
896 if (aFilter->data().mActive)
897 {
898 // update the filter in the proxy
899 ComAssertRet (aFilter->id() != NULL, E_FAIL);
900 mUSBProxyService->removeFilter (aFilter->id());
901 aFilter->id() =
902 mUSBProxyService->insertFilter (ComPtr <IUSBDeviceFilter> (aFilter));
903 }
904 }
905
906 // save the global settings... yeah, on every single filter property change
907 alock.unlock();
908 return mParent->saveSettings();
909 }
910
911 return S_OK;
912}
913
914HRESULT Host::loadSettings (CFGNODE aGlobal)
915{
916 AutoLock lock (this);
917 CHECK_READY();
918
919 ComAssertRet (aGlobal, E_FAIL);
920
921 CFGNODE filters = NULL;
922 CFGLDRGetChildNode (aGlobal, "USBDeviceFilters", 0, &filters);
923 Assert (filters);
924
925 HRESULT rc = S_OK;
926
927 unsigned filterCount = 0;
928 CFGLDRCountChildren (filters, "DeviceFilter", &filterCount);
929 for (unsigned i = 0; i < filterCount && SUCCEEDED (rc); i++)
930 {
931 CFGNODE filter = NULL;
932 CFGLDRGetChildNode (filters, "DeviceFilter", i, &filter);
933 Assert (filter);
934
935 Bstr name;
936 CFGLDRQueryBSTR (filter, "name", name.asOutParam());
937 bool active;
938 CFGLDRQueryBool (filter, "active", &active);
939
940 Bstr vendorId;
941 CFGLDRQueryBSTR (filter, "vendorid", vendorId.asOutParam());
942 Bstr productId;
943 CFGLDRQueryBSTR (filter, "productid", productId.asOutParam());
944 Bstr revision;
945 CFGLDRQueryBSTR (filter, "revision", revision.asOutParam());
946 Bstr manufacturer;
947 CFGLDRQueryBSTR (filter, "manufacturer", manufacturer.asOutParam());
948 Bstr product;
949 CFGLDRQueryBSTR (filter, "product", product.asOutParam());
950 Bstr serialNumber;
951 CFGLDRQueryBSTR (filter, "serialnumber", serialNumber.asOutParam());
952 Bstr port;
953 CFGLDRQueryBSTR (filter, "port", port.asOutParam());
954
955 USBDeviceFilterAction_T action;
956 action = USBDeviceFilterAction_USBDeviceFilterIgnore;
957 Bstr actionStr;
958 CFGLDRQueryBSTR (filter, "action", actionStr.asOutParam());
959 if (actionStr == L"Ignore")
960 action = USBDeviceFilterAction_USBDeviceFilterIgnore;
961 else
962 if (actionStr == L"Hold")
963 action = USBDeviceFilterAction_USBDeviceFilterHold;
964 else
965 AssertMsgFailed (("Invalid action: %ls\n", actionStr.raw()));
966
967 ComObjPtr <HostUSBDeviceFilter> filterObj;
968 filterObj.createObject();
969 rc = filterObj->init (this,
970 name, active, vendorId, productId, revision,
971 manufacturer, product, serialNumber, port,
972 action);
973 // error info is set by init() when appropriate
974 if (SUCCEEDED (rc))
975 {
976 mUSBDeviceFilters.push_back (filterObj);
977 filterObj->mInList = true;
978
979 // notify the proxy (only when the filter is active)
980 if (filterObj->data().mActive)
981 {
982 HostUSBDeviceFilter *flt = filterObj; // resolve ambiguity
983 flt->id() =
984 mUSBProxyService->insertFilter (ComPtr <IUSBDeviceFilter> (flt));
985 }
986 }
987
988 CFGLDRReleaseNode (filter);
989 }
990
991 CFGLDRReleaseNode (filters);
992
993 return rc;
994}
995
996HRESULT Host::saveSettings (CFGNODE aGlobal)
997{
998 AutoLock lock (this);
999 CHECK_READY();
1000
1001 ComAssertRet (aGlobal, E_FAIL);
1002
1003 // first, delete the entry
1004 CFGNODE filters = NULL;
1005 int vrc = CFGLDRGetChildNode (aGlobal, "USBDeviceFilters", 0, &filters);
1006 if (VBOX_SUCCESS (vrc))
1007 {
1008 vrc = CFGLDRDeleteNode (filters);
1009 ComAssertRCRet (vrc, E_FAIL);
1010 }
1011 // then, recreate it
1012 vrc = CFGLDRCreateChildNode (aGlobal, "USBDeviceFilters", &filters);
1013 ComAssertRCRet (vrc, E_FAIL);
1014
1015 USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
1016 while (it != mUSBDeviceFilters.end())
1017 {
1018 AutoLock filterLock (*it);
1019 const HostUSBDeviceFilter::Data &data = (*it)->data();
1020
1021 CFGNODE filter = NULL;
1022 CFGLDRAppendChildNode (filters, "DeviceFilter", &filter);
1023
1024 CFGLDRSetBSTR (filter, "name", data.mName);
1025 CFGLDRSetBool (filter, "active", !!data.mActive);
1026
1027 // all are optional
1028 if (data.mVendorId.string())
1029 CFGLDRSetBSTR (filter, "vendorid", data.mVendorId.string());
1030 if (data.mProductId.string())
1031 CFGLDRSetBSTR (filter, "productid", data.mProductId.string());
1032 if (data.mRevision.string())
1033 CFGLDRSetBSTR (filter, "revision", data.mRevision.string());
1034 if (data.mManufacturer.string())
1035 CFGLDRSetBSTR (filter, "manufacturer", data.mManufacturer.string());
1036 if (data.mProduct.string())
1037 CFGLDRSetBSTR (filter, "product", data.mProduct.string());
1038 if (data.mSerialNumber.string())
1039 CFGLDRSetBSTR (filter, "serialnumber", data.mSerialNumber.string());
1040 if (data.mPort.string())
1041 CFGLDRSetBSTR (filter, "port", data.mPort.string());
1042
1043 // action is mandatory
1044 if (data.mAction == USBDeviceFilterAction_USBDeviceFilterIgnore)
1045 CFGLDRSetString (filter, "action", "Ignore");
1046 else
1047 if (data.mAction == USBDeviceFilterAction_USBDeviceFilterHold)
1048 CFGLDRSetString (filter, "action", "Hold");
1049 else
1050 AssertMsgFailed (("Invalid action: %d\n", data.mAction));
1051
1052 CFGLDRReleaseNode (filter);
1053
1054 ++ it;
1055 }
1056
1057 CFGLDRReleaseNode (filters);
1058
1059 return S_OK;
1060}
1061
1062/**
1063 * Marks the given host USB device as captured by the given machine and returns
1064 * it as IUSBDevice to the caller.
1065 *
1066 * Called by Console from the VM process (throug IInternalMachineControl).
1067 * Must return extended error info in case of errors.
1068 */
1069HRESULT Host::captureUSBDevice (SessionMachine *aMachine, INPTR GUIDPARAM aId,
1070 IUSBDevice **aHostDevice)
1071{
1072 ComAssertRet (aMachine, E_INVALIDARG);
1073 ComAssertRet (aHostDevice, E_POINTER);
1074
1075 AutoLock lock (this);
1076 CHECK_READY();
1077
1078 Guid id (aId);
1079
1080 ComObjPtr <HostUSBDevice> device;
1081 USBDeviceList::iterator it = mUSBDevices.begin();
1082 while (!device && it != mUSBDevices.end())
1083 {
1084 if ((*it)->id() == id)
1085 device = (*it);
1086 ++ it;
1087 }
1088
1089 if (!device)
1090 return setError (E_INVALIDARG,
1091 tr ("USB device with UUID {%s} is not currently attached to the host"),
1092 id.toString().raw());
1093
1094 if (device->state() == USBDeviceState_USBDeviceNotSupported)
1095 return setError (E_INVALIDARG,
1096 tr ("USB device '%s' with UUID {%s} cannot be accessed by guest "
1097 "computers"),
1098 device->name().raw(), id.toString().raw());
1099
1100 if (device->state() == USBDeviceState_USBDeviceUnavailable)
1101 return setError (E_INVALIDARG,
1102 tr ("USB device '%s' with UUID {%s} is being exclusively used by the "
1103 "host computer"),
1104 device->name().raw(), id.toString().raw());
1105
1106 if (device->state() == USBDeviceState_USBDeviceCaptured)
1107 return setError (E_INVALIDARG,
1108 tr ("USB device '%s' with UUID {%s} is already captured by the virtual "
1109 "machine '%ls'"),
1110 device->name().raw(), id.toString().raw(),
1111 aMachine->userData()->mName.raw());
1112
1113 // try capture the device
1114 bool ok = device->setCaptured (aMachine);
1115 if (!ok)
1116 {
1117 if (device->state() == USBDeviceState_USBDeviceBusy)
1118 return setError (E_FAIL,
1119 tr ("USB device with UUID {%s} is being accessed by the host "
1120 "computer and cannot be attached to the virtual machine."
1121 "Please try later"),
1122 id.toString().raw());
1123 else
1124 ComAssertRet (ok, E_FAIL);
1125 }
1126
1127 // return the device to the caller as IUSBDevice
1128 device.queryInterfaceTo (aHostDevice);
1129 return S_OK;
1130}
1131
1132/**
1133 * Replays all filters against the given USB device excluding filters of the
1134 * machine the device is currently marked as captured by.
1135 *
1136 * Called by Console from the VM process (throug IInternalMachineControl).
1137 */
1138HRESULT Host::releaseUSBDevice (SessionMachine *aMachine, INPTR GUIDPARAM aId)
1139{
1140 AutoLock lock (this);
1141 CHECK_READY();
1142
1143 ComObjPtr <HostUSBDevice> device;
1144 USBDeviceList::iterator it = mUSBDevices.begin();
1145 while (!device && it != mUSBDevices.end())
1146 {
1147 if ((*it)->id() == aId)
1148 device = (*it);
1149 ++ it;
1150 }
1151
1152 ComAssertRet (!!device, E_FAIL);
1153 ComAssertRet (device->machine() == aMachine, E_FAIL);
1154
1155 // reset the device and apply filters
1156 int vrc = device->reset();
1157 ComAssertRCRet (vrc, E_FAIL);
1158
1159 HRESULT rc = applyAllUSBFilters (device, aMachine);
1160 ComAssertComRC (rc);
1161
1162 return rc;
1163}
1164
1165/**
1166 * Runs the filters of the given machine against all currently available USB
1167 * devices, marks those that match as captured and returns them as the colection
1168 * of IUSBDevice instances.
1169 *
1170 * Called by Console from the VM process (through IInternalMachineControl).
1171 */
1172HRESULT Host::autoCaptureUSBDevices (SessionMachine *aMachine,
1173 IUSBDeviceCollection **aHostDevices)
1174{
1175 LogFlowMember (("Host::autoCaptureUSBDevices: aMachine=%p\n", aMachine));
1176
1177 AutoLock lock (this);
1178 CHECK_READY();
1179
1180 std::list <ComPtr <IUSBDevice> > list;
1181
1182 USBDeviceList::iterator it = mUSBDevices.begin();
1183 while (it != mUSBDevices.end())
1184 {
1185 ComObjPtr <HostUSBDevice> device = *it;
1186 if (device->isIgnored())
1187 continue;
1188
1189 if (device->state() == USBDeviceState_USBDeviceBusy ||
1190 device->state() == USBDeviceState_USBDeviceAvailable ||
1191 device->state() == USBDeviceState_USBDeviceHeld)
1192 {
1193 applyMachineUSBFilters (aMachine, device);
1194
1195 if (device->state() == USBDeviceState_USBDeviceCaptured)
1196 {
1197 // put the device to the return list
1198 ComPtr <IUSBDevice> d;
1199 device.queryInterfaceTo (d.asOutParam());
1200 Assert (!d.isNull());
1201 list.push_back (d);
1202 }
1203 }
1204 ++ it;
1205 }
1206
1207 ComObjPtr <IfaceUSBDeviceCollection> coll;
1208 coll.createObject();
1209 coll->init (list);
1210 coll.queryInterfaceTo (aHostDevices);
1211
1212 return S_OK;
1213}
1214
1215/**
1216 * Replays all filters against all USB devices currently marked as captured
1217 * by the given machine (excluding this machine's filters).
1218 *
1219 * Called by Console from the VM process (throug IInternalMachineControl).
1220 */
1221HRESULT Host::releaseAllUSBDevices (SessionMachine *aMachine)
1222{
1223 AutoLock lock (this);
1224 CHECK_READY();
1225
1226 USBDeviceList::iterator it = mUSBDevices.begin();
1227 while (it != mUSBDevices.end())
1228 {
1229 ComObjPtr <HostUSBDevice> device = *it;
1230 if (device->machine() == aMachine)
1231 {
1232 // reset the device and apply filters
1233 device->reset();
1234 HRESULT rc = applyAllUSBFilters (device, aMachine);
1235 ComAssertComRC (rc);
1236 }
1237 ++ it;
1238 }
1239
1240 return S_OK;
1241}
1242
1243// private methods
1244////////////////////////////////////////////////////////////////////////////////
1245
1246#ifdef __LINUX__
1247/**
1248 * Helper function to parse the given mount file and add found entries
1249 */
1250void Host::parseMountTable(char *mountTable, std::list <ComObjPtr <HostDVDDrive> > &list)
1251{
1252 FILE *mtab = setmntent(mountTable, "r");
1253 if (mtab)
1254 {
1255 struct mntent *mntent;
1256 char *mnt_type;
1257 char *mnt_dev;
1258 char *tmp;
1259 while ((mntent = getmntent(mtab)))
1260 {
1261 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
1262 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
1263 strcpy(mnt_type, mntent->mnt_type);
1264 strcpy(mnt_dev, mntent->mnt_fsname);
1265 // supermount fs case
1266 if (strcmp(mnt_type, "supermount") == 0)
1267 {
1268 tmp = strstr(mntent->mnt_opts, "fs=");
1269 if (tmp)
1270 {
1271 free(mnt_type);
1272 mnt_type = strdup(tmp + strlen("fs="));
1273 if (mnt_type)
1274 {
1275 tmp = strchr(mnt_type, ',');
1276 if (tmp)
1277 {
1278 *tmp = '\0';
1279 }
1280 }
1281 }
1282 tmp = strstr(mntent->mnt_opts, "dev=");
1283 if (tmp)
1284 {
1285 free(mnt_dev);
1286 mnt_dev = strdup(tmp + strlen("dev="));
1287 if (mnt_dev)
1288 {
1289 tmp = strchr(mnt_dev, ',');
1290 if (tmp)
1291 {
1292 *tmp = '\0';
1293 }
1294 }
1295 }
1296 }
1297 if (strcmp(mnt_type, "iso9660") == 0)
1298 {
1299 /** @todo check whether we've already got the drive in our list! */
1300 if (validateDevice(mnt_dev, true))
1301 {
1302 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1303 hostDVDDriveObj.createObject();
1304 hostDVDDriveObj->init (Bstr (mnt_dev));
1305 list.push_back (hostDVDDriveObj);
1306 }
1307 }
1308 free(mnt_dev);
1309 free(mnt_type);
1310 }
1311 endmntent(mtab);
1312 }
1313}
1314
1315/**
1316 * Helper function to check whether the given device node is a valid drive
1317 */
1318bool Host::validateDevice(char *deviceNode, bool isCDROM)
1319{
1320 struct stat statInfo;
1321 bool retValue = false;
1322
1323 // sanity check
1324 if (!deviceNode)
1325 {
1326 return false;
1327 }
1328
1329 // first a simple stat() call
1330 if (stat(deviceNode, &statInfo) < 0)
1331 {
1332 return false;
1333 } else
1334 {
1335 if (isCDROM)
1336 {
1337 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
1338 {
1339 int fileHandle;
1340 // now try to open the device
1341 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
1342 if (fileHandle >= 0)
1343 {
1344 cdrom_subchnl cdChannelInfo;
1345 // this call will finally reveal the whole truth
1346 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
1347 (errno == EIO) || (errno == ENOENT) ||
1348 (errno == EINVAL) || (errno == ENOMEDIUM))
1349 {
1350 retValue = true;
1351 }
1352 close(fileHandle);
1353 }
1354 }
1355 } else
1356 {
1357 // floppy case
1358 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
1359 {
1360 /// @todo do some more testing, maybe a nice IOCTL!
1361 retValue = true;
1362 }
1363 }
1364 }
1365 return retValue;
1366}
1367#endif // __LINUX__
1368
1369/**
1370 * Runs through all global filters to determine the state of the given
1371 * USB device, then unless ignored, runs trhough filters of all running machines
1372 * (excluding the given one) to automatically capture the device when there is a
1373 * match (the state of the device will be set to USBDeviceCaptured if so, and
1374 * the machine's process will be informed about the auto-capture).
1375 *
1376 * @param aDevice USB device to set state for
1377 * @param aMachine the machine whose filters are to be excluded (can be NULL)
1378 *
1379 * @note the method must be called from under this object's lock
1380 */
1381HRESULT Host::applyAllUSBFilters (ComObjPtr <HostUSBDevice> &aDevice,
1382 SessionMachine *aMachine /* = NULL */)
1383{
1384 LogFlowMember (("Host::applyAllUSBFilters: \n"));
1385
1386 // ignore unsupported devices
1387 if (aDevice->state() == USBDeviceState_USBDeviceNotSupported)
1388 return S_OK;
1389 // ignore unavailable devices as well
1390 if (aDevice->state() == USBDeviceState_USBDeviceUnavailable)
1391 return S_OK;
1392
1393 VirtualBox::SessionMachineVector machines;
1394 mParent->getOpenedMachines (machines);
1395
1396 // apply global filters
1397 USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
1398 while (it != mUSBDeviceFilters.end())
1399 {
1400 AutoLock filterLock (*it);
1401 const HostUSBDeviceFilter::Data &data = (*it)->data();
1402 if (aDevice->isMatch (data))
1403 {
1404 if (data.mAction == USBDeviceFilterAction_USBDeviceFilterIgnore)
1405 return S_OK;
1406 if (data.mAction == USBDeviceFilterAction_USBDeviceFilterHold)
1407 break;
1408 }
1409 ++ it;
1410 }
1411
1412 // apply machine filters
1413 for (size_t i = 0; i < machines.size(); i++)
1414 {
1415 if (aMachine && machines [i] == aMachine)
1416 continue;
1417
1418 applyMachineUSBFilters (machines [i], aDevice);
1419
1420 if (aDevice->state() == USBDeviceState_USBDeviceCaptured)
1421 {
1422 // inform the machine's process about the auto-capture
1423 ComPtr <IUSBDevice> d;
1424 aDevice.queryInterfaceTo (d.asOutParam());
1425 HRESULT rc = machines [i]->onUSBDeviceAttach (d);
1426 if (SUCCEEDED(rc))
1427 return rc;
1428
1429 // the machine rejected it, continue applying filters.
1430 aDevice->reset();
1431 }
1432 }
1433
1434 // no machine filters were matched.
1435 // if no global filters were matched as well, release the device
1436 // to make it available on the host
1437 if ( it == mUSBDeviceFilters.end()
1438 && aDevice->state() == USBDeviceState_USBDeviceHeld)
1439 aDevice->setHostDriven();
1440/** @todo dmik, what about USBDeviceFilterHold??? */
1441/**
1442 * bird, everything's ok from what I see. if USBDeviceFilterHold filter was
1443 * matched, setHostDevice() will not (and should not) be called
1444 * (because it != mUSBDeviceFilters.end() in that case).
1445 */
1446
1447 return S_OK;
1448}
1449
1450/**
1451 * Runs through filters of the given machine in order to automatically capture
1452 * the given USB device when there is a match (the state of the device will
1453 * be set to USBDeviceCaptured if so, but the machine's process will *NOT* be)
1454 * informed about the auto-capture).
1455 *
1456 * @param aMachine the machine whose filters are to be run
1457 * @param aDevice USB device, a candidate for auto-attaching
1458 *
1459 * @note Locks aMachine for reading.
1460 */
1461void Host::applyMachineUSBFilters (SessionMachine *aMachine,
1462 ComObjPtr <HostUSBDevice> &aDevice)
1463{
1464 LogFlowThisFunc (("\n"));
1465
1466 AssertReturn (aMachine, (void) 0);
1467 AssertReturn (aDevice->state() != USBDeviceState_USBDeviceUnavailable, (void) 0);
1468
1469 /* We're going to use aMachine which is not our child/parent, add a caller */
1470 AutoCaller autoCaller (aMachine);
1471 if (!autoCaller.isOk())
1472 {
1473 /* silently return, the machine might be not running any more */
1474 return;
1475 }
1476
1477 /* enter the machine's lock because we want to access its USB controller */
1478 AutoReaderLock machineLock (aMachine);
1479
1480 if (aMachine->usbController()->hasMatchingFilter (aDevice))
1481 {
1482 /* try capture the device */
1483 bool ok = aDevice->setCaptured (aMachine);
1484
1485 /*
1486 * false is valid only when the state remains USBDeviceBusy meaning that
1487 * the device is currently busy (being accessed by the host)
1488 */
1489 Assert (ok || aDevice->state() == USBDeviceState_USBDeviceBusy);
1490 NOREF (ok);
1491 }
1492}
1493
1494/**
1495 * Called by USB proxy service when a new device is physically attached
1496 * to the host.
1497 *
1498 * @param aDevice Pointer to the device which has been attached.
1499 */
1500void Host::onUSBDeviceAttached (HostUSBDevice *aDevice)
1501{
1502 LogFlowMember (("Host::onUSBDeviceAttached: aDevice=%p\n", aDevice));
1503 /// @todo (dmik) check locks
1504 AutoLock alock (this);
1505
1506 // add to the collecion
1507 mUSBDevices.push_back (aDevice);
1508
1509 // apply all filters (no need to lock the device, nobody can access it yet)
1510 ComObjPtr <HostUSBDevice> DevPtr(aDevice);
1511 HRESULT rc = applyAllUSBFilters (DevPtr);
1512 AssertComRC (rc);
1513}
1514
1515/**
1516 * Called by USB proxy service (?) when the device is physically detached
1517 * from the host.
1518 *
1519 * @param aDevice Pointer to the device which has been detached.
1520 */
1521void Host::onUSBDeviceDetached (HostUSBDevice *aDevice)
1522{
1523 LogFlowMember (("Host::onUSBDeviceDetached: aDevice=%p\n", aDevice));
1524 /// @todo (dmik) check locks
1525 AutoLock alock (this);
1526
1527 Guid id = aDevice->id();
1528
1529 ComObjPtr <HostUSBDevice> device;
1530 Host::USBDeviceList::iterator it = mUSBDevices.begin();
1531 while (it != mUSBDevices.end())
1532 {
1533 if ((*it)->id() == id)
1534 {
1535 device = (*it);
1536 break;
1537 }
1538 ++ it;
1539 }
1540
1541 AssertReturn (!!device, (void) 0);
1542
1543 // remove from the collecion
1544 mUSBDevices.erase (it);
1545
1546 if (device->machine())
1547 {
1548 // the device is captured by a machine, instruct it to release
1549 alock.unlock();
1550 HRESULT rc = device->machine()->onUSBDeviceDetach (device->id());
1551 AssertComRC (rc);
1552 }
1553}
1554
1555/**
1556 * Called by USB proxy service when the state of the host-driven device
1557 * has changed because of non proxy interaction.
1558 *
1559 * @param aDevice The device in question.
1560 */
1561void Host::onUSBDeviceStateChanged (HostUSBDevice *aDevice)
1562{
1563 LogFlowMember (("Host::onUSBDeviceStateChanged: \n"));
1564 /// @todo (dmik) check locks
1565 AutoLock alock (this);
1566
1567 /** @todo dmik, is there anything we should do here? For instance if the device now is available? */
1568}
1569
1570#ifdef __WIN__
1571
1572/* The original source of the VBoxTAP adapter creation/destruction code has the following copyright */
1573/*
1574 Copyright 2004 by the Massachusetts Institute of Technology
1575
1576 All rights reserved.
1577
1578 Permission to use, copy, modify, and distribute this software and its
1579 documentation for any purpose and without fee is hereby granted,
1580 provided that the above copyright notice appear in all copies and that
1581 both that copyright notice and this permission notice appear in
1582 supporting documentation, and that the name of the Massachusetts
1583 Institute of Technology (M.I.T.) not be used in advertising or publicity
1584 pertaining to distribution of the software without specific, written
1585 prior permission.
1586
1587 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1588 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1589 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1590 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1591 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1592 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1593 SOFTWARE.
1594*/
1595
1596
1597#define NETSHELL_LIBRARY _T("netshell.dll")
1598
1599/**
1600 * Use the IShellFolder API to rename the connection.
1601 */
1602static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
1603{
1604 /* This is the GUID for the network connections folder. It is constant.
1605 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
1606 const GUID CLSID_NetworkConnections = {
1607 0x7007ACC7, 0x3202, 0x11D1, {
1608 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
1609 }
1610 };
1611
1612 LPITEMIDLIST pidl = NULL;
1613 IShellFolder *pShellFolder = NULL;
1614 HRESULT hr;
1615
1616 /* Build the display name in the form "::{GUID}". */
1617 if (wcslen (wGuid) >= MAX_PATH)
1618 return E_INVALIDARG;
1619 WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
1620 swprintf (szAdapterGuid, L"::%ls", wGuid);
1621
1622 /* Create an instance of the network connections folder. */
1623 hr = CoCreateInstance (CLSID_NetworkConnections, NULL,
1624 CLSCTX_INPROC_SERVER, IID_IShellFolder,
1625 reinterpret_cast <LPVOID *> (&pShellFolder));
1626 /* Parse the display name. */
1627 if (SUCCEEDED (hr))
1628 {
1629 hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
1630 &pidl, NULL);
1631 }
1632 if (SUCCEEDED (hr))
1633 {
1634 hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
1635 &pidl);
1636 }
1637
1638 CoTaskMemFree (pidl);
1639
1640 if (pShellFolder)
1641 pShellFolder->Release();
1642
1643 return hr;
1644}
1645
1646extern "C" HRESULT RenameConnection (PCWSTR GuidString, PCWSTR NewName)
1647{
1648 typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
1649 lpHrRenameConnection RenameConnectionFunc = NULL;
1650 HRESULT status;
1651
1652 /* First try the IShellFolder interface, which was unimplemented
1653 * for the network connections folder before XP. */
1654 status = rename_shellfolder (GuidString, NewName);
1655 if (status == E_NOTIMPL)
1656 {
1657/** @todo that code doesn't seem to work! */
1658 /* The IShellFolder interface is not implemented on this platform.
1659 * Try the (undocumented) HrRenameConnection API in the netshell
1660 * library. */
1661 CLSID clsid;
1662 HINSTANCE hNetShell;
1663 status = CLSIDFromString ((LPOLESTR) GuidString, &clsid);
1664 if (FAILED(status))
1665 return E_FAIL;
1666 hNetShell = LoadLibrary (NETSHELL_LIBRARY);
1667 if (hNetShell == NULL)
1668 return E_FAIL;
1669 RenameConnectionFunc =
1670 (lpHrRenameConnection) GetProcAddress (hNetShell,
1671 "HrRenameConnection");
1672 if (RenameConnectionFunc == NULL)
1673 {
1674 FreeLibrary (hNetShell);
1675 return E_FAIL;
1676 }
1677 status = RenameConnectionFunc (&clsid, NewName);
1678 FreeLibrary (hNetShell);
1679 }
1680 if (FAILED (status))
1681 return status;
1682
1683 return S_OK;
1684}
1685
1686#define DRIVERHWID _T("vboxtap")
1687
1688#define SetErrBreak(strAndArgs) \
1689 if (1) { \
1690 aErrMsg = Utf8StrFmt strAndArgs; vrc = VERR_GENERAL_FAILURE; break; \
1691 } else do {} while (0)
1692
1693/* static */
1694int Host::createNetworkInterface (SVCHlpClient *aClient,
1695 const Utf8Str &aName,
1696 Guid &aGUID, Utf8Str &aErrMsg)
1697{
1698 LogFlowFuncEnter();
1699 LogFlowFunc (("Network connection name = '%s'\n", aName.raw()));
1700
1701 AssertReturn (aClient, VERR_INVALID_POINTER);
1702 AssertReturn (!aName.isNull(), VERR_INVALID_PARAMETER);
1703
1704 int vrc = VINF_SUCCESS;
1705
1706 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1707 SP_DEVINFO_DATA DeviceInfoData;
1708 DWORD ret = 0;
1709 BOOL found = FALSE;
1710 BOOL registered = FALSE;
1711 BOOL destroyList = FALSE;
1712 TCHAR pCfgGuidString [50];
1713
1714 do
1715 {
1716 BOOL ok;
1717 GUID netGuid;
1718 SP_DRVINFO_DATA DriverInfoData;
1719 SP_DEVINSTALL_PARAMS DeviceInstallParams;
1720 TCHAR className [MAX_PATH];
1721 DWORD index = 0;
1722 PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
1723 /* for our purposes, 2k buffer is more
1724 * than enough to obtain the hardware ID
1725 * of the VBoxTAP driver. */
1726 DWORD detailBuf [2048];
1727
1728 HKEY hkey = NULL;
1729 DWORD cbSize;
1730 DWORD dwValueType;
1731
1732 /* initialize the structure size */
1733 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1734 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
1735
1736 /* copy the net class GUID */
1737 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
1738
1739 /* create an empty device info set associated with the net class GUID */
1740 hDeviceInfo = SetupDiCreateDeviceInfoList (&netGuid, NULL);
1741 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1742 SetErrBreak (("SetupDiCreateDeviceInfoList failed (0x%08X)",
1743 GetLastError()));
1744
1745 /* get the class name from GUID */
1746 ok = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
1747 if (!ok)
1748 SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
1749 GetLastError()));
1750
1751 /* create a device info element and add the new device instance
1752 * key to registry */
1753 ok = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
1754 DICD_GENERATE_ID, &DeviceInfoData);
1755 if (!ok)
1756 SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
1757 GetLastError()));
1758
1759 /* select the newly created device info to be the currently
1760 selected member */
1761 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
1762 if (!ok)
1763 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
1764 GetLastError()));
1765
1766 /* build a list of class drivers */
1767 ok = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
1768 SPDIT_CLASSDRIVER);
1769 if (!ok)
1770 SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
1771 GetLastError()));
1772
1773 destroyList = TRUE;
1774
1775 /* enumerate the driver info list */
1776 while (TRUE)
1777 {
1778 BOOL ret;
1779
1780 ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
1781 SPDIT_CLASSDRIVER, index, &DriverInfoData);
1782
1783 /* if the function failed and GetLastError() returned
1784 * ERROR_NO_MORE_ITEMS, then we have reached the end of the
1785 * list. Othewise there was something wrong with this
1786 * particular driver. */
1787 if (!ret)
1788 {
1789 if(GetLastError() == ERROR_NO_MORE_ITEMS)
1790 break;
1791 else
1792 {
1793 index++;
1794 continue;
1795 }
1796 }
1797
1798 pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
1799 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
1800
1801 /* if we successfully find the hardware ID and it turns out to
1802 * be the one for the loopback driver, then we are done. */
1803 if (SetupDiGetDriverInfoDetail (hDeviceInfo,
1804 &DeviceInfoData,
1805 &DriverInfoData,
1806 pDriverInfoDetail,
1807 sizeof (detailBuf),
1808 NULL))
1809 {
1810 TCHAR * t;
1811
1812 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
1813 * whole list and see if there is a match somewhere. */
1814 t = pDriverInfoDetail->HardwareID;
1815 while (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
1816 {
1817 if (!_tcsicmp(t, DRIVERHWID))
1818 break;
1819
1820 t += _tcslen(t) + 1;
1821 }
1822
1823 if (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
1824 {
1825 found = TRUE;
1826 break;
1827 }
1828 }
1829
1830 index ++;
1831 }
1832
1833 if (!found)
1834 SetErrBreak ((tr ("Could not find Host Interface Networking driver! "
1835 "Please reinstall")));
1836
1837 /* set the loopback driver to be the currently selected */
1838 ok = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
1839 &DriverInfoData);
1840 if (!ok)
1841 SetErrBreak (("SetupDiSetSelectedDriver failed (0x%08X)",
1842 GetLastError()));
1843
1844 /* register the phantom device to prepare for install */
1845 ok = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
1846 &DeviceInfoData);
1847 if (!ok)
1848 SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
1849 GetLastError()));
1850
1851 /* registered, but remove if errors occur in the following code */
1852 registered = TRUE;
1853
1854 /* ask the installer if we can install the device */
1855 ok = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
1856 &DeviceInfoData);
1857 if (!ok)
1858 {
1859 if (GetLastError() != ERROR_DI_DO_DEFAULT)
1860 SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
1861 GetLastError()));
1862 /* that's fine */
1863 }
1864
1865 /* install the files first */
1866 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
1867 &DeviceInfoData);
1868 if (!ok)
1869 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
1870 GetLastError()));
1871
1872 /* get the device install parameters and disable filecopy */
1873 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
1874 ok = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
1875 &DeviceInstallParams);
1876 if (ok)
1877 {
1878 DeviceInstallParams.Flags |= DI_NOFILECOPY;
1879 ok = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
1880 &DeviceInstallParams);
1881 if (!ok)
1882 SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
1883 GetLastError()));
1884 }
1885
1886 /*
1887 * Register any device-specific co-installers for this device,
1888 */
1889
1890 ok = SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS,
1891 hDeviceInfo,
1892 &DeviceInfoData);
1893 if (!ok)
1894 SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
1895 GetLastError()));
1896
1897 /*
1898 * install any installer-specified interfaces.
1899 * and then do the real install
1900 */
1901 ok = SetupDiCallClassInstaller (DIF_INSTALLINTERFACES,
1902 hDeviceInfo,
1903 &DeviceInfoData);
1904 if (!ok)
1905 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
1906 GetLastError()));
1907
1908 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICE,
1909 hDeviceInfo,
1910 &DeviceInfoData);
1911 if (!ok)
1912 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
1913 GetLastError()));
1914
1915 /* Figure out NetCfgInstanceId */
1916 hkey = SetupDiOpenDevRegKey (hDeviceInfo,
1917 &DeviceInfoData,
1918 DICS_FLAG_GLOBAL,
1919 0,
1920 DIREG_DRV,
1921 KEY_READ);
1922 if (hkey == INVALID_HANDLE_VALUE)
1923 SetErrBreak (("SetupDiOpenDevRegKey failed (0x%08X)",
1924 GetLastError()));
1925
1926 cbSize = sizeof (pCfgGuidString);
1927 DWORD ret;
1928 ret = RegQueryValueEx (hkey, _T ("NetCfgInstanceId"), NULL,
1929 &dwValueType, (LPBYTE) pCfgGuidString, &cbSize);
1930 RegCloseKey (hkey);
1931
1932 ret = RenameConnection (pCfgGuidString, Bstr (aName));
1933 if (FAILED (ret))
1934 SetErrBreak (("Failed to set interface name (ret=0x%08X, "
1935 "pCfgGuidString='%ls', cbSize=%d)",
1936 ret, pCfgGuidString, cbSize));
1937 }
1938 while (0);
1939
1940 /*
1941 * cleanup
1942 */
1943
1944 if (hDeviceInfo != INVALID_HANDLE_VALUE)
1945 {
1946 /* an error has occured, but the device is registered, we must remove it */
1947 if (ret != 0 && registered)
1948 SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
1949
1950 found = SetupDiDeleteDeviceInfo (hDeviceInfo, &DeviceInfoData);
1951
1952 /* destroy the driver info list */
1953 if (destroyList)
1954 SetupDiDestroyDriverInfoList (hDeviceInfo, &DeviceInfoData,
1955 SPDIT_CLASSDRIVER);
1956 /* clean up the device info set */
1957 SetupDiDestroyDeviceInfoList (hDeviceInfo);
1958 }
1959
1960 /* return the network connection GUID on success */
1961 if (VBOX_SUCCESS (vrc))
1962 {
1963 /* remove the curly bracket at the end */
1964 pCfgGuidString [_tcslen (pCfgGuidString) - 1] = '\0';
1965 LogFlowFunc (("Network connection GUID string = {%ls}\n", pCfgGuidString + 1));
1966
1967 aGUID = Guid (Utf8Str (pCfgGuidString + 1));
1968 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", aGUID.raw()));
1969 Assert (!aGUID.isEmpty());
1970 }
1971
1972 LogFlowFunc (("vrc=%Vrc\n", vrc));
1973 LogFlowFuncLeave();
1974 return vrc;
1975}
1976
1977/* static */
1978int Host::removeNetworkInterface (SVCHlpClient *aClient,
1979 const Guid &aGUID,
1980 Utf8Str &aErrMsg)
1981{
1982 LogFlowFuncEnter();
1983 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", aGUID.raw()));
1984
1985 AssertReturn (aClient, VERR_INVALID_POINTER);
1986 AssertReturn (!aGUID.isEmpty(), VERR_INVALID_PARAMETER);
1987
1988 int vrc = VINF_SUCCESS;
1989
1990 do
1991 {
1992 TCHAR lszPnPInstanceId [512] = {0};
1993
1994 /* We have to find the device instance ID through a registry search */
1995
1996 HKEY hkeyNetwork = 0;
1997 HKEY hkeyConnection = 0;
1998
1999 do
2000 {
2001 char strRegLocation [256];
2002 sprintf (strRegLocation,
2003 "SYSTEM\\CurrentControlSet\\Control\\Network\\"
2004 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\{%s}",
2005 aGUID.toString().raw());
2006 LONG status;
2007 status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, strRegLocation, 0,
2008 KEY_READ, &hkeyNetwork);
2009 if ((status != ERROR_SUCCESS) || !hkeyNetwork)
2010 SetErrBreak ((
2011 tr ("Host interface network is not found in registry (%s) [1]"),
2012 strRegLocation));
2013
2014 status = RegOpenKeyExA (hkeyNetwork, "Connection", 0,
2015 KEY_READ, &hkeyConnection);
2016 if ((status != ERROR_SUCCESS) || !hkeyConnection)
2017 SetErrBreak ((
2018 tr ("Host interface network is not found in registry (%s) [2]"),
2019 strRegLocation));
2020
2021 DWORD len = sizeof (lszPnPInstanceId);
2022 DWORD dwKeyType;
2023 status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
2024 &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
2025 if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
2026 SetErrBreak ((
2027 tr ("Host interface network is not found in registry (%s) [3]"),
2028 strRegLocation));
2029 }
2030 while (0);
2031
2032 if (hkeyConnection)
2033 RegCloseKey (hkeyConnection);
2034 if (hkeyNetwork)
2035 RegCloseKey (hkeyNetwork);
2036
2037 if (VBOX_FAILURE (vrc))
2038 break;
2039
2040 /*
2041 * Now we are going to enumerate all network devices and
2042 * wait until we encounter the right device instance ID
2043 */
2044
2045 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2046
2047 do
2048 {
2049 BOOL ok;
2050 DWORD ret = 0;
2051 GUID netGuid;
2052 SP_DEVINFO_DATA DeviceInfoData;
2053 DWORD index = 0;
2054 BOOL found = FALSE;
2055 DWORD size = 0;
2056
2057 /* initialize the structure size */
2058 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2059
2060 /* copy the net class GUID */
2061 memcpy (&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
2062
2063 /* return a device info set contains all installed devices of the Net class */
2064 hDeviceInfo = SetupDiGetClassDevs (&netGuid, NULL, NULL, DIGCF_PRESENT);
2065
2066 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2067 SetErrBreak (("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
2068
2069 /* enumerate the driver info list */
2070 while (TRUE)
2071 {
2072 TCHAR *deviceHwid;
2073
2074 ok = SetupDiEnumDeviceInfo (hDeviceInfo, index, &DeviceInfoData);
2075
2076 if (!ok)
2077 {
2078 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2079 break;
2080 else
2081 {
2082 index++;
2083 continue;
2084 }
2085 }
2086
2087 /* try to get the hardware ID registry property */
2088 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2089 &DeviceInfoData,
2090 SPDRP_HARDWAREID,
2091 NULL,
2092 NULL,
2093 0,
2094 &size);
2095 if (!ok)
2096 {
2097 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2098 {
2099 index++;
2100 continue;
2101 }
2102
2103 deviceHwid = (TCHAR *) malloc (size);
2104 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2105 &DeviceInfoData,
2106 SPDRP_HARDWAREID,
2107 NULL,
2108 (PBYTE)deviceHwid,
2109 size,
2110 NULL);
2111 if (!ok)
2112 {
2113 free (deviceHwid);
2114 deviceHwid = NULL;
2115 index++;
2116 continue;
2117 }
2118 }
2119 else
2120 {
2121 /* something is wrong. This shouldn't have worked with a NULL buffer */
2122 index++;
2123 continue;
2124 }
2125
2126 for (TCHAR *t = deviceHwid;
2127 t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
2128 t += _tcslen (t) + 1)
2129 {
2130 if (!_tcsicmp (DRIVERHWID, t))
2131 {
2132 /* get the device instance ID */
2133 TCHAR devID [MAX_DEVICE_ID_LEN];
2134 if (CM_Get_Device_ID(DeviceInfoData.DevInst,
2135 devID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
2136 {
2137 /* compare to what we determined before */
2138 if (wcscmp(devID, lszPnPInstanceId) == 0)
2139 {
2140 found = TRUE;
2141 break;
2142 }
2143 }
2144 }
2145 }
2146
2147 if (deviceHwid)
2148 {
2149 free (deviceHwid);
2150 deviceHwid = NULL;
2151 }
2152
2153 if (found)
2154 break;
2155
2156 index++;
2157 }
2158
2159 if (found == FALSE)
2160 SetErrBreak ((tr ("Host Interface Network driver not found (0x%08X)"),
2161 GetLastError()));
2162
2163 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2164 if (!ok)
2165 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2166 GetLastError()));
2167
2168 ok = SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2169 if (!ok)
2170 SetErrBreak (("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)",
2171 GetLastError()));
2172 }
2173 while (0);
2174
2175 /* clean up the device info set */
2176 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2177 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2178
2179 if (VBOX_FAILURE (vrc))
2180 break;
2181 }
2182 while (0);
2183
2184 LogFlowFunc (("vrc=%Vrc\n", vrc));
2185 LogFlowFuncLeave();
2186 return vrc;
2187}
2188
2189#undef SetErrBreak
2190
2191/* static */
2192HRESULT Host::networkInterfaceHelperClient (SVCHlpClient *aClient,
2193 Progress *aProgress,
2194 void *aUser, int *aVrc)
2195{
2196 LogFlowFuncEnter();
2197 LogFlowFunc (("aClient={%p}, aProgress={%p}, aUser={%p}\n",
2198 aClient, aProgress, aUser));
2199
2200 AssertReturn ((aClient == NULL && aProgress == NULL && aVrc == NULL) ||
2201 (aClient != NULL && aProgress != NULL && aVrc != NULL),
2202 E_POINTER);
2203 AssertReturn (aUser, E_POINTER);
2204
2205 std::auto_ptr <NetworkInterfaceHelperClientData>
2206 d (static_cast <NetworkInterfaceHelperClientData *> (aUser));
2207
2208 if (aClient == NULL)
2209 {
2210 /* "cleanup only" mode, just return (it will free aUser) */
2211 return S_OK;
2212 }
2213
2214 HRESULT rc = S_OK;
2215 int vrc = VINF_SUCCESS;
2216
2217 switch (d->msgCode)
2218 {
2219 case SVCHlpMsg::CreateHostNetworkInterface:
2220 {
2221 LogFlowFunc (("CreateHostNetworkInterface:\n"));
2222 LogFlowFunc (("Network connection name = '%ls'\n", d->name.raw()));
2223
2224 /* write message and parameters */
2225 vrc = aClient->write (d->msgCode);
2226 if (VBOX_FAILURE (vrc)) break;
2227 vrc = aClient->write (Utf8Str (d->name));
2228 if (VBOX_FAILURE (vrc)) break;
2229
2230 /* wait for a reply */
2231 bool endLoop = false;
2232 while (!endLoop)
2233 {
2234 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
2235
2236 vrc = aClient->read (reply);
2237 if (VBOX_FAILURE (vrc)) break;
2238
2239 switch (reply)
2240 {
2241 case SVCHlpMsg::CreateHostNetworkInterface_OK:
2242 {
2243 /* read the GUID */
2244 Guid guid;
2245 vrc = aClient->read (guid);
2246 if (VBOX_FAILURE (vrc)) break;
2247
2248 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", guid.raw()));
2249
2250 /* initialize the object returned to the caller by
2251 * CreateHostNetworkInterface() */
2252 rc = d->iface->init (d->name, guid);
2253 endLoop = true;
2254 break;
2255 }
2256 case SVCHlpMsg::Error:
2257 {
2258 /* read the error message */
2259 Utf8Str errMsg;
2260 vrc = aClient->read (errMsg);
2261 if (VBOX_FAILURE (vrc)) break;
2262
2263 rc = setError (E_FAIL, errMsg);
2264 endLoop = true;
2265 break;
2266 }
2267 default:
2268 {
2269 endLoop = true;
2270 ComAssertMsgFailedBreak ((
2271 "Invalid message code %d (%08lX)\n",
2272 reply, reply),
2273 rc = E_FAIL);
2274 }
2275 }
2276 }
2277
2278 break;
2279 }
2280 case SVCHlpMsg::RemoveHostNetworkInterface:
2281 {
2282 LogFlowFunc (("RemoveHostNetworkInterface:\n"));
2283 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", d->guid.raw()));
2284
2285 /* write message and parameters */
2286 vrc = aClient->write (d->msgCode);
2287 if (VBOX_FAILURE (vrc)) break;
2288 vrc = aClient->write (d->guid);
2289 if (VBOX_FAILURE (vrc)) break;
2290
2291 /* wait for a reply */
2292 bool endLoop = false;
2293 while (!endLoop)
2294 {
2295 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
2296
2297 vrc = aClient->read (reply);
2298 if (VBOX_FAILURE (vrc)) break;
2299
2300 switch (reply)
2301 {
2302 case SVCHlpMsg::OK:
2303 {
2304 /* no parameters */
2305 rc = S_OK;
2306 endLoop = true;
2307 break;
2308 }
2309 case SVCHlpMsg::Error:
2310 {
2311 /* read the error message */
2312 Utf8Str errMsg;
2313 vrc = aClient->read (errMsg);
2314 if (VBOX_FAILURE (vrc)) break;
2315
2316 rc = setError (E_FAIL, errMsg);
2317 endLoop = true;
2318 break;
2319 }
2320 default:
2321 {
2322 endLoop = true;
2323 ComAssertMsgFailedBreak ((
2324 "Invalid message code %d (%08lX)\n",
2325 reply, reply),
2326 rc = E_FAIL);
2327 }
2328 }
2329 }
2330
2331 break;
2332 }
2333 default:
2334 ComAssertMsgFailedBreak ((
2335 "Invalid message code %d (%08lX)\n",
2336 d->msgCode, d->msgCode),
2337 rc = E_FAIL);
2338 }
2339
2340 if (aVrc)
2341 *aVrc = vrc;
2342
2343 LogFlowFunc (("rc=0x%08X, vrc=%Vrc\n", rc, vrc));
2344 LogFlowFuncLeave();
2345 return rc;
2346}
2347
2348/* static */
2349int Host::networkInterfaceHelperServer (SVCHlpClient *aClient,
2350 SVCHlpMsg::Code aMsgCode)
2351{
2352 LogFlowFuncEnter();
2353 LogFlowFunc (("aClient={%p}, aMsgCode=%d\n", aClient, aMsgCode));
2354
2355 AssertReturn (aClient, VERR_INVALID_POINTER);
2356
2357 int vrc = VINF_SUCCESS;
2358
2359 switch (aMsgCode)
2360 {
2361 case SVCHlpMsg::CreateHostNetworkInterface:
2362 {
2363 LogFlowFunc (("CreateHostNetworkInterface:\n"));
2364
2365 Utf8Str name;
2366 vrc = aClient->read (name);
2367 if (VBOX_FAILURE (vrc)) break;
2368
2369 Guid guid;
2370 Utf8Str errMsg;
2371 vrc = createNetworkInterface (aClient, name, guid, errMsg);
2372
2373 if (VBOX_SUCCESS (vrc))
2374 {
2375 /* write success followed by GUID */
2376 vrc = aClient->write (SVCHlpMsg::CreateHostNetworkInterface_OK);
2377 if (VBOX_FAILURE (vrc)) break;
2378 vrc = aClient->write (guid);
2379 if (VBOX_FAILURE (vrc)) break;
2380 }
2381 else
2382 {
2383 /* write failure followed by error message */
2384 if (errMsg.isEmpty())
2385 errMsg = Utf8StrFmt ("Unspecified error (%Vrc)", vrc);
2386 vrc = aClient->write (SVCHlpMsg::Error);
2387 if (VBOX_FAILURE (vrc)) break;
2388 vrc = aClient->write (errMsg);
2389 if (VBOX_FAILURE (vrc)) break;
2390 }
2391
2392 break;
2393 }
2394 case SVCHlpMsg::RemoveHostNetworkInterface:
2395 {
2396 LogFlowFunc (("RemoveHostNetworkInterface:\n"));
2397
2398 Guid guid;
2399 vrc = aClient->read (guid);
2400 if (VBOX_FAILURE (vrc)) break;
2401
2402 Utf8Str errMsg;
2403 vrc = removeNetworkInterface (aClient, guid, errMsg);
2404
2405 if (VBOX_SUCCESS (vrc))
2406 {
2407 /* write parameter-less success */
2408 vrc = aClient->write (SVCHlpMsg::OK);
2409 if (VBOX_FAILURE (vrc)) break;
2410 }
2411 else
2412 {
2413 /* write failure followed by error message */
2414 if (errMsg.isEmpty())
2415 errMsg = Utf8StrFmt ("Unspecified error (%Vrc)", vrc);
2416 vrc = aClient->write (SVCHlpMsg::Error);
2417 if (VBOX_FAILURE (vrc)) break;
2418 vrc = aClient->write (errMsg);
2419 if (VBOX_FAILURE (vrc)) break;
2420 }
2421
2422 break;
2423 }
2424 default:
2425 AssertMsgFailedBreak ((
2426 "Invalid message code %d (%08lX)\n", aMsgCode, aMsgCode),
2427 VERR_GENERAL_FAILURE);
2428 }
2429
2430 LogFlowFunc (("vrc=%Vrc\n", vrc));
2431 LogFlowFuncLeave();
2432 return vrc;
2433}
2434
2435#endif /* __WIN__ */
2436
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette