sorry -- I'm taking off in few minutes and wanted to commit not after_xl
authorJiri Kuthan <jiri@iptel.org>
Thu, 6 Mar 2003 17:43:17 +0000 (17:43 +0000)
committerJiri Kuthan <jiri@iptel.org>
Thu, 6 Mar 2003 17:43:17 +0000 (17:43 +0000)
to road-block dependent work -- I will post on that and provide
history of changes when I'm back

22 files changed:
Makefile
Makefile.defs
examples/ctd.sh
modules/tm/h_table.c
modules/tm/h_table.h
modules/tm/t_funcs.c
modules/tm/t_funcs.h
modules/tm/t_fwd.c
modules/tm/t_fwd.h
modules/tm/t_hooks.h
modules/tm/t_lookup.c
modules/tm/t_lookup.h
modules/tm/t_reply.c
modules/tm/t_reply.h
modules/tm/timer.c
modules/tm/tm.c
modules/tm/tm_load.c
modules/tm/tm_load.h
modules/tm/uac.c
msg_translator.c
msg_translator.h
parser/msg_parser.h

index 5536902..18715aa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ auto_gen=lex.yy.c cfg.tab.c   #lexx, yacc etc
 #include  source related defs
 include Makefile.sources
 
-override exclude_modules:=CVS cpl cpl-c ext radius_acc radius_auth snmp \
+override exclude_modules:=CVS cpl cpl-c ext radius_acc radius_auth snmp jabber sms pa extcmd msilo auth \
        $(exclude_modules)
 static_modules=
 static_modules_path=$(addprefix modules/, $(static_modules))
index daf619f..8f4c46d 100644 (file)
@@ -175,8 +175,6 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
         -DADAPTIVE_WAIT -DADAPTIVE_WAIT_LOOPS=1024 \
         -DDNS_IP_HACK \
         -DUSE_IPV6 \
-        -DVOICE_MAIL \
-        -D_TOTAG \
         -DUSE_TCP \
         -DDISABLE_NAGLE \
         -DDIGEST_DOMAIN \
@@ -197,7 +195,7 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
         #-DNO_LOG
 
 #PROFILE=  -pg #set this if you want profiling
-#mode = debug
+mode = debug
 ifeq ($(mode),)
        mode = release
 endif
index 7896a94..6ae6a68 100755 (executable)
@@ -55,7 +55,7 @@ else
 fi
 # address of user wishing to initiate conversation
 if [ -z "$1" ] ; then
-       URI="sip:113311@192.168.2.16"
+       URI="sip:44@192.168.2.16"
        echo "caller unspecified -- taking default value $URI"
 else
        URI="$1"
index fdcbd79..57e18ac 100644 (file)
 #include "t_cancel.h"
 #include "t_stats.h"
 
+static enum kill_reason kr;
+
 /* pointer to the big table where all the transaction data
    lives
 */
 
 static struct s_table*  tm_table;
 
+void set_kr( enum kill_reason _kr )
+{
+       if (kr!=0 && _kr!=0) {
+                       DBG("DEBUG: set_kr: kill reason reset: "
+                                       "old=%d update=%d\n", kr, _kr );
+       }
+       kr|=_kr;
+}
+enum kill_reason get_kr() {
+       return kr;
+}
+
 void lock_hash(int i) 
 {
        lock(&tm_table->entrys[i].mutex);
@@ -84,6 +98,7 @@ void free_cell( struct cell* dead_cell )
        char *b;
        int i;
        struct sip_msg *rpl;
+       struct totag_elem *tt, *foo;
 
        release_cell_lock( dead_cell );
        shm_lock();
@@ -116,6 +131,15 @@ void free_cell( struct cell* dead_cell )
                }
        }
 
+       /* collected to tags */
+       tt=dead_cell->fwded_totags;
+       while(tt) {
+               foo=tt->next;
+               shm_free_unsafe(tt->tag.s);
+               shm_free_unsafe(tt);
+               tt=foo;
+       }
+
        /* the cell's body */
        shm_free_unsafe( dead_cell );
 
@@ -158,6 +182,9 @@ struct cell*  build_cell( struct sip_msg* p_msg )
        /*fprintf(stderr,"before clone VIA |%.*s|\n",via_len(p_msg->via1),
                via_s(p_msg->via1,p_msg));*/
 
+       callback_event(TMCB_REQUEST_IN, new_cell, p_msg, 
+                       p_msg ? p_msg->REQ_METHOD : METHOD_UNDEF );
+
        if (p_msg) {
                new_cell->uas.request = sip_msg_cloner(p_msg);
                if (!new_cell->uas.request)
index e0653ca..f30aa3f 100644 (file)
@@ -120,10 +120,16 @@ typedef struct ua_server
        struct sip_msg   *request;
        struct retr_buf  response;
        unsigned int     status;
+       /* keep to-tags for local 200 replies for INVITE -- 
+        * we need them for dialog-wise matching of ACKs;
+        * the pointer shows to shmem-ed reply */
+       str                              local_totag;
 #ifdef _TOTAG
        str              to_tag;
 #endif
+#ifdef _OBSO
        unsigned int     isACKed;
+#endif
 }ua_server_type;
 
 
@@ -151,6 +157,11 @@ typedef struct ua_client
 }ua_client_type;
 
 
+struct totag_elem {
+       str tag;
+       short acked;
+       struct totag_elem *next;
+};
 
 /* transaction context */
 
@@ -205,7 +216,8 @@ typedef struct cell
 
        /* number of forks */
        int nr_of_outgoings;
-       /* nr of replied branch */
+       /* nr of replied branch; 0..MAX_BRANCHES=branch value,
+        * -1 no reply, -2 local reply */
        int relaied_reply_branch;
        /* UA Server */
        struct ua_server  uas;
@@ -221,16 +233,9 @@ typedef struct cell
           dropping when C timer hits
        */
        int noisy_ctimer;
-       /* is it a local transaction ? */
+       /* is it a local UAC transaction ? */
        int local;
 
-#ifdef _XWAIT
-       /* protection against reentering WAIT state */
-       ser_lock_t      wait_mutex;
-       /* has the transaction been put on wait status ? */
-       int on_wait;
-#endif
-
        /* MD5checksum  (meaningful only if syn_branch=0 */
        char md5[MD5_LEN];
 
@@ -239,7 +244,12 @@ typedef struct cell
        short damocles;
 #endif
        /* has the transaction been scheduled to die? */
-       enum kill_reason kr;
+/*     enum kill_reason kr; */
+
+       /* to-tags of 200/INVITEs which were received from downstream and 
+        * forwarded or passed to UAC; note that there can be arbitrarily 
+        * many due to downstream forking; */
+       struct totag_elem *fwded_totags;
 }cell_type;
 
 
@@ -266,14 +276,9 @@ struct s_table
        struct entry   entrys[ TABLE_ENTRIES ];
 };
 
-inline static void set_kr( struct cell *t, enum kill_reason kr )
-{
-       if (t->kr!=0) {
-               LOG(L_ERR, "ERROR: set_kr: kill_reason reset: from=%d to=%d\n",
-               t->kr, kr);
-       }
-       t->kr|=kr;
-}
+
+void set_kr( enum kill_reason kr );
+enum kill_reason get_kr();
 
 struct s_table* get_tm_table();
 struct s_table* init_hash_table();
index 08bf287..dcf95fc 100644 (file)
@@ -101,7 +101,7 @@ void tm_shutdown()
 */
 int t_release_transaction( struct cell *trans )
 {
-       set_kr(trans,REQ_RLSD);
+       set_kr(REQ_RLSD);
 
        reset_timer( & trans->uas.response.fr_timer );
        reset_timer( & trans->uas.response.retr_timer );
index f290a73..38910e4 100644 (file)
@@ -92,10 +92,12 @@ int send_pr_buffer( struct retr_buf *rb,
        UNREF_UNSAFE(_T_cell); \
        UNLOCK_HASH( (_T_cell)->hash_index ); })
 #define REF_UNSAFE(_T_cell) ({  (_T_cell)->ref_count++; })
+#ifdef _OBSO
 #define REF(_T_cell) ({ \
        LOCK_HASH( (_T_cell)->hash_index ); \
        REF_UNSAFE(_T_cell); \
        UNLOCK_HASH( (_T_cell)->hash_index ); })
+#endif
 #define INIT_REF_UNSAFE(_T_cell) (_T_cell)->ref_count=1
 #define IS_REFFED_UNSAFE(_T_cell) ((_T_cell)->ref_count!=0)
 
@@ -111,19 +113,14 @@ void tm_shutdown();
 int  t_add_transaction( struct sip_msg* p_msg  );
 
 
-/* returns 1 if everything was OK or -1 for error
- */
+/* returns 1 if everything was OK or -1 for error */
 int t_release_transaction( struct cell *trans );
 
 
-/* int forward_serial_branch(struct cell* Trans,int branch); */
-int t_put_on_wait(  struct cell  *Trans  );
 int get_ip_and_port_from_uri( str* uri , unsigned int *param_ip,
        unsigned int *param_port);
 
 
-int t_newtran( struct sip_msg* p_msg );
-
 void put_on_wait(  struct cell  *Trans  );
 
 void start_retr( struct retr_buf *rb );
index bd713d9..3ec319a 100644 (file)
@@ -75,7 +75,7 @@ char *print_uac_request( struct cell *t, struct sip_msg *i_req,
        i_req->new_uri=*uri;
 
        /* ... give apps a chance to change things ... */
-       callback_event( TMCB_REQUEST_OUT, t, i_req, -i_req->REQ_METHOD);
+       callback_event( TMCB_REQUEST_FWDED, t, i_req, -i_req->REQ_METHOD);
 
        /* ... and build it now */
        buf=build_req_buf_from_sip_req( i_req, len, send_sock, i_req->rcv.proto );
@@ -110,6 +110,45 @@ error01:
        return shbuf;
 }
 
