efl

Форк
0
/
efl_io_queue_example.c 
376 строк · 11.6 Кб
1
#define EFL_BETA_API_SUPPORT
2
#include <Efl_Net.h>
3
#include <Ecore_Getopt.h>
4

5
static Eina_List *waiting = NULL;
6
static Eina_List *commands = NULL;
7
static Eina_Slice line_delimiter;
8
static Eo *send_queue, *receive_queue;
9

10
static void
11
_command_next(void)
12
{
13
   Eina_Slice slice;
14
   char *cmd;
15

16
   if (!commands)
17
     {
18
        efl_io_queue_eos_mark(send_queue);
19
        return;
20
     }
21

22
   cmd = commands->data;
23
   commands = eina_list_remove_list(commands, commands);
24

25
   slice = (Eina_Slice)EINA_SLICE_STR(cmd);
26
   efl_io_writer_write(send_queue, &slice, NULL);
27
   fprintf(stderr, "INFO: sent '" EINA_SLICE_STR_FMT "'\n",
28
           EINA_SLICE_STR_PRINT(slice));
29

30
   /* don't use line_delimiter directly, 'len' may be changed! */
31
   slice = line_delimiter;
32
   efl_io_writer_write(send_queue, &slice, NULL);
33
   free(cmd);
34
}
35

36
static void
37
_receiver_data(void *data EINA_UNUSED, const Efl_Event *event)
38
{
39
   Eina_Slice slice = efl_io_queue_slice_get(event->object);
40

41
   /* this will happen when we're called when we issue our own
42
    * efl_io_queue_clear() below.
43
    */
44
   if (slice.len == 0) return;
45

46
   /*
47
    * If the server didn't send us the line terminator and closed the
48
    * connection (ie: efl_io_reader_eos_get() == true) or if the
49
    * efl_io_copier_buffer_limit_set() was reached (note we do not set
50
    * it in this example), then we may have a line without a trailing
51
    * delimiter. Check for that.
52
    */
53
   if (!eina_slice_endswith(slice,  line_delimiter))
54
     {
55
        fprintf(stderr, "WARNING: received without line-delimiter '"
56
                EINA_SLICE_STR_FMT "'\n",
57
                EINA_SLICE_STR_PRINT(slice));
58
     }
59
   else
60
     {
61
        slice.len -= line_delimiter.len;
62
        fprintf(stderr, "INFO: received '" EINA_SLICE_STR_FMT "'\n",
63
                EINA_SLICE_STR_PRINT(slice));
64
     }
65

66
   efl_io_queue_clear(event->object);
67
   _command_next();
68
}
69

70
static void
71
_dialer_connected(void *data EINA_UNUSED, const Efl_Event *event)
72
{
73
   fprintf(stderr, "INFO: connected to %s (%s)\n",
74
           efl_net_dialer_address_dial_get(event->object),
75
           efl_net_socket_address_remote_get(event->object));
76

77
   _command_next();
78
}
79

80
static void
81
_copier_done(void *data EINA_UNUSED, const Efl_Event *event)
82
{
83
   fprintf(stderr, "INFO: %s done\n", efl_name_get(event->object));
84

85
   waiting = eina_list_remove(waiting, event->object);
86
   if (!waiting)
87
     efl_loop_quit(efl_loop_get(event->object), EINA_VALUE_EMPTY);
88
}
89

90
static void
91
_copier_error(void *data EINA_UNUSED, const Efl_Event *event)
92
{
93
   const Eina_Error *perr = event->info;
94
   fprintf(stderr, "INFO: %s error: #%d '%s'\n",
95
           efl_name_get(event->object), *perr, eina_error_msg_get(*perr));
96

97
   efl_loop_quit(efl_loop_get(event->object), eina_value_int_init(EXIT_FAILURE));
98
}
99

100
EFL_CALLBACKS_ARRAY_DEFINE(copier_cbs,
101
                           { EFL_IO_COPIER_EVENT_DONE, _copier_done },
102
                           { EFL_IO_COPIER_EVENT_ERROR, _copier_error });
103

104
static char *
105
_unescape(const char *str)
106
{
107
   char *ret = strdup(str);
108
   char *c, *w;
109
   Eina_Bool escaped = EINA_FALSE;
110

111
   for (c = ret, w = ret; *c != '\0'; c++)
112
     {
113
        if (escaped)
114
          {
115
             escaped = EINA_FALSE;
116
             switch (*c)
117
               {
118
                case 'n': *w = '\n'; break;
119
                case 'r': *w = '\r'; break;
120
                case 't': *w = '\t'; break;
121
                default: w++; /* no change */
122
               }
123
             w++;
124
          }
125
        else
126
          {
127
             if (*c == '\\')
128
               escaped = EINA_TRUE;
129
             else
130
               w++;
131
          }
132
     }
133
   *w = '\0';
134
   return ret;
135
}
136

