int next_number(GEOSCommand *command, double *value) { int type; int size; char *buffer = command->param_bytes; int *index = &command->index; int ivalue; if(ei_get_type(buffer, index, &type, &size)) { return -1; } int ret = 0; switch(type) { case ERL_SMALL_INTEGER_EXT: case ERL_INTEGER_EXT: if(next_int(command, &ivalue)) { ret = -1; } else *value = ivalue; break; case ERL_FLOAT_EXT: ret = next_double(command, value); break; default: ret = -1; } return ret; }
static void handle_write(const char *req, int *req_index) { if (!uart_is_open(uart)) { send_error_response("ebadf"); return; } int term_size; if (ei_decode_tuple_header(req, req_index, &term_size) < 0 || term_size != 2) errx(EXIT_FAILURE, "expecting {data, timeout}"); int term_type; if (ei_get_type(req, req_index, &term_type, &term_size) < 0 || term_type != ERL_BINARY_EXT) errx(EXIT_FAILURE, "expecting data as a binary"); uint8_t *to_write = malloc(term_size); long amount_to_write; if (ei_decode_binary(req, req_index, to_write, &amount_to_write) < 0) errx(EXIT_FAILURE, "decode binary error?"); long timeout; if (ei_decode_long(req, req_index, &timeout) < 0) errx(EXIT_FAILURE, "expecting timeout"); // uart_write always invokes a callback when it completes (error or no error). uart_write(uart, to_write, amount_to_write, timeout); }
static int select_known_elems(struct exmpp_xml_ctx *ctx, const char *buf, int index) { int type, list_name_len; char list_name[MAXATOMLEN]; struct exmpp_hashtable *kl; if (ei_get_type(buf, &index, &type, &list_name_len) != 0) return (-1); if (ei_decode_atom(buf, &index, list_name) != 0) return (-1); if (strcmp(list_name, "false") == 0) { ctx->check_elems = 0; return (0); } if (strcmp(list_name, "true") == 0) { if (ctx->known_elems == NULL) return (-1); ctx->check_elems = 1; return (0); } kl = exmpp_ht_fetch(known_elems_index, list_name, list_name_len); if (kl == NULL) return (-1); ctx->known_elems = kl; ctx->check_elems = 1; return (0); }
int ei_decode_string_or_binary(char *buf, int *index, int maxlen, char *dst) { int type, size, res; long len; ei_get_type(buf, index, &type, &size); if (type == ERL_NIL_EXT || size == 0) { dst[0] = '\0'; return 0; } if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT) { return -1; } else if (size > maxlen) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of %s with size %d into a buffer of size %d\n", type == ERL_BINARY_EXT ? "binary" : "string", size, maxlen); return -1; } else if (type == ERL_BINARY_EXT) { res = ei_decode_binary(buf, index, dst, &len); dst[len] = '\0'; /* binaries aren't null terminated */ } else { res = ei_decode_string(buf, index, dst); } return res; }
static int update_list(struct exmpp_hashtable *kl, const char *buf, int *index) { int nb_items, i, type, item_len; char item[MAXATOMLEN]; /* We check that we have a real list. */ if (ei_decode_list_header(buf, index, &nb_items) != 0) return (-1); if (nb_items < 0) return (0); for (i = 0; i < nb_items; ++i) { /* Decode the item. */ if (ei_get_type(buf, index, &type, &item_len) != 0) return (-1); if (ei_decode_atom(buf, index, item) != 0) return (-1); /* Add it to the list. */ if (!exmpp_ht_exists(kl, item, item_len)) exmpp_ht_store(kl, item, item_len, &DUMMY); } return (0); }
int ei_decode_string_or_binary(char *buf, int *index, char **dst) { int type, size, res; long len; ei_get_type(buf, index, &type, &size); if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_NIL_EXT) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size); return -1; } *dst = malloc(size + 1); if (type == ERL_NIL_EXT) { res = 0; **dst = '\0'; } else if (type == ERL_BINARY_EXT) { res = ei_decode_binary(buf, index, *dst, &len); (*dst)[len] = '\0'; } else { res = ei_decode_string(buf, index, *dst); } return res; }
int next_string(GEOSCommand *command, char **data) { char *buffer = command->param_bytes; int *index = &command->index; int type; int size; if(ei_get_type(buffer, index, &type, &size)) { return -1; } if(type != ERL_STRING_EXT && type != ERL_BINARY_EXT) { return 1; } char* sdata = (char *) malloc(size); if(sdata == NULL) { return -1; } if(type == ERL_STRING_EXT) { if(ei_decode_string(buffer, index, sdata)) { free(sdata); return -1; } } else { long s; if(ei_decode_binary(buffer, index, sdata, &s)) { free(sdata); return -1; } } *data = sdata; return 0; }
/** * Decode string/binary into destination buffer. * */ int ei_decode_strorbin(char *buf, int *index, int maxlen, char *dst) { int type, size, res; long len; ei_get_type(buf, index, &type, &size); if (type == ERL_NIL_EXT || size == 0) { dst[0] = '\0'; return 0; } if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT) { return -1; } else if (size > maxlen) { LM_ERR("buffer size %d too small for %s with size %d\n", maxlen, type == ERL_BINARY_EXT ? "binary" : "string", size); return -1; } else if (type == ERL_BINARY_EXT) { res = ei_decode_binary(buf, index, dst, &len); dst[len] = '\0'; } else { res = ei_decode_string(buf, index, dst); } return res; }
int next_int(GEOSCommand *command, int *ivalue) { int type; int size; if(ei_get_type(command->param_bytes, &command->index, &type, &size)) { return -1; } switch(type) { case ERL_SMALL_INTEGER_EXT: { char cvalue; if(ei_decode_char(command->param_bytes, &command->index, &cvalue)) { return -1; } *ivalue = (unsigned char) cvalue; return 0; } case ERL_INTEGER_EXT: { long lvalue; if(next_long(command, &lvalue)) { return -1; } *ivalue = (int) lvalue; return 0; } default: return -1; } }
gboolean GN_value_set(int ARI, ei_x_buff *XBUF, char *B, int *I){ GValue* object; int type, len; gboolean v_boolean; gchar v_atom[MAXATOMLEN+1]; gchar* v_gchar; gint64 v_gint64; gdouble v_double; /* no return value */ if ( ! gn_check_arity(XBUF, 2, ARI) ) return FALSE; if ( ! gn_get_arg_struct(XBUF, B, I, "GValue", (void**)&object) ) return FALSE; if ( G_IS_VALUE(object) ) g_value_unset(object); ei_get_type(B,I,&type,&len); /* can't fail */ switch (type) { case ERL_ATOM_EXT: if ( ! ei_decode_boolean(B, I, (int*)&v_boolean) ){ g_value_init(object,G_TYPE_BOOLEAN); g_value_set_boolean(object, v_boolean); } else if ( gn_get_arg_gchar_fix(XBUF, B, I, v_atom) ){ g_value_init(object,G_TYPE_STRING); g_value_set_string(object,v_atom); } else { return FALSE; } break; case ERL_SMALL_INTEGER_EXT: case ERL_INTEGER_EXT: case ERL_SMALL_BIG_EXT: case ERL_LARGE_BIG_EXT: if ( ! gn_get_arg_gint64(XBUF, B, I, &v_gint64) ) return FALSE; g_value_init(object,G_TYPE_INT64); g_value_set_int64(object, v_gint64); break; case ERL_FLOAT_EXT: if ( ! gn_get_arg_gdouble(XBUF, B, I, &v_double) ) return FALSE; g_value_init(object,G_TYPE_DOUBLE); g_value_set_double(object, v_double); break; case ERL_NIL_EXT: case ERL_STRING_EXT: if ( ! gn_get_arg_gchar(XBUF, B, I, &v_gchar) ) return FALSE; g_value_init(object,G_TYPE_STRING); g_value_set_string(object,v_gchar); free(v_gchar); break; default: gn_enc_1_error(XBUF, "bad_erl_type"); return FALSE; break; } gn_put_void(XBUF); return TRUE; }
static switch_status_t handle_msg_api(listener_t *listener, erlang_msg * msg, int arity, ei_x_buff * buf, ei_x_buff * rbuf) { char api_cmd[MAXATOMLEN]; int type; int size; char *arg; switch_bool_t fail = SWITCH_FALSE; if (arity < 3) { fail = SWITCH_TRUE; } ei_get_type(buf->buff, &buf->index, &type, &size); if ((size > (sizeof(api_cmd) - 1)) || ei_decode_atom(buf->buff, &buf->index, api_cmd)) { fail = SWITCH_TRUE; } ei_get_type(buf->buff, &buf->index, &type, &size); arg = malloc(size + 1); if (ei_decode_string_or_binary(buf->buff, &buf->index, size, arg)) { fail = SWITCH_TRUE; } if (!fail) { struct api_command_struct acs = { 0 }; acs.listener = listener; acs.api_cmd = api_cmd; acs.arg = arg; acs.bg = 0; acs.pid = msg->from; api_exec(NULL, (void *) &acs); switch_safe_free(arg); /* don't reply */ return SWITCH_STATUS_FALSE; } else { ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "badarg"); return SWITCH_STATUS_SUCCESS; } }
int my_decode_nil(const char *buf, int *index, struct my_obj* dummy) { int type, size, ret; ret = ei_get_type(buf, index, &type, &size); (*index)++; return ret ? ret : !(type == ERL_NIL_EXT); }
eqmlTerm(const char * buf, int index = 0) : _buf(buf), _index(index) { if (index == 0) ei_decode_version(_buf, &_index, NULL); ei_get_type(_buf, &_index, &_type, &_size); if (isTuple()) ei_decode_tuple_header(_buf, &_index, &_arity); }
/* calculate enough sigle-byte length */ int calcSGByteLength(char* erlBuf, int* pIndex) { int type, size; if (ei_get_type(erlBuf, pIndex, &type, &size) == 0) { return size == 0 ? 64:size + 1; } else { return 0; } }
static char* decode_string(const char *buf, int *index) { int type, length; char *str; ei_get_type(buf, index, &type, &length); str = malloc(sizeof(char) * (length + 1)); ei_decode_string(buf, index, str); return str; }
/** * @brief Helper for decoding atoms that checks the length of the atom * @param buf the request * @param index the index into the request * @param dest where to store the response * @param maxlength the length of the destination * @return -1 on error; 0 on success */ int erlcmd_decode_atom(const char *buf, int *index, char *dest, int maxlength) { int type; int size; if (ei_get_type(buf, index, &type, &size) < 0 || type != ERL_ATOM_EXT || size + 1 > maxlength) return -1; return ei_decode_atom(buf, index, dest); }
static char* decode_binary(const char *buf, int *index, int *len) { int type; char *str; long length; /* from ei_decode_binary */ ei_get_type(buf, index, &type, len); str = malloc(sizeof(char) * (*len + 1)); ei_decode_binary(buf, index, str, &length); assert((int)length == *len); return str; }
static char * alloc_buffer(ei_x_buff *eip, int *index, int *sizep) { int err; int type, size; err = ei_get_type(eip->buff, index, &type, &size); if (err < 0) { msg_warn("cannot get term size"); return NULL; } *sizep = size + 1; return mymalloc(*sizep); }
int ei_decode_atom_safe(char *buf, int *index, char *dst) { int type, size; ei_get_type(buf, index, &type, &size); if (type != ERL_ATOM_EXT) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed atom\n", type, size); return -1; } else if (size > MAXATOMLEN) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of atom with size %d into a buffer of size %d\n", size, MAXATOMLEN); return -1; } else { return ei_decode_atom(buf, index, dst); } }
static int sql_bind_and_exec(sqlite3_drv_t *drv, char *buffer, int buffer_size) { int result; int index = 0; int type, size; const char *rest; sqlite3_stmt *statement; long bin_size; char *command; #ifdef DEBUG fprintf(drv->log, "Preexec: %.*s\n", buffer_size, buffer); fflush(drv->log); #endif ei_decode_version(buffer, &index, NULL); result = ei_decode_tuple_header(buffer, &index, &size); if (result || (size != 2)) { return output_error(drv, SQLITE_MISUSE, "Expected a tuple of SQL command and params"); } // decode SQL statement ei_get_type(buffer, &index, &type, &size); // TODO support any iolists if (type != ERL_BINARY_EXT) { return output_error(drv, SQLITE_MISUSE, "SQL should be sent as an Erlang binary"); } command = driver_alloc(size * sizeof(char)); ei_decode_binary(buffer, &index, command, &bin_size); // assert(bin_size == size) result = sqlite3_prepare_v2(drv->db, command, size, &statement, &rest); driver_free(command); if (result != SQLITE_OK) { return output_db_error(drv); } else if (statement == NULL) { return output_error(drv, SQLITE_MISUSE, "empty statement"); } result = bind_parameters(drv, buffer, buffer_size, &index, statement, &type, &size); if (result == SQLITE_OK) { return sql_exec_statement(drv, statement); } else { return result; // error has already been output } }
static ErlDrvSSizeT syslogdrv_control(ErlDrvData handle, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { syslogdrv_t* d = (syslogdrv_t*)handle; if (d->open) { return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } int index = 0, version, arity, type, size; if (command != SYSLOGDRV_OPEN) { return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } if (ei_decode_version(buf, &index, &version)) { return encode_error(*rbuf, "badver"); } if (ei_decode_tuple_header(buf, &index, &arity) || arity != 3) { return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } if (ei_get_type(buf, &index, &type, &size)) { return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } if (type == ERL_STRING_EXT) { long logopt, facility; if (d->ident) { driver_free(d->ident); } d->ident = driver_alloc(size+1); if (d->ident == NULL) { return encode_error(*rbuf, "enomem"); } if (ei_decode_string(buf, &index, d->ident)) { return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } if (ei_decode_long(buf, &index, &logopt) || ei_decode_long(buf, &index, &facility)) { return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } d->logopt = (int)logopt; d->facility = (int)facility; d->open = 1; return 0; } else { return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } }
/* * Find member in tuple (aka RPC struct) */ static int find_member(erl_rpc_ctx_t *ctx, int arity, const char* member_name) { int index,i=0; int type,size; char key_name[MAXATOMLEN]; /* save position */ index = ctx->request_index; /* { name, Value, name, Value...} */ while (i < arity) { if (ei_get_type(ctx->request->buff,&ctx->request_index,&type,&size)) { erl_rpc_fault(ctx,400,"Bad struct member type"); goto error; } if(ei_decode_atom(ctx->request->buff,&ctx->request_index, key_name)) { erl_rpc_fault(ctx,400,"Bad member name"); goto error; } if (strcasecmp(member_name,key_name)) { if(ei_skip_term(ctx->request->buff,&ctx->request_index)) { erl_rpc_fault(ctx,400,"Unexpected end of struct tuple"); goto error; } continue; } else { /* return at current position */ return 0; } i++; } erl_rpc_fault(ctx,400, "Member %s not found",member_name); error: ctx->request_index = index; return -1; }
/* catch the response to ei_rpc_to (which comes back as {rex, {Ref, Pid}} The {Ref,Pid} bit can be handled by handle_ref_tuple */ static switch_status_t handle_msg_rpcresponse(listener_t *listener, erlang_msg * msg, int arity, ei_x_buff * buf, ei_x_buff * rbuf) { int type, size, arity2, tmpindex; ei_get_type(buf->buff, &buf->index, &type, &size); switch (type) { case ERL_SMALL_TUPLE_EXT: case ERL_LARGE_TUPLE_EXT: tmpindex = buf->index; ei_decode_tuple_header(buf->buff, &tmpindex, &arity2); return handle_ref_tuple(listener, msg, buf, rbuf); default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unknown rpc response\n"); break; } /* no reply */ return SWITCH_STATUS_FALSE; }
static void setup(bloom_drv_t *driver, char *buf, int len) { long n; double e; char *filename; int size; int type; int index = 0; ei_decode_version(buf, &index, NULL); ei_decode_tuple_header(buf, &index, NULL); ei_get_type(buf, &index, &type, &size); filename = driver_alloc(size+1); ei_decode_string(buf, &index, filename); ei_decode_long(buf, &index, &n); ei_decode_double(buf, &index, &e); driver->bloom = bloom_open(filename, n, e); driver_free(filename); }
static int get_known_list_name(const char *buf, int *index, char *list_name, int *list_name_len) { int arity, type; /* The term has the form {List_Name, List}. */ if (ei_decode_tuple_header(buf, index, &arity) != 0) return (-1); if (arity != 2) return (-1); /* Decode the list name. */ if (ei_get_type(buf, index, &type, list_name_len) != 0) return (-1); if (ei_decode_atom(buf, index, list_name) != 0) return (-1); return (0); }
int ei_decode_alloc_string(char *buff, int *index, unsigned char **str, int *len) { int type = 0; EI(ei_get_type(buff, index, &type, len)); if(type == ERL_STRING_EXT) { *str = genq_alloc((sizeof(unsigned char))*(*len+1)); EIC(ei_decode_string_safe(buff, index, *str), free_alloc_string(str, len)); return 0; } else if(type == ERL_LIST_EXT || type == ERL_NIL_EXT) { // String larger than 65535 int arity = 0; EI(ei_decode_list_header(buff, index, &arity)); *str = genq_alloc((sizeof(unsigned char))*(*len+1)); int i; for(i=0; i < *len; ++i) { EIC(ei_decode_char_safe(buff, index, &(*str)[i]), free_alloc_string(str, len)); } (*str)[*len] = '\0'; if(arity > 0) { EIC(ei_skip_term(buff, index), free_alloc_string(str, len)); // skip tail } return 0; } else if(type == ERL_ATOM_EXT) { *str = genq_alloc(sizeof(unsigned char)*(*len+1)); (*str)[*len] = '\0'; EIC(ei_decode_atom_safe(buff, index, *str), free_alloc_string(str, len)); return 0; } else if(type == ERL_BINARY_EXT) { *str = genq_alloc(sizeof(unsigned char)*(*len+1)); (*str)[*len] = '\0'; long llen = 0; EIC(ei_decode_binary(buff, index, *str, &llen), free_alloc_string(str, len)); return 0; } else { LOG("ERROR unknown type %d\n", type); *len = -1; return -1; } }
static int handle_response(DICT_ERLANG *dict_erlang, const char *key, ei_x_buff *resp, char **res) { int err, index = 0; int res_type, res_size; err = ei_get_type(resp->buff, &index, &res_type, &res_size); if (err != 0) { msg_warn_erl("ei_get_type"); return err; } switch (res_type) { case ERL_ATOM_EXT: err = decode_atom(resp, &index, "not_found"); if (err != 0) return err; return 0; case ERL_SMALL_TUPLE_EXT: case ERL_LARGE_TUPLE_EXT: { int arity; err = decode_tuple(resp, &index, 2); if (err == -1) return err; err = decode_atom(resp, &index, "ok"); if (err != 0) return err; *res = decode_bitstring_list(dict_erlang, key, resp, &index); if (*res == NULL) return -1; return 1; } default: msg_warn("unexpected response type"); return -1; } /* NOTREACHED */ }
/* * Handle {name, kv_list} * * name is the serial port name * kv_list a list of configuration values (speed, parity, etc.) */ static void handle_open(const char *req, int *req_index) { int term_type; int term_size; if (ei_decode_tuple_header(req, req_index, &term_size) < 0 || term_size != 2) errx(EXIT_FAILURE, ":open requires a 2-tuple"); char name[32]; long binary_len; if (ei_get_type(req, req_index, &term_type, &term_size) < 0 || term_type != ERL_BINARY_EXT || term_size >= (int) sizeof(name) || ei_decode_binary(req, req_index, name, &binary_len) < 0) { // The name is almost certainly too long, so report that it // doesn't exist. send_error_response("enoent"); return; } name[term_size] = '\0'; struct uart_config config = current_config; if (parse_option_list(req, req_index, &config) < 0) { send_error_response("einval"); return; } // If the uart was already open, close and open it again if (uart_is_open(uart)) uart_close(uart); if (uart_open(uart, name, &config) >= 0) { current_config = config; send_ok_response(); } else { send_error_response(uart_last_error()); } }
/** * @brief Decode a string from Erlang that was either encoded as a list of characters (Erlang) * or as a binary (Elixir). This function also checks the length of the string. * @param buf the request * @param index the index into the request * @param dest where to store the response * @param maxlength the length of the destination * @return -1 on error; 0 on success */ int erlcmd_decode_string(const char *buf, int *index, char *dest, int maxlength) { int type; int size; if (ei_get_type(buf, index, &type, &size) < 0) return -1; if (type == ERL_STRING_EXT) { if (size + 1 > maxlength) return -1; return ei_decode_string(buf, index, dest); } else if (type == ERL_BINARY_EXT) { if (size + 1 > maxlength) return -1; dest[size] = '\0'; long unused; return ei_decode_binary(buf, index, dest, &unused); } else return -1; }
void erl_lua_pushnumber(lua_drv_t *driver_data, char *buf, int index) { double dnum; long long lnum; int type, len; ei_get_type(buf, &index, &type, &len); switch (type) { case ERL_FLOAT_EXT: ei_decode_double(buf, &index, &dnum); lua_pushnumber(driver_data->L, dnum); break; default: ei_decode_longlong(buf, &index, &lnum); lua_pushnumber(driver_data->L, lnum); break; } reply_ok(driver_data); }