/** * 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; }
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); }
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; }
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; }
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; }
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; }
int oe_sizecalc_erlang_binary(CORBA_Environment *ev, int* _index, int* _size) { long _malloc_size = 0; int _error = 0; if(*_size == 0) *_size = ((*_size + sizeof(erlang_binary))+sizeof(double)-1)&~(sizeof(double)-1); if ((_error = ei_decode_binary(ev->_inbuf, _index, 0, &_malloc_size)) < 0) return _error; *_size = ((*_size + (int)_malloc_size)+sizeof(double)-1)&~(sizeof(double)-1); return 0; }
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 char * decode_bitstring(ei_x_buff *eip, int *index) { int err; int size; long len; char *buf; buf = alloc_buffer(eip, index, &size); err = ei_decode_binary(eip->buff, index, buf, &len); if (err < 0) { msg_warn("cannot decode response bitstring"); return NULL; } buf[size-1] = '\0'; return buf; }
int oe_decode_erlang_binary(CORBA_Environment *ev, char *_first, int* _index, erlang_binary *binary) { long _length = 0; int _error = 0; if((char*) binary == _first) *_index = ((*_index + sizeof(erlang_binary))+sizeof(double)-1)&~(sizeof(double)-1); binary->_buffer = (CORBA_octet *)(_first+*_index); if ((_error = ei_decode_binary(ev->_inbuf, &ev->_iin, binary->_buffer, &_length)) < 0) return _error; binary->_length = (CORBA_unsigned_long)_length; *_index = ((*_index)+_length+sizeof(double)-1)&~(sizeof(double)-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; } }
/** * @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; }
/* * 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()); } }
bool decodeBinary(char* erlBuf, int* pIndex, char* outBuf, int bufLen, long* outLen) { int type, size; long long integerValue = 0; double doubleValue = 0; ei_get_type(erlBuf, pIndex, &type, &size); if (bufLen >= size && ei_decode_binary(erlBuf, pIndex, outBuf, outLen) == 0) { } else if (bufLen > size && ei_decode_string(erlBuf, pIndex, outBuf) == 0) { *outLen = strlen(outBuf); } else if (ei_decode_longlong(erlBuf, pIndex, &integerValue) == 0) { snprintf(outBuf, bufLen, "%lld", integerValue); *outLen = strlen(outBuf); } else if (ei_decode_double(erlBuf, pIndex, &doubleValue) == 0) { snprintf(outBuf, bufLen, "%lf", doubleValue); *outLen = strlen(outBuf); } else { return false; } return true; }
bool decodeDouble(char* erlBuf, int* pIndex, double* outValue) { long len = 0; int type, size; long long integerValue = 0; char strValue[64]; if(ei_decode_double(erlBuf, pIndex, outValue) == 0) { } else if (ei_decode_longlong(erlBuf, pIndex, &integerValue) == 0) { *outValue = (double)integerValue; } else if (ei_get_type(erlBuf, pIndex, &type, &size) == 0 && size < 64){ if (ei_decode_string(erlBuf, pIndex, strValue) == 0) { } else if (ei_decode_binary(erlBuf, pIndex, strValue, &len) == 0) { strValue[len] = '\0'; } if (sscanf(strValue, "%lf", outValue) < 1) { return false; } } else { return false; } return true; }
static int decode_gssapi_binary(char *buf, int *index, gss_buffer_desc *bin) { int type = 0; int len = 0; long llen; EI(ei_get_type(buf, index, &type, &len)); EI(type != ERL_BINARY_EXT); bin->length = len; bin->value = malloc(len); llen = len; EI(ei_decode_binary(buf, index, bin->value, &llen)); bin->length = llen; /* fprintf(stderr, "decode_gssapi_binary ok\n"); */ return 0; }
static void i2c_handle_request(const char *req, void *cookie) { struct i2c_info *i2c = (struct i2c_info *) cookie; // Commands are of the form {Command, Arguments}: // { atom(), term() } int req_index = sizeof(uint16_t); if (ei_decode_version(req, &req_index, NULL) < 0) errx(EXIT_FAILURE, "Message version issue?"); int arity; if (ei_decode_tuple_header(req, &req_index, &arity) < 0 || arity != 2) errx(EXIT_FAILURE, "expecting {cmd, args} tuple"); char cmd[MAXATOMLEN]; if (ei_decode_atom(req, &req_index, cmd) < 0) errx(EXIT_FAILURE, "expecting command atom"); char resp[256]; int resp_index = sizeof(uint16_t); // Space for payload size ei_encode_version(resp, &resp_index); if (strcmp(cmd, "read") == 0) { long int len; if (ei_decode_long(req, &req_index, &len) < 0 || len < 1 || len > I2C_SMBUS_BLOCK_MAX) errx(EXIT_FAILURE, "read amount: min=1, max=%d", I2C_SMBUS_BLOCK_MAX); char data[I2C_SMBUS_BLOCK_MAX]; if (i2c_transfer(i2c, 0, 0, data, len)) ei_encode_binary(resp, &resp_index, data,len); else { ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "error"); ei_encode_atom(resp, &resp_index, "i2c_read_failed"); } } else if (strcmp(cmd, "write") == 0) { char data[I2C_SMBUS_BLOCK_MAX]; int len; int type; long llen; if (ei_get_type(req, &req_index, &type, &len) < 0 || type != ERL_BINARY_EXT || len < 1 || len > I2C_SMBUS_BLOCK_MAX || ei_decode_binary(req, &req_index, &data, &llen) < 0) errx(EXIT_FAILURE, "write: need a binary between 1 and %d bytes", I2C_SMBUS_BLOCK_MAX); if (i2c_transfer(i2c, data, len, 0, 0)) ei_encode_atom(resp, &resp_index, "ok"); else { ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "error"); ei_encode_atom(resp, &resp_index, "i2c_write_failed"); } } else if (strcmp(cmd, "wrrd") == 0) { char write_data[I2C_SMBUS_BLOCK_MAX]; char read_data[I2C_SMBUS_BLOCK_MAX]; int write_len; long int read_len; int type; long llen; if (ei_decode_tuple_header(req, &req_index, &arity) < 0 || arity != 2) errx(EXIT_FAILURE, "wrrd: expecting {write_data, read_count} tuple"); if (ei_get_type(req, &req_index, &type, &write_len) < 0 || type != ERL_BINARY_EXT || write_len < 1 || write_len > I2C_SMBUS_BLOCK_MAX || ei_decode_binary(req, &req_index, &write_data, &llen) < 0) errx(EXIT_FAILURE, "wrrd: need a binary between 1 and %d bytes", I2C_SMBUS_BLOCK_MAX); if (ei_decode_long(req, &req_index, &read_len) < 0 || read_len < 1 || read_len > I2C_SMBUS_BLOCK_MAX) errx(EXIT_FAILURE, "wrrd: read amount: min=1, max=%d", I2C_SMBUS_BLOCK_MAX); if (i2c_transfer(i2c, write_data, write_len, read_data, read_len)) ei_encode_binary(resp, &resp_index, read_data, read_len); else { ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "error"); ei_encode_atom(resp, &resp_index, "i2c_wrrd_failed"); } } else errx(EXIT_FAILURE, "unknown command: %s", cmd); debug("sending response: %d bytes", resp_index); erlcmd_send(resp, resp_index); }
void dump_eterm(ei_x_buff *x) { int etype, esize, arity; long long num; char *atom; int i; char *binary; long bin_size; double fnum; ei_get_type(x->buff, &x->index, &etype, &esize); uwsgi_log("etype: %d/%c esize: %d\n", etype, etype, esize); switch(etype) { case ERL_SMALL_INTEGER_EXT: case ERL_INTEGER_EXT: case ERL_SMALL_BIG_EXT: case ERL_LARGE_BIG_EXT: ei_decode_longlong(x->buff, &x->index, &num); uwsgi_log("num: %lu\n", num); break; case ERL_FLOAT_EXT: ei_decode_double(x->buff, &x->index, &fnum); uwsgi_log("float: %f\n", fnum); break; case ERL_STRING_EXT: atom = uwsgi_malloc(esize+1); ei_decode_string(x->buff, &x->index, atom); uwsgi_log("string: %s\n", atom); free(atom); break; case ERL_ATOM_EXT: atom = uwsgi_malloc(esize+1); ei_decode_atom(x->buff, &x->index, atom); uwsgi_log("atom: %s\n", atom); free(atom); break; case ERL_SMALL_TUPLE_EXT: case ERL_LARGE_TUPLE_EXT: ei_decode_tuple_header(x->buff, &x->index, &arity); for(i=0;i<arity;i++) { dump_eterm(x); } break; case ERL_LIST_EXT: case ERL_NIL_EXT: ei_decode_list_header(x->buff, &x->index, &arity); if (arity == 0) { uwsgi_log("nil value\n"); break; } for(i=0;i<arity+1;i++) { dump_eterm(x); } break; case ERL_BINARY_EXT: binary = uwsgi_malloc(esize); ei_decode_binary(x->buff, &x->index, binary, &bin_size); uwsgi_log("binary data of %d bytes\n", bin_size); free(binary); break; default: uwsgi_log("ignored...\n"); ei_skip_term(x->buff, &x->index); break; } }
static ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT, char **rbuf, ErlDrvSizeT) { driver_data_t *data = (driver_data_t *)drv_data; ei_x_buff x; ei_x_new_with_version(&x); switch ((TPCE::eCommand)command) { case TPCE::CMD_ALL_INIT: { int index = 0, version, arity; char atom[MAXATOMLEN+1]; bool found = true; ei_decode_version(buf, &index, &version); ei_decode_list_header(buf, &index, &arity); for (int size = arity, i = 0; found && i < size; i++) { ei_decode_tuple_header(buf, &index, &arity); if (2 == arity) { ei_term term; ei_decode_atom(buf, &index, atom); ei_decode_ei_term(buf, &index, &term); if (0 == strcmp(atom, "id")) { data->id = term.value.i_val; } else if (0 == strcmp(atom, "path") && ERL_STRING_EXT == term.ei_type) { char v[term.size+1]; ei_decode_string(buf, &index, v); strncpy(data->path, v, sizeof(data->path)); } else if (0 == strcmp(atom, "path") && ERL_BINARY_EXT == term.ei_type) { char v[term.size+1]; long l = term.size; ei_decode_binary(buf, &index, v, &l); v[l] = '\0'; strncpy(data->path, v, sizeof(data->path)); } else if (0 == strcmp(atom, "configured_customer_count")) { data->configured_customer_count = term.value.i_val; } else if (0 == strcmp(atom, "active_customer_count")) { data->active_customer_count = term.value.i_val; } else if (0 == strcmp(atom, "scale_factor")) { data->scale_factor = term.value.i_val; } else if (0 == strcmp(atom, "days_of_initial_trades")) { data->days_of_initial_trades = term.value.i_val; } else { found = false; } } } if (found) { ei_x_encode_atom(&x, "ok"); } else { ergen_drv_encode_error1(&x, "badmatch", atom); } } break; case TPCE::CMD_ALL_CONFIG: { ei_x_encode_atom(&x, "ok"); } break; case TPCE::CMD_ALL_ALLOC: { void *ptr = ergen_driver_new(data); if (NULL != ptr) { data->driver = ptr; ei_x_encode_atom(&x, "ok"); } else { ergen_drv_encode_error0(&x, "nomem"); } } break; case TPCE::CMD_ALL_FREE: { void *ptr = data->driver; if (NULL != ptr) { ergen_driver_delete(ptr); data->driver = NULL; } ei_x_encode_atom(&x, "ok"); } break; default: { ergen_drv_encode_error0(&x, "badarg"); } break; } ErlDrvSizeT result = x.index; *rbuf = (char *)ergen_drv_bindup(x.buff, result); ei_x_free(&x); return result; }
/* decode an object and insert it into the table */ static int mn_decode_insert(ei_reg *reg, const char *msgbuf, int *index, char *key) { long keylen; long objlen; long objtype; void *objbuf = NULL; long i; double f; if (ei_decode_long(msgbuf,index,&keylen) || ei_decode_long(msgbuf,index,&objlen) || ei_decode_long(msgbuf,index,&objtype)) return -1; /* decode key */ if (ei_decode_string(msgbuf,index,key)) { if (objbuf) free(objbuf); return -1; } /* finally! decode object and insert in table */ /* don't forget to fix attributes (dirty bit for example) */ /* FIXME: added cast but 64 bit trouble I think */ switch ((int)objtype & EI_REG_TYPEMASK) { case EI_INT: if (ei_decode_long(msgbuf,index,&i)) return -1; ei_reg_setival(reg,key,i); break; case EI_FLT: if (ei_decode_double(msgbuf,index,&f)) return -1; ei_reg_setfval(reg,key,f); break; case EI_STR: objbuf = NULL; if (objlen > 0) { if (!(objbuf = malloc(objlen))) return -1; if (ei_decode_string(msgbuf,index,objbuf)) { free(objbuf); return -1; } ei_reg_setsval(reg,key,objbuf); } else { /* just a pointer to nothing */ if (ei_decode_long(msgbuf,index,&i)) return -1; ei_reg_setsval(reg,key,NULL); } break; case EI_BIN: objbuf = NULL; if (objlen > 0) { if (!(objbuf = malloc(objlen))) return -1; if (ei_decode_binary(msgbuf,index,objbuf,&i)) { free(objbuf); return -1; } /* assert(i == objlen) */ ei_reg_setpval(reg,key,objbuf,objlen); } else { /* just a pointer to nothing */ if (ei_decode_long(msgbuf,index,&i)) return -1; ei_reg_setpval(reg,key,(void *)i,0); } break; default: /* unknown type */ if (objbuf) free(objbuf); return -1; } /* switch */ return 0; }
static int control(ErlDrvData handle, unsigned int command, char* buf, int count, char** res, int res_size) { tcbdb_drv_t *driver = (tcbdb_drv_t*)handle; TCBDB *bdb = driver->bdb; int index = 1, tp, sz, version; char key[MAX_KEY_SIZE], value[MAX_VALUE_SIZE]; long key_size, value_size; long long long_tmp; bool rs; const char *value_tmp = NULL; ei_x_buff x; ei_x_new_with_version(&x); if (bdb == NULL && command != OPEN) return ei_error(&x, "database_not_opened", res, res_size); ei_decode_version(buf, &index, &version); switch (command) { case OPEN: // open(Filepath::string()) if (bdb == NULL) { ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_STRING_EXT) return ei_error(&x, "invalid_argument", res, res_size); TCBDB *bdb = tcbdbnew(); tcbdbsetmutex(bdb); tcbdbsetcache(bdb, 104800, 51200); tcbdbsetxmsiz(bdb, 1048576); tcbdbtune(bdb, 0, 0, 0, 7, -1, BDBTLARGE); char *file = driver_alloc(sz + 1); ei_decode_string(buf, &index, file); rs = tcbdbopen(bdb, file, BDBOWRITER | BDBOCREAT); driver_free(file); if (!rs) return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); driver->bdb = bdb; ei_x_encode_atom(&x, "ok"); } else return ei_error(&x, "database already opened", res, res_size); break; case CLOSE: tcbdbclose(bdb); tcbdbdel(bdb); driver->bdb = NULL; ei_x_encode_atom(&x, "ok"); break; case PUT: case PUTDUP: case PUTCAT: case PUTKEEP: // put({Key::binary(), Value::binary()}) ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_SMALL_TUPLE_EXT || sz != 2) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_tuple_header(buf, &index, &sz); ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &key[0], &key_size); ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT) return ei_error(&x, "invalid_argument", res, res_size); if (sz <= MAX_VALUE_SIZE) { ei_decode_binary(buf, &index, &value[0], &value_size); switch (command) { case PUT: rs = tcbdbput(bdb, &key[0], key_size, &value[0], value_size); break; case PUTDUP: rs = tcbdbputdup(bdb, &key[0], key_size, &value[0], value_size); break; case PUTCAT: rs = tcbdbputcat(bdb, &key[0], key_size, &value[0], value_size); break; default: rs = tcbdbputkeep(bdb, &key[0], key_size, &value[0], value_size); } } else { void *p = driver_alloc(sz); if (p) { ei_decode_binary(buf, &index, p, &value_size); switch (command) { case PUT: rs = tcbdbput(bdb, &key[0], key_size, p, value_size); break; case PUTDUP: rs = tcbdbputdup(bdb, &key[0], key_size, p, value_size); break; case PUTCAT: rs = tcbdbputcat(bdb, &key[0], key_size, p, value_size); break; default: rs = tcbdbputkeep(bdb, &key[0], key_size, p, value_size); } driver_free(p); } else return ei_error(&x, "too long value", res, res_size); }; if (!rs) return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); ei_x_encode_atom(&x, "ok"); break; case GET: // get(Key::binary()) -> {ok, Value} | {error, not_found} ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &key[0], &key_size); value_tmp = tcbdbget3(bdb, &key[0], key_size, &sz); ei_x_encode_tuple_header(&x, 2); if (value_tmp != NULL) { ei_x_encode_atom(&x, "ok"); ei_x_encode_binary(&x, value_tmp, sz); } else { ei_x_encode_atom(&x, "error"); ei_x_encode_atom(&x, "not_found"); } break; case GETDUP: // get(Key::binary()) -> {ok, Values} ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &key[0], &key_size); TCLIST *vals = tcbdbget4(bdb, key, key_size); if (vals) { ei_x_encode_tuple_header(&x, 2); ei_x_encode_atom(&x, "ok"); int j; for (j=0; j<tclistnum(vals); j++) { value_tmp = tclistval(vals, j, &sz); ei_x_encode_list_header(&x, 1); ei_x_encode_binary(&x, value_tmp, sz); } tclistdel(vals); ei_x_encode_empty_list(&x); } else { ei_x_encode_tuple_header(&x, 2); ei_x_encode_atom(&x, "ok"); ei_x_encode_empty_list(&x); } break; case REMOVE: // remove(Keys::list()) // remove(Key::binary()) // remove({Key::binary(), Value::binary()}) ei_get_type(buf, &index, &tp, &sz); if (tp == ERL_LIST_EXT) { int count, j; ei_decode_list_header(buf, &index, &count); for (j=0; j<count; j++) { ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &key[0], &key_size); if (!tcbdbout3(bdb, &key[0], key_size)) return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); } ei_x_encode_atom(&x, "ok"); } else if (tp == ERL_BINARY_EXT && sz <= MAX_KEY_SIZE) { ei_decode_binary(buf, &index, &key[0], &key_size); tcbdbout3(bdb, &key[0], key_size); ei_x_encode_atom(&x, "ok"); } else if (tp == ERL_SMALL_TUPLE_EXT && sz == 2) { ei_decode_tuple_header(buf, &index, &sz); // get key ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &key[0], &key_size); // get value ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_VALUE_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &value[0], &value_size); // remove by key&value BDBCUR *cur = tcbdbcurnew(bdb); if (!tcbdbcurjump(cur, &key[0], key_size)) return ei_error(&x, "record_not_found", res, res_size); bool removed = false, not_found = false; while (!removed && !not_found) { int cur_key_size, cur_val_size; const void *curkey = tcbdbcurkey3(cur, &cur_key_size); if (cur_key_size == key_size && memcmp(curkey, key, key_size) == 0) { const void *curval = tcbdbcurval3(cur, &cur_val_size); if (cur_val_size == value_size && memcmp(curval, value, value_size) == 0) { tcbdbcurout(cur); removed = true; } else if (!tcbdbcurnext(cur)) not_found = true; } else not_found = true; } if (not_found) ei_x_encode_atom(&x, "not_found"); else ei_x_encode_atom(&x, "ok"); } else return ei_error(&x, "invalid_argument", res, res_size); break; case RANGE: /* * range({Prefix::binary(), limit:integer()}) * range({StartKey::binary(), BeginInclusion::boolean(), EndKey::binary(), EndInclusion::binary(), limit:integer()}) */ ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_SMALL_TUPLE_EXT || sz < 2) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_tuple_header(buf, &index, &sz); ei_get_type(buf, &index, &tp, &sz); if (tp == ERL_BINARY_EXT && sz <= MAX_KEY_SIZE) { char keys[MAX_KEY_SIZE], keyf[MAX_KEY_SIZE]; long keys_size, keyf_size; int keys_inc, keyf_inc; long max = -1; TCLIST *range; ei_decode_binary(buf, &index, &keys[0], &keys_size); ei_get_type(buf, &index, &tp, &sz); if (tp == ERL_ATOM_EXT) { // range ei_decode_boolean(buf, &index, &keys_inc); ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &keyf[0], &keyf_size); ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_ATOM_EXT) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_boolean(buf, &index, &keyf_inc); ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_INTEGER_EXT) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_long(buf, &index, &max); range = tcbdbrange(bdb, &keys[0], keys_size, keys_inc == 1, &keyf[0], keyf_size, keyf_inc == 1, max); } else if (tp == ERL_INTEGER_EXT) { // prefix ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_INTEGER_EXT) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_long(buf, &index, &max); range = tcbdbfwmkeys(bdb, &keys[0], keys_size, max); } else return ei_error(&x, "invalid_argument", res, res_size); const char *key; int key_size, value_size; int idx, cnt = 0, rcount = tclistnum(range); ei_x_encode_tuple_header(&x, 2); ei_x_encode_atom(&x, "ok"); BDBCUR *cur = tcbdbcurnew(bdb); for (idx=0; idx<rcount; idx++) { key = tclistval(range, idx, &key_size); TCLIST *vals = tcbdbget4(bdb, key, key_size); if (vals) { int j; for (j=0; j<tclistnum(vals); j++) { ei_x_encode_list_header(&x, 1); value_tmp = tclistval(vals, j, &value_size); ei_x_encode_binary(&x, value_tmp, value_size); if (max >= 0 && ++cnt >= max) break; } tclistdel(vals); } idx++; } tcbdbcurdel(cur); tclistdel(range); ei_x_encode_empty_list(&x); } else return ei_error(&x, "invalid_argument", res, res_size); break; case SYNC: // sync() if (!tcbdbsync(bdb)) return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); ei_x_encode_atom(&x, "ok"); break; case INFO: // info() ei_x_encode_tuple_header(&x, 3); ei_x_encode_atom(&x, "ok"); long_tmp = tcbdbrnum(bdb); ei_x_encode_longlong(&x, long_tmp); long_tmp = tcbdbfsiz(bdb); ei_x_encode_longlong(&x, long_tmp); break; case ITERATE: // Read(none) -> {ok, Key} | {error, not_found} // Read(Key::binary()) -> {ok, Key} | {error, not_found} ei_get_type(buf, &index, &tp, &sz); BDBCUR *cur = tcbdbcurnew(bdb); if (tp == ERL_BINARY_EXT && sz <= MAX_KEY_SIZE) { ei_decode_binary(buf, &index, &key[0], &key_size); rs = tcbdbcurjump(cur, &key[0], key_size) && tcbdbcurnext(cur); } else rs = tcbdbcurfirst(cur); if (rs) { int key_size; const char *key = tcbdbcurkey3(cur, &key_size); ei_x_encode_tuple_header(&x, 2); ei_x_encode_atom(&x, "ok"); ei_x_encode_binary(&x, key, key_size); tcbdbcurdel(cur); } else { tcbdbcurdel(cur); return ei_error(&x, "not_found", res, res_size); } break; case VANISH: // vanish() -> ok if (!tcbdbvanish(bdb)) return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); ei_x_encode_atom(&x, "ok"); break; case BACKUP: // backup(path::string()) -> ok | {error, Reason} ei_get_type(buf, &index, &tp, &sz); if (tp == ERL_STRING_EXT) { char *file = driver_alloc(sz + 1); ei_decode_string(buf, &index, file); if (tcbdbcopy(driver->bdb, file)) ei_x_encode_atom(&x, "ok"); else return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); } else return ei_error(&x, "invalid_argument", res, res_size); break; default: return ei_error(&x, "invalid_command", res, res_size); } if (res_size < x.index) (*res) = (char *)driver_alloc(x.index); int n = x.index; memcpy(*res, x.buff, x.index); ei_x_free(&x); return n; };
static int print_term(FILE* fp, ei_x_buff* x, const char* buf, int* index) { int i, doquote, n, m, ty, r; char a[MAXATOMLEN], *p; int ch_written = 0; /* counter of written chars */ erlang_pid pid; erlang_port port; erlang_ref ref; double d; long l; int tindex = *index; /* use temporary index for multiple (and failable) decodes */ if (fp == NULL && x == NULL) return -1; doquote = 0; ei_get_type_internal(buf, index, &ty, &n); switch (ty) { case ERL_ATOM_EXT: case ERL_ATOM_UTF8_EXT: case ERL_SMALL_ATOM_EXT: case ERL_SMALL_ATOM_UTF8_EXT: if (ei_decode_atom(buf, index, a) < 0) goto err; doquote = !islower((int)a[0]); for (p = a; !doquote && *p != '\0'; ++p) doquote = !(isalnum((int)*p) || *p == '_' || *p == '@'); if (doquote) { xputc('\'', fp, x); ++ch_written; } xputs(a, fp, x); ch_written += strlen(a); if (doquote) { xputc('\'', fp, x); ++ch_written; } break; case ERL_PID_EXT: case ERL_NEW_PID_EXT: if (ei_decode_pid(buf, index, &pid) < 0) goto err; ch_written += xprintf(fp, x, "<%s.%d.%d>", pid.node, pid.num, pid.serial); break; case ERL_PORT_EXT: case ERL_NEW_PORT_EXT: if (ei_decode_port(buf, index, &port) < 0) goto err; ch_written += xprintf(fp, x, "#Port<%d.%d>", port.id, port.creation); break; case ERL_NEW_REFERENCE_EXT: case ERL_NEWER_REFERENCE_EXT: case ERL_REFERENCE_EXT: if (ei_decode_ref(buf, index, &ref) < 0) goto err; ch_written += xprintf(fp, x, "#Ref<"); for (i = 0; i < ref.len; ++i) { ch_written += xprintf(fp, x, "%d", ref.n[i]); if (i < ref.len - 1) { xputc('.', fp, x); ++ch_written; } } xputc('>', fp, x); ++ch_written; break; case ERL_NIL_EXT: if (ei_decode_list_header(buf, index, &n) < 0) goto err; ch_written += xprintf(fp, x, "[]"); break; case ERL_LIST_EXT: if (ei_decode_list_header(buf, &tindex, &n) < 0) goto err; xputc('[', fp, x); ch_written++; for (i = 0; i < n; ++i) { r = print_term(fp, x, buf, &tindex); if (r < 0) goto err; ch_written += r; if (i < n - 1) { xputs(", ", fp, x); ch_written += 2; } } if (ei_get_type_internal(buf, &tindex, &ty, &n) < 0) goto err; if (ty != ERL_NIL_EXT) { xputs(" | ", fp, x); ch_written += 3; r = print_term(fp, x, buf, &tindex); if (r < 0) goto err; ch_written += r; } else { if (ei_decode_list_header(buf, &tindex, &n) < 0) goto err; } xputc(']', fp, x); ch_written++; *index = tindex; break; case ERL_STRING_EXT: p = ei_malloc(n+1); if (p == NULL) goto err; if (ei_decode_string(buf, index, p) < 0) { ei_free(p); goto err; } ch_written += print_string(fp, x, p, n); ei_free(p); break; case ERL_SMALL_TUPLE_EXT: case ERL_LARGE_TUPLE_EXT: if (ei_decode_tuple_header(buf, &tindex, &n) < 0) goto err; xputc('{', fp, x); ch_written++; for (i = 0; i < n; ++i) { r = print_term(fp, x, buf, &tindex); if (r < 0) goto err; ch_written += r; if (i < n-1) { xputs(", ", fp, x); ch_written += 2; } } *index = tindex; xputc('}', fp, x); ch_written++; break; case ERL_BINARY_EXT: p = ei_malloc(n); if (p == NULL) goto err; if (ei_decode_binary(buf, index, p, &l) < 0) { ei_free(p); goto err; } ch_written += xprintf(fp, x, "#Bin<"); if (l > BINPRINTSIZE) m = BINPRINTSIZE; else m = l; --m; for (i = 0; i < m; ++i) { ch_written += xprintf(fp, x, "%d,", p[i]); } ch_written += xprintf(fp, x, "%d", p[i]); if (l > BINPRINTSIZE) ch_written += xprintf(fp, x, ",..."); xputc('>', fp, x); ++ch_written; ei_free(p); break; case ERL_SMALL_INTEGER_EXT: case ERL_INTEGER_EXT: if (ei_decode_long(buf, index, &l) < 0) goto err; ch_written += xprintf(fp, x, "%ld", l); break; case ERL_SMALL_BIG_EXT: case ERL_LARGE_BIG_EXT: { erlang_big *b; char *ds; if ( (b = ei_alloc_big(n)) == NULL) goto err; if (ei_decode_big(buf, index, b) < 0) { ei_free_big(b); goto err; } if ( (ds = ei_big_to_str(b)) == NULL ) { ei_free_big(b); goto err; } ch_written += xprintf(fp, x, ds); free(ds); ei_free_big(b); } break; case ERL_FLOAT_EXT: case NEW_FLOAT_EXT: if (ei_decode_double(buf, index, &d) < 0) goto err; ch_written += xprintf(fp, x, "%f", d); break; default: goto err; } return ch_written; err: return -1; }
static ErlDrvSSizeT syslogdrv_control(ErlDrvData handle, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { syslogdrv_t* d = (syslogdrv_t*)handle; 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 != 4) { 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, len; ErlDrvBinary* ref = 0; syslogdrv_t* nd = (syslogdrv_t*)driver_alloc(sizeof(syslogdrv_t)); if (nd == NULL) { return encode_error(*rbuf, "enomem"); } nd->ident = driver_alloc(size+1); if (nd->ident == NULL) { return encode_error(*rbuf, "enomem"); } if (ei_decode_string(buf, &index, nd->ident)) { driver_free(nd->ident); driver_free(nd); return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } if (ei_decode_long(buf, &index, &logopt) || ei_decode_long(buf, &index, &facility)) { driver_free(nd->ident); driver_free(nd); return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } if (ei_get_type(buf, &index, &type, &size)) { driver_free(nd->ident); driver_free(nd); return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } if (type != ERL_BINARY_EXT) { driver_free(nd->ident); driver_free(nd); return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } ref = driver_alloc_binary(size); if (ref == NULL) { return encode_error(*rbuf, "enomem"); } if (ei_decode_binary(buf, &index, ref->orig_bytes, &len)) { driver_free_binary(ref); driver_free(nd->ident); driver_free(nd); return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } nd->logopt = (int)logopt; nd->facility = (int)facility; nd->open = 1; { ErlDrvTermData refdata = TERM_DATA(ref->orig_bytes); ErlDrvPort port = d->port; ErlDrvTermData pid = driver_caller(port); ErlDrvData data = (ErlDrvData)nd; nd->port = driver_create_port(port, pid, DRV_NAME, data); if (nd->port == (ErlDrvPort)-1) { driver_free_binary(ref); driver_free(nd->ident); driver_free(nd); return (ErlDrvSSizeT)ERL_DRV_ERROR_GENERAL; } set_port_control_flags(nd->port, PORT_CONTROL_FLAG_BINARY); ErlDrvTermData term[] = { ERL_DRV_EXT2TERM, refdata, ref->orig_size, ERL_DRV_ATOM, driver_mk_atom("ok"), ERL_DRV_PORT, driver_mk_port(nd->port), ERL_DRV_TUPLE, 2, ERL_DRV_TUPLE, 2, }; erl_drv_output_term(driver_mk_port(port), term, sizeof term/sizeof *term); } driver_free_binary(ref); return 0; } else { return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG; } }
int ei_skip_term(const char* buf, int* index) { int i, n, ty; /* ASSERT(ep != NULL); */ ei_get_type_internal(buf, index, &ty, &n); switch (ty) { case ERL_ATOM_EXT: /* FIXME: what if some weird locale is in use? */ if (ei_decode_atom_as(buf, index, NULL, MAXATOMLEN_UTF8, (ERLANG_LATIN1|ERLANG_UTF8), NULL, NULL) < 0) return -1; break; case ERL_PID_EXT: case ERL_NEW_PID_EXT: if (ei_decode_pid(buf, index, NULL) < 0) return -1; break; case ERL_PORT_EXT: case ERL_NEW_PORT_EXT: if (ei_decode_port(buf, index, NULL) < 0) return -1; break; case ERL_NEW_REFERENCE_EXT: case ERL_NEWER_REFERENCE_EXT: case ERL_REFERENCE_EXT: if (ei_decode_ref(buf, index, NULL) < 0) return -1; break; case ERL_NIL_EXT: if (ei_decode_list_header(buf, index, &n) < 0) return -1; break; case ERL_LIST_EXT: if (ei_decode_list_header(buf, index, &n) < 0) return -1; for (i = 0; i < n; ++i) ei_skip_term(buf, index); if (ei_get_type_internal(buf, index, &ty, &n) < 0) return -1; if (ty != ERL_NIL_EXT) ei_skip_term(buf, index); else if (ei_decode_list_header(buf, index, &n) < 0) return -1; break; case ERL_STRING_EXT: if (ei_decode_string(buf, index, NULL) < 0) return -1; break; case ERL_SMALL_TUPLE_EXT: case ERL_LARGE_TUPLE_EXT: if (ei_decode_tuple_header(buf, index, &n) < 0) return -1; for (i = 0; i < n; ++i) ei_skip_term(buf, index); break; case ERL_MAP_EXT: if (ei_decode_map_header(buf, index, &n) < 0) return -1; n *= 2; for (i = 0; i < n; ++i) ei_skip_term(buf, index); break; case ERL_BINARY_EXT: if (ei_decode_binary(buf, index, NULL, NULL) < 0) return -1; break; case ERL_SMALL_INTEGER_EXT: case ERL_INTEGER_EXT: if (ei_decode_long(buf, index, NULL) < 0) return -1; break; case ERL_SMALL_BIG_EXT: case ERL_LARGE_BIG_EXT: if (ei_decode_big(buf, index, NULL) < 0) return -1; break; case ERL_FLOAT_EXT: case NEW_FLOAT_EXT: if (ei_decode_double(buf, index, NULL) < 0) return -1; break; case ERL_FUN_EXT: case ERL_NEW_FUN_EXT: if (ei_decode_fun(buf, index, NULL) < 0) return -1; break; default: return -1; } return 0; }
static inline int decode_and_bind_param( sqlite3_drv_t *drv, char *buffer, int *p_index, sqlite3_stmt *statement, int param_index, int *p_type, int *p_size) { int result; sqlite3_int64 int64_val; double double_val; char* char_buf_val; long bin_size; ei_get_type(buffer, p_index, p_type, p_size); switch (*p_type) { case ERL_SMALL_INTEGER_EXT: case ERL_INTEGER_EXT: case ERL_SMALL_BIG_EXT: case ERL_LARGE_BIG_EXT: ei_decode_longlong(buffer, p_index, &int64_val); result = sqlite3_bind_int64(statement, param_index, int64_val); break; case ERL_FLOAT_EXT: #ifdef NEW_FLOAT_EXT case NEW_FLOAT_EXT: // what's the difference? #endif ei_decode_double(buffer, p_index, &double_val); result = sqlite3_bind_double(statement, param_index, double_val); break; case ERL_ATOM_EXT: // include space for null separator char_buf_val = driver_alloc((*p_size + 1) * sizeof(char)); ei_decode_atom(buffer, p_index, char_buf_val); if (strncmp(char_buf_val, "null", 5) == 0) { result = sqlite3_bind_null(statement, param_index); } else { output_error(drv, SQLITE_MISUSE, "Non-null atom as parameter"); return 1; } break; case ERL_STRING_EXT: // include space for null separator char_buf_val = driver_alloc((*p_size + 1) * sizeof(char)); ei_decode_string(buffer, p_index, char_buf_val); result = sqlite3_bind_text(statement, param_index, char_buf_val, *p_size, &driver_free_fun); break; case ERL_BINARY_EXT: char_buf_val = driver_alloc(*p_size * sizeof(char)); ei_decode_binary(buffer, p_index, char_buf_val, &bin_size); result = sqlite3_bind_text(statement, param_index, char_buf_val, *p_size, &driver_free_fun); break; case ERL_SMALL_TUPLE_EXT: // assume this is {blob, Blob} ei_get_type(buffer, p_index, p_type, p_size); ei_decode_tuple_header(buffer, p_index, p_size); if (*p_size != 2) { output_error(drv, SQLITE_MISUSE, "bad parameter type"); return 1; } ei_skip_term(buffer, p_index); // skipped the atom 'blob' ei_get_type(buffer, p_index, p_type, p_size); if (*p_type != ERL_BINARY_EXT) { output_error(drv, SQLITE_MISUSE, "bad parameter type"); return 1; } char_buf_val = driver_alloc(*p_size * sizeof(char)); ei_decode_binary(buffer, p_index, char_buf_val, &bin_size); result = sqlite3_bind_blob(statement, param_index, char_buf_val, *p_size, &driver_free_fun); break; default: output_error(drv, SQLITE_MISUSE, "bad parameter type"); return 1; } if (result != SQLITE_OK) { output_db_error(drv); return result; } return SQLITE_OK; }
int main(void) #endif { ErlConnect conp; Erl_IpAddr thisipaddr = (Erl_IpAddr)0; FILE *fp = (FILE *)0; char* charp = "foo"; double *doublep = NULL; double doublex = 0.0; ei_cnode xec; ei_reg *ei_regp = NULL; ei_term eterm; ei_x_buff eix; erlang_big *bigp = NULL; erlang_fun efun; erlang_msg *msgp = NULL; erlang_msg emsg; erlang_pid *pidp = NULL; erlang_pid epid; erlang_port eport; erlang_ref eref; erlang_trace etrace; int *intp = NULL; int intx = 0; long *longp = NULL; long longx = 0; short creation = 0; struct ei_reg_stat *ei_reg_statp = NULL; struct ei_reg_tabstat *ei_reg_tabstatp = NULL; struct hostent *hostp = NULL; unsigned char * ucharp = (unsigned char *)"foo"; unsigned long *ulongp = NULL; unsigned long ulongx = 0; void *voidp = NULL; #ifndef VXWORKS EI_LONGLONG *longlongp = (EI_LONGLONG*)NULL; EI_LONGLONG longlongx = 0; EI_ULONGLONG *ulonglongp = (EI_ULONGLONG*)NULL; EI_ULONGLONG ulonglongx = 0; #endif enum erlang_char_encoding enc; intx = erl_errno; ei_connect_init(&xec, charp, charp, creation); ei_connect_xinit (&xec, charp, charp, charp, thisipaddr, charp, creation); ei_connect(&xec, charp); ei_xconnect (&xec, thisipaddr, charp); ei_receive(intx, ucharp, intx); ei_receive_msg(intx, &emsg, &eix); ei_xreceive_msg(intx, &emsg, &eix); ei_send(intx, &epid, charp, intx); ei_reg_send(&xec, intx, charp, charp, intx); ei_rpc(&xec, intx, charp, charp, charp, intx, &eix); ei_rpc_to(&xec, intx, charp, charp, charp, intx); ei_rpc_from(&xec, intx, intx, &emsg, &eix); ei_publish(&xec, intx); ei_accept(&xec, intx, &conp); ei_unpublish(&xec); ei_thisnodename(&xec); ei_thishostname(&xec); ei_thisalivename(&xec); ei_self(&xec); ei_gethostbyname(charp); ei_gethostbyaddr(charp, intx, intx); ei_gethostbyname_r(charp, hostp, charp, intx, intp); ei_gethostbyaddr_r(charp, intx, intx, hostp, charp, intx, intp); ei_encode_version(charp, intp); ei_x_encode_version(&eix); ei_encode_long(charp, intp, longx); ei_x_encode_long(&eix, longx); ei_encode_ulong(charp, intp, ulongx); ei_x_encode_ulong(&eix, ulongx); ei_encode_double(charp, intp, doublex); ei_x_encode_double(&eix, doublex); ei_encode_boolean(charp, intp, intx); ei_x_encode_boolean(&eix, intx); ei_encode_char(charp, intp, 'a'); ei_x_encode_char(&eix, 'a'); ei_encode_string(charp, intp, charp); ei_encode_string_len(charp, intp, charp, intx); ei_x_encode_string(&eix, charp); ei_x_encode_string_len(&eix, charp, intx); ei_encode_atom(charp, intp, charp); ei_encode_atom_as(charp, intp, charp, ERLANG_LATIN1, ERLANG_UTF8); ei_encode_atom_len(charp, intp, charp, intx); ei_encode_atom_len_as(charp, intp, charp, intx, ERLANG_ASCII, ERLANG_LATIN1); ei_x_encode_atom(&eix, charp); ei_x_encode_atom_as(&eix, charp, ERLANG_LATIN1, ERLANG_UTF8); ei_x_encode_atom_len(&eix, charp, intx); ei_x_encode_atom_len_as(&eix, charp, intx, ERLANG_LATIN1, ERLANG_UTF8); ei_encode_binary(charp, intp, (void *)0, longx); ei_x_encode_binary(&eix, (void*)0, intx); ei_encode_pid(charp, intp, &epid); ei_x_encode_pid(&eix, &epid); ei_encode_fun(charp, intp, &efun); ei_x_encode_fun(&eix, &efun); ei_encode_port(charp, intp, &eport); ei_x_encode_port(&eix, &eport); ei_encode_ref(charp, intp, &eref); ei_x_encode_ref(&eix, &eref); ei_encode_trace(charp, intp, &etrace); ei_x_encode_trace(&eix, &etrace); ei_encode_tuple_header(charp, intp, intx); ei_x_encode_tuple_header(&eix, longx); ei_encode_list_header(charp, intp, intx); ei_x_encode_list_header(&eix, longx); /* #define ei_encode_empty_list(buf,i) ei_encode_list_header(buf,i,0) */ ei_x_encode_empty_list(&eix); ei_get_type(charp, intp, intp, intp); ei_get_type_internal(charp, intp, intp, intp); ei_decode_version(charp, intp, intp); ei_decode_long(charp, intp, longp); ei_decode_ulong(charp, intp, ulongp); ei_decode_double(charp, intp, doublep); ei_decode_boolean(charp, intp, intp); ei_decode_char(charp, intp, charp); ei_decode_string(charp, intp, charp); ei_decode_atom(charp, intp, charp); ei_decode_atom_as(charp, intp, charp, MAXATOMLEN_UTF8, ERLANG_WHATEVER, &enc, &enc); ei_decode_binary(charp, intp, (void *)0, longp); ei_decode_fun(charp, intp, &efun); free_fun(&efun); ei_decode_pid(charp, intp, &epid); ei_decode_port(charp, intp, &eport); ei_decode_ref(charp, intp, &eref); ei_decode_trace(charp, intp, &etrace); ei_decode_tuple_header(charp, intp, intp); ei_decode_list_header(charp, intp, intp); ei_decode_ei_term(charp, intp, &eterm); ei_print_term(fp, charp, intp); ei_s_print_term(&charp, charp, intp); ei_x_format(&eix, charp); ei_x_format_wo_ver(&eix, charp); ei_x_new(&eix); ei_x_new_with_version(&eix); ei_x_free(&eix); ei_x_append(&eix, &eix); ei_x_append_buf(&eix, charp, intx); ei_skip_term(charp, intp); ei_reg_open(intx); ei_reg_resize(ei_regp, intx); ei_reg_close(ei_regp); ei_reg_setival(ei_regp, charp, longx); ei_reg_setfval(ei_regp, charp, doublex); ei_reg_setsval(ei_regp, charp, charp); ei_reg_setpval(ei_regp, charp, voidp, intx); ei_reg_setval(ei_regp, charp, intx); ei_reg_getival(ei_regp, charp); ei_reg_getfval(ei_regp, charp); ei_reg_getsval(ei_regp, charp); ei_reg_getpval(ei_regp, charp, intp); ei_reg_getval(ei_regp, charp, intx); ei_reg_markdirty(ei_regp, charp); ei_reg_delete(ei_regp, charp); ei_reg_stat(ei_regp, charp, ei_reg_statp); ei_reg_tabstat(ei_regp, ei_reg_tabstatp); ei_reg_dump(intx, ei_regp, charp, intx); ei_reg_restore(intx, ei_regp, charp); ei_reg_purge(ei_regp); #if defined(HAVE_GMP_H) && defined(HAVE_LIBGMP) { mpz_t obj; ei_decode_bignum(charp, intp, obj); ei_encode_bignum(charp, intp, obj); ei_x_encode_bignum(&eix, obj); } #endif /* HAVE_GMP_H && HAVE_LIBGMP */ #ifndef VXWORKS ei_decode_longlong(charp, intp, longlongp); ei_decode_ulonglong(charp, intp, ulonglongp); ei_encode_longlong(charp, intp, longlongx); ei_encode_ulonglong(charp, intp, ulonglongx); ei_x_encode_longlong(&eix, longlongx); ei_x_encode_ulonglong(&eix, ulonglongx); #endif #ifdef USE_EI_UNDOCUMENTED ei_decode_intlist(charp, intp, longp, intp); ei_receive_encoded(intx, &charp, intp, msgp, intp); ei_send_encoded(intx, pidp, charp, intx); ei_send_reg_encoded(intx, pidp, charp, charp, intx); ei_decode_big(charp, intp, bigp); ei_big_comp(bigp, bigp); ei_big_to_double(bigp, doublep); ei_small_to_big(intx, bigp); ei_alloc_big(intx); ei_free_big(bigp); #endif /* USE_EI_UNDOCUMENTED */ return BUFSIZ + EAGAIN + EHOSTUNREACH + EIO + EI_BIN + EI_DELET + EI_DIRTY + EI_FLT + EI_FORCE + EI_INT + EI_NOPURGE + EI_STR + EMSGSIZE + ENOMEM + ERL_ERROR + ERL_EXIT + ERL_LINK + ERL_MSG + ERL_NO_TIMEOUT + ERL_REG_SEND + ERL_SEND + ERL_TICK + ERL_TIMEOUT + ERL_UNLINK + ETIMEDOUT + MAXATOMLEN; }
static void show_term(const char *termbuf, int *index, FILE *stream) { int type; char smallbuf[EISHOWBUF]; int version; long num; double fnum; erlang_pid pid; erlang_port port; erlang_ref ref; int i, len; char *s; ei_get_type_internal(termbuf,index,&type,&len); switch (type) { case ERL_VERSION_MAGIC: /* just skip past this */ ei_decode_version(termbuf,index,&version); show_term(termbuf,index,stream); break; case ERL_ATOM_EXT: ei_decode_atom(termbuf,index,smallbuf); fprintf(stream,"%s",smallbuf); break; case ERL_STRING_EXT: /* strings can be much longer than EISHOWBUF */ if (len < EISHOWBUF) s = smallbuf; else if (!(s = malloc(len+1))) break; /* FIXME just break if can't? */ ei_decode_string(termbuf,index,s); if (printable_list_p((uint8 *)s,len)) { /* just show it as it is */ fprintf(stream,"\"%s\"",s); } else { /* show it as a list instead */ fprintf(stream,"["); for (i=0; i<len; i++) { if (i > 0) fprintf(stream,", "); fprintf(stream,"%d",s[i]); } fprintf(stream,"]"); } /* did we allocate anything? */ if (s && (s != smallbuf)) free(s); break; /* FIXME add case using ei_decode_longlong */ case ERL_SMALL_BIG_EXT: case ERL_SMALL_INTEGER_EXT: case ERL_INTEGER_EXT: if (ei_decode_long(termbuf,index,&num) == 0) { fprintf(stream,"%ld",num); } else { ei_decode_skip_bignum(termbuf,index,NULL); fprintf(stream,"#Bignum"); } break; case ERL_FLOAT_EXT: case NEW_FLOAT_EXT: ei_decode_double(termbuf,index,&fnum); fprintf(stream,"%f",fnum); break; case ERL_PID_EXT: ei_decode_pid(termbuf,index,&pid); show_pid(stream,&pid); break; case ERL_SMALL_TUPLE_EXT: case ERL_LARGE_TUPLE_EXT: ei_decode_tuple_header(termbuf,index,&len); fprintf(stream,"{"); for (i=0; i<len; i++) { if (i > 0) fprintf(stream,", "); show_term(termbuf,index,stream); } fprintf(stream,"}"); break; case ERL_LIST_EXT: ei_decode_list_header(termbuf,index,&len); fprintf(stream,"["); for (i=0; i<len; i++) { if (i > 0) fprintf(stream,", "); show_term(termbuf,index,stream); } /* get the empty list at the end */ ei_decode_list_header(termbuf,index,&len); fprintf(stream,"]"); break; case ERL_NIL_EXT: ei_decode_list_header(termbuf,index,&len); fprintf(stream,"[]"); break; case ERL_REFERENCE_EXT: case ERL_NEW_REFERENCE_EXT: ei_decode_ref(termbuf,index,&ref); fprintf(stream,"#Ref<%s",ref.node); for (i = 0; i < ref.len; i++) { fprintf(stream,".%u",ref.n[i]); } fprintf(stream,".%u>",ref.creation); break; case ERL_PORT_EXT: ei_decode_port(termbuf,index,&port); fprintf(stream,"#Port<%s.%u.%u>",port.node,port.id,port.creation); break; case ERL_BINARY_EXT: ei_decode_binary(termbuf,index,NULL,&num); fprintf(stream,"#Bin<%ld>",num); break; case ERL_LARGE_BIG_EXT: /* doesn't actually decode - just skip over it */ /* FIXME if GMP, what to do here?? */ ei_decode_skip_bignum(termbuf,index,NULL); fprintf(stream,"#Bignum"); break; case ERL_FUN_EXT: { char atom[MAXATOMLEN]; long idx; long uniq; const char* s = termbuf + *index, * s0 = s; int n_free; ++s; n_free = get32be(s); *index += s - s0; ei_decode_pid(termbuf, index, NULL); /* skip pid */ ei_decode_atom(termbuf, index, atom); /* get module, index, uniq */ ei_decode_long(termbuf, index, &idx); ei_decode_long(termbuf, index, &uniq); fprintf(stream,"#Fun<%s.%ld.%ld>", atom, idx, uniq); for (i = 0; i < n_free; ++i) { /* FIXME how to report error ?! */ if (ei_skip_term(termbuf, index) != 0) fprintf(stderr,"<ERROR> show_msg: unknown type of term !"); } break; } default: fprintf(stream,"#Unknown<%d.%d>",type,len); /* unfortunately we don't know how to skip over this type in * the buffer if we don't even know what it is, so we return. */ return; break; } }
int ei_decode_term(const char *buf, int *index, void *t) { const char *s = buf + *index; const char *s0 = s; if (t) { ETERM *tmp; /* this decodes and advances s */ if (!(tmp = erl_decode_buf((unsigned char **)&s))) return -1; *(ETERM **)t = tmp; *index += s - s0; return 0; } else { int tmpindex = *index; long ttype; int arity; int i; /* these are all the external types */ switch ((ttype = get8(s))) { case ERL_SMALL_INTEGER_EXT: case ERL_INTEGER_EXT: case ERL_SMALL_BIG_EXT: return ei_decode_long(buf,index,NULL); case ERL_FLOAT_EXT: case NEW_FLOAT_EXT: return ei_decode_double(buf,index,NULL); case ERL_ATOM_EXT: return ei_decode_atom(buf,index,NULL); case ERL_REFERENCE_EXT: case ERL_NEW_REFERENCE_EXT: return ei_decode_ref(buf,index,NULL); case ERL_PORT_EXT: return ei_decode_port(buf,index,NULL); case ERL_PID_EXT: return ei_decode_pid(buf,index,NULL); case ERL_SMALL_TUPLE_EXT: case ERL_LARGE_TUPLE_EXT: if (ei_decode_tuple_header(buf,index,&arity) < 0) return -1; for (i=0; i<arity; i++) { if (ei_decode_term(buf,index,NULL)) { /* restore possibly changed index before returning */ *index = tmpindex; return -1; } } return 0; case ERL_STRING_EXT: return ei_decode_string(buf,index,NULL); case ERL_LIST_EXT: case ERL_NIL_EXT: if (ei_decode_list_header(buf,index,&arity) < 0) return -1; if (arity) { for (i=0; i<arity; i++) { if (ei_decode_term(buf,index,NULL) < 0) { /* restore possibly changed index before returning */ *index = tmpindex; return -1; } } if (ei_decode_list_header(buf,index,&arity) < 0) { *index = tmpindex; return -1; } } return 0; case ERL_BINARY_EXT: return ei_decode_binary(buf,index,NULL,NULL); case ERL_LARGE_BIG_EXT: default: break; } } return -1; }
void loop() { int64_t dts_shift = AV_NOPTS_VALUE; uint32_t buf_size = 10240; char *buf = (char *)malloc(buf_size); while(1) { uint32_t len; int idx = 0; int read_bytes = 0; if((read_bytes = read1(in_fd, &len, 4)) != 4) { if(read_bytes == 0) { _exit(0); } error("Can't read input length: %d", read_bytes); } len = ntohl(len); if(len > buf_size) { buf_size = len; free(buf); buf = (char *)malloc(buf_size); } if((read_bytes = read1(in_fd, buf, len)) != len) error("Can't read %d bytes from input: %d", len, read_bytes); int version = 0; ei_decode_version(buf, &idx, &version); int command_idx = idx; int arity = 0; if(ei_decode_tuple_header(buf, &idx, &arity) == -1) error("must pass tuple"); int t = 0; int size = 0; ei_get_type(buf, &idx, &t, &size); if(t != ERL_ATOM_EXT) error("first element must be atom"); char command[MAXATOMLEN+1]; ei_decode_atom(buf, &idx, command); arity--; if(!strcmp(command, "ping")) { pong(); continue; } if(!strcmp(command, "exit")) { return; } if(!strcmp(command, "init_input")) { if(arity != 3) error("Must provide 3 arguments to init_input command"); char content[1024]; char codec[1024]; if(ei_decode_atom(buf, &idx, content) == -1) error("Must provide content as an atom"); if(ei_decode_atom(buf, &idx, codec) == -1) error("Must provide codec as an atom"); int decoder_config_len = 0; ei_get_type(buf, &idx, &t, &decoder_config_len); if(t != ERL_BINARY_EXT) error("decoder config must be a binary"); uint8_t *decoder_config = av_mallocz(decoder_config_len + FF_INPUT_BUFFER_PADDING_SIZE); long bin_len = 0; ei_decode_binary(buf, &idx, decoder_config, &bin_len); Track *t = NULL; if(!strcmp(content, "video")) { t = &input_video; } else if(!strcmp(content, "audio")) { t = &input_audio; } else { error("Unknown media content: '%s'", content); } if(t->codec) error("Double initialization of media '%s'", content); t->codec = avcodec_find_decoder_by_name(codec); t->ctx = avcodec_alloc_context3(t->codec); if(!t->codec || !t->ctx) error("Unknown %s decoder '%s'", content, codec); t->ctx->time_base = (AVRational){1, 90}; t->ctx->extradata_size = decoder_config_len; t->ctx->extradata = decoder_config; if(avcodec_open2(t->ctx, t->codec, NULL) < 0) error("failed to allocate %s decoder", content); reply_atom("ready"); continue; } if(!strcmp(command, "init_output")) { if(arity != 4) error("Must provide 4 arguments to init_output command"); char content[1024]; char codec[1024]; if(ei_decode_atom(buf, &idx, content) == -1) error("Must provide content as an atom"); if(ei_decode_atom(buf, &idx, codec) == -1) error("Must provide codec as an atom"); long track_id = -1; if(ei_decode_long(buf, &idx, &track_id) == -1) error("track_id must be integer"); if(track_id < 1 || track_id > MAX_OUTPUT_TRACKS+1) error("track_id must be from 1 to %d", MAX_OUTPUT_TRACKS+1); track_id--; Track *t = NULL; if(!strcmp(content, "audio")) { t = &output_audio[out_audio_count++]; } else if(!strcmp(content, "video")) { t = &output_video[out_video_count++]; } else { error("invalid_content '%s'", content); } t->track_id = track_id; t->codec = avcodec_find_encoder_by_name(codec); t->ctx = avcodec_alloc_context3(t->codec); if(!t->codec || !t->ctx) error("Unknown encoder '%s'", codec); AVCodecContext* ctx = t->ctx; AVDictionary *opts = NULL; int options_count = 0; if(ei_decode_list_header(buf, &idx, &options_count) < 0) error("options must be a proplist"); while(options_count > 0) { int arity1 = 0; int t,s; ei_get_type(buf, &idx, &t, &s); if(t == ERL_NIL_EXT) { ei_skip_term(buf, &idx); break; } if(ei_decode_tuple_header(buf, &idx, &arity1) < 0) error("options must be a proper proplist"); if(arity1 != 2) error("tuples in options proplist must be arity 2"); char key[MAXATOMLEN]; if(ei_decode_atom(buf, &idx, key) == 0) { if(!strcmp(key, "width")) { long w = 0; if(ei_decode_long(buf, &idx, &w) < 0) error("width must be integer"); ctx->width = w; continue; } if(!strcmp(key, "height")) { long h = 0; if(ei_decode_long(buf, &idx, &h) < 0) error("height must be integer"); ctx->height = h; continue; } if(!strcmp(key, "bitrate")) { long b = 0; if(ei_decode_long(buf, &idx, &b) < 0) error("bitrate must be integer"); ctx->bit_rate = b; continue; } if(!strcmp(key, "sample_rate")) { long sr = 0; if(ei_decode_long(buf, &idx, &sr) < 0) error("sample_rate must be integer"); ctx->sample_rate = sr; continue; } if(!strcmp(key, "channels")) { long ch = 0; if(ei_decode_long(buf, &idx, &ch) < 0) error("channels must be integer"); ctx->channels = ch; continue; } fprintf(stderr, "Unknown key: '%s'\r\n", key); ei_skip_term(buf, &idx); continue; } else if(ei_decode_string(buf, &idx, key) == 0) { char value[MAXATOMLEN]; if(ei_decode_string(buf, &idx, value) < 0) error("key-value must be strings"); av_dict_set(&opts, key, value, 0); } else { error("Invalid options proplist"); } } if(!strcmp(content, "video")) { ctx->pix_fmt = AV_PIX_FMT_YUV420P; } if(!strcmp(content, "audio")) { ctx->sample_fmt = AV_SAMPLE_FMT_S16; ctx->profile = FF_PROFILE_AAC_MAIN; } ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; ctx->time_base = (AVRational){1,90}; if(avcodec_open2(ctx, t->codec, &opts) < 0) error("failed to allocate video encoder"); AVPacket config; config.dts = config.pts = 0; config.flags = CODEC_FLAG_GLOBAL_HEADER; config.data = ctx->extradata; config.size = ctx->extradata_size; reply_avframe(&config, t->codec); continue; } if(!strcmp(command, "video_frame")) { idx = command_idx; struct video_frame *fr = read_video_frame(buf, &idx); AVPacket packet; av_new_packet(&packet, fr->body.size); memcpy(packet.data, fr->body.data, fr->body.size); packet.size = fr->body.size; packet.dts = fr->dts*90; packet.pts = fr->pts*90; packet.stream_index = fr->track_id; // if(packet_size != pkt_size) error("internal error in reading frame body"); if(fr->content == frame_content_audio) { if(!input_audio.ctx) error("input audio uninitialized"); AVFrame *decoded_frame = avcodec_alloc_frame(); int got_output = 0; int ret = avcodec_decode_audio4(input_audio.ctx, decoded_frame, &got_output, &packet); if(got_output) { reply_atom("ok"); } else { error("Got: %d, %d\r\n", ret, got_output); } free(fr); continue; } if(fr->content == frame_content_video) { if(!input_video.ctx) error("input video uninitialized"); AVFrame *decoded_frame = avcodec_alloc_frame(); int could_decode = 0; int ret = avcodec_decode_video2(input_video.ctx, decoded_frame, &could_decode, &packet); if(ret < 0) { error("failed to decode video"); } if(could_decode) { decoded_frame->pts = av_frame_get_best_effort_timestamp(decoded_frame); int sent_config = 0; AVPacket pkt; av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; int could_encode = 0; if(out_video_count <= 0) error("trying to transcode uninitialized video"); if(avcodec_encode_video2(output_video[0].ctx, &pkt, decoded_frame, &could_encode) != 0) error("Failed to encode h264"); if(could_encode) { if(dts_shift == AV_NOPTS_VALUE) { dts_shift = -pkt.dts; } pkt.dts += dts_shift; reply_avframe(&pkt, output_video[0].codec); } else if(!sent_config) { reply_atom("ok"); } free(fr); continue; } else { reply_atom("ok"); free(fr); continue; } } error("Unknown content"); } // AVCodecContext // AVPacket // AVFrame char *s = (char *)malloc(1024); ei_s_print_term(&s, buf, &command_idx); error("Unknown command: %s", s); } }