+/* introduce a new uac, which is blind -- it only creates the
+   data structures and starts FR timer, but that's it; it does
+   not print messages and send anything anywhere; that is good
+   for FIFO apps -- the transaction must look operationally
+   and FR must be ticking, whereas the request is "forwarded"
+   using a non-SIP way and will be replied the same way
+*/
+int add_blind_uac( /*struct cell *t*/ )
+{
+       unsigned short branch;
+       struct cell *t;
+
+       t=get_t();
+       if (t==T_UNDEFINED || !t ) {
+               LOG(L_ERR, "ERROR: add_blind_uac: no transaction context\n");
+               return -1;
+       }
+
+       branch=t->nr_of_outgoings;      
+       if (branch==MAX_BRANCHES) {
+               LOG(L_ERR, "ERROR: add_blind_uac: "
+                       "maximum number of branches exceeded\n");
+               return -1;
+       }
+       /* make sure it will be replied */
+       t->noisy_ctimer=1; 
+       t->nr_of_outgoings++;
+       /* start FR timer -- protocol set by default to PROTO_NONE,
+       which means retransmission timer will not be started
+    */
+       start_retr(&t->uac[branch].request);
+       /* we are on a timer -- don't need to put on wait on script
+          clean-up     
+       */
+       set_kr(REQ_FWDED); 
+
+       return 1; /* success */
+}
+
 /* introduce a new uac to transaction; returns its branch id (>=0)
    or error (<0); it doesn't send a message yet -- a reply to it
    might interfere with the processes of adding multiple branches
@@ -343,7 +382,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
        /* make -Wall happy */
        current_uri.s=0;
 
-       set_kr(t, REQ_FWDED);
+       set_kr(REQ_FWDED);
 
        if (p_msg->REQ_METHOD==METHOD_CANCEL) {
                t_invite=t_lookupOriginalT(  p_msg );
index 8176722..171874e 100644 (file)
@@ -40,6 +40,7 @@
 #include "../../proxy.h"
 
 typedef int (*tfwd_f)(struct sip_msg* p_msg , struct proxy_l * proxy );
+typedef int (*taddblind_f)( /*struct cell *t */ );
 
 int t_replicate(struct sip_msg *p_msg, struct proxy_l * proxy, int proto);
 char *print_uac_request( struct cell *t, struct sip_msg *i_req,
@@ -48,6 +49,7 @@ void e2e_cancel( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell
 int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite, int branch );
 int add_uac(   struct cell *t, struct sip_msg *request, str *uri,
                                struct proxy_l *proxy, int proto );
+int add_blind_uac( /* struct cell *t */ );
 int t_forward_nonack( struct cell *t, struct sip_msg* p_msg,
                                                struct proxy_l * p, int proto);
 int t_forward_ack( struct sip_msg* p_msg );
index 80616fc..86fec98 100644 (file)
 struct sip_msg;
 struct cell;
 
-typedef enum { TMCB_REPLY,  TMCB_E2EACK, TMCB_REPLY_IN, 
-       TMCB_REQUEST_OUT, TMCB_LOCAL_COMPLETED, TMCB_ON_NEGATIVE,
-       TMCB_END } tmcb_type;
+typedef enum { 
+               /* input events */
+               TMCB_RESPONSE_IN=1, TMCB_REQUEST_IN, TMCB_E2EACK_IN, 
+               /* routing decisions in progress */
+               TMCB_REQUEST_FWDED, TMCB_RESPONSE_FWDED, TMCB_ON_FAILURE,
+               /* completion events */
+               TMCB_RESPONSE_OUT, TMCB_LOCAL_COMPLETED, 
+               TMCB_END } tmcb_type;
 
 /* 
-       TMCB_REPLY      -  a reply has been sent out
-         no chance to change anything in the message; 
-         still good enough for many uses, such as accounting
-         of completed transactions; note well that the message
-         passed to the callback may also have value FAKED_REPLY,
-         i.e., refering to it will segfault
-       TMCB_REPLY_IN - a reply was received and is about to be forwarded;
-         compared to TMCB_REPLY, it is a very internal callback and
-         you should use it with lot of caution
-         - it allows you to change the message (called before printing
-           the relayed message)
-         - it is called from a reply lock -- it is mroe dangerous and
-           anything you do makes the processes spend more time in
-           the lock, decreasing overall performance
-         - is is called only for replies >100, <300 (final replies
-           might be cached on forking, stored in shmem -- then, there
-               is no more easy way to change messages)
-         - as it is called before printing and forwarding, there is
-           no guarantee the message will be sent out -- either can
-           fail
-
-               Note: none of the reply callbacks will be evoked if
-               "silent C timer" hits. Silent C timer is a feature which
-               prevents cancellation of a call in progress by a server
-               in the middle, when C timer expires. On one side, 
-               INVITE transactional state cannot be kept for ever,
-               on the other side you want to allow long ringing 
-               uninterrupted by a proxy server. The silent_c feature
-               -- if circumstances allow -- simply discards transaction
-               state when C timer hits, the transaction can then complete
-               statelessly. Then, however, the stateful callback will
-               NOT be called. If you do not wish this behaviour (e.g.,
-               for sake of transaction accounting, in which you do
-               not desire users to wait until silent C hits and
-               eventually complete an unaccounted transaction), turn
-               silent C off either globaly (TM option "noisy_ctimer"
-               set to 1) or for a specific transaction (you can for
-               example set the transaction member "noisy_timer"
-               from request callback.)
-
-       TMCB_E2EACK - presumably, an end2end ACK was received and
-               is about to be processed statelessly; you better don't
-           use this callback as there is no reliable way to match
-           an e2e ACK to an INVITE transaction, we just try it for
-           those, who believe they can't live without knowing about
-           the ACK; There are more reasons why the e2e ACK callback
-           is never triggered: 1) the e2eACK does not pass the server
-           at all 2) the e2e ACK does not match an INVITE transaction
-               because its r-uri or via is different
-       TMCB_REQUEST_OUT - a request was received and is about to be fwd-ed;
-               it is not called on retransmissions; it is called prior to
-               printing the relayed message, i.e., changes to it can
-               be done
-       TMCB_LOCAL_COMPLETED - a local transaction completed; note that
-           the callback parameter may be FAKED_REPLY
-       TMCB_MISSED -- transaction was replied with a negative value;
-               called from within a REPLY_LOCK, message may be FAKED_REPLY
-       TMCB_ON_NEGATIVE -- called whenever a transaction is about to complete
-           with a negative result; it's a great time to introduce a new
-           uac (serial forking) or change the reply code; be cautions
-           though -- it is called from within REPLY_LOCK and careless
-           usage of the callback can easily result in a deadlock; msg
-           is always 0 (callback refers to whole transaction and not
-           to individual message), code is the currently lowest status
-           code
-       TMCB_END        - just a bumper
+ *  Caution: most of the callbacks work with shmem-ized messages
+ *  which you can no more change (e.g., lumps are fixed). Most
+ *  reply-processing callbacks are also called from a mutex,
+ *  which may cause deadlock if you are not careful. Also, reply
+ *  callbacks may pass the value of FAKED_REPLY messages, which
+ *  is a non-dereferencable pointer indicating that no message
+ *  was received and a timer hit instead.
+ *
+ *  Callback description:
+ *  ---------------------
+ *
+ * TMCB_REQUEST_IN -- a brand-new request was received and is
+ * about to establish transaction; it is not yet cloned and
+ * lives in pkg mem -- your last chance to mangle it before
+ * it gets shmem-ized (then, it's read-only); it's called from
+ * HASH_LOCK, so be careful. It is guaranteed not to be
+ * a retransmission.
+ *
+ * TMCB_RESPONSE_IN -- a brand-new reply was received which matches
+ * an existing transaction. It may or may not be a retranmisssion.
+ *
+ *  TMCB_RESPONSE_OUT -- a final reply was sent out (eiter local 
+ *  or proxied) -- there is nothing more you can change from
+ *  the callback, it is good for accounting-like uses.
+ *
+ *    Note: the message passed to callback may also have
+ *    value FAKED_REPLY (like other reply callbacks) which
+ *    indicates a psedo_reply caused by a timer. Check for
+ *    this value before derefing -- you will cause a segfault
+ *    otherwise.
+ *
+ *  TMCB_ON_FAILURE -- called on receipt of a reply or timer;
+ *  it means all branches completed with a failure; that's 
+ *  a chance for example to add new transaction branches
+ *
+ *  TMCB_RESPONSE_FWDED -- called when a reply is about to be
+ *  forwarded; it is called after a message is received but before
+ *  a message is sent out: it is called when the decision is 
+ *  made to forward a reply; it is parametrized by pkg message 
+ *  which caused the transaction to complete (which is not 
+ *  necessarily the same which will be forwarded). As forwarding
+ *  has not been executed and may fail, there is no guarentee
+ *  a reply will be successfuly sent out at this point of time.
+ *
+ *     Note: TMCB_REPLY_ON_FAILURE and TMCB_REPLY_FWDED are
+ *     called from reply mutex which is used to deterministically
+ *     process multiple replies received in parallel. A failure
+ *     to set the mutex again or stay too long in the callback
+ *     may result in deadlock.
+ *
+ *     Note: the reply callbacks will not be evoked if "silent
+ *     C-timer hits". That's a feature to clean transactional
+ *     state from a proxy quickly -- transactions will then
+ *     complete statelessly. If you wish to disable this
+ *     feature, either set the global option "noisy_ctimer"
+ *     to 1, or set t->noisy_ctimer for selected transaction.
+ *
+ *  TMCB_E2EACK_IN -- called when an ACK belonging to a proxied
+ *  INVITE transaction completed with 200 arrived. Note that
+ *  because it can be only dialog-wise matched, only the first
+ *  transaction occurence will be matched with spirals. If
+ *  record-routing is not enabled, you will never receive the
+ *  ACK and the callback will be never triggered.
+ *
+ *
+ *  TMCB_REQUEST_FWDED -- request is being forwarded out. It is 
+ *  called before a message is forwarded and it is your last
+ *  chance to change its shape. 
+ *
+ *  TMCB_LOCAL COMPLETED -- final reply for localy initiated
+ *  transaction arrived. Message may be FAKED_REPLY.
+ *
+ *  TMCB_END   - just a bumper
 
        see the 'acc' module for an example of callback usage
 
        note that callbacks MUST be installed before forking
     (callback lists do not live in shmem and have no access
-       protection)
+       protection), i.e., at best from mod_init functions.
 */
 
 typedef void (transaction_cb) ( struct cell* t, struct sip_msg* msg, 
index 495a157..e606961 100644 (file)
@@ -71,6 +71,7 @@
 #include "../../dprint.h"
 #include "../../config.h"
 #include "../../parser/parser_f.h"
+#include "../../parser/parse_from.h"
 #include "../../ut.h"
 #include "../../timer.h"
 #include "../../hash_func.h"
@@ -141,54 +142,178 @@ struct cell *get_t() { return T; }
 void set_t(struct cell *t) { T=t; }
 void init_t() {global_msg_id=0; set_t(T_UNDEFINED);}
 
+static inline int parse_dlg( struct sip_msg *msg )
+{
+       if (parse_headers(msg, HDR_FROM | HDR_CSEQ | HDR_TO, 0)==-1) {
+               LOG(L_ERR, "ERROR: tid_matching: From or Cseq or To invalid\n");
+               return 0;
+       }
+       if (parse_from_header(msg)==-1) {
+               LOG(L_ERR, "ERROR: tid_matching: From broken\n");
+               return 0;
+       }
+       /* To is automatically parsed through HDR_TO in parse bitmap,
+        * we don't need to worry about it now
+       if (parse_to_header(msg)==-1) {
+               LOG(L_ERR, "ERROR: tid_matching: To broken\n");
+               return 0;
+       }
+       */
+       return 1;
+}
+
+/* is the ACK (p_msg) in p_msg dialog-wise equal to the INVITE (t_msg) 
+ * except to-tags? */
+static inline int partial_dlg_matching(struct sip_msg *t_msg, struct sip_msg *p_msg)
+{
+       struct to_body *inv_from;
+
+       if (!EQ_LEN(callid)) return 0;
+       if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len)
+               return 0;
+       inv_from=get_from(t_msg);
+       if (!inv_from) {
+               LOG(L_ERR, "ERROR: partial_dlg_matching: INV/From not parsed\n");
+               return 0;
+       }
+       if (inv_from->tag_value.len!=get_from(p_msg)->tag_value.len)
+               return 0;
+       if (!EQ_STR(callid)) 
+               return 0;
+       if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,
+                       get_cseq(p_msg)->number.len)!=0)
+               return 0;
+       if (memcmp(inv_from->tag_value.s, get_from(p_msg)->tag_value.s,
+                       get_from(p_msg)->tag_value.len)!=0)
+               return 0;
+       return 1;
+}
+
+/* are to-tags in ACK/200 same as those we sent out? */
+static inline int dlg_matching(struct cell *p_cell, struct sip_msg *ack )
+{
+       if (get_to(ack)->tag_value.len!=p_cell->uas.local_totag.len)
+               return 0;
+       if (memcmp(get_to(ack)->tag_value.s,p_cell->uas.local_totag.s,
+                               p_cell->uas.local_totag.len)!=0)
+               return 0;
+       return 1;
+}
+
+static inline int ack_matching(struct cell *p_cell, struct sip_msg *p_msg) 
+{
+       /* partial dialog matching -- no to-tag, only from-tag, 
+        * callid, cseq number ; */
+       if (!partial_dlg_matching(p_cell->uas.request, p_msg)) 
+               return 0;
+
+       /* if this transaction is proxied (as opposed to UAS) we're
+        * done now -- we ignore to-tags; the ACK simply belongs to
+        * this UAS part of dialog, whatever to-tag it gained
+        */
+       if (p_cell->relaied_reply_branch!=-2) {
+               return 2; /* e2e proxied ACK */
+       }
+       /* it's a local dialog -- we wish to verify to-tags too */
+       if (dlg_matching(p_cell, p_msg)) {
+               return 1;
+       }
+       return 0;
+}
+
+/* branch-based transaction matching */
+static inline int via_matching( struct via_body *inv_via, 
+                               struct via_body *ack_via )
+{
+       if (inv_via->tid.len!=ack_via->tid.len)
+               return 0;
+       if (memcmp(inv_via->tid.s, ack_via->tid.s,
+                               ack_via->tid.len)!=0)
+               return 0;
+       /* ok, tid matches -- now make sure that the
+        * originater matches too to avoid confusion with
+        * different senders generating the same tid
+        */
+       if (inv_via->host.len!=ack_via->host.len)
+               return 0;;
+       if (memcmp(inv_via->host.s, ack_via->host.s,
+                       ack_via->host.len)!=0)
+               return 0;
+       if (inv_via->port!=ack_via->port)
+               return 0;
+       if (inv_via->transport.len!=ack_via->transport.len)
+               return 0;
+       if (memcmp(inv_via->transport.s, ack_via->transport.s,
+                       ack_via->transport.len)!=0)
+               return 0;
+       /* everything matched -- we found it */
+       return 1;
+}
+
 
 /* transaction matching a-la RFC-3261 using transaction ID in branch
- * (the function assumes there is magic cookie in branch) */
+   (the function assumes there is magic cookie in branch) 
+   It returns:
+        2 if e2e ACK for a proxied transaction found
+     1  if found (covers ACK for local UAS)
+        0  if not found (trans undefined)
+*/
 
