summaryrefslogtreecommitdiff
path: root/src/examples/ecore/efl_net_dialer_websocket_example.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/examples/ecore/efl_net_dialer_websocket_example.c')
-rw-r--r--src/examples/ecore/efl_net_dialer_websocket_example.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/src/examples/ecore/efl_net_dialer_websocket_example.c b/src/examples/ecore/efl_net_dialer_websocket_example.c
new file mode 100644
index 0000000000..fa7bb2b7c2
--- /dev/null
+++ b/src/examples/ecore/efl_net_dialer_websocket_example.c
@@ -0,0 +1,384 @@
+#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 int lines_text = 0;
+static int lines_binary = 0;
+
+static void
+_dummy_send(Eo *dialer, Eina_Bool text, size_t lines)
+{
+ size_t len = lines * 80;
+ char *buf = malloc(len + 1);
+ const size_t az_range = 'Z' - 'A';
+ size_t i;
+
+ for (i = 0; i < lines; i++) {
+ char *ln = buf + i * 80;
+ uint8_t chr;
+
+ snprintf(ln, 11, "%9zd ", i + 1);
+ if (text)
+ chr = (i % az_range) + 'A';
+ else
+ chr = i & 0xff;
+ memset(ln + 10, chr, 69);
+ ln[79] = '\n';
+ }
+ buf[len] = '\0';
+
+ if (text)
+ efl_net_dialer_websocket_text_send(dialer, buf);
+ else
+ {
+ Eina_Slice slice = {.mem = buf, .len = len};
+ efl_net_dialer_websocket_binary_send(dialer, slice);
+ }
+ free(buf);
+}
+
+static void
+_ws_pong(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ fprintf(stderr, "INFO: got PONG: %s\n", (const char *)event->info);
+
+ efl_net_dialer_websocket_close_request(event->object,
+ EFL_NET_DIALER_WEBSOCKET_CLOSE_REASON_NORMAL,
+ "close it!");
+}
+
+static void
+_ws_closed_reason(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ Efl_Net_Dialer_Websocket_Closed_Reason *reason = event->info;
+ fprintf(stderr, "INFO: got CLOSE: %4d '%s'\n",
+ reason->reason, reason->message);
+}
+
+static void
+_ws_message_text(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ fprintf(stderr, "INFO: got TEXT:\n%s\n", (const char *)event->info);
+
+ if (lines_text < 5)
+ _dummy_send(event->object, EINA_TRUE, ++lines_text);
+ else
+ _dummy_send(event->object, EINA_FALSE, ++lines_binary);
+}
+
+static void
+_ws_message_binary(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ const Eina_Slice *slice = event->info;
+ size_t i;
+
+ fprintf(stderr, "INFO: got BINARY %zd bytes\n", slice->len);
+
+ for (i = 0; i < slice->len; i++)
+ {
+ const int c = slice->bytes[i];
+ if (isprint(c))
+ fprintf(stderr, " %#4x(%c)", c, c);
+ else
+ fprintf(stderr, " %#4x", c);
+ }
+
+ fprintf(stderr, "\n");
+
+ if (lines_binary < 5)
+ _dummy_send(event->object, EINA_FALSE, ++lines_binary);
+ else
+ efl_net_dialer_websocket_ping(event->object, "will close on pong");
+}
+
+static void
+_closed(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ fprintf(stderr, "INFO: closed %s\n",
+ efl_name_get(event->object));
+ ecore_main_loop_quit();
+}
+
+static void
+_eos(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ fprintf(stderr, "INFO: eos %s\n",
+ efl_name_get(event->object));
+}
+
+static void
+_connected(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ Eina_Stringshare *protocol;
+ Eina_Iterator *itr;
+ fprintf(stderr, "INFO: connected %s\n",
+ efl_net_dialer_address_dial_get(event->object));
+
+ itr = efl_net_dialer_websocket_response_protocols_get(event->object);
+ EINA_ITERATOR_FOREACH(itr, protocol)
+ fprintf(stderr, "INFO: server protocol: %s\n", protocol);
+ eina_iterator_free(itr);
+
+ _dummy_send(event->object, EINA_TRUE, ++lines_text);
+}
+
+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;
+ ecore_main_loop_quit();
+}
+
+EFL_CALLBACKS_ARRAY_DEFINE(dialer_cbs,
+ { EFL_NET_DIALER_WEBSOCKET_EVENT_PONG, _ws_pong },
+ { EFL_NET_DIALER_WEBSOCKET_EVENT_CLOSED_REASON, _ws_closed_reason },
+ { EFL_NET_DIALER_WEBSOCKET_EVENT_MESSAGE_TEXT, _ws_message_text },
+ { EFL_NET_DIALER_WEBSOCKET_EVENT_MESSAGE_BINARY, _ws_message_binary },
+ { EFL_NET_DIALER_EVENT_CONNECTED, _connected },
+ { EFL_NET_DIALER_EVENT_RESOLVED, _resolved },
+ { EFL_NET_DIALER_EVENT_ERROR, _error },
+ { EFL_IO_CLOSER_EVENT_CLOSED, _closed },
+ { EFL_IO_READER_EVENT_EOS, _eos });
+
+
+static const char *authentication_method_choices[] = {
+ "none",
+ "basic",
+ "digest",
+ "negotiate",
+ "ntlm",
+ "ntlm_winbind",
+ "any_safe",
+ "any",
+ NULL,
+};
+
+static Efl_Net_Http_Authentication_Method
+_parse_authentication_method(const char *str)
+{
+ if (strcmp(str, "basic") == 0)
+ return EFL_NET_HTTP_AUTHENTICATION_METHOD_BASIC;
+ if (strcmp(str, "digest") == 0)
+ return EFL_NET_HTTP_AUTHENTICATION_METHOD_DIGEST;
+ if (strcmp(str, "negotiate") == 0)
+ return EFL_NET_HTTP_AUTHENTICATION_METHOD_NEGOTIATE;
+ if (strcmp(str, "ntlm") == 0)
+ return EFL_NET_HTTP_AUTHENTICATION_METHOD_NTLM;
+ if (strcmp(str, "ntlm_winbind") == 0)
+ return EFL_NET_HTTP_AUTHENTICATION_METHOD_NTLM_WINBIND;
+ if (strcmp(str, "any_safe") == 0)
+ return EFL_NET_HTTP_AUTHENTICATION_METHOD_ANY_SAFE;
+ if (strcmp(str, "any") == 0)
+ return EFL_NET_HTTP_AUTHENTICATION_METHOD_ANY;
+
+ return EFL_NET_HTTP_AUTHENTICATION_METHOD_NONE;
+}
+
+static const Ecore_Getopt options = {
+ "efl_net_dialer_websocket_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_Websocket usage in message-based mode.\n"
+ "In this example couple of text and binary messages are sent to the server, "
+ "as well as a ping. On pong the websocket is closed."
+ "\n"
+ "For the EFL I/O interfaces example, see efl_io_copier_example.c"
+ "\n",
+ EINA_FALSE,
+ {
+ ECORE_GETOPT_APPEND('p', "websocket-protocol", "WebSocket protocol to request", ECORE_GETOPT_TYPE_STR),
+ ECORE_GETOPT_STORE_STR('U', "username", "Authentication username"),
+ ECORE_GETOPT_STORE_STR('P', "password", "Authentication password"),
+ ECORE_GETOPT_CHOICE('A', "authentication-method", "Authentication method", authentication_method_choices),
+ ECORE_GETOPT_STORE_BOOL('R', "authentication-restricted", "Authentication method must be restricted"),
+ ECORE_GETOPT_STORE_BOOL('r', "allow-redirects", "allow redirections by following 'Location:' headers"),
+ ECORE_GETOPT_STORE_DOUBLE('t', "connect-timeout", "timeout in seconds for the connection phase"),
+ ECORE_GETOPT_APPEND('H', "header", "Add custom headers. Format must be 'Key: Value'", ECORE_GETOPT_TYPE_STR),
+ ECORE_GETOPT_STORE_STR('X', "proxy", "Set a specific proxy for the connection"),
+ ECORE_GETOPT_STORE_STR('c', "cookie-jar", "Set the cookie-jar file to read/save cookies from. Empty means an in-memory cookie-jar"),
+
+ 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, such as wss://echo.websocket.org", "address"),
+ ECORE_GETOPT_SENTINEL
+ }
+};
+
+int
+main(int argc, char **argv)
+{
+ char *address = NULL;
+ char *username = NULL;
+ char *password = NULL;
+ char *authentication_method_str = "basic";
+ char *proxy = NULL;
+ char *cookie_jar = NULL;
+ Eina_Bool authentication_restricted = EINA_FALSE;
+ Eina_Bool allow_redirects = EINA_TRUE;
+ double timeout_dial = 30.0;
+ Eina_List *headers = NULL;
+ Eina_List *protocols = NULL;
+ Eina_Bool quit_option = EINA_FALSE;
+ Ecore_Getopt_Value values[] = {
+ ECORE_GETOPT_VALUE_LIST(protocols),
+ ECORE_GETOPT_VALUE_STR(username),
+ ECORE_GETOPT_VALUE_STR(password),
+ ECORE_GETOPT_VALUE_STR(authentication_method_str),
+ ECORE_GETOPT_VALUE_BOOL(authentication_restricted),
+ ECORE_GETOPT_VALUE_BOOL(allow_redirects),
+ ECORE_GETOPT_VALUE_DOUBLE(timeout_dial),
+ ECORE_GETOPT_VALUE_LIST(headers),
+ ECORE_GETOPT_VALUE_STR(proxy),
+ ECORE_GETOPT_VALUE_STR(cookie_jar),
+
+ /* 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;
+ Efl_Net_Http_Authentication_Method authentication_method;
+ Efl_Net_Http_Header *header;
+ Eina_Iterator *itr;
+ Eina_Error err;
+ char *str;
+
+ ecore_init();
+ ecore_con_init();
+ ecore_con_url_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;
+ }
+
+ authentication_method = _parse_authentication_method(authentication_method_str);
+
+ if (cookie_jar && cookie_jar[0] == ' ')
+ cookie_jar = "";
+
+ dialer = efl_add(EFL_NET_DIALER_WEBSOCKET_CLASS, loop,
+ efl_name_set(efl_self, "dialer"),
+ efl_net_dialer_websocket_authentication_set(efl_self, username, password, authentication_method, authentication_restricted),
+ efl_net_dialer_websocket_allow_redirects_set(efl_self, allow_redirects),
+ efl_net_dialer_websocket_cookie_jar_set(efl_self, cookie_jar),
+ efl_net_dialer_proxy_set(efl_self, proxy),
+ efl_net_dialer_timeout_dial_set(efl_self, timeout_dial),
+ efl_event_callback_array_add(efl_self, dialer_cbs(), NULL));
+ if (!dialer)
+ {
+ retval = EXIT_FAILURE;
+ fprintf(stderr, "ERROR: could not create WebSockets dialer\n");
+ goto end;
+ }
+
+ EINA_LIST_FREE(headers, str)
+ {
+ char *p = strchr(str, ':');
+ if (p)
+ {
+ p[0] = '\0';
+ p++;
+ while ((p[0] != '\0') && isspace(p[0]))
+ p++;
+ }
+ efl_net_dialer_websocket_request_header_add(dialer, str, p);
+ free(str);
+ }
+
+ EINA_LIST_FREE(protocols, str)
+ {
+ efl_net_dialer_websocket_request_protocol_add(dialer, str);
+ free(str);
+ }
+
+ err = efl_net_dialer_dial(dialer, address);
+ if (err != 0)
+ {
+ retval = EXIT_FAILURE;
+ fprintf(stderr, "ERROR: could not dial '%s': %s",
+ address, eina_error_msg_get(err));
+ goto no_mainloop;
+ }
+
+ fprintf(stderr,
+ "INFO: dialed %s\n"
+ "INFO: - allow_redirects=%d\n"
+ "INFO: - cookie_jar=%s\n"
+ "INFO: - timeout_dial=%fs\n"
+ "INFO: - proxy=%s\n"
+ "INFO: - request headers:\n",
+ efl_net_dialer_address_dial_get(dialer),
+ efl_net_dialer_websocket_allow_redirects_get(dialer),
+ efl_net_dialer_websocket_cookie_jar_get(dialer),
+ efl_net_dialer_timeout_dial_get(dialer),
+ efl_net_dialer_proxy_get(dialer));
+ itr = efl_net_dialer_websocket_request_headers_get(dialer);
+ EINA_ITERATOR_FOREACH(itr, header)
+ fprintf(stderr, "INFO: %s: %s\n", header->key, header->value);
+ eina_iterator_free(itr);
+
+ fprintf(stderr, "INFO: - request protocols:\n");
+ itr = efl_net_dialer_websocket_request_protocols_get(dialer);
+ EINA_ITERATOR_FOREACH(itr, str)
+ fprintf(stderr, "INFO: %s\n", str);
+ eina_iterator_free(itr);
+
+ ecore_main_loop_begin();
+
+ fprintf(stderr, "INFO: main loop finished.\n");
+
+ no_mainloop:
+ efl_del(dialer);
+
+ end:
+ ecore_con_url_shutdown();
+ ecore_con_shutdown();
+ ecore_shutdown();
+
+ return retval;
+}