VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/VBoxNetNAT.cpp@ 45733

Last change on this file since 45733 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.0 KB
Line 
1/* $Id: VBoxNetNAT.cpp 44529 2013-02-04 15:54:15Z vboxsync $ */
2/** @file
3 * VBoxNetNAT - NAT Service for connecting to IntNet.
4 */
5
6/*
7 * Copyright (C) 2009-2011 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/** @page pg_net_nat VBoxNetNAT
19 *
20 * Write a few words...
21 *
22 */
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <iprt/net.h>
28#include <iprt/initterm.h>
29#include <iprt/alloca.h>
30#include <iprt/err.h>
31#include <iprt/time.h>
32#include <iprt/timer.h>
33#include <iprt/thread.h>
34#include <iprt/stream.h>
35#include <iprt/path.h>
36#include <iprt/param.h>
37#include <iprt/pipe.h>
38#include <iprt/getopt.h>
39#include <iprt/string.h>
40#include <iprt/mem.h>
41#include <iprt/message.h>
42#include <iprt/req.h>
43#include <iprt/file.h>
44#include <iprt/semaphore.h>
45#define LOG_GROUP LOG_GROUP_NAT_SERVICE
46#include <VBox/log.h>
47
48#include <VBox/sup.h>
49#include <VBox/intnet.h>
50#include <VBox/intnetinline.h>
51#include <VBox/vmm/pdmnetinline.h>
52#include <VBox/vmm/vmm.h>
53#include <VBox/version.h>
54
55#include <vector>
56#include <string>
57
58#include "../NetLib/VBoxNetLib.h"
59#include "../NetLib/VBoxNetBaseService.h"
60#include <libslirp.h>
61
62#ifdef RT_OS_WINDOWS /* WinMain */
63# include <Windows.h>
64# include <stdlib.h>
65#else
66# include <errno.h>
67#endif
68
69
70
71/*******************************************************************************
72* Structures and Typedefs *
73*******************************************************************************/
74static RTGETOPTDEF g_aGetOptDef[] =
75{
76 { "--pf", 'p', RTGETOPT_REQ_STRING }
77};
78
79typedef struct NATSEVICEPORTFORWARDRULE
80{
81 char *pszPortForwardRuleName;
82 struct in_addr IpV4HostAddr;
83 uint16_t u16HostPort;
84 struct in_addr IpV4GuestAddr;
85 uint16_t u16GuestPort;
86 bool fUdp;
87 char *pszStrRaw;
88} NATSEVICEPORTFORWARDRULE, *PNATSEVICEPORTFORWARDRULE;
89
90class VBoxNetNAT : public VBoxNetBaseService
91{
92public:
93 VBoxNetNAT();
94 virtual ~VBoxNetNAT();
95 void usage(void);
96 void run(void);
97 virtual int init(void);
98 virtual int parseOpt(int rc, const RTGETOPTUNION& getOptVal);
99
100public:
101 PNATState m_pNATState;
102 RTNETADDRIPV4 m_Ipv4Netmask;
103 bool m_fPassDomain;
104 RTTHREAD m_ThrNAT;
105 RTTHREAD m_ThrSndNAT;
106 RTTHREAD m_ThrUrgSndNAT;
107#ifdef RT_OS_WINDOWS
108 HANDLE m_hWakeupEvent;
109#else
110 RTPIPE m_hPipeWrite;
111 RTPIPE m_hPipeRead;
112#endif
113 /** Queue for NAT-thread-external events. */
114 /** event to wakeup the guest receive thread */
115 RTSEMEVENT m_EventSend;
116 /** event to wakeup the guest urgent receive thread */
117 RTSEMEVENT m_EventUrgSend;
118
119 RTREQQUEUE m_hReqQueue;
120 RTREQQUEUE m_hSendQueue;
121 RTREQQUEUE m_hUrgSendQueue;
122 volatile uint32_t cUrgPkt;
123 volatile uint32_t cPkt;
124 bool fIsRunning;
125 std::vector<PNATSEVICEPORTFORWARDRULE> m_vecPortForwardRuleFromCmdLine;
126};
127
128
129
130/*******************************************************************************
131* Global Variables *
132*******************************************************************************/
133/** Pointer to the NAT server. */
134class VBoxNetNAT *g_pNAT;
135static DECLCALLBACK(int) AsyncIoThread(RTTHREAD pThread, void *pvUser);
136static DECLCALLBACK(int) natSndThread(RTTHREAD pThread, void *pvUser);
137static DECLCALLBACK(int) natUrgSndThread(RTTHREAD pThread, void *pvUser);
138static void SendWorker(struct mbuf *m, size_t cb);
139static void IntNetSendWorker(bool urg, void *pvFrame, size_t cbFrame, struct mbuf *m);
140
141
142static void natNotifyNATThread(void)
143{
144 int rc;
145#ifndef RT_OS_WINDOWS
146 /* kick select() */
147 size_t cbIgnored;
148 rc = RTPipeWrite(g_pNAT->m_hPipeWrite, "", 1, &cbIgnored);
149#else
150 /* kick WSAWaitForMultipleEvents */
151 rc = WSASetEvent(g_pNAT->hWakeupEvent);
152#endif
153 AssertRC(rc);
154}
155
156VBoxNetNAT::VBoxNetNAT()
157{
158#if defined(RT_OS_WINDOWS)
159 /*@todo check if we can remove this*/
160 VBoxNetBaseService();
161#endif
162 m_enmTrunkType = kIntNetTrunkType_WhateverNone;
163 m_TrunkName = "";
164 m_MacAddress.au8[0] = 0x08;
165 m_MacAddress.au8[1] = 0x00;
166 m_MacAddress.au8[2] = 0x27;
167 m_MacAddress.au8[3] = 0x40;
168 m_MacAddress.au8[4] = 0x41;
169 m_MacAddress.au8[5] = 0x42;
170 m_Ipv4Address.u = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10, 0, 2, 2)));
171 m_Ipv4Netmask.u = RT_H2N_U32_C(0xffffff);
172 cPkt = 0;
173 cUrgPkt = 0;
174 VBoxNetBaseService::init();
175 for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
176 m_vecOptionDefs.push_back(&g_aGetOptDef[i]);
177}
178
179VBoxNetNAT::~VBoxNetNAT() { }
180int VBoxNetNAT::init()
181{
182 int rc;
183#if 0
184 using namespace com;
185 HRESULT hrc = com::Initialize();
186 if (FAILED(hrc))
187 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM!");
188#endif
189
190 /*
191 * Initialize slirp.
192 */
193 rc = slirp_init(&m_pNATState, RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10, 0, 2, 0))), m_Ipv4Netmask.u, m_fPassDomain, false, 0x40, 100, this);
194 AssertReleaseRC(rc);
195
196 /* Why ? */
197 slirp_set_ethaddr_and_activate_port_forwarding(m_pNATState, &m_MacAddress.au8[0], INADDR_ANY);
198#if 0
199 in_addr ipv4HostAddr;
200 in_addr ipv4GuestAddr;
201 ipv4GuestAddr.s_addr = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10, 0, 2, 15)));
202 ipv4HostAddr.s_addr = INADDR_ANY;
203 slirp_add_redirect(m_pNATState, false, ipv4HostAddr, 2022, ipv4GuestAddr , 22, NULL);
204#endif
205 std::vector<PNATSEVICEPORTFORWARDRULE>::iterator it;
206 for (it = m_vecPortForwardRuleFromCmdLine.begin(); it != m_vecPortForwardRuleFromCmdLine.end(); ++it)
207 {
208 slirp_add_redirect(m_pNATState, (*it)->fUdp, (*it)->IpV4HostAddr, (*it)->u16HostPort, (*it)->IpV4GuestAddr , (*it)->u16GuestPort, NULL);
209 RTStrFree((*it)->pszStrRaw);
210 RTMemFree((*it));
211 }
212 m_vecPortForwardRuleFromCmdLine.clear();
213#ifndef RT_OS_WINDOWS
214 /*
215 * Create the control pipe.
216 */
217 rc = RTPipeCreate(&m_hPipeRead, &m_hPipeWrite, 0 /*fFlags*/);
218 AssertReleaseRC(rc);
219#else
220 m_hWakeupEvent = CreateEvent(NULL, FALSE, FALSE, NULL); /* auto-reset event */
221 AssertReleaseRC(m_hWakeupEvent != NULL);
222 slirp_register_external_event(m_pNATState, m_hWakeupEvent, VBOX_WAKEUP_EVENT_INDEX);
223#endif
224 rc = RTReqQueueCreate(&m_hReqQueue);
225 AssertReleaseRC(rc);
226
227 rc = RTReqQueueCreate(&m_hSendQueue);
228 AssertReleaseRC(rc);
229
230 rc = RTReqQueueCreate(&m_hUrgSendQueue);
231 AssertReleaseRC(rc);
232
233 g_pNAT->fIsRunning = true;
234 rc = RTThreadCreate(&m_ThrNAT, AsyncIoThread, this, 128 * _1K, RTTHREADTYPE_DEFAULT, 0, "NAT");
235 rc = RTThreadCreate(&m_ThrSndNAT, natSndThread, this, 128 * _1K, RTTHREADTYPE_DEFAULT, 0, "SndNAT");
236 rc = RTThreadCreate(&m_ThrUrgSndNAT, natUrgSndThread, this, 128 * _1K, RTTHREADTYPE_DEFAULT, 0, "UrgSndNAT");
237 rc = RTSemEventCreate(&m_EventSend);
238 rc = RTSemEventCreate(&m_EventUrgSend);
239 AssertReleaseRC(rc);
240 return VINF_SUCCESS;
241}
242
243/* Mandatory functions */
244void VBoxNetNAT::run()
245{
246
247 /*
248 * The loop.
249 */
250 fIsRunning = true;
251 PINTNETRINGBUF pRingBuf = &m_pIfBuf->Recv;
252 RTThreadSetType(RTThreadSelf(), RTTHREADTYPE_IO);
253 for (;;)
254 {
255 /*
256 * Wait for a packet to become available.
257 */
258 INTNETIFWAITREQ WaitReq;
259 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
260 WaitReq.Hdr.cbReq = sizeof(WaitReq);
261 WaitReq.pSession = m_pSession;
262 WaitReq.hIf = m_hIf;
263 WaitReq.cMillies = 2000; /* 2 secs - the sleep is for some reason uninterruptible... */ /** @todo fix interruptability in SrvIntNet! */
264#if 0
265 RTReqProcess(m_hSendQueue, 0);
266 RTReqProcess(m_hUrgSendQueue, 0);
267#endif
268 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_WAIT, 0, &WaitReq.Hdr);
269 if (RT_FAILURE(rc))
270 {
271 if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
272 {
273 natNotifyNATThread();
274 continue;
275 }
276 LogRel(("VBoxNetNAT: VMMR0_DO_INTNET_IF_WAIT returned %Rrc\n", rc));
277 return;
278 }
279
280 /*
281 * Process the receive buffer.
282 */
283 PCINTNETHDR pHdr;
284 while ((pHdr = IntNetRingGetNextFrameToRead(pRingBuf)) != NULL)
285 {
286 uint16_t const u16Type = pHdr->u16Type;
287 size_t cbFrame = pHdr->cbFrame;
288 size_t cbIgnored;
289 void *pvSlirpFrame;
290 struct mbuf *m;
291 switch (u16Type)
292 {
293 case INTNETHDR_TYPE_FRAME:
294 m = slirp_ext_m_get(g_pNAT->m_pNATState, cbFrame, &pvSlirpFrame, &cbIgnored);
295 if (!m)
296 {
297 LogRel(("NAT: Can't allocate send buffer cbFrame=%u\n", cbFrame));
298 break;
299 }
300 memcpy(pvSlirpFrame, IntNetHdrGetFramePtr(pHdr, m_pIfBuf), cbFrame);
301#if 0
302 IntNetRingSkipFrame(&m_pIfBuf->Recv);
303#endif
304
305 /* don't wait, we may have to wakeup the NAT thread first */
306 rc = RTReqQueueCallEx(m_hReqQueue, NULL /*ppReq*/, 0 /*cMillies*/, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
307 (PFNRT)SendWorker, 2, m, cbFrame);
308 natNotifyNATThread();
309 AssertReleaseRC(rc);
310 break;
311 case INTNETHDR_TYPE_GSO:
312#if 1
313 {
314 /** @todo pass these unmodified. */
315 PCPDMNETWORKGSO pGso = IntNetHdrGetGsoContext(pHdr, m_pIfBuf);
316 if (!PDMNetGsoIsValid(pGso, cbFrame, cbFrame - sizeof(*pGso)))
317 {
318 IntNetRingSkipFrame(&m_pIfBuf->Recv);
319 STAM_REL_COUNTER_INC(&m_pIfBuf->cStatBadFrames);
320 continue;
321 }
322
323 uint8_t abHdrScratch[256];
324 cbFrame -= sizeof(PDMNETWORKGSO);
325 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, cbFrame);
326 for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
327 {
328 uint32_t cbSegFrame;
329 void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)(pGso + 1), cbFrame, abHdrScratch,
330 iSeg, cSegs, &cbSegFrame);
331 m = slirp_ext_m_get(g_pNAT->m_pNATState, cbSegFrame, &pvSlirpFrame, &cbIgnored);
332 if (!m)
333 {
334 LogRel(("NAT: Can't allocate send buffer cbSegFrame=%u seg=%u/%u\n",
335 cbSegFrame, iSeg, cSegs));
336 break;
337 }
338 memcpy(pvSlirpFrame, pvSegFrame, cbSegFrame);
339
340 rc = RTReqQueueCallEx(m_hReqQueue, NULL /*ppReq*/, 0 /*cMillies*/,
341 RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
342 (PFNRT)SendWorker, 2, m, cbSegFrame);
343 natNotifyNATThread();
344 AssertReleaseRC(rc);
345 }
346 }
347 break;
348#endif
349 case INTNETHDR_TYPE_PADDING:
350 break;
351 default:
352 STAM_REL_COUNTER_INC(&m_pIfBuf->cStatBadFrames);
353 break;
354 }
355
356 IntNetRingSkipFrame(&m_pIfBuf->Recv);
357 }
358 }
359 fIsRunning = false;
360}
361
362void VBoxNetNAT::usage()
363{
364}
365
366int VBoxNetNAT::parseOpt(int rc, const RTGETOPTUNION& Val)
367{
368 switch (rc)
369 {
370 case 'p':
371 {
372#define ITERATE_TO_NEXT_TERM(ch, pRule, strRaw) \
373 do { \
374 while (*ch != ',') \
375 { \
376 if (*ch == 0) \
377 { \
378 if (pRule) \
379 RTMemFree(pRule); \
380 if(strRaw) \
381 RTStrFree(strRaw); \
382 return VERR_INVALID_PARAMETER; \
383 } \
384 ch++; \
385 } \
386 *ch = '\0'; \
387 ch++; \
388 } while(0)
389 PNATSEVICEPORTFORWARDRULE pRule = (PNATSEVICEPORTFORWARDRULE)RTMemAlloc(sizeof(NATSEVICEPORTFORWARDRULE));
390 if (!pRule)
391 return VERR_NO_MEMORY;
392 char *strName;
393 char *strProto;
394 char *strHostIp;
395 char *strHostPort;
396 char *strGuestIp;
397 char *strGuestPort;
398 char *strRaw = RTStrDup(Val.psz);
399 char *ch = strRaw;
400 if (!strRaw)
401 {
402 RTMemFree(pRule);
403 return VERR_NO_MEMORY;
404 }
405
406 strName = RTStrStrip(ch);
407 ITERATE_TO_NEXT_TERM(ch, pRule, strRaw);
408 strProto = RTStrStrip(ch);
409 ITERATE_TO_NEXT_TERM(ch, pRule, strRaw);
410 strHostIp = RTStrStrip(ch);
411 ITERATE_TO_NEXT_TERM(ch, pRule, strRaw);
412 strHostPort = RTStrStrip(ch);
413 ITERATE_TO_NEXT_TERM(ch, pRule, strRaw);
414 strGuestIp = RTStrStrip(ch);
415 ITERATE_TO_NEXT_TERM(ch, pRule, strRaw);
416 strGuestPort = RTStrStrip(ch);
417 if (RTStrICmp(strProto, "udp") == 0)
418 pRule->fUdp = true;
419 else if (RTStrICmp(strProto, "tcp") == 0)
420 pRule->fUdp = false;
421 else
422 {
423 RTStrFree(strRaw);
424 RTMemFree(pRule);
425 return VERR_INVALID_PARAMETER;
426 }
427 if ( strHostIp == NULL
428 || inet_aton(strHostIp, &pRule->IpV4HostAddr) == 0)
429 pRule->IpV4HostAddr.s_addr = INADDR_ANY;
430 if ( strGuestIp == NULL
431 || inet_aton(strGuestIp, &pRule->IpV4GuestAddr) == 0)
432 {
433 RTMemFree(pRule);
434 RTMemFree(strRaw);
435 return VERR_INVALID_PARAMETER;
436 }
437 pRule->u16HostPort = RTStrToUInt16(strHostPort);
438 pRule->u16GuestPort = RTStrToUInt16(strGuestPort);
439 if ( !pRule->u16HostPort
440 || !pRule->u16GuestPort)
441 {
442 RTMemFree(pRule);
443 RTMemFree(strRaw);
444 return VERR_INVALID_PARAMETER;
445 }
446 pRule->pszStrRaw = strRaw;
447 m_vecPortForwardRuleFromCmdLine.push_back(pRule);
448 return VINF_SUCCESS;
449#undef ITERATE_TO_NEXT_TERM
450 }
451 default:;
452 }
453 return VERR_NOT_FOUND;
454}
455
456/**
457 * Entry point.
458 */
459extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
460{
461 Log2(("NAT: main\n"));
462 g_pNAT = new VBoxNetNAT();
463 Log2(("NAT: initialization\n"));
464 int rc = g_pNAT->parseArgs(argc - 1, argv + 1);
465 if (!rc)
466 {
467 g_pNAT->init();
468 Log2(("NAT: parsing command line\n"));
469 Log2(("NAT: try go online\n"));
470 g_pNAT->tryGoOnline();
471 Log2(("NAT: main loop\n"));
472 g_pNAT->run();
473 }
474 delete g_pNAT;
475 return 0;
476}
477
478
479/** slirp's hooks */
480extern "C" int slirp_can_output(void * pvUser)
481{
482 return 1;
483}
484
485extern "C" void slirp_urg_output(void *pvUser, struct mbuf *m, const uint8_t *pu8Buf, int cb)
486{
487 LogFlowFunc(("ENTER: m:%p, pu8Buf:%p, cb:%d\n", m, pu8Buf, cb));
488 int rc = RTReqQueueCallEx(g_pNAT->m_hUrgSendQueue, NULL /*ppReq*/, 0 /*cMillies*/, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
489 (PFNRT)IntNetSendWorker, 4, (uintptr_t)1, (uintptr_t)pu8Buf, (uintptr_t)cb, (uintptr_t)m);
490 ASMAtomicIncU32(&g_pNAT->cUrgPkt);
491 RTSemEventSignal(g_pNAT->m_EventUrgSend);
492 AssertReleaseRC(rc);
493 LogFlowFuncLeave();
494}
495extern "C" void slirp_output(void *pvUser, struct mbuf *m, const uint8_t *pu8Buf, int cb)
496{
497 LogFlowFunc(("ENTER: m:%p, pu8Buf:%p, cb:%d\n", m, pu8Buf, cb));
498 AssertRelease(g_pNAT == pvUser);
499 int rc = RTReqQueueCallEx(g_pNAT->m_hSendQueue, NULL /*ppReq*/, 0 /*cMillies*/, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
500 (PFNRT)IntNetSendWorker, 4, (uintptr_t)0, (uintptr_t)pu8Buf, (uintptr_t)cb, (uintptr_t)m);
501 ASMAtomicIncU32(&g_pNAT->cPkt);
502 RTSemEventSignal(g_pNAT->m_EventSend);
503 AssertReleaseRC(rc);
504 LogFlowFuncLeave();
505}
506
507extern "C" void slirp_output_pending(void *pvUser)
508{
509 AssertMsgFailed(("Unimplemented"));
510}
511
512/**
513 * Worker function for drvNATSend().
514 * @thread "NAT" thread.
515 */
516static void SendWorker(struct mbuf *m, size_t cb)
517{
518 LogFlowFunc(("ENTER: m:%p ,cb:%d\n", m, cb));
519 slirp_input(g_pNAT->m_pNATState, m, cb);
520 LogFlowFuncLeave();
521}
522
523static void IntNetSendWorker(bool fUrg, void *pvFrame, size_t cbFrame, struct mbuf *m)
524{
525 VBoxNetNAT *pThis = g_pNAT;
526 INTNETIFSENDREQ SendReq;
527 int rc;
528
529 LogFlowFunc(("ENTER: urg:%RTbool ,pvFrame:%p, cbFrame:%d, m:%p\n", fUrg, pvFrame, cbFrame, m));
530 if (!fUrg)
531 {
532 /* non-urgent datagramm sender */
533 while ( ASMAtomicReadU32(&g_pNAT->cUrgPkt) != 0
534 || ASMAtomicReadU32(&g_pNAT->cPkt) == 0)
535 rc = RTSemEventWait(g_pNAT->m_EventSend, RT_INDEFINITE_WAIT);
536 }
537 else
538 {
539 while (ASMAtomicReadU32(&g_pNAT->cUrgPkt) == 0)
540 rc = RTSemEventWait(g_pNAT->m_EventUrgSend, RT_INDEFINITE_WAIT);
541 }
542 rc = IntNetRingWriteFrame(&pThis->m_pIfBuf->Send, pvFrame, cbFrame);
543 if (RT_FAILURE(rc))
544 {
545 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
546 SendReq.Hdr.cbReq = sizeof(SendReq);
547 SendReq.pSession = pThis->m_pSession;
548 SendReq.hIf = pThis->m_hIf;
549 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SEND, 0, &SendReq.Hdr);
550
551 rc = IntNetRingWriteFrame(&pThis->m_pIfBuf->Send, pvFrame, cbFrame);
552
553 }
554 if (RT_SUCCESS(rc))
555 {
556 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
557 SendReq.Hdr.cbReq = sizeof(SendReq);
558 SendReq.pSession = pThis->m_pSession;
559 SendReq.hIf = pThis->m_hIf;
560 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SEND, 0, &SendReq.Hdr);
561 }
562 AssertRC((rc));
563 if (RT_FAILURE(rc))
564 Log2(("VBoxNetNAT: Failed to send packet; rc=%Rrc\n", rc));
565
566 if (!fUrg)
567 {
568 ASMAtomicDecU32(&g_pNAT->cPkt);
569 }
570 else {
571 if (ASMAtomicDecU32(&g_pNAT->cUrgPkt) == 0)
572 RTSemEventSignal(g_pNAT->m_EventSend);
573 }
574 slirp_ext_m_free(pThis->m_pNATState, m, (uint8_t *)pvFrame);
575 natNotifyNATThread();
576 LogFlowFuncLeave();
577}
578
579static DECLCALLBACK(int) AsyncIoThread(RTTHREAD pThread, void *pvUser)
580{
581 VBoxNetNAT *pThis = (VBoxNetNAT *)pvUser;
582 int nFDs = -1;
583#ifdef RT_OS_WINDOWS
584 HANDLE *pahEvents = slirp_get_events(pThis->m_pNATState);
585#else /* RT_OS_WINDOWS */
586 unsigned int cPollNegRet = 0;
587#endif /* !RT_OS_WINDOWS */
588
589 LogFlow(("drvNATAsyncIoThread: pThis=%p\n", pThis));
590
591 /*
592 * Polling loop.
593 */
594 for(;;)
595 {
596 /*
597 * To prevent concurrent execution of sending/receiving threads
598 */
599#ifndef RT_OS_WINDOWS
600 nFDs = slirp_get_nsock(pThis->m_pNATState);
601 /* allocation for all sockets + Management pipe */
602 struct pollfd *polls = (struct pollfd *)RTMemAlloc((1 + nFDs) * sizeof(struct pollfd) + sizeof(uint32_t));
603 if (polls == NULL)
604 return VERR_NO_MEMORY;
605
606 /* don't pass the management pipe */
607 slirp_select_fill(pThis->m_pNATState, &nFDs, &polls[1]);
608 unsigned int cMsTimeout = slirp_get_timeout_ms(pThis->m_pNATState);
609
610 polls[0].fd = RTPipeToNative(pThis->m_hPipeRead);
611 /* POLLRDBAND usually doesn't used on Linux but seems used on Solaris */
612 polls[0].events = POLLRDNORM|POLLPRI|POLLRDBAND;
613 polls[0].revents = 0;
614
615 int cChangedFDs = poll(polls, nFDs + 1, cMsTimeout);
616 if (cChangedFDs < 0)
617 {
618 if (errno == EINTR)
619 {
620 Log2(("NAT: signal was caught while sleep on poll\n"));
621 /* No error, just process all outstanding requests but don't wait */
622 cChangedFDs = 0;
623 }
624 else if (cPollNegRet++ > 128)
625 {
626 LogRel(("NAT:Poll returns (%s) suppressed %d\n", strerror(errno), cPollNegRet));
627 cPollNegRet = 0;
628 }
629 }
630
631 if (cChangedFDs >= 0)
632 {
633 slirp_select_poll(pThis->m_pNATState, &polls[1], nFDs);
634 if (polls[0].revents & (POLLRDNORM|POLLPRI|POLLRDBAND))
635 {
636 /* drain the pipe
637 *
638 * Note!
639 * drvNATSend decoupled so we don't know how many times
640 * device's thread sends before we've entered multiplex,
641 * so to avoid false alarm drain pipe here to the very end
642 *
643 * @todo: Probably we should counter drvNATSend to count how
644 * deep pipe has been filed before drain.
645 *
646 */
647 /** @todo XXX: Make it reading exactly we need to drain the
648 * pipe. */
649 char ch;
650 size_t cbRead;
651 RTPipeRead(pThis->m_hPipeRead, &ch, 1, &cbRead);
652 }
653 }
654 /* process _all_ outstanding requests but don't wait */
655 RTReqQueueProcess(pThis->m_hReqQueue, 0);
656 RTMemFree(polls);
657
658#else /* RT_OS_WINDOWS */
659 nFDs = -1;
660 slirp_select_fill(pThis->m_pNATState, &nFDs);
661 DWORD dwEvent = WSAWaitForMultipleEvents(nFDs, pahEvents, FALSE,
662 slirp_get_timeout_ms(pThis->m_pNATState),
663 FALSE);
664 if ( (dwEvent < WSA_WAIT_EVENT_0 || dwEvent > WSA_WAIT_EVENT_0 + nFDs - 1)
665 && dwEvent != WSA_WAIT_TIMEOUT)
666 {
667 int error = WSAGetLastError();
668 LogRel(("NAT: WSAWaitForMultipleEvents returned %d (error %d)\n", dwEvent, error));
669 RTAssertReleasePanic();
670 }
671
672 if (dwEvent == WSA_WAIT_TIMEOUT)
673 {
674 /* only check for slow/fast timers */
675 slirp_select_poll(pThis->m_pNATState, /* fTimeout=*/true, /*fIcmp=*/false);
676 continue;
677 }
678
679 /* poll the sockets in any case */
680 slirp_select_poll(pThis->m_pNATState, /* fTimeout=*/false, /* fIcmp=*/(dwEvent == WSA_WAIT_EVENT_0));
681 /* process _all_ outstanding requests but don't wait */
682 RTReqQueueProcess(pThis->m_hReqQueue, 0);
683#endif /* RT_OS_WINDOWS */
684 }
685
686 return VINF_SUCCESS;
687}
688
689static DECLCALLBACK(int) natSndThread(RTTHREAD pThread, void *pvUser)
690{
691 while (g_pNAT->fIsRunning)
692 RTReqQueueProcess(g_pNAT->m_hSendQueue, 0);
693 return VINF_SUCCESS;
694}
695static DECLCALLBACK(int) natUrgSndThread(RTTHREAD pThread, void *pvUser)
696{
697 while (g_pNAT->fIsRunning)
698 RTReqQueueProcess(g_pNAT->m_hUrgSendQueue, 0);
699 return VINF_SUCCESS;
700}
701
702#ifndef VBOX_WITH_HARDENING
703
704int main(int argc, char **argv, char **envp)
705{
706 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
707 if (RT_FAILURE(rc))
708 return RTMsgInitFailure(rc);
709
710 return TrustedMain(argc, argv, envp);
711}
712
713# if defined(RT_OS_WINDOWS)
714
715static LRESULT CALLBACK WindowProc(HWND hwnd,
716 UINT uMsg,
717 WPARAM wParam,
718 LPARAM lParam
719)
720{
721 if(uMsg == WM_DESTROY)
722 {
723 PostQuitMessage(0);
724 return 0;
725 }
726 return DefWindowProc (hwnd, uMsg, wParam, lParam);
727}
728
729static LPCSTR g_WndClassName = "VBoxNetNatClass";
730
731static DWORD WINAPI MsgThreadProc(__in LPVOID lpParameter)
732{
733 HWND hwnd = 0;
734 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL);
735 bool bExit = false;
736
737 /* Register the Window Class. */
738 WNDCLASS wc;
739 wc.style = 0;
740 wc.lpfnWndProc = WindowProc;
741 wc.cbClsExtra = 0;
742 wc.cbWndExtra = sizeof(void *);
743 wc.hInstance = hInstance;
744 wc.hIcon = NULL;
745 wc.hCursor = NULL;
746 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
747 wc.lpszMenuName = NULL;
748 wc.lpszClassName = g_WndClassName;
749
750 ATOM atomWindowClass = RegisterClass(&wc);
751
752 if (atomWindowClass != 0)
753 {
754 /* Create the window. */
755 hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
756 g_WndClassName, g_WndClassName,
757 WS_POPUPWINDOW,
758 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
759
760 if (hwnd)
761 {
762 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
763 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
764
765 MSG msg;
766 while (GetMessage(&msg, NULL, 0, 0))
767 {
768 TranslateMessage(&msg);
769 DispatchMessage(&msg);
770 }
771
772 DestroyWindow (hwnd);
773
774 bExit = true;
775 }
776
777 UnregisterClass (g_WndClassName, hInstance);
778 }
779
780 if(bExit)
781 {
782 /* no need any accuracy here, in anyway the DHCP server usually gets terminated with TerminateProcess */
783 exit(0);
784 }
785
786 return 0;
787}
788
789
790
791/** (We don't want a console usually.) */
792int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
793{
794#if 0
795 NOREF(hInstance); NOREF(hPrevInstance); NOREF(lpCmdLine); NOREF(nCmdShow);
796
797 HANDLE hThread = CreateThread(
798 NULL, /*__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, */
799 0, /*__in SIZE_T dwStackSize, */
800 MsgThreadProc, /*__in LPTHREAD_START_ROUTINE lpStartAddress,*/
801 NULL, /*__in_opt LPVOID lpParameter,*/
802 0, /*__in DWORD dwCreationFlags,*/
803 NULL /*__out_opt LPDWORD lpThreadId*/
804 );
805
806 if(hThread != NULL)
807 CloseHandle(hThread);
808
809#endif
810 return main(__argc, __argv, environ);
811}
812# endif /* RT_OS_WINDOWS */
813
814#endif /* !VBOX_WITH_HARDENING */
815
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