yet another ecore_con overhaul!

*internal function rename
*******finally fix ssl handshaking to be non-blocking


SVN revision: 52665
This commit is contained in:
Mike Blumenkrantz 2010-09-24 04:15:42 +00:00
parent e7392af747
commit 60b4269b5f
3 changed files with 204 additions and 119 deletions

View File

@ -1266,7 +1266,7 @@ _ecore_con_client_free(Ecore_Con_Client *cl)
}
static void
kill_server(Ecore_Con_Server *svr)
_ecore_con_server_kill(Ecore_Con_Server *svr)
{
if (!svr->delete_me)
{
@ -1385,7 +1385,7 @@ _ecore_con_cb_tcp_listen(void *data, Ecore_Con_Info *net_info)
error:
ecore_con_ssl_server_shutdown(svr);
kill_server(svr);
_ecore_con_server_kill(svr);
}
static void
@ -1461,7 +1461,7 @@ _ecore_con_cb_udp_listen(void *data, Ecore_Con_Info *net_info)
error:
ecore_con_ssl_server_shutdown(svr);
kill_server(svr);
_ecore_con_server_kill(svr);
}
static void
@ -1523,8 +1523,13 @@ _ecore_con_cb_tcp_connect(void *data, Ecore_Con_Info *net_info)
svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
_ecore_con_cl_handler, svr, NULL, NULL);
if ((svr->type & ECORE_CON_SSL) && (ecore_con_ssl_server_init(svr)))
goto error;
if (svr->type & ECORE_CON_SSL)
{
svr->handshaking = EINA_TRUE;
svr->ssl_state = ECORE_CON_SSL_STATE_INIT;
if (ecore_con_ssl_server_init(svr))
goto error;
}
if (!svr->fd_handler)
goto error;
@ -1535,7 +1540,7 @@ _ecore_con_cb_tcp_connect(void *data, Ecore_Con_Info *net_info)
error:
ecore_con_ssl_server_shutdown(svr);
kill_server(svr);
_ecore_con_server_kill(svr);
}
static void
@ -1586,7 +1591,7 @@ _ecore_con_cb_udp_connect(void *data, Ecore_Con_Info *net_info)
error:
ecore_con_ssl_server_shutdown(svr);
kill_server(svr);
_ecore_con_server_kill(svr);
}
static Ecore_Con_State
@ -1616,7 +1621,7 @@ svr_try_connect_plain(Ecore_Con_Server *svr)
if (so_err != 0)
{
/* we lost our server! */
kill_server(svr);
_ecore_con_server_kill(svr);
return ECORE_CON_DISCONNECTED;
}
@ -1658,7 +1663,7 @@ static Ecore_Con_State svr_try_connect(Ecore_Con_Server *svr)
return svr_try_connect_plain(svr);
case ECORE_CON_DISCONNECTED:
kill_server(svr);
_ecore_con_server_kill(svr);
return ECORE_CON_DISCONNECTED;
default:
@ -1740,8 +1745,13 @@ _ecore_con_svr_tcp_handler(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__)
cl->fd = new_fd;
cl->host_server = svr;
if ((svr->type & ECORE_CON_SSL) && (ecore_con_ssl_client_init(cl)))
goto error;
if (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 error;
}
cl->fd_handler = ecore_main_fd_handler_add(cl->fd, ECORE_FD_READ,
_ecore_con_svr_cl_handler, cl, NULL, NULL);
@ -1751,7 +1761,7 @@ _ecore_con_svr_tcp_handler(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__)
if (!svr->path)
cl->ip = _ecore_con_pretty_ip((struct sockaddr *)&incoming, size_in);
if (!cl->delete_me)
if ((!cl->delete_me) && (!cl->handshaking))
{
Ecore_Con_Event_Client_Add *e;
@ -1818,7 +1828,7 @@ _ecore_con_cl_read(Ecore_Con_Server *svr)
}
if (lost_server)
kill_server(svr);
_ecore_con_server_kill(svr);
break;
}
@ -1851,6 +1861,17 @@ _ecore_con_cl_handler(void *data, Ecore_Fd_Handler *fd_handler)
if (svr->delete_me)
return ECORE_CALLBACK_RENEW;
if (svr->handshaking)
{
if (ecore_con_ssl_server_init(svr))
{
ERR("ssl handshaking failed!");
ecore_main_fd_handler_del(svr->fd_handler);
close(svr->fd);
}
return ECORE_CALLBACK_RENEW;
}
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
_ecore_con_cl_read(svr);
else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE))
@ -1912,7 +1933,7 @@ _ecore_con_cl_udp_handler(void *data, Ecore_Fd_Handler *fd_handler)
else if ((errno == EIO) || (errno == EBADF) ||
(errno == EPIPE) || (errno == EINVAL) ||
(errno == ENOSPC) || (errno == ECONNREFUSED))
kill_server(svr);
_ecore_con_server_kill(svr);
}
else if (ecore_main_fd_handler_active_get(fd_handler,
ECORE_FD_WRITE))
@ -2153,6 +2174,17 @@ _ecore_con_svr_cl_handler(void *data, Ecore_Fd_Handler *fd_handler)
if (cl->delete_me)
return ECORE_CALLBACK_RENEW;
if (cl->handshaking)
{
if (ecore_con_ssl_client_init(cl))
{
ERR("ssl handshaking failed!");
ecore_main_fd_handler_del(cl->fd_handler);
close(cl->fd);
}
return ECORE_CALLBACK_RENEW;
}
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
_ecore_con_svr_cl_read(cl);
@ -2189,7 +2221,7 @@ _ecore_con_server_flush(Ecore_Con_Server *svr)
if (count < 1)
{
/* we lost our server! */
kill_server(svr);
_ecore_con_server_kill(svr);
return;
}

View File

@ -75,6 +75,13 @@ typedef enum _Ecore_Con_Ssl_Error
ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED
} Ecore_Con_Ssl_Error;
typedef enum _Ecore_Con_Ssl_Handshake
{
ECORE_CON_SSL_STATE_DONE = 0,
ECORE_CON_SSL_STATE_HANDSHAKING,
ECORE_CON_SSL_STATE_INIT
} Ecore_Con_Ssl_State;
struct _Ecore_Con_Client
{
ECORE_MAGIC;
@ -98,6 +105,8 @@ struct _Ecore_Con_Client
SSL *ssl;
int ssl_err;
#endif
Eina_Bool handshaking : 1;
Ecore_Con_Ssl_State ssl_state;
Eina_Bool dead : 1;
Eina_Bool delete_me : 1;
};
@ -139,6 +148,8 @@ struct _Ecore_Con_Server
Eina_Bool dead : 1;
Eina_Bool created : 1; /* EINA_TRUE if server is our listening server */
Eina_Bool connecting : 1;
Eina_Bool handshaking : 1; /* EINA_TRUE if server is ssl handshaking */
Ecore_Con_Ssl_State ssl_state;
Eina_Bool reject_excess_clients : 1;
Eina_Bool delete_me : 1;
};

View File

@ -362,56 +362,66 @@ _ecore_con_ssl_server_init_gnutls(Ecore_Con_Server *svr)
GNUTLS_SSL3,
0
};
if (svr->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */
return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED;
switch (svr->type & ECORE_CON_SSL)
switch (svr->ssl_state)
{
case ECORE_CON_USE_SSL3:
case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT:
proto = ssl3_proto;
break;
case ECORE_CON_SSL_STATE_DONE:
return ECORE_CON_SSL_ERROR_NONE;
case ECORE_CON_SSL_STATE_INIT:
if (svr->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */
return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED;
case ECORE_CON_USE_TLS:
case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT:
proto = tls_proto;
break;
switch (svr->type & ECORE_CON_SSL)
{
case ECORE_CON_USE_SSL3:
case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT:
proto = ssl3_proto;
break;
case ECORE_CON_USE_MIXED:
case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT:
proto = mixed_proto;
break;
case ECORE_CON_USE_TLS:
case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT:
proto = tls_proto;
break;
default:
return ECORE_CON_SSL_ERROR_NONE;
}
case ECORE_CON_USE_MIXED:
case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT:
proto = mixed_proto;
break;
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&svr->session, GNUTLS_CLIENT));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_set_default_priority(svr->session));
default:
return ECORE_CON_SSL_ERROR_NONE;
}
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_CERTIFICATE, svr->cert));
//SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_PSK, svr->pskcred_c));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_ANON, svr->anoncred_c));
if (!((svr->type & ECORE_CON_SSL) & ECORE_CON_LOAD_CERT))
{
int kx[] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, 0 };
int cipher[] = { GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_3DES_CBC, 0 };
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_cipher_set_priority(svr->session, cipher));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_kx_set_priority(svr->session, kx));
}
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&svr->session, GNUTLS_CLIENT));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_set_default_priority(svr->session));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_protocol_set_priority(svr->session, proto));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_compression_set_priority(svr->session, compress));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_CERTIFICATE, svr->cert));
//SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_PSK, svr->pskcred_c));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(svr->session, GNUTLS_CRD_ANON, svr->anoncred_c));
if (!((svr->type & ECORE_CON_SSL) & ECORE_CON_LOAD_CERT))
{
int kx[] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, 0 };
int cipher[] = { GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_3DES_CBC, 0 };
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_cipher_set_priority(svr->session, cipher));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_kx_set_priority(svr->session, kx));
}
gnutls_dh_set_prime_bits(svr->session, 512);
gnutls_transport_set_ptr(svr->session, (gnutls_transport_ptr_t)svr->fd);
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_protocol_set_priority(svr->session, proto));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_compression_set_priority(svr->session, compress));
do
{
gnutls_dh_set_prime_bits(svr->session, 512);
gnutls_transport_set_ptr(svr->session, (gnutls_transport_ptr_t)svr->fd);
svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
case ECORE_CON_SSL_STATE_HANDSHAKING:
ret = gnutls_handshake(svr->session);
SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret));
} while (ret < 0);
if (!ret)
{
svr->handshaking = EINA_FALSE;
svr->ssl_state = ECORE_CON_SSL_STATE_DONE;
}
default:
break;
}
return ECORE_CON_SSL_ERROR_NONE;
@ -581,57 +591,68 @@ _ecore_con_ssl_client_init_gnutls(Ecore_Con_Client *cl)
GNUTLS_TLS1_0,
GNUTLS_SSL3,
0 };
if (cl->host_server->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */
return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED;
switch (cl->host_server->type & ECORE_CON_SSL)
switch (cl->ssl_state)
{
case ECORE_CON_USE_SSL3:
case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT:
proto = ssl3_proto;
break;
case ECORE_CON_SSL_STATE_DONE:
return ECORE_CON_SSL_ERROR_NONE;
case ECORE_CON_SSL_STATE_INIT:
if (cl->host_server->type & ECORE_CON_USE_SSL2) /* not supported because of security issues */
return ECORE_CON_SSL_ERROR_SSL2_NOT_SUPPORTED;
case ECORE_CON_USE_TLS:
case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT:
proto = tls_proto;
break;
switch (cl->host_server->type & ECORE_CON_SSL)
{
case ECORE_CON_USE_SSL3:
case ECORE_CON_USE_SSL3 | ECORE_CON_LOAD_CERT:
proto = ssl3_proto;
break;
case ECORE_CON_USE_MIXED:
case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT:
proto = mixed_proto;
break;
case ECORE_CON_USE_TLS:
case ECORE_CON_USE_TLS | ECORE_CON_LOAD_CERT:
proto = tls_proto;
break;
default:
return ECORE_CON_SSL_ERROR_NONE;
}
case ECORE_CON_USE_MIXED:
case ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT:
proto = mixed_proto;
break;
_client_connected++;
default:
return ECORE_CON_SSL_ERROR_NONE;
}
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&cl->session, GNUTLS_SERVER));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_set_default_priority(cl->session));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_protocol_set_priority(cl->session, proto));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_compression_set_priority(cl->session, compress));
_client_connected++;
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_ANON, cl->host_server->anoncred_s));
//SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_PSK, cl->host_server->pskcred_s));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_CERTIFICATE, cl->host_server->cert));
if (!((cl->host_server->type & ECORE_CON_SSL) & ECORE_CON_LOAD_CERT))
{
int kx[] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, 0 };
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_kx_set_priority(cl->session, kx));
}
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_init(&cl->session, GNUTLS_SERVER));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_set_default_priority(cl->session));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_protocol_set_priority(cl->session, proto));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_compression_set_priority(cl->session, compress));
gnutls_certificate_server_set_request(cl->session, GNUTLS_CERT_REQUEST);
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_ANON, cl->host_server->anoncred_s));
//SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_PSK, cl->host_server->pskcred_s));
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_credentials_set(cl->session, GNUTLS_CRD_CERTIFICATE, cl->host_server->cert));
if (!((cl->host_server->type & ECORE_CON_SSL) & ECORE_CON_LOAD_CERT))
{
int kx[] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, 0 };
SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_kx_set_priority(cl->session, kx));
}
gnutls_dh_set_prime_bits(cl->session, 2048);
gnutls_transport_set_ptr(cl->session, (gnutls_transport_ptr_t)cl->fd);
gnutls_certificate_server_set_request(cl->session, GNUTLS_CERT_REQUEST);
do
{
gnutls_dh_set_prime_bits(cl->session, 2048);
gnutls_transport_set_ptr(cl->session, (gnutls_transport_ptr_t)cl->fd);
cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
case ECORE_CON_SSL_STATE_HANDSHAKING:
ret = gnutls_handshake(cl->session);
SSL_ERROR_CHECK_GOTO_ERROR(gnutls_error_is_fatal(ret));
} while (ret < 0);
if (!ret)
{
cl->handshaking = EINA_FALSE;
cl->ssl_state = ECORE_CON_SSL_STATE_DONE;
}
default:
break;
}
/* TODO: add cert verification support */
return ECORE_CON_SSL_ERROR_NONE;
@ -875,31 +896,42 @@ error:
static Ecore_Con_Ssl_Error
_ecore_con_ssl_server_init_openssl(Ecore_Con_Server *svr)
{
int ret = -1;
int err, ret = -1;
SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl = SSL_new(svr->ssl_ctx)));
SSL_ERROR_CHECK_GOTO_ERROR(!SSL_set_fd(svr->ssl, svr->fd));
SSL_set_connect_state(svr->ssl);
do
switch (svr->ssl_state)
{
int err;
case ECORE_CON_SSL_STATE_DONE:
return ECORE_CON_SSL_ERROR_NONE;
case ECORE_CON_SSL_STATE_INIT:
SSL_ERROR_CHECK_GOTO_ERROR(!(svr->ssl = SSL_new(svr->ssl_ctx)));
SSL_ERROR_CHECK_GOTO_ERROR(!SSL_set_fd(svr->ssl, svr->fd));
SSL_set_connect_state(svr->ssl);
svr->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
case ECORE_CON_SSL_STATE_HANDSHAKING:
ret = SSL_do_handshake(svr->ssl);
err = SSL_get_error(svr->ssl, ret);
SSL_ERROR_CHECK_GOTO_ERROR((err == SSL_ERROR_SYSCALL) || (err == SSL_ERROR_SSL));
} while (ret < 1);
if (ret == 1)
{
svr->handshaking = EINA_FALSE;
svr->ssl_state = ECORE_CON_SSL_STATE_DONE;
}
default:
break;
}
return ECORE_CON_SSL_ERROR_NONE;
error:
do
{
unsigned long err;
unsigned long sslerr;
err = ERR_get_error();
if (!err) break;
ERR("openssl error: %s", ERR_reason_error_string(err));
sslerr = ERR_get_error();
if (!sslerr) break;
ERR("openssl error: %s", ERR_reason_error_string(sslerr));
} while (1);
_ecore_con_ssl_server_shutdown_openssl(svr);
return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
@ -1078,30 +1110,40 @@ _ecore_con_ssl_server_write_openssl(Ecore_Con_Server *svr, unsigned char *buf,
static Ecore_Con_Ssl_Error
_ecore_con_ssl_client_init_openssl(Ecore_Con_Client *cl)
{
int ret = -1;
SSL_ERROR_CHECK_GOTO_ERROR(!(cl->ssl = SSL_new(cl->host_server->ssl_ctx)));
SSL_ERROR_CHECK_GOTO_ERROR(!SSL_set_fd(cl->ssl, cl->fd));
SSL_set_accept_state(cl->ssl);
do
int err, ret = -1;
switch (cl->ssl_state)
{
int err;
case ECORE_CON_SSL_STATE_DONE:
return ECORE_CON_SSL_ERROR_NONE;
case ECORE_CON_SSL_STATE_INIT:
SSL_ERROR_CHECK_GOTO_ERROR(!(cl->ssl = SSL_new(cl->host_server->ssl_ctx)));
SSL_ERROR_CHECK_GOTO_ERROR(!SSL_set_fd(cl->ssl, cl->fd));
SSL_set_accept_state(cl->ssl);
cl->ssl_state = ECORE_CON_SSL_STATE_HANDSHAKING;
case ECORE_CON_SSL_STATE_HANDSHAKING:
ret = SSL_do_handshake(cl->ssl);
err = SSL_get_error(cl->ssl, ret);
SSL_ERROR_CHECK_GOTO_ERROR((err == SSL_ERROR_SYSCALL) || (err == SSL_ERROR_SSL));
} while (ret < 1);
if (ret == 1)
{
cl->handshaking = EINA_FALSE;
cl->ssl_state = ECORE_CON_SSL_STATE_DONE;
}
default:
break;
}
return ECORE_CON_SSL_ERROR_NONE;
error:
do
{
unsigned long err;
unsigned long sslerr;
err = ERR_get_error();
if (!err) break;
ERR("openssl error: %s", ERR_reason_error_string(err));
sslerr = ERR_get_error();
if (!sslerr) break;
ERR("openssl error: %s", ERR_reason_error_string(sslerr));
} while (1);
_ecore_con_ssl_client_shutdown_openssl(cl);
return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;