VirtualBox

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

Last change on this file since 96399 was 96399, checked in by vboxsync, 2 years ago

/Config.kmk and many other places: Change VBOX_VENDOR to the official copyright holder text, needs follow-up changes and equivalent adjustments elsewhere.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.8 KB
Line 
1/* $Id: VBoxNetBaseService.cpp 96399 2022-08-22 14:47:39Z 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 "Copyright (C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
332 "\n"
333 "Usage: %s <options>\n"
334 "\n"
335 "Options:\n",
336 RTProcShortName(),
337 RTBldCfgVersion(),
338 RTBldCfgRevision(),
339 RTProcShortName());
340 for (unsigned int i = 0; i < m->m_vecOptionDefs.size(); i++)
341 RTPrintf(" -%c, %s\n", m->m_vecOptionDefs[i]->iShort, m->m_vecOptionDefs[i]->pszLong);
342 usage(); /* to print Service Specific usage */
343 return 1; /** @todo this exit code is wrong, of course. :/ */
344
345 default:
346 {
347 int rc1 = parseOpt(rc, Val);
348 if (RT_FAILURE(rc1))
349 {
350 RTEXITCODE rcExit = RTGetOptPrintError(rc, &Val);
351 RTPrintf("Use --help for more information.\n");
352 return rcExit;
353 }
354 break;
355 }
356 }
357 }
358
359 RTMemFree(paOptionArray);
360 return RTEXITCODE_SUCCESS;
361}
362
363
364int VBoxNetBaseService::tryGoOnline(void)
365{
366 /*
367 * Open the session, load ring-0 and issue the request.
368 */
369 int rc = SUPR3Init(&m->m_pSession);
370 if (RT_FAILURE(rc))
371 {
372 m->m_pSession = NIL_RTR0PTR;
373 LogRel(("VBoxNetBaseService: SUPR3Init -> %Rrc\n", rc));
374 return rc;
375 }
376
377 char szPath[RTPATH_MAX];
378 rc = RTPathExecDir(szPath, sizeof(szPath) - sizeof("/VMMR0.r0"));
379 if (RT_FAILURE(rc))
380 {
381 LogRel(("VBoxNetBaseService: RTPathExecDir -> %Rrc\n", rc));
382 return rc;
383 }
384
385 rc = SUPR3LoadVMM(strcat(szPath, "/VMMR0.r0"), NULL);
386 if (RT_FAILURE(rc))
387 {
388 LogRel(("VBoxNetBaseService: SUPR3LoadVMM(\"%s\") -> %Rrc\n", szPath, rc));
389 return rc;
390 }
391
392 /*
393 * Create the open request.
394 */
395 PINTNETBUF pBuf;
396 INTNETOPENREQ OpenReq;
397 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
398 OpenReq.Hdr.cbReq = sizeof(OpenReq);
399 OpenReq.pSession = m->m_pSession;
400 RTStrCopy(OpenReq.szNetwork, sizeof(OpenReq.szNetwork), m->m_NetworkName.c_str());
401 OpenReq.szNetwork[sizeof(OpenReq.szNetwork) - 1] = '\0';
402 RTStrCopy(OpenReq.szTrunk, sizeof(OpenReq.szTrunk), m->m_TrunkName.c_str());
403 OpenReq.szTrunk[sizeof(OpenReq.szTrunk) - 1] = '\0';
404 OpenReq.enmTrunkType = m->m_enmTrunkType;
405 OpenReq.fFlags = 0; /** @todo check this */
406 OpenReq.cbSend = m->m_cbSendBuf;
407 OpenReq.cbRecv = m->m_cbRecvBuf;
408 OpenReq.hIf = INTNET_HANDLE_INVALID;
409
410 /*
411 * Issue the request.
412 */
413 Log2(("attempting to open/create network \"%s\"...\n", OpenReq.szNetwork));
414 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_OPEN, 0, &OpenReq.Hdr);
415 if (RT_FAILURE(rc))
416 {
417 Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_OPEN,) failed, rc=%Rrc\n", rc));
418 return rc;
419 }
420 m->m_hIf = OpenReq.hIf;
421 Log2(("successfully opened/created \"%s\" - hIf=%#x\n", OpenReq.szNetwork, m->m_hIf));
422
423 /*
424 * Get the ring-3 address of the shared interface buffer.
425 */
426 INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq;
427 GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
428 GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq);
429 GetBufferPtrsReq.pSession = m->m_pSession;
430 GetBufferPtrsReq.hIf = m->m_hIf;
431 GetBufferPtrsReq.pRing3Buf = NULL;
432 GetBufferPtrsReq.pRing0Buf = NIL_RTR0PTR;
433 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, 0, &GetBufferPtrsReq.Hdr);
434 if (RT_FAILURE(rc))
435 {
436 Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS,) failed, rc=%Rrc\n", rc));
437 return rc;
438 }
439 pBuf = GetBufferPtrsReq.pRing3Buf;
440 Log2(("pBuf=%p cbBuf=%d cbSend=%d cbRecv=%d\n",
441 pBuf, pBuf->cbBuf, pBuf->cbSend, pBuf->cbRecv));
442 m->m_pIfBuf = pBuf;
443
444 /*
445 * Activate the interface.
446 */
447 INTNETIFSETACTIVEREQ ActiveReq;
448 ActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
449 ActiveReq.Hdr.cbReq = sizeof(ActiveReq);
450 ActiveReq.pSession = m->m_pSession;
451 ActiveReq.hIf = m->m_hIf;
452 ActiveReq.fActive = true;
453 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SET_ACTIVE, 0, &ActiveReq.Hdr);
454 if (RT_SUCCESS(rc))
455 return 0;
456
457 /* bail out */
458 Log2(("VBoxNetBaseService: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE,) failed, rc=%Rrc\n", rc));
459
460 /* ignore this error */
461 return VINF_SUCCESS;
462}
463
464
465void VBoxNetBaseService::shutdown(void)
466{
467 syncEnter();
468 if (!m->fShutdown)
469 {
470 m->fShutdown = true;
471 if (m->m_hThrRecv != NIL_RTTHREAD)
472 {
473 int rc = abortWait();
474 AssertRC(rc == VINF_SUCCESS || rc == VERR_SEM_DESTROYED);
475 rc = m->m_EventQ->interruptEventQueueProcessing();
476 if (RT_SUCCESS(rc))
477 {
478 rc = RTThreadWait(m->m_hThrRecv, 60000, NULL);
479 if (RT_FAILURE(rc))
480 Log1WarningFunc(("RTThreadWait(%RTthrd) -> %Rrc\n", m->m_hThrRecv, rc));
481 }
482 else
483 {
484 AssertMsgFailed(("interruptEventQueueProcessing() failed\n"));
485 RTThreadWait(m->m_hThrRecv , 0, NULL);
486 }
487 }
488 }
489 syncLeave();
490}
491
492
493int VBoxNetBaseService::syncEnter()
494{
495 return RTCritSectEnter(&m->m_csThis);
496}
497
498
499int VBoxNetBaseService::syncLeave()
500{
501 return RTCritSectLeave(&m->m_csThis);
502}
503
504
505int VBoxNetBaseService::waitForIntNetEvent(int cMillis)
506{
507 INTNETIFWAITREQ WaitReq;
508 LogFlowFunc(("ENTER:cMillis: %d\n", cMillis));
509 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
510 WaitReq.Hdr.cbReq = sizeof(WaitReq);
511 WaitReq.pSession = m->m_pSession;
512 WaitReq.hIf = m->m_hIf;
513 WaitReq.cMillies = cMillis;
514
515 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_WAIT, 0, &WaitReq.Hdr);
516 LogFlowFuncLeaveRC(rc);
517 return rc;
518}
519
520
521int VBoxNetBaseService::abortWait()
522{
523 INTNETIFABORTWAITREQ AbortReq;
524 LogFlowFunc(("ENTER:\n"));
525 AbortReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
526 AbortReq.Hdr.cbReq = sizeof(AbortReq);
527 AbortReq.pSession = m->m_pSession;
528 AbortReq.hIf = m->m_hIf;
529 AbortReq.fNoMoreWaits = true;
530
531 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_ABORT_WAIT, 0, &AbortReq.Hdr);
532 LogFlowFuncLeaveRC(rc);
533 return rc;
534}
535
536
537/* S/G API */
538int VBoxNetBaseService::sendBufferOnWire(PCINTNETSEG paSegs, size_t cSegs, size_t cbFrame)
539{
540 /* Allocate frame */
541 PINTNETHDR pHdr = NULL;
542 uint8_t *pbFrame = NULL;
543 int rc = IntNetRingAllocateFrame(&m->m_pIfBuf->Send, (uint32_t)cbFrame, &pHdr, (void **)&pbFrame);
544 AssertRCReturn(rc, rc);
545
546 /* Now we fill pvFrame with S/G above */
547 size_t offFrame = 0;
548 for (size_t idxSeg = 0; idxSeg < cSegs; ++idxSeg)
549 {
550 memcpy(&pbFrame[offFrame], paSegs[idxSeg].pv, paSegs[idxSeg].cb);
551 offFrame += paSegs[idxSeg].cb;
552 }
553
554 /* Commit */
555 IntNetRingCommitFrameEx(&m->m_pIfBuf->Send, pHdr, cbFrame);
556
557 LogFlowFuncLeaveRC(rc);
558 return rc;
559}
560
561/**
562 * forcible ask for send packet on the "wire"
563 */
564void VBoxNetBaseService::flushWire()
565{
566 INTNETIFSENDREQ SendReq;
567 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
568 SendReq.Hdr.cbReq = sizeof(SendReq);
569 SendReq.pSession = m->m_pSession;
570 SendReq.hIf = m->m_hIf;
571 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SEND, 0, &SendReq.Hdr);
572 AssertRCReturnVoid(rc);
573 LogFlowFuncLeave();
574}
575
576
577int VBoxNetBaseService::hlpUDPBroadcast(unsigned uSrcPort, unsigned uDstPort,
578 void const *pvData, size_t cbData) const
579{
580 return VBoxNetUDPBroadcast(m->m_pSession, m->m_hIf, m->m_pIfBuf,
581 m->m_Ipv4Address, &m->m_MacAddress, uSrcPort,
582 uDstPort, pvData, cbData);
583
584}
585
586
587const std::string VBoxNetBaseService::getServiceName() const
588{
589 return m->m_ServiceName;
590}
591
592
593void VBoxNetBaseService::setServiceName(const std::string& aName)
594{
595 m->m_ServiceName = aName;
596}
597
598
599const std::string VBoxNetBaseService::getNetworkName() const
600{
601 return m->m_NetworkName;
602}
603
604
605void VBoxNetBaseService::setNetworkName(const std::string& aName)
606{
607 m->m_NetworkName = aName;
608}
609
610
611const RTMAC VBoxNetBaseService::getMacAddress() const
612{
613 return m->m_MacAddress;
614}
615
616
617void VBoxNetBaseService::setMacAddress(const RTMAC& aMac)
618{
619 m->m_MacAddress = aMac;
620}
621
622
623const RTNETADDRIPV4 VBoxNetBaseService::getIpv4Address() const
624{
625 return m->m_Ipv4Address;
626}
627
628
629void VBoxNetBaseService::setIpv4Address(const RTNETADDRIPV4& aAddress)
630{
631 m->m_Ipv4Address = aAddress;
632}
633
634
635const RTNETADDRIPV4 VBoxNetBaseService::getIpv4Netmask() const
636{
637 return m->m_Ipv4Netmask;
638}
639
640
641void VBoxNetBaseService::setIpv4Netmask(const RTNETADDRIPV4& aNetmask)
642{
643 m->m_Ipv4Netmask = aNetmask;
644}
645
646
647uint32_t VBoxNetBaseService::getSendBufSize() const
648{
649 return m->m_cbSendBuf;
650}
651
652
653void VBoxNetBaseService::setSendBufSize(uint32_t cbBuf)
654{
655 m->m_cbSendBuf = cbBuf;
656}
657
658
659uint32_t VBoxNetBaseService::getRecvBufSize() const
660{
661 return m->m_cbRecvBuf;
662}
663
664
665void VBoxNetBaseService::setRecvBufSize(uint32_t cbBuf)
666{
667 m->m_cbRecvBuf = cbBuf;
668}
669
670
671int32_t VBoxNetBaseService::getVerbosityLevel() const
672{
673 return m->m_cVerbosity;
674}
675
676
677void VBoxNetBaseService::setVerbosityLevel(int32_t aVerbosity)
678{
679 m->m_cVerbosity = aVerbosity;
680}
681
682
683void VBoxNetBaseService::addCommandLineOption(PCRTGETOPTDEF optDef)
684{
685 m->m_vecOptionDefs.push_back(optDef);
686}
687
688
689void VBoxNetBaseService::doReceiveLoop()
690{
691 int rc;
692 /* Well we're ready */
693 PINTNETRINGBUF pRingBuf = &m->m_pIfBuf->Recv;
694
695 for (;;)
696 {
697 /*
698 * Wait for a packet to become available.
699 */
700 rc = waitForIntNetEvent(2000);
701 if (rc == VERR_SEM_DESTROYED)
702 break;
703
704 if (RT_FAILURE(rc))
705 {
706 if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
707 {
708 /* do we want interrupt anyone ??? */
709 continue;
710 }
711 LogRel(("VBoxNetBaseService: waitForIntNetEvent returned %Rrc\n", rc));
712 AssertRCReturnVoid(rc);
713 }
714
715 /*
716 * Process the receive buffer.
717 */
718 PCINTNETHDR pHdr;
719 while ((pHdr = IntNetRingGetNextFrameToRead(pRingBuf)) != NULL)
720 {
721 uint8_t const u8Type = pHdr->u8Type;
722 size_t cbFrame = pHdr->cbFrame;
723 switch (u8Type)
724 {
725 case INTNETHDR_TYPE_FRAME:
726 {
727 void *pvFrame = IntNetHdrGetFramePtr(pHdr, m->m_pIfBuf);
728 rc = processFrame(pvFrame, cbFrame);
729 if (RT_FAILURE(rc) && rc == VERR_IGNORED)
730 {
731 /* XXX: UDP + ARP for DHCP */
732 VBOXNETUDPHDRS Hdrs;
733 size_t cb;
734 void *pv = VBoxNetUDPMatch(m->m_pIfBuf, RTNETIPV4_PORT_BOOTPS, &m->m_MacAddress,
735 VBOXNETUDP_MATCH_UNICAST
736 | VBOXNETUDP_MATCH_BROADCAST
737 | VBOXNETUDP_MATCH_CHECKSUM
738 | (m->m_cVerbosity > 2 ? VBOXNETUDP_MATCH_PRINT_STDERR : 0),
739 &Hdrs, &cb);
740 if (pv && cb)
741 processUDP(pv, cb);
742 else
743 VBoxNetArpHandleIt(m->m_pSession, m->m_hIf, m->m_pIfBuf, &m->m_MacAddress, m->m_Ipv4Address);
744 }
745 break;
746 }
747 case INTNETHDR_TYPE_GSO:
748 {
749 PCPDMNETWORKGSO pGso = IntNetHdrGetGsoContext(pHdr, m->m_pIfBuf);
750 rc = processGSO(pGso, cbFrame);
751 if (RT_FAILURE(rc) && rc == VERR_IGNORED)
752 break;
753 break;
754 }
755
756 case INTNETHDR_TYPE_PADDING:
757 break;
758
759 default:
760 break;
761 }
762 IntNetRingSkipFrame(&m->m_pIfBuf->Recv);
763 } /* loop */
764 }
765}
766
767
768int VBoxNetBaseService::startReceiveThreadAndEnterEventLoop()
769{
770 AssertMsgReturn(isMainNeeded(), ("It's expected that we need Main"), VERR_INTERNAL_ERROR);
771
772 /* start receiving thread */
773 int rc = RTThreadCreate(&m->m_hThrRecv, /* thread handle*/
774 &VBoxNetBaseService::Data::recvLoop, /* routine */
775 this, /* user data */
776 128 * _1K, /* stack size */
777 RTTHREADTYPE_IO, /* type */
778 RTTHREADFLAGS_WAITABLE, /* flags */
779 "RECV");
780 AssertRCReturn(rc, rc);
781
782 m->m_EventQ = com::NativeEventQueue::getMainEventQueue();
783 AssertPtrReturn(m->m_EventQ, VERR_INTERNAL_ERROR);
784
785 while (!m->fShutdown)
786 {
787 rc = m->m_EventQ->processEventQueue(RT_INDEFINITE_WAIT);
788 if (rc == VERR_INTERRUPTED)
789 {
790 LogFlow(("Event queue processing ended with rc=%Rrc\n", rc));
791 break;
792 }
793 }
794
795 return VINF_SUCCESS;
796}
797
798
799void VBoxNetBaseService::debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const
800{
801 if (iMinLevel <= m->m_cVerbosity)
802 {
803 va_list va;
804 va_start(va, pszFmt);
805 debugPrintV(iMinLevel, fMsg, pszFmt, va);
806 va_end(va);
807 }
808}
809
810
811/**
812 * Print debug message depending on the m_cVerbosity level.
813 *
814 * @param iMinLevel The minimum m_cVerbosity level for this message.
815 * @param fMsg Whether to dump parts for the current service message.
816 * @param pszFmt The message format string.
817 * @param va Optional arguments.
818 */
819void VBoxNetBaseService::debugPrintV(int iMinLevel, bool fMsg, const char *pszFmt, va_list va) const
820{
821 RT_NOREF(fMsg);
822 if (iMinLevel <= m->m_cVerbosity)
823 {
824 va_list vaCopy; /* This dude is *very* special, thus the copy. */
825 va_copy(vaCopy, va);
826 RTStrmPrintf(g_pStdErr, "%s: %s: %N\n",
827 RTProcShortName(),
828 iMinLevel >= 2 ? "debug" : "info",
829 pszFmt,
830 &vaCopy);
831 va_end(vaCopy);
832 }
833}
834
835
836PRTGETOPTDEF VBoxNetBaseService::getOptionsPtr()
837{
838 PRTGETOPTDEF pOptArray = NULL;
839 pOptArray = (PRTGETOPTDEF)RTMemAlloc(sizeof(RTGETOPTDEF) * m->m_vecOptionDefs.size());
840 if (!pOptArray)
841 return NULL;
842 for (unsigned int i = 0; i < m->m_vecOptionDefs.size(); ++i)
843 {
844 PCRTGETOPTDEF pOpt = m->m_vecOptionDefs[i];
845 memcpy(&pOptArray[i], pOpt, sizeof(*pOpt));
846 }
847 return pOptArray;
848}
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