#include <string.h>
#include <unistd.h>
#include <hev-task.h>
#include <hev-task-io.h>
#include <hev-task-io-socket.h>
#include <hev-memory-allocator.h>
#include "hev-socks5-misc-priv.h"
#include "hev-socks5-logger-priv.h"
#include "hev-socks5-client-udp.h"
#define task_io_yielder hev_socks5_task_io_yielder
HevSocks5ClientUDP *
hev_socks5_client_udp_new (HevSocks5Type type)
{
HevSocks5ClientUDP *self;
int res;
self = hev_malloc0 (sizeof (HevSocks5ClientUDP));
if (!self)
return NULL;
res = hev_socks5_client_udp_construct (self, type);
if (res < 0) {
hev_free (self);
return NULL;
}
LOG_D ("%p socks5 client udp new", self);
return self;
}
static HevSocks5Addr *
hev_socks5_client_udp_get_upstream_addr (HevSocks5Client *base)
{
HevSocks5Addr *addr;
addr = hev_malloc0 (7);
if (addr)
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV4;
return addr;
}
static int
hev_socks5_client_udp_set_upstream_addr (HevSocks5Client *base,
HevSocks5Addr *addr)
{
HevSocks5ClientUDP *self = HEV_SOCKS5_CLIENT_UDP (base);
struct sockaddr_in6 saddr;
struct sockaddr *sadp;
HevSocks5Class *klass;
int res;
int fd;
if (HEV_SOCKS5 (base)->type != HEV_SOCKS5_TYPE_UDP_IN_UDP)
return 0;
saddr.sin6_family = AF_INET6;
sadp = (struct sockaddr *)&saddr;
res = hev_socks5_addr_to_sockaddr (addr, sadp);
if (res < 0) {
LOG_E ("%p socks5 client udp addr", self);
return -1;
}
fd = hev_socks5_socket (SOCK_DGRAM);
if (fd < 0) {
LOG_E ("%p socks5 client udp socket", self);
return -1;
}
klass = HEV_OBJECT_GET_CLASS (self);
res = klass->binder (HEV_SOCKS5 (self), fd, sadp);
if (res < 0) {
LOG_E ("%p socks5 client udp bind", self);
close (fd);
return -1;
}
res = hev_task_io_socket_connect (fd, sadp, sizeof (saddr), task_io_yielder,
self);
if (res < 0) {
LOG_E ("%p socks5 client udp connect", self);
close (fd);
return -1;
}
self->fd = fd;
return 0;
}
static int
hev_socks5_client_udp_get_fd (HevSocks5UDP *self)
{
int fd;
switch (HEV_SOCKS5 (self)->type) {
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
fd = HEV_SOCKS5 (self)->fd;
break;
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
fd = HEV_SOCKS5_CLIENT_UDP (self)->fd;
break;
default:
return -1;
}
return fd;
}
int
hev_socks5_client_udp_construct (HevSocks5ClientUDP *self, HevSocks5Type type)
{
int res;
res = hev_socks5_client_construct (&self->base, type);
if (res < 0)
return res;
LOG_I ("%p socks5 client udp construct", self);
HEV_OBJECT (self)->klass = HEV_SOCKS5_CLIENT_UDP_TYPE;
self->fd = -1;
return 0;
}
static void
hev_socks5_client_udp_destruct (HevObject *base)
{
HevSocks5ClientUDP *self = HEV_SOCKS5_CLIENT_UDP (base);
LOG_D ("%p socks5 client udp destruct", self);
if (self->fd >= 0)
close (self->fd);
HEV_SOCKS5_CLIENT_TYPE->destruct (base);
}
static void *
hev_socks5_client_udp_iface (HevObject *base, void *type)
{
HevSocks5ClientUDPClass *klass = HEV_OBJECT_GET_CLASS (base);
return &klass->udp;
}
HevObjectClass *
hev_socks5_client_udp_class (void)
{
static HevSocks5ClientUDPClass klass;
HevSocks5ClientUDPClass *kptr = &klass;
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
if (!okptr->name) {
HevSocks5ClientClass *ckptr;
HevSocks5UDPIface *uiptr;
memcpy (kptr, HEV_SOCKS5_CLIENT_TYPE, sizeof (HevSocks5ClientClass));
okptr->name = "HevSocks5ClientUDP";
okptr->destruct = hev_socks5_client_udp_destruct;
okptr->iface = hev_socks5_client_udp_iface;
ckptr = HEV_SOCKS5_CLIENT_CLASS (kptr);
ckptr->get_upstream_addr = hev_socks5_client_udp_get_upstream_addr;
ckptr->set_upstream_addr = hev_socks5_client_udp_set_upstream_addr;
uiptr = &kptr->udp;
memcpy (uiptr, HEV_SOCKS5_UDP_TYPE, sizeof (HevSocks5UDPIface));
uiptr->get_fd = hev_socks5_client_udp_get_fd;
}
return okptr;
}