Sfoglia il codice sorgente

t_suspend() and t_continue() functions are introduced.

These fuctions can be used by other modules to implement
asynchronous actions: t_suspend() saves the transaction, returns its
identifiers, and t_continue() continues the SIP request processing.
(The transaction processing does not continue from the same point
in the script, a separate route block defined by the parameter of
t_continue() is executed instead. The reply lock is held during the
route block execution.) FR timer is ticking while the
transaction is suspended, and the transaction's failure route is
executed if t_continue() is not called in time.

Missing: msg lumps are saved by t_suspend() and are not updated by
the subsequent t_relay(). This means that the modifications made
between them are lost.
Miklos Tirpak 17 anni fa
parent
commit
3ee91bcbc6

+ 6 - 1
modules/tm/t_cancel.c

@@ -103,7 +103,12 @@ int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags)
 	/* cancel pending client transactions, if any */
 	for( i=0 ; i<t->nr_of_outgoings ; i++ ) 
 		if (cancel_bm & (1<<i)){
-			r=cancel_branch(t, i, flags);
+			r=cancel_branch(
+				t,
+				i,
+				flags | ((t->uac[i].request.buffer==NULL)?
+					F_CANCEL_B_FAKE_REPLY:0) /* blind UAC? */
+			);
 			ret|=(r!=0)<<i;
 		}
 	return ret;

+ 7 - 1
modules/tm/t_fwd.c

@@ -733,7 +733,13 @@ void e2e_cancel( struct sip_msg *cancel_msg,
 			 * called with the cancel as the "current" transaction so
 			 * at most t_cancel REPLY_LOCK is held in this process =>
 			 * no deadlock possibility */
-			ret=cancel_branch(t_invite, i, cfg_get(tm,tm_cfg, cancel_b_flags));
+			ret=cancel_branch(
+				t_invite,
+				i,
+				cfg_get(tm,tm_cfg, cancel_b_flags)
+					| ((t_invite->uac[i].request.buffer==NULL)?
+						F_CANCEL_B_FAKE_REPLY:0) /* blind UAC? */
+			);
 			if (ret<0) cancel_bm &= ~(1<<i);
 			if (ret<lowest_error) lowest_error=ret;
 		}

+ 3 - 3
modules/tm/t_reply.c

