switch to a simulation of epoll

the native async event system on windows
is _not_ very good at getting external events
(i.e. we receive data, but we don't get any indication
that this ever happened)
pull/66/head
despair 6 years ago
parent c325246beb
commit be7ac352ca

@ -206,7 +206,7 @@ if(UNIX)
endif()
elseif(WIN32)
set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-windows.c)
add_definitions(-DWIN32_LEAN_AND_MEAN -DWIN32 -DWINVER=0x600 -D_WIN32_WINNT=0x600)
add_definitions(-DWIN32_LEAN_AND_MEAN -DWIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500)
else()
message(FATAL_ERROR "What operating system _are_ you building on/for?")
endif(UNIX)
@ -283,6 +283,10 @@ set(LIB_PLATFORM_SRC
${LIBTUNTAP_SRC}
# c++17 compat code
${CXX_COMPAT_SRC}
# win32 inline code
llarp/win32_inet.c
llarp/win32_intrnl.c
llarp/win32_upoll.c
)
set(NTRU_AVX_SRC
@ -487,7 +491,6 @@ set(LIB_SRC
llarp/service/protocol.cpp
llarp/service/tag.cpp
llarp/service/info.cpp
)
set(RC_SRC

@ -3,6 +3,7 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#ifndef ssize_t
#define ssize_t long
#endif

@ -3,6 +3,21 @@
#if defined(_WIN32) || defined(__MINGW32__)
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
// because this shit is not defined for Windows NT reeeee
#ifdef __cplusplus
extern "C"
{
#endif
#if _WIN32_WINNT < 0x600
const char*
inet_ntop(int af, const void* src, char* dst, size_t size);
int
inet_pton(int af, const char* src, void* dst);
#endif
#ifdef __cplusplus
}
#endif
typedef unsigned short in_port_t;
typedef unsigned int in_addr_t;
#else

@ -19,6 +19,7 @@
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
#endif

@ -25,8 +25,23 @@
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#include "libutp_inet_ntop.h"
// we already have our own definition of these
// -despair
#if _WIN32_WINNT < 0x600
namespace
{
extern "C"
{
const char *
inet_ntop(int af, const void *src, char *dst, size_t size);
int
inet_pton(int af, const char *src, void *dst);
}
} // namespace
#endif
//######################################################################
const char *
libutp::inet_ntop(int af, const void *src, char *dest, size_t length)

@ -212,7 +212,7 @@ extern "C"
}
*/
question->name = m_qName;
question->type = get16bits(moveable);
(*pos) += 2;
// printf("Now1 at [%d]\n", buffer - start);
@ -242,9 +242,9 @@ extern "C"
// llarp::LogDebug("Advancing to pos ", std::to_string(*pos));
moveable += (*pos); // advance to position
//hexDump(moveable, 12);
//hexDumpAt(buffer, *pos, 12);
// hexDump(moveable, 12);
// hexDumpAt(buffer, *pos, 12);
if(*moveable == '\xc0')
{
// hexDump(moveable, 2);
@ -267,10 +267,10 @@ extern "C"
/*
uint32_t readAt32 = *pos;
answer->name = getDNSstring(buffer, &readAt32);
llarp::LogInfo("Parsed string ", answer->name, " read ", std::to_string(readAt32));
moveable += readAt32; (*pos) += readAt32;
llarp::LogInfo("Parsed string ", answer->name, " read ",
std::to_string(readAt32)); moveable += readAt32; (*pos) += readAt32;
*/
//moveable++; (*pos)++;
// moveable++; (*pos)++;
}
/*
hexDump(moveable, 10);
@ -330,12 +330,12 @@ extern "C"
// FIXME: move this out of here, this shouldn't be responsible for decode
switch(answer->type)
{
case 2: // NS
case 2: // NS
// don't really need to do anything here
moveable += answer->rdLen;
(*pos) += answer->rdLen; // advance the length
break;
case 5:
break;
case 5:
moveable += answer->rdLen;
(*pos) += answer->rdLen; // advance the length
break;
@ -371,10 +371,10 @@ extern "C"
{
std::string revname = getDNSstring(buffer, pos);
llarp::LogInfo("revDNSname: ", revname);
//answer->rData = new uint8_t[answer->rdLen + 1];
// answer->rData = new uint8_t[answer->rdLen + 1];
answer->rData.resize(answer->rdLen);
memcpy(answer->rData.data(), revname.c_str(), answer->rdLen);
//answer->rData = (uint8_t *)strdup(revname.c_str()); // safer? nope
// answer->rData = (uint8_t *)strdup(revname.c_str()); // safer? nope
moveable += answer->rdLen;
//(*pos) += answer->rdLen; // advance the length
}

@ -224,13 +224,14 @@ generic_handle_dnsc_recvfrom(dnsc_answer_request *request,
for(uint32_t i = 0; i < hdr->qdCount; i++)
{
question = decode_question(castBufc, &pos);
//llarp::LogDebug("Read a question, now at ", std::to_string(pos));
// llarp::LogDebug("Read a question, now at ", std::to_string(pos));
// 1 dot: 1 byte for length + length
// 4 bytes for class/type
// castBuf += question->name.length() + 1 + 4;
// castBuf += 2; // skip answer label
}
llarp::LogDebug("Question ", std::to_string(question->type), " ", question->name);
llarp::LogDebug("Question ", std::to_string(question->type), " ",
question->name);
// FIXME: only handling one atm
std::vector< dns_msg_answer * > answers;
@ -296,15 +297,15 @@ generic_handle_dnsc_recvfrom(dnsc_answer_request *request,
// pos = 0; // reset pos
answer = decode_answer(castBufc, &pos);
// answers.push_back(answer);
llarp::LogDebug("Read an authority for ",
request->question.name, " at ", std::to_string(pos));
llarp::LogDebug("Read an authority for ", request->question.name, " at ",
std::to_string(pos));
// castBuf += answer->name.length() + 4 + 4 + 4 + answer->rdLen;
if((ssize_t)pos > sz)
{
llarp::LogWarn("Would read past end of dns packet. for ",
request->question.name);
break;
}
if((ssize_t)pos > sz)
{
llarp::LogWarn("Would read past end of dns packet. for ",
request->question.name);
break;
}
}
/*
@ -393,14 +394,14 @@ generic_handle_dnsc_recvfrom(dnsc_answer_request *request,
int ip = 0;
// if no answer, just bail now
if (!answer)
{
request->found = false;
request->resolved(request);
return;
}
// if no answer, just bail now
if(!answer)
{
request->found = false;
request->resolved(request);
return;
}
/* search for and print IPv4 addresses */
// if(dnsQuery->reqType == 0x01)
/*
@ -603,7 +604,7 @@ llarp_handle_dnsc_recvfrom(struct llarp_udp_io *const udp,
llarp::LogDebug("Header got client responses for id: ", hdr->id);
// if we sent this out, then there's an id
struct dns_tracker *tracker = (struct dns_tracker *)udp->user;
struct dns_tracker *tracker = (struct dns_tracker *)udp->user;
struct dnsc_answer_request *request = tracker->client_request[hdr->id].get();
// sometimes we'll get double responses
@ -694,7 +695,7 @@ void
llarp_host_resolved(dnsc_answer_request *const request)
{
dns_tracker *tracker = (dns_tracker *)request->context->tracker;
auto val = std::find_if(
auto val = std::find_if(
tracker->client_request.begin(), tracker->client_request.end(),
[request](
std::pair< const uint32_t, std::unique_ptr< dnsc_answer_request > >
@ -735,7 +736,7 @@ llarp_dnsc_init(struct dnsc_context *const dnsc,
llarp::LogInfo("DNSc adding relay ", dnsc_sockaddr);
dnsc->resolvers.push_back(dnsc_sockaddr);
dnsc->tracker = &dns_udp_tracker;
dnsc->logic = logic;
dnsc->logic = logic;
return true;
}

@ -13,7 +13,8 @@
#include <algorithm>
#ifdef _WIN32
#include <variant>
#include <win32_up.h>
#include <win32_upoll.h>
#endif
#ifndef MAX_WRITE_QUEUE_SIZE
@ -105,23 +106,35 @@ namespace llarp
typedef std::deque< WriteBuffer > LosslessWriteQueue_t;
// on windows, tcp/udp event loops are socket fds
// and TUN device is a plain old fd
std::variant< SOCKET, HANDLE > fd;
ULONG_PTR listener_id = 0;
bool isTCP = false;
bool write = false;
// constructors
// for udp
win32_ev_io(SOCKET f) : fd(f){};
// for tun
win32_ev_io(HANDLE t, LossyWriteQueue_t* q) : fd(t), m_LossyWriteQueue(q){}
// for tcp
win32_ev_io(SOCKET f, LosslessWriteQueue_t* q)
: fd(f), m_BlockingWriteQueue(q)
{
isTCP = true;
union {
intptr_t socket;
HANDLE tun;
} fd;
int flags = 0;
bool is_tun = false;
win32_ev_io(intptr_t f)
{
fd.socket = f;
}
/// for tun
win32_ev_io(HANDLE f, LossyWriteQueue_t* q) : m_LossyWriteQueue(q)
{
fd.tun = f;
}
/// for tcp
win32_ev_io(intptr_t f, LosslessWriteQueue_t* q) : m_BlockingWriteQueue(q)
{
fd.socket = f;
}
virtual void
error()
{
llarp::LogError(strerror(errno));
}
virtual int
@ -147,15 +160,13 @@ namespace llarp
virtual ssize_t
do_write(void* data, size_t sz)
{
// hmm, think we should deallocate event ports in the loop itself
WSAOVERLAPPED* portfd = new WSAOVERLAPPED;
memset(portfd, 0, sizeof(WSAOVERLAPPED));
if(std::holds_alternative< HANDLE >(fd))
WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, portfd);
else
WriteFile((HANDLE)std::get< SOCKET >(fd), data, sz, nullptr,
portfd);
return sz; // we grab the error in the event loop
DWORD x;
if(this->is_tun)
{
WriteFile(fd.tun, data, sz, &x, nullptr);
return x;
}
return uwrite(fd.socket, (char*)data, sz);
}
bool
@ -255,7 +266,7 @@ namespace llarp
virtual ~win32_ev_io()
{
closesocket(std::get< SOCKET >(fd));
uclose(fd.socket);
};
};
#endif

@ -11,67 +11,30 @@
#ifdef sizeof
#undef sizeof
#endif
struct sock_visitor
{
int
operator()(SOCKET a)
{
return a;
}
ULONG_PTR
operator()(HANDLE a)
{
return (ULONG_PTR)a;
}
};
// TODO: convert all socket errno calls to WSAGetLastError(3),
// don't think winsock sets regular errno to this day
namespace llarp
{
int
tcp_conn::read(void* buf, size_t sz)
{
WSABUF r_buf = {(u_long)sz, (char*)buf};
WSAOVERLAPPED* portfd = new WSAOVERLAPPED;
memset(portfd, 0, sizeof(WSAOVERLAPPED));
if(_shouldClose)
return -1;
WSARecv(std::get< SOCKET >(fd), &r_buf, 1, nullptr, 0, portfd, nullptr);
ssize_t amount = uread(fd.socket, (char*)buf, sz);
if(WSAGetLastError() == 997)
if(amount > 0)
{
if(tcp.read)
tcp.read(&tcp, buf, sz);
tcp.read(&tcp, buf, amount);
}
else
{
// error
_shouldClose = true;
delete portfd;
return -1;
}
return 0;
}
ssize_t
tcp_conn::do_write(void* buf, size_t sz)
{
WSABUF s_buf = {(u_long)sz, (char*)buf};
WSAOVERLAPPED* portfd = new WSAOVERLAPPED;
memset(portfd, 0, sizeof(WSAOVERLAPPED));
if(_shouldClose)
{
delete portfd;
return -1;
}
WSASend(std::get< SOCKET >(fd), &s_buf, 1, nullptr, 0, portfd, nullptr);
return sz;
}
void
tcp_conn::flush_write()
{
@ -79,6 +42,14 @@ namespace llarp
ev_io::flush_write();
}
ssize_t
tcp_conn::do_write(void* buf, size_t sz)
{
if(_shouldClose)
return -1;
return uwrite(fd.socket, (char*)buf, sz);
}
void
tcp_conn::connect()
{
@ -87,8 +58,7 @@ namespace llarp
slen = 115;
else if(_addr.ss_family == AF_INET6)
slen = sizeof(sockaddr_in6);
int result =
::connect(std::get< SOCKET >(fd), (const sockaddr*)&_addr, slen);
int result = ::connect(fd.socket, (const sockaddr*)&_addr, slen);
if(result == 0)
{
llarp::LogDebug("connected immedidately");
@ -112,11 +82,10 @@ namespace llarp
int
tcp_serv::read(void*, size_t)
{
SOCKET new_fd = ::accept(std::get< SOCKET >(fd), nullptr, nullptr);
if(new_fd == INVALID_SOCKET)
int new_fd = ::accept(fd.socket, nullptr, nullptr);
if(new_fd == -1)
{
llarp::LogError("failed to accept on ", std::get< SOCKET >(fd), ":",
strerror(errno));
llarp::LogError("failed to accept on ", fd.socket, ":", strerror(errno));
return -1;
}
// build handler
@ -137,7 +106,7 @@ namespace llarp
{
llarp_udp_io* udp;
udp_listener(SOCKET fd, llarp_udp_io* u) : ev_io(fd), udp(u){};
udp_listener(int fd, llarp_udp_io* u) : ev_io(fd), udp(u){};
~udp_listener()
{
@ -151,41 +120,25 @@ namespace llarp
return true;
}
virtual int
int
read(void* buf, size_t sz)
{
printf("read\n");
WSAOVERLAPPED* portfd = new WSAOVERLAPPED;
memset(portfd, 0, sizeof(WSAOVERLAPPED));
sockaddr_in6 src;
socklen_t slen = sizeof(src);
sockaddr* addr = (sockaddr*)&src;
unsigned long flags = 0;
WSABUF wbuf = {(u_long)sz, static_cast< char* >(buf)};
// WSARecvFrom
llarp::LogDebug("read ", sz, " bytes from socket");
int ret = ::WSARecvFrom(std::get< SOCKET >(fd), &wbuf, 1, nullptr, &flags,
addr, &slen, portfd, nullptr);
// 997 is the error code for queued ops
int s_errno = ::WSAGetLastError();
if(ret && s_errno != 997)
{
llarp::LogWarn("recv socket error ", s_errno);
delete portfd;
socklen_t slen = sizeof(sockaddr_in6);
sockaddr* addr = (sockaddr*)&src;
ssize_t ret = ::recvfrom(fd.socket, (char*)buf, sz, 0, addr, &slen);
if(ret < 0)
return -1;
}
udp->recvfrom(udp, addr, buf, sz);
if(static_cast< size_t >(ret) > sz)
return -1;
udp->recvfrom(udp, addr, buf, ret);
return 0;
}
virtual int
int
sendto(const sockaddr* to, const void* data, size_t sz)
{
printf("write\n");
WSAOVERLAPPED* portfd = new WSAOVERLAPPED;
memset(portfd, 0, sizeof(WSAOVERLAPPED));
socklen_t slen;
WSABUF wbuf = {(u_long)sz, (char*)data};
switch(to->sa_family)
{
case AF_INET:
@ -197,18 +150,12 @@ namespace llarp
default:
return -1;
}
// WSASendTo
llarp::LogDebug("write ", sz, " bytes into socket");
ssize_t sent = ::WSASendTo(std::get< SOCKET >(fd), &wbuf, 1, nullptr, 0,
to, slen, portfd, nullptr);
int s_errno = ::WSAGetLastError();
if(sent && s_errno != 997)
ssize_t sent = ::sendto(fd.socket, (char*)data, sz, 0, to, slen);
if(sent == -1)
{
llarp::LogWarn("send socket error ", s_errno);
delete portfd;
return -1;
llarp::LogWarn(strerror(errno));
}
return 0;
return sent;
}
};
@ -220,7 +167,10 @@ namespace llarp
: ev_io(INVALID_HANDLE_VALUE,
new LossyWriteQueue_t("win32_tun_write_queue", l, l))
, t(tio)
, tunif(tuntap_init()){};
, tunif(tuntap_init())
{
this->is_tun = true;
};
int
sendto(const sockaddr* to, const void* data, size_t sz)
@ -253,9 +203,9 @@ namespace llarp
ssize_t
do_write(void* data, size_t sz)
{
OVERLAPPED* tun_async = new OVERLAPPED;
memset(tun_async, 0, sizeof(WSAOVERLAPPED));
return WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, tun_async);
DWORD x;
WriteFile(fd.tun, data, sz, &x, nullptr);
return x;
}
int
@ -288,8 +238,8 @@ namespace llarp
return false;
}
fd = tunif->tun_fd;
if(std::get< HANDLE >(fd) == INVALID_HANDLE_VALUE)
fd.tun = tunif->tun_fd;
if(fd.tun == INVALID_HANDLE_VALUE)
return false;
// we're already non-blocking
@ -305,9 +255,8 @@ namespace llarp
struct llarp_win32_loop : public llarp_ev_loop
{
HANDLE iocpfd;
llarp_win32_loop() : iocpfd(INVALID_HANDLE_VALUE)
upoll_t* upollfd;
llarp_win32_loop() : upollfd(nullptr)
{
}
@ -315,9 +264,8 @@ struct llarp_win32_loop : public llarp_ev_loop
tcp_connect(struct llarp_tcp_connecter* tcp, const sockaddr* remoteaddr)
{
// create socket
SOCKET fd = WSASocket(remoteaddr->sa_family, SOCK_STREAM, 0, nullptr, 0,
WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
int fd = usocket(remoteaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return false;
llarp::tcp_conn* conn = new llarp::tcp_conn(this, fd, remoteaddr, tcp);
add_ev(conn, true);
@ -325,19 +273,11 @@ struct llarp_win32_loop : public llarp_ev_loop
return true;
}
~llarp_win32_loop()
{
if(iocpfd != INVALID_HANDLE_VALUE)
::CloseHandle(iocpfd);
iocpfd = INVALID_HANDLE_VALUE;
}
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
SOCKET fd = WSASocket(bindaddr->sa_family, SOCK_STREAM, 0, nullptr, 0,
WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
int fd = usocket(bindaddr->sa_family, SOCK_STREAM, 0);
if(fd == -1)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
if(bindaddr->sa_family == AF_INET6)
@ -352,136 +292,128 @@ struct llarp_win32_loop : public llarp_ev_loop
sz = 110; // current size in 10.0.17763, verify each time the beta PSDK
// is updated
}
if(::bind(fd, bindaddr, sz) == SOCKET_ERROR)
if(::bind(fd, bindaddr, sz) == -1)
{
::closesocket(fd);
uclose(fd);
return nullptr;
}
if(::listen(fd, 5) == SOCKET_ERROR)
if(ulisten(fd, 5) == -1)
{
::closesocket(fd);
uclose(fd);
return nullptr;
}
llarp::ev_io* serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
return new llarp::tcp_serv(this, fd, tcp);
}
return serv;
virtual bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
l->fd = ev->fd.socket;
return ev && add_ev(ev, false);
}
bool
init()
~llarp_win32_loop()
{
if(iocpfd == INVALID_HANDLE_VALUE)
iocpfd = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);
if(upollfd)
upoll_destroy(upollfd);
}
if(iocpfd == INVALID_HANDLE_VALUE)
return false;
bool
running() const
{
return upollfd != nullptr;
}
return true;
bool
init()
{
if(!upollfd)
upollfd = upoll_create(1);
return false;
}
// it works! -despair86, 3-Aug-18 @0420
// if this new stuff works, may consider digging up the other code
// from the grave...
int
tick(int ms)
{
DWORD iolen = 0;
ULONG_PTR ev_id = 0;
WSAOVERLAPPED* qdata = nullptr;
int idx = 0;
while(GetQueuedCompletionStatus(iocpfd, &iolen, &ev_id, &qdata, ms))
upoll_event events[1024];
int result;
result = upoll_wait(upollfd, events, 1024, ms);
if(result > 0)
{
llarp::ev_io* ev = reinterpret_cast< llarp::ev_io* >(ev_id);
if(ev)
int idx = 0;
while(idx < result)
{
if(ev->write)
ev->flush_write_buffers(iolen);
else
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
if(ev)
{
if(qdata->Pointer) // the start packet is empty
if(events[idx].events & UPOLLERR)
{
ev->error();
}
else
{
memcpy(readbuf, qdata->Pointer, iolen);
ev->read(readbuf, iolen);
if(events[idx].events & UPOLLIN)
{
ev->read(readbuf, sizeof(readbuf));
}
if(events[idx].events & UPOLLOUT)
{
ev->flush_write();
}
}
}
++idx;
}
++idx;
delete qdata;
}
tick_listeners();
if(!idx)
idx--;
return idx;
/*
OVERLAPPED_ENTRY events[1024];
memset(&events, 0, sizeof(OVERLAPPED_ENTRY) * 1024);
ULONG result = 0;
::GetQueuedCompletionStatusEx(iocpfd, events, 1024, &result, ms,
false); ULONG idx = 0; while(idx < result)
{
llarp::ev_io* ev =
reinterpret_cast< llarp::ev_io*
>(events[idx].lpCompletionKey); if(ev && events[idx].lpOverlapped &&
events[idx].lpOverlapped->Pointer)
{
auto amount =
std::min(EV_READ_BUF_SZ,events[idx].dwNumberOfBytesTransferred);
if(ev->write)
ev->flush_write_buffers(amount);
else
{
memcpy(readbuf, events[idx].lpOverlapped->Pointer, amount);
ev->read(readbuf, amount);
}
delete events[idx].lpOverlapped;
}
++idx;
}
tick_listeners();
printf("exit loop: %lu\n", idx);
return idx;
*/
if(result != -1)
tick_listeners();
return result;
}
// ok apparently this isn't being used yet...
int
run()
{
DWORD iolen = 0;
ULONG_PTR ev_id = 0;
WSAOVERLAPPED* qdata = nullptr;
int idx = 0;
BOOL result =
::GetQueuedCompletionStatus(iocpfd, &iolen, &ev_id, &qdata, 10);
if(result && qdata)
upoll_event events[1024];
int result;
do
{
llarp::udp_listener* ev = reinterpret_cast< llarp::udp_listener* >(ev_id);
if(ev)
result = upoll_wait(upollfd, events, 1024, EV_TICK_INTERVAL);
if(result > 0)
{
llarp::LogDebug("size: ", iolen, "\tev_id: ", ev_id,
"\tqdata: ", qdata);
if(iolen <= sizeof(readbuf))
ev->read(readbuf, iolen);
int idx = 0;
while(idx < result)
{
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
if(ev)
{
if(events[idx].events & UPOLLERR)
{
ev->error();
}
else
{
if(events[idx].events & UPOLLIN)
{
ev->read(readbuf, sizeof(readbuf));
}
if(events[idx].events & UPOLLOUT)
{
ev->flush_write();
}
}
}
++idx;
}
}
++idx;
}
if(!idx)
return -1;
else
{
result = idx;
tick_listeners();
}
if(result != -1)
tick_listeners();
} while(upollfd);
return result;
}
SOCKET
int
udp_bind(const sockaddr* addr)
{
socklen_t slen;
@ -494,28 +426,26 @@ struct llarp_win32_loop : public llarp_ev_loop
slen = sizeof(struct sockaddr_in6);
break;
default:
return INVALID_SOCKET;
return -1;
}
SOCKET fd = WSASocket(addr->sa_family, SOCK_DGRAM, 0, nullptr, 0,
WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
int fd = usocket(addr->sa_family, SOCK_DGRAM, 0);
if(fd == -1)
{
perror("WSASocket()");
return INVALID_SOCKET;
perror("usocket()");
return -1;
}
if(addr->sa_family == AF_INET6)
{
// enable dual stack explicitly
int dual = 1;
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&dual,
sizeof(dual))
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&dual, sizeof(dual))
== -1)
{
// failed
perror("setsockopt()");
closesocket(fd);
return INVALID_SOCKET;
close(fd);
return -1;
}
}
llarp::Addr a(*addr);
@ -523,49 +453,17 @@ struct llarp_win32_loop : public llarp_ev_loop
if(bind(fd, addr, slen) == -1)
{
perror("bind()");
closesocket(fd);
return INVALID_SOCKET;
close(fd);
return -1;
}
llarp::LogDebug("socket fd is ", fd);
return fd;
}
bool
close_ev(llarp::ev_io* ev)
{
// On Windows, just close the descriptor to decrease the iocp refcount
// and stop any pending I/O
BOOL stopped;
int close_fd;
if(std::holds_alternative< SOCKET >(ev->fd))
{
stopped =
::CancelIo(reinterpret_cast< HANDLE >(std::get< SOCKET >(ev->fd)));
close_fd = closesocket(std::get< SOCKET >(ev->fd));
}
else
{
stopped = ::CancelIo(std::get< HANDLE >(ev->fd));
close_fd = CloseHandle(std::get< HANDLE >(ev->fd));
if(close_fd)
close_fd = 0; // must be zero
else
close_fd = 1;
}
return close_fd == 0 && stopped == TRUE;
}
llarp::ev_io*
create_udp(llarp_udp_io* l, const sockaddr* src)
{
SOCKET fd = udp_bind(src);
llarp::LogDebug("new socket fd is ", fd);
if(fd == INVALID_SOCKET)
return nullptr;
llarp::udp_listener* listener = new llarp::udp_listener(fd, l);
l->impl = listener;
return listener;
return upoll_ctl(upollfd, UPOLL_CTL_DEL, ev->fd.socket, nullptr) != -1;
}
llarp::ev_io*
@ -573,63 +471,38 @@ struct llarp_win32_loop : public llarp_ev_loop
{
llarp::tun* t = new llarp::tun(tun, this);
if(t->setup())
{
return t;
}
delete t;
return nullptr;
}
bool
add_ev(llarp::ev_io* ev, bool write)
llarp::ev_io*
create_udp(llarp_udp_io* l, const sockaddr* src)
{
ev->listener_id = reinterpret_cast< ULONG_PTR >(ev);
OVERLAPPED* o = new OVERLAPPED;
memset(o, 0, sizeof(OVERLAPPED));
// if the write flag was set earlier,
// clear it on demand
if(ev->write && !write)
ev->write = false;
int fd = udp_bind(src);
if(fd == -1)
return nullptr;
llarp::ev_io* listener = new llarp::udp_listener(fd, l);
l->impl = listener;
return listener;
}
bool
add_ev(llarp::ev_io* e, bool write)
{
upoll_event ev;
ev.data.ptr = e;
ev.events = UPOLLIN | UPOLLERR;
if(write)
ev->write = true;
// now write a blank packet containing nothing but the address of
// the event listener
if(ev->isTCP)
{
if(!::CreateIoCompletionPort((HANDLE)std::get< SOCKET >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
else
goto start_loop;
}
if(std::holds_alternative< SOCKET >(ev->fd))
{
if(!::CreateIoCompletionPort((HANDLE)std::get< SOCKET >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
}
else
ev.events |= UPOLLOUT;
if(upoll_ctl(upollfd, UPOLL_CTL_ADD, e->fd.socket, &ev) == -1)
{
if(!::CreateIoCompletionPort(std::get< HANDLE >(ev->fd), iocpfd,
ev->listener_id, 0))
{
delete ev;
return false;
}
delete e;
return false;
}
start_loop:
handlers.emplace_back(ev);
delete o;
llarp::LogInfo("added fd ", std::visit(sock_visitor{}, ev->fd), " to event queue");
handlers.emplace_back(e);
return true;
}
@ -657,44 +530,13 @@ struct llarp_win32_loop : public llarp_ev_loop
return ret;
}
bool
running() const
{
return iocpfd != INVALID_HANDLE_VALUE;
}
bool
udp_listen(llarp_udp_io* l, const sockaddr* src)
{
auto ev = create_udp(l, src);
if(ev)
l->fd = std::get< SOCKET >(ev->fd);
return ev && add_ev(ev, false);
}
void
stop()
{
// Are we leaking any file descriptors?
// This was part of the reason I had this
// in the destructor.
/*if(iocpfd != INVALID_HANDLE_VALUE)
::CloseHandle(iocpfd);
iocpfd = INVALID_HANDLE_VALUE;*/
if(upollfd)
upoll_destroy(upollfd);
upollfd = nullptr;
}
};
// This hands us a new event port for the tun
// read/write functions that can later be freed with
// operator delete in the event loop tick
extern "C"
{
OVERLAPPED*
getTunEvPort()
{
OVERLAPPED* newport = new OVERLAPPED;
return newport;
}
}
#endif

@ -17,6 +17,7 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#endif
namespace llarp
@ -329,29 +330,13 @@ namespace llarp
static_cast< LinkLayer* >(utp_context_get_userdata(arg->context));
llarp::LogDebug("utp_sendto ", Addr(*arg->address), " ", arg->len,
" bytes");
#ifdef _WIN32
WSABUF s;
int i,x;
WSAOVERLAPPED* o = new WSAOVERLAPPED;
memset(o, 0, sizeof(WSAOVERLAPPED));
s.buf = (char*)arg->buf;
s.len = arg->len;
i = WSASendTo(l->m_udp.fd, &s, 1, nullptr, arg->flags, arg->address,
arg->address_len, o, nullptr);
x = WSAGetLastError();
if((i && x == 997) || (!i))
return 0;
else
llarp::LogError("sendto failed: ", strerror(WSAGetLastError()));
#else
if(::sendto(l->m_udp.fd, (char*)arg->buf, arg->len, arg->flags,
arg->address, arg->address_len)
== -1
&& errno)
if(::sendto(l->m_udp.fd, (char*)arg->buf, arg->len, arg->flags,
arg->address, arg->address_len)
== -1
&& errno)
{
llarp::LogError("sendto failed: ", strerror(errno));
}
#endif
return 0;
}

@ -68,8 +68,25 @@ operator==(const sockaddr_in6& a, const sockaddr_in6& b)
#include <iphlpapi.h>
#include <strsafe.h>
// current strategy: mingw 32-bit builds call an inlined version of the function
// microsoft c++ and mingw 64-bit builds call the normal function
#define DEFAULT_BUFFER_SIZE 15000
// the inline monkey patch for downlevel platforms
#ifndef _MSC_VER
extern "C" DWORD FAR PASCAL
_GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved,
PIP_ADAPTER_ADDRESSES pAdapterAddresses,
PULONG pOutBufLen);
#endif
// in any case, we still need to implement some form of
// getifaddrs(3) with compatible semantics on NT...
// daemon.ini section [bind] will have something like
// [bind]
// Ethernet=1090
// inside, since that's what we use in windows to refer to
// network interfaces
struct llarp_nt_ifaddrs_t
{
struct llarp_nt_ifaddrs_t* ifa_next; /* Pointer to the next structure. */
@ -123,6 +140,148 @@ llarp_nt_sockaddr_pton(const char* src, struct sockaddr* dst)
return 0;
}
/* NB: IP_ADAPTER_INFO size varies size due to sizeof (time_t), the API assumes
* 4-byte datatype whilst compiler uses an 8-byte datatype. Size can be forced
* with -D_USE_32BIT_TIME_T with side effects to everything else.
*
* Only supports IPv4 addressing similar to SIOCGIFCONF socket option.
*
* Interfaces that are not "operationally up" will return the address 0.0.0.0,
* this includes adapters with static IP addresses but with disconnected cable.
* This is documented under the GetIpAddrTable API. Interface status can only
* be determined by the address, a separate flag is introduced with the
* GetAdapterAddresses API.
*
* The IPv4 loopback interface is not included.
*
* Available in Windows 2000 and Wine 1.0.
*/
static bool
_llarp_nt_getadaptersinfo(struct llarp_nt_ifaddrs_t** ifap)
{
DWORD dwRet;
ULONG ulOutBufLen = DEFAULT_BUFFER_SIZE;
PIP_ADAPTER_INFO pAdapterInfo = nullptr;
PIP_ADAPTER_INFO pAdapter = nullptr;
/* loop to handle interfaces coming online causing a buffer overflow
* between first call to list buffer length and second call to enumerate.
*/
for(unsigned i = 3; i; i--)
{
#ifdef DEBUG
fprintf(stderr, "IP_ADAPTER_INFO buffer length %lu bytes.\n", ulOutBufLen);
#endif
pAdapterInfo = (IP_ADAPTER_INFO*)_llarp_nt_heap_alloc(ulOutBufLen);
dwRet = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
if(ERROR_BUFFER_OVERFLOW == dwRet)
{
_llarp_nt_heap_free(pAdapterInfo);
pAdapterInfo = nullptr;
}
else
{
break;
}
}
switch(dwRet)
{
case ERROR_SUCCESS: /* NO_ERROR */
break;
case ERROR_BUFFER_OVERFLOW:
errno = ENOBUFS;
if(pAdapterInfo)
_llarp_nt_heap_free(pAdapterInfo);
return false;
default:
errno = dwRet;
#ifdef DEBUG
fprintf(stderr, "system call failed: %lu\n", GetLastError());
#endif
if(pAdapterInfo)
_llarp_nt_heap_free(pAdapterInfo);
return false;
}
/* count valid adapters */
int n = 0, k = 0;
for(pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next)
{
for(IP_ADDR_STRING* pIPAddr = &pAdapter->IpAddressList; pIPAddr;
pIPAddr = pIPAddr->Next)
{
/* skip null adapters */
if(strlen(pIPAddr->IpAddress.String) == 0)
continue;
++n;
}
}
#ifdef DEBUG
fprintf(stderr, "GetAdaptersInfo() discovered %d interfaces.\n", n);
#endif
/* contiguous block for adapter list */
struct _llarp_nt_ifaddrs_t* ifa =
llarp_nt_new0(struct _llarp_nt_ifaddrs_t, n);
struct _llarp_nt_ifaddrs_t* ift = ifa;
/* now populate list */
for(pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next)
{
for(IP_ADDR_STRING* pIPAddr = &pAdapter->IpAddressList; pIPAddr;
pIPAddr = pIPAddr->Next)
{
/* skip null adapters */
if(strlen(pIPAddr->IpAddress.String) == 0)
continue;
/* address */
ift->_ifa.ifa_addr = (struct sockaddr*)&ift->_addr;
assert(1
== llarp_nt_sockaddr_pton(pIPAddr->IpAddress.String,
ift->_ifa.ifa_addr));
/* name */
#ifdef DEBUG
fprintf(stderr, "name:%s IPv4 index:%lu\n", pAdapter->AdapterName,
pAdapter->Index);
#endif
ift->_ifa.ifa_name = ift->_name;
StringCchCopyN(ift->_ifa.ifa_name, 128, pAdapter->AdapterName, 128);
/* flags: assume up, broadcast and multicast */
ift->_ifa.ifa_flags = IFF_UP | IFF_BROADCAST | IFF_MULTICAST;
if(pAdapter->Type == MIB_IF_TYPE_LOOPBACK)
ift->_ifa.ifa_flags |= IFF_LOOPBACK;
/* netmask */
ift->_ifa.ifa_netmask = (sockaddr*)&ift->_netmask;
assert(1
== llarp_nt_sockaddr_pton(pIPAddr->IpMask.String,
ift->_ifa.ifa_netmask));
/* next */
if(k++ < (n - 1))
{
ift->_ifa.ifa_next = (struct llarp_nt_ifaddrs_t*)(ift + 1);
ift = (struct _llarp_nt_ifaddrs_t*)(ift->_ifa.ifa_next);
}
else
{
ift->_ifa.ifa_next = nullptr;
}
}
}
if(pAdapterInfo)
_llarp_nt_heap_free(pAdapterInfo);
*ifap = (struct llarp_nt_ifaddrs_t*)ifa;
return true;
}
#if 0
/* Supports both IPv4 and IPv6 addressing. The size of IP_ADAPTER_ADDRESSES
* changes between Windows XP, XP SP1, and Vista with additional members.
*
@ -136,6 +295,9 @@ llarp_nt_sockaddr_pton(const char* src, struct sockaddr* dst)
* and lower layer down.
*
* Available in Windows XP and Wine 1.3.
*
* NOTE(despair): an inline implementation is provided, much like
* getaddrinfo(3) for old hosts. See "win32_intrnl.*"
*/
static bool
_llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
@ -152,7 +314,7 @@ _llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
fprintf(stderr, "IP_ADAPTER_ADDRESSES buffer length %lu bytes.\n", dwSize);
#endif
pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_llarp_nt_heap_alloc(dwSize);
dwRet = GetAdaptersAddresses(
dwRet = _GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME
@ -447,10 +609,6 @@ _llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
ift->_ifa.ifa_next = (struct llarp_nt_ifaddrs_t*)(ift + 1);
ift = (struct _llarp_nt_ifaddrs_t*)(ift->_ifa.ifa_next);
}
else
{
ift->_ifa.ifa_next = nullptr;
}
}
}
@ -459,13 +617,18 @@ _llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
*ifap = (struct llarp_nt_ifaddrs_t*)ifa;
return TRUE;
}
#endif
// an implementation of if_nametoindex(3) based on GetAdapterIndex(2)
// with a fallback to GetAdaptersAddresses(2) commented out for now
// unless it becomes evident that the first codepath fails in certain
// edge cases?
static unsigned
_llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
{
ULONG ifIndex;
DWORD dwSize = 4096, dwRet;
IP_ADAPTER_ADDRESSES *pAdapterAddresses = nullptr, *adapter;
DWORD /* dwSize = 4096,*/ dwRet;
// IP_ADAPTER_ADDRESSES *pAdapterAddresses = nullptr, *adapter;
char szAdapterName[256];
if(!ifname)
@ -479,6 +642,7 @@ _llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
else
return 0;
#if 0
/* fallback to finding index via iterating adapter list */
/* loop to handle interfaces coming online causing a buffer overflow
@ -487,7 +651,7 @@ _llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
for(unsigned i = 3; i; i--)
{
pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_llarp_nt_heap_alloc(dwSize);
dwRet = GetAdaptersAddresses(
dwRet = _GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST,
@ -533,6 +697,7 @@ _llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
if(pAdapterAddresses)
_llarp_nt_heap_free(pAdapterAddresses);
return 0;
#endif
}
// the emulated getifaddrs(3) itself.
@ -544,7 +709,7 @@ llarp_nt_getifaddrs(struct llarp_nt_ifaddrs_t** ifap)
fprintf(stderr, "llarp_nt_getifaddrs (ifap:%p error:%p)\n", (void*)ifap,
(void*)errno);
#endif
return _llarp_nt_getadaptersaddresses(ifap);
return _llarp_nt_getadaptersinfo(ifap);
}
static void

@ -11,6 +11,7 @@
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
#endif

@ -0,0 +1,315 @@
#if defined(__MINGW32__) && !defined(_WIN64)
/*
* Contains routines missing from WS2_32.DLL until 2006, if yer using
* Microsoft C/C++, then this code is irrelevant, as the official
* Platform SDK already links against these routines in the correct
* libraries.
*
* -despair86 30/07/18
*/
// these need to be in a specific order
#include <assert.h>
#include <llarp/net.h>
#include <windows.h>
#include <iphlpapi.h>
#if WINNT_CROSS_COMPILE && !NTSTATUS
typedef LONG NTSTATUS;
#endif
#include "win32_intrnl.h"
const char *
inet_ntop(int af, const void *src, char *dst, size_t size)
{
int address_length;
DWORD string_length = size;
struct sockaddr_storage sa;
struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
memset(&sa, 0, sizeof(sa));
switch(af)
{
case AF_INET:
address_length = sizeof(struct sockaddr_in);
sin->sin_family = af;
memcpy(&sin->sin_addr, src, sizeof(struct in_addr));
break;
case AF_INET6:
address_length = sizeof(struct sockaddr_in6);
sin6->sin6_family = af;
memcpy(&sin6->sin6_addr, src, sizeof(struct in6_addr));
break;
default:
return NULL;
}
if(WSAAddressToString((LPSOCKADDR)&sa, address_length, NULL, dst,
&string_length)
== 0)
{
return dst;
}
return NULL;
}
int
inet_pton(int af, const char *src, void *dst)
{
int address_length;
struct sockaddr_storage sa;
struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
switch(af)
{
case AF_INET:
address_length = sizeof(struct sockaddr_in);
break;
case AF_INET6:
address_length = sizeof(struct sockaddr_in6);
break;
default:
return -1;
}
if(WSAStringToAddress((LPTSTR)src, af, NULL, (LPSOCKADDR)&sa, &address_length)
== 0)
{
switch(af)
{
case AF_INET:
memcpy(dst, &sin->sin_addr, sizeof(struct in_addr));
break;
case AF_INET6:
memcpy(dst, &sin6->sin6_addr, sizeof(struct in6_addr));
break;
}
return 1;
}
return 0;
}
typedef struct _InterfaceIndexTable
{
DWORD numIndexes;
IF_INDEX indexes[1];
} InterfaceIndexTable;
// windows 2000
// todo(despair86): implement IPv6 detection using
// the ipv6 preview stack/adv net pack from 1999/2001
DWORD FAR PASCAL
_GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved,
PIP_ADAPTER_ADDRESSES pAdapterAddresses,
PULONG pOutBufLen)
{
InterfaceIndexTable *indexTable;
IFInfo ifInfo;
int i;
ULONG ret, requiredSize = 0;
PIP_ADAPTER_ADDRESSES currentAddress;
PUCHAR currentLocation;
HANDLE tcpFile;
(void)(Family);
if(!pOutBufLen)
return ERROR_INVALID_PARAMETER;
if(Reserved)
return ERROR_INVALID_PARAMETER;
indexTable = getInterfaceIndexTable();
if(!indexTable)
return ERROR_NOT_ENOUGH_MEMORY;
ret = openTcpFile(&tcpFile, FILE_READ_DATA);
if(!NT_SUCCESS(ret))
return ERROR_NO_DATA;
for(i = indexTable->numIndexes; i >= 0; i--)
{
if(NT_SUCCESS(
getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo)))
{
/* The whole struct */
requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
/* Friendly name */
if(!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
requiredSize +=
strlen((char *)ifInfo.if_info.ent.if_descr) + 1; // FIXME
/* Adapter name */
requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
/* Unicast address */
if(!(Flags & GAA_FLAG_SKIP_UNICAST))
requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
/* FIXME: Implement multicast, anycast, and dns server stuff */
/* FIXME: Implement dns suffix and description */
requiredSize += 2 * sizeof(WCHAR);
/* We're only going to implement what's required for XP SP0 */
}
}
#ifdef DEBUG
fprintf(stderr, "size: %ld, requiredSize: %ld\n", *pOutBufLen, requiredSize);
#endif
if(!pAdapterAddresses || *pOutBufLen < requiredSize)
{
*pOutBufLen = requiredSize;
closeTcpFile(tcpFile);
free(indexTable);
return ERROR_BUFFER_OVERFLOW;
}
RtlZeroMemory(pAdapterAddresses, requiredSize);
/* Let's set up the pointers */
currentAddress = pAdapterAddresses;
for(i = indexTable->numIndexes; i >= 0; i--)
{
if(NT_SUCCESS(
getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo)))
{
currentLocation =
(PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
/* FIXME: Friendly name */
if(!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
{
currentAddress->FriendlyName = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
}
/* Adapter name */
currentAddress->AdapterName = (PVOID)currentLocation;
currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
/* Unicast address */
if(!(Flags & GAA_FLAG_SKIP_UNICAST))
{
currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
currentAddress->FirstUnicastAddress->Address.lpSockaddr =
(PVOID)currentLocation;
currentLocation += sizeof(struct sockaddr);
}
/* FIXME: Implement multicast, anycast, and dns server stuff */
/* FIXME: Implement dns suffix and description */
currentAddress->DnsSuffix = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
currentAddress->Description = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
currentAddress->Next = (PVOID)currentLocation;
/* Terminate the last address correctly */
if(i == 0)
currentAddress->Next = NULL;
/* We're only going to implement what's required for XP SP0 */
currentAddress = currentAddress->Next;
}
}
/* Now again, for real this time */
currentAddress = pAdapterAddresses;
for(i = indexTable->numIndexes; i >= 0; i--)
{
if(NT_SUCCESS(
getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo)))
{
/* Make sure we're not looping more than we hoped for */
assert(currentAddress);
/* Alignment information */
currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
currentAddress->IfIndex = indexTable->indexes[i];
/* Adapter name */
strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr);
if(!(Flags & GAA_FLAG_SKIP_UNICAST))
{
currentAddress->FirstUnicastAddress->Length =
sizeof(IP_ADAPTER_UNICAST_ADDRESS);
currentAddress->FirstUnicastAddress->Flags = 0; // FIXME
currentAddress->FirstUnicastAddress->Next =
NULL; // FIXME: Support more than one address per adapter
currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family =
AF_INET;
memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
&ifInfo.ip_addr.iae_addr, sizeof(ifInfo.ip_addr.iae_addr));
currentAddress->FirstUnicastAddress->Address.iSockaddrLength =
sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
currentAddress->FirstUnicastAddress->PrefixOrigin =
IpPrefixOriginOther; // FIXME
currentAddress->FirstUnicastAddress->SuffixOrigin =
IpSuffixOriginOther; // FIXME
currentAddress->FirstUnicastAddress->DadState =
IpDadStatePreferred; // FIXME
currentAddress->FirstUnicastAddress->ValidLifetime =
0xFFFFFFFF; // FIXME
currentAddress->FirstUnicastAddress->PreferredLifetime =
0xFFFFFFFF; // FIXME
currentAddress->FirstUnicastAddress->LeaseLifetime =
0xFFFFFFFF; // FIXME
}
/* FIXME: Implement multicast, anycast, and dns server stuff */
currentAddress->FirstAnycastAddress = NULL;
currentAddress->FirstMulticastAddress = NULL;
currentAddress->FirstDnsServerAddress = NULL;
/* FIXME: Implement dns suffix, description, and friendly name */
currentAddress->DnsSuffix[0] = UNICODE_NULL;
currentAddress->Description[0] = UNICODE_NULL;
currentAddress->FriendlyName[0] = UNICODE_NULL;
/* Physical Address */
memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr,
ifInfo.if_info.ent.if_physaddrlen);
currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
/* Flags */
currentAddress->Flags = 0; // FIXME
/* MTU */
currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
/* Interface type */
currentAddress->IfType = ifInfo.if_info.ent.if_type;
/* Operational status */
if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
currentAddress->OperStatus = IfOperStatusUp;
else
currentAddress->OperStatus = IfOperStatusDown;
/* We're only going to implement what's required for XP SP0 */
/* Move to the next address */
currentAddress = currentAddress->Next;
}
}
closeTcpFile(tcpFile);
free(indexTable);
return NO_ERROR;
}
#endif

