Пример #1
0
/*if msg is set -> it will fake the env. vars conforming with the msg; if NULL
 * the env. will be restore to original */
static inline void faked_env( struct cell *t,struct sip_msg *msg)
{
	static struct cell *backup_t;
	static struct usr_avp **backup_list;
	static struct socket_info* backup_si;
	static int backup_route_type;

	if (msg) {
		swap_route_type( backup_route_type, FAILURE_ROUTE);
		/* tm actions look in beginning whether transaction is
		 * set -- whether we are called from a reply-processing 
		 * or a timer process, we need to set current transaction;
		 * otherwise the actions would attempt to look the transaction
		 * up (unnecessary overhead, refcounting)
		 */
		/* backup */
		backup_t = get_t();
		/* fake transaction */
		set_t(t);
		/* 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;
	} else {
		/* restore original environment */
		set_t(backup_t);
		set_route_type( backup_route_type );
		/* restore original avp list */
		set_avp_list( backup_list );
		bind_address = backup_si;
	}
}
Пример #2
0
/* run the error route with correct handling - simpler wrapper to 
   allow the usage from other parts of the code */
void run_error_route(struct sip_msg* msg, int force_reset)
{
	int old_route;
	LM_DBG("triggering\n");
	swap_route_type(old_route, ERROR_ROUTE);
	run_actions(error_rlist.a, msg);
	/* reset error info */
	init_err_info();
	set_route_type(old_route);
}
Пример #3
0
/*
 * Send a request using data from the dialog structure
 */
