From f4306d654dc55e8a0449698da18f371644d656df Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Wed, 7 Dec 2016 13:34:28 -0200 Subject: [PATCH] ecore_con: Ecore_Con_Server now on top of Efl_Net! This is a major work and unfortunately couldn't be split into smaller pieces as old code was highly coupled. Ecore_Con_Server is now a wrapper around Efl_Net_Dialer_Simple (ecore_con_server_connect()) and Efl_Net_Server_Simple (ecore_con_server_add()), doing all that the original version did with some fixes so ecore_con_ssl_server_upgrade() and ecore_con_ssl_client_upgrade() are more usable -- see the examples and -t/--type=tcp+ssl. I tried to be bug-compatible, with code annotations where things doesn't make sense. This was based on ecore_con_suite tests and some manual experimenting with the examples, these can be helpful if you find regressions (report/assign to me). --- src/Makefile_Ecore_Con.am | 15 +- src/lib/ecore_con/Ecore_Con.h | 130 +- src/lib/ecore_con/Ecore_Con_Eo.h | 5 - src/lib/ecore_con/Ecore_Con_Legacy.h | 29 - src/lib/ecore_con/ecore_con.c | 2862 +------------------- src/lib/ecore_con/ecore_con_alloc.c | 4 + src/lib/ecore_con/ecore_con_eet.c | 5 +- src/lib/ecore_con/ecore_con_eet_base.eo | 5 +- src/lib/ecore_con/ecore_con_info.c | 297 -- src/lib/ecore_con/ecore_con_legacy.c | 2517 ++++++++++++++++- src/lib/ecore_con/ecore_con_local.c | 301 +- src/lib/ecore_con/ecore_con_private.h | 297 +- src/lib/ecore_con/ecore_con_socks.c | 488 +--- src/lib/ecore_con/ecore_con_ssl.c | 1963 -------------- src/lib/ecore_con/efl_network.eo | 201 -- src/lib/ecore_con/efl_network_client.eo | 30 - src/lib/ecore_con/efl_network_connector.eo | 8 - src/lib/ecore_con/efl_network_server.eo | 93 - 18 files changed, 2671 insertions(+), 6579 deletions(-) delete mode 100644 src/lib/ecore_con/Ecore_Con_Legacy.h delete mode 100644 src/lib/ecore_con/ecore_con_info.c delete mode 100644 src/lib/ecore_con/ecore_con_ssl.c delete mode 100644 src/lib/ecore_con/efl_network.eo delete mode 100644 src/lib/ecore_con/efl_network_client.eo delete mode 100644 src/lib/ecore_con/efl_network_connector.eo delete mode 100644 src/lib/ecore_con/efl_network_server.eo diff --git a/src/Makefile_Ecore_Con.am b/src/Makefile_Ecore_Con.am index c3e51ae441..1fc3ea5441 100644 --- a/src/Makefile_Ecore_Con.am +++ b/src/Makefile_Ecore_Con.am @@ -2,10 +2,6 @@ ### Library ecore_con_eolian_files = \ - lib/ecore_con/efl_network.eo \ - lib/ecore_con/efl_network_client.eo \ - lib/ecore_con/efl_network_server.eo \ - lib/ecore_con/efl_network_connector.eo \ lib/ecore_con/efl_net_socket.eo \ lib/ecore_con/efl_net_socket_simple.eo \ lib/ecore_con/efl_net_socket_fd.eo \ @@ -71,7 +67,6 @@ lib_LTLIBRARIES += lib/ecore_con/libecore_con.la installed_ecoreconmainheadersdir = $(includedir)/ecore-con-@VMAJ@ dist_installed_ecoreconmainheaders_DATA = \ lib/ecore_con/Ecore_Con.h \ -lib/ecore_con/Ecore_Con_Legacy.h \ lib/ecore_con/Ecore_Con_Eo.h \ lib/ecore_con/Ecore_Con_Eet.h \ lib/ecore_con/Ecore_Con_Eet_Legacy.h \ @@ -83,16 +78,15 @@ nodist_installed_ecoreconmainheaders_DATA = \ lib_ecore_con_libecore_con_la_SOURCES = \ lib/ecore_con/ecore_con_alloc.c \ lib/ecore_con/ecore_con.c \ +lib/ecore_con/ecore_con_legacy.c \ lib/ecore_con/ecore_con_eet.c \ lib/ecore_con/ecore_con_socks.c \ -lib/ecore_con/ecore_con_ssl.c \ lib/ecore_con/ecore_con_url.c \ lib/ecore_con/ecore_con_url_curl.c \ lib/ecore_con/ecore_con_url_curl.h \ static_libs/http-parser/http_parser.c \ static_libs/http-parser/http_parser.h \ lib/ecore_con/ecore_con_private.h \ -lib/ecore_con/ecore_con_info.c \ lib/ecore_con/efl_net_socket.c \ lib/ecore_con/efl_net_socket_simple.c \ lib/ecore_con/efl_net_socket_fd.c \ @@ -113,7 +107,8 @@ lib/ecore_con/efl_net_server_udp_client.c \ lib/ecore_con/efl_net_socket_ssl.c \ lib/ecore_con/efl_net_ssl_context.c \ lib/ecore_con/efl_net_dialer_ssl.c \ -lib/ecore_con/efl_net_server_ssl.c +lib/ecore_con/efl_net_server_ssl.c \ +lib/ecore_con/ecore_con_local.c if EFL_NET_CONTROL_BACKEND_CONNMAN lib_ecore_con_libecore_con_la_SOURCES += \ @@ -146,9 +141,9 @@ lib/ecore_con/efl_net_ssl_ctx-gnutls.c \ lib/ecore_con/efl_net_ssl_ctx-none.c if HAVE_WINDOWS -lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local_win32.c +#lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local_win32.c else -lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local.c \ +lib_ecore_con_libecore_con_la_SOURCES += \ lib/ecore_con/efl_net_socket_unix.c \ lib/ecore_con/efl_net_dialer_unix.c \ lib/ecore_con/efl_net_server_unix.c diff --git a/src/lib/ecore_con/Ecore_Con.h b/src/lib/ecore_con/Ecore_Con.h index 393b94c825..e8592f9580 100644 --- a/src/lib/ecore_con/Ecore_Con.h +++ b/src/lib/ecore_con/Ecore_Con.h @@ -227,7 +227,41 @@ extern "C" { #define ECORE_CON_USE_SSL ECORE_CON_USE_SSL2 #define ECORE_CON_REMOTE_SYSTEM ECORE_CON_REMOTE_TCP -typedef Eo Ecore_Con; +/** Types for an ecore_con client/server object. A correct way to set this + * type is with an ECORE_CON_$TYPE, optionally OR'ed with an ECORE_CON_$USE if + * encryption is desired, and LOAD_CERT if the previously loaded certificate + * should be used. + * + * @ingroup Ecore_Con + */ +typedef enum +{ + ECORE_CON_LOCAL_USER = 0, /** Socket in "~/.ecore" */ + ECORE_CON_LOCAL_SYSTEM = 1, /** Socket in /tmp */ + ECORE_CON_LOCAL_ABSTRACT = 2, /** Abstract socket */ + ECORE_CON_REMOTE_TCP = 3, /** Remote server using TCP */ + ECORE_CON_REMOTE_MCAST = 4, /** Remote multicast UDP server (ecore_con_server_add() only) */ + ECORE_CON_REMOTE_UDP = 5, /** Remote server using UDP */ + ECORE_CON_REMOTE_BROADCAST = 6, /** Remote broadcast using UDP (ecore_con_server_connect() only) */ + ECORE_CON_REMOTE_NODELAY = 7, /** Remote TCP connection sending packets + * immediately */ + ECORE_CON_REMOTE_CORK = 8, /** Remote TCP connection sending data in large chunks + * Note: Only available on Linux + * + * @since 1.2 */ + ECORE_CON_USE_SSL2 = 16 /* 1 << 4 */, /** Use SSL2: UNSUPPORTED. */ + ECORE_CON_USE_SSL3 = 32 /* 1 << 5 */, /** Use SSL3: UNSUPPORTED. */ + ECORE_CON_USE_TLS = 64 /* 1 << 6 */, /** Use TLS */ + ECORE_CON_USE_MIXED = 96 /* Ecore.Con.Type.use_tls | Ecore.Con.Type.use_ssl3 */, /** Use both TLS and SSL3 */ + ECORE_CON_LOAD_CERT = 128 /* 1 << 7 */, /** Attempt to use the loaded + * certificate */ + ECORE_CON_NO_PROXY = 256 /* 1 << 8 */, /** Disable all types of proxy on the + * server Note: Only functional for + * clients + * + * @since 1.2 */ + ECORE_CON_SOCKET_ACTIVATE = 512 /* 1 << 9 */ +} Ecore_Con_Type; /** * @typedef Ecore_Con_Socks @@ -265,13 +299,38 @@ typedef void (*Ecore_Con_Dns_Cb)(const char *canonname, /** @} */ -#ifndef EFL_NOLEGACY_API_SUPPORT -#include "Ecore_Con_Legacy.h" -#endif #ifdef EFL_BETA_API_SUPPORT #include "Ecore_Con_Eo.h" #endif +/** + * @struct _Ecore_Con_Server + * Used to provide legacy ABI/ABI compatibility with non-Eo applications. + * @ingroup Ecore_Con_Server_Group + */ +struct _Ecore_Con_Server; + +/** + * @typedef Ecore_Con_Server + * Used to provide legacy API/ABI compatibility with non-Eo applications. + * @ingroup Ecore_Con_Server_Group + */ +typedef struct _Ecore_Con_Server Ecore_Con_Server; + +/** + * @struct _Ecore_Con_Client + * Used to provide legacy ABI/ABI compatibility with non-Eo applications. + * @ingroup Ecore_Con_Client_Group + */ +struct _Ecore_Con_Client; + +/** + * @typedef Ecore_Con_Client + * Used to provide legacy API/ABI compatibility with non-Eo applications. + * @ingroup Ecore_Con_Client_Group + */ +typedef struct _Ecore_Con_Client Ecore_Con_Client; + /** * @struct _Ecore_Con_Url @@ -650,6 +709,26 @@ EAPI int ecore_con_init(void); */ EAPI int ecore_con_shutdown(void); +/** + * @brief Do an asynchronous DNS lookup. + * + * This function performs a DNS lookup on the hostname specified by name, then + * calls done_cb with the result and the data given as parameter. The result + * will be given to the done_cb as follows: + * + * canonname - the canonical name of the address, ip - the resolved ip address, + * addr - a pointer to the socket address, addrlen - the length of the socket + * address, in bytes, data - the data pointer given as parameter. + * + * @param[in] name IP address or server name to translate. + * @param[in] done_cb Callback to notify when done. + * @param[in] data User data to be given to done_cb. + * + * @return @c true if the request did not fail to be set up, @c false + * otherwise. + */ +EAPI Eina_Bool ecore_con_lookup(const char *name, Ecore_Con_Dns_Cb done_cb, const void *data) EINA_ARG_NONNULL(1); + /** * @} */ @@ -1142,6 +1221,10 @@ EAPI char *ecore_con_local_path_new(Eina_Bool is_system, const char *name, int p * or changed with ecore_con_server_data_set(). * * @see ecore_con_local_path_new() + * + * @note This API is deprecated and new code should use + * #EFL_NET_SERVER_SIMPLE_CLASS. + * See @li @ref efl_net_server_simple_example.c */ EAPI Ecore_Con_Server *ecore_con_server_add(Ecore_Con_Type type, const char *name, int port, @@ -1194,6 +1277,10 @@ EAPI Ecore_Con_Server *ecore_con_server_add(Ecore_Con_Type type, * or changed with ecore_con_server_data_set(). * * @see ecore_con_local_path_new() + * + * @note This API is deprecated and new code should use + * #EFL_NET_DIALER_SIMPLE_CLASS. + * See @li @ref efl_net_dialer_simple_example.c */ EAPI Ecore_Con_Server *ecore_con_server_connect(Ecore_Con_Type type, const char *name, int port, @@ -1210,6 +1297,18 @@ EAPI Ecore_Con_Server *ecore_con_server_connect(Ecore_Con_Type type, */ EAPI void * ecore_con_server_del(Ecore_Con_Server *svr); +/** + * @brief Retrieves the name of server. + * + * The name returned is the name used to connect on this server. + * + * @param svr The given server. + * @return The name of the server. + * + * @ingroup Efl_Network_Server + */ +EAPI const char *ecore_con_server_name_get(const Ecore_Con_Server *svr); + /** * @brief Retrieve the data associated with the given server. * @@ -1304,6 +1403,21 @@ EAPI int ecore_con_server_send(Ecore_Con_Server *svr, EAPI void ecore_con_server_client_limit_set(Ecore_Con_Server *svr, int client_limit, char reject_excess_clients); + +/** + * @brief Retrieves the current list of clients. + * + * Each node in the returned list points to an @ref Efl_Network_Client. This + * list cannot be modified or freed. It can also change if new clients are + * connected or disconnected, and will become invalid when the server is + * deleted/freed. + * + * @param svr The given server. + * @return The list of clients on this server. + * + */ +EAPI const Eina_List *ecore_con_server_clients_get(const Ecore_Con_Server *svr); + /** * @brief Get the IP address of a server that has been connected to. * @@ -1532,7 +1646,13 @@ EAPI Eina_Bool ecore_con_client_connected_get(const Ecore_Con_Client *cl */ EAPI int ecore_con_client_port_get(const Ecore_Con_Client *cl); - +/** + * @brief The server the client is connected to. + * + * @param cl The client + * @return The server the client is connected to. + */ +EAPI Ecore_Con_Server *ecore_con_client_server_get(const Ecore_Con_Client *cl); /** * @} diff --git a/src/lib/ecore_con/Ecore_Con_Eo.h b/src/lib/ecore_con/Ecore_Con_Eo.h index e919d4ccb9..76c6d304ec 100644 --- a/src/lib/ecore_con/Ecore_Con_Eo.h +++ b/src/lib/ecore_con/Ecore_Con_Eo.h @@ -1,8 +1,3 @@ -#include "efl_network.eo.h" -#include "efl_network_server.eo.h" -#include "efl_network_connector.eo.h" -#include "efl_network_client.eo.h" - #include "efl_net_socket.eo.h" #include "efl_net_dialer.eo.h" #include "efl_net_server.eo.h" diff --git a/src/lib/ecore_con/Ecore_Con_Legacy.h b/src/lib/ecore_con/Ecore_Con_Legacy.h deleted file mode 100644 index 1333eed935..0000000000 --- a/src/lib/ecore_con/Ecore_Con_Legacy.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _ECORE_CON_LEGACY_H -#define _ECORE_CON_LEGACY_H -#include -#include - -#include "efl_network.eo.legacy.h" -#include "efl_network_server.eo.legacy.h" -#include "efl_network_connector.eo.legacy.h" -#include "efl_network_client.eo.legacy.h" - - -/******************************************************************** - * ecore_con_base.eo.h - *******************************************************************/ -typedef Eo Ecore_Con_Base; - - -/******************************************************************** - * ecore_con_client.eo.h - *******************************************************************/ -typedef Eo Ecore_Con_Client; - - -/******************************************************************** - * ecore_con_server.eo.h - *******************************************************************/ -typedef Eo Ecore_Con_Server; - -#endif diff --git a/src/lib/ecore_con/ecore_con.c b/src/lib/ecore_con/ecore_con.c index e9dfd7621a..d603eae052 100644 --- a/src/lib/ecore_con/ecore_con.c +++ b/src/lib/ecore_con/ecore_con.c @@ -51,134 +51,11 @@ #define MSG_NOSIGNAL 0 /* noop */ #endif -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 *obj); - -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); - -#define EO_CONSTRUCTOR_CHECK_RETURN(obj) do { \ - if (efl_finalized_get(obj)) \ - { \ - ERR("This function is only allowed during construction."); \ - return; \ - } \ -} while (0) - #ifdef HAVE_SYSTEMD int sd_fd_index = 0; int sd_fd_max = 0; #endif -void -_ecore_con_client_kill(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (cl->delete_me) - DBG("Multi kill request for client %p", cl); - else - { - ecore_con_event_client_del(obj); - 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 *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (svr->delete_me) - DBG("Multi kill request for svr %p", svr); - else - ecore_con_event_server_del(obj); - - 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; - EWAPI Eina_Error EFL_NET_DIALER_ERROR_COULDNT_CONNECT = 0; EWAPI Eina_Error EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_PROXY = 0; EWAPI Eina_Error EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_HOST = 0; @@ -189,12 +66,8 @@ EWAPI Eina_Error EFL_NET_SERVER_ERROR_COULDNT_RESOLVE_HOST = 0; EWAPI Eina_Error EFL_NET_SOCKET_SSL_ERROR_HANDSHAKE = 0; EWAPI Eina_Error EFL_NET_SOCKET_SSL_ERROR_CERTIFICATE_VERIFY_FAILED = 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; typedef struct pxProxyFactory_ pxProxyFactory; typedef struct _Ecore_Con_Libproxy { @@ -226,18 +99,7 @@ ecore_con_init(void) goto ecore_con_log_error; 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(); + ecore_con_legacy_init(); EFL_NET_DIALER_ERROR_COULDNT_CONNECT = eina_error_msg_static_register("Couldn't connect to server"); EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_PROXY = eina_error_msg_static_register("Couldn't resolve proxy name"); @@ -249,16 +111,6 @@ ecore_con_init(void) EFL_NET_SOCKET_SSL_ERROR_HANDSHAKE = eina_error_msg_static_register("Failed SSL handshake"); EFL_NET_SOCKET_SSL_ERROR_CERTIFICATE_VERIFY_FAILED = eina_error_msg_static_register("Failed to verify peer's certificate"); - 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(); - ecore_con_local_init(); - #ifdef HAVE_SYSTEMD sd_fd_max = sd_listen_fds(0); #endif @@ -283,9 +135,6 @@ ecore_err: EAPI int ecore_con_shutdown(void) { - Eina_List *l, *l2; - Ecore_Con_Server *obj; - /* _ecore_con_init_count should not go below zero. */ if (_ecore_con_init_count < 1) { @@ -310,26 +159,8 @@ ecore_con_shutdown(void) EINA_LOG_STATE_START, EINA_LOG_STATE_SHUTDOWN); - EINA_LIST_FOREACH_SAFE(servers, l, l2, obj) - { - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Event_Server_Add *ev; + ecore_con_legacy_shutdown(); - if (!svr) continue; - 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(obj); - } - - ecore_con_socks_shutdown(); - if (!_ecore_con_event_count) ecore_con_mempool_shutdown(); - - ecore_con_local_shutdown(); - ecore_con_info_shutdown(); - ecore_con_ssl_shutdown(); eina_log_domain_unregister(_ecore_con_log_dom); _ecore_con_log_dom = -1; ecore_shutdown(); @@ -340,2695 +171,18 @@ ecore_con_shutdown(void) return _ecore_con_init_count; } -EOLIAN static Eina_Bool -_efl_network_lookup(Eo *kls_obj EINA_UNUSED, void *pd EINA_UNUSED, const char *name, Ecore_Con_Dns_Cb done_cb, const void *data) -{ - Ecore_Con_Server *obj; - Ecore_Con_Lookup *lk; - struct addrinfo hints; - - if (!name || !done_cb) - return EINA_FALSE; - - obj = efl_add(EFL_NETWORK_CONNECTOR_CLASS, NULL, efl_network_server_connection_type_set(efl_added, ECORE_CON_REMOTE_TCP), efl_network_server_name_set(efl_added, name), efl_network_port_set(efl_added, 1025)); - - lk = malloc(sizeof (Ecore_Con_Lookup)); - if (!lk) - { - return EINA_FALSE; - } - - lk->done_cb = done_cb; - lk->data = data; - - ecore_con_server_data_set(obj, lk); - - 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(obj, _ecore_con_lookup_done, obj, - &hints)) - return EINA_TRUE; - - free(lk); - efl_del(obj); - 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 *obj; - - /* local system socket: FILE: /tmp/.ecore_service|[name]|[port] */ - /* remote system socket: TCP/IP: [name]:[port] */ - obj = efl_add(EFL_NETWORK_SERVER_CLASS, NULL, efl_network_server_connection_type_set(efl_added, compl_type), efl_network_server_name_set(efl_added, name), efl_network_port_set(efl_added, port)); - - ecore_con_server_data_set(obj, (void *) data); - - return obj; -} - -EOLIAN static Eo * -_efl_network_server_efl_object_constructor(Ecore_Con_Server *obj, Efl_Network_Server_Data *svr) -{ - obj = efl_constructor(efl_super(obj, EFL_NETWORK_SERVER_CLASS)); - - svr->fd = INVALID_SOCKET; - svr->reject_excess_clients = EINA_FALSE; - svr->client_limit = -1; - svr->clients = NULL; - - return obj; -} - -EOLIAN static Eo * -_efl_network_server_efl_object_finalize(Ecore_Con_Server *obj, Efl_Network_Server_Data *svr) -{ - Ecore_Con_Type compl_type = svr->type; - Ecore_Con_Type type; - - efl_finalize(efl_super(obj, EFL_NETWORK_SERVER_CLASS)); - - svr->created = EINA_TRUE; - svr->ppid = getpid(); - svr->start_time = ecore_time_get(); - svr->use_cert = (svr->type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT; - - servers = eina_list_append(servers, obj); - - if (!svr->name) - goto error; - - type = compl_type & ECORE_CON_TYPE; - - 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)) && - (svr->port < 0), error); - - if (ecore_con_ssl_server_prepare(obj, compl_type & ECORE_CON_SSL)) - goto error; - - if ((type == ECORE_CON_LOCAL_USER) || - (type == ECORE_CON_LOCAL_SYSTEM) || - (type == ECORE_CON_LOCAL_ABSTRACT)) - /* Local */ -#ifdef _WIN32 - if (!ecore_con_local_listen(obj)) - goto error; -#else - if (!ecore_con_local_listen(obj, _ecore_con_svr_tcp_handler, obj)) - 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(obj, _ecore_con_cb_tcp_listen, - obj)) - goto error; - } - else if ((type == ECORE_CON_REMOTE_MCAST) || - (type == ECORE_CON_REMOTE_UDP)) - /* UDP and MCAST */ - if (!ecore_con_info_udp_listen(obj, _ecore_con_cb_udp_listen, - obj)) - goto error; - - return obj; - -error: - if (svr->delete_me) return NULL; - _ecore_con_server_kill(obj); - 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 *obj; - /* local user socket: FILE: ~/.ecore/[name]/[port] */ - /* local system socket: FILE: /tmp/.ecore_service|[name]|[port] */ - /* remote system socket: TCP/IP: [name]:[port] */ - obj = efl_add(EFL_NETWORK_CONNECTOR_CLASS, NULL, efl_network_server_connection_type_set(efl_added, compl_type), efl_network_server_name_set(efl_added, name), efl_network_port_set(efl_added, port)); - - ecore_con_server_data_set(obj, (void *) data); - - return obj; -} - -EOLIAN static Eo * -_efl_network_connector_efl_object_finalize(Ecore_Con_Server *obj, void *pd EINA_UNUSED) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Type compl_type = svr->type; - Ecore_Con_Type type; - - /* XXX: We intentionally put SERVER class here and not connector, as we'd - * like to skip that one. */ - efl_finalize(efl_super(obj, EFL_NETWORK_SERVER_CLASS)); - - 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; - servers = eina_list_append(servers, obj); - - if (!svr->name || !(svr->name[0])) - goto error; - - 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(obj, 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)) && - (svr->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(obj, _ecore_con_cl_handler)) goto error; -#else - if (!ecore_con_local_connect(obj, _ecore_con_cl_handler, obj)) 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(obj, _ecore_con_cb_tcp_connect, obj), 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(obj, _ecore_con_cb_udp_connect, obj), error); - - return obj; - -error: - return NULL; -} - -EAPI void -ecore_con_server_timeout_set(Ecore_Con *obj, double timeout) -{ - efl_network_timeout_set((Ecore_Con *)obj, timeout); -} - -EOLIAN static void -_efl_network_server_efl_network_timeout_set(Eo *obj, Efl_Network_Server_Data *svr, double timeout) -{ - if (svr->created) - svr->client_disconnect_time = timeout; - else - svr->disconnect_time = timeout; - - _ecore_con_server_timer_update(obj); -} - -EAPI double -ecore_con_server_timeout_get(const Ecore_Con *obj) -{ - return efl_network_timeout_get((Ecore_Con *)obj); -} - -EOLIAN static double -_efl_network_server_efl_network_timeout_get(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr) -{ - return svr->created ? svr->client_disconnect_time : svr->disconnect_time; -} - -EAPI void * -ecore_con_server_del(Ecore_Con_Server *obj) -{ - if (!obj) return NULL; - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - - if (!svr || svr->delete_me) - return NULL; - -#ifdef _WIN32 - WSASendDisconnect(svr->fd, NULL); -#endif - _ecore_con_server_kill(obj); - return svr->data; -} - -EAPI void * -ecore_con_server_data_get(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) - return NULL; - - return svr->data; -} - -EAPI void * -ecore_con_server_data_set(Ecore_Con_Server *obj, - void *data) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - void *ret = NULL; - - if (!svr) - return NULL; - - ret = svr->data; - svr->data = data; - return ret; -} - -EAPI Eina_Bool -ecore_con_server_connected_get(const Ecore_Con *obj) -{ - return efl_network_connected_get((Ecore_Con *)obj); -} - -EOLIAN static Eina_Bool -_efl_network_server_efl_network_connected_get(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr) -{ - return !svr->connecting; -} - -EOLIAN static const Eina_List * -_efl_network_server_clients_get(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr) -{ - return svr->clients; -} - -EOLIAN static void -_efl_network_server_connection_type_set(Eo *obj, Efl_Network_Server_Data *svr, Ecore_Con_Type type) -{ - EO_CONSTRUCTOR_CHECK_RETURN(obj); - - svr->type = type; -} - -EOLIAN static Ecore_Con_Type -_efl_network_server_connection_type_get(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr) -{ - return svr->type; -} - -EOLIAN static void -_efl_network_server_name_set(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr, const char *name) -{ - EO_CONSTRUCTOR_CHECK_RETURN(obj); - - if (svr->name) - free(svr->name); - - svr->name = strdup(name); -} - -EOLIAN static const char * -_efl_network_server_name_get(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr) -{ - return svr->name; -} - EAPI int -ecore_con_server_port_get(const Ecore_Con *obj) +ecore_con_ssl_available_get(void) { - return efl_network_port_get((Ecore_Con *)obj); -} - -EOLIAN static void -_efl_network_server_efl_network_port_set(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr, int port) -{ - EO_CONSTRUCTOR_CHECK_RETURN(obj); - - svr->port = port; -} - -EOLIAN static int -_efl_network_server_efl_network_port_get(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr) -{ - return svr->port; -} - -EAPI int -ecore_con_server_send(Ecore_Con *obj, const void *data, int size) -{ - return efl_network_send((Ecore_Con *)obj, data, size); -} - -EOLIAN static int -_efl_network_server_efl_network_send(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr, const void *data, int size) -{ - 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 != INVALID_SOCKET) && ((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 - } - if (!eina_binbuf_append_length(svr->buf, data, size)) - ERR("eina_binbuf_append_length() failed"); - - return size; -} - -EOLIAN static void -_efl_network_server_client_limit_set(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr, - int client_limit, - char reject_excess_clients) -{ - svr->client_limit = client_limit; - svr->reject_excess_clients = reject_excess_clients; -} - -EOLIAN static void -_efl_network_server_client_limit_get(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr, - int *client_limit, - char *reject_excess_clients) -{ - if (client_limit) *client_limit = svr->client_limit; - if (reject_excess_clients) *reject_excess_clients = svr->reject_excess_clients; -} - -EAPI const char * -ecore_con_server_ip_get(const Ecore_Con *obj) -{ - return efl_network_ip_get(obj); -} - -EOLIAN static const char * -_efl_network_server_efl_network_ip_get(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr) -{ - return svr->ip; -} - -EAPI double -ecore_con_server_uptime_get(const Ecore_Con *obj) -{ - return efl_network_uptime_get(obj); -} - -EOLIAN static double -_efl_network_server_efl_network_uptime_get(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr) -{ - return ecore_time_get() - svr->start_time; -} - -EAPI void -ecore_con_server_flush(Ecore_Con *obj) -{ - efl_network_flush((Ecore_Con *)obj); -} - -EOLIAN static void -_efl_network_server_efl_network_flush(Eo *obj, Efl_Network_Server_Data *svr EINA_UNUSED) -{ - _ecore_con_server_flush(obj); -} - -/** - * @} - */ - -/** - * @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 *obj, const void *data, int size) -{ - return efl_network_send((Ecore_Con *)obj, data, size); -} - -EOLIAN static int -_efl_network_client_efl_network_send(Eo *obj EINA_UNUSED, Efl_Network_Client_Data *cl, const void *data, int size) -{ - Efl_Network_Server_Data *host_server = NULL; - 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); - - if (cl->host_server) - host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_CLIENT_CLASS); - - - if (cl->host_server && ((host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP)) - { - int ret; - - ret = (int)sendto(host_server->fd, data, size, 0, - (struct sockaddr *)cl->client_addr, - cl->client_addr_len); - return ret; - } - else - { - if (!cl->buf) - { - cl->buf = eina_binbuf_new(); - EINA_SAFETY_ON_NULL_RETURN_VAL(cl->buf, 0); -#ifdef TCP_CORK - if ((cl->fd != INVALID_SOCKET) && (host_server) && - ((host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK)) - { - int state = 1; - if (setsockopt(cl->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 - } - if (!eina_binbuf_append_length(cl->buf, data, size)) - ERR("eina_binbuf_append_length() failed"); - } - return size; -} - -EOLIAN static Ecore_Con_Server * -_efl_network_client_server_get(Eo *obj EINA_UNUSED, Efl_Network_Client_Data *cl) -{ - return cl->host_server; -} - -EOLIAN static Eina_Bool -_efl_network_client_efl_network_connected_get(Eo *obj EINA_UNUSED, Efl_Network_Client_Data *cl) -{ - return !cl->delete_me; -} - -EAPI Eina_Bool -ecore_con_client_connected_get(const Ecore_Con *obj) -{ - return efl_network_connected_get((Ecore_Con *)obj); -} - -EOLIAN static void -_efl_network_client_efl_network_timeout_set(Eo *obj, Efl_Network_Client_Data *cl, double timeout) -{ - cl->disconnect_time = timeout; - - _ecore_con_cl_timer_update(obj); -} - -EAPI void -ecore_con_client_timeout_set(Ecore_Con *obj, double timeout) -{ - efl_network_timeout_set((Ecore_Con *)obj, timeout); -} - -EOLIAN static double -_efl_network_client_efl_network_timeout_get(Eo *obj EINA_UNUSED, Efl_Network_Client_Data *cl) -{ - return cl->disconnect_time; -} - -EAPI double -ecore_con_client_timeout_get(const Ecore_Con *obj) -{ - return efl_network_timeout_get((Ecore_Con *)obj); -} - -EAPI void * -ecore_con_client_del(Ecore_Con_Client *obj) -{ - if (!obj) return NULL; - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (!cl) return NULL; - -#ifdef _WIN32 - WSASendDisconnect(cl->fd, NULL); -#endif - - _ecore_con_client_kill(obj); - return cl->data; -} - -EAPI void -ecore_con_client_data_set(Ecore_Con_Client *obj, - const void *data) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (!cl) - return; - - cl->data = (void *)data; -} - -EAPI void * -ecore_con_client_data_get(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (!cl) - return NULL; - - return cl->data; -} - -EOLIAN static const char * -_efl_network_client_efl_network_ip_get(Eo *obj EINA_UNUSED, Efl_Network_Client_Data *cl) -{ - if (!cl->ip) - cl->ip = _ecore_con_pretty_ip(cl->client_addr); - - return cl->ip; -} - -EAPI const char * -ecore_con_client_ip_get(const Ecore_Con *obj) -{ - return efl_network_ip_get(obj); -} - -EOLIAN static int -_efl_network_client_efl_network_port_get(Eo *obj EINA_UNUSED, Efl_Network_Client_Data *cl) -{ - Efl_Network_Server_Data *sd = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - - if (sd->type != ECORE_CON_REMOTE_TCP && - sd->type != ECORE_CON_REMOTE_MCAST && - sd->type != ECORE_CON_REMOTE_UDP && - sd->type != ECORE_CON_REMOTE_BROADCAST && - sd->type != ECORE_CON_REMOTE_NODELAY) - return -1; - - if (cl->client_addr->sa_family == AF_INET) - return ((struct sockaddr_in *)cl->client_addr)->sin_port; -#ifdef HAVE_IPV6 - return ((struct sockaddr_in6 *)cl->client_addr)->sin6_port; +#if HAVE_GNUTLS + return 1; +#elif HAVE_OPENSSL + return 2; #else - return -1; + return 0; #endif } -EAPI int -ecore_con_client_port_get(const Ecore_Con *obj) -{ - return efl_network_port_get((Ecore_Con *)obj); -} - -EOLIAN static double -_efl_network_client_efl_network_uptime_get(Eo *obj EINA_UNUSED, Efl_Network_Client_Data *cl) -{ - return ecore_time_get() - cl->start_time; -} - -EAPI double -ecore_con_client_uptime_get(const Ecore_Con *obj) -{ - return efl_network_uptime_get(obj); -} - -EOLIAN static void -_efl_network_client_efl_network_flush(Eo *obj, Efl_Network_Client_Data *cl EINA_UNUSED) -{ - _ecore_con_client_flush(obj); -} - -EAPI void -ecore_con_client_flush(Ecore_Con *obj) -{ - efl_network_flush((Ecore_Con *)obj); -} - -EAPI int -ecore_con_server_fd_get(const Ecore_Con *obj) -{ - return efl_network_fd_get((Ecore_Con *)obj); -} - -EOLIAN static int -_efl_network_server_efl_network_fd_get(Eo *obj EINA_UNUSED, Efl_Network_Server_Data *svr) -{ - if (svr->created) return -1; - if (svr->delete_me) return -1; - return ecore_main_fd_handler_fd_get(svr->fd_handler); -} - -EOLIAN static int -_efl_network_client_efl_network_fd_get(Eo *obj EINA_UNUSED, Efl_Network_Client_Data *cl) -{ - return ecore_main_fd_handler_fd_get(cl->fd_handler); -} - -EAPI int -ecore_con_client_fd_get(const Ecore_Con *obj) -{ - return efl_network_fd_get((Ecore_Con *)obj); -} - -/** - * @} - */ - -void -ecore_con_event_proxy_bind(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Event_Proxy_Bind *e; - int ev = ECORE_CON_EVENT_PROXY_BIND; - - e = ecore_con_event_proxy_bind_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - - svr->event_count = eina_list_append(svr->event_count, e); - _ecore_con_server_timer_update(obj); - e->server = obj; - e->ip = svr->proxyip; - e->port = svr->proxyport; - ecore_event_add(ev, e, - _ecore_con_event_server_add_free, NULL); - _ecore_con_event_count++; -} - -void -ecore_con_event_server_add(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - /* we got our server! */ - Ecore_Con_Event_Server_Add *e; - int ev = ECORE_CON_EVENT_SERVER_ADD; - - e = ecore_con_event_server_add_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - - svr->connecting = EINA_FALSE; - svr->start_time = ecore_time_get(); - svr->event_count = eina_list_append(svr->event_count, e); - _ecore_con_server_timer_update(obj); - e->server = obj; - if (svr->upgrade) ev = ECORE_CON_EVENT_SERVER_UPGRADE; - ecore_event_add(ev, e, - _ecore_con_event_server_add_free, NULL); - efl_event_callback_call(obj, EFL_NETWORK_EVENT_CONNECTION_UPGRADED, NULL); - _ecore_con_event_count++; -} - -void -ecore_con_event_server_del(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Event_Server_Del *e; - - svr->delete_me = EINA_TRUE; - INF("svr %p is dead", svr); - e = ecore_con_event_server_del_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - - svr->event_count = eina_list_append(svr->event_count, e); - _ecore_con_server_timer_update(obj); - e->server = obj; - if (svr->ecs) - { - svr->ecs_state = svr->ecs->lookup ? ECORE_CON_PROXY_STATE_RESOLVED : ECORE_CON_PROXY_STATE_DONE; - eina_stringshare_replace(&svr->proxyip, NULL); - svr->proxyport = 0; - } - ecore_event_add(ECORE_CON_EVENT_SERVER_DEL, e, - _ecore_con_event_server_del_free, NULL); - _ecore_con_event_count++; -} - -void -ecore_con_event_server_write(Ecore_Con_Server *obj, int num) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Event_Server_Write *e; - - e = ecore_con_event_server_write_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - - INF("Wrote %d bytes", num); - svr->event_count = eina_list_append(svr->event_count, e); - e->server = obj; - e->size = num; - ecore_event_add(ECORE_CON_EVENT_SERVER_WRITE, e, - (Ecore_End_Cb)_ecore_con_event_server_write_free, NULL); - _ecore_con_event_count++; -} - -void -ecore_con_event_server_data(Ecore_Con_Server *obj, unsigned char *buf, int num, Eina_Bool duplicate) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Event_Server_Data *e; - - e = ecore_con_event_server_data_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - - svr->event_count = eina_list_append(svr->event_count, e); - _ecore_con_server_timer_update(obj); - e->server = obj; - if (duplicate) - { - e->data = malloc(num); - if (!e->data) - { - ERR("server data allocation failure !"); - _ecore_con_event_server_data_free(NULL, e); - return; - } - memcpy(e->data, buf, num); - } - else - e->data = buf; - e->size = num; - ecore_event_add(ECORE_CON_EVENT_SERVER_DATA, e, - _ecore_con_event_server_data_free, NULL); - { - Ecore_Con_Event_Data_Received event_info = { NULL, 0 }; - event_info.data = e->data; - event_info.size = e->size; - efl_event_callback_call(obj, EFL_NETWORK_EVENT_DATA_RECEIVED, &event_info); - } - _ecore_con_event_count++; -} - -void -ecore_con_event_client_add(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - Ecore_Con_Event_Client_Add *e; - int ev = ECORE_CON_EVENT_CLIENT_ADD; - - e = ecore_con_event_client_add_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - - cl->event_count = eina_list_append(cl->event_count, e); - host_server->event_count = eina_list_append(host_server->event_count, e); - _ecore_con_cl_timer_update(obj); - cl->start_time = ecore_time_get(); - e->client = obj; - if (cl->upgrade) ev = ECORE_CON_EVENT_CLIENT_UPGRADE; - ecore_event_add(ev, e, - (Ecore_End_Cb)_ecore_con_event_client_add_free, cl->host_server); - efl_event_callback_call(obj, EFL_NETWORK_EVENT_CONNECTION_UPGRADED, NULL); - _ecore_con_event_count++; -} - -void -ecore_con_event_client_del(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - Ecore_Con_Event_Client_Del *e; - - if (!cl) return; - cl->delete_me = EINA_TRUE; - INF("cl %p is dead", cl); - e = ecore_con_event_client_del_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - cl->event_count = eina_list_append(cl->event_count, e); - - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - - host_server->event_count = eina_list_append(host_server->event_count, e); - _ecore_con_cl_timer_update(obj); - e->client = obj; - ecore_event_add(ECORE_CON_EVENT_CLIENT_DEL, e, - (Ecore_End_Cb)_ecore_con_event_client_del_free, cl->host_server); - _ecore_con_event_count++; -} - -void -ecore_con_event_client_write(Ecore_Con_Client *obj, int num) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - Ecore_Con_Event_Client_Write *e; - - e = ecore_con_event_client_write_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - - cl->event_count = eina_list_append(cl->event_count, e); - host_server->event_count = eina_list_append(host_server->event_count, e); - e->client = obj; - e->size = num; - ecore_event_add(ECORE_CON_EVENT_CLIENT_WRITE, e, - (Ecore_End_Cb)_ecore_con_event_client_write_free, cl->host_server); - _ecore_con_event_count++; -} - -void -ecore_con_event_client_data(Ecore_Con_Client *obj, unsigned char *buf, int num, Eina_Bool duplicate) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - Ecore_Con_Event_Client_Data *e; - - e = ecore_con_event_client_data_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - - cl->event_count = eina_list_append(cl->event_count, e); - host_server->event_count = eina_list_append(host_server->event_count, e); - _ecore_con_cl_timer_update(obj); - e->client = obj; - if ((duplicate) && (num > 0)) - { - e->data = malloc(num); - if (!e->data) - { - ERR("client data allocation failure !"); - _ecore_con_event_client_data_free(cl->host_server, e); - return; - } - memcpy(e->data, buf, num); - } - else - e->data = buf; - e->size = num; - ecore_event_add(ECORE_CON_EVENT_CLIENT_DATA, e, - (Ecore_End_Cb)_ecore_con_event_client_data_free, cl->host_server); - { - Ecore_Con_Event_Data_Received event_info = { NULL, 0 }; - event_info.data = e->data; - event_info.size = e->size; - efl_event_callback_call(obj, EFL_NETWORK_EVENT_DATA_RECEIVED, &event_info); - } - _ecore_con_event_count++; -} - -void -ecore_con_server_infos_del(Ecore_Con_Server *obj, void *info) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - svr->infos = eina_list_remove(svr->infos, info); -} - -void -_ecore_con_event_server_error(Ecore_Con_Server *obj, char *error, Eina_Bool duplicate) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Event_Server_Error *e; - - e = ecore_con_event_server_error_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - - e->server = obj; - e->error = duplicate ? strdup(error) : error; - DBG("%s", error); - svr->event_count = eina_list_append(svr->event_count, e); - ecore_event_add(ECORE_CON_EVENT_SERVER_ERROR, e, (Ecore_End_Cb)_ecore_con_event_server_error_free, NULL); - efl_event_callback_call(obj, EFL_NETWORK_EVENT_CONNECTION_ERROR, e->error); - _ecore_con_event_count++; -} - -void -ecore_con_event_client_error(Ecore_Con_Client *obj, const char *error) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - Ecore_Con_Event_Client_Error *e; - - e = ecore_con_event_client_error_alloc(); - EINA_SAFETY_ON_NULL_RETURN(e); - - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - - e->client = obj; - e->error = strdup(error); - DBG("%s", error); - cl->event_count = eina_list_append(cl->event_count, e); - host_server->event_count = eina_list_append(host_server->event_count, e); - ecore_event_add(ECORE_CON_EVENT_CLIENT_ERROR, e, (Ecore_End_Cb)_ecore_con_event_client_error_free, cl->host_server); - efl_event_callback_call(obj, EFL_NETWORK_EVENT_CONNECTION_ERROR, e->error); - _ecore_con_event_count++; -} - -static void -_ecore_con_server_free(Ecore_Con_Server *obj) -{ - efl_del(obj); -} - -EOLIAN static void -_efl_network_server_efl_object_destructor(Eo *obj, Efl_Network_Server_Data *svr) -{ - Ecore_Con_Client *cl_obj; - double t_start, t; - - if (svr->event_count) goto end; - - while (svr->infos) - { - ecore_con_info_data_clear(svr->infos->data); - svr->infos = eina_list_remove_list(svr->infos, svr->infos); - } - - t_start = ecore_time_get(); - while (svr->buf && (!svr->delete_me)) - { - _ecore_con_server_flush(obj); - t = ecore_time_get(); - if ((t - t_start) > 0.5) - { - WRN("ECORE_CON: EEK - stuck in _ecore_con_server_free() trying\n" - " to flush data out from the server, and have been for\n" - " %1.1f seconds. This is taking too long. Aborting flush.", - (t - t_start)); - break; - } - } - -#ifdef _WIN32 - ecore_con_local_win32_server_del(obj); -#endif - if (svr->event_count) goto end; - - if (svr->buf) - eina_binbuf_free(svr->buf); - - EINA_LIST_FREE(svr->clients, cl_obj) - { - Efl_Network_Client_Data *cl = efl_data_scope_get(cl_obj, EFL_NETWORK_CLIENT_CLASS); - Ecore_Con_Event_Server_Add *ev; - - /* some pointer hacks here to prevent double frees if people are being stupid */ - EINA_LIST_FREE(cl->event_count, ev) - ev->server = NULL; - cl->delete_me = EINA_TRUE; - INF("cl %p is dead", cl); - _ecore_con_client_free(cl_obj); - } - if ((svr->created) && (svr->path) && (svr->ppid == getpid())) - unlink(svr->path); - - ecore_con_ssl_server_shutdown(obj); - free(svr->name); - svr->name = NULL; - - free(svr->path); - svr->path = NULL; - - eina_stringshare_del(svr->ip); - eina_stringshare_del(svr->verify_name); - - if (svr->ecs_buf) eina_binbuf_free(svr->ecs_buf); - if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf); - - if (svr->fd_handler) - ecore_main_fd_handler_del(svr->fd_handler); - - if (svr->fd != INVALID_SOCKET) - closesocket(svr->fd); - - if (svr->until_deletion) - ecore_timer_del(svr->until_deletion); - - servers = eina_list_remove(servers, obj); - svr->data = NULL; - - efl_destructor(efl_super(obj, EFL_NETWORK_SERVER_CLASS)); -end: - return; -} - -static void -_ecore_con_client_free(Ecore_Con_Client *obj) -{ - efl_del(obj); -} - -EOLIAN static void -_efl_network_client_efl_object_destructor(Eo *obj, Efl_Network_Client_Data *cl) -{ - double t_start, t; - - if (cl->event_count) return; - - t_start = ecore_time_get(); - while ((cl->buf) && (!cl->delete_me)) - { - _ecore_con_client_flush(obj); - t = ecore_time_get(); - if ((t - t_start) > 0.5) - { - WRN("EEK - stuck in _ecore_con_client_free() trying\n" - " to flush data out from the client, and have been for\n" - " %1.1f seconds. This is taking too long. Aborting flush.", - (t - t_start)); - break; - } - } - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - - if (host_server) - { - host_server->clients = eina_list_remove(host_server->clients, obj); - --host_server->client_count; - } - -#ifdef _WIN32 - ecore_con_local_win32_client_del(obj); -#endif - - if (cl->event_count) return; - - if (cl->buf) eina_binbuf_free(cl->buf); - - if (host_server && (host_server->type & ECORE_CON_SSL)) - ecore_con_ssl_client_shutdown(obj); - - if (cl->fd_handler) - ecore_main_fd_handler_del(cl->fd_handler); - - if (cl->fd != INVALID_SOCKET) - closesocket(cl->fd); - - free(cl->client_addr); - cl->client_addr = NULL; - - if (cl->until_deletion) - ecore_timer_del(cl->until_deletion); - - eina_stringshare_del(cl->ip); - cl->data = NULL; - - efl_destructor(efl_super(obj, EFL_NETWORK_CLIENT_CLASS)); -} - -static Eina_Bool -_ecore_con_server_timer(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - ecore_con_server_del(obj); - - svr->until_deletion = NULL; - return ECORE_CALLBACK_CANCEL; -} - -static void -_ecore_con_server_timer_update(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (svr->disconnect_time) - { - if (svr->disconnect_time > 0) - { - if (svr->until_deletion) - { - ecore_timer_interval_set(svr->until_deletion, svr->disconnect_time); - ecore_timer_reset(svr->until_deletion); - } - else - svr->until_deletion = ecore_timer_add(svr->disconnect_time, (Ecore_Task_Cb)_ecore_con_server_timer, obj); - } - else if (svr->until_deletion) - { - ecore_timer_del(svr->until_deletion); - svr->until_deletion = NULL; - } - } - else - { - if (svr->until_deletion) - { - ecore_timer_del(svr->until_deletion); - svr->until_deletion = NULL; - } - } -} - -static Eina_Bool -_ecore_con_client_timer(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - ecore_con_client_del(obj); - - cl->until_deletion = NULL; - return ECORE_CALLBACK_CANCEL; -} - -static void -_ecore_con_cl_timer_update(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (cl->disconnect_time) - { - if (cl->disconnect_time > 0) - { - if (cl->until_deletion) - { - ecore_timer_interval_set(cl->until_deletion, cl->disconnect_time); - ecore_timer_reset(cl->until_deletion); - } - else - cl->until_deletion = ecore_timer_add(cl->disconnect_time, (Ecore_Task_Cb)_ecore_con_client_timer, obj); - } - else if (cl->until_deletion) - { - ecore_timer_del(cl->until_deletion); - cl->until_deletion = NULL; - } - } - else - { - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - - if (host_server && host_server->client_disconnect_time > 0) - { - if (cl->until_deletion) - { - ecore_timer_interval_set(cl->until_deletion, host_server->client_disconnect_time); - ecore_timer_reset(cl->until_deletion); - } - else - cl->until_deletion = ecore_timer_add(host_server->client_disconnect_time, (Ecore_Task_Cb)_ecore_con_client_timer, obj); - } - else if (cl->until_deletion) - { - ecore_timer_del(cl->until_deletion); - cl->until_deletion = NULL; - } - } -} - -static void -_ecore_con_cb_tcp_listen(void *data, - Ecore_Con_Info *net_info) -{ - Ecore_Con_Server *obj = data; - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - struct linger lin; - const char *memerr = NULL; -#ifdef _WIN32 - u_long mode = 1; -#endif - - errno = 0; - if (!net_info) /* error message has already been handled */ - { - svr->delete_me = EINA_TRUE; - goto error; - } - -#ifdef HAVE_SYSTEMD - if (svr->type & ECORE_CON_SOCKET_ACTIVATE && sd_fd_index < sd_fd_max) - { - if (sd_is_socket_inet(SD_LISTEN_FDS_START + sd_fd_index, - net_info->info.ai_family, - net_info->info.ai_socktype, - 1, - svr->port) <= 0) - { - ERR("Your systemd unit seems to provide fd in the wrong order for Socket activation."); - goto error; - } - - svr->fd = SD_LISTEN_FDS_START + sd_fd_index++; - - /* I am wondering if that's really going to work as the bind is already done */ - if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error; - - lin.l_onoff = 1; - lin.l_linger = 0; - if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin, - sizeof(struct linger)) < 0) - goto error; - - if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY) - { - int flag = 1; - - if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, - sizeof(int)) < 0) - { - goto error; - } - } - - goto fd_ready; - } -#endif - - svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, - net_info->info.ai_protocol); -#ifdef _WIN32 - if (svr->fd == INVALID_SOCKET) goto error; - - if (ioctlsocket(svr->fd, FIONBIO, &mode)) goto error; -#else - 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; -#endif - - lin.l_onoff = 1; - lin.l_linger = 0; - if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin, - sizeof(struct linger)) < 0) - goto error; - - if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY) - { - int flag = 1; - - if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, - sizeof(int)) < 0) - { - goto error; - } - } - - 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; - -#ifdef HAVE_SYSTEMD -fd_ready: -#endif - svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, - _ecore_con_svr_tcp_handler, obj, NULL, NULL); - if (!svr->fd_handler) - { - memerr = "Memory allocation failure"; - goto error; - } - - return; - -error: - if (errno || memerr) ecore_con_event_server_error(obj, memerr ? : strerror(errno)); - ecore_con_ssl_server_shutdown(obj); - _ecore_con_server_kill(obj); -} - -static void -_ecore_con_cb_udp_listen(void *data, - Ecore_Con_Info *net_info) -{ - Ecore_Con_Server *obj = data; - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Type type; - struct ip_mreq mreq; -#ifdef HAVE_IPV6 - struct ipv6_mreq mreq6; -#endif - const int on = 1; - const char *memerr = NULL; -#ifdef _WIN32 - u_long mode = 1; -#endif - - type = svr->type; - type &= ECORE_CON_TYPE; - - errno = 0; - if (!net_info) /* error message has already been handled */ - { - svr->delete_me = EINA_TRUE; - goto error; - } -#ifdef HAVE_SYSTEMD - if (svr->type & ECORE_CON_SOCKET_ACTIVATE && sd_fd_index < sd_fd_max) - { - if (sd_is_socket_inet(SD_LISTEN_FDS_START + sd_fd_index, - net_info->info.ai_family, - net_info->info.ai_socktype, - -1, - svr->port) <= 0) - { - ERR("Your systemd unit seems to provide fd in the wrong order for Socket activation."); - goto error; - } - svr->fd = SD_LISTEN_FDS_START + sd_fd_index++; - - if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) != 0) - goto error; - if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error; - - goto fd_ready; - } -#endif - svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, - net_info->info.ai_protocol); -#ifdef _WIN32 - if (svr->fd == INVALID_SOCKET) goto error; - - if (ioctlsocket(svr->fd, FIONBIO, &mode)) goto error; -#else - 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; -#endif - - if (type == ECORE_CON_REMOTE_MCAST) - { - 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, - (const void *)&mreq, sizeof(mreq)) != 0) - goto error; - } -#ifdef HAVE_IPV6 - 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_IPV6, IPV6_JOIN_GROUP, - (const void *)&mreq6, sizeof(mreq6)) != 0) - goto error; - } -#endif - } - - if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) != 0) - goto error; - - if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0) - goto error; - -#ifdef HAVE_SYSTEMD -fd_ready: -#endif - svr->fd_handler = - ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, - _ecore_con_svr_udp_handler, obj, NULL, NULL); - if (!svr->fd_handler) - { - memerr = "Memory allocation failure"; - goto error; - } - - svr->ip = eina_stringshare_add(net_info->ip); - - return; - -error: - if (errno || memerr) ecore_con_event_server_error(obj, memerr ? : strerror(errno)); - ecore_con_ssl_server_shutdown(obj); - _ecore_con_server_kill(obj); -} - -static void -_ecore_con_cb_tcp_connect(void *data, - Ecore_Con_Info *net_info) -{ - Ecore_Con_Server *obj = data; - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - int res; - int curstate = 0; - const char *memerr = NULL; -#ifdef _WIN32 - u_long mode = 1; -#endif - - errno = 0; - if (!net_info) /* error message has already been handled */ - { - svr->delete_me = EINA_TRUE; - goto error; - } - - svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, - net_info->info.ai_protocol); -#ifdef _WIN32 - if (svr->fd == INVALID_SOCKET) goto error; - - if (ioctlsocket(svr->fd, FIONBIO, &mode)) goto error; -#else - 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; -#endif - - if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, sizeof(curstate)) < 0) - goto error; - - if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY) - { - int flag = 1; - - if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) < 0) - { - goto error; - } - } - - res = connect(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen); -#ifdef _WIN32 - if (res == SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - { - char *err; - err = evil_format_message(WSAGetLastError()); - _ecore_con_event_server_error(obj, err, EINA_FALSE); - ecore_con_ssl_server_shutdown(obj); - _ecore_con_server_kill(obj); - return; - } - -#else - if (res < 0) - { - if (errno != EINPROGRESS) goto error; -#endif - svr->connecting = EINA_TRUE; - svr->fd_handler = - ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ | ECORE_FD_WRITE, - _ecore_con_cl_handler, obj, NULL, NULL); - } - else - { - ecore_con_event_server_add(obj); - svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, - _ecore_con_cl_handler, obj, NULL, NULL); - } - - if (svr->type & ECORE_CON_SSL) - { - svr->handshaking = EINA_TRUE; - svr->ssl_state = ECORE_CON_SSL_STATE_INIT; - DBG("%s ssl handshake", svr->ecs_state ? "Queuing" : "Beginning"); - if ((!svr->ecs_state) && ecore_con_ssl_server_init(obj)) - goto error; - } - - if (!svr->fd_handler) - { - memerr = "Memory allocation failure"; - goto error; - } - - if ((!svr->ecs) || (svr->ecs->lookup)) - svr->ip = eina_stringshare_add(net_info->ip); - - return; - -error: - ecore_con_event_server_error(obj, - memerr ? : errno ? strerror(errno) : "DNS error"); - ecore_con_ssl_server_shutdown(obj); - _ecore_con_server_kill(obj); -} - -static void -_ecore_con_cb_udp_connect(void *data, - Ecore_Con_Info *net_info) -{ - Ecore_Con_Server *obj = data; - int curstate = 0; - int broadcast = 1; - const char *memerr = NULL; - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); -#ifdef _WIN32 - u_long mode = 1; -#endif - - errno = 0; - if (!net_info) /* error message has already been handled */ - { - svr->delete_me = EINA_TRUE; - goto error; - } - - svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype, - net_info->info.ai_protocol); -#ifdef _WIN32 - if (svr->fd == INVALID_SOCKET) goto error; - - if (ioctlsocket(svr->fd, FIONBIO, &mode)) goto error; -#else - 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; -#endif - if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_BROADCAST) - { - if (setsockopt(svr->fd, SOL_SOCKET, SO_BROADCAST, - (const void *)&broadcast, - sizeof(broadcast)) < 0) - { - goto error; - } - } - if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, - (const void *)&curstate, sizeof(curstate)) < 0) - goto error; - - if (connect(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_FD_WRITE, - _ecore_con_cl_udp_handler, obj, NULL, NULL); - - if (!svr->fd_handler) - { - memerr = "Memory allocation failure"; - goto error; - } - - if ((!svr->ecs) || (svr->ecs->lookup)) - svr->ip = eina_stringshare_add(net_info->ip); - - return; - -error: - if (errno || memerr) ecore_con_event_server_error(obj, memerr ? : strerror(errno)); - ecore_con_ssl_server_shutdown(obj); - _ecore_con_server_kill(obj); -} - -static Ecore_Con_State -svr_try_connect_plain(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - int res; - int so_err = 0; - socklen_t size = sizeof(int); - - res = getsockopt(svr->fd, SOL_SOCKET, SO_ERROR, (void *)&so_err, &size); -#ifdef _WIN32 - if (res == SOCKET_ERROR) - so_err = WSAGetLastError(); - - if ((so_err == WSAEINPROGRESS) && !svr->delete_me) - return ECORE_CON_INPROGRESS; - -#else - if (res < 0) - so_err = errno; - - if ((so_err == EINPROGRESS) && !svr->delete_me) - return ECORE_CON_INPROGRESS; - -#endif - - if (so_err) - { - /* we lost our server! */ - ecore_con_event_server_error(obj, strerror(so_err)); - DBG("Connection lost: %s", strerror(so_err)); - _ecore_con_server_kill(obj); - return ECORE_CON_DISCONNECTED; - } - - if ((!svr->delete_me) && (!svr->handshaking) && svr->connecting) - { - if (svr->ecs) - { - if (ecore_con_socks_svr_init(obj)) - return ECORE_CON_INPROGRESS; - } - else - ecore_con_event_server_add(obj); - } - - if (svr->fd_handler) - { - if (svr->buf) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); - else - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); - } - - if (!svr->delete_me) - return ECORE_CON_CONNECTED; - else - return ECORE_CON_DISCONNECTED; -} - -static const char * -_ecore_con_pretty_ip(struct sockaddr *client_addr) -{ -#ifndef HAVE_IPV6 - char ipbuf[INET_ADDRSTRLEN + 1]; -#else - char ipbuf[INET6_ADDRSTRLEN + 1]; -#endif - int family = client_addr->sa_family; - void *src; - - switch (family) - { - case AF_INET: - src = &(((struct sockaddr_in *)client_addr)->sin_addr); - break; - -#ifdef HAVE_IPV6 - case AF_INET6: - src = &(((struct sockaddr_in6 *)client_addr)->sin6_addr); - - if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)) - { - family = AF_INET; - src = (char *)src + 12; - } - break; - -#endif - default: - return eina_stringshare_add("0.0.0.0"); - } - - if (!inet_ntop(family, src, ipbuf, sizeof(ipbuf))) - return eina_stringshare_add("0.0.0.0"); - - ipbuf[sizeof(ipbuf) - 1] = 0; - return eina_stringshare_add(ipbuf); -} - -static Eina_Bool -_ecore_con_svr_tcp_handler(void *data, - Ecore_Fd_Handler *fd_handler EINA_UNUSED) -{ - Ecore_Con_Server *svr_obj = data; - Ecore_Con_Client *obj = NULL; - unsigned char client_addr[256]; - unsigned int client_addr_len; - const char *clerr = NULL; - Efl_Network_Server_Data *svr = efl_data_scope_get(svr_obj, EFL_NETWORK_SERVER_CLASS); -#ifdef _WIN32 - u_long mode = 1; -#endif - - if (svr->delete_me) - return ECORE_CALLBACK_RENEW; - - if ((svr->client_limit >= 0) && (!svr->reject_excess_clients) && - (svr->client_count >= (unsigned int)svr->client_limit)) - return ECORE_CALLBACK_RENEW; - - /* a new client */ - - obj = efl_add(EFL_NETWORK_CLIENT_CLASS, NULL); - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (!cl) - { - ecore_con_event_server_error(svr_obj, "Memory allocation failure when attempting to add a new client"); - return ECORE_CALLBACK_RENEW; - } - cl->host_server = svr_obj; - - client_addr_len = sizeof(client_addr); - memset(&client_addr, 0, client_addr_len); - cl->fd = accept(svr->fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_addr_len); -#ifdef _WIN32 - if (cl->fd == INVALID_SOCKET) goto error; -#else - if (cl->fd < 0) goto error; -#endif - if ((svr->client_limit >= 0) && (svr->reject_excess_clients) && - (svr->client_count >= (unsigned int)svr->client_limit)) - { - clerr = "Maximum client limit reached"; - goto error; - } - -#ifdef _WIN32 - if (ioctlsocket(cl->fd, FIONBIO, &mode)) goto error; -#else - if (fcntl(cl->fd, F_SETFL, O_NONBLOCK) < 0) goto error; - if (fcntl(cl->fd, F_SETFD, FD_CLOEXEC) < 0) goto error; -#endif - cl->fd_handler = ecore_main_fd_handler_add(cl->fd, ECORE_FD_READ, - _ecore_con_svr_cl_handler, obj, NULL, NULL); - if (!cl->fd_handler) goto error; - - if ((!svr->upgrade) && (svr->type & ECORE_CON_SSL)) - { - cl->handshaking = EINA_TRUE; - cl->ssl_state = ECORE_CON_SSL_STATE_INIT; - if (ecore_con_ssl_client_init(obj)) - goto error; - } - - cl->client_addr = malloc(client_addr_len); - if (!cl->client_addr) - { - clerr = "Memory allocation failure when attempting to add a new client"; - goto error; - } - cl->client_addr_len = client_addr_len; - memcpy(cl->client_addr, &client_addr, client_addr_len); - - svr->clients = eina_list_append(svr->clients, obj); - svr->client_count++; - - if ((!cl->delete_me) && (!cl->handshaking)) - ecore_con_event_client_add(obj); - - return ECORE_CALLBACK_RENEW; - -error: - if (cl->fd_handler) ecore_main_fd_handler_del(cl->fd_handler); - if (cl->fd != INVALID_SOCKET) closesocket(cl->fd); - { - Ecore_Event *ev; - - EINA_LIST_FREE(cl->event_count, ev) - { - svr->event_count = eina_list_remove(svr->event_count, ev); - ecore_event_del(ev); - } - } - efl_del(obj); - if (clerr || errno) ecore_con_event_server_error(svr_obj, clerr ? : strerror(errno)); - return ECORE_CALLBACK_RENEW; -} - -static void -_ecore_con_cl_read(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - int num = 0; - Eina_Bool lost_server = EINA_TRUE; - unsigned char buf[READBUFSIZ]; - - DBG("svr=%p", svr); - - /* only possible with non-ssl connections */ - if (svr->connecting && (svr_try_connect_plain(obj) != ECORE_CON_CONNECTED)) - return; - - if (svr->handshaking && (!svr->ecs_state)) - { - DBG("Continuing ssl handshake"); - if (!ecore_con_ssl_server_init(obj)) - lost_server = EINA_FALSE; - _ecore_con_server_timer_update(obj); - } - - if (svr->ecs_state || !(svr->type & ECORE_CON_SSL)) - { - errno = 0; - num = recv(svr->fd, (char *)buf, sizeof(buf), 0); - - /* 0 is not a valid return value for a tcp socket */ -#ifdef _WIN32 - if ((num > 0) || ((num < 0) && (WSAGetLastError() == WSAEWOULDBLOCK))) -#else - if ((num > 0) || ((num < 0) && (errno == EAGAIN))) -#endif - lost_server = EINA_FALSE; - else if (num < 0) - ecore_con_event_server_error(obj, strerror(errno)); - } - else - { - num = ecore_con_ssl_server_read(obj, buf, sizeof(buf)); - /* this is not an actual 0 return, 0 here just means non-fatal error such as EAGAIN */ - if (num >= 0) - lost_server = EINA_FALSE; - } - - if ((!svr->delete_me) && (num > 0)) - { - if (svr->ecs_state) - ecore_con_socks_read(obj, buf, num); - else - ecore_con_event_server_data(obj, buf, num, EINA_TRUE); - } - - if (lost_server) - _ecore_con_server_kill(obj); -} - -static Eina_Bool -_ecore_con_cl_handler(void *data, - Ecore_Fd_Handler *fd_handler) -{ - Ecore_Con_Server *obj = data; - Eina_Bool want_read, want_write; - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - - if (svr->delete_me) - return ECORE_CALLBACK_RENEW; - - if (svr->delete_me) - return ECORE_CALLBACK_RENEW; - - want_read = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ); - want_write = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE); - - if ((!svr->ecs_state) && svr->handshaking && (want_read || want_write)) - { - DBG("Continuing ssl handshake: preparing to %s...", want_read ? "read" : "write"); -#ifdef ISCOMFITOR - if (want_read) - { - char buf[READBUFSIZ]; - ssize_t len; - len = recv(svr->fd, (char *)buf, sizeof(buf), MSG_DONTWAIT | MSG_PEEK); - DBG("%zu bytes in buffer", len); - } -#endif - if (ecore_con_ssl_server_init(obj)) - { - DBG("ssl handshaking failed!"); - svr->handshaking = EINA_FALSE; - } - else if (!svr->ssl_state) - ecore_con_event_server_add(obj); - return ECORE_CALLBACK_RENEW; - } - if (svr->ecs && svr->ecs_state && (svr->ecs_state < ECORE_CON_PROXY_STATE_READ) && (!svr->ecs_buf)) - { - if (svr->ecs_state < ECORE_CON_PROXY_STATE_INIT) - { - INF("PROXY STATE++"); - svr->ecs_state++; - } - if (ecore_con_socks_svr_init(obj)) return ECORE_CALLBACK_RENEW; - } - if (want_read) - _ecore_con_cl_read(obj); - else if (want_write) /* only possible with non-ssl connections */ - { - if (svr->connecting && (!svr_try_connect_plain(obj)) && (!svr->ecs_state)) - return ECORE_CALLBACK_RENEW; - - _ecore_con_server_flush(obj); - } - - return ECORE_CALLBACK_RENEW; -} - -static Eina_Bool -_ecore_con_cl_udp_handler(void *data, - Ecore_Fd_Handler *fd_handler) -{ - unsigned char buf[READBUFSIZ]; - int num; - Ecore_Con_Server *obj = data; - Eina_Bool want_read, want_write; - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - - want_read = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ); - want_write = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE); - - if (svr->delete_me || ((!want_read) && (!want_write))) - return ECORE_CALLBACK_RENEW; - - if (want_write) - { - _ecore_con_server_flush(obj); - return ECORE_CALLBACK_RENEW; - } - - num = recv(svr->fd, (char *)buf, READBUFSIZ, 0); - - if ((!svr->delete_me) && (num > 0)) - ecore_con_event_server_data(obj, buf, num, EINA_TRUE); - - if (num < 0 && (errno != EAGAIN) && (errno != EINTR)) - { - ecore_con_event_server_error(obj, strerror(errno)); - _ecore_con_server_kill(obj); - } - - return ECORE_CALLBACK_RENEW; -} - -static Eina_Bool -_ecore_con_svr_udp_handler(void *data, - Ecore_Fd_Handler *fd_handler) -{ - unsigned char buf[READBUFSIZ]; - unsigned char client_addr[256]; - socklen_t client_addr_len = sizeof(client_addr); - int num; - Ecore_Con_Server *svr_obj = data; - Ecore_Con_Client *obj = NULL; -#ifdef _WIN32 - u_long mode = 1; -#endif - - Efl_Network_Server_Data *svr = efl_data_scope_get(svr_obj, EFL_NETWORK_SERVER_CLASS); - if (svr->delete_me) - return ECORE_CALLBACK_RENEW; - - if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) - return ECORE_CALLBACK_RENEW; - - if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) - return ECORE_CALLBACK_RENEW; - -#ifdef _WIN32 - if (!ioctlsocket(svr->fd, FIONBIO, &mode)) - num = recvfrom(svr->fd, (char *)buf, sizeof(buf), 0, - (struct sockaddr *)&client_addr, - &client_addr_len); - -#else - num = recvfrom(svr->fd, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *)&client_addr, - &client_addr_len); -#endif - - if (num < 0 && (errno != EAGAIN) && (errno != EINTR)) - { - ecore_con_event_server_error(svr_obj, strerror(errno)); - if (!svr->delete_me) - ecore_con_event_client_del(NULL); - _ecore_con_server_kill(svr_obj); - return ECORE_CALLBACK_CANCEL; - } - -/* Create a new client for use in the client data event */ - obj = efl_add(EFL_NETWORK_CLIENT_CLASS, NULL); - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - EINA_SAFETY_ON_NULL_RETURN_VAL(cl, ECORE_CALLBACK_RENEW); - - cl->host_server = svr_obj; - cl->fd = INVALID_SOCKET; - cl->client_addr = malloc(client_addr_len); - if (!cl->client_addr) - { - free(cl); - return ECORE_CALLBACK_RENEW; - } - cl->client_addr_len = client_addr_len; - - memcpy(cl->client_addr, &client_addr, client_addr_len); - svr->clients = eina_list_append(svr->clients, obj); - svr->client_count++; - - ecore_con_event_client_add(obj); - ecore_con_event_client_data(obj, buf, num, EINA_TRUE); - - return ECORE_CALLBACK_RENEW; -} - -static void -_ecore_con_svr_cl_read(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - int num = 0; - Eina_Bool lost_client = EINA_TRUE; - unsigned char buf[READBUFSIZ]; - - DBG("cl=%p", cl); - - if (cl->handshaking) - { - /* add an extra handshake attempt just before read, even though - * read also attempts to handshake, to try to finish sooner - */ - if (ecore_con_ssl_client_init(obj)) - lost_client = EINA_FALSE; - - _ecore_con_cl_timer_update(obj); - } - - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (!(host_server->type & ECORE_CON_SSL) && (!cl->upgrade)) - { - num = recv(cl->fd, (char *)buf, sizeof(buf), 0); - - /* 0 is not a valid return value for a tcp socket */ - if ((num > 0) || ((num < 0) && ((errno == EAGAIN) || (errno == EINTR)))) - lost_client = EINA_FALSE; - else if (num < 0) - ecore_con_event_client_error(obj, strerror(errno)); - } - else - { - num = ecore_con_ssl_client_read(obj, buf, sizeof(buf)); - /* this is not an actual 0 return, 0 here just means non-fatal error such as EAGAIN */ - if (num >= 0) - lost_client = EINA_FALSE; - } - - if ((!cl->delete_me) && (num > 0)) - ecore_con_event_client_data(obj, buf, num, EINA_TRUE); - - if (lost_client) _ecore_con_client_kill(obj); -} - -static Eina_Bool -_ecore_con_svr_cl_handler(void *data, - Ecore_Fd_Handler *fd_handler) -{ - Ecore_Con_Client *obj = data; - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - - if (cl->delete_me) - return ECORE_CALLBACK_RENEW; - - if (cl->handshaking && ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ | ECORE_FD_WRITE)) - { - if (ecore_con_ssl_client_init(obj)) - { - DBG("ssl handshaking failed!"); - _ecore_con_client_kill(obj); - return ECORE_CALLBACK_RENEW; - } - else if (!cl->ssl_state) - ecore_con_event_client_add(obj); - } - else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) - _ecore_con_svr_cl_read(obj); - - else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) - _ecore_con_client_flush(obj); - - return ECORE_CALLBACK_RENEW; -} - -static void -_ecore_con_server_flush(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - int count; - size_t num; - size_t buf_len; - size_t *buf_offset; - const unsigned char *buf; - Eina_Binbuf *buf_p; - - DBG("(svr=%p,buf=%p)", svr, svr->buf); - if (!svr->fd_handler) return; -#ifdef _WIN32 - if (ecore_con_local_win32_server_flush(obj)) - return; -#endif - - if ((!svr->buf) && (!svr->ecs_buf)) - { - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); - return; - } - - if (svr->buf) - { - buf_p = svr->buf; - buf_offset = &(svr->write_buf_offset); - } - else - { - buf_p = svr->ecs_buf; - buf_offset = &(svr->ecs_buf_offset); - } - buf = eina_binbuf_string_get(buf_p); - buf_len = eina_binbuf_length_get(buf_p); - num = buf_len - *buf_offset; - - /* check whether we need to write anything at all. - * we must not write zero bytes with SSL_write() since it - * causes undefined behaviour - */ - /* we thank Tommy[D] for needing to check negative buffer sizes - * here because his system is amazing. - */ - if (num <= 0) return; - - if ((!svr->ecs_state) && svr->handshaking) - { - DBG("Continuing ssl handshake"); - if (ecore_con_ssl_server_init(obj)) - _ecore_con_server_kill(obj); - _ecore_con_server_timer_update(obj); - return; - } - - if (svr->ecs_state || (!(svr->type & ECORE_CON_SSL))) - count = send(svr->fd, (const char *)buf + *buf_offset, num, 0); - else - count = ecore_con_ssl_server_write(obj, buf + *buf_offset, num); - -#ifdef _WIN32 - if (count == SOCKET_ERROR) - { - switch (WSAGetLastError()) - { - case WSAEINTR: - case WSAEINPROGRESS: - case WSAEWOULDBLOCK: - break; - default: - { - LPTSTR s; - - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&s, 0, NULL); - ecore_con_event_server_error(obj, (char *)s); - free(s); - _ecore_con_server_kill(obj); - } - } - } -#else - if (count < 0) - { - if ((errno != EAGAIN) && (errno != EINTR)) - { - ecore_con_event_server_error(obj, strerror(errno)); - _ecore_con_server_kill(obj); - } - return; - } -#endif - - - if (count && (!svr->ecs_state)) ecore_con_event_server_write(obj, count); - - if (!eina_binbuf_remove(buf_p, 0, count)) - *buf_offset += count; - else - { - *buf_offset = 0; - buf_len -= count; - } - if (*buf_offset >= buf_len) - { - *buf_offset = 0; - eina_binbuf_free(buf_p); - - if (svr->ecs_buf) - { - svr->ecs_buf = NULL; - INF("PROXY STATE++"); - svr->ecs_state++; - } - else - { - svr->buf = NULL; -#ifdef TCP_CORK - if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK) - { - int state = 0; - 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("uncorking failed! %s", strerror(errno)); - } -#endif - } - if (svr->fd_handler) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); - } - else if (((unsigned int)count < num) && svr->fd_handler) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); -} - -static void -_ecore_con_client_flush(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - int count = 0; - size_t num = 0; - - if (!cl->fd_handler) return; -#ifdef _WIN32 - if (ecore_con_local_win32_client_flush(obj)) - return; -#endif - - if (!cl->buf) - { - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); - return; - } - - if (cl->handshaking) - { - if (ecore_con_ssl_client_init(obj)) - count = -1; - - _ecore_con_cl_timer_update(obj); - } - - if (!count) - { - if (!cl->buf) return; - num = eina_binbuf_length_get(cl->buf) - cl->buf_offset; - if (num <= 0) return; - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (!(host_server->type & ECORE_CON_SSL) && (!cl->upgrade)) - count = send(cl->fd, (char *)eina_binbuf_string_get(cl->buf) + cl->buf_offset, num, 0); - else - count = ecore_con_ssl_client_write(obj, eina_binbuf_string_get(cl->buf) + cl->buf_offset, num); - } - - if (count < 0) - { - if ((errno != EAGAIN) && (errno != EINTR) && (!cl->delete_me)) - { - ecore_con_event_client_error(obj, strerror(errno)); - _ecore_con_client_kill(obj); - } - - return; - } - - if (count) ecore_con_event_client_write(obj, count); - cl->buf_offset += count, num -= count; - if (cl->buf_offset >= eina_binbuf_length_get(cl->buf)) - { - cl->buf_offset = 0; - eina_binbuf_free(cl->buf); - cl->buf = NULL; -#ifdef TCP_CORK - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if ((host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK) - { - int state = 0; - if (setsockopt(cl->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0) - /* realistically this isn't anything serious so we can just log and continue */ - ERR("uncorking failed! %s", strerror(errno)); - } -#endif - if (cl->fd_handler) - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); - } - else if (cl->fd_handler) - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE); -} - -static void -_ecore_con_event_client_add_free(Ecore_Con_Server *obj, - void *ev) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Event_Client_Add *e; - - e = ev; - if (e->client) - { - Efl_Network_Client_Data *cl = efl_data_scope_get(e->client, EFL_NETWORK_CLIENT_CLASS); - Eina_Bool svrfreed = EINA_FALSE; - - if ((svr) && (cl)) - { - cl->event_count = eina_list_remove(cl->event_count, e); - if (cl->host_server) - { - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (host_server) - host_server->event_count = eina_list_remove(host_server->event_count, ev); - if ((!svr->event_count) && (svr->delete_me)) - { - _ecore_con_server_free(obj); - svrfreed = EINA_TRUE; - } - } - if (!svrfreed) - { - if ((!cl->event_count) && (cl->delete_me)) - ecore_con_client_del(e->client); - } - } - } - - ecore_con_event_client_add_free(e); - _ecore_con_event_count--; - if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) - ecore_con_mempool_shutdown(); -} - -static void -_ecore_con_event_client_del_free(Ecore_Con_Server *obj, - void *ev) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Event_Client_Del *e; - - e = ev; - if (e->client) - { - Efl_Network_Client_Data *cl = efl_data_scope_get(e->client, EFL_NETWORK_CLIENT_CLASS); - Eina_Bool svrfreed = EINA_FALSE; - - if ((svr) && (cl)) - { - cl->event_count = eina_list_remove(cl->event_count, e); - if (cl->host_server) - { - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (host_server) - host_server->event_count = eina_list_remove(host_server->event_count, ev); - if ((!svr->event_count) && (svr->delete_me)) - { - _ecore_con_server_free(obj); - svrfreed = EINA_TRUE; - } - } - if (!svrfreed) - { - if (!cl->event_count) - _ecore_con_client_free(e->client); - } - } - } - ecore_con_event_client_del_free(e); - _ecore_con_event_count--; - if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) - ecore_con_mempool_shutdown(); -} - -static void -_ecore_con_event_client_write_free(Ecore_Con_Server *obj, - Ecore_Con_Event_Client_Write *e) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (e->client) - { - Efl_Network_Client_Data *cl = efl_data_scope_get(e->client, EFL_NETWORK_CLIENT_CLASS); - Eina_Bool svrfreed = EINA_FALSE; - - if ((svr) && (cl)) - { - cl->event_count = eina_list_remove(cl->event_count, e); - if (cl->host_server) - { - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (host_server) - host_server->event_count = eina_list_remove(host_server->event_count, e); - if ((!svr->event_count) && (svr->delete_me)) - { - _ecore_con_server_free(obj); - svrfreed = EINA_TRUE; - } - } - if (!svrfreed) - { - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (((!cl->event_count) && (cl->delete_me)) || - ((cl->host_server && - ((host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP || - (host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_MCAST)))) - ecore_con_client_del(e->client); - } - } - } - ecore_con_event_client_write_free(e); - _ecore_con_event_count--; - if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) - ecore_con_mempool_shutdown(); -} - -static void -_ecore_con_event_client_data_free(Ecore_Con_Server *obj, - void *ev) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - Ecore_Con_Event_Client_Data *e; - - e = ev; - if (e->client) - { - Efl_Network_Client_Data *cl = efl_data_scope_get(e->client, EFL_NETWORK_CLIENT_CLASS); - Eina_Bool svrfreed = EINA_FALSE; - - if ((svr) && (cl)) - { - cl->event_count = eina_list_remove(cl->event_count, e); - if (cl->host_server) - { - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (host_server) - host_server->event_count = eina_list_remove(host_server->event_count, ev); - } - if ((!svr->event_count) && (svr->delete_me)) - { - _ecore_con_server_free(obj); - svrfreed = EINA_TRUE; - } - if (!svrfreed) - { - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (((!cl->event_count) && (cl->delete_me)) || - ((cl->host_server && - ((host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP || - (host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_MCAST)))) - ecore_con_client_del(e->client); - } - } - } - free(e->data); - ecore_con_event_client_data_free(e); - _ecore_con_event_count--; - if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) - ecore_con_mempool_shutdown(); -} - -static void -_ecore_con_event_server_add_free(void *data EINA_UNUSED, - void *ev) -{ - Ecore_Con_Event_Server_Add *e; - - e = ev; - if (e->server) - { - Efl_Network_Server_Data *svr = efl_data_scope_get(e->server, EFL_NETWORK_SERVER_CLASS); - if (svr) - { - svr->event_count = eina_list_remove(svr->event_count, ev); - if ((!svr->event_count) && (svr->delete_me)) - _ecore_con_server_free(e->server); - } - } - ecore_con_event_server_add_free(e); - _ecore_con_event_count--; - if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) - ecore_con_mempool_shutdown(); -} - -static void -_ecore_con_event_server_del_free(void *data EINA_UNUSED, - void *ev) -{ - Ecore_Con_Event_Server_Del *e; - - e = ev; - if (e->server) - { - Efl_Network_Server_Data *svr = efl_data_scope_get(e->server, EFL_NETWORK_SERVER_CLASS); - if (svr) - { - svr->event_count = eina_list_remove(svr->event_count, ev); - if (!svr->event_count) - _ecore_con_server_free(e->server); - } - } - ecore_con_event_server_del_free(e); - _ecore_con_event_count--; - if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) - ecore_con_mempool_shutdown(); -} - -static void -_ecore_con_event_server_write_free(void *data EINA_UNUSED, - Ecore_Con_Event_Server_Write *e) -{ - if (e->server) - { - Efl_Network_Server_Data *svr = efl_data_scope_get(e->server, EFL_NETWORK_SERVER_CLASS); - if (svr) - { - svr->event_count = eina_list_remove(svr->event_count, e); - if ((!svr->event_count) && (svr->delete_me)) - _ecore_con_server_free(e->server); - } - } - ecore_con_event_server_write_free(e); - _ecore_con_event_count--; - if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) - ecore_con_mempool_shutdown(); -} - -static void -_ecore_con_event_server_data_free(void *data EINA_UNUSED, - void *ev) -{ - Ecore_Con_Event_Server_Data *e; - - e = ev; - if (e->server) - { - Efl_Network_Server_Data *svr = efl_data_scope_get(e->server, EFL_NETWORK_SERVER_CLASS); - if (svr) - { - svr->event_count = eina_list_remove(svr->event_count, ev); - if ((!svr->event_count) && (svr->delete_me)) - _ecore_con_server_free(e->server); - } - } - - free(e->data); - ecore_con_event_server_data_free(e); - _ecore_con_event_count--; - if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) - ecore_con_mempool_shutdown(); -} - -static void -_ecore_con_event_server_error_free(void *data EINA_UNUSED, Ecore_Con_Event_Server_Error *e) -{ - if (e->server) - { - Efl_Network_Server_Data *svr = efl_data_scope_get(e->server, EFL_NETWORK_SERVER_CLASS); - if (svr) - { - svr->event_count = eina_list_remove(svr->event_count, e); - if ((!svr->event_count) && (svr->delete_me)) - _ecore_con_server_free(e->server); - } - } - free(e->error); - ecore_con_event_server_error_free(e); - _ecore_con_event_count--; - if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) - ecore_con_mempool_shutdown(); -} - -static void -_ecore_con_event_client_error_free(Ecore_Con_Server *obj, Ecore_Con_Event_Client_Error *e) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (e->client) - { - Efl_Network_Client_Data *cl = efl_data_scope_get(e->client, EFL_NETWORK_CLIENT_CLASS); - Eina_Bool svrfreed = EINA_FALSE; - - if ((svr) && (cl)) - { - if (eina_list_data_find(svr->clients, e->client)) - { - cl->event_count = eina_list_remove(cl->event_count, e); - if ((!cl->event_count) && (cl->delete_me)) - { - _ecore_con_client_free(e->client); - svrfreed = EINA_TRUE; - } - } - svr->event_count = eina_list_remove(svr->event_count, e); - if (!svrfreed) - { - if ((!svr->event_count) && (svr->delete_me)) - _ecore_con_server_free(obj); - } - } - } - free(e->error); - ecore_con_event_client_error_free(e); - _ecore_con_event_count--; - if ((!_ecore_con_event_count) && (!_ecore_con_init_count)) - ecore_con_mempool_shutdown(); -} - -static void -_ecore_con_lookup_done(void *data, - Ecore_Con_Info *infos) -{ - Ecore_Con_Server *obj = data; - Ecore_Con_Lookup *lk; - - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) return; - lk = svr->data; - - if (infos) - lk->done_cb(infos->info.ai_canonname, infos->ip, - infos->info.ai_addr, infos->info.ai_addrlen, - (void *)lk->data); - else - lk->done_cb(NULL, NULL, NULL, 0, (void *)lk->data); - - free(lk); -} - -#include "efl_network.eo.c" -#include "efl_network_client.eo.c" -#include "efl_network_server.eo.c" -#include "efl_network_connector.eo.c" #ifndef _WIN32 Eina_Bool diff --git a/src/lib/ecore_con/ecore_con_alloc.c b/src/lib/ecore_con/ecore_con_alloc.c index 1c04a557bc..b5d49b9486 100644 --- a/src/lib/ecore_con/ecore_con_alloc.c +++ b/src/lib/ecore_con/ecore_con_alloc.c @@ -35,7 +35,9 @@ GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Del, ecore_con_event_client_del); GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Write, ecore_con_event_client_write); GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Data, ecore_con_event_client_data); GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Error, ecore_con_event_server_error); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Upgrade, ecore_con_event_server_upgrade); GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Error, ecore_con_event_client_error); +GENERIC_ALLOC_FREE(Ecore_Con_Event_Client_Upgrade, ecore_con_event_client_upgrade); GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Add, ecore_con_event_server_add); GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Del, ecore_con_event_server_del); GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Write, ecore_con_event_server_write); @@ -48,7 +50,9 @@ static Ecore_Con_Mempool *mempool_array[] = { &ecore_con_event_client_write_mp, &ecore_con_event_client_data_mp, &ecore_con_event_server_error_mp, + &ecore_con_event_server_upgrade_mp, &ecore_con_event_client_error_mp, + &ecore_con_event_client_upgrade_mp, &ecore_con_event_server_add_mp, &ecore_con_event_server_del_mp, &ecore_con_event_server_write_mp, diff --git a/src/lib/ecore_con/ecore_con_eet.c b/src/lib/ecore_con/ecore_con_eet.c index 1cf9954ebc..aed9b9fc11 100644 --- a/src/lib/ecore_con/ecore_con_eet.c +++ b/src/lib/ecore_con/ecore_con_eet.c @@ -17,6 +17,9 @@ #include +#include "Ecore.h" +#include "Ecore_Con.h" +#include "ecore_con_private.h" #include "Ecore_Con_Eet.h" #define ECORE_CON_EET_RAW_MAGIC 0xDEAD007 @@ -699,7 +702,7 @@ _ecore_con_eet_base_efl_object_finalize(Eo *obj, Ecore_Con_Eet_Base_Data *pd) EOLIAN static void _ecore_con_eet_base_server_set(Eo *obj EINA_UNUSED, Ecore_Con_Eet_Base_Data *pd, Ecore_Con_Server *data) { - if (!efl_isa(data, EFL_NETWORK_SERVER_CLASS)) + if (!ecore_con_server_check(data)) return; pd->server = data; diff --git a/src/lib/ecore_con/ecore_con_eet_base.eo b/src/lib/ecore_con/ecore_con_eet_base.eo index fcbc83574f..9f57ea6e18 100644 --- a/src/lib/ecore_con/ecore_con_eet_base.eo +++ b/src/lib/ecore_con/ecore_con_eet_base.eo @@ -1,5 +1,4 @@ -import efl_network_server; - +struct @extern Ecore_Con_Server; type @extern Ecore_Con_Eet_Data_Cb: __undefined_type; [[Ecore connection eet data callback type]] /* FIXME: function pointers not supported. */ type @extern Ecore_Con_Eet_Raw_Data_Cb: __undefined_type; [[Ecore connection eet raw data callback type]]/* FIXME: function pointers not supported. */ @@ -19,7 +18,7 @@ class Ecore.Con.Eet.Base (Efl.Object) { get { } values { - data: Efl.Network.Server; [[Server object]] + data: ptr(Ecore_Con_Server); [[Server object]] } } @property data_callback { diff --git a/src/lib/ecore_con/ecore_con_info.c b/src/lib/ecore_con/ecore_con_info.c deleted file mode 100644 index 5038817c61..0000000000 --- a/src/lib/ecore_con/ecore_con_info.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * getaddrinfo with callback - * - * man getaddrinfo - * - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif - -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef __OpenBSD__ -# include -#endif -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_ARPA_INET_H -# include -#endif -#ifdef HAVE_ARPA_NAMESER_H -# include -#endif -#ifdef HAVE_NETDB_H -# include -#endif - -#include - -#include "Ecore.h" -#include "ecore_private.h" -#include "ecore_con_private.h" - -typedef struct _CB_Data CB_Data; - -struct _CB_Data -{ - EINA_INLIST; - Ecore_Con_Info_Cb cb_done; - void *data; - Ecore_Thread *thread; - struct addrinfo hints; - Ecore_Con_Info *result; - int error; - char service[NI_MAXSERV]; - char name[NI_MAXHOST]; -}; - -static void _ecore_con_info_slave_free (CB_Data *cbdata); -static void _ecore_con_info_slave_result(void *data, Ecore_Thread *th); -static void _ecore_con_info_slave_cancel(void *data, Ecore_Thread *th); -static void _ecore_con_info_slave_lookup(void *data, Ecore_Thread *th); - -static int info_init = 0; -static CB_Data *info_slaves = NULL; - -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) - { - CB_Data *cbdata; - - cbdata = info_slaves; - info_slaves = (CB_Data *)eina_inlist_remove - (EINA_INLIST_GET(info_slaves), EINA_INLIST_GET(info_slaves)); - ecore_thread_cancel(cbdata->thread); - } - } - return info_init; -} - -static void -_hints_fill(struct addrinfo *hints, int flags, int proto) -{ - memset(hints, 0, sizeof(struct addrinfo)); - hints->ai_family = AF_UNSPEC; - hints->ai_flags = flags; - if (proto == IPPROTO_TCP) hints->ai_socktype = SOCK_STREAM; - else hints->ai_socktype = SOCK_DGRAM; - hints->ai_protocol = proto; -} - -int -ecore_con_info_tcp_connect(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data) -{ - struct addrinfo hints; - _hints_fill(&hints, AI_CANONNAME, IPPROTO_TCP); - return ecore_con_info_get(svr, done_cb, data, &hints); -} - -int -ecore_con_info_tcp_listen(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data) -{ - struct addrinfo hints; - _hints_fill(&hints, AI_PASSIVE, IPPROTO_TCP); - return ecore_con_info_get(svr, done_cb, data, &hints); -} - -int -ecore_con_info_udp_connect(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data) -{ - struct addrinfo hints; - _hints_fill(&hints, AI_CANONNAME, IPPROTO_UDP); - return ecore_con_info_get(svr, done_cb, data, &hints); -} - -int -ecore_con_info_udp_listen(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data) -{ - struct addrinfo hints; - _hints_fill(&hints, AI_PASSIVE, IPPROTO_UDP); - return ecore_con_info_get(svr, done_cb, data, &hints); -} - -int -ecore_con_info_mcast_listen(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data) -{ - struct addrinfo hints; - _hints_fill(&hints, 0, IPPROTO_UDP); - return ecore_con_info_get(svr, done_cb, data, &hints); -} - -EAPI int -ecore_con_info_get(Ecore_Con_Server *obj, - Ecore_Con_Info_Cb done_cb, - void *data, - struct addrinfo *hints) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - CB_Data *cbdata; - - if (!svr) return 0; - cbdata = calloc(1, sizeof(CB_Data)); - if (!cbdata) - { - ecore_con_event_server_error(obj, "Memory allocation failure"); - return 0; - } - - cbdata->cb_done = done_cb; - cbdata->data = data; - cbdata->hints = *hints; - cbdata->thread = ecore_thread_run(_ecore_con_info_slave_lookup, - _ecore_con_info_slave_result, - _ecore_con_info_slave_cancel, - cbdata); - if (!cbdata->thread) - { - free(cbdata); - ecore_con_event_server_error(obj, "Memory allocation failure"); - return 0; - } - eina_convert_itoa(svr->ecs ? svr->ecs->port : svr->port, cbdata->service); - strncpy(cbdata->name, svr->ecs ? svr->ecs->ip : svr->name, NI_MAXHOST - 1); - cbdata->name[NI_MAXHOST - 1] = 0; - info_slaves = (CB_Data *)eina_inlist_append(EINA_INLIST_GET(info_slaves), - EINA_INLIST_GET(cbdata)); - svr->infos = eina_list_append(svr->infos, cbdata); - return 1; -} - -void -ecore_con_info_data_clear(void *info) -{ - CB_Data *cbdata = info; - cbdata->data = NULL; -} - -static void -_ecore_con_info_slave_free(CB_Data *cbdata) -{ - if (info_slaves) - info_slaves = (CB_Data *)eina_inlist_remove(EINA_INLIST_GET(info_slaves), - EINA_INLIST_GET(cbdata)); - if (cbdata->result) free(cbdata->result); - cbdata->result = NULL; - if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata); - cbdata->data = NULL; - free(cbdata); -} - -static void -_ecore_con_info_slave_result(void *data, Ecore_Thread *th EINA_UNUSED) -{ - CB_Data *cbdata = data; - - if (cbdata->result) // lookup ok - { - if (cbdata->data) cbdata->cb_done(cbdata->data, cbdata->result); - } - else // an error occured - { - if (cbdata->data) - { - char *str = strerror(cbdata->error); - ecore_con_event_server_error(cbdata->data, str); - cbdata->cb_done(cbdata->data, NULL); - } - } - if (cbdata->data) ecore_con_server_infos_del(cbdata->data, cbdata); - cbdata->data = NULL; - _ecore_con_info_slave_free(cbdata); -} - -static void -_ecore_con_info_slave_cancel(void *data, Ecore_Thread *th EINA_UNUSED) -{ - CB_Data *cbdata = data; - _ecore_con_info_slave_free(cbdata); -} - -static void -_ecore_con_info_slave_lookup(void *data, Ecore_Thread *th EINA_UNUSED) -{ - CB_Data *cbdata = data; - struct addrinfo *result = NULL; - - // do lookup, fill cbdata - if ((!getaddrinfo(cbdata->name, cbdata->service, &(cbdata->hints), &result)) - && (result)) - { - Ecore_Con_Info *info; - unsigned int canonname_size = 0, size; - - if (result->ai_canonname) - canonname_size = strlen(result->ai_canonname) + 1; - size = sizeof(Ecore_Con_Info) + result->ai_addrlen + canonname_size; - info = calloc(1, size); - if (info) - { - char hbuf[NI_MAXHOST] = { 0 }, sbuf[NI_MAXSERV] = { 0 }, *p; - - info->size = size; - memcpy(&(info->info), result, sizeof(struct addrinfo)); - p = ((char *)info) + sizeof(Ecore_Con_Info); - memcpy(p, result->ai_addr, result->ai_addrlen); - info->info.ai_addr = (struct sockaddr *)p; - if (result->ai_canonname) - { - p = ((char *)info) + sizeof(Ecore_Con_Info) + result->ai_addrlen; - memcpy(p, result->ai_canonname, canonname_size); - info->info.ai_canonname = p; - } - // we don't care about multiple entries - take first one then - info->info.ai_next = NULL; - if (!getnameinfo(result->ai_addr, result->ai_addrlen, - hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), - NI_NUMERICHOST | NI_NUMERICSERV)) - { - memcpy(info->ip, hbuf, sizeof(info->ip)); - memcpy(info->service, sbuf, sizeof(info->service)); - } - cbdata->result = info; - } - if (!cbdata->result) free(info); - } - if (!cbdata->result) cbdata->error = errno; - if (result) freeaddrinfo(result); -} diff --git a/src/lib/ecore_con/ecore_con_legacy.c b/src/lib/ecore_con/ecore_con_legacy.c index 107ccfd41f..cf2210faa8 100644 --- a/src/lib/ecore_con/ecore_con_legacy.c +++ b/src/lib/ecore_con/ecore_con_legacy.c @@ -1,15 +1,2516 @@ -/******************************************************************** - * ecore_con_url.eo.c - *******************************************************************/ -EAPI Eina_Bool -ecore_con_url_url_set(Ecore_Con_Url *obj, const char *url) +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_ARPA_INET_H +# include +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include "Ecore.h" +#include "ecore_private.h" +#include "Ecore_Con.h" +#include "ecore_con_private.h" + +#define ECORE_CON_TYPE 0x0f +#define ECORE_CON_SSL 0xf0 +#define ECORE_CON_SUPER_SSL 0xf00 + +/* This file exists solely to provide ABI compatibility */ + +struct _Ecore_Con_Server { - return efl_network_url_set((Ecore_Con_Url *)obj, url); + ECORE_MAGIC; + Eo *dialer; + Eo *server; + struct { + Efl_Future *job; + Eo *clients_ctx; + Eina_List *certs; + Eina_List *privkeys; + Eina_List *crls; + Eina_List *cafiles; + Eina_Stringshare *verify_name; + Eina_Bool verify; + Eina_Bool verify_basic; + Eina_Bool upgrading; + Ecore_Con_Type upgrade_type; + } ssl; + Eina_List *clients; + Eina_List *event_count; + const void *data; + Eina_Stringshare *name; + Eina_Stringshare *ip; + size_t pending_write; + double start_time; + double timeout; + Ecore_Con_Type type; + int port; + Eina_Bool want_mcast; + Eina_Bool is_dialer; + Eina_Bool connecting; + Eina_Bool delete_me; +}; + +struct _Ecore_Con_Client +{ + ECORE_MAGIC; + Eo *socket; + Ecore_Con_Server *svr; + Eina_List *event_count; + const void *data; + Eina_Stringshare *ip; + struct { + Efl_Future *job; + Eo *ctx; + Eina_Bool upgrading; + } ssl; + size_t pending_write; + double start_time; + int port; + Eina_Bool delete_me; +}; + +typedef struct _Ecore_Con_Lookup_Ctx { + Ecore_Thread *thread; + Ecore_Con_Dns_Cb cb; + const void *data; +} Ecore_Con_Lookup_Ctx; + +/* allows delete_me to be true */ +#define ECORE_CON_SERVER_CHECK_RELAXED_RETURN(svr, ...) \ + do \ + { \ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) \ + { \ + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __FUNCTION__); \ + return __VA_ARGS__; \ + } \ + } \ + while (0) + +#define ECORE_CON_SERVER_CHECK_RETURN(svr, ...) \ + do \ + { \ + ECORE_CON_SERVER_CHECK_RELAXED_RETURN(svr, __VA_ARGS__) ; \ + EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->delete_me, __VA_ARGS__); \ + } \ + while (0) + +#define ECORE_CON_CLIENT_CHECK_RELAXED_RETURN(cl, ...) \ + do \ + { \ + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) \ + { \ + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, __FUNCTION__); \ + return __VA_ARGS__; \ + } \ + } \ + while (0) + +#define ECORE_CON_CLIENT_CHECK_RETURN(cl, ...) \ + do \ + { \ + ECORE_CON_CLIENT_CHECK_RELAXED_RETURN(cl, __VA_ARGS__) ; \ + EINA_SAFETY_ON_TRUE_RETURN_VAL(cl->delete_me, __VA_ARGS__); \ + } \ + while (0) + + +/* from ecore_con_alloc.c */ +#define GENERIC_ALLOC_FREE_HEADER(TYPE, Type) \ + TYPE *Type##_alloc(void); \ + void Type##_free(TYPE *e); + +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Add, ecore_con_event_client_add); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Del, ecore_con_event_client_del); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Add, ecore_con_event_server_add); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Del, ecore_con_event_server_del); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Write, ecore_con_event_server_write); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Data, ecore_con_event_server_data); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Error, ecore_con_event_server_error); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Upgrade, ecore_con_event_server_upgrade); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Proxy_Bind, ecore_con_event_proxy_bind); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Write, ecore_con_event_client_write); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Data, ecore_con_event_client_data); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Error, ecore_con_event_client_error); +GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Upgrade, ecore_con_event_client_upgrade); +#undef GENERIC_ALLOC_FREE_HEADER + +/* shared */ +EAPI int ECORE_CON_EVENT_SERVER_DEL = 0; +EAPI int ECORE_CON_EVENT_SERVER_ERROR = 0; +/* ecore_con_server_add() */ +EAPI int ECORE_CON_EVENT_CLIENT_ADD = 0; +EAPI int ECORE_CON_EVENT_CLIENT_DEL = 0; +/* ecore_con_server_connect() */ +EAPI int ECORE_CON_EVENT_SERVER_ADD = 0; +EAPI int ECORE_CON_EVENT_SERVER_DATA = 0; +EAPI int ECORE_CON_EVENT_SERVER_WRITE = 0; +EAPI int ECORE_CON_EVENT_PROXY_BIND = 0; /* we're not supporting proxy bind, keep only for ABI */ +EAPI int ECORE_CON_EVENT_SERVER_UPGRADE = 0; +/* for each client from ECORE_CON_EVENT_CLIENT_ADD */ +EAPI int ECORE_CON_EVENT_CLIENT_DATA = 0; +EAPI int ECORE_CON_EVENT_CLIENT_WRITE = 0; +EAPI int ECORE_CON_EVENT_CLIENT_ERROR = 0; +EAPI int ECORE_CON_EVENT_CLIENT_UPGRADE = 0; + +static Eina_List *_servers = NULL; +static Eina_List *_ecore_con_lookups = NULL; +static int _ecore_con_event_count = 0; + +Ecore_Con_Socks *_ecore_con_proxy_once = NULL; +Ecore_Con_Socks *_ecore_con_proxy_global = NULL; + +void +ecore_con_legacy_init(void) +{ + 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(); + ECORE_CON_EVENT_SERVER_UPGRADE = ecore_event_type_new(); + ECORE_CON_EVENT_CLIENT_UPGRADE = 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"); + + ecore_con_socks_init(); +} + +static void _ecore_con_server_free(Ecore_Con_Server *svr); + +void +ecore_con_legacy_shutdown(void) +{ + Eina_List *l, *l2; + Ecore_Con_Server *svr; + Ecore_Con_Lookup_Ctx *lookup_ctx; + + EINA_LIST_FOREACH_SAFE(_servers, l, l2, svr) + { + Ecore_Con_Event_Server_Add *ev; + + if (!svr) continue; + 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); + } + + EINA_LIST_FREE(_ecore_con_lookups, lookup_ctx) + ecore_thread_cancel(lookup_ctx->thread); + + ecore_con_socks_shutdown(); + if (!_ecore_con_event_count) ecore_con_mempool_shutdown(); + else WRN("%d events still exist, leaking ecore_con mempools", _ecore_con_event_count); +} + +/** + * @addtogroup Ecore_Con_Client_Group Ecore Connection Client Functions + * + * Functions that operate on Ecore connection client objects, these + * are announced using ECORE_CON_EVENT_CLIENT_ADD by servers created + * with ecore_con_server_add(). + * + * @{ + */ + +static Efl_Callback_Array_Item *_ecore_con_client_socket_cbs(void); +static Efl_Callback_Array_Item *_ecore_con_client_socket_ssl_cbs(void); + +static void +_ecore_con_client_socket_close(Ecore_Con_Client *cl) +{ + if (!cl->socket) return; + + /* socket may remain alive due other references, we don't own it */ + efl_event_callback_array_del(cl->socket, _ecore_con_client_socket_cbs(), cl); + + if (!efl_io_closer_closed_get(cl->socket)) + efl_io_closer_close(cl->socket); +} + +static void +_ecore_con_client_free(Ecore_Con_Client *cl) +{ + cl->delete_me = EINA_TRUE; + + if (cl->svr) + cl->svr->clients = eina_list_remove(cl->svr->clients, cl); + + _ecore_con_client_socket_close(cl); + + if (cl->socket) + { + Eo *inner_socket = efl_io_buffered_stream_inner_io_get(cl->socket); + efl_event_callback_array_del(cl->socket, _ecore_con_client_socket_cbs(), cl); + if (efl_isa(inner_socket, EFL_NET_SOCKET_SSL_CLASS)) + efl_event_callback_array_del(inner_socket, _ecore_con_client_socket_ssl_cbs(), cl); + + if (efl_parent_get(cl->socket) != cl->svr->server) + efl_del(cl->socket); /* we own it */ + else + efl_unref(cl->socket); + cl->socket = NULL; + } + + if (cl->ssl.job) efl_future_cancel(cl->ssl.job); + + if (cl->ssl.ctx) + { + efl_unref(cl->ssl.ctx); + cl->ssl.ctx = NULL; + } + + if (cl->event_count) return; + + cl->data = NULL; + eina_stringshare_replace(&cl->ip, NULL); + + EINA_MAGIC_SET(cl, ECORE_MAGIC_NONE); + free(cl); +} + +/* BEGIN: post of Ecore_Event for ecore_con_server_connect() ************/ + +static void +_ecore_con_free_event_client_add(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Client_Add *ev = event; + + if (ev->client) + { + Ecore_Con_Client *cl = ev->client; + cl->event_count = eina_list_remove(cl->event_count, ev); + if ((!cl->event_count) && (cl->delete_me)) + _ecore_con_client_free(cl); + } + ecore_con_event_client_add_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_client_add(Ecore_Con_Client *cl) +{ + Ecore_Con_Event_Client_Add *ev = ecore_con_event_client_add_alloc(); + EINA_SAFETY_ON_NULL_GOTO(ev, error); + + ev->client = cl; + cl->event_count = eina_list_append(cl->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_CLIENT_ADD, ev, _ecore_con_free_event_client_add, NULL); + _ecore_con_event_count++; + return; + + error: + _ecore_con_client_free(cl); +} + +static void +_ecore_con_free_event_client_del(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Client_Del *ev = event; + + if (ev->client) + { + Ecore_Con_Client *cl = ev->client; + cl->event_count = eina_list_remove(cl->event_count, ev); + if (!cl->event_count) + _ecore_con_client_free(cl); + else + cl->delete_me = EINA_TRUE; + } + ecore_con_event_client_del_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_client_del(Ecore_Con_Client *cl) +{ + Ecore_Con_Event_Client_Del *ev = ecore_con_event_client_del_alloc(); + EINA_SAFETY_ON_NULL_GOTO(ev, error); + + ev->client = cl; + cl->event_count = eina_list_append(cl->event_count, ev); + + /* legacy compatibility: test suite expects NULL pointer for IP */ + eina_stringshare_replace(&cl->ip, NULL); + + ecore_event_add(ECORE_CON_EVENT_CLIENT_DEL, ev, _ecore_con_free_event_client_del, NULL); + _ecore_con_event_count++; + return; + + error: + _ecore_con_client_free(cl); +} + +static void +_ecore_con_free_event_client_data(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Client_Data *ev = event; + + if (ev->client) + { + Ecore_Con_Client *cl = ev->client; + cl->event_count = eina_list_remove(cl->event_count, ev); + if ((!cl->event_count) && (cl->delete_me)) + _ecore_con_client_free(cl); + } + free(ev->data); + ecore_con_event_client_data_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_client_data(Ecore_Con_Client *cl, Eina_Rw_Slice slice) +{ + Ecore_Con_Event_Client_Data *ev = ecore_con_event_client_data_alloc(); + EINA_SAFETY_ON_NULL_GOTO(ev, error); + + ev->client = cl; + ev->data = slice.mem; + ev->size = slice.len; + cl->event_count = eina_list_append(cl->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_CLIENT_DATA, ev, _ecore_con_free_event_client_data, NULL); + _ecore_con_event_count++; + return; + + error: + free(slice.mem); +} + +static void +_ecore_con_free_event_client_write(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Client_Write *ev = event; + + if (ev->client) + { + Ecore_Con_Client *cl = ev->client; + cl->event_count = eina_list_remove(cl->event_count, ev); + if ((!cl->event_count) && (cl->delete_me)) + _ecore_con_client_free(cl); + } + ecore_con_event_client_write_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_client_write(Ecore_Con_Client *cl, size_t size) +{ + Ecore_Con_Event_Client_Write *ev = ecore_con_event_client_write_alloc(); + EINA_SAFETY_ON_NULL_RETURN(ev); + + ev->client = cl; + ev->size = size; + cl->event_count = eina_list_append(cl->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_CLIENT_WRITE, ev, _ecore_con_free_event_client_write, NULL); + _ecore_con_event_count++; +} + +static void +_ecore_con_free_event_client_error(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Client_Error *ev = event; + + if (ev->client) + { + Ecore_Con_Client *cl = ev->client; + cl->event_count = eina_list_remove(cl->event_count, ev); + if ((!cl->event_count) && (cl->delete_me)) + _ecore_con_client_free(cl); + } + free(ev->error); + ecore_con_event_client_error_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_client_error(Ecore_Con_Client *cl, const char *err) +{ + Ecore_Con_Event_Client_Error *ev = ecore_con_event_client_error_alloc(); + EINA_SAFETY_ON_NULL_GOTO(ev, error); + + INF("cl=%p error from %s: %s", cl, efl_net_socket_address_remote_get(cl->socket), err); + + ev->client = cl; + ev->error = err ? strdup(err) : NULL; + cl->event_count = eina_list_append(cl->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_CLIENT_ERROR, ev, _ecore_con_free_event_client_error, NULL); + _ecore_con_event_count++; + return; + + error: + _ecore_con_client_free(cl); +} + +static void +_ecore_con_free_event_client_upgrade(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Client_Upgrade *ev = event; + + if (ev->client) + { + Ecore_Con_Client *cl = ev->client; + cl->event_count = eina_list_remove(cl->event_count, ev); + if ((!cl->event_count) && (cl->delete_me)) + _ecore_con_client_free(cl); + } + ecore_con_event_client_upgrade_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_client_upgrade(Ecore_Con_Client *cl) +{ + Ecore_Con_Event_Client_Upgrade *ev = ecore_con_event_client_upgrade_alloc(); + EINA_SAFETY_ON_NULL_GOTO(ev, error); + + ev->client = cl; + cl->event_count = eina_list_append(cl->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_CLIENT_UPGRADE, ev, _ecore_con_free_event_client_upgrade, NULL); + _ecore_con_event_count++; + return; + + error: + _ecore_con_client_free(cl); +} + +/* END: post of Ecore_Event for ecore_con_server_add() ******************/ + +static void +_ecore_con_client_socket_progress(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Client *cl = data; + size_t now = efl_io_buffered_stream_pending_write_get(cl->socket); + + if (cl->delete_me) return; + if (cl->ssl.upgrading) return; + + if (cl->pending_write == now) return; + EINA_SAFETY_ON_TRUE_GOTO(cl->pending_write < now, end); /* forgot to update! */ + + _ecore_con_post_event_client_write(cl, cl->pending_write - now); + + end: + cl->pending_write = now; +} + +static void +_ecore_con_client_socket_slice_changed(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Client *cl = data; + Eina_Slice ro_slice; + Eina_Rw_Slice rw_slice; + + if (cl->delete_me) return; + if (cl->ssl.upgrading) return; + + if (!efl_io_buffered_stream_slice_get(cl->socket, &ro_slice)) return; + if (ro_slice.len == 0) return; + + rw_slice = eina_slice_dup(ro_slice); + efl_io_buffered_stream_clear(cl->socket); + _ecore_con_post_event_client_data(cl, rw_slice); +} + +static void +_ecore_con_client_socket_finished(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Client *cl = data; + + DBG("client %p socket %p finished", cl, cl->socket); + + _ecore_con_client_socket_close(cl); + + _ecore_con_post_event_client_del(cl); +} + +static void +_ecore_con_client_socket_error(void *data, const Efl_Event *event) +{ + Ecore_Con_Client *cl = data; + Eina_Error *perr = event->info; + + if (cl->delete_me) return; + + WRN("error client %s: %s", efl_net_socket_address_remote_get(cl->socket), eina_error_msg_get(*perr)); + + _ecore_con_post_event_client_error(cl, eina_error_msg_get(*perr)); + _ecore_con_client_socket_close(cl); +} + +EFL_CALLBACKS_ARRAY_DEFINE(_ecore_con_client_socket_cbs, + { EFL_IO_BUFFERED_STREAM_EVENT_PROGRESS, _ecore_con_client_socket_progress }, + { EFL_IO_BUFFERED_STREAM_EVENT_SLICE_CHANGED, _ecore_con_client_socket_slice_changed }, + { EFL_IO_BUFFERED_STREAM_EVENT_FINISHED, _ecore_con_client_socket_finished }, + { EFL_IO_BUFFERED_STREAM_EVENT_ERROR, _ecore_con_client_socket_error }); + +static Ecore_Con_Client * +ecore_con_client_add(Ecore_Con_Server *svr, Eo *socket) +{ + Ecore_Con_Client *cl; + Eo *inner_socket; + + cl = calloc(1, sizeof(Ecore_Con_Client)); + EINA_SAFETY_ON_NULL_RETURN_VAL(cl, NULL); + + cl->socket = efl_ref(socket); + cl->svr = svr; + cl->start_time = ecore_time_get(); + cl->port = -1; + + inner_socket = efl_io_buffered_stream_inner_io_get(socket); + if (efl_isa(inner_socket, EFL_NET_SOCKET_TCP_CLASS) || + efl_isa(inner_socket, EFL_NET_SOCKET_SSL_CLASS) || + efl_isa(inner_socket, EFL_NET_SERVER_UDP_CLIENT_CLASS)) + { + const char *addr = efl_net_socket_address_remote_get(inner_socket); + if (addr) + { + const char *p; + if (addr[0] != '[') p = strchr(addr, ':'); + else + { + addr++; + p = strchr(addr, ']'); + } + if (p) + { + const char *portstr = p; + if (portstr[0] == ']') portstr++; + if (portstr[0] == ':') portstr++; /* not else if! */ + cl->ip = eina_stringshare_add_length(addr, p - addr); + cl->port = atoi(portstr); + } + } + } + else + { + /* legacy compatibility */ + cl->ip = eina_stringshare_add("0.0.0.0"); + cl->port = -1; + } + + efl_event_callback_array_add(cl->socket, _ecore_con_client_socket_cbs(), cl); + if (efl_isa(inner_socket, EFL_NET_SOCKET_SSL_CLASS)) + efl_event_callback_array_add(inner_socket, _ecore_con_client_socket_ssl_cbs(), cl); + + ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT); + svr->clients = eina_list_append(svr->clients, cl); + return cl; +} + +EAPI int +ecore_con_client_send(Ecore_Con_Client *cl, const void *data, int size) +{ + Eina_Error err; + Eina_Slice slice = { .mem = data, .len = size }; + + ECORE_CON_CLIENT_CHECK_RETURN(cl, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0); + EINA_SAFETY_ON_TRUE_RETURN_VAL(size < 1, 0); + + EINA_SAFETY_ON_NULL_RETURN_VAL(cl->socket, 0); + err = efl_io_writer_write(cl->socket, &slice, NULL); + if (err) + { + ERR("cl=%p could not send data=%p, size=%d: %s", cl, data, size, eina_error_msg_get(err)); + return 0; + } + cl->pending_write = efl_io_buffered_stream_pending_write_get(cl->socket); + + return slice.len; +} + +EAPI Eina_Bool +ecore_con_client_connected_get(const Ecore_Con_Client *cl) +{ + ECORE_CON_CLIENT_CHECK_RETURN(cl, EINA_FALSE); + return !efl_io_closer_closed_get(cl->socket); +} + +EAPI void +ecore_con_client_timeout_set(Ecore_Con_Client *cl, double timeout) +{ + ECORE_CON_CLIENT_CHECK_RETURN(cl); + efl_io_buffered_stream_inactivity_timeout_set(cl->socket, timeout); +} + +EAPI double +ecore_con_client_timeout_get(const Ecore_Con_Client *cl) +{ + ECORE_CON_CLIENT_CHECK_RETURN(cl, -1.0); + return efl_io_buffered_stream_inactivity_timeout_get(cl->socket); +} + +EAPI void * +ecore_con_client_del(Ecore_Con_Client *cl) +{ + const void *data; + + ECORE_CON_CLIENT_CHECK_RELAXED_RETURN(cl, NULL); + + data = cl->data; + + _ecore_con_client_free(cl); + return (void *)data; +} + +EAPI void +ecore_con_client_data_set(Ecore_Con_Client *cl, + const void *data) +{ + ECORE_CON_CLIENT_CHECK_RELAXED_RETURN(cl); + cl->data = data; +} + +EAPI void * +ecore_con_client_data_get(Ecore_Con_Client *cl) +{ + ECORE_CON_CLIENT_CHECK_RELAXED_RETURN(cl, NULL); + return (void *)cl->data; } EAPI const char * -ecore_con_url_url_get(const Ecore_Con_Url *obj) +ecore_con_client_ip_get(const Ecore_Con_Client *cl) { - return efl_network_url_get((Ecore_Con_Url *)obj); + ECORE_CON_CLIENT_CHECK_RELAXED_RETURN(cl, NULL); + return cl->ip; } +EAPI int +ecore_con_client_port_get(const Ecore_Con_Client *cl) +{ + ECORE_CON_CLIENT_CHECK_RELAXED_RETURN(cl, -1); + return cl->port; +} + +EAPI Ecore_Con_Server * +ecore_con_client_server_get(const Ecore_Con_Client *cl) +{ + ECORE_CON_CLIENT_CHECK_RELAXED_RETURN(cl, NULL); + return cl->svr; +} + +EAPI double +ecore_con_client_uptime_get(const Ecore_Con_Client *cl) +{ + ECORE_CON_CLIENT_CHECK_RELAXED_RETURN(cl, 0.0); + return ecore_time_get() - cl->start_time; +} + +EAPI void +ecore_con_client_flush(Ecore_Con_Client *cl) +{ + ECORE_CON_CLIENT_CHECK_RETURN(cl); + Eo *inner_socket; + + if (!cl->socket) return; + + efl_io_buffered_stream_flush(cl->socket, EINA_FALSE, EINA_TRUE); + + inner_socket = efl_io_buffered_stream_inner_io_get(cl->socket); + + if (!efl_isa(inner_socket, EFL_NET_SOCKET_TCP_CLASS)) return; + if (!efl_net_socket_tcp_cork_get(inner_socket)) return; + + efl_net_socket_tcp_cork_set(inner_socket, EINA_FALSE); + efl_net_socket_tcp_cork_set(inner_socket, EINA_TRUE); +} + +EAPI int +ecore_con_client_fd_get(const Ecore_Con_Client *cl) +{ + ECORE_CON_CLIENT_CHECK_RETURN(cl, SOCKET_TO_LOOP_FD(INVALID_SOCKET)); + if (cl->socket) + { + if (efl_isa(cl->socket, EFL_LOOP_FD_CLASS)) + return efl_loop_fd_get(cl->socket); + return SOCKET_TO_LOOP_FD(INVALID_SOCKET); + } + return SOCKET_TO_LOOP_FD(INVALID_SOCKET); +} + +static void +_ecore_con_client_socket_ssl_ready(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Client *cl = data; + + cl->ssl.upgrading = EINA_FALSE; + INF("cl=%p upgraded to SSL at %s", cl, efl_net_socket_address_remote_get(cl->socket)); + _ecore_con_post_event_client_upgrade(cl); +} + +static void +_ecore_con_client_socket_ssl_error(void *data, const Efl_Event *event) +{ + Ecore_Con_Client *cl = data; + Eina_Error *perr = event->info; + + if (cl->delete_me) return; + + WRN("SSL error client %s: %s", efl_net_socket_address_remote_get(cl->socket), eina_error_msg_get(*perr)); + + _ecore_con_post_event_client_error(cl, eina_error_msg_get(*perr)); + _ecore_con_client_socket_close(cl); +} + +EFL_CALLBACKS_ARRAY_DEFINE(_ecore_con_client_socket_ssl_cbs, + { EFL_NET_SOCKET_SSL_EVENT_SSL_READY, _ecore_con_client_socket_ssl_ready }, + { EFL_NET_SOCKET_SSL_EVENT_SSL_ERROR, _ecore_con_client_socket_ssl_error }); + +static void +_ecore_con_client_ssl_upgrade_job(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Client *cl = data; + Eo *loop = ecore_main_loop_get(); + Eo *inner_socket; + Eo *socket; + Eo *tcp_socket; + + tcp_socket = cl->socket; + cl->socket = NULL; /* take it, will be wrapped */ + + inner_socket = efl_add(EFL_NET_SOCKET_SSL_CLASS, loop, + efl_net_socket_ssl_adopt(efl_added, tcp_socket, cl->ssl.ctx)); + EINA_SAFETY_ON_NULL_GOTO(inner_socket, error_inner_socket); + + /* do not reparent tcp_socket! it's owned by server */ + efl_unref(tcp_socket); /* inner_socket keeps it */ + + socket = efl_add(EFL_NET_SOCKET_SIMPLE_CLASS, loop, + efl_io_buffered_stream_inner_io_set(efl_added, inner_socket)); + EINA_SAFETY_ON_NULL_GOTO(socket, error_socket); + + efl_parent_set(inner_socket, socket); + + efl_unref(inner_socket); /* socket keeps it */ + + cl->socket = socket; + efl_io_closer_close_on_exec_set(socket, EINA_TRUE); + efl_io_closer_close_on_destructor_set(socket, EINA_TRUE); + efl_event_callback_array_del(tcp_socket, _ecore_con_client_socket_cbs(), cl); + efl_event_callback_array_add(socket, _ecore_con_client_socket_cbs(), cl); + efl_event_callback_array_add(inner_socket, _ecore_con_client_socket_ssl_cbs(), cl); + + DBG("socket=%p upgraded to SSL with inner_socket=%p, ssl_ctx=%p, tcp_socket=%p. Start handshake...", + cl->socket, + efl_io_buffered_stream_inner_io_get(cl->socket), + cl->ssl.ctx, + tcp_socket); + return; + + error_socket: + efl_del(inner_socket); + error_inner_socket: + cl->socket = tcp_socket; /* put it back */ + _ecore_con_post_event_client_error(cl, "Couldn't finish SSL setup"); + _ecore_con_post_event_client_del(cl); +} + +static Eo * _ecore_con_server_ssl_ctx_create(const Ecore_Con_Server *svr); + +EAPI Eina_Bool +ecore_con_ssl_client_upgrade(Ecore_Con_Client *cl, Ecore_Con_Type compl_type) +{ + Ecore_Con_Server *svr; + Eo *ssl_ctx; + double start; + + ECORE_CON_CLIENT_CHECK_RETURN(cl, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL((compl_type & ECORE_CON_SSL) == 0, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(cl->ssl.upgrading, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(efl_io_buffered_stream_inner_io_get(cl->socket), EFL_NET_SOCKET_TCP_CLASS), EINA_FALSE); + + svr = cl->svr; + EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_isa(efl_net_server_simple_inner_server_get(svr->server), EFL_NET_SERVER_SSL_CLASS), EINA_FALSE); /* cannot upgrade if already SSL server! */ + + start = ecore_time_get(); + while (efl_io_buffered_stream_pending_write_get(cl->socket) && ((ecore_time_get() - start) <= ecore_animator_frametime_get())) + ecore_con_client_flush(cl); + if (efl_io_buffered_stream_pending_write_get(cl->socket)) + { + ERR("cl=%p still pending send %zd bytes! Flush client before upgrading to SSL!", + cl, efl_io_buffered_stream_pending_write_get(cl->socket)); + return EINA_FALSE; + } + + if ((!svr->ssl.upgrade_type) || (!svr->ssl.clients_ctx)) + { + svr->ssl.upgrade_type = compl_type; + svr->ssl.clients_ctx = _ecore_con_server_ssl_ctx_create(svr); + EINA_SAFETY_ON_NULL_RETURN_VAL(svr->ssl.clients_ctx, EINA_FALSE); + } + + if (svr->ssl.upgrade_type == compl_type) + ssl_ctx = efl_ref(svr->ssl.clients_ctx); + else + ssl_ctx = _ecore_con_server_ssl_ctx_create(svr); + + EINA_SAFETY_ON_NULL_RETURN_VAL(ssl_ctx, EINA_FALSE); + + cl->ssl.upgrading = EINA_TRUE; + cl->ssl.ctx = ssl_ctx; + efl_future_use(&cl->ssl.job, efl_loop_job(efl_loop_get(cl->socket), cl)); + efl_future_then(cl->ssl.job, _ecore_con_client_ssl_upgrade_job, NULL, NULL, cl); + + DBG("cl=%p SSL upgrading from %#x to type=%#x", cl, svr->type, compl_type); + + return EINA_TRUE; +} + +/** + * @} + */ + +Eina_Bool +ecore_con_server_check(const Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr, EINA_FALSE); + return EINA_TRUE; +} + +static Ecore_Con_Server * +_ecore_con_server_new(Eina_Bool is_dialer, Ecore_Con_Type type, const char *name, int port, const void *data) +{ + Ecore_Con_Server *svr = calloc(1, sizeof(Ecore_Con_Server)); + EINA_SAFETY_ON_NULL_RETURN_VAL(svr, NULL); + svr->start_time = ecore_time_get(); + svr->name = eina_stringshare_add(name); + svr->port = port; + svr->data = data; + svr->type = type; + svr->is_dialer = is_dialer; + + EINA_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER); + _servers = eina_list_append(_servers, svr); + return svr; +} + +static void +_ecore_con_server_dialer_close(Ecore_Con_Server *svr) +{ + if (!svr->dialer) return; + + if (!efl_io_closer_closed_get(svr->dialer)) + efl_io_closer_close(svr->dialer); +} + +static void +_ecore_con_server_free(Ecore_Con_Server *svr) +{ + const char *str; + + svr->delete_me = EINA_TRUE; + _servers = eina_list_remove(_servers, svr); + + while (svr->clients) + ecore_con_client_del(svr->clients->data); + + _ecore_con_server_dialer_close(svr); + + if (svr->dialer) + { + efl_del(svr->dialer); + svr->dialer = NULL; + } + + if (svr->server) + { + efl_del(svr->server); + svr->server = NULL; + } + + if (svr->ssl.clients_ctx) + { + efl_unref(svr->ssl.clients_ctx); + svr->ssl.clients_ctx = NULL; + } + + if (svr->ssl.job) efl_future_cancel(svr->ssl.job); + + if (svr->event_count) return; + + EINA_LIST_FREE(svr->ssl.certs, str) eina_stringshare_del(str); + EINA_LIST_FREE(svr->ssl.privkeys, str) eina_stringshare_del(str); + EINA_LIST_FREE(svr->ssl.crls, str) eina_stringshare_del(str); + EINA_LIST_FREE(svr->ssl.cafiles, str) eina_stringshare_del(str); + eina_stringshare_replace(&svr->ssl.verify_name, NULL); + + svr->data = NULL; + eina_stringshare_replace(&svr->name, NULL); + eina_stringshare_replace(&svr->ip, NULL); + + EINA_MAGIC_SET(svr, ECORE_MAGIC_NONE); + free(svr); +} + +/* BEGIN: post of shared Ecore_Event ***********************************/ + +static void +_ecore_con_free_event_server_del(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Server_Del *ev = event; + + if (ev->server) + { + Ecore_Con_Server *svr = ev->server; + svr->event_count = eina_list_remove(svr->event_count, ev); + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + } + ecore_con_event_server_del_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_server_del(Ecore_Con_Server *svr) +{ + Ecore_Con_Event_Server_Del *ev = ecore_con_event_server_del_alloc(); + EINA_SAFETY_ON_NULL_GOTO(ev, error); + + if (svr->dialer) + INF("svr=%p disconnected from %s (%s)", svr, efl_net_dialer_address_dial_get(svr->dialer), efl_net_socket_address_remote_get(svr->dialer)); + else if (svr->server) + INF("svr=%p stopped serving at %s", svr, efl_net_server_address_get(svr->server)); + else + INF("svr=%p name=%s, port=%d %s destroyed before SSL was configured", svr, svr->name, svr->port, svr->is_dialer ? "dialer" : "server"); + + if (svr->connecting) + { + DBG("svr=%p was still connecting to %s (%s), ignore ECORE_CON_EVENT_SERVER_DEL", svr, efl_net_dialer_address_dial_get(svr->dialer), efl_net_socket_address_remote_get(svr->dialer)); + return; + } + + ev->server = svr; + svr->event_count = eina_list_append(svr->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_SERVER_DEL, ev, _ecore_con_free_event_server_del, NULL); + _ecore_con_event_count++; + return; + + error: + _ecore_con_server_free(svr); +} + +static void +_ecore_con_free_event_server_error(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Server_Error *ev = event; + + if (ev->server) + { + Ecore_Con_Server *svr = ev->server; + svr->event_count = eina_list_remove(svr->event_count, ev); + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + } + free(ev->error); + ecore_con_event_server_error_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_server_error(Ecore_Con_Server *svr, const char *err) +{ + Ecore_Con_Event_Server_Error *ev = ecore_con_event_server_error_alloc(); + EINA_SAFETY_ON_NULL_GOTO(ev, error); + + if (svr->dialer) + INF("svr=%p error from %s (%s): %s", svr, efl_net_dialer_address_dial_get(svr->dialer), efl_net_socket_address_remote_get(svr->dialer), err); + else if (svr->server) + INF("svr=%p error at %s: %s", svr, efl_net_server_address_get(svr->server), err); + else + INF("svr=%p name=%s, port=%d %s error before SSL was configured: %s", svr, svr->name, svr->port, svr->is_dialer ? "dialer" : "server", err); + + ev->server = svr; + ev->error = err ? strdup(err) : NULL; + svr->event_count = eina_list_append(svr->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_SERVER_ERROR, ev, _ecore_con_free_event_server_error, NULL); + _ecore_con_event_count++; + return; + + error: + _ecore_con_server_free(svr); +} + +/* END: post of shared Ecore_Event ***********************************/ + + +/* BEGIN: post of Ecore_Event for ecore_con_server_connect() ************/ + +static void +_ecore_con_free_event_server_add(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Server_Add *ev = event; + + if (ev->server) + { + Ecore_Con_Server *svr = ev->server; + svr->event_count = eina_list_remove(svr->event_count, ev); + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + } + ecore_con_event_server_add_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_server_add(Ecore_Con_Server *svr) +{ + Ecore_Con_Event_Server_Add *ev = ecore_con_event_server_add_alloc(); + EINA_SAFETY_ON_NULL_GOTO(ev, error); + + ev->server = svr; + svr->event_count = eina_list_append(svr->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_SERVER_ADD, ev, _ecore_con_free_event_server_add, NULL); + _ecore_con_event_count++; + return; + + error: + _ecore_con_server_free(svr); +} + +static void +_ecore_con_free_event_server_data(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Server_Data *ev = event; + + if (ev->server) + { + Ecore_Con_Server *svr = ev->server; + svr->event_count = eina_list_remove(svr->event_count, ev); + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + } + free(ev->data); + ecore_con_event_server_data_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_server_data(Ecore_Con_Server *svr, Eina_Rw_Slice slice) +{ + Ecore_Con_Event_Server_Data *ev = ecore_con_event_server_data_alloc(); + EINA_SAFETY_ON_NULL_GOTO(ev, error); + + ev->server = svr; + ev->data = slice.mem; + ev->size = slice.len; + svr->event_count = eina_list_append(svr->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_SERVER_DATA, ev, _ecore_con_free_event_server_data, NULL); + _ecore_con_event_count++; + return; + + error: + free(slice.mem); +} + +static void +_ecore_con_free_event_server_write(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Server_Write *ev = event; + + if (ev->server) + { + Ecore_Con_Server *svr = ev->server; + svr->event_count = eina_list_remove(svr->event_count, ev); + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + } + ecore_con_event_server_write_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_server_write(Ecore_Con_Server *svr, size_t size) +{ + Ecore_Con_Event_Server_Write *ev = ecore_con_event_server_write_alloc(); + EINA_SAFETY_ON_NULL_RETURN(ev); + + ev->server = svr; + ev->size = size; + svr->event_count = eina_list_append(svr->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_SERVER_WRITE, ev, _ecore_con_free_event_server_write, NULL); + _ecore_con_event_count++; +} + +static void +_ecore_con_free_event_server_upgrade(void *data EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Server_Upgrade *ev = event; + + if (ev->server) + { + Ecore_Con_Server *svr = ev->server; + svr->event_count = eina_list_remove(svr->event_count, ev); + if ((!svr->event_count) && (svr->delete_me)) + _ecore_con_server_free(svr); + } + ecore_con_event_server_upgrade_free(ev); + _ecore_con_event_count--; +} + +static void +_ecore_con_post_event_server_upgrade(Ecore_Con_Server *svr) +{ + Ecore_Con_Event_Server_Upgrade *ev = ecore_con_event_server_upgrade_alloc(); + EINA_SAFETY_ON_NULL_GOTO(ev, error); + + ev->server = svr; + svr->event_count = eina_list_append(svr->event_count, ev); + + ecore_event_add(ECORE_CON_EVENT_SERVER_UPGRADE, ev, _ecore_con_free_event_server_upgrade, NULL); + _ecore_con_event_count++; + return; + + error: + _ecore_con_server_free(svr); +} + +/* END: post of Ecore_Event for ecore_con_server_connect() **************/ + +static void +_ecore_con_server_dialer_slice_changed(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Server *svr = data; + Eina_Slice ro_slice; + Eina_Rw_Slice rw_slice; + + if (svr->delete_me) return; + if (svr->ssl.upgrading) return; + + if (!efl_io_buffered_stream_slice_get(svr->dialer, &ro_slice)) return; + if (ro_slice.len == 0) return; + + rw_slice = eina_slice_dup(ro_slice); + efl_io_buffered_stream_clear(svr->dialer); + _ecore_con_post_event_server_data(svr, rw_slice); +} + +static void +_ecore_con_server_dialer_progress(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Server *svr = data; + size_t now; + + if (svr->delete_me) return; + if (svr->ssl.upgrading) return; + + now = efl_io_buffered_stream_pending_write_get(svr->dialer); + if (svr->pending_write == now) return; + EINA_SAFETY_ON_TRUE_GOTO(svr->pending_write < now, end); /* forgot to update! */ + + _ecore_con_post_event_server_write(svr, svr->pending_write - now); + + end: + svr->pending_write = now; +} + +static void +_ecore_con_server_dialer_finished(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Server *svr = data; + + if (svr->delete_me) return; + + _ecore_con_post_event_server_del(svr); +} + +static void +_ecore_con_server_dialer_error(void *data, const Efl_Event *event) +{ + Ecore_Con_Server *svr = data; + Eina_Error *perr = event->info; + + if (svr->delete_me) return; + + WRN("error reaching server %s: %s", efl_net_dialer_address_dial_get(svr->dialer), eina_error_msg_get(*perr)); + + _ecore_con_post_event_server_error(svr, eina_error_msg_get(*perr)); + _ecore_con_server_dialer_close(svr); +} + +static void +_ecore_con_server_dialer_resolved(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Server *svr = data; + Eo *inner_dialer; + + if (svr->delete_me) return; + + inner_dialer = efl_io_buffered_stream_inner_io_get(svr->dialer); + if (efl_isa(inner_dialer, EFL_NET_DIALER_TCP_CLASS) || + efl_isa(inner_dialer, EFL_NET_DIALER_UDP_CLASS) || + efl_isa(inner_dialer, EFL_NET_DIALER_SSL_CLASS)) + { + const char *p, *ip = efl_net_socket_address_remote_get(svr->dialer); + EINA_SAFETY_ON_NULL_RETURN(ip); + + if (ip[0] != '[') p = strchr(ip, ':'); + else + { + ip++; + p = strchr(ip, ']'); + } + EINA_SAFETY_ON_NULL_RETURN(p); + + eina_stringshare_del(svr->ip); + svr->ip = eina_stringshare_add_length(ip, p - ip); + } +} + +static void +_ecore_con_server_dialer_connected(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Server *svr = data; + + if (svr->delete_me) return; + if (svr->ssl.upgrading) + { + svr->ssl.upgrading = EINA_FALSE; + INF("svr=%p upgraded to SSL at %s (%s)", svr, efl_net_dialer_address_dial_get(svr->dialer), efl_net_socket_address_remote_get(svr->dialer)); + _ecore_con_post_event_server_upgrade(svr); + return; + } + + svr->connecting = EINA_FALSE; + svr->start_time = ecore_time_get(); + + INF("svr=%p connected to %s (%s)", svr, efl_net_dialer_address_dial_get(svr->dialer), efl_net_socket_address_remote_get(svr->dialer)); + + _ecore_con_post_event_server_add(svr); +} + +EFL_CALLBACKS_ARRAY_DEFINE(_ecore_con_server_dialer_cbs, + { EFL_IO_BUFFERED_STREAM_EVENT_PROGRESS, _ecore_con_server_dialer_progress }, + { EFL_IO_BUFFERED_STREAM_EVENT_SLICE_CHANGED, _ecore_con_server_dialer_slice_changed }, + { EFL_IO_BUFFERED_STREAM_EVENT_FINISHED, _ecore_con_server_dialer_finished }, + { EFL_NET_DIALER_EVENT_ERROR, _ecore_con_server_dialer_error }, + { EFL_NET_DIALER_EVENT_RESOLVED, _ecore_con_server_dialer_resolved }, + { EFL_NET_DIALER_EVENT_CONNECTED, _ecore_con_server_dialer_connected }); + +static void +_ecore_con_server_server_client_add(void *data, const Efl_Event *event) +{ + Ecore_Con_Server *svr = data; + Ecore_Con_Client *cl; + Eo *socket = event->info; + + INF("svr=%p address=%s got client %p (%s) address=%s", + svr, efl_net_server_address_get(svr->server), + socket, + efl_class_name_get(efl_io_buffered_stream_inner_io_get(socket)), + efl_net_socket_address_remote_get(socket)); + + cl = ecore_con_client_add(svr, socket); + EINA_SAFETY_ON_NULL_RETURN(cl); + + _ecore_con_post_event_client_add(cl); +} + +static void +_ecore_con_server_server_serving(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Server *svr = data; + Eo *inner_server; + const char *address = efl_net_server_address_get(svr->server); + const char *p; + char *ip; + + EINA_SAFETY_ON_NULL_RETURN(address); + + INF("svr=%p ready at %s", svr, address); + + if (!svr->want_mcast) return; + + inner_server = efl_net_server_simple_inner_server_get(svr->server); + + if (address[0] != '[') p = strchr(address, ':'); + else + { + address++; + p = strchr(address, ']'); + } + EINA_SAFETY_ON_NULL_RETURN(p); + + ip = malloc(p - address + 1); + EINA_SAFETY_ON_NULL_RETURN(ip); + + memcpy(ip, address, p - address); + ip[p - address] = '\0'; + + DBG("svr=%p join multicast group: %s", svr, ip); + efl_net_server_udp_multicast_join(inner_server, ip); + free(ip); +} + +static void +_ecore_con_server_server_error(void *data, const Efl_Event *event) +{ + Ecore_Con_Server *svr = data; + Eina_Error *perr = event->info; + + WRN("svr=%p address=%s error: %s", + svr, efl_net_server_address_get(svr->server), + eina_error_msg_get(*perr)); + + _ecore_con_post_event_server_error(svr, eina_error_msg_get(*perr)); +} + +EFL_CALLBACKS_ARRAY_DEFINE(_ecore_con_server_server_cbs, + { EFL_NET_SERVER_EVENT_CLIENT_ADD, _ecore_con_server_server_client_add }, + { EFL_NET_SERVER_EVENT_SERVING, _ecore_con_server_server_serving }, + { EFL_NET_SERVER_EVENT_ERROR, _ecore_con_server_server_error }); + +/** + * @addtogroup Ecore_Con_Server_Group Ecore Connection Server Functions + * + * Functions that operate on Ecore server objects. + * + * @{ + */ + +static Eina_Bool +_ecore_con_server_server_set(Ecore_Con_Server *svr, Eo *server) +{ + char address[4096] = ""; + Eo *inner_server = efl_net_server_simple_inner_server_get(server); + Ecore_Con_Type type = svr->type & ECORE_CON_TYPE; + Eina_Error err; + + svr->server = server; + efl_event_callback_array_add(server, _ecore_con_server_server_cbs(), svr); + + if (efl_isa(inner_server, EFL_NET_SERVER_TCP_CLASS) || + efl_isa(inner_server, EFL_NET_SERVER_UDP_CLASS) || + efl_isa(inner_server, EFL_NET_SERVER_SSL_CLASS)) + { + if (strchr(svr->name, ':')) + snprintf(address, sizeof(address), "[%s]:%d", svr->name, svr->port); + else + snprintf(address, sizeof(address), "%s:%d", svr->name, svr->port); + } + else if (type == ECORE_CON_LOCAL_ABSTRACT) + snprintf(address, sizeof(address), "abstract:%s", svr->name); + else if ((type == ECORE_CON_LOCAL_USER) || + (type == ECORE_CON_LOCAL_SYSTEM)) + { + char *path = ecore_con_local_path_new(type == ECORE_CON_LOCAL_SYSTEM, svr->name, svr->port); + if (!path) + { + ERR("could not create local path for name='%s', port=%d", svr->name, svr->port); + return EINA_FALSE; + } + else + { + eina_strlcpy(address, path, sizeof(address)); + free(path); + } + } + + if (efl_isa(inner_server, EFL_NET_SERVER_FD_CLASS)) + { + efl_net_server_fd_close_on_exec_set(inner_server, EINA_TRUE); + efl_net_server_fd_reuse_address_set(inner_server, EINA_TRUE); + efl_net_server_fd_reuse_port_set(inner_server, EINA_TRUE); + } + + if (efl_isa(inner_server, EFL_NET_SERVER_TCP_CLASS)) + { + /* old ecore_con did not map ipv4 to ipv6... */ + efl_net_server_tcp_ipv6_only_set(inner_server, EINA_TRUE); + } + else if (efl_isa(inner_server, EFL_NET_SERVER_UDP_CLASS)) + { + /* old ecore_con did not map ipv4 to ipv6... */ + efl_net_server_udp_ipv6_only_set(inner_server, EINA_TRUE); + svr->want_mcast = type == ECORE_CON_REMOTE_MCAST; + } + else if (efl_isa(inner_server, EFL_NET_SERVER_SSL_CLASS)) + { + /* old ecore_con did not map ipv4 to ipv6... */ + efl_net_server_ssl_ipv6_only_set(inner_server, EINA_TRUE); + efl_net_server_ssl_close_on_exec_set(inner_server, EINA_TRUE); + efl_net_server_ssl_reuse_address_set(inner_server, EINA_TRUE); + efl_net_server_ssl_reuse_port_set(inner_server, EINA_TRUE); + } +#ifdef EFL_NET_SERVER_UNIX_CLASS + else if (efl_isa(inner_server, EFL_NET_SERVER_UNIX_CLASS)) + { + efl_net_server_unix_unlink_before_bind_set(inner_server, EINA_TRUE); + efl_net_server_unix_leading_directories_create_set(inner_server, EINA_TRUE, (type == ECORE_CON_LOCAL_SYSTEM) ? 0755 : 0700); + } +#endif + + if (svr->type & ECORE_CON_SOCKET_ACTIVATE) + { + if (efl_isa(inner_server, EFL_NET_SERVER_FD_CLASS)) + efl_net_server_fd_socket_activate(inner_server, address); + else if (efl_isa(inner_server, EFL_NET_SERVER_SSL_CLASS)) + efl_net_server_ssl_socket_activate(inner_server, address); + else + { + ERR("svr=%p (%s): not able to socket-activate this type!", svr, efl_class_name_get(inner_server)); + goto serve; + } + + if (efl_net_server_serving_get(inner_server)) + { + DBG("svr=%p (%s) was socket activated as %s", + svr, efl_class_name_get(inner_server), address); + return EINA_TRUE; + } + else + ERR("svr=%p (%s): not able to socket-activate as %s. Try to serve...", svr, efl_class_name_get(inner_server), address); + } + + serve: + err = efl_net_server_serve(svr->server, address); + if (err) + { + WRN("Could not serve at address=%s using class=%s", + address, efl_class_name_get(inner_server)); + return EINA_FALSE; + } + + DBG("svr=%p server=%p (%s) address=%s", + svr, svr->server, efl_class_name_get(inner_server), + efl_net_server_address_get(svr->server)); + return EINA_TRUE; +} + +static Eo * +_ecore_con_server_ssl_ctx_create(const Ecore_Con_Server *svr) +{ + Efl_Net_Ssl_Cipher cipher = EFL_NET_SSL_CIPHER_AUTO; + Ecore_Con_Type ssl_type = svr->ssl.upgrade_type & ECORE_CON_SSL; + + if (ssl_type & ECORE_CON_USE_MIXED) + cipher = EFL_NET_SSL_CIPHER_AUTO; + else if (ssl_type & ECORE_CON_USE_TLS) + cipher = EFL_NET_SSL_CIPHER_TLSV1; + else if (ssl_type & ECORE_CON_USE_SSL3) + cipher = EFL_NET_SSL_CIPHER_SSLV3; + else if (ssl_type & ECORE_CON_USE_SSL2) + { + ERR("SSLv2 is unsupported!"); + return NULL; + } + + /* legacy compatibility: server never verified peer, only dialer did */ + + return efl_add(EFL_NET_SSL_CONTEXT_CLASS, NULL, + efl_net_ssl_context_certificates_set(efl_added, eina_list_iterator_new(svr->ssl.certs)), + efl_net_ssl_context_private_keys_set(efl_added, eina_list_iterator_new(svr->ssl.privkeys)), + efl_net_ssl_context_certificate_revogation_lists_set(efl_added, eina_list_iterator_new(svr->ssl.crls)), + efl_net_ssl_context_certificate_authorities_set(efl_added, eina_list_iterator_new(svr->ssl.cafiles)), + efl_net_ssl_context_default_paths_load_set(efl_added, EINA_FALSE), /* old API didn't load default paths */ + efl_net_ssl_context_setup(efl_added, cipher, EINA_FALSE)); +} + +static void +_ecore_con_server_server_ssl_job(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Server *svr = data; + Eo *loop = ecore_main_loop_get(); + Eo *ssl_ctx; + Eo *inner_server; + Eo *server; + + ssl_ctx = _ecore_con_server_ssl_ctx_create(svr); + EINA_SAFETY_ON_NULL_GOTO(ssl_ctx, error_ssl_ctx); + + inner_server = efl_add(EFL_NET_SERVER_SSL_CLASS, loop, + efl_net_server_ssl_context_set(efl_added, ssl_ctx)); + EINA_SAFETY_ON_NULL_GOTO(inner_server, error_inner_server); + + server = efl_add(EFL_NET_SERVER_SIMPLE_CLASS, loop, + efl_net_server_simple_inner_server_set(efl_added, inner_server)); + EINA_SAFETY_ON_NULL_GOTO(server, error_server); + + efl_parent_set(inner_server, server); + + efl_unref(ssl_ctx); /* inner_server keeps it */ + efl_unref(inner_server); /* server keeps it */ + + if (!_ecore_con_server_server_set(svr, server)) + goto error_serve; + + DBG("server=%p configured with inner_server=%p, ssl_ctx=%p", + svr->server, + efl_net_server_simple_inner_server_get(svr->server), + efl_net_server_ssl_context_get(efl_net_server_simple_inner_server_get(svr->server))); + + return; + + error_serve: + _ecore_con_post_event_server_error(svr, "Couldn't serve using SSL"); + _ecore_con_post_event_server_del(svr); + return; + + error_server: + efl_del(inner_server); + error_inner_server: + efl_del(ssl_ctx); + error_ssl_ctx: + _ecore_con_post_event_server_error(svr, "Couldn't finish SSL setup"); + _ecore_con_post_event_server_del(svr); +} + +/** + * @example ecore_con_server_example.c + * Shows how to write a simple server using the Ecore_Con library + * using ecore_con_server_add() + */ + +EAPI Ecore_Con_Server * +ecore_con_server_add(Ecore_Con_Type compl_type, + const char *name, + int port, + const void *data) +{ + const Efl_Class *cls = NULL; + Ecore_Con_Server *svr; + Ecore_Con_Type type; + Eo *server; + Eo *loop; + + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + + type = compl_type & ECORE_CON_TYPE; + + loop = ecore_main_loop_get(); + EINA_SAFETY_ON_NULL_RETURN_VAL(loop, NULL); + + svr = _ecore_con_server_new(EINA_FALSE, compl_type, name, port, data); + EINA_SAFETY_ON_NULL_RETURN_VAL(svr, NULL); + + switch (type) + { + case ECORE_CON_LOCAL_USER: + case ECORE_CON_LOCAL_SYSTEM: + case ECORE_CON_LOCAL_ABSTRACT: +#ifdef EFL_NET_SERVER_UNIX_CLASS + cls = EFL_NET_SERVER_UNIX_CLASS; +#else + ERR("Your platform doesn't support Efl_Net_Server-compatible local communication"); + // TODO: maybe write to a file and use TCP +#endif + break; + + case ECORE_CON_REMOTE_TCP: + case ECORE_CON_REMOTE_NODELAY: + case ECORE_CON_REMOTE_CORK: + cls = EFL_NET_SERVER_TCP_CLASS; + break; + + case ECORE_CON_REMOTE_UDP: + case ECORE_CON_REMOTE_MCAST: + cls = EFL_NET_SERVER_UDP_CLASS; + break; + + default: + ERR("Unsupported type=%#x & %#x = %#x", compl_type, ECORE_CON_TYPE, type); + } + + EINA_SAFETY_ON_NULL_GOTO(cls, error); + + if (compl_type & ECORE_CON_SSL) + { + if (cls != EFL_NET_SERVER_TCP_CLASS) + ERR("SSL can only be used with TCP types, got %s, forcing TCP", efl_class_name_get(cls)); + + /* efl_net_ssl_context must be created prior to the object as + * it's immutable once created. However the previous + * Ecore_Con_Server API returned a handle and then configured + * it, like in runtime, but in practice it's only effective + * before the server starts. + * + * Then do not create the SSL server right away, instead do it + * from a job, let the user configure SSL before the job + * finishes. + * + * EINA_SAFETY_ON_NULL_RETURN(svr->ssl.job) will alert users + * trying to configure after the job expires. + * + * We can do that since the documentation says: + * + * > Call this function on a server object before main loop + * > has started to enable verification of certificates + * > against loaded certificates. + */ + svr->ssl.upgrade_type = compl_type; + efl_future_use(&svr->ssl.job, efl_loop_job(loop, svr)); + efl_future_then(svr->ssl.job, _ecore_con_server_server_ssl_job, NULL, NULL, svr); + return svr; + } + + server = efl_add(EFL_NET_SERVER_SIMPLE_CLASS, loop, + efl_net_server_simple_inner_class_set(efl_added, cls)); + EINA_SAFETY_ON_NULL_GOTO(server, error); + + if (!_ecore_con_server_server_set(svr, server)) + goto error; + + return svr; + + error: + _ecore_con_server_free(svr); + return NULL; +} + +/** + * @brief convert @a socks to proxy URL string and apply using efl_net_dialer_proxy_set(). + * + * @param svr the server created by ecore_con_server_connect(). + * @param socks the socks handle created by + * ecore_con_socks4_remote_add() or ecore_con_socks5_remote_add(). + * + * @internal + */ +static void +_ecore_con_server_proxy_apply(Ecore_Con_Server *svr, const Ecore_Con_Socks *socks) +{ + char str[4096], port[sizeof(":65536")] = ""; + const char *protocol; + const char *user = ""; + const char *userpass_sep = ""; + const char *pass = ""; + const char *auth_sep = ""; + + if (socks->version == 4) + { + Ecore_Con_Socks_v4 *v4 = (Ecore_Con_Socks_v4 *)socks; + + if (v4->lookup) protocol = "socks4a"; + else protocol = "socks4"; + + if (v4->port > 0) + snprintf(port, sizeof(port), ":%d", v4->port); + + if (v4->username) + { + user = v4->username; + auth_sep = "@"; + } + } + else if (socks->version == 5) + { + Ecore_Con_Socks_v5 *v5 = (Ecore_Con_Socks_v5 *)socks; + + if (socks->lookup) protocol = "socks5h"; + else protocol = "socks5"; + + if (v5->port > 0) + snprintf(port, sizeof(port), ":%d", v5->port); + + if (v5->username) + { + user = v5->username; + auth_sep = "@"; + + if (v5->password) + { + pass = v5->password; + userpass_sep = ":"; + } + } + } + else + { + ERR("unsupported socks->version=%d", socks->version); + return; + } + + snprintf(str, sizeof(str), + "%s://%s%s%s%s%s%s", + protocol, + pass, userpass_sep, user, auth_sep, + socks->ip, port); + DBG("using proxy url='%s' for server=%s, port=%d", + str, svr->name, svr->port); + + efl_net_dialer_proxy_set(svr->dialer, str); + + if (socks->bind) + ERR("proxy bind is not supported! Ecore_Con_Socks=%p %s", socks, str); +} + +static Eina_Bool +_ecore_con_server_dialer_set(Ecore_Con_Server *svr, Eo *dialer) +{ + char address[4096] = ""; + Eo *inner_dialer = efl_io_buffered_stream_inner_io_get(dialer); + Ecore_Con_Type type = svr->type & ECORE_CON_TYPE; + Eina_Error err; + + svr->dialer = dialer; + efl_io_closer_close_on_exec_set(dialer, EINA_TRUE); + efl_io_closer_close_on_destructor_set(dialer, EINA_TRUE); + efl_io_buffered_stream_inactivity_timeout_set(dialer, svr->timeout); + efl_event_callback_array_add(dialer, _ecore_con_server_dialer_cbs(), svr); + + if (efl_isa(inner_dialer, EFL_NET_DIALER_TCP_CLASS)) + { + efl_net_socket_tcp_no_delay_set(inner_dialer, !!(type & ECORE_CON_REMOTE_NODELAY)); + efl_net_socket_tcp_cork_set(inner_dialer, !!(type & ECORE_CON_REMOTE_CORK)); + } + else if (efl_isa(inner_dialer, EFL_NET_DIALER_SSL_CLASS)) + { + efl_net_dialer_ssl_no_delay_set(inner_dialer, !!(type & ECORE_CON_REMOTE_NODELAY)); + } + + if (efl_isa(inner_dialer, EFL_NET_DIALER_TCP_CLASS) || + efl_isa(inner_dialer, EFL_NET_DIALER_UDP_CLASS) || + efl_isa(inner_dialer, EFL_NET_DIALER_SSL_CLASS)) + { + if (strchr(svr->name, ':')) + snprintf(address, sizeof(address), "[%s]:%d", svr->name, svr->port); + else + snprintf(address, sizeof(address), "%s:%d", svr->name, svr->port); + } + else if (type == ECORE_CON_LOCAL_ABSTRACT) + snprintf(address, sizeof(address), "abstract:%s", svr->name); + else if ((type == ECORE_CON_LOCAL_USER) || + (type == ECORE_CON_LOCAL_SYSTEM)) + { + char *path = ecore_con_local_path_new(type == ECORE_CON_LOCAL_SYSTEM, svr->name, svr->port); + if (!path) + { + ERR("could not create local path for name='%s', port=%d", svr->name, svr->port); + return EINA_FALSE; + } + else + { + eina_strlcpy(address, path, sizeof(address)); + free(path); + } + } + + if ((svr->type & ECORE_CON_NO_PROXY) == ECORE_CON_NO_PROXY) + { + DBG("svr=%p not using any proxy for dialer %p (%s)", + svr, svr->dialer, efl_class_name_get(inner_dialer)); + efl_net_dialer_proxy_set(svr->dialer, ""); + } + else if (type > ECORE_CON_LOCAL_ABSTRACT) + { + if (_ecore_con_proxy_once) + { + _ecore_con_server_proxy_apply(svr, _ecore_con_proxy_once); + _ecore_con_proxy_once = NULL; + } + else if (_ecore_con_proxy_global) + _ecore_con_server_proxy_apply(svr, _ecore_con_proxy_global); + } + + svr->connecting = EINA_TRUE; + + err = efl_net_dialer_dial(svr->dialer, address); + if (err) + { + WRN("Could not connect to address=%s using class=%s", + address, efl_class_name_get(inner_dialer)); + return EINA_FALSE; + } + + DBG("svr=%p dialer=%p (%s) address=%s", + svr, svr->dialer, efl_class_name_get(inner_dialer), + efl_net_dialer_address_dial_get(svr->dialer)); + return EINA_TRUE; +} + +static void +_ecore_con_server_dialer_ssl_job(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Server *svr = data; + Eo *loop = ecore_main_loop_get(); + Eo *ssl_ctx; + Eo *inner_dialer; + Eo *dialer; + Efl_Net_Ssl_Cipher cipher = EFL_NET_SSL_CIPHER_AUTO; + Efl_Net_Ssl_Verify_Mode verify_mode = EFL_NET_SSL_VERIFY_MODE_NONE; /* was the default */ + Ecore_Con_Type ssl_type = svr->ssl.upgrade_type & ECORE_CON_SSL; + + if (ssl_type & ECORE_CON_USE_MIXED) + cipher = EFL_NET_SSL_CIPHER_AUTO; + else if (ssl_type & ECORE_CON_USE_TLS) + cipher = EFL_NET_SSL_CIPHER_TLSV1; + else if (ssl_type & ECORE_CON_USE_SSL3) + cipher = EFL_NET_SSL_CIPHER_SSLV3; + else if (ssl_type & ECORE_CON_USE_SSL2) + { + ERR("SSLv2 is unsupported!"); + goto error_ssl_ctx; + } + + if (svr->ssl.verify) + verify_mode = EFL_NET_SSL_VERIFY_MODE_REQUIRED; + + ssl_ctx = efl_add(EFL_NET_SSL_CONTEXT_CLASS, NULL, + efl_net_ssl_context_certificates_set(efl_added, eina_list_iterator_new(svr->ssl.certs)), + efl_net_ssl_context_private_keys_set(efl_added, eina_list_iterator_new(svr->ssl.privkeys)), + efl_net_ssl_context_certificate_revogation_lists_set(efl_added, eina_list_iterator_new(svr->ssl.crls)), + efl_net_ssl_context_certificate_authorities_set(efl_added, eina_list_iterator_new(svr->ssl.cafiles)), + efl_net_ssl_context_verify_mode_set(efl_added, verify_mode), + efl_net_ssl_context_hostname_set(efl_added, svr->ssl.verify_name ? svr->ssl.verify_name : svr->name), + efl_net_ssl_context_hostname_verify_set(efl_added, svr->ssl.verify_basic), + efl_net_ssl_context_default_paths_load_set(efl_added, EINA_FALSE), /* old API didn't load default paths */ + efl_net_ssl_context_setup(efl_added, cipher, EINA_TRUE)); + EINA_SAFETY_ON_NULL_GOTO(ssl_ctx, error_ssl_ctx); + + inner_dialer = efl_add(EFL_NET_DIALER_SSL_CLASS, loop, + efl_net_dialer_ssl_context_set(efl_added, ssl_ctx)); + EINA_SAFETY_ON_NULL_GOTO(inner_dialer, error_inner_dialer); + + dialer = efl_add(EFL_NET_DIALER_SIMPLE_CLASS, loop, + efl_io_buffered_stream_inner_io_set(efl_added, inner_dialer)); + EINA_SAFETY_ON_NULL_GOTO(dialer, error_dialer); + + efl_parent_set(inner_dialer, dialer); + + efl_unref(ssl_ctx); /* inner_dialer keeps it */ + efl_unref(inner_dialer); /* dialer keeps it */ + + if (!_ecore_con_server_dialer_set(svr, dialer)) + goto error_dial; + + DBG("dialer=%p configured with inner_dialer=%p, ssl_ctx=%p", + svr->dialer, + efl_io_buffered_stream_inner_io_get(svr->dialer), + efl_net_dialer_ssl_context_get(efl_io_buffered_stream_inner_io_get(svr->dialer))); + + return; + + error_dial: + _ecore_con_post_event_server_error(svr, "Couldn't dial using SSL"); + _ecore_con_post_event_server_del(svr); + return; + + error_dialer: + efl_del(inner_dialer); + error_inner_dialer: + efl_del(ssl_ctx); + error_ssl_ctx: + _ecore_con_post_event_server_error(svr, "Couldn't finish SSL setup"); + _ecore_con_post_event_server_del(svr); +} + +static void +_ecore_con_server_dialer_ssl_upgrade_job(void *data, const Efl_Event *event EINA_UNUSED) +{ + Ecore_Con_Server *svr = data; + Eo *loop = ecore_main_loop_get(); + Eo *ssl_ctx; + Eo *inner_dialer; + Eo *dialer; + Eo *tcp_dialer; + Efl_Net_Ssl_Cipher cipher = EFL_NET_SSL_CIPHER_AUTO; + Efl_Net_Ssl_Verify_Mode verify_mode = EFL_NET_SSL_VERIFY_MODE_NONE; /* was the default */ + Ecore_Con_Type ssl_type = svr->ssl.upgrade_type & ECORE_CON_SSL; + + if (ssl_type & ECORE_CON_USE_MIXED) + cipher = EFL_NET_SSL_CIPHER_AUTO; + else if (ssl_type & ECORE_CON_USE_TLS) + cipher = EFL_NET_SSL_CIPHER_TLSV1; + else if (ssl_type & ECORE_CON_USE_SSL3) + cipher = EFL_NET_SSL_CIPHER_SSLV3; + else if (ssl_type & ECORE_CON_USE_SSL2) + { + ERR("SSLv2 is unsupported!"); + goto error_ssl_ctx; + } + + if (svr->ssl.verify) + verify_mode = EFL_NET_SSL_VERIFY_MODE_REQUIRED; + + ssl_ctx = efl_add(EFL_NET_SSL_CONTEXT_CLASS, NULL, + efl_net_ssl_context_certificates_set(efl_added, eina_list_iterator_new(svr->ssl.certs)), + efl_net_ssl_context_private_keys_set(efl_added, eina_list_iterator_new(svr->ssl.privkeys)), + efl_net_ssl_context_certificate_revogation_lists_set(efl_added, eina_list_iterator_new(svr->ssl.crls)), + efl_net_ssl_context_certificate_authorities_set(efl_added, eina_list_iterator_new(svr->ssl.cafiles)), + efl_net_ssl_context_verify_mode_set(efl_added, verify_mode), + efl_net_ssl_context_hostname_set(efl_added, svr->ssl.verify_name ? svr->ssl.verify_name : svr->name), + efl_net_ssl_context_hostname_verify_set(efl_added, svr->ssl.verify_basic), + efl_net_ssl_context_default_paths_load_set(efl_added, EINA_FALSE), /* old API didn't load default paths */ + efl_net_ssl_context_setup(efl_added, cipher, EINA_TRUE)); + EINA_SAFETY_ON_NULL_GOTO(ssl_ctx, error_ssl_ctx); + + tcp_dialer = svr->dialer; + svr->dialer = NULL; /* take it, will be wrapped */ + + inner_dialer = efl_add(EFL_NET_DIALER_SSL_CLASS, loop, + efl_net_socket_ssl_adopt(efl_added, tcp_dialer, ssl_ctx)); + EINA_SAFETY_ON_NULL_GOTO(inner_dialer, error_inner_dialer); + + efl_parent_set(tcp_dialer, inner_dialer); + + dialer = efl_add(EFL_NET_DIALER_SIMPLE_CLASS, loop, + efl_io_buffered_stream_inner_io_set(efl_added, inner_dialer)); + EINA_SAFETY_ON_NULL_GOTO(dialer, error_dialer); + + efl_parent_set(inner_dialer, dialer); + + efl_unref(ssl_ctx); /* inner_dialer keeps it */ + efl_unref(inner_dialer); /* dialer keeps it */ + + svr->dialer = dialer; + efl_io_closer_close_on_exec_set(dialer, EINA_TRUE); + efl_io_closer_close_on_destructor_set(dialer, EINA_TRUE); + efl_event_callback_array_del(tcp_dialer, _ecore_con_server_dialer_cbs(), svr); + efl_event_callback_array_add(dialer, _ecore_con_server_dialer_cbs(), svr); + + DBG("dialer=%p upgraded to SSL with inner_dialer=%p, ssl_ctx=%p, tcp_dialer=%p. Start handshake...", + svr->dialer, + efl_io_buffered_stream_inner_io_get(svr->dialer), + efl_net_dialer_ssl_context_get(efl_io_buffered_stream_inner_io_get(svr->dialer)), + tcp_dialer); + return; + + error_dialer: + efl_del(inner_dialer); + error_inner_dialer: + svr->dialer = tcp_dialer; /* put it back */ + efl_del(ssl_ctx); + error_ssl_ctx: + _ecore_con_post_event_server_error(svr, "Couldn't finish SSL setup"); + _ecore_con_post_event_server_del(svr); +} + +/** + * @example ecore_con_client_example.c + * + * Shows how to write a simple client (dialer that connects to the + * example server using ecore_con_server_connect(). + */ + +EAPI Ecore_Con_Server * +ecore_con_server_connect(Ecore_Con_Type compl_type, + const char *name, + int port, + const void *data) +{ + const Efl_Class *cls = NULL; + Ecore_Con_Server *svr; + Ecore_Con_Type type; + Eo *dialer; + Eo *loop; + + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + + type = compl_type & ECORE_CON_TYPE; + + loop = ecore_main_loop_get(); + EINA_SAFETY_ON_NULL_RETURN_VAL(loop, NULL); + + svr = _ecore_con_server_new(EINA_TRUE, compl_type, name, port, data); + EINA_SAFETY_ON_NULL_RETURN_VAL(svr, NULL); + + switch (type) + { + case ECORE_CON_LOCAL_USER: + case ECORE_CON_LOCAL_SYSTEM: + case ECORE_CON_LOCAL_ABSTRACT: +#ifdef EFL_NET_DIALER_UNIX_CLASS + cls = EFL_NET_DIALER_UNIX_CLASS; +#else + ERR("Your platform doesn't support Efl_Net_Dialer-compatible local communication"); + // TODO: maybe write to a file and use TCP +#endif + break; + + case ECORE_CON_REMOTE_TCP: + case ECORE_CON_REMOTE_NODELAY: + case ECORE_CON_REMOTE_CORK: + cls = EFL_NET_DIALER_TCP_CLASS; + break; + + case ECORE_CON_REMOTE_UDP: + case ECORE_CON_REMOTE_BROADCAST: + cls = EFL_NET_DIALER_UDP_CLASS; + break; + + default: + ERR("Unsupported type=%#x & %#x = %#x", compl_type, ECORE_CON_TYPE, type); + } + EINA_SAFETY_ON_NULL_GOTO(cls, error); + + if (compl_type & ECORE_CON_SSL) + { + if (cls != EFL_NET_DIALER_TCP_CLASS) + ERR("SSL can only be used with TCP types, got %s, forcing TCP", efl_class_name_get(cls)); + + /* efl_net_ssl_context must be created prior to the object as + * it's immutable once created. However the previous + * Ecore_Con_Server API returned a handle and then configured + * it, like in runtime, but in practice it's only effective + * before the connection happens. + * + * Then do not create the SSL dialer right away, instead do it + * from a job, let the user configure SSL before the job + * finishes. + * + * EINA_SAFETY_ON_NULL_RETURN(svr->ssl.job) will alert users + * trying to configure after the job expires. + * + * We can do that since the documentation says: + * + * > Call this function on a server object before main loop + * > has started to enable verification of certificates + * > against loaded certificates. + */ + efl_future_use(&svr->ssl.job, efl_loop_job(loop, svr)); + efl_future_then(svr->ssl.job, _ecore_con_server_dialer_ssl_job, NULL, NULL, svr); + return svr; + } + + dialer = efl_add(EFL_NET_DIALER_SIMPLE_CLASS, loop, + efl_net_dialer_simple_inner_class_set(efl_added, cls)); + EINA_SAFETY_ON_NULL_GOTO(dialer, error); + + if (!_ecore_con_server_dialer_set(svr, dialer)) + goto error; + + return svr; + + error: + _ecore_con_server_free(svr); + return NULL; +} + +EAPI const char * +ecore_con_server_name_get(const Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RELAXED_RETURN(svr, NULL); + return svr->name; +} + +EAPI void +ecore_con_server_client_limit_set(Ecore_Con_Server *svr, + int client_limit, + char reject_excess_clients) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr); + if (!svr->server) return; + efl_net_server_clients_limit_set(svr->server, client_limit, reject_excess_clients); +} + +EAPI const Eina_List * +ecore_con_server_clients_get(const Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr, NULL); + return svr->clients; +} + +EAPI void +ecore_con_server_timeout_set(Ecore_Con_Server *svr, double timeout) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr); + + svr->timeout = timeout; /* used for new clients */ + + if (!svr->dialer) return; + efl_io_buffered_stream_inactivity_timeout_set(svr->dialer, timeout); +} + +EAPI double +ecore_con_server_timeout_get(const Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr, -1.0); + return svr->timeout; +} + +EAPI void * +ecore_con_server_del(Ecore_Con_Server *svr) +{ + const void *data; + + ECORE_CON_SERVER_CHECK_RELAXED_RETURN(svr, NULL); + + data = svr->data; + + _ecore_con_server_free(svr); + return (void *)data; +} + +EAPI void * +ecore_con_server_data_get(Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RELAXED_RETURN(svr, NULL); + return (void *)svr->data; +} + +EAPI void * +ecore_con_server_data_set(Ecore_Con_Server *svr, + void *data) +{ + const void *old; + + ECORE_CON_SERVER_CHECK_RELAXED_RETURN(svr, NULL); + old = svr->data; + svr->data = data; + return (void *)old; +} + +EAPI Eina_Bool +ecore_con_server_connected_get(const Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr, EINA_FALSE); + if (svr->is_dialer) + { + if (svr->dialer) + return efl_net_dialer_connected_get(svr->dialer); + return EINA_FALSE; /* still setting up SSL */ + } + return EINA_TRUE; +} + +EAPI int +ecore_con_server_port_get(const Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RELAXED_RETURN(svr, -1); + return svr->port; +} + +EAPI int +ecore_con_server_send(Ecore_Con_Server *svr, const void *data, int size) +{ + Eina_Error err; + Eina_Slice slice = { .mem = data, .len = size }; + + ECORE_CON_SERVER_CHECK_RETURN(svr, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0); + EINA_SAFETY_ON_TRUE_RETURN_VAL(size < 1, 0); + EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->ssl.upgrading, 0); + + EINA_SAFETY_ON_NULL_RETURN_VAL(svr->dialer, 0); + err = efl_io_writer_write(svr->dialer, &slice, NULL); + if (err) + { + ERR("svr=%p could not send data=%p, size=%d: %s", + svr, data, size, eina_error_msg_get(err)); + return 0; + } + svr->pending_write = efl_io_buffered_stream_pending_write_get(svr->dialer); + + return slice.len; +} + +EAPI const char * +ecore_con_server_ip_get(const Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RELAXED_RETURN(svr, NULL); + return svr->ip; +} + +EAPI double +ecore_con_server_uptime_get(const Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RELAXED_RETURN(svr, 0.0); + return ecore_time_get() - svr->start_time; +} + +EAPI void +ecore_con_server_flush(Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr); + Eo *inner_dialer; + + if (!svr->dialer) return; + + efl_io_buffered_stream_flush(svr->dialer, EINA_FALSE, EINA_TRUE); + + inner_dialer = efl_io_buffered_stream_inner_io_get(svr->dialer); + + if (!efl_isa(inner_dialer, EFL_NET_SOCKET_TCP_CLASS)) return; + if (!efl_net_socket_tcp_cork_get(inner_dialer)) return; + + efl_net_socket_tcp_cork_set(inner_dialer, EINA_FALSE); + efl_net_socket_tcp_cork_set(inner_dialer, EINA_TRUE); +} + +EAPI int +ecore_con_server_fd_get(const Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr, SOCKET_TO_LOOP_FD(INVALID_SOCKET)); + if (svr->dialer) + { + Eo *inner_dialer = efl_io_buffered_stream_inner_io_get(svr->dialer); + if (efl_isa(inner_dialer, EFL_LOOP_FD_CLASS)) + return efl_loop_fd_get(inner_dialer); + return SOCKET_TO_LOOP_FD(INVALID_SOCKET); + } + if (svr->server) + { + Eo *inner_server = efl_net_server_simple_inner_server_get(svr->server); + if (efl_isa(inner_server, EFL_LOOP_FD_CLASS)) + return efl_loop_fd_get(inner_server); + return SOCKET_TO_LOOP_FD(INVALID_SOCKET); + } + return SOCKET_TO_LOOP_FD(INVALID_SOCKET); +} + +EAPI Eina_Bool +ecore_con_ssl_server_cert_add(Ecore_Con_Server *svr, const char *cert) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(cert, EINA_FALSE); + + if (!svr->server) /* SSL adds a job to allow setup */ + EINA_SAFETY_ON_NULL_RETURN_VAL(svr->ssl.job, EINA_FALSE); + else + EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->ssl.clients_ctx != NULL, EINA_FALSE); + + svr->ssl.certs = eina_list_append(svr->ssl.certs, eina_stringshare_add(cert)); + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_con_ssl_server_privkey_add(Ecore_Con_Server *svr, const char *privkey) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(privkey, EINA_FALSE); + + if (!svr->server) /* SSL adds a job to allow setup */ + EINA_SAFETY_ON_NULL_RETURN_VAL(svr->ssl.job, EINA_FALSE); + else + EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->ssl.clients_ctx != NULL, EINA_FALSE); + + svr->ssl.privkeys = eina_list_append(svr->ssl.privkeys, eina_stringshare_add(privkey)); + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_con_ssl_server_crl_add(Ecore_Con_Server *svr, const char *crl) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(crl, EINA_FALSE); + + if (!svr->server) /* SSL adds a job to allow setup */ + EINA_SAFETY_ON_NULL_RETURN_VAL(svr->ssl.job, EINA_FALSE); + else + EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->ssl.clients_ctx != NULL, EINA_FALSE); + + svr->ssl.crls = eina_list_append(svr->ssl.crls, eina_stringshare_add(crl)); + return EINA_TRUE; +} + +EAPI Eina_Bool +ecore_con_ssl_server_cafile_add(Ecore_Con_Server *svr, const char *cafile) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(cafile, EINA_FALSE); + + if (!svr->server) /* SSL adds a job to allow setup */ + EINA_SAFETY_ON_NULL_RETURN_VAL(svr->ssl.job, EINA_FALSE); + else + EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->ssl.clients_ctx != NULL, EINA_FALSE); + + svr->ssl.cafiles = eina_list_append(svr->ssl.cafiles, eina_stringshare_add(cafile)); + return EINA_TRUE; +} + +EAPI void +ecore_con_ssl_server_verify(Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr); + + if (!svr->server) /* SSL adds a job to allow setup */ + EINA_SAFETY_ON_NULL_RETURN(svr->ssl.job); + else + EINA_SAFETY_ON_TRUE_RETURN(svr->ssl.clients_ctx != NULL); + + if (!svr->is_dialer) + { + /* legacy compatible + print a warning */ + WRN("svr=%p created with ecore_con_server_add()", svr); + return; + } + + svr->ssl.verify = EINA_TRUE; +} + +EAPI void +ecore_con_ssl_server_verify_basic(Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr); + EINA_SAFETY_ON_NULL_RETURN(svr->ssl.job); + + if (!svr->server) /* SSL adds a job to allow setup */ + EINA_SAFETY_ON_NULL_RETURN(svr->ssl.job); + else + EINA_SAFETY_ON_TRUE_RETURN(svr->ssl.clients_ctx != NULL); + + if (!svr->is_dialer) + { + /* legacy compatible + print a warning */ + WRN("svr=%p created with ecore_con_server_add()", svr); + return; + } + + svr->ssl.verify_basic = EINA_TRUE; +} + +EAPI void +ecore_con_ssl_server_verify_name_set(Ecore_Con_Server *svr, const char *name) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr); + EINA_SAFETY_ON_NULL_RETURN(name); + + if (!svr->server) /* SSL adds a job to allow setup */ + EINA_SAFETY_ON_NULL_RETURN(svr->ssl.job); + else + EINA_SAFETY_ON_TRUE_RETURN(svr->ssl.clients_ctx != NULL); + + eina_stringshare_replace(&svr->ssl.verify_name, name); +} + +EAPI const char * +ecore_con_ssl_server_verify_name_get(Ecore_Con_Server *svr) +{ + ECORE_CON_SERVER_CHECK_RETURN(svr, NULL); + return svr->ssl.verify_name ? svr->ssl.verify_name : svr->name; +} + +EAPI Eina_Bool +ecore_con_ssl_server_upgrade(Ecore_Con_Server *svr, Ecore_Con_Type compl_type) +{ + double start; + + ECORE_CON_SERVER_CHECK_RETURN(svr, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(svr->dialer, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->server != NULL, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->ssl.upgrading, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL((compl_type & ECORE_CON_SSL) == 0, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(efl_io_buffered_stream_inner_io_get(svr->dialer), EFL_NET_DIALER_TCP_CLASS), EINA_FALSE); + + start = ecore_time_get(); + while (efl_io_buffered_stream_pending_write_get(svr->dialer) && ((ecore_time_get() - start) <= ecore_animator_frametime_get())) + ecore_con_server_flush(svr); + if (efl_io_buffered_stream_pending_write_get(svr->dialer)) + { + ERR("svr=%p still pending send %zd bytes! Flush server before upgrading to SSL!", + svr, efl_io_buffered_stream_pending_write_get(svr->dialer)); + return EINA_FALSE; + } + + svr->ssl.upgrading = EINA_TRUE; + svr->ssl.upgrade_type = compl_type; + efl_future_use(&svr->ssl.job, efl_loop_job(efl_loop_get(svr->dialer), svr)); + efl_future_then(svr->ssl.job, _ecore_con_server_dialer_ssl_upgrade_job, NULL, NULL, svr); + + DBG("svr=%p SSL upgrading from %#x to type=%#x", svr, svr->type, compl_type); + + return EINA_TRUE; +} + +/** + * @} + */ + +static void +_ecore_con_lookup_done_cb(void *data, const char *host, const char *port EINA_UNUSED, const struct addrinfo *hints EINA_UNUSED, struct addrinfo *result, int gai_error) +{ + Ecore_Con_Lookup_Ctx *ctx = data; + + ctx->thread = NULL; + + if (gai_error) + WRN("Failed to lookup host='%s': %s", host, gai_strerror(gai_error)); + else if (result) + { + char ip[INET6_ADDRSTRLEN]; + const void *mem; + + if (result->ai_family == AF_INET) + { + const struct sockaddr_in *a = (const struct sockaddr_in *)result->ai_addr; + mem = &a->sin_addr; + } + else if (result->ai_family == AF_INET6) + { + const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)result->ai_addr; + mem = &a->sin6_addr; + } + else + { + ERR("unexpected result->ai_family=%d", result->ai_family); + goto end; + } + + if (!inet_ntop(result->ai_family, mem, ip, sizeof(ip))) + { + ERR("could not convert IP to string: %s", strerror(errno)); + goto end; + } + ctx->cb(result->ai_canonname, ip, result->ai_addr, result->ai_addrlen, (void *)ctx->data); + } + + end: + freeaddrinfo(result); + _ecore_con_lookups = eina_list_remove(_ecore_con_lookups, ctx); + free(ctx); +} + +/* + * NOTE: this function has numerous problems: + * - not able to specify family (IPv4 or IPv6 or both). + * - callback reports a single result + * - doesn't return a handle to cancel (likely to access memory after free) + * - doesn't report errors + */ +EAPI Eina_Bool +ecore_con_lookup(const char *name, Ecore_Con_Dns_Cb done_cb, const void *data) +{ + Ecore_Con_Lookup_Ctx *ctx; + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_flags = AI_ADDRCONFIG | AI_V4MAPPED | AI_CANONNAME, + }; + + EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, EINA_FALSE); + + ctx = malloc(sizeof(Ecore_Con_Lookup_Ctx)); + EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE); + ctx->cb = done_cb; + ctx->data = data; + + ctx->thread = efl_net_ip_resolve_async_new(name, "0", &hints, _ecore_con_lookup_done_cb, ctx); + EINA_SAFETY_ON_NULL_GOTO(ctx->thread, error); + + _ecore_con_lookups = eina_list_append(_ecore_con_lookups, ctx); + return EINA_TRUE; + + error: + free(ctx); + return EINA_FALSE; +} diff --git a/src/lib/ecore_con/ecore_con_local.c b/src/lib/ecore_con/ecore_con_local.c index 1cccf046b0..a66a8b4500 100644 --- a/src/lib/ecore_con/ecore_con_local.c +++ b/src/lib/ecore_con/ecore_con_local.c @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include #ifdef HAVE_SYSTEMD @@ -28,16 +26,8 @@ #include "Ecore_Con.h" #include "ecore_con_private.h" -#define LENGTH_OF_SOCKADDR_UN(s) (strlen((s)->sun_path) + \ - (size_t)(((struct sockaddr_un *)NULL)-> \ - sun_path)) -#define LENGTH_OF_ABSTRACT_SOCKADDR_UN(s, path) (strlen(path) + 1 + \ - (size_t)(((struct sockaddr_un \ - *)NULL)->sun_path)) - -static int _ecore_con_local_init_count = 0; - -static const char *_ecore_con_local_path_get() +static const char * +_ecore_con_local_path_get(void) { const char *homedir = getenv("XDG_RUNTIME_DIR"); if (!homedir) homedir = eina_environment_home_get(); @@ -46,24 +36,6 @@ static const char *_ecore_con_local_path_get() return homedir; } -int -ecore_con_local_init(void) -{ - if (++_ecore_con_local_init_count != 1) - return _ecore_con_local_init_count; - - return _ecore_con_local_init_count; -} - -int -ecore_con_local_shutdown(void) -{ - if (--_ecore_con_local_init_count != 0) - return _ecore_con_local_init_count; - - return _ecore_con_local_init_count; -} - EAPI char * ecore_con_local_path_new(Eina_Bool is_system, const char *name, int port) { @@ -125,110 +97,6 @@ ecore_con_local_path_new(Eina_Bool is_system, const char *name, int port) } } -int -ecore_con_local_connect(Ecore_Con_Server *obj, - Eina_Bool (*cb_done)(void *data, Ecore_Fd_Handler *fd_handler), - void *data EINA_UNUSED) -{ -#ifndef HAVE_LOCAL_SOCKETS - return 0; -#else - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - char *buf = NULL; - struct sockaddr_un socket_unix; - int curstate = 0; - int socket_unix_len; - - if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) - { - buf = ecore_con_local_path_new(EINA_FALSE, svr->name, svr->port); - } - else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM) - { - buf = ecore_con_local_path_new(EINA_TRUE, svr->name, svr->port); - } - else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) - { - buf = strdup(svr->name); - } - - EINA_SAFETY_ON_NULL_RETURN_VAL(buf, 0); - - svr->fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (svr->fd < 0) - { - free(buf); - return 0; - } - - 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, (const void *)&curstate, - sizeof(curstate)) < 0) - goto error; - - socket_unix.sun_family = AF_UNIX; - - if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) - { -#ifdef HAVE_ABSTRACT_SOCKETS - /* copy name insto sun_path, prefixed by null to indicate abstract namespace */ - snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", - svr->name); - socket_unix.sun_path[0] = '\0'; - socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, - svr->name); -#else - WRN("Your system does not support abstract sockets!"); - goto error; -#endif - } - else - { - strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path) - 1); - socket_unix.sun_path[sizeof(socket_unix.sun_path) - 1] = '\0'; - socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix); - } - - if (connect(svr->fd, (struct sockaddr *)&socket_unix, - socket_unix_len) < 0) - { - DBG("local connection failed: %s", strerror(errno)); - goto error; - } - - svr->path = buf; - buf = NULL; - - if (svr->type & ECORE_CON_SSL) - { - if (!ecore_con_ssl_server_init(obj)) ERR("Can't init SSL"); - } - - svr->fd_handler = - ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, - cb_done, obj, NULL, NULL); - if (!svr->fd_handler) - goto error; - - if (!svr->delete_me) ecore_con_event_server_add(obj); - - free(buf); - - return 1; -error: - if (svr->fd) close(svr->fd); - svr->fd = -1; - free(buf); - return 0; -#endif -} - -#ifdef HAVE_LOCAL_SOCKETS void _ecore_con_local_mkpath(const char *path, mode_t mode) { @@ -274,168 +142,3 @@ _ecore_con_local_mkpath(const char *path, mode_t mode) end: free(s); } -#endif - -int -ecore_con_local_listen( - Ecore_Con_Server *obj, - Eina_Bool (* - cb_listen)(void *data, - Ecore_Fd_Handler * - fd_handler), - void *data - EINA_UNUSED) -{ -#ifdef HAVE_LOCAL_SOCKETS - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - char *buf = NULL; - struct sockaddr_un socket_unix; - struct linger lin; - mode_t pmode; - mode_t mask; - int socket_unix_len; - Eina_Bool abstract_socket; - - mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH; - - if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) - { - buf = ecore_con_local_path_new(EINA_FALSE, svr->name, svr->port); - - mask = S_IRUSR | S_IWUSR | S_IXUSR; - _ecore_con_local_mkpath(buf, mask); - - mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH; - } - else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM) - { - mask = 0; - buf = ecore_con_local_path_new(EINA_TRUE, svr->name, svr->port); - } - else if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) - { - buf = strdup(svr->name); - } - - EINA_SAFETY_ON_NULL_RETURN_VAL(buf, 0); - - pmode = umask(mask); -start: - socket_unix.sun_family = AF_UNIX; - if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT) - { - abstract_socket = EINA_TRUE; -#ifdef HAVE_ABSTRACT_SOCKETS - /* . is a placeholder */ - snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", - svr->name); - /* first char null indicates abstract namespace */ - socket_unix.sun_path[0] = '\0'; - socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, - svr->name); -#else - ERR("Your system does not support abstract sockets!"); - goto error_umask; -#endif - } - else - { - abstract_socket = EINA_FALSE; - strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path) - 1); - socket_unix.sun_path[sizeof(socket_unix.sun_path) - 1] = '\0'; - socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix); - } - -#ifdef HAVE_SYSTEMD - if (svr->type & ECORE_CON_SOCKET_ACTIVATE && sd_fd_index < sd_fd_max) - { - if (sd_is_socket_unix(SD_LISTEN_FDS_START + sd_fd_index, - SOCK_STREAM, 1, - socket_unix.sun_path, - abstract_socket ? socket_unix_len : 0) <= 0) - { - ERR("Your systemd unit seems to provide fd in the wrong order for Socket activation."); - goto error_umask; - } - svr->fd = SD_LISTEN_FDS_START + sd_fd_index++; - - if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) - goto error_umask; - - lin.l_onoff = 1; - lin.l_linger = 0; - if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin, - sizeof(struct linger)) < 0) - goto error_umask; - - goto fd_ready; - } -#else - (void)abstract_socket; -#endif - svr->fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (svr->fd < 0) - goto error_umask; - - if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) - goto error_fd; - - if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) - goto error_fd; - - lin.l_onoff = 1; - lin.l_linger = 0; - if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin, - sizeof(struct linger)) < 0) - goto error_fd; - - if (bind(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) - { - DBG("Local socket '%s' bind failed: %s", buf, strerror(errno)); - if ((((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) || - ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_SYSTEM)) && - (connect(svr->fd, (struct sockaddr *)&socket_unix, - socket_unix_len) < 0)) - { - DBG("Local socket '%s' connect test failed: %s", buf, strerror(errno)); - if (unlink(buf) >= 0) - goto start; - else - { - DBG("Local socket '%s' removal failed: %s", buf, strerror(errno)); - goto error_fd; - } - } - } - - if (listen(svr->fd, 4096) < 0) - goto error_fd; - -#ifdef HAVE_SYSTEMD -fd_ready: -#endif - svr->path = buf; - buf = NULL; - - svr->fd_handler = - ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, - cb_listen, obj, NULL, NULL); - umask(pmode); - if (!svr->fd_handler) - goto error; - - free(buf); - - return 1; - -error_fd: - close(svr->fd); - svr->fd = -1; -error_umask: - umask(pmode); -error: - free(buf); -#endif /* HAVE_LOCAL_SOCKETS */ - return 0; -} - diff --git a/src/lib/ecore_con/ecore_con_private.h b/src/lib/ecore_con/ecore_con_private.h index 9db016b003..639fb0d17f 100644 --- a/src/lib/ecore_con/ecore_con_private.h +++ b/src/lib/ecore_con/ecore_con_private.h @@ -8,20 +8,14 @@ #define ECORE_MAGIC_CON_CLIENT 0x77556677 #define ECORE_MAGIC_CON_URL 0x77074255 -#define ECORE_CON_TYPE 0x0f -#define ECORE_CON_SSL 0xf0 -#define ECORE_CON_SUPER_SSL 0xf00 - -#if HAVE_GNUTLS -# include -#elif HAVE_OPENSSL -# include -#endif - #ifdef HAVE_SYS_UN_H #include #endif +#ifdef HAVE_NETINET_IN_H +# include +#endif + #include #define READBUFSIZ 65536 @@ -58,174 +52,8 @@ extern int _ecore_con_log_dom; #endif #define CRI(...) EINA_LOG_DOM_CRIT(_ecore_con_log_dom, __VA_ARGS__) -typedef struct _Ecore_Con_Lookup Ecore_Con_Lookup; -typedef struct _Ecore_Con_Info Ecore_Con_Info; typedef struct Ecore_Con_Socks Ecore_Con_Socks_v4; typedef struct Ecore_Con_Socks_v5 Ecore_Con_Socks_v5; -typedef void (*Ecore_Con_Info_Cb)(void *data, Ecore_Con_Info *infos); - -typedef enum _Ecore_Con_State -{ - ECORE_CON_CONNECTED, - ECORE_CON_DISCONNECTED, - ECORE_CON_INPROGRESS -} Ecore_Con_State; - -typedef enum _Ecore_Con_Ssl_Error -{ - ECORE_CON_SSL_ERROR_NONE = 0, - ECORE_CON_SSL_ERROR_NOT_SUPPORTED, - ECORE_CON_SSL_ERROR_INIT_FAILED, - ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED, - ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED, - ECORE_CON_SSL_ERROR_SSL3_NOT_SUPPORTED -} Ecore_Con_Ssl_Error; - -typedef enum _Ecore_Con_Ssl_Handshake -{ - ECORE_CON_SSL_STATE_DONE = 0, - ECORE_CON_SSL_STATE_HANDSHAKING, - ECORE_CON_SSL_STATE_INIT -} Ecore_Con_Ssl_State; - -typedef enum Ecore_Con_Proxy_State -{ /* named PROXY instead of SOCKS in case some handsome and enterprising - * developer decides to add HTTP CONNECT support - */ - ECORE_CON_PROXY_STATE_DONE = 0, - ECORE_CON_PROXY_STATE_RESOLVED, - ECORE_CON_PROXY_STATE_INIT, - ECORE_CON_PROXY_STATE_READ, - ECORE_CON_PROXY_STATE_AUTH, - ECORE_CON_PROXY_STATE_REQUEST, - ECORE_CON_PROXY_STATE_CONFIRM, -} Ecore_Con_Proxy_State; - -struct _Efl_Network_Client_Data -{ -#ifdef _WIN32 - SOCKET fd; -#else - int fd; -#endif - Ecore_Con_Server *host_server; - void *data; - Ecore_Fd_Handler *fd_handler; - size_t buf_offset; - Eina_Binbuf *buf; - const char *ip; - Eina_List *event_count; - struct sockaddr *client_addr; - int client_addr_len; - double start_time; - Ecore_Timer *until_deletion; - double disconnect_time; -#if HAVE_GNUTLS - gnutls_datum_t session_ticket; - gnutls_session_t session; -#elif HAVE_OPENSSL - SSL *ssl; - int ssl_err; -#endif - Ecore_Con_Ssl_State ssl_state; - Eina_Bool handshaking : 1; - Eina_Bool upgrade : 1; /* STARTTLS queued */ - Eina_Bool delete_me : 1; /* del event has been queued */ -}; - -typedef struct _Efl_Network_Client_Data Efl_Network_Client_Data; - -struct _Efl_Network_Server_Data -{ -#ifdef _WIN32 - SOCKET fd; -#else - int fd; -#endif - Ecore_Con_Type type; - char *name; - int port; - char *path; - void *data; - Ecore_Fd_Handler *fd_handler; - Eina_List *clients; - unsigned int client_count; - Eina_Binbuf *buf; - size_t write_buf_offset; - Eina_List *infos; - Eina_List *event_count; - int client_limit; - pid_t ppid; - /* socks */ - Ecore_Con_Socks *ecs; - Ecore_Con_Proxy_State ecs_state; - int ecs_addrlen; - unsigned char ecs_addr[16]; - size_t ecs_buf_offset; - Eina_Binbuf *ecs_buf; - Eina_Binbuf *ecs_recvbuf; - const char *proxyip; - int proxyport; - /* endsocks */ - const char *verify_name; -#if HAVE_GNUTLS - gnutls_session_t session; - gnutls_anon_client_credentials_t anoncred_c; - gnutls_anon_server_credentials_t anoncred_s; - gnutls_psk_client_credentials_t pskcred_c; - gnutls_psk_server_credentials_t pskcred_s; - gnutls_certificate_credentials_t cert; - char *cert_file; - gnutls_dh_params_t dh_params; -#elif HAVE_OPENSSL - SSL_CTX *ssl_ctx; - SSL *ssl; - int ssl_err; -#endif - double start_time; - Ecore_Timer *until_deletion; - double disconnect_time; - double client_disconnect_time; - const char *ip; - Eina_Bool created : 1; /* @c EINA_TRUE if server is our listening server */ - Eina_Bool connecting : 1; /* @c EINA_FALSE if just initialized or connected */ - Eina_Bool handshaking : 1; /* @c EINA_TRUE if server is ssl handshaking */ - Eina_Bool upgrade : 1; /* STARTTLS queued */ - Eina_Bool disable_proxy : 1; /* proxy should never be used with this connection */ - Eina_Bool ssl_prepared : 1; - Eina_Bool use_cert : 1; /* @c EINA_TRUE if using certificate auth */ - Ecore_Con_Ssl_State ssl_state; /* current state of ssl handshake on the server */ - Eina_Bool verify : 1; /* @c EINA_TRUE if certificates will be verified */ - Eina_Bool verify_basic : 1; /* @c EINA_TRUE if certificates will be verified only against the hostname */ - Eina_Bool reject_excess_clients : 1; - Eina_Bool delete_me : 1; /* del event has been queued */ -#ifdef _WIN32 - Eina_Bool want_write : 1; - Eina_Bool read_stop : 1; - Eina_Bool read_stopped : 1; - HANDLE pipe; - HANDLE thread_read; - HANDLE event_read; - HANDLE event_peek; - DWORD nbr_bytes; -#endif -}; - -typedef struct _Efl_Network_Server_Data Efl_Network_Server_Data; - -struct _Ecore_Con_Info -{ - unsigned int size; - struct addrinfo info; - char ip[NI_MAXHOST]; - char service[NI_MAXSERV]; -}; - -struct _Ecore_Con_Lookup -{ - Ecore_Con_Dns_Cb done_cb; - const void *data; -}; struct Ecore_Con_Socks /* v4 */ { @@ -267,124 +95,18 @@ void ecore_con_libproxy_proxies_free(char **proxies); char **ecore_con_libproxy_proxies_get(const char *url); +Eina_Bool ecore_con_server_check(const Ecore_Con_Server *svr); + extern Ecore_Con_Socks *_ecore_con_proxy_once; extern Ecore_Con_Socks *_ecore_con_proxy_global; void ecore_con_socks_init(void); void ecore_con_socks_shutdown(void); -Eina_Bool ecore_con_socks_svr_init(Ecore_Con_Server *svr); -void ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num); -void ecore_con_socks_dns_cb(const char *canonname, const char *ip, struct sockaddr *addr, int addrlen, Ecore_Con_Server *svr); - -/* from ecore_con.c */ -void ecore_con_server_infos_del(Ecore_Con_Server *svr, void *info); -void ecore_con_event_proxy_bind(Ecore_Con_Server *svr); -void ecore_con_event_server_data(Ecore_Con_Server *svr, unsigned char *buf, int num, Eina_Bool duplicate); -void ecore_con_event_server_del(Ecore_Con_Server *svr); -#define ecore_con_event_server_error(svr, error) _ecore_con_event_server_error((svr), (char*)(error), EINA_TRUE) -void _ecore_con_event_server_error(Ecore_Con_Server *svr, char *error, Eina_Bool duplicate); -void ecore_con_event_client_add(Ecore_Con_Client *cl); -void ecore_con_event_client_data(Ecore_Con_Client *cl, unsigned char *buf, int num, Eina_Bool duplicate); -void ecore_con_event_client_del(Ecore_Con_Client *cl); -void ecore_con_event_client_error(Ecore_Con_Client *cl, const char *error); -void _ecore_con_server_kill(Ecore_Con_Server *svr); -void _ecore_con_client_kill(Ecore_Con_Client *cl); - -int ecore_con_local_init(void); -int ecore_con_local_shutdown(void); -/* from ecore_local_win32.c */ -#ifdef _WIN32 -Eina_Bool ecore_con_local_listen(Ecore_Con_Server *svr); -Eina_Bool ecore_con_local_connect(Ecore_Con_Server *svr, - Eina_Bool (*cb_done)(void *data, - Ecore_Fd_Handler *fd_handler)); -Eina_Bool ecore_con_local_win32_server_flush(Ecore_Con_Server *svr); -Eina_Bool ecore_con_local_win32_client_flush(Ecore_Con_Client *cl); -void ecore_con_local_win32_server_del(Ecore_Con_Server *svr); -void ecore_con_local_win32_client_del(Ecore_Con_Client *cl); -#else -/* from ecore_local.c */ -int ecore_con_local_connect(Ecore_Con_Server *svr, - Eina_Bool (*cb_done)( - void *data, - Ecore_Fd_Handler *fd_handler), - void *data); -int ecore_con_local_listen(Ecore_Con_Server *svr, - Eina_Bool (*cb_listen)( - void *data, - Ecore_Fd_Handler *fd_handler), - void *data); -#endif - -/* from ecore_con_info.c */ -int ecore_con_info_init(void); -int ecore_con_info_shutdown(void); -int ecore_con_info_tcp_connect(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data); -int ecore_con_info_tcp_listen(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data); -int ecore_con_info_udp_connect(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data); -int ecore_con_info_udp_listen(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data); -int ecore_con_info_mcast_listen(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data); -void ecore_con_info_data_clear(void *info); - -void ecore_con_event_server_add(Ecore_Con_Server *svr); - - -/* from ecore_con_ssl.c */ -Ecore_Con_Ssl_Error ecore_con_ssl_init(void); -Ecore_Con_Ssl_Error ecore_con_ssl_shutdown(void); -Ecore_Con_Ssl_Error ecore_con_ssl_server_prepare(Ecore_Con_Server *svr, int ssl_type); -Ecore_Con_Ssl_Error ecore_con_ssl_server_init(Ecore_Con_Server *svr); -Ecore_Con_Ssl_Error ecore_con_ssl_server_shutdown(Ecore_Con_Server *svr); -int ecore_con_ssl_server_read(Ecore_Con_Server *svr, - unsigned char *buf, - int size); -int ecore_con_ssl_server_write(Ecore_Con_Server *svr, - const unsigned char *buf, - int size); -Ecore_Con_Ssl_Error ecore_con_ssl_client_init(Ecore_Con_Client *svr); -Ecore_Con_Ssl_Error ecore_con_ssl_client_shutdown(Ecore_Con_Client *svr); -int ecore_con_ssl_client_read(Ecore_Con_Client *svr, - unsigned char *buf, - int size); -int ecore_con_ssl_client_write(Ecore_Con_Client *svr, - const unsigned char *buf, - int size); - -int ecore_con_info_get(Ecore_Con_Server *svr, - Ecore_Con_Info_Cb done_cb, - void *data, - struct addrinfo *hints); - - -#define GENERIC_ALLOC_FREE_HEADER(TYPE, Type) \ - TYPE *Type##_alloc(void); \ - void Type##_free(TYPE *e); - -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Add, ecore_con_event_client_add); -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Del, ecore_con_event_client_del); -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Write, ecore_con_event_client_write); -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Data, ecore_con_event_client_data); -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Error, ecore_con_event_server_error); -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Client_Error, ecore_con_event_client_error); -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Add, ecore_con_event_server_add); -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Del, ecore_con_event_server_del); -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Write, ecore_con_event_server_write); -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Data, ecore_con_event_server_data); -GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Proxy_Bind, ecore_con_event_proxy_bind); void ecore_con_mempool_init(void); void ecore_con_mempool_shutdown(void); -#undef GENERIC_ALLOC_FREE_HEADER +void ecore_con_legacy_init(void); +void ecore_con_legacy_shutdown(void); void _ecore_con_local_mkpath(const char *path, mode_t mode); @@ -429,6 +151,9 @@ void _ecore_con_local_mkpath(const char *path, mode_t mode); #ifndef AI_ADDRCONFIG #define AI_ADDRCONFIG 0 #endif +#ifndef AI_CANONNAME +#define AI_CANONNAME 0 +#endif /* Windows do not define EAI_SYSTEM, so just define to some number * that won't be matched, effectively disabling the subsequent diff --git a/src/lib/ecore_con/ecore_con_socks.c b/src/lib/ecore_con/ecore_con_socks.c index 0b8425957f..a81d37505f 100644 --- a/src/lib/ecore_con/ecore_con_socks.c +++ b/src/lib/ecore_con/ecore_con_socks.c @@ -47,36 +47,6 @@ #include "Ecore_Con.h" #include "ecore_con_private.h" -#if defined(_WIN32) && !defined(IF_NAMESIZE) -#define IF_NAMESIZE 16 -#endif - -/* http://tools.ietf.org/html/rfc1928 - o X'00' NO AUTHENTICATION REQUIRED - o X'01' GSSAPI - o X'02' USERNAME/PASSWORD - o X'03' to X'7F' IANA ASSIGNED - o X'80' to X'FE' RESERVED FOR PRIVATE METHODS - o X'FF' NO ACCEPTABLE METHODS - */ -#define ECORE_CON_SOCKS_V5_METHOD_NONE 0 -#define ECORE_CON_SOCKS_V5_METHOD_GSSAPI 1 -#define ECORE_CON_SOCKS_V5_METHOD_USERPASS 2 - -static int ECORE_CON_SOCKS_V5_METHODS[] = -{ - ECORE_CON_SOCKS_V5_METHOD_NONE, -// ECORE_CON_SOCKS_V5_METHOD_GSSAPI, TODO - ECORE_CON_SOCKS_V5_METHOD_USERPASS -}; - -#define ECORE_CON_SOCKS_V5_TOTAL_METHODS (sizeof(ECORE_CON_SOCKS_V5_METHODS) / sizeof(int)) - -#define _ecore_con_server_kill(svr) do { \ - DBG("KILL %p", (svr)); \ - _ecore_con_server_kill((svr)); \ - } while (0) - #define ECORE_CON_SOCKS_VERSION_CHECK(X) do { \ if (!(X) || ((X)->version < 4) || ((X)->version > 5)) \ return; \ @@ -86,15 +56,7 @@ static int ECORE_CON_SOCKS_V5_METHODS[] = return (ret); \ } while (0) -#define ECORE_CON_SOCKS_CAST(X) \ - Ecore_Con_Socks_v4 * v4 = NULL; \ - Ecore_Con_Socks_v5 *v5 = NULL; \ - if ((X) && ((X)->version == 4)) \ - v4 = (Ecore_Con_Socks_v4 *)(X); \ - else if ((X) && ((X)->version == 5)) \ - v5 = (Ecore_Con_Socks_v5 *)(X); - -Eina_List *ecore_con_socks_proxies = NULL; +static Eina_List *ecore_con_socks_proxies = NULL; static Ecore_Con_Socks * _ecore_con_socks_find(unsigned char version, const char *ip, int port, const char *username, size_t ulen, const char *password, size_t plen) @@ -133,405 +95,6 @@ _ecore_con_socks_free(Ecore_Con_Socks *ecs) free(ecs); } -static Eina_Bool -_ecore_con_socks_svr_init_v4(Ecore_Con_Server *obj, Ecore_Con_Socks_v4 *v4) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - size_t addrlen, buflen, ulen = 1; - unsigned char *sbuf; - - addrlen = v4->lookup ? strlen(svr->name) + 1 : 0; - if (v4->username) ulen += v4->ulen; - buflen = sizeof(char) * (8 + ulen + addrlen); - sbuf = malloc(buflen); - if (!sbuf) - { - ecore_con_event_server_error(obj, "Memory allocation failure!"); - _ecore_con_server_kill(obj); - return EINA_FALSE; - } - /* http://en.wikipedia.org/wiki/SOCKS */ - sbuf[0] = 4; - sbuf[1] = v4->bind ? 2 : 1; - sbuf[2] = svr->port >> 8; - sbuf[3] = svr->port & 0xff; - if (addrlen) - { - sbuf[4] = sbuf[5] = sbuf[6] = 0; - sbuf[7] = 1; - } - else - /* SOCKSv4 only handles IPV4, so addrlen is always 4 */ - memcpy(sbuf + 4, svr->ecs_addr, 4); - if (v4->username) - memcpy(sbuf + 8, v4->username, ulen); - else - sbuf[8] = 0; - if (addrlen) memcpy(sbuf + 8 + ulen, svr->name, addrlen); - - svr->ecs_buf = eina_binbuf_manage_new(sbuf, buflen, EINA_FALSE); - return EINA_TRUE; -} - -static Eina_Bool -_ecore_con_socks_svr_init_v5(Ecore_Con_Server *obj, Ecore_Con_Socks_v5 *v5) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - size_t buflen; - unsigned int x; - unsigned char *sbuf; - - if (v5->username) - buflen = sizeof(char) * (2 + ECORE_CON_SOCKS_V5_TOTAL_METHODS); - else - buflen = 3; - sbuf = malloc(buflen); - if (!sbuf) - { - ecore_con_event_server_error(obj, "Memory allocation failure!"); - _ecore_con_server_kill(obj); - return EINA_FALSE; - } - /* http://en.wikipedia.org/wiki/SOCKS - * http://tools.ietf.org/html/rfc1928 - */ - sbuf[0] = 5; - if (v5->username) - { - sbuf[1] = ECORE_CON_SOCKS_V5_TOTAL_METHODS; - for (x = 2; x < 2 + ECORE_CON_SOCKS_V5_TOTAL_METHODS; x++) - sbuf[x] = ECORE_CON_SOCKS_V5_METHODS[x - 2]; - } - else - { - sbuf[1] = 1; - sbuf[2] = ECORE_CON_SOCKS_V5_METHOD_NONE; - } - - svr->ecs_buf = eina_binbuf_manage_new(sbuf, buflen, EINA_FALSE); - return EINA_TRUE; -} - -#define ECORE_CON_SOCKS_READ(EXACT) \ - if (num < EXACT) \ - { \ - if (!svr->ecs_recvbuf) svr->ecs_recvbuf = eina_binbuf_new(); \ - if (!svr->ecs_recvbuf) goto error; \ - eina_binbuf_append_length(svr->ecs_recvbuf, buf, num); \ - /* the slowest connection on earth */ \ - if (eina_binbuf_length_get(svr->ecs_recvbuf) != EXACT) return; \ - data = eina_binbuf_string_get(svr->ecs_recvbuf); \ - } \ - else if (num > EXACT) \ - goto error; \ - else \ - data = buf - -static void -_ecore_con_socks_read_v4(Ecore_Con_Server *obj, Ecore_Con_Socks_v4 *v4 EINA_UNUSED, const unsigned char *buf, unsigned int num) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - const unsigned char *data; - DBG("SOCKS: %d bytes", num); - ECORE_CON_SOCKS_READ(8); - -/* http://ufasoft.com/doc/socks4_protocol.htm */ - if (data[0]) goto error; - switch (data[1]) - { - case 90: - /* success! */ - break; - - case 91: - ecore_con_event_server_error(obj, "proxy request rejected or failed"); - goto error; - - case 92: - ecore_con_event_server_error(obj, "proxying SOCKS server could not perform authentication"); - goto error; - - case 93: - ecore_con_event_server_error(obj, "proxy request authentication rejected"); - goto error; - - default: - ecore_con_event_server_error(obj, "garbage data from proxy"); - goto error; - } - if (svr->ecs->bind) - { - unsigned int nport; - char naddr[IF_NAMESIZE]; - - memcpy(&nport, &data[2], 2); - svr->proxyport = ntohl(nport); - - if (!inet_ntop(AF_INET, &data[4], naddr, sizeof(naddr))) goto error; - svr->proxyip = eina_stringshare_add(naddr); - ecore_con_event_proxy_bind(obj); - } - svr->ecs_state = ECORE_CON_PROXY_STATE_DONE; - INF("PROXY CONNECTED"); - if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf); - svr->ecs_recvbuf = NULL; - svr->ecs_buf_offset = svr->ecs_addrlen = 0; - memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr)); - if (!svr->ssl_state) - ecore_con_event_server_add(obj); - if (svr->ssl_state || (svr->buf && eina_binbuf_length_get(svr->buf))) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE); - return; -error: - _ecore_con_server_kill(obj); -} - -static Eina_Bool -_ecore_con_socks_auth_v5(Ecore_Con_Server *obj, Ecore_Con_Socks_v5 *v5) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - size_t size; - unsigned char *data; - switch (v5->method) - { - case ECORE_CON_SOCKS_V5_METHOD_NONE: - svr->ecs_state = ECORE_CON_PROXY_STATE_REQUEST; - return EINA_TRUE; - - case ECORE_CON_SOCKS_V5_METHOD_GSSAPI: - return EINA_TRUE; - - case ECORE_CON_SOCKS_V5_METHOD_USERPASS: - if (!v5->username) return EINA_FALSE; - if (!v5->password) v5->plen = 1; - /* http://tools.ietf.org/html/rfc1929 */ - size = sizeof(char) * (3 + v5->ulen + v5->plen); - data = malloc(size); - if (!data) break; - data[0] = 1; - data[1] = v5->ulen; - memcpy(&data[2], v5->username, v5->ulen); - data[1 + v5->ulen] = v5->plen; - if (v5->password) - memcpy(&data[2 + v5->ulen], v5->password, v5->plen); - else - data[2 + v5->ulen] = 0; - svr->ecs_buf = eina_binbuf_manage_new(data, size, EINA_FALSE); - return EINA_TRUE; - - default: - break; - } - return EINA_FALSE; -} - -static void -_ecore_con_socks_read_v5(Ecore_Con_Server *obj, Ecore_Con_Socks_v5 *v5, const unsigned char *buf, unsigned int num) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - const unsigned char *data; - - DBG("SOCKS: %d bytes", num); - switch (svr->ecs_state) - { - case ECORE_CON_PROXY_STATE_READ: - ECORE_CON_SOCKS_READ(2); - /* http://en.wikipedia.org/wiki/SOCKS */ - if (data[0] != 5) goto error; - if (data[1] == 0xFF) - { - ecore_con_event_server_error(obj, "proxy authentication methods rejected"); - goto error; - } - v5->method = data[1]; - if (!_ecore_con_socks_auth_v5(obj, v5)) goto error; - if (svr->ecs_state == ECORE_CON_PROXY_STATE_REQUEST) - { - /* run again to skip auth reading */ - _ecore_con_socks_read_v5(obj, v5, NULL, 0); - return; - } - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); - svr->ecs_state = ECORE_CON_PROXY_STATE_AUTH; - break; - - case ECORE_CON_PROXY_STATE_AUTH: - ECORE_CON_SOCKS_READ(2); - switch (v5->method) - { - case ECORE_CON_SOCKS_V5_METHOD_NONE: - CRI("HOW DID THIS HAPPEN?????????"); - goto error; - - case ECORE_CON_SOCKS_V5_METHOD_GSSAPI: - /* TODO: this */ - break; - - case ECORE_CON_SOCKS_V5_METHOD_USERPASS: - if (data[0] != 1) - { - ecore_con_event_server_error(obj, "protocol error"); - goto error; /* wrong version */ - } - if (data[1]) - { - ecore_con_event_server_error(obj, "proxy request authentication rejected"); - goto error; - } - - default: - break; - } - break; - - case ECORE_CON_PROXY_STATE_REQUEST: - { - size_t addrlen, buflen; - unsigned char *sbuf; - addrlen = v5->lookup ? strlen(svr->name) + 1 : (unsigned int)svr->ecs_addrlen; - buflen = sizeof(char) * (6 + addrlen); - sbuf = malloc(buflen); - if (!sbuf) - { - ecore_con_event_server_error(obj, "Memory allocation failure!"); - goto error; - } - sbuf[0] = 5; - sbuf[1] = v5->bind ? 2 : 1; /* TODO: 0x03 for UDP port association */ - sbuf[2] = 0; - if (v5->lookup) /* domain name */ - { - sbuf[3] = 3; - sbuf[4] = addrlen - 1; - memcpy(sbuf + 5, svr->name, addrlen - 1); - } - else - { - sbuf[3] = (svr->ecs_addrlen == 4) ? 1 : 4; - memcpy(sbuf + 4, svr->ecs_addr, addrlen); - } - sbuf[addrlen + 4] = svr->port >> 8; - sbuf[addrlen + 5] = svr->port & 0xff; - - svr->ecs_buf = eina_binbuf_manage_new(sbuf, buflen, EINA_FALSE); - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); - break; - } - - case ECORE_CON_PROXY_STATE_CONFIRM: - { - /* this is ugly because we have to read an exact number of bytes, - * but we don't know what that number is until we've already read - * at least 5 bytes to determine the length of the unknown stream. - * yep. - */ - size_t to_read, len = svr->ecs_recvbuf ? eina_binbuf_length_get(svr->ecs_recvbuf) : 0; - if (num + len < 5) - { - /* guarantees we get called again */ - ECORE_CON_SOCKS_READ(5); - } - if (len >= 5) - { - data = eina_binbuf_string_get(svr->ecs_recvbuf); - data += 3; - } - else - data = buf + 3 - len; - switch (data[0]) - { - case 1: - to_read = 4; - break; - - case 3: - to_read = data[1] + 1; - break; - - case 4: - to_read = 16; - /* lazy debugging stub comment */ - break; - - default: - ecore_con_event_server_error(obj, "protocol error"); - goto error; - } - /* at this point, we finally know exactly how much we need to read */ - ECORE_CON_SOCKS_READ(6 + to_read); - - if (data[0] != 5) - { - ecore_con_event_server_error(obj, "protocol error"); - goto error; /* wrong version */ - } - switch (data[1]) - { - case 0: - break; - - case 1: - ecore_con_event_server_error(obj, "general proxy failure"); - goto error; - - case 2: - ecore_con_event_server_error(obj, "connection not allowed by ruleset"); - goto error; - - case 3: - ecore_con_event_server_error(obj, "network unreachable"); - goto error; - - case 4: - ecore_con_event_server_error(obj, "host unreachable"); - goto error; - - case 5: - ecore_con_event_server_error(obj, "connection refused by destination host"); - goto error; - - case 6: - ecore_con_event_server_error(obj, "TTL expired"); - goto error; - - case 7: - ecore_con_event_server_error(obj, "command not supported / protocol error"); - goto error; - - case 8: - ecore_con_event_server_error(obj, "address type not supported"); - - default: - goto error; - } - if (data[2]) - { - ecore_con_event_server_error(obj, "protocol error"); - goto error; - } - memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr)); - if (!svr->ssl_state) - ecore_con_event_server_add(obj); - if (svr->ssl_state || (svr->buf && eina_binbuf_length_get(svr->buf))) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE); - svr->ecs_buf_offset = svr->ecs_addrlen = 0; - svr->ecs_state = ECORE_CON_PROXY_STATE_DONE; - INF("PROXY CONNECTED"); - break; - } - - default: - break; - } - if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf); - svr->ecs_recvbuf = NULL; - - return; -error: - _ecore_con_server_kill(obj); -} - -///////////////////////////////////////////////////////////////////////////////////// void ecore_con_socks_shutdown(void) { @@ -542,55 +105,6 @@ ecore_con_socks_shutdown(void) _ecore_con_proxy_global = NULL; } -void -ecore_con_socks_read(Ecore_Con_Server *obj, unsigned char *buf, int num) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - ECORE_CON_SOCKS_VERSION_CHECK(svr->ecs); - ECORE_CON_SOCKS_CAST(svr->ecs); - - if (svr->ecs_state < ECORE_CON_PROXY_STATE_READ) return; - - if (v4) _ecore_con_socks_read_v4(obj, v4, buf, (unsigned int)num); - else _ecore_con_socks_read_v5(obj, v5, buf, (unsigned int)num); -} - -Eina_Bool -ecore_con_socks_svr_init(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - ECORE_CON_SOCKS_VERSION_CHECK_RETURN(svr->ecs, EINA_FALSE); - ECORE_CON_SOCKS_CAST(svr->ecs); - - if (!svr->ip) return EINA_FALSE; - if (svr->ecs_buf) return EINA_FALSE; - if (svr->ecs_state != ECORE_CON_PROXY_STATE_INIT) return EINA_FALSE; - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); - if (v4) return _ecore_con_socks_svr_init_v4(obj, v4); - return _ecore_con_socks_svr_init_v5(obj, v5); -} - -void -ecore_con_socks_dns_cb(const char *canonname EINA_UNUSED, const char *ip, struct sockaddr *addr, int addrlen EINA_UNUSED, Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - svr->ip = eina_stringshare_add(ip); - svr->ecs_state++; - if (addr->sa_family == AF_INET) - { - memcpy(svr->ecs_addr, &((struct sockaddr_in *)addr)->sin_addr.s_addr, 4); - svr->ecs_addrlen = 4; - } -#ifdef HAVE_IPV6 - else - { - memcpy(svr->ecs_addr, &((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, 16); - svr->ecs_addrlen = 16; - } -#endif - ecore_con_socks_svr_init(obj); -} - void ecore_con_socks_init(void) { diff --git a/src/lib/ecore_con/ecore_con_ssl.c b/src/lib/ecore_con/ecore_con_ssl.c deleted file mode 100644 index b6e2c9882e..0000000000 --- a/src/lib/ecore_con/ecore_con_ssl.c +++ /dev/null @@ -1,1963 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif - -#if HAVE_GNUTLS -# include -# include -# include -#elif HAVE_OPENSSL -# include -# include -# include -#endif - -#ifdef HAVE_WS2TCPIP_H -# include -#endif - -#include - -#include - -#include "Ecore.h" -#include "ecore_con_private.h" - -EAPI int ECORE_CON_EVENT_CLIENT_UPGRADE = 0; -EAPI int ECORE_CON_EVENT_SERVER_UPGRADE = 0; - -static int _init_con_ssl_init_count = 0; - -#ifdef HAVE_GNUTLS -static int _client_connected = 0; - -# define SSL_SUFFIX(ssl_func) ssl_func ## _gnutls -# define _ECORE_CON_SSL_AVAILABLE 1 - -#elif HAVE_OPENSSL - -# define SSL_SUFFIX(ssl_func) ssl_func ## _openssl -# define _ECORE_CON_SSL_AVAILABLE 2 - -#else -# define SSL_SUFFIX(ssl_func) ssl_func ## _none -# define _ECORE_CON_SSL_AVAILABLE 0 - -#endif - -#if HAVE_GNUTLS -static void -_gnutls_print_errors(Eo *conn, int type, int ret) -{ - char buf[1024]; - - if (!ret) return; - - snprintf(buf, sizeof(buf), "GNUTLS error: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret)); - if (type == ECORE_CON_EVENT_CLIENT_ERROR) - ecore_con_event_client_error(conn, buf); - else - ecore_con_event_server_error(conn, buf); -} - -static void -_gnutls_print_session(const gnutls_datum_t *cert_list, unsigned int cert_list_size) -{ - char *c = NULL; - gnutls_x509_crt_t crt; - unsigned int x; - - if (!eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) return; - for (x = 0; x < cert_list_size; x++) - { - gnutls_x509_crt_init(&crt); - gnutls_x509_crt_import(crt, &cert_list[x], GNUTLS_X509_FMT_DER); - gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_FULL, (gnutls_datum_t *)&c); - INF("CERTIFICATE:\n%s", c); - gnutls_free(c); - gnutls_x509_crt_deinit(crt); - crt = NULL; - } -} - -#ifdef ISCOMFITOR -static void -_gnutls_log_func(int level, - const char *str) -{ - char buf[128]; - strncpy(buf, str, strlen(str) - 1); - DBG("|<%d>| %s", level, buf); -} - -#endif - -static const char * -SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_description_t status) -{ - switch (status) - { - case GNUTLS_HANDSHAKE_HELLO_REQUEST: - return "Hello request"; - - case GNUTLS_HANDSHAKE_CLIENT_HELLO: - return "Client hello"; - - case GNUTLS_HANDSHAKE_SERVER_HELLO: - return "Server hello"; - - case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: - return "New session ticket"; - - case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: - return "Certificate packet"; - - case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE: - return "Server key exchange"; - - case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: - return "Certificate request"; - - case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE: - return "Server hello done"; - - case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY: - return "Certificate verify"; - - case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE: - return "Client key exchange"; - - case GNUTLS_HANDSHAKE_FINISHED: - return "Finished"; - - case GNUTLS_HANDSHAKE_SUPPLEMENTAL: - return "Supplemental"; - } - return NULL; -} - -#elif HAVE_OPENSSL - -static void -_openssl_print_verify_error(int error) -{ - switch (error) - { -#define ERROR_SSL(X) \ -case (X): \ - ERR("%s", #X); \ - break -#ifdef X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT - ERROR_SSL(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT); -#endif -#ifdef X509_V_ERR_UNABLE_TO_GET_CRL - ERROR_SSL(X509_V_ERR_UNABLE_TO_GET_CRL); -#endif -#ifdef X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE - ERROR_SSL(X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE); -#endif -#ifdef X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE - ERROR_SSL(X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE); -#endif -#ifdef X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY - ERROR_SSL(X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY); -#endif -#ifdef X509_V_ERR_CERT_SIGNATURE_FAILURE - ERROR_SSL(X509_V_ERR_CERT_SIGNATURE_FAILURE); -#endif -#ifdef X509_V_ERR_CRL_SIGNATURE_FAILURE - ERROR_SSL(X509_V_ERR_CRL_SIGNATURE_FAILURE); -#endif -#ifdef X509_V_ERR_CERT_NOT_YET_VALID - ERROR_SSL(X509_V_ERR_CERT_NOT_YET_VALID); -#endif -#ifdef X509_V_ERR_CERT_HAS_EXPIRED - ERROR_SSL(X509_V_ERR_CERT_HAS_EXPIRED); -#endif -#ifdef X509_V_ERR_CRL_NOT_YET_VALID - ERROR_SSL(X509_V_ERR_CRL_NOT_YET_VALID); -#endif -#ifdef X509_V_ERR_CRL_HAS_EXPIRED - ERROR_SSL(X509_V_ERR_CRL_HAS_EXPIRED); -#endif -#ifdef X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD - ERROR_SSL(X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD); -#endif -#ifdef X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD - ERROR_SSL(X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD); -#endif -#ifdef X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD - ERROR_SSL(X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD); -#endif -#ifdef X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD - ERROR_SSL(X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); -#endif -#ifdef X509_V_ERR_OUT_OF_MEM - ERROR_SSL(X509_V_ERR_OUT_OF_MEM); -#endif -#ifdef X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT - ERROR_SSL(X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); -#endif -#ifdef X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN - ERROR_SSL(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN); -#endif -#ifdef X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY - ERROR_SSL(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY); -#endif -#ifdef X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE - ERROR_SSL(X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); -#endif -#ifdef X509_V_ERR_CERT_CHAIN_TOO_LONG - ERROR_SSL(X509_V_ERR_CERT_CHAIN_TOO_LONG); -#endif -#ifdef X509_V_ERR_CERT_REVOKED - ERROR_SSL(X509_V_ERR_CERT_REVOKED); -#endif -#ifdef X509_V_ERR_INVALID_CA - ERROR_SSL(X509_V_ERR_INVALID_CA); -#endif -#ifdef X509_V_ERR_PATH_LENGTH_EXCEEDED - ERROR_SSL(X509_V_ERR_PATH_LENGTH_EXCEEDED); -#endif -#ifdef X509_V_ERR_INVALID_PURPOSE - ERROR_SSL(X509_V_ERR_INVALID_PURPOSE); -#endif -#ifdef X509_V_ERR_CERT_UNTRUSTED - ERROR_SSL(X509_V_ERR_CERT_UNTRUSTED); -#endif -#ifdef X509_V_ERR_CERT_REJECTED - ERROR_SSL(X509_V_ERR_CERT_REJECTED); -#endif - /* These are 'informational' when looking for issuer cert */ -#ifdef X509_V_ERR_SUBJECT_ISSUER_MISMATCH - ERROR_SSL(X509_V_ERR_SUBJECT_ISSUER_MISMATCH); -#endif -#ifdef X509_V_ERR_AKID_SKID_MISMATCH - ERROR_SSL(X509_V_ERR_AKID_SKID_MISMATCH); -#endif -#ifdef X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH - ERROR_SSL(X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH); -#endif -#ifdef X509_V_ERR_KEYUSAGE_NO_CERTSIGN - ERROR_SSL(X509_V_ERR_KEYUSAGE_NO_CERTSIGN); -#endif - -#ifdef X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER - ERROR_SSL(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER); -#endif -#ifdef X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION - ERROR_SSL(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION); -#endif -#ifdef X509_V_ERR_KEYUSAGE_NO_CRL_SIGN - ERROR_SSL(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN); -#endif -#ifdef X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION - ERROR_SSL(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION); -#endif -#ifdef X509_V_ERR_INVALID_NON_CA - ERROR_SSL(X509_V_ERR_INVALID_NON_CA); -#endif -#ifdef X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED - ERROR_SSL(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED); -#endif -#ifdef X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE - ERROR_SSL(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE); -#endif -#ifdef X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED - ERROR_SSL(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED); -#endif - -#ifdef X509_V_ERR_INVALID_EXTENSION - ERROR_SSL(X509_V_ERR_INVALID_EXTENSION); -#endif -#ifdef X509_V_ERR_INVALID_POLICY_EXTENSION - ERROR_SSL(X509_V_ERR_INVALID_POLICY_EXTENSION); -#endif -#ifdef X509_V_ERR_NO_EXPLICIT_POLICY - ERROR_SSL(X509_V_ERR_NO_EXPLICIT_POLICY); -#endif -#ifdef X509_V_ERR_DIFFERENT_CRL_SCOPE - ERROR_SSL(X509_V_ERR_DIFFERENT_CRL_SCOPE); -#endif -#ifdef X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE - ERROR_SSL(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE); -#endif - -#ifdef X509_V_ERR_UNNESTED_RESOURCE - ERROR_SSL(X509_V_ERR_UNNESTED_RESOURCE); -#endif - -#ifdef X509_V_ERR_PERMITTED_VIOLATION - ERROR_SSL(X509_V_ERR_PERMITTED_VIOLATION); -#endif -#ifdef X509_V_ERR_EXCLUDED_VIOLATION - ERROR_SSL(X509_V_ERR_EXCLUDED_VIOLATION); -#endif -#ifdef X509_V_ERR_SUBTREE_MINMAX - ERROR_SSL(X509_V_ERR_SUBTREE_MINMAX); -#endif -#ifdef X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE - ERROR_SSL(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE); -#endif -#ifdef X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX - ERROR_SSL(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX); -#endif -#ifdef X509_V_ERR_UNSUPPORTED_NAME_SYNTAX - ERROR_SSL(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX); -#endif -#ifdef X509_V_ERR_CRL_PATH_VALIDATION_ERROR - ERROR_SSL(X509_V_ERR_CRL_PATH_VALIDATION_ERROR); -#endif - - /* The application is not happy */ -#ifdef X509_V_ERR_APPLICATION_VERIFICATION - ERROR_SSL(X509_V_ERR_APPLICATION_VERIFICATION); -#endif - } -#undef ERROR_SSL -} - -static void -_openssl_print_errors(Eo *conn, int type) -{ - char buf[1024]; - do - { - unsigned long err; - - err = ERR_get_error(); - if (!err) break; - snprintf(buf, sizeof(buf), "OpenSSL error: %s", ERR_reason_error_string(err)); - if (type == ECORE_CON_EVENT_CLIENT_ERROR) - ecore_con_event_client_error(conn, buf); - else - ecore_con_event_server_error(conn, buf); - } while (1); -} - -static Eina_Bool -_openssl_name_verify(const char *name, const char *svrname) -{ - if (name[0] == '*') - { - /* we allow *.domain.TLD with a wildcard, but nothing else */ - const char *p, *s; - - EINA_SAFETY_ON_TRUE_RETURN_VAL((name[1] != '.') || (!name[2]), EINA_FALSE); - p = strchr(name + 1, '*'); - EINA_SAFETY_ON_TRUE_RETURN_VAL(!!p, EINA_FALSE); - /* verify that we have a domain of at least *.X.TLD and not *.TLD */ - p = strchr(name + 2, '.'); - EINA_SAFETY_ON_TRUE_RETURN_VAL(!p, EINA_FALSE); - s = strchr(svrname, '.'); - EINA_SAFETY_ON_TRUE_RETURN_VAL(!s, EINA_FALSE); - /* same as above for the stored name */ - EINA_SAFETY_ON_TRUE_RETURN_VAL(!strchr(s + 1, '.'), EINA_FALSE); - if (strcasecmp(s, name + 1)) - { - ERR("%s != %s", s, name + 1); - return EINA_FALSE; - } - } - else - if (strcasecmp(name, svrname)) - { - ERR("%s != %s", name, svrname); - return EINA_FALSE; - } - return EINA_TRUE; -} - -static void -_openssl_print_session(SSL *ssl) -{ - /* print session info into DBG */ - SSL_SESSION *s; - STACK_OF(X509) * sk; - BIO *b; - char log[4096], *p; - int x; - - if (!eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) return; - - memset(log, 0, sizeof(log)); - b = BIO_new(BIO_s_mem()); - sk = SSL_get_peer_cert_chain(ssl); - if (sk) - { - DBG("CERTIFICATES:"); - for (x = 0; x < sk_X509_num(sk); x++) - { - p = X509_NAME_oneline(X509_get_subject_name(sk_X509_value(sk, x)), log, sizeof(log)); - DBG("%2d s:%s", x, p); - p = X509_NAME_oneline(X509_get_issuer_name(sk_X509_value(sk, x)), log, sizeof(log)); - DBG(" i:%s", p); - PEM_write_X509(stderr, sk_X509_value(sk, x)); - } - } - s = SSL_get_session(ssl); - SSL_SESSION_print(b, s); - fprintf(stderr, "\n"); - while (BIO_read(b, log, sizeof(log)) > 0) - fprintf(stderr, "%s", log); - - BIO_free(b); -} - -#endif - -#define SSL_ERROR_CHECK_GOTO_ERROR(X) \ - do \ - { \ - if ((X)) \ - { \ - ERR("Error at %s:%s:%d!", __FILE__, __PRETTY_FUNCTION__, __LINE__); \ - goto error; \ - } \ - } \ - while (0) - -static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_cafile_add) (Ecore_Con_Server *svr, const char *ca_file); -static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_crl_add) (Ecore_Con_Server *svr, const char *crl_file); -static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (Ecore_Con_Server *svr, const char *cert); -static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_privkey_add) (Ecore_Con_Server *svr, const char *key_file); - -static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_prepare) (Ecore_Con_Server *svr, int ssl_type); -static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_init) (Ecore_Con_Server *svr); -static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_server_shutdown) (Ecore_Con_Server *svr); -static int SSL_SUFFIX(_ecore_con_ssl_server_read) (Ecore_Con_Server *svr, unsigned char *buf, int size); -static int SSL_SUFFIX(_ecore_con_ssl_server_write) (Ecore_Con_Server *svr, const unsigned char *buf, int size); - -static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_client_init) (Ecore_Con_Client *cl); -static Ecore_Con_Ssl_Error SSL_SUFFIX(_ecore_con_ssl_client_shutdown) (Ecore_Con_Client *cl); -static int SSL_SUFFIX(_ecore_con_ssl_client_read) (Ecore_Con_Client *cl, - unsigned char *buf, int size); -static int SSL_SUFFIX(_ecore_con_ssl_client_write) (Ecore_Con_Client *cl, - const unsigned char *buf, int size); - -/* - * General SSL API - */ - -Ecore_Con_Ssl_Error -ecore_con_ssl_init(void) -{ - if (!_init_con_ssl_init_count++) - { -#if defined ISCOMFITOR && defined HAVE_GNUTLS - if (eina_log_domain_level_check(_ecore_con_log_dom, - EINA_LOG_LEVEL_DBG)) - { - gnutls_global_set_log_level(9); - gnutls_global_set_log_function(_gnutls_log_func); - } -#endif - emile_init(); - -#if _ECORE_CON_SSL_AVAILABLE != 0 - ECORE_CON_EVENT_CLIENT_UPGRADE = ecore_event_type_new(); - ECORE_CON_EVENT_SERVER_UPGRADE = ecore_event_type_new(); -#endif - } - - return _init_con_ssl_init_count; -} - -Ecore_Con_Ssl_Error -ecore_con_ssl_shutdown(void) -{ - /* _init_con_ssl_init_count should not go below zero. */ - if (_init_con_ssl_init_count < 1) - { - ERR("ecore_con_ssl_shutdown called without calling ecore_con_ssl_init.\n"); - return 0; - } - - if (!--_init_con_ssl_init_count) - emile_shutdown(); - - return _init_con_ssl_init_count; -} - -Ecore_Con_Ssl_Error -ecore_con_ssl_server_prepare(Ecore_Con_Server *svr, - int ssl_type) -{ - if (!ssl_type) - return ECORE_CON_SSL_ERROR_NONE; - if (!emile_cipher_init()) - return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; - - // We forcibly disable SSL3 now - if (ssl_type & ECORE_CON_USE_MIXED) - ssl_type &= ~ECORE_CON_USE_SSL3; - - if (ssl_type & ECORE_CON_USE_SSL2) - return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED; - - if (ssl_type & ECORE_CON_USE_SSL3) - return ECORE_CON_SSL_ERROR_SSL3_NOT_SUPPORTED; - - return SSL_SUFFIX(_ecore_con_ssl_server_prepare) (svr, ssl_type); -} - -Ecore_Con_Ssl_Error -ecore_con_ssl_server_init(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr || !(svr->type & ECORE_CON_SSL)) - return ECORE_CON_SSL_ERROR_NONE; - return SSL_SUFFIX(_ecore_con_ssl_server_init) (obj); -} - -Ecore_Con_Ssl_Error -ecore_con_ssl_server_shutdown(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr || !(svr->type & ECORE_CON_SSL)) - return ECORE_CON_SSL_ERROR_NONE; - return SSL_SUFFIX(_ecore_con_ssl_server_shutdown) (obj); -} - -int -ecore_con_ssl_server_read(Ecore_Con_Server *svr, - unsigned char *buf, - int size) -{ - return SSL_SUFFIX(_ecore_con_ssl_server_read) (svr, buf, size); -} - -int -ecore_con_ssl_server_write(Ecore_Con_Server *svr, - const unsigned char *buf, - int size) -{ - return SSL_SUFFIX(_ecore_con_ssl_server_write) (svr, buf, size); -} - -Ecore_Con_Ssl_Error -ecore_con_ssl_client_init(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (!cl) - return ECORE_CON_SSL_ERROR_NONE; - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (!host_server || !(host_server->type & ECORE_CON_SSL)) - return ECORE_CON_SSL_ERROR_NONE; - return SSL_SUFFIX(_ecore_con_ssl_client_init) (obj); -} - -Ecore_Con_Ssl_Error -ecore_con_ssl_client_shutdown(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (!cl) - return ECORE_CON_SSL_ERROR_NONE; - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (!host_server || !(host_server->type & ECORE_CON_SSL)) - return ECORE_CON_SSL_ERROR_NONE; - return SSL_SUFFIX(_ecore_con_ssl_client_shutdown) (obj); -} - -int -ecore_con_ssl_client_read(Ecore_Con_Client *cl, - unsigned char *buf, - int size) -{ - return SSL_SUFFIX(_ecore_con_ssl_client_read) (cl, buf, size); -} - -int -ecore_con_ssl_client_write(Ecore_Con_Client *cl, - const unsigned char *buf, - int size) -{ - return SSL_SUFFIX(_ecore_con_ssl_client_write) (cl, buf, size); -} - -EAPI int -ecore_con_ssl_available_get(void) -{ - return _ECORE_CON_SSL_AVAILABLE; -} - -EAPI void -ecore_con_ssl_server_verify(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) return; - - svr->verify = EINA_TRUE; -} - -EAPI void -ecore_con_ssl_server_verify_basic(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) return; - - svr->verify_basic = EINA_TRUE; -} - -EAPI void -ecore_con_ssl_server_verify_name_set(Ecore_Con_Server *obj, const char *name) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) return; - - eina_stringshare_replace(&svr->verify_name, name); -} - -EAPI const char * -ecore_con_ssl_server_verify_name_get(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) return NULL; - - return svr->verify_name ? : svr->name; -} - -EAPI Eina_Bool -ecore_con_ssl_server_cert_add(Ecore_Con_Server *obj, - const char *cert) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) return EINA_FALSE; - - if (!svr->ssl_prepared) - { - svr->use_cert = EINA_TRUE; - svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT; - if (ecore_con_ssl_server_prepare(obj, svr->type & ECORE_CON_SSL)) - return EINA_FALSE; - } - - return SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (obj, cert); -} - -EAPI Eina_Bool -ecore_con_ssl_server_cafile_add(Ecore_Con_Server *obj, - const char *ca_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) return EINA_FALSE; - - if (!svr->ssl_prepared) - { - svr->use_cert = EINA_TRUE; - svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT; - if (ecore_con_ssl_server_prepare(obj, svr->type & ECORE_CON_SSL)) - return EINA_FALSE; - } - - return SSL_SUFFIX(_ecore_con_ssl_server_cafile_add) (obj, ca_file); -} - -EAPI Eina_Bool -ecore_con_ssl_server_privkey_add(Ecore_Con_Server *obj, - const char *key_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) return EINA_FALSE; - - if (!svr->ssl_prepared) - { - svr->use_cert = EINA_TRUE; - svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT; - if (ecore_con_ssl_server_prepare(obj, svr->type & ECORE_CON_SSL)) - return EINA_FALSE; - } - - return SSL_SUFFIX(_ecore_con_ssl_server_privkey_add) (obj, key_file); -} - -EAPI Eina_Bool -ecore_con_ssl_server_crl_add(Ecore_Con_Server *obj, - const char *crl_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) return EINA_FALSE; - - if (!svr->ssl_prepared) - { - svr->use_cert = EINA_TRUE; - svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT; - if (ecore_con_ssl_server_prepare(obj, svr->type & ECORE_CON_SSL)) - return EINA_FALSE; - } - - return SSL_SUFFIX(_ecore_con_ssl_server_crl_add) (obj, crl_file); -} - -EAPI Eina_Bool -ecore_con_ssl_server_upgrade(Ecore_Con_Server *obj, Ecore_Con_Type ssl_type) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!svr) return EINA_FALSE; -#if _ECORE_CON_SSL_AVAILABLE == 0 - return EINA_FALSE; -#endif - - if (!svr->ssl_prepared) - { - if (ecore_con_ssl_server_prepare(obj, ssl_type)) - return EINA_FALSE; - } - if (!svr->use_cert) - svr->type |= ssl_type; - svr->upgrade = EINA_TRUE; - svr->handshaking = EINA_TRUE; - svr->ssl_state = ECORE_CON_SSL_STATE_INIT; - return !SSL_SUFFIX(_ecore_con_ssl_server_init) (obj); -} - -EAPI Eina_Bool -ecore_con_ssl_client_upgrade(Ecore_Con_Client *obj, Ecore_Con_Type ssl_type) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (!cl) - { - return EINA_FALSE; - } -#if _ECORE_CON_SSL_AVAILABLE == 0 - return EINA_FALSE; -#endif - - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - if (!host_server->ssl_prepared) - { - if (ecore_con_ssl_server_prepare(cl->host_server, ssl_type)) - return EINA_FALSE; - } - if (!host_server->use_cert) - host_server->type |= ssl_type; - cl->upgrade = EINA_TRUE; - host_server->upgrade = EINA_TRUE; - cl->handshaking = EINA_TRUE; - cl->ssl_state = ECORE_CON_SSL_STATE_INIT; - return !SSL_SUFFIX(_ecore_con_ssl_client_init) (obj); -} - -/** - * @} - */ - -#if HAVE_GNUTLS - -/* - * GnuTLS - */ - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_server_prepare_gnutls(Ecore_Con_Server *obj, - int ssl_type) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - int ret; - - switch (ssl_type) - { - case ECORE_CON_USE_TLS: - case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT: - case ECORE_CON_USE_MIXED: - case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT: - break; - - default: - return ECORE_CON_SSL_ERROR_NONE; - } - - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_allocate_credentials(&svr->cert)); - - if (svr->use_cert) - { - if (svr->created) - { - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_dh_params_init(&svr->dh_params)); - INF("Generating DH params"); - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_dh_params_generate2(svr->dh_params, 1024)); - - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_anon_allocate_server_credentials(&svr->anoncred_s)); - /* TODO: implement PSK */ - // SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_psk_allocate_server_credentials(&svr->pskcred_s)); - - gnutls_anon_set_server_dh_params(svr->anoncred_s, svr->dh_params); - gnutls_certificate_set_dh_params(svr->cert, svr->dh_params); - //gnutls_psk_set_server_dh_params(svr->pskcred_s, svr->dh_params); - INF("DH params successfully generated and applied!"); - } - else - { - //SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_psk_allocate_client_credentials(&svr->pskcred_c)); - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_anon_allocate_client_credentials(&svr->anoncred_c)); - } - } - - svr->ssl_prepared = EINA_TRUE; - return ECORE_CON_SSL_ERROR_NONE; - -error: - _gnutls_print_errors(obj, ECORE_CON_EVENT_SERVER_ERROR, ret); - _ecore_con_ssl_server_shutdown_gnutls(obj); - return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_server_init_gnutls(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - const gnutls_datum_t *cert_list; - unsigned int iter, cert_list_size; - gnutls_x509_crt_t cert = NULL; - const char *priority = "NORMAL:%VERIFY_ALLOW_X509_V1_CA_CRT"; - int ret = 0; - - switch (svr->ssl_state) - { - case ECORE_CON_SSL_STATE_DONE: - return ECORE_CON_SSL_ERROR_NONE; - - case ECORE_CON_SSL_STATE_INIT: - if (svr->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */ - return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED; - - switch (svr->type & ECORE_CON_SSL) - { - case ECORE_CON_USE_SSL3: - case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT: - priority = "NORMAL:%VERIFY_ALLOW_X509_V1_CA_CRT:!VERS-TLS1.0:!VERS-TLS1.1:!VERS-TLS1.2"; - break; - - case ECORE_CON_USE_TLS: - case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT: - priority = "NORMAL:%VERIFY_ALLOW_X509_V1_CA_CRT:!VERS-SSL3.0"; - break; - - case ECORE_CON_USE_MIXED: - case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT: - break; - - default: - return ECORE_CON_SSL_ERROR_NONE; - } - - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&svr->session, GNUTLS_CLIENT)); - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_enable_client(svr->session)); - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_server_name_set(svr->session, GNUTLS_NAME_DNS, svr->name, strlen(svr->name))); - INF("Applying priority string: %s", priority); - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_priority_set_direct(svr->session, priority, NULL)); - gnutls_handshake_set_private_extensions(svr->session, 1); - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_CERTIFICATE, svr->cert)); - // SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_PSK, svr->pskcred_c)); - if (!svr->use_cert) - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_ANON, svr->anoncred_c)); - - gnutls_dh_set_prime_bits(svr->session, 512); - gnutls_transport_set_ptr(svr->session, (gnutls_transport_ptr_t)((intptr_t)svr->fd)); - svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; - - case ECORE_CON_SSL_STATE_HANDSHAKING: - if (!svr->session) - { - DBG("Server was previously lost, going to error condition"); - goto error; - } - ret = gnutls_handshake(svr->session); - DBG("calling gnutls_handshake(): returned with '%s'", gnutls_strerror_name(ret)); - SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret)); - if (!ret) - { - svr->handshaking = EINA_FALSE; - svr->ssl_state = ECORE_CON_SSL_STATE_DONE; - } - else - { - if (gnutls_record_get_direction(svr->session)) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); - else - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); - return ECORE_CON_SSL_ERROR_NONE; - } - - default: - break; - } - - if ((!svr->verify) && (!svr->verify_basic)) - /* not verifying certificates, so we're done! */ - return ECORE_CON_SSL_ERROR_NONE; - if (svr->verify) - { - /* use CRL/CA lists to verify */ - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_verify_peers2(svr->session, &iter)); - if (iter & GNUTLS_CERT_INVALID) - ERR("The certificate is not trusted."); - else if (iter & GNUTLS_CERT_SIGNER_NOT_FOUND) - ERR("The certificate hasn't got a known issuer."); - else if (iter & GNUTLS_CERT_REVOKED) - ERR("The certificate has been revoked."); - else if (iter & GNUTLS_CERT_EXPIRED) - ERR("The certificate has expired"); - else if (iter & GNUTLS_CERT_NOT_ACTIVATED) - ERR("The certificate is not yet activated"); - - if (iter) - goto error; - } - if (gnutls_certificate_type_get(svr->session) != GNUTLS_CRT_X509) - { - ERR("Warning: PGP certificates are not yet supported!"); - goto error; - } - - SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(svr->session, &cert_list_size))); - SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size); - - _gnutls_print_session(cert_list, cert_list_size); - - SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_init(&cert)); - SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)); - - SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, svr->verify_name ? : svr->name)); - gnutls_x509_crt_deinit(cert); - DBG("SSL certificate verification succeeded!"); - return ECORE_CON_SSL_ERROR_NONE; - -error: - _gnutls_print_errors(obj, ECORE_CON_EVENT_SERVER_ERROR, ret); - if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED)) - ERR("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(svr->session))); - if (svr->session && (svr->ssl_state != ECORE_CON_SSL_STATE_DONE)) - { - ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(svr->session))); - ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(svr->session))); - } - if (cert) - gnutls_x509_crt_deinit(cert); - _ecore_con_ssl_server_shutdown_gnutls(obj); - return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; -} - -static Eina_Bool -_ecore_con_ssl_server_cafile_add_gnutls(Ecore_Con_Server *obj, - const char *ca_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - struct stat st; - Eina_Iterator *it; - const char *file; - Eina_Bool error = EINA_FALSE; - - if (stat(ca_file, &st)) return EINA_FALSE; - if (S_ISDIR(st.st_mode)) - { - it = eina_file_ls(ca_file); - SSL_ERROR_CHECK_GOTO_ERROR(!it); - EINA_ITERATOR_FOREACH(it, file) - { - if (!error) - { - if (gnutls_certificate_set_x509_trust_file(svr->cert, file, GNUTLS_X509_FMT_PEM) < 1) - error++; - } - eina_stringshare_del(file); - } - eina_iterator_free(it); - } - else - SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_trust_file(svr->cert, ca_file, - GNUTLS_X509_FMT_PEM) < 1); - - return !error; -error: - ERR("Could not load CA file!"); - return EINA_FALSE; -} - -static Eina_Bool -_ecore_con_ssl_server_crl_add_gnutls(Ecore_Con_Server *obj, - const char *crl_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_crl_file(svr->cert, crl_file, - GNUTLS_X509_FMT_PEM) < 1); - - return EINA_TRUE; -error: - ERR("Could not load CRL file!"); - return EINA_FALSE; -} - -static Eina_Bool -_ecore_con_ssl_server_privkey_add_gnutls(Ecore_Con_Server *obj, - const char *key_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_key_file(svr->cert, svr->cert_file, key_file, - GNUTLS_X509_FMT_PEM)); - - return EINA_TRUE; -error: - ERR("Could not load certificate/key file!"); - return EINA_FALSE; -} - -static Eina_Bool -_ecore_con_ssl_server_cert_add_gnutls(Ecore_Con_Server *obj, - const char *cert_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (!(svr->cert_file = strdup(cert_file))) - return EINA_FALSE; - - return EINA_TRUE; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_server_shutdown_gnutls(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (svr->session) - { - gnutls_bye(svr->session, GNUTLS_SHUT_RDWR); - gnutls_deinit(svr->session); - } - - free(svr->cert_file); - svr->cert_file = NULL; - if (svr->cert) - gnutls_certificate_free_credentials(svr->cert); - svr->cert = NULL; - - if ((svr->type & ECORE_CON_SSL) && svr->created) - { - if (svr->dh_params) - { - gnutls_dh_params_deinit(svr->dh_params); - svr->dh_params = NULL; - } - if (svr->anoncred_s) - gnutls_anon_free_server_credentials(svr->anoncred_s); - // if (svr->pskcred_s) - // gnutls_psk_free_server_credentials(svr->pskcred_s); - - svr->anoncred_s = NULL; - svr->pskcred_s = NULL; - } - else if (svr->type & ECORE_CON_SSL) - { - if (svr->anoncred_c) - gnutls_anon_free_client_credentials(svr->anoncred_c); - // if (svr->pskcred_c) - // gnutls_psk_free_client_credentials(svr->pskcred_c); - - svr->anoncred_c = NULL; - svr->pskcred_c = NULL; - } - - svr->session = NULL; - - return ECORE_CON_SSL_ERROR_NONE; -} - -static int -_ecore_con_ssl_server_read_gnutls(Ecore_Con_Server *obj, - unsigned char *buf, - int size) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - int num; - - if (svr->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING) - { - DBG("Continuing gnutls handshake"); - if (!_ecore_con_ssl_server_init_gnutls(obj)) - return 0; - return -1; - } - - num = gnutls_record_recv(svr->session, buf, size); - if (num > 0) - return num; - - if (num == GNUTLS_E_REHANDSHAKE) - { - WRN("Rehandshake request ignored"); - return 0; - - svr->handshaking = EINA_TRUE; - svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; - if (!_ecore_con_ssl_server_init_gnutls(obj)) - return 0; - } - else if ((!gnutls_error_is_fatal(num)) && (num != GNUTLS_E_SUCCESS)) - return 0; - - return -1; -} - -static int -_ecore_con_ssl_server_write_gnutls(Ecore_Con_Server *obj, - const unsigned char *buf, - int size) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - int num; - - if (svr->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING) - { - DBG("Continuing gnutls handshake"); - if (!_ecore_con_ssl_server_init_gnutls(obj)) - return 0; - return -1; - } - - num = gnutls_record_send(svr->session, buf, size); - if (num > 0) - return num; - - if (num == GNUTLS_E_REHANDSHAKE) - { - WRN("Rehandshake request ignored"); - return 0; -/* this is only partly functional I think? */ - svr->handshaking = EINA_TRUE; - svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; - if (!_ecore_con_ssl_server_init_gnutls(obj)) - return 0; - } - else if (!gnutls_error_is_fatal(num)) - return 0; - - return -1; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_client_init_gnutls(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - const gnutls_datum_t *cert_list; - unsigned int iter, cert_list_size; - const char *priority = "NORMAL:%VERIFY_ALLOW_X509_V1_CA_CRT"; - int ret = 0; - - switch (cl->ssl_state) - { - case ECORE_CON_SSL_STATE_DONE: - return ECORE_CON_SSL_ERROR_NONE; - - case ECORE_CON_SSL_STATE_INIT: - if (host_server->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */ - return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED; - - switch (host_server->type & ECORE_CON_SSL) - { - case ECORE_CON_USE_SSL3: - case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT: - priority = "NORMAL:%VERIFY_ALLOW_X509_V1_CA_CRT:!VERS-TLS1.0:!VERS-TLS1.1:!VERS-TLS1.2"; - break; - - case ECORE_CON_USE_TLS: - case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT: - priority = "NORMAL:%VERIFY_ALLOW_X509_V1_CA_CRT:!VERS-SSL3.0"; - break; - - case ECORE_CON_USE_MIXED: - case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT: - break; - - default: - return ECORE_CON_SSL_ERROR_NONE; - } - - _client_connected++; - - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&cl->session, GNUTLS_SERVER)); - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_key_generate(&cl->session_ticket)); - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_session_ticket_enable_server(cl->session, &cl->session_ticket)); - INF("Applying priority string: %s", priority); - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_priority_set_direct(cl->session, priority, NULL)); - gnutls_handshake_set_private_extensions(cl->session, 1); - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_CERTIFICATE, host_server->cert)); - // SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_PSK, host_server->pskcred_s)); - if (!host_server->use_cert) - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_ANON, host_server->anoncred_s)); - - gnutls_certificate_server_set_request(cl->session, GNUTLS_CERT_REQUEST); - - gnutls_dh_set_prime_bits(cl->session, 2048); - gnutls_transport_set_ptr(cl->session, (gnutls_transport_ptr_t)((intptr_t)cl->fd)); - cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; - - case ECORE_CON_SSL_STATE_HANDSHAKING: - if (!cl->session) - { - DBG("Client was previously lost, going to error condition"); - goto error; - } - DBG("calling gnutls_handshake()"); - ret = gnutls_handshake(cl->session); - SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret)); - - if (!ret) - { - cl->handshaking = EINA_FALSE; - cl->ssl_state = ECORE_CON_SSL_STATE_DONE; - } - else - { - if (gnutls_record_get_direction(cl->session)) - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE); - else - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); - return ECORE_CON_SSL_ERROR_NONE; - } - - default: - break; - } - - if (!host_server->verify) - /* not verifying certificates, so we're done! */ - return ECORE_CON_SSL_ERROR_NONE; - /* use CRL/CA lists to verify */ - SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_verify_peers2(cl->session, &iter)); - if (iter & GNUTLS_CERT_INVALID) - ERR("The certificate is not trusted."); - else if (iter & GNUTLS_CERT_SIGNER_NOT_FOUND) - ERR("The certificate hasn't got a known issuer."); - else if (iter & GNUTLS_CERT_REVOKED) - ERR("The certificate has been revoked."); - else if (iter & GNUTLS_CERT_EXPIRED) - ERR("The certificate has expired"); - else if (iter & GNUTLS_CERT_NOT_ACTIVATED) - ERR("The certificate is not yet activated"); - - if (iter) - goto error; - if (gnutls_certificate_type_get(cl->session) != GNUTLS_CRT_X509) - { - ERR("Warning: PGP certificates are not yet supported!"); - goto error; - } - - SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(cl->session, &cert_list_size))); - SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size); - - _gnutls_print_session(cert_list, cert_list_size); -/* - gnutls_x509_crt_t cert = NULL; - SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_init(&cert)); - SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)); - - SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, host_server->name)); - gnutls_x509_crt_deinit(cert); - */ - DBG("SSL certificate verification succeeded!"); - return ECORE_CON_SSL_ERROR_NONE; - -error: - _gnutls_print_errors(obj, ECORE_CON_EVENT_CLIENT_ERROR, ret); - if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED)) - ERR("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(cl->session))); - if (cl->session && (cl->ssl_state != ECORE_CON_SSL_STATE_DONE)) - { - ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(cl->session))); - ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(cl->session))); - } -/* - if (cert) - gnutls_x509_crt_deinit(cert); - */ - _ecore_con_ssl_client_shutdown_gnutls(obj); - return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_client_shutdown_gnutls(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (cl->session) - { - gnutls_bye(cl->session, GNUTLS_SHUT_RDWR); - gnutls_deinit(cl->session); - gnutls_free(cl->session_ticket.data); - cl->session_ticket.data = NULL; - } - - cl->session = NULL; - - return ECORE_CON_SSL_ERROR_NONE; -} - -static int -_ecore_con_ssl_client_read_gnutls(Ecore_Con_Client *obj, - unsigned char *buf, - int size) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - int num; - - if (cl->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING) - { - if (!_ecore_con_ssl_client_init_gnutls(obj)) - return 0; - return -1; - } - - num = gnutls_record_recv(cl->session, buf, size); - if (num > 0) - return num; - - if (num == GNUTLS_E_REHANDSHAKE) - { - WRN("Rehandshake request ignored"); - return 0; - cl->handshaking = EINA_TRUE; - cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; - if (!_ecore_con_ssl_client_init_gnutls(obj)) - return 0; - WRN("Rehandshake request ignored"); - return 0; - } - else if ((!gnutls_error_is_fatal(num)) && (num != GNUTLS_E_SUCCESS)) - return 0; - - return -1; -} - -static int -_ecore_con_ssl_client_write_gnutls(Ecore_Con_Client *obj, - const unsigned char *buf, - int size) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - int num; - - if (cl->ssl_state == ECORE_CON_SSL_STATE_HANDSHAKING) - { - if (!_ecore_con_ssl_client_init_gnutls(obj)) - return 0; - return -1; - } - - num = gnutls_record_send(cl->session, buf, size); - if (num > 0) - return num; - - if (num == GNUTLS_E_REHANDSHAKE) - { - WRN("Rehandshake request ignored"); - return 0; - cl->handshaking = EINA_TRUE; - cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; - if (!_ecore_con_ssl_client_init_gnutls(obj)) - return 0; - } - else if (!gnutls_error_is_fatal(num)) - return 0; - - return -1; -} - -#elif HAVE_OPENSSL && !HAVE_GNUTLS - -/* - * OpenSSL - */ - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_server_prepare_openssl(Ecore_Con_Server *obj, - int ssl_type) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - long options; - int dh = 0; - - switch (ssl_type) - { - case ECORE_CON_USE_TLS: - case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT: - if (!svr->created) - SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method()))); - else - SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(TLSv1_server_method()))); - break; - - case ECORE_CON_USE_MIXED: - case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT: - if (!svr->created) - SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv23_client_method()))); - else - SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))); - options = SSL_CTX_get_options(svr->ssl_ctx); - SSL_CTX_set_options(svr->ssl_ctx, options | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE); - break; - - default: - svr->ssl_prepared = EINA_TRUE; - return ECORE_CON_SSL_ERROR_NONE; - } - - if ((!svr->use_cert) && svr->created) - { - DH *dh_params; - INF("Generating DH params"); - SSL_ERROR_CHECK_GOTO_ERROR(!(dh_params = DH_new())); - SSL_ERROR_CHECK_GOTO_ERROR(!DH_generate_parameters_ex(dh_params, 1024, DH_GENERATOR_5, NULL)); - SSL_ERROR_CHECK_GOTO_ERROR(!DH_check(dh_params, &dh)); - SSL_ERROR_CHECK_GOTO_ERROR((dh & DH_CHECK_P_NOT_PRIME) || (dh & DH_CHECK_P_NOT_SAFE_PRIME)); - SSL_ERROR_CHECK_GOTO_ERROR(!DH_generate_key(dh_params)); - SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_tmp_dh(svr->ssl_ctx, dh_params)); - DH_free(dh_params); - INF("DH params successfully generated and applied!"); - SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_cipher_list(svr->ssl_ctx, "aRSA+HIGH:+kEDH:+kRSA:!kSRP:!kPSK:+3DES:!MD5")); - } - else if (!svr->use_cert) - SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_cipher_list(svr->ssl_ctx, "aRSA+HIGH:+kEDH:+kRSA:!kSRP:!kPSK:+3DES:!MD5")); - - svr->ssl_prepared = EINA_TRUE; - return ECORE_CON_SSL_ERROR_NONE; - -error: - if (dh) - { - if (dh & DH_CHECK_P_NOT_PRIME) - ERR("openssl error: dh_params could not generate a prime!"); - else - ERR("openssl error: dh_params could not generate a safe prime!"); - } - else - _openssl_print_errors(obj, ECORE_CON_EVENT_SERVER_ERROR); - _ecore_con_ssl_server_shutdown_openssl(obj); - return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_server_init_openssl(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - int ret = -1; - - switch (svr->ssl_state) - { - case ECORE_CON_SSL_STATE_DONE: - return ECORE_CON_SSL_ERROR_NONE; - - case ECORE_CON_SSL_STATE_INIT: - SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl = SSL_new(svr->ssl_ctx))); - - SSL_ERROR_CHECK_GOTO_ERROR(!SSL_set_fd(svr->ssl, svr->fd)); - SSL_set_connect_state(svr->ssl); - svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; - - case ECORE_CON_SSL_STATE_HANDSHAKING: - if (!svr->ssl) - { - DBG("Server was previously lost, going to error condition"); - goto error; - } - ret = SSL_do_handshake(svr->ssl); - svr->ssl_err = SSL_get_error(svr->ssl, ret); - SSL_ERROR_CHECK_GOTO_ERROR((svr->ssl_err == SSL_ERROR_SYSCALL) || (svr->ssl_err == SSL_ERROR_SSL)); - - if (ret == 1) - { - svr->handshaking = EINA_FALSE; - svr->ssl_state = ECORE_CON_SSL_STATE_DONE; - } - else - { - if (svr->ssl_err == SSL_ERROR_WANT_READ) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); - else if (svr->ssl_err == SSL_ERROR_WANT_WRITE) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); - return ECORE_CON_SSL_ERROR_NONE; - } - - default: - break; - } - - _openssl_print_session(svr->ssl); - if ((!svr->verify) && (!svr->verify_basic)) - /* not verifying certificates, so we're done! */ - return ECORE_CON_SSL_ERROR_NONE; - - { - X509 *cert; - SSL_set_verify(svr->ssl, SSL_VERIFY_PEER, NULL); - /* use CRL/CA lists to verify */ - cert = SSL_get_peer_certificate(svr->ssl); - if (cert) - { - char *c; - int clen; - int name = 0; - - if (svr->verify) - { - int err; - - err = SSL_get_verify_result(svr->ssl); - _openssl_print_verify_error(err); - SSL_ERROR_CHECK_GOTO_ERROR(err); - } - clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_subject_alt_name, NULL, 0); - if (clen > 0) - name = NID_subject_alt_name; - else - clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, NULL, 0); - SSL_ERROR_CHECK_GOTO_ERROR(clen < 1); - if (!name) name = NID_commonName; - c = alloca(++clen); - X509_NAME_get_text_by_NID(X509_get_subject_name(cert), name, c, clen); - INF("CERT NAME: %s\n", c); - SSL_ERROR_CHECK_GOTO_ERROR(!_openssl_name_verify(c, svr->verify_name ? : svr->name)); - } - } - - DBG("SSL certificate verification succeeded!"); - - return ECORE_CON_SSL_ERROR_NONE; - -error: - _openssl_print_errors(obj, ECORE_CON_EVENT_SERVER_ERROR); - _ecore_con_ssl_server_shutdown_openssl(obj); - return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; -} - -static Eina_Bool -_ecore_con_ssl_server_cafile_add_openssl(Ecore_Con_Server *obj, - const char *ca_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - struct stat st; - - if (stat(ca_file, &st)) return EINA_FALSE; - if (S_ISDIR(st.st_mode)) - SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_load_verify_locations(svr->ssl_ctx, NULL, ca_file)); - else - SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_load_verify_locations(svr->ssl_ctx, ca_file, NULL)); - return EINA_TRUE; - -error: - _openssl_print_errors(obj, ECORE_CON_EVENT_SERVER_ERROR); - return EINA_FALSE; -} - -static Eina_Bool -_ecore_con_ssl_server_crl_add_openssl(Ecore_Con_Server *obj, - const char *crl_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - X509_STORE *st; - X509_LOOKUP *lu; - static Eina_Bool flag = EINA_FALSE; - - SSL_ERROR_CHECK_GOTO_ERROR(!(st = SSL_CTX_get_cert_store(svr->ssl_ctx))); - SSL_ERROR_CHECK_GOTO_ERROR(!(lu = X509_STORE_add_lookup(st, X509_LOOKUP_file()))); - SSL_ERROR_CHECK_GOTO_ERROR(X509_load_crl_file(lu, crl_file, X509_FILETYPE_PEM) < 1); - if (!flag) - { - X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); - flag = EINA_TRUE; - } - - return EINA_TRUE; - -error: - _openssl_print_errors(obj, ECORE_CON_EVENT_SERVER_ERROR); - return EINA_FALSE; -} - -static Eina_Bool -_ecore_con_ssl_server_privkey_add_openssl(Ecore_Con_Server *obj, - const char *key_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - FILE *fp = NULL; - EVP_PKEY *privkey = NULL; - - if (!(fp = fopen(key_file, "rb"))) - goto error; - - SSL_ERROR_CHECK_GOTO_ERROR(!(privkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL))); - - fclose(fp); - fp = NULL; - SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_PrivateKey(svr->ssl_ctx, privkey) < 1); - SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_check_private_key(svr->ssl_ctx) < 1); - - return EINA_TRUE; - -error: - if (fp) - fclose(fp); - _openssl_print_errors(obj, ECORE_CON_EVENT_SERVER_ERROR); - return EINA_FALSE; -} - -static Eina_Bool -_ecore_con_ssl_server_cert_add_openssl(Ecore_Con_Server *obj, - const char *cert_file) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - FILE *fp = NULL; - X509 *cert = NULL; - - if (!(fp = fopen(cert_file, "rb"))) - goto error; - - SSL_ERROR_CHECK_GOTO_ERROR(!(cert = PEM_read_X509(fp, NULL, NULL, NULL))); - - fclose(fp); - fp = NULL; - SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_certificate(svr->ssl_ctx, cert) < 1); - - return EINA_TRUE; - -error: - if (fp) - fclose(fp); - _openssl_print_errors(obj, ECORE_CON_EVENT_SERVER_ERROR); - return EINA_FALSE; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_server_shutdown_openssl(Ecore_Con_Server *obj) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - if (svr->ssl) - { - if (!SSL_shutdown(svr->ssl)) - SSL_shutdown(svr->ssl); - - SSL_free(svr->ssl); - } - - if (svr->ssl_ctx) - SSL_CTX_free(svr->ssl_ctx); - - svr->ssl = NULL; - svr->ssl_ctx = NULL; - svr->ssl_err = SSL_ERROR_NONE; - - return ECORE_CON_SSL_ERROR_NONE; -} - -static int -_ecore_con_ssl_server_read_openssl(Ecore_Con_Server *obj, - unsigned char *buf, - int size) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - int num; - - if (!svr->ssl) return -1; - num = SSL_read(svr->ssl, buf, size); - svr->ssl_err = SSL_get_error(svr->ssl, num); - - if (svr->fd_handler) - { - if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_READ) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); - else if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_WRITE) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); - } - - if ((svr->ssl_err == SSL_ERROR_ZERO_RETURN) || - (svr->ssl_err == SSL_ERROR_SYSCALL) || - (svr->ssl_err == SSL_ERROR_SSL)) - return -1; - - if (num < 0) - return 0; - - return num; -} - -static int -_ecore_con_ssl_server_write_openssl(Ecore_Con_Server *obj, - const unsigned char *buf, - int size) -{ - Efl_Network_Server_Data *svr = efl_data_scope_get(obj, EFL_NETWORK_SERVER_CLASS); - int num; - - num = SSL_write(svr->ssl, buf, size); - svr->ssl_err = SSL_get_error(svr->ssl, num); - - if (svr->fd_handler) - { - if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_READ) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); - else if (svr->ssl && svr->ssl_err == SSL_ERROR_WANT_WRITE) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); - } - - if ((svr->ssl_err == SSL_ERROR_ZERO_RETURN) || - (svr->ssl_err == SSL_ERROR_SYSCALL) || - (svr->ssl_err == SSL_ERROR_SSL)) - return -1; - - if (num < 0) - return 0; - - return num; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_client_init_openssl(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - Efl_Network_Server_Data *host_server = efl_data_scope_get(cl->host_server, EFL_NETWORK_SERVER_CLASS); - int ret = -1; - switch (cl->ssl_state) - { - case ECORE_CON_SSL_STATE_DONE: - return ECORE_CON_SSL_ERROR_NONE; - - case ECORE_CON_SSL_STATE_INIT: - SSL_ERROR_CHECK_GOTO_ERROR(!(cl->ssl = SSL_new(host_server->ssl_ctx))); - - SSL_ERROR_CHECK_GOTO_ERROR(!SSL_set_fd(cl->ssl, cl->fd)); - SSL_set_accept_state(cl->ssl); - cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING; - - case ECORE_CON_SSL_STATE_HANDSHAKING: - if (!cl->ssl) - { - DBG("Client was previously lost, going to error condition"); - goto error; - } - ret = SSL_do_handshake(cl->ssl); - cl->ssl_err = SSL_get_error(cl->ssl, ret); - SSL_ERROR_CHECK_GOTO_ERROR((cl->ssl_err == SSL_ERROR_SYSCALL) || (cl->ssl_err == SSL_ERROR_SSL)); - if (ret == 1) - { - cl->handshaking = EINA_FALSE; - cl->ssl_state = ECORE_CON_SSL_STATE_DONE; - } - else - { - if (cl->ssl_err == SSL_ERROR_WANT_READ) - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); - else if (cl->ssl_err == SSL_ERROR_WANT_WRITE) - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE); - return ECORE_CON_SSL_ERROR_NONE; - } - - default: - break; - } - - _openssl_print_session(cl->ssl); - if (!host_server->verify) - /* not verifying certificates, so we're done! */ - return ECORE_CON_SSL_ERROR_NONE; - SSL_set_verify(cl->ssl, SSL_VERIFY_PEER, NULL); - /* use CRL/CA lists to verify */ - if (SSL_get_peer_certificate(cl->ssl)) - { - int err; - - err = SSL_get_verify_result(cl->ssl); - _openssl_print_verify_error(err); - SSL_ERROR_CHECK_GOTO_ERROR(err); - } - - return ECORE_CON_SSL_ERROR_NONE; - -error: - _openssl_print_errors(obj, ECORE_CON_EVENT_CLIENT_ERROR); - _ecore_con_ssl_client_shutdown_openssl(obj); - return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_client_shutdown_openssl(Ecore_Con_Client *obj) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - if (cl->ssl) - { - if (!SSL_shutdown(cl->ssl)) - SSL_shutdown(cl->ssl); - - SSL_free(cl->ssl); - } - - cl->ssl = NULL; - cl->ssl_err = SSL_ERROR_NONE; - - return ECORE_CON_SSL_ERROR_NONE; -} - -static int -_ecore_con_ssl_client_read_openssl(Ecore_Con_Client *obj, - unsigned char *buf, - int size) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - int num; - - if (!cl->ssl) return -1; - num = SSL_read(cl->ssl, buf, size); - cl->ssl_err = SSL_get_error(cl->ssl, num); - - if (cl->fd_handler) - { - if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_READ) - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); - else if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_WRITE) - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE); - } - - if ((cl->ssl_err == SSL_ERROR_ZERO_RETURN) || - (cl->ssl_err == SSL_ERROR_SYSCALL) || - (cl->ssl_err == SSL_ERROR_SSL)) - return -1; - - if (num < 0) - return 0; - - return num; -} - -static int -_ecore_con_ssl_client_write_openssl(Ecore_Con_Client *obj, - const unsigned char *buf, - int size) -{ - Efl_Network_Client_Data *cl = efl_data_scope_get(obj, EFL_NETWORK_CLIENT_CLASS); - int num; - - num = SSL_write(cl->ssl, buf, size); - cl->ssl_err = SSL_get_error(cl->ssl, num); - - if (cl->fd_handler) - { - if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_READ) - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); - else if (cl->ssl && cl->ssl_err == SSL_ERROR_WANT_WRITE) - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE); - } - - if ((cl->ssl_err == SSL_ERROR_ZERO_RETURN) || - (cl->ssl_err == SSL_ERROR_SYSCALL) || - (cl->ssl_err == SSL_ERROR_SSL)) - return -1; - - if (num < 0) - return 0; - - return num; -} - -#else - -/* - * No Ssl - */ -static Ecore_Con_Ssl_Error -_ecore_con_ssl_server_prepare_none(Ecore_Con_Server *svr EINA_UNUSED, - int ssl_type EINA_UNUSED) -{ - return ECORE_CON_SSL_ERROR_NONE; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_server_init_none(Ecore_Con_Server *svr EINA_UNUSED) -{ - return ECORE_CON_SSL_ERROR_NOT_SUPPORTED; -} - -static Eina_Bool -_ecore_con_ssl_server_cafile_add_none(Ecore_Con_Server *svr EINA_UNUSED, - const char *ca_file EINA_UNUSED) -{ - return EINA_FALSE; -} - -static Eina_Bool -_ecore_con_ssl_server_cert_add_none(Ecore_Con_Server *svr EINA_UNUSED, - const char *cert_file EINA_UNUSED) -{ - return EINA_FALSE; -} - -static Eina_Bool -_ecore_con_ssl_server_privkey_add_none(Ecore_Con_Server *svr EINA_UNUSED, - const char *key_file EINA_UNUSED) -{ - return EINA_FALSE; -} - -static Eina_Bool -_ecore_con_ssl_server_crl_add_none(Ecore_Con_Server *svr EINA_UNUSED, - const char *crl_file EINA_UNUSED) -{ - return EINA_FALSE; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_server_shutdown_none(Ecore_Con_Server *svr EINA_UNUSED) -{ - return ECORE_CON_SSL_ERROR_NOT_SUPPORTED; -} - -static int -_ecore_con_ssl_server_read_none(Ecore_Con_Server *svr EINA_UNUSED, - unsigned char *buf EINA_UNUSED, - int size EINA_UNUSED) -{ - return -1; -} - -static int -_ecore_con_ssl_server_write_none(Ecore_Con_Server *svr EINA_UNUSED, - const unsigned char *buf EINA_UNUSED, - int size EINA_UNUSED) -{ - return -1; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_client_init_none(Ecore_Con_Client *cl EINA_UNUSED) -{ - return ECORE_CON_SSL_ERROR_NOT_SUPPORTED; -} - -static Ecore_Con_Ssl_Error -_ecore_con_ssl_client_shutdown_none(Ecore_Con_Client *cl EINA_UNUSED) -{ - return ECORE_CON_SSL_ERROR_NOT_SUPPORTED; -} - -static int -_ecore_con_ssl_client_read_none(Ecore_Con_Client *cl EINA_UNUSED, - unsigned char *buf EINA_UNUSED, - int size EINA_UNUSED) -{ - return -1; -} - -static int -_ecore_con_ssl_client_write_none(Ecore_Con_Client *cl EINA_UNUSED, - const unsigned char *buf EINA_UNUSED, - int size EINA_UNUSED) -{ - return -1; -} - -#endif diff --git a/src/lib/ecore_con/efl_network.eo b/src/lib/ecore_con/efl_network.eo deleted file mode 100644 index 2f95a0584f..0000000000 --- a/src/lib/ecore_con/efl_network.eo +++ /dev/null @@ -1,201 +0,0 @@ -type Ecore_Con_Dns_Cb: __undefined_type; [[Ecore connection DNS callback type]] - -enum Ecore.Con.Type -{ - [[Types for an ecore_con client/server object. A correct way to set this type is - with an ECORE_CON_$TYPE, optionally OR'ed with an ECORE_CON_$USE if encryption is desired, - and LOAD_CERT if the previously loaded certificate should be used.]] - legacy: ecore_con; - - local_user = 0, [[Socket in "~/.ecore"]] - local_system = 1, [[Socket in /tmp]] - local_abstract = 2, [[Abstract socket]] - remote_tcp = 3, [[Remote server using TCP]] - remote_mcast = 4, [[Remote multicast server]] - remote_udp = 5, [[Remote server using UDP]] - remote_broadcasT = 6, [[Remote broadcast using UDP]] - remote_nodelay = 7, [[Remote connection sending packets immediately]] - remote_cork = 8, [[Remote connection sending data in large chunks - Note: Only available on Linux - @since 1.2]] - use_ssl2 = (1 << 4), [[Use SSL2: UNSUPPORTED.]] - use_ssl3 = (1 << 5), [[Use SSL3: UNSUPPORTED.]] - use_tls = (1 << 6), [[Use TLS]] - use_mixed = Ecore.Con.Type.use_tls | Ecore.Con.Type.use_ssl3, [[Use both TLS and SSL3]] - load_cert = (1 << 7), [[Attempt to use the loaded certificate]] - no_proxy = (1 << 8), [[Disable all types of proxy on the server - Note: Only functional for clients - @since 1.2]] - socket_activate = (1 << 9) [[Indicate if the type is socket activated]] -} - -abstract Efl.Network (Efl.Object) { - [[Abstract base class for all EFL.Network classes]] - - legacy_prefix: ecore_con; - eo_prefix: efl_network; - data: null; - methods { - @property ip { - [[Control the IP address of a server that has been connected to. - - The parameter is a pointer to an internal string that contains the IP - address of the connected server in the form "XXX.YYY.ZZZ.AAA" IP - notation. This string should not be modified or trusted to stay - valid after deletion for the svr object. If no IP is known - null is returned. - ]] - get @virtual_pure { - legacy: null; - } - values { - ip: string; [[The IP address]] - } - } - @property uptime { - [[Check how long the object has been connected - - This function is used to find out how long a client has been - connected. - ]] - get @virtual_pure { - legacy: null; - } - values { - uptime: double; [[The total time, in seconds, that the object has been connected.]] - } - } - @property port @virtual_pure { - [[The port that the obj is connected to]] - set { - legacy: null; - } - get { - legacy: null; - } - values { - port: int; [[The port that obj is connected to, or -1 on error.]] - } - } - @property fd { - [[Get the fd that the server is connected to - - This function returns the fd which is used by the underlying server - connection. It should not be tampered with unless you REALLY know - what you are doing. - - Note: This function is only valid for servers created with - \@ref ecore_con_server_connect. - - Warning: Seriously. Don't use this unless you know what you are doing. - - @since 1.1 - ]] - get @virtual_pure { - legacy: null; - } - values { - fd: int; [[The fd, or -1 on failure.]] - } - } - @property connected { - [[Returns whether the client is still connected]] - get @virtual_pure { - legacy: null; - } - values { - connected: bool; [[$true if connected, $false otherwise.]] - } - } - @property timeout @virtual_pure { - [[Control the default time after which an inactive client will be - disconnected. - - This function is used by the server to set the default idle timeout - on clients. If any of the clients becomes idle for a time higher - than this value, it will be disconnected. A value of < 1 disables - the idle timeout. - - This timeout is not affected by the one set by @.timeout.set. A - client will be disconnected whenever the client or the server - timeout is reached. That means, the lower timeout value will be - used for that client if @.timeout.set is used on it. - ]] - set { - legacy: null; - } - get { - legacy: null; - } - values { - timeout: double; [[The timeout, in seconds, to disconnect after.]] - } - } - flush @virtual_pure { - [[Flushes all pending data to the given server. - - This function will block until all data is sent to the server. - ]] - legacy: null; - } - send @virtual_pure { - [[Sends the given data to the given server. - - This function will send the given data to the server as soon as the - program is back to the main loop. Thus, this function returns - immediately (non-blocking). If the data needs to be sent now, call - \@ref ecore_con_server_flush after this one. - ]] - legacy: null; - - params { - data: const(void_ptr); [[The given data]] - size: int; [[Length of the data, in bytes.]] - } - return: int; [[The number of bytes sent. 0 will be returned if there - is an error.]] - } - lookup @class { - [[Do an asynchronous DNS lookup. - - This function performs a DNS lookup on the hostname specified by name, - then calls done_cb with the result and the data given as parameter. - The result will be given to the done_cb as follows: - - canonname - the canonical name of the address, ip - the resolved ip - address, addr - a pointer to the socket address, addrlen - the length - of the socket address, in bytes, data - the data pointer given as - parameter. - ]] - params { - name: string @nonull; [[IP address or server name to translate.]] - done_cb: Ecore_Con_Dns_Cb; [[Callback to notify when done.]] - data: const(void_ptr); [[User data to be given to done_cb.]] - } - return: bool; [[$true if the request did not fail to be set up, $false otherwise.]] - } - } - events { - data,received: Ecore.Con.Event_Data.Received; [[Data received on connection]] - connection,upgraded; [[FIXME: what does upgrade mean here??]] - connection,error: string; [[Error received on connection]] - } -} - -/* FIXME: Should actually be a binbuf. */ -struct Ecore.Con.Event_Data.Received { - [[Ecore connection event data received data structure]] - data: void_ptr; [[The data that got sent.]] - size: int; [[The length of the data sent.]] -} - -/* TODO -* Add events (to all of the ecore con stuff, e.g url). -* Make server the father of the client - make sure I don't leak references. -* -* Still need to add constructor client, and most likely migrate ecore_con_eet. -* -* Split server to two classes, listener and connector (or w/e). -* -* Mark the constructing properties all around. -*/ diff --git a/src/lib/ecore_con/efl_network_client.eo b/src/lib/ecore_con/efl_network_client.eo deleted file mode 100644 index bf3f6c2f32..0000000000 --- a/src/lib/ecore_con/efl_network_client.eo +++ /dev/null @@ -1,30 +0,0 @@ -class Efl.Network.Client (Efl.Network) { - [[Efl network client]] - legacy_prefix: ecore_con_client; - eo_prefix: efl_network_client_obj; - methods { - @property server { - [[The server the client is connected to.]] - get { - } - values { - svr: Efl.Network.Server; [[The server the client is connected to.]] - } - } - } - implements { - Efl.Object.destructor; - Efl.Network.ip.get; - Efl.Network.uptime.get; - Efl.Network.port.get; - Efl.Network.fd.get; - Efl.Network.connected.get; - Efl.Network.timeout.set; - Efl.Network.timeout.get; - Efl.Network.flush; - Efl.Network.send; - } -} - -/* FIXME: Should SSL inherit from client? What's exactly the interaction here? - Fix clients to be children of server when created .*/ diff --git a/src/lib/ecore_con/efl_network_connector.eo b/src/lib/ecore_con/efl_network_connector.eo deleted file mode 100644 index 5b3e27e321..0000000000 --- a/src/lib/ecore_con/efl_network_connector.eo +++ /dev/null @@ -1,8 +0,0 @@ -class Efl.Network.Connector (Efl.Network.Server) { - [[Efl network connector class]] - eo_prefix: efl_network_connector_obj; - data: null; - implements { - Efl.Object.finalize; - } -} diff --git a/src/lib/ecore_con/efl_network_server.eo b/src/lib/ecore_con/efl_network_server.eo deleted file mode 100644 index 972e262ffa..0000000000 --- a/src/lib/ecore_con/efl_network_server.eo +++ /dev/null @@ -1,93 +0,0 @@ -class Efl.Network.Server (Efl.Network) { - [[Efl network server]] - legacy_prefix: ecore_con_server; - eo_prefix: efl_network_server; - methods { - @property name { - [[Retrieves the name of server. - - The name returned is the name used to connect on this server. - ]] - set { - legacy: null; - } - get { - } - values { - name: string; [[The name of the server.]] - } - } - @property client_limit { - [[Sets a limit on the number of clients that can be handled concurrently - by the given server, and a policy on what to do if excess clients - try to connect. - - Beware that if you set this once ecore is already running, you may - already have pending CLIENT_ADD events in your event queue. Those - clients have already connected and will not be affected by this call. - Only clients subsequently trying to connect will be affected. - ]] - set { - } - get { - legacy: null; - } - values { - client_limit: int; [[The maximum number of clients to handle - concurrently. -1 means unlimited (default). - 0 effectively disables the server.]] - reject_excess_clients: char; [[Set to 1 to automatically disconnect excess clients as - soon as they connect if you are already handling - client_limit clients. Set to 0 (default) to just - hold off on the "accept()" system call until the - number of active clients drops. This causes the - kernel to queue up to 4096 connections (or your - kernel's limit, whichever is lower). - ]] - } - } - /* FIXME: Should this return an iterator? */ - @property clients { - [[Retrieves the current list of clients. - - Each node in the returned list points to an \@ref Efl_Network_Client. - This list cannot be modified or freed. It can also change if new - clients are connected or disconnected, and will become invalid - when the server is deleted/freed. - ]] - get { - } - values { - // FIXME: Efl.Network.Client is needed, but that introduces a cycle - clients: const(list); [[The list of clients on this server.]] - } - } - @property connection_type { - [[Type of the server connection as defined in @Ecore.Con.Type]] - get { - legacy: null; - } - set { - legacy: null; - } - values { - conn_type: Ecore.Con.Type; [[Connection type]] - } - } - } - implements { - Efl.Object.constructor; - Efl.Object.destructor; - Efl.Object.finalize; - Efl.Network.ip.get; - Efl.Network.uptime.get; - Efl.Network.port.set; - Efl.Network.port.get; - Efl.Network.fd.get; - Efl.Network.connected.get; - Efl.Network.timeout.set; - Efl.Network.timeout.get; - Efl.Network.flush; - Efl.Network.send; - } -}