1 #define EFL_BETA_API_SUPPORT
2 #include <Efl_Net.h>
3 #include <Ecore_Getopt.h>
4 #include <fcntl.h>
5 
6 static Eina_Bool echo = EINA_FALSE;
7 static double timeout = 10.0;
8 
9 /* NOTE: client i/o events are only used as debug, you can omit these */
10 
11 static void
_client_can_read_changed(void * data EINA_UNUSED,const Efl_Event * event)12 _client_can_read_changed(void *data EINA_UNUSED, const Efl_Event *event)
13 {
14    fprintf(stderr, "INFO: client %s can_read=%d\n",
15            efl_net_socket_address_remote_get(event->object),
16            efl_io_reader_can_read_get(event->object));
17 }
18 
19 static void
_client_can_write_changed(void * data EINA_UNUSED,const Efl_Event * event)20 _client_can_write_changed(void *data EINA_UNUSED, const Efl_Event *event)
21 {
22    fprintf(stderr, "INFO: client %s can_write=%d\n",
23            efl_net_socket_address_remote_get(event->object),
24            efl_io_writer_can_write_get(event->object));
25 }
26 
27 static void
_client_eos(void * data EINA_UNUSED,const Efl_Event * event)28 _client_eos(void *data EINA_UNUSED, const Efl_Event *event)
29 {
30    fprintf(stderr, "INFO: client %s eos.\n",
31            efl_net_socket_address_remote_get(event->object));
32 }
33 
34 static void
_client_read_finished(void * data EINA_UNUSED,const Efl_Event * event)35 _client_read_finished(void *data EINA_UNUSED, const Efl_Event *event)
36 {
37    /* on _error() we close it, then do not read as it has nothing */
38    if (efl_io_closer_closed_get(event->object))
39      return;
40 
41    if (echo) return;
42 
43    fprintf(stderr,
44            "-- BEGIN RECEIVED DATA --\n"
45            EINA_SLICE_STR_FMT
46            "-- END RECEIVED DATA--\n",
47            EINA_SLICE_STR_PRINT(efl_io_buffered_stream_slice_get(event->object)));
48 }
49 
50 static void
_client_closed(void * data EINA_UNUSED,const Efl_Event * event)51 _client_closed(void *data EINA_UNUSED, const Efl_Event *event)
52 {
53    fprintf(stderr, "INFO: client %s closed.\n",
54            efl_net_socket_address_remote_get(event->object));
55 }
56 
57 /* this is the only event that matters, from here we remove our extra
58  * reference from the client and let it be deleted.
59  */
60 static void
_client_finished(void * data EINA_UNUSED,const Efl_Event * event)61 _client_finished(void *data EINA_UNUSED, const Efl_Event *event)
62 {
63    fprintf(stderr, "INFO: client %s finished sending and receiving, remove extra reference.\n",
64            efl_net_socket_address_remote_get(event->object));
65    if (!efl_io_closer_closed_get(event->object))
66      efl_io_closer_close(event->object);
67    efl_unref(event->object);
68 }
69 
70 /*
71  * On errors, such as ETIMEDOUT, we want to close the client if not
72  * happened yet.
73  */
74 static void
_client_error(void * data EINA_UNUSED,const Efl_Event * event)75 _client_error(void *data EINA_UNUSED, const Efl_Event *event)
76 {
77    Eina_Error *perr = event->info;
78    fprintf(stderr, "ERROR: client %s error: %s\n",
79            efl_net_socket_address_remote_get(event->object),
80            eina_error_msg_get(*perr));
81    if (!efl_io_closer_closed_get(event->object))
82      efl_io_closer_close(event->object);
83 }
84 
85 EFL_CALLBACKS_ARRAY_DEFINE(client_cbs,
86                            { EFL_IO_READER_EVENT_CAN_READ_CHANGED, _client_can_read_changed },
87                            { EFL_IO_READER_EVENT_EOS, _client_eos },
88                            { EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, _client_can_write_changed },
89                            { EFL_IO_CLOSER_EVENT_CLOSED, _client_closed },
90                            { EFL_IO_BUFFERED_STREAM_EVENT_READ_FINISHED, _client_read_finished },
91                            { EFL_IO_BUFFERED_STREAM_EVENT_FINISHED, _client_finished },
92                            { EFL_IO_BUFFERED_STREAM_EVENT_ERROR, _client_error });
93 
94 
95 /* copier events are of interest, you should hook to at least "done"
96  * and "error"
97  */
98 
99 /* echo copier is about the same socket, you can close it right away */
100 
101 static void
_echo_copier_done(void * data EINA_UNUSED,const Efl_Event * event)102 _echo_copier_done(void *data EINA_UNUSED, const Efl_Event *event)
103 {
104    Eo *copier = event->object;
105    fprintf(stderr, "INFO: echo copier done, close and del %p\n", copier);
106    efl_del(copier); /* set to close_on_destructor, will auto close copier and client */
107 }
108 
109 static void
_echo_copier_error(void * data EINA_UNUSED,const Efl_Event * event)110 _echo_copier_error(void *data EINA_UNUSED, const Efl_Event *event)
111 {
112    Eo *copier = event->object;
113    const Eina_Error *perr = event->info;
114 
115    if (*perr == ETIMEDOUT)
116      {
117         Eo *client = efl_io_copier_source_get(copier);
118         fprintf(stderr, "INFO: client '%s' timed out, delete it.\n",
119                 efl_net_socket_address_remote_get(client));
120         efl_del(copier);
121         return;
122      }
123 
124    efl_loop_quit(efl_loop_get(event->object), eina_value_int_init(EXIT_FAILURE));
125 
126    fprintf(stderr, "ERROR: echo copier %p failed %d '%s', close and del.\n",
127            copier, *perr, eina_error_msg_get(*perr));
128 
129    efl_del(copier);
130 }
131 
132 EFL_CALLBACKS_ARRAY_DEFINE(echo_copier_cbs,
133                            { EFL_IO_COPIER_EVENT_DONE, _echo_copier_done },
134                            { EFL_IO_COPIER_EVENT_ERROR, _echo_copier_error});
135 
136 /* server events are mandatory, afterall you need to define what's
137  * going to happen after a client socket is connected. This is the
138  * "client,add" event.
139  *
140  * if clients_limit and clients_reject_excess are set, then
141  * "client,rejected" is dispatched for rejected sockets, they contain
142  * the string with socket identification.
143  */
144 static void
_server_client_add(void * data EINA_UNUSED,const Efl_Event * event)145 _server_client_add(void *data EINA_UNUSED, const Efl_Event *event)
146 {
147    Efl_Net_Socket *client = event->info;
148 
149    fprintf(stderr, "INFO: accepted client %s\n",
150            efl_net_socket_address_remote_get(client));
151 
152    /* to use a client, you must efl_ref() it. */
153    efl_ref(client);
154 
155    /*
156     * monitor the client if it's done and for debug purposes
157     * (optional)
158     */
159    efl_event_callback_array_add(client, client_cbs(), NULL);
160 
161    efl_io_buffered_stream_timeout_inactivity_set(client, timeout);
162 
163    /*
164     * Since sockets are reader/writer/closer objects, we can use the
165     * Efl_Io_Copier utility.
166     */
167 
168    if (echo)
169      {
170         /*
171          * An echo copier is pretty simple, use the socket as both
172          * source and destination.
173          *
174          * This is the same as efl_net_server_example.c
175          */
176         Eo *echo_copier = efl_add(EFL_IO_COPIER_CLASS, efl_parent_get(client),
177                                   efl_io_copier_source_set(efl_added, client),
178                                   efl_io_copier_destination_set(efl_added, client),
179                                   efl_event_callback_array_add(efl_added, echo_copier_cbs(), client),
180                                   efl_io_closer_close_on_invalidate_set(efl_added, EINA_TRUE) /* we want to auto-close as we have a single copier */
181                                   );
182 
183         fprintf(stderr, "INFO: using an echo copier=%p for client %s\n",
184                 echo_copier, efl_net_socket_address_remote_get(client));
185         return;
186      }
187    else
188      {
189         /*
190          * Here is where the "simple" kicks in, instead of all the
191          * complexity listed in efl_net_server_example.c, we just
192          * "write & forget" the "Hello World!" and wait for all data
193          * to be received with a simple "finished" event.
194          */
195         Eina_Slice slice = EINA_SLICE_STR_LITERAL("Hello World!");
196 
197         efl_io_writer_write(client, &slice, NULL);
198         efl_io_buffered_stream_eos_mark(client); /* say that's it */
199      }
200 }
201 
202 static void
_server_client_rejected(void * data EINA_UNUSED,const Efl_Event * event)203 _server_client_rejected(void *data EINA_UNUSED, const Efl_Event *event)
204 {
205    const char *client_address = event->info;
206    fprintf(stderr, "INFO: rejected client %s\n", client_address);
207 }
208 
209 static void
_server_error(void * data EINA_UNUSED,const Efl_Event * event)210 _server_error(void *data EINA_UNUSED, const Efl_Event *event)
211 {
212    const Eina_Error *perr = event->info;
213    fprintf(stderr, "ERROR: %d '%s'\n", *perr, eina_error_msg_get(*perr));
214    efl_loop_quit(efl_loop_get(event->object), eina_value_int_init(EXIT_FAILURE));
215 }
216 
217 static void
_server_serving(void * data EINA_UNUSED,const Efl_Event * event)218 _server_serving(void *data EINA_UNUSED, const Efl_Event *event)
219 {
220    fprintf(stderr, "INFO: serving at %s\n",
221            efl_net_server_address_get(event->object));
222 
223    if (efl_class_get(event->object) == EFL_NET_SERVER_TCP_CLASS)
224      {
225         fprintf(stderr,
226                 "TCP options:\n"
227                 " - IPv6 only: %u\n",
228                 efl_net_server_ip_ipv6_only_get(event->object));
229      }
230    else if (efl_class_get(event->object) == EFL_NET_SERVER_UDP_CLASS)
231      {
232         Eina_Iterator *it;
233         const char *str;
234 
235         fprintf(stderr,
236                 "UDP options:\n"
237                 " - IPv6 only: %u\n"
238                 " - don't route: %u\n"
239                 " - multicast TTL: %u\n"
240                 " - multicast loopback: %u\n"
241                 " - multicast groups:\n",
242                 efl_net_server_ip_ipv6_only_get(event->object),
243                 efl_net_server_udp_dont_route_get(event->object),
244                 efl_net_server_udp_multicast_time_to_live_get(event->object),
245                 efl_net_server_udp_multicast_loopback_get(event->object));
246 
247         it = efl_net_server_udp_multicast_groups_get(event->object);
248         EINA_ITERATOR_FOREACH(it, str)
249           fprintf(stderr, "   * %s\n", str);
250         eina_iterator_free(it);
251      }
252 }
253 
254 EFL_CALLBACKS_ARRAY_DEFINE(server_cbs,
255                            { EFL_NET_SERVER_EVENT_CLIENT_ADD, _server_client_add },
256                            { EFL_NET_SERVER_EVENT_CLIENT_REJECTED, _server_client_rejected },
257                            { EFL_NET_SERVER_EVENT_SERVER_ERROR, _server_error },
258                            { EFL_NET_SERVER_EVENT_SERVING, _server_serving });
259 
260 static const char * protocols[] = {
261   "tcp",
262   "udp",
263   "ssl",
264 #ifdef EFL_NET_SERVER_WINDOWS_CLASS
265   "windows",
266 #endif
267 #ifdef EFL_NET_SERVER_UNIX_CLASS
268   "unix",
269 #endif
270   NULL
271 };
272 
273 static const char *ciphers_strs[] = {
274   "auto",
275   "tlsv1",
276   "tlsv1.1",
277   "tlsv1.2",
278   NULL
279 };
280 
281 static const Ecore_Getopt options = {
282   "efl_net_server_example", /* program name */
283   NULL, /* usage line */
284   "1", /* version */
285   "(C) 2016 Enlightenment Project", /* copyright */
286   "BSD 2-Clause", /* license */
287   /* long description, may be multiline and contain \n */
288   "Example of Efl_Net_Server objects usage.\n"
289   "\n"
290   "This example spawns a server of the given protocol at the given address.",
291   EINA_FALSE,
292   {
293     ECORE_GETOPT_STORE_TRUE('e', "echo",
294                             "Behave as 'echo' server, send back to client all the data receive"),
295     ECORE_GETOPT_STORE_TRUE(0, "socket-activated",
296                             "Try to use $LISTEN_FDS from systemd, if not do a regular serve()"),
297     ECORE_GETOPT_STORE_UINT('l', "clients-limit",
298                             "If set will limit number of clients to accept"),
299     ECORE_GETOPT_STORE_TRUE('r', "clients-reject-excess",
300                             "Immediately reject excess clients (over limit)"),
301     ECORE_GETOPT_STORE_FALSE(0, "ipv4-on-ipv6",
302                             "IPv4 clients will be automatically converted into IPv6 and handled transparently."),
303     ECORE_GETOPT_STORE_DOUBLE('t', "inactivity-timeout",
304                               "The timeout in seconds to disconnect a client. The timeout is restarted for each client when there is some activity. It's particularly useful for UDP where there is no disconnection event."),
305 
306     ECORE_GETOPT_VERSION('V', "version"),
307     ECORE_GETOPT_COPYRIGHT('C', "copyright"),
308     ECORE_GETOPT_LICENSE('L', "license"),
309     ECORE_GETOPT_HELP('h', "help"),
310 
311     ECORE_GETOPT_CATEGORY("udp", "UDP options"),
312     ECORE_GETOPT_STORE_TRUE(0, "udp-dont-route",
313                             "If true, datagrams won't be routed using a gateway, being restricted to the local network."),
314     ECORE_GETOPT_STORE_UINT(0, "udp-multicast-ttl",
315                             "Multicast time to live in number of hops from 0-255. Defaults to 1 (only local network)."),
316     ECORE_GETOPT_STORE_FALSE(0, "udp-multicast-noloopback",
317                             "Disable multicast loopback."),
318     ECORE_GETOPT_APPEND('M', "udp-multicast-group", "Join a multicast group in the form 'IP@INTERFACE', with optional '@INTERFACE', where INTERFACE is the IP address of the interface to join the multicast.", ECORE_GETOPT_TYPE_STR),
319 
320     ECORE_GETOPT_CATEGORY("ssl", "SSL options"),
321     ECORE_GETOPT_CHOICE('c', "ssl-cipher", "Cipher to use, defaults to 'auto'", ciphers_strs),
322     ECORE_GETOPT_APPEND(0, "ssl-certificate", "certificate path to use.", ECORE_GETOPT_TYPE_STR),
323     ECORE_GETOPT_APPEND(0, "ssl-private-key", "private key path to use.", ECORE_GETOPT_TYPE_STR),
324     ECORE_GETOPT_APPEND(0, "ssl-crl", "certificate revocation list to use.", ECORE_GETOPT_TYPE_STR),
325     ECORE_GETOPT_APPEND(0, "ssl-ca", "certificate authorities path to use.", ECORE_GETOPT_TYPE_STR),
326 
327     ECORE_GETOPT_CHOICE_METAVAR(0, NULL, "The server protocol.", "protocol",
328                                 protocols),
329     ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
330                                    "The server address to listen, such as "
331                                    "IPv4:PORT, [IPv6]:PORT, Unix socket path...",
332                                    "address"),
333 
334     ECORE_GETOPT_SENTINEL
335   }
336 };
337 
338 static Eo *simple_server = NULL;
339 
340 EAPI_MAIN void
efl_pause(void * data EINA_UNUSED,const Efl_Event * ev EINA_UNUSED)341 efl_pause(void *data EINA_UNUSED,
342           const Efl_Event *ev EINA_UNUSED)
343 {
344 }
345 
346 EAPI_MAIN void
efl_resume(void * data EINA_UNUSED,const Efl_Event * ev EINA_UNUSED)347 efl_resume(void *data EINA_UNUSED,
348            const Efl_Event *ev EINA_UNUSED)
349 {
350 }
351 
352 EAPI_MAIN void
efl_terminate(void * data EINA_UNUSED,const Efl_Event * ev EINA_UNUSED)353 efl_terminate(void *data EINA_UNUSED,
354               const Efl_Event *ev EINA_UNUSED)
355 {
356    /* FIXME: For the moment the main loop doesn't get
357       properly destroyed on shutdown which disallow
358       relying on parent destroying their children */
359    if (simple_server)
360      {
361         efl_del(simple_server);
362         simple_server = NULL;
363      }
364 
365    fprintf(stderr, "INFO: main loop finished.\n");
366 }
367 
368 EAPI_MAIN void
efl_main(void * data EINA_UNUSED,const Efl_Event * ev)369 efl_main(void *data EINA_UNUSED,
370          const Efl_Event *ev)
371 {
372    const Efl_Class *cls;
373    char *protocol = NULL;
374    char *address = NULL;
375    Eina_List *udp_mcast_groups = NULL;
376    char *str;
377    unsigned int clients_limit = 0;
378    unsigned udp_mcast_ttl = 1;
379    Eina_Bool clients_reject_excess = EINA_FALSE;
380    Eina_Bool ipv6_only = EINA_TRUE;
381    Eina_Bool udp_dont_route = EINA_FALSE;
382    Eina_Bool udp_mcast_loopback = EINA_TRUE;
383    Eina_List *certificates = NULL;
384    Eina_List *private_keys = NULL;
385    Eina_List *crls = NULL;
386    Eina_List *cas = NULL;
387    char *cipher_choice = NULL;
388    Eina_Bool socket_activated = EINA_FALSE;
389    Eina_Bool quit_option = EINA_FALSE;
390    Ecore_Getopt_Value values[] = {
391      ECORE_GETOPT_VALUE_BOOL(echo),
392      ECORE_GETOPT_VALUE_BOOL(socket_activated),
393      ECORE_GETOPT_VALUE_UINT(clients_limit),
394      ECORE_GETOPT_VALUE_BOOL(clients_reject_excess),
395      ECORE_GETOPT_VALUE_BOOL(ipv6_only),
396      ECORE_GETOPT_VALUE_DOUBLE(timeout),
397 
398      /* standard block to provide version, copyright, license and help */
399      ECORE_GETOPT_VALUE_BOOL(quit_option), /* -V/--version quits */
400      ECORE_GETOPT_VALUE_BOOL(quit_option), /* -C/--copyright quits */
401      ECORE_GETOPT_VALUE_BOOL(quit_option), /* -L/--license quits */
402      ECORE_GETOPT_VALUE_BOOL(quit_option), /* -h/--help quits */
403 
404      ECORE_GETOPT_VALUE_BOOL(quit_option), /* category: udp */
405      ECORE_GETOPT_VALUE_BOOL(udp_dont_route),
406      ECORE_GETOPT_VALUE_UINT(udp_mcast_ttl),
407      ECORE_GETOPT_VALUE_BOOL(udp_mcast_loopback),
408      ECORE_GETOPT_VALUE_LIST(udp_mcast_groups),
409 
410      ECORE_GETOPT_VALUE_BOOL(quit_option), /* category: ssl */
411      ECORE_GETOPT_VALUE_STR(cipher_choice),
412      ECORE_GETOPT_VALUE_LIST(certificates),
413      ECORE_GETOPT_VALUE_LIST(private_keys),
414      ECORE_GETOPT_VALUE_LIST(crls),
415      ECORE_GETOPT_VALUE_LIST(cas),
416 
417      /* positional argument */
418      ECORE_GETOPT_VALUE_STR(protocol),
419      ECORE_GETOPT_VALUE_STR(address),
420 
421      ECORE_GETOPT_VALUE_NONE /* sentinel */
422    };
423    int args;
424    Eo *server;
425    Eina_Error err;
426 
427    args = ecore_getopt_parse(&options, values, 0, NULL);
428    if (args < 0)
429      {
430         fputs("ERROR: Could not parse command line options.\n", stderr);
431         goto end;
432      }
433 
434    if (quit_option) goto end;
435 
436    args = ecore_getopt_parse_positional(&options, values, 0, NULL, args);
437    if (args < 0)
438      {
439         fputs("ERROR: Could not parse positional arguments.\n", stderr);
440         goto end;
441      }
442 
443    if (!protocol)
444      {
445         fputs("ERROR: missing protocol.\n", stderr);
446         goto end;
447      }
448 
449    if (strcmp(protocol, "tcp") == 0) cls = EFL_NET_SERVER_TCP_CLASS;
450    else if (strcmp(protocol, "udp") == 0) cls = EFL_NET_SERVER_UDP_CLASS;
451    else if (strcmp(protocol, "ssl") == 0) cls = EFL_NET_SERVER_SSL_CLASS;
452 #ifdef EFL_NET_SERVER_WINDOWS_CLASS
453    else if (strcmp(protocol, "windows") == 0) cls = EFL_NET_SERVER_WINDOWS_CLASS;
454 #endif
455 #ifdef EFL_NET_SERVER_UNIX_CLASS
456    else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_SERVER_UNIX_CLASS;
457 #endif
458    else
459      {
460         fprintf(stderr, "ERROR: unsupported protocol: %s\n", protocol);
461         goto end;
462      }
463 
464    simple_server = efl_add(EFL_NET_SERVER_SIMPLE_CLASS, ev->object, /* it's mandatory to use a main loop provider as the server parent */
465                            efl_net_server_simple_inner_class_set(efl_added, cls), /* alternatively you could create the inner server and set with efl_net_server_simple_inner_server_set() */
466                            efl_net_server_clients_limit_set(efl_added,
467                                                             clients_limit,
468                                                             clients_reject_excess), /* optional */
469                            efl_event_callback_array_add(efl_added, server_cbs(), NULL)); /* mandatory to have "client,add" in order to be useful */
470    if (!simple_server)
471      {
472         fprintf(stderr, "ERROR: could not create simple server for class %p (%s)\n",
473                 cls, efl_class_name_get(cls));
474         goto end;
475      }
476 
477    /* get the inner server so we can configure it for each protocol */
478    server = efl_net_server_simple_inner_server_get(simple_server);
479 
480    if (cls == EFL_NET_SERVER_TCP_CLASS)
481      {
482         efl_net_server_ip_ipv6_only_set(server, ipv6_only);
483         efl_net_server_fd_reuse_address_set(server, EINA_TRUE); /* optional, but nice for testing */
484         efl_net_server_fd_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
485 
486         if (socket_activated) efl_net_server_fd_socket_activate(server, address);
487      }
488    else if (cls == EFL_NET_SERVER_UDP_CLASS)
489      {
490         const Eina_List *lst;
491 
492         efl_net_server_ip_ipv6_only_set(server, ipv6_only);
493         efl_net_server_udp_dont_route_set(server, udp_dont_route);
494 
495         efl_net_server_udp_multicast_time_to_live_set(server, udp_mcast_ttl);
496         efl_net_server_udp_multicast_loopback_set(server, udp_mcast_loopback);
497 
498         EINA_LIST_FOREACH(udp_mcast_groups, lst, str)
499           efl_net_server_udp_multicast_join(server, str);
500 
501         efl_net_server_fd_reuse_address_set(server, EINA_TRUE); /* optional, but nice for testing */
502         efl_net_server_fd_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
503         if (socket_activated) efl_net_server_fd_socket_activate(server, address);
504      }
505    else if (cls == EFL_NET_SERVER_SSL_CLASS)
506      {
507         Eo *ssl_ctx;
508         Efl_Net_Ssl_Cipher cipher = EFL_NET_SSL_CIPHER_AUTO;
509         if (cipher_choice)
510           {
511              if (strcmp(cipher_choice, "auto") == 0)
512                cipher = EFL_NET_SSL_CIPHER_AUTO;
513              else if (strcmp(cipher_choice, "tlsv1") == 0)
514                cipher = EFL_NET_SSL_CIPHER_TLSV1;
515              else if (strcmp(cipher_choice, "tlsv1.1") == 0)
516                cipher = EFL_NET_SSL_CIPHER_TLSV1_1;
517              else if (strcmp(cipher_choice, "tlsv1.2") == 0)
518                cipher = EFL_NET_SSL_CIPHER_TLSV1_2;
519           }
520 
521         ssl_ctx = efl_add_ref(EFL_NET_SSL_CONTEXT_CLASS, NULL,
522                           efl_net_ssl_context_certificates_set(efl_added, eina_list_iterator_new(certificates)),
523                           efl_net_ssl_context_private_keys_set(efl_added, eina_list_iterator_new(private_keys)),
524                           efl_net_ssl_context_certificate_revocation_lists_set(efl_added, eina_list_iterator_new(crls)),
525                           efl_net_ssl_context_certificate_authorities_set(efl_added, eina_list_iterator_new(cas)),
526                           efl_net_ssl_context_setup(efl_added, cipher, EINA_FALSE /* a server! */));
527 
528         efl_net_server_ssl_context_set(server, ssl_ctx);
529 
530         efl_net_server_fd_reuse_address_set(server, EINA_TRUE); /* optional, but nice for testing */
531         efl_net_server_fd_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
532         if (socket_activated) efl_net_server_fd_socket_activate(server, address);
533      }
534 #ifdef EFL_NET_SERVER_UNIX_CLASS
535    else if (cls == EFL_NET_SERVER_UNIX_CLASS)
536      {
537         efl_net_server_unix_unlink_before_bind_set(server, EINA_TRUE); /* makes testing easier */
538         if (socket_activated) efl_net_server_fd_socket_activate(server, address);
539      }
540 #endif
541 
542    /* an explicit call to efl_net_server_serve() after the object is
543     * constructed allows for more complex setup, such as interacting
544     * with the object to add more properties that couldn't be done
545     * during efl_add().
546     */
547    if (!efl_net_server_serving_get(simple_server))
548      {
549         if (socket_activated)
550           fprintf(stderr, "WARNING: --socket-activated, but not able to use $LISTEN_FDS descriptors. Try to start the server...\n");
551 
552         err = efl_net_server_serve(simple_server, address);
553         if (err)
554           {
555              fprintf(stderr, "ERROR: could not serve(%s): %s\n",
556                      address, eina_error_msg_get(err));
557              goto end_server;
558           }
559      }
560 
561    return ;
562 
563  end_server:
564    efl_del(simple_server);
565    simple_server = NULL;
566 
567  end:
568    EINA_LIST_FREE(udp_mcast_groups, str)
569      free(str);
570 
571    efl_loop_quit(ev->object, eina_value_int_init(EXIT_FAILURE));
572 }
573 
574 EFL_MAIN_EX();
575