forked from enlightenment/efl
parent
f69ffbf261
commit
8db857be0d
|
@ -18,6 +18,8 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#include <netdb.h>
|
||||
|
||||
/**
|
||||
* @file Ecore_Con.h
|
||||
* @brief Sockets functions.
|
||||
|
@ -161,6 +163,11 @@ extern "C" {
|
|||
EAPI int ecore_con_url_url_set(Ecore_Con_Url *url_con, const char *url);
|
||||
EAPI int ecore_con_url_send(Ecore_Con_Url *url_con, void *data, size_t length, char *content_type);
|
||||
|
||||
EAPI int ecore_con_dns_gethostbyname(const char *name,
|
||||
void (*done_cb)(struct hostent *hostent, void *data),
|
||||
void *data);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -18,6 +18,7 @@ Ecore_Con.h
|
|||
|
||||
libecore_con_la_SOURCES = \
|
||||
ecore_con.c \
|
||||
ecore_con_dns.c \
|
||||
ecore_con_url.c \
|
||||
ecore_con_private.h
|
||||
|
||||
|
@ -32,5 +33,6 @@ endif
|
|||
|
||||
EXTRA_DIST = \
|
||||
ecore_con.c \
|
||||
ecore_con_dns.c \
|
||||
ecore_con_url.c \
|
||||
ecore_con_private.h
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <time.h>
|
||||
#endif
|
||||
|
||||
static void _ecore_con_cb_gethostbyname(struct hostent *he, void *data);
|
||||
static void _ecore_con_server_free(Ecore_Con_Server *svr);
|
||||
static void _ecore_con_client_free(Ecore_Con_Client *cl);
|
||||
static int _ecore_con_svr_handler(void *data, Ecore_Fd_Handler *fd_handler);
|
||||
|
@ -80,7 +81,10 @@ ecore_con_init(void)
|
|||
#if USE_OPENSSL
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* TODO Remember return value, if it fails, use gethostbyname() */
|
||||
ecore_con_dns_init();
|
||||
}
|
||||
if (!servers)
|
||||
servers = ecore_list_new();
|
||||
|
@ -104,6 +108,8 @@ ecore_con_shutdown(void)
|
|||
_ecore_con_server_free(ecore_list_remove_first(servers));
|
||||
ecore_list_destroy(servers);
|
||||
servers = NULL;
|
||||
|
||||
ecore_con_dns_shutdown();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -371,7 +377,6 @@ ecore_con_server_connect(Ecore_Con_Type compl_type,
|
|||
Ecore_Con_Server *svr;
|
||||
Ecore_Con_Type type;
|
||||
struct sockaddr_un socket_unix;
|
||||
struct sockaddr_in socket_addr;
|
||||
int curstate = 0;
|
||||
char buf[4096];
|
||||
|
||||
|
@ -437,36 +442,7 @@ ecore_con_server_connect(Ecore_Con_Type compl_type,
|
|||
}
|
||||
else if (type == ECORE_CON_REMOTE_SYSTEM)
|
||||
{
|
||||
struct hostent *he;
|
||||
|
||||
/* FIXME: gethostbyname is blocking... */
|
||||
if (!(he = gethostbyname(name))) goto error;
|
||||
svr->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (svr->fd < 0) goto error;
|
||||
if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
|
||||
if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
|
||||
if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) goto error;
|
||||
socket_addr.sin_family = AF_INET;
|
||||
socket_addr.sin_port = htons(port);
|
||||
memcpy((struct in_addr *)&socket_addr.sin_addr,
|
||||
he->h_addr, sizeof(struct in_addr));
|
||||
if (connect(svr->fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) < 0)
|
||||
{
|
||||
if (errno != EINPROGRESS)
|
||||
goto error;
|
||||
svr->connecting = 1;
|
||||
svr->fd_handler = ecore_main_fd_handler_add(svr->fd,
|
||||
ECORE_FD_READ | ECORE_FD_WRITE,
|
||||
_ecore_con_cl_handler, svr,
|
||||
NULL, NULL);
|
||||
}
|
||||
else
|
||||
svr->fd_handler = ecore_main_fd_handler_add(svr->fd,
|
||||
ECORE_FD_READ,
|
||||
_ecore_con_cl_handler, svr,
|
||||
NULL, NULL);
|
||||
|
||||
if (!svr->fd_handler) goto error;
|
||||
ecore_con_dns_gethostbyname(name, _ecore_con_cb_gethostbyname, svr);
|
||||
}
|
||||
|
||||
#if USE_OPENSSL
|
||||
|
@ -922,10 +898,52 @@ kill_server(Ecore_Con_Server *svr)
|
|||
svr->fd_handler = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_ecore_con_cb_gethostbyname(struct hostent *he, void *data)
|
||||
{
|
||||
Ecore_Con_Server *svr;
|
||||
struct sockaddr_in socket_addr;
|
||||
int curstate = 0;
|
||||
|
||||
svr = data;
|
||||
|
||||
svr->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (svr->fd < 0) goto error;
|
||||
if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
|
||||
if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
|
||||
if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) goto error;
|
||||
socket_addr.sin_family = AF_INET;
|
||||
socket_addr.sin_port = htons(svr->port);
|
||||
memcpy((struct in_addr *)&socket_addr.sin_addr,
|
||||
he->h_addr, sizeof(struct in_addr));
|
||||
if (connect(svr->fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) < 0)
|
||||
{
|
||||
if (errno != EINPROGRESS)
|
||||
goto error;
|
||||
svr->connecting = 1;
|
||||
svr->fd_handler = ecore_main_fd_handler_add(svr->fd,
|
||||
ECORE_FD_READ | ECORE_FD_WRITE,
|
||||
_ecore_con_cl_handler, svr,
|
||||
NULL, NULL);
|
||||
}
|
||||
else
|
||||
svr->fd_handler = ecore_main_fd_handler_add(svr->fd,
|
||||
ECORE_FD_READ,
|
||||
_ecore_con_cl_handler, svr,
|
||||
NULL, NULL);
|
||||
|
||||
if (!svr->fd_handler) goto error;
|
||||
return;
|
||||
|
||||
error:
|
||||
kill_server(svr);
|
||||
}
|
||||
|
||||
static int
|
||||
svr_try_connect_plain(Ecore_Con_Server *svr)
|
||||
{
|
||||
int so_err = 0, size = sizeof(int);
|
||||
int so_err = 0;
|
||||
unsigned int size = sizeof(int);
|
||||
|
||||
if (getsockopt(svr->fd, SOL_SOCKET, SO_ERROR, &so_err, &size) < 0)
|
||||
so_err = -1;
|
||||
|
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
||||
*/
|
||||
/*
|
||||
* Simple dns lookup
|
||||
*
|
||||
* http://www.faqs.org/rfcs/rfc1035.html
|
||||
* man resolv.conf
|
||||
*
|
||||
* And a sneakpeek at ares, ftp://athena-dist.mit.edu/pub/ATHENA/ares/
|
||||
*/
|
||||
/*
|
||||
* TODO
|
||||
* * Check env LOCALDOMAIN to override search
|
||||
* * Check env RES_OPTIONS to override options
|
||||
* * Lookup names using domain or search
|
||||
*
|
||||
* * Make search and domain mutually exclusive
|
||||
*
|
||||
* * Read /etc/host.conf
|
||||
* * Check /etc/hosts
|
||||
*
|
||||
* * Caching
|
||||
* * Remember all querys and delete on shutdown
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <Ecore.h>
|
||||
#include "ecore_private.h"
|
||||
|
||||
#define SERVERS 3
|
||||
|
||||
typedef struct _Ecore_Con_Dns_Query Ecore_Con_Dns_Query;
|
||||
struct _Ecore_Con_Dns_Query {
|
||||
Ecore_Oldlist list;
|
||||
|
||||
/* Can ask three servers */
|
||||
unsigned int id[SERVERS];
|
||||
int socket[SERVERS];
|
||||
Ecore_Fd_Handler *fd_handlers[SERVERS];
|
||||
|
||||
int length;
|
||||
|
||||
Ecore_Timer *timeout;
|
||||
|
||||
char *hostname;
|
||||
|
||||
struct {
|
||||
void (*cb)(struct hostent *hostent, void *data);
|
||||
void *data;
|
||||
} done;
|
||||
|
||||
};
|
||||
|
||||
static int _ecore_con_dns_timeout(void *data);
|
||||
static int _ecore_con_cb_fd_handler(void *data, Ecore_Fd_Handler *fd_handler);
|
||||
static void _ecore_con_dns_query_free(Ecore_Con_Dns_Query *query);
|
||||
|
||||
static int _init = 0;
|
||||
|
||||
static struct in_addr _servers[SERVERS];
|
||||
static int _server_count;
|
||||
|
||||
static char *_search[6];
|
||||
static int _search_count = 0;
|
||||
|
||||
static char *_domain = NULL;
|
||||
|
||||
static uint16_t _id = 0;
|
||||
|
||||
#define SET_16BIT(p, v) \
|
||||
(((p)[0]) = ((v) >> 8) & 0xff), \
|
||||
(((p)[1]) = v & 0xff)
|
||||
|
||||
#define GET_16BIT(p) (((p)[0]) << 8 | ((p)[1]))
|
||||
|
||||
int
|
||||
ecore_con_dns_init(void)
|
||||
{
|
||||
FILE *file;
|
||||
char buf[1024];
|
||||
char *p, *p2;
|
||||
int ret;
|
||||
|
||||
_init++;
|
||||
if (_init > 1) return 1;
|
||||
|
||||
memset(_servers, 0, sizeof(_servers));
|
||||
_server_count = 0;
|
||||
|
||||
file = fopen("/etc/resolv.conf", "rb");
|
||||
if (!file) return 0;
|
||||
while (fgets(buf, sizeof(buf), file))
|
||||
{
|
||||
if (strlen(buf) >= 1023)
|
||||
printf("WARNING: Very long line in resolv.conf\n");
|
||||
|
||||
/* remove whitespace */
|
||||
p = strchr(buf, ' ');
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
|
||||
if (!strncmp(buf, "nameserver", 10))
|
||||
{
|
||||
if (_server_count >= SERVERS) continue;
|
||||
|
||||
_servers[_server_count].s_addr = inet_addr(p);
|
||||
_server_count++;
|
||||
}
|
||||
else if (!strncmp(buf, "domain", 6))
|
||||
{
|
||||
_domain = strdup(p);
|
||||
}
|
||||
else if (!strncmp(buf, "search", 6))
|
||||
{
|
||||
while ((p) && (_search_count < 6))
|
||||
{
|
||||
/* Remove whitespace */
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
/* Find next element */
|
||||
p2 = strchr(p, ' ');
|
||||
if (!p2)
|
||||
p2 = strchr(p, '\t');
|
||||
if (p2)
|
||||
*p2 = 0;
|
||||
/* Get this element */
|
||||
_search[_search_count] = strdup(p);
|
||||
_search_count++;
|
||||
if (p2) p = p2 + 1;
|
||||
else p = NULL;
|
||||
}
|
||||
}
|
||||
else if (!strncmp(buf, "sortlist", 8))
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
else if (!strncmp(buf, "options", 8))
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
else
|
||||
printf("WARNING: Weird line in resolv.conf: %s\n", buf);
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
if (!_server_count)
|
||||
{
|
||||
/* We should try localhost */
|
||||
_servers[_server_count].s_addr = inet_addr("127.0.0.1");
|
||||
_server_count++;
|
||||
}
|
||||
if ((!_search_count) && (!_domain))
|
||||
{
|
||||
/* Get domain from hostname */
|
||||
ret = gethostname(buf, sizeof(buf));
|
||||
if ((ret > 0) && (ret < 1024))
|
||||
{
|
||||
p = strchr(buf, '.');
|
||||
if (p)
|
||||
{
|
||||
p++;
|
||||
_domain = strdup(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ecore_con_dns_shutdown(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
_init--;
|
||||
if (_init > 0) return;
|
||||
|
||||
if (_domain)
|
||||
{
|
||||
free(_domain);
|
||||
_domain = NULL;
|
||||
}
|
||||
for (i = 0; i < _search_count; i++)
|
||||
free(_search[i]);
|
||||
_search_count = 0;
|
||||
}
|
||||
|
||||
int
|
||||
ecore_con_dns_gethostbyname(const char *name,
|
||||
void (*done_cb)(struct hostent *hostent, void *data),
|
||||
void *data)
|
||||
{
|
||||
Ecore_Con_Dns_Query *query;
|
||||
int i;
|
||||
|
||||
if (!_server_count) return 0;
|
||||
if ((!name) || (!*name)) return 0;
|
||||
|
||||
query = calloc(1, sizeof(Ecore_Con_Dns_Query));
|
||||
if (!query) return 0;
|
||||
|
||||
query->done.cb = done_cb;
|
||||
query->done.data = data;
|
||||
query->timeout = ecore_timer_add(20.0, _ecore_con_dns_timeout, query);
|
||||
query->hostname = strdup(name);
|
||||
|
||||
/* We're crazy, just ask all servers! */
|
||||
for (i = 0; i < _server_count; i++)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
unsigned char buf[256];
|
||||
unsigned char *p, *q, *pl;
|
||||
int len;
|
||||
|
||||
query->socket[i] = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (query->socket[i] == -1)
|
||||
{
|
||||
printf("ERROR: Couldn't create socket\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr = _servers[i];
|
||||
sin.sin_port = htons(NAMESERVER_PORT);
|
||||
if (connect(query->socket[i], (struct sockaddr *) &sin, sizeof(sin)) == -1)
|
||||
{
|
||||
/* TODO: EINPROGRESS isn't a fatal error */
|
||||
printf("ERROR: Couldn't connect to nameserver\n");
|
||||
close(query->socket[i]);
|
||||
query->socket[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
query->id[i] = ++_id;
|
||||
|
||||
/* Create buf */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
p = buf;
|
||||
/* qid */
|
||||
SET_16BIT(p, query->id[i]);
|
||||
p += 2;
|
||||
/* opcode */
|
||||
*p |= (QUERY & 0xf) << 3;
|
||||
/* TODO: rd, do we always want recursive? */
|
||||
*p |= 1 & 0x1;
|
||||
p += 2;
|
||||
/* qdcount, only asking for one name */
|
||||
SET_16BIT(p, 1);
|
||||
|
||||
query->length += HFIXEDSZ;
|
||||
p = &buf[HFIXEDSZ];
|
||||
|
||||
/* remember where the length shall be placed */
|
||||
pl = p;
|
||||
p++;
|
||||
query->length++;
|
||||
/* name */
|
||||
q = name;
|
||||
len = 0;
|
||||
while ((*q) && (query->length < 1024))
|
||||
{
|
||||
if (*q == '.')
|
||||
{
|
||||
if (len)
|
||||
{
|
||||
*pl = len;
|
||||
pl = p;
|
||||
p++;
|
||||
len = 0;
|
||||
query->length++;
|
||||
}
|
||||
q++;
|
||||
}
|
||||
else if ((*q == '\\') && (*(q + 1) == 0))
|
||||
{
|
||||
q++;
|
||||
|
||||
*p++ = *q++;
|
||||
len++;
|
||||
query->length++;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = *q++;
|
||||
len++;
|
||||
query->length++;
|
||||
}
|
||||
}
|
||||
/* Null at the end of the query */
|
||||
if (len)
|
||||
{
|
||||
*pl = len;
|
||||
*p = 0;
|
||||
p++;
|
||||
query->length++;
|
||||
}
|
||||
|
||||
/* type */
|
||||
SET_16BIT(p, T_A);
|
||||
p += 2;
|
||||
/* class */
|
||||
SET_16BIT(p, C_IN);
|
||||
p += 2;
|
||||
query->length += QFIXEDSZ;
|
||||
|
||||
if (send(query->socket[i], buf, query->length, 0) == -1)
|
||||
{
|
||||
printf("ERROR: Send failed\n");
|
||||
close(query->socket[i]);
|
||||
query->socket[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
query->fd_handlers[i] = ecore_main_fd_handler_add(query->socket[i],
|
||||
ECORE_FD_READ|ECORE_FD_ERROR,
|
||||
_ecore_con_cb_fd_handler, query,
|
||||
NULL, NULL);
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_ecore_con_dns_timeout(void *data)
|
||||
{
|
||||
Ecore_Con_Dns_Query *query;
|
||||
|
||||
query = data;
|
||||
|
||||
if (query->done.cb)
|
||||
query->done.cb(NULL, query->done.data);
|
||||
_ecore_con_dns_query_free(query);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_ecore_con_cb_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
|
||||
{
|
||||
Ecore_Con_Dns_Query *query;
|
||||
int i, n, fd, found = 0;
|
||||
unsigned int id;
|
||||
unsigned char buf[256];
|
||||
|
||||
query = data;
|
||||
fd = ecore_main_fd_handler_fd_get(fd_handler);
|
||||
|
||||
n = recv(fd, buf, sizeof(buf), 0);
|
||||
if (n == -1) goto error;
|
||||
/* Check if this message is for us */
|
||||
id = GET_16BIT(buf);
|
||||
for (i = 0; i < _server_count; i++)
|
||||
{
|
||||
if (query->id[i] == id)
|
||||
{
|
||||
found = 1;
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((found) && (n > query->length))
|
||||
{
|
||||
/* This should be it! */
|
||||
unsigned char *p;
|
||||
int size;
|
||||
|
||||
p = buf;
|
||||
|
||||
/* Skip the query */
|
||||
p += query->length;
|
||||
|
||||
/* Skip the header */
|
||||
p += RRFIXEDSZ;
|
||||
size = GET_16BIT(p);
|
||||
if (size == 4)
|
||||
{
|
||||
struct hostent he;
|
||||
|
||||
p += 2;
|
||||
|
||||
/* Get the IP address */
|
||||
he.h_addr_list = malloc(2 * sizeof(char *));
|
||||
if (he.h_addr_list)
|
||||
{
|
||||
/* Fill in the hostent and return successfully. */
|
||||
/* TODO: Maybe get the hostname from the reply */
|
||||
he.h_name = strdup(query->hostname);
|
||||
/* he.h_aliases = aliases; */
|
||||
he.h_addrtype = AF_INET;
|
||||
he.h_length = sizeof(struct in_addr);
|
||||
he.h_addr_list[0] = malloc(4 * sizeof(char));
|
||||
memcpy(he.h_addr_list[0], p, he.h_length);
|
||||
he.h_addr_list[1] = NULL;
|
||||
|
||||
if (query->done.cb)
|
||||
query->done.cb(&he, query->done.data);
|
||||
free(he.h_addr_list);
|
||||
_ecore_con_dns_query_free(query);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
found = 0;
|
||||
for (i = 0; i < _server_count; i++)
|
||||
{
|
||||
if (query->fd_handlers[i] == fd_handler)
|
||||
{
|
||||
/* This server didn't do it */
|
||||
if (query->socket[i]) close(query->socket[i]);
|
||||
query->socket[i] = 0;
|
||||
query->fd_handlers[i] = NULL;
|
||||
break;
|
||||
}
|
||||
else if (query->socket[i])
|
||||
{
|
||||
/* We're still looking */
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
/* Shutdown */
|
||||
if (query->done.cb)
|
||||
query->done.cb(NULL, query->done.data);
|
||||
_ecore_con_dns_query_free(query);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_ecore_con_dns_query_free(Ecore_Con_Dns_Query *query)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _server_count; i++)
|
||||
{
|
||||
if (query->socket[i]) close(query->socket[i]);
|
||||
query->socket[i] = 0;
|
||||
if (query->fd_handlers[i]) ecore_main_fd_handler_del(query->fd_handlers[i]);
|
||||
query->fd_handlers[i] = NULL;
|
||||
}
|
||||
if (query->timeout) ecore_timer_del(query->timeout);
|
||||
query->timeout = NULL;
|
||||
free(query->hostname);
|
||||
free(query);
|
||||
}
|
|
@ -83,4 +83,8 @@ struct _Ecore_Con_Url
|
|||
char active : 1;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* from ecore_con_dns.c */
|
||||
int ecore_con_dns_init(void);
|
||||
void ecore_con_dns_shutdown(void);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue