# ecore_con
-AC_CHECK_HEADERS([arpa/inet.h arpa/nameser.h netinet/tcp.h netinet/in.h sys/socket.h sys/un.h ws2tcpip.h netdb.h])
+AC_CHECK_HEADERS([arpa/inet.h arpa/nameser.h netinet/tcp.h net/if.h netinet/in.h sys/socket.h sys/un.h ws2tcpip.h netdb.h])
if test "x${ac_cv_header_netdb_h}" = "xyes" ; then
have_addrinfo="yes"
typedef struct _Ecore_Con_Client Ecore_Con_Client;
/**
+ * @typedef Ecore_Con_Socks
+ * An object representing a SOCKS proxy
+ * @ingroup Ecore_Con_Socks_Group
+ * @since 1.2
+ */
+typedef struct Ecore_Con_Socks Ecore_Con_Socks;
+
+/**
* @typedef Ecore_Con_Url
* A handle to an http upload/download object
* @ingroup Ecore_Con_Url_Group
typedef struct _Ecore_Con_Event_Server_Write Ecore_Con_Event_Server_Write;
/**
+ * @typedef Ecore_Con_Event_Proxy_Bind
+ * Used as the @p data param for the corresponding event
+ * @since 1.2
+ */
+typedef struct _Ecore_Con_Event_Proxy_Bind Ecore_Con_Event_Proxy_Bind;
+
+/**
* @typedef Ecore_Con_Event_Url_Data
* Used as the @p data param for the corresponding event
* @ingroup Ecore_Con_Url_Group
};
/**
+ * @struct _Ecore_Con_Event_Proxy_Bind
+ * Used as the @p data param for the @ref ECORE_CON_EVENT_PROXY_BIND event
+ * @ingroup Ecore_Con_Socks_Group
+ * @since 1.2
+ */
+struct _Ecore_Con_Event_Proxy_Bind
+{
+ Ecore_Con_Server *server; /**< the server object connected to the proxy */
+ const char *ip; /**< the proxy-bound ip address */
+ int port; /**< the proxy-bound port */
+};
+
+/**
* @struct _Ecore_Con_Event_Url_Data
* Used as the @p data param for the @ref ECORE_CON_EVENT_URL_DATA event
* @ingroup Ecore_Con_Url_Group
EAPI extern int ECORE_CON_EVENT_CLIENT_DATA;
/** A server connection object has data */
EAPI extern int ECORE_CON_EVENT_SERVER_DATA;
+/** A server connection has successfully negotiated an ip:port binding
+ * @since 1.2
+ */
+EAPI extern int ECORE_CON_EVENT_PROXY_BIND;
/** A URL object has data */
EAPI extern int ECORE_CON_EVENT_URL_DATA;
/** A URL object has completed its transfer to and from the server and can be reused */
ECORE_CON_REMOTE_UDP = 5,
/** Remote broadcast using UDP */
ECORE_CON_REMOTE_BROADCAST = 6,
+ /** Remote connection sending packets immediately */
ECORE_CON_REMOTE_NODELAY = 7,
+ /** Remote connection sending data in large chunks
+ * @note Only available on Linux
+ * @since 1.2
+ */
+ ECORE_CON_REMOTE_CORK = 8,
/** Use SSL2: UNSUPPORTED. **/
ECORE_CON_USE_SSL2 = (1 << 4),
/** Use SSL3 */
EAPI Eina_Bool ecore_con_ssl_server_cafile_add(Ecore_Con_Server *svr, const char *ca_file);
EAPI void ecore_con_ssl_server_verify(Ecore_Con_Server *svr);
EAPI void ecore_con_ssl_server_verify_basic(Ecore_Con_Server *svr);
+EAPI void ecore_con_ssl_server_verify_name_set(Ecore_Con_Server *svr, const char *name);
+EAPI const char *ecore_con_ssl_server_verify_name_get(Ecore_Con_Server *svr);
EAPI Eina_Bool ecore_con_ssl_server_upgrade(Ecore_Con_Server *svr, Ecore_Con_Type compl_type);
EAPI Eina_Bool ecore_con_ssl_client_upgrade(Ecore_Con_Client *cl, Ecore_Con_Type compl_type);
* @}
*/
+EAPI Ecore_Con_Socks *ecore_con_socks4_remote_add(const char *ip, int port, const char *username);
+EAPI void ecore_con_socks4_lookup_set(Ecore_Con_Socks *ecs, Eina_Bool enable);
+EAPI Eina_Bool ecore_con_socks4_lookup_get(Ecore_Con_Socks *ecs);
+EAPI Eina_Bool ecore_con_socks4_remote_exists(const char *ip, int port, const char *username);
+EAPI void ecore_con_socks4_remote_del(const char *ip, int port, const char *username);
+EAPI void ecore_con_socks_bind_set(Ecore_Con_Socks *ecs, Eina_Bool is_bind);
+EAPI Eina_Bool ecore_con_socks_bind_get(Ecore_Con_Socks *ecs);
+EAPI unsigned int ecore_con_socks_version_get(Ecore_Con_Socks *ecs);
+EAPI void ecore_con_socks_remote_del(Ecore_Con_Socks *ecs);
+EAPI void ecore_con_socks_apply_once(Ecore_Con_Socks *ecs);
+EAPI void ecore_con_socks_apply_always(Ecore_Con_Socks *ecs);
+
/**
* @defgroup Ecore_Con_Server_Group Ecore Connection Server Functions
*
*/
EAPI int ecore_con_client_port_get(Ecore_Con_Client *cl);
+
+
/**
* @}
*/
const char *ca_path);
/**
+ * Set HTTP proxy to use.
+ *
+ * The parameter should be a char * to a zero terminated string holding
+ * the host name or dotted IP address. To specify port number in this string,
+ * append :[port] to the end of the host name.
+ * The proxy string may be prefixed with [protocol]:// since any such prefix
+ * will be ignored.
+ * The proxy's port number may optionally be specified with the separate option.
+ * If not specified, libcurl will default to using port 1080 for proxies.
+ *
+ * @param url_con Connection object that will use the proxy.
+ * @param proxy Porxy string or @c NULL to disable
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on error.
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_con_url_proxy_set(Ecore_Con_Url *url_con, const char *proxy);
+
+/**
+ * Set zero terminated username to use for proxy.
+ *
+ * if socks protocol is used for proxy, protocol should be socks5 and above.
+ *
+ * @param url_con Connection object that will use the proxy.
+ * @param username Username string.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on error.
+ *
+ * @see ecore_con_url_proxy_set()
+ *
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_con_url_proxy_username_set(Ecore_Con_Url *url_con, const char *username);
+
+/**
+ * Set zero terminated password to use for proxy.
+ *
+ * if socks protocol is used for proxy, protocol should be socks5 and above.
+ *
+ * @param url_con Connection object that will use the proxy.
+ * @param password Password string.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on error.
+ *
+ * @see ecore_con_url_proxy_set()
+ *
+ * @since 1.2
+ */
+EAPI Eina_Bool ecore_con_url_proxy_password_set(Ecore_Con_Url *url_con, const char *password);
+
+/**
+ * Set timeout in seconds.
+ *
+ * the maximum time in seconds that you allow the ecore con url transfer
+ * operation to take. Normally, name lookups can take a considerable time
+ * and limiting operations to less than a few minutes risk aborting perfectly
+ * normal operations.
+ *
+ * @param url_con Connection object that will use the timeout.
+ * @param timeout time in seconds.
+ *
+ * @see ecore_con_url_cookies_jar_file_set()
+ *
+ * @since 1.2
+ */
+EAPI void ecore_con_url_timeout_set(Ecore_Con_Url *url_con, double timeout);
+
+/**
* @}
*/
libecore_con_la_SOURCES = \
ecore_con.c \
+ecore_con_socks.c \
ecore_con_ssl.c \
ecore_con_url.c \
ecore_con_alloc.c
static Eina_Bool _ecore_con_client_timer(Ecore_Con_Client *cl);
static void _ecore_con_cl_timer_update(Ecore_Con_Client *cl);
-
+static void _ecore_con_client_kill(Ecore_Con_Client *cl);
static Eina_Bool _ecore_con_server_timer(Ecore_Con_Server *svr);
static void _ecore_con_server_timer_update(Ecore_Con_Server *svr);
static const char * _ecore_con_pretty_ip(struct sockaddr *client_addr);
+
+static void
+_ecore_con_client_kill(Ecore_Con_Client *cl)
+{
+ if (cl->delete_me)
+ DBG("Multi kill request for client %p", cl);
+ else
+ ecore_con_event_client_del(cl);
+ INF("Lost client %s", (cl->ip) ? cl->ip : "");
+ if (cl->fd_handler)
+ ecore_main_fd_handler_del(cl->fd_handler);
+
+ cl->fd_handler = NULL;
+}
+
+void
+_ecore_con_server_kill(Ecore_Con_Server *svr)
+{
+ if (svr->delete_me)
+ DBG("Multi kill request for svr %p", svr);
+ else
+ ecore_con_event_server_del(svr);
+
+ if (svr->fd_handler)
+ ecore_main_fd_handler_del(svr->fd_handler);
+
+ svr->fd_handler = NULL;
+}
+
+#define _ecore_con_server_kill(svr) do { \
+ DBG("KILL %p", (svr)); \
+ _ecore_con_server_kill((svr)); \
+} while (0)
+
+#define _ecore_con_client_kill(cl) do { \
+ DBG("KILL %p", (cl)); \
+ _ecore_con_client_kill((cl)); \
+} while (0)
+
EAPI int ECORE_CON_EVENT_CLIENT_ADD = 0;
EAPI int ECORE_CON_EVENT_CLIENT_DEL = 0;
EAPI int ECORE_CON_EVENT_SERVER_ADD = 0;
EAPI int ECORE_CON_EVENT_SERVER_WRITE = 0;
EAPI int ECORE_CON_EVENT_CLIENT_ERROR = 0;
EAPI int ECORE_CON_EVENT_SERVER_ERROR = 0;
+EAPI int ECORE_CON_EVENT_PROXY_BIND = 0;
static Eina_List *servers = NULL;
static int _ecore_con_init_count = 0;
static int _ecore_con_event_count = 0;
int _ecore_con_log_dom = -1;
+Ecore_Con_Socks *_ecore_con_proxy_once = NULL;
+Ecore_Con_Socks *_ecore_con_proxy_global = NULL;
EAPI int
ecore_con_init(void)
ECORE_CON_EVENT_SERVER_WRITE = ecore_event_type_new();
ECORE_CON_EVENT_CLIENT_ERROR = ecore_event_type_new();
ECORE_CON_EVENT_SERVER_ERROR = ecore_event_type_new();
+ ECORE_CON_EVENT_PROXY_BIND = ecore_event_type_new();
eina_magic_string_set(ECORE_MAGIC_CON_SERVER, "Ecore_Con_Server");
eina_magic_string_set(ECORE_MAGIC_CON_URL, "Ecore_Con_Url");
/* TODO Remember return value, if it fails, use gethostbyname() */
+ ecore_con_socks_init();
ecore_con_ssl_init();
ecore_con_info_init();
{
Ecore_Con_Event_Server_Add *ev;
- svr->delete_me = svr->dead = EINA_TRUE;
+ svr->delete_me = EINA_TRUE;
INF("svr %p is dead", svr);
/* some pointer hacks here to prevent double frees if people are being stupid */
EINA_LIST_FREE(svr->event_count, ev)
_ecore_con_server_free(svr);
}
+ ecore_con_socks_shutdown();
if (!_ecore_con_event_count) ecore_con_mempool_shutdown();
ecore_con_info_shutdown();
svr->port = port;
svr->data = (void *)data;
svr->created = EINA_TRUE;
- if (compl_type & ECORE_CON_LOAD_CERT)
- svr->use_cert = EINA_TRUE;
+ svr->use_cert = (compl_type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT;
svr->reject_excess_clients = EINA_FALSE;
svr->client_limit = -1;
svr->clients = NULL;
#endif
if ((type == ECORE_CON_REMOTE_TCP) ||
- (type == ECORE_CON_REMOTE_NODELAY))
+ (type == ECORE_CON_REMOTE_NODELAY) ||
+ (type == ECORE_CON_REMOTE_CORK))
{
/* TCP */
if (!ecore_con_info_tcp_listen(svr, _ecore_con_cb_tcp_listen,
svr->port = port;
svr->data = (void *)data;
svr->created = EINA_FALSE;
- svr->use_cert = (compl_type & ECORE_CON_LOAD_CERT);
+ svr->use_cert = (compl_type & ECORE_CON_SSL & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT;
svr->reject_excess_clients = EINA_FALSE;
svr->clients = NULL;
svr->client_limit = -1;
- if (ecore_con_ssl_server_prepare(svr, compl_type & ECORE_CON_SSL))
- goto error;
type = compl_type & ECORE_CON_TYPE;
+ if (type > ECORE_CON_LOCAL_ABSTRACT)
+ {
+ /* never use proxies on local connections */
+ if (_ecore_con_proxy_once)
+ svr->ecs = _ecore_con_proxy_once;
+ else if (_ecore_con_proxy_global)
+ svr->ecs = _ecore_con_proxy_global;
+ _ecore_con_proxy_once = NULL;
+ if (svr->ecs)
+ {
+ if ((!svr->ecs->lookup) &&
+ (!ecore_con_lookup(svr->name, (Ecore_Con_Dns_Cb)ecore_con_socks_dns_cb, svr)))
+ goto error;
+ if (svr->ecs->lookup)
+ svr->ecs_state = ECORE_CON_SOCKS_STATE_RESOLVED;
+ }
+
+ }
+ if (ecore_con_ssl_server_prepare(svr, compl_type & ECORE_CON_SSL))
+ goto error;
+
if (((type == ECORE_CON_REMOTE_TCP) ||
(type == ECORE_CON_REMOTE_NODELAY) ||
+ (type == ECORE_CON_REMOTE_CORK) ||
(type == ECORE_CON_REMOTE_UDP) ||
(type == ECORE_CON_REMOTE_BROADCAST)) &&
(port < 0))
#endif
if ((type == ECORE_CON_REMOTE_TCP) ||
- (type == ECORE_CON_REMOTE_NODELAY))
+ (type == ECORE_CON_REMOTE_NODELAY) ||
+ (type == ECORE_CON_REMOTE_CORK))
{
/* TCP */
if (!ecore_con_info_tcp_connect(svr, _ecore_con_cb_tcp_connect,
EAPI void *
ecore_con_server_del(Ecore_Con_Server *svr)
{
- void *data;
-
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_del");
if (svr->delete_me)
return NULL;
- data = svr->data;
- svr->delete_me = EINA_TRUE;
- if (svr->event_count)
- {
- if (svr->fd_handler)
- {
- ecore_main_fd_handler_del(svr->fd_handler);
- svr->fd_handler = NULL;
- }
- }
- else
- _ecore_con_server_free(svr);
-
- return data;
+ _ecore_con_server_kill(svr);
+ return svr->data;
}
EAPI void *
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
- ECORE_MAGIC_FAIL(svr,
- ECORE_MAGIC_CON_SERVER,
- "ecore_con_server_data_get");
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get");
return NULL;
}
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
- ECORE_MAGIC_FAIL(svr,
- ECORE_MAGIC_CON_SERVER,
- "ecore_con_server_data_get");
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get");
return NULL;
}
{
if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
{
- ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER,
- "ecore_con_server_connected_get");
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_connected_get");
return EINA_FALSE;
}
return 0;
}
- EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->dead, 0);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(svr->delete_me, 0);
EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0);
{
svr->buf = eina_binbuf_new();
EINA_SAFETY_ON_NULL_RETURN_VAL(svr->buf, 0);
+#ifdef TCP_CORK
+ if ((svr->fd >= 0) && ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK))
+ {
+ int state = 1;
+ if (setsockopt(svr->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0)
+ /* realistically this isn't anything serious so we can just log and continue */
+ ERR("corking failed! %s", strerror(errno));
+ }
+#endif
}
eina_binbuf_append_length(svr->buf, data, size);
return 0;
}
- EINA_SAFETY_ON_TRUE_RETURN_VAL(cl->dead, 0);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(cl->delete_me, 0);
EINA_SAFETY_ON_NULL_RETURN_VAL(data, 0);
{
cl->buf = eina_binbuf_new();
EINA_SAFETY_ON_NULL_RETURN_VAL(cl->buf, 0);
+#ifdef TCP_CORK
+ if ((cl->fd >= 0) && ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK))
+ {
+ int state = 1;
+ if (setsockopt(cl->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0)
+ /* realistically this isn't anything serious so we can just log and continue */
+ ERR("corking failed! %s", strerror(errno));
+ }
+#endif
}
eina_binbuf_append_length(cl->buf, data, size);
return EINA_FALSE;
}
- return !cl->dead;
+ return !cl->delete_me;
}
EAPI void
EAPI void *
ecore_con_client_del(Ecore_Con_Client *cl)
{
- void *data = NULL;
-
if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
{
ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_del");
return NULL;
}
- data = cl->data;
- cl->delete_me = EINA_TRUE;
- if (cl->event_count)
- {
- if (cl->fd_handler)
- {
- ecore_main_fd_handler_del(cl->fd_handler);
- cl->fd_handler = NULL;
- }
- }
- else
- {
- if (cl->host_server)
- {
- cl->host_server->clients = eina_list_remove(cl->host_server->clients, cl);
- --cl->host_server->client_count;
- }
-
- _ecore_con_client_free(cl);
- }
-
- return data;
+ _ecore_con_client_kill(cl);
+ return cl->data;
}
EAPI void
{
if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
{
- ECORE_MAGIC_FAIL(cl,
- ECORE_MAGIC_CON_CLIENT,
- "ecore_con_client_data_set");
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_set");
return;
}
{
if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT))
{
- ECORE_MAGIC_FAIL(cl,
- ECORE_MAGIC_CON_CLIENT,
- "ecore_con_client_data_get");
+ ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_get");
return NULL;
}
*/
void
+ecore_con_event_proxy_bind(Ecore_Con_Server *svr)
+{
+ Ecore_Con_Event_Proxy_Bind *e;
+ int ev = ECORE_CON_EVENT_PROXY_BIND;
+
+ e = ecore_con_event_proxy_bind_alloc();
+ EINA_SAFETY_ON_NULL_RETURN(e);
+
+ svr->event_count = eina_list_append(svr->event_count, e);
+ _ecore_con_server_timer_update(svr);
+ e->server = svr;
+ e->ip = svr->proxyip;
+ e->port = svr->proxyport;
+ ecore_event_add(ev, e,
+ _ecore_con_event_server_add_free, NULL);
+ _ecore_con_event_count++;
+}
+
+void
ecore_con_event_server_add(Ecore_Con_Server *svr)
{
/* we got our server! */
e = ecore_con_event_server_add_alloc();
EINA_SAFETY_ON_NULL_RETURN(e);
+ svr->connecting = EINA_FALSE;
+ svr->start_time = ecore_time_get();
svr->event_count = eina_list_append(svr->event_count, e);
_ecore_con_server_timer_update(svr);
e->server = svr;
{
Ecore_Con_Event_Server_Del *e;
+ svr->delete_me = EINA_TRUE;
+ INF("svr %p is dead", svr);
e = ecore_con_event_server_del_alloc();
EINA_SAFETY_ON_NULL_RETURN(e);
svr->event_count = eina_list_append(svr->event_count, e);
_ecore_con_server_timer_update(svr);
e->server = svr;
+ if (svr->ecs)
+ {
+ svr->ecs_state = svr->ecs->lookup ? ECORE_CON_SOCKS_STATE_RESOLVED : ECORE_CON_SOCKS_STATE_DONE;
+ eina_stringshare_replace(&svr->proxyip, NULL);
+ svr->proxyport = 0;
+ }
ecore_event_add(ECORE_CON_EVENT_SERVER_DEL, e,
_ecore_con_event_server_del_free, NULL);
_ecore_con_event_count++;
e = ecore_con_event_server_write_alloc();
EINA_SAFETY_ON_NULL_RETURN(e);
+ INF("Wrote %d bytes", num);
svr->event_count = eina_list_append(svr->event_count, e);
e->server = svr;
e->size = num;
Ecore_Con_Event_Client_Del *e;
if (!cl) return;
+ cl->delete_me = EINA_TRUE;
+ INF("cl %p is dead", cl);
e = ecore_con_event_client_del_alloc();
EINA_SAFETY_ON_NULL_RETURN(e);
cl->event_count = eina_list_append(cl->event_count, e);
}
void
-ecore_con_event_server_error(Ecore_Con_Server *svr, const char *error)
+_ecore_con_event_server_error(Ecore_Con_Server *svr, char *error, Eina_Bool duplicate)
{
Ecore_Con_Event_Server_Error *e;
EINA_SAFETY_ON_NULL_RETURN(e);
e->server = svr;
- e->error = strdup(error);
+ e->error = duplicate ? strdup(error) : error;
ERR("%s", error);
svr->event_count = eina_list_append(svr->event_count, e);
ecore_event_add(ECORE_CON_EVENT_SERVER_ERROR, e, (Ecore_End_Cb)_ecore_con_event_server_error_free, NULL);
ecore_con_info_data_clear(svr->infos->data);
svr->infos = eina_list_remove_list(svr->infos, svr->infos);
}
- if ((!svr->buf) && svr->delete_me && (!svr->dead) && (!svr->event_count))
- {
- /* this is a catch-all for cases when a server is not properly killed. */
- svr->dead = EINA_TRUE;
- INF("svr %p is dead", svr);
- ecore_con_event_server_del(svr);
- return;
- }
t_start = ecore_time_get();
- while (svr->buf && (!svr->dead))
+ while (svr->buf && (!svr->delete_me))
{
_ecore_con_server_flush(svr);
t = ecore_time_get();
/* some pointer hacks here to prevent double frees if people are being stupid */
EINA_LIST_FREE(cl->event_count, ev)
ev->server = NULL;
- cl->delete_me = cl->dead = EINA_TRUE;
+ cl->delete_me = EINA_TRUE;
INF("cl %p is dead", cl);
_ecore_con_client_free(cl);
}
free(svr->path);
eina_stringshare_del(svr->ip);
+ eina_stringshare_del(svr->verify_name);
+
+ if (svr->ecs_buf) eina_binbuf_free(svr->ecs_buf);
+ if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf);
if (svr->fd_handler)
ecore_main_fd_handler_del(svr->fd_handler);
if (cl->event_count) return;
- if (cl->delete_me && (!cl->dead) && (!cl->event_count))
- {
- /* this is a catch-all for cases when a client is not properly killed. */
- cl->dead = EINA_TRUE;
- INF("cl %p is dead", cl);
- ecore_con_event_client_del(cl);
- return;
- }
-
-
t_start = ecore_time_get();
- while ((cl->buf) && (!cl->dead))
+ while ((cl->buf) && (!cl->delete_me))
{
_ecore_con_client_flush(cl);
t = ecore_time_get();
return;
}
-static void
-_ecore_con_server_kill(Ecore_Con_Server *svr)
-{
- if (!svr->delete_me)
- ecore_con_event_server_del(svr);
-
- svr->dead = EINA_TRUE;
- INF("svr %p is dead", svr);
- if (svr->fd_handler)
- ecore_main_fd_handler_del(svr->fd_handler);
-
- svr->fd_handler = NULL;
-}
-
static Eina_Bool
_ecore_con_server_timer(Ecore_Con_Server *svr)
{
{
Ecore_Con_Server *svr;
struct linger lin;
+ const char *memerr = NULL;
svr = data;
+ errno = 0;
if (!net_info) /* error message has already been handled */
goto error;
svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
net_info->info.ai_protocol);
- if (svr->fd < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
-
- if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
-
- if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ if (svr->fd < 0) goto error;
+ if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+ if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
lin.l_onoff = 1;
lin.l_linger = 0;
if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin,
sizeof(struct linger)) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ goto error;
if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY)
{
sizeof(int)) < 0)
#endif
{
- ecore_con_event_server_error(svr, strerror(errno));
goto error;
}
}
- if (bind(svr->fd, net_info->info.ai_addr,
- net_info->info.ai_addrlen) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
- if (listen(svr->fd, 4096) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
+ goto error;
+
+ if (listen(svr->fd, 4096) < 0) goto error;
svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
_ecore_con_svr_tcp_handler, svr, NULL, NULL);
if (!svr->fd_handler)
{
- ecore_con_event_server_error(svr, "Memory allocation failure");
+ memerr = "Memory allocation failure";
goto error;
}
return;
error:
+ if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
ecore_con_ssl_server_shutdown(svr);
_ecore_con_server_kill(svr);
}
struct ipv6_mreq mreq6;
#endif
const int on = 1;
+ const char *memerr = NULL;
svr = data;
type = svr->type;
type &= ECORE_CON_TYPE;
+ errno = 0;
if (!net_info) /* error message has already been handled */
goto error;
svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
net_info->info.ai_protocol);
- if (svr->fd < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ if (svr->fd < 0) goto error;
if (type == ECORE_CON_REMOTE_MCAST)
{
{
if (!inet_pton(net_info->info.ai_family, net_info->ip,
&mreq.imr_multiaddr))
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ goto error;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(svr->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const void *)&mreq, sizeof(mreq)) != 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ goto error;
}
#ifdef HAVE_IPV6
else if (net_info->info.ai_family == AF_INET6)
{
if (!inet_pton(net_info->info.ai_family, net_info->ip,
&mreq6.ipv6mr_multiaddr))
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ goto error;
mreq6.ipv6mr_interface = htonl(INADDR_ANY);
if (setsockopt(svr->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const void *)&mreq6, sizeof(mreq6)) != 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ goto error;
}
#endif
}
if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) != 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
-
- if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
-
- if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ goto error;
+ if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+ if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ goto error;
svr->fd_handler =
ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
_ecore_con_svr_udp_handler, svr, NULL, NULL);
if (!svr->fd_handler)
{
- ecore_con_event_server_error(svr, "Memory allocation failure");
+ memerr = "Memory allocation failure";
goto error;
}
return;
error:
+ if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
ecore_con_ssl_server_shutdown(svr);
_ecore_con_server_kill(svr);
}
Ecore_Con_Server *svr;
int res;
int curstate = 0;
+ const char *memerr = NULL;
svr = data;
+ errno = 0;
if (!net_info) /* error message has already been handled */
goto error;
svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
net_info->info.ai_protocol);
- if (svr->fd < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ if (svr->fd < 0) goto error;
- if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
-
- if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+ if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, sizeof(curstate)) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ goto error;
if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY)
{
if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) < 0)
#endif
{
- ecore_con_event_server_error(svr, strerror(errno));
goto error;
}
}
if (res == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEINPROGRESS)
- goto error; /* FIXME: strerror on windows? */
+ {
+ char *err;
+ err = evil_format_message(WSAGetLastError());
+ _ecore_con_event_server_error(svr, err, EINA_FALSE);
+ ecore_con_ssl_server_shutdown(svr);
+ _ecore_con_server_kill(svr);
+ return;
+ }
#else
if (res < 0)
{
- if (errno != EINPROGRESS)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
-
+ if (errno != EINPROGRESS) goto error;
#endif
svr->connecting = EINA_TRUE;
svr->fd_handler =
{
svr->handshaking = EINA_TRUE;
svr->ssl_state = ECORE_CON_SSL_STATE_INIT;
- DBG("beginning ssl handshake");
- if (ecore_con_ssl_server_init(svr))
+ DBG("%s ssl handshake", svr->ecs_state ? "Queuing" : "Beginning");
+ if ((!svr->ecs_state) && ecore_con_ssl_server_init(svr))
goto error;
}
if (!svr->fd_handler)
{
- ecore_con_event_server_error(svr, "Memory allocation failure");
+ memerr = "Memory allocation failure";
goto error;
}
- svr->ip = eina_stringshare_add(net_info->ip);
+ if ((!svr->ecs) || (svr->ecs->lookup))
+ svr->ip = eina_stringshare_add(net_info->ip);
return;
error:
+ if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
ecore_con_ssl_server_shutdown(svr);
_ecore_con_server_kill(svr);
}
Ecore_Con_Server *svr;
int curstate = 0;
int broadcast = 1;
+ const char *memerr = NULL;
svr = data;
+ errno = 0;
if (!net_info) /* error message has already been handled */
goto error;
svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
net_info->info.ai_protocol);
- if (svr->fd < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
-
- if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
-
- if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
-
+ if (svr->fd < 0) goto error;
+ if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+ if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_BROADCAST)
{
if (setsockopt(svr->fd, SOL_SOCKET, SO_BROADCAST,
(const void *)&broadcast,
sizeof(broadcast)) < 0)
{
- ecore_con_event_server_error(svr, strerror(errno));
goto error;
}
}
- else if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR,
- (const void *)&curstate, sizeof(curstate)) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&curstate, sizeof(curstate)) < 0)
+ goto error;
if (connect(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto error;
- }
+ goto error;
svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ | ECORE_FD_WRITE,
_ecore_con_cl_udp_handler, svr, NULL, NULL);
if (!svr->fd_handler)
{
- ecore_con_event_server_error(svr, "Memory allocation failure");
+ memerr = "Memory allocation failure";
goto error;
}
- svr->ip = eina_stringshare_add(net_info->ip);
+ if ((!svr->ecs) || (svr->ecs->lookup))
+ svr->ip = eina_stringshare_add(net_info->ip);
return;
error:
+ if (errno || memerr) ecore_con_event_server_error(svr, memerr ?: strerror(errno));
ecore_con_ssl_server_shutdown(svr);
_ecore_con_server_kill(svr);
}
if (res == SOCKET_ERROR)
so_err = WSAGetLastError();
- if ((so_err == WSAEINPROGRESS) && !svr->dead)
+ if ((so_err == WSAEINPROGRESS) && !svr->delete_me)
return ECORE_CON_INPROGRESS;
#else
if (res < 0)
so_err = errno;
- if ((so_err == EINPROGRESS) && !svr->dead)
+ if ((so_err == EINPROGRESS) && !svr->delete_me)
return ECORE_CON_INPROGRESS;
#endif
if ((!svr->delete_me) && (!svr->handshaking) && svr->connecting)
{
- svr->connecting = EINA_FALSE;
- svr->start_time = ecore_time_get();
- ecore_con_event_server_add(svr);
+ if (svr->ecs)
+ {
+ if (ecore_con_socks_svr_init(svr))
+ return ECORE_CON_INPROGRESS;
+ }
+ else
+ ecore_con_event_server_add(svr);
}
if (svr->fd_handler && (!svr->buf))
ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
- if (!svr->dead)
+ if (!svr->delete_me)
return ECORE_CON_CONNECTED;
else
return ECORE_CON_DISCONNECTED;
Ecore_Con_Client *cl = NULL;
unsigned char client_addr[256];
unsigned int client_addr_len;
+ const char *clerr = NULL;
svr = data;
- if (svr->dead)
+ if (svr->delete_me)
return ECORE_CALLBACK_RENEW;
if (svr->delete_me)
client_addr_len = sizeof(client_addr);
memset(&client_addr, 0, client_addr_len);
cl->fd = accept(svr->fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_addr_len);
- if (cl->fd < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto free_cl;
- }
-
+ if (cl->fd < 0) goto error;
if ((svr->client_limit >= 0) && (svr->reject_excess_clients) &&
(svr->client_count >= (unsigned int)svr->client_limit))
{
- ecore_con_event_server_error(svr, "Maximum client limit reached");
- goto close_fd;
+ clerr = "Maximum client limit reached";
+ goto error;
}
- if (fcntl(cl->fd, F_SETFL, O_NONBLOCK) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto close_fd;
- }
- if (fcntl(cl->fd, F_SETFD, FD_CLOEXEC) < 0)
- {
- ecore_con_event_server_error(svr, strerror(errno));
- goto close_fd;
- }
+ if (fcntl(cl->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+ if (fcntl(cl->fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
cl->fd_handler = ecore_main_fd_handler_add(cl->fd, ECORE_FD_READ,
_ecore_con_svr_cl_handler, cl, NULL, NULL);
- if (!cl->fd_handler)
- goto close_fd;
-
+ if (!cl->fd_handler) goto error;
ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT);
if ((!svr->upgrade) && (svr->type & ECORE_CON_SSL))
cl->handshaking = EINA_TRUE;
cl->ssl_state = ECORE_CON_SSL_STATE_INIT;
if (ecore_con_ssl_client_init(cl))
- goto del_handler;
+ goto error;
}
cl->client_addr = malloc(client_addr_len);
if (!cl->client_addr)
{
- ecore_con_event_server_error(svr, "Memory allocation failure when attempting to add a new client");
- goto del_handler;
+ clerr = "Memory allocation failure when attempting to add a new client";
+ goto error;
}
cl->client_addr_len = client_addr_len;
memcpy(cl->client_addr, &client_addr, client_addr_len);
return ECORE_CALLBACK_RENEW;
- del_handler:
- ecore_main_fd_handler_del(cl->fd_handler);
- close_fd:
- close(cl->fd);
- free_cl:
+error:
+ if (cl->fd_handler) ecore_main_fd_handler_del(cl->fd_handler);
+ if (cl->fd >= 0) close(cl->fd);
free(cl);
-
+ if (clerr || errno) ecore_con_event_server_error(svr, clerr ?: strerror(errno));
return ECORE_CALLBACK_RENEW;
}
static void
_ecore_con_cl_read(Ecore_Con_Server *svr)
{
- DBG("svr=%p", svr);
int num = 0;
Eina_Bool lost_server = EINA_TRUE;
unsigned char buf[READBUFSIZ];
+ DBG("svr=%p", svr);
+
/* only possible with non-ssl connections */
if (svr->connecting && (svr_try_connect_plain(svr) != ECORE_CON_CONNECTED))
return;
- if (svr->handshaking)
+ if (svr->handshaking && (!svr->ecs_state))
{
DBG("Continuing ssl handshake");
if (!ecore_con_ssl_server_init(svr))
_ecore_con_server_timer_update(svr);
}
- if (!(svr->type & ECORE_CON_SSL))
+ if (svr->ecs_state || !(svr->type & ECORE_CON_SSL))
{
+ errno = 0;
num = read(svr->fd, buf, sizeof(buf));
/* 0 is not a valid return value for a tcp socket */
if ((num > 0) || ((num < 0) && (errno == EAGAIN)))
}
if ((!svr->delete_me) && (num > 0))
- ecore_con_event_server_data(svr, buf, num, EINA_TRUE);
+ {
+ if (svr->ecs_state)
+ ecore_con_socks_read(svr, buf, num);
+ else
+ ecore_con_event_server_data(svr, buf, num, EINA_TRUE);
+ }
if (lost_server)
_ecore_con_server_kill(svr);
Eina_Bool want_read, want_write;
svr = data;
- if (svr->dead)
+ if (svr->delete_me)
return ECORE_CALLBACK_RENEW;
if (svr->delete_me)
want_read = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ);
want_write = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE);
- if (svr->handshaking && (want_read || want_write))
+ if ((!svr->ecs_state) && svr->handshaking && (want_read || want_write))
{
DBG("Continuing ssl handshake: preparing to %s...", want_read ? "read" : "write");
#ifdef ISCOMFITOR
{
ERR("ssl handshaking failed!");
svr->handshaking = EINA_FALSE;
-
}
else if (!svr->ssl_state)
+ ecore_con_event_server_add(svr);
+ return ECORE_CALLBACK_RENEW;
+ }
+ if (svr->ecs && svr->ecs_state && (svr->ecs_state < ECORE_CON_SOCKS_STATE_READ) && (!svr->ecs_buf))
+ {
+ if (svr->ecs_state < ECORE_CON_SOCKS_STATE_INIT)
{
- svr->connecting = EINA_FALSE;
- svr->start_time = ecore_time_get();
- ecore_con_event_server_add(svr);
+ INF("PROXY STATE++");
+ svr->ecs_state++;
}
+ if (ecore_con_socks_svr_init(svr)) return ECORE_CALLBACK_RENEW;
}
- else if (want_read)
+ if (want_read)
_ecore_con_cl_read(svr);
else if (want_write) /* only possible with non-ssl connections */
{
- if (svr->connecting && (!svr_try_connect_plain(svr)))
+ if (svr->connecting && (!svr_try_connect_plain(svr)) && (!svr->ecs_state))
return ECORE_CALLBACK_RENEW;
_ecore_con_server_flush(svr);
want_write = ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE);
svr = data;
- if (svr->dead || svr->delete_me || ((!want_read) && (!want_write)))
+ if (svr->delete_me || svr->delete_me || ((!want_read) && (!want_write)))
return ECORE_CALLBACK_RENEW;
if (want_write)
svr = data;
- if (svr->delete_me || svr->dead)
+ if (svr->delete_me)
return ECORE_CALLBACK_RENEW;
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
ecore_con_event_server_error(svr, strerror(errno));
if (!svr->delete_me)
ecore_con_event_client_del(NULL);
-
- svr->dead = EINA_TRUE;
- INF("svr %p is dead", svr);
- svr->fd_handler = NULL;
+ _ecore_con_server_kill(svr);
return ECORE_CALLBACK_CANCEL;
}
if ((!cl->delete_me) && (num > 0))
ecore_con_event_client_data(cl, buf, num, EINA_TRUE);
- if (lost_client)
- {
- if (!cl->delete_me)
- ecore_con_event_client_del(cl);
- INF("Lost client %s", (cl->ip) ? cl->ip : "");
- cl->dead = EINA_TRUE;
- INF("cl %p is dead", cl);
- if (cl->fd_handler)
- ecore_main_fd_handler_del(cl->fd_handler);
-
- cl->fd_handler = NULL;
- return;
- }
+ if (lost_client) _ecore_con_client_kill(cl);
}
static Eina_Bool
Ecore_Con_Client *cl;
cl = data;
- if (cl->dead)
- return ECORE_CALLBACK_RENEW;
-
if (cl->delete_me)
return ECORE_CALLBACK_RENEW;
if (ecore_con_ssl_client_init(cl))
{
ERR("ssl handshaking failed!");
- cl->handshaking = EINA_FALSE;
- cl->dead = EINA_TRUE;
- INF("cl %p is dead", cl);
- INF("Lost client %s", (cl->ip) ? cl->ip : "");
- ecore_con_event_client_del(cl);
+ _ecore_con_client_kill(cl);
+ return ECORE_CALLBACK_RENEW;
}
else if (!cl->ssl_state)
ecore_con_event_client_add(cl);
_ecore_con_server_flush(Ecore_Con_Server *svr)
{
int count, num;
+ size_t buf_len, buf_offset;
+ const void *buf;
+ DBG("(svr=%p,buf=%p)", svr, svr->buf);
#ifdef _WIN32
if (ecore_con_local_win32_server_flush(svr))
return;
#endif
- if ((!svr->buf) && svr->fd_handler)
+ if ((!svr->buf) && (!svr->ecs_buf) && svr->fd_handler)
{
ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
return;
}
- num = eina_binbuf_length_get(svr->buf) - svr->write_buf_offset;
+ buf = svr->buf ? eina_binbuf_string_get(svr->buf) : eina_binbuf_string_get(svr->ecs_buf);
+ buf_len = svr->buf ? eina_binbuf_length_get(svr->buf) : eina_binbuf_length_get(svr->ecs_buf);
+ buf_offset = svr->buf ? svr->write_buf_offset : svr->ecs_buf_offset;
+ num = buf_len - buf_offset;
/* check whether we need to write anything at all.
* we must not write zero bytes with SSL_write() since it
*/
if (num <= 0) return;
- if (svr->handshaking)
+ if ((!svr->ecs_state) && svr->handshaking)
{
DBG("Continuing ssl handshake");
if (ecore_con_ssl_server_init(svr))
return;
}
- if (!(svr->type & ECORE_CON_SSL))
- count = write(svr->fd, eina_binbuf_string_get(svr->buf) + svr->write_buf_offset, num);
+ if (svr->ecs_state || (!(svr->type & ECORE_CON_SSL)))
+ count = write(svr->fd, buf + buf_offset, num);
else
- count = ecore_con_ssl_server_write(svr, eina_binbuf_string_get(svr->buf) + svr->write_buf_offset, num);
+ count = ecore_con_ssl_server_write(svr, buf + buf_offset, num);
if (count < 0)
{
return;
}
- if (count) ecore_con_event_server_write(svr, count);
- svr->write_buf_offset += count;
- if (svr->write_buf_offset >= eina_binbuf_length_get(svr->buf))
+ if (count && (!svr->ecs_state)) ecore_con_event_server_write(svr, count);
+ if (svr->ecs_buf)
+ buf_offset = svr->ecs_buf_offset += count;
+ else
+ buf_offset = svr->write_buf_offset += count;
+ if (buf_offset >= buf_len)
{
- svr->write_buf_offset = 0;
- eina_binbuf_free(svr->buf);
- svr->buf = NULL;
+ if (svr->ecs_buf)
+ {
+ svr->ecs_buf_offset = 0;
+ eina_binbuf_free(svr->ecs_buf);
+ svr->ecs_buf = NULL;
+ INF("PROXY STATE++");
+ svr->ecs_state++;
+ }
+ else
+ {
+ svr->write_buf_offset = 0;
+ eina_binbuf_free(svr->buf);
+ svr->buf = NULL;
+#ifdef TCP_CORK
+ if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK)
+ {
+ int state = 0;
+ if (setsockopt(svr->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0)
+ /* realistically this isn't anything serious so we can just log and continue */
+ ERR("uncorking failed! %s", strerror(errno));
+ }
+#endif
+ }
+
if (svr->fd_handler)
ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ);
}
if ((errno != EAGAIN) && (errno != EINTR) && (!cl->delete_me))
{
ecore_con_event_client_error(cl, strerror(errno));
- ecore_con_event_client_del(cl);
- cl->dead = EINA_TRUE;
- INF("cl %p is dead", cl);
- INF("Lost client %s", (cl->ip) ? cl->ip : "");
- if (cl->fd_handler)
- ecore_main_fd_handler_del(cl->fd_handler);
-
- cl->fd_handler = NULL;
+ _ecore_con_client_kill(cl);
}
return;
cl->buf_offset = 0;
eina_binbuf_free(cl->buf);
cl->buf = NULL;
+#ifdef TCP_CORK
+ if ((cl->host_server->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_CORK)
+ {
+ int state = 0;
+ if (setsockopt(cl->fd, IPPROTO_TCP, TCP_CORK, (char *)&state, sizeof(int)) < 0)
+ /* realistically this isn't anything serious so we can just log and continue */
+ ERR("uncorking failed! %s", strerror(errno));
+ }
+#endif
if (cl->fd_handler)
ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ);
}
if ((!svr->event_count) && (svr->delete_me))
_ecore_con_server_free(svr);
}
- if ((!e->client->event_count) && (e->client->delete_me))
+ if (!e->client->event_count)
ecore_con_client_del(e->client);
}
ecore_con_event_client_del_free(e);
if (e->server)
{
e->server->event_count = eina_list_remove(e->server->event_count, ev);
- if ((!e->server->event_count) && (e->server->delete_me))
+ if (!e->server->event_count)
_ecore_con_server_free(e->server);
}
ecore_con_event_server_del_free(e);
GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Del, ecore_con_event_server_del);
GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Write, ecore_con_event_server_write);
GENERIC_ALLOC_FREE(Ecore_Con_Event_Server_Data, ecore_con_event_server_data);
+GENERIC_ALLOC_FREE(Ecore_Con_Event_Proxy_Bind, ecore_con_event_proxy_bind);
static Ecore_Con_Mempool *mempool_array[] = {
&ecore_con_event_client_add_mp,
&ecore_con_event_server_add_mp,
&ecore_con_event_server_del_mp,
&ecore_con_event_server_write_mp,
- &ecore_con_event_server_data_mp
+ &ecore_con_event_server_data_mp,
+ &ecore_con_event_proxy_bind_mp
};
void
memcpy(&cares->hints, hints, sizeof(struct addrinfo));
}
- if (inet_pton(AF_INET, svr->name, &cares->addr.v4) == 1)
+ if (inet_pton(AF_INET, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v4) == 1)
{
cares->byaddr = EINA_TRUE;
cares->isv6 = EINA_FALSE;
cares);
}
#ifdef HAVE_IPV6
- else if (inet_pton(AF_INET6, svr->name, &cares->addr.v6) == 1)
+ else if (inet_pton(AF_INET6, svr->ecs ? svr->ecs->ip : svr->name, &cares->addr.v6) == 1)
{
cares->byaddr = EINA_TRUE;
cares->isv6 = EINA_TRUE;
else
{
cares->byaddr = EINA_FALSE;
- ares_gethostbyname(info_channel, svr->name, ai_family,
+ ares_gethostbyname(info_channel, svr->ecs ? svr->ecs->ip : svr->name, ai_family,
(ares_host_callback)_ecore_con_info_ares_host_cb,
cares);
}
goto on_mem_error;
addri->sin_family = AF_INET;
- addri->sin_port = htons(arg->svr->port);
+ addri->sin_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
memcpy(&addri->sin_addr.s_addr,
hostent->h_addr_list[0], sizeof(struct in_addr));
goto on_mem_error;
addri6->sin6_family = AF_INET6;
- addri6->sin6_port = htons(arg->svr->port);
+ addri6->sin6_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
addri6->sin6_flowinfo = 0;
addri6->sin6_scope_id = 0;
goto on_mem_error;
addri6->sin6_family = AF_INET6;
- addri6->sin6_port = htons(arg->svr->port);
+ addri6->sin6_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
addri6->sin6_flowinfo = 0;
addri6->sin6_scope_id = 0;
goto on_mem_error;
addri->sin_family = AF_INET;
- addri->sin_port = htons(arg->svr->port);
+ addri->sin_port = htons(arg->svr->ecs ? arg->svr->ecs->port : arg->svr->port);
memcpy(&addri->sin_addr.s_addr,
&arg->addr.v4, sizeof(struct in_addr));
int canonname_len = 0;
int err;
- eina_convert_itoa(svr->port, service);
+ eina_convert_itoa(svr->ecs ? svr->ecs->port : svr->port, service);
/* CHILD */
- if (!getaddrinfo(svr->name, service, hints, &result) && result)
+ if (!getaddrinfo(svr->ecs ? svr->ecs->ip : svr->name, service, hints, &result) && result)
{
if (result->ai_canonname)
canonname_len = strlen(result->ai_canonname) + 1;
typedef struct _Ecore_Con_Lookup Ecore_Con_Lookup;
typedef struct _Ecore_Con_Info Ecore_Con_Info;
-
+typedef struct Ecore_Con_Socks_v4 Ecore_Con_Socks_v4;
+typedef struct Ecore_Con_Socks_v5 Ecore_Con_Socks_v5;
typedef void (*Ecore_Con_Info_Cb)(void *data, Ecore_Con_Info *infos);
typedef enum _Ecore_Con_State
ECORE_CON_SSL_STATE_INIT
} Ecore_Con_Ssl_State;
+typedef enum Ecore_Con_Socks_State
+{
+ ECORE_CON_SOCKS_STATE_DONE = 0,
+ ECORE_CON_SOCKS_STATE_RESOLVED,
+ ECORE_CON_SOCKS_STATE_INIT,
+ ECORE_CON_SOCKS_STATE_READ
+} Ecore_Con_Socks_State;
+
struct _Ecore_Con_Client
{
ECORE_MAGIC;
#endif
Ecore_Con_Ssl_State ssl_state;
Eina_Bool handshaking : 1;
- Eina_Bool upgrade : 1;
- Eina_Bool dead : 1;
- Eina_Bool delete_me : 1;
+ Eina_Bool upgrade : 1; /* STARTTLS queued */
+ Eina_Bool delete_me : 1; /* del event has been queued */
};
struct _Ecore_Con_Server
Eina_List *event_count;
int client_limit;
pid_t ppid;
+ /* socks */
+ Ecore_Con_Socks *ecs;
+ Ecore_Con_Socks_State ecs_state;
+ int ecs_addrlen;
+ unsigned char ecs_addr[16];
+ unsigned int ecs_buf_offset;
+ Eina_Binbuf *ecs_buf;
+ Eina_Binbuf *ecs_recvbuf;
+ const char *proxyip;
+ int proxyport;
+ /* endsocks */
+ const char *verify_name;
#if USE_GNUTLS
gnutls_session_t session;
gnutls_anon_client_credentials_t anoncred_c;
double disconnect_time;
double client_disconnect_time;
const char *ip;
- Eina_Bool dead : 1;
Eina_Bool created : 1; /* EINA_TRUE if server is our listening server */
Eina_Bool connecting : 1; /* EINA_FALSE if just initialized or connected */
Eina_Bool handshaking : 1; /* EINA_TRUE if server is ssl handshaking */
- Eina_Bool upgrade : 1;
+ Eina_Bool upgrade : 1; /* STARTTLS queued */
Eina_Bool ssl_prepared : 1;
Eina_Bool use_cert : 1; /* EINA_TRUE if using certificate auth */
Ecore_Con_Ssl_State ssl_state; /* current state of ssl handshake on the server */
Eina_Bool verify : 1; /* EINA_TRUE if certificates will be verified */
Eina_Bool verify_basic : 1; /* EINA_TRUE if certificates will be verified only against the hostname */
Eina_Bool reject_excess_clients : 1;
- Eina_Bool delete_me : 1;
+ Eina_Bool delete_me : 1; /* del event has been queued */
#ifdef _WIN32
Eina_Bool want_write : 1;
Eina_Bool read_stop : 1;
Eina_List *additional_headers;
Eina_List *response_headers;
const char *url;
+ long proxy_type;
+
+ Ecore_Timer *timer;
Ecore_Con_Url_Time time_condition;
double timestamp;
const void *data;
};
+#define ECORE_CON_SOCKS_CAST_ELSE(X) \
+ Ecore_Con_Socks_v4 *v4 = NULL; \
+ Ecore_Con_Socks_v5 *v5 = NULL; \
+ if ((X) && ((X)->version == 4)) \
+ v4 = (Ecore_Con_Socks_v4*)(X); \
+ else if ((X) && ((X)->version == 5)) \
+ v5 = (Ecore_Con_Socks_v5*)(X); \
+ else
+
+struct Ecore_Con_Socks
+{
+ unsigned char version;
+
+ const char *ip;
+ int port;
+ const char *username;
+ Eina_Bool lookup : 1;
+ Eina_Bool bind : 1;
+};
+
+struct Ecore_Con_Socks_v4
+{
+ unsigned char version;
+
+ const char *ip;
+ int port;
+ const char *username;
+ Eina_Bool lookup : 1;
+ Eina_Bool bind : 1;
+};
+
+struct Ecore_Con_Socks_v5
+{
+ unsigned char version;
+
+ const char *ip;
+ int port;
+ const char *username;
+ Eina_Bool lookup : 1;
+ Eina_Bool bind : 1;
+};
+
+extern Ecore_Con_Socks *_ecore_con_proxy_once;
+extern Ecore_Con_Socks *_ecore_con_proxy_global;
+void ecore_con_socks_init(void);
+void ecore_con_socks_shutdown(void);
+Eina_Bool ecore_con_socks_svr_init(Ecore_Con_Server *svr);
+void ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num);
+void ecore_con_socks_dns_cb(const char *canonname, const char *ip, struct sockaddr *addr, int addrlen, Ecore_Con_Server *svr);
/* from ecore_con.c */
void ecore_con_server_infos_del(Ecore_Con_Server *svr, void *info);
+void ecore_con_event_proxy_bind(Ecore_Con_Server *svr);
void ecore_con_event_server_data(Ecore_Con_Server *svr, unsigned char *buf, int num, Eina_Bool duplicate);
void ecore_con_event_server_del(Ecore_Con_Server *svr);
-void ecore_con_event_server_error(Ecore_Con_Server *svr, const char *error);
+#define ecore_con_event_server_error(svr, error) _ecore_con_event_server_error((svr), (char*)(error), EINA_TRUE)
+void _ecore_con_event_server_error(Ecore_Con_Server *svr, char *error, Eina_Bool duplicate);
void ecore_con_event_client_add(Ecore_Con_Client *cl);
void ecore_con_event_client_data(Ecore_Con_Client *cl, unsigned char *buf, int num, Eina_Bool duplicate);
void ecore_con_event_client_del(Ecore_Con_Client *cl);
void ecore_con_event_client_error(Ecore_Con_Client *cl, const char *error);
-
+void _ecore_con_server_kill(Ecore_Con_Server *svr);
/* from ecore_local_win32.c */
#ifdef _WIN32
Eina_Bool ecore_con_local_listen(Ecore_Con_Server *svr);
GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Del, ecore_con_event_server_del);
GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Write, ecore_con_event_server_write);
GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Server_Data, ecore_con_event_server_data);
+GENERIC_ALLOC_FREE_HEADER(Ecore_Con_Event_Proxy_Bind, ecore_con_event_proxy_bind);
void ecore_con_mempool_init(void);
void ecore_con_mempool_shutdown(void);
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_NET_IF_H
+# include <net/if.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+#include "Ecore_Con.h"
+#include "ecore_con_private.h"
+
+#define _ecore_con_server_kill(svr) do { \
+ DBG("KILL %p", (svr)); \
+ _ecore_con_server_kill((svr)); \
+} while (0)
+
+Eina_List *ecore_con_socks_proxies = NULL;
+
+static Ecore_Con_Socks *
+_ecore_con_socks_find(unsigned char version, const char *ip, int port, const char *username)
+{
+ Eina_List *l;
+ Ecore_Con_Socks *ecs;
+
+ if (!ecore_con_socks_proxies) return NULL;
+
+ EINA_LIST_FOREACH(ecore_con_socks_proxies, l, ecs)
+ {
+ if (ecs->version != version) continue;
+ if (strcmp(ecs->ip, ip)) continue;
+ if ((port != -1) && (port != ecs->port)) continue;
+ if (username && strcmp(ecs->username, username)) continue;
+ return ecs;
+ }
+ return NULL;
+}
+
+static void
+_ecore_con_socks_free(Ecore_Con_Socks *ecs)
+{
+ ECORE_CON_SOCKS_CAST_ELSE(ecs) return;
+
+ if (_ecore_con_proxy_once == ecs) _ecore_con_proxy_once = NULL;
+ if (_ecore_con_proxy_global == ecs) _ecore_con_proxy_global = NULL;
+ eina_stringshare_del(ecs->ip);
+ eina_stringshare_del(ecs->username);
+ free(ecs);
+}
+/////////////////////////////////////////////////////////////////////////////////////
+void
+ecore_con_socks_shutdown(void)
+{
+ Ecore_Con_Socks *ecs;
+ EINA_LIST_FREE(ecore_con_socks_proxies, ecs)
+ _ecore_con_socks_free(ecs);
+ _ecore_con_proxy_once = NULL;
+ _ecore_con_proxy_global = NULL;
+}
+
+void
+ecore_con_socks_read(Ecore_Con_Server *svr, unsigned char *buf, int num)
+{
+ const unsigned char *data;
+ ECORE_CON_SOCKS_CAST_ELSE(svr->ecs) return;
+
+ if (svr->ecs_state != ECORE_CON_SOCKS_STATE_READ) return;
+
+ if (v4)
+ {
+ DBG("SOCKS: %d bytes", num);
+ if (num < 8)
+ {
+ if (!svr->ecs_recvbuf) svr->ecs_recvbuf = eina_binbuf_new();
+ if (!svr->ecs_recvbuf) goto error;
+ eina_binbuf_append_length(svr->ecs_recvbuf, buf, num);
+ /* the slowest connection on earth */
+ if (eina_binbuf_length_get(svr->ecs_recvbuf) != 8) return;
+ data = eina_binbuf_string_get(svr->ecs_recvbuf);
+ }
+ else if (num > 8) goto error;
+ else
+ data = buf;
+
+ /* http://ufasoft.com/doc/socks4_protocol.htm */
+ if (data[0]) goto error;
+ switch (data[1])
+ {
+ case 90:
+ /* success! */
+ break;
+ case 91:
+ ecore_con_event_server_error(svr, "proxy request rejected or failed");
+ goto error;
+ case 92:
+ ecore_con_event_server_error(svr, "proxying SOCKS server could not perform authentication");
+ goto error;
+ case 93:
+ ecore_con_event_server_error(svr, "proxy request authentication rejected");
+ goto error;
+ default:
+ ecore_con_event_server_error(svr, "garbage data from proxy");
+ goto error;
+ }
+ if (svr->ecs->bind)
+ {
+ unsigned int nport;
+ char naddr[IF_NAMESIZE];
+
+ memcpy(&nport, &data[2], 2);
+ svr->proxyport = ntohl(nport);
+
+ if (!inet_ntop(AF_INET, &data[4], naddr, sizeof(naddr))) goto error;
+ svr->proxyip = eina_stringshare_add(naddr);
+ ecore_con_event_proxy_bind(svr);
+ }
+ svr->ecs_state = ECORE_CON_SOCKS_STATE_DONE;
+ INF("PROXY CONNECTED");
+ if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf);
+ svr->ecs_recvbuf = NULL;
+ svr->ecs_buf_offset = svr->ecs_addrlen = 0;
+ memset(svr->ecs_addr, 0, sizeof(svr->ecs_addr));
+ if (!svr->ssl_state)
+ ecore_con_event_server_add(svr);
+ if (svr->ssl_state || (svr->buf && eina_binbuf_length_get(svr->buf)))
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ | ECORE_FD_WRITE);
+ }
+ return;
+error:
+ _ecore_con_server_kill(svr);
+}
+
+Eina_Bool
+ecore_con_socks_svr_init(Ecore_Con_Server *svr)
+{
+ unsigned char *sbuf;
+ ECORE_CON_SOCKS_CAST_ELSE(svr->ecs) return EINA_FALSE;
+
+ if (!svr->ip) return EINA_FALSE;
+ if (svr->ecs_buf) return EINA_FALSE;
+ if (svr->ecs_state != ECORE_CON_SOCKS_STATE_INIT) return EINA_FALSE;
+ ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE);
+ if (v4)
+ {
+ size_t addrlen, buflen, ulen = 1;
+ addrlen = svr->ecs->lookup ? strlen(svr->name) + 1: 0;
+ if (svr->ecs->username) ulen += strlen(svr->ecs->username);
+ buflen = sizeof(char) * (8 + ulen + addrlen);
+ sbuf = malloc(buflen);
+ if (!sbuf)
+ {
+ ecore_con_event_server_error(svr, "Memory allocation failure!");
+ _ecore_con_server_kill(svr);
+ return EINA_FALSE;
+ }
+ /* http://en.wikipedia.org/wiki/SOCKS */
+ sbuf[0] = 4;
+ sbuf[1] = v4->bind ? 2 : 1;
+ sbuf[2] = svr->port >> 8;
+ sbuf[3] = svr->port & 0xff;
+ if (addrlen)
+ {
+ sbuf[4] = sbuf[5] = sbuf[6] = 0;
+ sbuf[7] = 1;
+ }
+ else
+ memcpy(sbuf + 4, svr->ecs_addr, 4);
+ if (svr->ecs->username)
+ memcpy(sbuf + 8, svr->ecs->username, ulen);
+ else
+ sbuf[8] = 0;
+ if (addrlen) memcpy(sbuf + 8 + ulen, svr->name, addrlen);
+
+ svr->ecs_buf = eina_binbuf_manage_new_length(sbuf, buflen);
+ }
+ return EINA_TRUE;
+}
+
+void
+ecore_con_socks_dns_cb(const char *canonname __UNUSED__, const char *ip, struct sockaddr *addr, int addrlen, Ecore_Con_Server *svr)
+{
+ svr->ip = eina_stringshare_add(ip);
+ svr->ecs_addrlen = addrlen;
+ svr->ecs_state++;
+ if (addr->sa_family == AF_INET)
+ memcpy(svr->ecs_addr, &((struct sockaddr_in *)addr)->sin_addr.s_addr, 4);
+#ifdef HAVE_IPV6
+ else
+ memcpy(svr->ecs_addr, &((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, addrlen);
+#endif
+ ecore_con_socks_svr_init(svr);
+}
+
+void
+ecore_con_socks_init(void)
+{
+ const char *socks;
+ char *u, *h, *p, *l;
+ char buf[64];
+ int port, lookup = 0;
+ Ecore_Con_Socks *ecs;
+ unsigned char addr[sizeof(struct in_addr)];
+
+ /* ECORE_CON_SOCKS_V4=user@host:port:[1|0] */
+ socks = getenv("ECORE_CON_SOCKS_V4");
+ if ((!socks) || (!socks[0]) || (strlen(socks) > 64)) return;
+ strncpy(buf, socks, sizeof(buf));
+ h = strchr(buf, '@');
+ u = NULL;
+ /* username */
+ if (h && (h - buf > 0)) *h++ = 0, u = buf;
+ else h = buf;
+
+ /* host ip; I ain't resolvin shit here */
+ p = strchr(h, ':');
+ if (!p) return;
+ *p++ = 0;
+ if (!inet_pton(AF_INET, h, addr)) return;
+
+ errno = 0;
+ port = strtol(p, &l, 10);
+ if (errno || (port < 0) || (port > 65535)) return;
+ if (l && (l[0] == ':'))
+ lookup = (l[1] == '1');
+ ecs = ecore_con_socks4_remote_add(h, port, u);
+ if (!ecs) return;
+ ecore_con_socks4_lookup_set(ecs, lookup);
+ ecore_con_socks_apply_always(ecs);
+ INF("Added global proxy server %s%s%s:%d - DNS lookup %s",
+ u ?: "", u ? "@" : "", h, port, lookup ? "ENABLED" : "DISABLED");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @defgroup Ecore_Con_Socks_Group Ecore Connection SOCKS functions
+ * @{
+ */
+
+/**
+ * Add a SOCKS v4 proxy to the proxy list
+ *
+ * Use this to create (or return, if previously added) a SOCKS proxy
+ * object which can be used by any ecore_con servers.
+ * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
+ * @param port The port to connect to on the proxy
+ * @param username The username to use for the proxy (OPTIONAL)
+ * @return An allocated proxy object, or NULL on failure
+ * @note This object NEVER needs to be explicitly freed.
+ * @since 1.2
+ */
+EAPI Ecore_Con_Socks *
+ecore_con_socks4_remote_add(const char *ip, int port, const char *username)
+{
+ Ecore_Con_Socks *ecs;
+
+ if ((!ip) || (!ip[0]) || (port < 0) || (port > 65535)) return NULL;
+
+ ecs = _ecore_con_socks_find(4, ip, port, username);
+ if (ecs) return ecs;
+
+ ecs = calloc(1, sizeof(Ecore_Con_Socks_v4));
+ if (!ecs) return NULL;
+
+ ecs->version = 4;
+ ecs->ip = eina_stringshare_add(ip);
+ ecs->port = port;
+ ecs->username = eina_stringshare_add(username);
+ ecore_con_socks_proxies = eina_list_append(ecore_con_socks_proxies, ecs);
+ return ecs;
+}
+
+/**
+ * Set DNS lookup mode on an existing SOCKS v4 proxy
+ *
+ * According to RFC, SOCKS v4 does not require that a proxy perform
+ * its own DNS lookups for addresses. SOCKS v4a specifies the protocol
+ * for this. If you want to enable remote DNS lookup and are sure that your
+ * proxy supports it, use this function.
+ * @param ecs The proxy object
+ * @param enable If true, the proxy will perform the dns lookup
+ * @note By default, this setting is DISABLED.
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks4_lookup_set(Ecore_Con_Socks *ecs, Eina_Bool enable)
+{
+ ECORE_CON_SOCKS_CAST_ELSE(ecs) return;
+ if (v4) v4->lookup = !!enable;
+}
+
+/**
+ * Get DNS lookup mode on an existing SOCKS v4 proxy
+ *
+ * According to RFC, SOCKS v4 does not require that a proxy perform
+ * its own DNS lookups for addresses. SOCKS v4a specifies the protocol
+ * for this. This function returns whether lookups are enabled on a proxy object.
+ * @param ecs The proxy object
+ * @return If true, the proxy will perform the dns lookup
+ * @note By default, this setting is DISABLED.
+ * @since 1.2
+ */
+EAPI Eina_Bool
+ecore_con_socks4_lookup_get(Ecore_Con_Socks *ecs)
+{
+ ECORE_CON_SOCKS_CAST_ELSE(ecs) return EINA_FALSE;
+ return v4 ? v4->lookup : EINA_FALSE;
+}
+
+/**
+ * Find a SOCKS v4 proxy in the proxy list
+ *
+ * Use this to determine if a SOCKS proxy was previously added by checking
+ * the proxy list against the parameters given.
+ * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
+ * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip
+ * @param username The username used for the proxy (OPTIONAL)
+ * @return true only if a proxy exists matching the given params
+ * @note This function matches slightly more loosely than ecore_con_socks4_remote_add(), and
+ * ecore_con_socks4_remote_add() should be used to return the actual object.
+ * @since 1.2
+ */
+EAPI Eina_Bool
+ecore_con_socks4_remote_exists(const char *ip, int port, const char *username)
+{
+ if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0])))
+ return EINA_FALSE;
+ return !!_ecore_con_socks_find(4, ip, port, username);
+}
+
+/**
+ * Remove a SOCKS v4 proxy from the proxy list and delete it
+ *
+ * Use this to remove a SOCKS proxy from the proxy list by checking
+ * the list against the parameters given. The proxy will then be deleted.
+ * @param ip The ip address of the proxy (NOT DOMAIN NAME. IP ADDRESS.)
+ * @param port The port to connect to on the proxy, or -1 to match the first proxy with @p ip
+ * @param username The username used for the proxy (OPTIONAL)
+ * @note This function matches in the same way as ecore_con_socks4_remote_exists().
+ * @warning Be aware that deleting a proxy which is being used WILL ruin your life.
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks4_remote_del(const char *ip, int port, const char *username)
+{
+ Ecore_Con_Socks_v4 *v4;
+
+ if ((!ip) || (!ip[0]) || (port < -1) || (port > 65535) || (username && (!username[0]))) return;
+ if (!ecore_con_socks_proxies) return;
+
+ v4 = (Ecore_Con_Socks_v4*)_ecore_con_socks_find(4, ip, port, username);
+ if (!v4) return;
+ ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, v4);
+ _ecore_con_socks_free((Ecore_Con_Socks*)v4);
+}
+
+/**
+ * Enable bind mode on a SOCKS proxy
+ *
+ * Use this function to enable binding a remote port for use with a remote server.
+ * For more information, see http://ufasoft.com/doc/socks4_protocol.htm
+ * @param ecs The proxy object
+ * @param is_bind If true, the connection established will be a port binding
+ * @warning Be aware that changing the operation mode of an active proxy may result in undefined behavior
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks_bind_set(Ecore_Con_Socks *ecs, Eina_Bool is_bind)
+{
+ EINA_SAFETY_ON_NULL_RETURN(ecs);
+ ecs->bind = !!is_bind;
+}
+
+/**
+ * Return bind mode of a SOCKS proxy
+ *
+ * Use this function to return bind mode of a proxy (binding a remote port for use with a remote server).
+ * For more information, see http://ufasoft.com/doc/socks4_protocol.htm
+ * @param ecs The proxy object
+ * @return If true, the connection established will be a port binding
+ * @since 1.2
+ */
+EAPI Eina_Bool
+ecore_con_socks_bind_get(Ecore_Con_Socks *ecs)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ecs, EINA_FALSE);
+ return ecs->bind;
+}
+
+EAPI unsigned int
+ecore_con_socks_version_get(Ecore_Con_Socks *ecs)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ecs, 0);
+ return ecs->version;
+}
+
+/**
+ * Remove a SOCKS v4 proxy from the proxy list and delete it
+ *
+ * Use this to remove a SOCKS proxy from the proxy list by directly deleting the object given.
+ * @param ecs The proxy object to delete
+ * @warning Be aware that deleting a proxy which is being used WILL ruin your life.
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks_remote_del(Ecore_Con_Socks *ecs)
+{
+ EINA_SAFETY_ON_NULL_RETURN(ecs);
+ if (!ecore_con_socks_proxies) return;
+
+ ecore_con_socks_proxies = eina_list_remove(ecore_con_socks_proxies, ecs);
+ _ecore_con_socks_free(ecs);
+}
+
+/**
+ * Set a proxy object to be used with the next server created with ecore_con_server_connect()
+ *
+ * This function sets a proxy for the next ecore_con connection. After the next server is created,
+ * the proxy will NEVER be applied again unless explicitly enabled.
+ * @param ecs The proxy object
+ * @see ecore_con_socks_apply_always()
+ * @since 1.2
+ */
+EAPI void
+ecore_con_socks_apply_once(Ecore_Con_Socks *ecs)
+{
+ _ecore_con_proxy_once = ecs;
+}
+
+/**
+ * Set a proxy object to be used with all servers created with ecore_con_server_connect()
+ *
+ * This function sets a proxy for all ecore_con connections. It will always be used.
+ * @param ecs The proxy object
+ * @see ecore_con_socks_apply_once()
+ * @since 1.2
+ * @note ecore-con supports setting this through environment variables like so:
+ * ECORE_CON_SOCKS_V4=[user@]server:port:lookup
+ * user is the OPTIONAL string that would be passed to the proxy as the username
+ * server is the IP_ADDRESS of the proxy server
+ * port is the port to connect to on the proxy server
+ * lookup is 1 if the proxy should perform all DNS lookups, otherwise 0 or omitted
+ */
+EAPI void
+ecore_con_socks_apply_always(Ecore_Con_Socks *ecs)
+{
+ _ecore_con_proxy_global = ecs;
+}
+/** @} */
# include <ws2tcpip.h>
#endif
+#include <sys/stat.h>
#include "Ecore.h"
#include "ecore_con_private.h"
ecore_con_event_server_error(conn, buf);
}
+static void
+_gnutls_print_session(const gnutls_datum_t *cert_list, unsigned int cert_list_size)
+{
+ char *c = NULL;
+ gnutls_x509_crt_t crt;
+ unsigned int x;
+
+ if (!eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) return;
+ for (x = 0; x < cert_list_size; x++)
+ {
+ gnutls_x509_crt_init(&crt);
+ gnutls_x509_crt_import(crt, &cert_list[x], GNUTLS_X509_FMT_DER);
+ gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_FULL, (gnutls_datum_t*)&c);
+ INF("CERTIFICATE:\n%s", c);
+ gnutls_free(c);
+ gnutls_x509_crt_deinit(crt);
+ crt = NULL;
+ }
+}
+
#ifdef ISCOMFITOR
static void
_gnutls_log_func(int level,
const char *str)
{
- DBG("|<%d>| %s", level, str);
+ char buf[128];
+ strncat(buf, str, strlen(str) - 1);
+ DBG("|<%d>| %s", level, buf);
}
#endif
#elif USE_OPENSSL
static void
+_openssl_print_verify_error(int error)
+{
+ switch (error)
+ {
+#define ERROR(X) \
+ case (X): \
+ ERR("%s", #X); \
+ break
+#ifdef X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
+ ERROR(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_GET_CRL
+ ERROR(X509_V_ERR_UNABLE_TO_GET_CRL);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE
+ ERROR(X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE
+ ERROR(X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY
+ ERROR(X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
+#endif
+#ifdef X509_V_ERR_CERT_SIGNATURE_FAILURE
+ ERROR(X509_V_ERR_CERT_SIGNATURE_FAILURE);
+#endif
+#ifdef X509_V_ERR_CRL_SIGNATURE_FAILURE
+ ERROR(X509_V_ERR_CRL_SIGNATURE_FAILURE);
+#endif
+#ifdef X509_V_ERR_CERT_NOT_YET_VALID
+ ERROR(X509_V_ERR_CERT_NOT_YET_VALID);
+#endif
+#ifdef X509_V_ERR_CERT_HAS_EXPIRED
+ ERROR(X509_V_ERR_CERT_HAS_EXPIRED);
+#endif
+#ifdef X509_V_ERR_CRL_NOT_YET_VALID
+ ERROR(X509_V_ERR_CRL_NOT_YET_VALID);
+#endif
+#ifdef X509_V_ERR_CRL_HAS_EXPIRED
+ ERROR(X509_V_ERR_CRL_HAS_EXPIRED);
+#endif
+#ifdef X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD
+ ERROR(X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);
+#endif
+#ifdef X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD
+ ERROR(X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
+#endif
+#ifdef X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD
+ ERROR(X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD);
+#endif
+#ifdef X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD
+ ERROR(X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+#endif
+#ifdef X509_V_ERR_OUT_OF_MEM
+ ERROR(X509_V_ERR_OUT_OF_MEM);
+#endif
+#ifdef X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
+ ERROR(X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
+#endif
+#ifdef X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
+ ERROR(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
+ ERROR(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
+#endif
+#ifdef X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
+ ERROR(X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
+#endif
+#ifdef X509_V_ERR_CERT_CHAIN_TOO_LONG
+ ERROR(X509_V_ERR_CERT_CHAIN_TOO_LONG);
+#endif
+#ifdef X509_V_ERR_CERT_REVOKED
+ ERROR(X509_V_ERR_CERT_REVOKED);
+#endif
+#ifdef X509_V_ERR_INVALID_CA
+ ERROR(X509_V_ERR_INVALID_CA);
+#endif
+#ifdef X509_V_ERR_PATH_LENGTH_EXCEEDED
+ ERROR(X509_V_ERR_PATH_LENGTH_EXCEEDED);
+#endif
+#ifdef X509_V_ERR_INVALID_PURPOSE
+ ERROR(X509_V_ERR_INVALID_PURPOSE);
+#endif
+#ifdef X509_V_ERR_CERT_UNTRUSTED
+ ERROR(X509_V_ERR_CERT_UNTRUSTED);
+#endif
+#ifdef X509_V_ERR_CERT_REJECTED
+ ERROR(X509_V_ERR_CERT_REJECTED);
+#endif
+ /* These are 'informational' when looking for issuer cert */
+#ifdef X509_V_ERR_SUBJECT_ISSUER_MISMATCH
+ ERROR(X509_V_ERR_SUBJECT_ISSUER_MISMATCH);
+#endif
+#ifdef X509_V_ERR_AKID_SKID_MISMATCH
+ ERROR(X509_V_ERR_AKID_SKID_MISMATCH);
+#endif
+#ifdef X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH
+ ERROR(X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH);
+#endif
+#ifdef X509_V_ERR_KEYUSAGE_NO_CERTSIGN
+ ERROR(X509_V_ERR_KEYUSAGE_NO_CERTSIGN);
+#endif
+
+#ifdef X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER
+ ERROR(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER);
+#endif
+#ifdef X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION
+ ERROR(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION);
+#endif
+#ifdef X509_V_ERR_KEYUSAGE_NO_CRL_SIGN
+ ERROR(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN);
+#endif
+#ifdef X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION
+ ERROR(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION);
+#endif
+#ifdef X509_V_ERR_INVALID_NON_CA
+ ERROR(X509_V_ERR_INVALID_NON_CA);
+#endif
+#ifdef X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED
+ ERROR(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED);
+#endif
+#ifdef X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE
+ ERROR(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE);
+#endif
+#ifdef X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED
+ ERROR(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED);
+#endif
+
+#ifdef X509_V_ERR_INVALID_EXTENSION
+ ERROR(X509_V_ERR_INVALID_EXTENSION);
+#endif
+#ifdef X509_V_ERR_INVALID_POLICY_EXTENSION
+ ERROR(X509_V_ERR_INVALID_POLICY_EXTENSION);
+#endif
+#ifdef X509_V_ERR_NO_EXPLICIT_POLICY
+ ERROR(X509_V_ERR_NO_EXPLICIT_POLICY);
+#endif
+#ifdef X509_V_ERR_DIFFERENT_CRL_SCOPE
+ ERROR(X509_V_ERR_DIFFERENT_CRL_SCOPE);
+#endif
+#ifdef X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE
+ ERROR(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE);
+#endif
+
+#ifdef X509_V_ERR_UNNESTED_RESOURCE
+ ERROR(X509_V_ERR_UNNESTED_RESOURCE);
+#endif
+
+#ifdef X509_V_ERR_PERMITTED_VIOLATION
+ ERROR(X509_V_ERR_PERMITTED_VIOLATION);
+#endif
+#ifdef X509_V_ERR_EXCLUDED_VIOLATION
+ ERROR(X509_V_ERR_EXCLUDED_VIOLATION);
+#endif
+#ifdef X509_V_ERR_SUBTREE_MINMAX
+ ERROR(X509_V_ERR_SUBTREE_MINMAX);
+#endif
+#ifdef X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE
+ ERROR(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE);
+#endif
+#ifdef X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX
+ ERROR(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX);
+#endif
+#ifdef X509_V_ERR_UNSUPPORTED_NAME_SYNTAX
+ ERROR(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX);
+#endif
+#ifdef X509_V_ERR_CRL_PATH_VALIDATION_ERROR
+ ERROR(X509_V_ERR_CRL_PATH_VALIDATION_ERROR);
+#endif
+
+ /* The application is not happy */
+#ifdef X509_V_ERR_APPLICATION_VERIFICATION
+ ERROR(X509_V_ERR_APPLICATION_VERIFICATION);
+#endif
+ }
+#undef ERROR
+}
+
+static void
_openssl_print_errors(void *conn, int type)
{
char buf[1024];
EINA_SAFETY_ON_TRUE_RETURN_VAL(!s, EINA_FALSE);
/* same as above for the stored name */
EINA_SAFETY_ON_TRUE_RETURN_VAL(!strchr(s + 1, '.'), EINA_FALSE);
- EINA_SAFETY_ON_TRUE_RETURN_VAL(strcasecmp(s, name + 1), EINA_FALSE);
+ if (strcasecmp(s, name + 1))
+ {
+ ERR("%s != %s", s, name + 1);
+ return EINA_FALSE;
+ }
}
else
- EINA_SAFETY_ON_TRUE_RETURN_VAL(strcasecmp(name, svrname), EINA_FALSE);
+ if (strcasecmp(name, svrname))
+ {
+ ERR("%s != %s", name, svrname);
+ return EINA_FALSE;
+ }
return EINA_TRUE;
}
+static void
+_openssl_print_session(SSL *ssl)
+{
+ /* print session info into DBG */
+ SSL_SESSION *s;
+ STACK_OF(X509) *sk;
+ BIO *b;
+ char log[4096], *p;
+ int x;
+
+ if (!eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) return;
+
+ memset(log, 0, sizeof(log));
+ b = BIO_new(BIO_s_mem());
+ sk = SSL_get_peer_cert_chain(ssl);
+ if (sk)
+ {
+ DBG("CERTIFICATES:");
+ for (x = 0; x < sk_X509_num(sk); x++)
+ {
+ p = X509_NAME_oneline(X509_get_subject_name(sk_X509_value(sk, x)), log, sizeof(log));
+ DBG("%2d s:%s", x, p);
+ p = X509_NAME_oneline(X509_get_issuer_name(sk_X509_value(sk, x)), log, sizeof(log));
+ DBG(" i:%s", p);
+ PEM_write_X509(stderr, sk_X509_value(sk, x));
+ }
+ }
+ s = SSL_get_session(ssl);
+ SSL_SESSION_print(b, s);
+ fprintf(stderr, "\n");
+ while (BIO_read(b, log, sizeof(log)) > 0)
+ fprintf(stderr, "%s", log);
+
+ BIO_free(b);
+}
+
#endif
#define SSL_ERROR_CHECK_GOTO_ERROR(X) \
}
/**
+ * @brief Set the hostname to verify against in certificate verification
+ *
+ * Sometimes the certificate hostname will not match the hostname that you are
+ * connecting to, and will instead match a different name. An example of this is
+ * that if you connect to talk.google.com to use Google Talk, you receive Google's
+ * certificate for gmail.com. This certificate should be trusted, and so you must call
+ * this function with "gmail.com" as @p name.
+ * See RFC2818 for more details.
+ * @param svr The server object
+ * @param name The hostname to verify against
+ * @since 1.2
+ */
+EAPI void
+ecore_con_ssl_server_verify_name_set(Ecore_Con_Server *svr, const char *name)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__);
+ return;
+ }
+ eina_stringshare_replace(&svr->verify_name, name);
+}
+
+/**
+ * @brief Get the hostname to verify against in certificate verification
+ *
+ * This function returns the name which will be used to validate the SSL certificate
+ * common name (CN) or alt name (subjectAltName). It will default to the @p name
+ * param in ecore_con_server_connect(), but can be changed with ecore_con_ssl_server_verify_name_set().
+ * @param svr The server object
+ * @return The hostname which will be used
+ * @since 1.2
+ */
+EAPI const char *
+ecore_con_ssl_server_verify_name_get(Ecore_Con_Server *svr)
+{
+ if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+ {
+ ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__);
+ return NULL;
+ }
+ return svr->verify_name ?: svr->name;
+}
+
+/**
* @brief Add an ssl certificate for use in ecore_con functions.
*
* Use this function to add a SSL PEM certificate.
return EINA_FALSE;
}
+ if (!svr->ssl_prepared)
+ {
+ svr->use_cert = EINA_TRUE;
+ svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT;
+ if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL))
+ return EINA_FALSE;
+ }
+
return SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (svr, cert);
}
* If there is an error loading the CAs, an error will automatically be logged.
* @param ca_file The path to the CA file.
* @return EINA_FALSE if the file cannot be loaded, otherwise EINA_TRUE.
+ * @note since 1.2, this function can load directores
*/
EAPI Eina_Bool
return EINA_FALSE;
}
+ if (!svr->ssl_prepared)
+ {
+ svr->use_cert = EINA_TRUE;
+ svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT;
+ if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL))
+ return EINA_FALSE;
+ }
+
return SSL_SUFFIX(_ecore_con_ssl_server_cafile_add) (svr, ca_file);
}
return EINA_FALSE;
}
+ if (!svr->ssl_prepared)
+ {
+ svr->use_cert = EINA_TRUE;
+ svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT;
+ if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL))
+ return EINA_FALSE;
+ }
+
return SSL_SUFFIX(_ecore_con_ssl_server_privkey_add) (svr, key_file);
}
return EINA_FALSE;
}
+ if (!svr->ssl_prepared)
+ {
+ svr->use_cert = EINA_TRUE;
+ svr->type |= ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT;
+ if (ecore_con_ssl_server_prepare(svr, svr->type & ECORE_CON_SSL))
+ return EINA_FALSE;
+ }
+
return SSL_SUFFIX(_ecore_con_ssl_server_crl_add) (svr, crl_file);
}
if (ecore_con_ssl_server_prepare(svr, ssl_type))
return EINA_FALSE;
}
- svr->type |= ssl_type;
+ if (!svr->use_cert)
+ svr->type |= ssl_type;
svr->upgrade = EINA_TRUE;
svr->handshaking = EINA_TRUE;
svr->ssl_state = ECORE_CON_SSL_STATE_INIT;
if (ecore_con_ssl_server_prepare(cl->host_server, ssl_type))
return EINA_FALSE;
}
- cl->host_server->type |= ssl_type;
+ if (!cl->host_server->use_cert)
+ cl->host_server->type |= ssl_type;
cl->upgrade = EINA_TRUE;
cl->host_server->upgrade = EINA_TRUE;
cl->handshaking = EINA_TRUE;
return ECORE_CON_SSL_ERROR_INIT_FAILED;
#ifdef ISCOMFITOR
- gnutls_global_set_log_level(9);
- gnutls_global_set_log_function(_gnutls_log_func);
+ if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG))
+ {
+ gnutls_global_set_log_level(9);
+ gnutls_global_set_log_function(_gnutls_log_func);
+ }
#endif
return ECORE_CON_SSL_ERROR_NONE;
}
SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(svr->session, &cert_list_size)));
SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size);
+ _gnutls_print_session(cert_list, cert_list_size);
+
SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_init(&cert));
SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER));
- SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, svr->name));
+ SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, svr->verify_name ?: svr->name));
gnutls_x509_crt_deinit(cert);
DBG("SSL certificate verification succeeded!");
return ECORE_CON_SSL_ERROR_NONE;
_ecore_con_ssl_server_cafile_add_gnutls(Ecore_Con_Server *svr,
const char *ca_file)
{
- SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_trust_file(svr->cert, ca_file,
- GNUTLS_X509_FMT_PEM) < 1);
+ struct stat st;
+ Eina_Iterator *it;
+ const char *file;
+ Eina_Bool error = EINA_FALSE;
- return EINA_TRUE;
+ if (stat(ca_file, &st)) return EINA_FALSE;
+ if (S_ISDIR(st.st_mode))
+ {
+ it = eina_file_ls(ca_file);
+ SSL_ERROR_CHECK_GOTO_ERROR(!it);
+ EINA_ITERATOR_FOREACH(it, file)
+ {
+ if (!error)
+ {
+ if (gnutls_certificate_set_x509_trust_file(svr->cert, file, GNUTLS_X509_FMT_PEM) < 1)
+ error++;
+ }
+ eina_stringshare_del(file);
+ }
+ eina_iterator_free(it);
+ }
+ else
+ SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_trust_file(svr->cert, ca_file,
+ GNUTLS_X509_FMT_PEM) < 1);
+
+ return !error;
error:
ERR("Could not load CA file!");
return EINA_FALSE;
SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(cl->session, &cert_list_size)));
SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size);
+ _gnutls_print_session(cert_list, cert_list_size);
/*
gnutls_x509_crt_t cert = NULL;
SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_init(&cert));
break;
}
-#ifdef ISCOMFITOR
- {
- /* print session info into DBG */
- SSL_SESSION *s;
- BIO *b;
- char log[4096];
-
- memset(log, 0, sizeof(log));
- s = SSL_get_session(svr->ssl);
- b = BIO_new(BIO_s_mem());
- SSL_SESSION_print(b, s);
- while (BIO_read(b, log, sizeof(log)) > 0)
- DBG("%s", log);
-
- BIO_free(b);
- }
-#endif
+ _openssl_print_session(svr->ssl);
if ((!svr->verify) && (!svr->verify_basic))
/* not verifying certificates, so we're done! */
return ECORE_CON_SSL_ERROR_NONE;
cert = SSL_get_peer_certificate(svr->ssl);
if (cert)
{
- char buf[256] = {0};
+ char *c;
+ int clen;
+ int name = 0;
+
if (svr->verify)
- SSL_ERROR_CHECK_GOTO_ERROR(SSL_get_verify_result(svr->ssl));
- X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_subject_alt_name, buf, sizeof(buf));
- if (buf[0])
- SSL_ERROR_CHECK_GOTO_ERROR(!_openssl_name_verify(buf, svr->name));
- else
{
- X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, buf, sizeof(buf));
- SSL_ERROR_CHECK_GOTO_ERROR(!_openssl_name_verify(buf, svr->name));
+ int err;
+
+ err = SSL_get_verify_result(svr->ssl);
+ _openssl_print_verify_error(err);
+ SSL_ERROR_CHECK_GOTO_ERROR(err);
}
+ clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_subject_alt_name, NULL, 0);
+ if (clen > 0)
+ name = NID_subject_alt_name;
+ else
+ clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, NULL, 0);
+ SSL_ERROR_CHECK_GOTO_ERROR(clen < 1);
+ if (!name) name = NID_commonName;
+ c = alloca(++clen);
+ X509_NAME_get_text_by_NID(X509_get_subject_name(cert), name, c, clen);
+ INF("CERT NAME: %s\n", c);
+ SSL_ERROR_CHECK_GOTO_ERROR(!_openssl_name_verify(c, svr->verify_name ?: svr->name));
}
}
_ecore_con_ssl_server_cafile_add_openssl(Ecore_Con_Server *svr,
const char *ca_file)
{
- SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_load_verify_locations(svr->ssl_ctx, ca_file, NULL));
+ struct stat st;
+
+ if (stat(ca_file, &st)) return EINA_FALSE;
+ if (S_ISDIR(st.st_mode))
+ SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_load_verify_locations(svr->ssl_ctx, NULL, ca_file));
+ else
+ SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_load_verify_locations(svr->ssl_ctx, ca_file, NULL));
return EINA_TRUE;
error:
break;
}
-#ifdef ISCOMFITOR
- {
- /* print session info into DBG */
- SSL_SESSION *s;
- BIO *b;
- char log[4096];
-
- memset(log, 0, sizeof(log));
- s = SSL_get_session(cl->ssl);
- b = BIO_new(BIO_s_mem());
- SSL_SESSION_print(b, s);
- while (BIO_read(b, log, sizeof(log)) > 0)
- DBG("%s", log);
-
- BIO_free(b);
- }
-#endif
-
+ _openssl_print_session(cl->ssl);
if (!cl->host_server->verify)
/* not verifying certificates, so we're done! */
return ECORE_CON_SSL_ERROR_NONE;
SSL_set_verify(cl->ssl, SSL_VERIFY_PEER, NULL);
/* use CRL/CA lists to verify */
if (SSL_get_peer_certificate(cl->ssl))
- SSL_ERROR_CHECK_GOTO_ERROR(SSL_get_verify_result(cl->ssl));
+ {
+ int err;
+
+ err = SSL_get_verify_result(cl->ssl);
+ _openssl_print_verify_error(err);
+ SSL_ERROR_CHECK_GOTO_ERROR(err);
+ }
return ECORE_CON_SSL_ERROR_NONE;
void *ev);
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 Eina_Bool _ecore_con_url_timeout_cb(void *data);
static Eina_List *_url_con_list = NULL;
static Eina_List *_fd_hd_list = NULL;
return NULL;
}
+ url_con->proxy_type = -1;
+ if (_ecore_con_proxy_global)
+ {
+ if (_ecore_con_proxy_global->ip)
+ {
+ char host[128];
+ if (_ecore_con_proxy_global->port > 0 &&
+ _ecore_con_proxy_global->port <= 65535)
+ snprintf(host, sizeof(host), "socks4://%s:%d",
+ _ecore_con_proxy_global->ip,
+ _ecore_con_proxy_global->port);
+ else
+ snprintf(host, sizeof(host), "socks4://%s",
+ _ecore_con_proxy_global->ip);
+ ecore_con_url_proxy_set(url_con, host);
+ }
+ }
+
ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_ENCODING, "gzip,deflate");
if (ret != CURLE_OK)
{
{
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);
}
curl_easy_cleanup(url_con->curl_easy);
}
+ if (url_con->timer) ecore_timer_del(url_con->timer);
- _url_con_list = eina_list_remove(_url_con_list, url_con);
curl_slist_free_all(url_con->headers);
EINA_LIST_FREE(url_con->additional_headers, s)
free(s);
return res;
}
+EAPI Eina_Bool
+ecore_con_url_proxy_set(Ecore_Con_Url *url_con, const char *proxy)
+{
+#ifdef HAVE_CURL
+ int res = -1;
+ curl_version_info_data *vers = NULL;
+
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_set");
+ return EINA_FALSE;
+ }
+
+ if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
+ if (!url_con->url) return EINA_FALSE;
+
+ if (!proxy) res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXY, "");
+ else
+ {
+ // before curl version 7.21.7, socks protocol:// prefix is not supported
+ // (e.g. socks4://, socks4a://, socks5:// or socks5h://, etc.)
+ vers = curl_version_info(CURLVERSION_NOW);
+ if (vers->version_num < 0x71507)
+ {
+ url_con->proxy_type = CURLPROXY_HTTP;
+ if (strstr(proxy, "socks4")) url_con->proxy_type = CURLPROXY_SOCKS4;
+ else if (strstr(proxy, "socks4a")) url_con->proxy_type = CURLPROXY_SOCKS4A;
+ else if (strstr(proxy, "socks5")) url_con->proxy_type = CURLPROXY_SOCKS5;
+ else if (strstr(proxy, "socks5h")) url_con->proxy_type = CURLPROXY_SOCKS5_HOSTNAME;
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXYTYPE, url_con->proxy_type);
+ if (res != CURLE_OK)
+ {
+ ERR("curl proxy type setting failed: %s", curl_easy_strerror(res));
+ url_con->proxy_type = -1;
+ return EINA_FALSE;
+ }
+ }
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXY, proxy);
+ }
+ if (res != CURLE_OK)
+ {
+ ERR("curl proxy setting failed: %s", curl_easy_strerror(res));
+ url_con->proxy_type = -1;
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ (void)url_con;
+ (void)proxy;
+#endif
+}
+
+EAPI void
+ecore_con_url_timeout_set(Ecore_Con_Url *url_con, double timeout)
+{
+#ifdef HAVE_CURL
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_timeout_set");
+ return;
+ }
+
+ if (eina_list_data_find(_url_con_list, url_con)) return;
+ if (!url_con->url || timeout < 0) return;
+ if (url_con->timer) ecore_timer_del(url_con->timer);
+ url_con->timer = ecore_timer_add(timeout, _ecore_con_url_timeout_cb, url_con);
+#else
+ return;
+ (void)url_con;
+ (void)timeout;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_con_url_proxy_username_set(Ecore_Con_Url *url_con, const char *username)
+{
+#ifdef HAVE_CURL
+ int res = -1;
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_username_set");
+ return EINA_FALSE;
+ }
+
+ if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
+ if (!url_con->url) return EINA_FALSE;
+ if (!username) return EINA_FALSE;
+ if (url_con->proxy_type == CURLPROXY_SOCKS4 || url_con->proxy_type == CURLPROXY_SOCKS4A)
+ {
+ ERR("Proxy type should be socks5 and above");
+ return EINA_FALSE;
+ }
+
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERNAME, username);
+ if (res != CURLE_OK)
+ {
+ ERR("curl_easy_setopt() failed: %s", curl_easy_strerror(res));
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ (void)url_con;
+ (void)username;
+#endif
+}
+
+EAPI Eina_Bool
+ecore_con_url_proxy_password_set(Ecore_Con_Url *url_con, const char *password)
+{
+#ifdef HAVE_CURL
+ int res = -1;
+ if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
+ {
+ ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_password_set");
+ return EINA_FALSE;
+ }
+ if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
+ if (!url_con->url) return EINA_FALSE;
+ if (!password) return EINA_FALSE;
+ if (url_con->proxy_type == CURLPROXY_SOCKS4 || url_con->proxy_type == CURLPROXY_SOCKS4A)
+ {
+ ERR("Proxy type should be socks5 and above");
+ return EINA_FALSE;
+ }
+
+ res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PASSWORD, password);
+ if (res != CURLE_OK)
+ {
+ ERR("curl_easy_setopt() failed: %s", curl_easy_strerror(res));
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+#else
+ return EINA_FALSE;
+ (void)url_con;
+ (void)password;
+#endif
+}
/**
* @}
*/
#ifdef HAVE_CURL
+static Eina_Bool
+_ecore_con_url_timeout_cb(void *data)
+{
+ Ecore_Con_Url *url_con = data;
+ CURLMcode ret;
+ Ecore_Con_Event_Url_Complete *e;
+
+ if (!url_con) return ECORE_CALLBACK_CANCEL;
+ if (!url_con->curl_easy) return ECORE_CALLBACK_CANCEL;
+ if (!eina_list_data_find(_url_con_list, url_con)) return ECORE_CALLBACK_CANCEL;
+
+ 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);
+
+ curl_slist_free_all(url_con->headers);
+ url_con->headers = NULL;
+
+ url_con->timer = NULL;
+
+ 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);
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
static size_t
_ecore_con_url_data_cb(void *buffer,
size_t size,
# include <config.h>
#endif
+#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef BUILD_ECORE_CON
#define ECORE_MAGIC_FILE_DOWNLOAD_JOB 0xf7427cb8
+#define ECORE_FILE_DOWNLOAD_TIMEOUT 30
struct _Ecore_File_Download_Job
{
}
if (headers) eina_hash_foreach(headers, _ecore_file_download_headers_foreach_cb, job);
+ ecore_con_url_timeout_set(job->url_con, ECORE_FILE_DOWNLOAD_TIMEOUT);
ecore_con_url_fd_set(job->url_con, fileno(job->file));
ecore_con_url_data_set(job->url_con, data);