From 034fcf7d77fa215f7ceadffe218a3892762e9d0f Mon Sep 17 00:00:00 2001 From: discomfitor Date: Fri, 9 Dec 2011 22:35:12 +0000 Subject: [PATCH] optimize read mechanics for remote servers using ioctl to determine number of bytes available for reading. 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 | 4 ++ configure.ac | 1 + src/lib/ecore_con/ecore_con.c | 82 ++++++++++++++++++++++++++++------- src/lib/ecore_con/ecore_con_private.h | 3 ++ src/lib/ecore_con/ecore_con_socks.c | 22 +++++++++- 5 files changed, 95 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6ceb054..34f6e58 100644 --- a/ChangeLog +++ b/ChangeLog @@ -390,3 +390,7 @@ * 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 diff --git a/configure.ac b/configure.ac index 60c7636..461e089 100644 --- a/configure.ac +++ b/configure.ac @@ -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], diff --git a/src/lib/ecore_con/ecore_con.c b/src/lib/ecore_con/ecore_con.c index da59dc5..cd39aa1 100644 --- a/src/lib/ecore_con/ecore_con.c +++ b/src/lib/ecore_con/ecore_con.c @@ -38,6 +38,14 @@ # include #endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif + +#ifdef HAVE_WINSOCK2_H +# include +#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 diff --git a/src/lib/ecore_con/ecore_con_private.h b/src/lib/ecore_con/ecore_con_private.h index 85e4722..098ca69 100644 --- a/src/lib/ecore_con/ecore_con_private.h +++ b/src/lib/ecore_con/ecore_con_private.h @@ -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; diff --git a/src/lib/ecore_con/ecore_con_socks.c b/src/lib/ecore_con/ecore_con_socks.c index d44c1f5..c78759d 100644 --- a/src/lib/ecore_con/ecore_con_socks.c +++ b/src/lib/ecore_con/ecore_con_socks.c @@ -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); } -- 2.7.4