aboutsummaryrefslogtreecommitdiffstats
path: root/reference
diff options
context:
space:
mode:
authorAndy Williams <andy@andywilliams.me>2017-12-19 17:48:30 +0000
committerAndy Williams <andy@andywilliams.me>2017-12-19 17:48:30 +0000
commit42de664854c4163c74e75cf29733c90cab788e6e (patch)
treecb28a07429166a64d1f4a050f1f18400cc6e78ba /reference
parentnet: oops, missing semicolon somehow (diff)
downloadexamples-42de664854c4163c74e75cf29733c90cab788e6e.tar.gz
net: Add a buffered net io example that is far simpler than without
Diffstat (limited to 'reference')
-rw-r--r--reference/c/net/src/meson.build7
-rw-r--r--reference/c/net/src/net_io_buffered.c176
2 files changed, 183 insertions, 0 deletions
diff --git a/reference/c/net/src/meson.build b/reference/c/net/src/meson.build
index 22f5898c..025d8306 100644
--- a/reference/c/net/src/meson.build
+++ b/reference/c/net/src/meson.build
@@ -7,6 +7,13 @@ executable('efl_reference_net_io',
install : true
)
+executable('efl_reference_net_io_buffered',
+ files(['net_io_buffered.c']),
+ dependencies : deps,
+ include_directories : inc,
+ install : true
+)
+
executable('efl_reference_net_session',
files(['net_session.c']),
dependencies : deps,
diff --git a/reference/c/net/src/net_io_buffered.c b/reference/c/net/src/net_io_buffered.c
new file mode 100644
index 00000000..14e841a5
--- /dev/null
+++ b/reference/c/net/src/net_io_buffered.c
@@ -0,0 +1,176 @@
+#define EFL_EO_API_SUPPORT 1
+#define EFL_BETA_API_SUPPORT 1
+
+#include <stdio.h>
+
+#include <Eina.h>
+#include <Efl_Net.h>
+
+/*
+ * Efl.Net buffered input/output examples.
+ *
+ * This example builds on the net_io example by using a buffered_stream to
+ * simplify the logic. This helpfully provides the input and output queues
+ * and a copier internally. They can be accessed from the buffered stream
+ * if required but as demonstrated here that is likely not necessary.
+ */
+
+static Eina_List *_commands = NULL;
+static Eina_Slice _delimiter;
+static Efl_Net_Dialer *_dialer = NULL;
+static Efl_Io_Buffered_Stream *_stream = NULL;
+
+static void
+_quit(int retval)
+{
+ if (_stream)
+ {
+ efl_io_closer_close(_stream);
+ efl_del(_stream);
+ }
+
+ if (_dialer)
+ efl_del(_dialer);
+
+ efl_exit(retval);
+}
+
+static void
+_command_next(void)
+{
+ Eina_Slice slice;
+ char *cmd;
+
+ if (!_commands)
+ {
+ efl_io_buffered_stream_eos_mark(_stream);
+ return;
+ }
+
+ cmd = _commands->data;
+ _commands = eina_list_remove_list(_commands, _commands);
+
+ slice = (Eina_Slice)EINA_SLICE_STR(cmd);
+ efl_io_writer_write(_stream, &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(_stream, &slice, NULL);
+}
+
+static void
+_stream_line(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ Eina_Slice slice = efl_io_buffered_stream_slice_get(event->object);
+
+ // Can be caused when we issue efl_io_buffered_stream_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_buffered_stream_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
+_stream_done(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ fprintf(stderr, "INFO: %s done\n", efl_name_get(event->object));
+
+ _quit(EXIT_SUCCESS);
+}
+
+static void
+_stream_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));
+
+ _quit(EXIT_FAILURE);
+}
+
+EFL_CALLBACKS_ARRAY_DEFINE(stream_cbs,
+ { EFL_IO_BUFFERED_STREAM_EVENT_LINE, _stream_line },
+ { EFL_IO_READER_EVENT_EOS, _stream_done },
+ { EFL_IO_BUFFERED_STREAM_EVENT_ERROR, _stream_error });
+
+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;
+ Efl_Loop *loop;
+
+ _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");
+
+ /*
+ * 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 main 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");
+ _quit(EXIT_FAILURE);
+ }
+
+ /*
+ * Without the buffered stream we'd have to create two Efl.Io.Queue
+ * ourselves, as well as two Efl.Io.Copier to link them with the
+ * dialer.
+ *
+ * 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.
+ *
+ * On incoming data we peek at it with slice_get() and then clear().
+ */
+ _stream = efl_add(EFL_IO_BUFFERED_STREAM_CLASS, loop,
+ efl_name_set(efl_added, "stream"),
+ efl_io_buffered_stream_inner_io_set(efl_added, _dialer), /* mandatory! */
+ efl_io_buffered_stream_line_delimiter_set(efl_added, _delimiter),
+ efl_io_buffered_stream_max_queue_size_input_set(efl_added, buffer_limit),
+ efl_io_buffered_stream_max_queue_size_output_set(efl_added, buffer_limit),
+ efl_event_callback_array_add(efl_added, stream_cbs(), NULL));
+
+ err = efl_net_dialer_dial(_dialer, address);
+ if (err)
+ {
+ fprintf(stderr, "ERROR: could not dial %s: %s\n",
+ address, eina_error_msg_get(err));
+ _quit(EXIT_FAILURE);
+ }
+}
+EFL_MAIN()
+