ecore_con_server_example.c

Shows how to write a simple server using the Ecore_Con library using ecore_con_server_add()

//Compile with:
// gcc -o ecore_con_server_example ecore_con_server_example.c `pkg-config --libs --cflags ecore ecore-con eina`
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <Ecore.h>
#include <Ecore_Con.h>
#include <Ecore_Getopt.h>
/* Ecore_Con server example
* 2010 Mike Blumenkrantz
*/
static int retval = EXIT_SUCCESS;
static Eina_Bool echo = EINA_FALSE;
static Eina_Bool do_flush = EINA_FALSE;
static Eina_Bool single_message = EINA_FALSE;
static Eina_Bool do_ssl_upgrade = EINA_FALSE;
Eina_Bool
_add(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Con_Event_Client_Add *ev = event;
printf("INFO: client added %p: %s\n", ev->client, ecore_con_client_ip_get(ev->client));
if (!echo)
{
ecore_con_client_send(ev->client, "Hello World!", strlen("Hello World!"));
if (do_flush) ecore_con_client_flush(ev->client);
if (single_message) ecore_con_client_del(ev->client);
else if (do_ssl_upgrade)
{
const char upgrade_msg[] = "\nSend \"Upgrade: SSL\" followed by newline (\\n) to do it.\n";
ecore_con_client_send(ev->client, upgrade_msg, strlen(upgrade_msg));
if (do_flush) ecore_con_client_flush(ev->client);
}
}
return ECORE_CALLBACK_RENEW;
}
Eina_Bool
_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Con_Event_Client_Del *ev = event;
printf("INFO: client deleted %p: %s!\n", ev->client, ecore_con_client_ip_get(ev->client));
ecore_con_client_del(ev->client);
return ECORE_CALLBACK_RENEW;
}
Eina_Bool
_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Con_Event_Client_Data *ev = event;
const char upgrade_ssl[] = "Upgrade: SSL\n";
printf("INFO: client data %p: %s\n"
"INFO: - size: %d\n"
"-- BEGIN DATA --\n",
ev->client, ecore_con_client_ip_get(ev->client),
ev->size);
fwrite(ev->data, ev->size, 1, stdout);
puts("-- END DATA --");
if (do_ssl_upgrade && ((size_t)ev->size == strlen(upgrade_ssl)) &&
(memcmp(ev->data, upgrade_ssl, ev->size) == 0))
{
if (!ecore_con_ssl_client_upgrade(ev->client, ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT))
{
printf("ERROR: Failed to upgrade client=%p %s to SSL!\n", ev->client, ecore_con_client_ip_get(ev->client));
ecore_con_client_del(ev->client);
}
else
printf("INFO: upgrading client=%p %s to SSL!\n", ev->client, ecore_con_client_ip_get(ev->client));
return ECORE_CALLBACK_RENEW;
}
if (echo)
{
ecore_con_client_send(ev->client, ev->data, ev->size);
if (do_flush) ecore_con_client_flush(ev->client);
if (single_message) ecore_con_client_del(ev->client);
}
return ECORE_CALLBACK_RENEW;
}
Eina_Bool
_write_(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Con_Event_Client_Write *ev = event;
printf("Sent %d bytes to client %s\n", ev->size, ecore_con_client_ip_get(ev->client));
return ECORE_CALLBACK_RENEW;
}
Eina_Bool
_error(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Con_Event_Client_Error *ev = event;
printf("Client %s Error: %s\n", ecore_con_client_ip_get(ev->client), ev->error);
return ECORE_CALLBACK_RENEW;
}
Eina_Bool
_upgrade(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Con_Event_Client_Upgrade *ev = event;
printf("Client %s Upgraded to SSL.\n", ecore_con_client_ip_get(ev->client));
return ECORE_CALLBACK_RENEW;
}
static const char *types_strs[] = {
"tcp",
"udp",
"ssl",
"tcp+ssl",
"mcast",
"local-user",
"local-system",
NULL
};
static const Ecore_Getopt options = {
"ecore_con_server_example", /* program name */
NULL, /* usage line */
"1", /* version */
"(C) 2016 Enlightenment Project; 2010 Mike Blumenkrantz", /* copyright */
"BSD 2-Clause", /* license */
/* long description, may be multiline and contain \n */
"Example of ecore_con_server_add() usage.\n",
EINA_FALSE,
{
ECORE_GETOPT_CHOICE('t', "type", "Server type to use, defaults to 'tcp'", types_strs),
ECORE_GETOPT_STORE_TRUE(0, "socket-activated",
"Try to use $LISTEN_FDS from systemd, if not do a regular serve"),
ECORE_GETOPT_STORE_INT('l', "clients-limit",
"If set will limit number of clients to accept"),
ECORE_GETOPT_STORE_TRUE('r', "clients-reject-excess",
"Immediately reject excess clients (over limit)"),
ECORE_GETOPT_STORE_TRUE('e', "echo",
"Behave as 'echo' server, send back to client all the data receive"),
ECORE_GETOPT_STORE_TRUE('f', "flush", "Force a flush after every send call."),
ECORE_GETOPT_STORE_TRUE('m', "single-message", "Send a single message and delete the client."),
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 server name.", "name"),
ECORE_GETOPT_STORE_METAVAR_INT(0, NULL, "The server port.", "port"),
ECORE_GETOPT_SENTINEL
}
};
int
main(int argc, char **argv)
{
Ecore_Con_Type type;
char *name = NULL;
char *type_choice = NULL;
int clients_limit = -1;
int port = -1;
Eina_Bool socket_activated = EINA_FALSE;
Eina_Bool clients_reject_excess = EINA_FALSE;
Eina_Bool quit_option = EINA_FALSE;
Ecore_Getopt_Value values[] = {
ECORE_GETOPT_VALUE_STR(type_choice),
ECORE_GETOPT_VALUE_BOOL(socket_activated),
ECORE_GETOPT_VALUE_INT(clients_limit),
ECORE_GETOPT_VALUE_BOOL(clients_reject_excess),
ECORE_GETOPT_VALUE_BOOL(echo),
ECORE_GETOPT_VALUE_BOOL(do_flush),
ECORE_GETOPT_VALUE_BOOL(single_message),
/* 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(name),
ECORE_GETOPT_VALUE_INT(port),
ECORE_GETOPT_VALUE_NONE /* sentinel */
};
int args;
Ecore_Con_Server *svr;
eina_init();
ecore_init();
ecore_con_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;
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;
}
if (!type_choice) type_choice = "tcp";
if (strcmp(type_choice, "tcp") == 0)
type = ECORE_CON_REMOTE_TCP;
else if (strcmp(type_choice, "udp") == 0)
type = ECORE_CON_REMOTE_UDP;
else if (strcmp(type_choice, "ssl") == 0)
type = ECORE_CON_REMOTE_TCP | ECORE_CON_USE_MIXED | ECORE_CON_LOAD_CERT;
else if (strcmp(type_choice, "tcp+ssl") == 0)
{
type = ECORE_CON_REMOTE_TCP;
do_ssl_upgrade = EINA_TRUE;
}
else if (strcmp(type_choice, "local-user") == 0)
type = ECORE_CON_LOCAL_USER;
else if (strcmp(type_choice, "local-system") == 0)
type = ECORE_CON_LOCAL_SYSTEM;
else if (strcmp(type_choice, "mcast") == 0)
type = ECORE_CON_REMOTE_MCAST;
else
{
fprintf(stderr, "ERROR: unsupported --type/-t '%s'\n", type_choice);
retval = EXIT_FAILURE;
goto end;
}
if (socket_activated) type |= ECORE_CON_SOCKET_ACTIVATE;
svr = ecore_con_server_add(type, name, port, NULL);
if (!svr) goto end;
if ((strcmp(type_choice, "ssl") == 0)
#if 1
/* This just works since EFL v 1.19. Prior to this, loading a
* certificate would put the whole server in SSL mode, which is
* unexpected.
*
* There are no ecore_con_ssl_client_cert_add() to report a new
* certificate to clients (and it shouldn't, as it would be too
* expensive to setup for each client, this should be shared).
*
* With EFL v1.19 this can be done, but the whole setup should
* be done at most once before returning to the main loop.
*/
|| (strcmp(type_choice, "tcp+ssl") == 0)
#endif
)
{
if (!ecore_con_ssl_server_cert_add(svr, "server.pem"))
{
fprintf(stderr, "ERROR: could not add cert: server.pem\n");
goto no_mainloop;
}
if (!ecore_con_ssl_server_privkey_add(svr, "server.pem"))
{
fprintf(stderr, "ERROR: could not add privkey: server.pem\n");
goto no_mainloop;
}
}
/* set event handler for client connect */
ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, (Ecore_Event_Handler_Cb)_add, NULL);
/* set event handler for client disconnect */
ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, (Ecore_Event_Handler_Cb)_del, NULL);
/* set event handler for receiving client data */
ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, (Ecore_Event_Handler_Cb)_data, NULL);
/* set event handler that notifies of sent data */
ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_WRITE, (Ecore_Event_Handler_Cb)_write_, NULL);
/* set event handler that notifies of errors */
ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ERROR, (Ecore_Event_Handler_Cb)_error, NULL);
/* set event handler that notifies of upgrades */
ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_UPGRADE, (Ecore_Event_Handler_Cb)_upgrade, NULL);
/* start server */
ecore_main_loop_begin();
no_mainloop:
ecore_con_server_del(svr);
svr = NULL;
end:
ecore_con_shutdown();
ecore_shutdown();
eina_shutdown();
return retval;
}
ecore_con_client_send
ECORE_CON_API int ecore_con_client_send(Ecore_Con_Client *cl, const void *data, int size)
Sends the given data to the given client.
Definition: ecore_con_legacy.c:668
ecore_con_client_flush
ECORE_CON_API void ecore_con_client_flush(Ecore_Con_Client *cl)
Flushes all pending data to the given client.
Definition: ecore_con_legacy.c:767
ecore_con_client_ip_get
ECORE_CON_API const char * ecore_con_client_ip_get(const Ecore_Con_Client *cl)
Gets the IP address of a client that has connected.
Definition: ecore_con_legacy.c:739
ecore_con_client_del
ECORE_CON_API void * ecore_con_client_del(Ecore_Con_Client *cl)
Closes the connection and free memory allocated to the given client.
Definition: ecore_con_legacy.c:711
ECORE_CON_EVENT_CLIENT_ERROR
ECORE_CON_API int ECORE_CON_EVENT_CLIENT_ERROR
A client experienced an error.
Definition: ecore_con_legacy.c:168
ECORE_CON_EVENT_CLIENT_ADD
ECORE_CON_API int ECORE_CON_EVENT_CLIENT_ADD
A client has connected to the server.
Definition: ecore_con_legacy.c:157
ECORE_CON_EVENT_CLIENT_WRITE
ECORE_CON_API int ECORE_CON_EVENT_CLIENT_WRITE
A server connection has sent data to its client.
Definition: ecore_con_legacy.c:167
ECORE_CON_EVENT_CLIENT_DEL
ECORE_CON_API int ECORE_CON_EVENT_CLIENT_DEL
A client has disconnected from the server.
Definition: ecore_con_legacy.c:158
ECORE_CON_EVENT_CLIENT_UPGRADE
ECORE_CON_API int ECORE_CON_EVENT_CLIENT_UPGRADE
A client connection has been upgraded to SSL.
Definition: ecore_con_legacy.c:169
ECORE_CON_EVENT_CLIENT_DATA
ECORE_CON_API int ECORE_CON_EVENT_CLIENT_DATA
A client connected to the server has sent data.
Definition: ecore_con_legacy.c:166
ecore_con_shutdown
ECORE_CON_API int ecore_con_shutdown(void)
Shuts down the Ecore_Con library.
Definition: ecore_con.c:133
ecore_con_init
ECORE_CON_API int ecore_con_init(void)
Initializes the Ecore_Con library.
Definition: ecore_con.c:68
ecore_con_ssl_server_privkey_add
ECORE_CON_API Eina_Bool ecore_con_ssl_server_privkey_add(Ecore_Con_Server *svr, const char *key_file)
Adds an SSL private key for use in ecore_con functions.
Definition: ecore_con_legacy.c:2483
ecore_con_ssl_client_upgrade
ECORE_CON_API Eina_Bool ecore_con_ssl_client_upgrade(Ecore_Con_Client *cl, Ecore_Con_Type ssl_type)
Upgrades a connection to a specified level of encryption.
Definition: ecore_con_legacy.c:900
ecore_con_ssl_server_cert_add
ECORE_CON_API Eina_Bool ecore_con_ssl_server_cert_add(Ecore_Con_Server *svr, const char *cert)
Adds an SSL certificate for use in ecore_con functions.
Definition: ecore_con_legacy.c:2468
ecore_con_server_del
ECORE_CON_API void * ecore_con_server_del(Ecore_Con_Server *svr)
Closes the connection and free the given server.
Definition: ecore_con_legacy.c:2302
Ecore_Con_Server
struct _Ecore_Con_Server Ecore_Con_Server
Used to provide legacy API/ABI compatibility with non-Eo applications.
Definition: Ecore_Con.h:294
ecore_con_server_add
ECORE_CON_API Ecore_Con_Server * ecore_con_server_add(Ecore_Con_Type type, const char *name, int port, const void *data)
Creates a server to listen for connections.
Definition: ecore_con_legacy.c:1696
Ecore_Event_Handler_Cb
Eina_Bool(* Ecore_Event_Handler_Cb)(void *data, int type, void *event)
A callback used by the main loop to handle events of a specified type.
Definition: Ecore_Common.h:603
ecore_event_handler_add
Ecore_Event_Handler * ecore_event_handler_add(int type, Ecore_Event_Handler_Cb func, const void *data)
Adds an event handler.
Definition: ecore_events.c:13
ECORE_GETOPT_VALUE_NONE
#define ECORE_GETOPT_VALUE_NONE
Definition for options that store a NULL value.
Definition: Ecore_Getopt.h:1018
ECORE_GETOPT_VALUE_INT
#define ECORE_GETOPT_VALUE_INT(val)
Definition for options that store a single value in a variable of type int.
Definition: Ecore_Getopt.h:955
ECORE_GETOPT_CHOICE
#define ECORE_GETOPT_CHOICE(shortname, longname, help, choices_array)
Definition for filling Ecore_Getopt_Desc table with a true boolean value.
Definition: Ecore_Getopt.h:750
ECORE_GETOPT_VALUE_STR
#define ECORE_GETOPT_VALUE_STR(val)
Definition for options that store a single value in a variable of type string.
Definition: Ecore_Getopt.h:934
ECORE_GETOPT_STORE_METAVAR_INT
#define ECORE_GETOPT_STORE_METAVAR_INT(shortname, longname, help, metavar)
Definition for filling Ecore_Getopt_Desc table with an option of type int and metavar.
Definition: Ecore_Getopt.h:381
ECORE_GETOPT_STORE_METAVAR_STR
#define ECORE_GETOPT_STORE_METAVAR_STR(shortname, longname, help, metavar)
Definition for filling Ecore_Getopt_Desc table with an option of type string and metavar.
Definition: Ecore_Getopt.h:348
ECORE_GETOPT_LICENSE
#define ECORE_GETOPT_LICENSE(shortname, longname)
Definition for filling Ecore_Getopt_Desc table with a license action.
Definition: Ecore_Getopt.h:892
ECORE_GETOPT_VALUE_BOOL
#define ECORE_GETOPT_VALUE_BOOL(val)
Definition for options that store a single value in a variable of type boolean.
Definition: Ecore_Getopt.h:941
ECORE_GETOPT_VERSION
#define ECORE_GETOPT_VERSION(shortname, longname)
Definition for filling Ecore_Getopt_Desc table with a version action.
Definition: Ecore_Getopt.h:870
ecore_getopt_parse_positional
EAPI int ecore_getopt_parse_positional(const Ecore_Getopt *parser, Ecore_Getopt_Value *values, int argc, char **argv, int start)
Parses command line positional parameters.
Definition: ecore_getopt.c:2096
ecore_getopt_parse
EAPI int ecore_getopt_parse(const Ecore_Getopt *parser, Ecore_Getopt_Value *values, int argc, char **argv)
Parses command line parameters.
Definition: ecore_getopt.c:2032
ECORE_GETOPT_COPYRIGHT
#define ECORE_GETOPT_COPYRIGHT(shortname, longname)
Definition for filling Ecore_Getopt_Desc table with a copyright action.
Definition: Ecore_Getopt.h:881
ECORE_GETOPT_STORE_TRUE
#define ECORE_GETOPT_STORE_TRUE(shortname, longname, help)
Definition for filling Ecore_Getopt_Desc table with a true boolean value.
Definition: Ecore_Getopt.h:727
ECORE_GETOPT_HELP
#define ECORE_GETOPT_HELP(shortname, longname)
Definition for filling Ecore_Getopt_Desc table with a help action.
Definition: Ecore_Getopt.h:859
ECORE_GETOPT_STORE_INT
#define ECORE_GETOPT_STORE_INT(shortname, longname, help)
Definition for macro that fill Ecore_Getopt_Desc table with an option of type int.
Definition: Ecore_Getopt.h:279
ECORE_GETOPT_SENTINEL
#define ECORE_GETOPT_SENTINEL
Definition for filling Ecore_Getopt_Desc table with a sentinel to indicate the end of descriptions.
Definition: Ecore_Getopt.h:927
ecore_shutdown
EAPI int ecore_shutdown(void)
Shuts down connections, signal handlers sockets etc.
Definition: ecore.c:371
ecore_init
EAPI int ecore_init(void)
Sets up connections, signal handlers, sockets etc.
Definition: ecore.c:230
ECORE_CALLBACK_RENEW
#define ECORE_CALLBACK_RENEW
Return value to keep a callback.
Definition: Ecore_Common.h:153
ecore_main_loop_begin
void ecore_main_loop_begin(void)
Runs the application main loop.
Definition: ecore_main.c:1311
eina_shutdown
EINA_API int eina_shutdown(void)
Shuts down the Eina library.
Definition: eina_main.c:379
eina_init
EINA_API int eina_init(void)
Initializes the Eina library.
Definition: eina_main.c:291
EINA_TRUE
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition: eina_types.h:539
EINA_FALSE
#define EINA_FALSE
boolean value FALSE (numerical value 0)
Definition: eina_types.h:533
Eina_Bool
unsigned char Eina_Bool
Type to mimic a boolean.
Definition: eina_types.h:527
EINA_UNUSED
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition: eina_types.h:339
_Ecore_Con_Event_Client_Add
Used as the data param for the ECORE_CON_EVENT_CLIENT_ADD event.
Definition: Ecore_Con.h:442
_Ecore_Con_Event_Client_Add::client
Ecore_Con_Client * client
the client that connected
Definition: Ecore_Con.h:443
_Ecore_Con_Event_Client_Data
Used as the data param for the ECORE_CON_EVENT_CLIENT_DATA event.
Definition: Ecore_Con.h:518
_Ecore_Con_Event_Client_Data::data
void * data
the data that the client sent
Definition: Ecore_Con.h:520
_Ecore_Con_Event_Client_Data::client
Ecore_Con_Client * client
the client that connected
Definition: Ecore_Con.h:519
_Ecore_Con_Event_Client_Data::size
int size
the length of the data sent
Definition: Ecore_Con.h:521
_Ecore_Con_Event_Client_Del
Used as the data param for the ECORE_CON_EVENT_CLIENT_DEL event.
Definition: Ecore_Con.h:461
_Ecore_Con_Event_Client_Del::client
Ecore_Con_Client * client
the client that was lost
Definition: Ecore_Con.h:462
_Ecore_Con_Event_Client_Error
Used as the data param for the ECORE_CON_EVENT_CLIENT_ERROR event.
Definition: Ecore_Con.h:470
_Ecore_Con_Event_Client_Error::error
char * error
the error string describing what happened
Definition: Ecore_Con.h:472
_Ecore_Con_Event_Client_Error::client
Ecore_Con_Client * client
the client for which an error occurred
Definition: Ecore_Con.h:471
_Ecore_Con_Event_Client_Upgrade
Used as the data param for the ECORE_CON_EVENT_CLIENT_UPGRADE event.
Definition: Ecore_Con.h:452
_Ecore_Con_Event_Client_Upgrade::client
Ecore_Con_Client * client
the client that completed handshake
Definition: Ecore_Con.h:453
_Ecore_Con_Event_Client_Write
Used as the data param for the ECORE_CON_EVENT_CLIENT_WRITE event.
Definition: Ecore_Con.h:540
_Ecore_Con_Event_Client_Write::client
Ecore_Con_Client * client
the client that connected
Definition: Ecore_Con.h:541
_Ecore_Con_Event_Client_Write::size
int size
the length of the data sent
Definition: Ecore_Con.h:542
_Ecore_Getopt
Structure that contains information on all command line options.
Definition: Ecore_Getopt.h:212
_Ecore_Getopt_Value
Union listing the types of parameters that can take Getopt values.
Definition: Ecore_Getopt.h:130