1 :
2 :
3 : #define EX_UTILS_NO_USE_INPUT 1
4 : #define EX_UTILS_NO_USE_IO_FD 1
5 : #define EX_UTILS_NO_USE_OPEN 1
6 : #define EX_UTILS_NO_USE_INIT 1
7 : #define EX_UTILS_NO_USE_EXIT 1
8 : #include "ex_utils.h"
9 :
10 : #include <stdlib.h>
11 : #include <sys/socket.h>
12 : #include <getopt.h>
13 : #include <netinet/in.h>
14 : #include <netinet/tcp.h>
15 : #include <arpa/inet.h>
16 : #include <netdb.h>
17 : #include <sys/time.h>
18 : #include <time.h>
19 : #include <signal.h>
20 :
21 : #include <socket_poll.h>
22 : #include <timer_q.h>
23 :
24 : #define WAIT_SET_RECV_FLAG 1 /* work around ? */
25 :
26 : #define CL_PACKET_MAX 0xFFFF
27 : #define CL_MAX_CONNECT 128
28 :
29 : /* made up ... 8bits */
30 : #define CL_MSG_CLIENT_NONE INT_MAX
31 : #define CL_MSG_CLIENT_ZERO (INT_MAX - 1)
32 : #define CL_MAX_WAIT_SEND 16
33 :
34 :
35 : #include "evnt.h"
36 :
37 : #define EX_UTILS_NO_FUNCS 1
38 : #include "ex_utils.h"
39 :
40 : #include "mk.h"
41 :
42 : MALLOC_CHECK_DECL();
43 :
44 : #include "opt.h"
45 :
46 : struct con
47 : {
48 : struct Evnt ev[1];
49 : };
50 :
51 :
52 :
53 : #define CLEN COMPILE_STRLEN
54 :
55 : /* is the cstr a prefix of the vstr */
56 : #define VPREFIX(vstr, p, l, cstr) \
57 : (((l) >= CLEN(cstr)) && \
58 : vstr_cmp_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
59 :
60 : /* is the cstr a prefix of the vstr, no case */
61 : #define VIPREFIX(vstr, p, l, cstr) \
62 : (((l) >= CLEN(cstr)) && \
63 : vstr_cmp_case_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
64 :
65 :
66 : static int io_r_fd = STDIN_FILENO;
67 : unsigned int io_ind_r = 0; /* socket poll */
68 : static Vstr_base *io_r = NULL;
69 : static int io_w_fd = STDOUT_FILENO;
70 : unsigned int io_ind_w = 0; /* socket poll */
71 : static Vstr_base *io_w = NULL;
72 :
73 : static Timer_q_base *cl_timeout_base = NULL;
74 : static Timer_q_base *cl_timer_connect_base = NULL;
75 :
76 : static int server_clients_count = 0; /* current number of clients */
77 :
78 : static int server_clients = 1;
79 : static unsigned int server_timeout = (2 * 60); /* 2 minutes */
80 :
81 : static const char *server_filename = NULL;
82 :
83 : static Vlg *vlg = NULL;
84 :
85 :
86 : static void ui_out(void)
87 2145 : {
88 2145 : if (!io_ind_w)
89 40 : return;
90 :
91 2105 : SOCKET_POLL_INDICATOR(io_ind_w)->events |= POLLOUT;
92 : }
93 :
94 : static int cl_recv(struct Evnt *evnt)
95 734 : {
96 734 : int ret = evnt_cb_func_recv(evnt);
97 :
98 734 : if (!ret)
99 0 : goto malloc_bad;
100 :
101 3244 : while (evnt->io_r->len)
102 : {
103 2645 : size_t pos = 0;
104 2645 : size_t len = 0;
105 2645 : size_t ns1 = 0;
106 2645 : size_t vpos = 0;
107 2645 : size_t vlen = 0;
108 2645 : size_t nse2 = 0;
109 2645 : int done = FALSE;
110 :
111 2645 : if (!(ns1 = vstr_parse_netstr(evnt->io_r, 1, evnt->io_r->len, &pos, &len)))
112 : {
113 500 : if (!(SOCKET_POLL_INDICATOR(evnt->ind)->events & POLLIN))
114 0 : return (FALSE);
115 500 : return (TRUE);
116 : }
117 :
118 13886 : while ((nse2 = vstr_parse_netstr(evnt->io_r, pos, len, &vpos, &vlen)))
119 : {
120 10906 : if (!done && !vlen && (nse2 == len))
121 : {
122 228 : len = 0;
123 228 : evnt_got_pkt(evnt);
124 228 : break;
125 : }
126 :
127 10678 : if (done)
128 8761 : vstr_add_cstr_buf(io_w, io_w->len, " ");
129 :
130 10678 : vstr_add_vstr(io_w, io_w->len, evnt->io_r, vpos, vlen, VSTR_TYPE_ADD_DEF);
131 :
132 10678 : if (!done)
133 1917 : vstr_add_cstr_buf(io_w, io_w->len, ":");
134 :
135 10678 : done = TRUE;
136 :
137 10678 : len -= nse2; pos += nse2;
138 : }
139 2145 : if (done)
140 1917 : vstr_add_cstr_buf(io_w, io_w->len, "\n");
141 :
142 2145 : ui_out();
143 :
144 2145 : if (len)
145 0 : VLG_WARN_RET(FALSE, (vlg, "invalid entry\n"));
146 :
147 : /*
148 : if (io_w->conf->malloc_bad)
149 : goto malloc_bad;
150 : */
151 :
152 2145 : vstr_del(evnt->io_r, 1, ns1);
153 : }
154 :
155 234 : return (TRUE);
156 :
157 0 : malloc_bad:
158 0 : evnt->io_r->conf->malloc_bad = FALSE;
159 0 : evnt->io_w->conf->malloc_bad = FALSE;
160 0 : return (FALSE);
161 : }
162 :
163 : #define UI_CMD(x) \
164 : else if (vstr_cmp_case_cstr_eq(io_r, 1, len, x "\n")) \
165 : { \
166 : size_t ns1 = 0; \
167 : Vstr_base *out = con->io_w; \
168 : \
169 : if (!(ns1 = vstr_add_netstr_beg(out, out->len)) || \
170 : !vstr_add_cstr_ptr(out, out->len, x) || \
171 : !vstr_add_netstr_end(out, ns1, out->len) || \
172 : !evnt_send_add(con, FALSE, 0)) \
173 : { \
174 : evnt_close(con); \
175 : return; \
176 : } \
177 : evnt_put_pkt(con); \
178 : } \
179 : else if (VIPREFIX(io_r, 1, len, x " ")) do \
180 : { \
181 : size_t ns1 = 0; \
182 : size_t ns2 = 0; \
183 : size_t cmd_pos = 1; \
184 : size_t cmd_len = len; \
185 : size_t tmp = 0; \
186 : Vstr_base *out = con->io_w; \
187 : \
188 : cmd_len -= CLEN(x); cmd_pos += CLEN(x); \
189 : tmp = vstr_spn_cstr_chrs_fwd(io_r, cmd_pos, cmd_len, " "); \
190 : cmd_len -= tmp; cmd_pos += tmp; \
191 : \
192 : if (!(ns1 = vstr_add_netstr_beg(out, out->len)) || \
193 : !(ns2 = vstr_add_netstr_beg(out, out->len)) || \
194 : !vstr_add_cstr_ptr(out, out->len, x) || \
195 : !vstr_add_netstr_end(out, ns2, out->len) || \
196 : !(ns2 = vstr_add_netstr_beg(out, out->len)) || \
197 : !vstr_add_vstr(out, out->len, io_r, cmd_pos, cmd_len, 0) || \
198 : !vstr_add_netstr_end(out, ns2, out->len) || \
199 : !vstr_add_netstr_end(out, ns1, out->len) || \
200 : !evnt_send_add(con, FALSE, 0)) \
201 : { \
202 : evnt_close(con); \
203 : return; \
204 : } \
205 : evnt_put_pkt(con); \
206 : } while (FALSE)
207 :
208 : static void cl_connect(void); /* fwd ref */
209 : static void ui_parse(void)
210 1938 : {
211 1938 : size_t len = 0;
212 1938 : unsigned int count = 64;
213 1938 : struct Evnt *con = NULL;
214 :
215 1938 : vlg_dbg3(vlg, "ui_parse %zu\n", io_r->len);
216 :
217 1938 : if (!io_r->len)
218 1706 : return; /* don't start more connections for nothing */
219 :
220 232 : if (!(con = evnt_find_least_used()))
221 : {
222 0 : cl_connect();
223 0 : return;
224 : }
225 :
226 580 : while ((len = vstr_srch_chr_fwd(io_r, 1, io_r->len, '\n')) && --count)
227 : {
228 232 : size_t line_len = len;
229 :
230 : if (0) { /* not reached */ }
231 232 : UI_CMD("CLOSE");
232 192 : UI_CMD("DBG");
233 192 : UI_CMD("UNDBG");
234 192 : UI_CMD("LIST");
235 120 : UI_CMD("STATUS");
236 :
237 232 : vlg_dbg3(vlg, "bad input\n");
238 : /* ignore everything else */
239 :
240 232 : vstr_del(io_r, 1, line_len);
241 : }
242 232 : vlg_dbg3(vlg, "io_r left = %zu\n", io_r->len);
243 : }
244 : #undef UI_CMD
245 :
246 : static int cl_cb_func_connect(struct Evnt *evnt)
247 232 : {
248 : (void)evnt;
249 :
250 232 : vlg_dbg3(vlg, "connect\n");
251 :
252 232 : ui_parse();
253 :
254 232 : return (TRUE);
255 : }
256 :
257 : static int cl_cb_func_recv(struct Evnt *evnt)
258 734 : {
259 734 : return (cl_recv(evnt));
260 : }
261 :
262 : static void cl_cb_func_free(struct Evnt *evnt)
263 232 : {
264 232 : struct con *con = (struct con *)evnt;
265 :
266 232 : F(con);
267 :
268 232 : --server_clients_count;
269 232 : }
270 :
271 : static struct con *cl_make(const char *server_fname)
272 232 : {
273 232 : struct con *ret = MK(sizeof(struct con));
274 :
275 232 : if (!ret)
276 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
277 232 : if (!evnt_make_con_local(ret->ev, server_fname))
278 0 : err(EXIT_FAILURE, "%s", __func__);
279 :
280 232 : ret->ev->cbs->cb_func_connect = cl_cb_func_connect;
281 232 : ret->ev->cbs->cb_func_recv = cl_cb_func_recv;
282 232 : ret->ev->cbs->cb_func_free = cl_cb_func_free;
283 :
284 232 : ++server_clients_count;
285 :
286 232 : if (ret->ev->flag_q_none)
287 232 : cl_cb_func_connect(ret->ev);
288 :
289 232 : return (ret);
290 : }
291 :
292 : static void cl_connect(void)
293 232 : {
294 232 : struct con *con = cl_make(server_filename);
295 : struct timeval tv;
296 :
297 232 : if (server_timeout)
298 : {
299 232 : gettimeofday(&tv, NULL);
300 :
301 232 : TIMER_Q_TIMEVAL_ADD_SECS(&tv, 0, rand() % server_timeout);
302 :
303 232 : if (!(con->ev->tm_o = timer_q_add_node(cl_timeout_base, con, &tv,
304 : TIMER_Q_FLAG_NODE_DEFAULT)))
305 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
306 : }
307 232 : }
308 :
309 : static unsigned int cl_scan_io_fds(unsigned int ready)
310 1721 : {
311 1721 : const int bad_poll_flags = (POLLERR | /* POLLHUP | */ POLLNVAL);
312 :
313 1721 : vlg_dbg2(vlg, "BEG ready = %u\n", ready);
314 1721 : if (io_ind_r &&
315 : SOCKET_POLL_INDICATOR(io_ind_r)->revents & bad_poll_flags)
316 : {
317 0 : --ready;
318 :
319 0 : close(SOCKET_POLL_INDICATOR(io_ind_r)->fd);
320 0 : vlg_dbg2(vlg, "ERROR-POLL-IO_R(%d):\n",
321 : SOCKET_POLL_INDICATOR(io_ind_r)->revents);
322 0 : socket_poll_del(io_ind_r);
323 0 : io_ind_r = 0;
324 : }
325 1721 : if (SOCKET_POLL_INDICATOR(io_ind_w)->revents & bad_poll_flags)
326 : {
327 15 : --ready;
328 :
329 15 : close(SOCKET_POLL_INDICATOR(io_ind_w)->fd);
330 15 : vlg_dbg2(vlg, "ERROR-POLL-IO_W(%d):\n",
331 : SOCKET_POLL_INDICATOR(io_ind_w)->revents);
332 15 : socket_poll_del(io_ind_w);
333 15 : io_ind_w = 0;
334 : }
335 1721 : if (io_ind_r && (SOCKET_POLL_INDICATOR(io_ind_r)->revents & POLLIN))
336 : {
337 : unsigned int ern;
338 :
339 0 : --ready;
340 0 : while (vstr_sc_read_iov_fd(io_r, io_r->len, io_r_fd, 4, 32, &ern))
341 : { /* do nothing */ }
342 :
343 0 : switch (ern)
344 : {
345 : case VSTR_TYPE_SC_READ_FD_ERR_EOF:
346 0 : close(SOCKET_POLL_INDICATOR(io_ind_r)->fd);
347 0 : SOCKET_POLL_INDICATOR(io_ind_r)->fd = -1;
348 0 : socket_poll_del(io_ind_r);
349 0 : io_ind_r = 0;
350 0 : errno = EAGAIN;
351 : case VSTR_TYPE_SC_READ_FD_ERR_READ_ERRNO:
352 0 : if (errno != EAGAIN)
353 0 : break;
354 : case VSTR_TYPE_SC_READ_FD_ERR_NONE:
355 0 : ui_parse();
356 : default:
357 : break;
358 : }
359 0 : vlg_dbg2(vlg, "READ UI\n");
360 : }
361 1721 : else if (io_ind_w)
362 1706 : ui_parse();
363 :
364 1721 : if (io_ind_w && (SOCKET_POLL_INDICATOR(io_ind_w)->revents & POLLOUT))
365 : {
366 : unsigned int ern;
367 :
368 639 : --ready;
369 :
370 1278 : while (io_w->len && vstr_sc_write_fd(io_w, 1, io_w->len, io_w_fd, &ern))
371 : { /* do nothing */ }
372 :
373 639 : if (!io_w->len)
374 639 : SOCKET_POLL_INDICATOR(io_ind_w)->events &= ~POLLOUT;
375 639 : vlg_dbg2(vlg, "WRITE UI\n");
376 : }
377 :
378 1721 : return (ready);
379 : }
380 :
381 : static void usage(const char *program_name, int ret, const char *prefix)
382 0 : {
383 0 : Vstr_base *out = vstr_make_base(NULL);
384 :
385 0 : if (!out)
386 0 : errno = ENOMEM, err(EXIT_FAILURE, "usage");
387 :
388 0 : vstr_add_fmt(out, 0, "%s\n"
389 : " Format: %s [-chmtwV] <server name>\n"
390 : " --help -h - Print this message.\n"
391 : " --debug -d - Enable debug info.\n"
392 : " --clients -c - Number of connections to make.\n"
393 : " --nagle -n - Enable/disable nagle TCP option.\n"
394 : " --timeout -t - Timeout (usecs) between each message.\n"
395 : " --version -V - Print the version string.\n",
396 : prefix, program_name);
397 :
398 0 : if (io_put_all(out, ret ? STDERR_FILENO : STDOUT_FILENO) == IO_FAIL)
399 0 : err(EXIT_FAILURE, "write");
400 :
401 0 : exit (ret);
402 : }
403 :
404 :
405 : static void cl_cmd_line(int argc, char *argv[])
406 232 : {
407 232 : char optchar = 0;
408 232 : const char *program_name = NULL;
409 : struct option long_options[] =
410 : {
411 : {"help", no_argument, NULL, 'h'},
412 : {"clients", required_argument, NULL, 'c'},
413 : {"debug", required_argument, NULL, 'd'},
414 : {"execute", required_argument, NULL, 'e'},
415 : {"host", required_argument, NULL, 'H'},
416 : {"port", required_argument, NULL, 'P'},
417 : {"nagle", optional_argument, NULL, 'n'},
418 : {"timeout", required_argument, NULL, 't'},
419 : {"version", no_argument, NULL, 'V'},
420 : {NULL, 0, NULL, 0}
421 232 : };
422 232 : Vstr_base *out = vstr_make_base(NULL);
423 :
424 232 : if (!out)
425 0 : errno = ENOMEM, err(EXIT_FAILURE, "command line");
426 :
427 232 : program_name = opt_program_name(argv[0], "cntl");
428 :
429 696 : while ((optchar = getopt_long(argc, argv, "c:de:hH:nP:Rt:V",
430 : long_options, NULL)) != -1)
431 : {
432 232 : switch (optchar)
433 : {
434 0 : case '?': usage(program_name, EXIT_FAILURE, "");
435 0 : case 'h': usage(program_name, EXIT_SUCCESS, "");
436 :
437 : case 'V':
438 0 : vstr_add_fmt(out, 0,"\
439 : %s version 1.0.0, compiled on %s.\n\
440 : Written by James Antill\n\
441 : \n\
442 : Uses Vstr string library.\n\
443 : ",
444 : program_name, __DATE__);
445 :
446 0 : if (io_put_all(out, STDOUT_FILENO) == IO_FAIL)
447 0 : err(EXIT_FAILURE, "write");
448 :
449 0 : exit (EXIT_SUCCESS);
450 :
451 0 : case 'c': server_clients = atoi(optarg); break;
452 0 : case 't': server_timeout = atoi(optarg); break;
453 :
454 0 : case 'd': vlg_debug(vlg); break;
455 :
456 : case 'e':
457 : /* use cmd line instead of stdin */
458 232 : io_r_fd = -1;
459 232 : vstr_add_cstr_buf(io_r, io_r->len, optarg);
460 232 : vstr_add_cstr_buf(io_r, io_r->len, "\n");
461 232 : break;
462 :
463 : case 'n':
464 0 : if (!optarg)
465 0 : { evnt_opt_nagle = !evnt_opt_nagle; }
466 0 : else if (!strcasecmp("true", optarg)) evnt_opt_nagle = TRUE;
467 0 : else if (!strcasecmp("1", optarg)) evnt_opt_nagle = TRUE;
468 0 : else if (!strcasecmp("false", optarg)) evnt_opt_nagle = FALSE;
469 0 : else if (!strcasecmp("0", optarg)) evnt_opt_nagle = FALSE;
470 0 : break;
471 :
472 : default:
473 0 : abort();
474 : }
475 : }
476 232 : vstr_free_base(out); out = NULL;
477 :
478 232 : argc -= optind;
479 232 : argv += optind;
480 :
481 232 : if (argc != 1)
482 0 : usage(program_name, EXIT_FAILURE, "");
483 :
484 232 : server_filename = argv[0];
485 232 : }
486 :
487 : static void cl_timer_cli(int type, void *data)
488 464 : {
489 464 : struct con *con = data;
490 : struct timeval tv;
491 464 : unsigned long diff = 0;
492 :
493 464 : if (!con)
494 0 : return;
495 :
496 232 : ASSERT(evnt_fd(con->ev) != -1);
497 :
498 464 : if (type == TIMER_Q_TYPE_CALL_RUN_ALL)
499 0 : return;
500 :
501 464 : con->ev->tm_o = NULL;
502 :
503 464 : if (type == TIMER_Q_TYPE_CALL_DEL)
504 232 : return;
505 :
506 232 : gettimeofday(&tv, NULL);
507 232 : diff = timer_q_timeval_udiff_secs(&tv, &con->ev->mtime);
508 232 : if (diff > server_timeout)
509 : {
510 0 : vlg_dbg2(vlg, "timeout = %p (%lu, %lu)\n",
511 : con, diff, (unsigned long)server_timeout);
512 0 : close(SOCKET_POLL_INDICATOR(con->ev->ind)->fd);
513 0 : return;
514 : }
515 :
516 232 : if (type == TIMER_Q_TYPE_CALL_RUN_ALL)
517 0 : return;
518 :
519 232 : TIMER_Q_TIMEVAL_ADD_SECS(&tv, (server_timeout - diff) + 1, 0);
520 232 : if (!(con->ev->tm_o = timer_q_add_node(cl_timeout_base, con, &tv,
521 : TIMER_Q_FLAG_NODE_DEFAULT)))
522 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
523 : }
524 :
525 : static void cl_timer_con(int type, void *data)
526 0 : {
527 0 : int count = 0;
528 :
529 0 : ASSERT(!data);
530 :
531 0 : if (type == TIMER_Q_TYPE_CALL_DEL)
532 0 : return;
533 :
534 0 : while ((server_clients_count < server_clients) && (count < CL_MAX_CONNECT))
535 : {
536 0 : cl_connect();
537 0 : ++count;
538 : }
539 :
540 0 : if (type == TIMER_Q_TYPE_CALL_RUN_ALL)
541 0 : return;
542 :
543 0 : if (server_clients_count < server_clients)
544 : {
545 : struct timeval tv;
546 :
547 0 : gettimeofday(&tv, NULL);
548 0 : TIMER_Q_TIMEVAL_ADD_SECS(&tv, 1, 0);
549 0 : if (!timer_q_add_node(cl_timer_connect_base, NULL, &tv,
550 : TIMER_Q_FLAG_NODE_DEFAULT))
551 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
552 : }
553 : }
554 :
555 : static void cl_init(void)
556 232 : {
557 232 : int flags = TIMER_Q_FLAG_BASE_DEFAULT;
558 :
559 232 : cl_timeout_base = timer_q_add_base(cl_timer_cli, flags);
560 232 : cl_timer_connect_base = timer_q_add_base(cl_timer_con, flags);
561 :
562 232 : if (!cl_timeout_base)
563 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
564 232 : if (!cl_timer_connect_base)
565 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
566 :
567 232 : vlg_init();
568 :
569 232 : if (!(vlg = vlg_make()))
570 0 : errno = ENOMEM, err(EXIT_FAILURE, "init");
571 :
572 232 : evnt_logger(vlg);
573 232 : }
574 :
575 : static void cl_beg(void)
576 232 : {
577 232 : int count = 0;
578 :
579 232 : vlg_dbg3(vlg, "cl_beg\n");
580 :
581 232 : if (io_r_fd != -1)
582 : {
583 0 : vlg_dbg3(vlg, "cl_beg io_r beg\n");
584 0 : evnt_fd__set_nonblock(io_r_fd, TRUE);
585 0 : if (!(io_ind_r = socket_poll_add(io_r_fd)))
586 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
587 0 : SOCKET_POLL_INDICATOR(io_ind_r)->events |= POLLIN;
588 : }
589 :
590 232 : evnt_fd__set_nonblock(io_w_fd, TRUE);
591 232 : if (!(io_ind_w = socket_poll_add(io_w_fd)))
592 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
593 :
594 580 : while ((server_clients_count < server_clients) && (count < CL_MAX_CONNECT))
595 : {
596 232 : cl_connect();
597 232 : ++count;
598 : }
599 :
600 232 : if (server_clients_count < server_clients)
601 : {
602 : struct timeval tv;
603 :
604 0 : gettimeofday(&tv, NULL);
605 0 : TIMER_Q_TIMEVAL_ADD_SECS(&tv, 1, 0);
606 0 : if (!timer_q_add_node(cl_timer_connect_base, NULL, &tv,
607 : TIMER_Q_FLAG_NODE_DEFAULT))
608 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
609 : }
610 232 : }
611 :
612 : static void cl_signals(void)
613 232 : {
614 : struct sigaction sa;
615 :
616 232 : if (sigemptyset(&sa.sa_mask) == -1)
617 0 : err(EXIT_FAILURE, "%s", __func__);
618 :
619 : /* don't use SA_RESTART ... */
620 232 : sa.sa_flags = 0;
621 : /* ignore it... we don't have a use for it */
622 232 : sa.sa_handler = SIG_IGN;
623 :
624 232 : if (sigaction(SIGPIPE, &sa, NULL) == -1)
625 0 : err(EXIT_FAILURE, "%s", __func__);
626 232 : }
627 :
628 : int main(int argc, char *argv[])
629 232 : {
630 232 : if (!vstr_init())
631 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
632 :
633 232 : if (!vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '$') ||
634 : !vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_LOC_CSTR_THOU_SEP, "_") ||
635 : !vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_LOC_CSTR_THOU_GRP, "\3") ||
636 : !vstr_sc_fmt_add_all(NULL))
637 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
638 :
639 232 : if (!(io_r = vstr_make_base(NULL))) /* used in cmd line */
640 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
641 232 : if (!(io_w = vstr_make_base(NULL)))
642 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
643 :
644 232 : if (!socket_poll_init(0, SOCKET_POLL_TYPE_MAP_DIRECT))
645 0 : errno = ENOMEM, err(EXIT_FAILURE, "%s", __func__);
646 :
647 232 : srand(getpid() ^ time(NULL)); /* doesn't need to be secure... just different
648 : * for different runs */
649 :
650 232 : cl_signals();
651 :
652 232 : cl_init();
653 :
654 232 : cl_cmd_line(argc, argv);
655 :
656 232 : cl_beg();
657 :
658 2185 : while (io_ind_w && (io_w->len || evnt_waiting() || io_ind_r || io_r->len))
659 : {
660 1721 : int ready = evnt_poll();
661 : struct timeval tv;
662 :
663 1721 : if ((ready == -1) && (errno != EINTR))
664 0 : err(EXIT_FAILURE, "%s", __func__);
665 1721 : if (ready == -1)
666 0 : continue;
667 :
668 1721 : evnt_out_dbg3("1");
669 1721 : ready = cl_scan_io_fds(ready);
670 1721 : evnt_out_dbg3("2");
671 1721 : evnt_scan_fds(ready, CL_MAX_WAIT_SEND);
672 1721 : evnt_out_dbg3("3");
673 1721 : evnt_scan_send_fds();
674 1721 : evnt_out_dbg3("4");
675 :
676 1721 : gettimeofday(&tv, NULL);
677 1721 : timer_q_run_norm(&tv);
678 :
679 1721 : evnt_out_dbg3("5");
680 1721 : evnt_scan_send_fds();
681 1721 : evnt_out_dbg3("6");
682 : }
683 232 : evnt_out_dbg3("E");
684 :
685 232 : vstr_free_base(io_r);
686 232 : vstr_free_base(io_w);
687 :
688 232 : timer_q_del_base(cl_timeout_base);
689 232 : timer_q_del_base(cl_timer_connect_base);
690 :
691 232 : evnt_close_all();
692 :
693 232 : vlg_free(vlg);
694 :
695 232 : vlg_exit();
696 :
697 232 : vstr_exit();
698 :
699 116 : MALLOC_CHECK_EMPTY();
700 :
701 232 : exit (EXIT_SUCCESS);
702 : }
703 :
|