static void _ecore_con_cb_dns_lookup(void *data, struct hostent *he);
static void _ecore_con_cb_udp_dns_lookup(void *data, struct hostent *he);
+static void _ecore_con_cb_tcp_connect(void *data, Ecore_Con_Netinfo *info);
+static void _ecore_con_cb_udp_connect(void *data, Ecore_Con_Netinfo *info);
+static void _ecore_con_cb_tcp_listen(void *data, Ecore_Con_Netinfo *info);
+static void _ecore_con_cb_udp_listen(void *data, Ecore_Con_Netinfo *info);
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);
/* TODO Remember return value, if it fails, use gethostbyname() */
ecore_con_dns_init();
+ ecore_con_info_init();
servers = ecore_list_new();
ecore_list_destroy(servers);
servers = NULL;
+ ecore_con_info_shutdown();
ecore_con_dns_shutdown();
ecore_shutdown();
svr->name = strdup(name);
if (!svr->name) goto error;
- svr->type = type;
+ svr->type = compl_type;
svr->port = port;
svr->data = (void *)data;
svr->created = 1;
if (type == ECORE_CON_REMOTE_TCP)
{
- if (!ecore_con_dns_lookup(svr->name, _ecore_con_cb_dns_lookup, svr))
- goto error;
+ if (!ecore_con_info_tcp_connect(svr, _ecore_con_cb_tcp_connect, svr)) goto error;
}
else if (type == ECORE_CON_REMOTE_UDP)
{
- if (!ecore_con_dns_lookup(svr->name, _ecore_con_cb_udp_dns_lookup, svr))
- goto error;
+ if (!ecore_con_info_udp_connect(svr, _ecore_con_cb_udp_connect, svr)) goto error;
}
return svr;
kill_server(svr);
}
+static void
+_ecore_con_cb_tcp_listen(void *data, Ecore_Con_Netinfo *net_info)
+{
+ Ecore_Con_Server *svr;
+ struct linger lin;
+
+ svr = data;
+
+ if(!net_info) goto error;
+
+ svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, net_info->info.ai_protocol);
+ 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;
+ lin.l_onoff = 1;
+ lin.l_linger = 0;
+ if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0) goto error;
+/* socket_addr.sin_family = AF_INET; */
+/* socket_addr.sin_port = htons(port); */
+/* socket_addr.sin_addr.s_addr = htonl(INADDR_ANY); */
+ if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0) goto error;
+ if (listen(svr->fd, 4096) < 0) goto error;
+ svr->fd_handler =
+ ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
+ _ecore_con_svr_handler, svr, NULL, NULL);
+ if (!svr->fd_handler) goto error;
+
+#if USE_OPENSSL
+ if (svr->type & ECORE_CON_SSL)
+ {
+ if (!ssl_init_count)
+ {
+ SSL_library_init();
+ SSL_load_error_strings();
+ }
+ ssl_init_count++;
+
+ switch (svr->type & ECORE_CON_SSL)
+ {
+ case ECORE_CON_USE_SSL2:
+ if (!(svr->ssl_ctx = SSL_CTX_new(SSLv2_client_method())))
+ goto error;
+ break;
+ case ECORE_CON_USE_SSL3:
+ if (!(svr->ssl_ctx = SSL_CTX_new(SSLv3_client_method())))
+ goto error;
+ break;
+ case ECORE_CON_USE_TLS:
+ if (!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method())))
+ goto error;
+ break;
+ }
+
+ if (!(svr->ssl = SSL_new(svr->ssl_ctx)))
+ goto error;
+
+ SSL_set_fd(svr->ssl, svr->fd);
+ }
+#endif
+
+ return;
+
+ error:
+#if USE_OPENSSL
+ if (svr->ssl) SSL_free(svr->ssl);
+ if (svr->ssl_ctx) SSL_CTX_free(svr->ssl_ctx);
+#endif
+ kill_server(svr);
+}
+
+static void
+_ecore_con_cb_mcast_listen(void *data, Ecore_Con_Netinfo *net_info)
+{
+ Ecore_Con_Server *svr;
+ struct ip_mreq mreq;
+ struct ipv6_mreq mreq6;
+ const int on=1;
+
+ svr = data;
+
+ if (!net_info) goto error;
+
+ svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, net_info->info.ai_protocol);
+ if(svr->fd < 0) goto error;
+ if (net_info->info.ai_family == AF_INET)
+ {
+ if (!inet_pton(net_info->info.ai_family, net_info->ip, &mreq.imr_multiaddr)) goto error;
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (setsockopt(svr->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,sizeof(mreq)) != 0) goto error;
+ }
+ else if (net_info->info.ai_family == AF_INET6)
+ {
+ if (!inet_pton(net_info->info.ai_family, net_info->ip, &mreq6.ipv6mr_multiaddr)) goto error;
+ mreq6.ipv6mr_interface = htonl(INADDR_ANY);
+ if (setsockopt(svr->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq6,sizeof(mreq6)) != 0) goto error;
+ }
+ if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, &on,sizeof(on)) != 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 (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0) goto error;
+ svr->fd_handler =
+ ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
+ _ecore_con_svr_udp_handler, svr, NULL, NULL);
+ if (!svr->fd_handler) goto error;
+
+#if USE_OPENSSL
+ if (svr->type & ECORE_CON_SSL)
+ {
+ if (!ssl_init_count)
+ {
+ SSL_library_init();
+ SSL_load_error_strings();
+ }
+ ssl_init_count++;
+
+ switch (svr->type & ECORE_CON_SSL)
+ {
+ case ECORE_CON_USE_SSL2:
+ if (!(svr->ssl_ctx = SSL_CTX_new(SSLv2_client_method())))
+ goto error;
+ break;
+ case ECORE_CON_USE_SSL3:
+ if (!(svr->ssl_ctx = SSL_CTX_new(SSLv3_client_method())))
+ goto error;
+ break;
+ case ECORE_CON_USE_TLS:
+ if (!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method())))
+ goto error;
+ break;
+ }
+
+ if (!(svr->ssl = SSL_new(svr->ssl_ctx)))
+ goto error;
+
+ SSL_set_fd(svr->ssl, svr->fd);
+ }
+#endif
+
+ return;
+
+ error:
+#if USE_OPENSSL
+ if (svr->ssl) SSL_free(svr->ssl);
+ if (svr->ssl_ctx) SSL_CTX_free(svr->ssl_ctx);
+#endif
+ kill_server(svr);
+}
+
+static void
+_ecore_con_cb_udp_listen(void *data, Ecore_Con_Netinfo *net_info)
+{
+ //FIXME SSL
+ Ecore_Con_Server *svr;
+ struct sockaddr_in socket_addr;
+ int curstate = 0;
+ char buf[64];
+
+ svr = data;
+
+ if (!net_info) goto error;
+ svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, net_info->info.ai_protocol);
+ 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;
+ if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
+ goto error;
+ else
+ svr->fd_handler =
+ ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ | ECORE_FD_WRITE,
+ _ecore_con_cl_udp_handler, svr, NULL, NULL);
+ if (!svr->fd_handler) goto error;
+ svr->ip = strdup(net_info->ip);
+
+ return;
+
+ error:
+ kill_server(svr);
+}
+
+static void
+_ecore_con_cb_tcp_connect(void *data, Ecore_Con_Netinfo *net_info)
+{
+ Ecore_Con_Server *svr;
+ struct sockaddr_in socket_addr;
+ int curstate = 0;
+ char buf[64];
+
+ svr = data;
+
+ if (!net_info) goto error;
+ svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, net_info->info.ai_protocol);
+ 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;
+ if (connect(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 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;
+ svr->ip = strdup(net_info->ip);
+
+#if USE_OPENSSL
+ if (svr->type & ECORE_CON_SSL)
+ {
+ if (!ssl_init_count)
+ {
+ SSL_library_init();
+ SSL_load_error_strings();
+ }
+ ssl_init_count++;
+
+ switch (svr->type & ECORE_CON_SSL)
+ {
+ case ECORE_CON_USE_SSL2:
+ if (!(svr->ssl_ctx = SSL_CTX_new(SSLv2_client_method())))
+ goto error;
+ break;
+ case ECORE_CON_USE_SSL3:
+ if (!(svr->ssl_ctx = SSL_CTX_new(SSLv3_client_method())))
+ goto error;
+ break;
+ case ECORE_CON_USE_TLS:
+ if (!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method())))
+ goto error;
+ break;
+ }
+
+ if (!(svr->ssl = SSL_new(svr->ssl_ctx)))
+ goto error;
+
+ SSL_set_fd(svr->ssl, svr->fd);
+ }
+#endif
+
+ return;
+
+ error:
+ kill_server(svr);
+}
+
+static void
+_ecore_con_cb_udp_connect(void *data, Ecore_Con_Netinfo *net_info)
+{
+ Ecore_Con_Server *svr;
+ struct sockaddr_in socket_addr;
+ int curstate = 0;
+ char buf[64];
+
+ svr = data;
+
+ if (!net_info) goto error;
+ svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, net_info->info.ai_protocol);
+ 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;
+ if (connect(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
+ goto error;
+ else
+ svr->fd_handler =
+ ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ | ECORE_FD_WRITE,
+ _ecore_con_cl_udp_handler, svr, NULL, NULL);
+ if (!svr->fd_handler) goto error;
+ svr->ip = strdup(net_info->ip);
+
+ return;
+
+ error:
+ kill_server(svr);
+}
+
static Ecore_Con_State
svr_try_connect_plain(Ecore_Con_Server *svr)
{
--- /dev/null
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+/*
+ * getaddrinfo with callback
+ *
+ * man getaddrinfo
+ *
+ */
+#include "ecore_private.h"
+#include "Ecore.h"
+#include "ecore_con_private.h"
+
+#include <ctype.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+
+typedef struct _CB_Data CB_Data;
+
+typedef void (*CB_Func)(void *data, Ecore_Con_Netinfo *infos);
+
+struct _CB_Data
+{
+ Ecore_List2 __list_data;
+ CB_Func cb_done;
+ void *data;
+ Ecore_Fd_Handler *fdh;
+ pid_t pid;
+ Ecore_Event_Handler *handler;
+ int fd2;
+};
+
+
+static int _ecore_con_info_get(Ecore_Con_Server *svr, CB_Func done_cb, void *data);
+static void _ecore_con_info_readdata(CB_Data *cbdata);
+static void _ecore_con_info_slave_free(CB_Data *cbdata);
+static int _ecore_con_info_data_handler(void *data, Ecore_Fd_Handler *fd_handler);
+static int _ecore_con_info_exit_handler(void *data, int type __UNUSED__, void *event);
+
+static int info_init = 0;
+static Ecore_List2 *info_slaves = NULL;
+static struct addrinfo hints;
+
+int
+ecore_con_info_init(void)
+{
+ info_init++;
+ return info_init;
+}
+
+int
+ecore_con_info_shutdown(void)
+{
+ info_init--;
+ if (info_init == 0)
+ {
+ while (info_slaves) _ecore_con_info_slave_free((CB_Data *)info_slaves);
+ }
+ return info_init;
+}
+
+int
+ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
+ CB_Func done_cb,
+ void *data)
+{
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return _ecore_con_info_get(svr, done_cb, data);
+}
+
+int
+ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
+ CB_Func done_cb,
+ void *data)
+{
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return _ecore_con_info_get(svr, done_cb, data);
+}
+
+int
+ecore_con_info_udp_connect(Ecore_Con_Server *svr,
+ CB_Func done_cb,
+ void *data)
+{
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return _ecore_con_info_get(svr, done_cb, data);
+}
+
+int
+ecore_con_info_udp_listen(Ecore_Con_Server *svr,
+ CB_Func done_cb,
+ void *data)
+{
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return _ecore_con_info_get(svr, done_cb, data);
+}
+
+int
+ecore_con_pre_mcast_listen(Ecore_Con_Server *svr,
+ CB_Func done_cb,
+ void *data)
+{
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ hints.ai_addr = NULL;
+
+ return _ecore_con_info_get(svr, done_cb, data);
+}
+
+static int
+_ecore_con_info_get(Ecore_Con_Server *svr,
+ CB_Func done_cb,
+ void *data)
+{
+ CB_Data *cbdata;
+ int fd[2];
+
+ if (pipe(fd) < 0) return 0;
+ cbdata = calloc(1, sizeof(CB_Data));
+ if (!cbdata)
+ {
+ close(fd[0]);
+ close(fd[1]);
+ return 0;
+ }
+ cbdata->cb_done = done_cb;
+ cbdata->data = data;
+ cbdata->fd2 = fd[1];
+ if (!(cbdata->fdh = ecore_main_fd_handler_add(fd[0], ECORE_FD_READ,
+ _ecore_con_info_data_handler,
+ cbdata,
+ NULL, NULL)))
+ {
+ free(cbdata);
+ close(fd[0]);
+ close(fd[1]);
+ return 0;
+ }
+
+ if ((cbdata->pid = fork()) == 0)
+ {
+ Ecore_Con_Netinfo container;
+ struct addrinfo *result;
+ char service[NI_MAXSERV];
+ char hbuf[NI_MAXHOST];
+ char sbuf[NI_MAXSERV];
+
+ /* FIXME with EINA */
+ snprintf(service, NI_MAXSERV, "%i", svr->port);
+ /* CHILD */
+ if (!getaddrinfo(svr->name, service, &hints, &result) && result)
+ {
+ memcpy(&container.info, result, sizeof(struct addrinfo));
+ container.info.ai_canonname = NULL;
+ container.info.ai_next = NULL;
+ memcpy(&container.addr, result->ai_addr, sizeof(struct sockaddr));
+ if (!getnameinfo(&container.addr, container.info.ai_addrlen,
+ hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ {
+ memcpy(container.ip, hbuf, sizeof(container.ip));
+ memcpy(container.service, sbuf, sizeof(container.service));
+ }
+ else
+ {
+ memset(container.ip, 0, sizeof(container.ip));
+ memset(container.service, 0, sizeof(container.service));
+ }
+ write(fd[1], &container, sizeof(container));
+ }
+ else
+ write(fd[1], "", 1);
+
+ close(fd[1]);
+# ifdef __USE_ISOC99
+ _Exit(0);
+# else
+ _exit(0);
+# endif
+ }
+ /* PARENT */
+ cbdata->handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_info_exit_handler, cbdata);
+ close(fd[1]);
+ if (!cbdata->handler)
+ {
+ ecore_main_fd_handler_del(cbdata->fdh);
+ free(cbdata);
+ close(fd[0]);
+ return 0;
+ }
+ info_slaves = _ecore_list2_append(info_slaves, cbdata);
+ return 1;
+}
+
+static void
+_ecore_con_info_readdata(CB_Data *cbdata)
+{
+ Ecore_Con_Netinfo container;
+ ssize_t size;
+
+ size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &container,
+ sizeof(Ecore_Con_Netinfo));
+ if (size == sizeof(Ecore_Con_Netinfo))
+ {
+ container.info.ai_addr = &container.addr;
+ cbdata->cb_done(cbdata->data, &container);
+ }
+ else
+ cbdata->cb_done(cbdata->data, NULL);
+ cbdata->cb_done = NULL;
+}
+
+static void
+_ecore_con_info_slave_free(CB_Data *cbdata)
+{
+ info_slaves = _ecore_list2_remove(info_slaves, cbdata);
+ close(ecore_main_fd_handler_fd_get(cbdata->fdh));
+ ecore_main_fd_handler_del(cbdata->fdh);
+ ecore_event_handler_del(cbdata->handler);
+ free(cbdata);
+}
+
+static int
+_ecore_con_info_data_handler(void *data, Ecore_Fd_Handler *fd_handler)
+{
+ CB_Data *cbdata;
+
+ cbdata = data;
+ if (cbdata->cb_done)
+ {
+ if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+ _ecore_con_info_readdata(cbdata);
+ else
+ {
+ cbdata->cb_done(cbdata->data, NULL);
+ cbdata->cb_done = NULL;
+ }
+ }
+ _ecore_con_info_slave_free(cbdata);
+ return 0;
+}
+
+static int
+_ecore_con_info_exit_handler(void *data, int type __UNUSED__, void *event)
+{
+ CB_Data *cbdata;
+ Ecore_Exe_Event_Del *ev;
+
+ ev = event;
+ cbdata = data;
+ if (cbdata->pid != ev->pid) return 1;
+ return 0;
+ _ecore_con_info_slave_free(cbdata);
+ return 0;
+}