proxy.c revision 5e380bb6e05999a7e268cbd514e8a09f7d165f18
/* -*- indent-tabs-mode: nil; -*- */
#include "winutils.h"
#include "proxy.h"
#include "proxy_pollmgr.h"
#include "portfwd.h"
#ifndef RT_OS_WINDOWS
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <err.h>
#else
#endif
#endif
#ifndef __arraycount
# define __arraycount(a) (sizeof(a)/sizeof(a[0]))
#endif
static SOCKET proxy_create_socket(int, int);
volatile struct proxy_options *g_proxy_options;
static sys_thread_t pollmgr_tid;
/* XXX: for mapping loopbacks to addresses in our network (ip4) */
struct netif *g_proxy_netif;
/*
* Called on the lwip thread (aka tcpip thread) from tcpip_init() via
* its "tcpip_init_done" callback. Raw API is ok to use here
* (e.g. rtadvd), but netconn API is not.
*/
void
{
int status;
#if 1
#endif
/*
* XXX: We use stateless DHCPv6 only to report IPv6 address(es) of
* nameserver(s). Since we don't yet support IPv6 addresses in
* HostDnsService, there's no point in running DHCPv6.
*/
#if 0
#endif
}
status = pollmgr_init();
if (status < 0) {
/* NOTREACHED */
}
pxtcp_init();
pxudp_init();
portfwd_init();
if (!pollmgr_tid) {
/* NOTREACHED */
}
}
/**
* Send static callback message from poll manager thread to lwip
* thread, scheduling a function call in lwip thread context.
*
* XXX: Existing lwip api only provides non-blocking version for this.
* It may fail when lwip thread is not running (mbox invalid) or if
* post failed (mbox full). How to handle these?
*/
void
{
struct tcpip_callback_msg *m;
/*
* lwip plays games with fake incomplete struct tag to enforce API
*/
m = (struct tcpip_callback_msg *)msg;
error = tcpip_callbackmsg(m);
/* XXX: lwip thread is not running (mbox invalid) */
}
}
/**
* Create a non-blocking socket. Disable SIGPIPE for TCP sockets if
* possible. On Linux it's not possible and should be disabled for
* each send(2) individually.
*/
static SOCKET
{
SOCKET s;
int stype_and_flags;
int status;
#if defined(SOCK_NONBLOCK)
#endif
/*
* Disable SIGPIPE on disconnected socket. It might be easier to
* forgo it and just use MSG_NOSIGNAL on each send*(2), since we
* have to do it for Linux anyway, but Darwin does NOT have that
* flag (but has SO_NOSIGPIPE socket option).
*/
#if 0 /* XXX: Solaris has neither, the program should ignore SIGPIPE globally */
#endif
#endif
#if defined(SOCK_NOSIGPIPE)
if (stype == SOCK_STREAM) {
}
#endif
if (s == INVALID_SOCKET) {
perror("socket");
return INVALID_SOCKET;
}
#if !defined(SOCK_NONBLOCK) && !defined(RT_OS_WINDOWS)
{
int sflags;
if (sflags < 0) {
perror("F_GETFL");
closesocket(s);
return INVALID_SOCKET;
}
if (status < 0) {
perror("O_NONBLOCK");
closesocket(s);
return INVALID_SOCKET;
}
}
#endif
#if !defined(SOCK_NOSIGPIPE) && defined(SO_NOSIGPIPE)
if (stype == SOCK_STREAM) {
int on = 1;
if (status < 0) {
perror("SO_NOSIGPIPE");
closesocket(s);
return INVALID_SOCKET;
}
}
#endif
#if defined(RT_OS_WINDOWS)
{
if (status == SOCKET_ERROR) {
return INVALID_SOCKET;
}
}
#endif
return s;
}
/**
* Create a socket for outbound connection to dst_addr:dst_port.
*
* The socket is non-blocking and TCP sockets has SIGPIPE disabled if
* possible. On Linux it's not possible and should be disabled for
* each send(2) individually.
*/
{
struct sockaddr_in6 dst_sin6;
struct sockaddr_in dst_sin;
void *pdst_addr;
int status;
SOCKET s;
#if HAVE_SA_LEN
#endif
dst_sa_len = sizeof(dst_sin6);
}
else { /* sdom = PF_INET */
#if HAVE_SA_LEN
#endif
dst_sa_len = sizeof(dst_sin);
}
#if LWIP_PROXY_DEBUG && !RT_OS_WINDOWS
{
char addrbuf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
const char *addrstr;
DPRINTF(("---> %s %s%s%s:%d ",
dst_port));
}
#endif
if (s == INVALID_SOCKET) {
return INVALID_SOCKET;
}
DPRINTF(("socket %d\n", s));
/* TODO: needs locking if dynamic modifyvm is allowed */
src_sa_len = sizeof(struct sockaddr_in6);
}
else {
src_sa_len = sizeof(struct sockaddr_in);
}
if (status == SOCKET_ERROR) {
closesocket(s);
return INVALID_SOCKET;
}
}
closesocket(s);
return INVALID_SOCKET;
}
return s;
}
/**
* Create a socket for inbound (port-forwarded) connections to
* src_addr (port is part of sockaddr, so not a separate argument).
*
* The socket is non-blocking and TCP sockets has SIGPIPE disabled if
* possible. On Linux it's not possible and should be disabled for
* each send(2) individually.
*
* TODO?: Support v6-mapped v4 so that user can specify she wants
* "udp" and get both versions?
*/
{
SOCKET s;
int on;
int status;
if (s == INVALID_SOCKET) {
return INVALID_SOCKET;
}
DPRINTF(("socket %d\n", s));
on = 1;
if (status < 0) { /* not good, but not fatal */
warn("SO_REUSEADDR");
}
sizeof(struct sockaddr_in)
: sizeof(struct sockaddr_in6));
if (status < 0) {
perror("bind");
closesocket(s);
return INVALID_SOCKET;
}
if (stype == SOCK_STREAM) {
if (status < 0) {
perror("listen");
closesocket(s);
return INVALID_SOCKET;
}
}
return s;
}
void
{
/* On Windows we can run into issue here, perhaps SO_LINGER isn't enough, and
* we should use WSA{Send,Recv}Disconnect instead.
*
* Links for the reference:
*/
closesocket(s);
}
int
{
struct pbuf *q;
#ifndef RT_OS_WINDOWS
#else
int rc;
#endif
int error = 0;
/*
* Static iov[] is usually enough since UDP protocols use small
* datagrams to avoid fragmentation, but be prepared.
*/
if (clen > fixiovsize) {
/*
* XXX: TODO: check that clen is shorter than IOV_MAX
*/
goto out;
}
}
else {
}
LWIP_ASSERT1(q != NULL);
}
#ifndef RT_OS_WINDOWS
if (nsent < 0) {
DPRINTF(("%s: fd %d: sendmsg errno %d\n",
}
#else
if (rc == SOCKET_ERROR) {
DPRINTF(("%s: fd %d: sendmsg errno %d\n",
error = -WSAGetLastError();
}
#endif
out:
}
return error;
}
static const char *lwiperr[] = {
"ERR_OK",
"ERR_MEM",
"ERR_BUF",
"ERR_TIMEOUT",
"ERR_RTE",
"ERR_INPROGRESS",
"ERR_VAL",
"ERR_WOULDBLOCK",
"ERR_USE",
"ERR_ISCONN",
"ERR_ABRT",
"ERR_RST",
"ERR_CLSD",
"ERR_CONN",
"ERR_ARG",
"ERR_IF"
};
const char *
{
static char buf[32];
int e = -error;
if (0 < e || e < (int)__arraycount(lwiperr)) {
return lwiperr[e];
}
else {
return buf;
}
}