Example #1
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;
}
Example #2
0
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);
}
Example #3
0
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;
}
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
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
  }
}
Example #9
0
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;
}
Example #10
0
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;
}
Example #11
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;
}
Example #13
0
/*
 * 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());
    }
}
Example #14
0
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;
}
Example #15
0
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;
}
Example #16
0
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;
}
Example #17
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);
}
Example #18
0
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;
			
			
			
	}
	
	
}
Example #19
0
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;
}
Example #20
0
/* 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;
}
Example #21
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;
};
Example #22
0
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;
}
Example #23
0
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;
    }
}
Example #24
0
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;
}
Example #25
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;
}
Example #26
0
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;
}
Example #27
0
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;
    }
}
Example #28
0
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;
}
Example #29
0
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);
  }
}