ecore/ecore_con - Ecore_Con examples (server and client).
authorantognolli <antognolli@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 12 Jul 2011 14:37:22 +0000 (14:37 +0000)
committerantognolli <antognolli@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 12 Jul 2011 14:37:22 +0000 (14:37 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ecore@61297 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

doc/examples.dox
src/examples/Makefile.am
src/examples/ecore_con_client_simple_example.c [new file with mode: 0644]
src/examples/ecore_con_server_simple_example.c [new file with mode: 0644]

index 09984f2..cda5bd5 100644 (file)
@@ -11,6 +11,9 @@
  * @li @ref ecore_fd_handler_example_c
  * @li @ref ecore_poller_example_c
  * @li @ref ecore_con_lookup_example_c
+ * @li @ref ecore_con_url_download_example_c
+ * @li @ref ecore_con_server_simple_example_c
+ * @li @ref ecore_con_client_simple_example_c
  *
  */
 
  */
 
 /**
+ * @page ecore_con_server_simple_example_c Ecore_Con - Creating a server
+ *
+ * In this example we are going to create a server that listens for connections
+ * from clients through a TCP port. You can get the full source code at @ref
+ * ecore_con_server_simple_example.c.
+ *
+ * We begin our example in the main function, to demonstrate how to setup
+ * things, and then go to the callbacks that are needed for it to run properly.
+ *
+ * In the @c main function, after initializing the libraries, we use
+ * ecore_con_server_add() to startup the server. Look at the reference
+ * documentation of this function: it supports many types of server, and we are
+ * going to use #ECORE_CON_REMOTE_TCP (a TCP based server). Other arguments to
+ * this function are the address where we are listening on, the port, and a data
+ * pointer that will associate that data with the server:
+ *
+ * @dontinclude ecore_con_server_simple_example.c
+ * @skip main(void)
+ * @until exit
+ *
+ * Notice that we are listening only on 127.0.0.1, which is the internal
+ * loopback interface. If the server needs to listening on all of its ips, use
+ * 0.0.0.0 instead.
+ *
+ * We also need to set event handlers to be called when we receive any data from
+ * the clients, when a new client connects to our server, or when a client
+ * disconnects. These callbacks are:
+ *
+ * @until CLIENT_DATA
+ *
+ * More details about what these callbacks do will be given later.
+ *
+ * Now, before running the main loop, we also want to set some limits to our
+ * server. To avoid it to be overloaded with too many connections to handle, we
+ * are going to set a maximum of 3 clients connected at the same time. This
+ * number is used just to demonstrate the API. A good number to be used here
+ * would need to be determined by tests done on the server, to check the load
+ * supported by it.
+ *
+ * Any other client trying to connect to this server, after the limit is
+ * reached, will wait until one of the connected clients disconnect and the
+ * server accepts the new connection.
+ *
+ * Another important thing to do is setting a timeout, to avoid that a client
+ * hold a connection for too long without doing anything. This timeout will
+ * disconnect the idle client, allowing that other clients that may be waiting
+ * to connect finally can do it.
+ *
+ * Then we just start the main loop:
+ *
+ * @until main_loop_begin
+ *
+ * After exiting the main loop, we print the list of connected clients, and also
+ * free the data associated with each respective client. This data was
+ * previously associated using ecore_con_client_data_set():
+ *
+ * @until }
+ *
+ * Then before exiting we show the total uptime of the server:
+ *
+ * @until uptime
+ *
+ * Now let's go back to the used callbacks.
+ *
+ * The first callback, @c _add, is registered to the event
+ * #ECORE_CON_EVENT_CLIENT_ADD, which will be called whenever a client connects
+ * to the server.
+ *
+ * This callback will associate a data structure to this client, that will be
+ * used to count how many bytes were received from it. It also prints some info
+ * about the client, and send a welcome string to it. ecore_con_client_flush()
+ * is used to ensure that the string is sent immediately, instead of be
+ * bufferized.
+ *
+ * A timeout for idle specific for this client is also set, to demonstrate that
+ * it is independent of the general timeout of the server.
+ *
+ * Before exiting, the callback will display a list of all clients still
+ * connected to this server. The code for this callback follows:
+ *
+ * @dontinclude ecore_con_server_simple_example.c
+ * @skip Eina_Bool
+ * @until CALLBACK_RENEW
+ * @until }
+ *
+ * The second callback is @c _del. It is associated with
+ * #ECORE_CON_EVENT_CLIENT_DEL, and is called whenever a client disconnects from
+ * this server.
+ *
+ * It will just print some information about the client, free the associated
+ * data structure, and call ecore_con_client_del() on it before exiting the
+ * callback. Here's its code:
+ *
+ * @until CALLBACK_RENEW
+ * @until }
+ *
+ * The last callback will print any data received by this server from its
+ * clients. It also increments the "bytes received" counter, sdata, in the
+ * data structure associated with this client. The callback code follows:
+ *
+ * @until CALLBACK_RENEW
+ * @until }
+ *
+ * The important parts of this example were described above. If you need to see
+ * the full source code for it, there's a link to the code in the beginning of
+ * this page.
+ *
+ * @note This example contains a serious security flaw: it doesn't check for the
+ * size of data being received, thus allowing to the string to be exploited in
+ * some way. However, it is left like this to make the code simpler and just
+ * demonstrate the API usage.
+ */
+
+/**
+ * @page ecore_con_client_simple_example_c Ecore_Con - Creating a client
+ *
+ * Following the same idea as the @ref ecore_con_server_simple_example_c , this
+ * example will demonstrate how to create a client that connects to a specified
+ * server through a TCP port. You can see the full source code at @ref
+ * ecore_con_client_simple_example.c.
+ *
+ * Starting from the @c main function, after reading the command line argument
+ * list and initializing the libraries, we try to connect to the server:
+ *
+ * @dontinclude ecore_con_client_simple_example.c
+ * @skip main(
+ * @until exit(2)
+ * @until }
+ *
+ * After doing this, everything else in @c main is setting up callbacks for the
+ * client events, starting the main loop and shutting down the libraries after
+ * it.
+ *
+ * Now let's go to the callbacks. These callbacks are very similar to the server
+ * callbacks (our implementation for this example is very simple). On the
+ * @c _add callback, we just set a data structure to the server, print some
+ * information about the server, and send a welcome message to it:
+ *
+ * @dontinclude ecore_con_client_simple_example.c
+ * @skip Eina_Bool
+ * @until CALLBACK_RENEW
+ * @until }
+ *
+ * The @c _del callback is as simple as the previous one. We free the data
+ * associated with the server, print the uptime of this client, and quit the
+ * main loop (since there's nothing to do once we disconnect):
+ *
+ * @until CALLBACK_RENEW
+ * @until }
+ *
+ * The @c _data callback is also similar to the server data callback. it will
+ * print any received data, and increase the data counter in the structure
+ * associated with this server:
+ *
+ * @until CALLBACK_RENEW
+ *
+ * You can see the server counterpart functions of the ones used in this example
+ * in the @ref ecore_con_server_simple_example_c.
+ *
+ * @note This example contains a serious security flaw: it doesn't check for the
+ * size of data being received, thus allowing to the string to be exploited in
+ * some way. However, it is left like this to make the code simpler and just
+ * demonstrate the API usage.
+ */
+
+/**
  * @example ecore_idler_example.c
  * This example shows when @ref Ecore_Idler, @ref Ecore_Idle_Enterer and @ref
  * Ecore_Idle_Exiter are called. See
  */
 
 /**
+ * @example ecore_con_server_simple_example.c
+ * Shows how to setup a simple server that accepts client connections and sends
+ * a "hello" string to them. See the complete example description at @ref
+ * ecore_con_server_simple_example_c
+ */
+
+/**
+ * @example ecore_con_client_simple_example.c
+ * Shows how to setup a simple client that connects to a server and sends a
+ * "hello" string to it. See the complete example description at @ref
+ * ecore_con_client_simple_example_c
+ */
+
+/**
  * @example ecore_con_url_headers_example.c
  * Shows how to make GET or POST requests using an @ref Ecore_Con_Url object,
  * and make use of most of its API.  See the complete example description at
index a6614fa..ffc9cab 100644 (file)
@@ -30,6 +30,8 @@ SRCS = \
        ecore_con_lookup_example.c \
        ecore_con_url_headers_example.c \
        ecore_con_url_download_example.c \
+       ecore_con_server_simple_example.c \
+       ecore_con_client_simple_example.c \
        client_bench.c \
        server_bench.c \
        ecore_con_client_example.c \
@@ -63,13 +65,16 @@ pkglib_PROGRAMS += \
        ecore_con_lookup_example \
        ecore_con_url_headers_example \
        ecore_con_url_download_example \
+       ecore_con_server_simple_example \
+       ecore_con_client_simple_example \
        ecore_thread_example
 
 ecore_animator_example_LDADD = $(ECOREBASELDADD) @EVAS_LIBS@ $(top_builddir)/src/lib/ecore_evas/libecore_evas.la
 ecore_con_lookup_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la
 ecore_con_url_headers_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la
 ecore_con_url_download_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la
-#ecore_con_server_simple_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la
+ecore_con_server_simple_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la
+ecore_con_client_simple_example_LDADD = $(ECOREBASELDADD) $(top_builddir)/src/lib/ecore_con/libecore_con.la
 
 endif
 
diff --git a/src/examples/ecore_con_client_simple_example.c b/src/examples/ecore_con_client_simple_example.c
new file mode 100644 (file)
index 0000000..f6eb257
--- /dev/null
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <Ecore.h>
+#include <Ecore_Con.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else
+# define __UNUSED__
+#endif
+
+struct _Server {
+    int sdata;
+};
+
+Eina_Bool
+_add(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Server_Add *ev)
+{
+   char welcome[] = "hello! - sent from the client";
+   struct _Server *server = malloc(sizeof(*server));
+   server->sdata = 0;
+
+   ecore_con_server_data_set(ev->server, server);
+   printf("Server with ip %s, name %s, port %d, connected = %d!\n",
+         ecore_con_server_ip_get(ev->server),
+         ecore_con_server_name_get(ev->server),
+         ecore_con_server_port_get(ev->server),
+         ecore_con_server_connected_get(ev->server));
+   ecore_con_server_send(ev->server, welcome, sizeof(welcome));
+   ecore_con_server_flush(ev->server);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+
+Eina_Bool
+_del(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Server_Del *ev)
+{
+   if (!ev->server)
+     {
+       printf("Failed to establish connection to the server.\nExiting.\n");
+       ecore_main_loop_quit();
+       return ECORE_CALLBACK_RENEW;
+     }
+
+   struct _Server *server = ecore_con_server_data_get(ev->server);
+
+   printf("Lost server with ip %s!\n", ecore_con_server_ip_get(ev->server));
+
+   if (server)
+     {
+       printf("Total data received from this server: %d\n", server->sdata);
+       free(server);
+     }
+
+   ecore_con_server_del(ev->server);
+
+   ecore_main_loop_quit();
+   return ECORE_CALLBACK_RENEW;
+}
+
+Eina_Bool
+_data(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Server_Data *ev)
+{
+   char fmt[128];
+   struct _Server *server = ecore_con_server_data_get(ev->server);
+
+   snprintf(fmt, sizeof(fmt),
+            "Received %i bytes from server:\n"
+            ">>>>>\n"
+            "%%.%is\n"
+            ">>>>>\n",
+            ev->size, ev->size);
+
+   printf(fmt, ev->data);
+
+   server->sdata += ev->size;
+   return ECORE_CALLBACK_RENEW;
+}
+
+int main(int argc, const char *argv[])
+{
+   Ecore_Con_Server *svr;
+   const char *address;
+   int port = 8080;
+
+   if (argc < 2)
+     {
+       printf("wrong usage. Command syntax is:\n");
+       printf("\tecore_con_client_simple_example <address> [port]\n");
+       exit (1);
+     }
+
+   address = argv[1];
+
+   if (argc > 2)
+     port = atoi(argv[2]);
+
+   eina_init();
+   ecore_init();
+   ecore_con_init();
+
+   if (!(svr = ecore_con_server_connect(ECORE_CON_REMOTE_TCP, address, port, NULL)))
+     {
+       printf("could not connect to the server: %s, port %d.\n",
+              address, port);
+       exit(2);
+     }
+
+   /* set event handler for server connect */
+   ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, (Ecore_Event_Handler_Cb)_add, NULL);
+   /* set event handler for server disconnect */
+   ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, (Ecore_Event_Handler_Cb)_del, NULL);
+   /* set event handler for receiving server data */
+   ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, (Ecore_Event_Handler_Cb)_data, NULL);
+
+   /* start client */
+   ecore_main_loop_begin();
+
+   ecore_con_init();
+   ecore_init();
+   eina_init();
+
+   return 0;
+}
diff --git a/src/examples/ecore_con_server_simple_example.c b/src/examples/ecore_con_server_simple_example.c
new file mode 100644 (file)
index 0000000..e466ed4
--- /dev/null
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <Ecore.h>
+#include <Ecore_Con.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else
+# define __UNUSED__
+#endif
+
+struct _Client {
+    int sdata;
+};
+
+Eina_Bool
+_add(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Add *ev)
+{
+   char welcome[] = "hello! - sent from the server";
+   Ecore_Con_Server *srv;
+   Ecore_Con_Client *cl;
+   const Eina_List *clients, *l;
+
+   struct _Client *client = malloc(sizeof(*client));
+   client->sdata = 0;
+
+   printf("Client with ip %s, port %d, connected = %d!\n",
+         ecore_con_client_ip_get(ev->client),
+         ecore_con_client_port_get(ev->client),
+         ecore_con_client_connected_get(ev->client));
+
+   ecore_con_client_send(ev->client, welcome, sizeof(welcome));
+   ecore_con_client_flush(ev->client);
+
+   ecore_con_client_timeout_set(ev->client, 6);
+
+   ecore_con_client_data_set(ev->client, client);
+
+   srv = ecore_con_client_server_get(ev->client);
+   printf("Clients connected to this server:\n");
+   clients = ecore_con_server_clients_get(srv);
+   EINA_LIST_FOREACH(clients, l, cl)
+      printf("%s\n", ecore_con_client_ip_get(cl));
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+
+Eina_Bool
+_del(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Del *ev)
+{
+   struct _Client *client;
+
+   if (!ev->client)
+     return ECORE_CALLBACK_RENEW;
+
+   client = ecore_con_client_data_get(ev->client);
+
+   printf("Lost client with ip %s!\n", ecore_con_client_ip_get(ev->client));
+   printf("Total data received from this client: %d\n", client->sdata);
+   printf("Client was connected for %0.3f seconds.\n",
+         ecore_con_client_uptime_get(ev->client));
+
+   if (client)
+     free(client);
+
+   ecore_con_client_del(ev->client);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+Eina_Bool
+_data(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Data *ev)
+{
+   char fmt[128];
+   struct _Client *client = ecore_con_client_data_get(ev->client);
+
+   snprintf(fmt, sizeof(fmt),
+            "Received %i bytes from client %s port %d:\n"
+            ">>>>>\n"
+            "%%.%is\n"
+            ">>>>>\n",
+            ev->size, ecore_con_client_ip_get(ev->client),
+           ecore_con_client_port_get(ev->client), ev->size);
+
+   printf(fmt, ev->data);
+
+   client->sdata += ev->size;
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+int main(void)
+{
+   Ecore_Con_Server *svr;
+   Ecore_Con_Client *cl;
+   const Eina_List *clients, *l;
+
+   eina_init();
+   ecore_init();
+   ecore_con_init();
+
+   if (!(svr = ecore_con_server_add(ECORE_CON_REMOTE_TCP, "127.0.0.1", 8080, NULL)))
+     exit(1);
+
+   ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, (Ecore_Event_Handler_Cb)_add, NULL);
+   ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, (Ecore_Event_Handler_Cb)_del, NULL);
+   ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, (Ecore_Event_Handler_Cb)_data, NULL);
+
+   ecore_con_server_timeout_set(svr, 10);
+   ecore_con_server_client_limit_set(svr, 3, 0);
+
+   ecore_main_loop_begin();
+
+   clients = ecore_con_server_clients_get(svr);
+   printf("Clients connected to this server when exiting: %d\n",
+          eina_list_count(clients));
+   EINA_LIST_FOREACH(clients, l, cl)
+     {
+       printf("%s\n", ecore_con_client_ip_get(cl));
+       free(ecore_con_client_data_get(cl));
+     }
+
+   printf("Server was up for %0.3f seconds\n",
+          ecore_con_server_uptime_get(svr));
+
+   ecore_con_shutdown();
+   ecore_shutdown();
+   eina_shutdown();
+
+   return 0;
+}