efl

Форк
0
/
efl_net_server_example.c 
766 строк · 27.7 Кб
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
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
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
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
35
_client_closed(void *data EINA_UNUSED, const Efl_Event *event)
36
{
37
   fprintf(stderr, "INFO: client %s closed.\n",
38
           efl_net_socket_address_remote_get(event->object));
39
}
40

41
EFL_CALLBACKS_ARRAY_DEFINE(client_cbs,
42
                           { EFL_IO_READER_EVENT_CAN_READ_CHANGED, _client_can_read_changed },
43
                           { EFL_IO_READER_EVENT_EOS, _client_eos },
44
                           { EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, _client_can_write_changed },
45
                           { EFL_IO_CLOSER_EVENT_CLOSED, _client_closed });
46

47

48
/* copier events are of interest, you should hook to at least "done"
49
 * and "error"
50
 */
51

52
/* echo copier is about the same socket, you can close it right away */
53

54
static void
55
_echo_copier_done(void *data EINA_UNUSED, const Efl_Event *event)
56
{
57
   Eo *copier = event->object;
58
   fprintf(stderr, "INFO: echo copier done, close and del %p\n", copier);
59
   efl_del(copier); /* set to close_on_destructor, will auto close copier and client */
60
}
61

62
static void
63
_echo_copier_error(void *data EINA_UNUSED, const Efl_Event *event)
64
{
65
   Eo *copier = event->object;
66
   const Eina_Error *perr = event->info;
67

68
   if (*perr == ETIMEDOUT)
69
     {
70
        Eo *client = efl_io_copier_source_get(copier);
71
        fprintf(stderr, "INFO: client '%s' timed out, delete it.\n",
72
                efl_net_socket_address_remote_get(client));
73
        efl_del(copier);
74
        return;
75
     }
76

77
   efl_loop_quit(efl_loop_get(event->object), eina_value_int_init(EXIT_FAILURE));
78

79
   fprintf(stderr, "ERROR: echo copier %p failed %d '%s', close and del.\n",
80
           copier, *perr, eina_error_msg_get(*perr));
81

82
   efl_del(copier);
83
}
84

85
EFL_CALLBACKS_ARRAY_DEFINE(echo_copier_cbs,
86
                           { EFL_IO_COPIER_EVENT_DONE, _echo_copier_done },
87
                           { EFL_IO_COPIER_EVENT_ERROR, _echo_copier_error});
88

89
/* When sender and receiver peers are about different entities, you
90
 * can only close when both are done, otherwise the socket will be
91
 * prematurely closed.
92
 *
93
 * Here we use a struct with both copiers and NULL them once they are
94
 * done, when both are done we close the socket and free the struct.
95
 */
96
typedef struct {
97
   Eo *send_copier;
98
   Eo *recv_copier;
99
   Eo *client;
100
} Send_Recv_Data;
101

102
static Send_Recv_Data *
103
_send_recv_new(Eo *client)
104
{
105
   Send_Recv_Data *d = calloc(1, sizeof(Send_Recv_Data));
106
   if (!d) return NULL;
107

108
   /* take a reference since copiers will only hold their reference
109
    * while they are alive. As we're deleting them before calling
110
    * efl_io_closer_close(), then we need it for bit longer.
111
    */
112
   d->client = efl_ref(client);
113
   return d;
114
}
115

116
static void
117
_send_recv_free(Send_Recv_Data *d)
118
{
119
   efl_unref(d->client);
120
   free(d);
121
}
122

123
static void
124
_send_recv_done(Send_Recv_Data *d, Eo *copier)
125
{
126
   if (d->send_copier == copier) d->send_copier = NULL;
127
   else d->recv_copier = NULL;
128

129
   efl_del(copier);
130
   if (d->send_copier || d->recv_copier) return;
131
   efl_io_closer_close(d->client); /* manually close once both copiers are done */
132
   _send_recv_free(d);
133
}
134

