Example #1
0
/* function triggered from reactor in order to continue the processing
 */
int t_resume_async(int *fd, void *param)
{
    static struct sip_msg faked_req;
    static struct ua_client uac;
    async_ctx *ctx = (async_ctx *)param;
    struct cell *backup_t;
    struct cell *backup_cancelled_t;
    struct cell *backup_e2eack_t;
    struct usr_avp **backup_list;
    struct socket_info* backup_si;
    struct cell *t= ctx->t;
    int route;

    LM_DBG("resuming on fd %d, transaction %p \n",*fd, t);

    if (current_processing_ctx) {
        LM_CRIT("BUG - a context already set!\n");
        abort();
    }

    /* prepare for resume route */
    uac.br_flags = getb0flags( t->uas.request ) ;
    uac.uri = *GET_RURI( t->uas.request );
    if (!fake_req( &faked_req /* the fake msg to be built*/,
                   t->uas.request, /* the template msg saved in transaction */
                   &t->uas, /*the UAS side of the transaction*/
                   &uac, /* the fake UAC */
                   1 /* copy dst_uri too */)
       ) {
        LM_ERR("fake_req failed\n");
        return 0;
    }

    /* enviroment setting */
    current_processing_ctx = ctx->msg_ctx;
    backup_t = get_t();
    backup_e2eack_t = get_e2eack_t();
    backup_cancelled_t = get_cancelled_t();
    /* fake transaction */
    set_t( t );
    set_cancelled_t(ctx->cancelled_t);
    set_e2eack_t(ctx->e2eack_t);
    reset_kr();
    set_kr(ctx->kr);
    /* make available the avp list from transaction */
    backup_list = set_avp_list( &t->user_avps );
    /* set default send address to the saved value */
    backup_si = bind_address;
    bind_address = t->uac[0].request.dst.send_sock;

    async_status = ASYNC_DONE; /* assume default status as done */
    /* call the resume function in order to read and handle data */
    return_code = ctx->resume_f( *fd, &faked_req, ctx->resume_param );
    if (async_status==ASYNC_CONTINUE) {
        /* do not run the resume route */
        goto restore;
    } else if (async_status==ASYNC_CHANGE_FD) {
        if (return_code<0) {
            LM_ERR("ASYNC_CHANGE_FD: given file descriptor shall be positive!\n");
            goto restore;
        } else if (return_code > 0 && return_code == *fd) {
            /*trying to add the same fd; shall continue*/
            LM_CRIT("You are trying to replace the old fd with the same fd!"
                    "Will act as in ASYNC_CONTINUE!\n");
            goto restore;
        }

        /* remove the old fd from the reactor */
        reactor_del_reader( *fd, -1, IO_FD_CLOSING);
        *fd=return_code;

        /* insert the new fd inside the reactor */
        if (reactor_add_reader( *fd, F_SCRIPT_ASYNC, RCT_PRIO_ASYNC, (void*)ctx)<0 ) {
            LM_ERR("failed to add async FD to reactor -> act in sync mode\n");
            do {
                return_code = ctx->resume_f( *fd, &faked_req, ctx->resume_param );
                if (async_status == ASYNC_CHANGE_FD)
                    *fd=return_code;
            } while(async_status==ASYNC_CONTINUE||async_status==ASYNC_CHANGE_FD);
            goto route;
        }

        /* changed fd; now restore old state */
        goto restore;
    }

    /* remove from reactor, we are done */
    reactor_del_reader( *fd, -1, IO_FD_CLOSING);

route:
    if (async_status == ASYNC_DONE_CLOSE_FD)
        close(*fd);

    /* run the resume_route (some type as the original one) */
    swap_route_type(route, ctx->route_type);
    run_resume_route( ctx->resume_route, &faked_req);
    set_route_type(route);

    /* no need for the context anymore */
    shm_free(ctx);

    /* free also the processing ctx if still set
     * NOTE: it may become null if inside the run_resume_route
     * another async jump was made (and context attached again
     * to transaction) */
    if (current_processing_ctx) {
        context_destroy(CONTEXT_GLOBAL, current_processing_ctx);
        pkg_free(current_processing_ctx);
    }

restore:
    /* restore original environment */
    set_t(backup_t);
    set_cancelled_t(backup_cancelled_t);
    set_e2eack_t(backup_e2eack_t);
    /* restore original avp list */
    set_avp_list( backup_list );
    bind_address = backup_si;

    free_faked_req( &faked_req, t);
    current_processing_ctx = NULL;

    return 0;
}
Example #2
0
/* function triggered from reactor in order to continue the processing
 */
int t_resume_async(int fd, void *param)
{
	static struct sip_msg faked_req;
	static struct ua_client uac;
	async_ctx *ctx = (async_ctx *)param;
	struct cell *backup_t;
	struct usr_avp **backup_list;
	struct socket_info* backup_si;
	struct cell *t= ctx->t;
	int route;

	LM_DBG("resuming on fd %d, transaction %p \n",fd, t);

	if (current_processing_ctx) {
		LM_CRIT("BUG - a context already set!\n");
		abort();
	}

	/* prepare for resume route */
	uac.br_flags = getb0flags( t->uas.request ) ;
	uac.uri = *GET_RURI( t->uas.request );
	if (!fake_req( &faked_req /* the fake msg to be built*/,
		t->uas.request, /* the template msg saved in transaction */
		&t->uas, /*the UAS side of the transaction*/
		&uac, /* the fake UAC */
		1 /* copy dst_uri too */)
	) {
		LM_ERR("fake_req failed\n");
		return 0;
	}

	/* enviroment setting */
	current_processing_ctx = ctx->msg_ctx;
	backup_t = get_t();
	/* fake transaction */
	set_t( t );
	reset_kr();
	set_kr(ctx->kr);
	/* make available the avp list from transaction */
	backup_list = set_avp_list( &t->user_avps );
	/* set default send address to the saved value */
	backup_si = bind_address;
	bind_address = t->uac[0].request.dst.send_sock;

	async_status = ASYNC_DONE; /* assume default status as done */
	/* call the resume function in order to read and handle data */
	return_code = ctx->resume_f( fd, &faked_req, ctx->resume_param );
	if (async_status==ASYNC_CONTINUE) {
		/* do not run the resume route */
		goto restore;
	}

	/* remove from reactor, we are done */
	reactor_del_reader( fd, -1, IO_FD_CLOSING);

	if (async_status == ASYNC_DONE_CLOSE_FD)
		close(fd);

	/* run the resume_route (some type as the original one) */
	swap_route_type(route, ctx->route_type);
	run_resume_route( ctx->resume_route, &faked_req);
	set_route_type(route);

	/* no need for the context anymore */
	shm_free(ctx);

restore:
	/* restore original environment */
	set_t(backup_t);
	/* restore original avp list */
	set_avp_list( backup_list );
	bind_address = backup_si;

	free_faked_req( &faked_req, t);
	current_processing_ctx = NULL;

	return 0;
}
Example #3
0
int t_handle_async(struct sip_msg *msg, struct action* a , int resume_route)
{
    async_ctx *ctx = NULL;
    async_resume_module *ctx_f;
    void *ctx_p;
    struct cell *t;
    int r;
    int fd;

    /* create transaction and save everything into transaction */
    t=get_t();
    if ( t==0 || t==T_UNDEFINED ) {
        /* create transaction */
        r = t_newtran( msg , 1 /*full uas clone*/ );
        if (r==0) {
            /* retransmission -> no follow up; we return a negative
             * code to indicate do_action that the top route is
             * is completed (there no resume route to follow) */
            return -1;
        } else if (r<0) {
            LM_ERR("could not create a new transaction\n");
            goto failure;
        }
        t=get_t();
    } else {
        /* update the cloned UAS (from transaction)
         * with data from current msg */
        if (t->uas.request)
            update_cloned_msg_from_msg( t->uas.request, msg);
    }

    /* run the function (the action) and get back from it the FD,
     * resume function and param */
    if ( a->type!=AMODULE_T || a->elem[0].type!=ACMD_ST ||
            a->elem[0].u.data==NULL ) {
        LM_CRIT("BUG - invalid action for async I/O - it must be"
                " a MODULE_T ACMD_ST \n");
        goto failure;
    }

    async_status = ASYNC_NO_IO; /*assume defauly status "no IO done" */
    return_code = ((acmd_export_t*)(a->elem[0].u.data))->function(msg,
                  &ctx_f, &ctx_p,
                  (char*)a->elem[1].u.data, (char*)a->elem[2].u.data,
                  (char*)a->elem[3].u.data, (char*)a->elem[4].u.data,
                  (char*)a->elem[5].u.data, (char*)a->elem[6].u.data );
    /* what to do now ? */
    if (async_status>=0) {
        /* async I/O was successfully launched */
        fd = async_status;
        if (msg->REQ_METHOD==METHOD_ACK ||
                /* ^^^ end2end ACK, there is no actual transaction here */
                t->uas.request==NULL
                /* ^^^ local requests do not support async in local route */
           ) {
            goto sync;
        }
    } else if (async_status==ASYNC_NO_IO) {
        /* no IO, so simply go for resume route */
        goto resume;
    } else if (async_status==ASYNC_SYNC) {
        /* IO already done in SYNC'ed way */
        goto resume;
    } else if (async_status==ASYNC_CHANGE_FD) {
        LM_ERR("Incorrect ASYNC_CHANGE_FD status usage!"
               "You should use this status only from the"
               "resume function in case something went wrong"
               "and you have other alternatives!\n");
        /*FIXME should we go to resume or exit?it's quite an invalid scenario */
        goto resume;
    } else {
        /* generic error, go for resume route */
        goto resume;
    }

    /* do we have a reactor in this process, to handle this
       asyn I/O ? */
    if ( 0/*reactor_exists()*/ ) {
        /* no reactor, so we directly call the resume function
           which will block waiting for data */
        goto sync;
    }

    if ( (ctx=shm_malloc(sizeof(async_ctx)))==NULL) {
        LM_ERR("failed to allocate new ctx\n");
        goto sync;
    }

    ctx->resume_f = ctx_f;
    ctx->resume_param = ctx_p;
    ctx->resume_route = resume_route;
    ctx->route_type = route_type;
    ctx->msg_ctx = current_processing_ctx;
    ctx->t = t;
    ctx->kr = get_kr();

    ctx->cancelled_t = get_cancelled_t();
    ctx->e2eack_t = get_e2eack_t();

    current_processing_ctx = NULL;
    set_t(T_UNDEFINED);
    reset_cancelled_t();
    reset_e2eack_t();

    /* place the FD + resume function (as param) into reactor */
    if (reactor_add_reader( fd, F_SCRIPT_ASYNC, RCT_PRIO_ASYNC, (void*)ctx)<0 ) {
        LM_ERR("failed to add async FD to reactor -> act in sync mode\n");
        goto sync;
    }

    /* done, break the script */
    return 0;

sync:
    if (ctx) {
        /*
         * the context was moved in reactor, but the reactor could not
         * fullfil the request - we have to restore the environment -- razvanc
         */
        current_processing_ctx = ctx->msg_ctx;
        set_t(t);
        set_cancelled_t(ctx->cancelled_t);
        set_e2eack_t(ctx->e2eack_t);
        shm_free(ctx);
    }
    /* run the resume function */
    do {
        return_code = ctx_f( fd, msg, ctx_p );
        if (async_status == ASYNC_CHANGE_FD)
            fd = return_code;
    } while(async_status==ASYNC_CONTINUE||async_status==ASYNC_CHANGE_FD);
    /* run the resume route in sync mode */
    run_resume_route( resume_route, msg);

    /* break original script */
    return 0;

failure:
    /* execute here the resume route with failure indication */
    return_code = -1;
resume:
    /* run the resume route */
    run_resume_route( resume_route, msg);
    /* the triggering route is terminated and whole script ended */
    return 0;
}
Example #4
0
int t_handle_async(struct sip_msg *msg, struct action* a , int resume_route)
{
	async_ctx *ctx;
	async_resume_module *ctx_f;
	void *ctx_p;
	struct cell *t;
	int r;
	int fd;

	/* create transaction and save everything into transaction */
	t=get_t();
	if ( t==0 || t==T_UNDEFINED ) {
		/* create transaction */
		r = t_newtran( msg , 1 /*full uas clone*/ );
		if (r==0) {
			/* retransmission -> break the script, no follow up */
			return 0;
		} else if (r<0) {
			LM_ERR("could not create a new transaction\n");
			goto failure;
		}
		t=get_t();
	} else {
		/* update the cloned UAS (from transaction)
		 * with data from current msg */
		update_cloned_msg_from_msg( t->uas.request, msg);
	}

	/* run the function (the action) and get back from it the FD,
	 * resume function and param */
	if ( a->type!=AMODULE_T || a->elem[0].type!=ACMD_ST ||
	a->elem[0].u.data==NULL ) {
		LM_CRIT("BUG - invalid action for async I/O - it must be"
			" a MODULE_T ACMD_ST \n");
		goto failure;
	}

	async_status = ASYNC_NO_IO; /*assume defauly status "no IO done" */
	return_code = ((acmd_export_t*)(a->elem[0].u.data))->function(msg,
			&ctx_f, &ctx_p,
			(char*)a->elem[1].u.data, (char*)a->elem[2].u.data,
			(char*)a->elem[3].u.data, (char*)a->elem[4].u.data,
			(char*)a->elem[5].u.data, (char*)a->elem[6].u.data );
	/* what to do now ? */
	if (async_status>=0) {
		/* async I/O was succesfully launched */
		fd = async_status;
	} else if (async_status==ASYNC_NO_IO) {
		/* no IO, so simply go for resume route */
		goto resume;
	} else if (async_status==ASYNC_SYNC) {
		/* IO already done in SYNC'ed way */
		goto resume;
	} else {
		/* generic error, go for resume route */
		goto resume;
	}

	/* do we have a reactor in this process, to handle this 
	   asyn I/O ? */
	if ( 0/*reactor_exists()*/ ) {
		/* no reactor, so we directly call the resume function
		   which will block waiting for data */
		goto sync;
	}

	if ( (ctx=shm_malloc(sizeof(async_ctx)))==NULL) {
		LM_ERR("failed to allocate new ctx\n");
		goto sync;
	}

	ctx->resume_f = ctx_f;
	ctx->resume_param = ctx_p;
	ctx->resume_route = resume_route;
	ctx->route_type = route_type;
	ctx->msg_ctx = current_processing_ctx;
	ctx->t = t;
	ctx->kr = get_kr();

	current_processing_ctx = NULL;
	set_t(T_UNDEFINED);

	/* place the FD + resume function (as param) into reactor */
	if (reactor_add_reader( fd, F_SCRIPT_ASYNC, RCT_PRIO_ASYNC, (void*)ctx)<0 ) {
		LM_ERR("failed to add async FD to reactor -> act in sync mode\n");
		shm_free(ctx);
		goto sync;
	}

	/* done, break the script */
	return 0;

sync:
	/* run the resume function */
	do {
		return_code = ctx_f( fd, msg, ctx_p );
	} while(async_status!=ASYNC_CONTINUE);
	/* run the resume route in sync mode */
	run_resume_route( resume_route, msg);
	/* break original script */
	return 0;

failure:
	/* execute here the resume route with failure indication */
	return_code = -1;
resume:
	/* run the resume route */
	run_resume_route( resume_route, msg);
	/* the triggering route is terminated and whole script ended */
	return 0;
}