-static struct cell *tid_matching( int hash_index, 
-               struct via_body *via1, 
-               enum request_method skip_method)
+static int matching_3261( struct sip_msg *p_msg, struct cell **trans,
+                       enum request_method skip_method)
 {
        struct cell *p_cell;
        struct sip_msg  *t_msg;
+       struct via_body *via1;
+       int is_ack;
+       int dlg_parsed;
+       int ret;
 
-
+       via1=p_msg->via1;
+       is_ack=p_msg->REQ_METHOD==METHOD_ACK;
+       dlg_parsed=0;
        /* update parsed tid */
        via1->tid.s=via1->branch->value.s+MCOOKIE_LEN;
        via1->tid.len=via1->branch->value.len-MCOOKIE_LEN;
 
-       for ( p_cell = get_tm_table()->entrys[hash_index].first_cell;
+       for ( p_cell = get_tm_table()->entrys[p_msg->hash_index].first_cell;
                p_cell; p_cell = p_cell->next_cell ) 
        {
                t_msg=p_cell->uas.request;
                if (skip_method & t_msg->REQ_METHOD)
                        continue;
-               if (t_msg->via1->tid.len!=via1->tid.len)
-                       continue;
-               if (memcmp(t_msg->via1->tid.s, via1->tid.s,
-                               via1->tid.len)!=0)
-                       continue;
-               /* ok, tid matches -- now make sure that the
-                * originater matches too to avoid confusion with
-                * different senders generating the same tid
-                */
-               if (via1->host.len!=t_msg->via1->host.len)
-                       continue;
-               if (memcmp(via1->host.s, t_msg->via1->host.s,
-                                       via1->host.len)!=0)
-                       continue;
-               if (via1->port!=t_msg->via1->port)
-                       continue;
-               if (via1->transport.len!=t_msg->via1->transport.len)
+
+               /* dialog matching needs to be applied for ACK/200s */
+               if (is_ack && p_cell->uas.status<300) {
+                       /* make sure we have parsed all things we need for dialog
+                        * matching */
+                       if (!dlg_parsed) {
+                               dlg_parsed=1;
+                               if (!parse_dlg(p_msg)) {
+                                       LOG(L_ERR, "ERROR: tid_matching: dlg parsing failed\n");
+                                       return 0;
+                               }
+                       }
+                       ret=ack_matching(p_cell /* t w/invite */, p_msg /* ack */);
+                       if (ret>0) {
+                               *trans=p_cell;
+                               return ret; /* 2: e2e proxied ACK, 1 e2e UAS ACK */
+                       }
+                       /* this ACK is neither local "negative" one, nor a proxied
+                        * end-2-end one, nor an end-2-end one for a UAS transaction
+                        * -- we failed to match */
                        continue;
-               if (memcmp(via1->transport.s, t_msg->via1->transport.s,
-                                       via1->transport.len)!=0)
+               }
+               /* now real tid matching occurs  for negative ACKs and any 
+                * other requests */
+               if (!via_matching(t_msg->via1 /* inv via */, via1 /* ack */ ))
                        continue;
                /* all matched -- we found the transaction ! */
                DBG("DEBUG: RFC3261 transaction matched, tid=%.*s\n",
                        via1->tid.len, via1->tid.s);
 
-               return p_cell;
+               *trans=p_cell;
+               return 1;
        }
        /* :-( ... we didn't find any */
        DBG("DEBUG: RFC3261 transaction matching failed\n");
@@ -209,6 +334,7 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
        struct sip_msg  *t_msg;
        int ret;
        struct via_param *branch;
+       int match_status;
 
        /* parse all*/
        if (check_transaction_quadruple(p_msg)==0)
@@ -221,8 +347,7 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 
        /* start searching into the table */
        if (!p_msg->hash_index)
-               p_msg->hash_index=hash( p_msg->callid->body , 
-                       get_cseq(p_msg)->number ) ;
+               p_msg->hash_index=hash( p_msg->callid->body , get_cseq(p_msg)->number ) ;
        isACK = p_msg->REQ_METHOD==METHOD_ACK;
        DBG("t_lookup_request: start searching: hash=%d, isACK=%d\n",
                p_msg->hash_index,isACK);
@@ -245,29 +370,20 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
                        && memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) {
                /* huhuhu! the cookie is there -- let's proceed fast */
                LOCK_HASH(p_msg->hash_index);
-               p_cell=tid_matching(p_msg->hash_index, p_msg->via1, 
-                               /* skip transactions with different
-                                * method; otherwise CANCEL would 
-                                * match the previous INVITE trans.
-                                */
+               match_status=matching_3261(p_msg,&p_cell, 
+                               /* skip transactions with different method; otherwise CANCEL would 
+                                * match the previous INVITE trans.  */
                                isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD);
-               if (p_cell) {
-                       /* ACK/200 */
-                       if (isACK && p_cell->uas.status>=200 && p_cell->uas.status<300) {
-                               /* perhaps there are some spirals on the synonym list, but
-                                  it makes no sense to iterate the list until bitter end */
-                               t_ack=p_cell;
-                               ret=-2;
-                               goto notfound;
-                       }
-                       /* all but 200/ACK */
-                       goto found;
-               } 
-               /* new */
-               goto notfound;
+               switch(match_status) {
+                               case 0: goto notfound;  /* no match */
+                               case 1: goto found;     /* match */
+                               case 2: goto e2e_ack;   /* e2e proxy ACK */
+               }
        }
 
-       /* ok -- it's ugly old-fashioned transaction matching */
+       /* ok -- it's ugly old-fashioned transaction matching -- it is
+        * a bit simplified to be fast -- we don't do all the comparisons
+        * of parsed uri, which was simply too bloated */
        DBG("DEBUG: proceeding to pre-RFC3261 transaction matching\n");
 
        /* lock the whole entry*/
@@ -303,63 +419,39 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
                        /* ACK's relate only to INVITEs */
                        if (t_msg->REQ_METHOD!=METHOD_INVITE) continue;
 
+                       /* From|To URI , CallID, CSeq # must be always there */
                        /* compare lengths now */
                        if (!EQ_LEN(callid)) continue;
                        /* CSeq only the number without method ! */
                        if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len)
                                continue;
                        if (! EQ_LEN(from)) continue;
-                       /* To only the uri and ... */
+                       /* To only the uri -- to many UACs screw up tags  */
                        if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len)
                                continue;
