VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp

Last change on this file was 106061, checked in by vboxsync, 8 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.1 KB
Line 
1/* $Id: VBoxNetBaseService.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBoxNetBaseService - common services for VBoxNetDHCP and VBoxNetNAT.
4 */
5
6/*
7 * Copyright (C) 2009-2024 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
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_NET_SERVICE
33
34#include <VBox/com/com.h>
35#include <VBox/com/listeners.h>
36#include <VBox/com/string.h>
37#include <VBox/com/Guid.h>
38#include <VBox/com/array.h>
39#include <VBox/com/ErrorInfo.h>
40#include <VBox/com/errorprint.h>
41#include <VBox/com/VirtualBox.h>
42#include <VBox/com/NativeEventQueue.h>
43
44#include <iprt/alloca.h>
45#include <iprt/buildconfig.h>
46#include <iprt/err.h>
47#include <iprt/net.h> /* must come before getopt.h. */
48#include <iprt/getopt.h>
49#include <iprt/initterm.h>
50#include <iprt/param.h>
51#include <iprt/path.h>
52#include <iprt/process.h>
53#include <iprt/stream.h>
54#include <iprt/string.h>
55#include <iprt/time.h>
56#include <iprt/thread.h>
57#include <iprt/mem.h>
58#include <iprt/message.h>
59
60#include <VBox/sup.h>
61#include <VBox/intnet.h>
62#include <VBox/intnetinline.h>
63#include <VBox/vmm/vmm.h>
64#include <VBox/version.h>
65
66#include <vector>
67#include <iprt/sanitized/string>
68
69#include <VBox/err.h>
70#include <VBox/log.h>
71
72#include "VBoxNetLib.h"
73#include "VBoxNetBaseService.h"
74
75#ifdef RT_OS_WINDOWS /* WinMain */
76# include <iprt/win/windows.h>
77# include <stdlib.h>
78#endif
79
80
81/*********************************************************************************************************************************
82* Structures and Typedefs *
83*********************************************************************************************************************************/
84struct VBoxNetBaseService::Data
85{
86 Data(const std::string& aServiceName, const std::string& aNetworkName):
87 m_ServiceName(aServiceName),
88 m_NetworkName(aNetworkName),
89 m_enmTrunkType(kIntNetTrunkType_WhateverNone),
90 m_pSession(NIL_RTR0PTR),
91 m_cbSendBuf(128 * _1K),
92 m_cbRecvBuf(256 * _1K),
93 m_hIf(INTNET_HANDLE_INVALID),
94 m_pIfBuf(NULL),
95 m_cVerbosity(0),
96 m_fNeedMain(false),
97 m_EventQ(NULL),
98 m_hThrRecv(NIL_RTTHREAD),
99 fShutdown(false)
100 {
101 int rc = RTCritSectInit(&m_csThis);
102 AssertRC(rc);
103 };
104
105 std::string m_ServiceName;
106 std::string m_NetworkName;
107 std::string m_TrunkName;
108 INTNETTRUNKTYPE m_enmTrunkType;
109
110 RTMAC m_MacAddress;
111 RTNETADDRIPV4 m_Ipv4Address;
112 RTNETADDRIPV4 m_Ipv4Netmask;
113
114 PSUPDRVSESSION m_pSession;
115 uint32_t m_cbSendBuf;
116 uint32_t m_cbRecvBuf;
117 INTNETIFHANDLE m_hIf; /**< The handle to the network interface. */
118 PINTNETBUF m_pIfBuf; /**< Interface buffer. */
119
120 std::vector<PCRTGETOPTDEF> m_vecOptionDefs;
121
122 int32_t m_cVerbosity;
123
124 /* cs for syncing */
125 RTCRITSECT m_csThis;
126
127 /* Controls whether service will connect SVC for runtime needs */
128 bool m_fNeedMain;
129 /* Event Queue */
130 com::NativeEventQueue *m_EventQ;
131
132 /** receiving thread, used only if main is used */
133 RTTHREAD m_hThrRecv;
134
135 bool fShutdown;
136 static DECLCALLBACK(int) recvLoop(RTTHREAD, void *);
137};
138
139
140/*********************************************************************************************************************************
141* Global Variables *
142*********************************************************************************************************************************/
143/* Commonly used options for network configuration */
144static RTGETOPTDEF g_aGetOptDef[] =
145{
146 { "--name", 'N', RTGETOPT_REQ_STRING },
147 { "--network", 'n', RTGETOPT_REQ_STRING },
148 { "--trunk-name", 't', RTGETOPT_REQ_STRING },
149 { "--trunk-type", 'T', RTGETOPT_REQ_STRING },
150 { "--mac-address", 'a', RTGETOPT_REQ_MACADDR },
151 { "--ip-address", 'i', RTGETOPT_REQ_IPV4ADDR },
152 { "--netmask", 'm', RTGETOPT_REQ_IPV4ADDR },
153 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
154 { "--need-main", 'M', RTGETOPT_REQ_BOOL },
155};
156
157
158DECLCALLBACK(int) VBoxNetBaseService::Data::recvLoop(RTTHREAD, void *pvUser)
159{
160 VBoxNetBaseService *pThis = static_cast<VBoxNetBaseService *>(pvUser);
161
162 HRESULT hrc = com::Initialize();
163 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
164
165 pThis->doReceiveLoop();
166
167 return VINF_SUCCESS;
168}
169
170
171VBoxNetBaseService::VBoxNetBaseService(const std::string& aName, const std::string& aNetworkName):m(NULL)
172{
173 m = new VBoxNetBaseService::Data(aName, aNetworkName);
174
175 for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
176 m->m_vecOptionDefs.push_back(&g_aGetOptDef[i]);
177}
178
179
180VBoxNetBaseService::~VBoxNetBaseService()
181{
182 /*
183 * Close the interface connection.
184 */
185 if (m)
186 {
187 shutdown();
188 if (m->m_hIf != INTNET_HANDLE_INVALID)
189 {
190 INTNETIFCLOSEREQ CloseReq;
191 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
192 CloseReq.Hdr.cbReq = sizeof(CloseReq);
193 CloseReq.pSession = m->m_pSession;
194 CloseReq.hIf = m->m_hIf;
195 m->m_hIf = INTNET_HANDLE_INVALID;
196 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_CLOSE, 0, &CloseReq.Hdr);
197 AssertRC(rc);
198 }
199
200 if (m->m_pSession != NIL_RTR0PTR)
201 {
202 SUPR3Term(false /*fForced*/);
203 m->m_pSession = NIL_RTR0PTR;
204 }
205
206 RTCritSectDelete(&m->m_csThis);
207
208 delete m;
209 m = NULL;
210 }
211}
212
213
214int VBoxNetBaseService::init()
215{
216 if (isMainNeeded())
217 {
218 HRESULT hrc = com::Initialize();
219 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
220
221 hrc = virtualboxClient.createInprocObject(CLSID_VirtualBoxClient);
222 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
223
224 hrc = virtualboxClient->COMGETTER(VirtualBox)(virtualbox.asOutParam());
225 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
226 }
227
228 return VINF_SUCCESS;
229}
230
231
232bool VBoxNetBaseService::isMainNeeded() const
233{
234 return m->m_fNeedMain;
235}
236
237
238int VBoxNetBaseService::run()
239{
240 /**
241 * If the child class needs Main we start the receving thread which calls
242 * doReceiveLoop and enter to event polling loop. For other clients we do
243 * receiving on the current (main) thread.
244 */
245 if (isMainNeeded())
246 return startReceiveThreadAndEnterEventLoop();
247
248 doReceiveLoop();
249 return VINF_SUCCESS;
250}
251
252/**
253 * Parse the arguments.
254 *
255 * @returns 0 on success, fully bitched exit code on failure.
256 *
257 * @param argc Argument count.
258 * @param argv Argument vector.
259 *
260 * @todo r=bird: The --help and --version options shall not return a
261 * non-zero exit code. So, this method need to grow some
262 * complexity. I'm to blame for that blunder :/
263 */
264int VBoxNetBaseService::parseArgs(int argc, char **argv)
265{
266
267 RTGETOPTSTATE State;
268 PRTGETOPTDEF paOptionArray = getOptionsPtr();
269 int rc = RTGetOptInit(&State, argc, argv, paOptionArray, m->m_vecOptionDefs.size(), 0, 0 /*fFlags*/);
270 AssertRCReturn(rc, 49);
271#if 0
272 /* default initialization */
273 m_enmTrunkType = kIntNetTrunkType_WhateverNone;
274#endif
275 Log2(("BaseService: parseArgs enter\n"));
276
277 for (;;)
278 {
279 RTGETOPTUNION Val;
280 rc = RTGetOpt(&State, &Val);
281 if (!rc)
282 break;
283 switch (rc)
284 {
285 case 'N': // --name
286 m->m_ServiceName = Val.psz;
287 break;
288
289 case 'n': // --network
290 m->m_NetworkName = Val.psz;
291 break;
292
293 case 't': //--trunk-name
294 m->m_TrunkName = Val.psz;
295 break;
296
297 case 'T': //--trunk-type
298 if (!strcmp(Val.psz, "none"))
299 m->m_enmTrunkType = kIntNetTrunkType_None;
300 else if (!strcmp(Val.psz, "whatever"))
301 m->m_enmTrunkType = kIntNetTrunkType_WhateverNone;
302 else if (!strcmp(Val.psz, "netflt"))
303 m->m_enmTrunkType = kIntNetTrunkType_NetFlt;
304 else if (!strcmp(Val.psz, "netadp"))
305 m->m_enmTrunkType = kIntNetTrunkType_NetAdp;
306 else if (!strcmp(Val.psz, "srvnat"))
307 m->m_enmTrunkType = kIntNetTrunkType_SrvNat;
308 else
309 {
310 RTStrmPrintf(g_pStdErr, "Invalid trunk type '%s'\n", Val.psz);
311 return RTEXITCODE_SYNTAX;
312 }
313 break;
314
315 case 'a': // --mac-address
316 m->m_MacAddress = Val.MacAddr;
317 break;
318
319 case 'i': // --ip-address
320 m->m_Ipv4Address = Val.IPv4Addr;
321 break;
322
323 case 'm': // --netmask
324 m->m_Ipv4Netmask = Val.IPv4Addr;
325 break;
326
327 case 'v': // --verbose
328 m->m_cVerbosity++;
329 break;
330
331 case 'V': // --version (missed)
332 RTPrintf("%sr%u\n", RTBldCfgVersion(), RTBldCfgRevision());
333 return 1; /** @todo this exit code is wrong, of course. :/ */
334
335 case 'M': // --need-main
336 m->m_fNeedMain = true;
337 break;
338
339 case 'h': // --help (missed)
340 RTPrintf("%s Version %sr%u\n"
341 "Copyright (C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
342 "\n"
343 "Usage: %s <options>\n"
344 "\n"
345 "Options:\n",
346 RTProcShortName(),
347 RTBldCfgVersion(),
348 RTBldCfgRevision(),
349 RTProcShortName());
350 for (unsigned int i = 0; i < m->m_vecOptionDefs.size(); i++)
351 RTPrintf(" -%c, %s\n", m->m_vecOptionDefs[i]->iShort, m->m_vecOptionDefs[i]->pszLong);
352 usage(); /* to print Service Specific usage */
353 return 1; /** @todo this exit code is wrong, of course. :/ */
354
355 default:
356 {
357 int rc1 = parseOpt(rc, Val);
358 if (RT_FAILURE(rc1))
359 {
360 RTEXITCODE rcExit = RTGetOptPrintError(rc, &Val);
361 RTPrintf("Use --help for more information.\n");
362 return rcExit;
363 }
364 break;
365 }
366 }
367 }
368
369 RTMemFree(paOptionArray);
370 return RTEXITCODE_SUCCESS;
371}
372
373
374int VBoxNetBaseService::tryGoOnline(void)
375{
376 /*
377 * Open the session, load ring-0 and issue the request.
378 */
379 int rc = SUPR3Init(&m->m_pSession);
380 if (RT_FAILURE(rc))
381 {
382 m->m_pSession = NIL_RTR0PTR;
383 LogRel(("VBoxNetBaseService: SUPR3Init -> %Rrc\n", rc));
384 return rc;
385 }
386
387 char szPath[RTPATH_MAX];
388 rc = RTPathExecDir(szPath, sizeof(szPath) - sizeof("/VMMR0.r0"));
389 if (RT_FAILURE(rc))
390 {
391 LogRel(("VBoxNetBaseService: RTPathExecDir -> %Rrc\n", rc));
392 return rc;
393 }
394
395 rc = SUPR3LoadVMM(strcat(szPath, "/VMMR0.r0"), NULL);
396 if (RT_FAILURE(rc))
397 {
398 LogRel(("VBoxNetBaseService: SUPR3LoadVMM(\"%s\") -> %Rrc\n", szPath, rc));
399 return rc;
400 }
401
402 /*
403 * Create the open request.
404 */
405 PINTNETBUF pBuf;
406 INTNETOPENREQ OpenReq;
407 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
408 OpenReq.Hdr.cbReq = sizeof(OpenReq);
409 OpenReq.pSession = m->m_pSession;
410 RTStrCopy(OpenReq.szNetwork, sizeof(OpenReq.szNetwork), m->m_NetworkName.c_str());
411 OpenReq.szNetwork[sizeof(OpenReq.szNetwork) - 1] = '\0';
412 RTStrCopy(OpenReq.szTrunk, sizeof(OpenReq.szTrunk), m->m_TrunkName.c_str());
413 OpenReq.szTrunk[sizeof(OpenReq.szTrunk) - 1] = '\0';
414 OpenReq.enmTrunkType = m->m_enmTrunkType;
415 OpenReq.fFlags = 0; /** @todo check this */
416 OpenReq.cbSend = m->m_cbSendBuf;
417 OpenReq.cbRecv = m->m_cbRecvBuf;
418 OpenReq.hIf = INTNET_HANDLE_INVALID;
419
420 /*
421 * Issue the request.
422 */
423 Log2(("attempting to open/create network \"%s\"...\n", OpenReq.szNetwork));
424 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_OPEN, 0, &OpenReq.Hdr);
425 if (RT_FAILURE(rc))
426 {
427 Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_OPEN,) failed, rc=%Rrc\n", rc));
428 return rc;
429 }
430 m->m_hIf = OpenReq.hIf;
431 Log2(("successfully opened/created \"%s\" - hIf=%#x\n", OpenReq.szNetwork, m->m_hIf));
432
433 /*
434 * Get the ring-3 address of the shared interface buffer.
435 */
436 INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq;
437 GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
438 GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq);
439 GetBufferPtrsReq.pSession = m->m_pSession;
440 GetBufferPtrsReq.hIf = m->m_hIf;
441 GetBufferPtrsReq.pRing3Buf = NULL;
442 GetBufferPtrsReq.pRing0Buf = NIL_RTR0PTR;
443 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, 0, &GetBufferPtrsReq.Hdr);
444 if (RT_FAILURE(rc))
445 {
446 Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS,) failed, rc=%Rrc\n", rc));
447 return rc;
448 }
449 pBuf = GetBufferPtrsReq.pRing3Buf;
450 Log2(("pBuf=%p cbBuf=%d cbSend=%d cbRecv=%d\n",
451 pBuf, pBuf->cbBuf, pBuf->cbSend, pBuf->cbRecv));
452 m->m_pIfBuf = pBuf;
453
454 /*
455 * Activate the interface.
456 */
457 INTNETIFSETACTIVEREQ ActiveReq;
458 ActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
459 ActiveReq.Hdr.cbReq = sizeof(ActiveReq);
460 ActiveReq.pSession = m->m_pSession;
461 ActiveReq.hIf = m->m_hIf;
462 ActiveReq.fActive = true;
463 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SET_ACTIVE, 0, &ActiveReq.Hdr);
464 if (RT_SUCCESS(rc))
465 return 0;
466
467 /* bail out */
468 Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE,) failed, rc=%Rrc\n", rc));
469
470 /* ignore this error */
471 return VINF_SUCCESS;
472}
473
474
475void VBoxNetBaseService::shutdown(void)
476{
477 syncEnter();
478 if (!m->fShutdown)
479 {
480 m->fShutdown = true;
481 if (m->m_hThrRecv != NIL_RTTHREAD)
482 {
483 int rc = abortWait();
484 AssertRC(rc == VINF_SUCCESS || rc == VERR_SEM_DESTROYED);
485 rc = m->m_EventQ->interruptEventQueueProcessing();
486 if (RT_SUCCESS(rc))
487 {
488 rc = RTThreadWait(m->m_hThrRecv, 60000, NULL);
489 if (RT_FAILURE(rc))
490 Log1WarningFunc(("RTThreadWait(%RTthrd) -> %Rrc\n", m->m_hThrRecv, rc));
491 }
492 else
493 {
494 AssertMsgFailed(("interruptEventQueueProcessing() failed\n"));
495 RTThreadWait(m->m_hThrRecv , 0, NULL);
496 }
497 }
498 }
499 syncLeave();
500}
501
502
503int VBoxNetBaseService::syncEnter()
504{
505 return RTCritSectEnter(&m->m_csThis);
506}
507
508
509int VBoxNetBaseService::syncLeave()
510{
511 return RTCritSectLeave(&m->m_csThis);
512}
513
514
515int VBoxNetBaseService::waitForIntNetEvent(int cMillis)
516{
517 INTNETIFWAITREQ WaitReq;
518 LogFlowFunc(("ENTER:cMillis: %d\n", cMillis));
519 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
520 WaitReq.Hdr.cbReq = sizeof(WaitReq);
521 WaitReq.pSession = m->m_pSession;
522 WaitReq.hIf = m->m_hIf;
523 WaitReq.cMillies = cMillis;
524
525 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_WAIT, 0, &WaitReq.Hdr);
526 LogFlowFuncLeaveRC(rc);
527 return rc;
528}
529
530
531int VBoxNetBaseService::abortWait()
532{
533 INTNETIFABORTWAITREQ AbortReq;
534 LogFlowFunc(("ENTER:\n"));
535 AbortReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
536 AbortReq.Hdr.cbReq = sizeof(AbortReq);
537 AbortReq.pSession = m->m_pSession;
538 AbortReq.hIf = m->m_hIf;
539 AbortReq.fNoMoreWaits = true;
540
541 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_ABORT_WAIT, 0, &AbortReq.Hdr);
542 LogFlowFuncLeaveRC(rc);
543 return rc;
544}
545
546
547/* S/G API */
548int VBoxNetBaseService::sendBufferOnWire(PCINTNETSEG paSegs, size_t cSegs, size_t cbFrame)
549{
550 /* Allocate frame */
551 PINTNETHDR pHdr = NULL;
552 uint8_t *pbFrame = NULL;
553 int rc = IntNetRingAllocateFrame(&m->m_pIfBuf->Send, (uint32_t)cbFrame, &pHdr, (void **)&pbFrame);
554 AssertRCReturn(rc, rc);
555
556 /* Now we fill pvFrame with S/G above */
557 size_t offFrame = 0;
558 for (size_t idxSeg = 0; idxSeg < cSegs; ++idxSeg)
559 {
560 memcpy(&pbFrame[offFrame], paSegs[idxSeg].pv, paSegs[idxSeg].cb);
561 offFrame += paSegs[idxSeg].cb;
562 }
563
564 /* Commit */
565 IntNetRingCommitFrameEx(&m->m_pIfBuf->Send, pHdr, cbFrame);
566
567 LogFlowFuncLeaveRC(rc);
568 return rc;
569}
570
571/**
572 * forcible ask for send packet on the "wire"
573 */
574void VBoxNetBaseService::flushWire()
575{
576 INTNETIFSENDREQ SendReq;
577 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
578 SendReq.Hdr.cbReq = sizeof(SendReq);
579 SendReq.pSession = m->m_pSession;
580 SendReq.hIf = m->m_hIf;
581 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SEND, 0, &SendReq.Hdr);
582 AssertRCReturnVoid(rc);
583 LogFlowFuncLeave();
584}
585
586
587int VBoxNetBaseService::hlpUDPBroadcast(unsigned uSrcPort, unsigned uDstPort,
588 void const *pvData, size_t cbData) const
589{
590 return VBoxNetUDPBroadcast(m->m_pSession, m->m_hIf, m->m_pIfBuf,
591 m->m_Ipv4Address, &m->m_MacAddress, uSrcPort,
592 uDstPort, pvData, cbData);
593
594}
595
596
597const std::string VBoxNetBaseService::getServiceName() const
598{
599 return m->m_ServiceName;
600}
601
602
603void VBoxNetBaseService::setServiceName(const std::string& aName)
604{
605 m->m_ServiceName = aName;
606}
607
608
609const std::string VBoxNetBaseService::getNetworkName() const
610{
611 return m->m_NetworkName;
612}
613
614
615void VBoxNetBaseService::setNetworkName(const std::string& aName)
616{
617 m->m_NetworkName = aName;
618}
619
620
621const RTMAC VBoxNetBaseService::getMacAddress() const
622{
623 return m->m_MacAddress;
624}
625
626
627void VBoxNetBaseService::setMacAddress(const RTMAC& aMac)
628{
629 m->m_MacAddress = aMac;
630}
631
632
633const RTNETADDRIPV4 VBoxNetBaseService::getIpv4Address() const
634{
635 return m->m_Ipv4Address;
636}
637
638
639void VBoxNetBaseService::setIpv4Address(const RTNETADDRIPV4& aAddress)
640{
641 m->m_Ipv4Address = aAddress;
642}
643
644
645const RTNETADDRIPV4 VBoxNetBaseService::getIpv4Netmask() const
646{
647 return m->m_Ipv4Netmask;
648}
649
650
651void VBoxNetBaseService::setIpv4Netmask(const RTNETADDRIPV4& aNetmask)
652{
653 m->m_Ipv4Netmask = aNetmask;
654}
655
656
657uint32_t VBoxNetBaseService::getSendBufSize() const
658{
659 return m->m_cbSendBuf;
660}
661
662
663void VBoxNetBaseService::setSendBufSize(uint32_t cbBuf)
664{
665 m->m_cbSendBuf = cbBuf;
666}
667
668
669uint32_t VBoxNetBaseService::getRecvBufSize() const
670{
671 return m->m_cbRecvBuf;
672}
673
674
675void VBoxNetBaseService::setRecvBufSize(uint32_t cbBuf)
676{
677 m->m_cbRecvBuf = cbBuf;
678}
679
680
681int32_t VBoxNetBaseService::getVerbosityLevel() const
682{
683 return m->m_cVerbosity;
684}
685
686
687void VBoxNetBaseService::setVerbosityLevel(int32_t aVerbosity)
688{
689 m->m_cVerbosity = aVerbosity;
690}
691
692
693void VBoxNetBaseService::addCommandLineOption(PCRTGETOPTDEF optDef)
694{
695 m->m_vecOptionDefs.push_back(optDef);
696}
697
698
699void VBoxNetBaseService::doReceiveLoop()
700{
701 int rc;
702 /* Well we're ready */
703 PINTNETRINGBUF pRingBuf = &m->m_pIfBuf->Recv;
704
705 for (;;)
706 {
707 /*
708 * Wait for a packet to become available.
709 */
710 rc = waitForIntNetEvent(2000);
711 if (rc == VERR_SEM_DESTROYED)
712 break;
713
714 if (RT_FAILURE(rc))
715 {
716 if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
717 {
718 /* do we want interrupt anyone ??? */
719 continue;
720 }
721 LogRel(("VBoxNetBaseService: waitForIntNetEvent returned %Rrc\n", rc));
722 AssertRCReturnVoid(rc);
723 }
724
725 /*
726 * Process the receive buffer.
727 */
728 PCINTNETHDR pHdr;
729 while ((pHdr = IntNetRingGetNextFrameToRead(pRingBuf)) != NULL)
730 {
731 uint8_t const u8Type = pHdr->u8Type;
732 size_t cbFrame = pHdr->cbFrame;
733 switch (u8Type)
734 {
735 case INTNETHDR_TYPE_FRAME:
736 {
737 void *pvFrame = IntNetHdrGetFramePtr(pHdr, m->m_pIfBuf);
738 rc = processFrame(pvFrame, cbFrame);
739 if (RT_FAILURE(rc) && rc == VERR_IGNORED)
740 {
741 /* XXX: UDP + ARP for DHCP */
742 VBOXNETUDPHDRS Hdrs;
743 size_t cb;
744 void *pv = VBoxNetUDPMatch(m->m_pIfBuf, RTNETIPV4_PORT_BOOTPS, &m->m_MacAddress,
745 VBOXNETUDP_MATCH_UNICAST
746 | VBOXNETUDP_MATCH_BROADCAST
747 | VBOXNETUDP_MATCH_CHECKSUM
748 | (m->m_cVerbosity > 2 ? VBOXNETUDP_MATCH_PRINT_STDERR : 0),
749 &Hdrs, &cb);
750 if (pv && cb)
751 processUDP(pv, cb);
752 else
753 VBoxNetArpHandleIt(m->m_pSession, m->m_hIf, m->m_pIfBuf, &m->m_MacAddress, m->m_Ipv4Address);
754 }
755 break;
756 }
757 case INTNETHDR_TYPE_GSO:
758 {
759 PCPDMNETWORKGSO pGso = IntNetHdrGetGsoContext(pHdr, m->m_pIfBuf);
760 rc = processGSO(pGso, cbFrame);
761 if (RT_FAILURE(rc) && rc == VERR_IGNORED)
762 break;
763 break;
764 }
765
766 case INTNETHDR_TYPE_PADDING:
767 break;
768
769 default:
770 break;
771 }
772 IntNetRingSkipFrame(&m->m_pIfBuf->Recv);
773 } /* loop */
774 }
775}
776
777
778int VBoxNetBaseService::startReceiveThreadAndEnterEventLoop()
779{
780 AssertMsgReturn(isMainNeeded(), ("It's expected that we need Main"), VERR_INTERNAL_ERROR);
781
782 /* start receiving thread */
783 int rc = RTThreadCreate(&m->m_hThrRecv, /* thread handle*/
784 &VBoxNetBaseService::Data::recvLoop, /* routine */
785 this, /* user data */
786 128 * _1K, /* stack size */
787 RTTHREADTYPE_IO, /* type */
788 RTTHREADFLAGS_WAITABLE, /* flags */
789 "RECV");
790 AssertRCReturn(rc, rc);
791
792 m->m_EventQ = com::NativeEventQueue::getMainEventQueue();
793 AssertPtrReturn(m->m_EventQ, VERR_INTERNAL_ERROR);
794
795 while (!m->fShutdown)
796 {
797 rc = m->m_EventQ->processEventQueue(RT_INDEFINITE_WAIT);
798 if (rc == VERR_INTERRUPTED)
799 {
800 LogFlow(("Event queue processing ended with rc=%Rrc\n", rc));
801 break;
802 }
803 }
804
805 return VINF_SUCCESS;
806}
807
808
809void VBoxNetBaseService::debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const
810{
811 if (iMinLevel <= m->m_cVerbosity)
812 {
813 va_list va;
814 va_start(va, pszFmt);
815 debugPrintV(iMinLevel, fMsg, pszFmt, va);
816 va_end(va);
817 }
818}
819
820
821/**
822 * Print debug message depending on the m_cVerbosity level.
823 *
824 * @param iMinLevel The minimum m_cVerbosity level for this message.
825 * @param fMsg Whether to dump parts for the current service message.
826 * @param pszFmt The message format string.
827 * @param va Optional arguments.
828 */
829void VBoxNetBaseService::debugPrintV(int iMinLevel, bool fMsg, const char *pszFmt, va_list va) const
830{
831 RT_NOREF(fMsg);
832 if (iMinLevel <= m->m_cVerbosity)
833 {
834 va_list vaCopy; /* This dude is *very* special, thus the copy. */
835 va_copy(vaCopy, va);
836 RTStrmPrintf(g_pStdErr, "%s: %s: %N\n",
837 RTProcShortName(),
838 iMinLevel >= 2 ? "debug" : "info",
839 pszFmt,
840 &vaCopy);
841 va_end(vaCopy);
842 }
843}
844
845
846PRTGETOPTDEF VBoxNetBaseService::getOptionsPtr()
847{
848 PRTGETOPTDEF pOptArray = NULL;
849 pOptArray = (PRTGETOPTDEF)RTMemAlloc(sizeof(RTGETOPTDEF) * m->m_vecOptionDefs.size());
850 if (!pOptArray)
851 return NULL;
852 for (unsigned int i = 0; i < m->m_vecOptionDefs.size(); ++i)
853 {
854 PCRTGETOPTDEF pOpt = m->m_vecOptionDefs[i];
855 memcpy(&pOptArray[i], pOpt, sizeof(*pOpt));
856 }
857 return pOptArray;
858}
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