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