Esempio n. 1
0
static void gen_q_drv_output(ErlDrvData handle, char *buff,
        ErlDrvSizeT bufflen) {
    GenQData *d = (GenQData*)handle;

    QWork* work = genq_alloc_work(buff, bufflen);
    if(work->op == FUNC_OPTS) {
        LOG("received opts %ld\n", work->op);
        copy_qopts((QOpts*)work->data, &d->opts);
        genq_free_work(work);

        LOG("responding %s\n", "ok");
        ei_x_buff ok;
        ei_x_new(&ok);
        ei_x_encode_ok(&ok);
        driver_output(d->port, ok.buff, ok.index);
        ei_x_free(&ok);
        return;
    } else if(work->data == NULL) {
        genq_free_work(work);
        ei_x_buff error;
        ei_x_new(&error);
        ei_x_encode_error_tuple_atom(&error, "badarg");
        driver_output(d->port, error.buff, error.index);
        ei_x_free(&error);
        return;
    }
    work->opts = &d->opts;

    driver_async(d->port, work->dispatch_key,
            genq_work,
            work,
            genq_free_work);
}
Esempio n. 2
0
/* format a string into an ei_x_buff, except the version token */
static int eiformat(const char** fmt, union arg** args, ei_x_buff* x)
{
    const char* p = *fmt;
    int res;
    ei_x_buff x2;

    while (isspace((int)*p))
	++p;
    switch (*p) {
    case '~':
	res = pformat(&p, args, x);
	break;
    case '[':
	res = ei_x_new(&x2);
	if (res >= 0)
	    res = plist(&p, args, &x2, 0);
	if (res > 0)
	    res = ei_x_encode_list_header(x, res);
	if (res >= 0)
	    res = ei_x_append(x, &x2);
	ei_x_free(&x2);
	break;
    case '{':
	res = ei_x_new(&x2);
	if (res >= 0)
	    res = ptuple(&p, args, &x2, 0);
	if (res >= 0)
	    res = ei_x_encode_tuple_header(x, res);
	if (res >= 0)
	    res = ei_x_append(x, &x2);
	ei_x_free(&x2);
	break;
    case '"':
	res = pstring(&p, x);
	break;
    case '\'':
	res = pquotedatom(&p, x);
	break;
    default:
	if (isdigit((int)*p))
	    res = pdigit(&p, x);
	else if ((*p == '-' || *p == '+') && isdigit((int)*(p+1)))
	    res = pdigit(&p, x);
	else if (islower((int)*p))
	    res = patom(&p, x);
	else
	    res = -1;
	break;
	/*
	Variables
	*/
    }
    *fmt = p;
    return res;
}
Esempio n. 3
0
void *erlXML_StartElementHandler(expat_data *d,
				 const XML_Char *name,
				 const XML_Char **atts)
{
   int i;

   ei_x_encode_list_header(&event_buf, 1);
   ei_x_encode_tuple_header(&event_buf, 2);
   ei_x_encode_long(&event_buf, XML_START);
   ei_x_encode_tuple_header(&event_buf, 2);
   encode_name(name);
   ei_x_append(&event_buf, &xmlns_buf);
   ei_x_free(&xmlns_buf);
   ei_x_new(&xmlns_buf);

   for (i = 0; atts[i]; i += 2) {}

   if (i > 0)
   {
      ei_x_encode_list_header(&event_buf, i/2);

      for (i = 0; atts[i]; i += 2)
      {
	 ei_x_encode_tuple_header(&event_buf, 2);
	 encode_name(atts[i]);
	 ei_x_encode_binary(&event_buf, atts[i+1], strlen(atts[i+1]));
      }
   }

   ei_x_encode_empty_list(&event_buf);

   return NULL;
}
/**
  * Insert a row into a specified table, update on duplicate key.
  * \param _h structure representing database connection
  * \param _k key names
  * \param _v values of the keys
  * \param _n number of key=value pairs
 */
 int erlang_srdb1_insert_update(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v,
	const int _n)
 {
	ei_x_buff argbuf;
	int retcode;

	if ((!_h) || (!_k) || (!_v) || (!_n)) {
		LM_ERR("invalid parameter value\n");
		return -1;
	}
	LM_DBG("erlang_srdb1_insert_update table %.*s\n",CON_TABLE(_h)->len, CON_TABLE(_h)->s);
	ei_x_new(&argbuf);
	//encode tuple {db_op, table, [cols], [keys], [vals]}
	ei_x_encode_tuple_header(&argbuf, 5);
	ei_x_encode_atom(&argbuf,"insert_update");
	ei_x_encode_atom_len(&argbuf,CON_TABLE(_h)->s,CON_TABLE(_h)->len);

	ei_x_encode_list_header(&argbuf, 0); //_c
//	ei_x_encode_list_header(&argbuf, 0); //_k
	srdb1_encode_k(_k, NULL, _v, _n, &argbuf); //_k
	srdb1_encode_v(_k, _v, _n, &argbuf); //_v

	retcode=erl_bind.do_erlang_call(&(CON_ERLANG(_h)->con),&(CON_ERLANG(_h)->regname), &argbuf, NULL /*&retbuf*/);
	ei_x_free(&argbuf);
	if (retcode<0) {
//		if(retbuf.buff) shm_free(retbuf.buff);
		return retcode;
	}
	return 0;
}
Esempio n. 5
0
static ErlDrvData
exmpp_xml_start(ErlDrvPort port, char *command)
{
	struct exmpp_xml_data *edd;

	/* Set binary mode. */
	set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);

	/* Allocate driver data structure. */
	edd = driver_alloc(sizeof(*edd));
	if (edd == NULL)
		return (ERL_DRV_ERROR_GENERAL);

	/* Initialize generic context. */
	if (init_context(&edd->ctx) != 0) {
		driver_free(edd);
		return (ERL_DRV_ERROR_GENERAL);
	}
	edd->ctx.make_attributes = exmpp_xml_cb_make_attributes;

	/* Initialize driver instance's context. */
	edd->parser = NULL;

	/* Initialize the declared_nss list. */
	edd->declared_nss = driver_alloc(sizeof(*(edd->declared_nss)));
	if (edd->declared_nss == NULL) {
		free_context(&edd->ctx);
		driver_free(edd);
		return (ERL_DRV_ERROR_GENERAL);
	}
	ei_x_new(edd->declared_nss);

	return ((ErlDrvData)edd);
}
Esempio n. 6
0
/*
 * Now returns non-negative number for success, negative for failure.
 */