@ -0,0 +1,572 @@
#if defined(__MINGW32__) && !defined(_WIN64)
/*
* All the user-mode scaffolding necessary to backport GetAdaptersAddresses(2))
* to the NT 5.x series. See further comments for any limitations.
* NOTE: this is dead code, i haven't had time to debug it yet due to illness.
* For now, downlevel platforms use GetAdaptersInfo(2) which is inet4 only.
* -despair86 20/08/18
*/
#include <assert.h>
#include <stdio.h>
// apparently mingw-w64 loses its shit over this
// but only for 32-bit builds, naturally
#ifdef WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#endif
// these need to be in a specific order
#include <windows.h>
#include <winternl.h>
#include <tdi.h>
#include "win32_intrnl.h"
const PWCHAR TcpFileName = L"\\Device\\Tcp";
// from ntdll.dll
typedef void(FAR PASCAL *pRtlInitUString)(UNICODE_STRING *, const WCHAR *);
typedef NTSTATUS(FAR PASCAL *pNTOpenFile)(HANDLE *, ACCESS_MASK,
OBJECT_ATTRIBUTES *,
IO_STATUS_BLOCK *, ULONG, ULONG);
typedef NTSTATUS(FAR PASCAL *pNTClose)(HANDLE);
#define FSCTL_TCP_BASE FILE_DEVICE_NETWORK
#define _TCP_CTL_CODE(Function, Method, Access) \
CTL_CODE(FSCTL_TCP_BASE, Function, Method, Access)
#define IOCTL_TCP_QUERY_INFORMATION_EX \
_TCP_CTL_CODE(0, METHOD_NEITHER, FILE_ANY_ACCESS)
typedef struct _InterfaceIndexTable
{
DWORD numIndexes;
DWORD numAllocated;
DWORD indexes[1];
} InterfaceIndexTable;
NTSTATUS
tdiGetMibForIfEntity(HANDLE tcpFile, TDIEntityID *ent,
IFEntrySafelySized *entry)
{
TCP_REQUEST_QUERY_INFORMATION_EX req;
NTSTATUS status = 0;
DWORD returnSize;
#ifdef DEBUG
fprintf(stderr, "TdiGetMibForIfEntity(tcpFile %x,entityId %x)\n",
(int)tcpFile, (int)ent->tei_instance);
#endif
memset(&req, 0, sizeof(req));
req.ID.toi_class = INFO_CLASS_PROTOCOL;
req.ID.toi_type = INFO_TYPE_PROVIDER;
req.ID.toi_id = 1;
req.ID.toi_entity = *ent;
status =
DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req,
sizeof(req), entry, sizeof(*entry), &returnSize, NULL);
if(!status)
{
perror("IOCTL Failed\n");
return 0xc0000001;
}
fprintf(stderr,
"TdiGetMibForIfEntity() => {\n"
" if_index ....................... %lx\n"
" if_type ........................ %lx\n"
" if_mtu ......................... %ld\n"
" if_speed ....................... %lx\n"
" if_physaddrlen ................. %ld\n",
entry->ent.if_index, entry->ent.if_type, entry->ent.if_mtu,
entry->ent.if_speed, entry->ent.if_physaddrlen);
fprintf(stderr,
" if_physaddr .................... %02x:%02x:%02x:%02x:%02x:%02x\n"
" if_descr ....................... %s\n",
entry->ent.if_physaddr[0] & 0xff, entry->ent.if_physaddr[1] & 0xff,
entry->ent.if_physaddr[2] & 0xff, entry->ent.if_physaddr[3] & 0xff,
entry->ent.if_physaddr[4] & 0xff, entry->ent.if_physaddr[5] & 0xff,
entry->ent.if_descr);
fprintf(stderr, "} status %08lx\n", status);
return 0;
}
static NTSTATUS
tdiGetSetOfThings(HANDLE tcpFile, DWORD toiClass, DWORD toiType, DWORD toiId,
DWORD teiEntity, DWORD teiInstance, DWORD fixedPart,
DWORD entrySize, PVOID *tdiEntitySet, PDWORD numEntries)
{
TCP_REQUEST_QUERY_INFORMATION_EX req;
PVOID entitySet = 0;
NTSTATUS status = 0;
DWORD allocationSizeForEntityArray = entrySize * MAX_TDI_ENTITIES,
arraySize = entrySize * MAX_TDI_ENTITIES;
memset(&req, 0, sizeof(req));
req.ID.toi_class = toiClass;
req.ID.toi_type = toiType;
req.ID.toi_id = toiId;
req.ID.toi_entity.tei_entity = teiEntity;
req.ID.toi_entity.tei_instance = teiInstance;
/* There's a subtle problem here...
* If an interface is added at this exact instant, (as if by a PCMCIA
* card insertion), the array will still not have enough entries after
* have allocated it after the first DeviceIoControl call.
*
* We'll get around this by repeating until the number of interfaces
* stabilizes.
*/
do
{
status =
DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req,
sizeof(req), 0, 0, &allocationSizeForEntityArray, NULL);
if(!status)
return 0xc0000001;
arraySize = allocationSizeForEntityArray;
entitySet = HeapAlloc(GetProcessHeap(), 0, arraySize);
if(!entitySet)
{
status = ((NTSTATUS)0xC000009A);
return status;
}
status = DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req,
sizeof(req), entitySet, arraySize,
&allocationSizeForEntityArray, NULL);
/* This is why we have the loop -- we might have added an adapter */
if(arraySize == allocationSizeForEntityArray)
break;
HeapFree(GetProcessHeap(), 0, entitySet);
entitySet = 0;
if(!status)
return 0xc0000001;
} while(TRUE); /* We break if the array we received was the size we
* expected. Therefore, we got here because it wasn't */
*numEntries = (arraySize - fixedPart) / entrySize;
*tdiEntitySet = entitySet;
return 0;
}
static NTSTATUS
tdiGetEntityIDSet(HANDLE tcpFile, TDIEntityID **entitySet, PDWORD numEntities)
{
NTSTATUS status =
tdiGetSetOfThings(tcpFile, INFO_CLASS_GENERIC, INFO_TYPE_PROVIDER,
ENTITY_LIST_ID, GENERIC_ENTITY, 0, 0,
sizeof(TDIEntityID), (PVOID *)entitySet, numEntities);
return status;
}
NTSTATUS
tdiGetIpAddrsForIpEntity(HANDLE tcpFile, TDIEntityID *ent, IPAddrEntry **addrs,
PDWORD numAddrs)
{
NTSTATUS status;
#ifdef DEBUG
fprintf(stderr, "TdiGetIpAddrsForIpEntity(tcpFile 0x%p, entityId 0x%lx)\n",
tcpFile, ent->tei_instance);
#endif
status = tdiGetSetOfThings(tcpFile, INFO_CLASS_PROTOCOL, INFO_TYPE_PROVIDER,
0x102, CL_NL_ENTITY, ent->tei_instance, 0,
sizeof(IPAddrEntry), (PVOID *)addrs, numAddrs);
return status;
}
static VOID
tdiFreeThingSet(PVOID things)
{
HeapFree(GetProcessHeap(), 0, things);
}
NTSTATUS
openTcpFile(PHANDLE tcpFile, ACCESS_MASK DesiredAccess)
{
UNICODE_STRING fileName;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
pRtlInitUString _RtlInitUnicodeString;
pNTOpenFile _NTOpenFile;
HANDLE ntdll;
ntdll = GetModuleHandle("ntdll.dll");
_RtlInitUnicodeString =
(pRtlInitUString)GetProcAddress(ntdll, "RtlInitUnicodeString");
_NTOpenFile = (pNTOpenFile)GetProcAddress(ntdll, "NtOpenFile");
_RtlInitUnicodeString(&fileName, TcpFileName);
InitializeObjectAttributes(&objectAttributes, &fileName, OBJ_CASE_INSENSITIVE,
NULL, NULL);
status = _NTOpenFile(tcpFile, DesiredAccess | SYNCHRONIZE, &objectAttributes,
&ioStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
/* String does not need to be freed: it points to the constant
* string we provided */
if(!NT_SUCCESS(status))
*tcpFile = INVALID_HANDLE_VALUE;
return status;
}
VOID
closeTcpFile(HANDLE h)
{
pNTClose _NTClose;
HANDLE ntdll = GetModuleHandle("ntdll.dll");
_NTClose = (pNTClose)GetProcAddress(ntdll, "NtClose");
assert(h != INVALID_HANDLE_VALUE);
_NTClose(h);
}
BOOL
isLoopback(HANDLE tcpFile, TDIEntityID *loop_maybe)
{
IFEntrySafelySized entryInfo;
NTSTATUS status;
status = tdiGetMibForIfEntity(tcpFile, loop_maybe, &entryInfo);
return NT_SUCCESS(status)
&& (entryInfo.ent.if_type == IFENT_SOFTWARE_LOOPBACK);
}
BOOL
isIpEntity(HANDLE tcpFile, TDIEntityID *ent)
{
UNREFERENCED_PARAMETER(tcpFile);
return (ent->tei_entity == CL_NL_ENTITY || ent->tei_entity == CO_NL_ENTITY);
}
NTSTATUS
getNthIpEntity(HANDLE tcpFile, DWORD index, TDIEntityID *ent)
{
DWORD numEntities = 0;
DWORD numRoutes = 0;
TDIEntityID *entitySet = 0;
NTSTATUS status = tdiGetEntityIDSet(tcpFile, &entitySet, &numEntities);
unsigned i;
if(!NT_SUCCESS(status))
return status;
for(i = 0; i < numEntities; i++)
{
if(isIpEntity(tcpFile, &entitySet[i]))
{
fprintf(stderr, "Entity %d is an IP Entity\n", i);
if(numRoutes == index)
break;
else
numRoutes++;
}
}
if(numRoutes == index && i < numEntities)
{
fprintf(stderr, "Index %lu is entity #%d - %04lx:%08lx\n", index, i,
entitySet[i].tei_entity, entitySet[i].tei_instance);
memcpy(ent, &entitySet[i], sizeof(*ent));
tdiFreeThingSet(entitySet);
return 0;
}
else
{
tdiFreeThingSet(entitySet);
return 0xc000001;
}
}
BOOL
isInterface(TDIEntityID *if_maybe)
{
return if_maybe->tei_entity == IF_ENTITY;
}
NTSTATUS
getInterfaceInfoSet(HANDLE tcpFile, IFInfo **infoSet, PDWORD numInterfaces)
{
DWORD numEntities;
TDIEntityID *entIDSet = NULL;
NTSTATUS status = tdiGetEntityIDSet(tcpFile, &entIDSet, &numEntities);
IFInfo *infoSetInt = 0;
int curInterf = 0;
unsigned i;
if(!NT_SUCCESS(status))
{
fprintf(stderr, "getInterfaceInfoSet: tdiGetEntityIDSet() failed: 0x%lx\n",
status);
return status;
}
infoSetInt = HeapAlloc(GetProcessHeap(), 0, sizeof(IFInfo) * numEntities);
if(infoSetInt)
{
for(i = 0; i < numEntities; i++)
{
if(isInterface(&entIDSet[i]))
{
infoSetInt[curInterf].entity_id = entIDSet[i];
status = tdiGetMibForIfEntity(tcpFile, &entIDSet[i],
&infoSetInt[curInterf].if_info);
fprintf(stderr, "tdiGetMibForIfEntity: %08lx\n", status);
if(NT_SUCCESS(status))
{
DWORD numAddrs;
IPAddrEntry *addrs;
TDIEntityID ip_ent;
unsigned j;
status = getNthIpEntity(tcpFile, curInterf, &ip_ent);
if(NT_SUCCESS(status))
status =
tdiGetIpAddrsForIpEntity(tcpFile, &ip_ent, &addrs, &numAddrs);
for(j = 0; NT_SUCCESS(status) && j < numAddrs; j++)
{
fprintf(stderr, "ADDR %d: index %ld (target %ld)\n", j,
addrs[j].iae_index,
infoSetInt[curInterf].if_info.ent.if_index);
if(addrs[j].iae_index == infoSetInt[curInterf].if_info.ent.if_index)
{
memcpy(&infoSetInt[curInterf].ip_addr, &addrs[j],
sizeof(addrs[j]));
curInterf++;
break;
}
}
if(NT_SUCCESS(status))
tdiFreeThingSet(addrs);
}
}
}
tdiFreeThingSet(entIDSet);
if(NT_SUCCESS(status))
{
*infoSet = infoSetInt;
*numInterfaces = curInterf;
}
else
{
HeapFree(GetProcessHeap(), 0, infoSetInt);
}
return status;
}
else
{
tdiFreeThingSet(entIDSet);
return ((NTSTATUS)0xC000009A);
}
}
NTSTATUS
getInterfaceInfoByName(HANDLE tcpFile, char *name, IFInfo *info)
{
IFInfo *ifInfo;
DWORD numInterfaces;
unsigned i;
NTSTATUS status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces);
if(NT_SUCCESS(status))
{
for(i = 0; i < numInterfaces; i++)
{
if(!strcmp((PCHAR)ifInfo[i].if_info.ent.if_descr, name))
{
memcpy(info, &ifInfo[i], sizeof(*info));
break;
}
}
HeapFree(GetProcessHeap(), 0, ifInfo);
return i < numInterfaces ? 0 : 0xc0000001;
}
return status;
}
NTSTATUS
getInterfaceInfoByIndex(HANDLE tcpFile, DWORD index, IFInfo *info)
{
IFInfo *ifInfo;
DWORD numInterfaces;
NTSTATUS status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces);
unsigned i;
if(NT_SUCCESS(status))
{
for(i = 0; i < numInterfaces; i++)
{
if(ifInfo[i].if_info.ent.if_index == index)
{
memcpy(info, &ifInfo[i], sizeof(*info));
break;
}
}
HeapFree(GetProcessHeap(), 0, ifInfo);
return i < numInterfaces ? 0 : 0xc0000001;
}
return status;
}
NTSTATUS
getIPAddrEntryForIf(HANDLE tcpFile, char *name, DWORD index, IFInfo *ifInfo)
{
NTSTATUS status = name ? getInterfaceInfoByName(tcpFile, name, ifInfo)
: getInterfaceInfoByIndex(tcpFile, index, ifInfo);
if(!NT_SUCCESS(status))
{
fprintf(stderr, "getIPAddrEntryForIf returning %lx\n", status);
}
return status;
}
InterfaceIndexTable *
getInterfaceIndexTableInt(BOOL nonLoopbackOnly)
{
DWORD numInterfaces, curInterface = 0;
unsigned i;
IFInfo *ifInfo;
InterfaceIndexTable *ret = 0;
HANDLE tcpFile;
NTSTATUS status = openTcpFile(&tcpFile, FILE_READ_DATA);
ifInfo = NULL;
if(NT_SUCCESS(status))
{
status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces);
fprintf(stderr, "InterfaceInfoSet: %08lx, %04lx:%08lx\n", status,
ifInfo->entity_id.tei_entity, ifInfo->entity_id.tei_instance);
if(NT_SUCCESS(status))
{
ret = (InterfaceIndexTable *)calloc(
1, sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
if(ret)
{
ret->numAllocated = numInterfaces;
fprintf(stderr, "NumInterfaces = %ld\n", numInterfaces);
for(i = 0; i < numInterfaces; i++)
{
fprintf(stderr, "Examining interface %d\n", i);
if(!nonLoopbackOnly || !isLoopback(tcpFile, &ifInfo[i].entity_id))
{
fprintf(stderr, "Interface %d matches (%ld)\n", i, curInterface);
ret->indexes[curInterface++] = ifInfo[i].if_info.ent.if_index;
}
}
ret->numIndexes = curInterface;
}
tdiFreeThingSet(ifInfo);
}
closeTcpFile(tcpFile);
}
return ret;
}
InterfaceIndexTable *
getInterfaceIndexTable(void)
{
return getInterfaceIndexTableInt(FALSE);
}
#endif
// there's probably an use case for a _newer_ implementation
// of pthread_setname_np(3), in fact, I may just merge _this_
// upstream...
#if 0
#include <windows.h>
typedef HRESULT(FAR PASCAL *p_SetThreadDescription)(void *, const wchar_t *);
#define EXCEPTION_SET_THREAD_NAME ((DWORD)0x406D1388)
typedef struct _THREADNAME_INFO
{
DWORD dwType; /* must be 0x1000 */
LPCSTR szName; /* pointer to name (in user addr space) */
DWORD dwThreadID; /* thread ID (-1=caller thread) */
DWORD dwFlags; /* reserved for future use, must be zero */
} THREADNAME_INFO;
void
SetThreadName(DWORD dwThreadID, LPCSTR szThreadName)
{
THREADNAME_INFO info;
DWORD infosize;
HANDLE hThread;
/* because loonix is SHIT and limits thread names to 16 bytes */
wchar_t thr_name_w[16];
p_SetThreadDescription _SetThreadDescription;
/* current win10 flights now have a new named-thread API, let's try to use
* that first! */
/* first, dlsym(2) the new call from system library */
hThread = NULL;
_SetThreadDescription = (p_SetThreadDescription)GetProcAddress(
GetModuleHandle("kernel32"), "SetThreadDescription");
if(_SetThreadDescription)
{
/* grab another reference to the thread */
hThread = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, dwThreadID);
/* windows takes unicode, our input is utf-8 or plain ascii */
MultiByteToWideChar(CP_ACP, 0, szThreadName, -1, thr_name_w, 16);
if(hThread)
_SetThreadDescription(hThread, thr_name_w);
else
goto old; /* for whatever reason, we couldn't get a handle to the thread.
Just use the old method. */
}
else
{
old:
info.dwType = 0x1000;
info.szName = szThreadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
infosize = sizeof(info) / sizeof(DWORD);
__try
{
RaiseException(EXCEPTION_SET_THREAD_NAME, 0, infosize, (DWORD *)&info);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
/* clean up */
if(hThread)
CloseHandle(hThread);
}
#endif

@ -0,0 +1,110 @@
#ifndef WIN32_INTRNL_H
#define WIN32_INTRNL_H
#if defined(__MINGW32__) && !defined(_WIN64)
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
#include <tdiinfo.h>
typedef unsigned long ulong;
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef unsigned int uint;
/* forward declare, each module has their own idea of what this is */
typedef struct _InterfaceIndexTable InterfaceIndexTable;
typedef struct IFEntry
{
ulong if_index;
ulong if_type;
ulong if_mtu;
ulong if_speed;
ulong if_physaddrlen;
uchar if_physaddr[8];
ulong if_adminstatus;
ulong if_operstatus;
ulong if_lastchange;
ulong if_inoctets;
ulong if_inucastpkts;
ulong if_innucastpkts;
ulong if_indiscards;
ulong if_inerrors;
ulong if_inunknownprotos;
ulong if_outoctets;
ulong if_outucastpkts;
ulong if_outnucastpkts;
ulong if_outdiscards;
ulong if_outerrors;
ulong if_outqlen;
ulong if_descrlen;
uchar if_descr[1];
} IFEntry;
typedef struct IPAddrEntry
{
ulong iae_addr;
ulong iae_index;
ulong iae_mask;
ulong iae_bcastaddr;
ulong iae_reasmsize;
ushort iae_context;
ushort iae_pad;
} IPAddrEntry;
typedef union _IFEntrySafelySized {
CHAR MaxSize[sizeof(DWORD) + sizeof(IFEntry) + 128 + 1];
IFEntry ent;
} IFEntrySafelySized;
#ifndef IFENT_SOFTWARE_LOOPBACK
#define IFENT_SOFTWARE_LOOPBACK 24 /* This is an SNMP constant from rfc1213 */
#endif /*IFENT_SOFTWARE_LOOPBACK*/
/* Encapsulates information about an interface */
typedef struct _IFInfo
{
TDIEntityID entity_id;
IFEntrySafelySized if_info;
IPAddrEntry ip_addr;
} IFInfo;
/* functions */
NTSTATUS
openTcpFile(PHANDLE tcpFile, ACCESS_MASK DesiredAccess);
VOID
closeTcpFile(HANDLE h);
BOOL
isLoopback(HANDLE tcpFile, TDIEntityID* loop_maybe);
BOOL
isIpEntity(HANDLE tcpFile, TDIEntityID* ent);
NTSTATUS
getNthIpEntity(HANDLE tcpFile, DWORD index, TDIEntityID* ent);
BOOL
isInterface(TDIEntityID* if_maybe);
NTSTATUS
getInterfaceInfoSet(HANDLE tcpFile, IFInfo** infoSet, PDWORD numInterfaces);
NTSTATUS
getInterfaceInfoByName(HANDLE tcpFile, char* name, IFInfo* info);
NTSTATUS
getInterfaceInfoByIndex(HANDLE tcpFile, DWORD index, IFInfo* info);
NTSTATUS
getIPAddrEntryForIf(HANDLE tcpFile, char* name, DWORD index, IFInfo* ifInfo);
InterfaceIndexTable*
getInterfaceIndexTableInt(BOOL nonLoopbackOnly);
InterfaceIndexTable*
getInterfaceIndexTable(void);
#endif
#endif

@ -0,0 +1,69 @@
#ifndef _UP_H_
#define _UP_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#define UPOLL_CTL_ADD 1
#define UPOLL_CTL_DEL 2
#define UPOLL_CTL_MOD 3
#define UPOLLIN 0x01
#define UPOLLOUT 0x02
#define UPOLLERR 0x04
#define UPOLLET 0x08
typedef struct upoll upoll_t;
typedef union upoll_data {
void* ptr;
intptr_t fd;
uint32_t u32;
uint64_t u64;
} upoll_data_t;
typedef struct upoll_event
{
uint32_t events;
upoll_data_t data;
} upoll_event_t;
upoll_t*
upoll_create(uint32_t size);
int
upoll_ctl(upoll_t* upq, int op, intptr_t fd, upoll_event_t* event);
int
upoll_wait(upoll_t* upq, upoll_event_t* events, int maxevents, int timeout);
void
upoll_destroy(upoll_t* upq);
intptr_t
usocket(int domain, int type, int proto);
intptr_t
uaccept(intptr_t sock);
int
ubind(intptr_t sock, const char* name, const char* serv);
int
ulisten(intptr_t sock, int backlog);
int
uconnect(intptr_t sock, const char* name, const char* serv);
int
uclose(intptr_t sock);
/* TCP sockets */
int
uread(intptr_t fd, char* buf, size_t len);
int
uwrite(intptr_t fd, const char* buf, size_t len);
int
usocketpair(intptr_t socks[2], int async);
#ifdef __cplusplus
}
#endif
#endif /* _UP_H_ */

