1 /* 2 * Copyright (C) 2022 Jo-Philipp Wich <jo@mein.io> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <errno.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include <limits.h> 21 #include <fcntl.h> 22 23 #include <libubox/uloop.h> 24 25 #include "ucode/module.h" 26 #include "ucode/platform.h" 27 28 #define ok_return(expr) do { last_error = 0; return (expr); } while(0) 29 #define err_return(err) do { last_error = err; return NULL; } while(0) 30 31 static uc_resource_type_t *timer_type, *handle_type, *process_type, *task_type, *pipe_type; 32 33 #ifdef HAVE_ULOOP_INTERVAL 34 static uc_resource_type_t *interval_type; 35 #endif 36 37 #ifdef HAVE_ULOOP_SIGNAL 38 static uc_resource_type_t *signal_type; 39 #endif 40 41 static uc_value_t *object_registry; 42 43 static int last_error = 0; 44 45 static size_t 46 uc_uloop_reg_add(uc_value_t *obj, uc_value_t *cb) 47 { 48 size_t i = 0; 49 50 while (ucv_array_get(object_registry, i)) 51 i += 2; 52 53 ucv_array_set(object_registry, i + 0, ucv_get(obj)); 54 ucv_array_set(object_registry, i + 1, ucv_get(cb)); 55 56 return i; 57 } 58 59 static bool 60 uc_uloop_reg_remove(size_t i) 61 { 62 if (i + 1 >= ucv_array_length(object_registry)) 63 return false; 64 65 ucv_array_set(object_registry, i + 0, NULL); 66 ucv_array_set(object_registry, i + 1, NULL); 67 68 return true; 69 } 70 71 static bool 72 uc_uloop_reg_invoke(uc_vm_t *vm, size_t i, uc_value_t *arg) 73 { 74 uc_value_t *obj = ucv_array_get(object_registry, i + 0); 75 uc_value_t *cb = ucv_array_get(object_registry, i + 1); 76 77 if (!ucv_is_callable(cb)) 78 return false; 79 80 uc_vm_stack_push(vm, ucv_get(obj)); 81 uc_vm_stack_push(vm, ucv_get(cb)); 82 uc_vm_stack_push(vm, ucv_get(arg)); 83 84 if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) { 85 uloop_end(); 86 87 return false; 88 } 89 90 ucv_put(uc_vm_stack_pop(vm)); 91 92 return true; 93 } 94 95 static uc_value_t * 96 uc_uloop_error(uc_vm_t *vm, size_t nargs) 97 { 98 uc_value_t *errmsg; 99 100 if (last_error == 0) 101 return NULL; 102 103 errmsg = ucv_string_new(strerror(last_error)); 104 last_error = 0; 105 106 return errmsg; 107 } 108 109 static uc_value_t * 110 uc_uloop_init(uc_vm_t *vm, size_t nargs) 111 { 112 int rv = uloop_init(); 113 114 if (rv == -1) 115 err_return(errno); 116 117 ok_return(ucv_boolean_new(true)); 118 } 119 120 static uc_value_t * 121 uc_uloop_run(uc_vm_t *vm, size_t nargs) 122 { 123 uc_value_t *timeout = uc_fn_arg(0); 124 int t, rv; 125 126 errno = 0; 127 t = timeout ? (int)ucv_int64_get(timeout) : -1; 128 129 if (errno) 130 err_return(errno); 131 132 rv = uloop_run_timeout(t); 133 134 ok_return(ucv_int64_new(rv)); 135 } 136 137 static uc_value_t * 138 uc_uloop_cancelling(uc_vm_t *vm, size_t nargs) 139 { 140 ok_return(ucv_boolean_new(uloop_cancelling())); 141 } 142 143 static uc_value_t * 144 uc_uloop_running(uc_vm_t *vm, size_t nargs) 145 { 146 bool prev = uloop_cancelled; 147 bool active; 148 149 uloop_cancelled = true; 150 active = uloop_cancelling(); 151 uloop_cancelled = prev; 152 153 ok_return(ucv_boolean_new(active)); 154 } 155 156 static uc_value_t * 157 uc_uloop_end(uc_vm_t *vm, size_t nargs) 158 { 159 uloop_end(); 160 161 ok_return(NULL); 162 } 163 164 static uc_value_t * 165 uc_uloop_done(uc_vm_t *vm, size_t nargs) 166 { 167 uloop_done(); 168 169 ok_return(NULL); 170 } 171 172 173 typedef struct { 174 struct uloop_timeout timeout; 175 size_t registry_index; 176 uc_vm_t *vm; 177 } uc_uloop_timer_t; 178 179 static void 180 uc_uloop_timeout_clear(uc_uloop_timer_t **timer) 181 { 182 /* drop registry entries and clear data to prevent reuse */ 183 uc_uloop_reg_remove((*timer)->registry_index); 184 free(*timer); 185 *timer = NULL; 186 } 187 188 static uc_value_t * 189 uc_uloop_timer_set(uc_vm_t *vm, size_t nargs) 190 { 191 uc_uloop_timer_t **timer = uc_fn_this("uloop.timer"); 192 uc_value_t *timeout = uc_fn_arg(0); 193 int t, rv; 194 195 if (!timer || !*timer) 196 err_return(EINVAL); 197 198 errno = 0; 199 t = timeout ? (int)ucv_int64_get(timeout) : -1; 200 201 if (errno) 202 err_return(errno); 203 204 rv = uloop_timeout_set(&(*timer)->timeout, t); 205 206 ok_return(ucv_boolean_new(rv == 0)); 207 } 208 209 static uc_value_t * 210 uc_uloop_timer_remaining(uc_vm_t *vm, size_t nargs) 211 { 212 uc_uloop_timer_t **timer = uc_fn_this("uloop.timer"); 213 int64_t rem; 214 215 if (!timer || !*timer) 216 err_return(EINVAL); 217 218 #ifdef HAVE_ULOOP_TIMEOUT_REMAINING64 219 rem = uloop_timeout_remaining64(&(*timer)->timeout); 220 #else 221 rem = (int64_t)uloop_timeout_remaining(&(*timer)->timeout); 222 #endif 223 224 ok_return(ucv_int64_new(rem)); 225 } 226 227 static uc_value_t * 228 uc_uloop_timer_cancel(uc_vm_t *vm, size_t nargs) 229 { 230 uc_uloop_timer_t **timer = uc_fn_this("uloop.timer"); 231 int rv; 232 233 if (!timer || !*timer) 234 err_return(EINVAL); 235 236 rv = uloop_timeout_cancel(&(*timer)->timeout); 237 238 uc_uloop_timeout_clear(timer); 239 240 ok_return(ucv_boolean_new(rv == 0)); 241 } 242 243 static void 244 uc_uloop_timer_cb(struct uloop_timeout *timeout) 245 { 246 uc_uloop_timer_t *timer = (uc_uloop_timer_t *)timeout; 247 248 uc_uloop_reg_invoke(timer->vm, timer->registry_index, NULL); 249 } 250 251 static uc_value_t * 252 uc_uloop_timer(uc_vm_t *vm, size_t nargs) 253 { 254 uc_value_t *timeout = uc_fn_arg(0); 255 uc_value_t *callback = uc_fn_arg(1); 256 uc_uloop_timer_t *timer; 257 uc_value_t *res; 258 int t; 259 260 errno = 0; 261 t = timeout ? ucv_int64_get(timeout) : -1; 262 263 if (errno) 264 err_return(errno); 265 266 if (!ucv_is_callable(callback)) 267 err_return(EINVAL); 268 269 timer = xalloc(sizeof(*timer)); 270 timer->timeout.cb = uc_uloop_timer_cb; 271 timer->vm = vm; 272 273 if (t >= 0) 274 uloop_timeout_set(&timer->timeout, t); 275 276 res = uc_resource_new(timer_type, timer); 277 278 timer->registry_index = uc_uloop_reg_add(res, callback); 279 280 ok_return(res); 281 } 282 283 284 typedef struct { 285 struct uloop_fd fd; 286 size_t registry_index; 287 uc_value_t *handle; 288 uc_vm_t *vm; 289 } uc_uloop_handle_t; 290 291 static void 292 uc_uloop_handle_clear(uc_uloop_handle_t **handle) 293 { 294 /* drop registry entries and clear data to prevent reuse */ 295 uc_uloop_reg_remove((*handle)->registry_index); 296 ucv_put((*handle)->handle); 297 free(*handle); 298 *handle = NULL; 299 } 300 301 static uc_value_t * 302 uc_uloop_handle_fileno(uc_vm_t *vm, size_t nargs) 303 { 304 uc_uloop_handle_t **handle = uc_fn_this("uloop.handle"); 305 306 if (!handle || !*handle) 307 err_return(EINVAL); 308 309 ok_return(ucv_int64_new((*handle)->fd.fd)); 310 } 311 312 static uc_value_t * 313 uc_uloop_handle_handle(uc_vm_t *vm, size_t nargs) 314 { 315 uc_uloop_handle_t **handle = uc_fn_this("uloop.handle"); 316 317 if (!handle || !*handle) 318 err_return(EINVAL); 319 320 ok_return(ucv_get((*handle)->handle)); 321 } 322 323 static uc_value_t * 324 uc_uloop_handle_delete(uc_vm_t *vm, size_t nargs) 325 { 326 uc_uloop_handle_t **handle = uc_fn_this("uloop.handle"); 327 int rv; 328 329 if (!handle || !*handle) 330 err_return(EINVAL); 331 332 rv = uloop_fd_delete(&(*handle)->fd); 333 334 uc_uloop_handle_clear(handle); 335 336 if (rv != 0) 337 err_return(errno); 338 339 ok_return(ucv_boolean_new(true)); 340 } 341 342 static void 343 uc_uloop_handle_cb(struct uloop_fd *fd, unsigned int flags) 344 { 345 uc_uloop_handle_t *handle = (uc_uloop_handle_t *)fd; 346 uc_value_t *f = ucv_uint64_new(flags); 347 348 uc_uloop_reg_invoke(handle->vm, handle->registry_index, f); 349 ucv_put(f); 350 } 351 352 static int 353 get_fd(uc_vm_t *vm, uc_value_t *val) 354 { 355 uc_value_t *fn; 356 int64_t n; 357 int fd; 358 359 fn = ucv_property_get(val, "fileno"); 360 361 if (ucv_is_callable(fn)) { 362 uc_vm_stack_push(vm, ucv_get(val)); 363 uc_vm_stack_push(vm, ucv_get(fn)); 364 365 if (uc_vm_call(vm, true, 0) == EXCEPTION_NONE) { 366 val = uc_vm_stack_pop(vm); 367 } 368 else { 369 errno = EBADF; 370 val = NULL; 371 } 372 } 373 else { 374 ucv_get(val); 375 } 376 377 n = ucv_int64_get(val); 378 379 if (errno) { 380 fd = -1; 381 } 382 else if (n < 0 || n > (int64_t)INT_MAX) { 383 errno = EBADF; 384 fd = -1; 385 } 386 else { 387 fd = (int)n; 388 } 389 390 ucv_put(val); 391 392 return fd; 393 } 394 395 static uc_value_t * 396 uc_uloop_handle(uc_vm_t *vm, size_t nargs) 397 { 398 uc_value_t *fileno = uc_fn_arg(0); 399 uc_value_t *callback = uc_fn_arg(1); 400 uc_value_t *flags = uc_fn_arg(2); 401 uc_uloop_handle_t *handle; 402 uc_value_t *res; 403 int fd, ret; 404 uint64_t f; 405 406 fd = get_fd(vm, fileno); 407 408 if (fd == -1) 409 err_return(errno); 410 411 f = ucv_uint64_get(flags); 412 413 if (errno) 414 err_return(errno); 415 416 if (f == 0 || f > (uint64_t)UINT_MAX) 417 err_return(EINVAL); 418 419 if (!ucv_is_callable(callback)) 420 err_return(EINVAL); 421 422 handle = xalloc(sizeof(*handle)); 423 handle->fd.fd = fd; 424 handle->fd.cb = uc_uloop_handle_cb; 425 handle->handle = ucv_get(fileno); 426 handle->vm = vm; 427 428 ret = uloop_fd_add(&handle->fd, (unsigned int)f); 429 430 if (ret != 0) { 431 free(handle); 432 err_return(errno); 433 } 434 435 res = uc_resource_new(handle_type, handle); 436 437 handle->registry_index = uc_uloop_reg_add(res, callback); 438 439 ok_return(res); 440 } 441 442 443 typedef struct { 444 struct uloop_process process; 445 size_t registry_index; 446 uc_vm_t *vm; 447 } uc_uloop_process_t; 448 449 static void 450 uc_uloop_process_clear(uc_uloop_process_t **process) 451 { 452 /* drop registry entries and clear data to prevent reuse */ 453 uc_uloop_reg_remove((*process)->registry_index); 454 *process = NULL; 455 } 456 457 static uc_value_t * 458 uc_uloop_process_pid(uc_vm_t *vm, size_t nargs) 459 { 460 uc_uloop_process_t **process = uc_fn_this("uloop.process"); 461 462 if (!process || !*process) 463 err_return(EINVAL); 464 465 ok_return(ucv_int64_new((*process)->process.pid)); 466 } 467 468 static uc_value_t * 469 uc_uloop_process_delete(uc_vm_t *vm, size_t nargs) 470 { 471 uc_uloop_process_t **process = uc_fn_this("uloop.process"); 472 int rv; 473 474 if (!process || !*process) 475 err_return(EINVAL); 476 477 rv = uloop_process_delete(&(*process)->process); 478 479 uc_uloop_process_clear(process); 480 481 if (rv != 0) 482 err_return(EINVAL); 483 484 ok_return(ucv_boolean_new(true)); 485 } 486 487 static void 488 uc_uloop_process_cb(struct uloop_process *proc, int exitcode) 489 { 490 uc_uloop_process_t *process = (uc_uloop_process_t *)proc; 491 uc_value_t *e = ucv_int64_new(exitcode >> 8); 492 493 uc_uloop_reg_invoke(process->vm, process->registry_index, e); 494 uc_uloop_process_clear(&process); 495 ucv_put(e); 496 } 497 498 static uc_value_t * 499 uc_uloop_process(uc_vm_t *vm, size_t nargs) 500 { 501 uc_value_t *executable = uc_fn_arg(0); 502 uc_value_t *arguments = uc_fn_arg(1); 503 uc_value_t *env_arg = uc_fn_arg(2); 504 uc_value_t *callback = uc_fn_arg(3); 505 uc_uloop_process_t *process; 506 uc_stringbuf_t *buf; 507 char **argp, **envp; 508 uc_value_t *res; 509 pid_t pid; 510 size_t i; 511 512 if (ucv_type(executable) != UC_STRING || 513 (arguments && ucv_type(arguments) != UC_ARRAY) || 514 (env_arg && ucv_type(env_arg) != UC_OBJECT) || 515 !ucv_is_callable(callback)) { 516 err_return(EINVAL); 517 } 518 519 pid = fork(); 520 521 if (pid == -1) 522 err_return(errno); 523 524 if (pid == 0) { 525 argp = calloc(ucv_array_length(arguments) + 2, sizeof(char *)); 526 envp = calloc(ucv_object_length(env_arg) + 1, sizeof(char *)); 527 528 if (!argp || !envp) 529 _exit(-1); 530 531 argp[0] = ucv_to_string(vm, executable); 532 533 for (i = 0; i < ucv_array_length(arguments); i++) 534 argp[i+1] = ucv_to_string(vm, ucv_array_get(arguments, i)); 535 536 i = 0; 537 538 ucv_object_foreach(env_arg, envk, envv) { 539 buf = xprintbuf_new(); 540 541 ucv_stringbuf_printf(buf, "%s=", envk); 542 ucv_to_stringbuf(vm, buf, envv, false); 543 544 envp[i++] = buf->buf; 545 546 free(buf); 547 } 548 549 execvpe((const char *)ucv_string_get(executable), 550 (char * const *)argp, (char * const *)envp); 551 552 _exit(-1); 553 } 554 555 process = xalloc(sizeof(*process)); 556 process->process.pid = pid; 557 process->process.cb = uc_uloop_process_cb; 558 process->vm = vm; 559 560 uloop_process_add(&process->process); 561 562 res = uc_resource_new(process_type, process); 563 564 process->registry_index = uc_uloop_reg_add(res, callback); 565 566 ok_return(res); 567 } 568 569 570 static bool 571 readall(int fd, void *buf, size_t len) 572 { 573 ssize_t rlen; 574 575 while (len > 0) { 576 rlen = read(fd, buf, len); 577 578 if (rlen == -1) { 579 if (errno == EINTR) 580 continue; 581 582 return false; 583 } 584 585 if (rlen == 0) { 586 errno = EINTR; 587 588 return false; 589 } 590 591 buf += rlen; 592 len -= rlen; 593 } 594 595 return true; 596 } 597 598 static bool 599 writeall(int fd, void *buf, size_t len) 600 { 601 ssize_t wlen; 602 603 while (len > 0) { 604 wlen = write(fd, buf, len); 605 606 if (wlen == -1) { 607 if (errno == EINTR) 608 continue; 609 610 return false; 611 } 612 613 buf += wlen; 614 len -= wlen; 615 } 616 617 return true; 618 } 619 620 typedef struct { 621 int input; 622 int output; 623 bool has_sender; 624 bool has_receiver; 625 } uc_uloop_pipe_t; 626 627 static uc_value_t * 628 uc_uloop_pipe_send_common(uc_vm_t *vm, uc_value_t *msg, int fd) 629 { 630 uc_stringbuf_t *buf; 631 size_t len; 632 bool rv; 633 634 buf = xprintbuf_new(); 635 636 printbuf_memset(buf, 0, 0, sizeof(len)); 637 ucv_to_stringbuf(vm, buf, msg, true); 638 639 len = printbuf_length(buf); 640 memcpy(buf->buf, &len, sizeof(len)); 641 642 rv = writeall(fd, buf->buf, len); 643 644 printbuf_free(buf); 645 646 if (!rv) 647 err_return(errno); 648 649 ok_return(ucv_boolean_new(true)); 650 } 651 652 static uc_value_t * 653 uc_uloop_pipe_send(uc_vm_t *vm, size_t nargs) 654 { 655 uc_uloop_pipe_t **pipe = uc_fn_this("uloop.pipe"); 656 uc_value_t *msg = uc_fn_arg(0); 657 658 if (!pipe || !*pipe) 659 err_return(EINVAL); 660 661 if (!(*pipe)->has_receiver) 662 err_return(EPIPE); 663 664 ok_return(uc_uloop_pipe_send_common(vm, msg, (*pipe)->output)); 665 } 666 667 static bool 668 uc_uloop_pipe_receive_common(uc_vm_t *vm, int fd, uc_value_t **res, bool skip) 669 { 670 enum json_tokener_error err = json_tokener_error_parse_eof; 671 json_tokener *tok = NULL; 672 json_object *jso = NULL; 673 char buf[1024]; 674 ssize_t rlen; 675 size_t len; 676 677 *res = NULL; 678 679 if (!readall(fd, &len, sizeof(len))) 680 err_return(errno); 681 682 /* message length 0 is special, means input requested on other pipe */ 683 if (len == 0) 684 err_return(ENODATA); 685 686 /* valid messages should be at least sizeof(len) plus one byte of payload */ 687 if (len <= sizeof(len)) 688 err_return(EINVAL); 689 690 len -= sizeof(len); 691 692 while (len > 0) { 693 rlen = read(fd, buf, len < sizeof(buf) ? len : sizeof(buf)); 694 695 if (rlen == -1) { 696 if (errno == EINTR) 697 continue; 698 699 goto read_fail; 700 } 701 702 /* premature EOF */ 703 if (rlen == 0) { 704 errno = EPIPE; 705 goto read_fail; 706 } 707 708 if (!skip) { 709 if (!tok) 710 tok = xjs_new_tokener(); 711 712 jso = json_tokener_parse_ex(tok, buf, rlen); 713 err = json_tokener_get_error(tok); 714 } 715 716 len -= rlen; 717 } 718 719 if (!skip) { 720 if (err == json_tokener_continue) { 721 jso = json_tokener_parse_ex(tok, "\0", 1); 722 err = json_tokener_get_error(tok); 723 } 724 725 json_tokener_free(tok); 726 727 if (err != json_tokener_success) { 728 errno = EINVAL; 729 goto read_fail; 730 } 731 732 *res = ucv_from_json(vm, jso); 733 734 json_object_put(jso); 735 } 736 737 return true; 738 739 read_fail: 740 if (tok) 741 json_tokener_free(tok); 742 743 json_object_put(jso); 744 err_return(errno); 745 } 746 747 static uc_value_t * 748 uc_uloop_pipe_receive(uc_vm_t *vm, size_t nargs) 749 { 750 uc_uloop_pipe_t **pipe = uc_fn_this("uloop.pipe"); 751 uc_value_t *rv; 752 size_t len = 0; 753 754 if (!pipe || !*pipe) 755 err_return(EINVAL); 756 757 if (!(*pipe)->has_sender) 758 err_return(EPIPE); 759 760 /* send zero-length message to signal input request */ 761 writeall((*pipe)->output, &len, sizeof(len)); 762 763 /* receive input message */ 764 uc_uloop_pipe_receive_common(vm, (*pipe)->input, &rv, false); 765 766 return rv; 767 } 768 769 static uc_value_t * 770 uc_uloop_pipe_sending(uc_vm_t *vm, size_t nargs) 771 { 772 uc_uloop_pipe_t **pipe = uc_fn_this("uloop.pipe"); 773 774 if (!pipe || !*pipe) 775 err_return(EINVAL); 776 777 ok_return(ucv_boolean_new((*pipe)->has_sender)); 778 } 779 780 static uc_value_t * 781 uc_uloop_pipe_receiving(uc_vm_t *vm, size_t nargs) 782 { 783 uc_uloop_pipe_t **pipe = uc_fn_this("uloop.pipe"); 784 785 if (!pipe || !*pipe) 786 err_return(EINVAL); 787 788 ok_return(ucv_boolean_new((*pipe)->has_receiver)); 789 } 790 791 792 typedef struct { 793 struct uloop_process process; 794 struct uloop_fd output; 795 size_t registry_index; 796 bool finished; 797 int input_fd; 798 uc_vm_t *vm; 799 uc_value_t *input_cb; 800 uc_value_t *output_cb; 801 } uc_uloop_task_t; 802 803 static int 804 patch_devnull(int fd, bool write) 805 { 806 int devnull = open("/dev/null", write ? O_WRONLY : O_RDONLY); 807 808 if (devnull != -1) { 809 dup2(fd, devnull); 810 close(fd); 811 } 812 813 return devnull; 814 } 815 816 static void 817 uloop_fd_close(struct uloop_fd *fd) { 818 if (fd->fd == -1) 819 return; 820 821 close(fd->fd); 822 fd->fd = -1; 823 } 824 825 static void 826 uc_uloop_task_clear(uc_uloop_task_t **task) 827 { 828 /* drop registry entries and clear data to prevent reuse */ 829 uc_uloop_reg_remove((*task)->registry_index); 830 *task = NULL; 831 } 832 833 static uc_value_t * 834 uc_uloop_task_pid(uc_vm_t *vm, size_t nargs) 835 { 836 uc_uloop_task_t **task = uc_fn_this("uloop.task"); 837 838 if (!task || !*task) 839 err_return(EINVAL); 840 841 if ((*task)->finished) 842 err_return(ESRCH); 843 844 ok_return(ucv_int64_new((*task)->process.pid)); 845 } 846 847 static uc_value_t * 848 uc_uloop_task_kill(uc_vm_t *vm, size_t nargs) 849 { 850 uc_uloop_task_t **task = uc_fn_this("uloop.task"); 851 int rv; 852 853 if (!task || !*task) 854 err_return(EINVAL); 855 856 if ((*task)->finished) 857 err_return(ESRCH); 858 859 rv = kill((*task)->process.pid, SIGTERM); 860 861 if (rv == -1) 862 err_return(errno); 863 864 ok_return(ucv_boolean_new(true)); 865 } 866 867 static uc_value_t * 868 uc_uloop_task_finished(uc_vm_t *vm, size_t nargs) 869 { 870 uc_uloop_task_t **task = uc_fn_this("uloop.task"); 871 872 if (!task || !*task) 873 err_return(EINVAL); 874 875 ok_return(ucv_boolean_new((*task)->finished)); 876 } 877 878 static void 879 uc_uloop_task_output_cb(struct uloop_fd *fd, unsigned int flags) 880 { 881 uc_uloop_task_t *task = container_of(fd, uc_uloop_task_t, output); 882 uc_value_t *obj = ucv_array_get(object_registry, task->registry_index); 883 uc_value_t *msg = NULL; 884 885 if (flags & ULOOP_READ) { 886 while (true) { 887 if (!uc_uloop_pipe_receive_common(task->vm, fd->fd, &msg, !task->output_cb)) { 888 /* input requested */ 889 if (last_error == ENODATA) { 890 uc_vm_stack_push(task->vm, ucv_get(obj)); 891 uc_vm_stack_push(task->vm, ucv_get(task->input_cb)); 892 893 if (uc_vm_call(task->vm, true, 0) != EXCEPTION_NONE) { 894 uloop_end(); 895 896 return; 897 } 898 899 msg = uc_vm_stack_pop(task->vm); 900 uc_uloop_pipe_send_common(task->vm, msg, task->input_fd); 901 ucv_put(msg); 902 903 continue; 904 } 905 906 /* error */ 907 break; 908 } 909 910 if (task->output_cb) { 911 uc_vm_stack_push(task->vm, ucv_get(obj)); 912 uc_vm_stack_push(task->vm, ucv_get(task->output_cb)); 913 uc_vm_stack_push(task->vm, msg); 914 915 if (uc_vm_call(task->vm, true, 1) == EXCEPTION_NONE) { 916 ucv_put(uc_vm_stack_pop(task->vm)); 917 } 918 else { 919 uloop_end(); 920 921 return; 922 } 923 } 924 else { 925 ucv_put(msg); 926 } 927 } 928 } 929 930 if (!fd->registered && task->finished) { 931 close(task->input_fd); 932 task->input_fd = -1; 933 934 uloop_fd_close(&task->output); 935 uloop_process_delete(&task->process); 936 937 uc_uloop_task_clear(&task); 938 } 939 } 940 941 static void 942 uc_uloop_task_process_cb(struct uloop_process *proc, int exitcode) 943 { 944 uc_uloop_task_t *task = container_of(proc, uc_uloop_task_t, process); 945 946 task->finished = true; 947 948 uc_uloop_task_output_cb(&task->output, ULOOP_READ); 949 } 950 951 static uc_value_t * 952 uc_uloop_task(uc_vm_t *vm, size_t nargs) 953 { 954 uc_value_t *func = uc_fn_arg(0); 955 uc_value_t *output_cb = uc_fn_arg(1); 956 uc_value_t *input_cb = uc_fn_arg(2); 957 int outpipe[2] = { -1, -1 }; 958 int inpipe[2] = { -1, -1 }; 959 uc_value_t *res, *cbs, *p; 960 uc_uloop_pipe_t *tpipe; 961 uc_uloop_task_t *task; 962 pid_t pid; 963 int err; 964 965 if (!ucv_is_callable(func) || 966 (output_cb && !ucv_is_callable(output_cb)) || 967 (input_cb && !ucv_is_callable(input_cb))) 968 err_return(EINVAL); 969 970 if (pipe(outpipe) == -1 || pipe(inpipe) == -1) { 971 err = errno; 972 973 close(outpipe[0]); close(outpipe[1]); 974 close(inpipe[0]); close(inpipe[1]); 975 976 err_return(err); 977 } 978 979 pid = fork(); 980 981 if (pid == -1) 982 err_return(errno); 983 984 if (pid == 0) { 985 uloop_done(); 986 987 patch_devnull(0, false); 988 patch_devnull(1, true); 989 patch_devnull(2, true); 990 991 vm->output = fdopen(1, "w"); 992 993 close(inpipe[1]); 994 close(outpipe[0]); 995 996 tpipe = xalloc(sizeof(*tpipe)); 997 tpipe->input = inpipe[0]; 998 tpipe->output = outpipe[1]; 999 tpipe->has_sender = input_cb; 1000 tpipe->has_receiver = output_cb; 1001 1002 p = uc_resource_new(pipe_type, tpipe); 1003 1004 uc_vm_stack_push(vm, func); 1005 uc_vm_stack_push(vm, ucv_get(p)); 1006 1007 if (uc_vm_call(vm, false, 1) == EXCEPTION_NONE) { 1008 res = uc_vm_stack_pop(vm); 1009 uc_uloop_pipe_send_common(vm, res, tpipe->output); 1010 ucv_put(res); 1011 } 1012 1013 ucv_put(p); 1014 1015 _exit(0); 1016 } 1017 1018 close(inpipe[0]); 1019 close(outpipe[1]); 1020 1021 task = xalloc(sizeof(*task)); 1022 task->process.pid = pid; 1023 task->process.cb = uc_uloop_task_process_cb; 1024 1025 task->vm = vm; 1026 1027 task->output.fd = outpipe[0]; 1028 task->output.cb = uc_uloop_task_output_cb; 1029 task->output_cb = output_cb; 1030 uloop_fd_add(&task->output, ULOOP_READ); 1031 1032 if (input_cb) { 1033 task->input_fd = inpipe[1]; 1034 task->input_cb = input_cb; 1035 } 1036 else { 1037 task->input_fd = -1; 1038 close(inpipe[1]); 1039 } 1040 1041 uloop_process_add(&task->process); 1042 1043 res = uc_resource_new(task_type, task); 1044 1045 cbs = ucv_array_new(NULL); 1046 ucv_array_set(cbs, 0, ucv_get(output_cb)); 1047 ucv_array_set(cbs, 1, ucv_get(input_cb)); 1048 1049 task->registry_index = uc_uloop_reg_add(res, cbs); 1050 1051 ok_return(res); 1052 } 1053 1054 1055 #ifdef HAVE_ULOOP_INTERVAL 1056 typedef struct { 1057 struct uloop_interval interval; 1058 size_t registry_index; 1059 uc_vm_t *vm; 1060 } uc_uloop_interval_t; 1061 1062 static void 1063 uc_uloop_interval_clear(uc_uloop_interval_t **interval) 1064 { 1065 /* drop registry entries and clear data to prevent reuse */ 1066 uc_uloop_reg_remove((*interval)->registry_index); 1067 free(*interval); 1068 *interval = NULL; 1069 } 1070 1071 static uc_value_t * 1072 uc_uloop_interval_set(uc_vm_t *vm, size_t nargs) 1073 { 1074 uc_uloop_interval_t **interval = uc_fn_this("uloop.interval"); 1075 uc_value_t *timeout = uc_fn_arg(0); 1076 int t, rv; 1077 1078 if (!interval || !*interval) 1079 err_return(EINVAL); 1080 1081 errno = 0; 1082 t = timeout ? (int)ucv_int64_get(timeout) : -1; 1083 1084 if (errno) 1085 err_return(errno); 1086 1087 rv = uloop_interval_set(&(*interval)->interval, t); 1088 1089 ok_return(ucv_boolean_new(rv == 0)); 1090 } 1091 1092 static uc_value_t * 1093 uc_uloop_interval_remaining(uc_vm_t *vm, size_t nargs) 1094 { 1095 uc_uloop_interval_t **interval = uc_fn_this("uloop.interval"); 1096 1097 if (!interval || !*interval) 1098 err_return(EINVAL); 1099 1100 ok_return(ucv_int64_new(uloop_interval_remaining(&(*interval)->interval))); 1101 } 1102 1103 static uc_value_t * 1104 uc_uloop_interval_expirations(uc_vm_t *vm, size_t nargs) 1105 { 1106 uc_uloop_interval_t **interval = uc_fn_this("uloop.interval"); 1107 1108 if (!interval || !*interval) 1109 err_return(EINVAL); 1110 1111 ok_return(ucv_int64_new((*interval)->interval.expirations)); 1112 } 1113 1114 static uc_value_t * 1115 uc_uloop_interval_cancel(uc_vm_t *vm, size_t nargs) 1116 { 1117 uc_uloop_interval_t **interval = uc_fn_this("uloop.interval"); 1118 int rv; 1119 1120 if (!interval || !*interval) 1121 err_return(EINVAL); 1122 1123 rv = uloop_interval_cancel(&(*interval)->interval); 1124 1125 uc_uloop_interval_clear(interval); 1126 1127 ok_return(ucv_boolean_new(rv == 0)); 1128 } 1129 1130 static void 1131 uc_uloop_interval_cb(struct uloop_interval *uintv) 1132 { 1133 uc_uloop_interval_t *interval = (uc_uloop_interval_t *)uintv; 1134 1135 uc_uloop_reg_invoke(interval->vm, interval->registry_index, NULL); 1136 } 1137 1138 static uc_value_t * 1139 uc_uloop_interval(uc_vm_t *vm, size_t nargs) 1140 { 1141 uc_value_t *timeout = uc_fn_arg(0); 1142 uc_value_t *callback = uc_fn_arg(1); 1143 uc_uloop_interval_t *interval; 1144 uc_value_t *res; 1145 int t; 1146 1147 errno = 0; 1148 t = timeout ? ucv_int64_get(timeout) : -1; 1149 1150 if (errno) 1151 err_return(errno); 1152 1153 if (!ucv_is_callable(callback)) 1154 err_return(EINVAL); 1155 1156 interval = xalloc(sizeof(*interval)); 1157 interval->interval.cb = uc_uloop_interval_cb; 1158 interval->vm = vm; 1159 1160 if (t >= 0) 1161 uloop_interval_set(&interval->interval, t); 1162 1163 res = uc_resource_new(interval_type, interval); 1164 1165 interval->registry_index = uc_uloop_reg_add(res, callback); 1166 1167 ok_return(res); 1168 } 1169 #endif 1170 1171 #ifdef HAVE_ULOOP_SIGNAL 1172 typedef struct { 1173 struct uloop_signal signal; 1174 size_t registry_index; 1175 uc_vm_t *vm; 1176 } uc_uloop_signal_t; 1177 1178 static void 1179 uc_uloop_signal_clear(uc_uloop_signal_t **signal) 1180 { 1181 /* drop registry entries and clear data to prevent reuse */ 1182 uc_uloop_reg_remove((*signal)->registry_index); 1183 free(*signal); 1184 *signal = NULL; 1185 } 1186 1187 static uc_value_t * 1188 uc_uloop_signal_signo(uc_vm_t *vm, size_t nargs) 1189 { 1190 uc_uloop_signal_t **signal = uc_fn_this("uloop.signal"); 1191 1192 if (!signal || !*signal) 1193 err_return(EINVAL); 1194 1195 ok_return(ucv_int64_new((*signal)->signal.signo)); 1196 } 1197 1198 static uc_value_t * 1199 uc_uloop_signal_delete(uc_vm_t *vm, size_t nargs) 1200 { 1201 uc_uloop_signal_t **signal = uc_fn_this("uloop.signal"); 1202 int rv; 1203 1204 if (!signal || !*signal) 1205 err_return(EINVAL); 1206 1207 rv = uloop_signal_delete(&(*signal)->signal); 1208 1209 uc_uloop_signal_clear(signal); 1210 1211 if (rv != 0) 1212 err_return(EINVAL); 1213 1214 ok_return(ucv_boolean_new(true)); 1215 } 1216 1217 static void 1218 uc_uloop_signal_cb(struct uloop_signal *usig) 1219 { 1220 uc_uloop_signal_t *signal = (uc_uloop_signal_t *)usig; 1221 1222 uc_uloop_reg_invoke(signal->vm, signal->registry_index, NULL); 1223 } 1224 1225 static int 1226 parse_signo(uc_value_t *sigspec) 1227 { 1228 if (ucv_type(sigspec) == UC_STRING) { 1229 const char *signame = ucv_string_get(sigspec); 1230 1231 if (!strncasecmp(signame, "SIG", 3)) 1232 signame += 3; 1233 1234 for (size_t i = 0; i < UC_SYSTEM_SIGNAL_COUNT; i++) { 1235 if (!uc_system_signal_names[i]) 1236 continue; 1237 1238 if (strcasecmp(uc_system_signal_names[i], signame)) 1239 continue; 1240 1241 return i; 1242 } 1243 } 1244 1245 uc_value_t *signum = ucv_to_number(sigspec); 1246 int64_t signo = ucv_int64_get(signum); 1247 ucv_put(signum); 1248 1249 if (signo < 1 || signo >= UC_SYSTEM_SIGNAL_COUNT) 1250 return -1; 1251 1252 return signo; 1253 } 1254 1255 static uc_value_t * 1256 uc_uloop_signal(uc_vm_t *vm, size_t nargs) 1257 { 1258 int signo = parse_signo(uc_fn_arg(0)); 1259 uc_value_t *callback = uc_fn_arg(1); 1260 uc_uloop_signal_t *signal; 1261 uc_value_t *res; 1262 1263 if (signo == -1 || !ucv_is_callable(callback)) 1264 err_return(EINVAL); 1265 1266 signal = xalloc(sizeof(*signal)); 1267 signal->signal.signo = signo; 1268 signal->signal.cb = uc_uloop_signal_cb; 1269 signal->vm = vm; 1270 1271 uloop_signal_add(&signal->signal); 1272 1273 res = uc_resource_new(signal_type, signal); 1274 1275 signal->registry_index = uc_uloop_reg_add(res, callback); 1276 1277 ok_return(res); 1278 } 1279 #endif 1280 1281 1282 static const uc_function_list_t timer_fns[] = { 1283 { "set", uc_uloop_timer_set }, 1284 { "remaining", uc_uloop_timer_remaining }, 1285 { "cancel", uc_uloop_timer_cancel }, 1286 }; 1287 1288 static const uc_function_list_t handle_fns[] = { 1289 { "fileno", uc_uloop_handle_fileno }, 1290 { "handle", uc_uloop_handle_handle }, 1291 { "delete", uc_uloop_handle_delete }, 1292 }; 1293 1294 static const uc_function_list_t process_fns[] = { 1295 { "pid", uc_uloop_process_pid }, 1296 { "delete", uc_uloop_process_delete }, 1297 }; 1298 1299 static const uc_function_list_t task_fns[] = { 1300 { "pid", uc_uloop_task_pid }, 1301 { "kill", uc_uloop_task_kill }, 1302 { "finished", uc_uloop_task_finished }, 1303 }; 1304 1305 static const uc_function_list_t pipe_fns[] = { 1306 { "send", uc_uloop_pipe_send }, 1307 { "receive", uc_uloop_pipe_receive }, 1308 { "sending", uc_uloop_pipe_sending }, 1309 { "receiving", uc_uloop_pipe_receiving }, 1310 }; 1311 1312 #ifdef HAVE_ULOOP_INTERVAL 1313 static const uc_function_list_t interval_fns[] = { 1314 { "set", uc_uloop_interval_set }, 1315 { "remaining", uc_uloop_interval_remaining }, 1316 { "expirations", 1317 uc_uloop_interval_expirations }, 1318 { "cancel", uc_uloop_interval_cancel }, 1319 }; 1320 #endif 1321 1322 #ifdef HAVE_ULOOP_SIGNAL 1323 static const uc_function_list_t signal_fns[] = { 1324 { "signo", uc_uloop_signal_signo }, 1325 { "delete", uc_uloop_signal_delete }, 1326 }; 1327 #endif 1328 1329 static const uc_function_list_t global_fns[] = { 1330 { "error", uc_uloop_error }, 1331 { "init", uc_uloop_init }, 1332 { "run", uc_uloop_run }, 1333 { "timer", uc_uloop_timer }, 1334 { "handle", uc_uloop_handle }, 1335 { "process", uc_uloop_process }, 1336 { "task", uc_uloop_task }, 1337 { "cancelling", uc_uloop_cancelling }, 1338 { "running", uc_uloop_running }, 1339 { "done", uc_uloop_done }, 1340 { "end", uc_uloop_end }, 1341 #ifdef HAVE_ULOOP_INTERVAL 1342 { "interval", uc_uloop_interval }, 1343 #endif 1344 #ifdef HAVE_ULOOP_SIGNAL 1345 { "signal", uc_uloop_signal }, 1346 #endif 1347 }; 1348 1349 1350 static void close_timer(void *ud) 1351 { 1352 uc_uloop_timer_t *timer = ud; 1353 1354 if (!timer) 1355 return; 1356 1357 uloop_timeout_cancel(&timer->timeout); 1358 free(timer); 1359 } 1360 1361 static void close_handle(void *ud) 1362 { 1363 uc_uloop_handle_t *handle = ud; 1364 1365 if (!handle) 1366 return; 1367 1368 uloop_fd_delete(&handle->fd); 1369 ucv_put(handle->handle); 1370 free(handle); 1371 } 1372 1373 static void close_process(void *ud) 1374 { 1375 uc_uloop_process_t *process = ud; 1376 1377 if (!process) 1378 return; 1379 1380 uloop_process_delete(&process->process); 1381 free(process); 1382 } 1383 1384 static void close_task(void *ud) 1385 { 1386 uc_uloop_task_t *task = ud; 1387 1388 if (!task) 1389 return; 1390 1391 uloop_process_delete(&task->process); 1392 uloop_fd_close(&task->output); 1393 1394 if (task->input_fd != -1) 1395 close(task->input_fd); 1396 1397 free(task); 1398 } 1399 1400 static void close_pipe(void *ud) 1401 { 1402 uc_uloop_pipe_t *pipe = ud; 1403 1404 if (!pipe) 1405 return; 1406 1407 close(pipe->input); 1408 close(pipe->output); 1409 1410 free(pipe); 1411 } 1412 1413 #ifdef HAVE_ULOOP_INTERVAL 1414 static void close_interval(void *ud) 1415 { 1416 uc_uloop_interval_t *interval = ud; 1417 1418 if (!interval) 1419 return; 1420 1421 uloop_interval_cancel(&interval->interval); 1422 free(interval); 1423 } 1424 #endif 1425 1426 #ifdef HAVE_ULOOP_SIGNAL 1427 static void close_signal(void *ud) 1428 { 1429 uc_uloop_signal_t *signal = ud; 1430 1431 if (!signal) 1432 return; 1433 1434 uloop_signal_delete(&signal->signal); 1435 free(signal); 1436 } 1437 #endif 1438 1439 1440 static struct { 1441 struct uloop_fd ufd; 1442 uc_vm_t *vm; 1443 } signal_handle; 1444 1445 static void 1446 uc_uloop_vm_signal_cb(struct uloop_fd *ufd, unsigned int events) 1447 { 1448 if (uc_vm_signal_dispatch(signal_handle.vm) != EXCEPTION_NONE) 1449 uloop_end(); 1450 } 1451 1452 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 1453 { 1454 int signal_fd; 1455 1456 uc_function_list_register(scope, global_fns); 1457 1458 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(x)) 1459 1460 ADD_CONST(ULOOP_READ); 1461 ADD_CONST(ULOOP_WRITE); 1462 ADD_CONST(ULOOP_EDGE_TRIGGER); 1463 ADD_CONST(ULOOP_BLOCKING); 1464 1465 timer_type = uc_type_declare(vm, "uloop.timer", timer_fns, close_timer); 1466 handle_type = uc_type_declare(vm, "uloop.handle", handle_fns, close_handle); 1467 process_type = uc_type_declare(vm, "uloop.process", process_fns, close_process); 1468 task_type = uc_type_declare(vm, "uloop.task", task_fns, close_task); 1469 pipe_type = uc_type_declare(vm, "uloop.pipe", pipe_fns, close_pipe); 1470 1471 #ifdef HAVE_ULOOP_INTERVAL 1472 interval_type = uc_type_declare(vm, "uloop.interval", interval_fns, close_interval); 1473 #endif 1474 1475 #ifdef HAVE_ULOOP_SIGNAL 1476 signal_type = uc_type_declare(vm, "uloop.signal", signal_fns, close_signal); 1477 #endif 1478 1479 object_registry = ucv_array_new(vm); 1480 1481 uc_vm_registry_set(vm, "uloop.registry", object_registry); 1482 1483 signal_fd = uc_vm_signal_notifyfd(vm); 1484 1485 if (signal_fd != -1 && uloop_init() == 0) { 1486 signal_handle.vm = vm; 1487 signal_handle.ufd.cb = uc_uloop_vm_signal_cb; 1488 signal_handle.ufd.fd = signal_fd; 1489 1490 uloop_fd_add(&signal_handle.ufd, ULOOP_READ); 1491 } 1492 } 1493
This page was automatically generated by LXR 0.3.1. • OpenWrt