137
static const Ecore_Getopt options = {
138
  "efl_io_queue_example", /* program name */
139
  NULL, /* usage line */
140
  "1", /* version */
141
  "(C) 2016 Enlightenment Project", /* copyright */
142
  "BSD 2-Clause", /* license */
143
  /* long description, may be multiline and contain \n */
144
  "Example of Efl_Io_Queue usage.\n"
145
  "\n"
146
  "This uses Efl_Io_Queue to easily interface with Efl_Io_Copier in order to "
147
  "send commands to a TCP server.",
148
  EINA_FALSE,
149
  {
150
    ECORE_GETOPT_STORE_STR('d', "line-delimiter",
151
                           "Changes the line delimiter to be used in both send and receive. Defaults to \\r\\n"),
152
    ECORE_GETOPT_STORE_ULONG('l', "buffer-limit",
153
                             "If set will limit buffer size to this limit of bytes. If used alongside with --line-delimiter and that delimiter was not found but bffer limit was reached, the line event will be triggered without the delimiter at the end."),
154
    ECORE_GETOPT_VERSION('V', "version"),
155
    ECORE_GETOPT_COPYRIGHT('C', "copyright"),
156
    ECORE_GETOPT_LICENSE('L', "license"),
157
    ECORE_GETOPT_HELP('h', "help"),
158

159
    ECORE_GETOPT_STORE_METAVAR_STR(0, NULL,
160
                                   "The server address as\n"
161
                                   "IP:PORT to connect using TCP and an IPv4 (A.B.C.D:PORT) or IPv6 ([A:B:C:D::E]:PORT).\n",
162
                                   "server_address"),
163
    ECORE_GETOPT_APPEND_METAVAR(0, NULL,
164
                                "Commands to send",
165
                                "commands",
166
                                ECORE_GETOPT_TYPE_STR),
167
    ECORE_GETOPT_SENTINEL
168
  }
169
};
170

171
EAPI_MAIN void
172
efl_pause(void *data EINA_UNUSED,
173
          const Efl_Event *ev EINA_UNUSED)
174
{
175
}
176

177
EAPI_MAIN void
178
efl_resume(void *data EINA_UNUSED,
179
           const Efl_Event *ev EINA_UNUSED)
180
{
181
}
182

183
EAPI_MAIN void
184
efl_terminate(void *data EINA_UNUSED,
185
              const Efl_Event *ev EINA_UNUSED)
186
{
187
  if (waiting)
188
    {
189
       fprintf(stderr, "ERROR: %d operations were waiting!\n",
190
               eina_list_count(waiting));
191
       eina_list_free(waiting);
192
       waiting = NULL;
193
    }
194
}
195

196
EAPI_MAIN void
197
efl_main(void *data EINA_UNUSED,
198
         const Efl_Event *ev)
