#include <string.h>
#include <errno.h>
#include <fcntl.h>
+#include <pthread.h>
#define countof(x) ( sizeof(x) / sizeof(x[0]) )
#define libc_error(ctx) ( JS_ThrowInternalError(ctx, "%s", strerror(errno)) )
+static JSValue js_os_fork(
+ JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv
+) {
+ return JS_NewInt32(ctx, fork());
+}
+
static JSValue js_os_socket(
JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv
) {
JS_CFUNC_DEF("socket", 3, js_os_socket),
JS_CFUNC_DEF("listen", 1, js_os_listen),
JS_CFUNC_DEF("accept", 1, js_os_accept),
+ JS_CFUNC_DEF("fork", 0, js_os_fork),
JS_CFUNC_MAGIC_DEF("bind", 2, js_os_bind, 0),
JS_CFUNC_MAGIC_DEF("connect", 2, js_os_bind, 1),
// JS_CFUNC_DEF("send", 2, js_os_send), // would be same as os.write
return JS_NewBool(ctx, data->connected);
}
+struct sock_async {
+ JSContext * ctx;
+ JSValue this;
+ JSValue flflrjct[2]; // fullfill / reject
+ JSValue (*func)(JSContext *, JSValueConst, int, JSValueConst *);
+ JSValue (*mfunc)(JSContext *, JSValueConst, int, JSValueConst *, int);
+ int magic;
+};
+
+
static JSValue js_sock_accept(
JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv
) {
else return libc_error(ctx);
}
}
+
static JSValue js_sock_send(
JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv
) {
} else to = NULL;
// Read Argument either as ArrayBuffer or String
- if ( (buf = JS_GetArrayBuffer(ctx, &len, argv[0])) ) {
+ if ( JS_IsUndefined(argv[0]) ) {
+ len = sendto(data->fd, NULL, 0, flags, to,
+ to ? sizeof(struct sockaddr_storage) : 0
+ );
+ } else if ( (buf = JS_GetArrayBuffer(ctx, &len, argv[0])) ) {
len = sendto(data->fd, buf, len, flags, to,
to ? sizeof(struct sockaddr_storage) : 0
);
if ( close(data->fd) ) return libc_error(ctx);
else return JS_UNDEFINED;
}
+
static void sock_destroy(JSRuntime *rt, JSValue this){
SocketData *data = JS_GetOpaque(this, socket_cid);
// close(data->fd); // do not do what a c programmer wouldn't do
js_free_rt(rt, data);
};
+static void *js_run_async(void *async) {
+ struct sock_async as = * (struct sock_async*) async;
+ JSValue ret;
+
+ if (as.func) {
+ ret = as.func(as.ctx, as.this, 0, &JS_UNDEFINED);
+ } else if (as.mfunc) {
+ ret = as.mfunc(as.ctx, as.this, 0, &JS_UNDEFINED, as.magic);
+ } else ret = JS_ThrowReferenceError(as.ctx, "js_run_async invalid");
+
+ if (JS_IsException(ret)) {
+ JS_Call(as.ctx, as.flflrjct[1], as.this, 1, &ret);
+ } else {
+ JS_Call(as.ctx, as.flflrjct[0], as.this, 1, &ret);
+ }
+ JS_FreeValue(as.ctx, as.flflrjct[0]);
+ JS_FreeValue(as.ctx, as.flflrjct[1]);
+ free(async);
+ return NULL;
+}
+
+static JSValue js_sock_async(
+ JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv, int mgc
+) {
+ JSValue promise; pthread_t thread; pthread_attr_t ta;
+ struct sock_async * a = malloc(sizeof(struct sock_async));
+ memset(a, 0, sizeof(struct sock_async));
+ a->ctx = ctx; a->this = this;
+
+ switch (mgc) {
+ case 1: a->func = js_sock_accept; break;
+ case 2: a->mfunc = js_sock_recv; a->magic = 0; break;
+ case 3: a->mfunc = js_sock_recv; a->magic = 1; break;
+ }
+
+ promise = JS_NewPromiseCapability(ctx, a->flflrjct);
+ if (JS_IsException(promise)) {
+ JS_FreeValue(ctx, a->flflrjct[0]);
+ JS_FreeValue(ctx, a->flflrjct[1]);
+ free(a);
+ } else {
+ pthread_attr_init(&ta);
+ pthread_attr_setdetachstate(&ta, PTHREAD_CREATE_DETACHED);
+ pthread_create(&thread, &ta, js_run_async, a);
+ pthread_attr_destroy(&ta);
+ }
+
+ return promise;
+}
+
static const JSCFunctionListEntry socket_ptype[] = {
JS_CFUNC_DEF("accept", 0, js_sock_accept),
+ JS_CFUNC_MAGIC_DEF("acceptAsync", 0, js_sock_async, 1),
JS_CFUNC_DEF("send", 1, js_sock_send),
JS_CFUNC_DEF("close", 0, js_sock_close),
JS_CFUNC_MAGIC_DEF("recv", 0, js_sock_recv, 0),
JS_CFUNC_MAGIC_DEF("recvString", 0, js_sock_recv, 1),
+ JS_CFUNC_MAGIC_DEF("recvAsync", 0, js_sock_async, 2),
+ JS_CFUNC_MAGIC_DEF("recvStringAsync", 0, js_sock_async, 3),
JS_CGETSET_MAGIC_DEF("localName", js_sock_get_addr, NULL, 0),
JS_CGETSET_MAGIC_DEF("localPort", js_sock_get_addr, NULL, 1),
JS_CGETSET_MAGIC_DEF("peerName", js_sock_get_addr, NULL, 2),
// JS_CGETSET_DEF("timeout", net_get_timeout, net_set_timeout),
JS_CFUNC_DEF("setTimeout", 1, net_set_timeout),
JS_CFUNC_DEF("getTimeout", 1, net_get_timeout),
+ JS_CFUNC_DEF("fork", 0, js_os_fork),
};
static int sock_modinit(JSContext *ctx, JSModuleDef *mod ) {