135
static void
136
_send_copier_done(void *data, const Efl_Event *event)
137
{
138
   Eo *copier = event->object;
139
   Eo *buffer = efl_io_copier_source_get(copier);
140
   Eo *client = efl_io_copier_destination_get(copier);
141
   Send_Recv_Data *d = data;
142
   Eina_Slice slice = efl_io_buffer_slice_get(buffer);
143

144
   /* show what we sent, just for debug */
145
   fprintf(stderr,
146
           "INFO: sent to %s %zd bytes:"
147
           "\n--BEGIN SENT DATA--\n"
148
           EINA_SLICE_STR_FMT
149
           "\n--END SENT DATA--\n",
150
           efl_net_socket_address_remote_get(client),
151
           slice.len, EINA_SLICE_STR_PRINT(slice));
152

153
   if (d->recv_copier)
154
     {
155
        /* only start the reader inactivity timeout once the sender is done */
156
        efl_io_copier_timeout_inactivity_set(d->recv_copier, efl_io_copier_timeout_inactivity_get(copier));
157
     }
158

159
   fprintf(stderr, "INFO: send copier done, check if should close %p\n", copier);
160
   _send_recv_done(d, copier);
161
}
162

163
static void
164
_send_copier_error(void *data, const Efl_Event *event)
165
{
166
   Eo *copier = event->object;
167
   Eo *buffer = efl_io_copier_source_get(copier);
168
   Eo *client = efl_io_copier_destination_get(copier);
169
   const Eina_Error *perr = event->info;
170
   Send_Recv_Data *d = data;
171
   uint64_t offset;
172
   Eina_Slice slice, remaining;
173

174
   if (*perr == ETIMEDOUT)
175
     {
176
        fprintf(stderr, "INFO: client '%s' timed out send, delete it.\n",
177
                efl_net_socket_address_remote_get(client));
178
        efl_io_closer_close(copier); /* forces client to be closed, thus closes the recv copier as an effect */
179
        return;
180
     }
181

182
   efl_loop_quit(efl_loop_get(event->object), eina_value_int_init(EXIT_FAILURE));
183

184
   offset = efl_io_buffer_position_read_get(buffer);
185
   slice = efl_io_buffer_slice_get(buffer);
186

187
   remaining = slice;
188
   remaining.bytes += offset;
189
   remaining.len -= offset;
190

191
   slice.len = offset;
192

193
   fprintf(stderr,
194
           "ERROR: sent to %s only %zd bytes:"
195
           "\n--BEGIN SENT DATA--\n"
196
           EINA_SLICE_STR_FMT
197
           "\n--END SENT DATA--\n"
198
           "Remaining %zd bytes:"
199
           "\n--BEGIN REMAINING DATA--\n"
200
           EINA_SLICE_STR_FMT
201
           "\n--END REMAINING DATA--\n",
202
           efl_net_socket_address_remote_get(client),
203
           slice.len, EINA_SLICE_STR_PRINT(slice),
204
           remaining.len, EINA_SLICE_STR_PRINT(remaining));
205

206
   fprintf(stderr, "ERROR: send copier %p failed %d '%s', check if should close..\n",
207
           copier, *perr, eina_error_msg_get(*perr));
208
   _send_recv_done(d, copier);
209
}
210

211
EFL_CALLBACKS_ARRAY_DEFINE(send_copier_cbs,
212
                           { EFL_IO_COPIER_EVENT_DONE, _send_copier_done },
213
                           { EFL_IO_COPIER_EVENT_ERROR, _send_copier_error});
214

215
static void
216
_recv_copier_done(void *data, const Efl_Event *event)
217
{
218
   Eo *copier = event->object;
219
   Eo *client = efl_io_copier_source_get(copier);
220
   Eo *buffer = efl_io_copier_destination_get(copier);
221
   Send_Recv_Data *d = data;
222
   Eina_Slice slice = efl_io_buffer_slice_get(buffer);
223

224
   /* show case, you could use a copier to Efl_Io_Stdout, a
225
    * file... and get progressive processing.
226
    *
227
    * Here we're using a memory buffer and printing everything at
228
    * once.
229
    *
230
    * You could also steal the binbuf with
231
    * efl_io_buffer_binbuf_steal()
232
    */
233
   fprintf(stderr,
234
           "INFO: recv from %s %zd bytes:"
235
           "\n--BEGIN RECV DATA--\n"
236
           EINA_SLICE_STR_FMT "\n"
237
           "\n--END RECV DATA--\n",
238
           efl_net_socket_address_remote_get(client),
239
           slice.len, EINA_SLICE_STR_PRINT(slice));
240

241
   fprintf(stderr, "INFO: receive copier done, check if should close %p\n", copier);
242
   _send_recv_done(d, copier);
243
}
244