@@ -626,7 +626,7 @@ static int _reply( struct cell *trans, struct sip_msg* p_msg,
 
 /*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)
+void faked_env( struct cell *t,struct sip_msg *msg)
 {
 	static enum route_mode backup_mode;
 	static struct cell *backup_t;
@@ -683,7 +683,7 @@ static inline void faked_env( struct cell *t,struct sip_msg *msg)
 }
 
 
-static inline int fake_req(struct sip_msg *faked_req,
+int fake_req(struct sip_msg *faked_req,
 							struct sip_msg *shmem_msg, int extra_flags)
 {
 	/* on_negative_reply faked msg now copied from shmem msg (as opposed
@@ -731,7 +731,7 @@ error00:
 	return 0;
 }
 
-void inline static free_faked_req(struct sip_msg *faked_req, struct cell *t)
+void free_faked_req(struct sip_msg *faked_req, struct cell *t)
 {
 	struct hdr_field *hdr;
 

+ 6 - 0
modules/tm/t_reply.h

@@ -156,4 +156,10 @@ void t_drop_replies(void);
 extern const char* rpc_reply_doc[2];
 void rpc_reply(rpc_t* rpc, void* c);
 
+void faked_env( struct cell *t,struct sip_msg *msg);
+int fake_req(struct sip_msg *faked_req,
+			struct sip_msg *shmem_msg, int extra_flags);
+
+void free_faked_req(struct sip_msg *faked_req, struct cell *t);
+
 #endif

+ 154 - 0
modules/tm/t_suspend.c

@@ -0,0 +1,154 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
+ * --------
+ *  2008-11-10	Initial version (Miklos)
+ *
+ */
+
+#include "sip_msg.h"
+#include "t_reply.h"
+#include "h_table.h"
+#include "t_lookup.h"
+#include "t_fwd.h"
+#include "timer.h"
+#include "t_suspend.h"
+
+int t_suspend(struct sip_msg *msg,
+		unsigned int *hash_index, unsigned int *label)
+{
+	struct cell	*t;
+
+	t = get_t();
+	if (!t || t == T_UNDEFINED) {
+		LOG(L_ERR, "ERROR: t_suspend: " \
+			"transaction has not been created yet\n");
+		return -1;
+	}
+
+	/* send a 100 Trying reply, because the INVITE processing
+	will probably take a long time */
+	if (msg->REQ_METHOD==METHOD_INVITE && (t->flags&T_AUTO_INV_100)) {
+		if (!t_reply( t, msg , 100 ,
+			"trying -- your call is important to us"))
+				DBG("SER: ERROR: t_suspend (100)\n");
+	}
+
+#ifdef POSTPONE_MSG_CLONING
+	if ((t->nr_of_outgoings==0) && /* if there had already been
+				an UAC created, then the lumps were
+				saved as well */
+		save_msg_lumps(t->uas.request, msg)
+	) {
+		LOG(L_ERR, "ERROR: t_suspend: " \
+			"failed to save the message lumps\n");
+		return -1;
+	}
+#endif
+	/* save the message flags */
+	t->uas.request->flags = msg->flags;
+
+	*hash_index = t->hash_index;
+	*label = t->label;
+
+	/* add a bling UAC to let the fr timer running */
+	if (add_blind_uac() < 0) {
+		LOG(L_ERR, "ERROR: t_suspend: " \
+			"failed to add the blind UAC\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int t_continue(unsigned int hash_index, unsigned int label,
+		struct action *route)
+{
+	struct cell	*t;
+	struct sip_msg	faked_req;
+	struct run_act_ctx	ra_ctx;
+	int	branch;
+
+	if (t_lookup_ident(&t, hash_index, label) < 0) {
+		LOG(L_ERR, "ERROR: t_continue: transaction not found\n");
+		return -1;
+	}
+
+	/* The transaction has to be locked to protect it
+	 * form calling t_continue() multiple times simultaneously */
+	LOCK_REPLIES(t);
+
+	/* Try to find the blind UAC, and cancel its fr timer.
+	 * We assume that the last blind uac called t_continue(). */
+	for (	branch = t->nr_of_outgoings-1;
+		branch >= 0 && t->uac[branch].request.buffer;
+		branch--);
+
+	if (branch >= 0) {
+		stop_rb_timers(&t->uac[branch].request);
+		/* Set last_received to something >= 200,
+		 * the actual value does not matter, the branch
+		 * will never be picked up for response forwarding.
+		 * If last_received is lower than 200,
+		 * then the branch may tried to be cancelled later,
+		 * for example when t_reply() is called from
+		 * a failure rute => deadlock, because both
+		 * of them need the reply lock to be held. */
+		t->uac[branch].last_received=500;
+	}
+	/* else
+		Not a huge problem, fr timer will fire, but CANCEL
+		will not be sent. last_received will be set to 408. */
+
+	/* fake the request and the environment, like in failure_route */
+	if (!fake_req(&faked_req, t->uas.request, 0 /* extra flags */)) {
+		LOG(L_ERR, "ERROR: t_continue: fake_req failed\n");
+		UNLOCK_REPLIES(t);
+		return -1;
+	}
+	faked_env( t, &faked_req);
+
+	init_run_actions_ctx(&ra_ctx);
+	if (run_actions(&ra_ctx, route, &faked_req)<0)
+		LOG(L_ERR, "ERROR: t_continue: Error in run_action\n");
+
+	/* TODO: save_msg_lumps should clone the lumps to shm mem */
+
+	/* restore original environment and free the fake msg */
+	faked_env( t, 0);
+	free_faked_req(&faked_req, t);
+
+	/* update the flags */
+	t->uas.request->flags = faked_req.flags;
+
+	UNLOCK_REPLIES(t);
+
+	/* release the transaction */
+	t_unref(t->uas.request);
+
+	return 0;
+}

+ 42 - 0
modules/tm/t_suspend.h

@@ -0,0 +1,42 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _T_SUSPEND_H
+#define _T_SUSPEND_H
+
+int t_suspend(struct sip_msg *msg,
+		unsigned int *hash_index, unsigned int *label);
+typedef int (*t_suspend_f)(struct sip_msg *msg,
+		unsigned int *hash_index, unsigned int *label);
+
+int t_continue(unsigned int hash_index, unsigned int label,
+		struct action *route);
+typedef int (*t_continue_f)(unsigned int hash_index, unsigned int label,
+		struct action *route);
+
+#endif /* _T_SUSPEND_H */

+ 2 - 0
modules/tm/tm.c

@@ -400,6 +400,8 @@ static cmd_export_t cmds[]={
 	{"t_get_canceled_ident",   (cmd_function)t_get_canceled_ident,  NO_SCRIPT,
 			0, 0},
 #endif
+	{"t_suspend",          (cmd_function)t_suspend,         NO_SCRIPT,   0, 0},
+	{"t_continue",         (cmd_function)t_continue,        NO_SCRIPT,   0, 0},
 	{0,0,0,0,0}
 };
 

+ 10 - 0
modules/tm/tm_load.c

@@ -216,5 +216,15 @@ int load_tm( struct tm_binds *tmb)
 		return -1;
 	}
 #endif
+	if (! (tmb->t_suspend=(t_suspend_f)find_export("t_suspend",
+			NO_SCRIPT, 0))) {
+		LOG( L_ERR, LOAD_ERROR "'t_suspend' not found\n");
+		return -1;
+	}
+	if (! (tmb->t_continue=(t_continue_f)find_export("t_continue",
+			NO_SCRIPT, 0))) {
+		LOG( L_ERR, LOAD_ERROR "'t_continue' not found\n");
+		return -1;
+	}
 	return 1;
 }

+ 3 - 0
modules/tm/tm_load.h

@@ -47,6 +47,7 @@
 #include "t_reply.h"
 #include "dlg.h"
 #include "t_cancel.h"
+#include "t_suspend.h"
 
 /* export not usable from scripts */
 #define NO_SCRIPT	-1
@@ -129,6 +130,8 @@ struct tm_binds {
 	void* reserved3;
 	void* reserved4;
 #endif
+	t_suspend_f	t_suspend;
+	t_continue_f	t_continue;
 };
 
 extern int tm_init;