-                       /* don't care about to-tags -- many UAC screw them
-                        * up anyway, and it doesn't hurt if we ignore 
-                        * them */
-#ifdef ACKTAG
-                       /* ... its to-tag compared to reply's tag */
-                       if (p_cell->uas.to_tag.len!=get_to(p_msg)->tag_value.len)
-                               continue;
-#endif
-
-                       /* we first skip r-uri and Via and proceed with
-                          content of other header-fields */
-
-                       if ( memcmp(t_msg->callid->body.s, p_msg->callid->body.s,
-                               p_msg->callid->body.len)!=0) continue;
-                       if ( memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,
+                       if (!EQ_STR(callid)) continue;
+                       if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,
                                get_cseq(p_msg)->number.len)!=0) continue;
                        if (!EQ_STR(from)) continue;
                        if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s,
                                get_to(t_msg)->uri.len)!=0) continue;
-#ifdef ACKTAG
-                       if (
-#ifdef _BUG
-                               p_cell->uas.to_tag.len!=0 /* to-tags empty */ || 
-#endif
-                               memcmp(p_cell->uas.to_tag.s, get_to(p_msg)->tag_value.s,
-                               p_cell->uas.to_tag.len)!=0) continue;
-#endif
-       
-                       /* ok, now only r-uri or via can mismatch; they must match
-                          for non-2xx; if it is a 2xx, we don't try to match
-                          (we might have checked that earlier to speed-up, but
-                          we still want to see a diagnosti message telling
-                          "this ACK presumably belongs to this 2xx transaction";
-                          might change in future); the reason is 2xx ACKs are
-                          a separate transaction which may carry different
-                          r-uri/via1 and is thus also impossible to match it
-                          uniquely to a spiraled transaction;
-                       */
-                       if (p_cell->uas.status>=200 && p_cell->uas.status<300) {
-                               DBG("DEBUG: an ACK hit a 2xx transaction (T=%p); "
-                                       "considered mismatch\n", p_cell );
-                               /* perhaps there are some spirals on the synonym list, but
-                                  it makes no sense to iterate the list until bitter end */
-                               t_ack=p_cell;
-                               ret=-2;
-                               break;
+
+                       /* it is e2e ACK/200 */
+                       if (p_cell->uas.status<300) {
+                               /* all criteria for proxied ACK are ok */
+                               if (p_cell->relaied_reply_branch!=-2) 
+                                       goto e2e_ack;
+                               /* it's a local UAS transaction */
+                               if (dlg_matching(p_cell, p_msg))
+                                       goto found;
+                               continue;
                        }
-                       /* its for a >= 300 ... everything must match ! */
+
+                       /* it is not an e2e ACK/200 -- perhaps it is 
+                        * local negative case; in which case we will want
+                        * more elements to match: r-uri and via; allow
+                        * mismatching r-uri as an config option for broken
+                        * UACs */
                        if (ruri_matching && ! EQ_REQ_URI_LEN ) continue;
                        if (! EQ_VIA_LEN(via1)) continue;
                        if (ruri_matching && !EQ_REQ_URI_STR) continue;
@@ -378,12 +470,21 @@ notfound:
                UNLOCK_HASH(p_msg->hash_index);
        }
        DBG("DEBUG: t_lookup_request: no transaction found\n");
-       return ret;
+       return -1;
+
+e2e_ack:
+       t_ack=p_cell;   /* e2e proxied ACK */
+       set_t(0);
+       if (!leave_new_locked) {
+               UNLOCK_HASH(p_msg->hash_index);
+       }
+       DBG("DEBUG: t_lookup_request: e2e proxy ACK found\n");
+       return -2;
 
 found:
        set_t(p_cell);
        REF_UNSAFE( T );
-       set_kr(T, REQ_EXIST);
+       set_kr(REQ_EXIST);
        UNLOCK_HASH( p_msg->hash_index );
        DBG("DEBUG: t_lookup_request: transaction found (T=%p)\n",T);
        return 1;
@@ -402,6 +503,7 @@ struct cell* t_lookupOriginalT(  struct sip_msg* p_msg )
        unsigned int     hash_index;
        struct sip_msg  *t_msg;
        struct via_param *branch;
+       int ret;
 
 
        /* start searching in the table */
@@ -423,12 +525,12 @@ struct cell* t_lookupOriginalT(  struct sip_msg* p_msg )
                        && memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) {
                /* huhuhu! the cookie is there -- let's proceed fast */
                LOCK_HASH(hash_index);
-               p_cell=tid_matching(hash_index, p_msg->via1, 
+               ret=matching_3261(p_msg, &p_cell,
                                /* we are seeking the original transaction --
                                 * skip CANCEL transactions during search
                                 */
                                METHOD_CANCEL);
-               if (p_cell) goto found; else goto notfound;
+               if (ret==1) goto found; else goto notfound;
        }
 
        /* no cookies --proceed to old-fashioned pre-3261 t-matching */
@@ -658,6 +760,23 @@ int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
                REF_UNSAFE( T );
                UNLOCK_HASH(hash_index);
                DBG("DEBUG: t_reply_matching: reply matched (T=%p)!\n",T);
+               /* if this is a 200 for INVITE, we will wish to store to-tags to be
+                * able to distuingish retransmissions later and not to call
+                * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are
+                * enabled -- except callback customers, nobody cares about 
+                * retransmissions of multiple 200/INV or ACK/200s
+                */
+               if (p_cell->is_invite && p_msg->REPLY_STATUS>=200 
+                               && p_msg->REPLY_STATUS<300 
+                               && ( (!p_cell->local && 
+                                       (callback_array[TMCB_RESPONSE_OUT]||
+                                               callback_array[TMCB_E2EACK_IN]))
+                                       || (p_cell->local && callback_array[TMCB_LOCAL_COMPLETED]) )) {
+                       if (parse_headers(p_msg, HDR_TO, 0)==-1) {
+                               LOG(L_ERR, "ERROR: t_reply_matching: to parsing failed\n");
+                       }
+               }
+               callback_event(TMCB_RESPONSE_IN, T, p_msg, p_msg->REPLY_STATUS);
                return 1;
        } /* for cycle */
 
@@ -675,10 +794,12 @@ nomatch2:
 
 
 