int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
				transaction_cb cb, void* cbp,release_tmcb_param release_func)
{
	union sockaddr_union to_su, new_to_su;
	struct cell *new_cell;
	struct cell *backup_cell;
	struct retr_buf *request;
	static struct sip_msg *req;
	struct usr_avp **backup;
	char *buf, *buf1;
	int buf_len, buf_len1;
	int ret, flags, sflag_bk;
	int backup_route_type;
	int sip_msg_len;
	unsigned int hi;
	struct socket_info *new_send_sock;
	str h_to, h_from, h_cseq, h_callid;
	struct proxy_l *proxy, *new_proxy;
	unsigned short dst_changed;

	ret=-1;

	/*** added by dcm
	 * - needed by external ua to send a request within a dlg
	 */
	if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0)
		goto error3;

	if(dialog->obp.s)
		dialog->hooks.next_hop = &dialog->obp;

	LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len,
			dialog->hooks.next_hop->s);

	/* calculate the socket corresponding to next hop */
	proxy = uri2proxy( dialog->hooks.next_hop,
		dialog->send_sock ? dialog->send_sock->proto : PROTO_NONE );
	if (proxy==0)  {
		ret=E_BAD_ADDRESS;
		goto error3;
	}
	/* use the first address */
	hostent2su( &to_su,
		&proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT);

	/* check/discover the send socket */
	if (dialog->send_sock) {
		/* if already set, the protocol of send sock must have the 
		   the same type as the proto required by destination URI */
		if (proxy->proto != dialog->send_sock->proto)
			dialog->send_sock = NULL;
	}
	if (dialog->send_sock==NULL) {
		/* get the send socket */
		dialog->send_sock = get_send_socket( NULL/*msg*/, &to_su, proxy->proto);
		if (!dialog->send_sock) {
			LM_ERR("no corresponding socket for af %d\n", to_su.s.sa_family);
			ser_error = E_NO_SOCKET;
			goto error2;
		}
	}
	LM_DBG("sending socket is %.*s \n",
		dialog->send_sock->name.len,dialog->send_sock->name.s);


	/* ***** Create TRANSACTION and all related  ***** */
	new_cell = build_cell( NULL/*msg*/, 1/*full UAS clone*/);
	if (!new_cell) {
		ret=E_OUT_OF_MEM;
		LM_ERR("short of cell shmem\n");
		goto error2;
	}

	/* pass the transaction flags from dialog to transaction */
	new_cell->flags |= dialog->T_flags;

	/* add the callback the transaction for LOCAL_COMPLETED event */
	flags = TMCB_LOCAL_COMPLETED;
	/* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */
	if (pass_provisional_replies || pass_provisional(new_cell))
		flags |= TMCB_LOCAL_RESPONSE_OUT;
	if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,release_func)!=1){
		ret=E_OUT_OF_MEM;
		LM_ERR("short of tmcb shmem\n");
		goto error2;
	}

	if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0)
		new_cell->flags |= T_IS_INVITE_FLAG;
	new_cell->flags |= T_IS_LOCAL_FLAG;

	request = &new_cell->uac[0].request;
	if (dialog->forced_to_su.s.sa_family == AF_UNSPEC)
		request->dst.to = to_su;
	else
		request->dst.to = dialog->forced_to_su;
	request->dst.send_sock = dialog->send_sock;
	request->dst.proto = dialog->send_sock->proto;
	request->dst.proto_reserved1 = 0;

	hi=dlg2hash(dialog);
	LOCK_HASH(hi);
	insert_into_hash_table_unsafe(new_cell, hi);
	UNLOCK_HASH(hi);

	/* copy AVPs into transaction */
	new_cell->user_avps = dialog->avps;
	dialog->avps = NULL;


	/* ***** Create the message buffer ***** */
	buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len);
	if (!buf) {
		LM_ERR("failed to build message\n");
		ret=E_OUT_OF_MEM;
		goto error1;
	}

	if (local_rlist.a) {
		LM_DBG("building sip_msg from buffer\n");
		req = buf_to_sip_msg(buf, buf_len, dialog);
		if (req==NULL) {
			LM_ERR("failed to build sip_msg from buffer\n");
		} else {
			/* set this transaction as active one */
			backup_cell = get_t();
			set_t( new_cell );
			/* set transaction AVP list */
			backup = set_avp_list( &new_cell->user_avps );
			/* backup script flags */
			sflag_bk = getsflags();
			/* disable parallel forking */
			set_dset_state( 0 /*disable*/);

			/* run the route */
			swap_route_type( backup_route_type, LOCAL_ROUTE);
			run_top_route( local_rlist.a, req);
			set_route_type( backup_route_type );

			/* transfer current message context back to t */
			new_cell->uac[0].br_flags = getb0flags(req);
			/* restore the prevoius active transaction */
			set_t( backup_cell );

			set_dset_state( 1 /*enable*/);
			setsflagsval(sflag_bk);
			set_avp_list( backup );

			/* check for changes - if none, do not regenerate the buffer */
			dst_changed = 1;
			if (req->new_uri.s || req->force_send_socket!=dialog->send_sock ||
			req->dst_uri.len != dialog->hooks.next_hop->len ||
			memcmp(req->dst_uri.s,dialog->hooks.next_hop->s,req->dst_uri.len) ||
			(dst_changed=0)==0 || req->add_rm || req->body_lumps){

				new_send_sock = NULL;
				/* do we also need to change the destination? */
				if (dst_changed) {
					/* calculate the socket corresponding to next hop */
					new_proxy = uri2proxy(
						req->dst_uri.s ? &(req->dst_uri) : &req->new_uri,
						PROTO_NONE );
					if (new_proxy==0)
						goto abort_update;
					/* use the first address */
					hostent2su( &new_to_su,
						&new_proxy->host, new_proxy->addr_idx,
						new_proxy->port ? new_proxy->port:SIP_PORT);
					/* get the send socket */
					new_send_sock = get_send_socket( req, &new_to_su,
						new_proxy->proto);
					if (!new_send_sock) {
						free_proxy( new_proxy );
						pkg_free( new_proxy );
						LM_ERR("no socket found for the new destination\n");
						goto abort_update;
					}
				}

				/* if interface change, we need to re-build the via */
				if (new_send_sock && new_send_sock != dialog->send_sock) {
					LM_DBG("Interface change in local route -> "
						"rebuilding via\n");
					if (!del_lump(req,req->h_via1->name.s - req->buf,
					req->h_via1->len,0)) {
						LM_ERR("Failed to remove initial via \n");
						goto abort_update;
					}

					memcpy(req->add_to_branch_s,req->via1->branch->value.s,
						req->via1->branch->value.len);
					req->add_to_branch_len = req->via1->branch->value.len;

					/* update also info about new destination and send sock */
					dialog->send_sock = new_send_sock;
					free_proxy( proxy );
					pkg_free( proxy );
					proxy = new_proxy;
					request->dst.send_sock = new_send_sock;
					request->dst.proto = new_send_sock->proto;
					request->dst.proto_reserved1 = 0;

					/* build the shm buffer now */
					set_init_lump_flags(LUMPFLAG_BRANCH);
					buf1 = build_req_buf_from_sip_req(req,
						(unsigned int*)&buf_len1,
						new_send_sock, new_send_sock->proto,
						MSG_TRANS_SHM_FLAG);
					reset_init_lump_flags();
					del_flaged_lumps( &req->add_rm, LUMPFLAG_BRANCH);

				} else {

					LM_DBG("Change in local route -> rebuilding buffer\n");
					/* build the shm buffer now */
					buf1 = build_req_buf_from_sip_req(req,
						(unsigned int*)&buf_len1,
						dialog->send_sock, dialog->send_sock->proto,
						MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG);
					/* now as it used, hide the original VIA header */
					del_lump(req,req->h_via1->name.s - req->buf,
						req->h_via1->len, 0);

				}

				if (!buf1) {
					LM_ERR("no more shm mem\n");
					/* keep original buffer */
					goto abort_update;
				}
				/* update shortcuts */
				if(!req->add_rm && !req->new_uri.s) {
					/* headers are not affected, simply tranlate */
					new_cell->from.s = new_cell->from.s - buf + buf1;
					new_cell->to.s = new_cell->to.s - buf + buf1;
					new_cell->callid.s = new_cell->callid.s - buf + buf1;
					new_cell->cseq_n.s = new_cell->cseq_n.s - buf + buf1;
				} else {
					/* use heavy artilery :D */
					if (extract_ftc_hdrs( buf1, buf_len1, &h_from, &h_to,
					&h_cseq, &h_callid)!=0 ) {
						LM_ERR("failed to update shortcut pointers\n");
						shm_free(buf1);
						goto abort_update;
					}
					new_cell->from = h_from;
					new_cell->to = h_to;
					new_cell->callid = h_callid;
					new_cell->cseq_n = h_cseq;
				}
				/* here we rely on how build_uac_req()
				   builds the first line */
				new_cell->uac[0].uri.s = buf1 +
					req->first_line.u.request.method.len + 1;
				new_cell->uac[0].uri.len = GET_RURI(req)->len;

				/* update also info about new destination and send sock */
				if (new_send_sock)
					request->dst.to = new_to_su;

				shm_free(buf);
				buf = buf1;
				buf_len = buf_len1;
				/* use new buffer */
			} else {
				/* no changes over the message, buffer is already generated,
				   just hide the original VIA for potential further branches */
				del_lump(req,req->h_via1->name.s-req->buf,req->h_via1->len,0);
			}
abort_update:
			/* save the SIP message into transaction */
			new_cell->uas.request = sip_msg_cloner( req, &sip_msg_len, 1);
			if (new_cell->uas.request==NULL) {
				/* reset any T triggering */
				new_cell->on_negative = 0;
				new_cell->on_reply = 0;
			} else {
				new_cell->uas.end_request=
					((char*)new_cell->uas.request)+sip_msg_len;
			}
			/* no parallel support in UAC transactions */
			new_cell->on_branch = 0;
			free_sip_msg(req);
		}
	}

	/* for DNS based failover, copy the DNS proxy into transaction */
	if (!disable_dns_failover) {
		new_cell->uac[0].proxy = shm_clone_proxy( proxy, 1/*do_free*/);
		if (new_cell->uac[0].proxy==NULL)
			LM_ERR("failed to store DNS info -> no DNS based failover\n");
	}

	new_cell->method.s = buf;
	new_cell->method.len = method->len;

	request->buffer.s = buf;
	request->buffer.len = buf_len;
	new_cell->nr_of_outgoings++;

	if(last_localT) {
		*last_localT = new_cell;
		REF_UNSAFE(new_cell);
	}

	if (SEND_BUFFER(request) == -1) {
		LM_ERR("attempt to send to '%.*s' failed\n",
			dialog->hooks.next_hop->len,
			dialog->hooks.next_hop->s);
	}

	if (method->len==ACK_LEN && memcmp(method->s, ACK, ACK_LEN)==0 ) {
		t_release_transaction(new_cell);
	} else {
		start_retr(request);
	}

	free_proxy( proxy );
	pkg_free( proxy );

	return 1;

