forked from enlightenment/efl
efl_net_{server,dialer}_ssl: TCP + SSL easy to use.
in the previous commit we're manually upgrading an existing TCP socket to SSL. It is desired since some protocols need to negotiate, like STARTTLS and the likes Now we offer 2 classes that does autostart SSL once the socket is ready.
This commit is contained in:
parent
5e8dd491a5
commit
a5ebf67a83
|
@ -22,6 +22,8 @@ ecore_con_eolian_files = \
|
|||
lib/ecore_con/efl_net_server_udp_client.eo \
|
||||
lib/ecore_con/efl_net_socket_ssl.eo \
|
||||
lib/ecore_con/efl_net_ssl_context.eo \
|
||||
lib/ecore_con/efl_net_dialer_ssl.eo \
|
||||
lib/ecore_con/efl_net_server_ssl.eo \
|
||||
lib/ecore_con/ecore_con_eet_base.eo \
|
||||
lib/ecore_con/ecore_con_eet_server_obj.eo \
|
||||
lib/ecore_con/ecore_con_eet_client_obj.eo \
|
||||
|
@ -100,7 +102,9 @@ lib/ecore_con/efl_net_server_tcp.c \
|
|||
lib/ecore_con/efl_net_server_udp.c \
|
||||
lib/ecore_con/efl_net_server_udp_client.c \
|
||||
lib/ecore_con/efl_net_socket_ssl.c \
|
||||
lib/ecore_con/efl_net_ssl_context.c
|
||||
lib/ecore_con/efl_net_ssl_context.c \
|
||||
lib/ecore_con/efl_net_dialer_ssl.c \
|
||||
lib/ecore_con/efl_net_server_ssl.c
|
||||
|
||||
EXTRA_DIST2 += lib/ecore_con/ecore_con_legacy.c
|
||||
|
||||
|
|
|
@ -324,6 +324,10 @@ static const Ecore_Getopt options = {
|
|||
"If set will change the base chunk size used while reading."),
|
||||
ECORE_GETOPT_STORE_DOUBLE('t', "inactivity-timeout",
|
||||
"If greater than zero, specifies the number of seconds without any reads or writes that the copier will be timed out."),
|
||||
|
||||
ECORE_GETOPT_STORE_FALSE(0, "no-ssl-verify",
|
||||
"Disables SSL verify, to use with self-signed certificates and the likes"),
|
||||
|
||||
ECORE_GETOPT_VERSION('V', "version"),
|
||||
ECORE_GETOPT_COPYRIGHT('C', "copyright"),
|
||||
ECORE_GETOPT_LICENSE('L', "license"),
|
||||
|
@ -339,6 +343,7 @@ static const Ecore_Getopt options = {
|
|||
#ifndef _WIN32
|
||||
"unix://path to connect to an AF_UNIX server. For Linux one can create abstract sockets with unix://abstract:name.\n"
|
||||
#endif
|
||||
"ssl://IP:PORT to connect using TCP+SSL and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n"
|
||||
"",
|
||||
"input-file"),
|
||||
ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
|
||||
|
@ -354,6 +359,7 @@ static const Ecore_Getopt options = {
|
|||
#ifndef _WIN32
|
||||
"unix://path to connect to an AF_UNIX server. For Linux one can create abstract sockets with unix://abstract:name.\n"
|
||||
#endif
|
||||
"ssl://IP:PORT to connect using TCP+SSL and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n"
|
||||
"",
|
||||
"output-file"),
|
||||
ECORE_GETOPT_SENTINEL
|
||||
|
@ -369,6 +375,7 @@ main(int argc, char **argv)
|
|||
unsigned long buffer_limit = 0;
|
||||
unsigned long read_chunk_size = 0;
|
||||
double timeout = 0.0;
|
||||
Eina_Bool ssl_verify = EINA_TRUE;
|
||||
Eina_Bool quit_option = EINA_FALSE;
|
||||
Ecore_Getopt_Value values[] = {
|
||||
ECORE_GETOPT_VALUE_STR(line_delimiter),
|
||||
|
@ -376,6 +383,8 @@ main(int argc, char **argv)
|
|||
ECORE_GETOPT_VALUE_ULONG(read_chunk_size),
|
||||
ECORE_GETOPT_VALUE_DOUBLE(timeout),
|
||||
|
||||
ECORE_GETOPT_VALUE_BOOL(ssl_verify),
|
||||
|
||||
/* standard block to provide version, copyright, license and help */
|
||||
ECORE_GETOPT_VALUE_BOOL(quit_option), /* -V/--version quits */
|
||||
ECORE_GETOPT_VALUE_BOOL(quit_option), /* -C/--copyright quits */
|
||||
|
@ -572,6 +581,36 @@ main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
else if (strncmp(input_fname, "ssl://", strlen("ssl://")) == 0)
|
||||
{
|
||||
/*
|
||||
* Since Efl.Net.Socket implements the required interfaces,
|
||||
* they can be used here as well.
|
||||
*/
|
||||
const char *address = input_fname + strlen("ssl://");
|
||||
Eina_Error err;
|
||||
input = efl_add(EFL_NET_DIALER_SSL_CLASS, ecore_main_loop_get(),
|
||||
efl_event_callback_array_add(efl_added, input_cbs(), NULL), /* optional */
|
||||
efl_event_callback_array_add(efl_added, dialer_cbs(), NULL) /* optional */
|
||||
);
|
||||
if (!input)
|
||||
{
|
||||
fprintf(stderr, "ERROR: could not create SSL Dialer.\n");
|
||||
retval = EXIT_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
efl_net_socket_ssl_verify_mode_set(input, ssl_verify ? EFL_NET_SSL_VERIFY_MODE_REQUIRED : EFL_NET_SSL_VERIFY_MODE_NONE);
|
||||
efl_net_socket_ssl_hostname_verify_set(input, ssl_verify);
|
||||
|
||||
err = efl_net_dialer_dial(input, address);
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "ERROR: could not SSL dial %s: %s\n",
|
||||
address, eina_error_msg_get(err));
|
||||
goto end_input;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* regular file, open with flags: read-only and close-on-exec */
|
||||
|
@ -787,6 +826,36 @@ main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
else if (strncmp(output_fname, "ssl://", strlen("ssl://")) == 0)
|
||||
{
|
||||
/*
|
||||
* Since Efl.Net.Socket implements the required interfaces,
|
||||
* they can be used here as well.
|
||||
*/
|
||||
const char *address = output_fname + strlen("ssl://");
|
||||
Eina_Error err;
|
||||
output = efl_add(EFL_NET_DIALER_SSL_CLASS, ecore_main_loop_get(),
|
||||
efl_event_callback_array_add(efl_added, output_cbs(), NULL), /* optional */
|
||||
efl_event_callback_array_add(efl_added, dialer_cbs(), NULL) /* optional */
|
||||
);
|
||||
if (!output)
|
||||
{
|
||||
fprintf(stderr, "ERROR: could not create SSL Dialer.\n");
|
||||
retval = EXIT_FAILURE;
|
||||
goto end_input;
|
||||
}
|
||||
|
||||
efl_net_socket_ssl_verify_mode_set(output, ssl_verify ? EFL_NET_SSL_VERIFY_MODE_REQUIRED : EFL_NET_SSL_VERIFY_MODE_NONE);
|
||||
efl_net_socket_ssl_hostname_verify_set(output, ssl_verify);
|
||||
|
||||
err = efl_net_dialer_dial(output, address);
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "ERROR: could not SSL dial %s: %s\n",
|
||||
address, eina_error_msg_get(err));
|
||||
goto end_output;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* regular file, open with flags: write-only, close-on-exec,
|
||||
|
|
|
@ -474,12 +474,21 @@ EFL_CALLBACKS_ARRAY_DEFINE(server_cbs,
|
|||
static const char * protocols[] = {
|
||||
"tcp",
|
||||
"udp",
|
||||
"ssl",
|
||||
#ifndef _WIN32
|
||||
"unix",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *ciphers_strs[] = {
|
||||
"auto",
|
||||
"sslv3",
|
||||
"tlsv1",
|
||||
"tlsv1.1",
|
||||
"tlsv1.2",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const Ecore_Getopt options = {
|
||||
"efl_net_server_example", /* program name */
|
||||
|
@ -518,6 +527,13 @@ static const Ecore_Getopt options = {
|
|||
"Disable multicast loopback."),
|
||||
ECORE_GETOPT_APPEND('M', "udp-multicast-group", "Join a multicast group in the form 'IP@INTERFACE', with optional '@INTERFACE', where INTERFACE is the IP address of the interface to join the multicast.", ECORE_GETOPT_TYPE_STR),
|
||||
|
||||
ECORE_GETOPT_CATEGORY("ssl", "SSL options"),
|
||||
ECORE_GETOPT_CHOICE('c', "ssl-cipher", "Cipher to use, defaults to 'auto'", ciphers_strs),
|
||||
ECORE_GETOPT_APPEND(0, "ssl-certificate", "certificate path to use.", ECORE_GETOPT_TYPE_STR),
|
||||
ECORE_GETOPT_APPEND(0, "ssl-private-key", "private key path to use.", ECORE_GETOPT_TYPE_STR),
|
||||
ECORE_GETOPT_APPEND(0, "ssl-crl", "certificate revogation list to use.", ECORE_GETOPT_TYPE_STR),
|
||||
ECORE_GETOPT_APPEND(0, "ssl-ca", "certificate authorities path to use.", ECORE_GETOPT_TYPE_STR),
|
||||
|
||||
ECORE_GETOPT_CHOICE_METAVAR(0, NULL, "The server protocol.", "protocol",
|
||||
protocols),
|
||||
ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
|
||||
|
@ -543,6 +559,11 @@ main(int argc, char **argv)
|
|||
Eina_Bool ipv6_only = EINA_TRUE;
|
||||
Eina_Bool udp_dont_route = EINA_FALSE;
|
||||
Eina_Bool udp_mcast_loopback = EINA_TRUE;
|
||||
Eina_List *certificates = NULL;
|
||||
Eina_List *private_keys = NULL;
|
||||
Eina_List *crls = NULL;
|
||||
Eina_List *cas = NULL;
|
||||
char *cipher_choice = NULL;
|
||||
Eina_Bool quit_option = EINA_FALSE;
|
||||
Ecore_Getopt_Value values[] = {
|
||||
ECORE_GETOPT_VALUE_BOOL(echo),
|
||||
|
@ -563,6 +584,13 @@ main(int argc, char **argv)
|
|||
ECORE_GETOPT_VALUE_BOOL(udp_mcast_loopback),
|
||||
ECORE_GETOPT_VALUE_LIST(udp_mcast_groups),
|
||||
|
||||
ECORE_GETOPT_VALUE_BOOL(quit_option), /* category: ssl */
|
||||
ECORE_GETOPT_VALUE_STR(cipher_choice),
|
||||
ECORE_GETOPT_VALUE_LIST(certificates),
|
||||
ECORE_GETOPT_VALUE_LIST(private_keys),
|
||||
ECORE_GETOPT_VALUE_LIST(crls),
|
||||
ECORE_GETOPT_VALUE_LIST(cas),
|
||||
|
||||
/* positional argument */
|
||||
ECORE_GETOPT_VALUE_STR(protocol),
|
||||
ECORE_GETOPT_VALUE_STR(address),
|
||||
|
@ -603,6 +631,7 @@ main(int argc, char **argv)
|
|||
|
||||
if (strcmp(protocol, "tcp") == 0) cls = EFL_NET_SERVER_TCP_CLASS;
|
||||
else if (strcmp(protocol, "udp") == 0) cls = EFL_NET_SERVER_UDP_CLASS;
|
||||
else if (strcmp(protocol, "ssl") == 0) cls = EFL_NET_SERVER_SSL_CLASS;
|
||||
#ifndef _WIN32
|
||||
else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_SERVER_UNIX_CLASS;
|
||||
#endif
|
||||
|
@ -642,6 +671,33 @@ main(int argc, char **argv)
|
|||
EINA_LIST_FOREACH(udp_mcast_groups, lst, str)
|
||||
efl_net_server_udp_multicast_join(server, str);
|
||||
}
|
||||
else if (cls == EFL_NET_SERVER_SSL_CLASS)
|
||||
{
|
||||
Eo *ssl_ctx;
|
||||
Efl_Net_Ssl_Cipher cipher = EFL_NET_SSL_CIPHER_AUTO;
|
||||
if (cipher_choice)
|
||||
{
|
||||
if (strcmp(cipher_choice, "auto") == 0)
|
||||
cipher = EFL_NET_SSL_CIPHER_AUTO;
|
||||
else if (strcmp(cipher_choice, "sslv3") == 0)
|
||||
cipher = EFL_NET_SSL_CIPHER_SSLV3;
|
||||
else if (strcmp(cipher_choice, "tlsv1") == 0)
|
||||
cipher = EFL_NET_SSL_CIPHER_TLSV1;
|
||||
else if (strcmp(cipher_choice, "tlsv1.1") == 0)
|
||||
cipher = EFL_NET_SSL_CIPHER_TLSV1_1;
|
||||
else if (strcmp(cipher_choice, "tlsv1.2") == 0)
|
||||
cipher = EFL_NET_SSL_CIPHER_TLSV1_2;
|
||||
}
|
||||
|
||||
ssl_ctx = efl_add(EFL_NET_SSL_CONTEXT_CLASS, NULL,
|
||||
efl_net_ssl_context_certificates_set(efl_added, eina_list_iterator_new(certificates)),
|
||||
efl_net_ssl_context_private_keys_set(efl_added, eina_list_iterator_new(private_keys)),
|
||||
efl_net_ssl_context_certificate_revogation_lists_set(efl_added, eina_list_iterator_new(crls)),
|
||||
efl_net_ssl_context_certificate_authorities_set(efl_added, eina_list_iterator_new(cas)),
|
||||
efl_net_ssl_context_setup(efl_added, cipher, EINA_FALSE /* a server! */));
|
||||
|
||||
efl_net_server_ssl_context_set(server, ssl_ctx);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
else if (cls == EFL_NET_SERVER_UNIX_CLASS)
|
||||
{
|
||||
|
|
|
@ -37,3 +37,5 @@
|
|||
|
||||
#include "efl_net_ssl_context.eo.h"
|
||||
#include "efl_net_socket_ssl.eo.h"
|
||||
#include "efl_net_dialer_ssl.eo.h"
|
||||
#include "efl_net_server_ssl.eo.h"
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
#define EFL_NET_DIALER_SSL_PROTECTED 1
|
||||
#define EFL_NET_DIALER_PROTECTED 1
|
||||
#define EFL_NET_SOCKET_PROTECTED 1
|
||||
#define EFL_IO_READER_PROTECTED 1
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "Ecore.h"
|
||||
#include "Ecore_Con.h"
|
||||
#include "ecore_con_private.h"
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_SSL_H
|
||||
# include <netinet/ssl.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_EVIL
|
||||
# include <Evil.h>
|
||||
#endif
|
||||
|
||||
#define MY_CLASS EFL_NET_DIALER_SSL_CLASS
|
||||
|
||||
typedef struct _Efl_Net_Dialer_Ssl_Data
|
||||
{
|
||||
Eo *sock;
|
||||
Eo *ssl_ctx;
|
||||
Efl_Future *connect_timeout;
|
||||
Eina_Bool connected;
|
||||
} Efl_Net_Dialer_Ssl_Data;
|
||||
|
||||
static void
|
||||
_efl_net_dialer_ssl_ready(void *data EINA_UNUSED, const Efl_Event *event)
|
||||
{
|
||||
Eo *o = event->object;
|
||||
efl_net_dialer_connected_set(o, EINA_TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_net_dialer_ssl_error(void *data EINA_UNUSED, const Efl_Event *event)
|
||||
{
|
||||
Eo *o = event->object;
|
||||
Eina_Error *perr = event->info;
|
||||
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_ERROR, perr);
|
||||
}
|
||||
|
||||
EFL_CALLBACKS_ARRAY_DEFINE(_efl_net_dialer_ssl_cbs,
|
||||
{ EFL_NET_SOCKET_SSL_EVENT_SSL_READY, _efl_net_dialer_ssl_ready },
|
||||
{ EFL_NET_SOCKET_SSL_EVENT_SSL_ERROR, _efl_net_dialer_ssl_error });
|
||||
|
||||
EOLIAN static Eo*
|
||||
_efl_net_dialer_ssl_efl_object_constructor(Eo *o, Efl_Net_Dialer_Ssl_Data *pd)
|
||||
{
|
||||
o = efl_constructor(efl_super(o, MY_CLASS));
|
||||
if (!o) return NULL;
|
||||
|
||||
pd->sock = efl_add(EFL_NET_DIALER_TCP_CLASS, o);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->sock, NULL);
|
||||
|
||||
efl_event_callback_array_add(o, _efl_net_dialer_ssl_cbs(), o);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
EOLIAN static Eo*
|
||||
_efl_net_dialer_ssl_efl_object_finalize(Eo *o, Efl_Net_Dialer_Ssl_Data *pd)
|
||||
{
|
||||
if (!pd->ssl_ctx)
|
||||
pd->ssl_ctx = efl_ref(efl_net_ssl_context_default_dialer_get(EFL_NET_SSL_CONTEXT_CLASS));
|
||||
|
||||
efl_net_socket_ssl_adopt(o, pd->sock, pd->ssl_ctx);
|
||||
return efl_finalize(efl_super(o, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_ssl_efl_object_destructor(Eo *o, Efl_Net_Dialer_Ssl_Data *pd)
|
||||
{
|
||||
if (efl_io_closer_close_on_destructor_get(o) &&
|
||||
(!efl_io_closer_closed_get(o)))
|
||||
efl_io_closer_close(o);
|
||||
|
||||
if (pd->sock)
|
||||
{
|
||||
efl_del(pd->sock);
|
||||
pd->sock = NULL;
|
||||
}
|
||||
|
||||
if (pd->ssl_ctx)
|
||||
{
|
||||
efl_unref(pd->ssl_ctx);
|
||||
pd->ssl_ctx = NULL;
|
||||
}
|
||||
|
||||
efl_destructor(efl_super(o, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_ssl_ssl_context_set(Eo *o, Efl_Net_Dialer_Ssl_Data *pd, Eo *ssl_ctx)
|
||||
{
|
||||
EINA_SAFETY_ON_TRUE_RETURN(efl_finalized_get(o));
|
||||
EINA_SAFETY_ON_FALSE_RETURN(efl_isa(ssl_ctx, EFL_NET_SSL_CONTEXT_CLASS));
|
||||
|
||||
if (pd->ssl_ctx == ssl_ctx) return;
|
||||
efl_unref(pd->ssl_ctx);
|
||||
pd->ssl_ctx = efl_ref(ssl_ctx);
|
||||
}
|
||||
|
||||
EOLIAN static Eo *
|
||||
_efl_net_dialer_ssl_ssl_context_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd)
|
||||
{
|
||||
return pd->ssl_ctx;
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_net_dialer_ssl_connect_timeout(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
Eo *o = data;
|
||||
Eina_Error err = ETIMEDOUT;
|
||||
|
||||
efl_ref(o);
|
||||
efl_io_reader_eos_set(o, EINA_TRUE);
|
||||
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_ERROR, &err);
|
||||
efl_unref(o);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Error
|
||||
_efl_net_dialer_ssl_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Ssl_Data *pd, const char *address)
|
||||
{
|
||||
double timeout;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
|
||||
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_net_dialer_connected_get(o), EISCONN);
|
||||
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(o), EBADF);
|
||||
|
||||
if (pd->connect_timeout)
|
||||
efl_future_cancel(pd->connect_timeout);
|
||||
|
||||
timeout = efl_net_dialer_timeout_dial_get(pd->sock);
|
||||
if (timeout > 0.0)
|
||||
{
|
||||
efl_future_use(&pd->connect_timeout, efl_loop_timeout(efl_loop_get(o), timeout, o));
|
||||
efl_future_then(pd->connect_timeout, _efl_net_dialer_ssl_connect_timeout, NULL, NULL, o);
|
||||
efl_future_link(o, pd->connect_timeout);
|
||||
}
|
||||
|
||||
return efl_net_dialer_dial(pd->sock, address);
|
||||
}
|
||||
|
||||
EOLIAN static const char *
|
||||
_efl_net_dialer_ssl_efl_net_dialer_address_dial_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_dialer_address_dial_get(pd->sock);
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_ssl_efl_net_dialer_proxy_set(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd, const char *proxy_url)
|
||||
{
|
||||
efl_net_dialer_proxy_set(pd->sock, proxy_url);
|
||||
}
|
||||
|
||||
EOLIAN static const char *
|
||||
_efl_net_dialer_ssl_efl_net_dialer_proxy_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_dialer_proxy_get(pd->sock);
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_ssl_efl_net_dialer_timeout_dial_set(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd, double seconds)
|
||||
{
|
||||
efl_net_dialer_timeout_dial_set(pd->sock, seconds);
|
||||
|
||||
if (pd->connect_timeout)
|
||||
efl_future_cancel(pd->connect_timeout);
|
||||
|
||||
if ((seconds > 0.0) && (!pd->connected))
|
||||
{
|
||||
efl_future_use(&pd->connect_timeout, efl_loop_timeout(efl_loop_get(o), seconds, o));
|
||||
efl_future_then(pd->connect_timeout, _efl_net_dialer_ssl_connect_timeout, NULL, NULL, o);
|
||||
}
|
||||
}
|
||||
|
||||
EOLIAN static double
|
||||
_efl_net_dialer_ssl_efl_net_dialer_timeout_dial_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_dialer_timeout_dial_get(pd->sock);
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_ssl_efl_net_dialer_connected_set(Eo *o, Efl_Net_Dialer_Ssl_Data *pd, Eina_Bool connected)
|
||||
{
|
||||
if (pd->connect_timeout)
|
||||
efl_future_cancel(pd->connect_timeout);
|
||||
if (pd->connected == connected) return;
|
||||
pd->connected = connected;
|
||||
if (connected) efl_event_callback_call(o, EFL_NET_DIALER_EVENT_CONNECTED, NULL);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_net_dialer_ssl_efl_net_dialer_connected_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd)
|
||||
{
|
||||
return pd->connected;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Error
|
||||
_efl_net_dialer_ssl_efl_io_closer_close(Eo *o, Efl_Net_Dialer_Ssl_Data *pd EINA_UNUSED)
|
||||
{
|
||||
efl_net_dialer_connected_set(o, EINA_FALSE);
|
||||
return efl_io_closer_close(efl_super(o, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_net_dialer_ssl_keep_alive_set(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd, Eina_Bool keep_alive)
|
||||
{
|
||||
return efl_net_dialer_ssl_keep_alive_set(pd->sock, keep_alive);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_net_dialer_ssl_keep_alive_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_dialer_ssl_keep_alive_get(pd->sock);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_net_dialer_ssl_no_delay_set(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd, Eina_Bool no_delay)
|
||||
{
|
||||
return efl_net_dialer_ssl_no_delay_set(pd->sock, no_delay);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_net_dialer_ssl_no_delay_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_socket_tcp_no_delay_get(pd->sock);
|
||||
}
|
||||
|
||||
#include "efl_net_dialer_ssl.eo.c"
|
|
@ -0,0 +1,78 @@
|
|||
class Efl.Net.Dialer.Ssl (Efl.Net.Socket.Ssl, Efl.Net.Dialer) {
|
||||
[[Connects to a remote SSL server using TCP.
|
||||
|
||||
This creates an internal @Efl.Net.Dialer.Tcp and once connected
|
||||
it will start the SSL handshake.
|
||||
|
||||
If the proxy is NULL (default), then the system proxy will be
|
||||
used. On UNIX that's the environment variable $socks_proxy (or
|
||||
'$proxy' or '$all_proxy') is used if the given address doesn't
|
||||
match $no_proxy patterns. To disable proxy use an empty string.
|
||||
|
||||
If the proxy is NULL (default), then the system proxy will be
|
||||
used. On UNIX that's the environment variable $socks_proxy (or
|
||||
'$all_proxy') is used if the given address doesn't match
|
||||
$no_proxy patterns. To disable proxy use an empty string. If
|
||||
provided proxy must be one of the protocols:
|
||||
|
||||
- socks5://username:password\@proxyserver:port (SOCKSv5)
|
||||
- socks5h://username\@proxyserver:port (let socks server to resolve domain)
|
||||
- socks5://proxyserver:port
|
||||
- socks5://proxyserver (default port 1080)
|
||||
- socks4a://proxyserver:port (SOCKSv4 and let socks server to resolve domain)
|
||||
- socks4://proxyserver:port (SOCKSv4)
|
||||
|
||||
@since 1.19
|
||||
]]
|
||||
|
||||
methods {
|
||||
@property ssl_context {
|
||||
[[Defines the SSL context to use for this dialer.
|
||||
|
||||
This specifies a shared context for all clients, with
|
||||
certificate, private keys, CRL, CAs...
|
||||
|
||||
It must be called before @Efl.Object.finalize!
|
||||
]]
|
||||
values {
|
||||
ssl_context: Efl.Net.Ssl.Context;
|
||||
}
|
||||
}
|
||||
|
||||
@property keep_alive {
|
||||
[[Controls keep-alive using SO_KEEPALIVE]]
|
||||
get { }
|
||||
set {
|
||||
return: bool (false); [[$true on success]]
|
||||
}
|
||||
values {
|
||||
keep_alive: bool;
|
||||
}
|
||||
}
|
||||
|
||||
@property no_delay {
|
||||
[[Controls TCP's no-delay using TCP_NODELAY]]
|
||||
get { }
|
||||
set {
|
||||
return: bool (false); [[$true on success]]
|
||||
}
|
||||
values {
|
||||
no_delay: bool;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: no cork as it doesn't make sense here for the wrapped connection */
|
||||
}
|
||||
|
||||
implements {
|
||||
Efl.Object.constructor;
|
||||
Efl.Object.destructor;
|
||||
Efl.Object.finalize;
|
||||
Efl.Net.Dialer.dial;
|
||||
Efl.Net.Dialer.address_dial.get;
|
||||
Efl.Net.Dialer.connected;
|
||||
Efl.Net.Dialer.proxy;
|
||||
Efl.Net.Dialer.timeout_dial;
|
||||
Efl.Io.Closer.close;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
#define EFL_NET_SERVER_SSL_PROTECTED 1
|
||||
#define EFL_NET_SERVER_FD_PROTECTED 1
|
||||
#define EFL_NET_SERVER_PROTECTED 1
|
||||
#define EFL_LOOP_FD_PROTECTED 1
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "Ecore.h"
|
||||
#include "Ecore_Con.h"
|
||||
#include "ecore_con_private.h"
|
||||
|
||||
#define MY_CLASS EFL_NET_SERVER_SSL_CLASS
|
||||
|
||||
typedef struct _Efl_Net_Server_Ssl_Data
|
||||
{
|
||||
Eo *server;
|
||||
Eo *ssl_ctx;
|
||||
} Efl_Net_Server_Ssl_Data;
|
||||
|
||||
static void
|
||||
_efl_net_server_ssl_tcp_client_add(void *data, const Efl_Event *event)
|
||||
{
|
||||
Eo *o = data;
|
||||
Efl_Net_Server_Ssl_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
||||
Eo *client_ssl;
|
||||
Eo *client_tcp = event->info;
|
||||
const char *addr = efl_net_socket_address_remote_get(client_tcp);
|
||||
|
||||
if (!pd->ssl_ctx)
|
||||
{
|
||||
ERR("ssl server %p rejecting client %p '%s' since no SSL context was set!", o, client_tcp, addr);
|
||||
efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_REJECTED, (void *)addr);
|
||||
return;
|
||||
}
|
||||
|
||||
client_ssl = efl_add(EFL_NET_SOCKET_SSL_CLASS, o,
|
||||
efl_net_socket_ssl_adopt(efl_added, client_tcp, pd->ssl_ctx));
|
||||
if (!client_ssl)
|
||||
{
|
||||
ERR("ssl server %p could not wrap client %p '%s' using context=%p", o, client_tcp, addr, pd->ssl_ctx);
|
||||
efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_REJECTED, (void *)addr);
|
||||
return;
|
||||
}
|
||||
|
||||
efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_ADD, client_ssl);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_net_server_ssl_tcp_client_rejected(void *data, const Efl_Event *event)
|
||||
{
|
||||
Eo *o = data;
|
||||
char *client = event->info;
|
||||
efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_REJECTED, client);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_net_server_ssl_tcp_error(void *data, const Efl_Event *event)
|
||||
{
|
||||
Eo *o = data;
|
||||
Eina_Error *perr = event->info;
|
||||
efl_event_callback_call(o, EFL_NET_SERVER_EVENT_ERROR, perr);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_net_server_ssl_tcp_serving(void *data, const Efl_Event *event EINA_UNUSED)
|
||||
{
|
||||
Eo *o = data;
|
||||
efl_event_callback_call(o, EFL_NET_SERVER_EVENT_SERVING, NULL);
|
||||
}
|
||||
|
||||
EFL_CALLBACKS_ARRAY_DEFINE(_efl_net_server_ssl_tcp_cbs,
|
||||
{ EFL_NET_SERVER_EVENT_CLIENT_ADD, _efl_net_server_ssl_tcp_client_add },
|
||||
{ EFL_NET_SERVER_EVENT_CLIENT_REJECTED, _efl_net_server_ssl_tcp_client_rejected },
|
||||
{ EFL_NET_SERVER_EVENT_ERROR, _efl_net_server_ssl_tcp_error },
|
||||
{ EFL_NET_SERVER_EVENT_SERVING, _efl_net_server_ssl_tcp_serving });
|
||||
|
||||
EOLIAN Efl_Object *
|
||||
_efl_net_server_ssl_efl_object_constructor(Eo *o, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
o = efl_constructor(efl_super(o, MY_CLASS));
|
||||
if (!o) return NULL;
|
||||
|
||||
pd->server = efl_add(EFL_NET_SERVER_TCP_CLASS, o,
|
||||
efl_event_callback_array_add(efl_added, _efl_net_server_ssl_tcp_cbs(), o));
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->server, NULL);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
EOLIAN void
|
||||
_efl_net_server_ssl_efl_object_destructor(Eo *o, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
if (pd->server)
|
||||
{
|
||||
efl_del(pd->server);
|
||||
pd->server = NULL;
|
||||
}
|
||||
|
||||
efl_destructor(efl_super(o, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_server_ssl_ssl_context_set(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd, Eo *ssl_ctx)
|
||||
{
|
||||
EINA_SAFETY_ON_FALSE_RETURN(efl_isa(ssl_ctx, EFL_NET_SSL_CONTEXT_CLASS));
|
||||
|
||||
if (pd->ssl_ctx == ssl_ctx) return;
|
||||
efl_unref(pd->ssl_ctx);
|
||||
pd->ssl_ctx = efl_ref(ssl_ctx);
|
||||
}
|
||||
|
||||
EOLIAN static Eo *
|
||||
_efl_net_server_ssl_ssl_context_get(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
return pd->ssl_ctx;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Error
|
||||
_efl_net_server_ssl_efl_net_server_serve(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd, const char *address)
|
||||
{
|
||||
return efl_net_server_serve(pd->server, address);
|
||||
}
|
||||
|
||||
EOLIAN static const char *
|
||||
_efl_net_server_ssl_efl_net_server_address_get(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_server_address_get(pd->server);
|
||||
}
|
||||
|
||||
EOLIAN static unsigned int
|
||||
_efl_net_server_ssl_efl_net_server_clients_count_get(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_server_clients_count_get(pd->server);
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_server_ssl_efl_net_server_clients_limit_set(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd, unsigned int limit, Eina_Bool reject_excess)
|
||||
{
|
||||
efl_net_server_clients_limit_set(pd->server, limit, reject_excess);
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_server_ssl_efl_net_server_clients_limit_get(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd, unsigned int *limit, Eina_Bool *reject_excess)
|
||||
{
|
||||
efl_net_server_clients_limit_get(pd->server, limit, reject_excess);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_net_server_ssl_efl_net_server_serving_get(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_server_serving_get(pd->server);
|
||||
}
|
||||
|
||||
EOLIAN int
|
||||
_efl_net_server_ssl_family_get(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_server_fd_family_get(pd->server);
|
||||
}
|
||||
|
||||
EOLIAN Eina_Bool
|
||||
_efl_net_server_ssl_close_on_exec_set(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd, Eina_Bool close_on_exec)
|
||||
{
|
||||
return efl_net_server_fd_close_on_exec_set(pd->server, close_on_exec);
|
||||
}
|
||||
|
||||
EOLIAN Eina_Bool
|
||||
_efl_net_server_ssl_close_on_exec_get(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_server_fd_close_on_exec_get(pd->server);
|
||||
}
|
||||
|
||||
EOLIAN Eina_Bool
|
||||
_efl_net_server_ssl_reuse_address_set(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd, Eina_Bool reuse_address)
|
||||
{
|
||||
return efl_net_server_fd_reuse_address_set(pd->server, reuse_address);
|
||||
}
|
||||
|
||||
EOLIAN Eina_Bool
|
||||
_efl_net_server_ssl_reuse_address_get(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_server_fd_reuse_address_get(pd->server);
|
||||
}
|
||||
|
||||
EOLIAN Eina_Bool
|
||||
_efl_net_server_ssl_reuse_port_set(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd, Eina_Bool reuse_port)
|
||||
{
|
||||
return efl_net_server_fd_reuse_port_set(pd->server, reuse_port);
|
||||
}
|
||||
|
||||
EOLIAN Eina_Bool
|
||||
_efl_net_server_ssl_reuse_port_get(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_server_fd_reuse_port_get(pd->server);
|
||||
}
|
||||
|
||||
EOLIAN void
|
||||
_efl_net_server_ssl_ipv6_only_set(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd, Eina_Bool ipv6_only)
|
||||
{
|
||||
efl_net_server_tcp_ipv6_only_set(pd->server, ipv6_only);
|
||||
}
|
||||
|
||||
EOLIAN Eina_Bool
|
||||
_efl_net_server_ssl_ipv6_only_get(Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd)
|
||||
{
|
||||
return efl_net_server_tcp_ipv6_only_get(pd->server);
|
||||
}
|
||||
|
||||
|
||||
#include "efl_net_server_ssl.eo.c"
|
|
@ -0,0 +1,111 @@
|
|||
class Efl.Net.Server.Ssl (Efl.Loop_User, Efl.Net.Server) {
|
||||
[[A SSL server over TCP.
|
||||
|
||||
@since 1.19
|
||||
]]
|
||||
|
||||
methods {
|
||||
@property ssl_context {
|
||||
[[Defines the SSL context to use for this server.
|
||||
|
||||
This specifies a shared context for all clients, with
|
||||
certificate, private keys, CRL, CAs...
|
||||
|
||||
If changed in runtime, it will only affect new clients.
|
||||
]]
|
||||
values {
|
||||
ssl_context: Efl.Net.Ssl.Context;
|
||||
}
|
||||
}
|
||||
|
||||
@property family {
|
||||
[[The address family (AF_*) family of this socket.
|
||||
|
||||
It will be one of AF_INET (IPv4), AF_INET6 (IPv6),
|
||||
AF_UNIX...
|
||||
|
||||
It must be set before the @Efl.Loop.Fd.fd.set is called
|
||||
with a valid file descriptor.
|
||||
]]
|
||||
get { }
|
||||
values {
|
||||
family: int;
|
||||
}
|
||||
}
|
||||
|
||||
@property close_on_exec {
|
||||
[[Controls Close-on-Exec() using FD_CLOEXEC.
|
||||
|
||||
Children socket will inherit the server's setting by
|
||||
default. One can change the behavior using each instance
|
||||
@Efl.Io.Closer.close_on_exec.set.
|
||||
]]
|
||||
get { }
|
||||
set {
|
||||
return: bool (false); [[$true on success]]
|
||||
}
|
||||
values {
|
||||
close_on_exec: bool;
|
||||
}
|
||||
}
|
||||
|
||||
@property reuse_address {
|
||||
[[Controls address reuse() using SO_REUSEADDR]]
|
||||
get { }
|
||||
set {
|
||||
return: bool (false); [[$true on success]]
|
||||
}
|
||||
values {
|
||||
reuse_address: bool;
|
||||
}
|
||||
}
|
||||
|
||||
@property reuse_port {
|
||||
[[Controls port reuse() using SO_REUSEPORT (since linux 3.9)]]
|
||||
get { }
|
||||
set {
|
||||
return: bool (false); [[$true on success]]
|
||||
}
|
||||
values {
|
||||
reuse_port: bool;
|
||||
}
|
||||
}
|
||||
|
||||
@property ipv6_only {
|
||||
[[Whenever IPv6 listen address will accept only same-family clients or will allow IPv4 to connect as well.
|
||||
|
||||
Since Linux 2.4.21, Windows Vista and MacOS X these
|
||||
control whenever a server that did bind to an IPv6
|
||||
address will accept only IPv6 clients or will also
|
||||
accept IPv4 by automatically converting them in an IPv6
|
||||
address, allowing a single socket to handle both
|
||||
protocols.
|
||||
|
||||
If an IPv6 address was used in @Efl.Net.Server.address,
|
||||
this property is $false and an IPv4 connects, then an
|
||||
address such as [::ffff:IPv4]:PORT will be used, such as
|
||||
[::ffff:192.168.0.2]:1234, where the IPv4 address can be
|
||||
extracted.
|
||||
|
||||
If an IPv4 address was used in @Efl.Net.Server.address,
|
||||
this has no effect.
|
||||
|
||||
Systems can configure their default value, usually true
|
||||
(allows only IPv6 clients).
|
||||
]]
|
||||
values {
|
||||
ipv6_only: bool;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
implements {
|
||||
Efl.Object.constructor;
|
||||
Efl.Object.destructor;
|
||||
Efl.Net.Server.serve;
|
||||
Efl.Net.Server.address.get;
|
||||
Efl.Net.Server.clients_count.get;
|
||||
Efl.Net.Server.clients_limit;
|
||||
Efl.Net.Server.serving.get;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
var Efl.Net.Socket.Ssl.Error.HANDSHAKE: Eina.Error; [[Failed SSL handshake]]
|
||||
var Efl.Net.Socket.Ssl.Error.CERTIFICATE_VERIFY_FAILED: Eina.Error; [[Failed to verify peer's certificate]]
|
||||
|
||||
class Efl.Net.Socket.Ssl (Efl.Object, Efl.Net.Socket) {
|
||||
class Efl.Net.Socket.Ssl (Efl.Loop_User, Efl.Net.Socket) {
|
||||
[[A wrapper socket doing SSL (Secure Sockets Layer).
|
||||
|
||||
Use this wrapper around an existing socket to do secure
|
||||
|
|
Loading…
Reference in New Issue