t_suspend() and t_continue() functions are introduced.
authorMiklos Tirpak <miklos@iptel.org>
Mon, 10 Nov 2008 12:47:02 +0000 (12:47 +0000)
committerMiklos Tirpak <miklos@iptel.org>
Mon, 10 Nov 2008 12:47:02 +0000 (12:47 +0000)
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.

modules/tm/t_cancel.c
modules/tm/t_fwd.c
modules/tm/t_reply.c
modules/tm/t_reply.h
modules/tm/t_suspend.c [new file with mode: 0644]
modules/tm/t_suspend.h [new file with mode: 0644]
modules/tm/tm.c
modules/tm/tm_load.c
modules/tm/tm_load.h

index 35916ee..96e4a84 100644 (file)
@@ -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;
index 99ac6c6..3e3e5c4 100644 (file)
@@ -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;
                }
index c73e08a..e6197ac 100644 (file)
@@ -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;
 
index 142c353..4b3ebab 100644 (file)
@@ -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
diff --git a/modules/tm/t_suspend.c b/modules/tm/t_suspend.c
new file mode 100644 (file)
index 0000000..21b66fa
--- /dev/null
@@ -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:
+ *    info@iptel.org
+ *
+ * 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;
+}
diff --git a/modules/tm/t_suspend.h b/modules/tm/t_suspend.h
new file mode 100644 (file)
index 0000000..8a9df8b
--- /dev/null
@@ -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:
+ *    info@iptel.org
+ *
+ * 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 */
index 8d35c56..1223972 100644 (file)
@@ -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}
 };
 
index 7e72cb8..0d8b22f 100644 (file)
@@ -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;
 }
index 4381555..8e67dcc 100644 (file)
@@ -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;