error1:
	LOCK_HASH(hi);
	remove_from_hash_table_unsafe(new_cell);
	UNLOCK_HASH(hi);
	free_cell(new_cell);
error2:
	free_proxy( proxy );
	pkg_free( proxy );
error3:
	return ret;
}
Пример #4
0
static inline int pre_print_uac_request( struct cell *t, int branch,
					struct sip_msg *request, struct sip_msg_body **body_clone)
{
	int backup_route_type;
	struct usr_avp **backup_list;
	char *p;

	/* ... we calculate branch ... */
	if (!t_calc_branch(t, branch, request->add_to_branch_s,
			&request->add_to_branch_len ))
	{
		LM_ERR("branch computation failed\n");
		goto error;
	}

	/* from now on, flag all new lumps with LUMPFLAG_BRANCH flag in order to
	 * be able to remove them later --bogdan */
	set_init_lump_flags(LUMPFLAG_BRANCH);

	/* copy path vector into branch */
	if (request->path_vec.len) {
		t->uac[branch].path_vec.s =
			shm_realloc(t->uac[branch].path_vec.s, request->path_vec.len+1);
		if (t->uac[branch].path_vec.s==NULL) {
			LM_ERR("shm_realloc failed\n");
			goto error;
		}
		t->uac[branch].path_vec.len = request->path_vec.len;
		memcpy( t->uac[branch].path_vec.s, request->path_vec.s,
			request->path_vec.len+1);
	}

