pxudp.c revision 1c08b0ec28ca5c600c21c0ab5a53cae73f1c821d
/* -*- indent-tabs-mode: nil; -*- */
#define LOG_GROUP LOG_GROUP_NAT_SERVICE
#include "winutils.h"
#include "proxy.h"
#include "proxy_pollmgr.h"
#include "pxremap.h"
#ifndef RT_OS_WINDOWS
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <poll.h>
#include <err.h> /* BSD'ism */
#else
#include <stdlib.h>
#include <stdio.h>
#include "winpoll.h"
#endif
struct pxudp {
/**
* Our poll manager handler.
*/
struct pollmgr_handler pmhdl;
/**
* lwIP ("internal") side of the proxied connection.
*/
/**
* Host ("external") side of the proxied connection.
*/
/**
* For some protocols (notably: DNS) we know we are getting just
* one reply, so we don't want the pcb and the socket to sit there
* waiting to be g/c'ed by timeout. This field counts request and
* replies for them.
*/
int count;
/**
* Mailbox for inbound pbufs.
*
* XXX: since we have single producer and single consumer we can
* use lockless ringbuf like for pxtcp.
*/
/**
* lwIP thread's strong reference to us.
*/
struct pollmgr_refptr *rp;
/*
*/
};
static struct pxudp *pxudp_allocate(void);
static void pxudp_drain_inmbox(struct pxudp *);
static void pxudp_free(struct pxudp *);
/* poll manager callbacks for pxudp related channels */
/* poll manager callbacks for individual sockets */
/* convenience function for poll manager callback */
static int pxudp_schedule_delete(struct pxudp *);
/* lwip thread callbacks called via proxy_lwip_post() */
static void pxudp_pcb_delete_pxudp(void *);
/* udp pcb callbacks &c */
static void pxudp_pcb_expired(struct pxudp *);
static void pxudp_pcb_write_inbound(void *);
static void pxudp_pcb_forward_inbound(struct pxudp *);
/* poll manager handlers for pxudp channels */
static struct pollmgr_handler pxudp_pmgr_chan_add_hdl;
static struct pollmgr_handler pxudp_pmgr_chan_del_hdl;
void
pxudp_init(void)
{
/*
* Create channels.
*/
}
/**
* Syntactic sugar for sending pxudp pointer over poll manager
* channel. Used by lwip thread functions.
*/
static ssize_t
{
}
/**
* Syntactic sugar for sending weak reference to pxudp over poll
* manager channel. Used by lwip thread functions.
*/
static ssize_t
{
}
/**
* Counterpart of pxudp_chan_send().
*/
static struct pxudp *
{
return pxudp;
}
/**
* Counterpart of pxudp_chan_send_weak().
*/
struct pxudp *
{
struct pollmgr_refptr *rp;
struct pollmgr_handler *base;
return pxudp;
}
/**
* POLLMGR_CHAN_PXUDP_ADD handler.
*
* Get new pxudp from lwip thread and start polling its socket.
*/
static int
{
int status;
DPRINTF(("pxudp_add: new pxudp %p; pcb %p\n",
if (status < 0) {
}
return POLLIN;
}
/**
* POLLMGR_CHAN_PXUDP_DEL handler.
*/
static int
{
return POLLIN;
}
/*
* Go back to lwip thread to delete after any pending callbacks
* for unprocessed inbound traffic are drained.
*/
return POLLIN;
}
static struct pxudp *
pxudp_allocate(void)
{
return NULL;
}
return NULL;
}
return NULL;
}
do { \
} while (0)
return pxudp;
}
static void
{
void *ptr;
return;
}
pbuf_free(p);
}
}
static void
{
}
/**
* Dissociate pxudp and its udp_pcb.
*
* Unlike its TCP cousin returns the pcb since UDP pcbs need to be
* actively deleted, so save callers the trouble of saving a copy
* before calling us.
*/
static struct udp_pcb *
{
return NULL;
}
return pcb;
}
/**
* Lwip thread callback invoked via pxudp::msg_delete
*
* Since we use static messages to communicate to the lwip thread, we
* cannot delete pxudp without making sure there are no unprocessed
* messages in the lwip thread mailbox.
*
* The easiest way to ensure that is to send this "delete" message as
* the last one and when it's processed we know there are no more and
* it's safe to delete pxudp.
*
* Channel callback should use pxudp_schedule_delete() convenience
* function defined below.
*/
static void
pxudp_pcb_delete_pxudp(void *arg)
{
}
}
}
/**
* Poll manager callback should use this convenience wrapper to
* schedule pxudp deletion on the lwip thread and to deregister from
* the poll manager.
*/
static int
{
/*
* If pollmgr_refptr_get() is called by any channel before
* scheduled deletion happens, let them know we are gone.
*/
/*
* Schedule deletion. Since poll manager thread may be pre-empted
* right after we send the message, the deletion may actually
* happen on the lwip thread before we return from this function,
* so it's not safe to refer to pxudp after this call.
*/
/* tell poll manager to deregister us */
return -1;
}
/**
* New proxied UDP conversation created.
* Global callback for udp_proxy_accept().
*/
static void
{
int mapping;
int sdom;
LWIP_ASSERT1(p != NULL);
pxudp = pxudp_allocate();
DPRINTF(("pxudp_allocate: failed\n"));
pbuf_free(p);
return;
}
#if 0 /* XXX: DNS IPv6->IPv4 remapping hack */
if (mapping == PXREMAP_MAPPED
&& PCB_ISIPV6(newpcb))
{
/*
* "Remap" DNS over IPv6 to IPv4 since Ubuntu dnsmasq does not
* listen on IPv6.
*/
}
#endif /* DNS IPv6->IPv4 remapping hack */
if (sock == INVALID_SOCKET) {
pbuf_free(p);
return;
}
/* dispatch directly instead of calling pxudp_pcb_recv() */
}
/**
* udp_recv() callback.
*/
static void
{
if (p != NULL) {
}
else {
}
}
static void
{
}
pbuf_free(p);
}
/**
* Proxy udp_pcbs are expired by timer, which is signaled by passing
* NULL pbuf to the udp_recv() callback. At that point the pcb is
* removed from the list of proxy udp pcbs so no new datagrams will be
* delivered.
*/
static void
{
DPRINTF2(("%s: pxudp %p, pcb %p, sock %d: expired\n",
}
}
/**
*/
static int
{
struct pbuf *p;
return pxudp_schedule_delete(pxudp);
}
/*
* XXX: AFAICS, there's no way to match the error with the
* outgoing datagram that triggered it, since we do non-blocking
* sends from lwip thread.
*/
int sockerr = -1;
int status;
if (status < 0) {
DPRINTF(("%s: sock %d: SO_ERROR failed with errno %d\n",
}
else {
DPRINTF(("%s: sock %d: errno %d\n",
}
}
return POLLIN;
}
if (nread == SOCKET_ERROR) {
return POLLIN;
}
if (p == NULL) {
return POLLIN;
}
pbuf_free(p);
return POLLIN;
}
pbuf_free(p);
return POLLIN;
}
return POLLIN;
}
/**
* Callback from poll manager to trigger sending to guest.
*/
static void
pxudp_pcb_write_inbound(void *ctx)
{
return;
}
}
static void
{
struct pbuf *p;
return;
}
if (timo == SYS_MBOX_EMPTY) {
return;
}
DPRINTF(("%s: udp_send(pcb %p) err %d\n",
}
pbuf_free(p);
/*
* If we enabled counting in pxudp_pcb_forward_outbound() check
* that we have (all) the reply(s).
*/
}
}
}