-/* Functions update T (T gets either a valid pointer in it or it equals zero) if no transaction
-  * for current message exists;
-  * it returns 1 if found, 0 if not found, -1 on error
-  */
+/* Determine current transaction
+ *
+ *                   Found      Not Found     Error (e.g. parsing)
+ *  Return Value     1          0             -1
+ *  T                ptr        0             T_UNDEFINED
+ */
 int t_check( struct sip_msg* p_msg , int *param_branch )
 {
        int local_branch;
@@ -693,8 +814,20 @@ int t_check( struct sip_msg* p_msg , int *param_branch )
                /* transaction lookup */
                if ( p_msg->first_line.type==SIP_REQUEST ) {
                        /* force parsing all the needed headers*/
-                       if (parse_headers(p_msg, HDR_EOH, 0 )==-1)
+                       if (parse_headers(p_msg, HDR_EOH, 0 )==-1) {
+                               LOG(L_ERR, "ERROR: t_check: parsing error\n");
                                return -1;
+                       }
+                       /* in case, we act as UAS for INVITE and reply with 200,
+                        * we will need to run dialog-matching for subsequent
+                        * ACK, for which we need From-tag; We also need from-tag
+                        * in case people want to have proxied e2e ACKs accounted
+                        */
+                       if (p_msg->REQ_METHOD==METHOD_INVITE 
+                                                       && parse_from_header(p_msg)==-1) {
+                               LOG(L_ERR, "ERROR: t_check: from parsing failed\n");
+                               return -1;
+                       }
                        t_lookup_request( p_msg , 0 /* unlock before returning */ );
                } else {
                        /* we need Via for branch and Cseq method to distinguish
@@ -738,7 +871,7 @@ int t_check( struct sip_msg* p_msg , int *param_branch )
                        DBG("DEBUG: t_check: T previously sought and not found\n");
        }
 
-       return ((T)?1:0) ;
+       return T ? (T==T_UNDEFINED ? -1 : 1 ) : 0;
 }
 
 int init_rb( struct retr_buf *rb, struct sip_msg *msg)
@@ -840,6 +973,21 @@ int t_newtran( struct sip_msg* p_msg )
        if (lret<0) {
                new_cell=0;
                if ( p_msg->REQ_METHOD!=METHOD_ACK ) {
+                       /* REVIEW */
+                       /* for ACK-dlw-wise matching, we want From-tags */
+                       if (p_msg->REQ_METHOD==METHOD_INVITE) {
+                               if (parse_from_header(p_msg)<0) {
+                                       LOG(L_ERR, "ERROR: t_newtran: no valid From\n");
+                                       return E_BAD_REQ;
+                               }
+                       }
+                       /* REVIEW */
+                       /* make sure uri will be parsed before cloning */
+                       if (parse_sip_msg_uri(p_msg)<0) {
+                               LOG(L_ERR, "ERROR: t_new_tran: uri invalid\n");
+                               return E_BAD_REQ;
+                       }
+                       
                        /* add new transaction */
                        new_cell = build_cell( p_msg ) ;
                        if  ( !new_cell ){
@@ -867,6 +1015,7 @@ int t_newtran( struct sip_msg* p_msg )
 
                                new_cell->method=new_cell->uas.request->first_line.u.request.method;
                                new_cell->is_invite=p_msg->REQ_METHOD==METHOD_INVITE;
+
                        }
 
                }
@@ -875,7 +1024,9 @@ int t_newtran( struct sip_msg* p_msg )
                if (lret==-2) {
                                REF_UNSAFE(t_ack);
                                UNLOCK_HASH(p_msg->hash_index);
-                               callback_event( TMCB_E2EACK, t_ack, p_msg, p_msg->REQ_METHOD );
+                               if (unmatched_totag(t_ack, p_msg)) {
+                                               callback_event( TMCB_E2EACK_IN, t_ack, p_msg, p_msg->REQ_METHOD );
+                               }
                                UNREF(t_ack);
                } else { /* not e2e ACK */
                        UNLOCK_HASH(p_msg->hash_index);
@@ -915,10 +1066,13 @@ int t_newtran( struct sip_msg* p_msg )
 
 int t_unref( struct sip_msg* p_msg  )
 {
+       enum kill_reason kr;
+
        if (T==T_UNDEFINED || T==T_NULL_CELL)
                return -1;
-       if (T->kr==0 
-               ||(p_msg->REQ_METHOD==METHOD_ACK && !(T->kr & REQ_RLSD))) {
+       kr=get_kr();
+       if (kr==0 
+               ||(p_msg->REQ_METHOD==METHOD_ACK && !(kr & REQ_RLSD))) {
                LOG(L_WARN, "WARNING: script writer didn't release transaction\n");
                t_release_transaction(T);
        }
@@ -927,7 +1081,6 @@ int t_unref( struct sip_msg* p_msg  )
        return 1;
 }
 
-#ifdef VOICE_MAIL
 int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned int* label)
 {
     struct cell* t;
@@ -947,14 +1100,13 @@ int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned
     return 1;
 }
 
-int t_lookup_ident(struct sip_msg** p_msg, unsigned int hash_index, unsigned int label)
+int t_lookup_ident(struct cell ** trans, unsigned int hash_index, unsigned int label)
 {
-    int ret = 0;
     struct cell* p_cell;
 
     if(hash_index >= TABLE_ENTRIES){
-       LOG(L_ERR,"ERROR: t_lookup_ident: invalid hash_index=%u\n",hash_index);
-       return -1;
+               LOG(L_ERR,"ERROR: t_lookup_ident: invalid hash_index=%u\n",hash_index);
+               return -1;
     }
 
     LOCK_HASH(hash_index);
@@ -963,21 +1115,23 @@ int t_lookup_ident(struct sip_msg** p_msg, unsigned int hash_index, unsigned int
     for ( p_cell = get_tm_table()->entrys[hash_index].first_cell;
          p_cell; p_cell = p_cell->next_cell ) 
     {
-       if(p_cell->label == label){
-           ret = 1;
-           break;
-       }
+               if(p_cell->label == label){
+                       REF_UNSAFE(p_cell);
+               UNLOCK_HASH(hash_index);
+                       set_t(p_cell);
+                       *trans=p_cell;
+                       DBG("DEBUG: t_lookup_ident: transaction found\n");
+                       return 1;
+               }
     }
+       
+       UNLOCK_HASH(hash_index);
+       set_t(0);
+       *trans=p_cell;
 
-    if(ret==1){
-       DBG("DEBUG: t_lookup_ident: transaction found\n");
-       *p_msg = p_cell->uas.request;
-    }
-    else
        DBG("DEBUG: t_lookup_ident: transaction not found\n");
     
-    UNLOCK_HASH(hash_index);
-    return ret;
+    return -1;
 }
 
 int t_is_local(struct sip_msg* p_msg)
@@ -995,8 +1149,3 @@ int t_is_local(struct sip_msg* p_msg)
     
     return t->local;
 }
-
-#endif
-
-
-
index 2e22e4e..ec4efb4 100644 (file)
@@ -75,7 +75,6 @@ struct cell *get_t();
  * primarily set by lookup functions */
 void set_t(struct cell *t);
 
-#ifdef VOICE_MAIL
 
 #define T_GET_TI       "t_get_trans_ident"
 #define T_LOOKUP_IDENT "t_lookup_ident"
@@ -83,12 +82,11 @@ void set_t(struct cell *t);
 
 typedef int (*tislocal_f)(struct sip_msg*);
 typedef int (*tget_ti_f)(struct sip_msg*, unsigned int*, unsigned int*);
-typedef int (*tlookup_ident_f)(struct sip_msg**, unsigned int, unsigned int);
+typedef int (*tlookup_ident_f)(struct cell**, unsigned int, unsigned int);
 
 int t_is_local(struct sip_msg*);
 int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned int* label);
-int t_lookup_ident(struct sip_msg** p_msg, unsigned int hash_index, unsigned int label);
-#endif
+int t_lookup_ident(struct cell** trans, unsigned int hash_index, unsigned int label);
 
 #endif
 
index a888296..6d7cd98 100644 (file)
  * 2003-01-19  faked lump list created in on_reply handlers
  */
 
+
+#include <assert.h>
 #include "defs.h"
 
 #include "../../comp_defs.h"
 
 #include "../../hash_func.h"
 #include "t_funcs.h"
+#include "h_table.h"
 #include "../../dprint.h"
 #include "../../config.h"
 #include "../../parser/parser_f.h"
@@ -73,6 +76,7 @@ static char *tm_tag_suffix;
 /* where to go if there is no positive reply */
 static int goto_on_negative=0;
 
+
 /* we store the reply_route # in private memory which is
    then processed during t_relay; we cannot set this value
    before t_relay creates transaction context or after
@@ -101,6 +105,88 @@ void tm_init_tags()
                "SER-TM/tags", TM_TAG_SEPARATOR );
 }
 
+/* returns 0 if the message was previously acknowledged
+ * (i.e., no E2EACK callback is needed) and one if the
+ * callback shall be executed */
+int unmatched_totag(struct cell *t, struct sip_msg *ack)
+{
+       struct totag_elem *i;
+       str *tag;
+
+       if (parse_headers(ack, HDR_TO,0)==-1 || 
+                               !ack->to ) {
+               LOG(L_ERR, "ERROR: ack_totag_set: To invalid\n");
+               return 1;
+       }
+       tag=&get_to(ack)->tag_value;
+       for (i=t->fwded_totags; i; i=i->next) {
+               if (i->tag.len==tag->len
+                               && memcmp(i->tag.s, tag->s, tag->len)==0) {
+                       DBG("DEBUG: totag for e2e ACK found: %d\n", i->acked);
+                       /* to-tag recorded, and an ACK has been received for it */
+                       if (i->acked) return 0;
+                       /* to-tag recorded, but this ACK came for the first time */
+                       i->acked=1;
+                       return 1;
+               }
+       }
+       /* surprising: to-tag never sighted before */
+       return 1;
+}
+
+
+/* append a newly received tag from a 200/INVITE to 
+ * transaction's set; (only safe if called from within
+ * a REPLY_LOCK); it returns 1 if such a to tag already
+ * exists
+ */
+inline static int update_totag_set(struct cell *t, struct sip_msg *ok)
+{
+       struct totag_elem *i, *n;
+       str *tag;
+       char *s;
+
+       if (!ok->to || !ok->to->parsed) {
+               LOG(L_ERR, "ERROR: update_totag_set: to not parsed\n");
+               return 0;
+       }
+       tag=&get_to(ok)->tag_value;
+       if (!tag->s) {
+               LOG(L_ERR, "ERROR: update_totag_set: no tag in to\n");
+               return 0;
+       }
+
+       for (i=t->fwded_totags; i; i=i->next) {
+               if (i->tag.len==tag->len
+                               && memcmp(i->tag.s, tag->s, tag->len) ==0 )
+                       /* to tag already recorded */
+#ifdef XL_DEBUG
+                       LOG(L_CRIT, "DEBUG: update_totag_set: totag retranmission\n");
+#else
+                       DBG("DEBUG: update_totag_set: totag retranmission\n");
+#endif
+                       return 1;
+       }
+       /* that's a new to-tag -- record it */
+       shm_lock();
+       n=(struct totag_elem*) shm_malloc_unsafe(sizeof(struct totag_elem));
+       s=(char *)shm_malloc_unsafe(tag->len);
+       shm_unlock();
+       if (!s || !n) {
+               LOG(L_ERR, "ERROR: update_totag_set: no  memory \n");
+               if (n) shm_free(n);
+               if (s) shm_free(s);
+               return 0;
+       }
+       memset(n, 0, sizeof(struct totag_elem));
+       memcpy(s, tag->s, tag->len );
+       n->tag.s=s;n->tag.len=tag->len;
+       n->next=t->fwded_totags;
+       t->fwded_totags=n;
+       DBG("DEBUG: update_totag_set: new totag \n");
+       return 0;
+}
+
 
 static char *build_ack(struct sip_msg* rpl,struct cell *trans,int branch,
        unsigned int *ret_len)
@@ -315,7 +401,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
                /* no more pending branches -- try if that changes after
                   a callback
                */
-               callback_event( TMCB_ON_NEGATIVE, Trans, 
+               callback_event( TMCB_ON_FAILURE, Trans, 
                        lowest_b==branch?reply:Trans->uac[lowest_b].reply, 
                        lowest_s );
 
@@ -458,18 +544,7 @@ error:
 }
 
 
-#ifdef VOICE_MAIL
-static int _reply_light( struct cell *trans, char* buf, unsigned int len,
-                        unsigned int code, char * text, 
-                        char *to_tag, unsigned int to_tag_len, int lock );
 
-int t_reply_light( struct cell *t, char* buf, unsigned int len,
-                  unsigned int code, char * text,
-                  char *to_tag, unsigned int to_tag_len )
-{
-    return _reply_light( t, buf, len, code, text, to_tag, to_tag_len, 1 /* lock replies */ );
-}
-#endif
 
 int t_reply( struct cell *t, struct sip_msg* p_msg, unsigned int code, 
        char * text )
@@ -484,69 +559,26 @@ int t_reply_unsafe( struct cell *t, struct sip_msg* p_msg, unsigned int code,
 }
 
 
-
-/* send a UAS reply
- * returns 1 if everything was OK or -1 for error
- */
-static int _reply( struct cell *trans, struct sip_msg* p_msg, 
-       unsigned int code, char * text, int lock )
+static inline void update_local_tags(struct cell *trans, 
+                               struct bookmark *bm, char *dst_buffer,
+                               char *src_buffer /* to which bm refers */)
 {
-#ifndef VOICE_MAIL
-       unsigned int len, buf_len=0;
-       char * buf;
-       struct retr_buf *rb;
-
-       branch_bm_t cancel_bitmap;
-#else
-       unsigned int len;
-       char * buf;
-#endif
-
-       if (code>=200) set_kr(trans,REQ_RPLD);
-       /*
-       buf = build_res_buf_from_sip_req(code,text,trans->uas.tag->s,
-               trans->uas.tag->len, trans->uas.request,&len);
-       */
-#ifndef VOICE_MAIL
-       cancel_bitmap=0;
-#endif
-       /* compute the buffer in private memory prior to entering lock;
-        * create to-tag if needed */
-       if (code>=180 && p_msg->to 
-                       && (get_to(p_msg)->tag_value.s==0 
-                           || get_to(p_msg)->tag_value.len==0)) {
-               calc_crc_suffix( p_msg, tm_tag_suffix );
-               buf = build_res_buf_from_sip_req(code,text, 
-                               tm_tags, TOTAG_VALUE_LEN, 
-                               p_msg,&len);
-#ifdef VOICE_MAIL
-
-               return _reply_light(trans,buf,len,code,text,
-                                   tm_tags, TOTAG_VALUE_LEN,
-                                   lock);
-#endif
-       } else {
-               buf = build_res_buf_from_sip_req(code,text, 0,0, /* no to-tag */
-                       p_msg,&len);
-#ifdef VOICE_MAIL
-
-               return _reply_light(trans,buf,len,code,text,
-                                   0,0, /* no to-tag */
-                                   lock);
-#endif
+       if (bm->to_tag_val.s) {
+               trans->uas.local_totag.s=bm->to_tag_val.s-src_buffer+dst_buffer;
+               trans->uas.local_totag.len=bm->to_tag_val.len;
        }
-       DBG("DEBUG: t_reply: buffer computed\n");
-#ifdef VOICE_MAIL
 }
 
+
 static int _reply_light( struct cell *trans, char* buf, unsigned int len,
                         unsigned int code, char * text, 
-                        char *to_tag, unsigned int to_tag_len, int lock )
+                        char *to_tag, unsigned int to_tag_len, int lock,
+                        struct bookmark *bm    )
 {
        struct retr_buf *rb;
-       unsigned int buf_len=0;
-       branch_bm_t cancel_bitmap=0;
-#endif
+       unsigned int buf_len;
+       branch_bm_t cancel_bitmap;
+
        if (!buf)
        {
                DBG("DEBUG: t_reply: response building failed\n");
@@ -560,6 +592,7 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len,
                goto error;
        }
 
+       cancel_bitmap=0;
        if (lock) LOCK_REPLIES( trans );
        if (trans->is_invite) which_cancel(trans, &cancel_bitmap );
        if (trans->uas.status>=200) {
@@ -567,6 +600,19 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len,
                        " when a final %d was sent out\n", code, trans->uas.status);
                goto error2;
        }
+
+#ifdef _TOTAG
+       if(to_tag){
+           trans->uas.to_tag.s = (char*)shm_resize( trans->uas.to_tag.s, to_tag_len );
+           if(! trans->uas.to_tag.s ){
+                       LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n");
+                       goto error2; 
+           }
+           trans->uas.to_tag.len = to_tag_len;
+           memcpy( trans->uas.to_tag.s, to_tag, to_tag_len );
+       }
+#endif
+
        rb = & trans->uas.response;
        rb->activ_type=code;
 
@@ -576,27 +622,17 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len,
        /* puts the reply's buffer to uas.response */
        if (! rb->buffer ) {
                        LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n");
-                       goto error2;
+                       goto error3;
        }
+       update_local_tags(trans, bm, rb->buffer, buf);
+
        rb->buffer_len = len ;
        memcpy( rb->buffer , buf , len );
-#ifdef VOICE_MAIL
-       if(to_tag){
-           trans->uas.to_tag.s = (char*)shm_resize( trans->uas.to_tag.s, to_tag_len );
-           if(! trans->uas.to_tag.s ){
-                       LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n");
-                       // Is it ok? or should i free rb->buffer also, 
-                       // or will it be freed in free_cell() ?
-                       goto error2; 
-           }
-           trans->uas.to_tag.len = to_tag_len;
-           memcpy( trans->uas.to_tag.s, to_tag, to_tag_len );
-       }
-#endif
        /* needs to be protected too because what timers are set depends
           on current transactions status */
        /* t_update_timers_after_sending_reply( rb ); */
        update_reply_stats( code );
+       trans->relaied_reply_branch=-2;
        tm_stats->replied_localy++;
        if (lock) UNLOCK_REPLIES( trans );
        
@@ -609,7 +645,7 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len,
                        if (trans->completion_cb) 
                                trans->completion_cb( trans, FAKED_REPLY, code, 0 /* empty param */);
                } else {
-                       callback_event( TMCB_REPLY, trans, FAKED_REPLY, code );
+                       callback_event( TMCB_RESPONSE_OUT, trans, FAKED_REPLY, code );
                }
 
                cleanup_uac_timers( trans );