	/* do the same for the advertised port & address */
	if (request->set_global_address.len) {
		t->uac[branch].adv_address.s = shm_realloc(t->uac[branch].adv_address.s,
			request->set_global_address.len+1);
		if (t->uac[branch].adv_address.s==NULL) {
			LM_ERR("shm_realloc failed for storing the advertised address "
				"(len=%d)\n",request->set_global_address.len);
			goto error;
		}
		t->uac[branch].adv_address.len = request->set_global_address.len;
		memcpy( t->uac[branch].adv_address.s, request->set_global_address.s,
			request->set_global_address.len+1);
	}
	if (request->set_global_port.len) {
		t->uac[branch].adv_port.s = shm_realloc(t->uac[branch].adv_port.s,
			request->set_global_port.len+1);
		if (t->uac[branch].adv_port.s==NULL) {
			LM_ERR("shm_realloc failed for storing the advertised port "
				"(len=%d)\n",request->set_global_port.len);
			goto error;
		}
		t->uac[branch].adv_port.len = request->set_global_port.len;
		memcpy( t->uac[branch].adv_port.s, request->set_global_port.s,
			request->set_global_port.len+1);
	}


	/********** run route & callback ************/

	/* run branch route, if any; run it before RURI's DNS lookup
	 * to allow to be changed --bogdan */
	if (t->on_branch) {
		/* need to pkg_malloc the dst_uri */
		if ( request->dst_uri.s && request->dst_uri.len>0 ) {
			if ( (p=pkg_malloc(request->dst_uri.len))==0 ) {
				LM_ERR("no more pkg mem\n");
				ser_error=E_OUT_OF_MEM;
				goto error;
			}
			memcpy( p, request->dst_uri.s, request->dst_uri.len);
			request->dst_uri.s = p;
		}
		/* need to pkg_malloc the new_uri */
		if ( (p=pkg_malloc(request->new_uri.len))==0 ) {
			LM_ERR("no more pkg mem\n");
			ser_error=E_OUT_OF_MEM;
			goto error;
		}
		memcpy( p, request->new_uri.s, request->new_uri.len);
		request->new_uri.s = p;
		request->parsed_uri_ok = 0;
		/* make a clone of the original body, to restore it later */
		if (clone_sip_msg_body( request, NULL, body_clone, 0)!=0) {
			LM_ERR("faile to clone the body, branch route changes will be"
				" preserved\n");
		}
		/* make available the avp list from transaction */
		backup_list = set_avp_list( &t->user_avps );
		/* run branch route */
		swap_route_type( backup_route_type, BRANCH_ROUTE);

		_tm_branch_index = branch;
		if(run_top_route(sroutes->branch[t->on_branch].a,request)&ACT_FL_DROP){
			LM_DBG("dropping branch <%.*s>\n", request->new_uri.len,
					request->new_uri.s);
			_tm_branch_index = 0;
			/* restore the route type */
			set_route_type( backup_route_type );
			/* restore original avp list */
			set_avp_list( backup_list );
			goto error;
		}

		_tm_branch_index = 0;
		/* restore the route type */
		set_route_type( backup_route_type );
		/* restore original avp list */
		set_avp_list( backup_list );
	}

	/* run the specific callbacks for this transaction */
	run_trans_callbacks( TMCB_REQUEST_FWDED, t, request, 0,
			-request->REQ_METHOD);

