static ERL_NIF_TERM open_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { posix_errno_t posix_errno; efile_data_t *d; ErlNifPid controlling_process; enum efile_modes_t modes; ERL_NIF_TERM result; efile_path_t path; if(argc != 2 || !enif_is_list(env, argv[1])) { return enif_make_badarg(env); } modes = efile_translate_modelist(env, argv[1]); if((posix_errno = efile_marshal_path(env, argv[0], &path))) { return posix_error_to_tuple(env, posix_errno); } else if((posix_errno = efile_open(&path, modes, efile_resource_type, &d))) { return posix_error_to_tuple(env, posix_errno); } result = enif_make_resource(env, d); enif_release_resource(d); enif_self(env, &controlling_process); if(enif_monitor_process(env, d, &controlling_process, &d->monitor)) { return posix_error_to_tuple(env, EINVAL); } return enif_make_tuple2(env, am_ok, result); }
// fwrite implementation static ERL_NIF_TERM io_libc_fwrite(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { char fmt[1024]; int len = 0; if((len = enif_get_string(env, argv[0], fmt, sizeof(fmt), ERL_NIF_LATIN1)) <= 0) return enif_make_badarg(env); if(!enif_is_list(env, argv[1])) return enif_make_badarg(env); ERL_NIF_TERM items = argv[1]; // At first, allocate result as empty binary ErlNifBinary result; enif_alloc_binary(0, &result); // Get escape sequences one-by-one from fmt with according values from items char *cur_fmt = fmt; int format_result; while ((format_result = format_first(env, &result, &cur_fmt, &items)) > 0) { // Nothing to do here, everything is ok } // good: return resulting binary if (format_result >= 0) return enif_make_binary(env, &result); // bad: make badarg. TODO: return something pointing to erroneous place return enif_make_badarg(env); };
ERL_NIF_TERM decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { Decoder* d; jiffy_st* st = (jiffy_st*) enif_priv_data(env); ERL_NIF_TERM tmp_argv[5]; ERL_NIF_TERM opts; ERL_NIF_TERM val; if(argc != 2) { return enif_make_badarg(env); } d = dec_new(env); if(d == NULL) { return make_error(st, env, "internal_error"); } tmp_argv[0] = argv[0]; tmp_argv[1] = enif_make_resource(env, d); tmp_argv[2] = st->atom_error; tmp_argv[3] = enif_make_list(env, 0); tmp_argv[4] = enif_make_list(env, 0); enif_release_resource(d); opts = argv[1]; if(!enif_is_list(env, opts)) { return enif_make_badarg(env); } while(enif_get_list_cell(env, opts, &val, &opts)) { if(get_bytes_per_iter(env, val, &(d->bytes_per_red))) { continue; } else if(get_bytes_per_red(env, val, &(d->bytes_per_red))) { continue; } else if(enif_compare(val, d->atoms->atom_return_maps) == 0) { #if MAP_TYPE_PRESENT d->return_maps = 1; #else return enif_make_badarg(env); #endif } else if(enif_compare(val, d->atoms->atom_return_trailer) == 0) { d->return_trailer = 1; } else if(enif_compare(val, d->atoms->atom_dedupe_keys) == 0) { d->dedupe_keys = 1; } else if(enif_compare(val, d->atoms->atom_use_nil) == 0) { d->null_term = d->atoms->atom_nil; } else if(get_null_term(env, val, &(d->null_term))) { continue; } else { return enif_make_badarg(env); } } return decode_iter(env, 5, tmp_argv); }
/* * argv[0] an atom * argv[1] a binary * argv[2] a ref * argv[3] 'ok' * argv[4] a fun * argv[5] a pid * argv[6] a port * argv[7] an empty list * argv[8] a non-empty list * argv[9] a tuple */ static ERL_NIF_TERM check_is(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM ok_atom = enif_make_atom(env, "ok"); if (!enif_is_atom(env, argv[0])) return enif_make_badarg(env); if (!enif_is_binary(env, argv[1])) return enif_make_badarg(env); if (!enif_is_ref(env, argv[2])) return enif_make_badarg(env); if (!enif_is_identical(argv[3], ok_atom)) return enif_make_badarg(env); if (!enif_is_fun(env, argv[4])) return enif_make_badarg(env); if (!enif_is_pid(env, argv[5])) return enif_make_badarg(env); if (!enif_is_port(env, argv[6])) return enif_make_badarg(env); if (!enif_is_empty_list(env, argv[7])) return enif_make_badarg(env); if (!enif_is_list(env, argv[7])) return enif_make_badarg(env); if (!enif_is_list(env, argv[8])) return enif_make_badarg(env); if (!enif_is_tuple(env, argv[9])) return enif_make_badarg(env); return ok_atom; }
static ERL_NIF_TERM create_worker_data(ErlNifEnv *env, int32_t argc, const ERL_NIF_TERM *argv) { BundlePaths *bundle_paths; ERL_NIF_TERM list, head, tail, result; unsigned int index, length, string_length; char *new_path; WorkerData *worker_data; (void)(argc); list = argv[0]; if (!enif_is_list(env, list)) return enif_make_badarg(env); enif_get_list_length(env, list, &length); bundle_paths = bundle_paths_new(length); index = 0; tail = list; while (enif_get_list_cell(env, tail, &head, &tail)) { if (!enif_is_list(env, head)) return enif_make_badarg(env); enif_get_list_length(env, head, &string_length); new_path = malloc(sizeof(char) * string_length + 1); if (!enif_get_string(env, head, new_path, string_length + 1, ERL_NIF_LATIN1)) return enif_make_badarg(env); bundle_paths->paths[index] = new_path; index += 1; } worker_data = enif_alloc_resource(WORKER_DATA, sizeof(WorkerData)); worker_data_initialize(worker_data, length); worker_data_read(bundle_paths, worker_data); result = enif_make_resource(env, worker_data); enif_release_resource(&worker_data); bundle_paths_free(&bundle_paths); return result; }
ERL_NIF_TERM encode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { jiffy_st* st = (jiffy_st*) enif_priv_data(env); Encoder* e; ERL_NIF_TERM opts; ERL_NIF_TERM val; ERL_NIF_TERM tmp_argv[3]; if(argc != 2) { return enif_make_badarg(env); } e = enc_new(env); if(e == NULL) { return make_error(st, env, "internal_error"); } tmp_argv[0] = enif_make_resource(env, e); tmp_argv[1] = enif_make_list(env, 1, argv[0]); tmp_argv[2] = enif_make_list(env, 0); enif_release_resource(e); opts = argv[1]; if(!enif_is_list(env, opts)) { return enif_make_badarg(env); } while(enif_get_list_cell(env, opts, &val, &opts)) { if(enif_compare(val, e->atoms->atom_uescape) == 0) { e->uescape = 1; } else if(enif_compare(val, e->atoms->atom_pretty) == 0) { e->pretty = 1; } else if(enif_compare(val, e->atoms->atom_escape_forward_slashes) == 0) { e->escape_forward_slashes = 1; } else if(enif_compare(val, e->atoms->atom_use_nil) == 0) { e->use_nil = 1; } else if(enif_compare(val, e->atoms->atom_force_utf8) == 0) { // Ignore, handled in Erlang } else if(get_bytes_per_iter(env, val, &(e->bytes_per_red))) { continue; } else if(get_bytes_per_red(env, val, &(e->bytes_per_red))) { continue; } else { return enif_make_badarg(env); } } return encode_iter(env, 3, tmp_argv); }
static ERL_NIF_TERM eval2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary script_binary; if (!enif_inspect_binary(env, argv[0], &script_binary)){ return enif_make_badarg(env); } if (!enif_is_list(env, argv[1])) { enif_release_binary(&script_binary); return enif_make_badarg(env); } mrb_state *mrb; mrbc_context *cxt; mrb = mrb_open(); if (mrb == NULL) { return enif_make_atom(env, "error"); } unsigned int mrb_argv_len; enif_get_list_length(env, argv[1], &mrb_argv_len); mrb_value mrb_argv = mrb_ary_new(mrb); ERL_NIF_TERM cur; for(cur = argv[1]; !enif_is_empty_list(env, cur); ) { ERL_NIF_TERM head, tail; enif_get_list_cell(env, cur, &head, &tail); mrb_ary_push(mrb, mrb_argv, erl2mruby(env, mrb, head)); cur = tail; } mrb_define_global_const(mrb, "ARGV", mrb_argv); char *script = malloc(script_binary.size+1); strncpy(script, (const char *)script_binary.data, (int)script_binary.size); script[script_binary.size] = '\0'; cxt = mrbc_context_new(mrb); struct mrb_parser_state* st = mrb_parse_string(mrb, (const char *)script, cxt); int n = mrb_generate_code(mrb, st); mrb_pool_close(st->pool); mrb_value result = mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_nil_value()); ERL_NIF_TERM erl_result = mruby2erl(env, mrb, result); free(script); mrbc_context_free(mrb, cxt); mrb_close(mrb); enif_release_binary(&script_binary); return erl_result; }
static ERL_NIF_TERM open_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { posix_errno_t posix_errno; efile_data_t *d; ErlNifPid controlling_process; enum efile_modes_t modes; ERL_NIF_TERM result; efile_path_t path; ASSERT(argc == 2); if(!enif_is_list(env, argv[1])) { return enif_make_badarg(env); } modes = efile_translate_modelist(env, argv[1]); if((posix_errno = efile_marshal_path(env, argv[0], &path))) { return posix_error_to_tuple(env, posix_errno); } else if((posix_errno = efile_open(&path, modes, efile_resource_type, &d))) { return posix_error_to_tuple(env, posix_errno); } enif_self(env, &controlling_process); if(enif_monitor_process(env, d, &controlling_process, &d->monitor)) { /* We need to close the file manually as we haven't registered a * destructor. */ posix_errno_t ignored; erts_atomic32_set_acqb(&d->state, EFILE_STATE_CLOSED); efile_close(d, &ignored); return posix_error_to_tuple(env, EINVAL); } /* Note that we do not call enif_release_resource at this point. While it's * normally safe to leave resource management to the GC, efile_close is a * blocking operation which must not be done in the GC callback, and we * can't defer it as the resource is gone as soon as it returns. * * We instead keep the resource alive until efile_close is called, after * which it's safe to leave things to the GC. If the controlling process * were to die before the user had a chance to close their file, the above * monitor will tell the erts_prim_file process to close it for them. */ result = enif_make_resource(env, d); return enif_make_tuple2(env, am_ok, result); }
static ERL_NIF_TERM elua_gencall_sync(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { elua_t *res; // first arg: ref if(!enif_get_resource(env, argv[0], RES_SYNC, (void**) &res)) { return enif_make_badarg(env); } if(!enif_is_list(env, argv[3])) { return enif_make_badarg(env); } return gencall(env, res->L, argv[1], argv[2], argv[3]); }
static ERL_NIF_TERM nif_scheduler_reconcileTasks(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { unsigned int length ; state_ptr state = (state_ptr) enif_priv_data(env); if(state->initilised == 0 ) { return enif_make_tuple2(env, enif_make_atom(env, "state_error"), enif_make_atom(env, "scheduler_not_inited")); } if(!enif_is_list(env, argv[0])) { return enif_make_tuple3(env, enif_make_atom(env, "argument_error"), enif_make_atom(env, "invalid_or_corrupted_parameter"), enif_make_atom(env, "task_status_array")); }; if(!enif_get_list_length(env, argv[0], &length)) { return enif_make_tuple3(env, enif_make_atom(env, "argument_error"), enif_make_atom(env, "invalid_or_corrupted_parameter"), enif_make_atom(env, "task_status_array")); } ErlNifBinary binary_arr[length]; if(!inspect_array_of_binary_objects(env, argv[0], &binary_arr )) { return enif_make_tuple3(env, enif_make_atom(env, "argument_error"), enif_make_atom(env, "invalid_or_corrupted_parameter"), enif_make_atom(env, "task_status_array")); } BinaryNifArray binaryNifArrayHolder ; binaryNifArrayHolder.length = length; binaryNifArrayHolder.obj = &binary_arr[0]; SchedulerDriverStatus status = scheduler_reconcileTasks( state->scheduler_state, &binaryNifArrayHolder); return get_return_value_from_status(env, status); }
static ERL_NIF_TERM elua_gencall_async(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { elua_t *res; msg_t *msg; ErlNifPid pid; if(argc != 6) { return enif_make_badarg(env); } // first arg: ref if(!enif_get_resource(env, argv[0], RES_SYNC, (void**) &res)) { return enif_make_badarg(env); } // ref if(!enif_is_ref(env, argv[1])) { return make_error_tuple(env, "invalid_ref"); } // dest pid if(!enif_get_local_pid(env, argv[2], &pid)) { return make_error_tuple(env, "invalid_pid"); } // fourth arg: list of input args if(!enif_is_list(env, argv[5])) { return enif_make_badarg(env); } msg = msg_create(); if(!msg) { return make_error_tuple(env, "command_create_failed"); } msg->type = msg_gencall; msg->ref = enif_make_copy(msg->env, argv[1]); msg->pid = pid; msg->arg1 = enif_make_copy(msg->env, argv[3]); msg->arg2 = enif_make_copy(msg->env, argv[4]); msg->arg3 = enif_make_copy(msg->env, argv[5]); msg->res = res; return push_command(env, res, msg); }
static ERL_NIF_TERM open_1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { char *device; unsigned int length; uint8_t tmp8; uint32_t tmp32; state.env = env; state.fd = -1; state.mode = 0; state.bits_per_word = 0; state.max_speed_hz = 0; if (argc != 1 || !enif_is_list(env, argv[0])) return enif_make_badarg(env); if (!enif_get_list_length(env, argv[0], &length)) return enif_make_badarg(env); device = (char *) enif_alloc(length + 1); enif_get_string(env, argv[0], device, length + 1, ERL_NIF_LATIN1); if ((state.fd = open(device, O_RDWR, 0)) == -1) { return enif_make_badarg(env); } if (ioctl(state.fd, SPI_IOC_RD_MODE, &tmp8) == -1) { close(state.fd); enif_free(device); return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, "read mode", ERL_NIF_LATIN1)); } state.mode = tmp8; if (ioctl(state.fd, SPI_IOC_RD_BITS_PER_WORD, &tmp8) == -1) { close(state.fd); enif_free(device); return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, "read bits per word", ERL_NIF_LATIN1)); } state.bits_per_word = tmp8; if (ioctl(state.fd, SPI_IOC_RD_MAX_SPEED_HZ, &tmp32) == -1) { close(state.fd); enif_free(device); return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, "read max speed hz", ERL_NIF_LATIN1)); } state.max_speed_hz = tmp32; enif_free(device); return enif_make_atom(env, "ok"); }
static ERL_NIF_TERM xfer2_1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { int status, val, i; struct spi_ioc_transfer xfer; uint8_t *txbuf, *rxbuf; unsigned int length; ERL_NIF_TERM cell, head, tail, res, list; if (state.fd == -1) return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, "device closed", ERL_NIF_LATIN1)); if (argc != 1 || !enif_is_list(env, argv[0])) return enif_make_badarg(env); if (!enif_get_list_length(env, argv[0], &length)) return enif_make_badarg(env); txbuf = (uint8_t *) enif_alloc(sizeof(uint8_t) * length); rxbuf = (uint8_t *) enif_alloc(sizeof(uint8_t) * length); list = argv[0]; for (i = 0; enif_get_list_cell(env, list, &head, &tail); ++i, list = tail) { if (!enif_get_int(env, head, &val)) { return enif_make_badarg(env); } txbuf[i] = val; } xfer.tx_buf = (unsigned long) txbuf; xfer.rx_buf = (unsigned long) rxbuf; xfer.len = length; status = ioctl(state.fd, SPI_IOC_MESSAGE(1), &xfer); if (status < 0) { enif_free(txbuf); enif_free(rxbuf); return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, "spi ioc message", ERL_NIF_LATIN1)); } list = enif_make_list(env, 0); for (i = length - 1; i >= 0; --i) { cell = enif_make_uint(env, (unsigned int) rxbuf[i]); list = enif_make_list_cell(env, cell, list); } res = enif_make_tuple2(env, enif_make_atom(env, "ok"), list); enif_free(txbuf); enif_free(rxbuf); return res; }
int enc_init(Encoder* e, ErlNifEnv* env, ERL_NIF_TERM opts, ErlNifBinary* bin) { ERL_NIF_TERM val; e->env = env; e->atoms = enif_priv_data(env); e->uescape = 0; e->pretty = 0; e->shiftcnt = 0; e->count = 0; if(!enif_is_list(env, opts)) { return 0; } while(enif_get_list_cell(env, opts, &val, &opts)) { if(enif_compare(val, e->atoms->atom_uescape) == 0) { e->uescape = 1; } else if(enif_compare(val, e->atoms->atom_pretty) == 0) { e->pretty = 1; } else if(enif_compare(val, e->atoms->atom_force_utf8) == 0) { // Ignore, handled in Erlang } else { return 0; } } e->iolen = 0; e->iolist = enif_make_list(env, 0); e->curr = bin; if(!enif_alloc_binary(BIN_INC_SIZE, e->curr)) { return 0; } memset(e->curr->data, 0, e->curr->size); e->p = (char*) e->curr->data; e->u = (unsigned char*) e->curr->data; e->i = 0; return 1; }
static void push_nif_list(lua_State* lua, ERL_NIF_TERM list, ErlNifEnv* env, ErlNifResourceType* resource_type) { const int top = lua_gettop(lua); int map_count = 0; int array_count = 0; if(enif_is_list(env, list)) { ERL_NIF_TERM head; ERL_NIF_TERM tail = list; while(enif_get_list_cell(env, tail, &head, &tail)) { if(push_table_iskvp(env, head, NULL)) { ++map_count; } else { ++array_count; } } luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_createtable(lua, array_count, map_count); ERL_NIF_TERM array_items[array_count + map_count]; tail = list; int index = 0; while(enif_get_list_cell(env, tail, &head, &tail)) { if(!push_table_set(lua, env, head, resource_type)) { array_items[index++] = head; } } push_table_append(lua, env, resource_type, array_items, index); } assert(lua_gettop(lua) == top+1); }
ERL_NIF_TERM meter_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { meter_handle *handle = (meter_handle *)enif_alloc_resource(meter_RESOURCE, sizeof(meter_handle)); if (enif_is_list(env, argv[0])) { memset(handle, '\0', sizeof(meter_handle)); pthread_mutex_init(&(handle->m), NULL); handle->tick_interval = DEFAULT_METER_TICK_INTERVAL; fold(env, argv[0], parse_meter_option, *handle); handle->p = new meter<>(handle->tick_interval); ERL_NIF_TERM result = enif_make_resource(env, handle); enif_release_resource(handle); return enif_make_tuple2(env, ATOM_OK, result); } else { return enif_make_badarg(env); } }
ERL_NIF_TERM histogram_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { histogram_handle *handle = (histogram_handle *)enif_alloc_resource(histogram_RESOURCE, sizeof(histogram_handle)); if (enif_is_list(env, argv[0])) { memset(handle, '\0', sizeof(histogram_handle)); pthread_mutex_init(&(handle->m), NULL); handle->size = DEFAULT_RESERVOIR_SIZE; handle->width = DEFAULT_WINDOW_WIDTH; fold(env, argv[0], parse_histogram_option, *handle); handle->p = new histogram<>(handle->size, handle->width); ERL_NIF_TERM result = enif_make_resource(env, handle); enif_release_resource(handle); return enif_make_tuple2(env, ATOM_OK, result); } else { return enif_make_badarg(env); } }
static ERL_NIF_TERM xfer_2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { unsigned int channel, length; int result, i, val; uint8_t *buffer; ERL_NIF_TERM cell, head, tail, list; if (argc < 2 || !enif_is_number(env, argv[0]) || !enif_is_list(env, argv[1])) { return enif_make_badarg(env); } if (!enif_get_uint(env, argv[0], &channel) || channel < 0 || channel > 1) { return enif_make_badarg(env); } if (!enif_get_list_length(env, argv[1], &length) || length == 0) { return enif_make_badarg(env); } buffer = (uint8_t *) enif_alloc(sizeof(uint8_t) * length); list = argv[1]; for (i = 0; enif_get_list_cell(env, list, &head, &tail); ++i, list = tail) { if (!enif_get_int(env, head, &val)) { return enif_make_badarg(env); } buffer[i] = val; } result = wiringPiSPIDataRW(channel, buffer, length); if (result == -1) { result = errno; enif_free(buffer); return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, result)); } list = enif_make_list(env, 0); for (i = length - 1; i >= 0; --i) { cell = enif_make_uint(env, (unsigned int) buffer[i]); list = enif_make_list_cell(env, cell, list); } enif_free(buffer); return enif_make_tuple2(env, enif_make_atom(env, "ok"), list); }
static ERL_NIF_TERM exec_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { unsigned path_length, args_count, arg_length; ERL_NIF_TERM head, tail; int i = 0; enif_get_list_length(env, argv[0], &path_length); enif_get_list_length(env, argv[1], &args_count); char* exec_argv[args_count + 2]; char path[path_length + 1]; if (!enif_get_string(env, argv[0], path, path_length + 1, ERL_NIF_LATIN1) || !enif_is_list(env, argv[1])) { return enif_make_badarg(env); } tail = argv[1]; while(enif_get_list_cell(env, tail, &head, &tail) != 0) { enif_get_list_length(env, head, &arg_length); char* arg = (char*) malloc(sizeof(char) * (arg_length + 1)); if (!enif_get_string(env, head, arg, arg_length + 1, ERL_NIF_LATIN1)) { return enif_make_badarg(env); } exec_argv[i + 1] = arg; i++; } exec_argv[0] = path; exec_argv[args_count + 1] = NULL; execv(path, exec_argv); return enif_make_atom(env, "ok"); }
static ERL_NIF_TERM nif_notify(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary summary; ErlNifBinary body; ErlNifBinary icon; ErlNifBinary category; int urgency = NOTIFY_URGENCY_NORMAL; int timeout = 0; gchar *s_summary = NULL; gchar *s_body = NULL; gchar *s_icon = NULL; gchar *s_category = NULL; ERL_NIF_TERM hints; ERL_NIF_TERM head; ERL_NIF_TERM tail; const ERL_NIF_TERM *array; int arity = 0; NotifyNotification *notify = NULL; ERL_NIF_TERM rv = atom_ok; if (!enif_inspect_iolist_as_binary(env, argv[0], &summary)) return enif_make_badarg(env); if (!enif_inspect_iolist_as_binary(env, argv[1], &body)) return enif_make_badarg(env); if (!enif_inspect_iolist_as_binary(env, argv[2], &icon)) return enif_make_badarg(env); if (!enif_inspect_iolist_as_binary(env, argv[3], &category)) return enif_make_badarg(env); if (!enif_get_int(env, argv[4], &urgency)) return enif_make_badarg(env); if (!enif_get_int(env, argv[5], &timeout)) return enif_make_badarg(env); if (!enif_is_list(env, argv[6])) return enif_make_badarg(env); hints = argv[6]; s_summary = stralloc(&summary); s_body = stralloc(&body); s_icon = stralloc(&icon); s_category = stralloc(&category); if ( (s_summary == NULL) || (s_body == NULL) || (s_icon == NULL) || (s_category == NULL)) { rv = enif_make_tuple2(env, atom_error, atom_nomem); goto ERR; } notify = notify_notification_new(s_summary, s_body, s_icon); notify_notification_set_category(notify, s_category); notify_notification_set_urgency(notify, urgency); notify_notification_set_timeout(notify, timeout); while (enif_get_list_cell(env, hints, &head, &tail)) { ERL_NIF_TERM key; ERL_NIF_TERM value = atom_undefined; if (enif_get_tuple(env, head, &arity, &array)) { switch (arity) { case 2: value = array[1]; key = array[0]; break; default: rv = enif_make_badarg(env); goto ERR; } } else if (enif_is_list(env, head)) { arity = 0; key = head; } else { rv = enif_make_badarg(env); goto ERR; } if (notify_hints_type(env, notify, arity, key, value) < 0) { rv = enif_make_badarg(env); goto ERR; } hints = tail; } notify_notification_show(notify, NULL); ERR: if (notify) g_object_unref(G_OBJECT(notify)); strfree(s_summary); strfree(s_body); strfree(s_icon); strfree(s_category); return rv; }
static void push_nif_term(lua_State* lua, ERL_NIF_TERM message, ErlNifEnv* env, ErlNifResourceType* resource_type) { const int top = lua_gettop(lua); if(enif_is_atom(env, message)) { push_nif_atom(lua, message, env); } else if(enif_is_binary(env, message)) { // TODO @@@ binary also seems to be the custom types // that erlang makes. This may be OK, but maybe we should // think about putting a special type for them in lua push_nif_binary(lua, message, env); } else if(enif_is_list(env, message)) { if(enif_is_empty_list(env, message)) { luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_newtable(lua); } else { // TODO @@@ try to send it as an IO list first and // if that fails send it as a regular list push_nif_list(lua, message, env, resource_type); } } else if(enif_is_tuple(env, message)) { push_nif_tuple(lua, message, env, resource_type); } else if(enif_is_pid(env, message)) { push_nif_pid(lua, message, env); } else if(enif_is_ref(env, message)) { push_nif_ref(lua, message, env); } else if(enif_is_exception(env, message)) { //printf("#exception\n"); luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_pushliteral(lua, "sending an exception is not supported"); } else if(enif_is_fun(env, message)) { //printf("#fun\n"); luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_pushliteral(lua, "sending a function reference is not supported"); } else if(enif_is_port(env, message)) { //printf("#port\n"); luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_pushliteral(lua, "sending a port is not supported"); } else { // thank you r14 -- must be a number push_nif_number(lua, message, env); } assert(lua_gettop(lua) == top+1); }
static ERL_NIF_TERM gencall(ErlNifEnv *env, lua_State *L, const ERL_NIF_TERM arg_func, const ERL_NIF_TERM arg_fmt, const ERL_NIF_TERM arg_list) { char buff_str[STACK_STRING_BUFF]; char buff_fmt[STACK_STRING_BUFF]; char buff_fun[STACK_STRING_BUFF/2]; unsigned input_len=0; unsigned output_len=0; if(enif_get_string(env, arg_func, buff_fun, STACK_STRING_BUFF/2, ERL_NIF_LATIN1)<=0){ return enif_make_badarg(env); } if(enif_get_string(env, arg_fmt, buff_fmt, STACK_STRING_BUFF, ERL_NIF_LATIN1)<=0){ return enif_make_badarg(env); } if(!enif_is_list(env, arg_list)){ return enif_make_badarg(env); } input_len = strchr(buff_fmt, ':') - buff_fmt; output_len = strlen(buff_fmt) - input_len -1; // printf("input args %d output args %d fun %s\n", input_len, output_len, buff_fun); ERL_NIF_TERM head,tail,list; list=arg_list; int i=0, status = 0, ret; ERL_NIF_TERM return_list = enif_make_list(env, 0); lua_getglobal(L, buff_fun); const char *error; while(buff_fmt[i]!='\0') { // printf("i:%d %c\n", i, buff_fmt[i]); if(status==0 && buff_fmt[i]!=':') { ret = enif_get_list_cell(env, list, &head, &tail); if(!ret) { error = FMT_AND_LIST_NO_MATCH; goto error; } list=tail; } switch(buff_fmt[i]) { case ':' : status=1; if(lua_pcall(L, input_len, output_len,0) != LUA_OK) { error = lua_tostring(L, -1); lua_pop(L,1); return enif_make_tuple2(env, atom_error, enif_make_string(env, error, ERL_NIF_LATIN1)); } //output_len = - 1; break; case 'i': if( status == 0) { int input_int; ret = enif_get_int(env, head, &input_int); // printf("input %d\n", input_int); if(!ret) { error = FMT_AND_LIST_NO_MATCH; goto error; } lua_pushinteger(L, input_int); } else if ( status==1 ){ int isnum; int n = lua_tointegerx(L, -1, &isnum); if(!isnum){ error = FMT_AND_LIST_NO_MATCH; goto error; } // printf("output %d %d\n", output_len, n); return_list = enif_make_list_cell(env, enif_make_int(env, n), return_list); lua_pop(L,1); output_len--; } break; case 's': if( status == 0) { ret = enif_get_string(env, head, buff_str, STACK_STRING_BUFF, ERL_NIF_LATIN1); if(ret<=0) { error = FMT_AND_LIST_NO_MATCH; goto error; } lua_pushstring(L, buff_str); } else if ( status==1 ) { const char *s = lua_tostring(L, -1); if (s==NULL) { error = FMT_AND_RET_NO_MATCH; goto error; } // printf("output %d %s\n", output_len, s); return_list = enif_make_list_cell(env, enif_make_string(env, s, ERL_NIF_LATIN1), return_list); lua_pop(L,1); output_len--; } break; /* case 'd': */ /* break; */ /* case 'b': */ /* break; */ default: error = FMT_WRONG; goto error; break; } i++; } return enif_make_tuple2(env, atom_ok, return_list); error: // printf("in error \n"); // @fix clean the heap var. // before call, pop the call if(status ==0 ) { lua_pop(L, 1); } else if(output_len>0) { lua_pop(L, output_len); } return make_error_tuple(env, error); }
static ERL_NIF_TERM trace_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { lttng_decl_procbuf(pid); unsigned int len; char undef[] = "undefined"; lttng_pid_to_str(argv[2], pid); if (argv[0] == atom_call) { const ERL_NIF_TERM* tuple; int arity; lttng_decl_mfabuf(mfa); if (enif_get_tuple(env, argv[3], &arity, &tuple)) { if (enif_is_list(env, tuple[2])) { enif_get_list_length(env, tuple[2], &len); } else { enif_get_uint(env, tuple[2], &len); } lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); LTTNG3(function_call, pid, mfa, 0); } else { LTTNG3(function_call, pid, undef, 0); } } else if (argv[0] == atom_return_from) { const ERL_NIF_TERM* tuple; int arity; lttng_decl_mfabuf(mfa); if (enif_get_tuple(env, argv[3], &arity, &tuple)) { enif_get_uint(env, tuple[2], &len); lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); LTTNG3(function_return, pid, mfa, 0); } else { LTTNG3(function_return, pid, undef, 0); } } else if (argv[0] == atom_return_to) { const ERL_NIF_TERM* tuple; int arity; lttng_decl_mfabuf(mfa); if (enif_get_tuple(env, argv[3], &arity, &tuple)) { enif_get_uint(env, tuple[2], &len); lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); LTTNG3(function_return, pid, mfa, 0); } else { LTTNG3(function_return, pid, undef, 0); } } else if (argv[0] == atom_exception_from) { const ERL_NIF_TERM* tuple; int arity; lttng_decl_mfabuf(mfa); char class[LTTNG_BUFFER_SZ]; enif_get_tuple(env, argv[4], &arity, &tuple); erts_snprintf(class, LTTNG_BUFFER_SZ, "%T", tuple[0]); if (enif_get_tuple(env, argv[3], &arity, &tuple)) { enif_get_uint(env, tuple[2], &len); lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); LTTNG3(function_exception, pid, mfa, class); } else {
ERL_NIF_TERM encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { Encoder enc; Encoder* e = &enc; ErlNifBinary bin; ERL_NIF_TERM ret; ERL_NIF_TERM stack; ERL_NIF_TERM curr; ERL_NIF_TERM item; const ERL_NIF_TERM* tuple; int arity; ErlNifSInt64 lval; double dval; if(argc != 2) { return enif_make_badarg(env); } if(!enc_init(e, env, argv[1], &bin)) { return enif_make_badarg(env); } stack = enif_make_list(env, 1, argv[0]); while(!enif_is_empty_list(env, stack)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_identical(curr, e->atoms->ref_object)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_object(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { ret = enc_error(e, "invalid_object_pair"); goto done; } if(arity != 2) { ret = enc_error(e, "invalid_object_pair"); goto done; } if(!enc_comma(e)) { ret = enc_error(e, "internal_error"); goto done; } if(!enc_string(e, tuple[0])) { ret = enc_error(e, "invalid_object_key"); goto done; } if(!enc_colon(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_object, stack); stack = enif_make_list_cell(env, tuple[1], stack); } else if(enif_is_identical(curr, e->atoms->ref_array)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_array(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enc_comma(e)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else if(enif_compare(curr, e->atoms->atom_null) == 0) { if(!enc_literal(e, "null", 4)) { ret = enc_error(e, "null"); goto done; } } else if(enif_compare(curr, e->atoms->atom_true) == 0) { if(!enc_literal(e, "true", 4)) { ret = enc_error(e, "true"); goto done; } } else if(enif_compare(curr, e->atoms->atom_false) == 0) { if(!enc_literal(e, "false", 5)) { ret = enc_error(e, "false"); goto done; } } else if(enif_is_binary(env, curr)) { if(!enc_string(e, curr)) { ret = enc_error(e, "invalid_string"); goto done; } } else if(enif_is_atom(env, curr)) { if(!enc_string(e, curr)) { ret = enc_error(e, "invalid_string"); goto done; } } else if(enif_get_int64(env, curr, &lval)) { if(!enc_long(e, lval)) { ret = enc_error(e, "internal_error"); goto done; } } else if(enif_get_double(env, curr, &dval)) { if(!enc_double(e, dval)) { ret = enc_error(e, "internal_error"); goto done; } } else if(enif_get_tuple(env, curr, &arity, &tuple)) { if(arity != 1) { ret = enc_error(e, "invalid_ejson"); goto done; } if(!enif_is_list(env, tuple[0])) { ret = enc_error(e, "invalid_object"); goto done; } if(!enc_start_object(e)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, tuple[0])) { if(!enc_end_object(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, tuple[0], &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { ret = enc_error(e, "invalid_object_member"); goto done; } if(arity != 2) { ret = enc_error(e, "invalid_object_member_arity"); goto done; } if(!enc_string(e, tuple[0])) { ret = enc_error(e, "invalid_object_member_key"); goto done; } if(!enc_colon(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_object, stack); stack = enif_make_list_cell(env, tuple[1], stack); } else if(enif_is_list(env, curr)) { if(!enc_start_array(e)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_array(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else { if(!enc_unknown(e, curr)) { ret = enc_error(e, "internal_error"); goto done; } } } if(!enc_done(e, &item)) { ret = enc_error(e, "internal_error"); goto done; } if(e->iolen == 0) { ret = item; } else { ret = enif_make_tuple2(env, e->atoms->atom_partial, item); } done: enc_destroy(e); return ret; }
/* 0: list */ static ERL_NIF_TERM nif_alloc(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM head = {0}; ERL_NIF_TERM tail = {0}; int arity = 0; char key[MAXATOMLEN+1]; /* Includes terminating NULL */ const ERL_NIF_TERM *array = NULL; ERL_NIF_TERM resources = {0}; ErlNifBinary req = {0}; if (!enif_is_list(env, argv[0]) || enif_is_empty_list(env, argv[0])) return enif_make_badarg(env); resources = enif_make_list(env, 0); if (!enif_alloc_binary(0, &req)) return error_tuple(env, ENOMEM); tail = argv[0]; /* [binary(), {ptr, integer()}, {ptr, binary()}, ...] */ while (enif_get_list_cell(env, tail, &head, &tail)) { int index = req.size; ErlNifBinary bin = {0}; if (enif_inspect_binary(env, head, &bin)) { enif_realloc_binary(&req, req.size+bin.size); (void)memcpy(req.data+index, bin.data, bin.size); } else if (enif_get_tuple(env, head, &arity, &array)) { ALLOC_STATE *p = NULL; ERL_NIF_TERM res = {0}; size_t val = 0; ErlNifBinary initial = {0}; if ( (arity != 2) || !enif_get_atom(env, array[0], key, sizeof(key), ERL_NIF_LATIN1) || (strcmp(key, "ptr") != 0)) return enif_make_badarg(env); if ( !(enif_get_ulong(env, array[1], (unsigned long *)&val) && val > 0) && !(enif_inspect_binary(env, array[1], &initial) && initial.size > 0)) return enif_make_badarg(env); val = (initial.size > 0) ? initial.size : val; p = enif_alloc_resource(PROCKET_ALLOC_RESOURCE, sizeof(ALLOC_STATE)); if (p == NULL) return error_tuple(env, ENOMEM); p->size = val; p->buf = calloc(val, 1); if (p->buf == NULL) { enif_release_resource(p); return error_tuple(env, ENOMEM); } if (initial.size > 0) (void)memcpy(p->buf, initial.data, p->size); if (!enif_realloc_binary(&req, req.size+sizeof(void *))) return error_tuple(env, ENOMEM); (void)memcpy(req.data+index, &p->buf, sizeof(void *)); res = enif_make_resource(env, p); enif_release_resource(p); resources = enif_make_list_cell(env, res, resources); } else return enif_make_badarg(env); } return enif_make_tuple3(env, atom_ok, enif_make_binary(env, &req), resources); }
static mrb_value erl2mruby(ErlNifEnv* env, mrb_state* mrb, ERL_NIF_TERM term) { if (enif_is_atom(env, term)) { unsigned len; enif_get_atom_length(env, term, &len, ERL_NIF_LATIN1); char * atom_str = (char *)malloc(sizeof(char)*(len+1)); int r = enif_get_atom(env, term, atom_str, len+1, ERL_NIF_LATIN1); mrb_value value; if(strncmp(atom_str, "nil", r) == 0){ value = mrb_nil_value(); }else if(strncmp(atom_str, "true", r) == 0){ value = mrb_true_value(); }else if(strncmp(atom_str, "false", r) == 0){ value = mrb_false_value(); }else{ value = mrb_symbol_value(mrb_intern_cstr(mrb, atom_str)); } free(atom_str); return value; } else if (enif_is_binary(env, term)) { ErlNifBinary bin; enif_inspect_binary(env, term, &bin); return mrb_str_new(mrb, (const char *)bin.data, bin.size); } else if (enif_is_number(env, term)) { double d; if (enif_get_double(env, term, &d)) { return mrb_float_value(mrb, (mrb_float)d); } else { ErlNifSInt64 i; enif_get_int64(env, term, &i); return mrb_fixnum_value((mrb_int)i); } } else if (enif_is_empty_list(env, term)) { return mrb_ary_new(mrb); } else if (enif_is_list(env, term)) { unsigned len; enif_get_list_length(env, term, &len); mrb_value ary = mrb_ary_new(mrb); ERL_NIF_TERM cur; for (cur = term; !enif_is_empty_list(env, cur); ) { ERL_NIF_TERM head, tail; enif_get_list_cell(env, cur, &head, &tail); mrb_ary_push(mrb, ary, erl2mruby(env, mrb, head)); cur = tail; } return ary; } else if (enif_is_tuple(env, term)) { int arity; const ERL_NIF_TERM * array; enif_get_tuple(env, term, &arity, &array); unsigned len = 0; enif_get_list_length(env, array[0], &len); mrb_value hash = mrb_hash_new(mrb); ERL_NIF_TERM cur; for(cur = array[0]; !enif_is_empty_list(env, cur); ){ ERL_NIF_TERM head, tail; enif_get_list_cell(env, cur, &head, &tail); const ERL_NIF_TERM * array0; int arity0; enif_get_tuple(env, head, &arity0, &array0); mrb_hash_set(mrb, hash, erl2mruby(env, mrb, array0[0]), erl2mruby(env, mrb, array0[1])); cur = tail; } return hash; } else { return mrb_nil_value(); } }
ERL_NIF_TERM _hi_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { hi_ctx_t* ctx = NULL; hh_ctx_t* hdr = NULL; hi_opts_t* opts = NULL; ErlNifResourceType* hh_ctx_type = get_hh_ctx_type(env); ErlNifResourceType* hi_ctx_type = get_hi_ctx_type(env); if (argc != 3 || hh_ctx_type == NULL || hi_ctx_type == NULL || !enif_get_resource(env, argv[0], hi_ctx_type, (void **)&ctx) || !enif_get_resource(env, argv[1], hh_ctx_type, (void **)&hdr) || !enif_is_list(env, argv[2])) { return enif_make_badarg(env); } opts = (hi_opts_t *)enif_alloc(sizeof(hi_opts_t)); parse_opts(env, argv[2], opts, (void *)parse_opt); uint32_t iterator_type = ctx->type; void* it = NULL; if (iterator_type == HDR_ITER_REC) { struct hdr_recorded_iter * iter = enif_alloc(sizeof(struct hdr_recorded_iter)); hdr_recorded_iter_init(iter, hdr->data); it = iter; } if (iterator_type == HDR_ITER_LIN) { if (opts->linear_value_units_per_bucket <= 0) { return make_error(env, "bad_linear_value_unit"); } struct hdr_linear_iter * iter = enif_alloc(sizeof(struct hdr_linear_iter)); hdr_linear_iter_init( iter, hdr->data, opts->linear_value_units_per_bucket); it = iter; } if (iterator_type == HDR_ITER_LOG) { if (opts->log_value_units_first_bucket <= 0) { return make_error(env, "bad_log_value_unit"); } if (opts->log_base <= 0) { return make_error(env, "bad_log_base"); } struct hdr_log_iter * iter = enif_alloc(sizeof(struct hdr_log_iter)); hdr_log_iter_init( iter, hdr->data, opts->log_value_units_first_bucket, opts->log_base); it = iter; } if (iterator_type == HDR_ITER_PCT) { if (opts->percentile_ticks_per_half_distance <= 0) { return make_error(env, "bad_percentile_half_ticks"); } struct hdr_percentile_iter * iter = enif_alloc(sizeof(struct hdr_percentile_iter)); hdr_percentile_iter_init( iter, hdr->data, opts->percentile_ticks_per_half_distance); it = iter; } ctx->type = iterator_type; ctx->opts = opts; ctx->iter = it; return ATOM_OK; }
static void ks_selector_arg(ks_returner_t *ret, ks_pattern_t *pattern, ERL_NIF_TERM arg) { unsigned size; char *string; int result; ErlNifSInt64 integer; if (ret->ready != B_TRUE) { if (enif_is_atom(ret->env, arg)) { enif_get_atom_length(ret->env, arg, &size, ERL_NIF_LATIN1); string = (char *)(malloc(sizeof (char) * (size + 1))); if (string == NULL) { ret->term = EKSTAT_ERROR("atom malloc"); ret->ready = B_TRUE; return; } result = enif_get_atom(ret->env, arg, string, size + 1, ERL_NIF_LATIN1); if (result == 0) { ret->term = enif_make_badarg(ret->env); ret->ready = B_TRUE; } else { if (strncmp(string, "_", result) == 0) { pattern->pstr = "*"; pattern->free = B_FALSE; } else { ret->term = enif_make_badarg(ret->env); ret->ready = B_TRUE; } free(string); } } else if (enif_is_list(ret->env, arg)) { enif_get_list_length(ret->env, arg, &size); string = (char *)(malloc(sizeof (char) * (size + 1))); if (string == NULL) { ret->term = EKSTAT_ERROR("list malloc"); ret->ready = B_TRUE; return; } result = enif_get_string(ret->env, arg, string, size + 1, ERL_NIF_LATIN1); if (result == 0) { ret->term = enif_make_badarg(ret->env); ret->ready = B_TRUE; } else { pattern->pstr = (char *)(ks_safe_strdup(ret, string)); pattern->free = B_TRUE; } free(string); } else if (enif_is_number(ret->env, arg)) { if (enif_get_int64(ret->env, arg, &integer)) { (void) asprintf(&string, "%d", integer); pattern->pstr = (char *)(ks_safe_strdup(ret, string)); pattern->free = B_TRUE; } else { ret->term = enif_make_badarg(ret->env); ret->ready = B_TRUE; } free(string); } else { ret->term = enif_make_badarg(ret->env); ret->ready = B_TRUE; } } }
static ERL_NIF_TERM mmap_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { Mmap *desc; ERL_NIF_TERM f; ErlNifBinary bin_path; char path[PATH_SIZE]; int fd; struct stat st; int debug = 0; ERL_NIF_TERM opt, opts; if (!enif_inspect_binary(env, argv[0], &bin_path)) { return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, "Should pass binary filename", ERL_NIF_LATIN1)); } if (!enif_is_list(env, argv[1])) { return enif_make_badarg(env); } bzero(path, PATH_SIZE); strncpy(path, (const char *)bin_path.data, bin_path.size >= PATH_SIZE ? PATH_SIZE - 1 : bin_path.size); opts = argv[1]; while(enif_get_list_cell(env, opts, &opt, &opts)) { if(!enif_compare(opt, enif_make_atom(env, "debug"))) { debug = 1; } } fd = open(path, O_RDONLY); if(fd == -1) { return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, strerror(errno), ERL_NIF_LATIN1)); } if(fstat(fd, &st)) { close(fd); return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, strerror(errno), ERL_NIF_LATIN1)); } if (debug) fprintf(stderr, "Opened file %s %ld\r\n", path, (ssize_t)st.st_size); desc = (Mmap *)enif_alloc_resource(MmapResource, sizeof(Mmap)); if(!desc) { close(fd); return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, "Couldn't allocate mmap resource", ERL_NIF_LATIN1)); } desc->fd = fd; desc->size = st.st_size; if (debug) fprintf(stderr, "Mmaping file: %p\r\n", desc); desc->ptr = mmap(NULL, desc->size, PROT_READ, MAP_FILE | MAP_PRIVATE, desc->fd, 0); close(fd); if(desc->ptr == MAP_FAILED) { enif_release_resource(desc); return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, "Couldn't mmap", ERL_NIF_LATIN1)); } if (debug) fprintf(stderr, "Mmaped file to %p\r\n", desc->ptr); f = enif_make_resource_binary(env, (void *)desc, desc->ptr, desc->size); enif_release_resource(desc); desc->debug = debug; return enif_make_tuple2(env, enif_make_atom(env, "ok"), f); }
static ERL_NIF_TERM nif_sendmsg(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { int sockfd = -1; int flags = 0; ssize_t n = 0; ErlNifBinary buf = {0}; ErlNifBinary sa = {0}; ERL_NIF_TERM cdata_list, head, tail; char *cdata = NULL; struct iovec iov[1]; struct msghdr message; struct cmsghdr *cmsg; size_t cdata_size = 0; if (!enif_get_int(env, argv[0], &sockfd)) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[1], &buf)) return enif_make_badarg(env); if (!enif_get_int(env, argv[2], &flags)) return enif_make_badarg(env); if (!enif_is_list(env, argv[3])) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[4], &sa)) return enif_make_badarg(env); cdata_list = argv[3]; // figure out how much control data we'll need to send while(enif_get_list_cell(env, cdata_list, &head, &tail)) { const ERL_NIF_TERM* fields; int arity; int level, type; ErlNifBinary cdata_field = {0}; if (!enif_get_tuple(env, head, &arity, &fields) || arity != 3) { return enif_make_badarg(env); } if (!enif_get_int(env, fields[0], &level)) { return enif_make_badarg(env); } if (!enif_get_int(env, fields[1], &type)) { return enif_make_badarg(env); } if (!enif_inspect_binary(env, fields[2], &cdata_field)) { return enif_make_badarg(env); } cdata_size += CMSG_SPACE(cdata_field.size); cdata_list = tail; } if (cdata_size > 0) { // allocate enough control data space, if any // freebsd throws einval if the cdata length is 0 // but the pointer isn't NULL if (!(cdata = malloc(cdata_size))) { return error_tuple(env, ENOMEM); } } // set up the iov and msghdr stuff iov[0].iov_base=(buf.size == 0 ? NULL : buf.data); iov[0].iov_len=buf.size; message.msg_name=(sa.size == 0 ? NULL : sa.data); message.msg_namelen=sa.size; message.msg_iov=iov; message.msg_iovlen=1; message.msg_control=cdata; message.msg_controllen=cdata_size; // loop over the control data again, this time filling in the data in the // msghdr cdata_list = argv[3]; cmsg = CMSG_FIRSTHDR(&message); while(cmsg && enif_get_list_cell(env, cdata_list, &head, &tail)) { const ERL_NIF_TERM* fields; int arity; unsigned char *cmsg_data; ErlNifBinary cdata_field = {0}; // don't need to check here, we'd have crashed in the last loop if // things were wrong enif_get_tuple(env, head, &arity, &fields); enif_get_int(env, fields[0], &cmsg->cmsg_level); enif_get_int(env, fields[1], &cmsg->cmsg_type); enif_inspect_binary(env, fields[2], &cdata_field); cmsg_data = CMSG_DATA(cmsg); // copy the control data into the cdata struct memcpy(cmsg_data, cdata_field.data, cdata_field.size); // set the length cmsg->cmsg_len=CMSG_LEN(cdata_field.size); cdata_list = tail; cmsg = CMSG_NXTHDR(&message,cmsg); } n = sendmsg(sockfd, &message, flags); if (n < 0) return error_tuple(env, errno); return enif_make_tuple2(env, atom_ok, enif_make_int64(env, n)); }