mirror of https://github.com/oxen-io/lokinet
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)
This commit is contained in:
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;
|
||||
}
|
||||
|
||||
|
|
63
llarp/ev.hpp
63
llarp/ev.hpp
|
@ -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;
|
||||
union {
|
||||
intptr_t socket;
|
||||
HANDLE tun;
|
||||
} fd;
|
||||
|
||||
// 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)
|
||||
int flags = 0;
|
||||
bool is_tun = false;
|
||||
|
||||
win32_ev_io(intptr_t f)
|
||||
{
|
||||
isTCP = true;
|
||||
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);
|
||||
}
|
||||
|
||||
~llarp_win32_loop()
|
||||
{
|
||||
if(upollfd)
|
||||
upoll_destroy(upollfd);
|
||||
}
|
||||
|
||||
bool
|
||||
running() const
|
||||
{
|
||||
return upollfd != nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
init()
|
||||
{
|
||||
if(iocpfd == INVALID_HANDLE_VALUE)
|
||||
iocpfd = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);
|
||||
|
||||
if(iocpfd == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
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)
|
||||
{
|
||||
memcpy(readbuf, qdata->Pointer, iolen);
|
||||
ev->read(readbuf, iolen);
|
||||
ev->error();
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
*/
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
llarp::udp_listener* ev = reinterpret_cast< llarp::udp_listener* >(ev_id);
|
||||
if(ev)
|
||||
{
|
||||
llarp::LogDebug("size: ", iolen, "\tev_id: ", ev_id,
|
||||
"\tqdata: ", qdata);
|
||||
if(iolen <= sizeof(readbuf))
|
||||
ev->read(readbuf, iolen);
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
|
||||
if(!idx)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
result = idx;
|
||||
if(result != -1)
|
||||
tick_listeners();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SOCKET
|
||||
int
|
||||
run()
|
||||
{
|
||||
upoll_event events[1024];
|
||||
int result;
|
||||
do
|
||||
{
|
||||
result = upoll_wait(upollfd, events, 1024, EV_TICK_INTERVAL);
|
||||
if(result > 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
if(result != -1)
|
||||
tick_listeners();
|
||||
} while(upollfd);
|
||||
return result;
|
||||
}
|
||||
|
||||
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)
|
||||
ev.events |= UPOLLOUT;
|
||||
if(upoll_ctl(upollfd, UPOLL_CTL_ADD, e->fd.socket, &ev) == -1)
|
||||
{
|
||||
if(!::CreateIoCompletionPort((HANDLE)std::get< SOCKET >(ev->fd), iocpfd,
|
||||
ev->listener_id, 0))
|
||||
{
|
||||
delete ev;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
goto start_loop;
|
||||
delete e;
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if(!::CreateIoCompletionPort(std::get< HANDLE >(ev->fd), iocpfd,
|
||||
ev->listener_id, 0))
|
||||
{
|
||||
delete ev;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
183
llarp/net.cpp
183
llarp/net.cpp
|
@ -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(¬e->queue);
|
||||
note->event = *event;
|
||||
note->fd = fd;
|
||||
ulist_append(&upq->alive, ¬e->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 = ¬e->event;
|
||||
ulist_remove(¬e->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 InitializeWizard();
|
||||
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…
Reference in New Issue