ajwillia-ms pushed a commit to branch master. http://git.enlightenment.org/tools/examples.git/commit/?id=42de664854c4163c74e75cf29733c90cab788e6e
commit 42de664854c4163c74e75cf29733c90cab788e6e Author: Andy Williams <[email protected]> Date: Tue Dec 19 17:48:30 2017 +0000 net: Add a buffered net io example that is far simpler than without --- reference/c/net/src/meson.build | 7 ++ reference/c/net/src/net_io_buffered.c | 176 ++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) diff --git a/reference/c/net/src/meson.build b/reference/c/net/src/meson.build index 22f5898..025d830 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 0000000..14e841a --- /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() + --
