diff --git a/legacy/ecore/doc/examples.dox b/legacy/ecore/doc/examples.dox index 09984f2f93..cda5bd549a 100644 --- a/legacy/ecore/doc/examples.dox +++ b/legacy/ecore/doc/examples.dox @@ -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 * */ @@ -592,6 +595,172 @@ * @until } */ +/** + * @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 @@ -652,6 +821,20 @@ * complete example description at @ref ecore_con_url_download_example_c */ +/** + * @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, diff --git a/legacy/ecore/src/examples/Makefile.am b/legacy/ecore/src/examples/Makefile.am index a6614faf5a..ffc9cabf3d 100644 --- a/legacy/ecore/src/examples/Makefile.am +++ b/legacy/ecore/src/examples/Makefile.am @@ -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/legacy/ecore/src/examples/ecore_con_client_simple_example.c b/legacy/ecore/src/examples/ecore_con_client_simple_example.c new file mode 100644 index 0000000000..f6eb257602 --- /dev/null +++ b/legacy/ecore/src/examples/ecore_con_client_simple_example.c @@ -0,0 +1,124 @@ +#include +#include +#include + +#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
[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/legacy/ecore/src/examples/ecore_con_server_simple_example.c b/legacy/ecore/src/examples/ecore_con_server_simple_example.c new file mode 100644 index 0000000000..e466ed4701 --- /dev/null +++ b/legacy/ecore/src/examples/ecore_con_server_simple_example.c @@ -0,0 +1,131 @@ +#include +#include +#include + +#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; +}