Tizen 2.0 Release
[profile/ivi/ecore.git] / src / lib / ecore_con / ecore_con.c
index 8bebde0..ab57378 100644 (file)
@@ -1,17 +1,41 @@
-/*
- * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
- */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
 
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
 #include <sys/stat.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/un.h>
 #include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
 
-#include <config.h>
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+#endif
 
-#if USE_OPENSSL
-#include <time.h>
+#ifdef HAVE_EVIL
+# include <Evil.h>
 #endif
 
 #include "Ecore.h"
 #include "Ecore_Con.h"
 #include "ecore_con_private.h"
 
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-#ifdef HAVE_WINSOCK2_H
-# include <winsock2.h>
-#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_cb_dns_lookup(void *data, struct hostent *he);
-static void _ecore_con_server_free(Ecore_Con_Server *svr);
-static void _ecore_con_client_free(Ecore_Con_Client *cl);
-static int _ecore_con_svr_handler(void *data, Ecore_Fd_Handler *fd_handler);
-static int _ecore_con_cl_handler(void *data, Ecore_Fd_Handler *fd_handler);
-static int _ecore_con_svr_cl_handler(void *data, Ecore_Fd_Handler *fd_handler);
 static void _ecore_con_server_flush(Ecore_Con_Server *svr);
 static void _ecore_con_client_flush(Ecore_Con_Client *cl);
-static void _ecore_con_event_client_add_free(void *data, void *ev);
-static void _ecore_con_event_client_del_free(void *data, void *ev);
-static void _ecore_con_event_client_data_free(void *data, 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_client_add_free(Ecore_Con_Server *svr,
+                                             void *ev);
+static void _ecore_con_event_client_del_free(Ecore_Con_Server *svr,
+                                             void *ev);
+static void _ecore_con_event_client_data_free(Ecore_Con_Server *svr,
+                                              void *ev);
+static void _ecore_con_event_server_add_free(void *data,
+                                             void *ev);
+static void _ecore_con_event_server_del_free(void *data,
+                                             void *ev);
+static void _ecore_con_event_server_data_free(void *data,
+                                              void *ev);
+static void _ecore_con_event_server_error_free(void *data,
+                                               Ecore_Con_Event_Server_Error *e);
+static void _ecore_con_event_client_error_free(Ecore_Con_Server *svr,
+                                               Ecore_Con_Event_Client_Error *e);
+static void _ecore_con_event_server_write_free(void *data,
+                                               Ecore_Con_Event_Server_Write *e);
+static void _ecore_con_event_client_write_free(Ecore_Con_Server *svr,
+                                               Ecore_Con_Event_Client_Write *e);
+
+static void _ecore_con_lookup_done(void           *data,
+                                   Ecore_Con_Info *infos);
+
+static const char * _ecore_con_pretty_ip(struct sockaddr *client_addr);
+
+
+void
+_ecore_con_client_kill(Ecore_Con_Client *cl)
+{
+   if (cl->delete_me)
+     DBG("Multi kill request for client %p", cl);
+   else
+     {
+        ecore_con_event_client_del(cl);
+        if (cl->buf) return;
+     }
+   INF("Lost client %s", (cl->ip) ? cl->ip : "");
+   if (cl->fd_handler)
+     ecore_main_fd_handler_del(cl->fd_handler);
+
+   cl->fd_handler = NULL;
+}
+
+void
+_ecore_con_server_kill(Ecore_Con_Server *svr)
+{
+   if (svr->delete_me)
+     DBG("Multi kill request for svr %p", svr);
+   else
+     ecore_con_event_server_del(svr);
+
+   if (svr->fd_handler)
+     ecore_main_fd_handler_del(svr->fd_handler);
+
+   svr->fd_handler = NULL;
+}
+
+#define _ecore_con_server_kill(svr) do { \
+   DBG("KILL %p", (svr)); \
+   _ecore_con_server_kill((svr)); \
+} while (0)
+
+#define _ecore_con_client_kill(cl) do { \
+   DBG("KILL %p", (cl)); \
+   _ecore_con_client_kill((cl)); \
+} while (0)
 
 EAPI int ECORE_CON_EVENT_CLIENT_ADD = 0;
 EAPI int ECORE_CON_EVENT_CLIENT_DEL = 0;
@@ -47,936 +151,1142 @@ EAPI int ECORE_CON_EVENT_SERVER_ADD = 0;
 EAPI int ECORE_CON_EVENT_SERVER_DEL = 0;
 EAPI int ECORE_CON_EVENT_CLIENT_DATA = 0;
 EAPI int ECORE_CON_EVENT_SERVER_DATA = 0;
+EAPI int ECORE_CON_EVENT_CLIENT_WRITE = 0;
+EAPI int ECORE_CON_EVENT_SERVER_WRITE = 0;
+EAPI int ECORE_CON_EVENT_CLIENT_ERROR = 0;
+EAPI int ECORE_CON_EVENT_SERVER_ERROR = 0;
+EAPI int ECORE_CON_EVENT_PROXY_BIND = 0;
+
+static Eina_List *servers = NULL;
+static int _ecore_con_init_count = 0;
+static int _ecore_con_event_count = 0;
+int _ecore_con_log_dom = -1;
+Ecore_Con_Socks *_ecore_con_proxy_once = NULL;
+Ecore_Con_Socks *_ecore_con_proxy_global = NULL;
+
+EAPI int
+ecore_con_init(void)
+{
+   if (++_ecore_con_init_count != 1)
+     return _ecore_con_init_count;
+
+#ifdef HAVE_EVIL
+   if (!evil_init())
+     return --_ecore_con_init_count;
 
-static Ecore_List *servers = NULL;
-static int init_count = 0;
-#if USE_OPENSSL
-static int ssl_init_count = 0;
 #endif
 
-#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))
+   if (!ecore_init())
+     return --_ecore_con_init_count;
 
-/**
- * @defgroup Ecore_Con_Lib_Group Ecore Connection Library Functions
- *
- * Utility functions that set up and shut down the Ecore Connection
- * library.
- */
+   _ecore_con_log_dom = eina_log_domain_register
+       ("ecore_con", ECORE_CON_DEFAULT_LOG_COLOR);
+   if (_ecore_con_log_dom < 0)
+     {
+        EINA_LOG_ERR("Impossible to create a log domain for Ecore Con.");
+        ecore_shutdown();
+        return --_ecore_con_init_count;
+     }
 
-/**
- * Initialises the Ecore_Con library.
- * @return  Number of times the library has been initialised without being
- *          shut down.
- * @ingroup Ecore_Con_Lib_Group
- */
-EAPI int
-ecore_con_init(void)
-{
-   if (++init_count != 1) return init_count;
+   ecore_con_mempool_init();
 
-   ecore_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();
 
-   /* TODO Remember return value, if it fails, use gethostbyname() */
-   ecore_con_dns_init();
 
-   servers = ecore_list_new();
+   eina_magic_string_set(ECORE_MAGIC_CON_SERVER, "Ecore_Con_Server");
+   eina_magic_string_set(ECORE_MAGIC_CON_CLIENT, "Ecore_Con_Client");
+   eina_magic_string_set(ECORE_MAGIC_CON_URL, "Ecore_Con_Url");
+
+   /* TODO Remember return value, if it fails, use gethostbyname() */
+   ecore_con_socks_init();
+   ecore_con_ssl_init();
+   ecore_con_info_init();
 
-   return init_count;
+   return _ecore_con_init_count;
 }
 
-/**
- * Shuts down the Ecore_Con library.
- * @return  Number of times the library has been initialised without being
- *          shut down.
- * @ingroup Ecore_Con_Lib_Group
- */
 EAPI int
 ecore_con_shutdown(void)
 {
-   if (--init_count != 0) return init_count;
+   Eina_List *l, *l2;
+   Ecore_Con_Server *svr;
+
+   if (--_ecore_con_init_count != 0)
+     return _ecore_con_init_count;
 
-   while (!ecore_list_empty_is(servers))
-     _ecore_con_server_free(ecore_list_first_remove(servers));
-   ecore_list_destroy(servers);
-   servers = NULL;
+   EINA_LIST_FOREACH_SAFE(servers, l, l2, svr)
+     {
+        Ecore_Con_Event_Server_Add *ev;
+
+        svr->delete_me = EINA_TRUE;
+        INF("svr %p is dead", svr);
+        /* some pointer hacks here to prevent double frees if people are being stupid */
+        EINA_LIST_FREE(svr->event_count, ev)
+          ev->server = NULL;
+        _ecore_con_server_free(svr);
+     }
 
-   ecore_con_dns_shutdown();
+   ecore_con_socks_shutdown();
+   if (!_ecore_con_event_count) ecore_con_mempool_shutdown();
 
+   ecore_con_info_shutdown();
+   ecore_con_ssl_shutdown();
+   eina_log_domain_unregister(_ecore_con_log_dom);
+   _ecore_con_log_dom = -1;
    ecore_shutdown();
+#ifdef HAVE_EVIL
+   evil_shutdown();
+#endif
+
+   return _ecore_con_init_count;
+}
+
+EAPI Eina_Bool
+ecore_con_lookup(const char      *name,
+                 Ecore_Con_Dns_Cb done_cb,
+                 const void      *data)
+{
+   Ecore_Con_Server *svr;
+   Ecore_Con_Lookup *lk;
+   struct addrinfo hints;
+
+   if (!name || !done_cb)
+     return EINA_FALSE;
+
+   svr = calloc(1, sizeof(Ecore_Con_Server));
+   if (!svr)
+     return EINA_FALSE;
+
+   lk = malloc(sizeof (Ecore_Con_Lookup));
+   if (!lk)
+     {
+        free(svr);
+        return EINA_FALSE;
+     }
+
+   lk->done_cb = done_cb;
+   lk->data = data;
 
-   return init_count;
+   svr->name = strdup(name);
+   if (!svr->name)
+     goto on_error;
+
+   svr->type = ECORE_CON_REMOTE_TCP;
+   svr->port = 1025;
+   svr->data = lk;
+   svr->created = EINA_TRUE;
+   svr->reject_excess_clients = EINA_FALSE;
+   svr->client_limit = -1;
+   svr->clients = NULL;
+   svr->ppid = getpid();
+
+   memset(&hints, 0, sizeof(struct addrinfo));
+   hints.ai_family = AF_UNSPEC;
+   hints.ai_socktype = SOCK_STREAM;
+   hints.ai_flags = AI_CANONNAME;
+   hints.ai_protocol = IPPROTO_TCP;
+   hints.ai_canonname = NULL;
+   hints.ai_next = NULL;
+   hints.ai_addr = NULL;
+
+   if (ecore_con_info_get(svr, _ecore_con_lookup_done, svr,
+                          &hints))
+     return EINA_TRUE;
+
+   free(svr->name);
+on_error:
+   free(lk);
+   free(svr);
+   return EINA_FALSE;
 }
 
 /**
- * @defgroup Ecore_Con_Server_Group Ecore Connection Server Functions
+ * @addtogroup Ecore_Con_Server_Group Ecore Connection Server Functions
  *
  * Functions that operate on Ecore server objects.
+ *
+ * @{
  */
 
 /**
- * Creates a server to listen for connections.
- *
- * The socket on which the server listens depends on the connection
- * type:
- * @li If @a compl_type is @c ECORE_CON_LOCAL_USER, the server will listen on
- *     the Unix socket "~/.ecore/[name]/[port]".
- * @li If @a compl_type is @c ECORE_CON_LOCAL_SYSTEM, the server will listen
- *     on Unix socket "/tmp/.ecore_service|[name]|[port]".
- * @li If @a compl_type is @c ECORE_CON_REMOTE_SYSTEM, the server will listen
- *     on TCP port @c port.
- *
- * @param  compl_type The connection type.
- * @param  name       Name to associate with the socket.  It is used when
- *                    generating the socket name of a Unix socket.  Though
- *                    it is not used for the TCP socket, it still needs to
- *                    be a valid character array.  @c NULL will not be
- *                    accepted.
- * @param  port       Number to identify socket.  When a Unix socket is used,
- *                    it becomes part of the socket name.  When a TCP socket
- *                    is used, it is used as the TCP port.
- * @param  data       Data to associate with the created Ecore_Con_Server
- *                    object.
- * @return A new Ecore_Con_Server.
- * @ingroup Ecore_Con_Server_Group
+ * @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_add(Ecore_Con_Type compl_type,
+                     const char    *name,
+                     int            port,
+                     const void    *data)
 {
-   Ecore_Con_Server   *svr;
-   Ecore_Con_Type      type;
-   struct sockaddr_in  socket_addr;
-   struct sockaddr_un  socket_unix;
-   struct linger       lin;
-   char                buf[4096];
+   Ecore_Con_Server *svr;
+   Ecore_Con_Type type;
+
+   if (port < 0 || !name)
+     return NULL;  /* local  user   socket: FILE:   ~/.ecore/[name]/[port] */
 
-   if (port < 0) return NULL;
-   /* local  user   socket: FILE:   ~/.ecore/[name]/[port] */
    /* local  system socket: FILE:   /tmp/.ecore_service|[name]|[port] */
    /* remote system socket: TCP/IP: [name]:[port] */
    svr = calloc(1, sizeof(Ecore_Con_Server));
-   if (!svr) return NULL;
-
-   type = compl_type;
-#if USE_OPENSSL
-   /* unset the SSL flag for the following checks */
-   type &= ECORE_CON_TYPE;
-#endif
-
-   if ((type == ECORE_CON_LOCAL_USER) || (type == ECORE_CON_LOCAL_SYSTEM) ||
-       (type == ECORE_CON_LOCAL_ABSTRACT))
-     {
-       const char *homedir;
-       struct stat st;
-       mode_t pmode, mask;
-       int socket_unix_len;
-
-       if (!name) goto error;
-       mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
-
-       if (type == ECORE_CON_LOCAL_USER)
-         {
-            homedir = getenv("HOME");
-            if (!homedir) homedir = getenv("TMP");
-            if (!homedir) homedir = "/tmp";
-            mask = S_IRUSR | S_IWUSR | S_IXUSR;
-            snprintf(buf, sizeof(buf), "%s/.ecore", homedir);
-            if (stat(buf, &st) < 0) mkdir(buf, mask);
-            snprintf(buf, sizeof(buf), "%s/.ecore/%s", homedir, name);
-            if (stat(buf, &st) < 0) mkdir(buf, mask);
-            snprintf(buf, sizeof(buf), "%s/.ecore/%s/%i", homedir, name, port);
-            mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
-         }
-       else if (type == ECORE_CON_LOCAL_SYSTEM)
-         {
-            mask = 0;
-            if (name[0] == '/')
-              {
-                 if (port >= 0)
-                   snprintf(buf, sizeof(buf), "%s|%i", name, port);
-                 else
-                   snprintf(buf, sizeof(buf), "%s", name);
-              }
-            else
-              snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i", name, port);
-         }
-       else if (type == ECORE_CON_LOCAL_ABSTRACT)
-         strncpy(buf, name, sizeof(buf));
-       pmode = umask(mask);
-       start:
-       svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (svr->fd < 0)
-         {
-            umask(pmode);
-            goto error;
-         }
-       if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
-         {
-            umask(pmode);
-            goto error;
-         }
-       if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
-         {
-            umask(pmode);
-            goto error;
-         }
-       lin.l_onoff = 1;
-       lin.l_linger = 0;
-       if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0)
-         {
-            umask(pmode);
-            goto error;
-         }
-       socket_unix.sun_family = AF_UNIX;
-       if (type == ECORE_CON_LOCAL_ABSTRACT)
-         {
-#ifdef HAVE_ABSTRACT_SOCKET
-            /* . is a placeholder */
-            snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", name);
-            /* first char null indicates abstract namespace */
-            socket_unix.sun_path[0] = '\0';
-            socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, name);
-#else
-            fprintf(stderr, "Your system does not support abstract sockets!\n");
-            umask(pmode);
-            goto error;
-#endif
-         }
-       else
-         {
-            strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
-            socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
-         }
-       if (bind(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
-         {
-            if (connect(svr->fd, (struct sockaddr *)&socket_unix,
-                        socket_unix_len) < 0)
-              {
-                 if ((type == ECORE_CON_LOCAL_USER) || 
-                     (type == ECORE_CON_LOCAL_SYSTEM))
-                   {
-                      if (unlink(buf) < 0)
-                        {
-                           umask(pmode);
-                           goto error;
-                        }
-                      else
-                        goto start;
-                   }
-                 else
-                   {
-                      umask(pmode);
-                      goto error;
-                   }
-              }
-            else
-              {
-                 umask(pmode);
-                 goto error;
-              }
-         }
-       if (listen(svr->fd, 4096) < 0)
-         {
-            umask(pmode);
-            goto error;
-         }
-       svr->path = strdup(buf);
-       if (!svr->path)
-         {
-            umask(pmode);
-            goto error;
-         }
-       svr->fd_handler = 
-         ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
-                                   _ecore_con_svr_handler, svr, NULL, NULL);
-       umask(pmode);
-       if (!svr->fd_handler) goto error;
-     }
-   else if (type == ECORE_CON_REMOTE_SYSTEM)
-     {
-       svr->fd = socket(AF_INET, SOCK_STREAM, 0);
-       if (svr->fd < 0) goto error;
-       if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
-       if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
-       lin.l_onoff = 1;
-       lin.l_linger = 0;
-       if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0) goto error;
-       socket_addr.sin_family = AF_INET;
-       socket_addr.sin_port = htons(port);
-       socket_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-       if (bind(svr->fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) < 0) goto error;
-       if (listen(svr->fd, 4096) < 0) goto error;
-       svr->fd_handler = 
-         ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
-                                   _ecore_con_svr_handler, svr, NULL, NULL);
-       if (!svr->fd_handler) goto error;
-     }
-
-#if USE_OPENSSL
-   if (compl_type & ECORE_CON_SSL)
-     {
-       if (!ssl_init_count)
-         {
-            SSL_library_init();
-            SSL_load_error_strings();
-         }
-       ssl_init_count++;
-
-       switch (compl_type & ECORE_CON_SSL)
-         {
-          case ECORE_CON_USE_SSL2:
-             if (!(svr->ssl_ctx = SSL_CTX_new(SSLv2_client_method())))
-               goto error;
-             break;
-          case ECORE_CON_USE_SSL3:
-             if (!(svr->ssl_ctx = SSL_CTX_new(SSLv3_client_method())))
-               goto error;
-             break;
-          case ECORE_CON_USE_TLS:
-             if (!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method())))
-               goto error;
-             break;
-         }
-
-       if (!(svr->ssl = SSL_new(svr->ssl_ctx)))
-         goto error;
-
-       SSL_set_fd(svr->ssl, svr->fd);
-     }
-#endif
+   if (!svr)
+     return NULL;
 
    svr->name = strdup(name);
