VirtualBox

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

Last change on this file since 95259 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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