VirtualBox

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

Last change on this file since 332 was 259, checked in by vboxsync, 18 years ago

don't try to open CDROM drives with O_EXCL, we don't use this flag later anyway

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