optimize read mechanics for remote servers using ioctl to determine number of bytes...
authordiscomfitor <discomfitor@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 9 Dec 2011 22:35:12 +0000 (22:35 +0000)
committerdiscomfitor <discomfitor@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 9 Dec 2011 22:35:12 +0000 (22:35 +0000)
in general, this should provide an improvement which scales with the amount of data being transferred:
* small transfers will incur a small amount of overhead from potentially unneeded memory as I try to account for a bug in FIONREAD which returns a number that is smaller than the actual number of bytes available for read on a socket
* large transfers will no longer require any copies of the data

on systems which do not provide the FIONREAD ioctl(), old functionality will be used
this should work on windows, though I (obviously) can't test it myself

thus ends the longest commit message I have ever written

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ecore@66063 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

ChangeLog
configure.ac
src/lib/ecore_con/ecore_con.c
src/lib/ecore_con/ecore_con_private.h
src/lib/ecore_con/ecore_con_socks.c

index 6ceb054..34f6e58 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
         * Allow SSL certificates to be loaded for STARTTLS
         * Added functions to set/get the hostname used for SSL certificate verification
         * ecore_con_ssl_server_cafile_add() now accepts directories
+
+2011-12-09 Mike Blumenkrantz
+
+        * Created optimized reading mechanism for remote server connections
index 60c7636..461e089 100644 (file)
@@ -1415,6 +1415,7 @@ AC_ARG_ENABLE([ipv6],
 
 if test "x${have_ecore_con}" = "xyes" ; then
 
+   AC_CHECK_HEADERS([sys/ioctl.h winsock2.h])
    # Verify IPV6 availability in headers
    if test "x${want_ipv6}" != "xno" ; then
       AC_CHECK_TYPES([struct ipv6_mreq],
index da59dc5..cd39aa1 100644 (file)
 # include <Evil.h>
 #endif
 
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+
 #include "Ecore.h"
 #include "ecore_private.h"
 #include "Ecore_Con.h"
@@ -1049,7 +1057,11 @@ ecore_con_event_server_data(Ecore_Con_Server *svr, unsigned char *buf, int num,
    Ecore_Con_Event_Server_Data *e;
 
    e = ecore_con_event_server_data_alloc();
-   EINA_SAFETY_ON_NULL_RETURN(e);
+   if (!e)
+     {
+        if (!duplicate) free(buf);
+        return;
+     }
 
    svr->event_count = eina_list_append(svr->event_count, e);
    _ecore_con_server_timer_update(svr);
@@ -1999,9 +2011,14 @@ _ecore_con_svr_tcp_handler(void                        *data,
 static void
 _ecore_con_cl_read(Ecore_Con_Server *svr)
 {
-   int num = 0;
-   Eina_Bool lost_server = EINA_TRUE;
+   int num2 = 0, num = 0;
+#ifdef FIONREAD
+   double lr;
+   unsigned char *buf = NULL;
+#else
    unsigned char buf[READBUFSIZ];
+#endif
+   Eina_Bool lost_server = EINA_TRUE;
 
    DBG("svr=%p", svr);
 
@@ -2016,23 +2033,42 @@ _ecore_con_cl_read(Ecore_Con_Server *svr)
            lost_server = EINA_FALSE;
         _ecore_con_server_timer_update(svr);
      }
-
+#ifdef FIONREAD
+# ifdef _WIN32
+   if (ioctlsocket(svr->fd, FIONREAD, &num)) goto error;
+# else
+   errno = 0;
+   if (ioctl(svr->fd, FIONREAD, &num)) goto error;
+# endif
+   if (!num) return; /* FIXME: this shouldn't happen */
+   lr = ecore_time_get();
+   if ((num < 100) && (lr - svr->last_read < 0.01)) num2 = READBUFSIZ / 8;
+   else if (num > READBUFSIZ) num2 = READBUFSIZ;
+   if (num2)
+     {
+        DBG("%d bytes available for read from ioctl(), trying size (%d) to avoid congestion", num, num2);
+        num = num2;
+     }
+   else
+     DBG("%d bytes available for read", num);
+   svr->last_read = lr;
+   buf = malloc(num);
+   if (!buf) goto error;
+#else
+   num = sizeof(buf);
+   (void)num2;
+#endif
    if (svr->ecs_state || !(svr->type & ECORE_CON_SSL))
      {
-        errno = 0;
-        num = read(svr->fd, buf, sizeof(buf));
+        num = read(svr->fd, buf, num);
         /* 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));
+        if ((num < 0) || (errno && (errno != EAGAIN))) goto error;
      }
    else
      {
-        num = ecore_con_ssl_server_read(svr, buf, sizeof(buf));
+        num = ecore_con_ssl_server_read(svr, buf, num);
         /* 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 (num < 0) goto error;
      }
 
    if ((!svr->delete_me) && (num > 0))
@@ -2040,11 +2076,25 @@ _ecore_con_cl_read(Ecore_Con_Server *svr)
         if (svr->ecs_state)
           ecore_con_socks_read(svr, buf, num);
         else
-          ecore_con_event_server_data(svr, buf, num, EINA_TRUE);
+          ecore_con_event_server_data(svr, buf, num,
+#ifdef FIONREAD
+          EINA_FALSE
+#else
+          EINA_TRUE
+#endif
+          );
      }
 
-   if (lost_server)
-      _ecore_con_server_kill(svr);
+   return;
+error:
+#ifndef _WIN32
+   /* FIXME: strerror on windows */
+   ecore_con_event_server_error(svr, strerror(errno));
+#endif
+#ifdef FIONREAD
+   free(buf);
+#endif
+   _ecore_con_server_kill(svr);
 }
 
 static Eina_Bool
index 85e4722..098ca69 100644 (file)
@@ -150,6 +150,7 @@ struct _Ecore_Con_Server
    const char *proxyip;
    int proxyport;
    /* endsocks */
+   /* SSL */
    const char *verify_name;
 #if USE_GNUTLS
    gnutls_session_t session;
@@ -165,7 +166,9 @@ struct _Ecore_Con_Server
    SSL *ssl;
    int ssl_err;
 #endif
+   /* ENDSSL */
    double start_time;
+   double last_read;
    Ecore_Timer *until_deletion;
    double disconnect_time;
    double client_disconnect_time;
index d44c1f5..c78759d 100644 (file)
@@ -103,11 +103,25 @@ ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num)
         DBG("SOCKS: %d bytes", num);
         if (num < 8)
           {
+#ifdef FIONREAD
+             if (!svr->ecs_recvbuf)
+               svr->ecs_recvbuf = eina_binbuf_manage_new_length(buf, num);
+             else
+               eina_binbuf_append_length(svr->ecs_recvbuf, buf, num);
+             if (!svr->ecs_recvbuf) goto error;
+#else
              if (!svr->ecs_recvbuf) svr->ecs_recvbuf = eina_binbuf_new();
              if (!svr->ecs_recvbuf) goto error;
              eina_binbuf_append_length(svr->ecs_recvbuf, buf, num);
+#endif
              /* the slowest connection on earth */
-             if (eina_binbuf_length_get(svr->ecs_recvbuf) != 8) return;
+             if (eina_binbuf_length_get(svr->ecs_recvbuf) != 8)
+               {
+#ifdef FIONREAD
+                  free(buf);
+#endif
+                  return;
+               }
              data = eina_binbuf_string_get(svr->ecs_recvbuf);
           }
         else if (num > 8) goto error;
@@ -149,6 +163,9 @@ ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num)
         svr->ecs_state = ECORE_CON_SOCKS_STATE_DONE;
         INF("PROXY CONNECTED");
         if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf);
+#ifdef FIONREAD
+        else free(buf);
+#endif
         svr->ecs_recvbuf = NULL;
         svr->ecs_buf_offset = svr->ecs_addrlen = 0;
         memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr));
@@ -159,6 +176,9 @@ ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num)
      }
    return;
 error:
+#ifdef FIONREAD
+   free(buf);
+#endif
    _ecore_con_server_kill(svr);
 }