@@ -632,6 +668,13 @@ static int _reply_light( struct cell *trans, char* buf, unsigned int len,
        DBG("DEBUG: t_reply: finished\n");
        return 1;
 
+error3:
+#ifdef _TOTAG
+       if (totag) {
+               shm_free(trans->uas.to_tag.s);
+               trans->uas.to_tag.s=0;
+       }
+#endif
 error2:
        if (lock) UNLOCK_REPLIES( trans );
        pkg_free ( buf );
@@ -644,11 +687,47 @@ error:
        return -1;
 }
 
+/* send a UAS reply
+ * returns 1 if everything was OK or -1 for error
+ */
+static int _reply( struct cell *trans, struct sip_msg* p_msg, 
+       unsigned int code, char * text, int lock )
+{
+       unsigned int len;
+       char * buf;
+       struct bookmark bm;
+
+       if (code>=200) set_kr(REQ_RPLD);
+       /* compute the buffer in private memory prior to entering lock;
+        * create to-tag if needed */
+       if (code>=180 && p_msg->to 
+                               && (get_to(p_msg)->tag_value.s==0 
+                           || get_to(p_msg)->tag_value.len==0)) {
+               calc_crc_suffix( p_msg, tm_tag_suffix );
+               buf = build_res_buf_from_sip_req(code,text, 
+                               tm_tags, TOTAG_VALUE_LEN, 
+                               p_msg,&len, &bm);
+
+               return _reply_light(trans,buf,len,code,text,
+                                   tm_tags, TOTAG_VALUE_LEN,
+                                   lock, &bm);
+       } else {
+               buf = build_res_buf_from_sip_req(code,text, 0,0, /* no to-tag */
+                       p_msg,&len, &bm);
+
+               return _reply_light(trans,buf,len,code,text,
+                                   0,0, /* no to-tag */
+                                   lock, &bm);
+       }
+       DBG("DEBUG: t_reply: buffer computed\n");
+}
+
 void set_final_timer( /* struct s_table *h_table, */ struct cell *t )
 {
        if ( !t->local 
                && t->uas.request->REQ_METHOD==METHOD_INVITE 
-               && t->uas.status>=300  ) {
+               && (t->uas.status>=300 || 
+                               (t->relaied_reply_branch==-2 && t->uas.status>=200) )) {
                        /* crank timers for negative replies */
                        start_retr( &t->uas.response );
        } else put_on_wait(t);
@@ -706,6 +785,8 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
        unsigned int res_len;
        int relayed_code;
        struct sip_msg *relayed_msg;
+       struct bookmark bm;
+       int totag_retr;
 #ifdef _TOTAG
        str     to_tag;
 #endif
@@ -718,6 +799,7 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
        buf=0;
        relayed_msg=0;
        relayed_code=0;
+       totag_retr=0;
 
 
        /* remember, what was sent upstream to know whether we are
@@ -747,12 +829,12 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
                   anyway 
         */
                if (msg_status<300 && branch==relay) {
-                       callback_event( TMCB_REPLY_IN, t, p_msg, msg_status );
+                       callback_event( TMCB_RESPONSE_FWDED, t, p_msg, msg_status );
                }
                /* try bulding the outbound reply from either the current
               or a stored message */
                relayed_msg = branch==relay ? p_msg :  t->uac[relay].reply;
-               if (relayed_msg ==FAKED_REPLY) {
+               if (relayed_msg==FAKED_REPLY) {
                        tm_stats->replied_localy++;
                        relayed_code = branch==relay
                                ? msg_status : t->uac[relay].last_received;
@@ -765,11 +847,11 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
                                                relayed_code,
                                                error_text(relayed_code),
                                                tm_tags, TOTAG_VALUE_LEN, 
-                                               t->uas.request, &res_len );
+                                               t->uas.request, &res_len, &bm );
                        } else {
                                buf = build_res_buf_from_sip_req( relayed_code,
                                        error_text(relayed_code), 0,0, /* no to-tag */
-                                       t->uas.request, &res_len );
+                                       t->uas.request, &res_len, &bm );
                        }
 
                } else {
@@ -804,6 +886,10 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
                }
                uas_rb->buffer_len = res_len;
                memcpy( uas_rb->buffer, buf, res_len );
