efl/src/lib/ecore_con/ecore_con.c

2599 lines
72 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
2010-01-04 15:43:16 -08:00
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef HAVE_NETINET_TCP_H
# include <netinet/tcp.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
#endif
#ifdef HAVE_WS2TCPIP_H
# include <ws2tcpip.h>
#endif
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "Ecore.h"
#include "ecore_private.h"
#include "Ecore_Con.h"
#include "ecore_con_private.h"
static Eina_Bool _ecore_con_client_timer(Ecore_Con_Client *cl);
static void _ecore_con_cl_timer_update(Ecore_Con_Client *cl);
static Eina_Bool _ecore_con_server_timer(Ecore_Con_Server *svr);
static void _ecore_con_server_timer_update(Ecore_Con_Server *svr);
static void _ecore_con_cb_tcp_connect(void *data,
Ecore_Con_Info *info);
static void _ecore_con_cb_udp_connect(void *data,
Ecore_Con_Info *info);
static void _ecore_con_cb_tcp_listen(void *data,
Ecore_Con_Info *info);
static void _ecore_con_cb_udp_listen(void *data,
Ecore_Con_Info *info);
static void _ecore_con_server_free(Ecore_Con_Server *svr);
static void _ecore_con_client_free(Ecore_Con_Client *cl);
static void _ecore_con_cl_read(Ecore_Con_Server *svr);
static Eina_Bool _ecore_con_svr_tcp_handler(void *data,
Ecore_Fd_Handler *fd_handler);
static Eina_Bool _ecore_con_cl_handler(void *data,
Ecore_Fd_Handler *fd_handler);
static Eina_Bool _ecore_con_cl_udp_handler(void *data,
Ecore_Fd_Handler *fd_handler);
static Eina_Bool _ecore_con_svr_udp_handler(void *data,
Ecore_Fd_Handler *fd_handler);
static void _ecore_con_svr_cl_read(Ecore_Con_Client *cl);
static Eina_Bool _ecore_con_svr_cl_handler(void *data,
Ecore_Fd_Handler *fd_handler);
static void _ecore_con_server_flush(Ecore_Con_Server *svr);
static void _ecore_con_client_flush(Ecore_Con_Client *cl);
static void _ecore_con_event_client_add_free(Ecore_Con_Server *svr,
void *ev);
static void _ecore_con_event_client_del_free(Ecore_Con_Server *svr,
void *ev);
static void _ecore_con_event_client_data_free(Ecore_Con_Server *svr,
void *ev);
static void _ecore_con_event_server_add_free(void *data,
void *ev);
static void _ecore_con_event_server_del_free(void *data,
void *ev);
static void _ecore_con_event_server_data_free(void *data,
void *ev);
static void _ecore_con_event_server_error_free(void *data,
Ecore_Con_Event_Server_Error *e);
static void _ecore_con_event_client_error_free(Ecore_Con_Server *svr,
Ecore_Con_Event_Client_Error *e);
static void _ecore_con_event_server_write_free(void *data,
Ecore_Con_Event_Server_Write *e);
static void _ecore_con_event_client_write_free(Ecore_Con_Server *svr,
Ecore_Con_Event_Client_Write *e);
static void _ecore_con_lookup_done(void *data,
Ecore_Con_Info *infos);
static const char * _ecore_con_pretty_ip(struct sockaddr *client_addr);
void
_ecore_con_client_kill(Ecore_Con_Client *cl)
{
if (cl->delete_me)
DBG("Multi kill request for client %p", cl);
else
{
ecore_con_event_client_del(cl);
if (cl->buf) return;
}
INF("Lost client %s", (cl->ip) ? cl->ip : "");
if (cl->fd_handler)
ecore_main_fd_handler_del(cl->fd_handler);
cl->fd_handler = NULL;
}
void
_ecore_con_server_kill(Ecore_Con_Server *svr)
{
if (svr->delete_me)
DBG("Multi kill request for svr %p", svr);
else
ecore_con_event_server_del(svr);
if (svr->fd_handler)
ecore_main_fd_handler_del(svr->fd_handler);
svr->fd_handler = NULL;
}
#define _ecore_con_server_kill(svr) do { \
DBG("KILL %p", (svr)); \
_ecore_con_server_kill((svr)); \
} while (0)
#define _ecore_con_client_kill(cl) do { \
DBG("KILL %p", (cl)); \
_ecore_con_client_kill((cl)); \
} while (0)
EAPI int ECORE_CON_EVENT_CLIENT_ADD = 0;
EAPI int ECORE_CON_EVENT_CLIENT_DEL = 0;
EAPI int ECORE_CON_EVENT_SERVER_ADD = 0;
EAPI int ECORE_CON_EVENT_SERVER_DEL = 0;
EAPI int ECORE_CON_EVENT_CLIENT_DATA = 0;
EAPI int ECORE_CON_EVENT_SERVER_DATA = 0;
EAPI int ECORE_CON_EVENT_CLIENT_WRITE = 0;
EAPI int ECORE_CON_EVENT_SERVER_WRITE = 0;
EAPI int ECORE_CON_EVENT_CLIENT_ERROR = 0;
EAPI int ECORE_CON_EVENT_SERVER_ERROR = 0;
EAPI int ECORE_CON_EVENT_PROXY_BIND = 0;
static Eina_List *servers = NULL;
static int _ecore_con_init_count = 0;
static int _ecore_con_event_count = 0;
int _ecore_con_log_dom = -1;
Ecore_Con_Socks *_ecore_con_proxy_once = NULL;
Ecore_Con_Socks *_ecore_con_proxy_global = NULL;
EAPI int
ecore_con_init(void)
{
if (++_ecore_con_init_count != 1)
return _ecore_con_init_count;
#ifdef HAVE_EVIL
if (!evil_init())
return --_ecore_con_init_count;
#endif
if (!ecore_init())
return --_ecore_con_init_count;
_ecore_con_log_dom = eina_log_domain_register
("ecore_con", ECORE_CON_DEFAULT_LOG_COLOR);
2010-11-05 18:22:50 -07:00
if (_ecore_con_log_dom < 0)
{
EINA_LOG_ERR("Impossible to create a log domain for Ecore Con.");
ecore_shutdown();
return --_ecore_con_init_count;
}
ecore_con_mempool_init();
ECORE_CON_EVENT_CLIENT_ADD = ecore_event_type_new();
ECORE_CON_EVENT_CLIENT_DEL = ecore_event_type_new();
ECORE_CON_EVENT_SERVER_ADD = ecore_event_type_new();
ECORE_CON_EVENT_SERVER_DEL = ecore_event_type_new();
ECORE_CON_EVENT_CLIENT_DATA = ecore_event_type_new();
ECORE_CON_EVENT_SERVER_DATA = ecore_event_type_new();
ECORE_CON_EVENT_CLIENT_WRITE = ecore_event_type_new();
ECORE_CON_EVENT_SERVER_WRITE = ecore_event_type_new();
ECORE_CON_EVENT_CLIENT_ERROR = ecore_event_type_new();
ECORE_CON_EVENT_SERVER_ERROR = ecore_event_type_new();
ECORE_CON_EVENT_PROXY_BIND = ecore_event_type_new();
eina_magic_string_set(ECORE_MAGIC_CON_SERVER, "Ecore_Con_Server");
eina_magic_string_set(ECORE_MAGIC_CON_CLIENT, "Ecore_Con_Client");
eina_magic_string_set(ECORE_MAGIC_CON_URL, "Ecore_Con_Url");
/* TODO Remember return value, if it fails, use gethostbyname() */
ecore_con_socks_init();
ecore_con_ssl_init();
ecore_con_info_init();
return _ecore_con_init_count;
}
EAPI int
ecore_con_shutdown(void)
{
Eina_List *l, *l2;
Ecore_Con_Server *svr;
if (--_ecore_con_init_count != 0)
return _ecore_con_init_count;
EINA_LIST_FOREACH_SAFE(servers, l, l2, svr)
{
Ecore_Con_Event_Server_Add *ev;
svr->delete_me = EINA_TRUE;
INF("svr %p is dead", svr);
/* some pointer hacks here to prevent double frees if people are being stupid */
EINA_LIST_FREE(svr->event_count, ev)
ev->server = NULL;
_ecore_con_server_free(svr);
}
ecore_con_socks_shutdown();
if (!_ecore_con_event_count) ecore_con_mempool_shutdown();
ecore_con_info_shutdown();
ecore_con_ssl_shutdown();
eina_log_domain_unregister(_ecore_con_log_dom);
_ecore_con_log_dom = -1;
ecore_shutdown();
#ifdef HAVE_EVIL
evil_shutdown();
#endif
return _ecore_con_init_count;
}
EAPI Eina_Bool
ecore_con_lookup(const char *name,
Ecore_Con_Dns_Cb done_cb,
const void *data)
{
Ecore_Con_Server *svr;
Ecore_Con_Lookup *lk;
struct addrinfo hints;
if (!name || !done_cb)
return EINA_FALSE;
svr = calloc(1, sizeof(Ecore_Con_Server));
if (!svr)
return EINA_FALSE;
lk = malloc(sizeof (Ecore_Con_Lookup));
if (!lk)
{
free(svr);
return EINA_FALSE;
}
lk->done_cb = done_cb;
lk->data = data;
svr->name = strdup(name);
if (!svr->name)
goto on_error;
svr->type = ECORE_CON_REMOTE_TCP;
svr->port = 1025;
svr->data = lk;
svr->created = EINA_TRUE;
svr->reject_excess_clients = EINA_FALSE;
svr->client_limit = -1;
svr->clients = NULL;
svr->ppid = getpid();
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;
if (ecore_con_info_get(svr, _ecore_con_lookup_done, svr,
&hints))
return EINA_TRUE;
free(svr->name);
on_error:
free(lk);
free(svr);
return EINA_FALSE;
}
/**
* @addtogroup Ecore_Con_Server_Group Ecore Connection Server Functions
*
* Functions that operate on Ecore server objects.
*
* @{
*/
/**
* @example ecore_con_server_example.c
* Shows how to write a simple server using the Ecore_Con library.
*/
EAPI Ecore_Con_Server *
ecore_con_server_add(Ecore_Con_Type compl_type,
const char *name,
int port,
const void *data)
{
Ecore_Con_Server *svr;
Ecore_Con_Type type;
if (port < 0 || !name)
return NULL; /* local user socket: FILE: ~/.ecore/[name]/[port] */
/* local system socket: FILE: /tmp/.ecore_service|[name]|[port] */
/* remote system socket: TCP/IP: [name]:[port] */
svr = calloc(1, sizeof(Ecore_Con_Server));
if (!svr)
return NULL;
svr->name = strdup(name);
if (!svr->name)
goto error;
svr->type = compl_type;
svr->port = port;
svr->data = (void *)data;
svr->created = EINA_TRUE;
svr->use_cert = (compl_type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT;
svr->reject_excess_clients = EINA_FALSE;
svr->client_limit = -1;
svr->clients = NULL;
svr->ppid = getpid();
if (ecore_con_ssl_server_prepare(svr, compl_type & ECORE_CON_SSL))
goto error;
type = compl_type & ECORE_CON_TYPE;
if ((type == ECORE_CON_LOCAL_USER) ||
(type == ECORE_CON_LOCAL_SYSTEM) ||
(type == ECORE_CON_LOCAL_ABSTRACT))
/* Local */
#ifdef _WIN32
if (!ecore_con_local_listen(svr))
goto error;
#else
if (!ecore_con_local_listen(svr, _ecore_con_svr_tcp_handler, svr))
goto error;
#endif
if ((type == ECORE_CON_REMOTE_TCP) ||
(type == ECORE_CON_REMOTE_NODELAY) ||
(type == ECORE_CON_REMOTE_CORK))
{
/* TCP */
if (!ecore_con_info_tcp_listen(svr, _ecore_con_cb_tcp_listen,
svr))
goto error;
}
else if ((type == ECORE_CON_REMOTE_MCAST) ||
(type == ECORE_CON_REMOTE_UDP))
/* UDP and MCAST */
if (!ecore_con_info_udp_listen(svr, _ecore_con_cb_udp_listen,
svr))
goto error;
servers = eina_list_append(servers, svr);
ECORE_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER);
return svr;
error:
if (svr->name)
free(svr->name);
if (svr->path)
free(svr->path);
if (svr->fd_handler)
ecore_main_fd_handler_del(svr->fd_handler);
if (svr->fd > 0)
close(svr->fd);
if (svr->buf)
eina_binbuf_free(svr->buf);
if (svr->ip)
eina_stringshare_del(svr->ip);
ecore_con_ssl_server_shutdown(svr);
free(svr);
return NULL;
}
EAPI Ecore_Con_Server *
ecore_con_server_connect(Ecore_Con_Type compl_type,
const char *name,
int port,
const void *data)
{
Ecore_Con_Server *svr;
Ecore_Con_Type type;
if ((!name) || (!name[0]))
return NULL;
/* local user socket: FILE: ~/.ecore/[name]/[port] */
/* local system socket: FILE: /tmp/.ecore_service|[name]|[port] */
/* remote system socket: TCP/IP: [name]:[port] */
svr = calloc(1, sizeof(Ecore_Con_Server));
if (!svr)
return NULL;
svr->name = strdup(name);
if (!svr->name)
goto error;
svr->type = compl_type;
svr->port = port;
svr->data = (void *)data;
svr->created = EINA_FALSE;
svr->use_cert = (compl_type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT;
svr->disable_proxy = (compl_type & ECORE_CON_SUPER_SSL & ECORE_CON_NO_PROXY) == ECORE_CON_NO_PROXY;
svr->reject_excess_clients = EINA_FALSE;
svr->clients = NULL;
svr->client_limit = -1;
type = compl_type & ECORE_CON_TYPE;
if ((!svr->disable_proxy) && (type > ECORE_CON_LOCAL_ABSTRACT))
{
/* never use proxies on local connections */
if (_ecore_con_proxy_once)
svr->ecs = _ecore_con_proxy_once;
else if (_ecore_con_proxy_global)
svr->ecs = _ecore_con_proxy_global;
_ecore_con_proxy_once = NULL;
if (svr->ecs)
{
if ((!svr->ecs->lookup) &&
(!ecore_con_lookup(svr->name, (Ecore_Con_Dns_Cb)ecore_con_socks_dns_cb, svr)))
goto error;
if (svr->ecs->lookup)
svr->ecs_state = ECORE_CON_PROXY_STATE_RESOLVED;
}
}
EINA_SAFETY_ON_TRUE_GOTO(ecore_con_ssl_server_prepare(svr, compl_type & ECORE_CON_SSL), error);
EINA_SAFETY_ON_TRUE_GOTO(((type == ECORE_CON_REMOTE_TCP) ||
(type == ECORE_CON_REMOTE_NODELAY) ||
(type == ECORE_CON_REMOTE_CORK) ||
(type == ECORE_CON_REMOTE_UDP) ||
(type == ECORE_CON_REMOTE_BROADCAST)) &&
(port < 0), error);
if ((type == ECORE_CON_LOCAL_USER) ||
(type == ECORE_CON_LOCAL_SYSTEM) ||
(type == ECORE_CON_LOCAL_ABSTRACT))
/* Local */
#ifdef _WIN32
if (!ecore_con_local_connect(svr, _ecore_con_cl_handler)) goto error;
#else
if (!ecore_con_local_connect(svr, _ecore_con_cl_handler, svr)) goto error;
#endif
if ((type == ECORE_CON_REMOTE_TCP) ||
(type == ECORE_CON_REMOTE_NODELAY) ||
(type == ECORE_CON_REMOTE_CORK))
{
/* TCP */
EINA_SAFETY_ON_FALSE_GOTO(ecore_con_info_tcp_connect(svr, _ecore_con_cb_tcp_connect, svr), error);
}
else if ((type == ECORE_CON_REMOTE_UDP) || (type == ECORE_CON_REMOTE_BROADCAST))
/* UDP and MCAST */
EINA_SAFETY_ON_FALSE_GOTO(ecore_con_info_udp_connect(svr, _ecore_con_cb_udp_connect, svr), error);
servers = eina_list_append(servers, svr);
ECORE_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER);
return svr;
error:
if (svr->name)
free(svr->name);
if (svr->path)
free(svr->path);
if (svr->fd_handler)
ecore_main_fd_handler_del(svr->fd_handler);
if (svr->fd > 0)
close(svr->fd);
ecore_con_ssl_server_shutdown(svr);
free(svr);
return NULL;
}
EAPI void
ecore_con_server_timeout_set(Ecore_Con_Server *svr,
double timeout)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_timeout_set");
return;
}
if (svr->created)
svr->client_disconnect_time = timeout;
else
svr->disconnect_time = timeout;
}
EAPI double
ecore_con_server_timeout_get(Ecore_Con_Server *svr)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_timeout_get");
return 0;
}
return svr->created ? svr->client_disconnect_time : svr->disconnect_time;
}
EAPI void *
ecore_con_server_del(Ecore_Con_Server *svr)
{
if (!svr) return NULL;
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_del");
return NULL;
}
if (svr->delete_me)
return NULL;
_ecore_con_server_kill(svr);
return svr->data;
}
EAPI void *
ecore_con_server_data_get(Ecore_Con_Server *svr)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get");
return NULL;
}
return svr->data;
}
EAPI void *
ecore_con_server_data_set(Ecore_Con_Server *svr,
void *data)
{
void *ret = NULL;
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get");
return NULL;
}
ret = svr->data;
svr->data = data;
return ret;
}
EAPI Eina_Bool
ecore_con_server_connected_get(Ecore_Con_Server *svr)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_connected_get");
return EINA_FALSE;
}
if (svr->connecting)
return EINA_FALSE;
return EINA_TRUE;
}
EAPI const Eina_List *
ecore_con_server_clients_get(Ecore_Con_Server *svr)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
"ecore_con_server_clients_get");
return NULL;
}
return svr->clients;
}
EAPI const char *
ecore_con_server_name_get(Ecore_Con_Server *svr)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
"ecore_con_server_name_get");
return NULL;
}
return svr->name;
}
EAPI int
ecore_con_server_port_get(Ecore_Con_Server *svr)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
"ecore_con_server_port_get");
return -1;
}
return svr->port;
}
EAPI int
ecore_con_server_send(Ecore_Con_Server *svr,
const void *data,
int size)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_send");
return 0;
}
EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->delete_me, 0);
EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0);
EINA_SAFETY_ON_TRUE_RETURN_VAL(size < 1, 0);
if (svr->fd_handler)
ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);
if (!svr->buf)
{
svr->buf = eina_binbuf_new();
EINA_SAFETY_ON_NULL_RETURN_VAL(svr->buf, 0);
#ifdef TCP_CORK
if ((svr->fd >= 0) && ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK))
{
int state = 1;
if (setsockopt(svr->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0)
/* realistically this isn't anything serious so we can just log and continue */
ERR("corking failed! %s", strerror(errno));
}
#endif
}
eina_binbuf_append_length(svr->buf, data, size);
return size;
}
EAPI void
ecore_con_server_client_limit_set(Ecore_Con_Server *svr,
int client_limit,
char reject_excess_clients)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
"ecore_con_server_client_limit_set");
return;
}
svr->client_limit = client_limit;
svr->reject_excess_clients = reject_excess_clients;
}
EAPI const char *
ecore_con_server_ip_get(Ecore_Con_Server *svr)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_ip_get");
return NULL;
}
return svr->ip;
}
EAPI double
ecore_con_server_uptime_get(Ecore_Con_Server *svr)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_uptime_get");
return -1;
}
return ecore_time_get() - svr->start_time;
}
2007-02-16 10:12:38 -08:00
EAPI void
ecore_con_server_flush(Ecore_Con_Server *svr)
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_flush");
return;
2007-02-16 10:12:38 -08:00
}
2007-02-16 10:12:38 -08:00
_ecore_con_server_flush(svr);
}
/**
* @}
*/
/**
* @addtogroup Ecore_Con_Client_Group Ecore Connection Client Functions
*
* Functions that operate on Ecore connection client objects.
*
* @{
*/
/**
* @example ecore_con_client_example.c
* Shows how to write a simple client that connects to the example server.
*/
EAPI int
ecore_con_client_send(Ecore_Con_Client *cl,
const void *data,
int size)
{
if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
{
ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_send");
return 0;
}
EINA_SAFETY_ON_TRUE_RETURN_VAL(cl->delete_me, 0);
EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0);
EINA_SAFETY_ON_TRUE_RETURN_VAL(size < 1, 0);
if (cl->fd_handler)
ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);