Beispiel #1
0
int find_first_gteq(char* buf, int pos, void* key, compare_info* lu, int at_least)
{
    int list_arity, inner_arity;
    int list_pos = 0, cmp_val;
    off_t pair_pos = 0;
    if(ei_decode_list_header(buf, &pos, &list_arity) < 0)
    {
        return ERROR_PARSE;
    }
    while(list_pos < list_arity)
    {
        //{<<"key", some other term}
        pair_pos = pos; //Save pos of kv/kp pair tuple

        if(ei_decode_tuple_header(buf, &pos, &inner_arity) < 0)
        {
            return ERROR_PARSE;
        }

        lu->last_cmp_key = (*lu->from_ext)(lu, buf,pos);
        cmp_val = (*lu->compare) (lu->last_cmp_key, key);
        lu->last_cmp_val = cmp_val;
        lu->list_pos = list_pos;
        if(cmp_val >= 0 && list_pos >= at_least)
        {
            break;
        }
        ei_skip_term(buf, &pos); //skip over the key
        ei_skip_term(buf, &pos); //skip over the value
        list_pos++;
    }
    return pair_pos;
}
Beispiel #2
0
int mr_push_kv_range(char* buf, int pos, int bound, int end, couchfile_modify_result *dst)
{
    int current = 0;
    int term_begin_pos;
    ei_decode_list_header(buf, &pos, NULL);
    int errcode = 0;
    while(current < end && errcode == 0)
    {
        term_begin_pos = pos;
        ei_skip_term(buf, &pos);
        if(current >= bound)
        { //Parse KV pair into a leaf_value
            couchfile_leaf_value *lv = malloc(sizeof(couchfile_leaf_value));

            lv->term.buf = buf+term_begin_pos;
            lv->term.size = pos-term_begin_pos;

            nodelist* n = make_nodelist();
            dst->values_end->next = n;
            dst->values_end = n;
            n->value.leaf = lv;

            dst->node_len += lv->term.size;
            dst->count++;
            errcode = maybe_flush(dst);
        }
        current++;
    }
    return errcode;
}
Beispiel #3
0
void term_to_buf(eterm_buf *dst, char* buf, int *pos)
{
    int start = *pos;
    ei_skip_term(buf, pos);
    dst->buf = buf + start;
    dst->size = *pos - start;
}
Beispiel #4
0
	eqmlTerm operator[] (int elem) const
	{
		int idx = _index;
		for (int i = 1; i < elem; ++i)
			ei_skip_term(_buf, &idx);

		return eqmlTerm(_buf, idx);
	}
Beispiel #5
0
/*
 * Find member in tuple (aka RPC struct)
 */
