Module: sip-router
Branch: master
Commit: 07276eb9a1173b4e58d14aa82a7b81e5f2dca824
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=07276eb…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Date: Wed Jul 15 22:39:20 2009 +0200
ctl(s): support for '.' and type autoconversion
- support for the new '.' rpc->scan modifier (when used it
turns auto-conversion on for the next input parameter, e.g.:
rpc->scan(".s", &str))
- new module "autoconversion" module parameter that enables
auto-conversion globally
- fixed minor parameter number bug in binrpc faults, when the
'*' modifier was used in rpc->scan()
- added binrpc context garbage collection supports (needed to
track memory allocation used in type conversions)
---
modules_s/ctl/binrpc_run.c | 189 +++++++++++++++++++++++++++++++++++++++++---
modules_s/ctl/ctl.c | 5 +
2 files changed, 181 insertions(+), 13 deletions(-)
diff --git a/modules_s/ctl/binrpc_run.c b/modules_s/ctl/binrpc_run.c
index 0fac504..aa50e8a 100644
--- a/modules_s/ctl/binrpc_run.c
+++ b/modules_s/ctl/binrpc_run.c
@@ -39,12 +39,20 @@
#include "io_listener.h"
#include <stdio.h> /* vsnprintf */
+#include <stdlib.h> /* strtod */
#include <stdarg.h>
+/* if set try to automatically convert values to the requested type in
+ rpc->scan (default: not set) */
+int autoconvert=0;
+
+
#define BINRPC_MAX_BODY 4096 /* maximum body for send */
#define STRUCT_MAX_BODY 1024
#define MAX_MSG_CHUNKS 96
+#define BINRPC_GC_IBSIZE 4 /* initial gc block size (pointers no.) */
+
struct rpc_struct_head{
struct rpc_struct_l* next;
struct rpc_struct_l* prev;
@@ -72,11 +80,21 @@ struct binrpc_recv_ctx{
int in_struct;
};
+
+struct binrpc_gc_block{
+ unsigned short p_no; /**< array size */
+ unsigned short idx; /**< current/last used pos. in the array */
+ struct binrpc_gc_block* next;
+ void* p[1]; /**< array of pointers that will be free'd */
+};
+
+
struct binrpc_ctx{
struct binrpc_recv_ctx in;
struct binrpc_send_ctx out;
void* send_h; /* send handle */
char* method;
+ struct binrpc_gc_block* gc; /**< garbage collection */
int replied;
};
@@ -113,6 +131,51 @@ static rpc_t binrpc_callbacks={
+/** mark a pointer for freeing when the ctx is destroyed.
+ * @return 0 on success, -1 on error
+ */
+inline static int binrpc_gc_track(struct binrpc_ctx* ctx, void* p)
+{
+ struct binrpc_gc_block* b;
+ int n;
+
+ b=ctx->gc;
+ if (b==0 || (b->idx>=b->p_no)){
+ n=(b==0)?BINRPC_GC_IBSIZE:b->p_no*2;
+ b=pkg_malloc(sizeof(*b)+n*sizeof(void*)-sizeof(b->p));
+ if (b==0)
+ return -1;
+ b->p_no=n;
+ b->idx=0;
+ /* link in front */
+ b->next=ctx->gc;
+ ctx->gc=b;
+ }
+ b->p[b->idx]=p;
+ b->idx++;
+ return 0;
+}
+
+
+
+/** free all the tracked pointer from ctx->gc.
+ */
+inline static void binrpc_gc_collect(struct binrpc_ctx* ctx)
+{
+ struct binrpc_gc_block* b;
+ struct binrpc_gc_block* next;
+ int i;
+
+ for(b=ctx->gc; b; b=next){
+ next=b->next;
+ for (i=0; i<b->idx; i++)
+ pkg_free(b->p[i]);
+ pkg_free(b);
+ }
+ ctx->gc=0;
+}
+
+
static struct rpc_struct_l* new_rpc_struct()
{
struct rpc_struct_l* rs;
@@ -322,6 +385,7 @@ inline void destroy_binrpc_ctx(struct binrpc_ctx* ctx)
pkg_free(ctx->out.pkt.body);
ctx->out.pkt.body=0;
}
+ binrpc_gc_collect(ctx);
}
@@ -583,6 +647,88 @@ static char* rpc_type_name(int type)
+/** converts a binrpc_val to int.
+ *@return int val on success, 0 and sets err on error (E_BINRPC_TYPE) */
+inline static int binrpc_val_conv_int( struct binrpc_val* v, int* err)
+{
+ int ret;
+
+ *err=0;
+ switch(v->type){
+ case BINRPC_T_INT:
+ return v->u.intval;
+ case BINRPC_T_DOUBLE:
+ return (int) v->u.fval;
+ case BINRPC_T_STR:
+ if (str2sint(&v->u.strval, &ret)==0)
+ return ret;
+ }
+ *err=E_BINRPC_TYPE;
+ return 0;
+}
+
+
+
+/** converts a binrpc_val to double.
+ *@return double val on success, 0 and sets err on error (E_BINRPC_TYPE) */
+inline static double binrpc_val_conv_double( struct binrpc_val* v, int* err)
+{
+ double ret;
+ char* end;
+
+ *err=0;
+ switch(v->type){
+ case BINRPC_T_DOUBLE:
+ return v->u.fval;
+ case BINRPC_T_INT:
+ return (double)v->u.intval;
+ case BINRPC_T_STR:
+ ret=strtod(v->u.strval.s, &end);
+ if (end!=v->u.strval.s)
+ return ret;
+ }
+ *err=E_BINRPC_TYPE;
+ return 0;
+}
+
+
+
+/** converts a binrpc_val to str.
+ *@return str val pointer on success, 0 and sets err on error (E_BINRPC_TYPE)*/
+inline static str* binrpc_val_conv_str(struct binrpc_ctx* ctx,
+ struct binrpc_val* v, int* err)
+{
+ str* ret;
+ char* s;
+ int len;
+
+ *err=0;
+ switch(v->type){
+ case BINRPC_T_STR:
+ return &v->u.strval;
+ case BINRPC_T_INT:
+ s=int2str(v->u.intval, &len);
+ ret=pkg_malloc(sizeof(*ret)+len+1);
+ if (ret==0 || binrpc_gc_track(ctx, ret)!=0){
+ *err=E_BINRPC_OVERFLOW;
+ return 0;
+ }
+ ret->s=(char*)ret+sizeof(*ret);
+ ret->len=len;
+ memcpy(ret->s, s, len);
+ ret->s[len]=0;
+ return ret;
+ case BINRPC_T_DOUBLE:
+ /* for now the double to string conversion is not supported*/
+ *err=E_BINRPC_BUG;
+ return 0;
+ }
+ *err=E_BINRPC_TYPE;
+ return 0;
+}
+
+
+
/* rpc interface functions */
/* returns the number of parameters read
@@ -595,45 +741,61 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...)
char* orig_fmt;
int nofault;
int modifiers;
+ int autoconv;
+ int i;
+ double d;
+ str* s;
va_start(ap, fmt);
orig_fmt=fmt;
nofault = 0;
modifiers=0;
+ autoconv=autoconvert;
for (;*fmt; fmt++){
switch(*fmt){
case '*': /* start of optional parameters */
nofault = 1;
modifiers++;
- break;
+ continue;
+ case '.': /* autoconv. on for the next parameter */
+ modifiers++;
+ autoconv=1;
+ continue;
case 'b': /* bool */
case 't': /* time */
case 'd': /* int */
- v.type=BINRPC_T_INT;
+ v.type=autoconv?BINRPC_T_ALL:BINRPC_T_INT;
ctx->in.s=binrpc_read_record(&ctx->in.ctx, ctx->in.s,
ctx->in.end, &v, &err);
- if (err<0) goto error_read;
- *(va_arg(ap, int*))=v.u.intval;
+ if (err<0 || ((i=binrpc_val_conv_int(&v, &err))==0 && err<0))
+ goto error_read;
+ *(va_arg(ap, int*))=i;
break;
case 'f':
- v.type=BINRPC_T_DOUBLE;
+ v.type=autoconv?BINRPC_T_ALL:BINRPC_T_DOUBLE;
ctx->in.s=binrpc_read_record(&ctx->in.ctx, ctx->in.s,
ctx->in.end, &v, &err);
- if (err<0) goto error_read;
- *(va_arg(ap, double*))=v.u.fval;
+ if (err<0 || ((d=binrpc_val_conv_double(&v, &err))==0 &&
+ err<0))
+ goto error_read;
+ *(va_arg(ap, double*))=d;
break;
case 's': /* asciiz */
case 'S': /* str */
- v.type=BINRPC_T_STR;
- v.u.strval.s="if you get this string, you don't"
- "check rpc_scan return code !!! (very bad)";
- v.u.strval.len=strlen(v.u.strval.s);
+ v.type=autoconv?BINRPC_T_ALL:BINRPC_T_STR;
ctx->in.s=binrpc_read_record(&ctx->in.ctx, ctx->in.s,
ctx->in.end, &v,&err);
+ if (err<0 || ((s=binrpc_val_conv_str(ctx, &v, &err))==0 &&
+ err<0)){
+ v.u.strval.s="if you get this string, you don't"
+ "check rpc_scan return code !!! (very bad)";
+ v.u.strval.len=strlen(v.u.strval.s);
+ s=&v.u.strval;
+ }
if (*fmt=='s'){
- *(va_arg(ap, char**))=v.u.strval.s; /* 0 term by proto*/
+ *(va_arg(ap, char**))=s->s; /* 0 term by proto*/
}else{
- *(va_arg(ap, str*))=v.u.strval;
+ *(va_arg(ap, str*))=*s;
}
if (err<0) goto error_read;
break;
@@ -652,6 +814,7 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...)
default:
goto error_inv_param;
}
+ autoconv=autoconvert; /* reset autoconv*/
ctx->in.record_no++;
}
va_end(ap);
diff --git a/modules_s/ctl/ctl.c b/modules_s/ctl/ctl.c
index 071c2e2..730de47 100644
--- a/modules_s/ctl/ctl.c
+++ b/modules_s/ctl/ctl.c
@@ -66,6 +66,10 @@ static int usock_mode=0600; /* permissions, default rw-------*/
static int usock_uid=-1; /* username and group for the unix sockets*/
static int usock_gid=-1;
+/* if set try to automatically convert values to the requested type in
+ rpc->scan (default: not set) */
+extern int autoconvert;
+
static int add_binrpc_socket(modparam_t type, void * val);
#ifdef USE_FIFO
static int add_fifo_socket(modparam_t type, void * val);
@@ -98,6 +102,7 @@ static param_export_t params[]={
{"mode", PARAM_INT, &usock_mode },
{"user", PARAM_STRING|PARAM_USE_FUNC, fix_user },
{"group", PARAM_STRING|PARAM_USE_FUNC, fix_group },
+ {"autoconversion", PARAM_INT, &autoconvert },
{0,0,0}
}; /* no params */