@ -0,0 +1,669 @@
#ifdef _WIN32
#pragma GCC diagnostic ignored "-Wvla"
/* emulated epoll, because the native async event system does not do
* particularly well with notification
*/
#include "win32_upoll.h"
#define uhash_slot(K, S) (((K) ^ (K >> 8)) & (S - 1))
static uhash_t*
uhash_create(uint32_t size)
{
unsigned int i;
size--;
size |= size >> 1;
size |= size >> 2;
size |= size >> 4;
size |= size >> 8;
size |= size >> 16;
size++;
uhash_t* hash = (uhash_t*)calloc(1, sizeof(uhash_t) + size * sizeof(ulist_t));
hash->count = 0;
hash->size = size;
hash->items = (ulist_t*)(((char*)hash) + sizeof(uhash_t));
for(i = 0; i < size; i++)
{
ulist_init(&hash->items[i]);
}
return hash;
}
static void*
uhash_lookup(uhash_t* hash, intptr_t key)
{
uint32_t slot = uhash_slot(key, hash->size);
ulist_t* q;
ulist_scan(q, &hash->items[slot])
{
uitem_t* i = ulist_data(q, uitem_t, list);
if(i->key == key)
return i->val;
}
return NULL;
}
static void
uhash_insert(uhash_t* hash, intptr_t key, void* val)
{
uint32_t slot = uhash_slot(key, hash->size);
uitem_t* item = (uitem_t*)calloc(1, sizeof(uitem_t));
ulist_init(&item->list);
item->key = key;
item->val = val;
ulist_append(&hash->items[slot], &item->list);
}
static int
uhash_delete(uhash_t* hash, intptr_t key)
{
uint32_t slot = uhash_slot(key, hash->size);
ulist_t* q;
ulist_scan(q, &hash->items[slot])
{
uitem_t* i = ulist_data(q, uitem_t, list);
if(i->key == key)
{
ulist_remove(q);
free(q);
return 1;
}
}
return 0;
}
static int
uhash_destroy(uhash_t* hash)
{
int i;
for(i = 0; i < hash->size; i++)
{
while(!ulist_empty(&hash->items[i]))
{
ulist_t* q = ulist_next(&hash->items[i]);
uitem_t* n = ulist_data(q, uitem_t, list);
ulist_remove(q);
free(n);
}
}
return 0;
}
upoll_t*
upoll_create(uint32_t size)
{
assert(size > 0);
upoll_t* upq = (upoll_t*)calloc(1, sizeof(upoll_t));
ulist_init(&upq->alive);
upq->table = uhash_create(size);
return upq;
}
void
upoll_destroy(upoll_t* upq)
{
assert(upq != NULL);
uhash_destroy(upq->table);
ulist_t* q;
unote_t* n;
while(!ulist_empty(&upq->alive))
{
q = ulist_next(&upq->alive);
n = ulist_data(n, unote_t, queue);
ulist_remove(q);
free(n);
}
free(upq);
}
int
upoll_ctl(upoll_t* upq, int op, intptr_t fd, upoll_event_t* event)
{
if(fd < 0)
return -EBADF;
unote_t* note = NULL;
switch(op)
{
case UPOLL_CTL_ADD:
{
note = (unote_t*)uhash_lookup(upq->table, fd);
if(!note)
{
note = (unote_t*)calloc(1, sizeof(unote_t));
note->upoll = upq;
ulist_init(&note->queue);
note->event = *event;
note->fd = fd;
ulist_append(&upq->alive, &note->queue);
uhash_insert(upq->table, fd, (void*)note);
}
break;
}
case UPOLL_CTL_DEL:
{
note = (unote_t*)uhash_lookup(upq->table, fd);
if(!note)
return -ENOENT;
event = &note->event;
ulist_remove(&note->queue);
uhash_delete(upq->table, fd);
free(note);
break;
}
case UPOLL_CTL_MOD:
{
note = (unote_t*)uhash_lookup(upq->table, fd);
if(!note)
return -ENOENT;
note->event = *event;
break;
}
default:
{
return -EINVAL;
}
}
return 0;
}
#if defined(HAVE_POLL)
int
upoll_wait_poll(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
{
/* FD_SETSIZE should be smaller than OPEN_MAX, but OPEN_MAX isn't portable */
if(nev > FD_SETSIZE)
nev = FD_SETSIZE;
unote_t* nvec[nev];
int r, i, nfds = 0;
uint32_t hint;
struct pollfd pfds[nev];
unote_t* n = NULL;
ulist_t* s = ulist_mark(&upq->alive);
ulist_t* q = ulist_next(&upq->alive);
while(q != s && nfds < nev)
{
n = ulist_data(q, unote_t, queue);
q = ulist_next(q);
ulist_remove(&n->queue);
ulist_insert(&upq->alive, &n->queue);
nvec[nfds] = n;
pfds[nfds].events = 0;
pfds[nfds].fd = n->fd;
if(n->event.events & UPOLLIN)
{
pfds[nfds].events |= POLLIN;
}
if(n->event.events & UPOLLOUT)
{
pfds[nfds].events |= POLLOUT;
}
nfds++;
}
r = poll(pfds, nfds, timeout);
if(r < 0)
return -errno;
int e = 0;
for(i = 0; i < nfds && e < nev; i++)
{
hint = 0;
if(pfds[i].revents)
{
n = nvec[i];
if(pfds[i].revents & POLLIN)
hint |= UPOLLIN;
if(pfds[i].revents & POLLOUT)
hint |= UPOLLOUT;
if(pfds[i].revents & (POLLERR | POLLNVAL | POLLHUP))
hint |= (UPOLLERR | UPOLLIN);
if(hint & UPOLLERR)
hint &= ~UPOLLOUT;
evs[e].data = n->event.data;
evs[e].events = hint;
++e;
}
}
return e;
}
#else
int
upoll_wait_select(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
{
if(nev > FD_SETSIZE)
nev = FD_SETSIZE;
unote_t* nvec[nev];
int i, maxfd = 0, e = 0, nfds = 0;
fd_set pollin, pollout, pollerr;
FD_ZERO(&pollin);
FD_ZERO(&pollout);
FD_ZERO(&pollerr);
struct timeval tv;
struct timeval* tvp = &tv;
tv.tv_usec = 0;
if(timeout < 0)
{
tvp = NULL;
}
else if(timeout == 0)
tv.tv_sec = 0;
else
{
tv.tv_sec = (timeout / 1000);
tv.tv_usec = (timeout % 1000) * 1000;
}
unote_t* n = NULL;
ulist_t* s = ulist_mark(&upq->alive);
ulist_t* q = ulist_next(&upq->alive);
while(q != s && nfds < nev)
{
n = ulist_data(q, unote_t, queue);
q = ulist_next(q);
ulist_remove(&n->queue);
ulist_insert(&upq->alive, &n->queue);
nvec[nfds] = n;
if(n->event.events & UPOLLIN)
{
FD_SET(n->fd, &pollin);
}
if(n->event.events & UPOLLOUT)
{
FD_SET(n->fd, &pollout);
}
FD_SET(n->fd, &pollerr);
if(maxfd < n->fd)
maxfd = n->fd;
nfds++;
}
#if defined(__WINDOWS__)
int rc = select(0, &pollin, &pollout, &pollerr, tvp);
if(rc == SOCKET_ERROR)
{
assert(WSAGetLastError() == WSAENOTSOCK);
return -WSAGetLastError();
}
#else
int rc = select(maxfd + 1, &pollin, &pollout, &pollerr, tvp);
if(rc == -1)
{
assert(errno == EINTR || errno == EBADF);
return -errno;
}
#endif
e = 0;
for(i = 0; i < nfds && e < nev; i++)
{
uint32_t hint = 0;
unote_t* n = nvec[i];
if(FD_ISSET(n->fd, &pollin))
{
hint |= UPOLLIN;
}
if(FD_ISSET(n->fd, &pollerr))
{
hint |= (UPOLLERR | UPOLLIN);
}
else if(FD_ISSET(n->fd, &pollout))
{
hint |= UPOLLOUT;
}
if(hint)
{
evs[e].data = n->event.data;
evs[e].events = hint;
++e;
}
}
return e;
}
#endif
int
upoll_wait(upoll_t* upq, upoll_event_t* evs, int nev, int timeout)
{
int r = 0;
#if defined(HAVE_POLL)
r = upoll_wait_poll(upq, evs, nev, timeout);
#else
r = upoll_wait_select(upq, evs, nev, timeout);
#endif
return r;
}
intptr_t
usocket(int domain, int type, int proto)
{
intptr_t fd = (intptr_t)socket(domain, type, proto);
#if defined(__WINDOWS__)
if(fd < 0)
return -WSAGetLastError();
unsigned long flags = 1;
int rc = ioctlsocket((SOCKET)fd, FIONBIO, &flags);
if(rc < 0)
return -WSAGetLastError();
#else
if(fd < 0)
return -errno;
int rc = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
if(rc < 0)
return -errno;
#endif
return fd;
}
int
ubind(intptr_t fd, const char* host, const char* serv)
{
struct addrinfo* info;
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
int optval = 0;
unsigned int optlen = sizeof(optval);
#if defined(__WINDOWS__)
int rc = getsockopt((SOCKET)fd, SOL_SOCKET, SO_TYPE, (char*)&optval,
(int*)&optlen);
#else
int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
#endif
hint.ai_family = AF_INET;
hint.ai_socktype = optval;
rc = getaddrinfo(host, serv, &hint, &info);
optval = 1;
if(!rc)
{
#if defined(__WINDOWS__)
rc = setsockopt((SOCKET)fd, SOL_SOCKET, SO_REUSEADDR, (char*)&optval,
sizeof(optval));
#else
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
#endif
if(!rc)
rc = bind(fd, info->ai_addr, info->ai_addrlen);
}
freeaddrinfo(info);
if(rc)
{
#if defined(__WINDOWS__)
return WSAGetLastError();
#else
return errno;
#endif
}
return 0;
}
int
uconnect(intptr_t fd, const char* host, const char* serv)
{
struct addrinfo* info;
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
int optval = 0;
unsigned int optlen;
#if defined(__WINDOWS__)
int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, (char*)&optval, (int*)&optlen);
#else
int rc = getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
#endif
hint.ai_family = AF_INET;
hint.ai_socktype = optval;
rc = getaddrinfo(host, serv, &hint, &info);
if(!rc)
{
#if defined(__WINDOWS__)
rc = connect((SOCKET)fd, info->ai_addr, info->ai_addrlen);
#else
rc = connect(fd, info->ai_addr, info->ai_addrlen);
#endif
}
freeaddrinfo(info);
if(rc)
{
#if defined(__WINDOWS__)
if(WSAGetLastError() != WSAEWOULDBLOCK)
return WSAGetLastError();
#else
if(errno != EINPROGRESS)
return errno;
#endif
}
return 0;
}
int
ulisten(intptr_t sock, int backlog)
{
return listen(sock, backlog);
}
intptr_t
uaccept(intptr_t sock)
{
struct sockaddr addr;
addr.sa_family = AF_INET;
socklen_t addr_len;
#if defined(__WINDOWS__)
intptr_t fd = (intptr_t)accept((SOCKET)sock, &addr, &addr_len);
if(fd == -1)
return WSAGetLastError();
#else
intptr_t fd = accept(sock, &addr, &addr_len);
if(fd < 0)
return errno;
#endif
return fd;
}
int
uclose(intptr_t sock)
{
#if defined(__WINDOWS__)
return closesocket((SOCKET)sock);
#else
return close(sock);
#endif
}
int
uread(intptr_t fd, char* buf, size_t len)
{
return recv(fd, buf, len, 0);
}
int
uwrite(intptr_t fd, const char* buf, size_t len)
{
return send(fd, buf, len, 0);
}
/* adapted from (renamed make_overlapped to async for allergy reasons): */
/* socketpair.c
Copyright 2007, 2010 by Nathan C. Myers <ncm@cantrip.org>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
The name of the author must not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Changes:
* 2014-02-12: merge David Woodhouse, Ger Hobbelt improvements
* git.infradead.org/users/dwmw2/openconnect.git/commitdiff/bdeefa54
* github.com/GerHobbelt/selectable-socketpair
* always init the socks[] to -1/INVALID_SOCKET on error, both on Win32/64
* and UNIX/other platforms
* 2013-07-18: Change to BSD 3-clause license
* 2010-03-31:
* set addr to 127.0.0.1 because win32 getsockname does not always set it.
* 2010-02-25:
* set SO_REUSEADDR option to avoid leaking some windows resource.
* Windows System Error 10049, "Event ID 4226 TCP/IP has reached
* the security limit imposed on the number of concurrent TCP connect
* attempts." Bleah.
* 2007-04-25:
* preserve value of WSAGetLastError() on all error returns.
* 2007-04-22: (Thanks to Matthew Gregan <kinetik@flim.org>)
* s/EINVAL/WSAEINVAL/ fix trivial compile failure
* s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout
* of a child process.
* add argument make_overlapped
*/
#if defined(__WINDOWS__)
int
usocketpair(intptr_t socks[2], int async)
{
union {
struct sockaddr_in inaddr;
struct sockaddr addr;
} a;
SOCKET listener;
int e;
socklen_t addrlen = sizeof(a.inaddr);
DWORD flags = (async ? WSA_FLAG_OVERLAPPED : 0);
int reuse = 1;
if(socks == 0)
{
WSASetLastError(WSAEINVAL);
return SOCKET_ERROR;
}
socks[0] = socks[1] = -1;
listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listener == INVALID_SOCKET)
return SOCKET_ERROR;
memset(&a, 0, sizeof(a));
a.inaddr.sin_family = AF_INET;
a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
a.inaddr.sin_port = 0;
for(;;)
{
if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse,
(socklen_t)sizeof(reuse))
== -1)
break;
if(bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
break;
memset(&a, 0, sizeof(a));
if(getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR)
break;
// win32 getsockname may only set the port number, p=0.0005.
// ( http://msdn.microsoft.com/library/ms738543.aspx ):
a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
a.inaddr.sin_family = AF_INET;
if(listen(listener, 1) == SOCKET_ERROR)
break;
socks[0] = (intptr_t)WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags);
if(socks[0] == -1)
break;
if(connect((SOCKET)socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
break;
socks[1] = (intptr_t)accept(listener, NULL, NULL);
if(socks[1] == -1)
break;
closesocket(listener);
return 0;
}
e = WSAGetLastError();
closesocket(listener);
closesocket((SOCKET)socks[0]);
closesocket((SOCKET)socks[1]);
WSASetLastError(e);
socks[0] = socks[1] = -1;
return SOCKET_ERROR;
}
#else
int
usocketpair(intptr_t socks[2], int dummy)
{
int sovec[2];
if(socks == 0)
{
errno = EINVAL;
return -1;
}
dummy = socketpair(AF_LOCAL, SOCK_STREAM, 0, sovec);
if(dummy)
{
socks[0] = socks[1] = -1;
}
else
{
socks[0] = sovec[0];
socks[1] = sovec[1];
}
return dummy;
}
#endif
#endif

