pxtcp.c revision 7ab47b96268d2f9deec494cfc079642eb4df6c01
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/* -*- indent-tabs-mode: nil; -*- */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#define LOG_GROUP LOG_GROUP_NAT_SERVICE
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include "winutils.h"
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
c58f1213e628a545081c70e26c6b67a841cff880vboxsync#include "pxtcp.h"
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include "proxy.h"
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include "proxy_pollmgr.h"
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include "pxremap.h"
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include "portfwd.h" /* fwspec */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#ifndef RT_OS_WINDOWS
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <sys/types.h>
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <sys/socket.h>
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <sys/ioctl.h>
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#ifdef RT_OS_SOLARIS
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <sys/filio.h> /* FIONREAD is BSD'ism */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <stdlib.h>
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <stdint.h>
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <stdio.h>
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <string.h>
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <poll.h>
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <err.h> /* BSD'ism */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#else
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include <stdlib.h>
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include <stdio.h>
141a285580775ead77d73bb52a63701a5591dc6dvboxsync#include <string.h>
141a285580775ead77d73bb52a63701a5591dc6dvboxsync
141a285580775ead77d73bb52a63701a5591dc6dvboxsync#include <iprt/stdint.h>
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include "winpoll.h"
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#endif
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#include "lwip/opt.h"
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include "lwip/sys.h"
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include "lwip/tcpip.h"
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include "lwip/netif.h"
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include "lwip/tcp_impl.h" /* XXX: to access tcp_abandon() */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include "lwip/icmp.h"
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include "lwip/icmp6.h"
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync/*
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * Different OSes have different quirks in reporting POLLHUP for TCP
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * sockets.
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync *
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 */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#if defined(RT_OS_NETBSD) || defined(RT_OS_SOLARIS)
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync# define HAVE_TCP_POLLHUP 0 /* not reported */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#elif defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS)
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync# define HAVE_TCP_POLLHUP POLLIN /* reported when remote closes */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#else
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync# define HAVE_TCP_POLLHUP (POLLIN|POLLOUT) /* reported when both directions are closed */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#endif
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync/**
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 *
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.
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstruct ringbuf {
9ad3427071ba81a2bbf60f5d9a04eb69c147ea6evboxsync char *buf;
9ad3427071ba81a2bbf60f5d9a04eb69c147ea6evboxsync size_t bufsize;
9ad3427071ba81a2bbf60f5d9a04eb69c147ea6evboxsync
9ad3427071ba81a2bbf60f5d9a04eb69c147ea6evboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Start of free space, producer writes here (up till "unacked").
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync volatile size_t vacant;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync volatile size_t unacked;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t unsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync};
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstruct pxtcp {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Our poll manager handler. Must be first, strong/weak
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * references depend on this "inheritance".
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pollmgr_handler pmhdl;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * lwIP (internal/guest) side of the proxied connection.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct tcp_pcb *pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Host (external) side of the proxied connection.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync SOCKET sock;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Socket events we are currently polling for.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int events;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Socket error. Currently used to save connect(2) errors so that
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * we can decide if we need to send ICMP error.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int sockerr;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Interface that we have got the SYN from. Needed to send ICMP
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * with correct source address.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct netif *netif;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
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 *
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pbuf *unsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int outbound_close;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Outbound half-close has been done on the socket.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int outbound_close_done;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * External has closed its side. We might not be able to forward
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * it immediately if we have unforwarded data.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int inbound_close;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Inbound half-close has been done on the pcb.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int inbound_close_done;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int inbound_pull;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int deferred_delete;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Ring-buffer for inbound data.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync struct ringbuf inbuf;
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync /**
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync * lwIP thread's strong reference to us.
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync */
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync struct pollmgr_refptr *rp;
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync /*
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync * We use static messages to call functions on the lwIP thread to
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync * void malloc/free overhead.
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync */
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync struct tcpip_msg msg_delete; /* delete pxtcp */
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 */
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync};
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync
615c2f5544718590f05af51eff75bd1bbac4be54vboxsyncstatic struct pxtcp *pxtcp_allocate(void);
615c2f5544718590f05af51eff75bd1bbac4be54vboxsyncstatic void pxtcp_free(struct pxtcp *);
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync
615c2f5544718590f05af51eff75bd1bbac4be54vboxsyncstatic void pxtcp_pcb_associate(struct pxtcp *, struct tcp_pcb *);
615c2f5544718590f05af51eff75bd1bbac4be54vboxsyncstatic void pxtcp_pcb_dissociate(struct pxtcp *);
615c2f5544718590f05af51eff75bd1bbac4be54vboxsync
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);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#if !(HAVE_TCP_POLLHUP & POLLOUT)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_pmgr_chan_del(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_pmgr_chan_reset(struct pollmgr_handler *, SOCKET, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
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
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
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
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/* convenience functions for poll manager callbacks */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_schedule_delete(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_schedule_reset(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int pxtcp_schedule_reject(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
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
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 void pxtcp_pcb_err(void *, err_t);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t pxtcp_pcb_forward_outbound(struct pxtcp *, struct pbuf *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_forward_outbound_close(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t pxtcp_sock_send(struct pxtcp *, IOVEC *, size_t);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
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_cancel_poll(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void pxtcp_pcb_reject(struct netif *, struct tcp_pcb *, struct pbuf *, int);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncDECLINLINE(void) pxtcp_pcb_maybe_deferred_delete(struct pxtcp *);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
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;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#if !(HAVE_TCP_POLLHUP & POLLOUT)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pollmgr_handler pxtcp_pmgr_chan_del_hdl;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pollmgr_handler pxtcp_pmgr_chan_reset_hdl;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Init PXTCP - must be run when neither lwIP tcpip thread, nor poll
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * manager threads haven't been created yet.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncvoid
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_init(void)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Create channels.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#define CHANNEL(SLOT, NAME) do { \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync NAME##_hdl.callback = NAME; \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync NAME##_hdl.data = NULL; \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync NAME##_hdl.slot = -1; \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pollmgr_add_chan(SLOT, &NAME##_hdl); \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync } while (0)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
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#if !(HAVE_TCP_POLLHUP & POLLOUT)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CHANNEL(POLLMGR_CHAN_PXTCP_DEL, pxtcp_pmgr_chan_del);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CHANNEL(POLLMGR_CHAN_PXTCP_RESET, pxtcp_pmgr_chan_reset);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#undef CHANNEL
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Listen to outgoing connection from guest(s).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_proxy_accept(pxtcp_pcb_heard);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Syntactic sugar for sending pxtcp pointer over poll manager
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * channel. Used by lwip thread functions.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_chan_send(enum pollmgr_slot_t slot, struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pollmgr_chan_send(slot, &pxtcp, sizeof(pxtcp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Syntactic sugar for sending weak reference to pxtcp over poll
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * manager channel. Used by lwip thread functions.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_chan_send_weak(enum pollmgr_slot_t slot, struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pollmgr_refptr_weak_ref(pxtcp->rp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pollmgr_chan_send(slot, &pxtcp->rp, sizeof(pxtcp->rp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Counterpart of pxtcp_chan_send().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pxtcp *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_chan_recv(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = (struct pxtcp *)pollmgr_chan_recv_ptr(handler, fd, revents);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Counterpart of pxtcp_chan_send_weak().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pxtcp *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_chan_recv_strong(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pollmgr_refptr *rp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pollmgr_handler *base;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync rp = (struct pollmgr_refptr *)pollmgr_chan_recv_ptr(handler, fd, revents);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync base = (struct pollmgr_handler *)pollmgr_refptr_get(rp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = (struct pxtcp *)base;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Register pxtcp with poll manager.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
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.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncint
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_add(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int status;
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync LWIP_ASSERT1(pxtcp != NULL);
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync LWIP_ASSERT1(pxtcp->sock >= 0);
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync LWIP_ASSERT1(pxtcp->pmhdl.callback != NULL);
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync LWIP_ASSERT1(pxtcp->pmhdl.data == (void *)pxtcp);
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync LWIP_ASSERT1(pxtcp->pmhdl.slot < 0);
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync status = pollmgr_add(&pxtcp->pmhdl, pxtcp->sock, pxtcp->events);
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync return status;
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync}
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync/**
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync * Unregister pxtcp with poll manager.
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync *
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync * Used for POLLMGR_CHAN_PXTCP_RESET and by port-forwarding (on error
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync * leg).
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync */
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsyncvoid
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsyncpxtcp_pmgr_del(struct pxtcp *pxtcp)
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync{
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync LWIP_ASSERT1(pxtcp != NULL);
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync
76d3e53889c5a02a3881bd3cfa31509d61cea9d0vboxsync pollmgr_del_slot(pxtcp->pmhdl.slot);
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync}
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync
91b5f2a7d9797385e53af76c22883fa15fd25adfvboxsync/**
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync * POLLMGR_CHAN_PXTCP_ADD handler.
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync *
91b5f2a7d9797385e53af76c22883fa15fd25adfvboxsync * Get new pxtcp from lwip thread and start polling its socket.
91b5f2a7d9797385e53af76c22883fa15fd25adfvboxsync */
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsyncstatic int
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsyncpxtcp_pmgr_chan_add(struct pollmgr_handler *handler, SOCKET fd, int revents)
62affeb44694facf8de89ef52bb676150f979887vboxsync{
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync struct pxtcp *pxtcp;
62affeb44694facf8de89ef52bb676150f979887vboxsync int status;
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync pxtcp = pxtcp_chan_recv(handler, fd, revents);
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync DPRINTF0(("pxtcp_add: new pxtcp %p; pcb %p; sock %d\n",
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync (void *)pxtcp, (void *)pxtcp->pcb, pxtcp->sock));
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync
d8818699735c83c36fc9555f85e6d86b610cdc67vboxsync status = pxtcp_pmgr_add(pxtcp);
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync if (status < 0) {
d8818699735c83c36fc9555f85e6d86b610cdc67vboxsync (void) pxtcp_schedule_reset(pxtcp);
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync }
d8818699735c83c36fc9555f85e6d86b610cdc67vboxsync
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync return POLLIN;
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync}
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync/**
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync * POLLMGR_CHAN_PXTCP_POLLOUT handler.
d8818699735c83c36fc9555f85e6d86b610cdc67vboxsync *
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.
d8818699735c83c36fc9555f85e6d86b610cdc67vboxsync */
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsyncstatic int
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsyncpxtcp_pmgr_chan_pollout(struct pollmgr_handler *handler, SOCKET fd, int revents)
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync{
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync struct pxtcp *pxtcp;
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync pxtcp = pxtcp_chan_recv_strong(handler, fd, revents);
109c0d54dc2438e7887f198daefb7e164c8a9dffvboxsync DPRINTF0(("pxtcp_pollout: pxtcp %p\n", (void *)pxtcp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
9ad3427071ba81a2bbf60f5d9a04eb69c147ea6evboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pmhdl.data == (void *)pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pmhdl.slot > 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->events |= POLLOUT;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pollmgr_update_events(pxtcp->pmhdl.slot, pxtcp->events);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * POLLMGR_CHAN_PXTCP_POLLIN handler.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_chan_pollin(struct pollmgr_handler *handler, SOCKET fd, int revents)
9ad3427071ba81a2bbf60f5d9a04eb69c147ea6evboxsync{
9ad3427071ba81a2bbf60f5d9a04eb69c147ea6evboxsync struct pxtcp *pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = pxtcp_chan_recv_strong(handler, fd, revents);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("pxtcp_pollin: pxtcp %p\n", (void *)pxtcp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pmhdl.data == (void *)pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pmhdl.slot > 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbound_close) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->events |= POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pollmgr_update_events(pxtcp->pmhdl.slot, pxtcp->events);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
9ad3427071ba81a2bbf60f5d9a04eb69c147ea6evboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#if !(HAVE_TCP_POLLHUP & POLLOUT)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * POLLMGR_CHAN_PXTCP_DEL handler.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Schedule pxtcp deletion. We only need this if host system doesn't
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * report POLLHUP for fully closed tcp sockets.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_chan_del(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = pxtcp_chan_recv_strong(handler, fd, revents);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp == NULL) {
9ad3427071ba81a2bbf60f5d9a04eb69c147ea6evboxsync return POLLIN;
9ad3427071ba81a2bbf60f5d9a04eb69c147ea6evboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("PXTCP_DEL: pxtcp %p; pcb %p; sock %d\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pxtcp->pcb, pxtcp->sock));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pmhdl.callback != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pmhdl.data == (void *)pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->inbound_close); /* EOF read */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->outbound_close_done); /* EOF sent */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pmgr_del(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void) pxtcp_schedule_delete(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif /* !(HAVE_TCP_POLLHUP & POLLOUT) */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * POLLMGR_CHAN_PXTCP_RESET handler.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Close the socket with RST and delete pxtcp.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_chan_reset(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = pxtcp_chan_recv_strong(handler, fd, revents);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF0(("PXTCP_RESET: pxtcp %p; pcb %p; sock %d\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pxtcp->pcb, pxtcp->sock));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pmhdl.callback != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pmhdl.data == (void *)pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pmgr_del(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_reset_socket(pxtcp->sock);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->sock = INVALID_SOCKET;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void) pxtcp_schedule_reset(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic struct pxtcp *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_allocate(void)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = (struct pxtcp *)malloc(sizeof(*pxtcp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return NULL;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pmhdl.callback = NULL;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pmhdl.data = (void *)pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pmhdl.slot = -1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->pcb = NULL;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->sock = INVALID_SOCKET;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->events = 0;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->sockerr = 0;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->netif = NULL;
b891b477f403c0a8a1eea185f9bc4ef9c99caf2dvboxsync pxtcp->unsent = NULL;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->outbound_close = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->outbound_close_done = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbound_close = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbound_close_done = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbound_pull = 0;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->deferred_delete = 0;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->inbuf.bufsize = 64 * 1024;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->inbuf.buf = (char *)malloc(pxtcp->inbuf.bufsize);
4d93fcdfb645b86163cfea77f687172295988d16vboxsync if (pxtcp->inbuf.buf == NULL) {
4d93fcdfb645b86163cfea77f687172295988d16vboxsync free(pxtcp);
4d93fcdfb645b86163cfea77f687172295988d16vboxsync return NULL;
b891b477f403c0a8a1eea185f9bc4ef9c99caf2dvboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbuf.vacant = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbuf.unacked = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbuf.unsent = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->rp = pollmgr_refptr_create(&pxtcp->pmhdl);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->rp == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync free(pxtcp->inbuf.buf);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync free(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return NULL;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#define CALLBACK_MSG(MSG, FUNC) \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync do { \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->MSG.type = TCPIP_MSG_CALLBACK_STATIC; \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->MSG.sem = NULL; \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->MSG.msg.cb.function = FUNC; \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->MSG.msg.cb.ctx = (void *)pxtcp; \
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync } while (0)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CALLBACK_MSG(msg_delete, pxtcp_pcb_delete_pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync CALLBACK_MSG(msg_reset, pxtcp_pcb_reset_pxtcp);
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 CALLBACK_MSG(msg_inpull, pxtcp_pcb_pull_inbound);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#undef CALLBACK_MSG
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Exported to fwtcp to create pxtcp for incoming port-forwarded
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * connections. Completed with pcb in pxtcp_pcb_connect().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
3e7e8dae1bd305767a63ff29f1ae8bd8dccb8000vboxsyncstruct pxtcp *
3e7e8dae1bd305767a63ff29f1ae8bd8dccb8000vboxsyncpxtcp_create_forwarded(SOCKET sock)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = pxtcp_allocate();
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return NULL;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->sock = sock;
3e7e8dae1bd305767a63ff29f1ae8bd8dccb8000vboxsync pxtcp->pmhdl.callback = pxtcp_pmgr_pump;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->events = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_associate(struct pxtcp *pxtcp, struct tcp_pcb *pcb)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pcb != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pcb = pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_arg(pcb, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_recv(pcb, pxtcp_pcb_recv);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_sent(pcb, pxtcp_pcb_sent);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_poll(pcb, NULL, 255);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_err(pcb, pxtcp_pcb_err);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_free(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->unsent != NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pbuf_free(pxtcp->unsent);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbuf.buf != NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync free(pxtcp->inbuf.buf);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
3e7e8dae1bd305767a63ff29f1ae8bd8dccb8000vboxsync free(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncvoid
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_cancel_forwarded(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pcb == NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_reset_pxtcp(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_dissociate(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp == NULL || pxtcp->pcb == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: pxtcp %p <-> pcb %p\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync LWIP_ASSERT1(pxtcp->pcb->callback_arg == pxtcp);
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync tcp_recv(pxtcp->pcb, NULL);
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync tcp_sent(pxtcp->pcb, NULL);
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync tcp_poll(pxtcp->pcb, NULL, 255);
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync tcp_err(pxtcp->pcb, NULL);
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync tcp_arg(pxtcp->pcb, NULL);
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync pxtcp->pcb = NULL;
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync}
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync/**
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync * Lwip thread callback invoked via pxtcp::msg_delete
1d9b8ac46277d5cbab832794c5cfcce1e0521873vboxsync *
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 *
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 *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Poll manager handlers should use pxtcp_schedule_delete()
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * convenience function.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_delete_pxtcp(void *ctx)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp = (struct pxtcp *)ctx;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: pxtcp %p, pcb %p, sock %d%s\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb, pxtcp->sock,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (pxtcp->deferred_delete && !pxtcp->inbound_pull
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ? " (was deferred)" : "")));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync LWIP_ASSERT1(pxtcp->pmhdl.slot < 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->outbound_close_done);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->inbound_close); /* not necessarily done */
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * pxtcp is no longer registered with poll manager, so it's safe
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * to close the socket.
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->sock != INVALID_SOCKET) {
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync closesocket(pxtcp->sock);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp->sock = INVALID_SOCKET;
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync }
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync /*
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 */
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync if (pxtcp->pcb == NULL) {
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pollmgr_refptr_unref(pxtcp->rp);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp_free(pxtcp);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync return;
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync }
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync /*
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * Have we completely forwarded all inbound traffic to the guest?
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync *
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 */
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync if (pxtcp_pcb_forward_inbound_done(pxtcp)) {
0931358f459881bc01b54d3118e0fc1b9a43bdc3vboxsync pxtcp_pcb_dissociate(pxtcp);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pollmgr_refptr_unref(pxtcp->rp);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp_free(pxtcp);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync }
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync else {
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync DPRINTF2(("delete: pxtcp %p; pcb %p:"
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync " unacked %d, unsent %d, vacant %d, %s - DEFER!\n",
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync (void *)pxtcp, (void *)pxtcp->pcb,
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync (int)pxtcp->inbuf.unacked,
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync (int)pxtcp->inbuf.unsent,
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync (int)pxtcp->inbuf.vacant,
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp->inbound_close_done ? "FIN sent" : "FIN is NOT sent"));
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync LWIP_ASSERT1(!pxtcp->deferred_delete);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp->deferred_delete = 1;
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync }
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync}
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync/**
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.
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync */
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsyncDECLINLINE(void)
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsyncpxtcp_pcb_maybe_deferred_delete(struct pxtcp *pxtcp)
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync{
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync if (pxtcp->deferred_delete && pxtcp_pcb_forward_inbound_done(pxtcp)) {
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp_pcb_delete_pxtcp(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_schedule_delete(struct pxtcp *pxtcp)
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * If pollmgr_refptr_get() is called by any channel before
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * scheduled deletion happens, let them know we are gone.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pmhdl.slot = -1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_lwip_post(&pxtcp->msg_delete);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* tell poll manager to deregister us */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return -1;
aede31badacc724e58bbfe5b7e48d4875bd70844vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Lwip thread callback invoked via pxtcp::msg_reset
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Like pxtcp_pcb_delete(), but sends RST to the guest before
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * deleting this pxtcp.
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_reset_pxtcp(void *ctx)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync struct pxtcp *pxtcp = (struct pxtcp *)ctx;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF0(("%s: pxtcp %p, pcb %p, sock %d\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb, pxtcp->sock));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->sock != INVALID_SOCKET) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_reset_socket(pxtcp->sock);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->sock = INVALID_SOCKET;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->pcb != NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct tcp_pcb *pcb = pxtcp->pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_dissociate(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_abort(pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pollmgr_refptr_unref(pxtcp->rp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_free(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
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 *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * See pxtcp_schedule_delete() for additional comments.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_schedule_reset(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pmhdl.slot = -1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_lwip_post(&pxtcp->msg_reset);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return -1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
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.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_reject(struct netif *netif, struct tcp_pcb *pcb,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pbuf *p, int sockerr)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct netif *oif;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int reset = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync oif = ip_current_netif();
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ip_current_netif() = netif;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (sockerr == ECONNREFUSED) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync reset = 1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else if (PCB_ISIPV6(pcb)) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (sockerr == EHOSTDOWN) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync icmp6_dest_unreach(p, ICMP6_DUR_ADDRESS); /* XXX: ??? */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else if (sockerr == EHOSTUNREACH
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync || sockerr == ENETDOWN
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync || sockerr == ENETUNREACH)
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync {
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync }
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync }
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync else {
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync if (sockerr == EHOSTDOWN
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync || sockerr == EHOSTUNREACH
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync || sockerr == ENETDOWN
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync || sockerr == ENETUNREACH)
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync {
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync icmp_dest_unreach(p, ICMP_DUR_HOST);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync }
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync }
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync ip_current_netif() = oif;
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync tcp_abandon(pcb, reset);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync}
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync/**
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 *
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * This is like pxtcp_pcb_reset_pxtcp() but is more discriminate in
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * how this unestablished connection is terminated.
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync */
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsyncstatic void
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsyncpxtcp_pcb_accept_refuse(void *ctx)
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync{
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync struct pxtcp *pxtcp = (struct pxtcp *)ctx;
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync DPRINTF0(("%s: pxtcp %p, pcb %p, sock %d: %R[sockerr]\n",
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb,
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp->sock, pxtcp->sockerr));
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync LWIP_ASSERT1(pxtcp != NULL);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync LWIP_ASSERT1(pxtcp->sock == INVALID_SOCKET);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync if (pxtcp->pcb != NULL) {
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync struct tcp_pcb *pcb = pxtcp->pcb;
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp_pcb_dissociate(pxtcp);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp_pcb_reject(pxtcp->netif, pcb, pxtcp->unsent, pxtcp->sockerr);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync }
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pollmgr_refptr_unref(pxtcp->rp);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync pxtcp_free(pxtcp);
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync}
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync/**
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * Convenience wrapper for poll manager connect callback to reject
6a89b975ab84f4a47fb86fc27ba6c33c701720cfvboxsync * connection attempt.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Like pxtcp_schedule_reset(), but the callback is more discriminate
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * in how this unestablished connection is terminated.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_schedule_reject(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->msg_accept.msg.cb.function = pxtcp_pcb_accept_refuse;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pmhdl.slot = -1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_lwip_post(&pxtcp->msg_accept);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return -1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Global tcp_proxy_accept() callback for proxied outgoing TCP
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * connections from guest(s).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_heard(void *arg, struct tcp_pcb *newpcb, err_t error)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pbuf *p = (struct pbuf *)arg;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ipX_addr_t dst_addr;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int sdom;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync SOCKET sock;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ssize_t nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int sockerr = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_UNUSED_ARG(error); /* always ERR_OK */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(newpcb->state == SYN_RCVD_0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_accept(newpcb, pxtcp_pcb_accept);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_arg(newpcb, NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_setprio(newpcb, TCP_PRIO_MAX);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxremap_outbound_ipX(PCB_ISIPV6(newpcb), &dst_addr, &newpcb->local_ip);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sdom = PCB_ISIPV6(newpcb) ? PF_INET6 : PF_INET;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sock = proxy_connected_socket(sdom, SOCK_STREAM,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync &dst_addr, newpcb->local_port);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (sock == INVALID_SOCKET) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sockerr = SOCKERRNO();
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync goto abort;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = pxtcp_allocate();
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_reset_socket(sock);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync goto abort;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* save initial datagram in case we need to reply with ICMP */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pbuf_ref(p);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->unsent = p;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->netif = ip_current_netif();
4d93fcdfb645b86163cfea77f687172295988d16vboxsync
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp_pcb_associate(pxtcp, newpcb);
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->sock = sock;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pmhdl.callback = pxtcp_pmgr_connect;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->events = POLLOUT;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync
4d93fcdfb645b86163cfea77f687172295988d16vboxsync nsent = pxtcp_chan_send(POLLMGR_CHAN_PXTCP_ADD, pxtcp);
4d93fcdfb645b86163cfea77f687172295988d16vboxsync if (nsent < 0) {
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp->sock = INVALID_SOCKET;
a828fbe5454430a560bd0b69e6d1752ad4634c67vboxsync proxy_reset_socket(sock);
4d93fcdfb645b86163cfea77f687172295988d16vboxsync pxtcp_pcb_accept_refuse(pxtcp);
4d93fcdfb645b86163cfea77f687172295988d16vboxsync return ERR_ABRT;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
4d93fcdfb645b86163cfea77f687172295988d16vboxsync return ERR_OK;
4d93fcdfb645b86163cfea77f687172295988d16vboxsync
4d93fcdfb645b86163cfea77f687172295988d16vboxsync abort:
4d93fcdfb645b86163cfea77f687172295988d16vboxsync DPRINTF0(("%s: pcb %p, sock %d: %R[sockerr]\n",
4d93fcdfb645b86163cfea77f687172295988d16vboxsync __func__, (void *)newpcb, sock, sockerr));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_reject(ip_current_netif(), newpcb, p, sockerr);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_ABRT;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
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.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_accept(void *arg, struct tcp_pcb *pcb, err_t error)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp = (struct pxtcp *)arg;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_UNUSED_ARG(pcb); /* used only in asserts */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_UNUSED_ARG(error); /* always ERR_OK */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pcb = pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pcb->callback_arg == pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* send any inbound data that are already queued */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_forward_inbound(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_OK;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Initial poll manager callback for proxied outgoing TCP connections.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp_pcb_accept() sets pxtcp::pmhdl::callback to this.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
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.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_connect(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = (struct pxtcp *)handler->data;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(handler == &pxtcp->pmhdl);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(fd == pxtcp->sock);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (revents & (POLLNVAL | POLLHUP | POLLERR)) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (revents & POLLNVAL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->sock = INVALID_SOCKET;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->sockerr = ETIMEDOUT;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync socklen_t optlen = (socklen_t)sizeof(pxtcp->sockerr);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int status;
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync SOCKET s;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync status = getsockopt(pxtcp->sock, SOL_SOCKET, SO_ERROR,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (char *)&pxtcp->sockerr, &optlen);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (status == SOCKET_ERROR) { /* should not happen */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: sock %d: SO_ERROR failed: %R[sockerr]\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, fd, SOCKERRNO()));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: sock %d: connect: %R[sockerr]\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, fd, pxtcp->sockerr));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync s = pxtcp->sock;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->sock = INVALID_SOCKET;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync closesocket(s);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp_schedule_reject(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (revents & POLLOUT) { /* connect is successful */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* confirm accept to the guest */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_lwip_post(&pxtcp->msg_accept);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Switch to common callback used for all established proxied
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * connections.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pmhdl.callback = pxtcp_pmgr_pump;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync /*
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 */
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync pxtcp->events = POLLIN;
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync return pxtcp->events;
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync }
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync /* should never get here */
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync DPRINTF0(("%s: pxtcp %p, sock %d: unexpected revents 0x%x\n",
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync __func__, (void *)pxtcp, fd, revents));
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync return pxtcp_schedule_reset(pxtcp);
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync}
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync/**
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 */
a0a962c856e508933f3137cb0d583af5c206dc55vboxsyncstatic void
a0a962c856e508933f3137cb0d583af5c206dc55vboxsyncpxtcp_pcb_accept_confirm(void *ctx)
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync{
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync struct pxtcp *pxtcp = (struct pxtcp *)ctx;
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync err_t error;
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync LWIP_ASSERT1(pxtcp != NULL);
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync if (pxtcp->pcb == NULL) {
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync return;
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync }
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync /* we are not going to reply with ICMP, so we can drop initial pbuf */
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync LWIP_ASSERT1(pxtcp->unsent != NULL);
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync pbuf_free(pxtcp->unsent);
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync pxtcp->unsent = NULL;
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync error = tcp_proxy_accept_confirm(pxtcp->pcb);
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync /*
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 */
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync if (error == ERR_ABRT) {
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync pxtcp->pcb = NULL; /* pcb is gone */
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_RESET, pxtcp);
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync }
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync /*
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 */
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync}
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync/**
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync * Entry point for port-forwarding.
a0a962c856e508933f3137cb0d583af5c206dc55vboxsync *
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.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncvoid
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_connect(struct pxtcp *pxtcp, const struct fwspec *fwspec)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct sockaddr_storage ss;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync socklen_t sslen;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct tcp_pcb *pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ipX_addr_t src_addr, dst_addr;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync u16_t src_port, dst_port;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int status;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync err_t error;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pcb == NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(fwspec->stype == SOCK_STREAM);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pcb = tcp_new();
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pcb == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync goto reset;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_setprio(pcb, TCP_PRIO_MAX);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_associate(pxtcp, pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sslen = sizeof(ss);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync status = getpeername(pxtcp->sock, (struct sockaddr *)&ss, &sslen);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (status == SOCKET_ERROR) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync goto reset;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* nit: comapres PF and AF, but they are the same everywhere */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(ss.ss_family == fwspec->sdom);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync status = fwany_ipX_addr_set_src(&src_addr, (const struct sockaddr *)&ss);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (status == PXREMAP_FAILED) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync goto reset;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (ss.ss_family == PF_INET) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync const struct sockaddr_in *peer4 = (const struct sockaddr_in *)&ss;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync src_port = peer4->sin_port;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync memcpy(&dst_addr.ip4, &fwspec->dst.sin.sin_addr, sizeof(ip_addr_t));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync dst_port = fwspec->dst.sin.sin_port;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else { /* PF_INET6 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync const struct sockaddr_in6 *peer6 = (const struct sockaddr_in6 *)&ss;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ip_set_v6(pcb, 1);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync src_port = peer6->sin6_port;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync memcpy(&dst_addr.ip6, &fwspec->dst.sin6.sin6_addr, sizeof(ip6_addr_t));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync dst_port = fwspec->dst.sin6.sin6_port;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* lwip port arguments are in host order */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync src_port = ntohs(src_port);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync dst_port = ntohs(dst_port);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync error = tcp_proxy_bind(pcb, ipX_2_ip(&src_addr), src_port);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (error != ERR_OK) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync goto reset;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync error = tcp_connect(pcb, ipX_2_ip(&dst_addr), dst_port,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* callback: */ pxtcp_pcb_connected);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (error != ERR_OK) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync goto reset;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync reset:
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_RESET, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Port-forwarded connection to guest is successful, pump data.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_connected(void *arg, struct tcp_pcb *pcb, err_t error)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp = (struct pxtcp *)arg;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(error == ERR_OK); /* always called with ERR_OK */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_UNUSED_ARG(error);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pcb == pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pcb->callback_arg == pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_UNUSED_ARG(pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF0(("%s: new pxtcp %p; pcb %p; sock %d\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb, pxtcp->sock));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* ACK on connection is like ACK on data in pxtcp_pcb_sent() */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_POLLIN, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_OK;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_recv() callback.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t error)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp = (struct pxtcp *)arg;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(error == ERR_OK); /* always called with ERR_OK */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_UNUSED_ARG(error);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pcb == pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pcb->callback_arg == pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_UNUSED_ARG(pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Have we done sending previous batch?
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->unsent != NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (p != NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Return an error to tell TCP to hold onto that pbuf.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * It will be presented to us later from tcp_fasttmr().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_WOULDBLOCK;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Unlike data, p == NULL indicating orderly shutdown is
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * NOT presented to us again
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->outbound_close = 1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_OK;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Guest closed?
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (p == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->outbound_close = 1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_forward_outbound_close(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_OK;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Got data, send what we can without blocking.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp_pcb_forward_outbound(pxtcp, p);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Guest half-closed its TX side of the connection.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
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().
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_forward_outbound_close(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct tcp_pcb *pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->outbound_close);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(!pxtcp->outbound_close_done);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pcb = pxtcp->pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pcb != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("outbound_close: pxtcp %p; pcb %p %s\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, tcp_debug_state_str(pcb->state)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* set the flag first, since shutdown() may trigger POLLHUP */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->outbound_close_done = 1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync shutdown(pxtcp->sock, SHUT_WR); /* half-close the socket */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#if !(HAVE_TCP_POLLHUP & POLLOUT)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We need to nudge poll manager manually, since OS will not
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * report POLLHUP.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbound_close) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_DEL, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* no more outbound data coming to us */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_recv(pcb, NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 *
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp_pcb_forward_inbound_done(pxtcp)) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_dissociate(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Forward outbound data from pcb to socket.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
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 *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * (Re)scehdules one-time callout if not all data are sent.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_forward_outbound(struct pxtcp *pxtcp, struct pbuf *p)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pbuf *qs, *q;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t qoff;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t forwarded;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int sockerr;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->unsent == NULL || pxtcp->unsent == p);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync forwarded = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sockerr = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync q = NULL;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync qoff = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync qs = p;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync while (qs != NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync IOVEC iov[8];
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync const size_t iovsize = sizeof(iov)/sizeof(iov[0]);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t fwd1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ssize_t nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t i;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync fwd1 = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync for (i = 0, q = qs; i < iovsize && q != NULL; ++i, q = q->next) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(q->len > 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync IOVEC_SET_BASE(iov[i], q->payload);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync IOVEC_SET_LEN(iov[i], q->len);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync fwd1 += q->len;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * TODO: This is where application-level proxy can hook into
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * to process outbound traffic.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync nsent = pxtcp_sock_send(pxtcp, iov, i);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (nsent == (ssize_t)fwd1) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* successfully sent this chain fragment completely */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync forwarded += nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync qs = q;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else if (nsent >= 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* successfully sent only some data */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync forwarded += nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* find the first pbuf that was not completely forwarded */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync qoff = nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync for (i = 0, q = qs; i < iovsize && q != NULL; ++i, q = q->next) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (qoff < q->len) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync break;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync qoff -= q->len;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(q != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(qoff < q->len);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync break;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sockerr = -nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (proxy_error_is_transient(sockerr)) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sockerr = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync q = qs;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync qoff = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync break;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (forwarded > 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_recved(pxtcp->pcb, (u16_t)forwarded);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (q == NULL) { /* everything is forwarded? */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(sockerr == 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(forwarded == p->tot_len);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->unsent = NULL;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pbuf_free(p);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->outbound_close) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_forward_outbound_close(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (q != p) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* free forwarded pbufs at the beginning of the chain */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pbuf_ref(q);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pbuf_free(p);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (qoff > 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* advance payload pointer past the forwarded part */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pbuf_header(q, -(s16_t)qoff);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->unsent = q;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Have sendmsg() failed?
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Connection reset will be detected by poll and
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp_schedule_reset() will be called.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Otherwise something *really* unexpected must have happened,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * so we'd better abort.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (sockerr != 0 && sockerr != ECONNRESET) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct tcp_pcb *pcb = pxtcp->pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_dissociate(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_abort(pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* call error callback manually since we've already dissociated */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_err((void *)pxtcp, ERR_ABRT);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_ABRT;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* schedule one-shot POLLOUT on the socket */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_POLLOUT, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_OK;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#if !defined(RT_OS_WINDOWS)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_sock_send(struct pxtcp *pxtcp, IOVEC *iov, size_t iovlen)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct msghdr mh;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ssize_t nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#ifdef MSG_NOSIGNAL
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync const int send_flags = MSG_NOSIGNAL;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#else
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync const int send_flags = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync memset(&mh, 0, sizeof(mh));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync mh.msg_iov = iov;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync mh.msg_iovlen = iovlen;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync nsent = sendmsg(pxtcp->sock, &mh, send_flags);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (nsent < 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync nsent = -SOCKERRNO();
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#else /* RT_OS_WINDOWS */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_sock_send(struct pxtcp *pxtcp, IOVEC *iov, size_t iovlen)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DWORD nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int status;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync status = WSASend(pxtcp->sock, iov, (DWORD)iovlen, &nsent,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync 0, NULL, NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (status == SOCKET_ERROR) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return -SOCKERRNO();
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif /* RT_OS_WINDOWS */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Callback from poll manager (on POLLOUT) to send data from
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp::unsent pbuf to socket.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_write_outbound(void *ctx)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp = (struct pxtcp *)ctx;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->pcb == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_forward_outbound(pxtcp, pxtcp->unsent);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Common poll manager callback used by both outgoing and incoming
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * (port-forwarded) connections that has connected socket.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic int
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int status;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int sockerr;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp = (struct pxtcp *)handler->data;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(handler == &pxtcp->pmhdl);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(fd == pxtcp->sock);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (revents & POLLNVAL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->sock = INVALID_SOCKET;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp_schedule_reset(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (revents & POLLERR) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync socklen_t optlen = (socklen_t)sizeof(sockerr);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync status = getsockopt(pxtcp->sock, SOL_SOCKET, SO_ERROR,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (char *)&sockerr, &optlen);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (status == SOCKET_ERROR) { /* should not happen */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("sock %d: SO_ERROR failed: %R[sockerr]\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync fd, SOCKERRNO()));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF0(("sock %d: %R[sockerr]\n", fd, sockerr));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp_schedule_reset(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (revents & POLLOUT) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->events &= ~POLLOUT;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_lwip_post(&pxtcp->msg_outbound);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (revents & POLLIN) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ssize_t nread;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int stop_pollin;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync nread = pxtcp_sock_read(pxtcp, &stop_pollin);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (nread < 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sockerr = -(int)nread;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF0(("sock %d: %R[sockerr]\n", fd, sockerr));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp_schedule_reset(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (stop_pollin) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->events &= ~POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (nread > 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_lwip_post(&pxtcp->msg_inbound);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#if !HAVE_TCP_POLLHUP
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * If host does not report POLLHUP for closed sockets
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * (e.g. NetBSD) we should check for full close manually.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbound_close && pxtcp->outbound_close_done) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1((revents & POLLHUP) == 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp_schedule_delete(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#if !HAVE_TCP_POLLHUP
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1((revents & POLLHUP) == 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#else
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (revents & POLLHUP) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("sock %d: HUP\n", fd));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#if HAVE_TCP_POLLHUP == POLLIN
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Remote closed inbound.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (!pxtcp->outbound_close_done) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->events &= ~POLLIN;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (!pxtcp->inbound_close) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* the rest of the input has to be pulled */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_lwip_post(&pxtcp->msg_inpull);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Both directions are closed.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->outbound_close_done);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbound_close) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* there's no unread data, we are done */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp_schedule_delete(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* pull the rest of the input first (deferred_delete) */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pmhdl.slot = -1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync proxy_lwip_post(&pxtcp->msg_inpull);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return -1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* NOTREACHED */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif /* HAVE_TCP_POLLHUP */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return pxtcp->events;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Read data from socket to ringbuf. This may be used both on lwip
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * and poll manager threads.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
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 *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Returns number of bytes read. NB: EOF is reported as 1!
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Returns zero if nothing was read, either because buffer is full, or
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * if no data is available (EWOULDBLOCK, EINTR &c).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Returns -errno on real socket errors.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic ssize_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_sock_read(struct pxtcp *pxtcp, int *pstop)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync IOVEC iov[2];
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t iovlen;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ssize_t nread;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync const size_t sz = pxtcp->inbuf.bufsize;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t beg, lim, wrnew;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *pstop = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync beg = pxtcp->inbuf.vacant;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync IOVEC_SET_BASE(iov[0], &pxtcp->inbuf.buf[beg]);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* lim is the index we can NOT write to */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync lim = pxtcp->inbuf.unacked;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (lim == 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync lim = sz - 1; /* empty slot at the end */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else if (lim == 1 && beg != 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync lim = sz; /* empty slot at the beginning */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync --lim;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (beg == lim) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Buffer is full, stop polling for POLLIN.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp_pcb_sent() will re-enable POLLIN when guest ACKs
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * data, freeing space in the ring buffer.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *pstop = 1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (beg < lim) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* free space in one chunk */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync iovlen = 1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync IOVEC_SET_LEN(iov[0], lim - beg);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* free space in two chunks */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync iovlen = 2;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync IOVEC_SET_LEN(iov[0], sz - beg);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync IOVEC_SET_BASE(iov[1], &pxtcp->inbuf.buf[0]);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync IOVEC_SET_LEN(iov[1], lim);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync * TODO: This is where application-level proxy can hook into to
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync * process inbound traffic.
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync */
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync nread = pxtcp_sock_recv(pxtcp, iov, iovlen);
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync if (nread > 0) {
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync wrnew = beg + nread;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync if (wrnew >= sz) {
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync wrnew -= sz;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync }
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync pxtcp->inbuf.vacant = wrnew;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync DPRINTF2(("pxtcp %p: sock %d read %d bytes\n",
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync (void *)pxtcp, pxtcp->sock, (int)nread));
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync return nread;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync }
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync else if (nread == 0) {
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync *pstop = 1;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync pxtcp->inbound_close = 1;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync DPRINTF2(("pxtcp %p: sock %d read EOF\n",
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync (void *)pxtcp, pxtcp->sock));
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync return 1;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync }
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync else {
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync int sockerr = -nread;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync if (proxy_error_is_transient(sockerr)) {
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync /* haven't read anything, just return */
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync DPRINTF2(("pxtcp %p: sock %d read cancelled\n",
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync (void *)pxtcp, pxtcp->sock));
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync return 0;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync }
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync else {
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync /* socket error! */
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync DPRINTF0(("pxtcp %p: sock %d read: %R[sockerr]\n",
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync (void *)pxtcp, pxtcp->sock, sockerr));
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync return -sockerr;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync }
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync }
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync}
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync#if !defined(RT_OS_WINDOWS)
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsyncstatic ssize_t
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsyncpxtcp_sock_recv(struct pxtcp *pxtcp, IOVEC *iov, size_t iovlen)
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync{
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync struct msghdr mh;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync ssize_t nread;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync memset(&mh, 0, sizeof(mh));
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync mh.msg_iov = iov;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync mh.msg_iovlen = iovlen;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync nread = recvmsg(pxtcp->sock, &mh, 0);
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync if (nread < 0) {
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync nread = -SOCKERRNO();
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync }
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync return nread;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync}
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync#else /* RT_OS_WINDOWS */
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsyncstatic ssize_t
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsyncpxtcp_sock_recv(struct pxtcp *pxtcp, IOVEC *iov, size_t iovlen)
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync{
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync DWORD flags;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync DWORD nread;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync int status;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync flags = 0;
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync status = WSARecv(pxtcp->sock, iov, (DWORD)iovlen, &nread,
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync &flags, NULL, NULL);
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync if (status == SOCKET_ERROR) {
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync return -SOCKERRNO();
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync }
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync
9c5875d62215e6a088a86658e5553af6b8401f1cvboxsync return (ssize_t)nread;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif /* RT_OS_WINDOWS */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Callback from poll manager (pxtcp::msg_inbound) to trigger output
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * from ringbuf to guest.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_write_inbound(void *ctx)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp = (struct pxtcp *)ctx;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->pcb == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_forward_inbound(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_poll() callback
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
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 * rescue.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_poll(void *arg, struct tcp_pcb *pcb)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp = (struct pxtcp *)arg;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_UNUSED_ARG(pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("%s: pxtcp %p; pcb %p\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_forward_inbound(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_maybe_deferred_delete(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_OK;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_schedule_poll(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_poll(pxtcp->pcb, pxtcp_pcb_poll, 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_cancel_poll(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_poll(pxtcp->pcb, NULL, 255);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Forward inbound data from ring buffer to the guest.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Scheduled by poll manager thread after it receives more data into
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * the ring buffer (we have more data to send).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
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 *
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_forward_inbound(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct tcp_pcb *pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t sndbuf;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t beg, lim, sndlim;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t toeob, tolim;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t nsent;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync err_t error;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pcb = pxtcp->pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pcb == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (/* __predict_false */ pcb->state < ESTABLISHED) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("forward_inbound: pxtcp %p; pcb %p %s - later...\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, tcp_debug_state_str(pcb->state)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync beg = pxtcp->inbuf.unsent; /* private to lwip thread */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync lim = pxtcp->inbuf.vacant;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (beg == lim) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbound_close && !pxtcp->inbound_close_done) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_forward_inbound_close(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_output(pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Else, there's no data to send.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
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 *
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sndbuf = tcp_sndbuf(pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (sndbuf == 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync nsent = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync toeob = pxtcp->inbuf.bufsize - beg;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (lim < beg) { /* lim wrapped */
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 }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else { /* we are limited by the end of the buffer, beg will wrap */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync u8_t maybemore;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (toeob == sndbuf || lim == 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync maybemore = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync maybemore = TCP_WRITE_FLAG_MORE;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync error = tcp_write(pcb, &pxtcp->inbuf.buf[beg], toeob, maybemore);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (error != ERR_OK) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync goto writeerr;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync nsent += toeob;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbuf.unsent = 0; /* wrap */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (maybemore) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync beg = 0;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sndbuf -= toeob;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* we are done sending, but ... */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync goto check_inbound_close;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(beg < lim);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync sndlim = beg + sndbuf;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (lim > sndlim) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync lim = sndlim;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tolim = lim - beg;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (tolim > 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync error = tcp_write(pcb, &pxtcp->inbuf.buf[beg], (u16_t)tolim, 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (error != ERR_OK) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync goto writeerr;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync nsent += tolim;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbuf.unsent = lim;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync check_inbound_close:
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbound_close && pxtcp->inbuf.unsent == pxtcp->inbuf.vacant) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_forward_inbound_close(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("forward_inbound: pxtcp %p, pcb %p: sent %d bytes\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, (int)nsent));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_output(pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_cancel_poll(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync writeerr:
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (error == ERR_MEM) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (nsent > 0) { /* first write succeeded, second failed */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("forward_inbound: pxtcp %p, pcb %p: sent %d bytes only\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, (int)nsent));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_output(pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("forward_inbound: pxtcp %p, pcb %p: ERR_MEM\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_schedule_poll(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("forward_inbound: pxtcp %p, pcb %p: %s\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, proxy_lwip_strerr(error)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* XXX: We shouldn't get ERR_ARG. Check ERR_CONN conditions early? */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(error == ERR_MEM);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_forward_inbound_close(struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct tcp_pcb *pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync err_t error;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->inbound_close);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(!pxtcp->inbound_close_done);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->inbuf.unsent == pxtcp->inbuf.vacant);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pcb = pxtcp->pcb;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pcb != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("inbound_close: pxtcp %p; pcb %p: %s\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, tcp_debug_state_str(pcb->state)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync error = tcp_shutdown(pcb, /*RX*/ 0, /*TX*/ 1);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (error != ERR_OK) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("inbound_close: pxtcp %p; pcb %p:"
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync " tcp_shutdown: error=%s\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb, proxy_lwip_strerr(error)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_schedule_poll(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_cancel_poll(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbound_close_done = 1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
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 *
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->outbound_close_done && pxtcp_pcb_forward_inbound_done(pxtcp)) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_dissociate(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
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).
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncDECLINLINE(int)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_forward_inbound_done(const struct pxtcp *pxtcp)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return (pxtcp->inbound_close_done /* also implies that all data forwarded */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync && pxtcp->inbuf.unacked == pxtcp->inbuf.unsent);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_sent() callback - guest acknowledged len bytes.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We can advance inbuf::unacked index, making more free space in the
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * ringbuf and wake up producer on poll manager thread.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
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.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic err_t
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp = (struct pxtcp *)arg;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync size_t unacked;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pcb == pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pcb->callback_arg == pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_UNUSED_ARG(pcb); /* only in assert */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("%s: pxtcp %p; pcb %p: +%d ACKed:"
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync " unacked %d, unsent %d, vacant %d\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pcb, (int)len,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (int)pxtcp->inbuf.unacked,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (int)pxtcp->inbuf.unsent,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (int)pxtcp->inbuf.vacant));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (/* __predict_false */ len == 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* we are notified to start pulling */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(!pxtcp->inbound_close);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->inbound_pull);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync unacked = pxtcp->inbuf.unacked;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Advance unacked index. Guest acknowledged the data, so it
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * won't be needed again for potential retransmits.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync unacked = pxtcp->inbuf.unacked + len;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (unacked > pxtcp->inbuf.bufsize) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync unacked -= pxtcp->inbuf.bufsize;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbuf.unacked = unacked;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* arrange for more inbound data */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (!pxtcp->inbound_close) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (!pxtcp->inbound_pull) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* wake up producer, in case it has stopped polling for POLLIN */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_POLLIN, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#ifdef RT_OS_WINDOWS
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /**
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync recv(pxtcp->sock, NULL, 0, 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync#endif
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync ssize_t nread;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int stop_pollin; /* ignored */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync nread = pxtcp_sock_read(pxtcp, &stop_pollin);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (nread < 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync int sockerr = -(int)nread;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_UNUSED_ARG(sockerr);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF0(("%s: sock %d: %R[sockerr]\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, pxtcp->sock, sockerr));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * Since we are pulling, pxtcp is no longer registered
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * with poll manager so we can kill it directly.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_reset_pxtcp(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_ABRT;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* forward more data if we can */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (!pxtcp->inbound_close_done) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_forward_inbound(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * NB: we might have dissociated from a pcb that transitioned
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * to LAST_ACK state, so don't refer to pcb below.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* have we got all the acks? */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->inbound_close /* no more new data */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync && pxtcp->inbuf.unsent == pxtcp->inbuf.vacant /* all data is sent */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync && unacked == pxtcp->inbuf.unsent) /* ... and is acked */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync char *buf;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: pxtcp %p; pcb %p; all data ACKed\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* no more retransmits, so buf is not needed */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync buf = pxtcp->inbuf.buf;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbuf.buf = NULL;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync free(buf);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /* no more acks, so no more callbacks */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->pcb != NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync tcp_sent(pxtcp->pcb, NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * We may be the last callback for this pcb if we have also
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * successfully forwarded inbound_close.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_maybe_deferred_delete(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return ERR_OK;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
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 *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * pxtcp::sock is deregistered from poll manager after this callback
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * is scheduled.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_pull_inbound(void *ctx)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp = (struct pxtcp *)ctx;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->pcb == NULL) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: pxtcp %p: PCB IS GONE\n", __func__, (void *)pxtcp));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_reset_pxtcp(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->inbound_pull = 1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->outbound_close_done) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: pxtcp %p: pcb %p (deferred delete)\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->deferred_delete = 1;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF(("%s: pxtcp %p: pcb %p\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync __func__, (void *)pxtcp, (void *)pxtcp->pcb));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_sent(pxtcp, pxtcp->pcb, 0);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync/**
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * tcp_err() callback.
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncstatic void
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsyncpxtcp_pcb_err(void *arg, err_t error)
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync{
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct pxtcp *pxtcp = (struct pxtcp *)arg;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp != NULL);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync /*
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * ERR_CLSD is special - it is reported here when:
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * . guest has already half-closed
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * . we send FIN to guest when external half-closes
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync * . guest acks that FIN
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync *
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 *
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 */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (error == ERR_CLSD) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync struct tcp_pcb *pcb = pxtcp->pcb; /* still alive */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF2(("ERR_CLSD: pxtcp %p; pcb %p:"
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync " pcb->acked %d;"
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync " unacked %d, unsent %d, vacant %d\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, (void *)pcb,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pcb->acked,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (int)pxtcp->inbuf.unacked,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (int)pxtcp->inbuf.unsent,
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (int)pxtcp->inbuf.vacant));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pxtcp->pcb == pcb);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync LWIP_ASSERT1(pcb->callback_arg == pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pcb->acked > 0) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_sent(pxtcp, pcb, pcb->acked);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync return;
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync DPRINTF0(("tcp_err: pxtcp=%p, error=%s\n",
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync (void *)pxtcp, proxy_lwip_strerr(error)));
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp->pcb = NULL; /* pcb is gone */
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync if (pxtcp->deferred_delete) {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_pcb_reset_pxtcp(pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync else {
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync pxtcp_chan_send_weak(POLLMGR_CHAN_PXTCP_RESET, pxtcp);
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync }
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync}
831acea16fc15fff2cf90a217d02eea69bf27a40vboxsync