	/* copy dst_uri into branch (after branch route possible updated it) */
	if (request->dst_uri.len) {
		t->uac[branch].duri.s =
			shm_realloc(t->uac[branch].duri.s, request->dst_uri.len);
		if (t->uac[branch].duri.s==NULL) {
			LM_ERR("shm_realloc failed\n");
			goto error;
		}
		t->uac[branch].duri.len = request->dst_uri.len;
		memcpy( t->uac[branch].duri.s,request->dst_uri.s,request->dst_uri.len);
	}

	return 0;
error:
	return -1;
}
Пример #5
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;
}
Пример #6
0
/*
 * Send a request using data from the dialog structure
 */
int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
				transaction_cb cb, void* cbp,release_tmcb_param release_func)
{
	union sockaddr_union to_su;
	struct cell *new_cell;
	struct retr_buf *request;
	static struct sip_msg *req;
	struct usr_avp **backup;
	char *buf, *buf1;
	int buf_len, buf_len1;
	int ret, flags, sflag_bk;
	int backup_route_type;
	unsigned int hi;
	struct socket_info* send_sock;

	ret=-1;
	
	/*** added by dcm 
	 * - needed by external ua to send a request within a dlg
	 */
	if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0)
		goto error2;

	if(dialog->obp.s)
		dialog->hooks.next_hop = &dialog->obp;

	LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len,
			dialog->hooks.next_hop->s);

	/* calculate the socket corresponding to next hop */
	send_sock = uri2sock(0, dialog->hooks.next_hop, &to_su,
			PROTO_NONE);
	if (send_sock==0) {
		ret=ser_error;
		LM_ERR("no socket found\n");
		goto error2;
	}
	/* if a send socket defined verify if the same protocol */
	if(dialog->send_sock) {
		if(send_sock->proto != dialog->send_sock->proto)
		{
			dialog->send_sock = send_sock;
		}
	}
	else
	{
		dialog->send_sock = send_sock;
	}

	new_cell = build_cell(0);
	if (!new_cell) {
		ret=E_OUT_OF_MEM;
		LM_ERR("short of cell shmem\n");
		goto error2;
	}

	/* pass the transaction flags from dialog to transaction */
	new_cell->flags |= dialog->T_flags;

	/* add the callback the transaction for LOCAL_COMPLETED event */
	flags = TMCB_LOCAL_COMPLETED;
	/* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */
	if (pass_provisional_replies || pass_provisional(new_cell))
		flags |= TMCB_LOCAL_RESPONSE_OUT;
	if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,release_func)!=1){
		ret=E_OUT_OF_MEM;
		LM_ERR("short of tmcb shmem\n");
		goto error2;
	}

	if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0)
		new_cell->flags |= T_IS_INVITE_FLAG;
	new_cell->flags |= T_IS_LOCAL_FLAG;

	request = &new_cell->uac[0].request;
	request->dst.to = to_su;
	request->dst.send_sock = dialog->send_sock;
	request->dst.proto = dialog->send_sock->proto;
	request->dst.proto_reserved1 = 0;

	hi=dlg2hash(dialog);
	LOCK_HASH(hi);
	insert_into_hash_table_unsafe(new_cell, hi);
	UNLOCK_HASH(hi);

	buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len);
	if (!buf) {
		LM_ERR("failed to build message\n");
		ret=E_OUT_OF_MEM;
		goto error1;
	}

	if (local_rlist.a) {
		LM_DBG("building sip_msg from buffer\n");
		req = buf_to_sip_msg(buf, buf_len, dialog);
		if (req==NULL) {
			LM_ERR("failed to build sip_msg from buffer");
		} else {
			/* set transaction AVP list */
			backup = set_avp_list( &new_cell->user_avps );
			/* backup script flags */
			sflag_bk = getsflags();
			/* disable parallel forking */
			set_dset_state( 0 /*disable*/);

			/* transfer current message context back to t */
			new_cell->uac[0].br_flags = req->flags;

			/* run the route */
			swap_route_type( backup_route_type, LOCAL_ROUTE);
			run_top_route( local_rlist.a, req);
			set_route_type( backup_route_type );

			set_dset_state( 1 /*enable*/);
			setsflagsval(sflag_bk);
			set_avp_list( backup );

			/* check for changes - if none, do not regenerate the buffer 
			 * we ignore any change on RURI and DSTURI and they should not
			 * be changed  -bogdan */
			if (req->new_uri.s)
				{ pkg_free(req->new_uri.s); req->new_uri.s=0; req->new_uri.len=0; }
			if (req->dst_uri.s)
				{ pkg_free(req->dst_uri.s); req->dst_uri.s=0; req->dst_uri.len=0; }

			if (req->add_rm || req->body_lumps) {
				LM_DBG("re-building the buffer (sip_msg changed) - lumps are"
					"%p %p\n",req->add_rm, req->body_lumps);
				/* build the shm buffer now */
				buf1 = build_req_buf_from_sip_req(req,(unsigned int*)&buf_len1,
					dialog->send_sock, dialog->send_sock->proto,
					MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG );
				if (!buf1) {
					LM_ERR("no more shm mem\n"); 
					/* keep original buffer */
				} else {
					shm_free(buf);
					buf = buf1;
					buf_len = buf_len1;
					/* use new buffer */
				}
			}
			free_sip_msg(req);
		}
	}

	new_cell->method.s = buf;
	new_cell->method.len = method->len;

	request->buffer.s = buf;
	request->buffer.len = buf_len;
	new_cell->nr_of_outgoings++;

	if(last_localT)
	{
		*last_localT = new_cell;
		REF_UNSAFE(new_cell);
	}

	if (SEND_BUFFER(request) == -1) {
		LM_ERR("attempt to send to '%.*s' failed\n", 
			dialog->hooks.next_hop->len,
			dialog->hooks.next_hop->s);
	}

	if (method->len==ACK_LEN && memcmp(method->s, ACK, ACK_LEN)==0 ) {
		t_release_transaction(new_cell);
	} else {
		start_retr(request);
	}


	return 1;