static int find_member(erl_rpc_ctx_t *ctx, int arity, const char* member_name)
{
	int index,i=0;
	int type,size;
	char key_name[MAXATOMLEN];

	/* save position */
	index = ctx->request_index;

	/* { name, Value, name, Value...} */
	while (i < arity)
	{
		if (ei_get_type(ctx->request->buff,&ctx->request_index,&type,&size))
		{
			erl_rpc_fault(ctx,400,"Bad struct member type");
			goto error;
		}

		if(ei_decode_atom(ctx->request->buff,&ctx->request_index, key_name))
		{
			erl_rpc_fault(ctx,400,"Bad member name");
			goto error;
		}

		if (strcasecmp(member_name,key_name))
		{
			if(ei_skip_term(ctx->request->buff,&ctx->request_index))
			{
				erl_rpc_fault(ctx,400,"Unexpected end of struct tuple");
				goto error;
			}
			continue;
		}
		else
		{
			/* return at current position */
			return 0;
		}

		i++;
	}

	erl_rpc_fault(ctx,400, "Member %s not found",member_name);

error:
	ctx->request_index = index;
	return -1;
}
Beispiel #6
0
void mr_push_kp_range(char* buf, int pos, int bound, int end, couchfile_modify_result *dst)
{
    DBG("Moving items %d - %d into result.\r\n", bound, end);
    int current = 0;
    ei_decode_list_header(buf, &pos, NULL);
    while(current < end)
    {
        if(current >= bound)
        {
            DBG("   .... %d\r\n", current);
            mr_push_pointerinfo(read_pointer(buf,pos), dst);
        }
        ei_skip_term(buf, &pos);
        current++;
    }
}
Beispiel #7
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;
    }
}
Beispiel #8
0
static int parse_option_list(const char *req, int *req_index, struct uart_config *config)
{
    int term_type;
    int option_count;
    if (ei_get_type(req, req_index, &term_type, &option_count) < 0 ||
            (term_type != ERL_LIST_EXT && term_type != ERL_NIL_EXT)) {
        debug("expecting option list");
        return -1;
    }

    if (term_type == ERL_NIL_EXT)
        option_count = 0;
    else
        ei_decode_list_header(req, req_index, &option_count);

    // Go through all of the options
    for (int i = 0; i < option_count; i++) {
        int term_size;
        if (ei_decode_tuple_header(req, req_index, &term_size) < 0 ||
                term_size != 2) {
            debug("expecting kv tuple for options");
            return -1;
        }

        char key[16];
        if (ei_decode_atom(req, req_index, key) < 0) {
            debug("expecting atoms for option keys");
            return -1;
        }

        if (strcmp(key, "active") == 0) {
            int val;
            if (ei_decode_boolean(req, req_index, &val) < 0) {
                debug("active should be a bool");
                return -1;
            }
            config->active = (val != 0);
        } else if (strcmp(key, "speed") == 0) {
            long val;
            if (ei_decode_long(req, req_index, &val) < 0) {
                debug("speed should be an integer");
                return -1;
            }
            config->speed = val;
        } else if (strcmp(key, "data_bits") == 0) {
            long val;
            if (ei_decode_long(req, req_index, &val) < 0) {
                debug("data_bits should be an integer");
                return -1;
            }
            config->data_bits = val;
        } else if (strcmp(key, "stop_bits") == 0) {
            long val;
            if (ei_decode_long(req, req_index, &val) < 0) {
                debug("stop_bits should be an integer");
                return -1;
            }
            config->stop_bits = val;
        } else if (strcmp(key, "parity") == 0) {
            char parity[16];
            if (ei_decode_atom(req, req_index, parity) < 0) {
                debug("parity should be an atom");
                return -1;
            }
            if (strcmp(parity, "none") == 0) config->parity = UART_PARITY_NONE;
            else if (strcmp(parity, "even") == 0) config->parity = UART_PARITY_EVEN;
            else if (strcmp(parity, "odd") == 0) config->parity = UART_PARITY_ODD;
            else if (strcmp(parity, "space") == 0) config->parity = UART_PARITY_SPACE;
            else if (strcmp(parity, "mark") == 0) config->parity = UART_PARITY_MARK;
        } else if (strcmp(key, "flow_control") == 0) {
            char flow_control[16];
            if (ei_decode_atom(req, req_index, flow_control) < 0) {
                debug("flow_control should be an atom");
                return -1;
            }
            if (strcmp(flow_control, "none") == 0) config->flow_control = UART_FLOWCONTROL_NONE;
            else if (strcmp(flow_control, "hardware") == 0) config->flow_control = UART_FLOWCONTROL_HARDWARE;
            else if (strcmp(flow_control, "software") == 0) config->flow_control = UART_FLOWCONTROL_SOFTWARE;
        } else {
            // unknown term
            ei_skip_term(req, req_index);
        }
    }
    return 0;
}
Beispiel #9
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;
}
Beispiel #10
0
int erl_rpc_scan(erl_rpc_ctx_t* ctx, char* fmt, ...)
{
	int* int_ptr;
	char** char_ptr;
	str* str_ptr;
	double* double_ptr;
	void** void_ptr;
	str s; /* helper str */

	int reads = 0;
	int modifiers = 0;
	int autoconv = 0;

	int type,size;
	erl_rpc_ctx_t *handler;

	va_list ap;

	va_start(ap,fmt);

	while(*fmt && ctx->size)
	{
		/* optional and we at the end of decoding params */
		if (ctx->optional && !ctx->size)
		{
			break;
		}

		if (ei_get_type(ctx->request->buff,&ctx->request_index,&type,&size))
		{
			erl_rpc_fault(ctx,400,"Can't determine data type, for parameter #%d",reads);
			LM_ERR("Can't determine data type, for parameter #%d",reads);

			goto error;
		}

		switch(*fmt)
		{
		case '*': /* start of optional parameters */
			modifiers++;
			ctx->optional = 1;
			reads++;
			fmt++;
			continue;
		case '.':  /* autoconvert */
			modifiers++;
			autoconv = 1;
			reads++;
			fmt++;
			continue;
		case 'b': /* Bool */
		case 't': /* Date and time */
		case 'd': /* Integer */
			int_ptr = va_arg(ap, int*);

			if (get_int(int_ptr,ctx,reads,autoconv))
			{
				goto error;
			}

			break;
		case 'f': /* double */
			double_ptr = va_arg(ap, double*);

			if (get_double(double_ptr,ctx,reads,autoconv))
			{
				goto error;
			}

			break;
		case 'S': /* str structure */

			str_ptr = va_arg(ap, str*);

			if (get_str(str_ptr,ctx,reads,autoconv))
			{
				goto error;
			}

			break;
		case 's':/* zero terminated string */

			char_ptr = va_arg(ap, char **);
			if (get_str(&s,ctx,reads,autoconv))
			{
				goto error;
			}

			*char_ptr = s.s;

			break;
		case '{':
			void_ptr = va_arg(ap,void**);

			if (type!=ERL_SMALL_TUPLE_EXT && type!=ERL_LARGE_TUPLE_EXT)
			{
				erl_rpc_fault(ctx,400,"Bad type of parameter #%d (t=%c).",reads,type);
				goto error;
			}

			handler = (erl_rpc_ctx_t*)pkg_malloc(sizeof(erl_rpc_ctx_t));

			if (!handler)
			{
				erl_rpc_fault(ctx,500, "Internal Server Error (No memory left)");
				LM_ERR("Not enough memory\n");
				goto error;
			}

			*handler = *ctx; /* copy state */
			handler->optional = 0;
			handler->no_params = 0;
			handler->size = size; /* size of tuple */

			if (add_to_recycle_bin(JUNK_PKGCHAR,handler,ctx))
			{
				pkg_free(handler);
				goto error;
			}

			/* skip element */
			if (ei_skip_term(ctx->request->buff,&ctx->request_index))
			{
				goto error;
			}

			/* go where we stopped */
			*(erl_rpc_ctx_t**)void_ptr = handler;

			break;
		 default:
			 LM_ERR("Invalid parameter type in formatting string: %c\n", *fmt);
			 erl_rpc_fault(ctx, 500, "Server Internal Error (Invalid Formatting String)");
			 goto error;
		}

		autoconv = 0; /* reset autovoncersion for next parameter */
		reads++;
		fmt++;
		ctx->size--;
	}
    va_end(ap);
    return reads-modifiers;

error:
    va_end(ap);
    return -(reads-modifiers);

}
Beispiel #11
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;
    }
}
Beispiel #12
0
void decode_encode(struct Type** tv, int nobj)
{
    struct my_obj objv[10];
    int oix = 0;
    char* packet;
    char* inp;
    char* outp;
    char out_buf[BUFSZ];
    int size1, size2, size3;
    int err, i;
    ei_x_buff arg;

    packet = read_packet(NULL);
    inp = packet+1;
    outp = out_buf;
    ei_x_new(&arg);
    for (i=0; i<nobj; i++) {
        struct Type* t = tv[i];

        MESSAGE("ei_decode_%s, arg is type %s", t->name, t->type);

        size1 = 0;
        err = t->ei_decode_fp(inp, &size1, NULL);
        if (err != 0) {
            if (err != -1) {
                fail("decode returned non zero but not -1");
            } else {
                fail("decode returned non zero");
            }
            return;
        }
        if (size1 < 1) {
            fail("size is < 1");
            return;
        }

        if (size1 > BUFSZ) {
            fail("size is > BUFSZ");
            return;
        }

        size2 = 0;
        objv[oix].nterms = 0;
        objv[oix].startp = inp;
        err = t->ei_decode_fp(inp, &size2, &objv[oix]);
        if (err != 0) {
            if (err != -1) {
                fail("decode returned non zero but not -1");
            } else {
                fail("decode returned non zero");
            }
            return;
        }
        if (size1 != size2) {
            MESSAGE("size1 = %d, size2 = %d\n",size1,size2);
            fail("decode sizes differs");
            return;
        }

        if (!objv[oix].nterms) {
            size2 = 0;
            err = ei_skip_term(inp, &size2);
            if (err != 0) {
                fail("ei_skip_term returned non zero");
                return;
            }
            if (size1 != size2) {
                MESSAGE("size1 = %d, size2 = %d\n",size1,size2);
                fail("skip size differs");
                return;
            }
        }

        MESSAGE("ei_encode_%s buf is NULL, arg is type %s", t->name, t->type);
        size2 = 0;
        err = t->ei_encode_fp(NULL, &size2, &objv[oix]);
        if (err != 0) {
            if (err != -1) {
                fail("size calculation returned non zero but not -1");
                return;
            } else {
                fail("size calculation returned non zero");
                return;
            }
        }
        if (size1 != size2) {
            MESSAGE("size1 = %d, size2 = %d\n",size1,size2);
            fail("decode and encode size differs when buf is NULL");
            return;
        }
        MESSAGE("ei_encode_%s, arg is type %s", t->name, t->type);
        size3 = 0;
        err = t->ei_encode_fp(outp, &size3, &objv[oix]);
        if (err != 0) {
            if (err != -1) {
                fail("returned non zero but not -1");
            } else {
                fail("returned non zero");
            }
            return;
        }
        if (size1 != size3) {
            MESSAGE("size1 = %d, size2 = %d\n",size1,size3);
            fail("decode and encode size differs");
            return;
        }

        MESSAGE("ei_x_encode_%s, arg is type %s", t->name, t->type);
        err = t->ei_x_encode_fp(&arg, &objv[oix]);
        if (err != 0) {
            if (err != -1) {
                fail("returned non zero but not -1");
            } else {
                fail("returned non zero");
            }
            ei_x_free(&arg);
            return;
        }
        if (arg.index < 1) {
            fail("size is < 1");
            ei_x_free(&arg);
            return;
        }

        inp += size1;
        outp += size1;

        if (objv[oix].nterms) { /* container term */
            if (++oix >= sizeof(objv)/sizeof(*objv))
                fail("Term too deep");
        }
        else { /* "leaf" term */
            while (oix > 0) {
                if (--(objv[oix - 1].nterms) == 0) {
                    /* last element in container */
                    --oix;

                    size2 = 0;
                    err = ei_skip_term(objv[oix].startp, &size2);
                    if (err != 0) {
                        fail("ei_skip_term returned non zero");
                        return;
                    }
                    if (objv[oix].startp + size2 != inp) {
                        MESSAGE("size1 = %d, size2 = %d\n", size1, size2);
                        fail("container skip size differs");
                        return;
                    }
                }
                else
                    break; /* more elements in container */
            }
        }

    }
    if (oix > 0) {
        fail("Container not complete");
    }
    send_buffer(out_buf, outp - out_buf);
    send_buffer(arg.buff, arg.index);
    ei_x_free(&arg);
    free_packet(packet);
}
Beispiel #13
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;
			
			
			
	}
	
	
}
Beispiel #14
0
void uwsgi_erlang_rpc(int fd, erlang_pid *from, ei_x_buff *x) {

	int etype, esize;
	int arity;

	char *gen_call;
	char *module;
	char *call;
	char buffer[0xffff];

	char *argv[256] ;
	uint16_t argvs[256] ;
	int argc = 0;
	uint16_t ret;
	ei_x_buff xr;

	erlang_ref eref;

	ei_get_type(x->buff, &x->index, &etype, &esize);

#ifdef UWSGI_DEBUG
	uwsgi_log("%d %c %c %c\n", etype, etype, ERL_SMALL_TUPLE_EXT, ERL_LARGE_TUPLE_EXT);
#endif
	if (etype != ERL_SMALL_TUPLE_EXT && etype != ERL_LARGE_TUPLE_EXT) return;

	ei_decode_tuple_header(x->buff, &x->index, &arity);

#ifdef UWSGI_DEBUG
	uwsgi_log("rpc arity %d\n", arity);
#endif
	if (arity != 3) return ;

	ei_get_type(x->buff, &x->index, &etype, &esize);

	if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;

	gen_call = uwsgi_malloc(esize);

	if (etype == ERL_ATOM_EXT) {
                ei_decode_atom(x->buff, &x->index, gen_call);
        }
        else {
                ei_decode_string(x->buff, &x->index, gen_call);
        }

#ifdef UWSGI_DEBUG
	uwsgi_log("gen call = %s\n", gen_call);
#endif

	ei_get_type(x->buff, &x->index, &etype, &esize);
	
	if (etype != ERL_SMALL_TUPLE_EXT) return ;

	ei_decode_tuple_header(x->buff, &x->index, &arity);
	if (arity != 2) return ;

	ei_get_type(x->buff, &x->index, &etype, &esize);
	ei_skip_term(x->buff, &x->index);
	ei_get_type(x->buff, &x->index, &etype, &esize);
	ei_decode_ref(x->buff, &x->index, &eref);

	ei_get_type(x->buff, &x->index, &etype, &esize);

	module = uwsgi_malloc(esize);

	if (etype == ERL_ATOM_EXT) {
		ei_decode_atom(x->buff, &x->index, module);
	}
	else {
		ei_decode_string(x->buff, &x->index, module);
	}

	ei_get_type(x->buff, &x->index, &etype, &esize);

	if (etype != ERL_SMALL_TUPLE_EXT) return ;

	ei_decode_tuple_header(x->buff, &x->index, &arity);

#ifdef UWSGI_DEBUG
	uwsgi_log("arity: %d\n", arity);
#endif
	if (arity != 5) return ;

	ei_get_type(x->buff, &x->index, &etype, &esize);

        char *method = uwsgi_malloc(esize);

        if (etype == ERL_ATOM_EXT) {
                ei_decode_atom(x->buff, &x->index, method);
        }
        else {
                ei_decode_string(x->buff, &x->index, method);
        }

        if (strcmp(method, "call")) return;

        ei_get_type(x->buff, &x->index, &etype, &esize);

	if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;

	module = uwsgi_malloc(esize);

	if (etype == ERL_ATOM_EXT) {
		ei_decode_atom(x->buff, &x->index, module);
	}
	else {
		ei_decode_string(x->buff, &x->index, module);
	}

	ei_get_type(x->buff, &x->index, &etype, &esize);

	if (etype != ERL_ATOM_EXT && etype != ERL_STRING_EXT) return ;

	call = uwsgi_malloc(esize);

	if (etype == ERL_ATOM_EXT) {
		ei_decode_atom(x->buff, &x->index, call);
	}
	else {
		ei_decode_string(x->buff, &x->index, call);
	}

#ifdef UWSGI_DEBUG
	uwsgi_log("RPC %s %s\n", module, call);
#endif

	ei_get_type(x->buff, &x->index, &etype, &esize);

	if (etype == ERL_ATOM_EXT) {
		argc = 1;
		argv[0] = uwsgi_malloc(esize+1);
		ei_decode_atom(x->buff, &x->index, argv[0]);	
		argvs[1] = esize;
	}
	else if (etype == ERL_STRING_EXT) {
		argc = 1;
		argv[0] = uwsgi_malloc(esize+1);
		ei_decode_string(x->buff, &x->index, argv[0]);	
		argvs[1] = esize;
	}

	ret = uwsgi_rpc(call, argc, argv, argvs, buffer);

#ifdef UWSGI_DEBUG
	uwsgi_log("buffer: %.*s\n", ret, buffer);
#endif

	ei_x_new_with_version(&xr);

	ei_x_encode_tuple_header(&xr, 2);
	//ei_x_encode_atom(&xr, "rex");
	ei_x_encode_ref(&xr, &eref);
	ei_x_encode_string_len(&xr, buffer, ret);

	uwsgi_log("ei_send to %d %s %d %d %d: %d %d\n", fd, from->node, from->num , from->serial, from->creation, xr.index, ei_send(fd, from, xr.buff, xr.index));
	//uwsgi_log("ei_send to %d %s %d %d %d: %d %d\n", fd, from->node, from->num , from->serial, from->creation, xr.index, ei_reg_send(&uerl.cnode, fd, "rex", xr.buff, xr.index));
	
	
}
Beispiel #15
0
int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
{
    const char *s = buf + *index;
    const char *s0 = s;
    int i, ix, ix0, n;

    switch (get8(s)) {
    case ERL_FUN_EXT:
	/* mark as old (R7 and older) external fun */
	if (p != NULL) p->arity = -1;
	/* first number of free vars (environment) */
	n = get32be(s);
	/* then the pid */
	ix = 0;
	if (ei_decode_pid(s, &ix, (p == NULL ? (erlang_pid*)NULL : &p->pid)) < 0)
	    return -1;
	/* then the module (atom) */
	if (ei_decode_atom(s, &ix, (p == NULL ? (char*)NULL : p->module)) < 0)
	    return -1;
	/* then the index */
	if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->index)) < 0)
	    return -1;
	/* then the uniq */
	if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->uniq)) < 0)
	    return -1;
	/* finally the free vars */
	ix0 = ix;
	for (i = 0; i < n; ++i) {
	    if (ei_skip_term(s, &ix) < 0)
		return -1;
	}
	if (p != NULL) {
	    p->n_free_vars = n;
	    p->free_var_len = ix - ix0;
	    p->free_vars = ei_malloc(ix - ix0);	/* FIXME check result */
	    memcpy(p->free_vars, s + ix0, ix - ix0);
	}
	s += ix;
	*index += s-s0;
        return 0;
	break;
    case ERL_NEW_FUN_EXT:
	/* first total size */
	n = get32be(s);
	/* then the arity */
	i = get8(s);
	if (p != NULL) p->arity = i;
	/* then md5 */
	if (p != NULL) memcpy(p->md5, s, 16);
	s += 16;
	/* then index */
	i = get32be(s);
	if (p != NULL) p->index = i;
	/* then the number of free vars (environment) */
	i = get32be(s);
	if (p != NULL) p->n_free_vars = i;
	/* then the module (atom) */
	ix = 0;
	if (ei_decode_atom(s, &ix, (p == NULL ? (char*)NULL : p->module)) < 0)
	    return -1;
	/* then the old_index */
	if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->old_index)) < 0)
	    return -1;
	/* then the old_uniq */
	if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->uniq)) < 0)
	    return -1;
	/* the the pid */
	if (ei_decode_pid(s, &ix, (p == NULL ? (erlang_pid*)NULL : &p->pid)) < 0)
	    return -1;
	/* finally the free vars */
	s += ix;
	n = n - (s - s0) + 1;
	if (p != NULL) {
	    p->free_var_len = n;
	    if (n > 0) {
		p->free_vars = malloc(n); /* FIXME check result */
		memcpy(p->free_vars, s, n);
	    }
	}
	*index += s-s0;
        return 0;
	break;
    default:
	return -1;
    }
}
Beispiel #16
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);
  }
}
Beispiel #17
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;
}
Beispiel #18
0
int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
{
    const char *s = buf + *index;
    const char *s0 = s;
    int i, ix, ix0, n;
    erlang_pid* p_pid;
    char* p_module;
    erlang_char_encoding* p_module_org_enc;
    long* p_index;
    long* p_uniq;
    long* p_old_index;

    if (p != NULL) {
	p_pid = &p->pid;
	p_module = &p->module[0];
	p_module_org_enc = &p->module_org_enc;
	p_index = &p->index;
	p_uniq = &p->uniq;
	p_old_index = &p->old_index;
    }
    else {
	p_pid = NULL; p_module = NULL; p_module_org_enc = NULL;
	p_index = NULL; p_uniq = NULL; p_old_index = NULL;
    }

    switch (get8(s)) {
    case ERL_FUN_EXT:
	/* mark as old (R7 and older) external fun */
	if (p != NULL) p->arity = -1;
	/* first number of free vars (environment) */
	n = get32be(s);
	/* then the pid */
	ix = 0;
	if (ei_decode_pid(s, &ix, p_pid) < 0)
	    return -1;
	/* then the module (atom) */
	if (ei_decode_atom_as(s, &ix, p_module, MAXATOMLEN_UTF8, ERLANG_UTF8,
			      p_module_org_enc, NULL) < 0)
	    return -1;
	/* then the index */
	if (ei_decode_long(s, &ix, p_index) < 0)
	    return -1;
	/* then the uniq */
	if (ei_decode_long(s, &ix, p_uniq) < 0)
	    return -1;
	/* finally the free vars */
	ix0 = ix;
	for (i = 0; i < n; ++i) {
	    if (ei_skip_term(s, &ix) < 0)
		return -1;
	}
	if (p != NULL) {
	    p->n_free_vars = n;
	    p->free_var_len = ix - ix0;
	    p->free_vars = ei_malloc(ix - ix0);
	    if (!(p->free_vars)) return -1;
	    memcpy(p->free_vars, s + ix0, ix - ix0);
	}
	s += ix;
	*index += s-s0;
        return 0;
	break;
    case ERL_NEW_FUN_EXT:
	/* first total size */
	n = get32be(s);
	/* then the arity */
	i = get8(s);
	if (p != NULL) p->arity = i;
	/* then md5 */
	if (p != NULL) memcpy(p->md5, s, 16);
	s += 16;
	/* then index */
	i = get32be(s);
	if (p != NULL) p->index = i;
	/* then the number of free vars (environment) */
	i = get32be(s);
	if (p != NULL) p->n_free_vars = i;
	/* then the module (atom) */
	ix = 0;
	if (ei_decode_atom_as(s, &ix, p_module, MAXATOMLEN_UTF8, ERLANG_UTF8,
			      p_module_org_enc, NULL) < 0)
	    return -1;
	/* then the old_index */
	if (ei_decode_long(s, &ix, p_old_index) < 0)
	    return -1;
	/* then the old_uniq */
	if (ei_decode_long(s, &ix, p_uniq) < 0)
	    return -1;
	/* the the pid */
	if (ei_decode_pid(s, &ix, p_pid) < 0)
	    return -1;
	/* finally the free vars */
	s += ix;
	n = n - (s - s0) + 1;
	if (n < 0) return -1;
	if (p != NULL) {
	    p->free_var_len = n;
	    if (n > 0) {
		p->free_vars = malloc(n);
		if (!(p->free_vars)) return -1;
		memcpy(p->free_vars, s, n);
	    }
	}
	s += n;
	*index += s-s0;
        return 0;
	break;
    default:
	return -1;
    }
}
Beispiel #19
0
int modify_node(couchfile_modify_request *rq, couchfile_pointer_info *nptr,
                int start, int end, couchfile_modify_result *dst)
{
    eterm_buf current_node;
    int curnode_pos = 0;
    int read_size = 0;
    int list_start_pos = 0;
    int node_len = 0;
    int node_bound = 0;
    int errcode = 0;
    int kpos = 0;

    char node_type[MAXATOMLEN + 1];
    node_type[0] = 0;

    DBG("Enter modify_node. %d - %d\r\n", start, end);

    if(start == end)
    {
        return 0;
    }

    if(nptr == NULL)
    {
        current_node = empty_root;
    }
    else
    {
        if((read_size = pread_bin(rq->fd, nptr->pointer, &current_node.buf)) < 0)
        {
            return ERROR_READ_FILE;
        }
        current_node.size = read_size;
        DBG("... read node from %d\r\n", nptr->pointer);
        curnode_pos++; //Skip over 131.
    }

    couchfile_modify_result *local_result = make_modres(rq);

    ei_decode_tuple_header(current_node.buf, &curnode_pos, NULL);
    if(ei_decode_atom(current_node.buf, &curnode_pos, node_type) < 0)
    {
        errcode = ERROR_PARSE;
        goto cleanup;
    }
    list_start_pos = curnode_pos;
    if(ei_decode_list_header(current_node.buf, &curnode_pos, &node_len) < 0)
    {
        errcode = ERROR_PARSE;
        goto cleanup;
    }

    if(strcmp("kv_node", node_type) == 0)
    {
        local_result->node_type = KV_NODE;
        while(start < end)
        {
            DBG("act on kvnode item\r\n");
            if(node_bound >= node_len)
            { //We're at the end of a leaf node.
                DBG("   ... exec action at end!\r\n");
                switch(rq->actions[start].type)
                {
                    case ACTION_INSERT:
                        local_result->modified = 1;
                        mr_push_action(&rq->actions[start], local_result);
                    break;

                    case ACTION_REMOVE:
                        local_result->modified = 1;
                    break;

                    case ACTION_FETCH:
                        if(rq->fetch_callback)
                        {
                            //not found
                            (*rq->fetch_callback)(rq, rq->actions[start].key, NULL);
                        }
                    break;
                }
                start++;
            }
            else
            {
                kpos = find_first_gteq(current_node.buf, list_start_pos,
                        rq->actions[start].cmp_key,
                        &rq->cmp, node_bound);

                if(kpos < 0)
                {
                    errcode = ERROR_PARSE;
                    goto cleanup;
                }

                //Add items from node_bound up to but not including the current
                mr_push_kv_range(current_node.buf, list_start_pos, node_bound,
                        rq->cmp.list_pos, local_result);

                if(rq->cmp.last_cmp_val > 0) // Node key > action key
                {
                    DBG("   Inserting action before\r\n");
                    switch(rq->actions[start].type)
                    {
                        case ACTION_INSERT:
                            local_result->modified = 1;
                            mr_push_action(&rq->actions[start], local_result);
                        break;

                        case ACTION_REMOVE:
                            local_result->modified = 1;
                        break;

                        case ACTION_FETCH:
                            if(rq->fetch_callback)
                            {
                                //not found
                                (*rq->fetch_callback)(rq, rq->actions[start].key, NULL);
                            }
                        break;
                    }

                    start++;
                    node_bound = rq->cmp.list_pos;
                }
                else if(rq->cmp.last_cmp_val < 0) // Node key < action key
                {
                    DBG("   -- Continue with this action\r\n");
                    node_bound = rq->cmp.list_pos + 1;
                    mr_push_kv_range(current_node.buf, list_start_pos, node_bound - 1,
                            node_bound, local_result);
                }
                else //Node key == action key
                {
                    DBG("   Replacing value with action\r\n");
                    switch(rq->actions[start].type)
                    {
                        case ACTION_INSERT:
                            local_result->modified = 1;
                            mr_push_action(&rq->actions[start], local_result);
                            node_bound = rq->cmp.list_pos + 1;
                        break;

                        case ACTION_REMOVE:
                            local_result->modified = 1;
                            node_bound = rq->cmp.list_pos + 1;
                        break;

                        case ACTION_FETCH:
                            if(rq->fetch_callback)
                            {
                                eterm_buf cb_tmp;
                                int cb_vpos = kpos;
                                ei_decode_tuple_header(current_node.buf, &cb_vpos, NULL);
                                ei_skip_term(current_node.buf, &cb_vpos);
                                cb_tmp.buf = current_node.buf + cb_vpos;
                                cb_tmp.size = cb_vpos;
                                ei_skip_term(current_node.buf, &cb_vpos);
                                cb_tmp.size = cb_vpos - cb_tmp.size;
                                (*rq->fetch_callback)(rq, rq->actions[start].key, &cb_tmp);
                            }
                            node_bound = rq->cmp.list_pos;
                        break;
                    }
                    start++;
                }
            }
        }
        //Push any items past the end of what we dealt with onto result.
        if(node_bound < node_len)
        {
            mr_push_kv_range(current_node.buf, list_start_pos, node_bound,
                    node_len, local_result);
        }
    }
    else if(strcmp("kp_node", node_type) == 0)
    {
        local_result->node_type = KP_NODE;
        while(start < end)
        {
            kpos = find_first_gteq(current_node.buf, list_start_pos,
                    rq->actions[start].cmp_key,
                    &rq->cmp, node_bound);

            if(kpos < 0)
            {
                errcode = ERROR_PARSE;
                goto cleanup;
            }

            if(rq->cmp.list_pos == (node_len - 1)) //got last item in kp_node
            {
                //Push all items in node onto mr
                mr_push_kp_range(current_node.buf, list_start_pos, node_bound,
                        rq->cmp.list_pos, local_result);
                DBG("  ...descending into final item of kpnode\r\n");
                couchfile_pointer_info *desc = read_pointer(current_node.buf, kpos);
                errcode = modify_node(rq, desc, start, end, local_result);
                if(local_result->values_end->value.pointer != desc)
                {
                        free(desc);
                }

                if(errcode < 0)
                {
                    goto cleanup;
                }
                node_bound = node_len;
                break;
            }
            else
            {
                //Get all actions with key <= the key of the current item in the
                //kp_node

                //Push items in node up to but not including current onto mr
                mr_push_kp_range(current_node.buf, list_start_pos, node_bound,
                        rq->cmp.list_pos - 1, local_result);
                int range_end = start;
                while(range_end < end &&
                      ((*rq->cmp.compare)(rq->actions[range_end].cmp_key, rq->cmp.last_cmp_key) <= 0))
                {
                    range_end++;
                }

                DBG("  ...descending into item %d of kpnode\r\n", rq->cmp.list_pos);
                node_bound = rq->cmp.list_pos + 1;
                couchfile_pointer_info *desc = read_pointer(current_node.buf, kpos);
                errcode = modify_node(rq, desc, start, range_end, local_result);
                if(local_result->values_end->value.pointer != desc)
                {
                        free(desc);
                }
                if(errcode < 0)
                {
                    goto cleanup;
                }
                start = range_end;
            }
        }
        DBG(".. Finished kp node, up to %d\r\n", node_bound);
        if(node_bound < node_len)
        {
            //Processed all the actions but haven't exhausted this kpnode.
            //push the rest of it onto the mr.
            mr_push_kp_range(current_node.buf, list_start_pos, node_bound, node_len,
                    local_result);
        }
    }
    else
    {
        errcode = ERROR_PARSE;
        goto cleanup;
    }
    //If we've done modifications, write out the last leaf node.
    errcode = flush_mr(local_result);
    if(errcode == 0)
    {
        if(!local_result->modified && nptr != NULL)
        {
            //If we didn't do anything, give back the pointer to the original
            mr_push_pointerinfo(nptr, dst);
        }
        else
        {
            //Otherwise, give back the pointers to the nodes we've created.
            dst->modified = 1;
            errcode = mr_move_pointers(local_result, dst);
        }
    }
cleanup:
    free_modres(local_result);

    if(current_node.buf != empty_root.buf)
    {
        free(current_node.buf);
    }

    return errcode;
}
Beispiel #20
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;
}
/**
 * Query a table for specified rows.
 * \param _h structure representing database connection
 * \param _k key names
 * \param _op operators
 *\param  _v values of the keys that must match
 * \param _c column names to return
 * \param _n number of key=values pairs to compare
 * \param _nc number of columns to return
 * \param _o order by the specified column
 * \param _r pointer to a structure representing the result
 * \return zero on success, negative value on failure
 */
