[sr-dev] git:tirpi/cfg_framework_multivalue: ctl: rpc-> scan does not immediately send out errors
Miklos Tirpak
miklos at iptel.org
Tue Oct 5 16:31:47 CEST 2010
Hi Andrei,
if you do not mind, I modified the ctl module a little bit, this feature
was needed for the cfg.set RPC command to support both int and string
parameters simultaneously.
Do you think that it is worth cherry-picking this change along with the
cfg.set RPC command to the master branch before 3.1 is released?
Thanks,
Miklos
On 10/05/2010 04:20 PM, Miklos Tirpak wrote:
> Module: sip-router
> Branch: tirpi/cfg_framework_multivalue
> Commit: 77576163bacf3d25ba5694563df173ce2aa4aa5f
> URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=77576163bacf3d25ba5694563df173ce2aa4aa5f
>
> Author: Miklos Tirpak<miklos at iptel.org>
> Committer: Miklos Tirpak<miklos at iptel.org>
> Date: Tue Oct 5 16:09:27 2010 +0200
>
> ctl: rpc->scan does not immediately send out errors
>
> When the rpc scan function cannot read a parameter because of
> a type mismatch, the function only prepares the error reply but
> does not send it out immediately. The scan can be retried with
> different parameter specification which resets the prepared
> error message.
>
> This allows variable types of parameters of the same rpc function,
> for example:
>
> if (rpc->scan(c, "d",&i) == 1)
> /* int parameter */
> else if (rpc->scan(c, "s",&ch) == 1)
> /* char* parameter */
> else
> return /* error */
>
> ---
>
> modules/ctl/binrpc_run.c | 124 ++++++++++++++++++++++++++++++++++++---------
> 1 files changed, 99 insertions(+), 25 deletions(-)
>
> diff --git a/modules/ctl/binrpc_run.c b/modules/ctl/binrpc_run.c
> index 989f889..4732c19 100644
> --- a/modules/ctl/binrpc_run.c
> +++ b/modules/ctl/binrpc_run.c
> @@ -97,6 +97,8 @@ struct binrpc_ctx{
> char* method;
> struct binrpc_gc_block* gc; /**< garbage collection */
> int replied;
> + int err_code;
> + str err_phrase; /**< Leading zero must be included! */
> };
>
>
> @@ -388,6 +390,10 @@ inline void destroy_binrpc_ctx(struct binrpc_ctx* ctx)
> pkg_free(ctx->out.pkt.body);
> ctx->out.pkt.body=0;
> }
> + if (ctx->err_phrase.s){
> + pkg_free(ctx->err_phrase.s);
> + ctx->err_phrase.s=NULL;
> + }
> binrpc_gc_collect(ctx);
> }
>
> @@ -395,32 +401,23 @@ inline void destroy_binrpc_ctx(struct binrpc_ctx* ctx)
>
> #define MAX_FAULT_LEN 256
> #define FAULT_START_BUF (3 /* maxint*/+2/*max str header*/)
> -static void rpc_fault(struct binrpc_ctx* ctx, int code, char* fmt, ...)
> +static void _rpc_fault(struct binrpc_ctx* ctx, int code,
> + char *phrase, int phrase_len)
> {
> - char buf[MAX_FAULT_LEN];
> static unsigned char fault_start[FAULT_START_BUF];
> static unsigned char hdr[BINRPC_MAX_HDR_SIZE];
> struct iovec v[3];
> struct binrpc_pkt body;
> int b_len;
> - va_list ap;
> - int len;
> int hdr_len;
> int err;
> -
> +
> if (ctx->replied){
> LOG(L_ERR, "ERROR: binrpc: rpc_send: rpc method %s tried to reply"
> " more then once\n", ctx->method?ctx->method:"");
> return;
> }
> err=0;
> - va_start(ap, fmt);
> - len=vsnprintf(buf, MAX_FAULT_LEN, fmt, ap); /* ignore trunc. errors */
> - if ((len<0) || (len> MAX_FAULT_LEN))
> - len=MAX_FAULT_LEN-1;
> - va_end(ap);
> -
> - len++; /* vnsprintf doesn't include the terminating 0 */
> err=binrpc_init_pkt(&body, fault_start, FAULT_START_BUF);
> if (err<0){
> LOG(L_ERR, "ERROR: binrpc_init_pkt error\n");
> @@ -429,22 +426,22 @@ static void rpc_fault(struct binrpc_ctx* ctx, int code, char* fmt, ...)
> /* adding a fault "manually" to avoid extra memcpys */
> err=binrpc_addint(&body, code);
> if (err<0){
> - LOG(L_ERR, "ERROR: rpc_fault: addint error\n");
> + LOG(L_ERR, "ERROR: _rpc_fault: addint error\n");
> goto error;
> }
> - err=binrpc_add_str_mark(&body, BINRPC_T_STR, len);
> + err=binrpc_add_str_mark(&body, BINRPC_T_STR, phrase_len);
> if (err<0){
> - LOG(L_ERR, "ERROR: rpc_fault: add_str_mark error\n");
> + LOG(L_ERR, "ERROR: _rpc_fault: add_str_mark error\n");
> goto error;
> }
> /*
> - err=binrpc_addfault(&body, code, buf, len);
> + err=binrpc_addfault(&body, code, phrase, phrase_len);
> if (err<0){
> LOG(L_ERR, "ERROR: binrpc_addfault error\n");
> goto error;
> }*/
> b_len=binrpc_pkt_len(&body);
> - err=hdr_len=binrpc_build_hdr(BINRPC_FAULT, b_len+len,
> + err=hdr_len=binrpc_build_hdr(BINRPC_FAULT, b_len+phrase_len,
> ctx->in.ctx.cookie, hdr, BINRPC_MAX_HDR_SIZE);
> if (err<0){
> LOG(L_ERR, "ERROR: binrpc_build_hdr error\n");
> @@ -454,25 +451,90 @@ static void rpc_fault(struct binrpc_ctx* ctx, int code, char* fmt, ...)
> v[0].iov_len=hdr_len;
> v[1].iov_base=body.body;
> v[1].iov_len=b_len;
> - v[2].iov_base=buf;
> - v[2].iov_len=len;
> + v[2].iov_base=phrase;
> + v[2].iov_len=phrase_len;
> if ((err=sock_send_v(ctx->send_h, v, 3))<0){
> if (err==-2){
> - LOG(L_ERR, "ERROR: binrpc_fault: send failed: "
> + LOG(L_ERR, "ERROR: _rpc_fault: send failed: "
> "datagram too big\n");
> return;
> }
> - LOG(L_ERR, "ERROR: binrpc_fault: send failed\n");
> + LOG(L_ERR, "ERROR: _rpc_fault: send failed\n");
> return;
> }
> ctx->replied=1;
> return;
> error:
> - LOG(L_ERR, "ERROR: binrpc_fault: binrpc_* failed with: %s (%d)\n",
> + LOG(L_ERR, "ERROR: _rpc_fault: binrpc_* failed with: %s (%d)\n",
> binrpc_error(err), err);
> }
>
> +static void rpc_fault(struct binrpc_ctx* ctx, int code, char* fmt, ...)
> +{
> + char buf[MAX_FAULT_LEN];
> + va_list ap;
> + int len;
>
> + if (ctx->replied){
> + LOG(L_ERR, "ERROR: binrpc: rpc_send: rpc method %s tried to reply"
> + " more then once\n", ctx->method?ctx->method:"");
> + return;
> + }
> + va_start(ap, fmt);
> + len=vsnprintf(buf, MAX_FAULT_LEN, fmt, ap); /* ignore trunc. errors */
> + if ((len<0) || (len> MAX_FAULT_LEN))
> + len=MAX_FAULT_LEN-1;
> + va_end(ap);
> +
> + len++; /* vnsprintf doesn't include the terminating 0 */
> + return _rpc_fault(ctx, code, buf, len);
> +}
> +
> +/* Prepare the error reply without sending out the message */
> +static int rpc_fault_prepare(struct binrpc_ctx* ctx, int code, char* fmt, ...)
> +{
> + char buf[MAX_FAULT_LEN];
> + va_list ap;
> + int len;
> +
> + if (ctx->replied){
> + LOG(L_ERR, "ERROR: binrpc: rpc_send: rpc method %s tried to reply"
> + " more then once\n", ctx->method?ctx->method:"");
> + return -1;
> + }
> + va_start(ap, fmt);
> + len=vsnprintf(buf, MAX_FAULT_LEN, fmt, ap); /* ignore trunc. errors */
> + if ((len<0) || (len> MAX_FAULT_LEN))
> + len=MAX_FAULT_LEN-1;
> + va_end(ap);
> +
> + len++; /* vnsprintf doesn't include the terminating 0 */
> +
> + ctx->err_code = code;
> + if (ctx->err_phrase.s)
> + pkg_free(ctx->err_phrase.s);
> + ctx->err_phrase.s = (char*)pkg_malloc(sizeof(char)*len);
> + if (!ctx->err_phrase.s) {
> + ctx->err_code = 0;
> + ctx->err_phrase.len = 0;
> + LOG(L_ERR, "ERROR: rpc_fault_prepare: not enough memory\n");
> + return -1;
> + }
> + memcpy(ctx->err_phrase.s, buf, len);
> + ctx->err_phrase.len = len;
> + return 0;
> +}
> +
> +/* Reset the saved error code */
> +static void rpc_fault_reset(struct binrpc_ctx* ctx)
> +{
> + ctx->err_code = 0;
> + if (ctx->err_phrase.s) {
> + pkg_free(ctx->err_phrase.s);
> + ctx->err_phrase.s = NULL;
> + ctx->err_phrase.len = 0;
> + }
> +}
>
> /* build the reply from the current body */
> static int rpc_send(struct binrpc_ctx* ctx)
> @@ -596,14 +658,21 @@ int process_rpc_req(unsigned char* buf, int size, int* bytes_needed,
> f_ctx.method=val.u.strval.s;
> rpc_e->function(&binrpc_callbacks,&f_ctx);
> if (f_ctx.replied==0){
> + if ((binrpc_pkt_len(&f_ctx.out.pkt)==0)
> + && f_ctx.err_code&& f_ctx.err_phrase.s
> + ) {
> + _rpc_fault(&f_ctx, f_ctx.err_code,
> + f_ctx.err_phrase.s, f_ctx.err_phrase.len);
> /* to get an error reply if the rpc handlers hasn't replied
> * uncomment the following code:
> - * if (binrpc_pkt_len(&f_ctx.out.pkt)==0){
> + * } else if (binrpc_pkt_len(&f_ctx.out.pkt)==0){
> rpc_fault(&f_ctx, 500, "internal server error: no reply");
> LOG(L_ERR, "ERROR: rpc method %s hasn't replied\n",
> val.u.strval.s);
> - }else */
> + */
> + } else {
> rpc_send(&f_ctx);
> + }
> }
> end:
> *bytes_needed=0; /* full read */
> @@ -749,6 +818,9 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...)
> double d;
> str* s;
>
> + /* clear the previously saved error code */
> + rpc_fault_reset(ctx);
> +
> va_start(ap, fmt);
> orig_fmt=fmt;
> nofault = 0;
> @@ -823,8 +895,10 @@ static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...)
> va_end(ap);
> return (int)(fmt-orig_fmt)-modifiers;
> error_read:
> + /* Do not immediately send out the error message, the user might retry the scan with
> + different parameters */
> if(nofault==0 || ((err!=E_BINRPC_MORE_DATA)&& (err!=E_BINRPC_EOP)))
> - rpc_fault(ctx, 400, "error at parameter %d: expected %s type but"
> + rpc_fault_prepare(ctx, 400, "error at parameter %d: expected %s type but"
> " %s", ctx->in.record_no, rpc_type_name(v.type),
> binrpc_error(err));
> /*
>
>
> _______________________________________________
> sr-dev mailing list
> sr-dev at lists.sip-router.org
> http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
More information about the sr-dev
mailing list