-   if (!svr->name) goto error;
-   svr->type = type;
+   if (!svr->name)
+     goto error;
+
+   svr->type = compl_type;
    svr->port = port;
    svr->data = (void *)data;
-   svr->created = 1;
-   svr->reject_excess_clients = 0;
+   svr->created = EINA_TRUE;
+   svr->use_cert = (compl_type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT;
+   svr->reject_excess_clients = EINA_FALSE;
    svr->client_limit = -1;
-   svr->clients = ecore_list_new();
+   svr->clients = NULL;
    svr->ppid = getpid();
-   ecore_list_append(servers, svr);
+   if (ecore_con_ssl_server_prepare(svr, compl_type & ECORE_CON_SSL))
+     goto error;
+
+   type = compl_type & ECORE_CON_TYPE;
+
+   if ((type == ECORE_CON_LOCAL_USER) ||
+       (type == ECORE_CON_LOCAL_SYSTEM) ||
+       (type == ECORE_CON_LOCAL_ABSTRACT))
+     /* Local */
+#ifdef _WIN32
+     if (!ecore_con_local_listen(svr))
+       goto error;
+#else
+     if (!ecore_con_local_listen(svr, _ecore_con_svr_tcp_handler, svr))
+       goto error;
+#endif
+
+   if ((type == ECORE_CON_REMOTE_TCP) ||
+       (type == ECORE_CON_REMOTE_NODELAY) ||
+       (type == ECORE_CON_REMOTE_CORK))
+     {
+        /* TCP */
+         if (!ecore_con_info_tcp_listen(svr, _ecore_con_cb_tcp_listen,
+                                        svr))
+           goto error;
+     }
+   else if ((type == ECORE_CON_REMOTE_MCAST) ||
+            (type == ECORE_CON_REMOTE_UDP))
+     /* UDP and MCAST */
+     if (!ecore_con_info_udp_listen(svr, _ecore_con_cb_udp_listen,
+                                    svr))
+       goto error;
+
+   servers = eina_list_append(servers, svr);
    ECORE_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER);
+
    return svr;
 
-   error:
-   if (svr->name) free(svr->name);
-   if (svr->path) free(svr->path);
-   if (svr->fd >= 0) close(svr->fd);
-   if (svr->fd_handler) ecore_main_fd_handler_del(svr->fd_handler);
-   if (svr->write_buf) free(svr->write_buf);
-   if (svr->ip) free(svr->ip);
-#if USE_OPENSSL
-   if (svr->ssl) SSL_free(svr->ssl);
-   if (svr->ssl_ctx) SSL_CTX_free(svr->ssl_ctx);
-#endif
+error:
+   if (svr->name)
+     free(svr->name);
+
+   if (svr->path)
+     free(svr->path);
+
+
+   if (svr->fd_handler)
+     ecore_main_fd_handler_del(svr->fd_handler);
+
+   if (svr->fd > 0)
+     close(svr->fd);
+
+   if (svr->buf)
+     eina_binbuf_free(svr->buf);
+
+   if (svr->ip)
+     eina_stringshare_del(svr->ip);
+
+   ecore_con_ssl_server_shutdown(svr);
    free(svr);
    return NULL;
 }
 
-/**
- * Creates a server object to represent the server listening at the
- * given port.
- *
- * The socket to which the server connects depends on the connection type:
- * @li If @a compl_type is @c ECORE_CON_LOCAL_USER, the function will
- *     connect to the server listening on the Unix socket
- *     "~/.ecore/[name]/[port]".
- * @li If @a compl_type is @c ECORE_CON_LOCAL_SYSTEM, the function will
- *     connect to the server listening on the Unix socket
- *     "/tmp/.ecore_service|[name]|[port]".
- * @li If @a compl_type is @c ECORE_CON_REMOTE_SYSTEM, the function will
- *     connect to the server listening on the TCP port "[name]:[port]".
- *
- * @param  compl_type The connection type.
- * @param  name       Name used when determining what socket to connect to.
- *                    It is used to generate the socket name when the socket
- *                    is a Unix socket.  It is used as the hostname when
- *                    connecting with a TCP socket.
- * @param  port       Number to identify the socket to connect to.  Used when
- *                    generating the socket name for a Unix socket, or as the
- *                    TCP port when connecting to a TCP socket.
- * @param  data       Data to associate with the created Ecore_Con_Server
- *                    object.
- * @return A new Ecore_Con_Server.
- * @ingroup Ecore_Con_Server_Group
- */
 EAPI Ecore_Con_Server *
