[sr-dev] git:master: ctl(s): support for '.' and type autoconversion

Andrei Pelinescu-Onciul andrei at iptel.org
Wed Jul 15 22:58:36 CEST 2009


Module: sip-router
Branch: master
Commit: 07276eb9a1173b4e58d14aa82a7b81e5f2dca824
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=07276eb9a1173b4e58d14aa82a7b81e5f2dca824

Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei at 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 */
 




More information about the sr-dev mailing list