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.
This commit is contained in:
Gustavo Sverzut Barbieri 2016-08-29 23:35:31 -03:00
parent f1c691d0f5
commit b004b8a4f9
2 changed files with 62 additions and 4 deletions

View File

@ -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;

View File

@ -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;
}