efl_net_dialer_tcp: make asynchronous resolve and connect.

both resolve (getaddrinfo()) and connect() are now done in
Ecore_Thread, avoid to block the main loop.

My plan is to always use the threaded connect() using a blocking
socket, only set it to non-blocking after the socket is returned to
the main thread and before it's accessible to the user. It will make
the connect behavior more uniform.

Some errors were moved from HTTP to Dialer as they are more generic.
This commit is contained in:
Gustavo Sverzut Barbieri 2016-09-09 20:09:51 -03:00
parent 45ce4c8008
commit cb8695e9d6
8 changed files with 501 additions and 91 deletions

View File

@ -16,6 +16,12 @@
#include "efl_net_server_tcp.eo.h"
#include "efl_net_http_types.eot.h"
/* TODO: should be generated from 'var Efl.Net.Dialer.Error.*' */
extern Eina_Error EFL_NET_DIALER_ERROR_COULDNT_CONNECT;
extern Eina_Error EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_PROXY;
extern Eina_Error EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_HOST;
/* TODO: should be generated from 'var Efl.Net.Http.Error.*' */
extern Eina_Error EFL_NET_HTTP_ERROR_BAD_CONTENT_ENCODING;
extern Eina_Error EFL_NET_HTTP_ERROR_BAD_DOWNLOAD_RESUME;
@ -23,9 +29,6 @@ extern Eina_Error EFL_NET_HTTP_ERROR_BAD_FUNCTION_ARGUMENT;
extern Eina_Error EFL_NET_HTTP_ERROR_CHUNK_FAILED;
extern Eina_Error EFL_NET_HTTP_ERROR_CONV_FAILED;
extern Eina_Error EFL_NET_HTTP_ERROR_CONV_REQD;
extern Eina_Error EFL_NET_HTTP_ERROR_COULDNT_CONNECT;
extern Eina_Error EFL_NET_HTTP_ERROR_COULDNT_RESOLVE_HOST;
extern Eina_Error EFL_NET_HTTP_ERROR_COULDNT_RESOLVE_PROXY;
extern Eina_Error EFL_NET_HTTP_ERROR_FAILED_INIT;
extern Eina_Error EFL_NET_HTTP_ERROR_FILE_COULDNT_READ_FILE;
extern Eina_Error EFL_NET_HTTP_ERROR_FILESIZE_EXCEEDED;

View File

