ecore_con - move libproxy to a slave binary with stdin/out msging
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>
Sun, 8 Jan 2017 13:57:54 +0000 (22:57 +0900)
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>
Mon, 9 Jan 2017 06:29:33 +0000 (15:29 +0900)
so here's the ugly problem. libproxy. yes. we've discussed memory
usage (e.g. it may have to execute javascript and pull in lots of deps
etc.) but we dlopene'd on the fly. ok... but this didn't solve another
issue i hit:

libproxy was causing enlightenment to abort(). some internal bit of
libproxy was raising a c++ exception. this wasn't caught. this causes
an abort(). takes down your entire desktop. FANTASTIC. this is bad. i
wouldnt' expect a library we depend on to be THIS anti-social but
libproxy seemingly is. it SHOULd catch its error sand just propagate
back to us so we can handle gracefully.

there reall is no way around this - isolate libproxy. it's even worse
that libproxy can load arbitrary modules that come from anywhere sho
who knows what issues this can cause. isolation is the best solution i
can think of.

so this makes an elf+net_proxy_helper we spawn the first time we need
a proxy lookup. we re-use that binary again and again until it exits
(it should exit after 10 seconds of being idle with no requests coming
in/pending). it'll respawn again later if needed. this involves now
the efl net threads having to marshall back to mainloop to do the
spawn and to write to the proxy process (reading is done by async exe
data events and the data is passed down a thread queue to the waitng
efl net thread). if the exe dies with pending requests unanswered then
it's respawned again and the req's are re-sent to it... just in case.
it has a limit on how often it'll respawn quickly.

this seems to work in my limited testing. this ALSO now isolates
memory usage of libproxy to another slave process AND this process
will die taking its memory with it once it's been idle for long
enough. that;s also another good solution to keeping libproxy impact
at bay.

.gitignore
src/Makefile_Ecore_Con.am
src/bin/ecore_con/efl_net_proxy_helper.c [new file with mode: 0644]
src/lib/ecore_con/ecore_con.c
src/lib/ecore_con/ecore_con_private.h
src/lib/ecore_con/ecore_con_proxy_helper.c [new file with mode: 0644]
src/lib/ecore_con/efl_net_dialer_http.c

index 0dbb552..b00829a 100644 (file)
@@ -76,3 +76,4 @@ Session.vim
 /elm_intro.h
 /src/modules/evas/engines/gl_common/shader_3d/evas_3d_shaders.x
 /src/scripts/eo/eo_debug
+/src/bin/ecore_con/efl_net_proxy_helper
index 3c62337..093c26a 100644 (file)
@@ -80,6 +80,7 @@ nodist_installed_ecoreconmainheaders_DATA = \
 lib_ecore_con_libecore_con_la_SOURCES = \
 lib/ecore_con/ecore_con_alloc.c \
 lib/ecore_con/ecore_con.c \
+lib/ecore_con/ecore_con_proxy_helper.c \
 lib/ecore_con/ecore_con_legacy.c \
 lib/ecore_con/ecore_con_eet.c \
 lib/ecore_con/ecore_con_socks.c \
@@ -152,7 +153,12 @@ lib/ecore_con/efl_net_dialer_unix.c \
 lib/ecore_con/efl_net_server_unix.c
 endif
 
-lib_ecore_con_libecore_con_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_CON_CFLAGS@
+lib_ecore_con_libecore_con_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
+-DPACKAGE_BIN_DIR=\"$(bindir)\" \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DPACKAGE_DATA_DIR=\"$(datadir)/ecore\" \
+-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)\" \
+@ECORE_CON_CFLAGS@
 lib_ecore_con_libecore_con_la_LIBADD = @ECORE_CON_LIBS@ @EVIL_LIBS@
 lib_ecore_con_libecore_con_la_DEPENDENCIES = @ECORE_CON_INTERNAL_LIBS@
 lib_ecore_con_libecore_con_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
@@ -169,6 +175,22 @@ static_libs/http-parser/test.c \
 static_libs/http-parser/contrib/parsertrace.c \
 static_libs/http-parser/contrib/url_parser.c
 
