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 27 #define err_return(err) do { last_error = err; return NULL; } while(0) 28 29 static uc_resource_type_t *timer_type, *handle_type, *process_type, *task_type, *pipe_type; 30 static uc_value_t *object_registry; 31 32 static int last_error = 0; 33 34 static size_t 35 uc_uloop_reg_add(uc_value_t *obj, uc_value_t *cb) 36 { 37 size_t i = 0; 38 39 while (ucv_array_get(object_registry, i)) 40 i += 2; 41 42 ucv_array_set(object_registry, i + 0, ucv_get(obj)); 43 ucv_array_set(object_registry, i + 1, ucv_get(cb)); 44 45 return i; 46 } 47 48 static bool 49 uc_uloop_reg_remove(size_t i) 50 { 51 if (i + 1 >= ucv_array_length(object_registry)) 52 return false; 53 54 ucv_array_set(object_registry, i + 0, NULL); 55 ucv_array_set(object_registry, i + 1, NULL); 56 57 return true; 58 } 59 60 static bool 61 uc_uloop_reg_invoke(uc_vm_t *vm, size_t i, uc_value_t *arg) 62 { 63 uc_value_t *obj = ucv_array_get(object_registry, i + 0); 64 uc_value_t *cb = ucv_array_get(object_registry, i + 1); 65 66 if (!ucv_is_callable(cb)) 67 return false; 68 69 uc_vm_stack_push(vm, ucv_get(obj)); 70 uc_vm_stack_push(vm, ucv_get(cb)); 71 uc_vm_stack_push(vm, ucv_get(arg)); 72 73 if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) { 74 uloop_end(); 75 76 return false; 77 } 78 79 ucv_put(uc_vm_stack_pop(vm)); 80 81 return true; 82 } 83 84 static uc_value_t * 85 uc_uloop_error(uc_vm_t *vm, size_t nargs) 86 { 87 uc_value_t *errmsg; 88 89 if (last_error == 0) 90 return NULL; 91 92 errmsg = ucv_string_new(strerror(last_error)); 93 last_error = 0; 94 95 return errmsg; 96 } 97 98 static uc_value_t * 99 uc_uloop_init(uc_vm_t *vm, size_t nargs) 100 { 101 int rv = uloop_init(); 102 103 if (rv == -1) 104 err_return(errno); 105 106 return ucv_boolean_new(true); 107 } 108 109 static uc_value_t * 110 uc_uloop_run(uc_vm_t *vm, size_t nargs) 111 { 112 uc_value_t *timeout = uc_fn_arg(0); 113 int t, rv; 114 115 errno = 0; 116 t = timeout ? (int)ucv_int64_get(timeout) : -1; 117 118 if (errno) 119 err_return(errno); 120 121 rv = uloop_run_timeout(t); 122 123 return ucv_int64_new(rv); 124 } 125 126 static uc_value_t * 127 uc_uloop_cancelling(uc_vm_t *vm, size_t nargs) 128 { 129 return ucv_boolean_new(uloop_cancelling()); 130 } 131 132 static uc_value_t * 133 uc_uloop_running(uc_vm_t *vm, size_t nargs) 134 { 135 bool prev = uloop_cancelled; 136 bool active; 137 138 uloop_cancelled = true; 139 active = uloop_cancelling(); 140 uloop_cancelled = prev; 141 142 return ucv_boolean_new(active); 143 } 144 145 static uc_value_t * 146 uc_uloop_end(uc_vm_t *vm, size_t nargs) 147 { 148 uloop_end(); 149 150 return NULL; 151 } 152 153 static uc_value_t * 154 uc_uloop_done(uc_vm_t *vm, size_t nargs) 155 { 156 uloop_done(); 157 158 return NULL; 159 } 160 161 162 typedef struct { 163 struct uloop_timeout timeout; 164 size_t registry_index; 165 uc_vm_t *vm; 166 } uc_uloop_timer_t; 167 168 static void 169 uc_uloop_timeout_clear(uc_uloop_timer_t **timer) 170 { 171 /* drop registry entries and clear data to prevent reuse */ 172 uc_uloop_reg_remove((*timer)->registry_index); 173 free(*timer); 174 *timer = NULL; 175 } 176 177 static uc_value_t * 178 uc_uloop_timer_set(uc_vm_t *vm, size_t nargs) 179 { 180 uc_uloop_timer_t **timer = uc_fn_this("uloop.timer"); 181 uc_value_t *timeout = uc_fn_arg(0); 182 int t, rv; 183 184 if (!timer || !*timer) 185 err_return(EINVAL); 186 187 errno = 0; 188 t = timeout ? (int)ucv_int64_get(timeout) : -1; 189 190 if (errno) 191 err_return(errno); 192 193 rv = uloop_timeout_set(&(*timer)->timeout, t); 194 195 return ucv_boolean_new(rv == 0); 196 } 197 198 static uc_value_t * 199 uc_uloop_timer_remaining(uc_vm_t *vm, size_t nargs) 200 { 201 uc_uloop_timer_t **timer = uc_fn_this("uloop.timer"); 202 int64_t rem; 203 204 if (!timer || !*timer) 205 err_return(EINVAL); 206 207 #ifdef HAVE_ULOOP_TIMEOUT_REMAINING64 208 rem = uloop_timeout_remaining64(&(*timer)->timeout); 209 #else 210 rem = (int64_t)uloop_timeout_remaining(&(*timer)->timeout); 211 #endif 212 213 return ucv_int64_new(rem); 214 } 215 216 static uc_value_t * 217 uc_uloop_timer_cancel(uc_vm_t *vm, size_t nargs) 218 { 219 uc_uloop_timer_t **timer = uc_fn_this("uloop.timer"); 220 int rv; 221 222 if (!timer || !*timer) 223 err_return(EINVAL); 224 225 rv = uloop_timeout_cancel(&(*timer)->timeout); 226 227 uc_uloop_timeout_clear(timer); 228 229 return ucv_boolean_new(rv == 0); 230 } 231 232 static void 233 uc_uloop_timer_cb(struct uloop_timeout *timeout) 234 { 235 uc_uloop_timer_t *timer = (uc_uloop_timer_t *)timeout; 236 237 uc_uloop_reg_invoke(timer->vm, timer->registry_index, NULL); 238 } 239 240 static uc_value_t * 241 uc_uloop_timer(uc_vm_t *vm, size_t nargs) 242 { 243 uc_value_t *timeout = uc_fn_arg(0); 244 uc_value_t *callback = uc_fn_arg(1); 245 uc_uloop_timer_t *timer; 246 uc_value_t *res; 247 int t; 248 249 errno = 0; 250 t = timeout ? ucv_int64_get(timeout) : -1; 251 252 if (errno) 253 err_return(errno); 254 255 if (!ucv_is_callable(callback)) 256 err_return(EINVAL); 257 258 timer = xalloc(sizeof(*timer)); 259 timer->timeout.cb = uc_uloop_timer_cb; 260 timer->vm = vm; 261 262 if (t >= 0) 263 uloop_timeout_set(&timer->timeout, t); 264 265 res = uc_resource_new(timer_type, timer); 266 267 timer->registry_index = uc_uloop_reg_add(res, callback); 268 269 return res; 270 } 271 272 273 typedef struct { 274 struct uloop_fd fd; 275 size_t registry_index; 276 uc_value_t *handle; 277 uc_vm_t *vm; 278 } uc_uloop_handle_t; 279 280 static void 281 uc_uloop_handle_clear(uc_uloop_handle_t **handle) 282 { 283 /* drop registry entries and clear data to prevent reuse */ 284 uc_uloop_reg_remove((*handle)->registry_index); 285 ucv_put((*handle)->handle); 286 free(*handle); 287 *handle = NULL; 288 } 289 290 static uc_value_t * 291 uc_uloop_handle_fileno(uc_vm_t *vm, size_t nargs) 292 { 293 uc_uloop_handle_t **handle = uc_fn_this("uloop.handle"); 294 295 if (!handle || !*handle) 296 err_return(EINVAL); 297 298 return ucv_int64_new((*handle)->fd.fd); 299 } 300 301 static uc_value_t * 302 uc_uloop_handle_handle(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 return ucv_get((*handle)->handle); 310 } 311 312 static uc_value_t * 313 uc_uloop_handle_delete(uc_vm_t *vm, size_t nargs) 314 { 315 uc_uloop_handle_t **handle = uc_fn_this("uloop.handle"); 316 int rv; 317 318 if (!handle || !*handle) 319 err_return(EINVAL); 320 321 rv = uloop_fd_delete(&(*handle)->fd); 322 323 uc_uloop_handle_clear(handle); 324 325 if (rv != 0) 326 err_return(errno); 327 328 return ucv_boolean_new(true); 329 } 330 331 static void 332 uc_uloop_handle_cb(struct uloop_fd *fd, unsigned int flags) 333 { 334 uc_uloop_handle_t *handle = (uc_uloop_handle_t *)fd; 335 uc_value_t *f = ucv_uint64_new(flags); 336 337 uc_uloop_reg_invoke(handle->vm, handle->registry_index, f); 338 ucv_put(f); 339 } 340 341 static int 342 get_fd(uc_vm_t *vm, uc_value_t *val) 343 { 344 uc_value_t *fn; 345 int64_t n; 346 int fd; 347 348 fn = ucv_property_get(val, "fileno"); 349 350 if (ucv_is_callable(fn)) { 351 uc_vm_stack_push(vm, ucv_get(val)); 352 uc_vm_stack_push(vm, ucv_get(fn)); 353 354 if (uc_vm_call(vm, true, 0) == EXCEPTION_NONE) { 355 val = uc_vm_stack_pop(vm); 356 } 357 else { 358 errno = EBADF; 359 val = NULL; 360 } 361 } 362 else { 363 ucv_get(val); 364 } 365 366 n = ucv_int64_get(val); 367 368 if (errno) { 369 fd = -1; 370 } 371 else if (n < 0 || n > (int64_t)INT_MAX) { 372 errno = EBADF; 373 fd = -1; 374 } 375 else { 376 fd = (int)n; 377 } 378 379 ucv_put(val); 380 381 return fd; 382 } 383 384 static uc_value_t * 385 uc_uloop_handle(uc_vm_t *vm, size_t nargs) 386 { 387 uc_value_t *fileno = uc_fn_arg(0); 388 uc_value_t *callback = uc_fn_arg(1); 389 uc_value_t *flags = uc_fn_arg(2); 390 uc_uloop_handle_t *handle; 391 uc_value_t *res; 392 int fd, ret; 393 uint64_t f; 394 395 fd = get_fd(vm, fileno); 396 397 if (fd == -1) 398 err_return(errno); 399 400 f = ucv_uint64_get(flags); 401 402 if (errno) 403 err_return(errno); 404 405 if (f == 0 || f > (uint64_t)UINT_MAX) 406 err_return(EINVAL); 407 408 if (!ucv_is_callable(callback)) 409 err_return(EINVAL); 410 411 handle = xalloc(sizeof(*handle)); 412 handle->fd.fd = fd; 413 handle->fd.cb = uc_uloop_handle_cb; 414 handle->handle = ucv_get(fileno); 415 handle->vm = vm; 416 417 ret = uloop_fd_add(&handle->fd, (unsigned int)f); 418 419 if (ret != 0) { 420 free(handle); 421 err_return(errno); 422 } 423 424 res = uc_resource_new(handle_type, handle); 425 426 handle->registry_index = uc_uloop_reg_add(res, callback); 427 428 return res; 429 } 430 431 432 typedef struct { 433 struct uloop_process process; 434 size_t registry_index; 435 uc_vm_t *vm; 436 } uc_uloop_process_t; 437 438 static void 439 uc_uloop_process_clear(uc_uloop_process_t **process) 440 { 441 /* drop registry entries and clear data to prevent reuse */ 442 uc_uloop_reg_remove((*process)->registry_index); 443 *process = NULL; 444 } 445 446 static uc_value_t * 447 uc_uloop_process_pid(uc_vm_t *vm, size_t nargs) 448 { 449 uc_uloop_process_t **process = uc_fn_this("uloop.process"); 450 451 if (!process || !*process) 452 err_return(EINVAL); 453 454 return ucv_int64_new((*process)->process.pid); 455 } 456 457 static uc_value_t * 458 uc_uloop_process_delete(uc_vm_t *vm, size_t nargs) 459 { 460 uc_uloop_process_t **process = uc_fn_this("uloop.process"); 461 int rv; 462 463 if (!process || !*process) 464 err_return(EINVAL); 465 466 rv = uloop_process_delete(&(*process)->process); 467 468 uc_uloop_process_clear(process); 469 470 if (rv != 0) 471 err_return(EINVAL); 472 473 return ucv_boolean_new(true); 474 } 475 476 static void 477 uc_uloop_process_cb(struct uloop_process *proc, int exitcode) 478 { 479 uc_uloop_process_t *process = (uc_uloop_process_t *)proc; 480 uc_value_t *e = ucv_int64_new(exitcode >> 8); 481 482 uc_uloop_reg_invoke(process->vm, process->registry_index, e); 483 uc_uloop_process_clear(&process); 484 ucv_put(e); 485 } 486 487 static uc_value_t * 488 uc_uloop_process(uc_vm_t *vm, size_t nargs) 489 { 490 uc_value_t *executable = uc_fn_arg(0); 491 uc_value_t *arguments = uc_fn_arg(1); 492 uc_value_t *environ = uc_fn_arg(2); 493 uc_value_t *callback = uc_fn_arg(3); 494 uc_uloop_process_t *process; 495 uc_stringbuf_t *buf; 496 char **argp, **envp; 497 uc_value_t *res; 498 pid_t pid; 499 size_t i; 500 501 if (ucv_type(executable) != UC_STRING || 502 (arguments && ucv_type(arguments) != UC_ARRAY) || 503 (environ && ucv_type(environ) != UC_OBJECT) || 504 !ucv_is_callable(callback)) { 505 err_return(EINVAL); 506 } 507 508 pid = fork(); 509 510 if (pid == -1) 511 err_return(errno); 512 513 if (pid == 0) { 514 argp = calloc(ucv_array_length(arguments) + 2, sizeof(char *)); 515 envp = calloc(ucv_object_length(environ) + 1, sizeof(char *)); 516 517 if (!argp || !envp) 518 _exit(-1); 519 520 argp[0] = ucv_to_string(vm, executable); 521 522 for (i = 0; i < ucv_array_length(arguments); i++) 523 argp[i+1] = ucv_to_string(vm, ucv_array_get(arguments, i)); 524 525 i = 0; 526 527 ucv_object_foreach(environ, envk, envv) { 528 buf = xprintbuf_new(); 529 530 ucv_stringbuf_printf(buf, "%s=", envk); 531 ucv_to_stringbuf(vm, buf, envv, false); 532 533 envp[i++] = buf->buf; 534 535 free(buf); 536 } 537 538 #ifdef __APPLE__ 539 execve((const char *)ucv_string_get(executable), 540 (char * const *)argp, (char * const *)envp); 541 #else 542 execvpe((const char *)ucv_string_get(executable), 543 (char * const *)argp, (char * const *)envp); 544 #endif 545 546 _exit(-1); 547 } 548 549 process = xalloc(sizeof(*process)); 550 process->process.pid = pid; 551 process->process.cb = uc_uloop_process_cb; 552 process->vm = vm; 553 554 uloop_process_add(&process->process); 555 556 res = uc_resource_new(process_type, process); 557 558 process->registry_index = uc_uloop_reg_add(res, callback); 559 560 return res; 561 } 562 563 564 static bool 565 readall(int fd, void *buf, size_t len) 566 { 567 ssize_t rlen; 568 569 while (len > 0) { 570 rlen = read(fd, buf, len); 571 572 if (rlen == -1) { 573 if (errno == EINTR) 574 continue; 575 576 return false; 577 } 578 579 if (rlen == 0) { 580 errno = EINTR; 581 582 return false; 583 } 584 585 buf += rlen; 586 len -= rlen; 587 } 588 589 return true; 590 } 591 592 static bool 593 writeall(int fd, void *buf, size_t len) 594 { 595 ssize_t wlen; 596 597 while (len > 0) { 598 wlen = write(fd, buf, len); 599 600 if (wlen == -1) { 601 if (errno == EINTR) 602 continue; 603 604 return false; 605 } 606 607 buf += wlen; 608 len -= wlen; 609 } 610 611 return true; 612 } 613 614 typedef struct { 615 int input; 616 int output; 617 bool has_sender; 618 bool has_receiver; 619 } uc_uloop_pipe_t; 620 621 static uc_value_t * 622 uc_uloop_pipe_send_common(uc_vm_t *vm, uc_value_t *msg, int fd) 623 { 624 uc_stringbuf_t *buf; 625 size_t len; 626 bool rv; 627 628 buf = xprintbuf_new(); 629 630 printbuf_memset(buf, 0, 0, sizeof(len)); 631 ucv_to_stringbuf(vm, buf, msg, true); 632 633 len = printbuf_length(buf); 634 memcpy(buf->buf, &len, sizeof(len)); 635 636 rv = writeall(fd, buf->buf, len); 637 638 printbuf_free(buf); 639 640 if (!rv) 641 err_return(errno); 642 643 return ucv_boolean_new(true); 644 } 645 646 static uc_value_t * 647 uc_uloop_pipe_send(uc_vm_t *vm, size_t nargs) 648 { 649 uc_uloop_pipe_t **pipe = uc_fn_this("uloop.pipe"); 650 uc_value_t *msg = uc_fn_arg(0); 651 652 if (!pipe || !*pipe) 653 err_return(EINVAL); 654 655 if (!(*pipe)->has_receiver) 656 err_return(EPIPE); 657 658 return uc_uloop_pipe_send_common(vm, msg, (*pipe)->output); 659 } 660 661 static bool 662 uc_uloop_pipe_receive_common(uc_vm_t *vm, int fd, uc_value_t **res, bool skip) 663 { 664 enum json_tokener_error err = json_tokener_error_parse_eof; 665 json_tokener *tok = NULL; 666 json_object *jso = NULL; 667 char buf[1024]; 668 ssize_t rlen; 669 size_t len; 670 671 *res = NULL; 672 673 if (!readall(fd, &len, sizeof(len))) 674 err_return(errno); 675 676 /* message length 0 is special, means input requested on other pipe */ 677 if (len == 0) 678 err_return(ENODATA); 679 680 /* valid messages should be at least sizeof(len) plus one byte of payload */ 681 if (len <= sizeof(len)) 682 err_return(EINVAL); 683 684 len -= sizeof(len); 685 686 while (len > 0) { 687 rlen = read(fd, buf, len < sizeof(buf) ? len : sizeof(buf)); 688 689 if (rlen == -1) { 690 if (errno == EINTR) 691 continue; 692 693 goto read_fail; 694 } 695 696 /* premature EOF */ 697 if (rlen == 0) { 698 errno = EPIPE; 699 goto read_fail; 700 } 701 702 if (!skip) { 703 if (!tok) 704 tok = xjs_new_tokener(); 705 706 jso = json_tokener_parse_ex(tok, buf, rlen); 707 err = json_tokener_get_error(tok); 708 } 709 710 len -= rlen; 711 } 712 713 if (!skip) { 714 if (err == json_tokener_continue) { 715 jso = json_tokener_parse_ex(tok, "\0", 1); 716 err = json_tokener_get_error(tok); 717 } 718 719 json_tokener_free(tok); 720 721 if (err != json_tokener_success) { 722 errno = EINVAL; 723 goto read_fail; 724 } 725 726 *res = ucv_from_json(vm, jso); 727 728 json_object_put(jso); 729 } 730 731 return true; 732 733 read_fail: 734 if (tok) 735 json_tokener_free(tok); 736 737 json_object_put(jso); 738 err_return(errno); 739 } 740 741 static uc_value_t * 742 uc_uloop_pipe_receive(uc_vm_t *vm, size_t nargs) 743 { 744 uc_uloop_pipe_t **pipe = uc_fn_this("uloop.pipe"); 745 uc_value_t *rv; 746 size_t len = 0; 747 748 if (!pipe || !*pipe) 749 err_return(EINVAL); 750 751 if (!(*pipe)->has_sender) 752 err_return(EPIPE); 753 754 /* send zero-length message to signal input request */ 755 writeall((*pipe)->output, &len, sizeof(len)); 756 757 /* receive input message */ 758 uc_uloop_pipe_receive_common(vm, (*pipe)->input, &rv, false); 759 760 return rv; 761 } 762 763 static uc_value_t * 764 uc_uloop_pipe_sending(uc_vm_t *vm, size_t nargs) 765 { 766 uc_uloop_pipe_t **pipe = uc_fn_this("uloop.pipe"); 767 768 if (!pipe || !*pipe) 769 err_return(EINVAL); 770 771 return ucv_boolean_new((*pipe)->has_sender); 772 } 773 774 static uc_value_t * 775 uc_uloop_pipe_receiving(uc_vm_t *vm, size_t nargs) 776 { 777 uc_uloop_pipe_t **pipe = uc_fn_this("uloop.pipe"); 778 779 if (!pipe || !*pipe) 780 err_return(EINVAL); 781 782 return ucv_boolean_new((*pipe)->has_receiver); 783 } 784 785 786 typedef struct { 787 struct uloop_process process; 788 struct uloop_fd output; 789 size_t registry_index; 790 bool finished; 791 int input_fd; 792 uc_vm_t *vm; 793 uc_value_t *input_cb; 794 uc_value_t *output_cb; 795 } uc_uloop_task_t; 796 797 static int 798 patch_devnull(int fd, bool write) 799 { 800 int devnull = open("/dev/null", write ? O_WRONLY : O_RDONLY); 801 802 if (devnull != -1) { 803 dup2(fd, devnull); 804 close(fd); 805 } 806 807 return devnull; 808 } 809 810 static void 811 uloop_fd_close(struct uloop_fd *fd) { 812 if (fd->fd == -1) 813 return; 814 815 close(fd->fd); 816 fd->fd = -1; 817 } 818 819 static void 820 uc_uloop_task_clear(uc_uloop_task_t **task) 821 { 822 /* drop registry entries and clear data to prevent reuse */ 823 uc_uloop_reg_remove((*task)->registry_index); 824 *task = NULL; 825 } 826 827 static uc_value_t * 828 uc_uloop_task_pid(uc_vm_t *vm, size_t nargs) 829 { 830 uc_uloop_task_t **task = uc_fn_this("uloop.task"); 831 832 if (!task || !*task) 833 err_return(EINVAL); 834 835 if ((*task)->finished) 836 err_return(ESRCH); 837 838 return ucv_int64_new((*task)->process.pid); 839 } 840 841 static uc_value_t * 842 uc_uloop_task_kill(uc_vm_t *vm, size_t nargs) 843 { 844 uc_uloop_task_t **task = uc_fn_this("uloop.task"); 845 int rv; 846 847 if (!task || !*task) 848 err_return(EINVAL); 849 850 if ((*task)->finished) 851 err_return(ESRCH); 852 853 rv = kill((*task)->process.pid, SIGTERM); 854 855 if (rv == -1) 856 err_return(errno); 857 858 return ucv_boolean_new(true); 859 } 860 861 static uc_value_t * 862 uc_uloop_task_finished(uc_vm_t *vm, size_t nargs) 863 { 864 uc_uloop_task_t **task = uc_fn_this("uloop.task"); 865 866 if (!task || !*task) 867 err_return(EINVAL); 868 869 return ucv_boolean_new((*task)->finished); 870 } 871 872 static void 873 uc_uloop_task_output_cb(struct uloop_fd *fd, unsigned int flags) 874 { 875 uc_uloop_task_t *task = container_of(fd, uc_uloop_task_t, output); 876 uc_value_t *obj = ucv_array_get(object_registry, task->registry_index); 877 uc_value_t *msg = NULL; 878 879 if (flags & ULOOP_READ) { 880 while (true) { 881 if (!uc_uloop_pipe_receive_common(task->vm, fd->fd, &msg, !task->output_cb)) { 882 /* input requested */ 883 if (last_error == ENODATA) { 884 uc_vm_stack_push(task->vm, ucv_get(obj)); 885 uc_vm_stack_push(task->vm, ucv_get(task->input_cb)); 886 887 if (uc_vm_call(task->vm, true, 0) != EXCEPTION_NONE) { 888 uloop_end(); 889 890 return; 891 } 892 893 msg = uc_vm_stack_pop(task->vm); 894 uc_uloop_pipe_send_common(task->vm, msg, task->input_fd); 895 ucv_put(msg); 896 897 continue; 898 } 899 900 /* error */ 901 break; 902 } 903 904 if (task->output_cb) { 905 uc_vm_stack_push(task->vm, ucv_get(obj)); 906 uc_vm_stack_push(task->vm, ucv_get(task->output_cb)); 907 uc_vm_stack_push(task->vm, msg); 908 909 if (uc_vm_call(task->vm, true, 1) == EXCEPTION_NONE) { 910 ucv_put(uc_vm_stack_pop(task->vm)); 911 } 912 else { 913 uloop_end(); 914 915 return; 916 } 917 } 918 else { 919 ucv_put(msg); 920 } 921 } 922 } 923 924 if (!fd->registered && task->finished) { 925 close(task->input_fd); 926 task->input_fd = -1; 927 928 uloop_fd_close(&task->output); 929 uloop_process_delete(&task->process); 930 931 uc_uloop_task_clear(&task); 932 } 933 } 934 935 static void 936 uc_uloop_task_process_cb(struct uloop_process *proc, int exitcode) 937 { 938 uc_uloop_task_t *task = container_of(proc, uc_uloop_task_t, process); 939 940 task->finished = true; 941 942 uc_uloop_task_output_cb(&task->output, ULOOP_READ); 943 } 944 945 static uc_value_t * 946 uc_uloop_task(uc_vm_t *vm, size_t nargs) 947 { 948 uc_value_t *func = uc_fn_arg(0); 949 uc_value_t *output_cb = uc_fn_arg(1); 950 uc_value_t *input_cb = uc_fn_arg(2); 951 int outpipe[2] = { -1, -1 }; 952 int inpipe[2] = { -1, -1 }; 953 uc_value_t *res, *cbs, *p; 954 uc_uloop_pipe_t *tpipe; 955 uc_uloop_task_t *task; 956 pid_t pid; 957 int err; 958 959 if (!ucv_is_callable(func) || 960 (output_cb && !ucv_is_callable(output_cb)) || 961 (input_cb && !ucv_is_callable(input_cb))) 962 err_return(EINVAL); 963 964 if (pipe(outpipe) == -1 || pipe(inpipe) == -1) { 965 err = errno; 966 967 close(outpipe[0]); close(outpipe[1]); 968 close(inpipe[0]); close(inpipe[1]); 969 970 err_return(err); 971 } 972 973 pid = fork(); 974 975 if (pid == -1) 976 err_return(errno); 977 978 if (pid == 0) { 979 uloop_done(); 980 981 patch_devnull(0, false); 982 patch_devnull(1, true); 983 patch_devnull(2, true); 984 985 vm->output = fdopen(1, "w"); 986 987 close(inpipe[1]); 988 close(outpipe[0]); 989 990 tpipe = xalloc(sizeof(*tpipe)); 991 tpipe->input = inpipe[0]; 992 tpipe->output = outpipe[1]; 993 tpipe->has_sender = input_cb; 994 tpipe->has_receiver = output_cb; 995 996 p = uc_resource_new(pipe_type, tpipe); 997 998 uc_vm_stack_push(vm, func); 999 uc_vm_stack_push(vm, ucv_get(p)); 1000 1001 if (uc_vm_call(vm, false, 1) == EXCEPTION_NONE) { 1002 res = uc_vm_stack_pop(vm); 1003 uc_uloop_pipe_send_common(vm, res, tpipe->output); 1004 ucv_put(res); 1005 } 1006 1007 ucv_put(p); 1008 1009 _exit(0); 1010 } 1011 1012 close(inpipe[0]); 1013 close(outpipe[1]); 1014 1015 task = xalloc(sizeof(*task)); 1016 task->process.pid = pid; 1017 task->process.cb = uc_uloop_task_process_cb; 1018 1019 task->vm = vm; 1020 1021 task->output.fd = outpipe[0]; 1022 task->output.cb = uc_uloop_task_output_cb; 1023 task->output_cb = output_cb; 1024 uloop_fd_add(&task->output, ULOOP_READ); 1025 1026 if (input_cb) { 1027 task->input_fd = inpipe[1]; 1028 task->input_cb = input_cb; 1029 } 1030 else { 1031 task->input_fd = -1; 1032 close(inpipe[1]); 1033 } 1034 1035 uloop_process_add(&task->process); 1036 1037 res = uc_resource_new(task_type, task); 1038 1039 cbs = ucv_array_new(NULL); 1040 ucv_array_set(cbs, 0, ucv_get(output_cb)); 1041 ucv_array_set(cbs, 1, ucv_get(input_cb)); 1042 1043 task->registry_index = uc_uloop_reg_add(res, cbs); 1044 1045 return res; 1046 } 1047 1048 1049 static const uc_function_list_t timer_fns[] = { 1050 { "set", uc_uloop_timer_set }, 1051 { "remaining", uc_uloop_timer_remaining }, 1052 { "cancel", uc_uloop_timer_cancel }, 1053 }; 1054 1055 static const uc_function_list_t handle_fns[] = { 1056 { "fileno", uc_uloop_handle_fileno }, 1057 { "handle", uc_uloop_handle_handle }, 1058 { "delete", uc_uloop_handle_delete }, 1059 }; 1060 1061 static const uc_function_list_t process_fns[] = { 1062 { "pid", uc_uloop_process_pid }, 1063 { "delete", uc_uloop_process_delete }, 1064 }; 1065 1066 static const uc_function_list_t task_fns[] = { 1067 { "pid", uc_uloop_task_pid }, 1068 { "kill", uc_uloop_task_kill }, 1069 { "finished", uc_uloop_task_finished }, 1070 }; 1071 1072 static const uc_function_list_t pipe_fns[] = { 1073 { "send", uc_uloop_pipe_send }, 1074 { "receive", uc_uloop_pipe_receive }, 1075 { "sending", uc_uloop_pipe_sending }, 1076 { "receiving", uc_uloop_pipe_receiving }, 1077 }; 1078 1079 static const uc_function_list_t global_fns[] = { 1080 { "error", uc_uloop_error }, 1081 { "init", uc_uloop_init }, 1082 { "run", uc_uloop_run }, 1083 { "timer", uc_uloop_timer }, 1084 { "handle", uc_uloop_handle }, 1085 { "process", uc_uloop_process }, 1086 { "task", uc_uloop_task }, 1087 { "cancelling", uc_uloop_cancelling }, 1088 { "running", uc_uloop_running }, 1089 { "done", uc_uloop_done }, 1090 { "end", uc_uloop_end }, 1091 }; 1092 1093 1094 static void close_timer(void *ud) 1095 { 1096 uc_uloop_timer_t *timer = ud; 1097 1098 if (!timer) 1099 return; 1100 1101 uloop_timeout_cancel(&timer->timeout); 1102 free(timer); 1103 } 1104 1105 static void close_handle(void *ud) 1106 { 1107 uc_uloop_handle_t *handle = ud; 1108 1109 if (!handle) 1110 return; 1111 1112 uloop_fd_delete(&handle->fd); 1113 ucv_put(handle->handle); 1114 free(handle); 1115 } 1116 1117 static void close_process(void *ud) 1118 { 1119 uc_uloop_process_t *process = ud; 1120 1121 if (!process) 1122 return; 1123 1124 uloop_process_delete(&process->process); 1125 free(process); 1126 } 1127 1128 static void close_task(void *ud) 1129 { 1130 uc_uloop_task_t *task = ud; 1131 1132 if (!task) 1133 return; 1134 1135 uloop_process_delete(&task->process); 1136 uloop_fd_close(&task->output); 1137 1138 if (task->input_fd != -1) 1139 close(task->input_fd); 1140 1141 free(task); 1142 } 1143 1144 static void close_pipe(void *ud) 1145 { 1146 uc_uloop_pipe_t *pipe = ud; 1147 1148 if (!pipe) 1149 return; 1150 1151 close(pipe->input); 1152 close(pipe->output); 1153 1154 free(pipe); 1155 } 1156 1157 1158 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 1159 { 1160 uc_function_list_register(scope, global_fns); 1161 1162 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(x)) 1163 1164 ADD_CONST(ULOOP_READ); 1165 ADD_CONST(ULOOP_WRITE); 1166 ADD_CONST(ULOOP_EDGE_TRIGGER); 1167 ADD_CONST(ULOOP_BLOCKING); 1168 1169 timer_type = uc_type_declare(vm, "uloop.timer", timer_fns, close_timer); 1170 handle_type = uc_type_declare(vm, "uloop.handle", handle_fns, close_handle); 1171 process_type = uc_type_declare(vm, "uloop.process", process_fns, close_process); 1172 task_type = uc_type_declare(vm, "uloop.task", task_fns, close_task); 1173 pipe_type = uc_type_declare(vm, "uloop.pipe", pipe_fns, close_pipe); 1174 1175 object_registry = ucv_array_new(vm); 1176 1177 uc_vm_registry_set(vm, "uloop.registry", object_registry); 1178 } 1179
This page was automatically generated by LXR 0.3.1. • OpenWrt