forked from enlightenment/efl
addded efl_net_{socket,dialer,server}_unix
This introduces AF_UNIX server and dialer, these are not available on Windows as in that platform we'll create a custom class for native 'local' communication. In the future we can add a wrapper class Efl.Net.Local that will use the class for each platform, but won't expose its details. For instance, if we ever expose 'credentials' (which I didn't because they are not portable), then it doesn't make sense to try to match that on Windows. The 'Efl.Net.Local' would just stick to the basics: Reader, Writer and Closer APIs.
This commit is contained in:
parent
84ee276b12
commit
651ff13616
|
@ -25,6 +25,14 @@ ecore_con_eolian_files = \
|
|||
lib/ecore_con/ecore_con_eet_client_obj.eo \
|
||||
lib/ecore_con/efl_network_url.eo
|
||||
|
||||
if HAVE_WINDOWS
|
||||
else
|
||||
ecore_con_eolian_files += \
|
||||
lib/ecore_con/efl_net_socket_unix.eo \
|
||||
lib/ecore_con/efl_net_dialer_unix.eo \
|
||||
lib/ecore_con/efl_net_server_unix.eo
|
||||
endif
|
||||
|
||||
ecore_con_eolian_type_files = \
|
||||
lib/ecore_con/efl_net_http_types.eot
|
||||
|
||||
|
@ -94,7 +102,10 @@ EXTRA_DIST2 += lib/ecore_con/ecore_con_legacy.c
|
|||
if HAVE_WINDOWS
|
||||
lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local_win32.c
|
||||
else
|
||||
lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local.c
|
||||
lib_ecore_con_libecore_con_la_SOURCES += lib/ecore_con/ecore_con_local.c \
|
||||
lib/ecore_con/efl_net_socket_unix.c \
|
||||
lib/ecore_con/efl_net_dialer_unix.c \
|
||||
lib/ecore_con/efl_net_server_unix.c
|
||||
endif
|
||||
|
||||
lib_ecore_con_libecore_con_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_CON_CFLAGS@
|
||||
|
|
|
@ -55,3 +55,4 @@
|
|||
/efl_net_dialer_websocket_example
|
||||
/efl_net_dialer_websocket_autobahntestee
|
||||
/efl_net_dialer_udp_example
|
||||
/efl_net_dialer_unix_example
|
||||
|
|
|
@ -314,6 +314,12 @@ efl_net_dialer_websocket_autobahntestee_LDADD = $(ECORE_CON_COMMON_LDADD)
|
|||
efl_net_dialer_udp_example_SOURCES = efl_net_dialer_udp_example.c
|
||||
efl_net_dialer_udp_example_LDADD = $(ECORE_CON_COMMON_LDADD)
|
||||
|
||||
if ! HAVE_WINDOWS
|
||||
EXTRA_PROGRAMS += efl_net_dialer_unix_example
|
||||
efl_net_dialer_unix_example_SOURCES = efl_net_dialer_unix_example.c
|
||||
efl_net_dialer_unix_example_LDADD = $(ECORE_CON_COMMON_LDADD)
|
||||
endif
|
||||
|
||||
SRCS = \
|
||||
ecore_animator_example.c \
|
||||
ecore_buffer_example.c \
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
#define EFL_BETA_API_SUPPORT 1
|
||||
#define EFL_EO_API_SUPPORT 1
|
||||
#include <Ecore.h>
|
||||
#include <Ecore_Con.h>
|
||||
#include <Ecore_Getopt.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static int retval = EXIT_SUCCESS;
|
||||
static Eina_Bool do_read = EINA_FALSE;
|
||||
|
||||
static void
|
||||
_connected(void *data EINA_UNUSED, const Efl_Event *event)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"INFO: connected to '%s' (%s)\n"
|
||||
"INFO: - local address=%s\n"
|
||||
"INFO: - read-after-write=%u\n",
|
||||
efl_net_dialer_address_dial_get(event->object),
|
||||
efl_net_socket_address_remote_get(event->object),
|
||||
efl_net_socket_address_local_get(event->object),
|
||||
do_read);
|
||||
}
|
||||
|
||||
static void
|
||||
_eos(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
|
||||
{
|
||||
fprintf(stderr, "INFO: end of stream. \n");
|
||||
ecore_main_loop_quit();
|
||||
}
|
||||
|
||||
static void
|
||||
_can_read(void *data EINA_UNUSED, const Efl_Event *event)
|
||||
{
|
||||
char buf[4];
|
||||
Eina_Rw_Slice rw_slice = EINA_SLICE_ARRAY(buf);
|
||||
Eina_Error err;
|
||||
Eina_Bool can_read = efl_io_reader_can_read_get(event->object);
|
||||
|
||||
/* NOTE: this message may appear with can read=0 BEFORE
|
||||
* "read '...'" because efl_io_readr_read() will change the status
|
||||
* of can_read to FALSE prior to return so we can print it!
|
||||
*/
|
||||
fprintf(stderr, "INFO: can read=%d\n", can_read);
|
||||
if (!can_read) return;
|
||||
if (!do_read) return;
|
||||
|
||||
err = efl_io_reader_read(event->object, &rw_slice);
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "ERROR: could not read: %s\n", eina_error_msg_get(err));
|
||||
retval = EXIT_FAILURE;
|
||||
ecore_main_loop_quit();
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "INFO: read '" EINA_SLICE_STR_FMT "'\n", EINA_SLICE_STR_PRINT(rw_slice));
|
||||
}
|
||||
|
||||
static void
|
||||
_can_write(void *data EINA_UNUSED, const Efl_Event *event)
|
||||
{
|
||||
static Eina_Slice slice = EINA_SLICE_STR_LITERAL("Hello World!");
|
||||
Eina_Slice to_write;
|
||||
Eina_Error err;
|
||||
Eina_Bool can_write = efl_io_writer_can_write_get(event->object);
|
||||
|
||||
/* NOTE: this message may appear with can write=0 BEFORE
|
||||
* "wrote '...'" because efl_io_writer_write() will change the status
|
||||
* of can_write to FALSE prior to return so we can print it!
|
||||
*/
|
||||
fprintf(stderr, "INFO: can write=%d (wanted bytes=%zd)\n", can_write, slice.len);
|
||||
if (!can_write) return;
|
||||
if (slice.len == 0) return;
|
||||
|
||||
to_write = slice;
|
||||
err = efl_io_writer_write(event->object, &to_write, &slice);
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "ERROR: could not write: %s\n", eina_error_msg_get(err));
|
||||
retval = EXIT_FAILURE;
|
||||
ecore_main_loop_quit();
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "INFO: wrote '" EINA_SLICE_STR_FMT "', still pending=%zd bytes\n", EINA_SLICE_STR_PRINT(to_write), slice.len);
|
||||
|
||||
if ((!do_read) && (slice.len == 0))
|
||||
{
|
||||
retval = EXIT_SUCCESS;
|
||||
ecore_main_loop_quit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_resolved(void *data EINA_UNUSED, const Efl_Event *event)
|
||||
{
|
||||
fprintf(stderr, "INFO: resolved %s => %s\n",
|
||||
efl_net_dialer_address_dial_get(event->object),
|
||||
efl_net_socket_address_remote_get(event->object));
|
||||
}
|
||||
|
||||
static void
|
||||
_error(void *data EINA_UNUSED, const Efl_Event *event)
|
||||
{
|
||||
const Eina_Error *perr = event->info;
|
||||
fprintf(stderr, "INFO: error: %d '%s'\n", *perr, eina_error_msg_get(*perr));
|
||||
retval = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
EFL_CALLBACKS_ARRAY_DEFINE(dialer_cbs,
|
||||
{ EFL_NET_DIALER_EVENT_CONNECTED, _connected },
|
||||
{ EFL_NET_DIALER_EVENT_RESOLVED, _resolved },
|
||||
{ EFL_NET_DIALER_EVENT_ERROR, _error },
|
||||
{ EFL_IO_READER_EVENT_EOS, _eos },
|
||||
{ EFL_IO_READER_EVENT_CAN_READ_CHANGED, _can_read },
|
||||
{ EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, _can_write }
|
||||
);
|
||||
|
||||
static const Ecore_Getopt options = {
|
||||
"efl_net_dialer_unix_example", /* program name */
|
||||
NULL, /* usage line */
|
||||
"1", /* version */
|
||||
"(C) 2016 Enlightenment Project", /* copyright */
|
||||
"BSD 2-Clause", /* license */
|
||||
/* long description, may be multiline and contain \n */
|
||||
"Example of Efl_Net_Dialer_Unix usage, sending a message and receiving a reply\n",
|
||||
EINA_FALSE,
|
||||
{
|
||||
ECORE_GETOPT_STORE_TRUE('r', "read-after-write", "Do a read after writes are done."),
|
||||
ECORE_GETOPT_VERSION('V', "version"),
|
||||
ECORE_GETOPT_COPYRIGHT('C', "copyright"),
|
||||
ECORE_GETOPT_LICENSE('L', "license"),
|
||||
ECORE_GETOPT_HELP('h', "help"),
|
||||
ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
|
||||
"The address (URL) to dial", "address"),
|
||||
ECORE_GETOPT_SENTINEL
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *address = NULL;
|
||||
Eina_Bool quit_option = EINA_FALSE;
|
||||
Ecore_Getopt_Value values[] = {
|
||||
ECORE_GETOPT_VALUE_BOOL(do_read),
|
||||
|
||||
/* 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 */
|
||||
ECORE_GETOPT_VALUE_BOOL(quit_option), /* -L/--license quits */
|
||||
ECORE_GETOPT_VALUE_BOOL(quit_option), /* -h/--help quits */
|
||||
|
||||
/* positional argument */
|
||||
ECORE_GETOPT_VALUE_STR(address),
|
||||
|
||||
ECORE_GETOPT_VALUE_NONE /* sentinel */
|
||||
};
|
||||
int args;
|
||||
Eo *dialer, *loop;
|
||||
Eina_Error err;
|
||||
|
||||
ecore_init();
|
||||
ecore_con_init();
|
||||
|
||||
args = ecore_getopt_parse(&options, values, argc, argv);
|
||||
if (args < 0)
|
||||
{
|
||||
fputs("ERROR: Could not parse command line options.\n", stderr);
|
||||
retval = EXIT_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (quit_option) goto end;
|
||||
|
||||
loop = ecore_main_loop_get();
|
||||
|
||||
args = ecore_getopt_parse_positional(&options, values, argc, argv, args);
|
||||
if (args < 0)
|
||||
{
|
||||
fputs("ERROR: Could not parse positional arguments.\n", stderr);
|
||||
retval = EXIT_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
dialer = efl_add(EFL_NET_DIALER_UNIX_CLASS, loop,
|
||||
efl_name_set(efl_added, "dialer"),
|
||||
efl_event_callback_array_add(efl_added, dialer_cbs(), NULL));
|
||||
|
||||
err = efl_net_dialer_dial(dialer, address);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stderr, "ERROR: could not dial '%s': %s",
|
||||
address, eina_error_msg_get(err));
|
||||
goto no_mainloop;
|
||||
}
|
||||
|
||||
ecore_main_loop_begin();
|
||||
|
||||
fprintf(stderr, "INFO: main loop finished.\n");
|
||||
|
||||
no_mainloop:
|
||||
efl_del(dialer);
|
||||
|
||||
end:
|
||||
ecore_con_shutdown();
|
||||
ecore_shutdown();
|
||||
|
||||
return retval;
|
||||
}
|
|
@ -474,6 +474,9 @@ EFL_CALLBACKS_ARRAY_DEFINE(server_cbs,
|
|||
static const char * protocols[] = {
|
||||
"tcp",
|
||||
"udp",
|
||||
#ifndef _WIN32
|
||||
"unix",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -600,6 +603,9 @@ 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;
|
||||
#ifndef _WIN32
|
||||
else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_SERVER_UNIX_CLASS;
|
||||
#endif
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: unsupported protocol: %s\n", protocol);
|
||||
|
@ -636,6 +642,12 @@ main(int argc, char **argv)
|
|||
EINA_LIST_FOREACH(udp_mcast_groups, lst, str)
|
||||
efl_net_server_udp_multicast_join(server, str);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
else if (cls == EFL_NET_SERVER_UNIX_CLASS)
|
||||
{
|
||||
efl_net_server_unix_unlink_before_bind_set(server, EINA_TRUE); /* makes testing easier */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* an explicit call to efl_net_server_serve() after the object is
|
||||
* constructed allows for more complex setup, such as interacting
|
||||
|
|
|
@ -15,6 +15,13 @@
|
|||
#include "efl_net_dialer_tcp.eo.h"
|
||||
#include "efl_net_server_tcp.eo.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#else
|
||||
#include "efl_net_socket_unix.eo.h"
|
||||
#include "efl_net_dialer_unix.eo.h"
|
||||
#include "efl_net_server_unix.eo.h"
|
||||
#endif
|
||||
|
||||
#include "efl_net_socket_udp.eo.h"
|
||||
#include "efl_net_dialer_udp.eo.h"
|
||||
#include "efl_net_server_udp.eo.h"
|
||||
|
|
|
@ -3027,7 +3027,60 @@ _ecore_con_lookup_done(void *data,
|
|||
#include "efl_network_connector.eo.c"
|
||||
|
||||
Eina_Bool
|
||||
efl_net_ip_port_fmt(char *buf, int buflen, const struct sockaddr *addr)
|
||||
efl_net_unix_fmt(char *buf, size_t buflen, SOCKET fd, const struct sockaddr_un *addr, socklen_t addrlen)
|
||||
{
|
||||
const char *src = addr->sun_path;
|
||||
socklen_t pathlen = addrlen - offsetof(struct sockaddr_un, sun_path);
|
||||
|
||||
if (addr->sun_family != AF_UNIX)
|
||||
{
|
||||
ERR("unsupported address family: %d", addr->sun_family);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
if (addrlen == offsetof(struct sockaddr_un, sun_path))
|
||||
{
|
||||
int r = snprintf(buf, buflen, "unnamed:%d", fd);
|
||||
if (r < 0)
|
||||
{
|
||||
ERR("snprintf(): %s", strerror(errno));
|
||||
return EINA_FALSE;
|
||||
}
|
||||
else if ((size_t)r > buflen)
|
||||
{
|
||||
ERR("buflen=%zu is too small, required=%d", buflen, r);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
if (src[0] != '\0')
|
||||
{
|
||||
if (buflen < pathlen)
|
||||
{
|
||||
ERR("buflen=%zu is too small, required=%u", buflen, pathlen);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buflen < pathlen + sizeof("abstract:") - 2)
|
||||
{
|
||||
ERR("buflen=%zu is too small, required=%zu", buflen, pathlen + sizeof("abstract:") - 2);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
memcpy(buf, "abstract:", sizeof("abstract:") - 1);
|
||||
buf += sizeof("abstract:") - 1;
|
||||
src++;
|
||||
}
|
||||
|
||||
memcpy(buf, src, pathlen);
|
||||
buf[pathlen] = '\0';
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
efl_net_ip_port_fmt(char *buf, size_t buflen, const struct sockaddr *addr)
|
||||
{
|
||||
char p[INET6_ADDRSTRLEN];
|
||||
const void *mem;
|
||||
|
@ -3069,9 +3122,9 @@ efl_net_ip_port_fmt(char *buf, int buflen, const struct sockaddr *addr)
|
|||
ERR("could not snprintf(): %s", strerror(errno));
|
||||
return EINA_FALSE;
|
||||
}
|
||||
else if (r > buflen)
|
||||
else if ((size_t)r > buflen)
|
||||
{
|
||||
ERR("buffer is too small: %d, required %d", buflen, r);
|
||||
ERR("buffer is too small: %zu, required %d", buflen, r);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
|
@ -3294,7 +3347,7 @@ static void
|
|||
_efl_net_connect_async_run(void *data, Ecore_Thread *thread EINA_UNUSED)
|
||||
{
|
||||
Efl_Net_Connect_Async_Data *d = data;
|
||||
char buf[INET6_ADDRSTRLEN + sizeof("[]:65536")] = "";
|
||||
char buf[INET6_ADDRSTRLEN + sizeof("[]:65536") + sizeof(struct sockaddr_un)] = "";
|
||||
int r;
|
||||
|
||||
/* allows ecore_thread_cancel() to cancel at some points, see
|
||||
|
@ -3319,7 +3372,12 @@ _efl_net_connect_async_run(void *data, Ecore_Thread *thread EINA_UNUSED)
|
|||
}
|
||||
|
||||
if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG))
|
||||
efl_net_ip_port_fmt(buf, sizeof(buf), d->addr);
|
||||
{
|
||||
if (d->addr->sa_family == AF_UNIX)
|
||||
efl_net_unix_fmt(buf, sizeof(buf), d->sockfd, (const struct sockaddr_un *)d->addr, d->addrlen);
|
||||
else
|
||||
efl_net_ip_port_fmt(buf, sizeof(buf), d->addr);
|
||||
}
|
||||
|
||||
DBG("connecting fd=%d to %s", d->sockfd, buf);
|
||||
|
||||
|
|
|
@ -402,7 +402,8 @@ void _efl_net_server_udp_client_feed(Eo *client, Eina_Rw_Slice slice);
|
|||
|
||||
void _efl_net_socket_udp_init(Eo *o, const struct sockaddr *addr, socklen_t addrlen, const char *str);
|
||||
|
||||
Eina_Bool efl_net_ip_port_fmt(char *buf, int buflen, const struct sockaddr *addr);
|
||||
Eina_Bool efl_net_unix_fmt(char *buf, size_t buflen, SOCKET fd, const struct sockaddr_un *addr, socklen_t addrlen);
|
||||
Eina_Bool efl_net_ip_port_fmt(char *buf, size_t buflen, const struct sockaddr *addr);
|
||||
|
||||
/**
|
||||
* @brief splits an address in the format "host:port" in two
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
#define EFL_NET_DIALER_UNIX_PROTECTED 1
|
||||
#define EFL_NET_DIALER_PROTECTED 1
|
||||
#define EFL_NET_SOCKET_FD_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_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#define MY_CLASS EFL_NET_DIALER_UNIX_CLASS
|
||||
|
||||
typedef struct _Efl_Net_Dialer_Unix_Data
|
||||
{
|
||||
struct {
|
||||
Ecore_Thread *thread;
|
||||
Efl_Future *timeout;
|
||||
} connect;
|
||||
Efl_Future *connect_job;
|
||||
Eina_Stringshare *address_dial;
|
||||
Eina_Bool connected;
|
||||
double timeout_dial;
|
||||
} Efl_Net_Dialer_Unix_Data;
|
||||
|
||||
EOLIAN static Eo*
|
||||
_efl_net_dialer_unix_efl_object_constructor(Eo *o, Efl_Net_Dialer_Unix_Data *pd EINA_UNUSED)
|
||||
{
|
||||
o = efl_constructor(efl_super(o, MY_CLASS));
|
||||
if (!o) return NULL;
|
||||
|
||||
efl_net_dialer_timeout_dial_set(o, 30.0);
|
||||
return o;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_unix_efl_object_destructor(Eo *o, Efl_Net_Dialer_Unix_Data *pd)
|
||||
{
|
||||
if (efl_io_closer_close_on_destructor_get(o) &&
|
||||
(!efl_io_closer_closed_get(o)))
|
||||
efl_io_closer_close(o);
|
||||
|
||||
if (pd->connect.thread)
|
||||
{
|
||||
ecore_thread_cancel(pd->connect.thread);
|
||||
pd->connect.thread = NULL;
|
||||
}
|
||||
|
||||
efl_destructor(efl_super(o, MY_CLASS));
|
||||
|
||||
eina_stringshare_replace(&pd->address_dial, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_net_dialer_unix_connect_timeout(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
Eo *o = data;
|
||||
Efl_Net_Dialer_Unix_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
||||
Eina_Error err = ETIMEDOUT;
|
||||
|
||||
if (pd->connect.thread)
|
||||
{
|
||||
ecore_thread_cancel(pd->connect.thread);
|
||||
pd->connect.thread = NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_net_dialer_unix_connected(void *data, const struct sockaddr *addr, socklen_t addrlen EINA_UNUSED, int sockfd, Eina_Error err)
|
||||
{
|
||||
Eo *o = data;
|
||||
Efl_Net_Dialer_Unix_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
||||
|
||||
pd->connect.thread = NULL;
|
||||
|
||||
efl_ref(o); /* we're emitting callbacks then continuing the workflow */
|
||||
|
||||
if (err) goto error;
|
||||
|
||||
efl_net_socket_fd_family_set(o, addr->sa_family);
|
||||
efl_loop_fd_set(o, sockfd);
|
||||
if (efl_net_socket_address_remote_get(o))
|
||||
{
|
||||
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_RESOLVED, NULL);
|
||||
efl_net_dialer_connected_set(o, EINA_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = EFL_NET_DIALER_ERROR_COULDNT_CONNECT;
|
||||
efl_loop_fd_set(o, INVALID_SOCKET);
|
||||
closesocket(sockfd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
if (err)
|
||||
{
|
||||
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_unix_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Unix_Data *pd EINA_UNUSED, const char *address)
|
||||
{
|
||||
struct sockaddr_un addr = { .sun_family = AF_UNIX };
|
||||
socklen_t addrlen;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
|
||||
EINA_SAFETY_ON_TRUE_RETURN_VAL(address[0] == '\0', EINVAL);
|
||||
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_net_dialer_connected_get(o), EISCONN);
|
||||
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(o), EBADF);
|
||||
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_loop_fd_get(o) >= 0, EALREADY);
|
||||
|
||||
if (pd->connect.thread)
|
||||
{
|
||||
ecore_thread_cancel(pd->connect.thread);
|
||||
pd->connect.thread = NULL;
|
||||
}
|
||||
|
||||
if (strncmp(address, "abstract:", strlen("abstract:")) == 0)
|
||||
{
|
||||
const char *path = address + strlen("abstract:");
|
||||
if (strlen(path) + 2 > sizeof(addr.sun_path))
|
||||
{
|
||||
ERR("abstract path is too long: %s", path);
|
||||
return EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
addr.sun_path[0] = '\0';
|
||||
memcpy(addr.sun_path + 1, path, strlen(path) + 1);
|
||||
addrlen = strlen(path) + 2 + offsetof(struct sockaddr_un, sun_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *path = address;
|
||||
if (strlen(path) + 1 > sizeof(addr.sun_path))
|
||||
{
|
||||
ERR("path is too long: %s", path);
|
||||
return EFL_NET_DIALER_ERROR_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
memcpy(addr.sun_path, path, strlen(path) + 1);
|
||||
addrlen = strlen(path) + 1 + offsetof(struct sockaddr_un, sun_path);
|
||||
}
|
||||
|
||||
pd->connect.thread = efl_net_connect_async_new((const struct sockaddr *)&addr, addrlen, SOCK_STREAM, 0,
|
||||
efl_io_closer_close_on_exec_get(o),
|
||||
_efl_net_dialer_unix_connected, o);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->connect.thread, EINVAL);
|
||||
|
||||
efl_net_dialer_address_dial_set(o, address);
|
||||
|
||||
if (pd->connect.timeout)
|
||||
efl_future_cancel(pd->connect.timeout);
|
||||
if (pd->timeout_dial > 0.0)
|
||||
{
|
||||
efl_future_use(&pd->connect.timeout, efl_loop_timeout(efl_loop_get(o), pd->timeout_dial, o));
|
||||
efl_future_then(pd->connect.timeout, _efl_net_dialer_unix_connect_timeout, NULL, NULL, o);
|
||||
efl_future_link(o, pd->connect.timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_unix_efl_net_dialer_address_dial_set(Eo *o EINA_UNUSED, Efl_Net_Dialer_Unix_Data *pd, const char *address)
|
||||
{
|
||||
eina_stringshare_replace(&pd->address_dial, address);
|
||||
}
|
||||
|
||||
EOLIAN static const char *
|
||||
_efl_net_dialer_unix_efl_net_dialer_address_dial_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Unix_Data *pd)
|
||||
{
|
||||
return pd->address_dial;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_unix_efl_net_dialer_timeout_dial_set(Eo *o EINA_UNUSED, Efl_Net_Dialer_Unix_Data *pd, double seconds)
|
||||
{
|
||||
pd->timeout_dial = seconds;
|
||||
if (pd->connect.timeout)
|
||||
efl_future_cancel(pd->connect.timeout);
|
||||
|
||||
if ((pd->timeout_dial > 0.0) && (pd->connect.thread))
|
||||
{
|
||||
efl_future_use(&pd->connect.timeout, efl_loop_timeout(efl_loop_get(o), pd->timeout_dial, o));
|
||||
efl_future_then(pd->connect.timeout, _efl_net_dialer_unix_connect_timeout, NULL, NULL, o);
|
||||
}
|
||||
}
|
||||
|
||||
EOLIAN static double
|
||||
_efl_net_dialer_unix_efl_net_dialer_timeout_dial_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Unix_Data *pd)
|
||||
{
|
||||
return pd->timeout_dial;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_unix_efl_net_dialer_connected_set(Eo *o, Efl_Net_Dialer_Unix_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_unix_efl_net_dialer_connected_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Unix_Data *pd)
|
||||
{
|
||||
return pd->connected;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Error
|
||||
_efl_net_dialer_unix_efl_io_closer_close(Eo *o, Efl_Net_Dialer_Unix_Data *pd EINA_UNUSED)
|
||||
{
|
||||
efl_net_dialer_connected_set(o, EINA_FALSE);
|
||||
return efl_io_closer_close(efl_super(o, MY_CLASS));
|
||||
}
|
||||
|
||||
#include "efl_net_dialer_unix.eo.c"
|
|
@ -0,0 +1,22 @@
|
|||
class Efl.Net.Dialer.Unix (Efl.Net.Socket.Unix, Efl.Net.Dialer) {
|
||||
[[Connects to a local AF_UNIX server.
|
||||
|
||||
The dial address is a file system path (portable) or
|
||||
"abstract:ID" (Linux-only extension).
|
||||
|
||||
\@note Proxies are meaningless for AF_UNIX family, thus are not
|
||||
implemented.
|
||||
|
||||
@since 1.19
|
||||
]]
|
||||
|
||||
implements {
|
||||
Efl.Object.constructor;
|
||||
Efl.Object.destructor;
|
||||
Efl.Net.Dialer.dial;
|
||||
Efl.Net.Dialer.address_dial;
|
||||
Efl.Net.Dialer.connected;
|
||||
Efl.Net.Dialer.timeout_dial;
|
||||
Efl.Io.Closer.close;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
#define EFL_NET_SERVER_UNIX_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"
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
/* no include EVIL as it's not supposed to be compiled on Windows */
|
||||
|
||||
#define MY_CLASS EFL_NET_SERVER_UNIX_CLASS
|
||||
|
||||
typedef struct _Efl_Net_Server_Unix_Data
|
||||
{
|
||||
Efl_Future *bind_job;
|
||||
Eina_Bool unlink_before_bind;
|
||||
} Efl_Net_Server_Unix_Data;
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_server_unix_efl_object_destructor(Eo *o, Efl_Net_Server_Unix_Data *pd EINA_UNUSED)
|
||||
{
|
||||
SOCKET fd = efl_loop_fd_get(o);
|
||||
|
||||
if (fd != INVALID_SOCKET)
|
||||
{
|
||||
const char *address = efl_net_server_address_get(o);
|
||||
if ((address) && (strncmp(address, "abstract:", strlen("abstract:")) != 0))
|
||||
unlink(address);
|
||||
}
|
||||
|
||||
efl_destructor(efl_super(o, MY_CLASS));
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_net_server_unix_bind_job(void *data, const Efl_Event *event EINA_UNUSED)
|
||||
{
|
||||
Eo *o = data;
|
||||
Efl_Net_Server_Unix_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
||||
const char *address = efl_net_server_address_get(o);
|
||||
struct sockaddr_un addr = { .sun_family = AF_UNIX };
|
||||
socklen_t addrlen;
|
||||
SOCKET fd;
|
||||
Eina_Error err = 0;
|
||||
int r;
|
||||
|
||||
pd->bind_job = NULL;
|
||||
|
||||
efl_ref(o); /* we're emitting callbacks then continuing the workflow */
|
||||
|
||||
efl_net_server_fd_family_set(o, AF_UNIX);
|
||||
|
||||
do
|
||||
{
|
||||
fd = efl_net_socket4(AF_UNIX, SOCK_STREAM, 0,
|
||||
efl_net_server_fd_close_on_exec_get(o));
|
||||
if (fd == INVALID_SOCKET)
|
||||
{
|
||||
err = efl_net_socket_error_get();
|
||||
ERR("socket(AF_UNIX, SOCK_STREAM, 0): %s", eina_error_msg_get(err));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (strncmp(address, "abstract:", strlen("abstract:")) == 0)
|
||||
{
|
||||
const char *path = address + strlen("abstract:");
|
||||
if (strlen(path) + 2 > sizeof(addr.sun_path))
|
||||
{
|
||||
ERR("abstract path is too long: %s", path);
|
||||
err = EFL_NET_SERVER_ERROR_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
addr.sun_path[0] = '\0';
|
||||
memcpy(addr.sun_path + 1, path, strlen(path) + 1);
|
||||
addrlen = strlen(path) + 2 + offsetof(struct sockaddr_un, sun_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *path = address;
|
||||
if (strlen(path) + 1 > sizeof(addr.sun_path))
|
||||
{
|
||||
ERR("path is too long: %s", path);
|
||||
err = EFL_NET_SERVER_ERROR_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
memcpy(addr.sun_path, path, strlen(path) + 1);
|
||||
addrlen = strlen(path) + 1 + offsetof(struct sockaddr_un, sun_path);
|
||||
}
|
||||
|
||||
if ((pd->unlink_before_bind) && (addr.sun_path[0] != '\0'))
|
||||
{
|
||||
DBG("unlinking AF_UNIX path '%s'", addr.sun_path);
|
||||
unlink(addr.sun_path);
|
||||
}
|
||||
|
||||
r = bind(fd, (struct sockaddr *)&addr, addrlen);
|
||||
if (r != 0)
|
||||
{
|
||||
err = efl_net_socket_error_get();
|
||||
if ((err == EADDRINUSE) && (pd->unlink_before_bind) && (addr.sun_path[0] != '\0'))
|
||||
{
|
||||
closesocket(fd);
|
||||
err = 0;
|
||||
continue;
|
||||
}
|
||||
DBG("bind(%d, %s): %s", fd, address, eina_error_msg_get(err));
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (pd->unlink_before_bind);
|
||||
|
||||
efl_loop_fd_set(o, fd);
|
||||
|
||||
r = listen(fd, 0);
|
||||
if (r != 0)
|
||||
{
|
||||
err = efl_net_socket_error_get();
|
||||
DBG("listen(%d): %s", fd, eina_error_msg_get(err));
|
||||
goto error;
|
||||
}
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) != 0)
|
||||
{
|
||||
err = efl_net_socket_error_get();
|
||||
ERR("getsockname(%d): %s", fd, eina_error_msg_get(err));
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
char str[sizeof(addr) + sizeof("abstract:")];
|
||||
if (!efl_net_unix_fmt(str, sizeof(str), fd, &addr, addrlen))
|
||||
ERR("could not format unix address");
|
||||
else
|
||||
{
|
||||
efl_net_server_address_set(o, str);
|
||||
address = efl_net_server_address_get(o);
|
||||
}
|
||||
}
|
||||
|
||||
DBG("fd=%d serving at %s", fd, address);
|
||||
efl_net_server_serving_set(o, EINA_TRUE);
|
||||
|
||||
error:
|
||||
if (err)
|
||||
{
|
||||
efl_event_callback_call(o, EFL_NET_SERVER_EVENT_ERROR, &err);
|
||||
if (fd) closesocket(fd);
|
||||
efl_loop_fd_set(o, INVALID_SOCKET);
|
||||
}
|
||||
|
||||
efl_unref(o);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Error
|
||||
_efl_net_server_unix_efl_net_server_serve(Eo *o, Efl_Net_Server_Unix_Data *pd, const char *address)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
|
||||
EINA_SAFETY_ON_TRUE_RETURN_VAL(address[0] == '\0', EINVAL);
|
||||
|
||||
efl_net_server_address_set(o, address);
|
||||
|
||||
if (pd->bind_job)
|
||||
efl_future_cancel(pd->bind_job);
|
||||
|
||||
efl_future_use(&pd->bind_job, efl_loop_job(efl_loop_get(o), o));
|
||||
efl_future_then(pd->bind_job, _efl_net_server_unix_bind_job, NULL, NULL, o);
|
||||
efl_future_link(o, pd->bind_job);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Efl_Callback_Array_Item *_efl_net_server_unix_client_cbs(void);
|
||||
|
||||
static void
|
||||
_efl_net_server_unix_client_event_closed(void *data, const Efl_Event *event)
|
||||
{
|
||||
Eo *server = data;
|
||||
Eo *client = event->object;
|
||||
|
||||
efl_event_callback_array_del(client, _efl_net_server_unix_client_cbs(), server);
|
||||
if (efl_parent_get(client) == server)
|
||||
efl_parent_set(client, NULL);
|
||||
|
||||
efl_net_server_clients_count_set(server, efl_net_server_clients_count_get(server) - 1);
|
||||
}
|
||||
|
||||
EFL_CALLBACKS_ARRAY_DEFINE(_efl_net_server_unix_client_cbs,
|
||||
{ EFL_IO_CLOSER_EVENT_CLOSED, _efl_net_server_unix_client_event_closed });
|
||||
|
||||
static void
|
||||
_efl_net_server_unix_efl_net_server_fd_client_add(Eo *o, Efl_Net_Server_Unix_Data *pd EINA_UNUSED, int client_fd)
|
||||
{
|
||||
Eo *client = efl_add(EFL_NET_SOCKET_UNIX_CLASS, o,
|
||||
efl_event_callback_array_add(efl_added, _efl_net_server_unix_client_cbs(), o),
|
||||
efl_io_closer_close_on_exec_set(efl_added, efl_net_server_fd_close_on_exec_get(o)),
|
||||
efl_io_closer_close_on_destructor_set(efl_added, EINA_TRUE),
|
||||
efl_loop_fd_set(efl_added, client_fd));
|
||||
if (!client)
|
||||
{
|
||||
ERR("could not create client object fd=%d", client_fd);
|
||||
closesocket(client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
efl_net_server_clients_count_set(o, efl_net_server_clients_count_get(o) + 1);
|
||||
efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_ADD, client);
|
||||
|
||||
if (efl_ref_get(client) == 1) /* users must take a reference themselves */
|
||||
{
|
||||
DBG("client %s was not handled, closing it...",
|
||||
efl_net_socket_address_remote_get(client));
|
||||
efl_del(client);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_net_server_unix_efl_net_server_fd_client_reject(Eo *o, Efl_Net_Server_Unix_Data *pd EINA_UNUSED, int client_fd)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen;
|
||||
char str[sizeof(addr) + sizeof("abstract:")] = "";
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
if (getpeername(client_fd, (struct sockaddr *)&addr, &addrlen) != 0)
|
||||
ERR("getpeername(%d): %s", client_fd, eina_error_msg_get(efl_net_socket_error_get()));
|
||||
else
|
||||
{
|
||||
if (!efl_net_unix_fmt(str, sizeof(str), client_fd, &addr, addrlen))
|
||||
ERR("could not format rejected client unix address fd=%d", client_fd);
|
||||
}
|
||||
|
||||
closesocket(client_fd);
|
||||
efl_event_callback_call(o, EFL_NET_SERVER_EVENT_CLIENT_REJECTED, str);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_net_server_unix_unlink_before_bind_set(Eo *o EINA_UNUSED, Efl_Net_Server_Unix_Data *pd, Eina_Bool unlink_before_bind)
|
||||
{
|
||||
pd->unlink_before_bind = unlink_before_bind;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_efl_net_server_unix_unlink_before_bind_get(Eo *o EINA_UNUSED, Efl_Net_Server_Unix_Data *pd)
|
||||
{
|
||||
return pd->unlink_before_bind;
|
||||
}
|
||||
|
||||
#include "efl_net_server_unix.eo.c"
|
|
@ -0,0 +1,28 @@
|
|||
class Efl.Net.Server.Unix (Efl.Net.Server.Fd) {
|
||||
[[An AF_UNIX server.
|
||||
|
||||
@since 1.19
|
||||
]]
|
||||
|
||||
methods {
|
||||
@property unlink_before_bind {
|
||||
[[AF_UNIX paths may be stale due crashes, remove files and try again.
|
||||
|
||||
If this property is $true, then it will unlink() before
|
||||
bind() is done, repeating this process if EADDRINUSE.
|
||||
|
||||
By default it's false and you will get EADDRINUSE.
|
||||
]]
|
||||
values {
|
||||
unlink_before_bind: bool; [[if $true, server will unlink() the path before bind() is called.]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
implements {
|
||||
Efl.Object.destructor;
|
||||
Efl.Net.Server.serve;
|
||||
Efl.Net.Server.Fd.client_add;
|
||||
Efl.Net.Server.Fd.client_reject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
#define EFL_NET_SOCKET_UNIX_PROTECTED 1
|
||||
#define EFL_NET_SOCKET_FD_PROTECTED 1
|
||||
#define EFL_LOOP_FD_PROTECTED 1
|
||||
#define EFL_IO_READER_FD_PROTECTED 1
|
||||
#define EFL_IO_WRITER_FD_PROTECTED 1
|
||||
#define EFL_IO_CLOSER_FD_PROTECTED 1
|
||||
#define EFL_IO_READER_PROTECTED 1
|
||||
#define EFL_IO_WRITER_PROTECTED 1
|
||||
#define EFL_IO_CLOSER_PROTECTED 1
|
||||
#define EFL_NET_SOCKET_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_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
/* no include EVIL as it's not supposed to be compiled on Windows */
|
||||
|
||||
#define MY_CLASS EFL_NET_SOCKET_UNIX_CLASS
|
||||
|
||||
typedef struct _Efl_Net_Socket_Unix_Data
|
||||
{
|
||||
} Efl_Net_Socket_Unix_Data;
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_socket_unix_efl_loop_fd_fd_set(Eo *o, Efl_Net_Socket_Unix_Data *pd EINA_UNUSED, int fd)
|
||||
{
|
||||
efl_loop_fd_set(efl_super(o, MY_CLASS), fd);
|
||||
|
||||
if (fd != INVALID_SOCKET)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen;
|
||||
int family;
|
||||
|
||||
family = efl_net_socket_fd_family_get(o);
|
||||
if (family == AF_UNSPEC) return;
|
||||
EINA_SAFETY_ON_TRUE_RETURN(family != AF_UNIX);
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) != 0)
|
||||
ERR("getsockname(%d): %s", fd, eina_error_msg_get(efl_net_socket_error_get()));
|
||||
else
|
||||
{
|
||||
char str[sizeof(addr) + sizeof("abstract:")];
|
||||
|
||||
if (!efl_net_unix_fmt(str, sizeof(str), fd, &addr, addrlen))
|
||||
ERR("could not format local unix address");
|
||||
else
|
||||
efl_net_socket_address_local_set(o, str);
|
||||
}
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
if (getpeername(fd, (struct sockaddr *)&addr, &addrlen) != 0)
|
||||
ERR("getpeername(%d): %s", fd, eina_error_msg_get(efl_net_socket_error_get()));
|
||||
else
|
||||
{
|
||||
char str[sizeof(addr) + sizeof("abstract:")];
|
||||
if (!efl_net_unix_fmt(str, sizeof(str), fd, &addr, addrlen))
|
||||
ERR("could not format remote unix address");
|
||||
else
|
||||
efl_net_socket_address_remote_set(o, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "efl_net_socket_unix.eo.c"
|
|
@ -0,0 +1,13 @@
|
|||
class Efl.Net.Socket.Unix (Efl.Net.Socket.Fd) {
|
||||
[[A base UNIX socket.
|
||||
|
||||
This is the common class and takes an existing FD, usually
|
||||
created by an dialer or server.
|
||||
|
||||
@since 1.19
|
||||
]]
|
||||
|
||||
implements {
|
||||
Efl.Loop.Fd.fd.set;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue