#if defined(__MSYS__)
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <hev-task.h>
#include <hev-task-io.h>
#include <hev-memory-allocator.h>
#include "hev-wintun.h"
#include "hev-tunnel.h"
typedef struct _HevPBuf HevPBuf;
struct _HevPBuf
{
struct pbuf_custom base;
void *mem;
};
static HevWinTun *wintun;
static HevWinTunAdapter *adapter;
static HevWinTunSession *session;
static char tun_name[IFNAMSIZ];
static void
hev_pbuf_free (struct pbuf *p)
{
HevPBuf *buf = (HevPBuf *)p;
hev_wintun_session_release (session, buf->mem);
hev_free (buf);
}
int
hev_tunnel_open (const char *name, int multi_queue)
{
wintun = hev_wintun_open ();
if (!wintun)
return -1;
adapter = hev_wintun_adapter_create (name);
if (!adapter)
goto free;
strncpy (tun_name, name, IFNAMSIZ - 1);
return 0;
free:
hev_wintun_close (wintun);
return -1;
}
void
hev_tunnel_close (int fd)
{
if (session)
hev_wintun_session_stop (session);
hev_wintun_adapter_close (adapter);
hev_wintun_close (wintun);
}
int
hev_tunnel_set_mtu (int mtu)
{
return hev_wintun_adapter_set_mtu (adapter, mtu);
}
int
hev_tunnel_set_state (int state)
{
if (state) {
session = hev_wintun_session_start (adapter);
if (!session)
return -1;
} else {
if (session) {
hev_wintun_session_stop (session);
session = NULL;
}
}
return 0;
}
int
hev_tunnel_set_ipv4 (const char *addr, unsigned int prefix)
{
char ipv4[4];
int res;
res = inet_pton (AF_INET, addr, ipv4);
if (!res)
return -1;
return hev_wintun_adapter_set_ipv4 (adapter, ipv4, prefix);
}
int
hev_tunnel_set_ipv6 (const char *addr, unsigned int prefix)
{
char ipv6[16];
int res;
res = inet_pton (AF_INET6, addr, ipv6);
if (!res)
return -1;
return hev_wintun_adapter_set_ipv6 (adapter, ipv6, prefix);
}
const char *
hev_tunnel_get_name (void)
{
return tun_name;
}
const char *
hev_tunnel_get_index (void)
{
static char tun_index[16];
int index;
index = hev_wintun_adapter_get_index (adapter);
if (index < 0)
return NULL;
snprintf (tun_index, sizeof (tun_index) - 1, "%d", index);
return tun_index;
}
int
hev_tunnel_add_task (int fd, HevTask *task)
{
void *handle = hev_wintun_session_get_read_wait_event (session);
return hev_task_add_whandle (task, handle);
}
void
hev_tunnel_del_task (int fd, HevTask *task)
{
void *handle = hev_wintun_session_get_read_wait_event (session);
hev_task_del_whandle (task, handle);
}
struct pbuf *
hev_tunnel_read (int fd, int mtu, HevTaskIOYielder yielder, void *yielder_data)
{
HevPBuf *buf;
void *packet;
int spin = 0;
int size;
retry:
packet = hev_wintun_session_receive (session, &size);
if (!packet) {
if (hev_wintun_get_last_error () == HEV_WINTUN_EAGAIN) {
if (spin++ < 1000) {
hev_task_yield (HEV_TASK_YIELD);
} else if (yielder) {
if (yielder (HEV_TASK_WAITIO, yielder_data))
return NULL;
} else {
hev_task_yield (HEV_TASK_WAITIO);
}
goto retry;
} else {
return NULL;
}
}
buf = hev_malloc (sizeof (HevPBuf));
if (!buf)
return NULL;
buf->mem = packet;
buf->base.custom_free_function = hev_pbuf_free;
pbuf_alloced_custom (PBUF_RAW, size, PBUF_RAM, &buf->base, packet, size);
return &buf->base.pbuf;
}
ssize_t
hev_tunnel_write (int fd, struct pbuf *buf)
{
struct pbuf *p = buf;
void *packet;
size_t size;
packet = hev_wintun_session_allocate (session, p->tot_len);
if (!packet)
return -1;
for (size = 0; p; p = p->next) {
memcpy (packet + size, p->payload, p->len);
size += p->len;
}
hev_wintun_session_send (session, packet);
return size;
}
#endif