VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/proxy_pollmgr.c@ 60869

Last change on this file since 60869 was 56300, checked in by vboxsync, 9 years ago

NetworkServices: Updated (C) year.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 17.8 KB
Line 
1/* $Id: proxy_pollmgr.c 56300 2015-06-09 14:36:22Z vboxsync $ */
2/** @file
3 * NAT Network - poll manager.
4 */
5
6/*
7 * Copyright (C) 2013-2015 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#define LOG_GROUP LOG_GROUP_NAT_SERVICE
19
20#include "winutils.h"
21
22#include "proxy_pollmgr.h"
23#include "proxy.h"
24
25#ifndef RT_OS_WINDOWS
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <err.h>
29#include <errno.h>
30#include <poll.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <time.h>
35#include <unistd.h>
36#else
37#include <iprt/err.h>
38#include <stdlib.h>
39#include <string.h>
40#include "winpoll.h"
41#endif
42
43#define POLLMGR_GARBAGE (-1)
44
45struct pollmgr {
46 struct pollfd *fds;
47 struct pollmgr_handler **handlers;
48 nfds_t capacity; /* allocated size of the arrays */
49 nfds_t nfds; /* part of the arrays in use */
50
51 /* channels (socketpair) for static slots */
52 SOCKET chan[POLLMGR_SLOT_STATIC_COUNT][2];
53#define POLLMGR_CHFD_RD 0 /* - pollmgr side */
54#define POLLMGR_CHFD_WR 1 /* - client side */
55} pollmgr;
56
57
58static void pollmgr_loop(void);
59
60static void pollmgr_add_at(int, struct pollmgr_handler *, SOCKET, int);
61static void pollmgr_refptr_delete(struct pollmgr_refptr *);
62
63
64/*
65 * We cannot portably peek at the length of the incoming datagram and
66 * pre-allocate pbuf chain to recvmsg() directly to it. On Linux it's
67 * possible to recv with MSG_PEEK|MSG_TRUC, but extra syscall is
68 * probably more expensive (haven't measured) than doing an extra copy
69 * of data, since typical UDP datagrams are small enough to avoid
70 * fragmentation.
71 *
72 * We can use shared buffer here since we read from sockets
73 * sequentially in a loop over pollfd.
74 */
75u8_t pollmgr_udpbuf[64 * 1024];
76
77
78int
79pollmgr_init(void)
80{
81 struct pollfd *newfds;
82 struct pollmgr_handler **newhdls;
83 nfds_t newcap;
84 int status;
85 nfds_t i;
86
87 pollmgr.fds = NULL;
88 pollmgr.handlers = NULL;
89 pollmgr.capacity = 0;
90 pollmgr.nfds = 0;
91
92 for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
93 pollmgr.chan[i][POLLMGR_CHFD_RD] = -1;
94 pollmgr.chan[i][POLLMGR_CHFD_WR] = -1;
95 }
96
97 for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
98#ifndef RT_OS_WINDOWS
99 status = socketpair(PF_LOCAL, SOCK_DGRAM, 0, pollmgr.chan[i]);
100 if (status < 0) {
101 DPRINTF(("socketpair: %R[sockerr]\n", SOCKERRNO()));
102 goto cleanup_close;
103 }
104#else
105 status = RTWinSocketPair(PF_INET, SOCK_DGRAM, 0, pollmgr.chan[i]);
106 if (RT_FAILURE(status)) {
107 goto cleanup_close;
108 }
109#endif
110 }
111
112
113 newcap = 16; /* XXX: magic */
114 LWIP_ASSERT1(newcap >= POLLMGR_SLOT_STATIC_COUNT);
115
116 newfds = (struct pollfd *)
117 malloc(newcap * sizeof(*pollmgr.fds));
118 if (newfds == NULL) {
119 DPRINTF(("%s: Failed to allocate fds array\n", __func__));
120 goto cleanup_close;
121 }
122
123 newhdls = (struct pollmgr_handler **)
124 malloc(newcap * sizeof(*pollmgr.handlers));
125 if (newhdls == NULL) {
126 DPRINTF(("%s: Failed to allocate handlers array\n", __func__));
127 free(newfds);
128 goto cleanup_close;
129 }
130
131 pollmgr.capacity = newcap;
132 pollmgr.fds = newfds;
133 pollmgr.handlers = newhdls;
134
135 pollmgr.nfds = POLLMGR_SLOT_STATIC_COUNT;
136
137 for (i = 0; i < pollmgr.capacity; ++i) {
138 pollmgr.fds[i].fd = INVALID_SOCKET;
139 pollmgr.fds[i].events = 0;
140 pollmgr.fds[i].revents = 0;
141 }
142
143 return 0;
144
145 cleanup_close:
146 for (i = 0; i < POLLMGR_SLOT_STATIC_COUNT; ++i) {
147 SOCKET *chan = pollmgr.chan[i];
148 if (chan[POLLMGR_CHFD_RD] >= 0) {
149 closesocket(chan[POLLMGR_CHFD_RD]);
150 closesocket(chan[POLLMGR_CHFD_WR]);
151 }
152 }
153
154 return -1;
155}
156
157
158/*
159 * Must be called before pollmgr loop is started, so no locking.
160 */
161SOCKET
162pollmgr_add_chan(int slot, struct pollmgr_handler *handler)
163{
164 if (slot >= POLLMGR_SLOT_FIRST_DYNAMIC) {
165 handler->slot = -1;
166 return -1;
167 }
168
169 pollmgr_add_at(slot, handler, pollmgr.chan[slot][POLLMGR_CHFD_RD], POLLIN);
170 return pollmgr.chan[slot][POLLMGR_CHFD_WR];
171}
172
173
174/*
175 * Must be called from pollmgr loop (via callbacks), so no locking.
176 */
177int
178pollmgr_add(struct pollmgr_handler *handler, SOCKET fd, int events)
179{
180 int slot;
181
182 DPRINTF2(("%s: new fd %d\n", __func__, fd));
183
184 if (pollmgr.nfds == pollmgr.capacity) {
185 struct pollfd *newfds;
186 struct pollmgr_handler **newhdls;
187 nfds_t newcap;
188 nfds_t i;
189
190 newcap = pollmgr.capacity * 2;
191
192 newfds = (struct pollfd *)
193 realloc(pollmgr.fds, newcap * sizeof(*pollmgr.fds));
194 if (newfds == NULL) {
195 DPRINTF(("%s: Failed to reallocate fds array\n", __func__));
196 handler->slot = -1;
197 return -1;
198 }
199
200 pollmgr.fds = newfds; /* don't crash/leak if realloc(handlers) fails */
201 /* but don't update capacity yet! */
202
203 newhdls = (struct pollmgr_handler **)
204 realloc(pollmgr.handlers, newcap * sizeof(*pollmgr.handlers));
205 if (newhdls == NULL) {
206 DPRINTF(("%s: Failed to reallocate handlers array\n", __func__));
207 /* if we failed to realloc here, then fds points to the
208 * new array, but we pretend we still has old capacity */
209 handler->slot = -1;
210 return -1;
211 }
212
213 pollmgr.handlers = newhdls;
214 pollmgr.capacity = newcap;
215
216 for (i = pollmgr.nfds; i < newcap; ++i) {
217 newfds[i].fd = INVALID_SOCKET;
218 newfds[i].events = 0;
219 newfds[i].revents = 0;
220 newhdls[i] = NULL;
221 }
222 }
223
224 slot = pollmgr.nfds;
225 ++pollmgr.nfds;
226
227 pollmgr_add_at(slot, handler, fd, events);
228 return slot;
229}
230
231
232static void
233pollmgr_add_at(int slot, struct pollmgr_handler *handler, SOCKET fd, int events)
234{
235 pollmgr.fds[slot].fd = fd;
236 pollmgr.fds[slot].events = events;
237 pollmgr.fds[slot].revents = 0;
238 pollmgr.handlers[slot] = handler;
239
240 handler->slot = slot;
241}
242
243
244ssize_t
245pollmgr_chan_send(int slot, void *buf, size_t nbytes)
246{
247 SOCKET fd;
248 ssize_t nsent;
249
250 if (slot >= POLLMGR_SLOT_FIRST_DYNAMIC) {
251 return -1;
252 }
253
254 fd = pollmgr.chan[slot][POLLMGR_CHFD_WR];
255 nsent = send(fd, buf, (int)nbytes, 0);
256 if (nsent == SOCKET_ERROR) {
257 DPRINTF(("send on chan %d: %R[sockerr]\n", slot, SOCKERRNO()));
258 return -1;
259 }
260 else if ((size_t)nsent != nbytes) {
261 DPRINTF(("send on chan %d: datagram truncated to %u bytes",
262 slot, (unsigned int)nsent));
263 return -1;
264 }
265
266 return nsent;
267}
268
269
270/**
271 * Receive a pointer sent over poll manager channel.
272 */
273void *
274pollmgr_chan_recv_ptr(struct pollmgr_handler *handler, SOCKET fd, int revents)
275{
276 void *ptr;
277 ssize_t nread;
278
279 if (revents & POLLNVAL) {
280 errx(EXIT_FAILURE, "chan %d: fd invalid", (int)handler->slot);
281 /* NOTREACHED */
282 }
283
284 if (revents & (POLLERR | POLLHUP)) {
285 errx(EXIT_FAILURE, "chan %d: fd error", (int)handler->slot);
286 /* NOTREACHED */
287 }
288
289 LWIP_ASSERT1(revents & POLLIN);
290 nread = recv(fd, (char *)&ptr, sizeof(ptr), 0);
291
292 if (nread == SOCKET_ERROR) {
293 err(EXIT_FAILURE, "chan %d: recv", (int)handler->slot);
294 /* NOTREACHED */
295 }
296 if (nread != sizeof(ptr)) {
297 errx(EXIT_FAILURE, "chan %d: recv: read %d bytes",
298 (int)handler->slot, (int)nread);
299 /* NOTREACHED */
300 }
301
302 return ptr;
303}
304
305
306void
307pollmgr_update_events(int slot, int events)
308{
309 LWIP_ASSERT1(slot >= POLLMGR_SLOT_FIRST_DYNAMIC);
310 LWIP_ASSERT1((nfds_t)slot < pollmgr.nfds);
311
312 pollmgr.fds[slot].events = events;
313}
314
315
316void
317pollmgr_del_slot(int slot)
318{
319 LWIP_ASSERT1(slot >= POLLMGR_SLOT_FIRST_DYNAMIC);
320
321 DPRINTF2(("%s(%d): fd %d ! DELETED\n",
322 __func__, slot, pollmgr.fds[slot].fd));
323
324 pollmgr.fds[slot].fd = INVALID_SOCKET; /* see poll loop */
325}
326
327
328void
329pollmgr_thread(void *ignored)
330{
331 LWIP_UNUSED_ARG(ignored);
332 pollmgr_loop();
333}
334
335
336static void
337pollmgr_loop(void)
338{
339 int nready;
340 SOCKET delfirst;
341 SOCKET *pdelprev;
342 int i;
343
344 for (;;) {
345#ifndef RT_OS_WINDOWS
346 nready = poll(pollmgr.fds, pollmgr.nfds, -1);
347#else
348 int rc = RTWinPoll(pollmgr.fds, pollmgr.nfds,RT_INDEFINITE_WAIT, &nready);
349 if (RT_FAILURE(rc)) {
350 err(EXIT_FAILURE, "poll"); /* XXX: what to do on error? */
351 /* NOTREACHED*/
352 }
353#endif
354
355 DPRINTF2(("%s: ready %d fd%s\n",
356 __func__, nready, (nready == 1 ? "" : "s")));
357
358 if (nready < 0) {
359 if (errno == EINTR) {
360 continue;
361 }
362
363 err(EXIT_FAILURE, "poll"); /* XXX: what to do on error? */
364 /* NOTREACHED*/
365 }
366 else if (nready == 0) { /* cannot happen, we wait forever (-1) */
367 continue; /* - but be defensive */
368 }
369
370
371 delfirst = INVALID_SOCKET;
372 pdelprev = &delfirst;
373
374 for (i = 0; (nfds_t)i < pollmgr.nfds && nready > 0; ++i) {
375 struct pollmgr_handler *handler;
376 SOCKET fd;
377 int revents, nevents;
378
379 fd = pollmgr.fds[i].fd;
380 revents = pollmgr.fds[i].revents;
381
382 /*
383 * Channel handlers can request deletion of dynamic slots
384 * by calling pollmgr_del_slot() that clobbers slot's fd.
385 */
386 if (fd == INVALID_SOCKET && i >= POLLMGR_SLOT_FIRST_DYNAMIC) {
387 /* adjust count if events were pending for that slot */
388 if (revents != 0) {
389 --nready;
390 }
391
392 /* pretend that slot handler requested deletion */
393 nevents = -1;
394 goto update_events;
395 }
396
397 if (revents == 0) {
398 continue; /* next fd */
399 }
400 --nready;
401
402 handler = pollmgr.handlers[i];
403
404 if (handler != NULL && handler->callback != NULL) {
405#if LWIP_PROXY_DEBUG /* DEBUG */
406 if (i < POLLMGR_SLOT_FIRST_DYNAMIC) {
407 if (revents == POLLIN) {
408 DPRINTF2(("%s: ch %d\n", __func__, i));
409 }
410 else {
411 DPRINTF2(("%s: ch %d @ revents 0x%x!\n",
412 __func__, i, revents));
413 }
414 }
415 else {
416 DPRINTF2(("%s: fd %d @ revents 0x%x\n",
417 __func__, fd, revents));
418 }
419#endif /* DEBUG */
420 nevents = (*handler->callback)(handler, fd, revents);
421 }
422 else {
423 DPRINTF0(("%s: invalid handler for fd %d: ", __func__, fd));
424 if (handler == NULL) {
425 DPRINTF0(("NULL\n"));
426 }
427 else {
428 DPRINTF0(("%p (callback = NULL)\n", (void *)handler));
429 }
430 nevents = -1; /* delete it */
431 }
432
433 update_events:
434 if (nevents >= 0) {
435 if (nevents != pollmgr.fds[i].events) {
436 DPRINTF2(("%s: fd %d ! nevents 0x%x\n",
437 __func__, fd, nevents));
438 }
439 pollmgr.fds[i].events = nevents;
440 }
441 else if (i < POLLMGR_SLOT_FIRST_DYNAMIC) {
442 /* Don't garbage-collect channels. */
443 DPRINTF2(("%s: fd %d ! DELETED (channel %d)\n",
444 __func__, fd, i));
445 pollmgr.fds[i].fd = INVALID_SOCKET;
446 pollmgr.fds[i].events = 0;
447 pollmgr.fds[i].revents = 0;
448 pollmgr.handlers[i] = NULL;
449 }
450 else {
451 DPRINTF2(("%s: fd %d ! DELETED\n", __func__, fd));
452
453 /* schedule for deletion (see g/c loop for details) */
454 *pdelprev = i; /* make previous entry point to us */
455 pdelprev = &pollmgr.fds[i].fd;
456
457 pollmgr.fds[i].fd = INVALID_SOCKET; /* end of list (for now) */
458 pollmgr.fds[i].events = POLLMGR_GARBAGE;
459 pollmgr.fds[i].revents = 0;
460 pollmgr.handlers[i] = NULL;
461 }
462 } /* processing loop */
463
464
465 /*
466 * Garbage collect and compact the array.
467 *
468 * We overload pollfd::fd of garbage entries to store the
469 * index of the next garbage entry. The garbage list is
470 * co-directional with the fds array. The index of the first
471 * entry is in "delfirst", the last entry "points to"
472 * INVALID_SOCKET.
473 *
474 * See update_events code for nevents < 0 at the end of the
475 * processing loop above.
476 */
477 while (delfirst != INVALID_SOCKET) {
478 const int last = pollmgr.nfds - 1;
479
480 /*
481 * We want a live entry in the last slot to swap into the
482 * freed slot, so make sure we have one.
483 */
484 if (pollmgr.fds[last].events == POLLMGR_GARBAGE /* garbage */
485 || pollmgr.fds[last].fd == INVALID_SOCKET) /* or killed */
486 {
487 /* drop garbage entry at the end of the array */
488 --pollmgr.nfds;
489
490 if (delfirst == last) {
491 /* congruent to delnext >= pollmgr.nfds test below */
492 delfirst = INVALID_SOCKET; /* done */
493 }
494 }
495 else {
496 const SOCKET delnext = pollmgr.fds[delfirst].fd;
497
498 /* copy live entry at the end to the first slot being freed */
499 pollmgr.fds[delfirst] = pollmgr.fds[last]; /* struct copy */
500 pollmgr.handlers[delfirst] = pollmgr.handlers[last];
501 pollmgr.handlers[delfirst]->slot = (int)delfirst;
502 --pollmgr.nfds;
503
504 if ((nfds_t)delnext >= pollmgr.nfds) {
505 delfirst = INVALID_SOCKET; /* done */
506 }
507 else {
508 delfirst = delnext;
509 }
510 }
511
512 pollmgr.fds[last].fd = INVALID_SOCKET;
513 pollmgr.fds[last].events = 0;
514 pollmgr.fds[last].revents = 0;
515 pollmgr.handlers[last] = NULL;
516 }
517 } /* poll loop */
518}
519
520
521/**
522 * Create strongly held refptr.
523 */
524struct pollmgr_refptr *
525pollmgr_refptr_create(struct pollmgr_handler *ptr)
526{
527 struct pollmgr_refptr *rp;
528
529 LWIP_ASSERT1(ptr != NULL);
530
531 rp = (struct pollmgr_refptr *)malloc(sizeof (*rp));
532 if (rp == NULL) {
533 return NULL;
534 }
535
536 sys_mutex_new(&rp->lock);
537 rp->ptr = ptr;
538 rp->strong = 1;
539 rp->weak = 0;
540
541 return rp;
542}
543
544
545static void
546pollmgr_refptr_delete(struct pollmgr_refptr *rp)
547{
548 if (rp == NULL) {
549 return;
550 }
551
552 LWIP_ASSERT1(rp->strong == 0);
553 LWIP_ASSERT1(rp->weak == 0);
554
555 sys_mutex_free(&rp->lock);
556 free(rp);
557}
558
559
560/**
561 * Add weak reference before "rp" is sent over a poll manager channel.
562 */
563void
564pollmgr_refptr_weak_ref(struct pollmgr_refptr *rp)
565{
566 sys_mutex_lock(&rp->lock);
567
568 LWIP_ASSERT1(rp->ptr != NULL);
569 LWIP_ASSERT1(rp->strong > 0);
570
571 ++rp->weak;
572
573 sys_mutex_unlock(&rp->lock);
574}
575
576
577/**
578 * Try to get the pointer from implicitely weak reference we've got
579 * from a channel.
580 *
581 * If we detect that the object is still strongly referenced, but no
582 * longer registered with the poll manager we abort strengthening
583 * conversion here b/c lwip thread callback is already scheduled to
584 * destruct the object.
585 */
586struct pollmgr_handler *
587pollmgr_refptr_get(struct pollmgr_refptr *rp)
588{
589 struct pollmgr_handler *handler;
590 size_t weak;
591
592 sys_mutex_lock(&rp->lock);
593
594 LWIP_ASSERT1(rp->weak > 0);
595 weak = --rp->weak;
596
597 handler = rp->ptr;
598 if (handler == NULL) {
599 LWIP_ASSERT1(rp->strong == 0);
600 sys_mutex_unlock(&rp->lock);
601 if (weak == 0) {
602 pollmgr_refptr_delete(rp);
603 }
604 return NULL;
605 }
606
607 LWIP_ASSERT1(rp->strong == 1);
608
609 /*
610 * Here we woild do:
611 *
612 * ++rp->strong;
613 *
614 * and then, after channel handler is done, we would decrement it
615 * back.
616 *
617 * Instead we check that the object is still registered with poll
618 * manager. If it is, there's no race with lwip thread trying to
619 * drop its strong reference, as lwip thread callback to destruct
620 * the object is always scheduled by its poll manager callback.
621 *
622 * Conversly, if we detect that the object is no longer registered
623 * with poll manager, we immediately abort. Since channel handler
624 * can't do anything useful anyway and would have to return
625 * immediately.
626 *
627 * Since channel handler would always find rp->strong as it had
628 * left it, just elide extra strong reference creation to avoid
629 * the whole back-and-forth.
630 */
631
632 if (handler->slot < 0) { /* no longer polling */
633 sys_mutex_unlock(&rp->lock);
634 return NULL;
635 }
636
637 sys_mutex_unlock(&rp->lock);
638 return handler;
639}
640
641
642/**
643 * Remove (the only) strong reference.
644 *
645 * If it were real strong/weak pointers, we should also call
646 * destructor for the referenced object, but
647 */
648void
649pollmgr_refptr_unref(struct pollmgr_refptr *rp)
650{
651 sys_mutex_lock(&rp->lock);
652
653 LWIP_ASSERT1(rp->strong == 1);
654 --rp->strong;
655
656 if (rp->strong > 0) {
657 sys_mutex_unlock(&rp->lock);
658 }
659 else {
660 size_t weak;
661
662 /* void *ptr = rp->ptr; */
663 rp->ptr = NULL;
664
665 /* delete ptr; // see doc comment */
666
667 weak = rp->weak;
668 sys_mutex_unlock(&rp->lock);
669 if (weak == 0) {
670 pollmgr_refptr_delete(rp);
671 }
672 }
673}
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