VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsNetwork.cpp@ 103771

Last change on this file since 103771 was 103771, checked in by vboxsync, 11 months ago

FE/Qt: UICommon: Switching dependency from UICommon to UIGlobalSession whenever is possible.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.7 KB
Line 
1/* $Id: UIMachineSettingsNetwork.cpp 103771 2024-03-11 15:16:04Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMachineSettingsNetwork class implementation.
4 */
5
6/*
7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QRegularExpression>
30#include <QVBoxLayout>
31
32/* GUI includes: */
33#include "QITabWidget.h"
34#include "UIErrorString.h"
35#include "UIGlobalSession.h"
36#include "UIMachineSettingsNetwork.h"
37#include "UINetworkAttachmentEditor.h"
38#include "UINetworkSettingsEditor.h"
39#include "UITranslator.h"
40
41/* COM includes: */
42#include "CNATEngine.h"
43#include "CNetworkAdapter.h"
44#include "CPlatformProperties.h"
45
46
47QString wipedOutString(const QString &strInputString)
48{
49 return strInputString.isEmpty() ? QString() : strInputString;
50}
51
52
53/** Machine settings: Network Adapter data structure. */
54struct UIDataSettingsMachineNetworkAdapter
55{
56 /** Constructs data. */
57 UIDataSettingsMachineNetworkAdapter()
58 : m_iSlot(0)
59 , m_fAdapterEnabled(false)
60 , m_adapterType(KNetworkAdapterType_Null)
61 , m_attachmentType(KNetworkAttachmentType_Null)
62 , m_promiscuousMode(KNetworkAdapterPromiscModePolicy_Deny)
63 , m_strBridgedAdapterName(QString())
64 , m_strInternalNetworkName(QString())
65 , m_strHostInterfaceName(QString())
66 , m_strGenericDriverName(QString())
67 , m_strGenericProperties(QString())
68 , m_strNATNetworkName(QString())
69#ifdef VBOX_WITH_CLOUD_NET
70 , m_strCloudNetworkName(QString())
71#endif
72#ifdef VBOX_WITH_VMNET
73 , m_strHostOnlyNetworkName(QString())
74#endif
75 , m_strMACAddress(QString())
76 , m_fCableConnected(false)
77 {}
78
79 /** Returns whether the @a other passed data is equal to this one. */
80 bool equal(const UIDataSettingsMachineNetworkAdapter &other) const
81 {
82 return true
83 && (m_iSlot == other.m_iSlot)
84 && (m_fAdapterEnabled == other.m_fAdapterEnabled)
85 && (m_adapterType == other.m_adapterType)
86 && (m_attachmentType == other.m_attachmentType)
87 && (m_promiscuousMode == other.m_promiscuousMode)
88 && (m_strBridgedAdapterName == other.m_strBridgedAdapterName)
89 && (m_strInternalNetworkName == other.m_strInternalNetworkName)
90 && (m_strHostInterfaceName == other.m_strHostInterfaceName)
91 && (m_strGenericDriverName == other.m_strGenericDriverName)
92 && (m_strGenericProperties == other.m_strGenericProperties)
93 && (m_strNATNetworkName == other.m_strNATNetworkName)
94#ifdef VBOX_WITH_CLOUD_NET
95 && (m_strCloudNetworkName == other.m_strCloudNetworkName)
96#endif
97#ifdef VBOX_WITH_VMNET
98 && (m_strHostOnlyNetworkName == other.m_strHostOnlyNetworkName)
99#endif
100 && (m_strMACAddress == other.m_strMACAddress)
101 && (m_fCableConnected == other.m_fCableConnected)
102 ;
103 }
104
105 /** Returns whether the @a other passed data is equal to this one. */
106 bool operator==(const UIDataSettingsMachineNetworkAdapter &other) const { return equal(other); }
107 /** Returns whether the @a other passed data is different from this one. */
108 bool operator!=(const UIDataSettingsMachineNetworkAdapter &other) const { return !equal(other); }
109
110 /** Holds the network adapter slot number. */
111 int m_iSlot;
112 /** Holds whether the network adapter is enabled. */
113 bool m_fAdapterEnabled;
114 /** Holds the network adapter type. */
115 KNetworkAdapterType m_adapterType;
116 /** Holds the network attachment type. */
117 KNetworkAttachmentType m_attachmentType;
118 /** Holds the network promiscuous mode policy. */
119 KNetworkAdapterPromiscModePolicy m_promiscuousMode;
120 /** Holds the bridged adapter name. */
121 QString m_strBridgedAdapterName;
122 /** Holds the internal network name. */
123 QString m_strInternalNetworkName;
124 /** Holds the host interface name. */
125 QString m_strHostInterfaceName;
126 /** Holds the generic driver name. */
127 QString m_strGenericDriverName;
128 /** Holds the generic driver properties. */
129 QString m_strGenericProperties;
130 /** Holds the NAT network name. */
131 QString m_strNATNetworkName;
132#ifdef VBOX_WITH_CLOUD_NET
133 /** Holds the cloud network name. */
134 QString m_strCloudNetworkName;
135#endif
136#ifdef VBOX_WITH_VMNET
137 /** Holds the host-only network name. */
138 QString m_strHostOnlyNetworkName;
139#endif
140 /** Holds the network adapter MAC address. */
141 QString m_strMACAddress;
142 /** Holds whether the network adapter is connected. */
143 bool m_fCableConnected;
144};
145
146
147/** Machine settings: Network page data structure. */
148struct UIDataSettingsMachineNetwork
149{
150 /** Constructs data. */
151 UIDataSettingsMachineNetwork() {}
152
153 /** Returns whether the @a other passed data is equal to this one. */
154 bool operator==(const UIDataSettingsMachineNetwork & /* other */) const { return true; }
155 /** Returns whether the @a other passed data is different from this one. */
156 bool operator!=(const UIDataSettingsMachineNetwork & /* other */) const { return false; }
157};
158
159
160/*********************************************************************************************************************************
161* Class UIMachineSettingsNetwork implementation. *
162*********************************************************************************************************************************/
163
164UIMachineSettingsNetwork::UIMachineSettingsNetwork()
165 : m_pCache(0)
166 , m_pTabWidget(0)
167{
168 prepare();
169}
170
171UIMachineSettingsNetwork::~UIMachineSettingsNetwork()
172{
173 cleanup();
174}
175
176bool UIMachineSettingsNetwork::changed() const
177{
178 return m_pCache ? m_pCache->wasChanged() : false;
179}
180
181void UIMachineSettingsNetwork::loadToCacheFrom(QVariant &data)
182{
183 /* Sanity check: */
184 if ( !m_pCache
185 || !m_pTabWidget)
186 return;
187
188 /* Fetch data to machine: */
189 UISettingsPageMachine::fetchData(data);
190
191 /* Clear cache initially: */
192 m_pCache->clear();
193
194 /* Cache name lists: */
195 refreshBridgedAdapterList();
196 refreshInternalNetworkList(true);
197 refreshHostInterfaceList();
198 refreshGenericDriverList(true);
199 refreshNATNetworkList();
200#ifdef VBOX_WITH_CLOUD_NET
201 refreshCloudNetworkList();
202#endif
203#ifdef VBOX_WITH_VMNET
204 refreshHostOnlyNetworkList();
205#endif
206
207 /* Prepare old data: */
208 UIDataSettingsMachineNetwork oldNetworkData;
209
210 /* For each network adapter: */
211 for (int iSlot = 0; iSlot < m_pTabWidget->count(); ++iSlot)
212 {
213 /* Prepare old data: */
214 UIDataSettingsMachineNetworkAdapter oldAdapterData;
215
216 /* Check whether adapter is valid: */
217 const CNetworkAdapter &comAdapter = m_machine.GetNetworkAdapter(iSlot);
218 if (!comAdapter.isNull())
219 {
220 /* Gather old data: */
221 oldAdapterData.m_iSlot = iSlot;
222 oldAdapterData.m_fAdapterEnabled = comAdapter.GetEnabled();
223 oldAdapterData.m_attachmentType = comAdapter.GetAttachmentType();
224 oldAdapterData.m_strBridgedAdapterName = wipedOutString(comAdapter.GetBridgedInterface());
225 oldAdapterData.m_strInternalNetworkName = wipedOutString(comAdapter.GetInternalNetwork());
226 oldAdapterData.m_strHostInterfaceName = wipedOutString(comAdapter.GetHostOnlyInterface());
227 oldAdapterData.m_strGenericDriverName = wipedOutString(comAdapter.GetGenericDriver());
228 oldAdapterData.m_strNATNetworkName = wipedOutString(comAdapter.GetNATNetwork());
229#ifdef VBOX_WITH_CLOUD_NET
230 oldAdapterData.m_strCloudNetworkName = wipedOutString(comAdapter.GetCloudNetwork());
231#endif
232#ifdef VBOX_WITH_VMNET
233 oldAdapterData.m_strHostOnlyNetworkName = wipedOutString(comAdapter.GetHostOnlyNetwork());
234#endif
235 oldAdapterData.m_adapterType = comAdapter.GetAdapterType();
236 oldAdapterData.m_promiscuousMode = comAdapter.GetPromiscModePolicy();
237 oldAdapterData.m_strMACAddress = comAdapter.GetMACAddress();
238 oldAdapterData.m_strGenericProperties = loadGenericProperties(comAdapter);
239 oldAdapterData.m_fCableConnected = comAdapter.GetCableConnected();
240 foreach (const QString &strRedirect, comAdapter.GetNATEngine().GetRedirects())
241 {
242 /* Gather old data & cache key: */
243 const QStringList &forwardingData = strRedirect.split(',');
244 AssertMsg(forwardingData.size() == 6, ("Redirect rule should be composed of 6 parts!\n"));
245 const UIDataPortForwardingRule oldForwardingData(forwardingData.at(0),
246 (KNATProtocol)forwardingData.at(1).toUInt(),
247 forwardingData.at(2),
248 forwardingData.at(3).toUInt(),
249 forwardingData.at(4),
250 forwardingData.at(5).toUInt());
251 const QString &strForwardingKey = forwardingData.at(0);
252 /* Cache old data: */
253 m_pCache->child(iSlot).child(strForwardingKey).cacheInitialData(oldForwardingData);
254 }
255 }
256
257 /* Cache old data: */
258 m_pCache->child(iSlot).cacheInitialData(oldAdapterData);
259 }
260
261 /* Cache old data: */
262 m_pCache->cacheInitialData(oldNetworkData);
263
264 /* Upload machine to data: */
265 UISettingsPageMachine::uploadData(data);
266}
267
268void UIMachineSettingsNetwork::getFromCache()
269{
270 /* Sanity check: */
271 if ( !m_pCache
272 || !m_pTabWidget)
273 return;
274
275 /* Load old data from cache: */
276 for (int iSlot = 0; iSlot < m_pTabWidget->count(); ++iSlot)
277 getFromCache(iSlot, m_pCache->child(iSlot));
278
279 /* Apply language settings: */
280 retranslateUi();
281
282 /* Polish page finally: */
283 polishPage();
284
285 /* Revalidate: */
286 revalidate();
287}
288
289void UIMachineSettingsNetwork::putToCache()
290{
291 /* Sanity check: */
292 if ( !m_pCache
293 || !m_pTabWidget)
294 return;
295
296 /* Prepare new data: */
297 UIDataSettingsMachineNetwork newNetworkData;
298
299 /* Gather new data to cache: */
300 for (int iSlot = 0; iSlot < m_pTabWidget->count(); ++iSlot)
301 putToCache(iSlot, m_pCache->child(iSlot));
302
303 /* Cache new data: */
304 m_pCache->cacheCurrentData(newNetworkData);
305}
306
307void UIMachineSettingsNetwork::saveFromCacheTo(QVariant &data)
308{
309 /* Fetch data to machine: */
310 UISettingsPageMachine::fetchData(data);
311
312 /* Update data and failing state: */
313 setFailed(!saveData());
314
315 /* Upload machine to data: */
316 UISettingsPageMachine::uploadData(data);
317}
318
319bool UIMachineSettingsNetwork::validate(QList<UIValidationMessage> &messages)
320{
321 /* Sanity check: */
322 if (!m_pTabWidget)
323 return false;
324
325 /* Pass by default: */
326 bool fValid = true;
327
328 /* Delegate validation to particular tab-editor: */
329 for (int iSlot = 0; iSlot < m_pTabWidget->count(); ++iSlot)
330 if (!validate(iSlot, messages))
331 fValid = false;
332
333 /* Return result: */
334 return fValid;
335}
336
337void UIMachineSettingsNetwork::retranslateUi()
338{
339 /* Sanity check: */
340 if (!m_pTabWidget)
341 return;
342
343 for (int iSlot = 0; iSlot < m_pTabWidget->count(); ++iSlot)
344 {
345 m_pTabWidget->setTabText(iSlot, tabTitle(iSlot));
346 reloadAlternatives(iSlot);
347 }
348}
349
350void UIMachineSettingsNetwork::handleFilterChange()
351{
352 /* Show tabs from 2nd to 4th in expert mode only: */
353 if (m_pTabWidget)
354 for (int i = 1; i < m_pTabWidget->count(); ++i)
355 m_pTabWidget->setTabVisible(i, m_fInExpertMode);
356}
357
358void UIMachineSettingsNetwork::polishPage()
359{
360 /* Sanity check: */
361 if ( !m_pCache
362 || !m_pTabWidget)
363 return;
364
365 for (int iSlot = 0; iSlot < m_pTabWidget->count(); ++iSlot)
366 {
367 m_pTabWidget->setTabEnabled(iSlot,
368 isMachineOffline() ||
369 (isMachineInValidMode() &&
370 m_pCache->childCount() > iSlot &&
371 m_pCache->child(iSlot).base().m_fAdapterEnabled));
372 polishTab(iSlot);
373 }
374}
375
376void UIMachineSettingsNetwork::sltHandleAlternativeNameChange()
377{
378 /* Sanity check: */
379 if (!m_pTabWidget)
380 return;
381
382 /* Determine the sender tab-editor: */
383 UINetworkSettingsEditor *pSender = qobject_cast<UINetworkSettingsEditor*>(sender());
384 AssertPtrReturnVoid(pSender);
385
386 /* Determine the sender slot: */
387 const int iSenderSlot = m_tabEditors.indexOf(pSender);
388
389 /* Check if we need to update other adapter tabs if
390 * alternative name for certain type is changed: */
391 bool fUpdateOthers = false;
392 switch (attachmentType(iSenderSlot))
393 {
394 case KNetworkAttachmentType_Internal:
395 {
396 if (!pSender->valueName(attachmentType(iSenderSlot)).isNull())
397 {
398 refreshInternalNetworkList();
399 fUpdateOthers = true;
400 }
401 break;
402 }
403 case KNetworkAttachmentType_Generic:
404 {
405 if (!pSender->valueName(attachmentType(iSenderSlot)).isNull())
406 {
407 refreshGenericDriverList();
408 fUpdateOthers = true;
409 }
410 break;
411 }
412 default:
413 break;
414 }
415
416 /* Update alternatives for all the tabs besides the sender: */
417 if (fUpdateOthers)
418 for (int iSlot = 0; iSlot < m_pTabWidget->count(); ++iSlot)
419 if (iSlot != iSenderSlot)
420 reloadAlternatives(iSlot);
421
422 /* Revalidate full page: */
423 revalidate();
424}
425
426void UIMachineSettingsNetwork::prepare()
427{
428 /* Prepare cache: */
429 m_pCache = new UISettingsCacheMachineNetwork;
430 AssertPtrReturnVoid(m_pCache);
431
432 /* Prepare everything: */
433 prepareWidgets();
434
435 /* Apply language settings: */
436 retranslateUi();
437}
438
439void UIMachineSettingsNetwork::prepareWidgets()
440{
441 /* Prepare main layout: */
442 QVBoxLayout *pLayoutMain = new QVBoxLayout(this);
443 if (pLayoutMain)
444 {
445 /* Prepare tab-widget: */
446 m_pTabWidget = new QITabWidget(this);
447 if (m_pTabWidget)
448 {
449 /* How many adapters to display: */
450 /** @todo r=klaus this needs to be done based on the actual chipset type of the VM,
451 * but in this place the m_machine field isn't set yet. My observation (on Linux)
452 * is that the limitation to 4 isn't necessary any more, but this needs to be checked
453 * on all platforms to be certain that it's usable everywhere. */
454 const ulong uCount = qMin((ULONG)4, gpGlobalSession->virtualBox().GetPlatformProperties(KPlatformArchitecture_x86).GetMaxNetworkAdapters(KChipsetType_PIIX3));
455
456 /* Create corresponding adapter tabs: */
457 for (ulong uSlot = 0; uSlot < uCount; ++uSlot)
458 prepareTab();
459
460 pLayoutMain->addWidget(m_pTabWidget);
461 }
462 }
463}
464
465void UIMachineSettingsNetwork::prepareTab()
466{
467 /* Prepare tab: */
468 UIEditor *pTab = new UIEditor(m_pTabWidget);
469 if (pTab)
470 {
471 /* Prepare tab layout: */
472 QVBoxLayout *pLayout = new QVBoxLayout(pTab);
473 if (pLayout)
474 {
475#ifdef VBOX_WS_MAC
476 /* On Mac OS X we can do a bit of smoothness: */
477 int iLeft, iTop, iRight, iBottom;
478 pLayout->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom);
479 pLayout->setContentsMargins(iLeft / 2, iTop / 2, iRight / 2, iBottom / 2);
480#endif
481
482 /* Prepare settings editor: */
483 UINetworkSettingsEditor *pEditor = new UINetworkSettingsEditor(this);
484 if (pEditor)
485 {
486 m_tabEditors << pEditor;
487 prepareConnections(pEditor);
488 pTab->addEditor(pEditor);
489 pLayout->addWidget(pEditor);
490 }
491
492 pLayout->addStretch();
493 }
494
495 addEditor(pTab);
496 m_pTabWidget->addTab(pTab, QString());
497 }
498}
499
500void UIMachineSettingsNetwork::prepareConnections(UINetworkSettingsEditor *pTabEditor)
501{
502 /* Attachment connections: */
503 connect(pTabEditor, &UINetworkSettingsEditor::sigFeatureStateChanged,
504 this, &UIMachineSettingsNetwork::revalidate);
505 connect(pTabEditor, &UINetworkSettingsEditor::sigAttachmentTypeChanged,
506 this, &UIMachineSettingsNetwork::revalidate);
507 connect(pTabEditor, &UINetworkSettingsEditor::sigAlternativeNameChanged,
508 this, &UIMachineSettingsNetwork::sltHandleAlternativeNameChange);
509
510 /* Advanced connections: */
511 connect(pTabEditor, &UINetworkSettingsEditor::sigMACAddressChanged,
512 this, &UIMachineSettingsNetwork::revalidate);
513}
514
515void UIMachineSettingsNetwork::cleanup()
516{
517 /* Cleanup cache: */
518 delete m_pCache;
519 m_pCache = 0;
520}
521
522void UIMachineSettingsNetwork::polishTab(int iSlot)
523{
524 /* Acquire tab-editor: */
525 UINetworkSettingsEditor *pTabEditor = m_tabEditors.at(iSlot);
526 AssertPtrReturnVoid(pTabEditor);
527
528 /* General stuff: */
529 pTabEditor->setFeatureAvailable(isMachineOffline());
530
531 /* Attachment stuff: */
532 pTabEditor->setAttachmentOptionsAvailable(isMachineInValidMode());
533
534 /* Advanced stuff: */
535 pTabEditor->setAdapterOptionsAvailable(isMachineOffline());
536 pTabEditor->setPromiscuousOptionsAvailable( attachmentType(iSlot) != KNetworkAttachmentType_Null
537 && attachmentType(iSlot) != KNetworkAttachmentType_Generic
538 && attachmentType(iSlot) != KNetworkAttachmentType_NAT);
539 pTabEditor->setMACOptionsAvailable(isMachineOffline());
540 pTabEditor->setGenericPropertiesAvailable(attachmentType(iSlot) == KNetworkAttachmentType_Generic);
541 pTabEditor->setCableOptionsAvailable(isMachineInValidMode());
542 pTabEditor->setForwardingOptionsAvailable(attachmentType(iSlot) == KNetworkAttachmentType_NAT);
543}
544
545void UIMachineSettingsNetwork::getFromCache(int iSlot, const UISettingsCacheMachineNetworkAdapter &adapterCache)
546{
547 /* Acquire tab-editor: */
548 UINetworkSettingsEditor *pTabEditor = m_tabEditors.at(iSlot);
549 AssertPtrReturnVoid(pTabEditor);
550
551 /* Get old data: */
552 const UIDataSettingsMachineNetworkAdapter &oldAdapterData = adapterCache.base();
553
554 /* Load adapter activity state: */
555 pTabEditor->setFeatureEnabled(oldAdapterData.m_fAdapterEnabled);
556
557 /* Load attachment type: */
558 pTabEditor->setValueType(oldAdapterData.m_attachmentType);
559 /* Load alternative names: */
560 pTabEditor->setValueName(KNetworkAttachmentType_Bridged, wipedOutString(oldAdapterData.m_strBridgedAdapterName));
561 pTabEditor->setValueName(KNetworkAttachmentType_Internal, wipedOutString(oldAdapterData.m_strInternalNetworkName));
562 pTabEditor->setValueName(KNetworkAttachmentType_HostOnly, wipedOutString(oldAdapterData.m_strHostInterfaceName));
563 pTabEditor->setValueName(KNetworkAttachmentType_Generic, wipedOutString(oldAdapterData.m_strGenericDriverName));
564 pTabEditor->setValueName(KNetworkAttachmentType_NATNetwork, wipedOutString(oldAdapterData.m_strNATNetworkName));
565#ifdef VBOX_WITH_CLOUD_NET
566 pTabEditor->setValueName(KNetworkAttachmentType_Cloud, wipedOutString(oldAdapterData.m_strCloudNetworkName));
567#endif
568#ifdef VBOX_WITH_VMNET
569 pTabEditor->setValueName(KNetworkAttachmentType_HostOnlyNetwork, wipedOutString(oldAdapterData.m_strHostOnlyNetworkName));
570#endif
571
572 /* Load settings: */
573 pTabEditor->setAdapterType(oldAdapterData.m_adapterType);
574 pTabEditor->setPromiscuousMode(oldAdapterData.m_promiscuousMode);
575 pTabEditor->setMACAddress(oldAdapterData.m_strMACAddress);
576 pTabEditor->setGenericProperties(oldAdapterData.m_strGenericProperties);
577 pTabEditor->setCableConnected(oldAdapterData.m_fCableConnected);
578
579 /* Load port forwarding rules: */
580 UIPortForwardingDataList portForwardingRules;
581 for (int i = 0; i < adapterCache.childCount(); ++i)
582 portForwardingRules << adapterCache.child(i).base();
583 pTabEditor->setPortForwardingRules(portForwardingRules);
584
585 /* Reload alternatives: */
586 reloadAlternatives(iSlot);
587}
588
589void UIMachineSettingsNetwork::putToCache(int iSlot, UISettingsCacheMachineNetworkAdapter &adapterCache)
590{
591 /* Acquire tab-editor: */
592 UINetworkSettingsEditor *pTabEditor = m_tabEditors.at(iSlot);
593 AssertPtrReturnVoid(pTabEditor);
594
595 /* Prepare new data: */
596 UIDataSettingsMachineNetworkAdapter newAdapterData;
597
598 /* Save slot number: */
599 newAdapterData.m_iSlot = iSlot;
600
601 /* Save adapter activity state: */
602 newAdapterData.m_fAdapterEnabled = pTabEditor->isFeatureEnabled();
603
604 /* Save attachment type & alternative name: */
605 newAdapterData.m_attachmentType = attachmentType(iSlot);
606 newAdapterData.m_strBridgedAdapterName = pTabEditor->valueName(KNetworkAttachmentType_Bridged);
607 newAdapterData.m_strInternalNetworkName = pTabEditor->valueName(KNetworkAttachmentType_Internal);
608 newAdapterData.m_strHostInterfaceName = pTabEditor->valueName(KNetworkAttachmentType_HostOnly);
609 newAdapterData.m_strGenericDriverName = pTabEditor->valueName(KNetworkAttachmentType_Generic);
610 newAdapterData.m_strNATNetworkName = pTabEditor->valueName(KNetworkAttachmentType_NATNetwork);
611#ifdef VBOX_WITH_CLOUD_NET
612 newAdapterData.m_strCloudNetworkName = pTabEditor->valueName(KNetworkAttachmentType_Cloud);
613#endif
614#ifdef VBOX_WITH_VMNET
615 newAdapterData.m_strHostOnlyNetworkName = pTabEditor->valueName(KNetworkAttachmentType_HostOnlyNetwork);
616#endif
617
618 /* Save settings: */
619 newAdapterData.m_adapterType = pTabEditor->adapterType();
620 newAdapterData.m_promiscuousMode = pTabEditor->promiscuousMode();
621 newAdapterData.m_strMACAddress = pTabEditor->macAddress();
622 newAdapterData.m_strGenericProperties = pTabEditor->genericProperties();
623 newAdapterData.m_fCableConnected = pTabEditor->cableConnected();
624
625 /* Save port forwarding rules: */
626 foreach (const UIDataPortForwardingRule &rule, pTabEditor->portForwardingRules())
627 adapterCache.child(rule.name).cacheCurrentData(rule);
628
629 /* Cache new data: */
630 adapterCache.cacheCurrentData(newAdapterData);
631}
632
633void UIMachineSettingsNetwork::reloadAlternatives(int iSlot)
634{
635 /* Acquire tab-editor: */
636 UINetworkSettingsEditor *pTabEditor = m_tabEditors.at(iSlot);
637 AssertPtrReturnVoid(pTabEditor);
638
639 pTabEditor->setValueNames(KNetworkAttachmentType_Bridged, bridgedAdapterList());
640 pTabEditor->setValueNames(KNetworkAttachmentType_Internal, internalNetworkList());
641 pTabEditor->setValueNames(KNetworkAttachmentType_HostOnly, hostInterfaceList());
642 pTabEditor->setValueNames(KNetworkAttachmentType_Generic, genericDriverList());
643 pTabEditor->setValueNames(KNetworkAttachmentType_NATNetwork, natNetworkList());
644#ifdef VBOX_WITH_CLOUD_NET
645 pTabEditor->setValueNames(KNetworkAttachmentType_Cloud, cloudNetworkList());
646#endif
647#ifdef VBOX_WITH_VMNET
648 pTabEditor->setValueNames(KNetworkAttachmentType_HostOnlyNetwork, hostOnlyNetworkList());
649#endif
650}
651
652KNetworkAttachmentType UIMachineSettingsNetwork::attachmentType(int iSlot) const
653{
654 /* Acquire tab-editor: */
655 UINetworkSettingsEditor *pTabEditor = m_tabEditors.at(iSlot);
656 AssertPtrReturn(pTabEditor, KNetworkAttachmentType_Null);
657 return pTabEditor->valueType();
658}
659
660QString UIMachineSettingsNetwork::alternativeName(int iSlot,
661 KNetworkAttachmentType enmType /* = KNetworkAttachmentType_Null */) const
662{
663 /* Acquire tab-editor: */
664 UINetworkSettingsEditor *pTabEditor = m_tabEditors.at(iSlot);
665 AssertPtrReturn(pTabEditor, QString());
666 if (enmType == KNetworkAttachmentType_Null)
667 enmType = attachmentType(iSlot);
668 return pTabEditor->valueName(enmType);
669}
670
671bool UIMachineSettingsNetwork::validate(int iSlot, QList<UIValidationMessage> &messages)
672{
673 /* Acquire tab-editor: */
674 UINetworkSettingsEditor *pTabEditor = m_tabEditors.at(iSlot);
675 AssertPtrReturn(pTabEditor, false);
676
677 /* Pass by default: */
678 bool fPass = true;
679
680 /* Prepare message: */
681 UIValidationMessage message;
682 message.first = UITranslator::removeAccelMark(tabTitle(iSlot));
683
684 /* Validate enabled adapter only: */
685 if (pTabEditor->isFeatureEnabled())
686 {
687 /* Validate alternatives: */
688 switch (attachmentType(iSlot))
689 {
690 case KNetworkAttachmentType_Bridged:
691 {
692 if (alternativeName(iSlot).isNull())
693 {
694 message.second << tr("No bridged network adapter is currently selected.");
695 fPass = false;
696 }
697 break;
698 }
699 case KNetworkAttachmentType_Internal:
700 {
701 if (alternativeName(iSlot).isNull())
702 {
703 message.second << tr("No internal network name is currently specified.");
704 fPass = false;
705 }
706 break;
707 }
708#ifndef VBOX_WITH_VMNET
709 case KNetworkAttachmentType_HostOnly:
710 {
711 if (alternativeName(iSlot).isNull())
712 {
713 message.second << tr("No host-only network adapter is currently selected.");
714 fPass = false;
715 }
716 break;
717 }
718#else /* VBOX_WITH_VMNET */
719 case KNetworkAttachmentType_HostOnly:
720 {
721 message.second << tr("Host-only adapters are no longer supported, use host-only networks instead.");
722 fPass = false;
723 break;
724 }
725#endif /* VBOX_WITH_VMNET */
726 case KNetworkAttachmentType_Generic:
727 {
728 if (alternativeName(iSlot).isNull())
729 {
730 message.second << tr("No generic driver is currently selected.");
731 fPass = false;
732 }
733 break;
734 }
735 case KNetworkAttachmentType_NATNetwork:
736 {
737 if (alternativeName(iSlot).isNull())
738 {
739 message.second << tr("No NAT network name is currently specified.");
740 fPass = false;
741 }
742 break;
743 }
744#ifdef VBOX_WITH_CLOUD_NET
745 case KNetworkAttachmentType_Cloud:
746 {
747 if (alternativeName(iSlot).isNull())
748 {
749 message.second << tr("No cloud network name is currently specified.");
750 fPass = false;
751 }
752 break;
753 }
754#endif /* VBOX_WITH_CLOUD_NET */
755#ifdef VBOX_WITH_VMNET
756 case KNetworkAttachmentType_HostOnlyNetwork:
757 {
758 if (alternativeName(iSlot).isNull())
759 {
760 message.second << tr("No host-only network name is currently specified.");
761 fPass = false;
762 }
763 break;
764 }
765#endif /* VBOX_WITH_VMNET */
766 default:
767 break;
768 }
769
770 /* Validate MAC-address length: */
771 if (pTabEditor->macAddress().size() < 12)
772 {
773 message.second << tr("The MAC address must be 12 hexadecimal digits long.");
774 fPass = false;
775 }
776
777 /* Make sure MAC-address is unicast: */
778 if (pTabEditor->macAddress().size() >= 2)
779 {
780 if (pTabEditor->macAddress().indexOf(QRegularExpression("^[0-9A-Fa-f][02468ACEace]")) != 0)
781 {
782 message.second << tr("The second digit in the MAC address may not be odd as only unicast addresses are allowed.");
783 fPass = false;
784 }
785 }
786 }
787
788 /* Serialize message: */
789 if (!message.second.isEmpty())
790 messages << message;
791
792 /* Return result: */
793 return fPass;
794}
795
796void UIMachineSettingsNetwork::refreshBridgedAdapterList()
797{
798 /* Reload bridged adapters: */
799 m_bridgedAdapterList = UINetworkAttachmentEditor::bridgedAdapters();
800}
801
802void UIMachineSettingsNetwork::refreshInternalNetworkList(bool fFullRefresh /* = false */)
803{
804 /* Sanity check: */
805 if (!m_pTabWidget)
806 return;
807
808 /* Reload internal network list: */
809 m_internalNetworkList.clear();
810 /* Get internal network names from other VMs: */
811 if (fFullRefresh)
812 m_internalNetworkListSaved = UINetworkAttachmentEditor::internalNetworks();
813 m_internalNetworkList << m_internalNetworkListSaved;
814 /* Append internal network list with names from all the tabs: */
815 for (int iSlot = 0; iSlot < m_pTabWidget->count(); ++iSlot)
816 {
817 const QString strName = alternativeName(iSlot, KNetworkAttachmentType_Internal);
818 if (!strName.isEmpty() && !m_internalNetworkList.contains(strName))
819 m_internalNetworkList << strName;
820 }
821}
822
823#ifdef VBOX_WITH_CLOUD_NET
824void UIMachineSettingsNetwork::refreshCloudNetworkList()
825{
826 /* Reload cloud network list: */
827 m_cloudNetworkList = UINetworkAttachmentEditor::cloudNetworks();
828}
829#endif /* VBOX_WITH_CLOUD_NET */
830
831#ifdef VBOX_WITH_VMNET
832void UIMachineSettingsNetwork::refreshHostOnlyNetworkList()
833{
834 /* Reload host-only network list: */
835 m_hostOnlyNetworkList = UINetworkAttachmentEditor::hostOnlyNetworks();
836}
837#endif /* VBOX_WITH_VMNET */
838
839void UIMachineSettingsNetwork::refreshHostInterfaceList()
840{
841 /* Reload host interfaces: */
842 m_hostInterfaceList = UINetworkAttachmentEditor::hostInterfaces();
843}
844
845void UIMachineSettingsNetwork::refreshGenericDriverList(bool fFullRefresh /* = false */)
846{
847 /* Sanity check: */
848 if (!m_pTabWidget)
849 return;
850
851 /* Load generic driver list: */
852 m_genericDriverList.clear();
853 /* Get generic driver names from other VMs: */
854 if (fFullRefresh)
855 m_genericDriverListSaved = UINetworkAttachmentEditor::genericDrivers();
856 m_genericDriverList << m_genericDriverListSaved;
857 /* Append generic driver list with names from all the tabs: */
858 for (int iSlot = 0; iSlot < m_pTabWidget->count(); ++iSlot)
859 {
860 const QString strName = alternativeName(iSlot, KNetworkAttachmentType_Generic);
861 if (!strName.isEmpty() && !m_genericDriverList.contains(strName))
862 m_genericDriverList << strName;
863 }
864}
865
866void UIMachineSettingsNetwork::refreshNATNetworkList()
867{
868 /* Reload nat networks: */
869 m_natNetworkList = UINetworkAttachmentEditor::natNetworks();
870}
871
872/* static */
873QString UIMachineSettingsNetwork::tabTitle(int iSlot)
874{
875 return QApplication::translate("UICommon", "Adapter %1").arg(QString("&%1").arg(iSlot + 1));
876}
877
878/* static */
879QString UIMachineSettingsNetwork::loadGenericProperties(const CNetworkAdapter &adapter)
880{
881 /* Prepare formatted string: */
882 QVector<QString> names;
883 QVector<QString> props;
884 props = adapter.GetProperties(QString(), names);
885 QString strResult;
886 /* Load generic properties: */
887 for (int i = 0; i < names.size(); ++i)
888 {
889 strResult += names[i] + "=" + props[i];
890 if (i < names.size() - 1)
891 strResult += "\n";
892 }
893 /* Return formatted string: */
894 return strResult;
895}
896
897/* static */
898bool UIMachineSettingsNetwork::saveGenericProperties(CNetworkAdapter &comAdapter, const QString &strProperties)
899{
900 /* Prepare result: */
901 bool fSuccess = true;
902 /* Save generic properties: */
903 if (fSuccess)
904 {
905 /* Acquire 'added' properties: */
906 const QStringList newProps = strProperties.split("\n");
907
908 /* Insert 'added' properties: */
909 QHash<QString, QString> hash;
910 for (int i = 0; fSuccess && i < newProps.size(); ++i)
911 {
912 /* Parse property line: */
913 const QString strLine = newProps.at(i);
914 const QString strKey = strLine.section('=', 0, 0);
915 const QString strVal = strLine.section('=', 1, -1);
916 if (strKey.isEmpty() || strVal.isEmpty())
917 continue;
918 /* Save property in the adapter and the hash: */
919 comAdapter.SetProperty(strKey, strVal);
920 fSuccess = comAdapter.isOk();
921 hash[strKey] = strVal;
922 }
923
924 /* Acquire actual properties ('added' and 'removed'): */
925 QVector<QString> names;
926 QVector<QString> props;
927 if (fSuccess)
928 {
929 props = comAdapter.GetProperties(QString(), names);
930 fSuccess = comAdapter.isOk();
931 }
932
933 /* Exclude 'removed' properties: */
934 for (int i = 0; fSuccess && i < names.size(); ++i)
935 {
936 /* Get property name and value: */
937 const QString strKey = names.at(i);
938 const QString strVal = props.at(i);
939 if (strVal == hash.value(strKey))
940 continue;
941 /* Remove property from the adapter: */
942 // Actually we are _replacing_ property value,
943 // not _removing_ it at all, but we are replacing it
944 // with default constructed value, which is QString().
945 comAdapter.SetProperty(strKey, hash.value(strKey));
946 fSuccess = comAdapter.isOk();
947 }
948 }
949 /* Return result: */
950 return fSuccess;
951}
952
953bool UIMachineSettingsNetwork::saveData()
954{
955 /* Sanity check: */
956 if ( !m_pCache
957 || !m_pTabWidget)
958 return false;
959
960 /* Prepare result: */
961 bool fSuccess = true;
962 /* Save network settings from cache: */
963 if (fSuccess && isMachineInValidMode() && m_pCache->wasChanged())
964 {
965 /* For each adapter: */
966 for (int iSlot = 0; fSuccess && iSlot < m_pTabWidget->count(); ++iSlot)
967 fSuccess = saveAdapterData(iSlot);
968 }
969 /* Return result: */
970 return fSuccess;
971}
972
973bool UIMachineSettingsNetwork::saveAdapterData(int iSlot)
974{
975 /* Sanity check: */
976 if (!m_pCache)
977 return false;
978
979 /* Prepare result: */
980 bool fSuccess = true;
981 /* Save adapter settings from cache: */
982 if (fSuccess && m_pCache->child(iSlot).wasChanged())
983 {
984 /* Get old data from cache: */
985 const UIDataSettingsMachineNetworkAdapter &oldAdapterData = m_pCache->child(iSlot).base();
986 /* Get new data from cache: */
987 const UIDataSettingsMachineNetworkAdapter &newAdapterData = m_pCache->child(iSlot).data();
988
989 /* Get network adapter for further activities: */
990 CNetworkAdapter comAdapter = m_machine.GetNetworkAdapter(iSlot);
991 fSuccess = m_machine.isOk() && comAdapter.isNotNull();
992
993 /* Show error message if necessary: */
994 if (!fSuccess)
995 notifyOperationProgressError(UIErrorString::formatErrorInfo(m_machine));
996 else
997 {
998 /* Save whether the adapter is enabled: */
999 if (fSuccess && isMachineOffline() && newAdapterData.m_fAdapterEnabled != oldAdapterData.m_fAdapterEnabled)
1000 {
1001 comAdapter.SetEnabled(newAdapterData.m_fAdapterEnabled);
1002 fSuccess = comAdapter.isOk();
1003 }
1004 /* Save adapter type: */
1005 if (fSuccess && isMachineOffline() && newAdapterData.m_adapterType != oldAdapterData.m_adapterType)
1006 {
1007 comAdapter.SetAdapterType(newAdapterData.m_adapterType);
1008 fSuccess = comAdapter.isOk();
1009 }
1010 /* Save adapter MAC address: */
1011 if (fSuccess && isMachineOffline() && newAdapterData.m_strMACAddress != oldAdapterData.m_strMACAddress)
1012 {
1013 comAdapter.SetMACAddress(newAdapterData.m_strMACAddress);
1014 fSuccess = comAdapter.isOk();
1015 }
1016 /* Save adapter attachment type: */
1017 switch (newAdapterData.m_attachmentType)
1018 {
1019 case KNetworkAttachmentType_Bridged:
1020 {
1021 if (fSuccess && newAdapterData.m_strBridgedAdapterName != oldAdapterData.m_strBridgedAdapterName)
1022 {
1023 comAdapter.SetBridgedInterface(newAdapterData.m_strBridgedAdapterName);
1024 fSuccess = comAdapter.isOk();
1025 }
1026 break;
1027 }
1028 case KNetworkAttachmentType_Internal:
1029 {
1030 if (fSuccess && newAdapterData.m_strInternalNetworkName != oldAdapterData.m_strInternalNetworkName)
1031 {
1032 comAdapter.SetInternalNetwork(newAdapterData.m_strInternalNetworkName);
1033 fSuccess = comAdapter.isOk();
1034 }
1035 break;
1036 }
1037 case KNetworkAttachmentType_HostOnly:
1038 {
1039 if (fSuccess && newAdapterData.m_strHostInterfaceName != oldAdapterData.m_strHostInterfaceName)
1040 {
1041 comAdapter.SetHostOnlyInterface(newAdapterData.m_strHostInterfaceName);
1042 fSuccess = comAdapter.isOk();
1043 }
1044 break;
1045 }
1046 case KNetworkAttachmentType_Generic:
1047 {
1048 if (fSuccess && newAdapterData.m_strGenericDriverName != oldAdapterData.m_strGenericDriverName)
1049 {
1050 comAdapter.SetGenericDriver(newAdapterData.m_strGenericDriverName);
1051 fSuccess = comAdapter.isOk();
1052 }
1053 if (fSuccess && newAdapterData.m_strGenericProperties != oldAdapterData.m_strGenericProperties)
1054 fSuccess = saveGenericProperties(comAdapter, newAdapterData.m_strGenericProperties);
1055 break;
1056 }
1057 case KNetworkAttachmentType_NATNetwork:
1058 {
1059 if (fSuccess && newAdapterData.m_strNATNetworkName != oldAdapterData.m_strNATNetworkName)
1060 {
1061 comAdapter.SetNATNetwork(newAdapterData.m_strNATNetworkName);
1062 fSuccess = comAdapter.isOk();
1063 }
1064 break;
1065 }
1066#ifdef VBOX_WITH_CLOUD_NET
1067 case KNetworkAttachmentType_Cloud:
1068 {
1069 if (fSuccess && newAdapterData.m_strCloudNetworkName != oldAdapterData.m_strCloudNetworkName)
1070 {
1071 comAdapter.SetCloudNetwork(newAdapterData.m_strCloudNetworkName);
1072 fSuccess = comAdapter.isOk();
1073 }
1074 break;
1075 }
1076#endif /* VBOX_WITH_CLOUD_NET */
1077#ifdef VBOX_WITH_VMNET
1078 case KNetworkAttachmentType_HostOnlyNetwork:
1079 {
1080 if (fSuccess && newAdapterData.m_strHostOnlyNetworkName != oldAdapterData.m_strHostOnlyNetworkName)
1081 {
1082 comAdapter.SetHostOnlyNetwork(newAdapterData.m_strHostOnlyNetworkName);
1083 fSuccess = comAdapter.isOk();
1084 }
1085 break;
1086 }
1087#endif /* VBOX_WITH_VMNET */
1088 default:
1089 break;
1090 }
1091 if (fSuccess && newAdapterData.m_attachmentType != oldAdapterData.m_attachmentType)
1092 {
1093 comAdapter.SetAttachmentType(newAdapterData.m_attachmentType);
1094 fSuccess = comAdapter.isOk();
1095 }
1096 /* Save adapter promiscuous mode: */
1097 if (fSuccess && newAdapterData.m_promiscuousMode != oldAdapterData.m_promiscuousMode)
1098 {
1099 comAdapter.SetPromiscModePolicy(newAdapterData.m_promiscuousMode);
1100 fSuccess = comAdapter.isOk();
1101 }
1102 /* Save whether the adapter cable connected: */
1103 if (fSuccess && newAdapterData.m_fCableConnected != oldAdapterData.m_fCableConnected)
1104 {
1105 comAdapter.SetCableConnected(newAdapterData.m_fCableConnected);
1106 fSuccess = comAdapter.isOk();
1107 }
1108
1109 /* Get NAT engine for further activities: */
1110 CNATEngine comEngine;
1111 if (fSuccess)
1112 {
1113 comEngine = comAdapter.GetNATEngine();
1114 fSuccess = comAdapter.isOk() && comEngine.isNotNull();
1115 }
1116
1117 /* Show error message if necessary: */
1118 if (!fSuccess)
1119 notifyOperationProgressError(UIErrorString::formatErrorInfo(comAdapter));
1120 else
1121 {
1122 /* Save adapter port forwarding rules: */
1123 if ( oldAdapterData.m_attachmentType == KNetworkAttachmentType_NAT
1124 || newAdapterData.m_attachmentType == KNetworkAttachmentType_NAT)
1125 {
1126 /* For each rule: */
1127 for (int iRule = 0; fSuccess && iRule < m_pCache->child(iSlot).childCount(); ++iRule)
1128 {
1129 /* Get rule cache: */
1130 const UISettingsCachePortForwardingRule &ruleCache = m_pCache->child(iSlot).child(iRule);
1131
1132 /* Remove rule marked for 'remove' or 'update': */
1133 if (ruleCache.wasRemoved() || ruleCache.wasUpdated())
1134 {
1135 comEngine.RemoveRedirect(ruleCache.base().name);
1136 fSuccess = comEngine.isOk();
1137 }
1138 }
1139 for (int iRule = 0; fSuccess && iRule < m_pCache->child(iSlot).childCount(); ++iRule)
1140 {
1141 /* Get rule cache: */
1142 const UISettingsCachePortForwardingRule &ruleCache = m_pCache->child(iSlot).child(iRule);
1143
1144 /* Create rule marked for 'create' or 'update': */
1145 if (ruleCache.wasCreated() || ruleCache.wasUpdated())
1146 {
1147 comEngine.AddRedirect(ruleCache.data().name, ruleCache.data().protocol,
1148 ruleCache.data().hostIp, ruleCache.data().hostPort.value(),
1149 ruleCache.data().guestIp, ruleCache.data().guestPort.value());
1150 fSuccess = comEngine.isOk();
1151 }
1152 }
1153
1154 /* Show error message if necessary: */
1155 if (!fSuccess)
1156 notifyOperationProgressError(UIErrorString::formatErrorInfo(comEngine));
1157 }
1158 }
1159 }
1160 }
1161 /* Return result: */
1162 return fSuccess;
1163}
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