@ -175,6 +175,10 @@ EAPI int ECORE_CON_EVENT_CLIENT_ERROR = 0;
EAPI int ECORE_CON_EVENT_SERVER_ERROR = 0;
EAPI int ECORE_CON_EVENT_PROXY_BIND = 0;
EAPI Eina_Error EFL_NET_DIALER_ERROR_COULDNT_CONNECT = 0;
EAPI Eina_Error EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_PROXY = 0;
EAPI Eina_Error EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_HOST = 0;
static Eina_List *servers = NULL;
static int _ecore_con_init_count = 0;
static int _ecore_con_event_count = 0;
@ -215,6 +219,10 @@ ecore_con_init(void)
ECORE_CON_EVENT_SERVER_ERROR = ecore_event_type_new();
ECORE_CON_EVENT_PROXY_BIND = ecore_event_type_new();
EFL_NET_DIALER_ERROR_COULDNT_CONNECT = eina_error_msg_static_register("Couldn't connect to server");
EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_PROXY = eina_error_msg_static_register("Couldn't resolve proxy name");
EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_HOST = eina_error_msg_static_register("Couldn't resolve host name");
eina_magic_string_set(ECORE_MAGIC_CON_SERVER, "Ecore_Con_Server");
eina_magic_string_set(ECORE_MAGIC_CON_CLIENT, "Ecore_Con_Client");
eina_magic_string_set(ECORE_MAGIC_CON_URL, "Ecore_Con_Url");
@ -3037,6 +3045,46 @@ efl_net_ip_port_fmt(char *buf, int buflen, const struct sockaddr *addr)
return EINA_TRUE;
}
Eina_Bool
efl_net_ip_port_split(char *buf, const char **p_host, const char **p_port)
{
char *host, *port;
EINA_SAFETY_ON_NULL_RETURN_VAL(buf, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(p_host, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(p_port, EINA_FALSE);
host = buf;
if (host[0] == '[')
{
/* IPv6 is: [IP]:port */
host++;
port = strchr(host, ']');
if (!port) return EINA_FALSE;
*port = '\0';
port++;
if (port[0] == ':')
port++;
else
port = NULL;
}
else
{
port = strchr(host, ':');
if (port)
{
*port = '\0';
port++;
}
}
*p_host = host;
*p_port = port;
return EINA_TRUE;
}
int
efl_net_socket4(int domain, int type, int protocol, Eina_Bool close_on_exec)
{
@ -3065,3 +3113,217 @@ efl_net_socket4(int domain, int type, int protocol, Eina_Bool close_on_exec)
return fd;
}
typedef struct _Efl_Net_Resolve_Async_Data
{
Efl_Net_Resolve_Async_Cb cb;
const void *data;
char *host;
char *port;
struct addrinfo *result;
struct addrinfo *hints;
int gai_error;
} Efl_Net_Resolve_Async_Data;
static void
_efl_net_resolve_async_run(void *data, Ecore_Thread *thread)
{
Efl_Net_Resolve_Async_Data *d = data;
while (!ecore_thread_check(thread))
{
DBG("resolving host='%s' port='%s'", d->host, d->port);
d->gai_error = getaddrinfo(d->host, d->port, d->hints, &d->result);
if (d->gai_error == 0) break;
if (d->gai_error == EAI_AGAIN) continue;
DBG("getaddrinfo(\"%s\", \"%s\") failed: %s", d->host, d->port, gai_strerror(d->gai_error));
break;
}
if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG))
{
char buf[INET6_ADDRSTRLEN + sizeof("[]:65536")] = "";
const struct addrinfo *addrinfo;
for (addrinfo = d->result; addrinfo != NULL; addrinfo = addrinfo->ai_next)
{
if (efl_net_ip_port_fmt(buf, sizeof(buf), addrinfo->ai_addr))
DBG("resolved host='%s' port='%s': %s", d->host, d->port, buf);
}
}
}
static void
_efl_net_resolve_async_data_free(Efl_Net_Resolve_Async_Data *d)
{
free(d->hints);
free(d->host);
free(d->port);
free(d);
}
static void
_efl_net_resolve_async_end(void *data, Ecore_Thread *thread EINA_UNUSED)
{
Efl_Net_Resolve_Async_Data *d = data;
d->cb((void *)d->data, d->host, d->port, d->hints, d->result, d->gai_error);
_efl_net_resolve_async_data_free(d);
}
static void
_efl_net_resolve_async_cancel(void *data, Ecore_Thread *thread EINA_UNUSED)
{
Efl_Net_Resolve_Async_Data *d = data;
if (d->result) freeaddrinfo(d->result);
_efl_net_resolve_async_data_free(d);
}
Ecore_Thread *
efl_net_resolve_async_new(const char *host, const char *port, const struct addrinfo *hints, Efl_Net_Resolve_Async_Cb cb, const void *data)
{
Efl_Net_Resolve_Async_Data *d;
EINA_SAFETY_ON_NULL_RETURN_VAL(host, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(port, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
d = malloc(sizeof(Efl_Net_Resolve_Async_Data));
EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
d->cb = cb;
d->data = data;
d->host = strdup(host);
EINA_SAFETY_ON_NULL_GOTO(d->host, failed_host);
d->port = strdup(port);
EINA_SAFETY_ON_NULL_GOTO(d->port, failed_port);
if (!hints) d->hints = NULL;
else
{
d->hints = malloc(sizeof(struct addrinfo));
EINA_SAFETY_ON_NULL_GOTO(d->hints, failed_hints);
memcpy(d->hints, hints, sizeof(struct addrinfo));
}
d->result = NULL;
return ecore_thread_run(_efl_net_resolve_async_run,
_efl_net_resolve_async_end,
_efl_net_resolve_async_cancel,
d);
failed_hints:
free(d->port);
failed_port:
free(d->host);
failed_host:
free(d);
return NULL;
}
typedef struct _Efl_Net_Connect_Async_Data
{
Efl_Net_Connect_Async_Cb cb;
const void *data;
socklen_t addrlen;
Eina_Bool close_on_exec;
int type;
int protocol;
int sockfd;
Eina_Error error;
struct sockaddr addr[];
} Efl_Net_Connect_Async_Data;
static void
_efl_net_connect_async_run(void *data, Ecore_Thread *thread)
{
Efl_Net_Connect_Async_Data *d = data;
char buf[INET6_ADDRSTRLEN + sizeof("[]:65536")] = "";
int r;
d->error = 0;
d->sockfd = efl_net_socket4(d->addr->sa_family, d->type, d->protocol, d->close_on_exec);
if (d->sockfd < 0)
{
d->error = errno;
DBG("socket(%d, %d, %d) failed: %s", d->addr->sa_family, d->type, d->protocol, strerror(errno));
return;
}
if (ecore_thread_check(thread))
{
d->error = ECANCELED;
close(d->sockfd);
d->sockfd = -1;
return;
}
if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG))
efl_net_ip_port_fmt(buf, sizeof(buf), d->addr);
DBG("connecting fd=%d to %s", d->sockfd, buf);
r = connect(d->sockfd, d->addr, d->addrlen);
if (r < 0)
{
d->error = errno;
close(d->sockfd);
d->sockfd = -1;
DBG("connect(%d, %s) failed: %s", d->sockfd, buf, strerror(errno));
return;
}
DBG("connected fd=%d to %s", d->sockfd, buf);
}
static void
_efl_net_connect_async_data_free(Efl_Net_Connect_Async_Data *d)
{
free(d);
}
static void
_efl_net_connect_async_end(void *data, Ecore_Thread *thread EINA_UNUSED)
{
Efl_Net_Connect_Async_Data *d = data;
d->cb((void *)d->data, d->addr, d->addrlen, d->sockfd, d->error);
_efl_net_connect_async_data_free(d);
}
static void
_efl_net_connect_async_cancel(void *data, Ecore_Thread *thread EINA_UNUSED)
{
Efl_Net_Connect_Async_Data *d = data;
if (d->sockfd >= 0) close(d->sockfd);
_efl_net_connect_async_data_free(d);
}
Ecore_Thread *
efl_net_connect_async_new(const struct sockaddr *addr, socklen_t addrlen, int type, int protocol, Eina_Bool close_on_exec, Efl_Net_Connect_Async_Cb cb, const void *data)
{
Efl_Net_Connect_Async_Data *d;
EINA_SAFETY_ON_NULL_RETURN_VAL(addr, NULL);
EINA_SAFETY_ON_TRUE_RETURN_VAL(addrlen < 1, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
d = malloc(sizeof(Efl_Net_Connect_Async_Data) + addrlen);
EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
d->cb = cb;
d->data = data;
d->addrlen = addrlen;
d->close_on_exec = close_on_exec;
d->type = type;
d->protocol = protocol;
memcpy(d->addr, addr, addrlen);
d->sockfd = -1;
d->error = 0;
return ecore_thread_run(_efl_net_connect_async_run,
_efl_net_connect_async_end,
_efl_net_connect_async_cancel,
d);
}

View File

@ -375,8 +375,70 @@ void ecore_con_mempool_shutdown(void);
Eina_Bool efl_net_ip_port_fmt(char *buf, int buflen, const struct sockaddr *addr);
/**
* @brief splits an address in the format "host:port" in two
* null-terminated strings.
*
* The address may be 'server.com:1234', 'server.com:http',
* 'server.com' (@c *p_port will be NULL), IPv4 127.0.0.1:456 or
* IPv6 [::1]:456
*
* @param[inout] buf contains the string to be split and will be modified.
* @param[out] p_host returns a pointer inside @a buf with
* null-terminated host part.
* @param[out] p_port returns a pointer with null-terminated port
* part. The pointer may be inside @a buf if port was
* specified or #NULL if it wasn't specified.
*
* @return #EINA_TRUE on success, #EINA_FALSE on errors.
*
* @internal
*/
Eina_Bool efl_net_ip_port_split(char *buf, const char **p_host, const char **p_port);
int efl_net_socket4(int domain, int type, int protocol, Eina_Bool close_on_exec);
/**
* @brief callback to notify of resolved address.
*
* The callback is given the ownership of the result, thus must free
* it with freeaddrinfo().
*
* @internal
*/
typedef void (*Efl_Net_Resolve_Async_Cb)(void *data, const char *host, const char *port, const struct addrinfo *hints, struct addrinfo *result, int gai_error);
/**
* @brief asynchronously resolve a host and port using getaddrinfo().
*
* This will call getaddrinfo() in a thread, taking care to return the
* result to the main loop and calling @a cb with given user @a data.
*
* @internal
*/
Ecore_Thread *efl_net_resolve_async_new(const char *host, const char *port, const struct addrinfo *hints, Efl_Net_Resolve_Async_Cb cb, const void *data);
/**
* @brief callback to notify of connection.
*
* The callback is given the ownership of the socket (sockfd), thus
* must close().
*
* @internal
*/
typedef void (*Efl_Net_Connect_Async_Cb)(void *data, const struct sockaddr *addr, socklen_t addrlen, int sockfd, Eina_Error error);
/**
* @brief asynchronously create a socket and connect to the address.
*
* This will call socket() and connect() in a thread, taking care to
* return the result to the main loop and calling @a cb with given
* user @a data.
*
* @internal
*/
Ecore_Thread *efl_net_connect_async_new(const struct sockaddr *addr, socklen_t addrlen, int type, int protocol, Eina_Bool close_on_exec, Efl_Net_Connect_Async_Cb cb, const void *data);
static inline Eina_Error
efl_net_socket_error_get(void)
{

View File

@ -32,9 +32,6 @@ EAPI Eina_Error EFL_NET_HTTP_ERROR_BAD_FUNCTION_ARGUMENT = 0;
EAPI Eina_Error EFL_NET_HTTP_ERROR_CHUNK_FAILED = 0;
EAPI Eina_Error EFL_NET_HTTP_ERROR_CONV_FAILED = 0;
EAPI Eina_Error EFL_NET_HTTP_ERROR_CONV_REQD = 0;
EAPI Eina_Error EFL_NET_HTTP_ERROR_COULDNT_CONNECT = 0;
EAPI Eina_Error EFL_NET_HTTP_ERROR_COULDNT_RESOLVE_HOST = 0;
EAPI Eina_Error EFL_NET_HTTP_ERROR_COULDNT_RESOLVE_PROXY = 0;
EAPI Eina_Error EFL_NET_HTTP_ERROR_FAILED_INIT = 0;
EAPI Eina_Error EFL_NET_HTTP_ERROR_FILE_COULDNT_READ_FILE = 0;
EAPI Eina_Error EFL_NET_HTTP_ERROR_FILESIZE_EXCEEDED = 0;
@ -90,6 +87,10 @@ _curlcode_to_eina_error(const CURLcode code)
case CURLE_AGAIN: return EAGAIN;
case CURLE_OUT_OF_MEMORY: return ENOMEM;
case CURLE_COULDNT_CONNECT: return EFL_NET_DIALER_ERROR_COULDNT_CONNECT;
case CURLE_COULDNT_RESOLVE_PROXY: return EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_PROXY;
case CURLE_COULDNT_RESOLVE_HOST: return EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_HOST;
#define _MAP(n) case CURLE_ ## n: return EFL_NET_HTTP_ERROR_ ## n
_MAP(BAD_CONTENT_ENCODING);
@ -98,9 +99,6 @@ _curlcode_to_eina_error(const CURLcode code)
_MAP(CHUNK_FAILED);
_MAP(CONV_FAILED);
_MAP(CONV_REQD);
_MAP(COULDNT_CONNECT);
_MAP(COULDNT_RESOLVE_HOST);
_MAP(COULDNT_RESOLVE_PROXY);
_MAP(FAILED_INIT);
_MAP(FILE_COULDNT_READ_FILE);
_MAP(FILESIZE_EXCEEDED);
@ -192,9 +190,6 @@ _c_init_errors(void)
_MAP(CHUNK_FAILED);
_MAP(CONV_FAILED);
_MAP(CONV_REQD);
_MAP(COULDNT_CONNECT);
_MAP(COULDNT_RESOLVE_HOST);
_MAP(COULDNT_RESOLVE_PROXY);
_MAP(FAILED_INIT);
_MAP(FILE_COULDNT_READ_FILE);
_MAP(FILESIZE_EXCEEDED);

View File

@ -1,3 +1,7 @@
var @extern Efl.Net.Dialer.Error.COULDNT_CONNECT: Eina.Error;
var @extern Efl.Net.Dialer.Error.COULDNT_RESOLVE_PROXY: Eina.Error;
var @extern Efl.Net.Dialer.Error.COULDNT_RESOLVE_HOST: Eina.Error;
interface Efl.Net.Dialer (Efl.Net.Socket) {
[[Creates a client socket to reach a remote peer.

View File

@ -31,117 +31,203 @@
typedef struct _Efl_Net_Dialer_Tcp_Data
{
struct {
Ecore_Thread *thread;
struct addrinfo *names;
struct addrinfo *current;
} resolve;
struct {
Ecore_Thread *thread;
} connect;
Eina_Stringshare *address_dial;
Eina_Stringshare *proxy;
Eina_Bool connected;
Eina_Bool closed;
double timeout_dial;
} Efl_Net_Dialer_Tcp_Data;
EOLIAN static void
_efl_net_dialer_tcp_efl_object_destructor(Eo *o, Efl_Net_Dialer_Tcp_Data *pd)
{
if (pd->connect.thread)
{
ecore_thread_cancel(pd->connect.thread);
pd->connect.thread = NULL;
}
if (pd->resolve.thread)
{
ecore_thread_cancel(pd->resolve.thread);
pd->resolve.thread = NULL;
}
pd->resolve.current = NULL;
if (pd->resolve.names)
{
freeaddrinfo(pd->resolve.names);
pd->resolve.names = NULL;
}
efl_destructor(efl_super(o, MY_CLASS));
eina_stringshare_replace(&pd->address_dial, NULL);
eina_stringshare_replace(&pd->proxy, NULL);
}
static void
_efl_net_dialer_tcp_connected(void *data, const struct sockaddr *addr EINA_UNUSED, socklen_t addrlen EINA_UNUSED, int fd, Eina_Error err)
{
Eo *o = data;
Efl_Net_Dialer_Tcp_Data *pd = efl_data_scope_get(o, MY_CLASS);
const struct addrinfo *addrinfo;
pd->connect.thread = NULL;
if (!err)
{
freeaddrinfo(pd->resolve.names);
pd->resolve.names = NULL;
pd->resolve.current = NULL;
efl_loop_fd_set(o, fd);
efl_net_dialer_connected_set(o, EINA_TRUE);
return;
}
if (!pd->resolve.current) return;
pd->resolve.current = pd->resolve.current->ai_next;
if (!pd->resolve.current)
{
freeaddrinfo(pd->resolve.names);
pd->resolve.names = NULL;
if (err)
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_ERROR, &err);
else
{
err = EFL_NET_DIALER_ERROR_COULDNT_CONNECT;
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_ERROR, &err);
}
return;
}
addrinfo = pd->resolve.current;
pd->connect.thread = efl_net_connect_async_new(addrinfo->ai_addr,
addrinfo->ai_addrlen,
SOCK_STREAM,
IPPROTO_TCP,
efl_net_socket_fd_close_on_exec_get(o),
_efl_net_dialer_tcp_connected,
o);
}
static void
_efl_net_dialer_tcp_connect(Eo *o, Efl_Net_Dialer_Tcp_Data *pd)
{
char buf[INET6_ADDRSTRLEN + sizeof("[]:65536")];
const struct addrinfo *addrinfo;
if (pd->closed || !pd->resolve.current) return;
efl_ref(o); /* we're emitting callbacks then continuing the workflow */
addrinfo = pd->resolve.current;
efl_net_socket_fd_family_set(o, addrinfo->ai_family);
if (efl_net_ip_port_fmt(buf, sizeof(buf), addrinfo->ai_addr))
{
efl_net_socket_address_remote_set(o, buf);
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_RESOLVED, NULL);
}
if (pd->closed) goto end; /* maybe closed from resolved event callback */
if (pd->connect.thread)
ecore_thread_cancel(pd->connect.thread);
pd->connect.thread = efl_net_connect_async_new(addrinfo->ai_addr,
addrinfo->ai_addrlen,
SOCK_STREAM,
IPPROTO_TCP,
efl_net_socket_fd_close_on_exec_get(o),
_efl_net_dialer_tcp_connected,
o);
end:
efl_unref(o);
}
static void
_efl_net_dialer_tcp_resolved(void *data, const char *host EINA_UNUSED, const char *port EINA_UNUSED, const struct addrinfo *hints EINA_UNUSED, struct addrinfo *result, int gai_error)
{
Eo *o = data;
Efl_Net_Dialer_Tcp_Data *pd = efl_data_scope_get(o, MY_CLASS);
pd->resolve.thread = NULL;
if (gai_error)
{
Eina_Error err = EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_HOST;
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_ERROR, &err);
if (result) freeaddrinfo(result);
return;
}
if (pd->resolve.names) freeaddrinfo(pd->resolve.names);
pd->resolve.names = result;
pd->resolve.current = result;
_efl_net_dialer_tcp_connect(o, pd);
}
EOLIAN static Eina_Error
_efl_net_dialer_tcp_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Tcp_Data *pd EINA_UNUSED, const char *address)
{
struct sockaddr_storage addr = {};
char *str, *host, *port;
int r, fd;
socklen_t addrlen;
char buf[INET6_ADDRSTRLEN + sizeof("[]:65536")];
const char *host, *port;
struct addrinfo hints = {
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP,
};
char *str;
EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_net_dialer_connected_get(o), EISCONN);
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(o), EBADF);
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_loop_fd_get(o) >= 0, EALREADY);
// TODO: change to getaddrinfo() and move to a thread...
str = host = strdup(address);
str = strdup(address);
EINA_SAFETY_ON_NULL_RETURN_VAL(str, ENOMEM);
if (host[0] == '[')
if (!efl_net_ip_port_split(str, &host, &port))
{
struct sockaddr_in6 *a = (struct sockaddr_in6 *)&addr;
/* IPv6 is: [IP]:port */
host++;
port = strchr(host, ']');
if (!port)
{
ERR("missing ']' in IPv6 address: %s", address);
goto invalid_address;
}
*port = '\0';
port++;
if (port[0] == ':')
port++;
else
port = NULL;
a->sin6_family = AF_INET6;
a->sin6_port = htons(port ? atoi(port) : 0);
r = inet_pton(AF_INET6, host, &(a->sin6_addr));
addrlen = sizeof(*a);
ERR("could not parse IP:PORT '%s'", address);
free(str);
return EINVAL;
}
else
if (strchr(host, ':')) hints.ai_family = AF_INET6;
if (!port) port = "0";
if (pd->connect.thread)
{
struct sockaddr_in *a = (struct sockaddr_in *)&addr;
port = strchr(host, ':');
if (port)
{
*port = '\0';
port++;
}
a->sin_family = AF_INET;
a->sin_port = htons(port ? atoi(port) : 0);
r = inet_pton(AF_INET, host, &(a->sin_addr));
addrlen = sizeof(*a);
ecore_thread_cancel(pd->connect.thread);
pd->connect.thread = NULL;
}
if (r != 1)
if (pd->resolve.names)
{
ERR("could not parse IP '%s' (%s)", host, address);
goto invalid_address;
freeaddrinfo(pd->resolve.names);
pd->resolve.names = NULL;
}
pd->resolve.current = NULL;
if (pd->resolve.thread)
ecore_thread_cancel(pd->resolve.thread);
pd->resolve.thread = efl_net_resolve_async_new(host, port, &hints, _efl_net_dialer_tcp_resolved, o);
free(str);
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->resolve.thread, EINVAL);
efl_net_socket_fd_family_set(o, addr.ss_family);
efl_net_dialer_address_dial_set(o, address);
if (efl_net_ip_port_fmt(buf, sizeof(buf), (struct sockaddr *)&addr))
{
efl_net_socket_address_remote_set(o, buf);
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_RESOLVED, NULL);
}
fd = efl_net_socket4(addr.ss_family, SOCK_STREAM, IPPROTO_TCP, efl_net_socket_fd_close_on_exec_get(o));
if (fd < 0)
{
ERR("socket(%d, SOCK_STREAM, IPPROTO_TCP): %s",
addr.ss_family, strerror(errno));
return errno;
}
r = connect(fd, (struct sockaddr *)&addr, addrlen);
if (r < 0)
{
int errno_bkp = errno;
ERR("connect(%d, %s): %s", fd, address, strerror(errno));
close(fd);
return errno_bkp;
}
efl_loop_fd_set(o, fd);
efl_net_dialer_connected_set(o, EINA_TRUE);
return 0;
invalid_address:
free(str);
return EINVAL;
}
EOLIAN static void
@ -197,8 +283,9 @@ _efl_net_dialer_tcp_efl_net_dialer_connected_get(Eo *o EINA_UNUSED, Efl_Net_Dial
}
EOLIAN static Eina_Error
_efl_net_dialer_tcp_efl_io_closer_close(Eo *o, Efl_Net_Dialer_Tcp_Data *pd EINA_UNUSED)
_efl_net_dialer_tcp_efl_io_closer_close(Eo *o, Efl_Net_Dialer_Tcp_Data *pd)
{
pd->closed = EINA_TRUE;
efl_net_dialer_connected_set(o, EINA_FALSE);
return efl_io_closer_close(efl_super(o, MY_CLASS));
}

