giant patch refactoring ecore-con-url from bluezery <opowel@gmail.com>

will it blend?!


SVN revision: 65888
This commit is contained in:
Mike Blumenkrantz 2011-12-05 06:08:46 +00:00
parent 32808c9760
commit 39467c29b6
2 changed files with 209 additions and 374 deletions

View File

@ -187,14 +187,8 @@ struct _Ecore_Con_Url
double timestamp;
void *data;
Ecore_Fd_Handler *fd_handler;
int fd;
int flags;
int received;
int write_fd;
Eina_Bool active : 1;
};
#endif

View File

@ -35,8 +35,6 @@ int ECORE_CON_EVENT_URL_COMPLETE = 0;
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,
@ -57,50 +55,17 @@ static size_t _ecore_con_url_read_cb(void *ptr,
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
/**
@ -113,51 +78,30 @@ EAPI int
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
@ -167,34 +111,31 @@ EAPI int
ecore_con_url_shutdown(void)
{
#ifdef HAVE_CURL
if (!_init_count)
return 0;
if (_init_count == 0) 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 (_curl_timeout)
ecore_timer_del(_curl_timeout);
_curl_timeout = NULL;
while (_url_con_list)
ecore_con_url_free(eina_list_data_get(_url_con_list));
if (_curlm)
if (--_init_count == 0)
{
curl_multi_cleanup(_curlm);
_curlm = NULL;
}
Ecore_Con_Url *con_url;
Ecore_Fd_Handler *fd_handler;
curl_global_cleanup();
if (_curl_timeout)
{
ecore_timer_del(_curl_timeout);
_curl_timeout = 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);
if (_curlm)
{
curl_multi_cleanup(_curlm);
_curlm = NULL;
}
curl_global_cleanup();
}
return _init_count;
#endif
return 1;
}
@ -237,7 +178,6 @@ ecore_con_url_new(const char *url)
if (!url_con)
return NULL;
url_con->fd = -1;
url_con->write_fd = -1;
url_con->curl_easy = curl_easy_init();
@ -344,31 +284,16 @@ ecore_con_url_free(Ecore_Con_Url *url_con)
}
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);
@ -415,8 +340,7 @@ ecore_con_url_url_set(Ecore_Con_Url *url_con,
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);
@ -668,8 +592,7 @@ _ecore_con_url_send(Ecore_Con_Url *url_con,
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;
@ -787,8 +710,7 @@ ecore_con_url_ftp_upload(Ecore_Con_Url *url_con,
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;
@ -1021,8 +943,7 @@ ecore_con_url_verbose_set(Ecore_Con_Url *url_con,
return;
}
if (url_con->active)
return;
if (eina_list_data_find(_url_con_list, url_con)) return;
if (!url_con->url)
return;
@ -1047,8 +968,7 @@ ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con,
return;
}
if (url_con->active)
return;
if (eina_list_data_find(_url_con_list, url_con)) return;
if (!url_con->url)
return;
@ -1085,8 +1005,7 @@ ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_con,
return;
}
if (url_con->active)
return;
if (eina_list_data_find(_url_con_list, url_con)) return;
if (!url_con->url)
return;
@ -1129,7 +1048,7 @@ ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con, const char *ca_path)
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);
@ -1154,54 +1073,6 @@ ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con, const char *ca_path)
*/
#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,
@ -1235,8 +1106,7 @@ _ecore_con_url_data_cb(void *buffer,
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
@ -1266,22 +1136,6 @@ _ecore_con_url_data_cb(void *buffer,
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,
@ -1324,8 +1178,7 @@ _ecore_con_url_progress_cb(void *clientp,
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;
@ -1358,208 +1211,196 @@ _ecore_con_url_read_cb(void *ptr,
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;
CURLMsg *curlmsg;
int n_remaining;
_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);
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 (FD_ISSET(fd, &exc_set))
flags |= ECORE_FD_ERROR;
if (flags)
if (curlmsg->easy_handle == url_con->curl_easy)
{
long ms = 0;
CURLMcode ret;
Ecore_Con_Event_Url_Complete *e;
ret = curl_multi_timeout(_curlm, &ms);
if (ret != CURLM_OK)
ERR("curl_multi_timeout failed: %s",
curl_multi_strerror(ret));
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 (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);
if (done)
{
_ecore_con_url_restart_fd_handler();
_fd_idler_handler = NULL;
if (!_url_con_list)
ecore_timer_freeze(_curl_timeout);
return data ==
(void *)0xACE ? ECORE_CALLBACK_RENEW : ECORE_CALLBACK_CANCEL;
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_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);
return ECORE_CALLBACK_RENEW;
}
static int
_ecore_con_url_process_completed_jobs(Ecore_Con_Url *url_con_to_match)
{
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;
/* Loop jobs and check if any are done */
while ((curlmsg = curl_multi_info_read(_curlm, &n_remaining)))
FD_ZERO(&_current_fd_set);
if (_fd_hd_list)
{
if (curlmsg->msg != CURLMSG_DONE)
continue;
/* find the job which is done */
EINA_LIST_FOREACH(_url_con_list, l, url_con)
Ecore_Fd_Handler *fd_handler;
EINA_LIST_FREE(_fd_hd_list, fd_handler)
{
if (curlmsg->easy_handle == url_con->curl_easy)
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);
}
}
EINA_LIST_FREE(_url_con_list, url_con)
{
CURLMcode ret;
Ecore_Con_Event_Url_Complete *e;
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));
}
}
static Eina_Bool
_ecore_con_url_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__)
{
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 void
_ecore_con_url_fdset(void)
{
CURLMcode ret;
fd_set read_set, write_set, exc_set;
int fd, fd_max;
Ecore_Fd_Handler *fd_handler;
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)
{
ERR("curl_multi_fdset failed: %s", curl_multi_strerror(ret));
return;
}
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 (!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);
url_con->fd = -1;
url_con->fd_handler = NULL;
}
_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 */
status = 0;
curl_easy_getinfo(curlmsg->easy_handle,
CURLINFO_RESPONSE_CODE,
&status);
e->status = status;
}
_url_complete_push_event(ECORE_CON_EVENT_URL_COMPLETE, e);
}
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));
break;
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);
}
}
}
}
return job_matched;
static Eina_Bool
_ecore_con_url_idler_handler(void *data __UNUSED__)
{
int still_running;
CURLMcode ret;
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;
}
_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);
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_ecore_con_url_perform(Ecore_Con_Url *url_con)
{
CURLMcode ret;
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;
}
_url_con_list = eina_list_append(_url_con_list, url_con);
ecore_timer_thaw(_curl_timeout);
return EINA_TRUE;
}
static void