ajwillia-ms pushed a commit to branch master.

http://git.enlightenment.org/tools/examples.git/commit/?id=8035919a325199a17cda669ca2630a8239051b48

commit 8035919a325199a17cda669ca2630a8239051b48
Author: Andy Williams <[email protected]>
Date:   Wed Nov 22 11:41:55 2017 +0000

    net: Add a simple net_io example simulating an HTTP client
    
    We connect to a remote host and execute a HEAD request and print the 
response
---
 reference/c/net/meson.build     |  12 ++
 reference/c/net/src/meson.build |   9 ++
 reference/c/net/src/net_io.c    | 258 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 279 insertions(+)

diff --git a/reference/c/net/meson.build b/reference/c/net/meson.build
new file mode 100644
index 0000000..fb6533a
--- /dev/null
+++ b/reference/c/net/meson.build
@@ -0,0 +1,12 @@
+project(
+  'efl-reference-net', 'c',
+  version : '0.0.1',
+  default_options: [ 'c_std=gnu99', 'warning_level=2' ],
+  meson_version : '>= 0.38.0')
+
+eina = dependency('eina', version : '>=1.20.99')
+efl = dependency('efl-net', version : '>=1.20.99')
+
+inc = include_directories('.')
+subdir('src')
+
diff --git a/reference/c/net/src/meson.build b/reference/c/net/src/meson.build
new file mode 100644
index 0000000..203a1cd
--- /dev/null
+++ b/reference/c/net/src/meson.build
@@ -0,0 +1,9 @@
+deps = [eina, efl]
+
+executable('efl_reference_net_io',
+  files(['net_io.c']),
+  dependencies : deps,
+  include_directories : inc,
+  install : true
+)
+
diff --git a/reference/c/net/src/net_io.c b/reference/c/net/src/net_io.c
new file mode 100644
index 0000000..bfab353
--- /dev/null
+++ b/reference/c/net/src/net_io.c
@@ -0,0 +1,258 @@
+#define EFL_EO_API_SUPPORT 1
+#define EFL_BETA_API_SUPPORT 1
+
+#include <stdio.h>
+
+#include <Eina.h>
+#include <Efl_Net.h>
+
+/*
+ * Efl.IO Networked examples.
+ *
+ * This example builds on the core_io example by connecting to a remote server
+ * using a dialler and a command queue.The response is printed to stdout.
+ */
+
+static Eina_List *_waiting = NULL;
+static Eina_List *_commands = NULL;
+static Eina_Slice _delimiter;
+static Eo *_dialer = NULL, *_sender = NULL, *_receiver = NULL;
+
+static void
+_command_next(void)
+{
+   Eina_Slice slice;
+   char *cmd;
+   Eo *send_queue;
+
+   send_queue = efl_io_copier_source_get(_sender);
+   if (!_commands)
+     {
+        efl_io_queue_eos_mark(send_queue);
+        return;
+     }
+
+   cmd = _commands->data;
+   _commands = eina_list_remove_list(_commands, _commands);
+
+   slice = (Eina_Slice)EINA_SLICE_STR(cmd);
+   efl_io_writer_write(send_queue, &slice, NULL);
+   fprintf(stderr, "INFO: sent '" EINA_SLICE_STR_FMT "'\n",
+           EINA_SLICE_STR_PRINT(slice));
+
+   /* don't use _delimiter directly, 'len' may be changed! */
+   slice = _delimiter;
+   efl_io_writer_write(send_queue, &slice, NULL);
+}
+
+static void
+_receiver_data(void *data EINA_UNUSED, const Efl_Event *event)
+{
+   Eina_Slice slice = efl_io_queue_slice_get(event->object);
+
+   // Can be caused when we issue efl_io_queue_clear()
+   if (slice.len == 0) return;
+
+   /*
+    * If the server didn't send us the line terminator and closed the
+    * connection (ie: efl_io_reader_eos_get() == true) or if the buffer
+    * limit was reached then we may have a line without a trailing delimiter.
+    */
+   if (eina_slice_endswith(slice, _delimiter))
+     slice.len -= _delimiter.len;
+
+   fprintf(stderr, "INFO: received '" EINA_SLICE_STR_FMT "'\n",
+           EINA_SLICE_STR_PRINT(slice));
+
+   efl_io_queue_clear(event->object);
+   _command_next();
+}
+
+static void
+_dialer_connected(void *data EINA_UNUSED, const Efl_Event *event)
+{
+   fprintf(stderr, "INFO: connected to %s (%s)\n",
+           efl_net_dialer_address_dial_get(event->object),
+           efl_net_socket_address_remote_get(event->object));
+
+   _command_next();
+}
+
+static void
+_copier_done(void *data EINA_UNUSED, const Efl_Event *event)
+{
+   fprintf(stderr, "INFO: %s done\n", efl_name_get(event->object));
+
+   _waiting = eina_list_remove(_waiting, event->object);
+   if (!_waiting)
+     efl_exit(EXIT_SUCCESS);
+}
+
+static void
+_copier_error(void *data EINA_UNUSED, const Efl_Event *event)
+{
+   const Eina_Error *perr = event->info;
+
+   fprintf(stderr, "INFO: %s error: #%d '%s'\n",
+           efl_name_get(event->object), *perr, eina_error_msg_get(*perr));
+
+   efl_exit(EXIT_FAILURE);
+}
+
+EFL_CALLBACKS_ARRAY_DEFINE(copier_cbs,
+                           { EFL_IO_COPIER_EVENT_DONE, _copier_done },
+                           { EFL_IO_COPIER_EVENT_ERROR, _copier_error });
+
+EAPI void
+efl_pause(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
+{
+}
+
+EAPI void
+efl_resume(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
+{
+}
+
+EAPI void
+efl_terminate(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
+{
+   if (_waiting)
+     {
+        fprintf(stderr, "ERROR: %d operations were waiting!\n",
+                eina_list_count(_waiting));
+        eina_list_free(_waiting);
+        _waiting = NULL;
+     }
+
+   if (_receiver)
+     {
+        efl_io_closer_close(_receiver);
+        efl_del(efl_io_copier_destination_get(_receiver));
+        efl_del(_receiver);
+     }
+
+   if (_sender)
+     {
+        efl_io_closer_close(_sender);
+        efl_del(efl_io_copier_source_get(_sender));
+        efl_del(_sender);
+     }
+
+   if (_dialer)
+     efl_del(_dialer);
+}
+
+EAPI_MAIN void
+efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
+{
+   char *address = "example.com:80";
+   unsigned long buffer_limit = 128;
+   Eina_Error err;
+   Eo *loop, *send_queue, *receive_queue;
+
+   _commands = eina_list_append(_commands, "HEAD / HTTP/1.1\r\nHost: 
example.com\r\nConnection: close\r\n\r\n");
+   _delimiter = (Eina_Slice)EINA_SLICE_STR("\r\n");
+
+   /*
+    * Without a send_queue we'd have to manually implement an
+    * Efl_Io_Reader object that would provide partial data when
+    * Efl_Io_Reader.read() is called by Efl_Io_Copier. This is
+    * cumbersome... we just want to write a full command and have the
+    * queue to handle that for us.
+    *
+    * Our example's usage is to write each command at once followed by
+    * the line_delimiter, then wait for a reply from the server, then
+    * write another.
+    */
+   send_queue = efl_add(EFL_IO_QUEUE_CLASS, NULL,
+                        efl_name_set(efl_added, "send_queue"),
+                        efl_io_queue_limit_set(efl_added, buffer_limit));
+   if (!send_queue)
+     {
+        fprintf(stderr, "ERROR: could not create Efl_Io_Queue (send)\n");
+        efl_exit(EXIT_FAILURE);
+     }
+
+   /*
+    * Without a receive_queue we'd have to manually implement an
+    * Efl_Io_Writer object that would handle write of partial data
+    * with Efl_Io_Writer.write() is called by Efl_Io_Copier.
+    *
+    * For output we could have another solution as well: use NULL
+    * destination and handle "line" or "data" events manually,
+    * stealing the buffer so it doesn't grow.
+    *
+    * Our example's usage is to peek its data with slice_get() then
+    * clear().
+    */
+   receive_queue = efl_add(EFL_IO_QUEUE_CLASS, NULL,
+                           efl_name_set(efl_added, "receive_queue"),
+                           efl_io_queue_limit_set(efl_added, buffer_limit),
+                           efl_event_callback_add(efl_added, 
EFL_IO_QUEUE_EVENT_SLICE_CHANGED, _receiver_data, NULL));
+   if (!receive_queue)
+     {
+        fprintf(stderr, "ERROR: could not create Efl_Io_Queue (receive)\n");
+        efl_exit(EXIT_FAILURE);
+     }
+
+   /*
+    * From here on it's mostly the same all Efl_Io_Copier would do,
+    * check efl_io_copier_simple_example.c and efl_io_copier_example.c
+    */
+
+   /*
+    * some objects such as the Efl.Io.Copier and Efl.Net.Dialer.Tcp
+    * depend on main loop, thus their parent must be a loop
+    * provider. We use the loop itself.
+    */
+   loop = ecore_main_loop_get();
+
+   /* The TCP client to use to send/receive network data */
+   _dialer = efl_add(EFL_NET_DIALER_TCP_CLASS, loop,
+                    efl_name_set(efl_added, "dialer"),
+                    efl_event_callback_add(efl_added, 
EFL_NET_DIALER_EVENT_CONNECTED, _dialer_connected, NULL));
+   if (!_dialer)
+     {
+        fprintf(stderr, "ERROR: could not create Efl_Net_Dialer_Tcp\n");
+        efl_exit(EXIT_FAILURE);
+     }
+
+   /* sender: send_queue->network */
+   _sender = efl_add(EFL_IO_COPIER_CLASS, loop,
+                    efl_name_set(efl_added, "sender"),
+                    efl_io_copier_line_delimiter_set(efl_added, _delimiter),
+                    efl_io_copier_source_set(efl_added, send_queue),
+                    efl_io_copier_destination_set(efl_added, _dialer),
+                    efl_event_callback_array_add(efl_added, copier_cbs(), 
NULL));
+   if (!_sender)
+     {
+        fprintf(stderr, "ERROR: could not create Efl_Io_Copier (sender)\n");
+        efl_exit(EXIT_FAILURE);
+     }
+
+   /* receiver: network->receive_queue */
+   _receiver = efl_add(EFL_IO_COPIER_CLASS, loop,
+                      efl_name_set(efl_added, "receiver"),
+                      efl_io_copier_line_delimiter_set(efl_added, _delimiter),
+                      efl_io_copier_source_set(efl_added, _dialer),
+                      efl_io_copier_destination_set(efl_added, receive_queue),
+                      efl_event_callback_array_add(efl_added, copier_cbs(), 
NULL));
+   if (!_receiver)
+     {
+        fprintf(stderr, "ERROR: could not create Efl_Io_Copier (receiver)\n");
+        efl_exit(EXIT_FAILURE);
+     }
+
+   err = efl_net_dialer_dial(_dialer, address);
+   if (err)
+     {
+        fprintf(stderr, "ERROR: could not dial %s: %s\n",
+                address, eina_error_msg_get(err));
+        efl_exit(EXIT_FAILURE);
+     }
+
+   _waiting = eina_list_append(_waiting, _sender);
+   _waiting = eina_list_append(_waiting, _receiver);
+}
+EFL_MAIN_EX()
+

-- 


Reply via email to