-ecore_con_server_connect(Ecore_Con_Type compl_type, const char *name, int port,
-                        const void *data)
+ecore_con_server_connect(Ecore_Con_Type compl_type,
+                         const char    *name,
+                         int            port,
+                         const void    *data)
 {
-   Ecore_Con_Server   *svr;
-   Ecore_Con_Type      type;
-   struct sockaddr_un  socket_unix;
-   int                 curstate = 0;
-   char                buf[4096];
+   Ecore_Con_Server *svr;
+   Ecore_Con_Type type;
 
-   if (!name) return NULL;
+   if ((!name) || (!name[0]))
+     return NULL;
    /* local  user   socket: FILE:   ~/.ecore/[name]/[port] */
    /* local  system socket: FILE:   /tmp/.ecore_service|[name]|[port] */
    /* remote system socket: TCP/IP: [name]:[port] */
    svr = calloc(1, sizeof(Ecore_Con_Server));
-   if (!svr) return NULL;
-
-   type = compl_type;
-#if USE_OPENSSL
-   /* unset the SSL flag for the following checks */
-   type &= ECORE_CON_TYPE;
-#endif
-   if ((type == ECORE_CON_REMOTE_SYSTEM) && (port < 0)) return NULL;
-
-   if ((type == ECORE_CON_LOCAL_USER) || (type == ECORE_CON_LOCAL_SYSTEM) ||
-       (type == ECORE_CON_LOCAL_ABSTRACT))
-     {
-       const char *homedir;
-       int socket_unix_len;
-
-       if (type == ECORE_CON_LOCAL_USER)
-         {
-            homedir = getenv("HOME");
-            if (!homedir) homedir = getenv("TMP");
-            if (!homedir) homedir = "/tmp";
-            snprintf(buf, sizeof(buf), "%s/.ecore/%s/%i", homedir, name, port);
-         }
-       else if (type == ECORE_CON_LOCAL_SYSTEM)
-         {
-            if (port < 0)
-              {
-                 if (name[0] == '/')
-                   strncpy(buf, name, sizeof(buf));
-                 else
-                   snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s", name);
-              }
-            else
-              {
-                 if (name[0] == '/')
-                   snprintf(buf, sizeof(buf), "%s|%i", name, port);
-                 else
-                   snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i", name, port);
-              }
-         }
-       else if (type == ECORE_CON_LOCAL_ABSTRACT)
-         strncpy(buf, name, sizeof(buf));
-
-       svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (svr->fd < 0) goto error;
-       if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
-       if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
-       if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) goto error;
-       socket_unix.sun_family = AF_UNIX;
-
-       if (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", name);
-            socket_unix.sun_path[0] = '\0';
-            socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, name);
-#else
-            fprintf(stderr, "Your system does not support abstract sockets!\n");
-            goto error;
-#endif
-         }
-       else
-         {
-            strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
-            socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
-         }
-
-       if (connect(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) goto error;
-       svr->path = strdup(buf);
-       if (!svr->path) goto error;
-       svr->fd_handler = 
-         ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
-                                   _ecore_con_cl_handler, svr, NULL, NULL);
-       if (!svr->fd_handler) goto error;
-
-       if (!svr->delete_me)
-         {
-            /* we got our server! */
-            Ecore_Con_Event_Server_Add *e;
-
-            e = calloc(1, sizeof(Ecore_Con_Event_Server_Add));
-            if (e)
-              {
-                 svr->event_count++;
-                 e->server = svr;
-                 ecore_event_add(ECORE_CON_EVENT_SERVER_ADD, e,
-                                 _ecore_con_event_server_add_free, NULL);
-              }
-         }
-     }
+   if (!svr)
+     return NULL;
 
    svr->name = strdup(name);
-   if (!svr->name) goto error;
+   if (!svr->name)
+     goto error;
+
    svr->type = compl_type;
    svr->port = port;
    svr->data = (void *)data;
-   svr->created = 0;
-   svr->reject_excess_clients = 0;
+   svr->created = EINA_FALSE;
+   svr->use_cert = (compl_type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT;
+   svr->disable_proxy = (compl_type & ECORE_CON_SUPER_SSL & ECORE_CON_NO_PROXY) == ECORE_CON_NO_PROXY;
+   svr->reject_excess_clients = EINA_FALSE;
+   svr->clients = NULL;
    svr->client_limit = -1;
-   svr->clients = ecore_list_new();
-   ecore_list_append(servers, svr);
-   ECORE_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER);
 
-   if (type == ECORE_CON_REMOTE_SYSTEM)
+   type = compl_type & ECORE_CON_TYPE;
+
+   if ((!svr->disable_proxy) && (type > ECORE_CON_LOCAL_ABSTRACT))
      {
-       if (!ecore_con_dns_lookup(svr->name, _ecore_con_cb_dns_lookup, svr))
-         goto error;
+        /* never use proxies on local connections */
+        if (_ecore_con_proxy_once)
+          svr->ecs = _ecore_con_proxy_once;
+        else if (_ecore_con_proxy_global)
+          svr->ecs = _ecore_con_proxy_global;
+        _ecore_con_proxy_once = NULL;
+        if (svr->ecs)
+          {
+             if ((!svr->ecs->lookup) &&
+                 (!ecore_con_lookup(svr->name, (Ecore_Con_Dns_Cb)ecore_con_socks_dns_cb, svr)))
+               goto error;
+             if (svr->ecs->lookup)
+               svr->ecs_state = ECORE_CON_PROXY_STATE_RESOLVED;
+          }
      }
+   EINA_SAFETY_ON_TRUE_GOTO(ecore_con_ssl_server_prepare(svr, compl_type & ECORE_CON_SSL), error);
 
-   return svr;
+   EINA_SAFETY_ON_TRUE_GOTO(((type == ECORE_CON_REMOTE_TCP) ||
+        (type == ECORE_CON_REMOTE_NODELAY) ||
+        (type == ECORE_CON_REMOTE_CORK) ||
+        (type == ECORE_CON_REMOTE_UDP) ||
+        (type == ECORE_CON_REMOTE_BROADCAST)) &&
+       (port < 0), error);
 
-   error:
-   if (svr->name) free(svr->name);
-   if (svr->path) free(svr->path);
-   if (svr->fd >= 0) close(svr->fd);
-   if (svr->fd_handler) ecore_main_fd_handler_del(svr->fd_handler);
-#if USE_OPENSSL
-   if (svr->ssl) SSL_free(svr->ssl);
-   if (svr->ssl_ctx) SSL_CTX_free(svr->ssl_ctx);
+   if ((type == ECORE_CON_LOCAL_USER) ||
+       (type == ECORE_CON_LOCAL_SYSTEM) ||
+       (type == ECORE_CON_LOCAL_ABSTRACT))
+     /* Local */
+#ifdef _WIN32
+     EINA_SAFETY_ON_FALSE_GOTO(ecore_con_local_connect(svr, _ecore_con_cl_handler), error);
+#else
+     EINA_SAFETY_ON_FALSE_GOTO(ecore_con_local_connect(svr, _ecore_con_cl_handler, svr), error);
 #endif
+
+   if ((type == ECORE_CON_REMOTE_TCP) ||
+       (type == ECORE_CON_REMOTE_NODELAY) ||
+       (type == ECORE_CON_REMOTE_CORK))
+     {
+        /* TCP */
+         EINA_SAFETY_ON_FALSE_GOTO(ecore_con_info_tcp_connect(svr, _ecore_con_cb_tcp_connect, svr), error);
+     }
+   else if ((type == ECORE_CON_REMOTE_UDP) || (type == ECORE_CON_REMOTE_BROADCAST))
+     /* UDP and MCAST */
+     EINA_SAFETY_ON_FALSE_GOTO(ecore_con_info_udp_connect(svr, _ecore_con_cb_udp_connect, svr), error);
+
+   servers = eina_list_append(servers, svr);
+   ECORE_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER);
+
+   return svr;
+
+error:
+   if (svr->name)
+     free(svr->name);
+
+   if (svr->path)
+     free(svr->path);
+
+   if (svr->fd_handler)
+     ecore_main_fd_handler_del(svr->fd_handler);
+
+   if (svr->fd > 0)
+     close(svr->fd);
+
+   ecore_con_ssl_server_shutdown(svr);
    free(svr);
    return NULL;
 }
 
-/**
- * Closes the connection and frees the given server.
- * @param   svr The given server.
- * @return  Data associated with the server when it was created.
- * @ingroup Ecore_Con_Server_Group
- */
-EAPI void *
-ecore_con_server_del(Ecore_Con_Server *svr)
+EAPI void
+ecore_con_server_timeout_set(Ecore_Con_Server *svr,
+                             double            timeout)
 {
-   void *data;
-
    if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
      {
-       ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_del");
-       return NULL;
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_timeout_set");
+        return;
      }
-   data = svr->data;
-   svr->data = NULL;
-   svr->delete_me = 1;
-   if (svr->event_count > 0)
+
+   if (svr->created)
+     svr->client_disconnect_time = timeout;
+   else
+     svr->disconnect_time = timeout;
+}
+
+EAPI double
+ecore_con_server_timeout_get(Ecore_Con_Server *svr)
+{
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
      {
-       if (svr->fd_handler)
-         {
-            ecore_main_fd_handler_del(svr->fd_handler);
-            svr->fd_handler = NULL;
-         }
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_timeout_get");
+        return 0;
      }
-   else
+
+   return svr->created ? svr->client_disconnect_time : svr->disconnect_time;
+}
+
+EAPI void *
+ecore_con_server_del(Ecore_Con_Server *svr)
+{
+   if (!svr) return NULL;
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
      {
-       _ecore_con_server_free(svr);
-       if (ecore_list_goto(servers, svr)) ecore_list_remove(servers);
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_del");
+        return NULL;
      }
-   return data;
+
+   if (svr->delete_me)
+     return NULL;
+
+   _ecore_con_server_kill(svr);
+   return svr->data;
 }
 
-/**
- * Retrieves the data associated with the given server.
- * @param   svr The given server.
- * @return  The associated data.
- * @ingroup Ecore_Con_Server_Group
- */
 EAPI void *
 ecore_con_server_data_get(Ecore_Con_Server *svr)
 {
    if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
      {
-       ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get");
-       return NULL;
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get");
+        return NULL;
      }
+
    return svr->data;
 }
 
-/**
- * Retrieves whether the given server is currently connected.
- * @todo Check that this function does what the documenter believes it does.
- * @param   svr The given server.
- * @return  @c 1 if the server is connected.  @c 0 otherwise.
- * @ingroup Ecore_Con_Server_Group
- */
-EAPI int
+EAPI void *
+ecore_con_server_data_set(Ecore_Con_Server *svr,
+                          void             *data)
+{
+   void *ret = NULL;
+
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+     {
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get");
+        return NULL;
+     }
+
+   ret = svr->data;
+   svr->data = data;
+   return ret;
+}
+
+EAPI Eina_Bool
 ecore_con_server_connected_get(Ecore_Con_Server *svr)
 {
    if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
      {
-       ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_connected_get");
-       return 0;
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_connected_get");
+        return EINA_FALSE;
      }
-   if (svr->connecting) return 0;
-   return 1;
+
+   if (svr->connecting)
+     return EINA_FALSE;
+
+   return EINA_TRUE;
 }
 
-/**
- * Retrieves the current list of clients.
- * @param   svr The given server.
- * @return  The list of clients on this server.
- * @ingroup Ecore_Con_Server_Group
- */
-EAPI Ecore_List *
+EAPI const Eina_List *
 ecore_con_server_clients_get(Ecore_Con_Server *svr)
 {
    if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
      {
-       ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_clients_get");
-       return NULL;
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
+                         "ecore_con_server_clients_get");
+        return NULL;
      }
+
    return svr->clients;
 }
 
-/**
- * Sends the given data to the given server.
- * @param   svr  The given server.
- * @param   data The given data.
- * @param   size Length of the data, in bytes, to send.
- * @return  The number of bytes sent.  @c 0 will be returned if there is an
- *          error.
- * @ingroup Ecore_Con_Server_Group
- */
+EAPI const char *
+ecore_con_server_name_get(Ecore_Con_Server *svr)
+{
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+     {
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
+                         "ecore_con_server_name_get");
+        return NULL;
+     }
+
+   return svr->name;
+}
+
+EAPI int
+ecore_con_server_port_get(Ecore_Con_Server *svr)
+{
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+     {
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
+                         "ecore_con_server_port_get");
+        return -1;
+     }
+   return svr->port;
+}
+
 EAPI int
-ecore_con_server_send(Ecore_Con_Server *svr, const void *data, int size)
+ecore_con_server_send(Ecore_Con_Server *svr,
+                      const void       *data,
+                      int               size)
 {
    if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
      {
-       ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_send");
-       return 0;
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_send");
+        return 0;
      }
-   if (svr->dead) return 0;
-   if (!data) return 0;
-   if (size < 1) return 0;
+
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->delete_me, 0);
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0);
+
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(size < 1, 0);
+
    if (svr->fd_handler)
      ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);
-   if (svr->write_buf)
-     {
-       unsigned char *newbuf;
 
-       newbuf = realloc(svr->write_buf, svr->write_buf_size + size);
-       if (newbuf) svr->write_buf = newbuf;
-       else return 0;
-       memcpy(svr->write_buf + svr->write_buf_size, data, size);
-       svr->write_buf_size += size;
-     }
-   else
+   if (!svr->buf)
      {
-       svr->write_buf = malloc(size);
-       if (!svr->write_buf) return 0;
-       svr->write_buf_size = size;
-       memcpy(svr->write_buf, data, size);
+        svr->buf = eina_binbuf_new();
+        EINA_SAFETY_ON_NULL_RETURN_VAL(svr->buf, 0);
+#ifdef TCP_CORK
+        if ((svr->fd >= 0) && ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK))
+          {
+             int state = 1;
+             if (setsockopt(svr->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0)
+               /* realistically this isn't anything serious so we can just log and continue */
+               ERR("corking failed! %s", strerror(errno));
+          }
+#endif
      }
+   eina_binbuf_append_length(svr->buf, data, size);
+
    return size;
 }
 
-/**
- * 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.
- * @param   svr           The given server.
- * @param   client_limit  The maximum number of clients to handle
- *                        concurrently.  -1 means unlimited (default).  0
- *                        effectively disables the server.
- * @param   reject_excess_clients  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).
- * @ingroup Ecore_Con_Server_Group
- */
 EAPI void
-ecore_con_server_client_limit_set(Ecore_Con_Server *svr, int client_limit, char reject_excess_clients)
+ecore_con_server_client_limit_set(Ecore_Con_Server *svr,
+                                  int               client_limit,
+                                  char              reject_excess_clients)
 {
    if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
      {
-       ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_client_limit_set");
-       return;
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
+                         "ecore_con_server_client_limit_set");
+        return;
      }
+
    svr->client_limit = client_limit;
    svr->reject_excess_clients = reject_excess_clients;
 }
 
-/**
- * Gets the IP address of a server that has been connected to.
- *
- * @param   svr           The given server.
- * @return  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 @p svr object. If no IP is known NULL is returned.
- * @ingroup Ecore_Con_Server_Group
- */
-EAPI char *
+EAPI const char *
 ecore_con_server_ip_get(Ecore_Con_Server *svr)
 {
    if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
      {
-       ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_ip_get");
-       return NULL;
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_ip_get");
+        return NULL;
      }
+
    return svr->ip;
 }
 
-/**
- * Flushes all pending data to the given server. Will return when done.
- *
- * @param   svr           The given server.
- * @ingroup Ecore_Con_Server_Group
- */
+EAPI double
+ecore_con_server_uptime_get(Ecore_Con_Server *svr)
+{
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+     {
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_uptime_get");
+        return -1;
+     }
+
+   return ecore_time_get() - svr->start_time;
+}
+
 EAPI void
 ecore_con_server_flush(Ecore_Con_Server *svr)
 {
    if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
      {
-       ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_flush");
-       return;
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_flush");
+        return;
      }
+
    _ecore_con_server_flush(svr);
 }
 
 /**
- * @defgroup Ecore_Con_Client_Group Ecore Connection Client Functions
+ * @}
+ */
+
+/**
+ * @addtogroup Ecore_Con_Client_Group Ecore Connection Client Functions
  *
  * Functions that operate on Ecore connection client objects.
+ *
+ * @{
  */
 
 /**
- * Sends the given data to the given client.
- * @param   cl   The given client.
- * @param   data The given data.
- * @param   size Length of the data, in bytes, to send.
- * @return  The number of bytes sent.  @c 0 will be returned if there is an
- *          error.
- * @ingroup Ecore_Con_Client_Group
+ * @example ecore_con_client_example.c
+ * Shows how to write a simple client that connects to the example server.
  */
+
 EAPI int
-ecore_con_client_send(Ecore_Con_Client *cl, const void *data, int size)
+ecore_con_client_send(Ecore_Con_Client *cl,
+                      const void       *data,
+                      int               size)
 {
    if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
      {
-       ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_send");
-       return 0;
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_send");
+        return 0;
      }
-   if (cl->dead) return 0;
-   if (!data) return 0;
-   if (size < 1) return 0;
+
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(cl->delete_me, 0);
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0);
+
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(size < 1, 0);
+
    if (cl->fd_handler)
      ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);
-   if (cl->buf)
-     {
-       unsigned char *newbuf;
 
-       newbuf = realloc(cl->buf, cl->buf_size + size);
-       if (newbuf) cl->buf = newbuf;
-       else return 0;
-       memcpy(cl->buf + cl->buf_size, data, size);
-       cl->buf_size += size;
-     }
-   else
+   if (cl->host_server && ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP))
+     sendto(cl->host_server->fd, data, size, 0, (struct sockaddr *)cl->client_addr,
+            cl->client_addr_len);
+   else if (!cl->buf)
      {
-       cl->buf = malloc(size);
-       if (!cl->buf) return 0;
-       cl->buf_size = size;
-       memcpy(cl->buf, data, size);
+        cl->buf = eina_binbuf_new();
+        EINA_SAFETY_ON_NULL_RETURN_VAL(cl->buf, 0);
+#ifdef TCP_CORK
+        if ((cl->fd >= 0) && ((cl->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
      }
+   eina_binbuf_append_length(cl->buf, data, size);
+
    return size;
 }
 
-/**
- * Retrieves the server representing the socket the client has
- * connected to.
- * @param   cl The given client.
- * @return  The server that the client connected to.
- * @ingroup Ecore_Con_Client_Group
- */
 EAPI Ecore_Con_Server *
 ecore_con_client_server_get(Ecore_Con_Client *cl)
 {
    if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
      {
-       ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_server_get");
-       return NULL;
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT,
+                         "ecore_con_client_server_get");
+        return NULL;
      }
-   return cl->server;
+
+   return cl->host_server;
 }
 
-/**
- * Closes the connection and frees memory allocated to the given client.
- * @param   cl The given client.
- * @return  Data associated with the client.
- * @ingroup Ecore_Con_Client_Group
- */
-EAPI void *
-ecore_con_client_del(Ecore_Con_Client *cl)
+EAPI Eina_Bool
+ecore_con_client_connected_get(Ecore_Con_Client *cl)
 {
-   void *data;
+   if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+     {
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT,
+                         "ecore_con_client_connected_get");
+        return EINA_FALSE;
+     }
+
+   return !cl->delete_me;
+}
 
+EAPI void
+ecore_con_client_timeout_set(Ecore_Con_Client *cl,
+                             double            timeout)
+{
    if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
      {
-       ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_del");
-       return NULL;
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT,
+                         "ecore_con_client_timeout_set");
+        return;
      }
-   data = cl->data;
-   cl->data = NULL;
-   cl->delete_me = 1;
-   if (cl->event_count > 0)
+
+   cl->disconnect_time = timeout;
+
+   _ecore_con_cl_timer_update(cl);
+}
+
+EAPI double
+ecore_con_client_timeout_get(Ecore_Con_Client *cl)
+{
+   if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
      {
-       if (cl->fd_handler)
-         {
-            ecore_main_fd_handler_del(cl->fd_handler);
-            cl->fd_handler = NULL;
-         }
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_timeout_get");
+        return 0;
      }
-   else
+
+   return cl->disconnect_time;
+}
+
+EAPI void *
+ecore_con_client_del(Ecore_Con_Client *cl)
+{
+   if (!cl) return NULL;
+   if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
      {
-       if (ecore_list_goto(cl->server->clients, cl))
-         ecore_list_remove(cl->server->clients);
-       _ecore_con_client_free(cl);
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_del");
+        return NULL;
      }
-   return data;
+
+   _ecore_con_client_kill(cl);
+   return cl->data;
 }
 
-/**
- * Sets the data associated with the given client to @p data.
- * @param   cl   The given client.
- * @param   data What to set the data to.
- * @ingroup Ecore_Con_Client_Group
- */
 EAPI void
-ecore_con_client_data_set(Ecore_Con_Client *cl, const void *data)
+ecore_con_client_data_set(Ecore_Con_Client *cl,
+                          const void       *data)
 {
    if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
      {
-       ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_set");
-       return;
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_set");
+        return;
      }
+
    cl->data = (void *)data;
 }
 
-/**
- * Retrieves the data associated with the given client.
- * @param   cl The given client.
- * @return  The data associated with @p cl.
- * @ingroup Ecore_Con_Client_Group
- */
 EAPI void *
 ecore_con_client_data_get(Ecore_Con_Client *cl)
 {
    if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
      {
-       ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_get");
-       return NULL;
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_get");
+        return NULL;
      }
+
    return cl->data;
 }
 
-/**
- * Gets the IP address of a cleint that has connected.
- *
- * @param   cl            The given client.
- * @return  A pointer to an internal string that contains the IP address of
- *          the connected client in the form "XXX.YYY.ZZZ.AAA" IP notation.
- *          This string should not be modified or trusted to stay valid after
- *          deletion for the @p cl object. If no IP is known NULL is returned.
- * @ingroup Ecore_Con_Client_Group
- */
-EAPI char *
+EAPI const char *
 ecore_con_client_ip_get(Ecore_Con_Client *cl)
 {
    if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
      {
-       ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_ip_get");
-       return NULL;
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_ip_get");
+        return NULL;
      }
+   if (!cl->ip)
+     cl->ip = _ecore_con_pretty_ip(cl->client_addr);
+
    return cl->ip;
 }
 
-/**
- * Flushes all pending data to the given client. Will return when done.
- *
- * @param   cl            The given client.
- * @ingroup Ecore_Con_Client_Group
- */
+EAPI int
+ecore_con_client_port_get(Ecore_Con_Client *cl)
+{
+   if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+     {
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_port_get");
+        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;
+#else
+   return -1;
+#endif
+}
+
+EAPI double
+ecore_con_client_uptime_get(Ecore_Con_Client *cl)
+{
+   if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+     {
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_uptime_get");
+        return -1;
+     }
+
+   return ecore_time_get() - cl->start_time;
+}
+
 EAPI void
 ecore_con_client_flush(Ecore_Con_Client *cl)
 {
    if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
      {
-       ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_flush");
-       return;
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_flush");
+        return;
      }
+
    _ecore_con_client_flush(cl);
 }
 
+EAPI int
+ecore_con_server_fd_get(Ecore_Con_Server *svr)
+{
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+     {
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__);
+        return -1;
+     }
+   if (svr->created) return -1;
+   if (svr->delete_me) return -1;
+   return ecore_main_fd_handler_fd_get(svr->fd_handler);
+}
+
+EAPI int
+ecore_con_client_fd_get(Ecore_Con_Client *cl)
+{
+   if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
+     {
+        ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, __func__);
+        return -1;
+     }
+   return ecore_main_fd_handler_fd_get(cl->fd_handler);
+}
+
 /**
- * Returns if SSL support is available
- * @return  1 if SSL is available, 0 if it is not.
- * @ingroup Ecore_Con_Client_Group
+ * @}
  */
