2016-10-31 20:31:56 -07:00
|
|
|
#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;
|
|
|
|
|
efl_net_server: add 'client_announce', share logic and fix a bug.
I just realized that if a client is not referenced it would leak in
the 'ssl' server as we must del it.
However, if we del the SSL socket, we're going to close the underlying
TCP. But we're from the TCP "client,add" callback and this causes
issues since "closed" will be emitted, our close callback will
unparent the client, which lead to it being deleted.
The proper solution is to only monitor "closed" if the client is
accepted. Otherwise we just check if it was closed, if we're the
parent, etc...
Fixing this in all servers were painful, we could share since most
inherit from Efl.Net.Server.Fd. Then add the "client_announce"
protected method to do it, and document how it should work.
2016-11-24 23:32:16 -08:00
|
|
|
static void
|
|
|
|
_efl_net_server_ssl_client_event_closed(void *data, const Efl_Event *event)
|
|
|
|
{
|
|
|
|
Eo *server = data;
|
|
|
|
Eo *client = event->object;
|
|
|
|
|
|
|
|
efl_event_callback_del(client, EFL_IO_CLOSER_EVENT_CLOSED, _efl_net_server_ssl_client_event_closed, server);
|
|
|
|
if (efl_parent_get(client) == server)
|
|
|
|
efl_parent_set(client, NULL);
|
|
|
|
|
|
|
|
/* do NOT change count as we're using the underlying server's count */
|
|
|
|
//efl_net_server_clients_count_set(server, efl_net_server_clients_count_get(server) - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_efl_net_server_ssl_efl_net_server_client_announce(Eo *o, Efl_Net_Server_Ssl_Data *pd EINA_UNUSED, Eo *client)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(client, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_FALSE_GOTO(efl_isa(client, EFL_NET_SOCKET_SSL_CLASS), wrong_type);
|
|
|
|
EINA_SAFETY_ON_FALSE_GOTO(efl_parent_get(client) == o, wrong_parent);
|
|
|
|
|
|
|
|
efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_ADD, client);
|
|
|
|
|
|
|
|
if (efl_parent_get(client) != o)
|
|
|
|
{
|
|
|
|
DBG("client %s was reparented! Ignoring it...",
|
|
|
|
efl_net_socket_address_remote_get(client));
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2017-11-08 01:30:42 -08:00
|
|
|
if (efl_ref_count(client) == 1) /* users must take a reference themselves */
|
efl_net_server: add 'client_announce', share logic and fix a bug.
I just realized that if a client is not referenced it would leak in
the 'ssl' server as we must del it.
However, if we del the SSL socket, we're going to close the underlying
TCP. But we're from the TCP "client,add" callback and this causes
issues since "closed" will be emitted, our close callback will
unparent the client, which lead to it being deleted.
The proper solution is to only monitor "closed" if the client is
accepted. Otherwise we just check if it was closed, if we're the
parent, etc...
Fixing this in all servers were painful, we could share since most
inherit from Efl.Net.Server.Fd. Then add the "client_announce"
protected method to do it, and document how it should work.
2016-11-24 23:32:16 -08:00
|
|
|
{
|
|
|
|
DBG("client %s was not handled, closing it...",
|
|
|
|
efl_net_socket_address_remote_get(client));
|
|
|
|
efl_del(client);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
else if (efl_io_closer_closed_get(client))
|
|
|
|
{
|
|
|
|
DBG("client %s was closed from 'client,add', delete it...",
|
|
|
|
efl_net_socket_address_remote_get(client));
|
|
|
|
efl_del(client);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do NOT change count as we're using the underlying server's count */
|
|
|
|
//efl_net_server_clients_count_set(o, efl_net_server_clients_count_get(o) + 1);
|
|
|
|
efl_event_callback_add(client, EFL_IO_CLOSER_EVENT_CLOSED, _efl_net_server_ssl_client_event_closed, o);
|
|
|
|
return EINA_TRUE;
|
|
|
|
|
|
|
|
wrong_type:
|
|
|
|
ERR("%p client %p (%s) doesn't implement Efl.Net.Socket.Ssl class, deleting it.", o, client, efl_class_name_get(efl_class_get(client)));
|
|
|
|
efl_del(client);
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
|
|
|
wrong_parent:
|
|
|
|
ERR("%p client %p (%s) parent=%p is not our child, deleting it.", o, client, efl_class_name_get(efl_class_get(client)), efl_parent_get(client));
|
|
|
|
efl_del(client);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2016-10-31 20:31:56 -07:00
|
|
|
static void
|
2017-09-29 16:01:02 -07:00
|
|
|
_efl_net_server_ssl_efl_net_server_fd_client_add(Eo *o, Efl_Net_Server_Ssl_Data *pd, int client_fd)
|
2016-10-31 20:31:56 -07:00
|
|
|
{
|
|
|
|
Eo *client_ssl;
|
2017-09-29 16:01:02 -07:00
|
|
|
Eo *client_tcp;
|
|
|
|
const char *addr;
|
|
|
|
|
|
|
|
client_tcp = efl_add(EFL_NET_SOCKET_TCP_CLASS, o,
|
|
|
|
efl_io_closer_close_on_exec_set(efl_added, efl_net_server_fd_close_on_exec_get(o)),
|
2018-04-17 16:17:29 -07:00
|
|
|
efl_io_closer_close_on_invalidate_set(efl_added, EINA_TRUE),
|
2017-09-29 16:01:02 -07:00
|
|
|
efl_loop_fd_set(efl_added, client_fd));
|
|
|
|
if (!client_tcp)
|
|
|
|
{
|
|
|
|
ERR("could not create client object fd=" SOCKET_FMT, (SOCKET)client_fd);
|
|
|
|
closesocket(client_fd);
|
|
|
|
return;
|
|
|
|
}
|
2016-10-31 20:31:56 -07:00
|
|
|
|
2017-09-29 16:01:02 -07:00
|
|
|
addr = efl_net_socket_address_remote_get(client_tcp);
|
2016-10-31 20:31:56 -07:00
|
|
|
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);
|
2017-09-29 16:01:02 -07:00
|
|
|
efl_del(client_tcp);
|
2016-10-31 20:31:56 -07:00
|
|
|
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);
|
2017-09-29 16:01:02 -07:00
|
|
|
efl_del(client_tcp);
|
2016-10-31 20:31:56 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
efl_net_server: add 'client_announce', share logic and fix a bug.
I just realized that if a client is not referenced it would leak in
the 'ssl' server as we must del it.
However, if we del the SSL socket, we're going to close the underlying
TCP. But we're from the TCP "client,add" callback and this causes
issues since "closed" will be emitted, our close callback will
unparent the client, which lead to it being deleted.
The proper solution is to only monitor "closed" if the client is
accepted. Otherwise we just check if it was closed, if we're the
parent, etc...
Fixing this in all servers were painful, we could share since most
inherit from Efl.Net.Server.Fd. Then add the "client_announce"
protected method to do it, and document how it should work.
2016-11-24 23:32:16 -08:00
|
|
|
efl_net_server_client_announce(o, client_ssl);
|
2016-10-31 20:31:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2017-09-29 16:01:02 -07:00
|
|
|
pd->server = efl_add(EFL_NET_SERVER_TCP_CLASS, o);
|
2016-10-31 20:31:56 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->server, NULL);
|
2017-09-29 16:01:02 -07:00
|
|
|
if (!efl_composite_attach(o, pd->server))
|
|
|
|
goto on_error;
|
2016-10-31 20:31:56 -07:00
|
|
|
|
|
|
|
return o;
|
2017-09-29 16:01:02 -07:00
|
|
|
|
|
|
|
on_error:
|
|
|
|
ERR("Failed to composite the object\n");
|
|
|
|
efl_del(pd->server);
|
|
|
|
efl_del(o);
|
|
|
|
return NULL;
|
2016-10-31 20:31:56 -07:00
|
|
|
}
|
|
|
|
|
2016-12-08 09:25:11 -08:00
|
|
|
static void
|
|
|
|
_efl_net_server_ssl_ctx_del(void *data, const Efl_Event *event EINA_UNUSED)
|
|
|
|
{
|
|
|
|
Eo *o = data;
|
|
|
|
Efl_Net_Server_Ssl_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
|
|
|
pd->ssl_ctx = NULL;
|
|
|
|
}
|
|
|
|
|
2016-10-31 20:31:56 -07:00
|
|
|
EOLIAN void
|
2018-04-09 17:01:21 -07:00
|
|
|
_efl_net_server_ssl_efl_object_invalidate(Eo *o, Efl_Net_Server_Ssl_Data *pd)
|
2016-10-31 20:31:56 -07:00
|
|
|
{
|
2018-04-09 17:01:21 -07:00
|
|
|
pd->server = NULL;
|
2016-10-31 20:31:56 -07:00
|
|
|
|
2018-04-09 17:01:21 -07:00
|
|
|
efl_destructor(efl_super(o, MY_CLASS));
|
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN void
|
|
|
|
_efl_net_server_ssl_efl_object_destructor(Eo *o, Efl_Net_Server_Ssl_Data *pd)
|
|
|
|
{
|
2016-12-08 09:25:11 -08:00
|
|
|
if (pd->ssl_ctx)
|
|
|
|
{
|
|
|
|
efl_event_callback_del(pd->ssl_ctx, EFL_EVENT_DEL, _efl_net_server_ssl_ctx_del, o);
|
|
|
|
efl_unref(pd->ssl_ctx);
|
|
|
|
pd->ssl_ctx = NULL;
|
|
|
|
}
|
|
|
|
|
2016-10-31 20:31:56 -07:00
|
|
|
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);
|
2016-12-08 09:25:11 -08:00
|
|
|
if (ssl_ctx)
|
|
|
|
efl_event_callback_add(ssl_ctx, EFL_EVENT_DEL, _efl_net_server_ssl_ctx_del, o);
|
2016-10-31 20:31:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static Eo *
|
2018-04-17 11:09:44 -07:00
|
|
|
_efl_net_server_ssl_ssl_context_get(const Eo *o EINA_UNUSED, Efl_Net_Server_Ssl_Data *pd)
|
2016-10-31 20:31:56 -07:00
|
|
|
{
|
|
|
|
return pd->ssl_ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "efl_net_server_ssl.eo.c"
|