static int apipe_write( const char* path, const char* buf, size_t count, off_t offset, struct fuse_file_info* info) { if (count == 0) return 0; struct PP_Var req_var = nspawn_dict_create(); nspawn_dict_setstring(req_var, "command", "nacl_apipe_write"); nspawn_dict_setint(req_var, "pipe_id", info->fh); struct PP_Var data = PSInterfaceVarArrayBuffer()->Create(count); if (data.type == PP_VARTYPE_NULL) return -EIO; void *p = PSInterfaceVarArrayBuffer()->Map(data); if (count > 0 && !p) { nspawn_var_release(data); nspawn_var_release(req_var); return -EIO; } memcpy(p, buf, count); PSInterfaceVarArrayBuffer()->Unmap(data); nspawn_dict_set(req_var, "data", data); struct PP_Var result_var = nspawn_send_request(req_var); int ret = nspawn_dict_getint(result_var, "count"); nspawn_var_release(result_var); return ret; }
struct PP_Var nspawn_send_request(struct PP_Var req_var) { /* * naclprocess.js is required in order send requests to JavaScript. * If NACL_PROCESS is not set in the environment then we assume it is * not present and exit early. Without this check we would block forever * waiting for a response for the JavaScript side. * * Only check this once per process, as some programs (emacs) * engage in manipulation of the environment that may not be safely * read at all times. */ static int checked_for_nacl_process = 0; if (!checked_for_nacl_process) { const char* naclprocess = getenv("NACL_PROCESS"); if (naclprocess == NULL) { fprintf(stderr, "nspawn_send_request called without NACL_PROCESS set\n"); return PP_MakeNull(); } checked_for_nacl_process = 1; } int64_t id = get_request_id(); char req_id[64]; sprintf(req_id, "%lld", id); nspawn_dict_setstring(req_var, "id", req_id); struct NaClSpawnReply reply; pthread_mutex_init(&reply.mu, NULL); pthread_cond_init(&reply.cond, NULL); PSEventRegisterMessageHandler(req_id, &handle_reply, &reply); PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), req_var); nspawn_var_release(req_var); pthread_mutex_lock(&reply.mu); /* * Wait for response for JavaScript. This can block for an unbounded amount * of time (e.g. waiting for a response to waitpid). */ int error = pthread_cond_wait(&reply.cond, &reply.mu); pthread_mutex_unlock(&reply.mu); pthread_cond_destroy(&reply.cond); pthread_mutex_destroy(&reply.mu); PSEventRegisterMessageHandler(req_id, NULL, &reply); if (error != 0) { fprintf(stderr, "nspawn_send_request: pthread_cond_timedwait: %s\n", strerror(error)); return PP_MakeNull(); } return reply.result_var; }
static int apipe_release(const char* path, struct fuse_file_info* info) { struct PP_Var req_var = nspawn_dict_create(); nspawn_dict_setstring(req_var, "command", "nacl_apipe_close"); nspawn_dict_setint(req_var, "pipe_id", info->fh); nspawn_dict_setint(req_var, "writer", (info->flags & O_WRONLY) == O_WRONLY); struct PP_Var result_var = nspawn_send_request(req_var); int ret = nspawn_dict_getint(result_var, "result"); nspawn_var_release(result_var); return ret; }
static int apipe_read( const char* path, char* buf, size_t count, off_t offset, struct fuse_file_info* info) { struct PP_Var req_var = nspawn_dict_create(); nspawn_dict_setstring(req_var, "command", "nacl_apipe_read"); nspawn_dict_setint(req_var, "pipe_id", info->fh); nspawn_dict_setint(req_var, "count", count); nspawn_dict_setint(req_var, "nonblock", (info->flags & O_NONBLOCK) == O_NONBLOCK); struct PP_Var result_var = nspawn_send_request(req_var); int err = nspawn_dict_getint(result_var, "error"); if (err != 0) { nspawn_var_release(result_var); return -err; } struct PP_Var data = nspawn_dict_get(result_var, "data"); assert(data.type == PP_VARTYPE_ARRAY_BUFFER); uint32_t len; if (!PSInterfaceVarArrayBuffer()->ByteLength(data, &len)) { nspawn_var_release(data); nspawn_var_release(result_var); return -EIO; } void *p = PSInterfaceVarArrayBuffer()->Map(data); if (len > 0 && !p) { nspawn_var_release(data); nspawn_var_release(result_var); return -EIO; } assert(len <= count); memcpy(buf, p, len); PSInterfaceVarArrayBuffer()->Unmap(data); nspawn_var_release(data); nspawn_var_release(result_var); return len; }
int nspawn_dict_getint_release(struct PP_Var dict_var, const char* key) { int ret = nspawn_dict_getint(dict_var, key); nspawn_var_release(dict_var); return ret; }