barbieri pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=b004b8a4f986f49e23c3314e7f59d4fb8f4fd524
commit b004b8a4f986f49e23c3314e7f59d4fb8f4fd524 Author: Gustavo Sverzut Barbieri <barbi...@profusion.mobi> Date: Mon Aug 29 23:35:31 2016 -0300 efl_net_dialer_http: keep fd directly. provide curl with CURLOPT_OPENSOCKETFUNCTION and keep the fd in our private data. This is required because on _efl_net_dialer_http_efl_io_writer_write() we may have no fdhandler. It happened to me while implementing the WebSocket that uses a bi-directional communication on top of HTTP and the server sent the whole message, CURL reads: recvfrom(7, "...", 16384, 0, NULL, NULL) = 86 recvfrom(7, "", 16384, 0, NULL, NULL) = 0 After the empty (second) recvfrom(), CURL will remove the fdhandler: DBG:ecore_con lib/ecore_con/efl_net_dialer_http.c:482 _efl_net_dialer_http_curlm_socket_manage() dialer=0x4000000040000005 fdhandler=(nil), fd=7, curl_easy=0x5561846ca8d0, flags=0x4 However I should be able to write to this socket, in my case I need to reply to a PING request with a PONG. --- src/lib/ecore_con/ecore_con_url_curl.h | 20 ++++++++++++++ src/lib/ecore_con/efl_net_dialer_http.c | 46 ++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/lib/ecore_con/ecore_con_url_curl.h b/src/lib/ecore_con/ecore_con_url_curl.h index ff9ad17..98d4a1e 100644 --- a/src/lib/ecore_con/ecore_con_url_curl.h +++ b/src/lib/ecore_con/ecore_con_url_curl.h @@ -40,6 +40,22 @@ typedef int curl_socket_t; #define curl_socket_typedef #endif /* curl_socket_typedef */ +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + #define CURL_POLL_NONE 0 #define CURL_POLL_IN 1 #define CURL_POLL_OUT 2 @@ -243,8 +259,12 @@ typedef enum CINIT(INFILESIZE_LARGE, OFF_T, 115), CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), CINIT(COOKIELIST, OBJECTPOINT, 135), + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), CINIT(USERNAME, OBJECTPOINT, 173), CINIT(PASSWORD, OBJECTPOINT, 174), + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), #define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA } CURLoption; diff --git a/src/lib/ecore_con/efl_net_dialer_http.c b/src/lib/ecore_con/efl_net_dialer_http.c index 68477ac..06c5743 100644 --- a/src/lib/ecore_con/efl_net_dialer_http.c +++ b/src/lib/ecore_con/efl_net_dialer_http.c @@ -200,6 +200,7 @@ typedef struct Efl_Net_Http_Authentication_Method method; Eina_Bool restricted; } authentication; + int fd; Eina_Error error; Efl_Net_Http_Version version; Efl_Net_Dialer_Http_Primary_Mode primary_mode; @@ -928,6 +929,37 @@ _efl_net_dialer_http_receive_header(const char *buffer, size_t count, size_t nit return len; } +static curl_socket_t +_efl_net_dialer_http_socket_open(void *data, curlsocktype purpose EINA_UNUSED, struct curl_sockaddr *addr) +{ + Eo *o = data; + Efl_Net_Dialer_Http_Data *pd = efl_data_scope_get(o, MY_CLASS); + + pd->fd = socket(addr->family, addr->socktype, addr->protocol); + if (pd->fd < 0) + ERR("could not create curl socket family=%d, type=%d, protocol=%d", + addr->family, addr->socktype, addr->protocol); + else + DBG("socket(%d, %d, %d) = %d", + addr->family, addr->socktype, addr->protocol, pd->fd); + + return pd->fd; +} + +static void +_efl_net_dialer_http_socket_close(void *data, curl_socket_t fd) +{ + Eo *o = data; + Efl_Net_Dialer_Http_Data *pd = efl_data_scope_get(o, MY_CLASS); + + EINA_SAFETY_ON_TRUE_RETURN(pd->fd != fd); + + DBG("close(%d)", fd); + + close(fd); + pd->fd = -1; +} + EOLIAN static Efl_Object * _efl_net_dialer_http_efl_object_constructor(Eo *o, Efl_Net_Dialer_Http_Data *pd) { @@ -961,6 +993,12 @@ _efl_net_dialer_http_efl_object_constructor(Eo *o, Efl_Net_Dialer_Http_Data *pd) curl_easy_setopt(pd->easy, CURLOPT_READFUNCTION, _efl_net_dialer_http_send_data); curl_easy_setopt(pd->easy, CURLOPT_READDATA, o); + curl_easy_setopt(pd->easy, CURLOPT_OPENSOCKETFUNCTION, _efl_net_dialer_http_socket_open); + curl_easy_setopt(pd->easy, CURLOPT_OPENSOCKETDATA, o); + + curl_easy_setopt(pd->easy, CURLOPT_CLOSESOCKETFUNCTION, _efl_net_dialer_http_socket_close); + curl_easy_setopt(pd->easy, CURLOPT_CLOSESOCKETDATA, o); + curl_easy_setopt(pd->easy, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(pd->easy, CURLOPT_VERBOSE, (long)(eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG))); @@ -1256,14 +1294,13 @@ _efl_net_dialer_http_efl_io_writer_write(Eo *o, Efl_Net_Dialer_Http_Data *pd, Ei pd->error = 0; rm = curl_multi_socket_action(pd->cm->multi, - ecore_main_fd_handler_fd_get(pd->fdhandler), + pd->fd, CURL_CSELECT_OUT, &pd->cm->running); if (rm != CURLM_OK) { err = _curlcode_to_eina_error(rm); - ERR("dialer=%p could not trigger socket=%d action: %s", - o, ecore_main_fd_handler_fd_get(pd->fdhandler), - eina_error_msg_get(err)); + ERR("dialer=%p could not trigger socket=%d (fdhandler=%p) action: %s", + o, pd->fd, pd->fdhandler, eina_error_msg_get(err)); goto error; } _efl_net_dialer_http_curlm_check(pd->cm); @@ -1315,6 +1352,7 @@ _efl_net_dialer_http_efl_io_closer_close(Eo *o, Efl_Net_Dialer_Http_Data *pd) if (pd->cm) { + DBG("close dialer=%p, cm=%p, easy=%p", o, pd->cm, pd->easy); _efl_net_dialer_http_curlm_remove(pd->cm, o, pd->easy); pd->cm = NULL; } --