-EAPI int
-ecore_con_ssl_available_get(void)
+
+void
+ecore_con_event_proxy_bind(Ecore_Con_Server *svr)
 {
-#if USE_OPENSSL
-   return 1;
-#else
-   return 0;
-#endif
+    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(svr);
+    e->server = svr;
+    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 *svr)
+{
+    /* 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(svr);
+    e->server = svr;
+    if (svr->upgrade) ev = ECORE_CON_EVENT_SERVER_UPGRADE;
+    ecore_event_add(ev, e,
+                    _ecore_con_event_server_add_free, NULL);
+   _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_server_del(Ecore_Con_Server *svr)
+{
+    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(svr);
+    e->server = svr;
+    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 *svr, int num)
+{
+   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 = svr;
+   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 *svr, unsigned char *buf, int num, Eina_Bool duplicate)
+{
+   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(svr);
+   e->server = svr;
+   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_count++;
+}
+
+void
+ecore_con_event_client_add(Ecore_Con_Client *cl)
+{
+   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);
+
+   cl->event_count = eina_list_append(cl->event_count, e);
+   cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e);
+   _ecore_con_cl_timer_update(cl);
+   e->client = cl;
+   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);
+   _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_client_del(Ecore_Con_Client *cl)
+{
+    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);
+
+    cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e);
+    _ecore_con_cl_timer_update(cl);
+    e->client = cl;
+    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 *cl, int num)
+{
+   Ecore_Con_Event_Client_Write *e;
+
+   e = ecore_con_event_client_write_alloc();
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   cl->event_count = eina_list_append(cl->event_count, e);
+   cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e);
+   e->client = cl;
+   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 *cl, unsigned char *buf, int num, Eina_Bool duplicate)
+{
+   Ecore_Con_Event_Client_Data *e;
+
+   e = ecore_con_event_client_data_alloc();
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   cl->event_count = eina_list_append(cl->event_count, e);
+   cl->host_server->event_count = eina_list_append(cl->host_server->event_count, e);
+   _ecore_con_cl_timer_update(cl);
+   e->client = cl;
+   if (duplicate)
+     {
+        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_count++;
+}
+
+
+void
+ecore_con_server_infos_del(Ecore_Con_Server *svr, void *info)
+{
+   svr->infos = eina_list_remove(svr->infos, info);
+}
+
+void
+_ecore_con_event_server_error(Ecore_Con_Server *svr, char *error, Eina_Bool duplicate)
+{
+   Ecore_Con_Event_Server_Error *e;
+
+   e = ecore_con_event_server_error_alloc();
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   e->server = svr;
+   e->error = duplicate ? strdup(error) : error;
+   ERR("%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);
+   _ecore_con_event_count++;
+}
+
+void
+ecore_con_event_client_error(Ecore_Con_Client *cl, const char *error)
+{
+   Ecore_Con_Event_Client_Error *e;
+
+   e = ecore_con_event_client_error_alloc();
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   e->client = cl;
+   e->error = strdup(error);
+// givving errors like this is not a good thing - MAYBET his belongs in debug... but not err.   
+//   ERR("%s", error);
+   cl->event_count = eina_list_append(cl->event_count, e);
+   cl->host_server->event_count = eina_list_append(cl->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);
+   _ecore_con_event_count++;
 }
 
 static void
 _ecore_con_server_free(Ecore_Con_Server *svr)
 {
+   Ecore_Con_Client *cl;
    double t_start, t;
 
-   ECORE_MAGIC_SET(svr, ECORE_MAGIC_NONE);
+   if (svr->event_count) return;
+
+   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->write_buf) && (!svr->dead))
-     {
-       _ecore_con_server_flush(svr);
-       t = ecore_time_get();
-       if ((t - t_start) > 0.5)
-         {
-            printf("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.\n",
-                   (t - t_start));
-            break;
-         }
-     }
-   if (svr->write_buf) free(svr->write_buf);
-   while (!ecore_list_empty_is(svr->clients))
-     _ecore_con_client_free(ecore_list_first_remove(svr->clients));
-   ecore_list_destroy(svr->clients);
-   if ((svr->created) && (svr->path) && (svr->ppid == getpid())) 
-     unlink(svr->path);
-   if (svr->fd >= 0) close(svr->fd);
-#if USE_OPENSSL
-   if (svr->ssl)
+   while (svr->buf && (!svr->delete_me))
      {
-       SSL_shutdown(svr->ssl);
-       SSL_free(svr->ssl);
+        _ecore_con_server_flush(svr);
+        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;
+          }
      }
-   if (svr->ssl_ctx) SSL_CTX_free(svr->ssl_ctx);
+
+#ifdef _WIN32
+   ecore_con_local_win32_server_del(svr);
 #endif
-   if (svr->name) free(svr->name);
-   if (svr->path) free(svr->path);
-   if (svr->ip) free(svr->ip);
-   if (svr->fd_handler) ecore_main_fd_handler_del(svr->fd_handler);
+   if (svr->event_count) return;
+   ECORE_MAGIC_SET(svr, ECORE_MAGIC_NONE);
+
+   if (svr->buf)
+     eina_binbuf_free(svr->buf);
+
+   EINA_LIST_FREE(svr->clients, cl)
+     {
+        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);
+     }
+   if ((svr->created) && (svr->path) && (svr->ppid == getpid()))
+     unlink(svr->path);
+
+   ecore_con_ssl_server_shutdown(svr);
+   free(svr->name);
+
+   free(svr->path);
+
+   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 > 0)
+     close(svr->fd);
+
+   if (svr->until_deletion)
+     ecore_timer_del(svr->until_deletion);
+
+   servers = eina_list_remove(servers, svr);
+   svr->data = NULL;
    free(svr);
 }
 
@@ -985,702 +1295,1345 @@ _ecore_con_client_free(Ecore_Con_Client *cl)
 {
    double t_start, t;
 
-   ECORE_MAGIC_SET(cl, ECORE_MAGIC_NONE);
+   if (cl->event_count) return;
+
    t_start = ecore_time_get();
-   while ((cl->buf) && (!cl->dead))
-     {
-       _ecore_con_client_flush(cl);
-       t = ecore_time_get();
-       if ((t - t_start) > 0.5)
-         {
-            printf("ECORE_CON: 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.\n",
-                   (t - t_start));
-            break;
-         }
-     }
-   if (cl->buf) free(cl->buf);
-   if (cl->fd >= 0) close(cl->fd);
-   if (cl->fd_handler) ecore_main_fd_handler_del(cl->fd_handler);
-   if (cl->ip) free(cl->ip);
+   while ((cl->buf) && (!cl->delete_me))
+     {
+        _ecore_con_client_flush(cl);
+        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;
+          }
+     }
+   cl->host_server->clients = eina_list_remove(cl->host_server->clients, cl);
+
+#ifdef _WIN32
+   ecore_con_local_win32_client_del(cl);
+#endif
+
+   if (cl->event_count) return;
+   ECORE_MAGIC_SET(cl, ECORE_MAGIC_NONE);
+
+   if (cl->buf) eina_binbuf_free(cl->buf);
+
+   if (cl->host_server->type & ECORE_CON_SSL)
+     ecore_con_ssl_client_shutdown(cl);
+
+   if (cl->fd_handler)
+     ecore_main_fd_handler_del(cl->fd_handler);
+
+   if (cl->fd > 0)
+     close(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;
    free(cl);
+   return;
 }
 
-static int
-_ecore_con_svr_handler(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__)
+static Eina_Bool
+_ecore_con_server_timer(Ecore_Con_Server *svr)
 {
-   Ecore_Con_Server   *svr;
-   int                 new_fd;
-   struct sockaddr_in  incoming;
-   size_t              size_in;
+   ecore_con_server_del(svr);
 
-   svr = data;
-   if (svr->dead) return 1;
-   if (svr->delete_me) return 1;
-   if ((svr->client_limit >= 0) && (!svr->reject_excess_clients))
+   svr->until_deletion = NULL;
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_ecore_con_server_timer_update(Ecore_Con_Server *svr)
+{
+   if (svr->disconnect_time)
      {
-       if (ecore_list_count(svr->clients) >= svr->client_limit) return 1;
+        if (svr->disconnect_time > 0)
+          {
+             if (svr->until_deletion)
+               ecore_timer_interval_set(svr->until_deletion, svr->disconnect_time);
+             else
+               svr->until_deletion = ecore_timer_add(svr->disconnect_time, (Ecore_Task_Cb)_ecore_con_server_timer, svr);
+          }
+        else if (svr->until_deletion)
+          {
+             ecore_timer_del(svr->until_deletion);
+             svr->until_deletion = NULL;
+          }
      }
-   /* a new client */
-   size_in = sizeof(struct sockaddr_in);
-   new_fd = accept(svr->fd, (struct sockaddr *)&incoming, (socklen_t *)&size_in);
-   if (new_fd >= 0)
-     {
-       Ecore_Con_Client *cl;
-       char buf[64];
-       uint32_t ip;
-
-       if ((svr->client_limit >= 0) && (svr->reject_excess_clients))
-         {
-            close(new_fd);
-            return 1;
-         }
-
-       cl = calloc(1, sizeof(Ecore_Con_Client));
-       if (!cl)
-         {
-            close(new_fd);
-            return 1;
-         }
-       fcntl(new_fd, F_SETFL, O_NONBLOCK);
-       fcntl(new_fd, F_SETFD, FD_CLOEXEC);
-       cl->fd = new_fd;
-       cl->server = svr;
-       cl->fd_handler = 
-         ecore_main_fd_handler_add(cl->fd, ECORE_FD_READ,
-                                   _ecore_con_svr_cl_handler, cl, NULL, NULL);
-       ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT);
-       ecore_list_append(svr->clients, cl);
-       if (!svr->path)
-         {
-            ip = incoming.sin_addr.s_addr;
-            snprintf(buf, sizeof(buf),
-                     "%i.%i.%i.%i",
-                     (ip      ) & 0xff,
-                     (ip >> 8 ) & 0xff,
-                     (ip >> 16) & 0xff,
-                     (ip >> 24) & 0xff);
-            cl->ip = strdup(buf);
-         }
-       if (!cl->delete_me)
-         {
-            Ecore_Con_Event_Client_Add *e;
-
-            e = calloc(1, sizeof(Ecore_Con_Event_Client_Add));
-            if (e)
-              {
-                 cl->event_count++;
-                 e->client = cl;
-                 ecore_event_add(ECORE_CON_EVENT_CLIENT_ADD, e,
-                                 _ecore_con_event_client_add_free, NULL);
-              }
-         }
-     }
-   return 1;
-}
-
-#if USE_OPENSSL
-/* Tries to connect an Ecore_Con_Server to an SSL host.
- * Returns 1 on success, -1 on fatal errors and 0 if the caller
- * should try again later.
- */
-static int
-svr_try_connect_ssl(Ecore_Con_Server *svr)
+   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 *cl)
+{
+   ecore_con_client_del(cl);
+
+   cl->until_deletion = NULL;
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_ecore_con_cl_timer_update(Ecore_Con_Client *cl)
+{
+   if (cl->disconnect_time)
+     {
+        if (cl->disconnect_time > 0)
+          {
+             if (cl->until_deletion)
+               ecore_timer_interval_set(cl->until_deletion, cl->disconnect_time);
+             else
+               cl->until_deletion = ecore_timer_add(cl->disconnect_time, (Ecore_Task_Cb)_ecore_con_client_timer, cl);
+          }
+        else if (cl->until_deletion)
+          {
+             ecore_timer_del(cl->until_deletion);
+             cl->until_deletion = NULL;
+          }
+     }
+   else
+     {
+        if (cl->host_server->client_disconnect_time > 0)
+          {
+             if (cl->until_deletion)
+               ecore_timer_interval_set(cl->until_deletion, cl->host_server->client_disconnect_time);
+             else
+               cl->until_deletion = ecore_timer_add(cl->host_server->client_disconnect_time, (Ecore_Task_Cb)_ecore_con_client_timer, cl);
+          }
+        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)
 {
-   int res, ssl_err, flag = 0;
+   Ecore_Con_Server *svr;
+   struct linger lin;
+   const char *memerr = NULL;
+
+   svr = data;
 
-   if (!ssl_init_count)
+   errno = 0;
+   if (!net_info) /* error message has already been handled */
      {
-       SSL_library_init();
-       SSL_load_error_strings();
+        svr->delete_me = EINA_TRUE;
+        goto error;
      }
-   ssl_init_count++;
 
-   res = SSL_connect(svr->ssl);
-   if (res == 1) return 1;
-   ssl_err = SSL_get_error(svr->ssl, res);
+   svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
+                    net_info->info.ai_protocol);
+   if (svr->fd < 0) goto error;
+   if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+   if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
 
-   if (ssl_err == SSL_ERROR_NONE) return 1;
-   if (ssl_err == SSL_ERROR_WANT_READ)       flag = ECORE_FD_READ;
-   else if (ssl_err == SSL_ERROR_WANT_WRITE) flag = ECORE_FD_WRITE;
-   else return -1;
-   if (svr->fd_handler)
+   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)
      {
-       if (flag) ecore_main_fd_handler_active_set(svr->fd_handler, flag);
+#ifdef HAVE_NETINET_TCP_H
+        int flag = 1;
+
+        if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag,
+                       sizeof(int)) < 0)
+#endif
+          {
+             goto error;
+          }
      }