int erl_rpc_to(int fd, char *mod, char *fun, ETERM *args)
{
    int r;
    ei_x_buff x;

    ei_x_new(&x);
    ei_x_encode_term(&x, args);
    r = ei_rpc_to(&erl_if_ec, fd, mod, fun, x.buff, x.index);
    ei_x_free(&x);
    return r;
} /* rpc_to */
static void ei_x_print_msg(ei_x_buff *buf, erlang_pid *pid, int send) {
    char *pbuf = NULL;
    int i = 0;
    ei_x_buff pidbuf;

    ei_x_new(&pidbuf);
    ei_x_encode_pid(&pidbuf, pid);

    ei_s_print_term(&pbuf, pidbuf.buff, &i);

    ei_x_print_reg_msg(buf, pbuf, send);
    free(pbuf);
}
/* function to make rpc call to remote node to retrieve a pid - 
   calls module:function(Ref). The response comes back as
   {rex, {Ref, Pid}}
 */
int ei_pid_from_rpc(struct ei_cnode_s *ec, int sockfd, erlang_ref * ref, char *module, char *function)
{
	ei_x_buff buf;
	ei_x_new(&buf);
	ei_x_encode_list_header(&buf, 1);
	ei_x_encode_ref(&buf, ref);
	ei_x_encode_empty_list(&buf);

	ei_rpc_to(ec, sockfd, module, function, buf.buff, buf.index);
	ei_x_free(&buf);

	return 0;
}
Esempio n. 9
0
static ErlDrvSSizeT
do_call(ErlDrvData drv_data, unsigned int command, char *buf, 
	  ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen, unsigned *ret_flags) 
{
    int nlen;
    ei_x_buff x;

    switch (command) {
    case 0:
	*rbuf = buf;
	*ret_flags |= DRIVER_CALL_KEEP_BUFFER;
	return len;
    case 1:
	ei_x_new(&x);
	ei_x_format(&x, "{[], a, [], b, c}");
	nlen = x.index;
	if (nlen > rlen) {
	    *rbuf =driver_alloc(nlen);
	}
	memcpy(*rbuf,x.buff,nlen);
	ei_x_free(&x);
	return nlen;
    case 2:
	ei_x_new(&x);
	ei_x_encode_version(&x);	
	ei_x_encode_tuple_header(&x,2);
	ei_x_encode_atom(&x,"return");
	ei_x_append_buf(&x,buf+1,len-1);
	nlen = x.index;
	if (nlen > rlen) {
	    *rbuf =driver_alloc(nlen);
	}
	memcpy(*rbuf,x.buff,nlen);
	ei_x_free(&x);
	return nlen;
    default:
	return -1;
    }
}
Esempio n. 10
0
static void ready_async(ErlDrvData handle, ErlDrvThreadData w) {
    GenQData* d = (GenQData*)handle;
    QWork* work = (QWork*)w;

    ei_x_buff result;
    ei_x_new(&result);

    genq_work_result(work, &result);
    genq_free_work(work);

    driver_output(d->port, result.buff, result.index);
    ei_x_free(&result);
}
Esempio n. 11
0
File: q2e.c Progetto: csurface/gen_q
int ei_x_encode_k(ei_x_buff* x, K r, QOpts* opts) {
    EI(ei_x_encode_tuple_header(x, 2));
    ei_x_buff* types = x;
    ei_x_buff values;
    EI(ei_x_new(&values));
    EIC(ei_x_encode_k_tv(types, &values, r, opts),
            ei_x_free(&values)); // cleanup expression
    // TODO - JMS - is there a way to do this without deep copying data?
    EIC(ei_x_append(types, &values),
            ei_x_free(&values)); // cleanup expression
    EI(ei_x_free(&values));
    return 0;
}
Esempio n. 12
0
int erl_receive_msg(int fd, unsigned char *buf, int bufsize, ErlMessage *emsg)
{
    ei_x_buff x;
    int r;

    ei_x_new(&x);
    r = erl_do_receive_msg(fd, &x, emsg);
    /* FIXME what is this about? */
    if (bufsize > x.index)
	bufsize = x.index;
    memcpy(buf, x.buff, bufsize);
    ei_x_free(&x);
    return r;
}
Esempio n. 13
0
int erl_xreceive_msg(int fd, unsigned char **buf, int *bufsize,
		  ErlMessage *emsg)
{
    ei_x_buff x;
    int r;

    ei_x_new(&x);
    r = erl_do_receive_msg(fd, &x, emsg);
    if (*bufsize < x.index)
	*buf = erl_realloc(*buf, x.index);
    *bufsize = x.index;
    memcpy(*buf, x.buff, *bufsize);
    ei_x_free(&x);
    return r;
}
Esempio n. 14
0
static ErlDrvSSizeT expat_erl_control(ErlDrvData drv_data,
			     unsigned int command,
			     char *buf, ErlDrvSizeT len,
			     char **rbuf, ErlDrvSizeT rlen)
{
   expat_data* d = (expat_data*)drv_data;
   int res, errcode;
   char *errstring;
   ErlDrvBinary *b;
   size_t size;

   switch (command)
   {
      case PARSE_COMMAND:
      case PARSE_FINAL_COMMAND:
	 ei_x_new_with_version(&event_buf);
	 ei_x_new(&xmlns_buf);
	 res = XML_Parse(d->parser, buf, len, command == PARSE_FINAL_COMMAND);

	 if(!res)
	 {
	    errcode = XML_GetErrorCode(d->parser);
	    errstring = (char *)XML_ErrorString(errcode);

	    ei_x_encode_list_header(&event_buf, 1);
	    ei_x_encode_tuple_header(&event_buf, 2);
	    ei_x_encode_long(&event_buf, XML_ERROR);
	    ei_x_encode_tuple_header(&event_buf, 2);
	    ei_x_encode_long(&event_buf, errcode);
	    ei_x_encode_binary(&event_buf, errstring, strlen(errstring));
	 }

	 ei_x_encode_empty_list(&event_buf);

	 size = event_buf.index;

	 b = driver_alloc_binary(size);
	 memcpy(b->orig_bytes, event_buf.buff, size);

	 ei_x_free(&event_buf);
	 ei_x_free(&xmlns_buf);
 
	 *rbuf = (char *)b;
	 return size;
      default:
	 return 0;
   }
}
Esempio n. 15
0
int ei_s_print_term(char** s, const char* buf, int* index)
{
    int r;
    ei_x_buff x;
    if (*s != NULL) {
	x.buff = *s;
	x.index = 0;
	x.buffsz = BUFSIZ;
    } else {
	ei_x_new(&x);
    }
    r = print_term(NULL, &x, buf, index);
    ei_x_append_buf(&x, "", 1); /* append '\0' */
    *s = x.buff;
    return r;
}
Esempio n. 16
0
/* tests de tipos simples */
int test_performance_atom(char *atom, int times) {
	
	ei_x_buff output;
	ei_x_buff input;
	erlang_msg msg;
	int version;
	int ei_res;
	int index;
	char decoded_atom[MAXATOMLEN]; 
	
	// Inicializa buffers
	ei_x_new_with_version(&output);
	ei_x_new(&input);
	
	// Codifica
	ei_x_encode_tuple_header(&output, 2);
	ei_x_encode_pid(&output, &local_pid);
	ei_x_encode_atom(&output, atom);
	
	for (int i = 0; i<times; i++) {
		if (ei_reg_send(&ec, connection_fd, REMOTE_SERVER_NAME, 
			output.buff, output.index) < 0) {
				return 1;
		}
		do {
			ei_res = ei_xreceive_msg(connection_fd, &msg, &input);
		} while(ei_res == ERL_TICK);
		
		if (ei_res == ERL_ERROR) {
			return -1;
		}
		index = 0;
		if (ei_decode_version(input.buff, &index, &version) < 0) {
			std::cout << "failed decoding version \n";
			return 1;
		}
				

		if (ei_decode_atom(input.buff, &index, decoded_atom) < 0) {
			std::cout << "failed decoding atom \n";
			return 1;
		}		
	}
		
	return 0;
}
Esempio n. 17
0
int
init_context(struct exmpp_xml_ctx *ctx)
{

	/* Set default options. */
	ctx->max_size = -1;
	ctx->root_depth = 0;
	ctx->emit_endtag = 0;
	ctx->names_as_atom = 1;
	ctx->check_nss = ctx->check_elems = 0;
	ctx->known_nss = ctx->known_elems = NULL;

	/* Clear callbacks. */
	ctx->make_declared_nss = NULL;
	ctx->make_attributes = NULL;
	ctx->make_attributes_legacy = NULL;

	/* Reset parsing state. */
	ctx->cur_size = 0;
	ctx->depth = 0;

	/* Allocate the current tree */
	ctx->current_tree = driver_alloc(sizeof(*(ctx->current_tree)));
	if (ctx->current_tree == NULL)
		return (-1);
	ei_x_new(ctx->current_tree);

	/* Allocate the complete trees list. */
	ctx->complete_trees = driver_alloc(sizeof(*(ctx->complete_trees)));
	if (ctx->complete_trees == NULL) {
		ei_x_free(ctx->current_tree);
		driver_free(ctx->current_tree);
		return (-1);
	}
	ei_x_new_with_version(ctx->complete_trees);
	ctx->complete_trees_ready = 0;

	return (0);
}
Esempio n. 18
0
static void cmd_ei_rpc(char* buf, int len)
{
    int index = 0, n;
    long fd;
    erlang_pid pid;
    ei_x_buff x, rpc_x;
    int r;
    char mod[MAXATOMLEN], func[MAXATOMLEN];

#if 0 && defined(__WIN32__) 
    DebugBreak();
#endif

    if (ei_decode_long(buf, &index, &fd) < 0)
	fail("expected long");
    if (ei_decode_pid(buf, &index, &pid) < 0)
	fail("expected pid (node)");
    if (ei_decode_tuple_header(buf, &index, &n) < 0 && n < 2)
	fail("expected tuple {module, function}");
    if (ei_decode_atom(buf, &index, mod) < 0)
	fail("expected atom (module)");
    if (ei_decode_atom(buf, &index, func) < 0)
	fail("expected atom (function)");
    message("pid %s %d %d %d\n", pid.node, pid.num, pid.serial, pid.creation);
    message("{%s, %s}\n", mod, func);
    if (ei_x_new(&rpc_x) < 0)
	fail("ei_x_new");
    if (ei_rpc(&ec, fd, mod, func, &buf[index], len - index, &rpc_x) < 0)
	fail("ei_rpc");
    if (ei_x_new_with_version(&x) < 0)
 	fail("ei_x_new_with_version");
    if (ei_x_append(&x, &rpc_x) < 0)
	fail("append");
    send_bin_term(&x);
    /*send_errno_result(ei_send(&ec, fd, &pid, x.buff, x.index));*/
    ei_x_free(&x);
    ei_x_free(&rpc_x);
}
Esempio n. 19
0
static void
send_printed3(char* format, char* p1, char* p2, int fl)
{
    char* b = NULL;
    char fn[100], * tmp = getenv("temp");
    FILE* f;
    int n, index = 0, ver;
    ei_x_buff x;

    ei_x_new(&x);
    if (fl) {
	ei_x_format(&x, format, *(float*)p1, *(float*)p2);
    } else {
	ei_x_format(&x, format, p1, p2);
    }
#ifdef VXWORKS
    tmp = ".";
#else
    if (tmp == NULL) tmp = "/tmp";
#endif
    strcpy(fn, tmp);
    strcat(fn, "/ei_print_test.txt");
    f = fopen(fn, "w+");
    ei_decode_version(x.buff, &index, &ver);
    n = ei_print_term(f, x.buff, &index);
    fseek(f, 0, SEEK_SET);
    b = malloc(n+1);
    fread(b, 1, n, f);
    b[n] = '\0';
    fclose(f);
    x.index = 0;
    ei_x_format(&x, "~s", b);
    send_bin_term(&x);
    free(b);
    ei_x_free(&x);
}
Esempio n. 20
0
static DWORD WINAPI
#else
static void*
#endif
    einode_thread(void* num)
{
    int n = (int)num;
    ei_cnode ec;
    char myname[100], destname[100];
    int r, fd, listen;
    ErlConnect conn;
    erlang_msg msg;
/*    FILE* f;*/

    sprintf(myname, "eiacc%d", n);
    printf("thread %d (%s) listening\n", n, myname, destname);
    r = ei_connect_init(&ec, myname, cookie, 0);
    if ((listen = my_listen(port+n)) <= 0) {
	printf("listen err\n");
	exit(7);
    }
    if (ei_publish(&ec, port + n) == -1) {
	printf("ei_publish port %d\n", port+n);
	exit(8);
    }
    fd = ei_accept(&ec, listen, &conn);
    printf("ei_accept %d\n", fd);
    if (fd >= 0) {
	ei_x_buff x, xs;
	int index, version;
	erlang_pid pid;

	ei_x_new(&x);
	for (;;) {
	    int got = ei_xreceive_msg(fd, &msg, &x);
	    if (got == ERL_TICK)
		continue;
	    if (got == ERL_ERROR) {
		printf("receive error %d\n", n);
		return 0;
	    }
	    printf("received %d\n", got);
	    break;
	}
	index = 0;
	if (ei_decode_version(x.buff, &index, &version) != 0) {
	    printf("ei_decode_version %d\n", n);
	    return 0;
	}
	if (ei_decode_pid(x.buff, &index, &pid) != 0) {
	    printf("ei_decode_pid %d\n", n);
	    return 0;
	}
/*	fprintf(f, "got pid from %s \n", pid.node);*/
	ei_x_new_with_version(&xs);
	ei_x_encode_tuple_header(&xs, 2);
	ei_x_encode_long(&xs, n);
	ei_x_encode_pid(&xs, &pid);
	r = ei_send(fd, &pid, xs.buff, xs.index);
/*	fprintf(f, "sent %d bytes %d\n", xs.index, r);*/
	shutdown(fd, SD_SEND);
	closesocket(fd);
	ei_x_free(&x);
	ei_x_free(&xs);
    } else {
	printf("coudn't connect fd %d r %d\n", fd, r);
    }
    printf("done thread %d\n", n);
/*    fclose(f);*/
    return 0;
}
Esempio n. 21
0
void decode_encode_big(struct Type* t)
{
    char *buf;
    char buf2[2048];
    void *p; /* (TYPE*) */
    int size1 = 0;
    int size2 = 0;
    int size3 = 0;
    int err, index = 0, len, type;
    ei_x_buff arg;

    MESSAGE("ei_decode_%s, arg is type %s", t->name, t->type);
    buf = read_packet(NULL);
    ei_get_type(buf+1, &index, &type, &len);
    p = ei_alloc_big(len);
    err = t->ei_decode_fp(buf+1, &size1, p);
    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;
    }

    MESSAGE("ei_encode_%s buf is NULL, arg is type %s", t->name, t->type);
    err = t->ei_encode_fp(NULL, &size2, p);
    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);
    err = t->ei_encode_fp(buf2, &size3, p);
    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;
    }
    send_buffer(buf2, size1);

    MESSAGE("ei_x_encode_%s, arg is type %s", t->name, t->type);
    ei_x_new(&arg);
    err = t->ei_x_encode_fp(&arg, p);
    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;
    }
    send_buffer(arg.buff, arg.index);
    ei_x_free(&arg);
    ei_free_big(p);
}
Esempio n. 22
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);
}
int erlang_srdb2_cmd_exec(db_res_t* res, db_cmd_t* cmd) {
	LM_DBG("erlang_srdb2_cmd_exec %p %p\n",res ,cmd);
	db_fld_t* fld;
	ei_x_buff argbuf;
	int i,cnt;
	char *pbuf=NULL;
	static str con=STR_STATIC_INIT("con1");
	static str regname=STR_STATIC_INIT("echo_server");

	LM_DBG("erlang_srdb2_cmd %p\n",cmd);
//	for(i = 0, fld = cmd->vals; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[i]); i++) {
//		rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
//		if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, set_str(&tmpstr, ","));
//	}
	ei_x_new(&argbuf);
	//encode tuple {db_op, table, [cols], [params]}
	ei_x_encode_tuple_header(&argbuf, 5);
	switch(cmd->type) {
	    case DB_PUT: ei_x_encode_atom(&argbuf,"insert"); break;
	    case DB_DEL: ei_x_encode_atom(&argbuf,"delete"); break;
	    case DB_GET: ei_x_encode_atom(&argbuf,"select"); break;
	    case DB_UPD: ei_x_encode_atom(&argbuf,"update"); break;
	    case DB_SQL: ei_x_encode_atom(&argbuf,"rawquery"); break;
	}
	ei_x_encode_atom_len(&argbuf,cmd->table.s,cmd->table.len);
	
	for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {}
	ei_x_encode_list_header(&argbuf, i);
	for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {
		ei_x_encode_atom(&argbuf,fld[i].name);
	}
	ei_x_encode_empty_list(&argbuf);
	
	if(cmd->match) {
	    for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {}
	    ei_x_encode_list_header(&argbuf, i);
	    for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
		ei_x_encode_tuple_header(&argbuf, 3);
		ei_x_encode_atom(&argbuf,fld[i].name);
		switch(fld[i].op) {
		    case DB_EQ:  ei_x_encode_atom(&argbuf,"="); break;
		    case DB_NE:  ei_x_encode_atom(&argbuf,"!="); break;
		    case DB_LT:  ei_x_encode_atom(&argbuf,"<"); break;
		    case DB_GT:  ei_x_encode_atom(&argbuf,">"); break;
		    case DB_LEQ: ei_x_encode_atom(&argbuf,"<="); break;
		    case DB_GEQ: ei_x_encode_atom(&argbuf,">="); break;
		}
		ei_x_encode_atom_len(&argbuf,fld[i].v.lstr.s,fld[i].v.lstr.len);
	    }
	    ei_x_encode_empty_list(&argbuf);
	} else {
	    ei_x_encode_list_header(&argbuf, 0);
	}
	if(cmd->vals) {
	    for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) {}
	    ei_x_encode_list_header(&argbuf, i);
	    for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {
		ei_x_encode_atom(&argbuf,fld[i].name);
	    }
	    ei_x_encode_empty_list(&argbuf);
	} else {
	    ei_x_encode_list_header(&argbuf, 0);
	}
	
	i=0;
	ei_s_print_term(&pbuf, argbuf.buff, &i);
	LM_DBG("message is pbuf='%s' buf.buffsz=%d buf.index=%d i=%d\n", pbuf, argbuf.buffsz,argbuf.index,i );
	free(pbuf);pbuf=NULL;
	erl_bind.do_erlang_call(&con,&regname, &argbuf, NULL);
	ei_x_free(&argbuf);
	return 0;
};
Esempio n. 24
0
int ei_x_new_with_version(ei_x_buff* x)
{
    if (ei_x_new(x) < 0)
	return -1;
    return ei_encode_version(x->buff, &x->index);
}
Esempio n. 25
0
ei_x_buff_ptr::ei_x_buff_ptr() : m_ptr(new ei_x_buff)
{
    ei_x_new(m_ptr.get());
}
Esempio n. 26
0
static int
erlang_query(DICT_ERLANG *dict_erlang, const char *key, ARGV *nodes,
             char *cookie, char *mod, char *fun, char **res)
{
    int cur_node;
    int err, index, retries;
    int res_version, res_type, res_size;
    int fd;
    ei_cnode ec;
    ei_x_buff args;
    ei_x_buff resp;
    VSTRING *node_name;

    node_name = vstring_alloc(15);
    /* Get an "unique" name for the node */
    vstring_sprintf(node_name, "dict_erlang%u", getpid() % 999);
    err = ei_connect_init(&ec, vstring_str(node_name), cookie, 0);
    if (err != 0) {
        msg_warn_erl("ei_connect_init");
        return -1;
    }

    retries = 3;
retry:
    cur_node = dict_erlang->active_node;
    do {
        fd = ei_connect(&ec, nodes->argv[cur_node]);
        if (fd >= 0) {
            dict_erlang->active_node = cur_node;
            if (msg_verbose)
                msg_info("connected to node %s", nodes->argv[cur_node]);
            break;
        }
        cur_node = (cur_node + 1) % nodes->argc;
    } while (cur_node != dict_erlang->active_node);

    if (fd < 0) {
        if (retries > 0 && erl_errno == EIO) {
            msg_warn_erl("no suitable nodes found, retrying");
            retries--;
            goto retry;
        }
        msg_warn_erl("no suitable nodes found, failing");
        return -1;
    }

    ei_x_new(&args);
    ei_x_new(&resp);

    ei_x_encode_list_header(&args, 1);
    ei_x_encode_binary(&args, key, strlen(key));
    ei_x_encode_empty_list(&args);

    err = ei_rpc(&ec, fd, mod, fun, args.buff, args.index, &resp);
    if (err == -1) {
        msg_warn_erl("ei_rpc");
        goto cleanup;
    }

    err = handle_response(dict_erlang, key, &resp, res);

cleanup:
    close(fd);
    ei_x_free(&args);
    ei_x_free(&resp);
    return err;
}
Esempio n. 27
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;
}
Esempio n. 28
0
void erlang_loop(int id, void *data) {

	ErlConnect econn;
	//ErlMessage em;
	erlang_msg em;
	int fd;

	int eversion;

	ei_x_buff x, xr;

	ei_x_new(&x); 
	ei_x_new(&xr); 

	
	/*
	int fd0 = ei_connect(&uerl.cnode, "anothernode@maverick64");
	uwsgi_log("fd0: %d\n", fd0);

	ei_x_encode_list_header(&x, 0);

	ei_rpc_to(&uerl.cnode, fd0, "erlang", "node", x.buff, x.index);

	ei_rpc_from(&uerl.cnode, fd0, 10000, &em, &xr);

	uwsgi_log("From: %s To: %s RegName: %s\n", em.from.node, em.to.node, em.toname);

	xr.index = 0;
	ei_decode_version(xr.buff, &xr.index, &eversion);
        uwsgi_log("eversion: %d\n", eversion);

	dump_eterm(&xr);	
	*/

	for(;;) {

		fd = ei_accept(&uerl.cnode, uerl.fd, &econn);

		if (fd >= 0) {

			for (;;) {
				if (ei_xreceive_msg(fd, &em, &x) == ERL_MSG) {

					if (em.msgtype == ERL_TICK)
						continue;

					uwsgi_log("[erlang] message From: %s To (process): %s\n", em.from.node, em.toname);


					
					x.index = 0;
					ei_decode_version(x.buff, &x.index, &eversion);
#ifdef UWSGI_DEBUG
					uwsgi_log("eversion: %d\n", eversion);
#endif

					if (!strcmp(em.toname, "rex")) {
						uwsgi_erlang_rpc(fd, &em.from, &x);
					}
					else {
						struct uwsgi_erlang_process *uep = uerl.uep;
						while(uep) {
							if (!strcmp(uep->name, em.toname)) {
								if (uep->plugin) {
									uep->plugin(uep->func, &x);	
								}
								break;
							}
							uep = uep->next;
						}

						if (!uep) {
							uwsgi_log("!!! unregistered erlang process requested, dumping it !!!\n");
							dump_eterm(&x);
						}
					}
					
					

/*

					if (em.msgtype) {
						dump_erl_obj(em.msg);
						erl_free_compound(em.msg);
					}
					if (em.to) {
						uwsgi_log("*** TO ***\n");
						dump_erl_obj(em.to);
						erl_free_compound(em.to);
					}

					if (em.from) {
						uwsgi_log("*** FROM ***\n");
						dump_erl_obj(em.from);
						erl_free_compound(em.from);
					}
*/

				}
				else {
					break;
				}
			}

			close(fd);

		}
	}
}
Esempio n. 29
0
/* Return values:
 * - -1 error
 * - 0 nothing
 * - 1 detach */