@ -0,0 +1,144 @@
#ifndef _UPOLL_H_
#define _UPOLL_H_
#include "win32_up.h"
#if(defined(__64BIT__) || defined(__x86_64__))
#define __IS_64BIT__
#else
#define __IS_32BIT__
#endif
#if(defined WIN32 || defined _WIN32)
#undef __WINDOWS__
#define __WINDOWS__
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include <sys/types.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#if defined(__WINDOWS__)
#include <io.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#else
#include <unistd.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#endif
#if defined(__linux__)
#undef HAVE_EPOLL
#define HAVE_EPOLL 1
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#undef HAVE_POLL
#define HAVE_POLL 1
#else
#undef HAVE_SELECT
#define HAVE_SELECT 1
#endif
#if defined(HAVE_EPOLL)
#include <sys/epoll.h>
#elif defined(HAVE_POLL)
#include <poll.h>
#endif
typedef struct unote unote_t;
typedef struct ulist ulist_t;
typedef struct uitem uitem_t;
typedef struct uhash uhash_t;
struct ulist
{
ulist_t* next;
ulist_t* prev;
};
struct uitem
{
ulist_t list;
intptr_t key;
void* val;
};
struct uhash
{
uint16_t count;
uint16_t size;
ulist_t* items;
};
struct upoll
{
int fd; /* backend fd (epoll, kqueue) */
ulist_t alive; /* all notes this queue knows about */
uhash_t* table;
};
struct unote
{
upoll_event_t event;
intptr_t fd;
ulist_t queue; /* handle for the queue's notes */
upoll_t* upoll;
};
#define container_of(ptr, type, member) \
((type*)((char*)(ptr)-offsetof(type, member)))
#define ulist_init(q) \
(q)->prev = q; \
(q)->next = q
#define ulist_head(h) (h)->next
#define ulist_next(q) (q)->next
#define ulist_tail(h) (h)->prev
#define ulist_prev(q) (q)->prev
#define ulist_empty(h) (h == (h)->prev)
#define ulist_append(h, x) \
(x)->prev = (h)->prev; \
(x)->prev->next = x; \
(x)->next = h; \
(h)->prev = x
#define ulist_insert(h, x) \
(x)->next = (h)->next; \
(x)->next->prev = x; \
(x)->prev = h; \
(h)->next = x
#define ulist_remove(x) \
(x)->next->prev = (x)->prev; \
(x)->prev->next = (x)->next; \
(x)->prev = x; \
(x)->next = x
#define ulist_mark(h) (h)
#define ulist_scan(q, h) \
for((q) = ulist_head(h); (q) != ulist_mark(h); (q) = ulist_next(q))
#define ulist_data(q, type, link) container_of(q, type, link)
#endif /* _UPOLL_H_ */