-   return 0;
+
+   if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
+     goto error;
+
+   if (listen(svr->fd, 4096) < 0) goto error;
+
+   svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
+                                               _ecore_con_svr_tcp_handler, svr, NULL, NULL);
+   if (!svr->fd_handler)
+     {
+        memerr = "Memory allocation failure";
+        goto error;
+     }
+
+   return;
+
+error:
+   if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
+   ecore_con_ssl_server_shutdown(svr);
+   _ecore_con_server_kill(svr);
 }
-#endif
 
 static void
-kill_server(Ecore_Con_Server *svr)
+_ecore_con_cb_udp_listen(void           *data,
+                         Ecore_Con_Info *net_info)
 {
-   if (!svr->delete_me)
+   Ecore_Con_Server *svr;
+   Ecore_Con_Type type;
+   struct ip_mreq mreq;
+#ifdef HAVE_IPV6
+   struct ipv6_mreq mreq6;
+#endif
+   const int on = 1;
+   const char *memerr = NULL;
+
+   svr = data;
+   type = svr->type;
+   type &= ECORE_CON_TYPE;
+
+   errno = 0;
+   if (!net_info) /* error message has already been handled */
      {
-       Ecore_Con_Event_Server_Del *e;
+        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);
+   if (svr->fd < 0) goto error;
 
-       e = calloc(1, sizeof(Ecore_Con_Event_Server_Del));
-       if (e)
-         {
-            svr->event_count++;
-            e->server = svr;
-            ecore_event_add(ECORE_CON_EVENT_SERVER_DEL, e,
-                            _ecore_con_event_server_del_free, NULL);
-         }
+   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_IP, IP_ADD_MEMBERSHIP,
+                            (const void *)&mreq6, sizeof(mreq6)) != 0)
+               goto error;
+          }
+#endif
      }
 
-   svr->dead = 1;
-   if (svr->fd_handler) ecore_main_fd_handler_del(svr->fd_handler);
-   svr->fd_handler = NULL;
+   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;
+   if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
+
+   if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
+     goto error;
+
+   svr->fd_handler =
+     ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
+                               _ecore_con_svr_udp_handler, svr, NULL, NULL);
+   if (!svr->fd_handler)
+     {
+        memerr = "Memory allocation failure";
+        goto error;
+     }
+
+   svr->ip = eina_stringshare_add(net_info->ip);
+
+   return;
+
+error:
+   if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
+   ecore_con_ssl_server_shutdown(svr);
+   _ecore_con_server_kill(svr);
 }
 
 static void
-_ecore_con_cb_dns_lookup(void *data, struct hostent *he)
+_ecore_con_cb_tcp_connect(void           *data,
+                          Ecore_Con_Info *net_info)
 {
-   Ecore_Con_Server   *svr;
-   struct sockaddr_in  socket_addr;
-   int                 curstate = 0;
-   char                buf[64];
-   uint32_t            ip;
+   Ecore_Con_Server *svr;
+   int res;
+   int curstate = 0;
+   const char *memerr = NULL;
 
    svr = data;
 
-   if (!he) goto error;
-   svr->fd = socket(AF_INET, SOCK_STREAM, 0);
+   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);
    if (svr->fd < 0) goto error;
+
    if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
    if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
-   if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) 
+
+   if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, sizeof(curstate)) < 0)
      goto error;
-   socket_addr.sin_family = AF_INET;
-   socket_addr.sin_port = htons(svr->port);
-   memcpy((struct in_addr *)&socket_addr.sin_addr,
-         he->h_addr, sizeof(struct in_addr));
-   if (connect(svr->fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) < 0)
-     {
-       if (errno != EINPROGRESS)
-         goto error;
-       svr->connecting = 1;
-       svr->fd_handler = 
-         ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ | ECORE_FD_WRITE,
-                                   _ecore_con_cl_handler, svr, NULL, NULL);
+
+   if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY)
+     {
+#ifdef HAVE_NETINET_TCP_H
+        int flag = 1;
+
+        if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) < 0)
+#endif
+          {
+             goto error;
+          }
+     }
+
+   res = connect(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen);
+#ifdef _WIN32
+   if (res == SOCKET_ERROR)
+     {
+        if (WSAGetLastError() != WSAEINPROGRESS)
+          {
+             char *err;
+             err = evil_format_message(WSAGetLastError());
+             _ecore_con_event_server_error(svr, err, EINA_FALSE);
+             ecore_con_ssl_server_shutdown(svr);
+             _ecore_con_server_kill(svr);
+             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, svr, NULL, NULL);
      }
    else
-     svr->fd_handler = 
-     ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
-                              _ecore_con_cl_handler, svr, NULL, NULL);
-
-   if (!svr->fd_handler) goto error;
-   ip = socket_addr.sin_addr.s_addr;
-   snprintf(buf, sizeof(buf),
-           "%i.%i.%i.%i",
-           (ip      ) & 0xff,
-           (ip >> 8 ) & 0xff,
-           (ip >> 16) & 0xff,
-           (ip >> 24) & 0xff);
-   svr->ip = strdup(buf);
-
-#if USE_OPENSSL
+     svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
+                                                 _ecore_con_cl_handler, svr, NULL, NULL);
+
    if (svr->type & ECORE_CON_SSL)
      {
-       if (!ssl_init_count)
-         {
-            SSL_library_init();
-            SSL_load_error_strings();
-         }
-       ssl_init_count++;
-
-       switch (svr->type & ECORE_CON_SSL)
-         {
-          case ECORE_CON_USE_SSL2:
-             if (!(svr->ssl_ctx = SSL_CTX_new(SSLv2_client_method())))
-               goto error;
-             break;
-          case ECORE_CON_USE_SSL3:
-             if (!(svr->ssl_ctx = SSL_CTX_new(SSLv3_client_method())))
-               goto error;
-             break;
-          case ECORE_CON_USE_TLS:
-             if (!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method())))
-               goto error;
-             break;
-         }
-
-       if (!(svr->ssl = SSL_new(svr->ssl_ctx)))
-         goto error;
-
-       SSL_set_fd(svr->ssl, svr->fd);
+        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(svr))
+          goto error;
      }
-#endif
+
+   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(svr, memerr ?: strerror(errno));
+   ecore_con_ssl_server_shutdown(svr);
+   _ecore_con_server_kill(svr);
+}
+
+static void
+_ecore_con_cb_udp_connect(void           *data,
+                          Ecore_Con_Info *net_info)
+{
+   Ecore_Con_Server *svr;
+   int curstate = 0;
+   int broadcast = 1;
+   const char *memerr = NULL;
+   svr = data;
+
+   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);
+   if (svr->fd < 0) goto error;
+   if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+   if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
+   if ((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, svr, 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:
-   kill_server(svr);
+error:
+   if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
+   ecore_con_ssl_server_shutdown(svr);
+   _ecore_con_server_kill(svr);
 }
 
-static int
+static Ecore_Con_State
 svr_try_connect_plain(Ecore_Con_Server *svr)
 {
+   int res;
    int so_err = 0;
-   unsigned int size = sizeof(int);
+   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;
 
-   if (getsockopt(svr->fd, SOL_SOCKET, SO_ERROR, &so_err, &size) < 0)
-     so_err = -1;
+#else
+   if (res < 0)
+     so_err = errno;
+
+   if ((so_err == EINPROGRESS) && !svr->delete_me)
+     return ECORE_CON_INPROGRESS;
+
+#endif
 
-   if (so_err != 0)
+   if (so_err)
      {
-       /* we lost our server! */
-       kill_server(svr);
+        /* we lost our server! */
+        ecore_con_event_server_error(svr, strerror(so_err));
+        ERR("Connection lost: %s", strerror(so_err));
+        _ecore_con_server_kill(svr);
+        return ECORE_CON_DISCONNECTED;
      }
+
+   if ((!svr->delete_me) && (!svr->handshaking) && svr->connecting)
+     {
+         if (svr->ecs)
+           {
+              if (ecore_con_socks_svr_init(svr))
+                return ECORE_CON_INPROGRESS;
+           }
+         else
+           ecore_con_event_server_add(svr);
+     }
+
+   if (svr->fd_handler && (!svr->buf))
+     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 __UNUSED__)
+{
+   Ecore_Con_Server *svr;
+   Ecore_Con_Client *cl = NULL;
+   unsigned char client_addr[256];
+   unsigned int client_addr_len;
+   const char *clerr = NULL;
+
+   svr = data;
+   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 */
+
+   cl = calloc(1, sizeof(Ecore_Con_Client));
+   if (!cl)
+     {
+        ecore_con_event_server_error(svr, "Memory allocation failure when attempting to add a new client");
+        return ECORE_CALLBACK_RENEW;
+     }
+   cl->host_server = svr;
+
+   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);
+   if (cl->fd < 0) goto error;
+   if ((svr->client_limit >= 0) && (svr->reject_excess_clients) &&
+       (svr->client_count >= (unsigned int)svr->client_limit))
      {
-       if (!svr->delete_me)
-         {
-            /* we got our server! */
-            Ecore_Con_Event_Server_Add *e;
+        clerr = "Maximum client limit reached";
+        goto error;
+     }
+
+   if (fcntl(cl->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+   if (fcntl(cl->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
+   cl->fd_handler = ecore_main_fd_handler_add(cl->fd, ECORE_FD_READ,
+                                              _ecore_con_svr_cl_handler, cl, NULL, NULL);
+   if (!cl->fd_handler) goto error;
+   ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT);
+
+   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(cl))
+          goto error;
+     }
 
-            svr->connecting = 0;
-            e = calloc(1, sizeof(Ecore_Con_Event_Server_Add));
-            if (e)
-              {
-                 svr->event_count++;
-                 e->server = svr;
-                 ecore_event_add(ECORE_CON_EVENT_SERVER_ADD, e,
-                                 _ecore_con_event_server_add_free, NULL);
-              }
-         }
-       if (svr->fd_handler)
-         {
-            if (!svr->write_buf)
-              ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
-         }
+   cl->client_addr = malloc(client_addr_len);
+   if (!cl->client_addr)
+     {
+        clerr = "Memory allocation failure when attempting to add a new client";
+        goto error;
      }
-   return (!svr->dead);
+   cl->client_addr_len = client_addr_len;
+   memcpy(cl->client_addr, &client_addr, client_addr_len);
+
+   svr->clients = eina_list_append(svr->clients, cl);
+   svr->client_count++;
+
+   if ((!cl->delete_me) && (!cl->handshaking))
+     ecore_con_event_client_add(cl);
+
+   return ECORE_CALLBACK_RENEW;
+
+error:
+   if (cl->fd_handler) ecore_main_fd_handler_del(cl->fd_handler);
+   if (cl->fd >= 0) close(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);
+        }
+   }
+   free(cl);
+   if (clerr || errno) ecore_con_event_server_error(svr, clerr ?: strerror(errno));
+   return ECORE_CALLBACK_RENEW;
 }
 
-/* returns 1 on success, 0 on failure */
-static int svr_try_connect(Ecore_Con_Server *svr)
+static void
+_ecore_con_cl_read(Ecore_Con_Server *svr)
 {
-#if USE_OPENSSL
-   if (!svr->ssl)
+   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(svr) != ECORE_CON_CONNECTED))
+      return;
+
+   if (svr->handshaking && (!svr->ecs_state))
      {
-#endif
-       return svr_try_connect_plain(svr);
-#if USE_OPENSSL
+        DBG("Continuing ssl handshake");
+        if (!ecore_con_ssl_server_init(svr))
+           lost_server = EINA_FALSE;
+        _ecore_con_server_timer_update(svr);
+     }
+
+   if (svr->ecs_state || !(svr->type & ECORE_CON_SSL))
+     {
+        errno = 0;
+        num = read(svr->fd, buf, sizeof(buf));
+        /* 0 is not a valid return value for a tcp socket */
+        if ((num > 0) || ((num < 0) && (errno == EAGAIN)))
+           lost_server = EINA_FALSE;
+        else if (num < 0)
+          ecore_con_event_server_error(svr, strerror(errno));
      }
    else
