2017-12-19 09:48:30 -08:00
|
|
|
#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
|
2018-01-04 08:40:14 -08:00
|
|
|
efl_main(void *data EINA_UNUSED, const Efl_Event *ev)
|
2017-12-19 09:48:30 -08:00
|
|
|
{
|
|
|
|
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
|
2018-01-04 08:40:14 -08:00
|
|
|
* provider. We use the loop passed to our main method.
|
2017-12-19 09:48:30 -08:00
|
|
|
*/
|
2018-01-04 08:40:14 -08:00
|
|
|
loop = ev->object;
|
2017-12-19 09:48:30 -08:00
|
|
|
|
|
|
|
/* 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"),
|
2019-03-09 06:54:38 -08:00
|
|
|
efl_event_callback_add(efl_added, EFL_NET_DIALER_EVENT_DIALER_CONNECTED, _dialer_connected, NULL));
|
2017-12-19 09:48:30 -08:00
|
|
|
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()
|
|
|
|
|