|
41 | 41 | #include <windows.h> |
42 | 42 | #include <conio.h> |
43 | 43 | #include <utime.h> |
| 44 | +#include <winsock2.h> |
44 | 45 | #else |
45 | 46 | #include <dlfcn.h> |
46 | 47 | #include <termios.h> |
47 | 48 | #include <sys/ioctl.h> |
48 | 49 | #include <sys/wait.h> |
| 50 | +#include <sys/types.h> |
| 51 | +#include <sys/socket.h> |
| 52 | +#include <netinet/in.h> |
| 53 | +#include <netinet/ip.h> |
| 54 | +#include <arpa/inet.h> |
| 55 | +#define __USE_XOPEN2K // for addrinfo |
| 56 | +#include <netdb.h> |
49 | 57 |
|
50 | 58 | #if defined(__FreeBSD__) |
51 | 59 | extern char **environ; |
@@ -80,10 +88,6 @@ typedef sig_t sighandler_t; |
80 | 88 | #define PATH_MAX 4096 |
81 | 89 | #endif |
82 | 90 |
|
83 | | -/* TODO: |
84 | | - - add socket calls |
85 | | -*/ |
86 | | - |
87 | 91 | typedef struct { |
88 | 92 | struct list_head link; |
89 | 93 | int fd; |
@@ -1671,6 +1675,11 @@ static int js_std_init(JSContext *ctx, JSModuleDef *m) |
1671 | 1675 | { |
1672 | 1676 | JSValue proto; |
1673 | 1677 |
|
| 1678 | + #if defined(_WIN32) |
| 1679 | + WSADATA wsa_data; |
| 1680 | + WSAStartup(0x0202, &wsa_data); |
| 1681 | + #endif |
| 1682 | + |
1674 | 1683 | /* FILE class */ |
1675 | 1684 | /* the class ID is created once */ |
1676 | 1685 | JS_NewClassID(&js_std_file_class_id); |
@@ -3401,6 +3410,220 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val, |
3401 | 3410 |
|
3402 | 3411 | #endif /* !_WIN32 */ |
3403 | 3412 |
|
| 3413 | +static int JS_toSockaddrStruct(JSContext *ctx, JSValue addr, |
| 3414 | + struct sockaddr_in *sockaddr) |
| 3415 | +{ |
| 3416 | + JSValue val; |
| 3417 | + const char *addr_str; |
| 3418 | + uint32_t port, family; |
| 3419 | + int ret; |
| 3420 | + |
| 3421 | + val = JS_GetPropertyStr(ctx, addr, "family"); |
| 3422 | + if (JS_IsException(val) || JS_IsUndefined(val) || |
| 3423 | + JS_ToUint32(ctx, &family, val)) { |
| 3424 | + sockaddr->sin_family = AF_INET; |
| 3425 | + } else { |
| 3426 | + sockaddr->sin_family = family; |
| 3427 | + } |
| 3428 | + JS_FreeValue(ctx, val); |
| 3429 | + |
| 3430 | + val = JS_GetPropertyStr(ctx, addr, "addr"); |
| 3431 | + addr_str = JS_ToCString(ctx, val); |
| 3432 | + ret = inet_pton(AF_INET, addr_str, &(sockaddr->sin_addr.s_addr)); |
| 3433 | + JS_FreeCString(ctx, addr_str); |
| 3434 | + JS_FreeValue(ctx, val); |
| 3435 | + if (ret != 1) |
| 3436 | + return -1; |
| 3437 | + |
| 3438 | + val = JS_GetPropertyStr(ctx, addr, "port"); |
| 3439 | + ret = JS_ToUint32(ctx, &port, val); |
| 3440 | + JS_FreeValue(ctx, val); |
| 3441 | + if(ret) |
| 3442 | + return -1; |
| 3443 | + sockaddr->sin_port = htons(port); |
| 3444 | + return 0; |
| 3445 | +} |
| 3446 | + |
| 3447 | +static JSValue js_toSockaddrObj(JSContext *ctx, struct sockaddr_in *sockaddr) |
| 3448 | +{ |
| 3449 | + JSValue obj, prop; |
| 3450 | + char ip_str[INET_ADDRSTRLEN]; |
| 3451 | + const char *ip_ptr; |
| 3452 | + |
| 3453 | + obj = JS_NewObject(ctx); |
| 3454 | + if (JS_IsException(obj)) |
| 3455 | + goto fail; |
| 3456 | + |
| 3457 | + prop = JS_NewUint32(ctx, sockaddr->sin_family); |
| 3458 | + JS_DefinePropertyValueStr(ctx, obj, "family", prop, JS_PROP_C_W_E); |
| 3459 | + |
| 3460 | + prop = JS_NewUint32(ctx, ntohs(sockaddr->sin_port)); |
| 3461 | + JS_DefinePropertyValueStr(ctx, obj, "port", prop, JS_PROP_C_W_E); |
| 3462 | + |
| 3463 | + ip_ptr = inet_ntop(AF_INET, &sockaddr->sin_addr, ip_str, sizeof(ip_str)); |
| 3464 | + prop = ip_ptr ? JS_NewString(ctx, ip_ptr) : JS_NULL; |
| 3465 | + JS_DefinePropertyValueStr(ctx, obj, "addr", prop, JS_PROP_C_W_E); |
| 3466 | + return obj; |
| 3467 | + |
| 3468 | + fail: |
| 3469 | + JS_FreeValue(ctx, obj); |
| 3470 | + return JS_EXCEPTION; |
| 3471 | +} |
| 3472 | + |
| 3473 | +static JSValue js_os_socket(JSContext *ctx, JSValueConst this_val, |
| 3474 | + int argc, JSValueConst *argv) |
| 3475 | +{ |
| 3476 | + int domain, type, protocol = 0, ret; |
| 3477 | + |
| 3478 | + if (JS_ToInt32(ctx, &domain, argv[0])) |
| 3479 | + return JS_EXCEPTION; |
| 3480 | + if (JS_ToInt32(ctx, &type, argv[1])) |
| 3481 | + return JS_EXCEPTION; |
| 3482 | + if (argc >= 3 && JS_ToInt32(ctx, &protocol, argv[2])) |
| 3483 | + return JS_EXCEPTION; |
| 3484 | + ret = js_get_errno(socket(domain, type, protocol)); |
| 3485 | + return JS_NewInt32(ctx, ret); |
| 3486 | +} |
| 3487 | + |
| 3488 | +static JSValue js_os_setsockopt(JSContext *ctx, JSValueConst this_val, |
| 3489 | + int argc, JSValueConst *argv) |
| 3490 | +{ |
| 3491 | + int sock, optname, ret; |
| 3492 | + uint8_t *opt; |
| 3493 | + size_t size; |
| 3494 | + |
| 3495 | + if (JS_ToInt32(ctx, &sock, argv[0])) |
| 3496 | + return JS_EXCEPTION; |
| 3497 | + if (JS_ToInt32(ctx, &optname, argv[1])) |
| 3498 | + return JS_EXCEPTION; |
| 3499 | + opt = JS_GetArrayBuffer(ctx, &size, argv[2]); |
| 3500 | + if (!opt) |
| 3501 | + return JS_EXCEPTION; |
| 3502 | + ret = js_get_errno(setsockopt(sock, SOL_SOCKET, optname, &opt, size)); |
| 3503 | + return JS_NewInt32(ctx, ret); |
| 3504 | +} |
| 3505 | + |
| 3506 | +static JSValue js_os_getaddrinfo(JSContext *ctx, JSValueConst this_val, |
| 3507 | + int argc, JSValueConst *argv) |
| 3508 | +{ |
| 3509 | + int ret; |
| 3510 | + socklen_t len, objLen; |
| 3511 | + JSValue obj, addrObj; |
| 3512 | + const char* node = NULL; |
| 3513 | + const char* service = NULL; |
| 3514 | + struct addrinfo *ai,*it; |
| 3515 | + |
| 3516 | + if (!JS_IsNull(argv[0]) && !JS_IsUndefined(argv[0])) |
| 3517 | + node = JS_ToCString(ctx, argv[0]); |
| 3518 | + service = JS_ToCString(ctx, argv[1]); |
| 3519 | + if (!service) |
| 3520 | + goto fail; |
| 3521 | + |
| 3522 | + ret = js_get_errno(getaddrinfo(node, service, NULL, &ai)); |
| 3523 | + if(ret) |
| 3524 | + goto fail; |
| 3525 | + |
| 3526 | + obj = JS_NewArray(ctx); |
| 3527 | + for (objLen = 0, it = ai; it; it = it->ai_next) { |
| 3528 | + for (len = 0; len < it->ai_addrlen; len++) { |
| 3529 | + addrObj = js_toSockaddrObj(ctx,(struct sockaddr_in *)&it->ai_addr[len]); |
| 3530 | + JS_SetPropertyUint32(ctx,obj,objLen++,addrObj); |
| 3531 | + } |
| 3532 | + } |
| 3533 | + |
| 3534 | + freeaddrinfo(ai); |
| 3535 | + return obj; |
| 3536 | +fail: |
| 3537 | + JS_FreeValue(ctx, obj); |
| 3538 | + JS_FreeCString(ctx, service); |
| 3539 | + JS_FreeCString(ctx, node); |
| 3540 | + return JS_EXCEPTION; |
| 3541 | +} |
| 3542 | + |
| 3543 | +static JSValue js_os_bind(JSContext *ctx, JSValueConst this_val, |
| 3544 | + int argc, JSValueConst *argv) |
| 3545 | +{ |
| 3546 | + int sockfd, ret; |
| 3547 | + struct sockaddr_in saddr; |
| 3548 | + |
| 3549 | + if (JS_ToInt32(ctx, &sockfd, argv[0])) |
| 3550 | + return JS_EXCEPTION; |
| 3551 | + if (JS_toSockaddrStruct(ctx, argv[1], &saddr)) |
| 3552 | + return JS_EXCEPTION; |
| 3553 | + ret = js_get_errno(bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr))); |
| 3554 | + return JS_NewInt32(ctx, ret); |
| 3555 | +} |
| 3556 | + |
| 3557 | +static JSValue js_os_listen(JSContext *ctx, JSValueConst this_val, |
| 3558 | + int argc, JSValueConst *argv) |
| 3559 | +{ |
| 3560 | + int sockfd, backlog = 10, ret; |
| 3561 | + |
| 3562 | + if (JS_ToInt32(ctx, &sockfd, argv[0])) |
| 3563 | + return JS_EXCEPTION; |
| 3564 | + if (argc >= 2 && JS_ToInt32(ctx, &backlog, argv[1])) |
| 3565 | + return JS_EXCEPTION; |
| 3566 | + |
| 3567 | + ret = js_get_errno(listen(sockfd, backlog)); |
| 3568 | + return JS_NewInt32(ctx, ret); |
| 3569 | +} |
| 3570 | + |
| 3571 | +static JSValue js_os_accept(JSContext *ctx, JSValueConst this_val, |
| 3572 | + int argc, JSValueConst *argv) |
| 3573 | +{ |
| 3574 | + JSValue arr, sockaddr_obj; |
| 3575 | + int sockfd, ret; |
| 3576 | + struct sockaddr_in client_addr; |
| 3577 | + socklen_t addr_len = sizeof(client_addr); |
| 3578 | + |
| 3579 | + if (JS_ToInt32(ctx, &sockfd, argv[0])) |
| 3580 | + return JS_EXCEPTION; |
| 3581 | + ret = js_get_errno(accept(sockfd, (struct sockaddr *)&client_addr, &addr_len)); |
| 3582 | + |
| 3583 | + // TODO: refactor into a JS_NewSockObj |
| 3584 | + sockaddr_obj = JS_NewObject(ctx); |
| 3585 | + if (JS_IsException(sockaddr_obj)) |
| 3586 | + return sockaddr_obj; |
| 3587 | + JS_DefinePropertyValue(ctx, sockaddr_obj, JS_NewAtom(ctx, "addr"), |
| 3588 | + JS_NewInt32(ctx, ntohl(client_addr.sin_addr.s_addr)), JS_PROP_C_W_E); |
| 3589 | + JS_DefinePropertyValue(ctx, sockaddr_obj, JS_NewAtom(ctx, "port"), |
| 3590 | + JS_NewInt32(ctx, ntohs(client_addr.sin_port)), JS_PROP_C_W_E); |
| 3591 | + |
| 3592 | + arr = JS_NewArray(ctx); |
| 3593 | + if (JS_IsException(arr)) |
| 3594 | + return arr; |
| 3595 | + |
| 3596 | + JS_DefinePropertyValueUint32(ctx, arr, 0, JS_NewInt32(ctx, ret), JS_PROP_C_W_E); |
| 3597 | + JS_DefinePropertyValueUint32(ctx, arr, 1, sockaddr_obj, JS_PROP_C_W_E); |
| 3598 | + return arr; |
| 3599 | +} |
| 3600 | +static JSValue js_os_connect(JSContext *ctx, JSValueConst this_val, |
| 3601 | + int argc, JSValueConst *argv) |
| 3602 | +{ |
| 3603 | + int sockfd, ret; |
| 3604 | + unsigned u32; |
| 3605 | + struct sockaddr_in client_addr; |
| 3606 | + socklen_t client_len = sizeof(client_addr); |
| 3607 | + JSValue val; |
| 3608 | + |
| 3609 | + if (JS_ToInt32(ctx, &sockfd, argv[0])) |
| 3610 | + return JS_EXCEPTION; |
| 3611 | + // TODO: refactor into a JS_GetSockObj |
| 3612 | + val = JS_GetPropertyStr(ctx, argv[1], "addr"); |
| 3613 | + ret = JS_ToUint32(ctx, &u32, val); |
| 3614 | + JS_FreeValue(ctx, val); |
| 3615 | + client_addr.sin_addr.s_addr = htonl(u32); |
| 3616 | + |
| 3617 | + val = JS_GetPropertyStr(ctx, argv[1], "port"); |
| 3618 | + ret = JS_ToUint32(ctx, &u32, val); |
| 3619 | + JS_FreeValue(ctx, val); |
| 3620 | + client_addr.sin_port = htons(u32); |
| 3621 | + |
| 3622 | + ret = js_get_errno(accept(sockfd, (struct sockaddr *)&client_addr, &client_len)); |
| 3623 | + |
| 3624 | + return JS_NewInt32(ctx, ret); |
| 3625 | +} |
| 3626 | + |
3404 | 3627 | #ifdef USE_WORKER |
3405 | 3628 |
|
3406 | 3629 | /* Worker */ |
@@ -3936,6 +4159,20 @@ static const JSCFunctionListEntry js_os_funcs[] = { |
3936 | 4159 | JS_CFUNC_DEF("dup", 1, js_os_dup ), |
3937 | 4160 | JS_CFUNC_DEF("dup2", 2, js_os_dup2 ), |
3938 | 4161 | #endif |
| 4162 | + /* SOCKET I/O */ |
| 4163 | + JS_CFUNC_DEF("socket", 2, js_os_socket ), |
| 4164 | + JS_CFUNC_DEF("setsockopt", 3, js_os_setsockopt ), |
| 4165 | + JS_CFUNC_DEF("getaddrinfo", 2, js_os_getaddrinfo ), |
| 4166 | + JS_CFUNC_DEF("bind", 2, js_os_bind ), |
| 4167 | + JS_CFUNC_DEF("listen", 1, js_os_listen ), |
| 4168 | + JS_CFUNC_DEF("accept", 1, js_os_accept ), |
| 4169 | + JS_CFUNC_DEF("connect", 1, js_os_connect ), |
| 4170 | + OS_FLAG(AF_INET), |
| 4171 | + OS_FLAG(AF_INET6), |
| 4172 | + OS_FLAG(SOCK_STREAM), |
| 4173 | + OS_FLAG(SOCK_DGRAM), |
| 4174 | + OS_FLAG(SOCK_RAW), |
| 4175 | + OS_FLAG(SO_REUSEADDR), |
3939 | 4176 | }; |
3940 | 4177 |
|
3941 | 4178 | static int js_os_init(JSContext *ctx, JSModuleDef *m) |
|
0 commit comments