245
static void
246
_recv_copier_error(void *data, const Efl_Event *event)
247
{
248
   Eo *copier = event->object;
249
   Eo *buffer = efl_io_copier_destination_get(copier);
250
   Eo *client = efl_io_copier_source_get(copier);
251
   const Eina_Error *perr = event->info;
252
   Send_Recv_Data *d = data;
253
   Eina_Slice slice;
254

255
   if (*perr == ETIMEDOUT)
256
     {
257
        fprintf(stderr, "INFO: client '%s' timed out recv, delete it.\n",
258
                efl_net_socket_address_remote_get(client));
259
        efl_io_closer_close(copier); /* forces client to be closed, thus closes the send copier as an effect */
260
        return;
261
     }
262

263
   efl_loop_quit(efl_loop_get(event->object), eina_value_int_init(EXIT_FAILURE));
264

265
   slice = efl_io_buffer_slice_get(buffer);
266
   fprintf(stderr,
267
           "ERROR: recv to %s only %zd bytes:"
268
           "\n--BEGIN RECV DATA--\n"
269
           EINA_SLICE_STR_FMT "\n"
270
           "\n--END RECV DATA--\n",
271
           efl_net_socket_address_remote_get(client),
272
           slice.len, EINA_SLICE_STR_PRINT(slice));
273

274
   fprintf(stderr, "ERROR: receive copier %p failed %d '%s', check if should close..\n",
275
           copier, *perr, eina_error_msg_get(*perr));
276
   _send_recv_done(d, copier);
277
}
278

279
EFL_CALLBACKS_ARRAY_DEFINE(recv_copier_cbs,
280
                           { EFL_IO_COPIER_EVENT_DONE, _recv_copier_done },
281
                           { EFL_IO_COPIER_EVENT_ERROR, _recv_copier_error});
282

283

284
/* server events are mandatory, afterall you need to define what's
285
 * going to happen after a client socket is connected. This is the
286
 * "client,add" event.
287
 *
288
 * if clients_limit and clients_reject_excess are set, then
289
 * "client,rejected" is dispatched for rejected sockets, they contain
290
 * the string with socket identification.
291
 */
292
static void
293
_server_client_add(void *data EINA_UNUSED, const Efl_Event *event)
294
{
295
   Efl_Net_Socket *client = event->info;
296

297
   fprintf(stderr, "INFO: accepted client %s\n",
298
           efl_net_socket_address_remote_get(client));
299

300
   /* to use a client, you must efl_ref() it. Here we're not doing it
301
    * explicitly because copiers do take a reference.
302
    */
303

304
   /*
305
    * monitor the client socket for debug purposes (optional)
306
    */
307
   efl_event_callback_array_add(client, client_cbs(), NULL);
308

309
   /*
310
    * Since sockets are reader/writer/closer objects, we can use the
311
    * Efl_Io_Copier utility.
312
    */
313

314
   if (echo)
315
     {
316
        /*
317
         * An echo copier is pretty simple, use the socket as both
318
         * source and destination.
319
         */
320
        Eo *echo_copier = efl_add(EFL_IO_COPIER_CLASS, efl_parent_get(client),
321
                                  efl_io_copier_source_set(efl_added, client),
322
                                  efl_io_copier_destination_set(efl_added, client),
323
                                  efl_io_copier_timeout_inactivity_set(efl_added, timeout),
324
                                  efl_event_callback_array_add(efl_added, echo_copier_cbs(), client),
325
                                  efl_io_closer_close_on_invalidate_set(efl_added, EINA_TRUE) /* we want to auto-close as we have a single copier */
326
                                  );
327

328
        fprintf(stderr, "INFO: using an echo copier=%p for client %s\n",
329
                echo_copier, efl_net_socket_address_remote_get(client));
330
        return;
331
     }
332
   else
333
     {
334
        /*
335
         * Here we create a fixed buffer with a string to send:
336
         *   - "Hello World!"
337
         * and another one to store the received buffer so we can print as
338
         * a single blob at the end.
339
         *
340
         * One can change these to Efl_Io_File or event pipe to something
341
         * else like Efl_Io_Stdin, Efl_Io_Stdout and it would just work.
342
         */
343
        static const Eina_Slice hello_world_slice = EINA_SLICE_STR_LITERAL("Hello World!");
344
        Send_Recv_Data *d;
345
        Eo *send_buffer, *recv_buffer;
346

347
        d = _send_recv_new(client);
348
        if (!d)
349
          {
350
             fprintf(stderr, "ERROR: could not allocate memory\n");
351
             return;
352
          }
353

354
        send_buffer = efl_add_ref(EFL_IO_BUFFER_CLASS, NULL,
355
                              efl_io_buffer_adopt_readonly(efl_added, hello_world_slice));
356

357
        /* Unlimited buffer to store the received data. */
358
        recv_buffer = efl_add_ref(EFL_IO_BUFFER_CLASS, NULL);
359

360
        /* an input copier that takes data from send_buffer and pushes to client */
361
        d->send_copier = efl_add(EFL_IO_COPIER_CLASS, efl_parent_get(client),
362
                                 efl_io_copier_source_set(efl_added, send_buffer),
363
                                 efl_io_copier_destination_set(efl_added, client),
364
                                 efl_io_copier_timeout_inactivity_set(efl_added, timeout),
365
                                 efl_event_callback_array_add(efl_added, send_copier_cbs(), d),
366
                                 efl_io_closer_close_on_invalidate_set(efl_added, EINA_FALSE) /* we must wait both copiers to finish before we close! */
367
                                 );
368

369
        fprintf(stderr, "INFO: using sender buffer %p with copier %p for client %s\n",
370
                send_buffer, d->send_copier, efl_net_socket_address_remote_get(client));
371

372
        efl_unref(send_buffer); /* d->send_copier adds a reference */
373
        if (!d->send_copier)
374
          fprintf(stderr, "ERROR: failed to create sender copier\n");
375

376

377
        /* an output copier that takes data from socket and pushes to recv_buffer. */
378
        d->recv_copier = efl_add(EFL_IO_COPIER_CLASS, efl_parent_get(client),
379
                                 efl_io_copier_source_set(efl_added, client),
380
                                 efl_io_copier_destination_set(efl_added, recv_buffer),
381
                                 efl_io_copier_timeout_inactivity_set(efl_added, 0.0), /* we'll only set an inactivity timeout once the sender is done */
382
                                 efl_event_callback_array_add(efl_added, recv_copier_cbs(), d),
383
                                 efl_io_closer_close_on_invalidate_set(efl_added, EINA_FALSE) /* we must wait both copiers to finish before we close! */
384
                                 );
385

386
        fprintf(stderr, "INFO: using receiver buffer %p with copier %p for client %s\n",
387
                recv_buffer, d->recv_copier, efl_net_socket_address_remote_get(client));
388

389
        efl_unref(recv_buffer); /* d->recv_copier adds a reference */
390
        if (!d->recv_copier)
391
          fprintf(stderr, "ERROR: failed to create receiver copier\n");
392

393
        if (!d->recv_copier && !d->send_copier)
394
          _send_recv_free(d);
395
     }
396
}
397

398
static void
399
_server_client_rejected(void *data EINA_UNUSED, const Efl_Event *event)
400
{
401
   const char *client_address = event->info;
402
   fprintf(stderr, "INFO: rejected client %s\n", client_address);
403
}
404

405
static void
406
_server_error(void *data EINA_UNUSED, const Efl_Event *event)
407
{
408
   const Eina_Error *perr = event->info;
409
   fprintf(stderr, "ERROR: %d '%s'\n", *perr, eina_error_msg_get(*perr));
410
   efl_loop_quit(efl_loop_get(event->object), eina_value_int_init(EXIT_FAILURE));
411
}
412

413
static void
414
_server_serving(void *data EINA_UNUSED, const Efl_Event *event)
415
{
416
   fprintf(stderr, "INFO: serving at %s\n",
417
           efl_net_server_address_get(event->object));
418

419
   if (efl_class_get(event->object) == EFL_NET_SERVER_TCP_CLASS)
420
     {
421
        fprintf(stderr,
422
                "TCP options:\n"
423
                " - IPv6 only: %u\n",
424
                efl_net_server_ip_ipv6_only_get(event->object));
425
     }
426
   else if (efl_class_get(event->object) == EFL_NET_SERVER_UDP_CLASS)
427
     {
428
        Eina_Iterator *it;
429
        const char *str;
430

431
        fprintf(stderr,
432
                "UDP options:\n"
433
                " - IPv6 only: %u\n"
434
                " - don't route: %u\n"
435
                " - multicast TTL: %u\n"
436
                " - multicast loopback: %u\n"
437
                " - multicast groups:\n",
438
                efl_net_server_ip_ipv6_only_get(event->object),
439
                efl_net_server_udp_dont_route_get(event->object),
440
                efl_net_server_udp_multicast_time_to_live_get(event->object),
441
                efl_net_server_udp_multicast_loopback_get(event->object));
442

443
        it = efl_net_server_udp_multicast_groups_get(event->object);
444
        EINA_ITERATOR_FOREACH(it, str)
445
          fprintf(stderr, "   * %s\n", str);
446
        eina_iterator_free(it);
447
     }
448
}
449

450
EFL_CALLBACKS_ARRAY_DEFINE(server_cbs,
451
                           { EFL_NET_SERVER_EVENT_CLIENT_ADD, _server_client_add },
452
                           { EFL_NET_SERVER_EVENT_CLIENT_REJECTED, _server_client_rejected },
453
                           { EFL_NET_SERVER_EVENT_SERVER_ERROR, _server_error },
454
                           { EFL_NET_SERVER_EVENT_SERVING, _server_serving });
455

456
static const char * protocols[] = {
457
  "tcp",
458
  "udp",
459
  "ssl",
460
#ifdef EFL_NET_SERVER_WINDOWS_CLASS
461
  "windows",
462
#endif
463
#ifdef EFL_NET_SERVER_UNIX_CLASS
464
  "unix",
465
#endif
466
  NULL
467
};
468

469
static const char *ciphers_strs[] = {
470
  "auto",
471
  "tlsv1",
472
  "tlsv1.1",
473
  "tlsv1.2",
474
  NULL
475
};
476

477
static const Ecore_Getopt options = {
478
  "efl_net_server_example", /* program name */
479
  NULL, /* usage line */
480
  "1", /* version */
481
  "(C) 2016 Enlightenment Project", /* copyright */
482
  "BSD 2-Clause", /* license */
483
  /* long description, may be multiline and contain \n */
484
  "Example of Efl_Net_Server objects usage.\n"
485
  "\n"
486
  "This example spawns a server of the given protocol at the given address.",
487
  EINA_FALSE,
488
  {
489
    ECORE_GETOPT_STORE_TRUE('e', "echo",
490
                            "Behave as 'echo' server, send back to client all the data receive"),
491
    ECORE_GETOPT_STORE_TRUE(0, "socket-activated",
492
                            "Try to use $LISTEN_FDS from systemd, if not do a regular serve()"),
493
    ECORE_GETOPT_STORE_UINT('l', "clients-limit",
494
                            "If set will limit number of clients to accept"),
495
    ECORE_GETOPT_STORE_TRUE('r', "clients-reject-excess",
496
                            "Immediately reject excess clients (over limit)"),
497
    ECORE_GETOPT_STORE_FALSE(0, "ipv4-on-ipv6",
498
                            "IPv4 clients will be automatically converted into IPv6 and handled transparently."),
499
    ECORE_GETOPT_STORE_DOUBLE('t', "inactivity-timeout",
500
                              "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."),
501

502
    ECORE_GETOPT_VERSION('V', "version"),
503
    ECORE_GETOPT_COPYRIGHT('C', "copyright"),
504
    ECORE_GETOPT_LICENSE('L', "license"),
505
    ECORE_GETOPT_HELP('h', "help"),
506

507
    ECORE_GETOPT_CATEGORY("udp", "UDP options"),
508
    ECORE_GETOPT_STORE_TRUE(0, "udp-dont-route",
509
                            "If true, datagrams won't be routed using a gateway, being restricted to the local network."),
510
    ECORE_GETOPT_STORE_UINT(0, "udp-multicast-ttl",
511
                            "Multicast time to live in number of hops from 0-255. Defaults to 1 (only local network)."),
512
    ECORE_GETOPT_STORE_FALSE(0, "udp-multicast-noloopback",
513
                            "Disable multicast loopback."),
514
    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),
515

516
    ECORE_GETOPT_CATEGORY("ssl", "SSL options"),
517
    ECORE_GETOPT_CHOICE('c', "ssl-cipher", "Cipher to use, defaults to 'auto'", ciphers_strs),
518
    ECORE_GETOPT_APPEND(0, "ssl-certificate", "certificate path to use.", ECORE_GETOPT_TYPE_STR),
519
    ECORE_GETOPT_APPEND(0, "ssl-private-key", "private key path to use.", ECORE_GETOPT_TYPE_STR),
520
    ECORE_GETOPT_APPEND(0, "ssl-crl", "certificate revocation list to use.", ECORE_GETOPT_TYPE_STR),
521
    ECORE_GETOPT_APPEND(0, "ssl-ca", "certificate authorities path to use.", ECORE_GETOPT_TYPE_STR),
522

523
    ECORE_GETOPT_CHOICE_METAVAR(0, NULL, "The server protocol.", "protocol",
524
                                protocols),
525
    ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
526
                                   "The server address to listen, such as "
527
                                   "IPv4:PORT, [IPv6]:PORT, Unix socket path...",
528
                                   "address"),