-     switch (svr_try_connect_ssl(svr)) {
-      case 1:
-       return svr_try_connect_plain(svr);
-      case -1:
-       kill_server(svr);
-       return 0;
-      default:
-       return 0;
+     {
+        num = ecore_con_ssl_server_read(svr, 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(svr, buf, num);
+        else
+          ecore_con_event_server_data(svr, buf, num, EINA_TRUE);
+     }
+
+   if (lost_server)
+      _ecore_con_server_kill(svr);
+}
+
+static Eina_Bool
+_ecore_con_cl_handler(void             *data,
+                      Ecore_Fd_Handler *fd_handler)
+{
+   Ecore_Con_Server *svr;
+   Eina_Bool want_read, want_write;
+
+   svr = data;
+   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, buf, sizeof(buf), MSG_DONTWAIT | MSG_PEEK);
+             DBG("%zu bytes in buffer", len);
+          }
 #endif
+        if (ecore_con_ssl_server_init(svr))
+          {
+             ERR("ssl handshaking failed!");
+             svr->handshaking = EINA_FALSE;
+          }
+        else if (!svr->ssl_state)
+          ecore_con_event_server_add(svr);
+        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(svr)) return ECORE_CALLBACK_RENEW;
+     }
+   if (want_read)
+     _ecore_con_cl_read(svr);
+   else if (want_write) /* only possible with non-ssl connections */
+     {
+        if (svr->connecting && (!svr_try_connect_plain(svr)) && (!svr->ecs_state))
+          return ECORE_CALLBACK_RENEW;
+
+        _ecore_con_server_flush(svr);
+     }
+
+   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 *svr;
+   Eina_Bool want_read, want_write;
+
+   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);
+
+   svr = data;
+   if (svr->delete_me || ((!want_read) && (!want_write)))
+     return ECORE_CALLBACK_RENEW;
+
+   if (want_write)
+     {
+        _ecore_con_server_flush(svr);
+        return ECORE_CALLBACK_RENEW;
+     }
+
+   num = read(svr->fd, buf, READBUFSIZ);
+
+   if ((!svr->delete_me) && (num > 0))
+     ecore_con_event_server_data(svr, buf, num, EINA_TRUE);
+
+   if (num < 0 && (errno != EAGAIN) && (errno != EINTR))
+     {
+        ecore_con_event_server_error(svr, strerror(errno));
+        _ecore_con_server_kill(svr);
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
 
-static int
-_ecore_con_cl_handler(void *data, Ecore_Fd_Handler *fd_handler)
+static Eina_Bool
+_ecore_con_svr_udp_handler(void             *data,
+                           Ecore_Fd_Handler *fd_handler)
 {
-   Ecore_Con_Server   *svr;
-#if USE_OPENSSL
-   int ssl_err = SSL_ERROR_NONE;
-#endif
+   unsigned char buf[READBUFSIZ];
+   unsigned char client_addr[256];
+   socklen_t client_addr_len = sizeof(client_addr);
+   int num;
+   Ecore_Con_Server *svr;
+   Ecore_Con_Client *cl = NULL;
 
    svr = data;
-   if (svr->dead) return 1;
-   if (svr->delete_me) return 1;
-   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+
+   if (svr->delete_me)
+     return ECORE_CALLBACK_RENEW;
+
+   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
      {
-       unsigned char *inbuf = NULL;
-       int            inbuf_num = 0;
+        _ecore_con_client_flush(cl);
+        return ECORE_CALLBACK_RENEW;
+     }
 
-       if (svr->connecting && !svr_try_connect(svr))
-          return 1;
+   if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+     return ECORE_CALLBACK_RENEW;
 
-       for (;;)
-         {
-            int num, lost_server;
-            char buf[READBUFSIZ];
+#ifdef _WIN32
+   num = fcntl(svr->fd, F_SETFL, O_NONBLOCK);
+   if (num >= 0)
+     num = recvfrom(svr->fd, (char *)buf, sizeof(buf), 0,
+                (struct sockaddr *)&client_addr,
+                &client_addr_len);
 
-            lost_server = 0;
-#if USE_OPENSSL
-            if (!svr->ssl)
-              {
-#endif
-                 if ((num = read(svr->fd, buf, READBUFSIZ)) < 1)
-                   {
-                      lost_server = ((errno == EIO) ||
-                                     (errno == EBADF) ||
-                                     (errno == EPIPE) ||
-                                     (errno == EINVAL) ||
-                                     (errno == ENOSPC) ||
-                                     (num == 0));
-                      /* is num == 0 is right - when the server closes us
-                       * off we will get this (as this is called when select
-                       * tells us there is data to read!)
-                       */
-                   }
-#if USE_OPENSSL
-              }
-            else
-              {
-                 num = SSL_read(svr->ssl, buf, READBUFSIZ);
-                 if (num < 1)
-                   {
-                      ssl_err = SSL_get_error(svr->ssl, num);
-                      lost_server = (ssl_err == SSL_ERROR_ZERO_RETURN);
-                      if (ssl_err == SSL_ERROR_SYSCALL)
-                        {
-                           if (num == 0) lost_server = 1;
-                           else
-                             {
-                                lost_server = ((errno == EIO) ||
-                                               (errno == EBADF) ||
-                                               (errno == EPIPE) ||
-                                               (errno == EINVAL) ||
-                                               (errno == ENOSPC) ||
-                                               (errno == ECONNRESET));
-                             }
-                        }
-                   }
-                 else
-                   ssl_err = SSL_ERROR_NONE;
-              }
-#endif
-            if (num < 1)
-              {
-                 if (inbuf)
-                   {
-                      if (!svr->delete_me)
-                        {
-                           Ecore_Con_Event_Server_Data *e;
-
-                           e = calloc(1, sizeof(Ecore_Con_Event_Server_Data));
-                           if (e)
-                             {
-                                svr->event_count++;
-                                e->server = svr;
-                                e->data = inbuf;
-                                e->size = inbuf_num;
-                                ecore_event_add(ECORE_CON_EVENT_SERVER_DATA, e,
-                                                _ecore_con_event_server_data_free,
-                                                NULL);
-                             }
-                        }
-                   }
-                 if (lost_server)
-                   {
-                      /* we lost our server! */
-                      kill_server(svr);
-                      return 1;
-                   }
-                 break;
-              }
-            else
-              {
-                 inbuf = realloc(inbuf, inbuf_num + num);
-                 memcpy(inbuf + inbuf_num, buf, num);
-                 inbuf_num += num;
-              }
-         }
-
-#if USE_OPENSSL
-       if (svr->fd_handler)
-         {
-            if (svr->ssl && ssl_err == SSL_ERROR_WANT_READ)
-              ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
-            else if (svr->ssl && ssl_err == SSL_ERROR_WANT_WRITE)
-              ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
-         }
+#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, strerror(errno));
+        if (!svr->delete_me)
+          ecore_con_event_client_del(NULL);
+        _ecore_con_server_kill(svr);
+        return ECORE_CALLBACK_CANCEL;
      }
-   else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
+
+
+/* Create a new client for use in the client data event */
+   cl = calloc(1, sizeof(Ecore_Con_Client));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cl, ECORE_CALLBACK_RENEW);
+
+   cl->host_server = svr;
+   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);
+   ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT);
+   svr->clients = eina_list_append(svr->clients, cl);
+   svr->client_count++;
+
+   ecore_con_event_client_add(cl);
+   ecore_con_event_client_data(cl, buf, num, EINA_TRUE);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_con_svr_cl_read(Ecore_Con_Client *cl)
+{
+   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(cl))
+          lost_client = EINA_FALSE;
+
+        _ecore_con_cl_timer_update(cl);
+     }
+
+   if (!(cl->host_server->type & ECORE_CON_SSL) && (!cl->upgrade))
+     {
+        num = read(cl->fd, buf, sizeof(buf));
+        /* 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(cl, strerror(errno));
+     }
+   else
      {
-       if (svr->connecting && !svr_try_connect (svr))
-          return 1;
-       _ecore_con_server_flush(svr);
+        num = ecore_con_ssl_client_read(cl, 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;
      }
 
-   return 1;
+   if ((!cl->delete_me) && (num > 0))
+     ecore_con_event_client_data(cl, buf, num, EINA_TRUE);
+
+   if (lost_client) _ecore_con_client_kill(cl);
 }
 
-static int
-_ecore_con_svr_cl_handler(void *data, Ecore_Fd_Handler *fd_handler)
+static Eina_Bool
+_ecore_con_svr_cl_handler(void             *data,
+                          Ecore_Fd_Handler *fd_handler)
 {
-   Ecore_Con_Client   *cl;
+   Ecore_Con_Client *cl;
 
    cl = data;
-   if (cl->dead) return 1;
-   if (cl->delete_me) return 1;
-   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
-     {
-       unsigned char *inbuf = NULL;
-       int            inbuf_num = 0;
-
-       for (;;)
-         {
-            char buf[65536];
-            int num;
-
-            errno = 0;
-            num = read(cl->fd, buf, 65536);
-            if (num < 1)
-              {
-                 if (inbuf)
-                   {
-                      if (!cl->delete_me)
-                        {
-                           Ecore_Con_Event_Client_Data *e;
-
-                           e = calloc(1, sizeof(Ecore_Con_Event_Client_Data));
-                           if (e)
-                             {
-                                cl->event_count++;
-                                e->client = cl;
-                                e->data = inbuf;
-                                e->size = inbuf_num;
-                                ecore_event_add(ECORE_CON_EVENT_CLIENT_DATA, e,
-                                                _ecore_con_event_client_data_free,
-                                                NULL);
-                             }
-                        }
-                   }
-                 if ((errno == EIO) ||  (errno == EBADF) ||
-                     (errno == EPIPE) || (errno == EINVAL) ||
-                     (errno == ENOSPC) || (num == 0)/* is num == 0 right? */)
-                   {
-                      if (!cl->delete_me)
-                        {
-                           /* we lost our client! */
-                           Ecore_Con_Event_Client_Del *e;
-
-                           e = calloc(1, sizeof(Ecore_Con_Event_Client_Del));
-                           if (e)
-                             {
-                                cl->event_count++;
-                                e->client = cl;
-                                ecore_event_add(ECORE_CON_EVENT_CLIENT_DEL, e,
-                                                _ecore_con_event_client_del_free,
-                                                NULL);
-                             }
-                        }
-                      cl->dead = 1;
-                      if (cl->fd_handler)
-                        ecore_main_fd_handler_del(cl->fd_handler);
-                      cl->fd_handler = NULL;
-                   }
-                 break;
-              }
-            else
-              {
-                 inbuf = realloc(inbuf, inbuf_num + num);
-                 memcpy(inbuf + inbuf_num, buf, num);
-                 inbuf_num += num;
-              }
-         }
+   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(cl))
+          {
+             ERR("ssl handshaking failed!");
+             _ecore_con_client_kill(cl);
+             return ECORE_CALLBACK_RENEW;
+          }
+        else if (!cl->ssl_state)
+          ecore_con_event_client_add(cl);
      }
+   else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+     _ecore_con_svr_cl_read(cl);
+
    else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
      _ecore_con_client_flush(cl);
-   return 1;
+
+   return ECORE_CALLBACK_RENEW;
 }
 
 static void
 _ecore_con_server_flush(Ecore_Con_Server *svr)
 {
-   int count, num, lost_server = 0;
-#if USE_OPENSSL
-   int ssl_err = SSL_ERROR_NONE;
+   int count, num;
+   size_t buf_len, buf_offset;
+   const unsigned char *buf;
+
+   DBG("(svr=%p,buf=%p)", svr, svr->buf);
+#ifdef _WIN32
+   if (ecore_con_local_win32_server_flush(svr))
+     return;
 #endif
 
-   if (!svr->write_buf) return;
+   if ((!svr->buf) && (!svr->ecs_buf) && svr->fd_handler)
+     {
+        ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
+        return;
+     }
+
+   buf = svr->buf ? eina_binbuf_string_get(svr->buf) : eina_binbuf_string_get(svr->ecs_buf);
+   buf_len = svr->buf ? eina_binbuf_length_get(svr->buf) : eina_binbuf_length_get(svr->ecs_buf);
+   buf_offset = svr->buf ? svr->write_buf_offset : svr->ecs_buf_offset;
+   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
-       */
-   if (svr->write_buf_size == svr->write_buf_offset)
-      return;
-
-   num = svr->write_buf_size - svr->write_buf_offset;
-#if USE_OPENSSL
-   if (!svr->ssl)
+    * 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)
      {
-#endif
-       count = write(svr->fd, svr->write_buf + svr->write_buf_offset, num);
-       if (count < 1)
-         lost_server = (errno == EIO || errno == EBADF ||
-                        errno == EPIPE || errno == EINVAL || errno == ENOSPC);
-#if USE_OPENSSL
+        DBG("Continuing ssl handshake");
+        if (ecore_con_ssl_server_init(svr))
+          _ecore_con_server_kill(svr);
+        _ecore_con_server_timer_update(svr);
+        return;
      }