+               if (relayed_msg==FAKED_REPLY) { /* to-tags for local replies */
+                       update_local_tags(t, &bm, uas_rb->buffer, buf);
+               }
+               tm_stats->replied_localy++;
 #ifdef _TOTAG
                /* to tag now */
                if (relayed_code>=300 && t->is_invite) {
@@ -828,6 +914,13 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
                /* update the status ... */
                t->uas.status = relayed_code;
                t->relaied_reply_branch = relay;
+
+               if (t->is_invite && relayed_msg!=FAKED_REPLY
+                               && relayed_code>=200 && relayed_code < 300
+                               && (callback_array[TMCB_RESPONSE_OUT] ||
+                                               callback_array[TMCB_E2EACK_IN]))  {
+                       totag_retr=update_totag_set(t, relayed_msg);
+               }
        }; /* if relay ... */
 
        UNLOCK_REPLIES( t );
@@ -837,7 +930,8 @@ enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
                SEND_PR_BUFFER( uas_rb, buf, res_len );
                DBG("DEBUG: reply relayed. buf=%p: %.9s..., shmem=%p: %.9s\n", 
                        buf, buf, uas_rb->buffer, uas_rb->buffer );
-               callback_event( TMCB_REPLY, t, relayed_msg, relayed_code );
+               if (!totag_retr) 
+                               callback_event( TMCB_RESPONSE_OUT, t, relayed_msg, relayed_code );
                pkg_free( buf );
        }
 
@@ -881,11 +975,13 @@ enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch,
        enum rps reply_status;
        struct sip_msg *winning_msg;
        int winning_code;
+       int totag_retr;
        /* branch_bm_t cancel_bitmap; */
 
        /* keep warning 'var might be used un-inited' silent */ 
        winning_msg=0;
        winning_code=0;
+       totag_retr=0;
 
        *cancel_bitmap=0;
 
@@ -909,13 +1005,23 @@ enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch,
                }
                t->uas.status = winning_code;
                update_reply_stats( winning_code );
+               if (t->is_invite && winning_msg!=FAKED_REPLY 
+                               && winning_code>=200 && winning_code <300
+                               && (callback_array[TMCB_RESPONSE_OUT] ||
+                                               callback_array[TMCB_E2EACK_IN]))  {
+                       totag_retr=update_totag_set(t, winning_msg);
+               }
+               
        }
        UNLOCK_REPLIES(t);
        if (local_winner>=0 && winning_code>=200 ) {
                DBG("DEBUG: local transaction completed\n");
-               callback_event( TMCB_LOCAL_COMPLETED, t, winning_msg, winning_code );
-               if (t->completion_cb) 
-                       t->completion_cb( t, winning_msg, winning_code, 0 /* empty param */);
+               if (!totag_retr) {
+                       callback_event( TMCB_LOCAL_COMPLETED, t, winning_msg, 
+                               winning_code );
+                       if (t->completion_cb) t->completion_cb( t, winning_msg, 
+                                               winning_code, 0 /* empty param */);
+               }
        }
        return reply_status;
 
@@ -1044,33 +1150,24 @@ done:
        return 0;
 }
 
-#ifdef VOICE_MAIL
 
-#include <assert.h>
 