int erlang_srdb1_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
	     const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
	     const db_key_t _o, db1_res_t** _r) {
	ei_x_buff argbuf,retbuf;
	int retcode,i,j,x;
	int n_cols,n_rows,len;
	db1_res_t *res;
	db_row_t *rows = NULL, *row;
	db_val_t *val;
	char atom[MAXATOMLEN], *p;
	ei_term term;
	int ei_type,size;
	str *sname;

	if (!_h || !_r) {
		LM_ERR("invalid parameter value\n");
		return -1;
	}
	*_r=NULL;
	LM_DBG("erlang_srdb1_query table %.*s\n",CON_TABLE(_h)->len, CON_TABLE(_h)->s);
	ei_x_new(&argbuf);
	//encode tuple {db_op, table, [cols], [params]}
	ei_x_encode_tuple_header(&argbuf, 5);
	ei_x_encode_atom(&argbuf,"select");
	ei_x_encode_atom_len(&argbuf,CON_TABLE(_h)->s,CON_TABLE(_h)->len);

	srdb1_encode_c(_c, _nc, &argbuf);
	srdb1_encode_k(_k, _op, _v, _n, &argbuf);
//	ei_x_encode_atom_len(&argbuf,_o->s,_o->len);
	ei_x_encode_list_header(&argbuf, 0);

	retcode=erl_bind.do_erlang_call(&(CON_ERLANG(_h)->con),&(CON_ERLANG(_h)->regname), &argbuf, &retbuf);
	ei_x_free(&argbuf);
	if (retcode<0) {
		if(retbuf.buff) shm_free(retbuf.buff);
		return retcode;
	}
	// we have a tuple there:
	ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &i);
	x=retbuf.index;
	ei_skip_term(retbuf.buff, &x);
	LM_DBG("erlang_srdb1_query: position of end of field list should be %d\n",x);
	//first is list of 5-element tuples containing name and type of field
	ei_decode_list_header(retbuf.buff, &(retbuf.index), &n_cols);
	LM_DBG("erlang_srdb1_query: length -f field_list is %d\n",n_cols);
	res=db_new_result();
	if (db_allocate_columns(res, n_cols) != 0) {
		LM_ERR("erlang_srdb1_query: db_allocate_columns failed\n");
		goto error;
	}
	RES_COL_N(res) = n_cols;
	for(i=0; i < n_cols; i++) {
		x=retbuf.index;
		ei_skip_term(retbuf.buff, &x);
		LM_DBG("erlang_srdb1_query: position of end of this field should be %d\n",x);
		ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &j);
		if( j!=5) LM_ERR("erlang_srdb1_query name&type list element tuple is not 5\n");
		ei_decode_atom(retbuf.buff, &(retbuf.index), atom);  //1  name
		len=strlen(atom);
		sname = (str*)pkg_malloc(sizeof(str)+len+1);
		if (!sname) {
			LM_ERR("no private memory left\n");
			goto error;
		}
		sname->len = len;
		sname->s = (char*)sname + sizeof(str);
		memcpy(sname->s, atom, len);
		sname->s[len] = '\0';
		RES_NAMES(res)[i] = sname;
		LM_DBG("decoded header %d, fieled 1: %s\n",i,atom);
		ei_decode_atom(retbuf.buff, &(retbuf.index), atom); //2 type atom
		if(strcmp("int",atom)==0) { RES_TYPES(res)[i]=DB1_INT; }
		if(strcmp("string",atom)==0) { RES_TYPES(res)[i]=DB1_STRING; }
		if(strcmp("float",atom)==0) { RES_TYPES(res)[i]=DB1_DOUBLE; }
		if(strcmp("datetime",atom)==0) { RES_TYPES(res)[i]=DB1_DATETIME; }