+### Binary
+proxyhelperdir = \
+$(libdir)/ecore_con/utils/$(MODULE_ARCH)
+proxyhelper_PROGRAMS = bin/ecore_con/efl_net_proxy_helper
+
+bin_ecore_con_efl_net_proxy_helper_SOURCES = \
+bin/ecore_con/efl_net_proxy_helper.c
+
+bin_ecore_con_efl_net_proxy_helper_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
+-DPACKAGE_BIN_DIR=\"$(bindir)\" \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DPACKAGE_DATA_DIR=\"$(datadir)/ecore\" \
+@EINA_CFLAGS@
+bin_ecore_con_efl_net_proxy_helper_LDADD = @USE_EINA_LIBS@
+bin_ecore_con_efl_net_proxy_helper_DEPEDNENCIES = @USE_EINA_INTERNAL_LIBS@
+
 ### Unit tests
 
 if EFL_ENABLE_TESTS
diff --git a/src/bin/ecore_con/efl_net_proxy_helper.c b/src/bin/ecore_con/efl_net_proxy_helper.c
new file mode 100644 (file)
index 0000000..69c371a
--- /dev/null
@@ -0,0 +1,264 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Eina.h"
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(EINA_LOG_DOMAIN_GLOBAL, __VA_ARGS__)
+
+#ifdef DBG
+# undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(EINA_LOG_DOMAIN_GLOBAL, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(EINA_LOG_DOMAIN_GLOBAL, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(EINA_LOG_DOMAIN_GLOBAL, __VA_ARGS__)
+
+#ifdef CRI
+# undef CRI
+#endif
+#define CRI(...) EINA_LOG_DOM_CRIT(EINA_LOG_DOMAIN_GLOBAL, __VA_ARGS__)
+
+typedef struct pxProxyFactory_  pxProxyFactory;
+typedef struct _Libproxy
+{
+   pxProxyFactory    *factory;
+   char           **(*px_proxy_factory_get_proxies) (pxProxyFactory *factory, const char *url);
+   void            *(*px_proxy_factory_new)         (void);
+   void             (*px_proxy_factory_free)        (pxProxyFactory *);
+   Eina_Module       *mod;
+} Libproxy;
+static Libproxy _libproxy = { 0 };
+
+static Eina_Spinlock pending_lock;
+static int pending = 0;
+static int opcount = 0;
+static Eina_List *join_list = NULL;
+
+static Eina_Bool
+init(void)
+{
+   if (!_libproxy.mod)
+     {
+#define LOAD(x) \
+   if (!_libproxy.mod) { \
+      _libproxy.mod = eina_module_new(x); \
+      if (_libproxy.mod) { \
+         if (!eina_module_load(_libproxy.mod)) { \
+            eina_module_free(_libproxy.mod); \
+            _libproxy.mod = NULL; \
+         } \
+      } \
+   }
+#if defined(_WIN32) || defined(__CYGWIN__)
+        LOAD("libproxy-1.dll");
+        LOAD("libproxy.dll");
+#elif defined(__APPLE__) && defined(__MACH__)
+        LOAD("libproxy.1.dylib");
+        LOAD("libproxy.dylib");
+#else
+        LOAD("libproxy.so.1");
+        LOAD("libproxy.so");
+#endif
+#undef LOAD
+        if (!_libproxy.mod)
+          {
+             DBG("Couldn't find libproxy in your system. Continue without it");
+             return EINA_FALSE;
+          }
+
+#define SYM(x) \
+   if ((_libproxy.x = eina_module_symbol_get(_libproxy.mod, #x)) == NULL) { \
+      ERR("libproxy (%s) missing symbol %s", \
+          eina_module_file_get(_libproxy.mod), #x); \
+      eina_module_free(_libproxy.mod); \
+      _libproxy.mod = NULL; \
+      return EINA_FALSE; \
+   }
+
+        SYM(px_proxy_factory_new);
+        SYM(px_proxy_factory_free);
+        SYM(px_proxy_factory_get_proxies);
+#undef SYM
+        DBG("using libproxy=%s", eina_module_file_get(_libproxy.mod));
+     }
+
+   if (!_libproxy.factory)
+     _libproxy.factory = _libproxy.px_proxy_factory_new();
+
+   return !!_libproxy.factory;
+}
+
+static void
+shutdown(void)
+{
+   if (_libproxy.factory)
+     {
+        _libproxy.px_proxy_factory_free(_libproxy.factory);
+        _libproxy.factory = NULL;
+     }
+   if (_libproxy.mod)
+     {
+        eina_module_free(_libproxy.mod);
+        _libproxy.mod = NULL;
+     }
+}
+
+static void *
+proxy_lookup(void *data, Eina_Thread t)
+{
+   char *cmd = data;
+   char **proxies, **itr;
+   const char *p, *url;
+   int id = atoi(cmd + 2);
+   int pending_local, opcount_prev;
+
+   if (id > 0)
+     {
+        for (p = cmd + 2; *p && (*p != ' '); p++);
+        if (*p == ' ')
+          {
+             url = p + 1;
+             proxies = _libproxy.px_proxy_factory_get_proxies
+               (_libproxy.factory, url);
+             if (proxies)
+               {
+                  for (itr = proxies; *itr != NULL; itr++)
+                    {
+                       fprintf(stdout, "P %i P %s\n", id, *itr);
+                       free(*itr);
+                    }
+                  free(proxies);
+               }
+             fprintf(stdout, "P %i E\n", id);
+             fflush(stdout);
+          }
+     }
+   free(cmd);
+
+   eina_spinlock_take(&pending_lock);
+     {
+        pending--;
+        pending_local = pending;
+        opcount_prev = opcount;
+     }
+   eina_spinlock_release(&pending_lock);
+   // if there are no more pending threads doing work - sleep for the
+   // timeout then check if we still are and if so - exit;
+   if (pending_local == 0) sleep(10);
+   eina_spinlock_take(&pending_lock);
+     {
+        Eina_Thread *tt;
+
+        if ((pending == 0) & (opcount == opcount_prev)) exit(0);
+        tt = calloc(1, sizeof(Eina_Thread));
+        if (tt)
+          {
+             *tt = t;
+             join_list = eina_list_append(join_list, tt);
+          }
+     }
+   eina_spinlock_release(&pending_lock);
+   return NULL;
+}
+
+static void
+handle(const char *cmd)
+{
+   // "P 1234 URL" -> Get Proxy, id=1234, url=URL
+   if ((cmd[0] == 'P') && (cmd[1] == ' '))
+     {
+        char *dup = strdup(cmd);
+
+        if (dup)
+          {
+             Eina_Thread t;
+
+             eina_spinlock_take(&pending_lock);
+               {
+                  pending++;
+                  opcount++;
+               }
+             eina_spinlock_release(&pending_lock);
+             if (!eina_thread_create(&t, EINA_THREAD_BACKGROUND, -1,
+                                     proxy_lookup, dup))
+               {
+                  abort();
+               }
+          }
+        return;
+     }
+}
+
+static void
+clean_threads(void)
+{
+   eina_spinlock_take(&pending_lock);
+     {
+        Eina_Thread *t;
+
+        EINA_LIST_FREE(join_list, t)
+          {
+             eina_thread_join(*t);
+             free(t);
+          }
+     }
+   eina_spinlock_release(&pending_lock);
+}
+
+int
+main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+{
+   char inbuf[8192];
+   eina_init();
+   if (init())
+     {
+        eina_spinlock_new(&pending_lock);
+        // 1 command per stdin line
+        while (fgets(inbuf, sizeof(inbuf) - 1, stdin))
+          {
+             // strip off newline and ensure the string is 0 terminated
+             int len = strlen(inbuf);
+             if (len > 0)
+               {
+                  if (inbuf[len -1 ] == '\n') inbuf[len - 1] = 0;
+                  else inbuf[len] = 0;
+                  handle(inbuf);
+               }
+             clean_threads();
+          }
+        eina_spinlock_free(&pending_lock);
+        shutdown();
+     }
+   else
+     {
+        // Failed to init libproxy so report this before exit
+        fprintf(stdout, "F\n");
+        fflush(stdout);
+        pause();
+     }
+   eina_shutdown();
+   return 0;
+}
index 58e0805..dd641da 100644 (file)
@@ -68,15 +68,11 @@ EWAPI Eina_Error EFL_NET_SOCKET_SSL_ERROR_CERTIFICATE_VERIFY_FAILED = 0;
 static int _ecore_con_init_count = 0;
 int _ecore_con_log_dom = -1;
 
-typedef struct pxProxyFactory_  pxProxyFactory;
-typedef struct _Ecore_Con_Libproxy {
-   pxProxyFactory *factory;
-   char **(*px_proxy_factory_get_proxies)(pxProxyFactory *factory, const char *url);
-   void *(*px_proxy_factory_new)(void);
-   void (*px_proxy_factory_free)(pxProxyFactory *);
-   Eina_Module *mod;
-} Ecore_Con_Libproxy;
-static Ecore_Con_Libproxy _ecore_con_libproxy;
+Eina_Bool   _efl_net_proxy_helper_can_do      (void);
+int         _efl_net_proxy_helper_url_req_send(const char *url);
+char      **_efl_net_proxy_helper_url_wait    (int id);
+void        _efl_net_proxy_helper_init        (void);
+void        _efl_net_proxy_helper_shutdown    (void);
 
 EAPI int
 ecore_con_init(void)
@@ -100,6 +96,8 @@ ecore_con_init(void)
           goto ecore_con_log_error;
      }
 
+   _efl_net_proxy_helper_init();
+
    ecore_con_mempool_init();
    ecore_con_legacy_init();
 
@@ -145,16 +143,7 @@ ecore_con_shutdown(void)
    if (--_ecore_con_init_count != 0)
      return _ecore_con_init_count;
 
-   if (_ecore_con_libproxy.factory)
-     {
-        _ecore_con_libproxy.px_proxy_factory_free(_ecore_con_libproxy.factory);
-        _ecore_con_libproxy.factory = NULL;
-     }
-   if (_ecore_con_libproxy.mod)
-     {
-        eina_module_free(_ecore_con_libproxy.mod);
-        _ecore_con_libproxy.mod = NULL;
-     }
+   _efl_net_proxy_helper_shutdown();
 
    eina_log_timing(_ecore_con_log_dom,
                    EINA_LOG_STATE_START,
@@ -2079,12 +2068,8 @@ _efl_net_ip_connect_async_run(void *data, Ecore_Thread *thread EINA_UNUSED)
 
    proxy = d->proxy;
 
-   if ((!proxy) && (_ecore_con_libproxy.factory))
+   if ((!proxy) && _efl_net_proxy_helper_can_do())
      {
-        /* libproxy is thread-safe but not cancellable.  the provided
-         * parameter must be a URL with schema, otherwise it won't
-         * return anything.
-         */
         Eina_Stringshare *url;
 
         url = eina_stringshare_printf("%s://%s:%s", d->protocol == IPPROTO_UDP ? "udp" : "tcp", host, port);
@@ -2608,64 +2593,12 @@ efl_net_udp_datagram_size_query(SOCKET fd)
    return READBUFSIZ;
 }
 
-Eina_Bool
-ecore_con_libproxy_init(void)
-{
-   if (!_ecore_con_libproxy.mod)
-     {
-#define LOAD(x)                                                         \
-          if (!_ecore_con_libproxy.mod) {                               \
-             _ecore_con_libproxy.mod = eina_module_new(x);              \
-             if (_ecore_con_libproxy.mod) {                             \
-                if (!eina_module_load(_ecore_con_libproxy.mod)) {       \
-                   eina_module_free(_ecore_con_libproxy.mod);           \
-                   _ecore_con_libproxy.mod = NULL;                      \
-                }                                                       \
-             }                                                          \
-          }
-#if defined(_WIN32) || defined(__CYGWIN__)
-        LOAD("libproxy-1.dll");
-        LOAD("libproxy.dll");
-#elif defined(__APPLE__) && defined(__MACH__)
-        LOAD("libproxy.1.dylib");
-        LOAD("libproxy.dylib");
-#else
-        LOAD("libproxy.so.1");
-        LOAD("libproxy.so");
-#endif
-#undef LOAD
-        if (!_ecore_con_libproxy.mod)
-          {
-             DBG("Couldn't find libproxy in your system. Continue without it");
-             return EINA_FALSE;
-          }
-
-#define SYM(x)                                                          \
-        if ((_ecore_con_libproxy.x = eina_module_symbol_get(_ecore_con_libproxy.mod, #x)) == NULL) { \
-           ERR("libproxy (%s) missing symbol %s", eina_module_file_get(_ecore_con_libproxy.mod), #x); \
-           eina_module_free(_ecore_con_libproxy.mod);                   \
-           _ecore_con_libproxy.mod = NULL;                              \
-           return EINA_FALSE;                                           \
-        }
-
-        SYM(px_proxy_factory_new);
-        SYM(px_proxy_factory_free);
-        SYM(px_proxy_factory_get_proxies);
-#undef SYM
-        DBG("using libproxy=%s", eina_module_file_get(_ecore_con_libproxy.mod));
-     }
-
-   if (!_ecore_con_libproxy.factory)
-     _ecore_con_libproxy.factory = _ecore_con_libproxy.px_proxy_factory_new();
-
-   return !!_ecore_con_libproxy.factory;
-}
-
 char **
 ecore_con_libproxy_proxies_get(const char *url)
 {
-   EINA_SAFETY_ON_NULL_RETURN_VAL(_ecore_con_libproxy.px_proxy_factory_get_proxies, NULL);
-   return _ecore_con_libproxy.px_proxy_factory_get_proxies(_ecore_con_libproxy.factory, url);
+   int id =  _efl_net_proxy_helper_url_req_send(url);
+   if (id < 0) return NULL;
+   return _efl_net_proxy_helper_url_wait(id);
 }
 
 void
index bcc9dea..42f6ded 100644 (file)
@@ -93,7 +93,6 @@ extern int sd_fd_max;
 #endif
 
 /* init must be called from main thread */
-Eina_Bool ecore_con_libproxy_init(void);
 void ecore_con_libproxy_proxies_free(char **proxies);
 /* BLOCKING! should be called from a worker thread */
 char **ecore_con_libproxy_proxies_get(const char *url);
diff --git a/src/lib/ecore_con/ecore_con_proxy_helper.c b/src/lib/ecore_con/ecore_con_proxy_helper.c
new file mode 100644 (file)
index 0000000..eda91e9
--- /dev/null
@@ -0,0 +1,427 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "Ecore_Con.h"
+#include "ecore_con_private.h"
+
+typedef struct {
+   Eina_Thread_Queue  *thq;
+   char               *str;
+   char              **proxies;
+   int                 id;
+   int                 busy;
+} Efl_Net_Proxy_Helper_Req;
+
+typedef struct {
+   Eina_Thread_Queue_Msg   head;
+   char                  **proxies;
+} Efl_Net_Proxy_Helper_Thq_Msg;
+
+static Eina_Bool            _efl_net_proxy_helper_works            = EINA_TRUE;
+static Ecore_Exe           *_efl_net_proxy_helper_exe              = NULL;
+static Eina_Prefix         *_efl_net_proxy_helper_prefix           = NULL;
+static Eina_Spinlock        _efl_net_proxy_helper_queue_lock;
+static int                  _efl_net_proxy_helper_req_id           = 0;
+static Eina_List           *_efl_net_proxy_helper_queue            = NULL;
+static Ecore_Event_Handler *_efl_net_proxy_helper_handler_exe_del  = NULL;
+static Ecore_Event_Handler *_efl_net_proxy_helper_handler_exe_data = NULL;
+static Eina_Bool            _efl_net_proxy_helper_queue_lock_init  = EINA_FALSE;
+static int                  _efl_net_proxy_helper_init_num         = 0;
+
+static int locks = 0;
+
+#ifdef _WIN32
+# define HELPER_EXT ".exe"
+#else
+# define HELPER_EXT
+#endif
+
+static void
+_efl_net_proxy_helper_spawn(void)
+{
+   char buf[PATH_MAX];
+   Eina_List *l;
+   Efl_Net_Proxy_Helper_Req *req;
+   static int run_in_tree = -1;
+
+   if (!_efl_net_proxy_helper_works) return;
+   if (_efl_net_proxy_helper_exe) return;
+   if (run_in_tree == -1)
+     {
+        run_in_tree = 0;
+#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
+        if (getuid() == geteuid())
+#endif
+          {
+             if (getenv("EFL_RUN_IN_TREE")) run_in_tree = 1;
+          }
+     }
+   // find binary location path
+   if (run_in_tree == 1)
+     snprintf
+       (buf, sizeof(buf),
+        PACKAGE_BUILD_DIR"/src/bin/ecore_con/utils/efl_net_proxy_helper"HELPER_EXT);
+   else
+     snprintf
+       (buf, sizeof(buf),
+        "%s/ecore_con/utils/"MODULE_ARCH"/efl_net_proxy_helper"HELPER_EXT,
+        eina_prefix_lib_get(_efl_net_proxy_helper_prefix));
+  // run it with stdin/out piped line buffered with events
+   _efl_net_proxy_helper_exe = ecore_exe_pipe_run
+     (buf,
+      ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
+      ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_TERM_WITH_PARENT |
+      ECORE_EXE_NOT_LEADER, NULL);
+   // resend unhandled requests
+   eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
+     {
+        locks++;
+        EINA_LIST_FOREACH(_efl_net_proxy_helper_queue, l, req)
+          ecore_exe_send(_efl_net_proxy_helper_exe,
+                         req->str, strlen(req->str));
+        locks--;
+     }
+   eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
+}
+
+static void
+_efl_net_proxy_helper_kill(void)
+{
+   if (!_efl_net_proxy_helper_exe) return;
+   // don't exit if anything is pending
+   if (_efl_net_proxy_helper_queue) return;
+   ecore_exe_kill(_efl_net_proxy_helper_exe);
+   ecore_exe_free(_efl_net_proxy_helper_exe);
+   _efl_net_proxy_helper_exe = NULL;
+}
+
+static void
+_efl_net_proxy_helper_cancel(void)
+{
+   eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
+     {
+        locks++;
+        Efl_Net_Proxy_Helper_Req *req;
+
+        EINA_LIST_FREE(_efl_net_proxy_helper_queue, req)
+          {
+             Efl_Net_Proxy_Helper_Thq_Msg *msg;
+             void *ref;
+
+             msg = eina_thread_queue_send
+               (req->thq, sizeof(Efl_Net_Proxy_Helper_Thq_Msg), &ref);
+             msg->proxies = NULL;
+             eina_thread_queue_send_done(req->thq, ref);
+             if (!req->busy)
+               {
+                  free(req->str);
+                  ecore_con_libproxy_proxies_free(req->proxies);
+                  eina_thread_queue_free(req->thq);
+                  free(req);
+               }
+          }
+        locks--;
+     }
+   eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
+}
+
+static void
+_efl_net_proxy_helper_proxy_add(int id, const char *url)
+{
+   Eina_List *l;
+   Efl_Net_Proxy_Helper_Req *req;
+
+   eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
+     {
+        locks++;
+        EINA_LIST_FOREACH(_efl_net_proxy_helper_queue, l, req)
+          {
+             if (req->id == id) break;
+             req = NULL;
+          }
+        if (req)
+          {
+             if (url)
+               {
+                  char **proxies = req->proxies;
+                  int n = 0;
+
+                  if (proxies)
+                    {
+                       for (n = 0; proxies[n]; n++);
+                    }
+                  n++;
+                  proxies = realloc(proxies, sizeof(char *) * (n + 1));
+                  if (proxies)
+                    {
+                       req->proxies = proxies;
+                       proxies[n - 1] = strdup(url);
+                       proxies[n] = NULL;
+                    }
+               }
+             else
+               {
+                  Efl_Net_Proxy_Helper_Thq_Msg *msg;
+                  void *ref;
+
+                  msg = eina_thread_queue_send
+                    (req->thq, sizeof(Efl_Net_Proxy_Helper_Thq_Msg), &ref);
+                  msg->proxies =  req->proxies;
+                  req->proxies = NULL;
+                  eina_thread_queue_send_done(req->thq, ref);
+               }
+          }
+        locks--;
+     }
+   eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
+}
+
+static Eina_Bool
+_efl_net_proxy_helper_cb_exe_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *info)
+{
+   Ecore_Exe_Event_Del *event = info;
+
+   if (!_efl_net_proxy_helper_exe) return EINA_TRUE;
+   if (event->exe == _efl_net_proxy_helper_exe)
+     {
+        static double last_respawn = 0.0;
+        double t;
+        Eina_Bool respawn = EINA_FALSE;
+
+        t = ecore_time_get();
+        _efl_net_proxy_helper_exe = NULL;
+        eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
+          {
+             locks++;
+             if (_efl_net_proxy_helper_queue)
+               {
+                  if ((t - last_respawn) > 5.0) respawn = EINA_TRUE;
+               }
+             locks--;
+          }
+        eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
+        if (respawn)
+          {
+             last_respawn = t;
+             _efl_net_proxy_helper_spawn();
+          }
+        return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_efl_net_proxy_helper_cb_exe_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *info)
+{
+   Ecore_Exe_Event_Data *event = info;
+
+   if (!_efl_net_proxy_helper_exe) return EINA_TRUE;
+   if (event->exe == _efl_net_proxy_helper_exe)
+     {
+        if (event->lines)
+          {
+             int i;
+
+             for (i = 0; event->lines[i].line; i++)
+               {
+                  char *line = event->lines[i].line;
+
+                  if (line[0] == 'F') // failure
+                    {
+                       _efl_net_proxy_helper_works = EINA_FALSE;
+                       _efl_net_proxy_helper_cancel();
+                       _efl_net_proxy_helper_kill();
+                    }
+                  else if ((line[0] == 'P') && (line[1] == ' ')) // proxy
+                    {
+                       int id = atoi(line + 2);
+                       char *p, *url = NULL;
+
+                       for (p = line + 2; *p && (*p != ' '); p++);
+                       if ((p[0] == ' ') && (p[1] == 'P') && (p[2] == ' '))
+                         url = p + 3;
+                       else if ((p[0] == ' ') && (p[1] == 'E'))
+                         url = NULL;
+                       _efl_net_proxy_helper_proxy_add(id, url);
+                    }
+               }
+          }
+        return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+Eina_Bool
+_efl_net_proxy_helper_can_do(void)
+{
+   return _efl_net_proxy_helper_works;
+}
+
+
+static void
+_efl_net_proxy_helper_cb_send_do(void *data)
+{
+   char *str = data;
+   if (!str) return;
+   // spawn exe if needed
+   if (!_efl_net_proxy_helper_exe) _efl_net_proxy_helper_spawn();
+   if (_efl_net_proxy_helper_exe)
+     ecore_exe_send(_efl_net_proxy_helper_exe, str, strlen(str));
+   free(str);
+}
+
+int
+_efl_net_proxy_helper_url_req_send(const char *url)
+{
+   char *buf;
+   int id = -1;
+   Efl_Net_Proxy_Helper_Req *req;
+
+   if (!_efl_net_proxy_helper_works) return -1;
+   eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
+     {
+        locks++;
+        // new id - just an int that eventually loops.
+        _efl_net_proxy_helper_req_id++;
+        if (_efl_net_proxy_helper_req_id >= ((1 << 30) - 1))
+          _efl_net_proxy_helper_req_id = 1;
+        id = _efl_net_proxy_helper_req_id;
+        locks--;
+     }
+   eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
+   // create request to quque up to look up responses for
+   req = calloc(1, sizeof(Efl_Net_Proxy_Helper_Req));
+   if (!req) return -1;
+   req->id = id;
+   req->thq = eina_thread_queue_new();
+   if (!req->thq)
+     {
+        free(req);
+        return -1;
+     }
+   buf = alloca(strlen(url) + 256);
+   sprintf(buf, "P %i %s\n", req->id, url);
+   req->str = strdup(buf);
+   if (!req->str)
+     {
+        eina_thread_queue_free(req->thq);
+        free(req);
+        return -1;
+     }
+   eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
+     {
+        locks++;
+        _efl_net_proxy_helper_queue =
+          eina_list_append(_efl_net_proxy_helper_queue, req);
+        locks--;
+     }
+   eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
+   // actually send the req now i'ts queued
+   ecore_main_loop_thread_safe_call_async
+     (_efl_net_proxy_helper_cb_send_do, strdup(buf));
+   return id;
+}
+
+char **
+_efl_net_proxy_helper_url_wait(int id)
+{
+   Eina_List *l;
+   Efl_Net_Proxy_Helper_Req *req;
+   Efl_Net_Proxy_Helper_Thq_Msg *msg;
+   void *ref;
+   char **ret = NULL;
+
+   if (id < 0) return NULL;
+   if (!_efl_net_proxy_helper_exe) return NULL;
+   eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
+     {
+        locks++;
+        EINA_LIST_FOREACH(_efl_net_proxy_helper_queue, l, req)
+          {
+             if (req->id == id) break;
+             req = NULL;
+          }
+        if (!req) goto end;
+        req->busy++;
+        locks--;
+     }
+   eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
+
+   msg = eina_thread_queue_wait(req->thq, &ref);
+   ret = msg->proxies;
+   msg->proxies = NULL;
+   eina_thread_queue_wait_done(req->thq, ref);
+
+   eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
+     {
+        locks++;
+        free(req->str);
+        ecore_con_libproxy_proxies_free(req->proxies);
+        eina_thread_queue_free(req->thq);
+        _efl_net_proxy_helper_queue =
+          eina_list_remove(_efl_net_proxy_helper_queue, req);
+        free(req);
+     }
+end:
+   locks--;
+   eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
+   return ret;
+}
+
+void
+_efl_net_proxy_helper_init(void)
+{
+   _efl_net_proxy_helper_init_num++;
+   if (_efl_net_proxy_helper_init_num > 1) return;
+   if (_efl_net_proxy_helper_prefix) return;
+   _efl_net_proxy_helper_prefix = eina_prefix_new
+     (NULL, ecore_con_init, "ECORE", "ecore", "checkme",
+      PACKAGE_BIN_DIR, PACKAGE_LIB_DIR, PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
+   if (!_efl_net_proxy_helper_queue_lock_init)
+     {
+        eina_spinlock_new(&_efl_net_proxy_helper_queue_lock);
+        _efl_net_proxy_helper_queue_lock_init = EINA_TRUE;
+     }
+   _efl_net_proxy_helper_handler_exe_del =
+     ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
+                             _efl_net_proxy_helper_cb_exe_del, NULL);
+   _efl_net_proxy_helper_handler_exe_data =
+     ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
+                             _efl_net_proxy_helper_cb_exe_data, NULL);
+}
+
+void
+_efl_net_proxy_helper_shutdown(void)
+{
+   _efl_net_proxy_helper_init_num--;
+   if (_efl_net_proxy_helper_init_num > 0) return;
+   if (!_efl_net_proxy_helper_prefix) return;
+   if (_efl_net_proxy_helper_exe)
+     {
+        _efl_net_proxy_helper_cancel();
+        _efl_net_proxy_helper_kill();
+     }
+   eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
+   eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
+   eina_prefix_free(_efl_net_proxy_helper_prefix);
+   _efl_net_proxy_helper_prefix = NULL;
+   ecore_event_handler_del(_efl_net_proxy_helper_handler_exe_del);
+   _efl_net_proxy_helper_handler_exe_del = NULL;
+   ecore_event_handler_del(_efl_net_proxy_helper_handler_exe_data);
+   _efl_net_proxy_helper_handler_exe_data = NULL;
+}
index b4d39e4..b5fe3e4 100644 (file)
@@ -1380,7 +1380,7 @@ _efl_net_dialer_http_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Http_Data *pd, co
 #undef IS_HEADER
      }
 
-   if ((!pd->proxy) && (ecore_con_libproxy_init()))
+   if (!pd->proxy)
      {
         Efl_Net_Dialer_Http_Libproxy_Context *ctx;