@ -31,14 +31,6 @@
#define FILE_ANY_ACCESS 0x00000000
#define METHOD_BUFFERED 0
// from ev_win32.hpp
// gives us a fresh OVERLAPPED port
// from the C++ arena
// that can later be destructed with
// operator delete at the end of the event loop
OVERLAPPED *
getTunEvPort();
/* From OpenVPN tap driver, common.h */
#define TAP_CONTROL_CODE(request, method) \
CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
@ -423,19 +415,17 @@ tuntap_sys_set_ipv6(struct device *dev, t_tun_in6_addr *s, uint32_t mask)
int
tuntap_read(struct device *dev, void *buf, size_t size)
{
/* free this somewhere! */
OVERLAPPED *ovl = getTunEvPort();
DWORD x;
if(size)
{
ReadFile(dev->tun_fd, buf, (DWORD)size, NULL, ovl);
ReadFile(dev->tun_fd, buf, (DWORD)size, &x, NULL);
int errcode = GetLastError();
if(errcode != 997)
if(errcode)
{
tuntap_log(TUNTAP_LOG_ERR,
(const char *)formated_error(L"%1%0", errcode));
free(ovl);
return -1;
}
}
@ -445,17 +435,16 @@ tuntap_read(struct device *dev, void *buf, size_t size)
int
tuntap_write(struct device *dev, void *buf, size_t size)
{
OVERLAPPED *ovl = getTunEvPort();
DWORD x;
if(size)
{
WriteFile(dev->tun_fd, buf, (DWORD)size, NULL, ovl);
WriteFile(dev->tun_fd, buf, (DWORD)size, &x, NULL);
int errcode = GetLastError();
if(errcode != 997)
if(errcode)
{
tuntap_log(TUNTAP_LOG_ERR,
(const char *)formated_error(L"%1%0", errcode));
free(ovl);
return -1;
}
}

@ -30,6 +30,13 @@
#if defined Windows
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#if _WIN32_WINNT < 0x0600
extern "C" int
inet_pton(int af, const char *src, void *dst);
extern "C" const char *
inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
#else
#include <arpa/inet.h>
#include <netinet/in.h>

@ -2,7 +2,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "loki-network"
#define MyAppVersion "0.3.0"
#define MyAppVersion "0.3.1"
#define MyAppPublisher "Loki Project"
#define MyAppURL "https://loki.network"
#define MyAppExeName "lokinet.exe"
@ -32,16 +32,15 @@ OutputDir={#DevPath}win32-setup
OutputBaseFilename=lokinet-win32
Compression=lzma
SolidCompression=yes
VersionInfoVersion=0.3.0
VersionInfoVersion=0.3.1
VersionInfoCompany=Loki Project
VersionInfoDescription=lokinet for windows
VersionInfoTextVersion=0.3.0-dev
VersionInfoTextVersion=0.3.1-dev
VersionInfoProductName=loki-network
VersionInfoProductVersion=0.3.0
VersionInfoProductTextVersion=0.3.0-dev
VersionInfoProductVersion=0.3.1
VersionInfoProductTextVersion=0.3.1-dev
InternalCompressLevel=ultra64
; rip D:
MinVersion=0,6.0
MinVersion=0,5.0
ArchitecturesInstallIn64BitMode=x64
VersionInfoCopyright=Copyright ©2018 Loki Project
AlwaysRestart=yes
@ -54,11 +53,11 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
[Files]
; we're grabbing the builds from jenkins-ci now, which are fully linked
; only one of these is installed
Source: "{#DevPath}build\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion 32bit; Check: not IsWin64
Source: "{#DevPath}build\lokinet64.exe"; DestDir: "{app}"; Flags: ignoreversion 64bit; Check: IsWin64
Source: "{#DevPath}build64\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion 64bit; Check: IsWin64
; eh, might as well ship the 32-bit port of everything else
; do we _need_ to ship these?
Source: "{#DevPath}build\dns.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#DevPath}build\llarpc.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#DevPath}build\rcutil.exe"; DestDir: "{app}"; Flags: ignoreversion
@ -66,22 +65,61 @@ Source: "{#DevPath}build\rcutil.exe"; DestDir: "{app}"; Flags: ignoreversion
; and download an initial RC
Source: "{#DevPath}lokinet-bootstrap.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
Source: "{#DevPath}win32-setup\7z.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
Source: "{tmp}\inet6.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; MinVersion: 0,5.0; OnlyBelowVersion: 0,5.1
; Copy the correct tuntap driver for the selected platform
Source: "{tmp}\tuntapv9.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; OnlyBelowVersion: 0, 6.0
Source: "{tmp}\tuntapv9_n6.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; MinVersion: 0,6.0
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[UninstallDelete]
Type: filesandordirs; Name: "{app}\tap-windows*"
Type: filesandordirs; Name: "{app}\inet6_driver"; MinVersion: 0,5.0; OnlyBelowVersion: 0,5.1
Type: filesandordirs; Name: "{userappdata}\.lokinet"
[UninstallRun]
Filename: "{app}\tap-windows-9.21.2\remove.bat"; WorkingDir: "{app}\tap-windows-9.21.2"; MinVersion: 0,6.0; Flags: runascurrentuser
Filename: "{app}\tap-windows-9.9.2\remove.bat"; WorkingDir: "{app}\tap-windows-9.9.2"; OnlyBelowVersion: 0,6.0; Flags: runascurrentuser
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
Version: TWindowsVersion;
begin
if CurStep = ssPostInstall then
begin
GetWindowsVersionEx(Version);
if Version.NTPlatform and (Version.Major = 5) and (Version.Minor = 0) then
// I need a better message...
MsgBox('Set up IPv6 in Network Connections after reboot.', mbInformation, MB_OK);
end;
end;
procedure InitializeWizard();
var
Version: TWindowsVersion;
S: String;
begin
GetWindowsVersionEx(Version);
if Version.NTPlatform and
(Version.Major < 6) then
begin
// Windows 2000, XP, .NET Svr 2003
// these have a horribly crippled WinInet that issues Triple-DES as its most secure
// cipher suite
idpAddFile('http://www.rvx86.net/files/tuntapv9.7z', ExpandConstant('{tmp}\tuntapv9.7z'));
// Windows 2000 only, we need to install inet6 separately
if (FileExists(ExpandConstant('{sys}\drivers\tcpip6.sys')) = false) and (Version.Major = 5) and (Version.Minor = 0) then
begin
idpAddFile('http://www.rvx86.net/files/inet6.7z', ExpandConstant('{tmp}\inet6.7z'));
end;
end
else
begin
// current versions of windows :-)
// (Arguably, one could pull this from any of the forks.)
idpAddFile('https://github.com/despair86/loki-network/raw/master/contrib/tuntapv9-ndis/tap-windows-9.21.2.7z', ExpandConstant('{tmp}\tuntapv9_n6.7z'));
end;
idpDownloadAfter(wpReady);
end;
@ -96,7 +134,13 @@ Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBa
[Run]
Filename: "{app}\{#MyAppExeName}"; Flags: nowait postinstall skipifsilent; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"
; wait until either one or two of these terminates
Filename: "{tmp}\7z.exe"; Parameters: "x tuntapv9.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract TUN/TAP-v9 driver"; StatusMsg: "Extracting driver..."; OnlyBelowVersion: 0, 6.0
Filename: "{tmp}\7z.exe"; Parameters: "x tuntapv9_n6.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract TUN/TAP-v9 driver"; StatusMsg: "Extracting driver..."; MinVersion: 0, 6.0
Filename: "{tmp}\7z.exe"; Parameters: "x inet6.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract inet6 driver"; StatusMsg: "Extracting IPv6 driver..."; MinVersion: 0, 5.0; OnlyBelowVersion: 0, 5.1
Filename: "{tmp}\lokinet-bootstrap.exe"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "bootstrap dht"; StatusMsg: "Downloading initial RC..."
; then ask to install drivers
Filename: "{app}\tap-windows-9.21.2\install.bat"; WorkingDir: "{app}\tap-windows-9.21.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; MinVersion: 0, 6.0
Filename: "{app}\tap-windows-9.9.2\install.bat"; WorkingDir: "{app}\tap-windows-9.9.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; OnlyBelowVersion: 0, 6.0
Filename: "{app}\tap-windows-9.21.2\install.bat"; WorkingDir: "{app}\tap-windows-9.21.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; MinVersion: 0, 6.0
; install inet6 if not present. (I'd assume netsh displays something helpful if inet6 is already set up and configured.)
Filename: "{app}\inet6_driver\setup\hotfix.exe"; Parameters: "/m /z"; WorkingDir: "{app}\inet6_driver\setup\"; Flags: runascurrentuser waituntilterminated; Description: "Install IPv6 driver"; StatusMsg: "Installing IPv6..."; OnlyBelowVersion: 0, 5.1
Filename: "{sys}\netsh.exe"; Parameters: "int ipv6 install"; Flags: runascurrentuser waituntilterminated; Description: "install ipv6 on whistler"; StatusMsg: "Installing IPv6..."; MinVersion: 0,5.1; OnlyBelowVersion: 0,6.0
Loading…
Cancel
Save