View File

@ -831,7 +831,7 @@ _efl_net_dialer_websocket_http_headers_done(void *data, const Efl_Event *event E
status = efl_net_dialer_http_response_status_get(pd->http);
if (status != EFL_NET_HTTP_STATUS_SWITCHING_PROTOCOLS)
{
Eina_Error err = EFL_NET_HTTP_ERROR_COULDNT_CONNECT;
Eina_Error err = EFL_NET_DIALER_ERROR_COULDNT_CONNECT;
if ((status >= 300) && (status < 400))
return;
WRN("failed WebSocket handshake: HTTP status=%d, expected=%d",
@ -871,7 +871,7 @@ _efl_net_dialer_websocket_http_headers_done(void *data, const Efl_Event *event E
if ((!upgraded) || (!connection_websocket) || (!accepted))
{
Eina_Error err = EFL_NET_HTTP_ERROR_COULDNT_CONNECT;
Eina_Error err = EFL_NET_DIALER_ERROR_COULDNT_CONNECT;
WRN("failed WebSocket handshake: upgraded=%d, connection_websocket=%d, accepted=%d",
upgraded, connection_websocket, accepted);
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_ERROR, &err);

View File

@ -126,9 +126,6 @@ var @extern Efl.Net.Http.Error.BAD_FUNCTION_ARGUMENT: Eina.Error;
var @extern Efl.Net.Http.Error.CHUNK_FAILED: Eina.Error;
var @extern Efl.Net.Http.Error.CONV_FAILED: Eina.Error;
var @extern Efl.Net.Http.Error.CONV_REQD: Eina.Error;
var @extern Efl.Net.Http.Error.COULDNT_CONNECT: Eina.Error;
var @extern Efl.Net.Http.Error.COULDNT_RESOLVE_HOST: Eina.Error;
var @extern Efl.Net.Http.Error.COULDNT_RESOLVE_PROXY: Eina.Error;
var @extern Efl.Net.Http.Error.FAILED_INIT: Eina.Error;
var @extern Efl.Net.Http.Error.FILE_COULDNT_READ_FILE: Eina.Error;
var @extern Efl.Net.Http.Error.FILESIZE_EXCEEDED: Eina.Error;