+
+   if (svr->ecs_state || (!(svr->type & ECORE_CON_SSL)))
+     count = write(svr->fd, buf + buf_offset, num);
    else
+     count = ecore_con_ssl_server_write(svr, buf + buf_offset, num);
+
+   if (count < 0)
      {
-       count = SSL_write(svr->ssl, svr->write_buf + svr->write_buf_offset, num);
+         if ((errno != EAGAIN) && (errno != EINTR))
+           {
+              ecore_con_event_server_error(svr, strerror(errno));
+              _ecore_con_server_kill(svr);
+           }
+         return;
+     }
 
-       if (count < 1)
-         {
-            ssl_err = SSL_get_error(svr->ssl, count);
-            lost_server = (ssl_err == SSL_ERROR_ZERO_RETURN);
-         }
+   if (count && (!svr->ecs_state)) ecore_con_event_server_write(svr, count);
+   if (svr->ecs_buf)
+     buf_offset = svr->ecs_buf_offset += count;
+   else
+     buf_offset = svr->write_buf_offset += count;
+   if (buf_offset >= buf_len)
+     {
+        if (svr->ecs_buf)
+          {
+             svr->ecs_buf_offset = 0;
+             eina_binbuf_free(svr->ecs_buf);
+             svr->ecs_buf = NULL;
+             INF("PROXY STATE++");
+             svr->ecs_state++;
+          }
+        else
+          {
+             svr->write_buf_offset = 0;
+             eina_binbuf_free(svr->buf);
+             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 ((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 *cl)
+{
+   int num = 0, count = 0;
+
+#ifdef _WIN32
+   if (ecore_con_local_win32_client_flush(cl))
+     return;
 #endif
 
-   if (lost_server)
+   if (!cl->buf && cl->fd_handler)
      {
-       /* we lost our server! */
-       kill_server(svr);
-       return;
+        ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
+        return;
      }
 
-   if (count < 1)
+   if (cl->handshaking)
      {
-#if USE_OPENSSL
-       if (svr->fd_handler)
-         {
-            if (svr->ssl && ssl_err == SSL_ERROR_WANT_READ)
-              ecore_main_fd_handler_active_set(svr->fd_handler,
-                                               ECORE_FD_READ);
-            else if (svr->ssl && ssl_err == SSL_ERROR_WANT_WRITE)
-              ecore_main_fd_handler_active_set(svr->fd_handler,
-                                               ECORE_FD_WRITE);
-         }
-#endif
-       return;
+        if (ecore_con_ssl_client_init(cl))
+          count = -1;
+
+        _ecore_con_cl_timer_update(cl);
      }
 
-   svr->write_buf_offset += count;
-   if (svr->write_buf_offset >= svr->write_buf_size)
+   if (!count)
      {
-       svr->write_buf_size = 0;
-       svr->write_buf_offset = 0;
-       free(svr->write_buf);
-       svr->write_buf = NULL;
-       if (svr->fd_handler)
-         ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
+        if (!cl->buf) return;
+        num = eina_binbuf_length_get(cl->buf) - cl->buf_offset;
+        if (num <= 0) return;
+        if (!(cl->host_server->type & ECORE_CON_SSL) && (!cl->upgrade))
+          count = write(cl->fd, eina_binbuf_string_get(cl->buf) + cl->buf_offset, num);
+        else
+          count = ecore_con_ssl_client_write(cl, eina_binbuf_string_get(cl->buf) + cl->buf_offset, num);
      }
-}
 
-static void
-_ecore_con_client_flush(Ecore_Con_Client *cl)
-{
-   int count, num;
+   if (count < 0)
+     {
+        if ((errno != EAGAIN) && (errno != EINTR) && (!cl->delete_me))
+          {
+              ecore_con_event_client_error(cl, strerror(errno));
+              _ecore_con_client_kill(cl);
+          }
+
+        return;
+     }
 
-   if (!cl->buf) return;
-   num = cl->buf_size - cl->buf_offset;
-   count = write(cl->fd, cl->buf + cl->buf_offset, num);
-   if (count < 1)
-     {
-       if ((errno == EIO) || (errno == EBADF) || (errno == EPIPE) ||
-           (errno == EINVAL) || (errno == ENOSPC))
-         {
-            if (!cl->delete_me)
-              {
-                 /* we lost our client! */
-                 Ecore_Con_Event_Client_Del *e;
-
-                 e = calloc(1, sizeof(Ecore_Con_Event_Client_Del));
-                 if (e)
-                   {
-                      cl->event_count++;
-                      e->client = cl;
-                      ecore_event_add(ECORE_CON_EVENT_CLIENT_DEL, e,
-                                      _ecore_con_event_client_del_free, NULL);
-                   }
-                 cl->dead = 1;
-                 if (cl->fd_handler)
-                   ecore_main_fd_handler_del(cl->fd_handler);
-                 cl->fd_handler = NULL;
-              }
-         }
-       return;
-     }
-   cl->buf_offset += count;
-   if (cl->buf_offset >= cl->buf_size)
-     {
-       cl->buf_size = 0;
-       cl->buf_offset = 0;
-       free(cl->buf);
-       cl->buf = NULL;
-       if (cl->fd_handler)
-         ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
+   if (count) ecore_con_event_client_write(cl, 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
+        if ((cl->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 && (num >= 0))
+     ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_WRITE);
 }
 
 static void
-_ecore_con_event_client_add_free(void *data __UNUSED__, void *ev)
+_ecore_con_event_client_add_free(Ecore_Con_Server *svr,
+                                 void      *ev)
 {
    Ecore_Con_Event_Client_Add *e;
 
    e = ev;
-   e->client->event_count--;
-   if ((e->client->event_count == 0) && (e->client->delete_me))
-     ecore_con_client_del(e->client);
-   free(e);
+   if (e->client)
+     {
+        Eina_Bool svrfreed = EINA_FALSE;
+        
+        e->client->event_count = eina_list_remove(e->client->event_count, e);
+        if (e->client->host_server)
+          {
+             e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, ev);
+             if ((!svr->event_count) && (svr->delete_me))
+               {
+                  _ecore_con_server_free(svr);
+                  svrfreed = EINA_TRUE;
+               }
+          }
+        if (!svrfreed)
+          {
+             if ((!e->client->event_count) && (e->client->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(void *data __UNUSED__, void *ev)
+_ecore_con_event_client_del_free(Ecore_Con_Server *svr,
+                                 void      *ev)
 {
    Ecore_Con_Event_Client_Del *e;
 
    e = ev;
-   e->client->event_count--;
-   if ((e->client->event_count == 0) && (e->client->delete_me))
-     ecore_con_client_del(e->client);
-   free(e);
+   if (e->client)
+     {
+        Eina_Bool svrfreed = EINA_FALSE;
+        
+        e->client->event_count = eina_list_remove(e->client->event_count, e);
+        if (e->client->host_server)
+          {
+             e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, ev);
+             if ((!svr->event_count) && (svr->delete_me))
+               {
+                  _ecore_con_server_free(svr);
+                  svrfreed = EINA_TRUE;
+               }
+          }
+        if (!svrfreed)
+          {
+             if (!e->client->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_data_free(void *data __UNUSED__, void *ev)
+_ecore_con_event_client_write_free(Ecore_Con_Server *svr,
+                                   Ecore_Con_Event_Client_Write *e)
+{
+   if (e->client)
+     {
+        Eina_Bool svrfreed = EINA_FALSE;
+        
+        e->client->event_count = eina_list_remove(e->client->event_count, e);
+        if (e->client->host_server)
+          {
+             e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, e);
+             if ((!svr->event_count) && (svr->delete_me))
+               {
+                  _ecore_con_server_free(svr);
+                  svrfreed = EINA_TRUE;
+               }
+          }
+        if (!svrfreed)
+          {
+             if (((!e->client->event_count) && (e->client->delete_me)) ||
+                 ((e->client->host_server &&
+                   ((e->client->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP ||
+                       (e->client->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 *svr,
+                                  void      *ev)
 {
    Ecore_Con_Event_Client_Data *e;
 
    e = ev;
-   e->client->event_count--;
-   if (e->data) free(e->data);
-   if ((e->client->event_count == 0) && (e->client->delete_me))
-     ecore_con_client_del(e->client);
-   free(e);
+   if (e->client)
+     {
+        Eina_Bool svrfreed = EINA_FALSE;
+        
+        e->client->event_count = eina_list_remove(e->client->event_count, e);
+        if (e->client->host_server)
+          {
+             e->client->host_server->event_count = eina_list_remove(e->client->host_server->event_count, ev);
+          }
+        if ((!svr->event_count) && (svr->delete_me))
+          {
+             _ecore_con_server_free(svr);
+             svrfreed = EINA_TRUE;
+          }
+        if (!svrfreed)
+          {
+             if (((!e->client->event_count) && (e->client->delete_me)) ||
+                 ((e->client->host_server &&
+                   ((e->client->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_UDP ||
+                       (e->client->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 __UNUSED__, void *ev)
+_ecore_con_event_server_add_free(void *data __UNUSED__,
+                                 void      *ev)
 {
    Ecore_Con_Event_Server_Add *e;
 
    e = ev;
-   e->server->event_count--;
-   if ((e->server->event_count == 0) && (e->server->delete_me))
-     ecore_con_server_del(e->server);
-   free(e);
+   if (e->server)
+     {
+        e->server->event_count = eina_list_remove(e->server->event_count, ev);
+        if ((!e->server->event_count) && (e->server->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 __UNUSED__, void *ev)
+_ecore_con_event_server_del_free(void *data __UNUSED__,
+                                 void      *ev)
 {
    Ecore_Con_Event_Server_Del *e;
 
    e = ev;
-   e->server->event_count--;
-   if ((e->server->event_count == 0) && (e->server->delete_me))
-     ecore_con_server_del(e->server);
-   free(e);
+   if (e->server)
+     {
+        e->server->event_count = eina_list_remove(e->server->event_count, ev);
+        if (!e->server->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 __UNUSED__,
+                                   Ecore_Con_Event_Server_Write *e)
+{
+   if (e->server)
+     {
+        e->server->event_count = eina_list_remove(e->server->event_count, e);
+        if ((!e->server->event_count) && (e->server->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 __UNUSED__, void *ev)
+_ecore_con_event_server_data_free(void *data __UNUSED__,
+                                  void      *ev)
 {
    Ecore_Con_Event_Server_Data *e;
 
    e = ev;
-   e->server->event_count--;
-   if (e->data) free(e->data);
-   if ((e->server->event_count == 0) && (e->server->delete_me))
-     ecore_con_server_del(e->server);
-   free(e);
+   if (e->server)
+     {
+        e->server->event_count = eina_list_remove(e->server->event_count, ev);
+        if ((!e->server->event_count) && (e->server->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 __UNUSED__, Ecore_Con_Event_Server_Error *e)
+{
+   if (e->server)
+     {
+        e->server->event_count = eina_list_remove(e->server->event_count, e);
+        if ((!e->server->event_count) && (e->server->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 *svr, Ecore_Con_Event_Client_Error *e)
+{
+   if (e->client)
+     {
+        Eina_Bool svrfreed = EINA_FALSE;
+        
+        if (eina_list_data_find(svr->clients, e->client))
+          {
+             e->client->event_count = eina_list_remove(e->client->event_count, e);
+             if ((!e->client->event_count) && (e->client->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(svr);
+          }
+     }
+   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 *svr;
+   Ecore_Con_Lookup *lk;
+
+   svr = data;
+   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(svr->name);
+   free(lk);
+   free(svr);
+}
+