-int t_reply_with_body( struct sip_msg* p_msg, unsigned int code, char * text, char * body, char * new_header, char * to_tag )
+int t_reply_with_body( struct cell *trans, unsigned int code, 
+               char * text, char * body, char * new_header, char * to_tag )
 {
-    struct cell * t;
-    //char to_tag[64];
+
     str  s_to_tag,sb,snh;
     char* res_buf;
-    int res_len,ret;
-
-    /*  check if we have a transaction */
-    if (t_check(p_msg, 0)==-1) {
-       LOG(L_ERR,"ERROR: t_reply_with_body: no transaction found.\n");
-       return -1;
-    }
-
-    t=get_t();
-    assert(t);
+    int res_len;
+       int ret;
+       struct bookmark bm;
 
     s_to_tag.s = to_tag;
     if(to_tag)
-       s_to_tag.len = strlen(to_tag);
+               s_to_tag.len = strlen(to_tag);
 
-    // mark the transaction as replied
-    set_kr(t,REQ_RPLD);
+    /* mark the transaction as replied */
+    if (code>=200) set_kr(REQ_RPLD);
 
     /* compute the response */
     sb.s = body;
@@ -1078,21 +1175,22 @@ int t_reply_with_body( struct sip_msg* p_msg, unsigned int code, char * text, ch
     snh.s = new_header;
     snh.len = strlen(new_header);
 
-    res_buf = build_res_buf_with_body_from_sip_req(code,text, s_to_tag.s, s_to_tag.len,
-                                                  sb.s,sb.len,
-                                                  snh.s,snh.len,
-                                                  p_msg,&res_len);
+    res_buf = build_res_buf_with_body_from_sip_req(
+                                       code,text, s_to_tag.s, s_to_tag.len,
+                                       sb.s,sb.len,
+                                       snh.s,snh.len,
+                                       trans->uas.request,&res_len, &bm);
     
     DBG("t_reply_with_body: buffer computed\n");
     // frees 'res_buf' ... no panic !
-    ret = t_reply_light(t, res_buf, res_len, code, text,
-                       s_to_tag.s, s_to_tag.len);
-
-    // TODO: i'm not sure i should do this here ...
-    if(t_unref(p_msg) == -1)
-       LOG(L_WARN,"WARNING: fifo_t_reply: could not unref transaction %p\n",t);
+    ret=_reply_light( trans, res_buf, res_len, code, text, 
+               s_to_tag.s, s_to_tag.len, 1 /* lock replies */, &bm );
+       /* this is ugly hack -- the function caller may wish to continue with
+        * transction and I unref; however, there is now only one use from
+        * vm/fifo_vm_reply and I'm currently to lazy to export UNREF; -jiri
+        */
+       UNREF(trans);
+       return ret;
 
-    return ret;
 }
 
-#endif
index 1b9676a..1b2ae44 100644 (file)
@@ -54,17 +54,17 @@ enum rps {
 enum route_mode { MODE_REQUEST=1, MODE_ONREPLY_REQUEST };
 extern enum route_mode rmode;
 
+/* has this to-tag been never seen in previous 200/INVs? */
+int unmatched_totag(struct cell *t, struct sip_msg *ack);
+
 /* branch bitmap type */
 typedef unsigned int branch_bm_t;
 
 /* reply export types */
-typedef int (*treply_f)( struct sip_msg* p_msg,
-       unsigned int code, char * text );
-#ifdef VOICE_MAIL
-typedef int (*treply_wb_f)( struct sip_msg* p_msg,
+typedef int (*treply_f)(struct sip_msg * , unsigned int , char * );
+typedef int (*treply_wb_f)( struct cell* trans,
        unsigned int code, char * text, char * body, 
        char * new_header, char * to_tag);
-#endif
 
 #define LOCK_REPLIES(_t) lock(&(_t)->reply_mutex )
 #define UNLOCK_REPLIES(_t) unlock(&(_t)->reply_mutex )
@@ -88,16 +88,16 @@ int t_retransmit_reply( /* struct sip_msg * */  );
  * Warning: 'buf' and 'len' should already have been build.
  * returns 1 if everything was OK or -1 for erro
  */
-#ifdef VOICE_MAIL
 
+#ifdef _OBSO
 int t_reply_light( struct cell *trans, char* buf, unsigned int len,
                   unsigned int code, char * text,
                   char *to_tag, unsigned int to_tag_len);
+#endif
 
-int t_reply_with_body( struct sip_msg* p_msg, unsigned int code, 
+int t_reply_with_body( struct cell *trans, unsigned int code, 
                       char * text, char * body, char * new_header, char * to_tag );
 
-#endif
 
 /* send a UAS reply
  * returns 1 if everything was OK or -1 for erro
index a1049e3..766a256 100644 (file)
@@ -336,7 +336,7 @@ inline static void final_response_handler( void *attr)
        if (r_buf->activ_type>0) {
 #              ifdef EXTRA_DEBUG
                if (t->uas.request->REQ_METHOD!=METHOD_INVITE
-                       || t->uas.status < 300 ) {
+                       || t->uas.status < 200 ) {
                        LOG(L_ERR, "ERROR: FR timer: uknown type reply buffer\n");
                        abort();
                }
index 788d6dd..87c4559 100644 (file)
@@ -158,12 +158,11 @@ struct module_exports exports= {
                                "register_tmcb",
                                T_UAC_DLG,
                                "load_tm",
-#ifdef VOICE_MAIL
                                T_REPLY_WB,
                                T_IS_LOCAL,
                                T_GET_TI,
                                T_LOOKUP_IDENT,
-#endif
+                               T_ADDBLIND,
                                "t_newdlg"
                        },
        (cmd_function[]){
@@ -189,12 +188,11 @@ struct module_exports exports= {
                                        (cmd_function) register_tmcb,
                                        (cmd_function) t_uac_dlg,
                                        (cmd_function) load_tm,
-#ifdef VOICE_MAIL
                                        (cmd_function) t_reply_with_body,
                                        (cmd_function) t_is_local,
                                        (cmd_function) t_get_trans_ident,
                                        (cmd_function) t_lookup_ident,
-#endif
+                                       (cmd_function) add_blind_uac,
                                        w_t_newdlg,
                                        },
        (int[]){
@@ -219,12 +217,11 @@ struct module_exports exports= {
                                NO_SCRIPT /* register_tmcb */,
                                NO_SCRIPT /* t_uac_dlg */,
                                NO_SCRIPT /* load_tm */,
-#ifdef VOICE_MAIL
                                NO_SCRIPT /* t_reply_with_body */,
                                NO_SCRIPT /* t_is_local */,
                                NO_SCRIPT /* t_get_trans_ident */,
                                NO_SCRIPT /* t_lookup_ident */,
-#endif
+                               NO_SCRIPT /* add_blind_uac */,
                                0 /* t_newdlg */
                        },
        (fixup_function[]){
@@ -249,19 +246,15 @@ struct module_exports exports= {
                                0,                                              /* register_tmcb */
                                0,                                              /* t_uac_dlg */
                                0,                                              /* load_tm */
-#ifdef VOICE_MAIL
                                0, /* t_reply_with_body */
                                0, /* t_is_local */
                                0, /* t_get_trans_ident */
                                0, /* t_lookup_ident */
-#endif
+                               0, /* add_blind_uac */
                                0                                               /* t_newdlg */
        
                },
-#ifdef VOICE_MAIL
-       4+
-#endif
-       14 + 8 /* *_(UDP|TCP) */,
+       5 /* voicemail */ + 14 + 8 /* *_(UDP|TCP) */,
 
        /* ------------ exported variables ---------- */
        (char *[]) { /* Module parameter names */
@@ -346,6 +339,9 @@ static int script_init( struct sip_msg *foo, void *bar)
        */
        t_on_negative( 0 );
 
+       /* reset the kr status */
+       set_kr(0);
+
        return 1;
 }
 
@@ -505,7 +501,11 @@ inline static int _w_t_forward_nonack(struct sip_msg* msg, char* proxy,
                                                                         char* _foo, int proto)
 {
        struct cell *t;
-       if (t_check( msg , 0 )==-1) return -1;
+       if (t_check( msg , 0 )==-1) {
+               LOG(L_ERR, "ERROR: forward_nonack: "
+                               "can't forward when no transaction was set up\n");
+               return -1;
+       }
        t=get_t();
        if ( t && t!=T_UNDEFINED ) {
                if (msg->REQ_METHOD==METHOD_ACK) {
index 08b86a9..f00ce8c 100644 (file)
@@ -57,7 +57,6 @@ int load_tm( struct tm_binds *tmb)
                LOG( L_ERR, LOAD_ERROR "'t_reply' not found\n");
                return -1;
        }
-#ifdef VOICE_MAIL
        if (!(tmb->t_reply_with_body=(treply_wb_f)find_export(T_REPLY_WB, NO_SCRIPT)) ) {
                LOG( L_ERR, LOAD_ERROR "'t_reply' not found\n");
                return -1;
@@ -74,7 +73,10 @@ int load_tm( struct tm_binds *tmb)
                LOG( L_ERR, LOAD_ERROR "'t_lookup_ident' not found\n");
                return -1;
        }
-#endif
+       if (!(tmb->t_addblind=(taddblind_f)find_export(T_ADDBLIND, NO_SCRIPT)) ) {
+               LOG( L_ERR, LOAD_ERROR "'addblind' not found\n");
+               return -1;
+       }
        if (!(tmb->t_forward_nonack=(tfwd_f)find_export(T_FORWARD_NONACK , 2)) ) {
                LOG( L_ERR, LOAD_ERROR "'t_forward_nonack' not found\n");
                return -1;
index 75e1150..610659d 100644 (file)
@@ -37,9 +37,7 @@
 #include "uac.h"
 #include "t_fwd.h"
 #include "t_reply.h"
-#ifdef VOICE_MAIL
-#    include "t_lookup.h"
-#endif
+#include "t_lookup.h"
 
 /* export not usable from scripts */
 #define NO_SCRIPT      -1
 #define T_RELAY_TCP "t_relay_tcp"
 #define T_UAC_DLG "t_uac_dlg"
 #define T_REPLY "t_reply"
-#ifdef VOICE_MAIL
 #define T_REPLY_WB "t_reply_with_body"
-#endif
+#define T_ADDBLIND "t_add_blind"
 #define T_REPLY_UNSAFE "t_reply_unsafe"
 #define T_FORWARD_NONACK "t_forward_nonack"
 #define T_FORWARD_NONACK_UDP "t_forward_nonack_udp"
 #define T_FORWARD_NONACK_TCP "t_forward_nonack_tcp"
+#define T_GET_TI       "t_get_trans_ident"
+#define T_LOOKUP_IDENT "t_lookup_ident"
+#define T_IS_LOCAL     "t_is_local"
+
 
 
 
@@ -66,14 +67,13 @@ struct tm_binds {
        register_tmcb_f register_tmcb;
        cmd_function    t_relay_to;
        cmd_function    t_relay;
-       tuacdlg_f               t_uac_dlg;
+       tuacdlg_f               t_uac_dlg;
        treply_f                t_reply;
-#ifdef VOICE_MAIL
-        treply_wb_f             t_reply_with_body;
-        tislocal_f              t_is_local;
-        tget_ti_f               t_get_trans_ident;
-        tlookup_ident_f         t_lookup_ident;
-#endif
+       treply_wb_f             t_reply_with_body;
+       tislocal_f              t_is_local;
+       tget_ti_f               t_get_trans_ident;
+       tlookup_ident_f t_lookup_ident;
+       taddblind_f             t_addblind;
        treply_f                t_reply_unsafe;
        tfwd_f                  t_forward_nonack;
 };
index 9649c78..7123cbc 100644 (file)
@@ -360,7 +360,7 @@ int t_uac_dlg(str* msg,                     /* Type of the message - MESSAGE, OP
 
        new_cell->is_invite = msg->len == INVITE_LEN && memcmp(msg->s, INVITE, INVITE_LEN) == 0;
        new_cell->local= 1 ;
-       set_kr(new_cell, REQ_FWDED);
+       set_kr(REQ_FWDED);
 
        request = &new_cell->uac[branch].request;
        request->dst.to = to_su;
index 026528a..e316c21 100644 (file)
@@ -829,19 +829,21 @@ error:
 
 char * build_res_buf_from_sip_req( unsigned int code, char *text,
                                        char *new_tag, unsigned int new_tag_len,
-                                       struct sip_msg* msg, unsigned int *returned_len)
+                                       struct sip_msg* msg, unsigned int *returned_len,
+                                       struct bookmark *bmark)
 {
     return build_res_buf_with_body_from_sip_req(code,text,new_tag,new_tag_len,
                                                0,0, /* no body */
                                                0,0, /* no content type */
-                                               msg,returned_len);
+                                               msg,returned_len, bmark);
 }
 
 char * build_res_buf_with_body_from_sip_req( unsigned int code, char *text ,
                                             char *new_tag, unsigned int new_tag_len ,
                                             char *body, unsigned int body_len,
                                             char *content_type, unsigned int content_type_len,
-                                            struct sip_msg* msg, unsigned int *returned_len)
+                                            struct sip_msg* msg, unsigned int *returned_len,
+                                                struct bookmark *bmark)
 {
        char              *buf, *p;
        unsigned int      len,foo;
@@ -862,6 +864,7 @@ char * build_res_buf_with_body_from_sip_req( unsigned int code, char *text ,
        char *content_len;
        char *after_body;
        str to_tag;
+       char *totags;
 
        received_buf=0;
        received_len=0;
@@ -1033,6 +1036,8 @@ char * build_res_buf_with_body_from_sip_req( unsigned int code, char *text ,
                                                /* before to-tag */
                                                append_str( p, hdr->name.s, to_tag.s-hdr->name.s);
                                                /* to tag replacement */
+                                               bmark->to_tag_val.s=p;
+                                               bmark->to_tag_val.len=new_tag_len;
                                                append_str( p, new_tag,new_tag_len);
                                                /* the rest after to-tag */
                                                append_str( p, to_tag.s+to_tag.len,
@@ -1041,12 +1046,20 @@ char * build_res_buf_with_body_from_sip_req( unsigned int code, char *text ,
                                                after_body=hdr->body.s+hdr->body.len;
                                                append_str( p, hdr->name.s, after_body-hdr->name.s);
                                                append_str(p, TOTAG_TOKEN, TOTAG_TOKEN_LEN);
+                                               bmark->to_tag_val.s=p;
+                                               bmark->to_tag_val.len=new_tag_len;
                                                append_str( p, new_tag,new_tag_len);
                                                append_str( p, after_body, 
                                                                                hdr->name.s+hdr->len-after_body);
                                        }
                                        break;
                                } /* no new to-tag -- proceed to 1:1 copying  */
+                               totags=((struct to_body*)(hdr->parsed))->tag_value.s;
+                               if (totags) {
+                                       bmark->to_tag_val.s=p+(totags-hdr->name.s);
+                                       bmark->to_tag_val.len=
+                                                       ((struct to_body*)(hdr->parsed))->tag_value.len;
+                               };
                        case HDR_FROM:
                        case HDR_CALLID:
                        case HDR_CSEQ:
index 09a23fd..092569e 100644 (file)
 #include "parser/msg_parser.h"
 #include "ip_addr.h"
 
+/* point to some remarkable positions in a SIP message */
+struct bookmark {
+       str to_tag_val;
+};
+
 char * build_req_buf_from_sip_req (    struct sip_msg* msg, 
                                unsigned int *returned_len, struct socket_info* send_sock,
                                int proto);
@@ -57,7 +62,8 @@ char * build_res_buf_from_sip_req(    unsigned int code ,
                                char *new_tag ,
                                unsigned int new_tag_len ,
                                struct sip_msg* msg,
-                               unsigned int *returned_len);
+                               unsigned int *returned_len,
+                               struct bookmark *bmark);
 char * build_res_buf_with_body_from_sip_req(   unsigned int code ,
                                char *text ,
                                char *new_tag ,
@@ -67,7 +73,8 @@ char * build_res_buf_with_body_from_sip_req(  unsigned int code ,
                                char *content_type,
                                unsigned int content_type_len,
                                struct sip_msg* msg,
-                               unsigned int *returned_len);
+                               unsigned int *returned_len,
+                               struct bookmark *bmark);
 
 char* via_builder( unsigned int *len,
        struct socket_info* send_sock,
index 58faed6..bf153fe 100644 (file)
@@ -56,7 +56,7 @@
 #define REPLY_CLASS(_reply) ((_reply)->REPLY_STATUS/100)
 
 /* number methods as power of two to allow bitmap matching */
-enum request_method { METHOD_INVITE=1, METHOD_CANCEL=2, METHOD_ACK=4, 
+enum request_method { METHOD_UNDEF=0, METHOD_INVITE=1, METHOD_CANCEL=2, METHOD_ACK=4, 
        METHOD_BYE=8, METHOD_OTHER=16 };