int ECORE_CON_EVENT_URL_PROGRESS = 0;
#ifdef HAVE_CURL
-static Eina_Bool _ecore_con_url_fd_handler(void *data,
- Ecore_Fd_Handler *fd_handler);
static Eina_Bool _ecore_con_url_perform(Ecore_Con_Url *url_con);
static size_t _ecore_con_url_header_cb(void *ptr,
size_t size,
void *stream);
static void _ecore_con_event_url_free(void *data __UNUSED__,
void *ev);
-static int _ecore_con_url_process_completed_jobs(
- Ecore_Con_Url *url_con_to_match);
static Eina_Bool _ecore_con_url_idler_handler(void *data);
+static Eina_Bool _ecore_con_url_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__);
-static Ecore_Idler *_fd_idler_handler = NULL;
static Eina_List *_url_con_list = NULL;
+static Eina_List *_fd_hd_list = NULL;
static CURLM *_curlm = NULL;
static fd_set _current_fd_set;
static int _init_count = 0;
static Ecore_Timer *_curl_timeout = NULL;
static Eina_Bool pipelining = EINA_FALSE;
-typedef struct _Ecore_Con_Url_Event Ecore_Con_Url_Event;
-struct _Ecore_Con_Url_Event
-{
- int type;
- void *ev;
-};
-
-static Eina_Bool
-_url_complete_idler_cb(void *data)
-{
- Ecore_Con_Url_Event *lev;
-
- lev = data;
- ecore_event_add(lev->type, lev->ev, _ecore_con_event_url_free, NULL);
- free(lev);
-
- return ECORE_CALLBACK_CANCEL;
-}
-
-static void
-_url_complete_push_event(int type,
- void *ev)
-{
- Ecore_Con_Url_Event *lev;
-
- lev = malloc(sizeof(Ecore_Con_Url_Event));
- lev->type = type;
- lev->ev = ev;
-
- ecore_idler_add(_url_complete_idler_cb, lev);
-}
-
#endif
/**
ecore_con_url_init(void)
{
#ifdef HAVE_CURL
- _init_count++;
-
- if (_init_count > 1)
- return _init_count;
+ if (++_init_count > 1) return _init_count;
- if (!ECORE_CON_EVENT_URL_DATA)
- {
- ECORE_CON_EVENT_URL_DATA = ecore_event_type_new();
- ECORE_CON_EVENT_URL_COMPLETE = ecore_event_type_new();
- ECORE_CON_EVENT_URL_PROGRESS = ecore_event_type_new();
- }
+ if (!ECORE_CON_EVENT_URL_DATA) ECORE_CON_EVENT_URL_DATA = ecore_event_type_new();
+ if (!ECORE_CON_EVENT_URL_COMPLETE) ECORE_CON_EVENT_URL_COMPLETE = ecore_event_type_new();
+ if (!ECORE_CON_EVENT_URL_PROGRESS) ECORE_CON_EVENT_URL_PROGRESS = ecore_event_type_new();
if (!_curlm)
{
long ms;
- FD_ZERO(&_current_fd_set);
- if (curl_global_init(CURL_GLOBAL_ALL))
- {
- while (_url_con_list)
- ecore_con_url_free(eina_list_data_get(_url_con_list));
- return 0;
- }
+ // curl_global_init() is not thread safe!
+ if (curl_global_init(CURL_GLOBAL_ALL)) return --_init_count;
_curlm = curl_multi_init();
- if (!_curlm)
- {
- while (_url_con_list)
- ecore_con_url_free(eina_list_data_get(_url_con_list));
-
- _init_count--;
- return 0;
- }
+ if (!_curlm) return --_init_count;
curl_multi_timeout(_curlm, &ms);
- if (ms <= 0)
- ms = 1000;
+ if (ms <= 0) ms = 100;
- _curl_timeout =
- ecore_timer_add((double)ms / 1000, _ecore_con_url_idler_handler,
- (void *)0xACE);
+ _curl_timeout = ecore_timer_add((double)ms / 1000, _ecore_con_url_idler_handler, (void *)0xACE);
ecore_timer_freeze(_curl_timeout);
}
- return 1;
+ return _init_count;
#else
return 0;
#endif
ecore_con_url_shutdown(void)
{
#ifdef HAVE_CURL
- if (!_init_count)
- return 0;
-
- _init_count--;
-
- if (_init_count != 0)
- return _init_count;
-
- if (_fd_idler_handler)
- ecore_idler_del(_fd_idler_handler);
-
- _fd_idler_handler = NULL;
+ if (_init_count == 0) return 0;
- if (_curl_timeout)
- ecore_timer_del(_curl_timeout);
-
- _curl_timeout = NULL;
+ if (--_init_count == 0)
+ {
+ Ecore_Con_Url *con_url;
+ Ecore_Fd_Handler *fd_handler;
- while (_url_con_list)
- ecore_con_url_free(eina_list_data_get(_url_con_list));
+ if (_curl_timeout)
+ {
+ ecore_timer_del(_curl_timeout);
+ _curl_timeout = NULL;
+ }
- if (_curlm)
- {
- curl_multi_cleanup(_curlm);
- _curlm = NULL;
- }
+ FD_ZERO(&_current_fd_set);
+ EINA_LIST_FREE(_url_con_list, con_url) ecore_con_url_free(con_url);
+ EINA_LIST_FREE(_fd_hd_list, fd_handler) ecore_main_fd_handler_del(fd_handler);
- curl_global_cleanup();
+ if (_curlm)
+ {
+ curl_multi_cleanup(_curlm);
+ _curlm = NULL;
+ }
+ curl_global_cleanup();
+ }
+ return _init_count;
#endif
return 1;
}
if (!url_con)
return NULL;
- url_con->fd = -1;
url_con->write_fd = -1;
url_con->curl_easy = curl_easy_init();
}
ECORE_MAGIC_SET(url_con, ECORE_MAGIC_NONE);
- if(url_con->fd != -1)
- {
- FD_CLR(url_con->fd, &_current_fd_set);
- if (url_con->fd_handler)
- ecore_main_fd_handler_del(url_con->fd_handler);
-
- url_con->fd = -1;
- url_con->fd_handler = NULL;
- }
if (url_con->curl_easy)
{
- // FIXME: For an unknown reason, progress continue to arrive after destruction
- // this prevent any further call to the callback.
curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION, NULL);
curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_TRUE);
- if (url_con->active)
+ if (eina_list_data_find(_url_con_list, url_con))
{
- url_con->active = EINA_FALSE;
-
ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
- if (ret != CURLM_OK)
- ERR("curl_multi_remove_handle failed: %s",
- curl_multi_strerror(ret));
+ if (ret != CURLM_OK) ERR("curl_multi_remove_handle failed: %s", curl_multi_strerror(ret));
}
curl_easy_cleanup(url_con->curl_easy);
return EINA_FALSE;
}
- if (url_con->active)
- return EINA_FALSE;
+ if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
eina_stringshare_replace(&url_con->url, url);
return EINA_FALSE;
}
- if (url_con->active)
- return EINA_FALSE;
+ if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
if (!url_con->url)
return EINA_FALSE;
return EINA_FALSE;
}
- if (url_con->active)
- return EINA_FALSE;
+ if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
if (!url_con->url)
return EINA_FALSE;
return;
}
- if (url_con->active)
- return;
+ if (eina_list_data_find(_url_con_list, url_con)) return;
if (!url_con->url)
return;
return;
}
- if (url_con->active)
- return;
+ if (eina_list_data_find(_url_con_list, url_con)) return;
if (!url_con->url)
return;
return;
}
- if (url_con->active)
- return;
+ if (eina_list_data_find(_url_con_list, url_con)) return;
if (!url_con->url)
return;
return -1;
}
- if (url_con->active) return -1;
+ if (eina_list_data_find(_url_con_list, url_con)) return -1;
if (!url_con->url) return -1;
if (ca_path == NULL)
res = curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 0);
*/
#ifdef HAVE_CURL
-static int
-_ecore_con_url_suspend_fd_handler(void)
-{
- Eina_List *l;
- Ecore_Con_Url *url_con;
- int deleted = 0;
-
- if (!_url_con_list)
- return 0;
-
- EINA_LIST_FOREACH(_url_con_list, l, url_con)
- {
- if (url_con->active && url_con->fd_handler)
- {
- ecore_main_fd_handler_del(url_con->fd_handler);
- url_con->fd_handler = NULL;
- deleted++;
- }
- }
-
- return deleted;
-}
-
-static int
-_ecore_con_url_restart_fd_handler(void)
-{
- Eina_List *l;
- Ecore_Con_Url *url_con;
- int activated = 0;
-
- if (!_url_con_list)
- return 0;
-
- EINA_LIST_FOREACH(_url_con_list, l, url_con)
- {
- if (!url_con->fd_handler && url_con->fd != -1)
- {
- url_con->fd_handler =
- ecore_main_fd_handler_add(url_con->fd, url_con->flags,
- _ecore_con_url_fd_handler,
- NULL, NULL, NULL);
- activated++;
- }
- }
-
- return activated;
-}
-
static size_t
_ecore_con_url_data_cb(void *buffer,
size_t size,
e->url_con = url_con;
e->size = real_size;
memcpy(e->data, buffer, real_size);
- ecore_event_add(ECORE_CON_EVENT_URL_DATA, e,
- _ecore_con_event_url_free, NULL);
+ ecore_event_add(ECORE_CON_EVENT_URL_DATA, e, _ecore_con_event_url_free, NULL);
}
}
else
return real_size;
}
-#define ECORE_CON_URL_TRANSMISSION(Transmit, Event, Url_con, Total, Now) \
- { \
- Ecore_Con_Event_Url_Progress *e; \
- if ((Total != 0) || (Now != 0)) \
- { \
- e = calloc(1, sizeof(Ecore_Con_Event_Url_Progress)); \
- if (e) \
- { \
- e->url_con = url_con; \
- e->total = Total; \
- e->now = Now; \
- ecore_event_add(Event, e, _ecore_con_event_url_free, NULL); \
- } \
- } \
- }
-
static size_t
_ecore_con_url_header_cb(void *ptr,
size_t size,
e->down.now = dlnow;
e->up.total = ultotal;
e->up.now = ulnow;
- ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, e,
- _ecore_con_event_url_free, NULL);
+ ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, e, _ecore_con_event_url_free, NULL);
}
return 0;
return retcode;
}
-static Eina_Bool
-_ecore_con_url_perform(Ecore_Con_Url *url_con)
+static void
+_ecore_con_url_info_read(void)
{
- fd_set read_set, write_set, exc_set;
- int fd_max, fd;
- int flags, still_running;
- int completed_immediately = 0;
- CURLMcode ret;
-
- _url_con_list = eina_list_append(_url_con_list, url_con);
-
- url_con->active = EINA_TRUE;
- curl_multi_add_handle(_curlm, url_con->curl_easy);
- curl_multi_perform(_curlm, &still_running);
-
- completed_immediately = _ecore_con_url_process_completed_jobs(url_con);
+ CURLMsg *curlmsg;
+ int n_remaining;
- if (!completed_immediately)
+ while ((curlmsg = curl_multi_info_read(_curlm, &n_remaining)))
{
- if (url_con->fd_handler)
- ecore_main_fd_handler_del(url_con->fd_handler);
-
- url_con->fd_handler = NULL;
-
- /* url_con still active -- set up an fd_handler */
- FD_ZERO(&read_set);
- FD_ZERO(&write_set);
- FD_ZERO(&exc_set);
-
- /* Stupid curl, why can't I get the fd to the current added job? */
- ret = curl_multi_fdset(_curlm, &read_set, &write_set, &exc_set,
- &fd_max);
- if (ret != CURLM_OK)
+ if (curlmsg->msg == CURLMSG_DONE)
{
- ERR("curl_multi_fdset failed: %s", curl_multi_strerror(ret));
- return EINA_FALSE;
- }
+ Eina_List *l, *ll;
+ Ecore_Con_Url *url_con;
- for (fd = 0; fd <= fd_max; fd++)
- {
- if (!FD_ISSET(fd, &_current_fd_set))
+ EINA_LIST_FOREACH_SAFE(_url_con_list, l, ll, url_con)
{
- flags = 0;
- if (FD_ISSET(fd, &read_set))
- flags |= ECORE_FD_READ;
-
- if (FD_ISSET(fd, &write_set))
- flags |= ECORE_FD_WRITE;
+ if (curlmsg->easy_handle == url_con->curl_easy)
+ {
+ CURLMcode ret;
+ Ecore_Con_Event_Url_Complete *e;
- if (FD_ISSET(fd, &exc_set))
- flags |= ECORE_FD_ERROR;
+ e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete));
+ if (e)
+ {
+ e->url_con = url_con;
+ e->status = 0;
+ if (curlmsg->data.result == CURLE_OK)
+ {
+ long status; /* curl API uses long, not int */
+ status = 0;
+ curl_easy_getinfo(curlmsg->easy_handle, CURLINFO_RESPONSE_CODE, &status);
+ e->status = status;
+ }
+ ecore_event_add(ECORE_CON_EVENT_URL_COMPLETE, e, _ecore_con_event_url_free, NULL);
+ }
- if (flags)
- {
- long ms = 0;
-
- ret = curl_multi_timeout(_curlm, &ms);
- if (ret != CURLM_OK)
- ERR("curl_multi_timeout failed: %s",
- curl_multi_strerror(ret));
-
- if (ms == 0)
- ms = 1000;
-
- FD_SET(fd, &_current_fd_set);
- url_con->fd = fd;
- url_con->flags = flags;
- url_con->fd_handler =
- ecore_main_fd_handler_add(fd, flags,
- _ecore_con_url_fd_handler,
- NULL, NULL, NULL);
+ ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
+ if (ret != CURLM_OK) ERR("curl_multi_remove_handle failed: %s", curl_multi_strerror(ret));
+ _url_con_list = eina_list_remove(_url_con_list, url_con);
break;
}
}
}
- if (!url_con->fd_handler)
- {
- /* Failed to set up an fd_handler */
- ecore_timer_freeze(_curl_timeout);
-
- ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
- if (ret != CURLM_OK)
- ERR("curl_multi_remove_handle failed: %s",
- curl_multi_strerror(ret));
-
- url_con->active = EINA_FALSE;
- url_con->fd = -1;
- return EINA_FALSE;
- }
-
- ecore_timer_thaw(_curl_timeout);
}
-
- return EINA_TRUE;
}
-static Eina_Bool
-_ecore_con_url_idler_handler(void *data)
+static void
+_ecore_con_url_curl_clear(void)
{
- int done, still_running;
-
- done = (curl_multi_perform(_curlm, &still_running) != CURLM_CALL_MULTI_PERFORM);
-
- _ecore_con_url_process_completed_jobs(NULL);
+ Ecore_Con_Url *url_con;
- if (done)
+ FD_ZERO(&_current_fd_set);
+ if (_fd_hd_list)
{
- _ecore_con_url_restart_fd_handler();
- _fd_idler_handler = NULL;
+ Ecore_Fd_Handler *fd_handler;
+ EINA_LIST_FREE(_fd_hd_list, fd_handler)
+ {
+ int fd = ecore_main_fd_handler_fd_get(fd_handler);
+ FD_CLR(fd, &_current_fd_set);
+ // FIXME: ecore_main_fd_handler_del() sometimes give errors
+ // because curl do not make fd itself controlled by users, but it can be ignored.
+ ecore_main_fd_handler_del(fd_handler);
+ }
+ }
- if (!_url_con_list)
- ecore_timer_freeze(_curl_timeout);
+ EINA_LIST_FREE(_url_con_list, url_con)
+ {
+ CURLMcode ret;
+ Ecore_Con_Event_Url_Complete *e;
- return data ==
- (void *)0xACE ? ECORE_CALLBACK_RENEW : ECORE_CALLBACK_CANCEL;
+ e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete));
+ if (e)
+ {
+ e->url_con = url_con;
+ e->status = 0;
+ ecore_event_add(ECORE_CON_EVENT_URL_COMPLETE, e, _ecore_con_event_url_free, NULL);
+ }
+ ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
+ if (ret != CURLM_OK) ERR("curl_multi_remove_handle failed: %s", curl_multi_strerror(ret));
}
-
- return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
-_ecore_con_url_fd_handler(void *data __UNUSED__,
- Ecore_Fd_Handler *fd_handler __UNUSED__)
+_ecore_con_url_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__)
{
- _ecore_con_url_suspend_fd_handler();
-
- if (!_fd_idler_handler)
- _fd_idler_handler = ecore_idler_add(
- _ecore_con_url_idler_handler, NULL);
-
+ if (_fd_hd_list)
+ {
+ Ecore_Fd_Handler *fd_handler;
+ EINA_LIST_FREE(_fd_hd_list, fd_handler)
+ {
+ int fd = ecore_main_fd_handler_fd_get(fd_handler);
+ FD_CLR(fd, &_current_fd_set);
+ // FIXME: ecore_main_fd_handler_del() sometimes give errors
+ // because curl do not make fd itself controlled by users, but it can be ignored.
+ ecore_main_fd_handler_del(fd_handler);
+ }
+ }
+ ecore_timer_thaw(_curl_timeout);
return ECORE_CALLBACK_RENEW;
}
-static int
-_ecore_con_url_process_completed_jobs(Ecore_Con_Url *url_con_to_match)
+static void
+_ecore_con_url_fdset(void)
{
- Eina_List *l;
- Ecore_Con_Url *url_con;
- Ecore_Con_Event_Url_Complete *e;
- CURLMsg *curlmsg;
CURLMcode ret;
- int n_remaining;
- int job_matched = 0;
+ fd_set read_set, write_set, exc_set;
+ int fd, fd_max;
+ Ecore_Fd_Handler *fd_handler;
- /* Loop jobs and check if any are done */
- while ((curlmsg = curl_multi_info_read(_curlm, &n_remaining)))
+ FD_ZERO(&read_set);
+ FD_ZERO(&write_set);
+ FD_ZERO(&exc_set);
+
+ ret = curl_multi_fdset(_curlm, &read_set, &write_set, &exc_set, &fd_max);
+ if (ret != CURLM_OK)
{
- if (curlmsg->msg != CURLMSG_DONE)
- continue;
+ ERR("curl_multi_fdset failed: %s", curl_multi_strerror(ret));
+ return;
+ }
- /* find the job which is done */
- EINA_LIST_FOREACH(_url_con_list, l, url_con)
+ for (fd = 0; fd <= fd_max; fd++)
+ {
+ int flags = 0;
+ if (FD_ISSET(fd, &read_set)) flags |= ECORE_FD_READ;
+ if (FD_ISSET(fd, &write_set)) flags |= ECORE_FD_WRITE;
+ if (FD_ISSET(fd, &exc_set)) flags |= ECORE_FD_ERROR;
+ if (flags)
{
- if (curlmsg->easy_handle == url_con->curl_easy)
+ if (!FD_ISSET(fd, &_current_fd_set))
{
- if (url_con_to_match &&
- (url_con == url_con_to_match))
- job_matched = 1;
-
- if(url_con->fd != -1)
- {
- FD_CLR(url_con->fd, &_current_fd_set);
- if (url_con->fd_handler)
- ecore_main_fd_handler_del(
- url_con->fd_handler);
+ FD_SET(fd, &_current_fd_set);
+ fd_handler = ecore_main_fd_handler_add(fd, flags, _ecore_con_url_fd_handler, NULL, NULL, NULL);
+ if (fd_handler) _fd_hd_list = eina_list_append(_fd_hd_list, fd_handler);
+ ecore_timer_freeze(_curl_timeout);
+ }
+ }
+ }
+}
- url_con->fd = -1;
- url_con->fd_handler = NULL;
- }
+static Eina_Bool
+_ecore_con_url_idler_handler(void *data __UNUSED__)
+{
+ int still_running;
+ CURLMcode ret;
- _url_con_list = eina_list_remove(_url_con_list, url_con);
- url_con->active = EINA_FALSE;
- e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete));
- if (e)
- {
- e->url_con = url_con;
- e->status = 0;
- if (curlmsg->data.result == CURLE_OK)
- {
- long status; /* curl API uses long, not int */
+ ret = curl_multi_perform(_curlm, &still_running);
+ if (ret != CURLM_OK)
+ {
+ ERR("curl_multi_perform() failed: %s", curl_multi_strerror(ret));
+ _ecore_con_url_curl_clear();
+ ecore_timer_freeze(_curl_timeout);
+ return ECORE_CALLBACK_RENEW;
+ }
+ if (ret == CURLM_CALL_MULTI_PERFORM)
+ {
+ DBG("Call multiperform again");
+ return ECORE_CALLBACK_RENEW;
+ }
- status = 0;
- curl_easy_getinfo(curlmsg->easy_handle,
- CURLINFO_RESPONSE_CODE,
- &status);
- e->status = status;
- }
+ _ecore_con_url_info_read();
+ if (still_running)
+ {
+ DBG("multiperform is still_running");
+ _ecore_con_url_fdset();
+ }
+ else
+ {
+ DBG("multiperform ended");
+ _ecore_con_url_curl_clear();
+ ecore_timer_freeze(_curl_timeout);
+ }
- _url_complete_push_event(ECORE_CON_EVENT_URL_COMPLETE, e);
- }
+ return ECORE_CALLBACK_RENEW;
+}
- ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
- if (ret != CURLM_OK)
- ERR("curl_multi_remove_handle failed: %s",
- curl_multi_strerror(ret));
+static Eina_Bool
+_ecore_con_url_perform(Ecore_Con_Url *url_con)
+{
+ CURLMcode ret;
- break;
- }
- }
+ ret = curl_multi_add_handle(_curlm, url_con->curl_easy);
+ if (ret != CURLM_OK)
+ {
+ ERR("curl_multi_add_handle() failed: %s", curl_multi_strerror(ret));
+ return EINA_FALSE;
}
- return job_matched;
+ _url_con_list = eina_list_append(_url_con_list, url_con);
+ ecore_timer_thaw(_curl_timeout);
+
+ return EINA_TRUE;
}
static void