pxtcp.c revision 7ab47b96268d2f9deec494cfc079642eb4df6c01
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/* -*- indent-tabs-mode: nil; -*- */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include "lwip/tcp_impl.h" /* XXX: to access tcp_abandon() */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * Different OSes have different quirks in reporting POLLHUP for TCP
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * Using shutdown(2) "how" values here would be more readable, but
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * since SHUT_RD is 0, we can't use 0 for "none", unfortunately.
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#elif defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS)
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync# define HAVE_TCP_POLLHUP POLLIN /* reported when remote closes */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync# define HAVE_TCP_POLLHUP (POLLIN|POLLOUT) /* reported when both directions are closed */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * Ring buffer for inbound data. Filled with data from the host
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * socket on poll manager thread. Data consumed by scheduling
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * tcp_write() to the pcb on the lwip thread.
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * NB: There is actually third party present, the lwip stack itself.
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * Thus the buffer doesn't have dual free vs. data split, but rather
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * three-way free / send and unACKed data / unsent data split.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Start of free space, producer writes here (up till "unacked").
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Start of sent but unacknowledged data. The data are "owned" by
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * the stack as it may need to retransmit. This is the free space
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * limit for producer.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Start of unsent data, consumer reads/sends from here (up till
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * "vacant"). Not declared volatile since it's only accessed from
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * the consumer thread.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Our poll manager handler. Must be first, strong/weak
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * references depend on this "inheritance".
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * lwIP (internal/guest) side of the proxied connection.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Host (external) side of the proxied connection.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Socket events we are currently polling for.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Socket error. Currently used to save connect(2) errors so that
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * we can decide if we need to send ICMP error.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Interface that we have got the SYN from. Needed to send ICMP
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * with correct source address.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * For tentatively accepted connections for which we are in
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * process of connecting to the real destination this is the
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * initial pbuf that we might need to build ICMP error.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * When connection is established this is used to hold outbound
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pbuf chain received by pxtcp_pcb_recv() but not yet completely
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * forwarded over the socket. We cannot "return" it to lwIP since
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * the head of the chain is already sent and freed.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Guest has closed its side. Reported to pxtcp_pcb_recv() only
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * once and we might not be able to forward it immediately if we
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * have unsent pbuf.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Outbound half-close has been done on the socket.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * External has closed its side. We might not be able to forward
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * it immediately if we have unforwarded data.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Inbound half-close has been done on the pcb.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * On systems that report POLLHUP as soon as the final FIN is
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * received on a socket we cannot continue polling for the rest of
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * input, so we have to read (pull) last data from the socket on
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * the lwIP thread instead of polling/pushing it from the poll
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * manager thread. See comment in pxtcp_pmgr_pump() POLLHUP case.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * When poll manager schedules delete we may not be able to delete
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * a pxtcp immediately if not all inbound data has been acked by
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * the guest: lwIP may need to resend and the data are in pxtcp's
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * inbuf::buf. We defer delete until all data are acked to
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp_pcb_sent().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Ring-buffer for inbound data.
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync * lwIP thread's strong reference to us.
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync * We use static messages to call functions on the lwIP thread to
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync * void malloc/free overhead.
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync struct tcpip_msg msg_reset; /* reset connection and delete pxtcp */
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync struct tcpip_msg msg_accept; /* confirm accept of proxied connection */
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync struct tcpip_msg msg_outbound; /* trigger send of outbound data */
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync struct tcpip_msg msg_inbound; /* trigger send of inbound data */
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync struct tcpip_msg msg_inpull; /* trigger pull of last inbound data */
615c2f5544718590f05af51eff75bd1bbac4be54vboxsyncstatic void pxtcp_pcb_associate(struct pxtcp *, struct tcp_pcb *);
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync/* poll manager callbacks for pxtcp related channels */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_pmgr_chan_add(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_pmgr_chan_pollout(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_pmgr_chan_pollin(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_pmgr_chan_del(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_pmgr_chan_reset(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/* helper functions for sending/receiving pxtcp over poll manager channels */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t pxtcp_chan_send(enum pollmgr_slot_t, struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t pxtcp_chan_send_weak(enum pollmgr_slot_t, struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pxtcp *pxtcp_chan_recv(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pxtcp *pxtcp_chan_recv_strong(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/* poll manager callbacks for individual sockets */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_pmgr_connect(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_pmgr_pump(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/* get incoming traffic into ring buffer */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t pxtcp_sock_read(struct pxtcp *, int *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t pxtcp_sock_recv(struct pxtcp *, IOVEC *, size_t); /* default */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/* convenience functions for poll manager callbacks */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/* lwip thread callbacks called via proxy_lwip_post() */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_delete_pxtcp(void *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_reset_pxtcp(void *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_accept_refuse(void *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_accept_confirm(void *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_write_outbound(void *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_write_inbound(void *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_pull_inbound(void *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/* tcp pcb callbacks */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t pxtcp_pcb_heard(void *, struct tcp_pcb *, err_t); /* global */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t pxtcp_pcb_accept(void *, struct tcp_pcb *, err_t);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t pxtcp_pcb_connected(void *, struct tcp_pcb *, err_t);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t pxtcp_pcb_recv(void *, struct tcp_pcb *, struct pbuf *, err_t);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t pxtcp_pcb_sent(void *, struct tcp_pcb *, u16_t);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t pxtcp_pcb_poll(void *, struct tcp_pcb *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t pxtcp_pcb_forward_outbound(struct pxtcp *, struct pbuf *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_forward_outbound_close(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t pxtcp_sock_send(struct pxtcp *, IOVEC *, size_t);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_forward_inbound(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_forward_inbound_close(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncDECLINLINE(int) pxtcp_pcb_forward_inbound_done(const struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_schedule_poll(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_reject(struct netif *, struct tcp_pcb *, struct pbuf *, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncDECLINLINE(void) pxtcp_pcb_maybe_deferred_delete(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/* poll manager handlers for pxtcp channels */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pollmgr_handler pxtcp_pmgr_chan_add_hdl;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pollmgr_handler pxtcp_pmgr_chan_pollout_hdl;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pollmgr_handler pxtcp_pmgr_chan_pollin_hdl;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pollmgr_handler pxtcp_pmgr_chan_del_hdl;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pollmgr_handler pxtcp_pmgr_chan_reset_hdl;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Init PXTCP - must be run when neither lwIP tcpip thread, nor poll
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * manager threads haven't been created yet.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Create channels.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync } while (0)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CHANNEL(POLLMGR_CHAN_PXTCP_ADD, pxtcp_pmgr_chan_add);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CHANNEL(POLLMGR_CHAN_PXTCP_POLLIN, pxtcp_pmgr_chan_pollin);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CHANNEL(POLLMGR_CHAN_PXTCP_POLLOUT, pxtcp_pmgr_chan_pollout);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CHANNEL(POLLMGR_CHAN_PXTCP_DEL, pxtcp_pmgr_chan_del);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CHANNEL(POLLMGR_CHAN_PXTCP_RESET, pxtcp_pmgr_chan_reset);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Listen to outgoing connection from guest(s).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Syntactic sugar for sending pxtcp pointer over poll manager
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * channel. Used by lwip thread functions.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_chan_send(enum pollmgr_slot_t slot, struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pollmgr_chan_send(slot, &pxtcp, sizeof(pxtcp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Syntactic sugar for sending weak reference to pxtcp over poll
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * manager channel. Used by lwip thread functions.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_chan_send_weak(enum pollmgr_slot_t slot, struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pollmgr_chan_send(slot, &pxtcp->rp, sizeof(pxtcp->rp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Counterpart of pxtcp_chan_send().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pxtcp *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_chan_recv(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = (struct pxtcp *)pollmgr_chan_recv_ptr(handler, fd, revents);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Counterpart of pxtcp_chan_send_weak().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pxtcp *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_chan_recv_strong(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync rp = (struct pollmgr_refptr *)pollmgr_chan_recv_ptr(handler, fd, revents);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync base = (struct pollmgr_handler *)pollmgr_refptr_get(rp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Register pxtcp with poll manager.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Used for POLLMGR_CHAN_PXTCP_ADD and by port-forwarding. Since
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * error handling is different in these two cases, we leave it up to
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * the caller.
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync status = pollmgr_add(&pxtcp->pmhdl, pxtcp->sock, pxtcp->events);
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync * Unregister pxtcp with poll manager.
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync * Used for POLLMGR_CHAN_PXTCP_RESET and by port-forwarding (on error
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync * POLLMGR_CHAN_PXTCP_ADD handler.
91b5f2a7d9797385e53af76c22883fa15fd25adfvboxsync * Get new pxtcp from lwip thread and start polling its socket.
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsyncpxtcp_pmgr_chan_add(struct pollmgr_handler *handler, SOCKET fd, int revents)
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync DPRINTF0(("pxtcp_add: new pxtcp %p; pcb %p; sock %d\n",
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync * POLLMGR_CHAN_PXTCP_POLLOUT handler.
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync * pxtcp_pcb_forward_outbound() on the lwIP thread tried to send data
d8818699735c83c36fc9555f85e6d86b610cdc67vboxsync * and failed, it now requests us to poll the socket for POLLOUT and
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync * schedule pxtcp_pcb_forward_outbound() when sock is writable again.
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsyncpxtcp_pmgr_chan_pollout(struct pollmgr_handler *handler, SOCKET fd, int revents)
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync pxtcp = pxtcp_chan_recv_strong(handler, fd, revents);
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync DPRINTF0(("pxtcp_pollout: pxtcp %p\n", (void *)pxtcp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pollmgr_update_events(pxtcp->pmhdl.slot, pxtcp->events);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * POLLMGR_CHAN_PXTCP_POLLIN handler.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_chan_pollin(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = pxtcp_chan_recv_strong(handler, fd, revents);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("pxtcp_pollin: pxtcp %p\n", (void *)pxtcp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pollmgr_update_events(pxtcp->pmhdl.slot, pxtcp->events);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * POLLMGR_CHAN_PXTCP_DEL handler.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Schedule pxtcp deletion. We only need this if host system doesn't
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * report POLLHUP for fully closed tcp sockets.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_chan_del(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = pxtcp_chan_recv_strong(handler, fd, revents);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->outbound_close_done); /* EOF sent */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif /* !(HAVE_TCP_POLLHUP & POLLOUT) */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * POLLMGR_CHAN_PXTCP_RESET handler.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Close the socket with RST and delete pxtcp.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_chan_reset(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = pxtcp_chan_recv_strong(handler, fd, revents);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF0(("PXTCP_RESET: pxtcp %p; pcb %p; sock %d\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pxtcp *
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->inbuf.buf = (char *)malloc(pxtcp->inbuf.bufsize);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync } while (0)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CALLBACK_MSG(msg_accept, pxtcp_pcb_accept_confirm);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CALLBACK_MSG(msg_outbound, pxtcp_pcb_write_outbound);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CALLBACK_MSG(msg_inbound, pxtcp_pcb_write_inbound);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Exported to fwtcp to create pxtcp for incoming port-forwarded
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * connections. Completed with pcb in pxtcp_pcb_connect().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_associate(struct pxtcp *pxtcp, struct tcp_pcb *pcb)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Counterpart to pxtcp_create_forwarded() to destruct pxtcp that
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * fwtcp failed to register with poll manager to post to lwip thread
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * for doing connect.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We must have dissociated from a fully closed pcb immediately
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * since lwip recycles them and we don't wan't to mess with what
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * would be someone else's pcb that we happen to have a stale
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pointer to.
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync * Lwip thread callback invoked via pxtcp::msg_delete
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync * Since we use static messages to communicate to the lwip thread, we
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync * cannot delete pxtcp without making sure there are no unprocessed
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * messages in the lwip thread mailbox.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * The easiest way to ensure that is to send this "delete" message as
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * the last one and when it's processed we know there are no more and
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * it's safe to delete pxtcp.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Poll manager handlers should use pxtcp_schedule_delete()
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * convenience function.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb, pxtcp->sock,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->inbound_close); /* not necessarily done */
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * pxtcp is no longer registered with poll manager, so it's safe
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * to close the socket.
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * We might have already dissociated from a fully closed pcb, or
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * guest might have sent us a reset while msg_delete was in
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * transit. If there's no pcb, we are done.
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * Have we completely forwarded all inbound traffic to the guest?
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * We may still be waiting for ACKs. We may have failed to send
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * some of the data (tcp_write() failed with ERR_MEM). We may
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * have failed to send the FIN (tcp_shutdown() failed with
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * ERR_MEM).
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync " unacked %d, unsent %d, vacant %d, %s - DEFER!\n",
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp->inbound_close_done ? "FIN sent" : "FIN is NOT sent"));
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * If we couldn't delete pxtcp right away in the msg_delete callback
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * from the poll manager thread, we repeat the check at the end of
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * relevant pcb callbacks.
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsyncpxtcp_pcb_maybe_deferred_delete(struct pxtcp *pxtcp)
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync if (pxtcp->deferred_delete && pxtcp_pcb_forward_inbound_done(pxtcp)) {
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * Poll manager callbacks should use this convenience wrapper to
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * schedule pxtcp deletion on the lwip thread and to deregister from
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * the poll manager.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * If pollmgr_refptr_get() is called by any channel before
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * scheduled deletion happens, let them know we are gone.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Schedule deletion. Since poll manager thread may be pre-empted
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * right after we send the message, the deletion may actually
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * happen on the lwip thread before we return from this function,
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * so it's not safe to refer to pxtcp after this call.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* tell poll manager to deregister us */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Lwip thread callback invoked via pxtcp::msg_reset
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Like pxtcp_pcb_delete(), but sends RST to the guest before
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * deleting this pxtcp.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb, pxtcp->sock));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Poll manager callbacks should use this convenience wrapper to
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * schedule pxtcp reset and deletion on the lwip thread and to
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * deregister from the poll manager.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * See pxtcp_schedule_delete() for additional comments.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Reject proxy connection attempt. Depending on the cause (sockerr)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * we may just drop the pcb silently, generate an ICMP datagram or
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * send TCP reset.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_reject(struct netif *netif, struct tcp_pcb *pcb,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync icmp6_dest_unreach(p, ICMP6_DUR_ADDRESS); /* XXX: ??? */
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * Called from poll manager thread via pxtcp::msg_accept when proxy
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * failed to connect to the destination. Also called when we failed
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * to register pxtcp with poll manager.
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * This is like pxtcp_pcb_reset_pxtcp() but is more discriminate in
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * how this unestablished connection is terminated.
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync DPRINTF0(("%s: pxtcp %p, pcb %p, sock %d: %R[sockerr]\n",
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp_pcb_reject(pxtcp->netif, pcb, pxtcp->unsent, pxtcp->sockerr);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * Convenience wrapper for poll manager connect callback to reject
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * connection attempt.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Like pxtcp_schedule_reset(), but the callback is more discriminate
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * in how this unestablished connection is terminated.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->msg_accept.msg.cb.function = pxtcp_pcb_accept_refuse;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Global tcp_proxy_accept() callback for proxied outgoing TCP
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * connections from guest(s).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_heard(void *arg, struct tcp_pcb *newpcb, err_t error)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * TCP first calls accept callback when it receives the first SYN
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * and "tentatively accepts" new proxied connection attempt. When
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * proxy "confirms" the SYN and sends SYN|ACK and the guest
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * replies with ACK the accept callback is called again, this time
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * with the established connection.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxremap_outbound_ipX(PCB_ISIPV6(newpcb), &dst_addr, &newpcb->local_ip);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* save initial datagram in case we need to reply with ICMP */
4d93fcdfb645b86163cfea77f687172295988d16vboxsync nsent = pxtcp_chan_send(POLLMGR_CHAN_PXTCP_ADD, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_reject(ip_current_netif(), newpcb, p, sockerr);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_proxy_accept() callback for accepted proxied outgoing TCP
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * connections from guest(s). This is "real" accept with three-way
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * handshake completed.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_accept(void *arg, struct tcp_pcb *pcb, err_t error)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* send any inbound data that are already queued */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Initial poll manager callback for proxied outgoing TCP connections.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp_pcb_accept() sets pxtcp::pmhdl::callback to this.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Waits for connect(2) to the destination to complete. On success
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * replaces itself with pxtcp_pmgr_pump() callback common to all
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * established TCP connections.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_connect(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync socklen_t optlen = (socklen_t)sizeof(pxtcp->sockerr);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync status = getsockopt(pxtcp->sock, SOL_SOCKET, SO_ERROR,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (status == SOCKET_ERROR) { /* should not happen */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: sock %d: SO_ERROR failed: %R[sockerr]\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (revents & POLLOUT) { /* connect is successful */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* confirm accept to the guest */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Switch to common callback used for all established proxied
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * connections.
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * Initially we poll for incoming traffic only. Outgoing
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * traffic is fast-forwarded by pxtcp_pcb_recv(); if it fails
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * it will ask us to poll for POLLOUT too.
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync /* should never get here */
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync DPRINTF0(("%s: pxtcp %p, sock %d: unexpected revents 0x%x\n",
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * Called from poll manager thread via pxtcp::msg_accept when proxy
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * connected to the destination. Finalize accept by sending SYN|ACK
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * to the guest.
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync /* we are not going to reply with ICMP, so we can drop initial pbuf */
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * If lwIP failed to enqueue SYN|ACK because it's out of pbufs it
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * abandons the pcb. Retrying that is not very easy, since it
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * would require keeping "fractional state". From guest's point
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * of view there is no reply to its SYN so it will either resend
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * the SYN (effetively triggering full connection retry for us),
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * or it will eventually time out.
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_RESET, pxtcp);
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * else if (error != ERR_OK): even if tcp_output() failed with
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * ERR_MEM - don't give up, that SYN|ACK is enqueued and will be
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * retransmitted eventually.
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * Entry point for port-forwarding.
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * fwtcp accepts new incoming connection, creates pxtcp for the socket
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * (with no pcb yet) and adds it to the poll manager (polling for
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * errors only). Then it calls this function to construct the pcb and
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * perform connection to the guest.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_connect(struct pxtcp *pxtcp, const struct fwspec *fwspec)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync status = getpeername(pxtcp->sock, (struct sockaddr *)&ss, &sslen);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* nit: comapres PF and AF, but they are the same everywhere */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync status = fwany_ipX_addr_set_src(&src_addr, (const struct sockaddr *)&ss);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync const struct sockaddr_in *peer4 = (const struct sockaddr_in *)&ss;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync memcpy(&dst_addr.ip4, &fwspec->dst.sin.sin_addr, sizeof(ip_addr_t));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else { /* PF_INET6 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync const struct sockaddr_in6 *peer6 = (const struct sockaddr_in6 *)&ss;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync memcpy(&dst_addr.ip6, &fwspec->dst.sin6.sin6_addr, sizeof(ip6_addr_t));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* lwip port arguments are in host order */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync error = tcp_proxy_bind(pcb, ipX_2_ip(&src_addr), src_port);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync error = tcp_connect(pcb, ipX_2_ip(&dst_addr), dst_port,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_RESET, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Port-forwarded connection to guest is successful, pump data.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_connected(void *arg, struct tcp_pcb *pcb, err_t error)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(error == ERR_OK); /* always called with ERR_OK */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb, pxtcp->sock));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* ACK on connection is like ACK on data in pxtcp_pcb_sent() */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_POLLIN, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_recv() callback.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t error)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(error == ERR_OK); /* always called with ERR_OK */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Have we done sending previous batch?
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (p != NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Return an error to tell TCP to hold onto that pbuf.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * It will be presented to us later from tcp_fasttmr().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Unlike data, p == NULL indicating orderly shutdown is
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * NOT presented to us again
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Guest closed?
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (p == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Got data, send what we can without blocking.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Guest half-closed its TX side of the connection.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Called either immediately from pxtcp_pcb_recv() when it gets NULL,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * or from pxtcp_pcb_forward_outbound() when it finishes forwarding
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * previously unsent data and sees pxtcp::outbound_close flag saved by
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp_pcb_recv().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_forward_outbound_close(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, tcp_debug_state_str(pcb->state)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* set the flag first, since shutdown() may trigger POLLHUP */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync shutdown(pxtcp->sock, SHUT_WR); /* half-close the socket */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We need to nudge poll manager manually, since OS will not
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * report POLLHUP.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_DEL, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* no more outbound data coming to us */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * If we have already done inbound close previously (active close
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * on the pcb), then we must not hold onto a pcb in TIME_WAIT
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * state since those will be recycled by lwip when it runs out of
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * free pcbs in the pool.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * The test is true also for a pcb in CLOSING state that waits
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * just for the ACK of its FIN (to transition to TIME_WAIT).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Forward outbound data from pcb to socket.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Called by pxtcp_pcb_recv() to forward new data and by callout
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * triggered by POLLOUT on the socket to send previously unsent data.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * (Re)scehdules one-time callout if not all data are sent.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_forward_outbound(struct pxtcp *pxtcp, struct pbuf *p)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->unsent == NULL || pxtcp->unsent == p);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync for (i = 0, q = qs; i < iovsize && q != NULL; ++i, q = q->next) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * TODO: This is where application-level proxy can hook into
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * to process outbound traffic.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* successfully sent this chain fragment completely */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else if (nsent >= 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* successfully sent only some data */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* find the first pbuf that was not completely forwarded */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync for (i = 0, q = qs; i < iovsize && q != NULL; ++i, q = q->next) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Some errors are really not errors - if we get them,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * it's not different from getting nsent == 0, so filter
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * them out here.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (q != p) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* free forwarded pbufs at the beginning of the chain */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* advance payload pointer past the forwarded part */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Have sendmsg() failed?
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Connection reset will be detected by poll and
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp_schedule_reset() will be called.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Otherwise something *really* unexpected must have happened,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * so we'd better abort.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* call error callback manually since we've already dissociated */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* schedule one-shot POLLOUT on the socket */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_POLLOUT, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_sock_send(struct pxtcp *pxtcp, IOVEC *iov, size_t iovlen)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync const int send_flags = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#else /* RT_OS_WINDOWS */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_sock_send(struct pxtcp *pxtcp, IOVEC *iov, size_t iovlen)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync status = WSASend(pxtcp->sock, iov, (DWORD)iovlen, &nsent,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif /* RT_OS_WINDOWS */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Callback from poll manager (on POLLOUT) to send data from
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp::unsent pbuf to socket.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Common poll manager callback used by both outgoing and incoming
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * (port-forwarded) connections that has connected socket.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync status = getsockopt(pxtcp->sock, SOL_SOCKET, SO_ERROR,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (status == SOCKET_ERROR) { /* should not happen */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("sock %d: SO_ERROR failed: %R[sockerr]\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * If host does not report POLLHUP for closed sockets
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * (e.g. NetBSD) we should check for full close manually.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbound_close && pxtcp->outbound_close_done) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Remote closed inbound.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We might still need to poll for POLLOUT, but we can not
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * poll for POLLIN anymore (even if not all data are read)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * because we will be spammed by POLLHUP.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* the rest of the input has to be pulled */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Both directions are closed.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* there's no unread data, we are done */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* pull the rest of the input first (deferred_delete) */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* NOTREACHED */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif /* HAVE_TCP_POLLHUP */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Read data from socket to ringbuf. This may be used both on lwip
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * and poll manager threads.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Flag pointed to by pstop is set when further reading is impossible,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * either temporary when buffer is full, or permanently when EOF is
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * received.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Returns number of bytes read. NB: EOF is reported as 1!
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Returns zero if nothing was read, either because buffer is full, or
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * if no data is available (EWOULDBLOCK, EINTR &c).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Returns -errno on real socket errors.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* lim is the index we can NOT write to */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (lim == 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Buffer is full, stop polling for POLLIN.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp_pcb_sent() will re-enable POLLIN when guest ACKs
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * data, freeing space in the ring buffer.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* free space in one chunk */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* free space in two chunks */
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync * TODO: This is where application-level proxy can hook into to
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync * process inbound traffic.
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync else if (nread == 0) {
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync /* haven't read anything, just return */
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync /* socket error! */
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsyncpxtcp_sock_recv(struct pxtcp *pxtcp, IOVEC *iov, size_t iovlen)
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync#else /* RT_OS_WINDOWS */
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsyncpxtcp_sock_recv(struct pxtcp *pxtcp, IOVEC *iov, size_t iovlen)
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync status = WSARecv(pxtcp->sock, iov, (DWORD)iovlen, &nread,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif /* RT_OS_WINDOWS */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Callback from poll manager (pxtcp::msg_inbound) to trigger output
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * from ringbuf to guest.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_poll() callback
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We swtich it on when tcp_write() or tcp_shutdown() fail with
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * ERR_MEM to prevent connection from stalling. If there are ACKs or
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * more inbound data then pxtcp_pcb_forward_inbound() will be
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * triggered again, but if neither happens, tcp_poll() comes to the
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * If the last thing holding up deletion of the pxtcp was failed
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_shutdown() and it succeeded, we may be the last callback.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Forward inbound data from ring buffer to the guest.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Scheduled by poll manager thread after it receives more data into
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * the ring buffer (we have more data to send).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Also called from tcp_sent() callback when guest ACKs some data,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * increasing pcb->snd_buf (we are permitted to send more data).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Also called from tcp_poll() callback if previous attempt to forward
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * inbound data failed with ERR_MEM (we need to try again).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (/* __predict_false */ pcb->state < ESTABLISHED) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * If we have just confirmed accept of this connection, the
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pcb is in SYN_RCVD state and we still haven't received the
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * ACK of our SYN. It's only in SYN_RCVD -> ESTABLISHED
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * transition that lwip decrements pcb->acked so that that ACK
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * is not reported to pxtcp_pcb_sent(). If we send something
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * now and immediately close (think "daytime", e.g.) while
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * still in SYN_RCVD state, we will move directly to
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * FIN_WAIT_1 and when our confirming SYN is ACK'ed lwip will
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * report it to pxtcp_pcb_sent().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("forward_inbound: pxtcp %p; pcb %p %s - later...\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, tcp_debug_state_str(pcb->state)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync beg = pxtcp->inbuf.unsent; /* private to lwip thread */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbound_close && !pxtcp->inbound_close_done) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Else, there's no data to send.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * If there is free space in the buffer, producer will
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * reschedule us as it receives more data and vacant (lim)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * advances.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * If buffer is full when all data have been passed to
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_write() but not yet acknowledged, we will advance
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * unacked on ACK, freeing some space for producer to write to
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * (then see above).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Can't send anything now. As guest ACKs some data, TCP will
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * call pxtcp_pcb_sent() callback and we will come here again.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We have three limits to consider:
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * - how much data we have in the ringbuf
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * - how much data we are allowed to send
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * - ringbuf size
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (sndbuf < toeob) { /* but we are limited by sndbuf */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* so beg is not going to wrap, treat sndbuf as lim */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync lim = beg + sndbuf; /* ... and proceed to the simple case */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else { /* we are limited by the end of the buffer, beg will wrap */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync error = tcp_write(pcb, &pxtcp->inbuf.buf[beg], toeob, maybemore);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* we are done sending, but ... */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync error = tcp_write(pcb, &pxtcp->inbuf.buf[beg], (u16_t)tolim, 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbound_close && pxtcp->inbuf.unsent == pxtcp->inbuf.vacant) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("forward_inbound: pxtcp %p, pcb %p: sent %d bytes\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (nsent > 0) { /* first write succeeded, second failed */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("forward_inbound: pxtcp %p, pcb %p: sent %d bytes only\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("forward_inbound: pxtcp %p, pcb %p: ERR_MEM\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("forward_inbound: pxtcp %p, pcb %p: %s\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, proxy_lwip_strerr(error)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* XXX: We shouldn't get ERR_ARG. Check ERR_CONN conditions early? */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_forward_inbound_close(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->inbuf.unsent == pxtcp->inbuf.vacant);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, tcp_debug_state_str(pcb->state)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync " tcp_shutdown: error=%s\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, proxy_lwip_strerr(error)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * If we have already done outbound close previously (passive
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * close on the pcb), then we must not hold onto a pcb in LAST_ACK
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * state since those will be deleted by lwip when that last ack
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * comes from the guest.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * NB: We do NOT check for deferred delete here, even though we
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * have just set one of its conditions, inbound_close_done. We
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * let pcb callbacks that called us do that. It's simpler and
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * cleaner that way.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->outbound_close_done && pxtcp_pcb_forward_inbound_done(pxtcp)) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Check that all forwarded inbound data is sent and acked, and that
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * inbound close is scheduled (we aren't called back when it's acked).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_forward_inbound_done(const struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return (pxtcp->inbound_close_done /* also implies that all data forwarded */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_sent() callback - guest acknowledged len bytes.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We can advance inbuf::unacked index, making more free space in the
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * ringbuf and wake up producer on poll manager thread.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We can also try to send more data if we have any since pcb->snd_buf
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * was increased and we are now permitted to send more.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync " unacked %d, unsent %d, vacant %d\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* we are notified to start pulling */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Advance unacked index. Guest acknowledged the data, so it
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * won't be needed again for potential retransmits.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* arrange for more inbound data */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* wake up producer, in case it has stopped polling for POLLIN */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_POLLIN, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We have't got enought room in ring buffer to read atm,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * but we don't want to lose notification from WSAW4ME when
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * space would be available, so we reset event with empty recv
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Since we are pulling, pxtcp is no longer registered
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * with poll manager so we can kill it directly.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* forward more data if we can */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * NB: we might have dissociated from a pcb that transitioned
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * to LAST_ACK state, so don't refer to pcb below.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* have we got all the acks? */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync && pxtcp->inbuf.unsent == pxtcp->inbuf.vacant /* all data is sent */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync && unacked == pxtcp->inbuf.unsent) /* ... and is acked */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* no more retransmits, so buf is not needed */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* no more acks, so no more callbacks */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We may be the last callback for this pcb if we have also
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * successfully forwarded inbound_close.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Callback from poll manager (pxtcp::msg_inpull) to switch
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp_pcb_sent() to actively pull the last bits of input. See
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * POLLHUP comment in pxtcp_pmgr_pump().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp::sock is deregistered from poll manager after this callback
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * is scheduled.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: pxtcp %p: PCB IS GONE\n", __func__, (void *)pxtcp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: pxtcp %p: pcb %p (deferred delete)\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_err() callback.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pcb is not passed to this callback since it may be already
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * deallocated by the stack, but we can't do anything useful with it
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * anyway since connection is gone.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * ERR_CLSD is special - it is reported here when:
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * . guest has already half-closed
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * . we send FIN to guest when external half-closes
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * . guest acks that FIN
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Since connection is closed but receive has been already closed
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * lwip can only report this via tcp_err. At this point the pcb
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * is still alive, so we can peek at it if need be.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * The interesting twist is when the ACK from guest that akcs our
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * FIN also acks some data. In this scenario lwip will NOT call
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_sent() callback with the ACK for that last bit of data but
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * instead will call tcp_err with ERR_CLSD right away. Since that
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * ACK also acknowledges all the data, we should run some of
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp_pcb_sent() logic here.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct tcp_pcb *pcb = pxtcp->pcb; /* still alive */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync " pcb->acked %d;"
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync " unacked %d, unsent %d, vacant %d\n",