barbieri pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=278866da2c0f770db5ebe3b5c0cd27839dd1c257

commit 278866da2c0f770db5ebe3b5c0cd27839dd1c257
Author: Gustavo Sverzut Barbieri <barbi...@profusion.mobi>
Date:   Tue Oct 18 18:51:59 2016 -0200

    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.
---
 configure.ac                                    |   2 +
 src/Makefile_Ecore_Con.am                       |   4 +
 src/examples/ecore/.gitignore                   |   1 +
 src/examples/ecore/Makefile.am                  |   9 +-
 src/examples/ecore/efl_io_copier_example.c      |  28 +++
 src/examples/ecore/efl_net_dialer_udp_example.c | 197 +++++++++++++++++++++
 src/lib/ecore_con/Ecore_Con_Eo.h                |   3 +
 src/lib/ecore_con/efl_net_dialer_udp.c          | 220 ++++++++++++++++++++++++
 src/lib/ecore_con/efl_net_dialer_udp.eo         |  18 ++
 src/lib/ecore_con/efl_net_socket_udp.c          | 155 +++++++++++++++++
 src/lib/ecore_con/efl_net_socket_udp.eo         |  26 +++
 11 files changed, 661 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0794852..c743063 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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 \
diff --git a/src/Makefile_Ecore_Con.am b/src/Makefile_Ecore_Con.am
index ae7166d..e5a5cd0 100644
--- a/src/Makefile_Ecore_Con.am
+++ b/src/Makefile_Ecore_Con.am
@@ -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 \
diff --git a/src/examples/ecore/.gitignore b/src/examples/ecore/.gitignore
index 826eebe..3aaec19 100644
--- a/src/examples/ecore/.gitignore
+++ b/src/examples/ecore/.gitignore
@@ -54,3 +54,4 @@
 /efl_net_dialer_http_example
 /efl_net_dialer_websocket_example
 /efl_net_dialer_websocket_autobahntestee
+/efl_net_dialer_udp_example
diff --git a/src/examples/ecore/Makefile.am b/src/examples/ecore/Makefile.am
index 35c930b..da6b086 100644
--- a/src/examples/ecore/Makefile.am
+++ b/src/examples/ecore/Makefile.am
@@ -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
 
diff --git a/src/examples/ecore/efl_io_copier_example.c 
b/src/examples/ecore/efl_io_copier_example.c
index 2a2af78..d6b2907 100644
--- a/src/examples/ecore/efl_io_copier_example.c
+++ b/src/examples/ecore/efl_io_copier_example.c
@@ -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,
diff --git a/src/examples/ecore/efl_net_dialer_udp_example.c 
b/src/examples/ecore/efl_net_dialer_udp_example.c
new file mode 100644
index 0000000..4193cc1
--- /dev/null
+++ b/src/examples/ecore/efl_net_dialer_udp_example.c
@@ -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;
+}
diff --git a/src/lib/ecore_con/Ecore_Con_Eo.h b/src/lib/ecore_con/Ecore_Con_Eo.h
index ec7a228..6d6fb03 100644
--- a/src/lib/ecore_con/Ecore_Con_Eo.h
+++ b/src/lib/ecore_con/Ecore_Con_Eo.h
@@ -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.*' */
diff --git a/src/lib/ecore_con/efl_net_dialer_udp.c 
b/src/lib/ecore_con/efl_net_dialer_udp.c
new file mode 100644
index 0000000..cc84eeb
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_dialer_udp.c
@@ -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"
diff --git a/src/lib/ecore_con/efl_net_dialer_udp.eo 
b/src/lib/ecore_con/efl_net_dialer_udp.eo
new file mode 100644
index 0000000..41ed220
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_dialer_udp.eo
@@ -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;
+    }
+}
diff --git a/src/lib/ecore_con/efl_net_socket_udp.c 
b/src/lib/ecore_con/efl_net_socket_udp.c
new file mode 100644
index 0000000..d76d4fd
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_socket_udp.c
@@ -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"
diff --git a/src/lib/ecore_con/efl_net_socket_udp.eo 
b/src/lib/ecore_con/efl_net_socket_udp.eo
new file mode 100644
index 0000000..782184b
--- /dev/null
+++ b/src/lib/ecore_con/efl_net_socket_udp.eo
@@ -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;
+    }
+}

-- 


Reply via email to