199
{
200
   char *address = NULL;
201
   char *line_delimiter_str = NULL;
202
   char *cmd;
203
   unsigned long buffer_limit = 0;
204
   Eina_Bool quit_option = EINA_FALSE;
205
   Ecore_Getopt_Value values[] = {
206
     ECORE_GETOPT_VALUE_STR(line_delimiter_str),
207
     ECORE_GETOPT_VALUE_ULONG(buffer_limit),
208

209
     /* standard block to provide version, copyright, license and help */
210
     ECORE_GETOPT_VALUE_BOOL(quit_option), /* -V/--version quits */
211
     ECORE_GETOPT_VALUE_BOOL(quit_option), /* -C/--copyright quits */
212
     ECORE_GETOPT_VALUE_BOOL(quit_option), /* -L/--license quits */
213
     ECORE_GETOPT_VALUE_BOOL(quit_option), /* -h/--help quits */
214

215
     /* positional argument */
216
     ECORE_GETOPT_VALUE_STR(address),
217
     ECORE_GETOPT_VALUE_LIST(commands),
218

219
     ECORE_GETOPT_VALUE_NONE /* sentinel */
220
   };
221
   Eina_Error err;
222
   int args;
223
   Eo *dialer, *sender, *receiver, *loop;
224

225
   args = ecore_getopt_parse(&options, values, 0, NULL);
226
   if (args < 0)
227
     {
228
        fputs("ERROR: Could not parse command line options.\n", stderr);
229
        goto end;
230
     }
231

232
   if (quit_option) goto end;
233

234
   args = ecore_getopt_parse_positional(&options, values, 0, NULL, args);
235
   if (args < 0)
236
     {
237
        fputs("ERROR: Could not parse positional arguments.\n", stderr);
238
        goto end;
239
     }
240

241
   line_delimiter_str = _unescape(line_delimiter_str ? line_delimiter_str : "\\r\\n");
242

243
   if (!commands)
244
     {
245
        fputs("ERROR: missing commands to send.\n", stderr);
246
        goto end;
247
     }
248

249
   line_delimiter = (Eina_Slice)EINA_SLICE_STR(line_delimiter_str);
250

251
   /*
252
    * Without a send_queue we'd have to manually implement an
253
    * Efl_Io_Reader object that would provide partial data when
254
    * Efl_Io_Reader.read() is called by Efl_Io_Copier. This is
255
    * cumbersome... we just want to write a full command and have the
256
    * queue to handle that for us.
257
    *
258
    * Our example's usage is to write each command at once followed by
259
    * the line_delimiter, then wait for a reply from the server, then
260
    * write another.
261
    */
262
   send_queue = efl_add_ref(EFL_IO_QUEUE_CLASS, NULL,
263
                        efl_name_set(efl_added, "send_queue"),
264
                        efl_io_queue_limit_set(efl_added, buffer_limit));
265
   if (!send_queue)
266
     {
267
        fprintf(stderr, "ERROR: could not create Efl_Io_Queue (send)\n");
268
        goto end;
269
     }
270

271
   /*
272
    * Without a receive_queue we'd have to manually implement an
273
    * Efl_Io_Writer object that would handle write of partial data
274
    * with Efl_Io_Writer.write() is called by Efl_Io_Copier.
275
    *
276
    * For output we could have another solution as well: use NULL
277
    * destination and handle "line" or "data" events manually,
278
    * stealing the buffer so it doesn't grow.
279
    *
280
    * Our example's usage is to peek its data with slice_get() then
281
    * clear().
282
    */
283
   receive_queue = efl_add_ref(EFL_IO_QUEUE_CLASS, NULL,
284
                           efl_name_set(efl_added, "receive_queue"),
285
                           efl_io_queue_limit_set(efl_added, buffer_limit),
286
                           efl_event_callback_add(efl_added, EFL_IO_QUEUE_EVENT_SLICE_CHANGED, _receiver_data, NULL));
287
   if (!receive_queue)
288
     {
289
        fprintf(stderr, "ERROR: could not create Efl_Io_Queue (receive)\n");
290
        goto error_receive_queue;
291
     }
292

293
   /*
294
    * From here on it's mostly the same all Efl_Io_Copier would do,
295
    * check efl_io_copier_simple_example.c and efl_io_copier_example.c
296
    */
297

298
   /*
299
    * some objects such as the Efl.Io.Copier and Efl.Net.Dialer.Tcp
300
    * depend on main loop, thus their parent must be a loop
301
    * provider. We use the loop itself.
302
    */
303
   loop = ev->object;
304

305
   /* The TCP client to use to send/receive network data */
306
   dialer = efl_add(EFL_NET_DIALER_TCP_CLASS, loop,
307
                    efl_name_set(efl_added, "dialer"),
308
                    efl_event_callback_add(efl_added, EFL_NET_DIALER_EVENT_DIALER_CONNECTED, _dialer_connected, NULL));
309
   if (!dialer)
310
     {
311
        fprintf(stderr, "ERROR: could not create Efl_Net_Dialer_Tcp\n");
312
        goto error_dialer;
313
     }
314

315
   /* sender: send_queue->network */
316
   sender = efl_add(EFL_IO_COPIER_CLASS, loop,
317
                    efl_name_set(efl_added, "sender"),
318
                    efl_io_copier_line_delimiter_set(efl_added, line_delimiter),
319
                    efl_io_copier_source_set(efl_added, send_queue),
320
                    efl_io_copier_destination_set(efl_added, dialer),
321
                    efl_event_callback_array_add(efl_added, copier_cbs(), NULL));
322
   if (!sender)
323
     {
324
        fprintf(stderr, "ERROR: could not create Efl_Io_Copier (sender)\n");
325
        goto error_sender;
326
     }
327

328
   /* receiver: network->receive_queue */
329
   receiver = efl_add(EFL_IO_COPIER_CLASS, loop,
330
                      efl_name_set(efl_added, "receiver"),
331
                      efl_io_copier_line_delimiter_set(efl_added, line_delimiter),
332
                      efl_io_copier_source_set(efl_added, dialer),
333
                      efl_io_copier_destination_set(efl_added, receive_queue),
334
                      efl_event_callback_array_add(efl_added, copier_cbs(), NULL));
335
   if (!receiver)
336
     {
337
        fprintf(stderr, "ERROR: could not create Efl_Io_Copier (receiver)\n");
338
        goto error_receiver;
339
     }
340

341
   err = efl_net_dialer_dial(dialer, address);
342
   if (err)
343
     {
344
        fprintf(stderr, "ERROR: could not dial %s: %s\n",
345
                address, eina_error_msg_get(err));
346
        goto error_dialing;
347
     }
348

349
   waiting = eina_list_append(waiting, sender);
350
   waiting = eina_list_append(waiting, receiver);
351

352
   return ;
353

354
 error_dialing:
355
   efl_io_closer_close(receiver);
356
   efl_del(receiver);
357
 error_receiver:
358
   efl_io_closer_close(sender);
359
   efl_del(sender);
360
 error_sender:
361
   efl_del(dialer);
362
 error_dialer:
363
   efl_unref(receive_queue);
364
 error_receive_queue:
365
   efl_unref(send_queue);
366
 end:
367
   EINA_LIST_FREE(commands, cmd)
368
     {
369
        fprintf(stderr, "ERROR: unsent command: %s\n", cmd);
370
        free(cmd);
371
     }
372

373
   efl_loop_quit(efl_loop_get(ev->object), eina_value_int_init(EXIT_FAILURE));
374
}
375

376
EFL_MAIN_EX();
377

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

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

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

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