error1:
	LOCK_HASH(hi);
	remove_from_hash_table_unsafe(new_cell);
	UNLOCK_HASH(hi);
	free_cell(new_cell);
error2:
	return ret;
}
Пример #7
0
static inline int pre_print_uac_request( struct cell *t, int branch, 
		struct sip_msg *request)
{
	int backup_route_type;
	struct usr_avp **backup_list;
	char *p;

	/* ... we calculate branch ... */
	if (!t_calc_branch(t, branch, request->add_to_branch_s,
			&request->add_to_branch_len ))
	{
		LOG(L_ERR, "ERROR:pre_print_uac_request: branch computation failed\n");
		goto error;
	}

	/* from now on, flag all new lumps with LUMPFLAG_BRANCH flag in order to
	 * be able to remove them later --bogdan */
	set_init_lump_flags(LUMPFLAG_BRANCH);

	/********** run route & callback ************/

	/* run branch route, if any; run it before RURI's DNS lookup 
	 * to allow to be changed --bogdan */
	if (t->on_branch) {
		/* need to pkg_malloc the dst_uri */
		if ( request->dst_uri.len ) {
			if ( (p=pkg_malloc(request->dst_uri.len))==0 ) {
				LOG(L_ERR,"ERROR:tm:pre_print_uac_request: no more pkg mem\n");
				ser_error=E_OUT_OF_MEM;
				goto error;
			}
			memcpy( p, request->dst_uri.s, request->dst_uri.len);
			request->dst_uri.s = p;
		}
		/* need to pkg_malloc the new_uri */
		if ( (p=pkg_malloc(request->new_uri.len))==0 ) {
			LOG(L_ERR,"ERROR:tm:pre_print_uac_request: no more pkg mem\n");
			ser_error=E_OUT_OF_MEM;
			goto error;
		}
		memcpy( p, request->new_uri.s, request->new_uri.len);
		request->new_uri.s = p;
		/* make available the avp list from transaction */
		backup_list = set_avp_list( &t->user_avps );
		/* run branch route */
		swap_route_type( backup_route_type, BRANCH_ROUTE);
		if (run_actions(branch_rlist[t->on_branch], request)==0 &&
		(action_flags&ACT_FL_DROP) ) {
			DBG("DEBUG:tm:pre_print_uac_request: dropping branch <%.*s>\n",
				request->dst_uri.len, request->dst_uri.s);
			goto error;
		}
		set_route_type( backup_route_type );
		/* restore original avp list */
		set_avp_list( backup_list );
	}

	/* run the specific callbacks for this transaction */
	run_trans_callbacks( TMCB_REQUEST_FWDED, t, request, 0,
			-request->REQ_METHOD);

	return 0;
error:
	return -1;
}
Пример #8
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;
}