//		if(strcmp("string",atom)==0) { RES_TYPES(res)[i]=DB1_BLOB; }
		ei_skip_term(retbuf.buff, &(retbuf.index));  //3 size (ignored)
		ei_skip_term(retbuf.buff, &(retbuf.index));  //4 default value (ignored)
		ei_skip_term(retbuf.buff, &(retbuf.index));  //3 null status (ignored)
		LM_DBG("end of %d record: %d\n",i,retbuf.index);
	}
	ei_decode_ei_term(retbuf.buff, &(retbuf.index), &term); // List tail,
	LM_DBG("erlang_srdb1_query: position after scanning is %d\n",retbuf.index);
	//now rows, list of tuples
	ei_decode_list_header(retbuf.buff, &(retbuf.index), &n_rows);
	LM_DBG("erlang_srdb1_query values list size is %d\n",n_rows);
	if (n_rows<=0) {
		LM_DBG("erlang_srdb1_query no rows returned\n");
		RES_ROWS(res) = NULL;
		RES_NUM_ROWS(res)=0;
		*_r=res;
		return 0;
	}
	RES_NUM_ROWS(res)=n_rows;
	rows = pkg_realloc(rows, sizeof(db_row_t) * n_rows);
	if (rows == NULL) {
		LM_ERR("erlang_srdb1_query: pkg_realloc rows failed\n");
		goto error;
	}
	RES_ROWS(res) = rows;
	for(i=0; i < n_rows; i++) {
		RES_ROW_N(res)=i+1;
		row = &RES_ROWS(res)[i];
		if (db_allocate_row(res, row) != 0) {
			LM_ERR("erlang_srdb1_query: db_allocate_row failed for row %d\n",i);
			goto error;
		}
		ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &j);
		if(j!=n_cols) {
			LM_ERR("erlang_srdb1_query: mismatch:values list element tuple size is %d n_cols from header was %d\n",j, n_cols);
		}
		for (j = 0, val = ROW_VALUES(row); j < RES_COL_N(res); j++, val++) {
			VAL_TYPE(val) = RES_TYPES(res)[j];
			VAL_NULL(val) = 0;
			VAL_FREE(val) = 0;
			retcode=ei_get_type_internal(retbuf.buff, &(retbuf.index), &ei_type, &size);
			if (retcode < 0) {
				LM_ERR("erlang_srdb1_query: error getting type for element %d %d\n",i,j);
				goto error;
			}
			LM_DBG("erlang_srdb1_query: element %d %d ei_type=%d size=%d\n",i,j,ei_type, size);
			switch(ei_type) {
				case ERL_SMALL_INTEGER_EXT:
				case ERL_INTEGER_EXT:
					retcode=ei_decode_long(retbuf.buff, &(retbuf.index), &VAL_INT(val));
					if(retcode < 0) goto error;
					LM_DBG("decoded interger %d\n",VAL_INT(val));
					break;
				case ERL_FLOAT_EXT:
				case NEW_FLOAT_EXT:
					retcode=ei_decode_double(retbuf.buff, &(retbuf.index), &VAL_DOUBLE(val));
					if(retcode < 0) goto error;
					LM_DBG("decoded float %f\n",VAL_DOUBLE(val));
					break;
				case ERL_ATOM_EXT:
				case ERL_SMALL_ATOM_EXT:
				case ERL_ATOM_UTF8_EXT:
				case ERL_SMALL_ATOM_UTF8_EXT:
					p=pkg_malloc(size+1);
					if(!p) { LM_ERR("erlang_srdb1_query: no memory\n"); goto error; }
					retcode=ei_decode_atom(retbuf.buff, &(retbuf.index), p);
					if(retcode < 0) {
						pkg_free(p);
						goto error;
					}
					LM_DBG("decoded small_atom_utf %s\n",p);
					VAL_STRING(val)=p;
					VAL_FREE(val)=1;
					break;
				case ERL_STRING_EXT:
					p=pkg_malloc(size+1);
					if(!p) { LM_ERR("erlang_srdb1_query: no memory\n"); goto error; }
					retcode=ei_decode_string(retbuf.buff, &(retbuf.index), p);
					if(retcode < 0) {
						pkg_free(p);
						goto error;
					}
					LM_DBG("decoded string %s\n",p);
					VAL_STRING(val)=p;
					VAL_FREE(val)=1;
					break;
				case ERL_SMALL_TUPLE_EXT:
				case ERL_LARGE_TUPLE_EXT:
					LM_DBG("got tuple)\n");
					if (VAL_TYPE(val)==DB1_DATETIME) {
					    struct tm tm;
					    LM_DBG("and col type is datetime\n");
					    retcode=ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &x);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &x);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_year);tm.tm_year -=1900;
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_mon); tm.tm_mon -=1;
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_mday);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &x);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_hour);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_min);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_sec);
					    if(retcode < 0) goto error;
					    VAL_TIME(val)=mktime(&tm);
					    break;
					}
					LM_ERR("erlang_srdb1_query: got tuple but valtype is not datetime element %d in row %d in response\n",j,i);
					break;
				case ERL_REFERENCE_EXT:
				case ERL_NEW_REFERENCE_EXT:
				case ERL_PORT_EXT:
				case ERL_PID_EXT:
				case ERL_NIL_EXT:
				case ERL_LIST_EXT:
				case ERL_BINARY_EXT:
				case ERL_SMALL_BIG_EXT:
				case ERL_LARGE_BIG_EXT:
				case ERL_NEW_FUN_EXT:
				case ERL_FUN_EXT:
				default:
				    LM_ERR("erlang_srdb1_query: don't know how to handle element %d in row %d in response\n",j,i);
			}
		}
	}
	ei_decode_ei_term(retbuf.buff, &(retbuf.index), &term); // List tail,
	*_r=res;
	return 0;
error:
	if (res)
		db_free_result(res);
	LM_ERR("erlang_srdb1_query: Failed\n");
	return -1;
}