summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2017-01-08 22:57:54 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2017-01-09 15:29:33 +0900
commitbd2f189d4c8dcaecde9b821f59ccd3978f940dfd (patch)
treec5bba7b5ebda7b4e72fc0ee38acd518bb8b28560
parent5bb9294966ef8a95089edb390e1093750ba38ca7 (diff)
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.
-rw-r--r--.gitignore1
-rw-r--r--src/Makefile_Ecore_Con.am24
-rw-r--r--src/bin/ecore_con/efl_net_proxy_helper.c264
-rw-r--r--src/lib/ecore_con/ecore_con.c91
-rw-r--r--src/lib/ecore_con/ecore_con_private.h1
-rw-r--r--src/lib/ecore_con/ecore_con_proxy_helper.c427
-rw-r--r--src/lib/ecore_con/efl_net_dialer_http.c2
7 files changed, 728 insertions, 82 deletions
diff --git a/.gitignore b/.gitignore
index 0dbb552..b00829a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,3 +76,4 @@ Session.vim
76/elm_intro.h 76/elm_intro.h
77/src/modules/evas/engines/gl_common/shader_3d/evas_3d_shaders.x 77/src/modules/evas/engines/gl_common/shader_3d/evas_3d_shaders.x
78/src/scripts/eo/eo_debug 78/src/scripts/eo/eo_debug
79/src/bin/ecore_con/efl_net_proxy_helper
diff --git a/src/Makefile_Ecore_Con.am b/src/Makefile_Ecore_Con.am
index 3c62337..093c26a 100644
--- a/src/Makefile_Ecore_Con.am
+++ b/src/Makefile_Ecore_Con.am
@@ -80,6 +80,7 @@ nodist_installed_ecoreconmainheaders_DATA = \
80lib_ecore_con_libecore_con_la_SOURCES = \ 80lib_ecore_con_libecore_con_la_SOURCES = \
81lib/ecore_con/ecore_con_alloc.c \ 81lib/ecore_con/ecore_con_alloc.c \
82lib/ecore_con/ecore_con.c \ 82lib/ecore_con/ecore_con.c \
83lib/ecore_con/ecore_con_proxy_helper.c \
83lib/ecore_con/ecore_con_legacy.c \ 84lib/ecore_con/ecore_con_legacy.c \
84lib/ecore_con/ecore_con_eet.c \ 85lib/ecore_con/ecore_con_eet.c \
85lib/ecore_con/ecore_con_socks.c \ 86lib/ecore_con/ecore_con_socks.c \
@@ -152,7 +153,12 @@ lib/ecore_con/efl_net_dialer_unix.c \
152lib/ecore_con/efl_net_server_unix.c 153lib/ecore_con/efl_net_server_unix.c
153endif 154endif
154 155
155lib_ecore_con_libecore_con_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_CON_CFLAGS@ 156lib_ecore_con_libecore_con_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
157-DPACKAGE_BIN_DIR=\"$(bindir)\" \
158-DPACKAGE_LIB_DIR=\"$(libdir)\" \
159-DPACKAGE_DATA_DIR=\"$(datadir)/ecore\" \
160-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)\" \
161@ECORE_CON_CFLAGS@
156lib_ecore_con_libecore_con_la_LIBADD = @ECORE_CON_LIBS@ @EVIL_LIBS@ 162lib_ecore_con_libecore_con_la_LIBADD = @ECORE_CON_LIBS@ @EVIL_LIBS@
157lib_ecore_con_libecore_con_la_DEPENDENCIES = @ECORE_CON_INTERNAL_LIBS@ 163lib_ecore_con_libecore_con_la_DEPENDENCIES = @ECORE_CON_INTERNAL_LIBS@
158lib_ecore_con_libecore_con_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@ 164lib_ecore_con_libecore_con_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
@@ -169,6 +175,22 @@ static_libs/http-parser/test.c \
169static_libs/http-parser/contrib/parsertrace.c \ 175static_libs/http-parser/contrib/parsertrace.c \
170static_libs/http-parser/contrib/url_parser.c 176static_libs/http-parser/contrib/url_parser.c
171 177
178### Binary
179proxyhelperdir = \
180$(libdir)/ecore_con/utils/$(MODULE_ARCH)
181proxyhelper_PROGRAMS = bin/ecore_con/efl_net_proxy_helper
182
183bin_ecore_con_efl_net_proxy_helper_SOURCES = \
184bin/ecore_con/efl_net_proxy_helper.c
185
186bin_ecore_con_efl_net_proxy_helper_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
187-DPACKAGE_BIN_DIR=\"$(bindir)\" \
188-DPACKAGE_LIB_DIR=\"$(libdir)\" \
189-DPACKAGE_DATA_DIR=\"$(datadir)/ecore\" \
190@EINA_CFLAGS@
191bin_ecore_con_efl_net_proxy_helper_LDADD = @USE_EINA_LIBS@
192bin_ecore_con_efl_net_proxy_helper_DEPEDNENCIES = @USE_EINA_INTERNAL_LIBS@
193
172### Unit tests 194### Unit tests
173 195
174if EFL_ENABLE_TESTS 196if 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
index 0000000..69c371a
--- /dev/null
+++ b/src/bin/ecore_con/efl_net_proxy_helper.c
@@ -0,0 +1,264 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdio.h>
6#include <string.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <errno.h>
10#include <unistd.h>
11#include <fcntl.h>
12
13#ifdef HAVE_EVIL
14# include <Evil.h>
15#endif
16
17#include "Eina.h"
18
19#ifdef ERR
20# undef ERR
21#endif
22#define ERR(...) EINA_LOG_DOM_ERR(EINA_LOG_DOMAIN_GLOBAL, __VA_ARGS__)
23
24#ifdef DBG
25# undef DBG
26#endif
27#define DBG(...) EINA_LOG_DOM_DBG(EINA_LOG_DOMAIN_GLOBAL, __VA_ARGS__)
28
29#ifdef INF
30# undef INF
31#endif
32#define INF(...) EINA_LOG_DOM_INFO(EINA_LOG_DOMAIN_GLOBAL, __VA_ARGS__)
33
34#ifdef WRN
35# undef WRN
36#endif
37#define WRN(...) EINA_LOG_DOM_WARN(EINA_LOG_DOMAIN_GLOBAL, __VA_ARGS__)
38
39#ifdef CRI
40# undef CRI
41#endif
42#define CRI(...) EINA_LOG_DOM_CRIT(EINA_LOG_DOMAIN_GLOBAL, __VA_ARGS__)
43
44typedef struct pxProxyFactory_ pxProxyFactory;
45typedef struct _Libproxy
46{
47 pxProxyFactory *factory;
48 char **(*px_proxy_factory_get_proxies) (pxProxyFactory *factory, const char *url);
49 void *(*px_proxy_factory_new) (void);
50 void (*px_proxy_factory_free) (pxProxyFactory *);
51 Eina_Module *mod;
52} Libproxy;
53static Libproxy _libproxy = { 0 };
54
55static Eina_Spinlock pending_lock;
56static int pending = 0;
57static int opcount = 0;
58static Eina_List *join_list = NULL;
59
60static Eina_Bool
61init(void)
62{
63 if (!_libproxy.mod)
64 {
65#define LOAD(x) \
66 if (!_libproxy.mod) { \
67 _libproxy.mod = eina_module_new(x); \
68 if (_libproxy.mod) { \
69 if (!eina_module_load(_libproxy.mod)) { \
70 eina_module_free(_libproxy.mod); \
71 _libproxy.mod = NULL; \
72 } \
73 } \
74 }
75#if defined(_WIN32) || defined(__CYGWIN__)
76 LOAD("libproxy-1.dll");
77 LOAD("libproxy.dll");
78#elif defined(__APPLE__) && defined(__MACH__)
79 LOAD("libproxy.1.dylib");
80 LOAD("libproxy.dylib");
81#else
82 LOAD("libproxy.so.1");
83 LOAD("libproxy.so");
84#endif
85#undef LOAD
86 if (!_libproxy.mod)
87 {
88 DBG("Couldn't find libproxy in your system. Continue without it");
89 return EINA_FALSE;
90 }
91
92#define SYM(x) \
93 if ((_libproxy.x = eina_module_symbol_get(_libproxy.mod, #x)) == NULL) { \
94 ERR("libproxy (%s) missing symbol %s", \
95 eina_module_file_get(_libproxy.mod), #x); \
96 eina_module_free(_libproxy.mod); \
97 _libproxy.mod = NULL; \
98 return EINA_FALSE; \
99 }
100
101 SYM(px_proxy_factory_new);
102 SYM(px_proxy_factory_free);
103 SYM(px_proxy_factory_get_proxies);
104#undef SYM
105 DBG("using libproxy=%s", eina_module_file_get(_libproxy.mod));
106 }
107
108 if (!_libproxy.factory)
109 _libproxy.factory = _libproxy.px_proxy_factory_new();
110
111 return !!_libproxy.factory;
112}
113
114static void
115shutdown(void)
116{
117 if (_libproxy.factory)
118 {
119 _libproxy.px_proxy_factory_free(_libproxy.factory);
120 _libproxy.factory = NULL;
121 }
122 if (_libproxy.mod)
123 {
124 eina_module_free(_libproxy.mod);
125 _libproxy.mod = NULL;
126 }
127}
128
129static void *
130proxy_lookup(void *data, Eina_Thread t)
131{
132 char *cmd = data;
133 char **proxies, **itr;
134 const char *p, *url;
135 int id = atoi(cmd + 2);
136 int pending_local, opcount_prev;
137
138 if (id > 0)
139 {
140 for (p = cmd + 2; *p && (*p != ' '); p++);
141 if (*p == ' ')
142 {
143 url = p + 1;
144 proxies = _libproxy.px_proxy_factory_get_proxies
145 (_libproxy.factory, url);
146 if (proxies)
147 {
148 for (itr = proxies; *itr != NULL; itr++)
149 {
150 fprintf(stdout, "P %i P %s\n", id, *itr);
151 free(*itr);
152 }
153 free(proxies);
154 }
155 fprintf(stdout, "P %i E\n", id);
156 fflush(stdout);
157 }
158 }
159 free(cmd);
160
161 eina_spinlock_take(&pending_lock);
162 {
163 pending--;
164 pending_local = pending;
165 opcount_prev = opcount;
166 }
167 eina_spinlock_release(&pending_lock);
168 // if there are no more pending threads doing work - sleep for the
169 // timeout then check if we still are and if so - exit;
170 if (pending_local == 0) sleep(10);
171 eina_spinlock_take(&pending_lock);
172 {
173 Eina_Thread *tt;
174
175 if ((pending == 0) & (opcount == opcount_prev)) exit(0);
176 tt = calloc(1, sizeof(Eina_Thread));
177 if (tt)
178 {
179 *tt = t;
180 join_list = eina_list_append(join_list, tt);
181 }
182 }
183 eina_spinlock_release(&pending_lock);
184 return NULL;
185}
186
187static void
188handle(const char *cmd)
189{
190 // "P 1234 URL" -> Get Proxy, id=1234, url=URL
191 if ((cmd[0] == 'P') && (cmd[1] == ' '))
192 {
193 char *dup = strdup(cmd);
194
195 if (dup)
196 {
197 Eina_Thread t;
198
199 eina_spinlock_take(&pending_lock);
200 {
201 pending++;
202 opcount++;
203 }
204 eina_spinlock_release(&pending_lock);
205 if (!eina_thread_create(&t, EINA_THREAD_BACKGROUND, -1,
206 proxy_lookup, dup))
207 {
208 abort();
209 }
210 }
211 return;
212 }
213}
214
215static void
216clean_threads(void)
217{
218 eina_spinlock_take(&pending_lock);
219 {
220 Eina_Thread *t;
221
222 EINA_LIST_FREE(join_list, t)
223 {
224 eina_thread_join(*t);
225 free(t);
226 }
227 }
228 eina_spinlock_release(&pending_lock);
229}
230
231int
232main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
233{
234 char inbuf[8192];
235 eina_init();
236 if (init())
237 {
238 eina_spinlock_new(&pending_lock);
239 // 1 command per stdin line
240 while (fgets(inbuf, sizeof(inbuf) - 1, stdin))
241 {
242 // strip off newline and ensure the string is 0 terminated
243 int len = strlen(inbuf);
244 if (len > 0)
245 {
246 if (inbuf[len -1 ] == '\n') inbuf[len - 1] = 0;
247 else inbuf[len] = 0;
248 handle(inbuf);
249 }
250 clean_threads();
251 }
252 eina_spinlock_free(&pending_lock);
253 shutdown();
254 }
255 else
256 {
257 // Failed to init libproxy so report this before exit
258 fprintf(stdout, "F\n");
259 fflush(stdout);
260 pause();
261 }
262 eina_shutdown();
263 return 0;
264}
diff --git a/src/lib/ecore_con/ecore_con.c b/src/lib/ecore_con/ecore_con.c
index 58e0805..dd641da 100644
--- a/src/lib/ecore_con/ecore_con.c
+++ b/src/lib/ecore_con/ecore_con.c
@@ -68,15 +68,11 @@ EWAPI Eina_Error EFL_NET_SOCKET_SSL_ERROR_CERTIFICATE_VERIFY_FAILED = 0;
68static int _ecore_con_init_count = 0; 68static int _ecore_con_init_count = 0;
69int _ecore_con_log_dom = -1; 69int _ecore_con_log_dom = -1;
70 70
71typedef struct pxProxyFactory_ pxProxyFactory; 71Eina_Bool _efl_net_proxy_helper_can_do (void);
72typedef struct _Ecore_Con_Libproxy { 72int _efl_net_proxy_helper_url_req_send(const char *url);
73 pxProxyFactory *factory; 73char **_efl_net_proxy_helper_url_wait (int id);
74 char **(*px_proxy_factory_get_proxies)(pxProxyFactory *factory, const char *url); 74void _efl_net_proxy_helper_init (void);
75 void *(*px_proxy_factory_new)(void); 75void _efl_net_proxy_helper_shutdown (void);
76 void (*px_proxy_factory_free)(pxProxyFactory *);
77 Eina_Module *mod;
78} Ecore_Con_Libproxy;
79static Ecore_Con_Libproxy _ecore_con_libproxy;
80 76
81EAPI int 77EAPI int
82ecore_con_init(void) 78ecore_con_init(void)
@@ -100,6 +96,8 @@ ecore_con_init(void)
100 goto ecore_con_log_error; 96 goto ecore_con_log_error;
101 } 97 }
102 98
99 _efl_net_proxy_helper_init();
100
103 ecore_con_mempool_init(); 101 ecore_con_mempool_init();
104 ecore_con_legacy_init(); 102 ecore_con_legacy_init();
105 103
@@ -145,16 +143,7 @@ ecore_con_shutdown(void)
145 if (--_ecore_con_init_count != 0) 143 if (--_ecore_con_init_count != 0)
146 return _ecore_con_init_count; 144 return _ecore_con_init_count;
147 145
148 if (_ecore_con_libproxy.factory) 146 _efl_net_proxy_helper_shutdown();
149 {
150 _ecore_con_libproxy.px_proxy_factory_free(_ecore_con_libproxy.factory);
151 _ecore_con_libproxy.factory = NULL;
152 }
153 if (_ecore_con_libproxy.mod)
154 {
155 eina_module_free(_ecore_con_libproxy.mod);
156 _ecore_con_libproxy.mod = NULL;
157 }
158 147
159 eina_log_timing(_ecore_con_log_dom, 148 eina_log_timing(_ecore_con_log_dom,
160 EINA_LOG_STATE_START, 149 EINA_LOG_STATE_START,
@@ -2079,12 +2068,8 @@ _efl_net_ip_connect_async_run(void *data, Ecore_Thread *thread EINA_UNUSED)
2079 2068
2080 proxy = d->proxy; 2069 proxy = d->proxy;
2081 2070
2082 if ((!proxy) && (_ecore_con_libproxy.factory)) 2071 if ((!proxy) && _efl_net_proxy_helper_can_do())
2083 { 2072 {
2084 /* libproxy is thread-safe but not cancellable. the provided
2085 * parameter must be a URL with schema, otherwise it won't
2086 * return anything.
2087 */
2088 Eina_Stringshare *url; 2073 Eina_Stringshare *url;
2089 2074
2090 url = eina_stringshare_printf("%s://%s:%s", d->protocol == IPPROTO_UDP ? "udp" : "tcp", host, port); 2075 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)
2608 return READBUFSIZ; 2593 return READBUFSIZ;
2609} 2594}
2610 2595
2611Eina_Bool
2612ecore_con_libproxy_init(void)
2613{
2614 if (!_ecore_con_libproxy.mod)
2615 {
2616#define LOAD(x) \
2617 if (!_ecore_con_libproxy.mod) { \
2618 _ecore_con_libproxy.mod = eina_module_new(x); \
2619 if (_ecore_con_libproxy.mod) { \
2620 if (!eina_module_load(_ecore_con_libproxy.mod)) { \
2621 eina_module_free(_ecore_con_libproxy.mod); \
2622 _ecore_con_libproxy.mod = NULL; \
2623 } \
2624 } \
2625 }
2626#if defined(_WIN32) || defined(__CYGWIN__)
2627 LOAD("libproxy-1.dll");
2628 LOAD("libproxy.dll");
2629#elif defined(__APPLE__) && defined(__MACH__)
2630 LOAD("libproxy.1.dylib");
2631 LOAD("libproxy.dylib");
2632#else
2633 LOAD("libproxy.so.1");
2634 LOAD("libproxy.so");
2635#endif
2636#undef LOAD
2637 if (!_ecore_con_libproxy.mod)
2638 {
2639 DBG("Couldn't find libproxy in your system. Continue without it");
2640 return EINA_FALSE;
2641 }
2642
2643#define SYM(x) \
2644 if ((_ecore_con_libproxy.x = eina_module_symbol_get(_ecore_con_libproxy.mod, #x)) == NULL) { \
2645 ERR("libproxy (%s) missing symbol %s", eina_module_file_get(_ecore_con_libproxy.mod), #x); \
2646 eina_module_free(_ecore_con_libproxy.mod); \
2647 _ecore_con_libproxy.mod = NULL; \
2648 return EINA_FALSE; \
2649 }
2650
2651 SYM(px_proxy_factory_new);
2652 SYM(px_proxy_factory_free);
2653 SYM(px_proxy_factory_get_proxies);
2654#undef SYM
2655 DBG("using libproxy=%s", eina_module_file_get(_ecore_con_libproxy.mod));
2656 }
2657
2658 if (!_ecore_con_libproxy.factory)
2659 _ecore_con_libproxy.factory = _ecore_con_libproxy.px_proxy_factory_new();
2660
2661 return !!_ecore_con_libproxy.factory;
2662}
2663
2664char ** 2596char **
2665ecore_con_libproxy_proxies_get(const char *url) 2597ecore_con_libproxy_proxies_get(const char *url)
2666{ 2598{
2667 EINA_SAFETY_ON_NULL_RETURN_VAL(_ecore_con_libproxy.px_proxy_factory_get_proxies, NULL); 2599 int id = _efl_net_proxy_helper_url_req_send(url);
2668 return _ecore_con_libproxy.px_proxy_factory_get_proxies(_ecore_con_libproxy.factory, url); 2600 if (id < 0) return NULL;
2601 return _efl_net_proxy_helper_url_wait(id);
2669} 2602}
2670 2603
2671void 2604void
diff --git a/src/lib/ecore_con/ecore_con_private.h b/src/lib/ecore_con/ecore_con_private.h
index bcc9dea..42f6ded 100644
--- a/src/lib/ecore_con/ecore_con_private.h
+++ b/src/lib/ecore_con/ecore_con_private.h
@@ -93,7 +93,6 @@ extern int sd_fd_max;
93#endif 93#endif
94 94
95/* init must be called from main thread */ 95/* init must be called from main thread */
96Eina_Bool ecore_con_libproxy_init(void);
97void ecore_con_libproxy_proxies_free(char **proxies); 96void ecore_con_libproxy_proxies_free(char **proxies);
98/* BLOCKING! should be called from a worker thread */ 97/* BLOCKING! should be called from a worker thread */
99char **ecore_con_libproxy_proxies_get(const char *url); 98char **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
index 0000000..eda91e9
--- /dev/null
+++ b/src/lib/ecore_con/ecore_con_proxy_helper.c
@@ -0,0 +1,427 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdio.h>
6#include <string.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <errno.h>
10#include <unistd.h>
11#include <fcntl.h>
12
13#ifdef HAVE_EVIL
14# include <Evil.h>
15#endif
16
17#include "Ecore.h"
18#include "ecore_private.h"
19#include "Ecore_Con.h"
20#include "ecore_con_private.h"
21
22typedef struct {
23 Eina_Thread_Queue *thq;
24 char *str;
25 char **proxies;
26 int id;
27 int busy;
28} Efl_Net_Proxy_Helper_Req;
29
30typedef struct {
31 Eina_Thread_Queue_Msg head;
32 char **proxies;
33} Efl_Net_Proxy_Helper_Thq_Msg;
34
35static Eina_Bool _efl_net_proxy_helper_works = EINA_TRUE;
36static Ecore_Exe *_efl_net_proxy_helper_exe = NULL;
37static Eina_Prefix *_efl_net_proxy_helper_prefix = NULL;
38static Eina_Spinlock _efl_net_proxy_helper_queue_lock;
39static int _efl_net_proxy_helper_req_id = 0;
40static Eina_List *_efl_net_proxy_helper_queue = NULL;
41static Ecore_Event_Handler *_efl_net_proxy_helper_handler_exe_del = NULL;
42static Ecore_Event_Handler *_efl_net_proxy_helper_handler_exe_data = NULL;
43static Eina_Bool _efl_net_proxy_helper_queue_lock_init = EINA_FALSE;
44static int _efl_net_proxy_helper_init_num = 0;
45
46static int locks = 0;
47
48#ifdef _WIN32
49# define HELPER_EXT ".exe"
50#else
51# define HELPER_EXT
52#endif
53
54static void
55_efl_net_proxy_helper_spawn(void)
56{
57 char buf[PATH_MAX];
58 Eina_List *l;
59 Efl_Net_Proxy_Helper_Req *req;
60 static int run_in_tree = -1;
61
62 if (!_efl_net_proxy_helper_works) return;
63 if (_efl_net_proxy_helper_exe) return;
64 if (run_in_tree == -1)
65 {
66 run_in_tree = 0;
67#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
68 if (getuid() == geteuid())
69#endif
70 {
71 if (getenv("EFL_RUN_IN_TREE")) run_in_tree = 1;
72 }
73 }
74 // find binary location path
75 if (run_in_tree == 1)
76 snprintf
77 (buf, sizeof(buf),
78 PACKAGE_BUILD_DIR"/src/bin/ecore_con/utils/efl_net_proxy_helper"HELPER_EXT);
79 else
80 snprintf
81 (buf, sizeof(buf),
82 "%s/ecore_con/utils/"MODULE_ARCH"/efl_net_proxy_helper"HELPER_EXT,
83 eina_prefix_lib_get(_efl_net_proxy_helper_prefix));
84 // run it with stdin/out piped line buffered with events
85 _efl_net_proxy_helper_exe = ecore_exe_pipe_run
86 (buf,
87 ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
88 ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_TERM_WITH_PARENT |
89 ECORE_EXE_NOT_LEADER, NULL);
90 // resend unhandled requests
91 eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
92 {
93 locks++;
94 EINA_LIST_FOREACH(_efl_net_proxy_helper_queue, l, req)
95 ecore_exe_send(_efl_net_proxy_helper_exe,
96 req->str, strlen(req->str));
97 locks--;
98 }
99 eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
100}
101
102static void
103_efl_net_proxy_helper_kill(void)
104{
105 if (!_efl_net_proxy_helper_exe) return;
106 // don't exit if anything is pending
107 if (_efl_net_proxy_helper_queue) return;
108 ecore_exe_kill(_efl_net_proxy_helper_exe);
109 ecore_exe_free(_efl_net_proxy_helper_exe);
110 _efl_net_proxy_helper_exe = NULL;
111}
112
113static void
114_efl_net_proxy_helper_cancel(void)
115{
116 eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
117 {
118 locks++;
119 Efl_Net_Proxy_Helper_Req *req;
120
121 EINA_LIST_FREE(_efl_net_proxy_helper_queue, req)
122 {
123 Efl_Net_Proxy_Helper_Thq_Msg *msg;
124 void *ref;
125
126 msg = eina_thread_queue_send
127 (req->thq, sizeof(Efl_Net_Proxy_Helper_Thq_Msg), &ref);
128 msg->proxies = NULL;
129 eina_thread_queue_send_done(req->thq, ref);
130 if (!req->busy)
131 {
132 free(req->str);
133 ecore_con_libproxy_proxies_free(req->proxies);
134 eina_thread_queue_free(req->thq);
135 free(req);
136 }
137 }
138 locks--;
139 }
140 eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
141}
142
143static void
144_efl_net_proxy_helper_proxy_add(int id, const char *url)
145{
146 Eina_List *l;
147 Efl_Net_Proxy_Helper_Req *req;
148
149 eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
150 {
151 locks++;
152 EINA_LIST_FOREACH(_efl_net_proxy_helper_queue, l, req)
153 {
154 if (req->id == id) break;
155 req = NULL;
156 }
157 if (req)
158 {
159 if (url)
160 {
161 char **proxies = req->proxies;
162 int n = 0;
163
164 if (proxies)
165 {
166 for (n = 0; proxies[n]; n++);
167 }
168 n++;
169 proxies = realloc(proxies, sizeof(char *) * (n + 1));
170 if (proxies)
171 {
172 req->proxies = proxies;
173 proxies[n - 1] = strdup(url);
174 proxies[n] = NULL;
175 }
176 }
177 else
178 {
179 Efl_Net_Proxy_Helper_Thq_Msg *msg;
180 void *ref;
181
182 msg = eina_thread_queue_send
183 (req->thq, sizeof(Efl_Net_Proxy_Helper_Thq_Msg), &ref);
184 msg->proxies = req->proxies;
185 req->proxies = NULL;
186 eina_thread_queue_send_done(req->thq, ref);
187 }
188 }
189 locks--;
190 }
191 eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
192}
193
194static Eina_Bool
195_efl_net_proxy_helper_cb_exe_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *info)
196{
197 Ecore_Exe_Event_Del *event = info;
198
199 if (!_efl_net_proxy_helper_exe) return EINA_TRUE;
200 if (event->exe == _efl_net_proxy_helper_exe)
201 {
202 static double last_respawn = 0.0;
203 double t;
204 Eina_Bool respawn = EINA_FALSE;
205
206 t = ecore_time_get();
207 _efl_net_proxy_helper_exe = NULL;
208 eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
209 {
210 locks++;
211 if (_efl_net_proxy_helper_queue)
212 {
213 if ((t - last_respawn) > 5.0) respawn = EINA_TRUE;
214 }
215 locks--;
216 }
217 eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
218 if (respawn)
219 {
220 last_respawn = t;
221 _efl_net_proxy_helper_spawn();
222 }
223 return EINA_FALSE;
224 }
225 return EINA_TRUE;
226}
227
228static Eina_Bool
229_efl_net_proxy_helper_cb_exe_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *info)
230{
231 Ecore_Exe_Event_Data *event = info;
232
233 if (!_efl_net_proxy_helper_exe) return EINA_TRUE;
234 if (event->exe == _efl_net_proxy_helper_exe)
235 {
236 if (event->lines)
237 {
238 int i;
239
240 for (i = 0; event->lines[i].line; i++)
241 {
242 char *line = event->lines[i].line;
243
244 if (line[0] == 'F') // failure
245 {
246 _efl_net_proxy_helper_works = EINA_FALSE;
247 _efl_net_proxy_helper_cancel();
248 _efl_net_proxy_helper_kill();
249 }
250 else if ((line[0] == 'P') && (line[1] == ' ')) // proxy
251 {
252 int id = atoi(line + 2);
253 char *p, *url = NULL;
254
255 for (p = line + 2; *p && (*p != ' '); p++);
256 if ((p[0] == ' ') && (p[1] == 'P') && (p[2] == ' '))
257 url = p + 3;
258 else if ((p[0] == ' ') && (p[1] == 'E'))
259 url = NULL;
260 _efl_net_proxy_helper_proxy_add(id, url);
261 }
262 }
263 }
264 return EINA_FALSE;
265 }
266 return EINA_TRUE;
267}
268
269Eina_Bool
270_efl_net_proxy_helper_can_do(void)
271{
272 return _efl_net_proxy_helper_works;
273}
274
275
276static void
277_efl_net_proxy_helper_cb_send_do(void *data)
278{
279 char *str = data;
280 if (!str) return;
281 // spawn exe if needed
282 if (!_efl_net_proxy_helper_exe) _efl_net_proxy_helper_spawn();
283 if (_efl_net_proxy_helper_exe)
284 ecore_exe_send(_efl_net_proxy_helper_exe, str, strlen(str));
285 free(str);
286}
287
288int
289_efl_net_proxy_helper_url_req_send(const char *url)
290{
291 char *buf;
292 int id = -1;
293 Efl_Net_Proxy_Helper_Req *req;
294
295 if (!_efl_net_proxy_helper_works) return -1;
296 eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
297 {
298 locks++;
299 // new id - just an int that eventually loops.
300 _efl_net_proxy_helper_req_id++;
301 if (_efl_net_proxy_helper_req_id >= ((1 << 30) - 1))
302 _efl_net_proxy_helper_req_id = 1;
303 id = _efl_net_proxy_helper_req_id;
304 locks--;
305 }
306 eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
307 // create request to quque up to look up responses for
308 req = calloc(1, sizeof(Efl_Net_Proxy_Helper_Req));
309 if (!req) return -1;
310 req->id = id;
311 req->thq = eina_thread_queue_new();
312 if (!req->thq)
313 {
314 free(req);
315 return -1;
316 }
317 buf = alloca(strlen(url) + 256);
318 sprintf(buf, "P %i %s\n", req->id, url);
319 req->str = strdup(buf);
320 if (!req->str)
321 {
322 eina_thread_queue_free(req->thq);
323 free(req);
324 return -1;
325 }
326 eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
327 {
328 locks++;
329 _efl_net_proxy_helper_queue =
330 eina_list_append(_efl_net_proxy_helper_queue, req);
331 locks--;
332 }
333 eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
334 // actually send the req now i'ts queued
335 ecore_main_loop_thread_safe_call_async
336 (_efl_net_proxy_helper_cb_send_do, strdup(buf));
337 return id;
338}
339
340char **
341_efl_net_proxy_helper_url_wait(int id)
342{
343 Eina_List *l;
344 Efl_Net_Proxy_Helper_Req *req;
345 Efl_Net_Proxy_Helper_Thq_Msg *msg;
346 void *ref;
347 char **ret = NULL;
348
349 if (id < 0) return NULL;
350 if (!_efl_net_proxy_helper_exe) return NULL;
351 eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
352 {
353 locks++;
354 EINA_LIST_FOREACH(_efl_net_proxy_helper_queue, l, req)
355 {
356 if (req->id == id) break;
357 req = NULL;
358 }
359 if (!req) goto end;
360 req->busy++;
361 locks--;
362 }
363 eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
364
365 msg = eina_thread_queue_wait(req->thq, &ref);
366 ret = msg->proxies;
367 msg->proxies = NULL;
368 eina_thread_queue_wait_done(req->thq, ref);
369
370 eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
371 {
372 locks++;
373 free(req->str);
374 ecore_con_libproxy_proxies_free(req->proxies);
375 eina_thread_queue_free(req->thq);
376 _efl_net_proxy_helper_queue =
377 eina_list_remove(_efl_net_proxy_helper_queue, req);
378 free(req);
379 }
380end:
381 locks--;
382 eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
383 return ret;
384}
385
386void
387_efl_net_proxy_helper_init(void)
388{
389 _efl_net_proxy_helper_init_num++;
390 if (_efl_net_proxy_helper_init_num > 1) return;
391 if (_efl_net_proxy_helper_prefix) return;
392 _efl_net_proxy_helper_prefix = eina_prefix_new
393 (NULL, ecore_con_init, "ECORE", "ecore", "checkme",
394 PACKAGE_BIN_DIR, PACKAGE_LIB_DIR, PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
395 if (!_efl_net_proxy_helper_queue_lock_init)
396 {
397 eina_spinlock_new(&_efl_net_proxy_helper_queue_lock);
398 _efl_net_proxy_helper_queue_lock_init = EINA_TRUE;
399 }
400 _efl_net_proxy_helper_handler_exe_del =
401 ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
402 _efl_net_proxy_helper_cb_exe_del, NULL);
403 _efl_net_proxy_helper_handler_exe_data =
404 ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
405 _efl_net_proxy_helper_cb_exe_data, NULL);
406}
407
408void
409_efl_net_proxy_helper_shutdown(void)
410{
411 _efl_net_proxy_helper_init_num--;
412 if (_efl_net_proxy_helper_init_num > 0) return;
413 if (!_efl_net_proxy_helper_prefix) return;
414 if (_efl_net_proxy_helper_exe)
415 {
416 _efl_net_proxy_helper_cancel();
417 _efl_net_proxy_helper_kill();
418 }
419 eina_spinlock_take(&_efl_net_proxy_helper_queue_lock);
420 eina_spinlock_release(&_efl_net_proxy_helper_queue_lock);
421 eina_prefix_free(_efl_net_proxy_helper_prefix);
422 _efl_net_proxy_helper_prefix = NULL;
423 ecore_event_handler_del(_efl_net_proxy_helper_handler_exe_del);
424 _efl_net_proxy_helper_handler_exe_del = NULL;
425 ecore_event_handler_del(_efl_net_proxy_helper_handler_exe_data);
426 _efl_net_proxy_helper_handler_exe_data = NULL;
427}
diff --git a/src/lib/ecore_con/efl_net_dialer_http.c b/src/lib/ecore_con/efl_net_dialer_http.c
index b4d39e4..b5fe3e4 100644
--- a/src/lib/ecore_con/efl_net_dialer_http.c
+++ b/src/lib/ecore_con/efl_net_dialer_http.c
@@ -1380,7 +1380,7 @@ _efl_net_dialer_http_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Http_Data *pd, co
1380#undef IS_HEADER 1380#undef IS_HEADER
1381 } 1381 }
1382 1382
1383 if ((!pd->proxy) && (ecore_con_libproxy_init())) 1383 if (!pd->proxy)
1384 { 1384 {
1385 Efl_Net_Dialer_Http_Libproxy_Context *ctx; 1385 Efl_Net_Dialer_Http_Libproxy_Context *ctx;
1386 1386