int cnode_read(int fd, char **ret_str) {
	ei_x_buff x;
	erlang_msg msg;
	int result, index, o_index, arity, type, size, ver, rv = CNODE_IGNORE;
	const char *str;
	char *s;
	char atom[MAXATOMLEN];

	ei_x_new(&x);
	/* We don't use xreceive because we're not expecting any big
	   messages and we don't want a huge term to cause our memory
	   usage to blow out and crash us. */
	/* Use a timeout of 1 millisecond even though we know we'll
	   be able to read at least some bytes, just to be sure we
	   do not get blocked (for long). Really we want to specify
	   "no timeout but don't block" to ei_receive_msg but it
	   doesn't provide that functionality. */
	result = ei_receive_msg_tmo(fd, &msg, &x, 1);

	if (result < 0) {
		LOG_V("ei_receive_msg_tmo failed (%d): %s", erl_errno, strerror(erl_errno));
		switch (erl_errno) {
			case ETIMEDOUT:
				DEBUG("ei_receive_msg_tmo: timed out.");
				break;
			case EAGAIN:
				DEBUG("ei_receive_msg_tmo: try again");
				break;
			case EMSGSIZE:
				DEBUG("ei_receive_msg_tmo: message too big");
				rv = CNODE_ERROR;
				break;
			case EIO:
				LOG_V("ei_receive_msg_tmo: IO error (%d: %s)", errno, strerror(errno));
				if (errno != EAGAIN)
					rv = CNODE_ERROR;
				break;
		}
	}
	else {
		if (result == ERL_TICK) { /* nothing to do */
			DEBUG("node tick message");
		}
		else {
			switch (msg.msgtype) {
				case ERL_SEND: str = "SEND"; break;
				case ERL_REG_SEND: str = "REG_SEND"; break;
				case ERL_LINK: str = "LINK"; break;
				case ERL_UNLINK: str = "UNLINK"; break;
				default: str = "unknown";
			}
			if (msg.msgtype == ERL_REG_SEND) {
				index = 0;

				if (ei_decode_version(x.buff, &index, &ver) == 0) {
					// DEBUG_V("data ver %d", ver);
				}

				o_index = index;

				if (ei_decode_atom(x.buff, &index, atom) == 0) {
					// DEBUG_V("atom %s", atom);
					if (!strcmp(atom, "detach")) {
						DEBUG("got detach message");
						rv = CNODE_DETACH;
					}
					else if (!strcmp(atom, "thump")) {
						rv = CNODE_THUMP;
					}
					else {
						DEBUG("message is unknown");
					}
				}
				else if (ei_decode_tuple_header(x.buff, &index, &arity) == 0) {
					if ((arity == 2)
					&& !ei_decode_atom(x.buff, &index, atom) && !strcmp(atom, "stdout")
					&& !ei_get_type(x.buff, &index, &type, &size)
					&& (type == ERL_STRING_EXT)) {
						*ret_str = (char *)malloc(size + 1);
						if (ei_decode_string(x.buff, &index, *ret_str)) {
							LOG("Failed to decode string for stdout message.");
							free(*ret_str);
							rv = CNODE_ERROR;
						}
						else
							rv = CNODE_STR;
					}
					else {
						index = o_index; // Re-set index to beginning of term.
						s = 0;
						ei_s_print_term(&s, x.buff, &index);
						LOG_V("Unknown tuple (arity %d): %s", arity, s);
						free(s);
					}
				}
				else {
					s = 0;
					ei_s_print_term(&s, x.buff, &index);
					LOG_V("Unknown message: %s", s);
					free(s);
				}
			}
			else {
				DEBUG_V("received %s message", str);
			}
		}
	}
	ei_x_free(&x);
	return rv;
}
/**
 * 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;
}