forked from enlightenment/efl
efl_net_dialer_udp: "connect" to an UDP server to send and receive data.
Like existing ecore_con code, this does not use SOCKSv5 UDP proxy. It's kinda cumbersome to add since requires a keep alive TCP connection to the server, a second UDP channel and framing around the original UDP frame. Added UDP_CORK (if present) to match TCP_UDP present in TCP sockets, this allows one to execute multiple write() calls that will result in a single datagram, generated when CORK becomes FALSE again. The efl_io_copier_example.c now accepts this as output. There is no input UDP as there is no way to notify the server of a connection (since such thing doesn't exit), usually servers react after a datagram is received, replying to the source.
This commit is contained in:
parent
23b9b0d78d
commit
278866da2c
|
@ -477,6 +477,7 @@ EFL_CHECK_PATH_MAX
|
|||
|
||||
EFL_CHECK_DEFINE(TCP_CORK, netinet/tcp.h)
|
||||
EFL_CHECK_DEFINE(TCP_NOPUSH, netinet/tcp.h)
|
||||
EFL_CHECK_DEFINE(UDP_CORK, netinet/udp.h)
|
||||
|
||||
#### Checks for types
|
||||
|
||||
|
@ -1784,6 +1785,7 @@ langinfo.h \
|
|||
features.h \
|
||||
netinet/in.h \
|
||||
netinet/tcp.h \
|
||||
netinet/udp.h \
|
||||
sys/prctl.h \
|
||||
sys/resource.h \
|
||||
sys/timerfd.h \
|
||||
|
|
|
@ -9,8 +9,10 @@ ecore_con_eolian_files = \
|
|||
lib/ecore_con/efl_net_socket.eo \
|
||||
lib/ecore_con/efl_net_socket_fd.eo \
|
||||
lib/ecore_con/efl_net_socket_tcp.eo \
|
||||
lib/ecore_con/efl_net_socket_udp.eo \
|
||||
lib/ecore_con/efl_net_dialer.eo \
|
||||
lib/ecore_con/efl_net_dialer_tcp.eo \
|
||||
lib/ecore_con/efl_net_dialer_udp.eo \
|
||||
lib/ecore_con/efl_net_dialer_http.eo \
|
||||
lib/ecore_con/efl_net_dialer_websocket.eo \
|
||||
lib/ecore_con/efl_net_server.eo \
|
||||
|
@ -73,8 +75,10 @@ lib/ecore_con/ecore_con_info.c \
|
|||
lib/ecore_con/efl_net_socket.c \
|
||||
lib/ecore_con/efl_net_socket_fd.c \
|
||||
lib/ecore_con/efl_net_socket_tcp.c \
|
||||
lib/ecore_con/efl_net_socket_udp.c \
|
||||
lib/ecore_con/efl_net_dialer.c \
|
||||
lib/ecore_con/efl_net_dialer_tcp.c \
|
||||
lib/ecore_con/efl_net_dialer_udp.c \
|
||||
lib/ecore_con/efl_net_dialer_http.c \
|
||||
lib/ecore_con/efl_net_dialer_websocket.c \
|
||||
lib/ecore_con/efl_net_server.c \
|
||||
|
|
|
@ -54,3 +54,4 @@
|
|||
/efl_net_dialer_http_example
|
||||
/efl_net_dialer_websocket_example
|
||||
/efl_net_dialer_websocket_autobahntestee
|
||||
/efl_net_dialer_udp_example
|
||||
|
|
|
@ -84,7 +84,8 @@ efl_io_queue_example \
|
|||
efl_net_server_example \
|
||||
efl_net_dialer_http_example \
|
||||
efl_net_dialer_websocket_example \
|
||||
efl_net_dialer_websocket_autobahntestee
|
||||
efl_net_dialer_websocket_autobahntestee \
|
||||
efl_net_dialer_udp_example
|
||||
|
||||
ECORE_COMMON_LDADD = \
|
||||
$(top_builddir)/src/lib/ecore/libecore.la \
|
||||
|
@ -310,6 +311,9 @@ efl_net_dialer_websocket_example_LDADD = $(ECORE_CON_COMMON_LDADD)
|
|||
efl_net_dialer_websocket_autobahntestee_SOURCES = efl_net_dialer_websocket_autobahntestee.c
|
||||
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)
|
||||
|
||||
SRCS = \
|
||||
ecore_animator_example.c \
|
||||
ecore_buffer_example.c \
|
||||
|
@ -363,7 +367,8 @@ efl_io_queue_example.c \
|
|||
efl_net_server_example.c \
|
||||
efl_net_dialer_http_example.c \
|
||||
efl_net_dialer_websocket_example.c \
|
||||
efl_net_dialer_websocket_autobahntestee.c
|
||||
efl_net_dialer_websocket_autobahntestee.c \
|
||||
efl_net_dialer_udp_example.c
|
||||
|
||||
DATA_FILES = red.png Makefile.examples
|
||||
|
||||
|
|
|
@ -344,6 +344,7 @@ static const Ecore_Getopt options = {
|
|||
"tcp://IP:PORT to connect using TCP and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n"
|
||||
"http://address to do a PUT request\n"
|
||||
"ws://address or wss:// to do WebSocket request\n"
|
||||
"udp://IP:PORT to connect using UDP and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n"
|
||||
"",
|
||||
"output-file"),
|
||||
ECORE_GETOPT_SENTINEL
|
||||
|
@ -658,6 +659,33 @@ main(int argc, char **argv)
|
|||
goto end_output;
|
||||
}
|
||||
}
|
||||
else if (strncmp(output_fname, "udp://", strlen("udp://")) == 0)
|
||||
{
|
||||
/*
|
||||
* Since Efl.Net.Socket implements the required interfaces,
|
||||
* they can be used here as well.
|
||||
*/
|
||||
const char *address = output_fname + strlen("udp://");
|
||||
Eina_Error err;
|
||||
output = efl_add(EFL_NET_DIALER_UDP_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 UDP Dialer.\n");
|
||||
retval = EXIT_FAILURE;
|
||||
goto end_input;
|
||||
}
|
||||
|
||||
err = efl_net_dialer_dial(output, address);
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "ERROR: could not UDP dial %s: %s\n",
|
||||
address, eina_error_msg_get(err));
|
||||
goto end_output;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* regular file, open with flags: write-only, close-on-exec,
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
#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)
|
||||
{
|
||||
char buf[1024];
|
||||
Eina_Rw_Slice rw_slice = {.mem = buf, .len = sizeof(buf)};
|
||||
Eina_Slice slice = EINA_SLICE_STR_LITERAL("Hello World");
|
||||
Eina_Error err;
|
||||
|
||||
fprintf(stderr, "INFO: connected %s\n",
|
||||
efl_net_dialer_address_dial_get(event->object));
|
||||
|
||||
err = efl_io_writer_write(event->object, &slice, NULL);
|
||||
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 "\n", EINA_SLICE_STR_PRINT(slice));
|
||||
|
||||
slice = (Eina_Slice)EINA_SLICE_STR_LITERAL("Second Write");
|
||||
err = efl_io_writer_write(event->object, &slice, NULL);
|
||||
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 "\n", EINA_SLICE_STR_PRINT(slice));
|
||||
|
||||
/* if CORK was used, then say we're done to generate the single final datagram */
|
||||
efl_net_socket_udp_cork_set(event->object, EINA_FALSE);
|
||||
|
||||
if (!do_read) goto end;
|
||||
|
||||
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));
|
||||
|
||||
end:
|
||||
retval = EXIT_SUCCESS;
|
||||
ecore_main_loop_quit();
|
||||
}
|
||||
|
||||
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 });
|
||||
|
||||
static const Ecore_Getopt options = {
|
||||
"efl_net_dialer_udp_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_Udp usage, sending a message and receiving a reply\n",
|
||||
EINA_FALSE,
|
||||
{
|
||||
ECORE_GETOPT_STORE_BOOL('r', "read-after-write", "Do a read after writes are done."),
|
||||
ECORE_GETOPT_STORE_BOOL('c', "cork", "use UDP_CORK around messages to generate a single datagram."),
|
||||
ECORE_GETOPT_STORE_DOUBLE('t', "connect-timeout", "timeout in seconds for the connection phase"),
|
||||
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 cork = EINA_FALSE;
|
||||
Eina_Bool quit_option = EINA_FALSE;
|
||||
double timeout_dial = 30.0;
|
||||
Ecore_Getopt_Value values[] = {
|
||||
ECORE_GETOPT_VALUE_BOOL(do_read),
|
||||
ECORE_GETOPT_VALUE_BOOL(cork),
|
||||
ECORE_GETOPT_VALUE_DOUBLE(timeout_dial),
|
||||
|
||||
/* 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_UDP_CLASS, loop,
|
||||
efl_name_set(efl_added, "dialer"),
|
||||
efl_net_socket_udp_cork_set(efl_added, cork),
|
||||
efl_net_dialer_timeout_dial_set(efl_added, timeout_dial),
|
||||
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;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"INFO: dialed %s\n"
|
||||
"INFO: - read-after-write=%hhu\n"
|
||||
"INFO: - cork=%hhu\n"
|
||||
"INFO: - timeout_dial=%fs\n",
|
||||
efl_net_dialer_address_dial_get(dialer),
|
||||
do_read,
|
||||
efl_net_socket_udp_cork_get(dialer),
|
||||
efl_net_dialer_timeout_dial_get(dialer));
|
||||
|
||||
ecore_main_loop_begin();
|
||||
|
||||
fprintf(stderr, "INFO: main loop finished.\n");
|
||||
|
||||
no_mainloop:
|
||||
efl_del(dialer);
|
||||
|
||||
end:
|
||||
ecore_con_shutdown();
|
||||
ecore_shutdown();
|
||||
|
||||
return retval;
|
||||
}
|
|
@ -15,6 +15,9 @@
|
|||
#include "efl_net_dialer_tcp.eo.h"
|
||||
#include "efl_net_server_tcp.eo.h"
|
||||
|
||||
#include "efl_net_socket_udp.eo.h"
|
||||
#include "efl_net_dialer_udp.eo.h"
|
||||
|
||||
#include "efl_net_http_types.eot.h"
|
||||
|
||||
/* TODO: should be generated from 'var Efl.Net.Dialer.Error.*' */
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
#define EFL_NET_DIALER_UDP_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_NETINET_UDP_H
|
||||
# include <netinet/udp.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_UDP_CLASS
|
||||
|
||||
typedef struct _Efl_Net_Dialer_Udp_Data
|
||||
{
|
||||
struct {
|
||||
Ecore_Thread *thread;
|
||||
Efl_Future *timeout;
|
||||
} connect;
|
||||
Eina_Stringshare *address_dial;
|
||||
Eina_Bool connected;
|
||||
Eina_Bool closed;
|
||||
double timeout_dial;
|
||||
} Efl_Net_Dialer_Udp_Data;
|
||||
|
||||
EOLIAN static Eo*
|
||||
_efl_net_dialer_udp_efl_object_constructor(Eo *o, Efl_Net_Dialer_Udp_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_udp_efl_object_destructor(Eo *o, Efl_Net_Dialer_Udp_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_udp_connect_timeout(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
Eo *o = data;
|
||||
Efl_Net_Dialer_Udp_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_udp_connected(void *data, const struct sockaddr *addr, socklen_t addrlen EINA_UNUSED, int sockfd, Eina_Error err)
|
||||
{
|
||||
Eo *o = data;
|
||||
Efl_Net_Dialer_Udp_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
||||
char buf[INET6_ADDRSTRLEN + sizeof("[]:65536")];
|
||||
|
||||
pd->connect.thread = NULL;
|
||||
|
||||
efl_ref(o); /* we're emitting callbacks then continuing the workflow */
|
||||
|
||||
if (err)
|
||||
{
|
||||
efl_io_reader_eos_set(o, EINA_TRUE);
|
||||
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_ERROR, &err);
|
||||
}
|
||||
else
|
||||
{
|
||||
efl_net_socket_fd_family_set(o, addr->sa_family);
|
||||
efl_loop_fd_set(o, sockfd);
|
||||
if (efl_net_ip_port_fmt(buf, sizeof(buf), addr))
|
||||
{
|
||||
efl_net_socket_address_remote_set(o, buf);
|
||||
efl_event_callback_call(o, EFL_NET_DIALER_EVENT_RESOLVED, NULL);
|
||||
}
|
||||
efl_net_dialer_connected_set(o, EINA_TRUE);
|
||||
}
|
||||
|
||||
efl_unref(o);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Error
|
||||
_efl_net_dialer_udp_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Udp_Data *pd EINA_UNUSED, const char *address)
|
||||
{
|
||||
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);
|
||||
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 (pd->connect.thread)
|
||||
ecore_thread_cancel(pd->connect.thread);
|
||||
|
||||
pd->connect.thread = efl_net_ip_connect_async_new(address,
|
||||
"",
|
||||
NULL,
|
||||
NULL,
|
||||
SOCK_DGRAM,
|
||||
IPPROTO_UDP,
|
||||
efl_io_closer_close_on_exec_get(o),
|
||||
_efl_net_dialer_udp_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_udp_connect_timeout, NULL, NULL, o);
|
||||
efl_future_link(o, pd->connect.timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_udp_efl_net_dialer_address_dial_set(Eo *o EINA_UNUSED, Efl_Net_Dialer_Udp_Data *pd, const char *address)
|
||||
{
|
||||
eina_stringshare_replace(&pd->address_dial, address);
|
||||
}
|
||||
|
||||
EOLIAN static const char *
|
||||
_efl_net_dialer_udp_efl_net_dialer_address_dial_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Udp_Data *pd)
|
||||
{
|
||||
return pd->address_dial;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_udp_efl_net_dialer_timeout_dial_set(Eo *o EINA_UNUSED, Efl_Net_Dialer_Udp_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_udp_connect_timeout, NULL, NULL, o);
|
||||
}
|
||||
}
|
||||
|
||||
EOLIAN static double
|
||||
_efl_net_dialer_udp_efl_net_dialer_timeout_dial_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Udp_Data *pd)
|
||||
{
|
||||
return pd->timeout_dial;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_dialer_udp_efl_net_dialer_connected_set(Eo *o, Efl_Net_Dialer_Udp_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_udp_efl_net_dialer_connected_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Udp_Data *pd)
|
||||
{
|
||||
return pd->connected;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Error
|
||||
_efl_net_dialer_udp_efl_io_closer_close(Eo *o, Efl_Net_Dialer_Udp_Data *pd)
|
||||
{
|
||||
pd->closed = EINA_TRUE;
|
||||
efl_net_dialer_connected_set(o, EINA_FALSE);
|
||||
return efl_io_closer_close(efl_super(o, MY_CLASS));
|
||||
}
|
||||
|
||||
#include "efl_net_dialer_udp.eo.c"
|
|
@ -0,0 +1,18 @@
|
|||
class Efl.Net.Dialer.Udp (Efl.Net.Socket.Udp, Efl.Net.Dialer) {
|
||||
[[Connects to a remote UDP server.
|
||||
|
||||
UDP proxies are not supported, not even using SOCKSv5.
|
||||
|
||||
@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,155 @@
|
|||
#define EFL_NET_SOCKET_UDP_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_NETINET_UDP_H
|
||||
# include <netinet/udp.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_SOCKET_UDP_CLASS
|
||||
|
||||
typedef struct _Efl_Net_Socket_Udp_Data
|
||||
{
|
||||
Eina_Bool cork;
|
||||
} Efl_Net_Socket_Udp_Data;
|
||||
|
||||
EOLIAN static void
|
||||
_efl_net_socket_udp_efl_loop_fd_fd_set(Eo *o, Efl_Net_Socket_Udp_Data *pd EINA_UNUSED, int fd)
|
||||
{
|
||||
efl_loop_fd_set(efl_super(o, MY_CLASS), fd);
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int family;
|
||||
|
||||
/* apply postponed values */
|
||||
efl_net_socket_udp_cork_set(o, pd->cork);
|
||||
|
||||
family = efl_net_socket_fd_family_get(o);
|
||||
if (family == AF_UNSPEC) return;
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) < 0)
|
||||
ERR("getsockname(%d): %s", fd, strerror(errno));
|
||||
else
|
||||
{
|
||||
char str[INET6_ADDRSTRLEN + sizeof("[]:65536")];
|
||||
if (efl_net_ip_port_fmt(str, sizeof(str), (struct sockaddr *)&addr))
|
||||
efl_net_socket_address_local_set(o, str);
|
||||
}
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
if (getpeername(fd, (struct sockaddr *)&addr, &addrlen) < 0)
|
||||
ERR("getpeername(%d): %s", fd, strerror(errno));
|
||||
else
|
||||
{
|
||||
char str[INET6_ADDRSTRLEN + sizeof("[]:65536")];
|
||||
if (efl_net_ip_port_fmt(str, sizeof(str), (struct sockaddr *)&addr))
|
||||
efl_net_socket_address_remote_set(o, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
_cork_option_get(void)
|
||||
{
|
||||
#if defined(HAVE_UDP_CORK)
|
||||
return UDP_CORK;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_net_socket_udp_cork_set(Eo *o, Efl_Net_Socket_Udp_Data *pd, Eina_Bool cork)
|
||||
{
|
||||
int value, fd, option;
|
||||
Eina_Bool old = pd->cork;
|
||||
|
||||
option = _cork_option_get();
|
||||
if (EINA_UNLIKELY(option < 0))
|
||||
{
|
||||
if (cork)
|
||||
ERR("Could not find a UDP_CORK equivalent on your system");
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
pd->cork = cork;
|
||||
|
||||
fd = efl_loop_fd_get(o);
|
||||
if (fd < 0) return EINA_TRUE; /* postpone until fd_set() */
|
||||
|
||||
value = cork;
|
||||
if (setsockopt(fd, IPPROTO_UDP, option, &value, sizeof(value)) < 0)
|
||||
{
|
||||
ERR("setsockopt(%d, IPPROTO_UDP, 0x%x, %d): %s",
|
||||
fd, option, value, strerror(errno));
|
||||
pd->cork = old;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_net_socket_udp_cork_get(Eo *o, Efl_Net_Socket_Udp_Data *pd)
|
||||
{
|
||||
int value = 0, fd;
|
||||
socklen_t valuelen;
|
||||
int option;
|
||||
|
||||
option = _cork_option_get();
|
||||
if (EINA_UNLIKELY(option < 0))
|
||||
{
|
||||
ERR("Could not find a UDP_CORK equivalent on your system");
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
fd = efl_loop_fd_get(o);
|
||||
if (fd < 0) return pd->cork;
|
||||
|
||||
/* if there is a fd, always query it directly as it may be modified
|
||||
* elsewhere by nasty users.
|
||||
*/
|
||||
valuelen = sizeof(value);
|
||||
if (getsockopt(fd, IPPROTO_UDP, option, &value, &valuelen) < 0)
|
||||
{
|
||||
ERR("getsockopt(%d, IPPROTO_UDP, 0x%x): %s",
|
||||
fd, option, strerror(errno));
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
pd->cork = !!value; /* sync */
|
||||
return pd->cork;
|
||||
}
|
||||
|
||||
#include "efl_net_socket_udp.eo.c"
|
|
@ -0,0 +1,26 @@
|
|||
class Efl.Net.Socket.Udp (Efl.Net.Socket.Fd) {
|
||||
[[A base UDP socket.
|
||||
|
||||
This is the common class and takes an existing FD, usually
|
||||
created by an dialer or server.
|
||||
|
||||
@since 1.19
|
||||
]]
|
||||
|
||||
methods {
|
||||
@property cork {
|
||||
[[Controls UDP's cork using UDP_CORK]]
|
||||
get { }
|
||||
set {
|
||||
return: bool (false); [[$true on success]]
|
||||
}
|
||||
values {
|
||||
cork: bool;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
implements {
|
||||
Efl.Loop.Fd.fd.set;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue