From 39ab16e4f0d24d70b7d1414df48af023b2018cf6 Mon Sep 17 00:00:00 2001 From: Daniel-Constantin Mierla Date: Wed, 26 Aug 2015 19:03:55 +0200 Subject: [PATCH] ctl: internal mode to allow non-strict reading binrpc packets - allow handling structs with simple values inside, some rpc responses are not strictly build as per xmlrpc/jsonrpc specs --- modules/ctl/binrpc.h | 114 ++++++++++++++++++++++----------------- modules/ctl/binrpc_run.c | 10 ++-- 2 files changed, 70 insertions(+), 54 deletions(-) diff --git a/modules/ctl/binrpc.h b/modules/ctl/binrpc.h index 5b47d883c79..4c27ed283e4 100644 --- a/modules/ctl/binrpc.h +++ b/modules/ctl/binrpc.h @@ -614,12 +614,15 @@ inline static int binrpc_bytes_needed(struct binrpc_parse_ctx *ctx) /* prefill v with the requested type, if type==BINRPC_T_ALL it * will be replaced by the actual record type * known problems: no support for arrays inside STRUCT + * param smode: allow simple vals inside struct (needed for + * not-strict-formatted rpc responses) * returns position after the record and *err==0 if succesfull * original position and *err<0 if not */ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx, unsigned char* buf, unsigned char* end, struct binrpc_val* v, + int smode, int* err ) { @@ -664,18 +667,30 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx, goto error_type; } v->type=type; - if (ctx->in_struct){ - switch(type){ - case BINRPC_T_STRUCT: + switch(type){ + case BINRPC_T_STRUCT: + if (ctx->in_struct){ if (end_tag){ ctx->in_struct--; v->u.end=1; }else{ - goto error_record; + if(smode==0) { + goto error_record; + } else { + v->u.end=0; + ctx->in_struct++; + } } - break; - case BINRPC_T_AVP: - /* name | value */ + } else { + if (end_tag) + goto error_record; + v->u.end=0; + ctx->in_struct++; + } + break; + case BINRPC_T_AVP: + /* name | value */ + if (ctx->in_struct){ v->name.s=(char*)p; v->name.len=(len-1); /* don't include 0 term */ p+=len; @@ -689,7 +704,7 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx, tmp=ctx->in_struct; ctx->in_struct=0; /* hack to parse a normal record */ v->type=type; /* hack */ - p=binrpc_read_record(ctx, p, end, v, err); + p=binrpc_read_record(ctx, p, end, v, smode, err); if (err<0){ ctx->in_struct=tmp; goto error; @@ -701,50 +716,51 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx, }else{ goto error_record; } - break; - default: - goto error_record; - } - }else{ - switch(type){ - case BINRPC_T_INT: - p=binrpc_read_int(&v->u.intval, len, p, end, err); - break; - case BINRPC_T_STR: - v->u.strval.s=(char*)p; - v->u.strval.len=(len-1); /* don't include terminating 0 */ - p+=len; - break; - case BINRPC_T_BYTES: - v->u.strval.s=(char*)p; - v->u.strval.len=len; - p+=len; - case BINRPC_T_STRUCT: - if (end_tag) - goto error_record; - v->u.end=0; - ctx->in_struct++; - break; - case BINRPC_T_ARRAY: - if (end_tag){ - if (ctx->in_array>0){ - ctx->in_array--; - v->u.end=1; - }else - goto error_record; + } else { + goto error_type; + } + break; + case BINRPC_T_INT: + if (ctx->in_struct && smode==0) goto error_record; + p=binrpc_read_int(&v->u.intval, len, p, end, err); + break; + case BINRPC_T_STR: + if (ctx->in_struct && smode==0) goto error_record; + v->u.strval.s=(char*)p; + v->u.strval.len=(len-1); /* don't include terminating 0 */ + p+=len; + break; + case BINRPC_T_BYTES: + if (ctx->in_struct && smode==0) goto error_record; + v->u.strval.s=(char*)p; + v->u.strval.len=len; + p+=len; + case BINRPC_T_ARRAY: + if (ctx->in_struct && smode==0) goto error_record; + if (end_tag){ + if (ctx->in_array>0){ + ctx->in_array--; + v->u.end=1; }else{ - ctx->in_array++; - v->u.end=0; + goto error_record; } - break; - case BINRPC_T_DOUBLE: /* FIXME: hack: represented as fixed point - inside an int */ - p=binrpc_read_int(&i, len, p, end, err); - v->u.fval=((double)i)/1000; - break; - default: + }else{ + ctx->in_array++; + v->u.end=0; + } + break; + case BINRPC_T_DOUBLE: /* FIXME: hack: represented as fixed point + inside an int */ + if (ctx->in_struct && smode==0) goto error_record; + p=binrpc_read_int(&i, len, p, end, err); + v->u.fval=((double)i)/1000; + break; + default: + if (ctx->in_struct){ + goto error_record; + } else { goto error_type; - } + } } ctx->offset+=(int)(p-buf); no_offs_update: diff --git a/modules/ctl/binrpc_run.c b/modules/ctl/binrpc_run.c index b06781bbce4..c4b72977a07 100644 --- a/modules/ctl/binrpc_run.c +++ b/modules/ctl/binrpc_run.c @@ -655,7 +655,7 @@ int process_rpc_req(unsigned char* buf, int size, int* bytes_needed, /* get rpc method */ val.type=BINRPC_T_STR; - f_ctx.in.s=binrpc_read_record(ctx, f_ctx.in.s, f_ctx.in.end, &val, &err); + f_ctx.in.s=binrpc_read_record(ctx, f_ctx.in.s, f_ctx.in.end, &val, 0, &err); if (err<0){ LOG(L_CRIT, "ERROR: bad rpc request method, binrpc error: %s (%d)\n", binrpc_error(err), err); @@ -857,7 +857,7 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...) case 'd': /* 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); + ctx->in.end, &v, 0, &err); if (err<0 || ((i=binrpc_val_conv_int(&v, &err))==0 && err<0)) goto error_read; *(va_arg(ap, int*))=i; @@ -865,7 +865,7 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...) case 'f': 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); + ctx->in.end, &v, 0, &err); if (err<0 || ((d=binrpc_val_conv_double(&v, &err))==0 && err<0)) goto error_read; @@ -875,7 +875,7 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...) case 'S': /* str */ 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); + ctx->in.end, &v, 0, &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" @@ -895,7 +895,7 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...) /* FIXME: structure reading doesn't work for now */ #if 0 ctx->in.s=binrpc_read_record(&ctx->in.ctx, ctx->in.s, - ctx->in.end, &v, &err); + ctx->in.end, &v, 0, &err); if (err<0) goto error_read; ctx->in.in_struct++; *(va_arg(ap, void**))=ctx; /* use the same context */