529

530
    ECORE_GETOPT_SENTINEL
531
  }
532
};
533

534
static Eo *server = NULL;
535

536
EAPI_MAIN void
537
efl_pause(void *data EINA_UNUSED,
538
          const Efl_Event *ev EINA_UNUSED)
539
{
540
}
541

542
EAPI_MAIN void
543
efl_resume(void *data EINA_UNUSED,
544
           const Efl_Event *ev EINA_UNUSED)
545
{
546
}
547

548
EAPI_MAIN void
549
efl_terminate(void *data EINA_UNUSED,
550
              const Efl_Event *ev EINA_UNUSED)
551
{
552
   /* FIXME: For the moment the main loop doesn't get
553
      properly destroyed on shutdown which disallow
554
      relying on parent destroying their children */
555
   if (server)
556
     {
557
        efl_del(server);
558
        server = NULL;
559
     }
560

561
   fprintf(stderr, "INFO: main loop finished.\n");
562
}
563

564
EAPI_MAIN void
565
efl_main(void *data EINA_UNUSED,
566
         const Efl_Event *ev)
567
{
568
   const Efl_Class *cls;
569
   char *protocol = NULL;
570
   char *address = NULL;
571
   Eina_List *udp_mcast_groups = NULL;
572
   char *str;
573
   unsigned int clients_limit = 0;
574
   unsigned udp_mcast_ttl = 1;
575
   Eina_Bool clients_reject_excess = EINA_FALSE;
576
   Eina_Bool ipv6_only = EINA_TRUE;
577
   Eina_Bool udp_dont_route = EINA_FALSE;
578
   Eina_Bool udp_mcast_loopback = EINA_TRUE;
579
   Eina_List *certificates = NULL;
580
   Eina_List *private_keys = NULL;
581
   Eina_List *crls = NULL;
582
   Eina_List *cas = NULL;
583
   char *cipher_choice = NULL;
584
   Eina_Bool socket_activated = EINA_FALSE;
585
   Eina_Bool quit_option = EINA_FALSE;
586
   Ecore_Getopt_Value values[] = {
587
     ECORE_GETOPT_VALUE_BOOL(echo),
588
     ECORE_GETOPT_VALUE_BOOL(socket_activated),
589
     ECORE_GETOPT_VALUE_UINT(clients_limit),
590
     ECORE_GETOPT_VALUE_BOOL(clients_reject_excess),
591
     ECORE_GETOPT_VALUE_BOOL(ipv6_only),
592
     ECORE_GETOPT_VALUE_DOUBLE(timeout),
593

594
     /* standard block to provide version, copyright, license and help */
595
     ECORE_GETOPT_VALUE_BOOL(quit_option), /* -V/--version quits */
596
     ECORE_GETOPT_VALUE_BOOL(quit_option), /* -C/--copyright quits */
597
     ECORE_GETOPT_VALUE_BOOL(quit_option), /* -L/--license quits */
598
     ECORE_GETOPT_VALUE_BOOL(quit_option), /* -h/--help quits */
599

600
     ECORE_GETOPT_VALUE_BOOL(quit_option), /* category: udp */
601
     ECORE_GETOPT_VALUE_BOOL(udp_dont_route),
602
     ECORE_GETOPT_VALUE_UINT(udp_mcast_ttl),
603
     ECORE_GETOPT_VALUE_BOOL(udp_mcast_loopback),
604
     ECORE_GETOPT_VALUE_LIST(udp_mcast_groups),
605

606
     ECORE_GETOPT_VALUE_BOOL(quit_option), /* category: ssl */
607
     ECORE_GETOPT_VALUE_STR(cipher_choice),
608
     ECORE_GETOPT_VALUE_LIST(certificates),
609
     ECORE_GETOPT_VALUE_LIST(private_keys),
610
     ECORE_GETOPT_VALUE_LIST(crls),
611
     ECORE_GETOPT_VALUE_LIST(cas),
612

613
     /* positional argument */
614
     ECORE_GETOPT_VALUE_STR(protocol),
615
     ECORE_GETOPT_VALUE_STR(address),
616

617
     ECORE_GETOPT_VALUE_NONE /* sentinel */
618
   };
619
   int args;
620
   Eina_Error err;
621

622
   args = ecore_getopt_parse(&options, values, 0, NULL);
623
   if (args < 0)
624
     {
625
        fputs("ERROR: Could not parse command line options.\n", stderr);
626
        goto end;
627
     }
628

629
   if (quit_option) goto end;
630

631
   args = ecore_getopt_parse_positional(&options, values, 0, NULL, args);
632
   if (args < 0)
633
     {
634
        fputs("ERROR: Could not parse positional arguments.\n", stderr);
635
        goto end;
636
     }
637

638
   if (!protocol)
639
     {
640
        fputs("ERROR: missing protocol.\n", stderr);
641
        goto end;
642
     }
643

644
   if (strcmp(protocol, "tcp") == 0) cls = EFL_NET_SERVER_TCP_CLASS;
645
   else if (strcmp(protocol, "udp") == 0) cls = EFL_NET_SERVER_UDP_CLASS;
646
   else if (strcmp(protocol, "ssl") == 0) cls = EFL_NET_SERVER_SSL_CLASS;
647
#ifdef EFL_NET_SERVER_WINDOWS_CLASS
648
   else if (strcmp(protocol, "windows") == 0) cls = EFL_NET_SERVER_WINDOWS_CLASS;
649
#endif
650
#ifdef EFL_NET_SERVER_UNIX_CLASS
651
   else if (strcmp(protocol, "unix") == 0) cls = EFL_NET_SERVER_UNIX_CLASS;
652
#endif
653
   else
654
     {
655
        fprintf(stderr, "ERROR: unsupported protocol: %s\n", protocol);
656
        goto end;
657
     }
658

659
   server = efl_add(cls, ev->object, /* it's mandatory to use a main loop provider as the server parent */
660
                    efl_net_server_clients_limit_set(efl_added,
661
                                                     clients_limit,
662
                                                     clients_reject_excess), /* optional */
663
                    efl_event_callback_array_add(efl_added, server_cbs(), NULL)); /* mandatory to have "client,add" in order to be useful */
664
   if (!server)
665
     {
666
        fprintf(stderr, "ERROR: could not create class %p (%s)\n",
667
                cls, efl_class_name_get(cls));
668
        goto end;
669
     }
670

671
   if (cls == EFL_NET_SERVER_TCP_CLASS)
672
     {
673
        efl_net_server_ip_ipv6_only_set(server, ipv6_only);
674
        efl_net_server_fd_reuse_address_set(server, EINA_TRUE); /* optional, but nice for testing */
675
        efl_net_server_fd_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
676

677
        if (socket_activated) efl_net_server_fd_socket_activate(server, address);
678
     }
679
   else if (cls == EFL_NET_SERVER_UDP_CLASS)
680
     {
681
        const Eina_List *lst;
682

683
        efl_net_server_ip_ipv6_only_set(server, ipv6_only);
684
        efl_net_server_udp_dont_route_set(server, udp_dont_route);
685

686
        efl_net_server_udp_multicast_time_to_live_set(server, udp_mcast_ttl);
687
        efl_net_server_udp_multicast_loopback_set(server, udp_mcast_loopback);
688

689
        EINA_LIST_FOREACH(udp_mcast_groups, lst, str)
690
          efl_net_server_udp_multicast_join(server, str);
691

692

693
        efl_net_server_fd_reuse_address_set(server, EINA_TRUE); /* optional, but nice for testing */
694
        efl_net_server_fd_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
695
        if (socket_activated) efl_net_server_fd_socket_activate(server, address);
696
     }
697
   else if (cls == EFL_NET_SERVER_SSL_CLASS)
698
     {
699
        Eo *ssl_ctx;
700
        Efl_Net_Ssl_Cipher cipher = EFL_NET_SSL_CIPHER_AUTO;
701
        if (cipher_choice)
702
          {
703
             if (strcmp(cipher_choice, "auto") == 0)
704
               cipher = EFL_NET_SSL_CIPHER_AUTO;
705
             else if (strcmp(cipher_choice, "tlsv1") == 0)
706
               cipher = EFL_NET_SSL_CIPHER_TLSV1;
707
             else if (strcmp(cipher_choice, "tlsv1.1") == 0)
708
               cipher = EFL_NET_SSL_CIPHER_TLSV1_1;
709
             else if (strcmp(cipher_choice, "tlsv1.2") == 0)
710
               cipher = EFL_NET_SSL_CIPHER_TLSV1_2;
711
          }
712

713
        ssl_ctx = efl_add_ref(EFL_NET_SSL_CONTEXT_CLASS, NULL,
714
                          efl_net_ssl_context_certificates_set(efl_added, eina_list_iterator_new(certificates)),
715
                          efl_net_ssl_context_private_keys_set(efl_added, eina_list_iterator_new(private_keys)),
716
                          efl_net_ssl_context_certificate_revocation_lists_set(efl_added, eina_list_iterator_new(crls)),
717
                          efl_net_ssl_context_certificate_authorities_set(efl_added, eina_list_iterator_new(cas)),
718
                          efl_net_ssl_context_setup(efl_added, cipher, EINA_FALSE /* a server! */));
719

720
        efl_net_server_ssl_context_set(server, ssl_ctx);
721

722
        efl_net_server_fd_reuse_address_set(server, EINA_TRUE); /* optional, but nice for testing */
723
        efl_net_server_fd_reuse_port_set(server, EINA_TRUE); /* optional, but nice for testing... not secure unless you know what you're doing */
724
        if (socket_activated) efl_net_server_fd_socket_activate(server, address);
725
     }
726
#ifdef EFL_NET_SERVER_UNIX_CLASS
727
   else if (cls == EFL_NET_SERVER_UNIX_CLASS)
728
     {
729
        efl_net_server_unix_unlink_before_bind_set(server, EINA_TRUE); /* makes testing easier */
730
        if (socket_activated) efl_net_server_fd_socket_activate(server, address);
731
     }
732
#endif
733

734
   /* an explicit call to efl_net_server_serve() after the object is
735
    * constructed allows for more complex setup, such as interacting
736
    * with the object to add more properties that couldn't be done
737
    * during efl_add().
738
    */
739
   if (!efl_net_server_serving_get(server))
740
     {
741
        if (socket_activated)
742
          fprintf(stderr, "WARNING: --socket-activated, but not able to use $LISTEN_FDS descriptors. Try to start the server...\n");
743

744
        err = efl_net_server_serve(server, address);
745
        if (err)
746
          {
747
             fprintf(stderr, "ERROR: could not serve(%s): %s\n",
748
                     address, eina_error_msg_get(err));
749
             goto end_server;
750
          }
751
     }
752

753
   return ;
754

755
 end_server:
756
   efl_del(server);
757
   server = NULL;
758

759
 end:
760
   EINA_LIST_FREE(udp_mcast_groups, str)
761
     free(str);
762

763
   efl_loop_quit(efl_loop_get(ev->object), eina_value_int_init(EXIT_FAILURE));
764
}
765

766
EFL_MAIN_EX();
767

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.