VirtualBox

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

Last change on this file since 88839 was 87450, checked in by vboxsync, 4 years ago

NAT/Net: Get rid of obsolete options -p/-P to pass port-forwarding
rules on the command line. It's a left-over from some very early test
code that just adds clutter. Leave the placeholders to add custom
options in place. Since there are no options, and arrays can't be
empty, use an array with a sentinel entry instead (and only the
sentinel for now).

While here fix VBoxNetBaseService::addCommandLineOption() - const and
pointer typedefs don't mean what they might seem to mean.

  • 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 87450 2021-01-27 02:00:34Z vboxsync $ */
2/** @file
3 * VBoxNetBaseService - common services for VBoxNetDHCP and VBoxNetNAT.
4 */
5
6/*
7 * Copyright (C) 2009-2020 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