efl/src/lib/ecore_con/ecore_con_proxy_helper.c

466 lines
14 KiB
C
Raw Normal View History

ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
#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 _WIN32
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
# include <Evil.h>
#endif
#include "Ecore.h"
#include "ecore_private.h"
#include "Ecore_Con.h"
#include "ecore_con_private.h"
2018-02-16 11:37:17 -08:00
#include "../../static_libs/buildsystem/buildsystem.h"
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
typedef struct {
Eina_Thread_Queue *thq;
char *str;
char **proxies;
int id;
int busy;
int fails;
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
} 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_delete_cb(void *data EINA_UNUSED, const Efl_Event *ev)
{
if (ev->object == _efl_net_proxy_helper_exe)
{
INF("HTTP proxy helper object died before the process exited.");
_efl_net_proxy_helper_exe = NULL;
}
}
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
static void
_efl_net_proxy_helper_spawn(void)
{
char buf[PATH_MAX];
Eina_List *l;
Efl_Net_Proxy_Helper_Req *req;
#ifdef NEED_RUN_IN_TREE
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
static int run_in_tree = -1;
#endif
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
if (!_efl_net_proxy_helper_works) return;
if (_efl_net_proxy_helper_exe) return;
#ifdef NEED_RUN_IN_TREE
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
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)
2018-02-16 11:37:17 -08:00
bs_binary_get(buf, sizeof(buf), "ecore_con/utils", "efl_net_proxy_helper");
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
else
#endif
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
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);
efl_event_callback_add(_efl_net_proxy_helper_exe, EFL_EVENT_DEL,
_efl_net_proxy_helper_delete_cb, NULL);
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
}
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
{
ERR("Out of memory allocating proxies in helper");
goto err;
}
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
}
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);
}
}
err:
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
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;
int min_fails = 0;
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
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;
}
if (respawn)
{
Eina_List *l;
Efl_Net_Proxy_Helper_Req *req;
EINA_LIST_FOREACH(_efl_net_proxy_helper_queue, l, req)
{
req->fails++;
if (req->fails > min_fails) min_fails = req->fails;
}
}
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
locks--;
}
eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
if (min_fails >= 5) _efl_net_proxy_helper_cancel();
else if (respawn)
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
{
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, Ecore_Thread *eth)
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
{
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);
if (ecore_thread_check(eth)) return -1;
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
// 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) || ecore_thread_check(eth))
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
{
eina_thread_queue_free(req->thq);
free(req->str);
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
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);
if (!msg) return NULL;
ecore_con - move libproxy to a slave binary with stdin/out msging 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.
2017-01-08 05:57:54 -08:00
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;
}