- patch from Miklos Tirpak <miklos@iptel.org>:
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Tue, 14 Nov 2006 18:11:06 +0000 (18:11 +0000)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Tue, 14 Nov 2006 18:11:06 +0000 (18:11 +0000)
   - tm minor fixes
   - tm dialog improvements
   - tm_binds extended (more function exported)

modules/tm/dlg.c
modules/tm/dlg.h
modules/tm/t_cancel.h
modules/tm/t_lookup.h
modules/tm/t_reply.c
modules/tm/t_reply.h
modules/tm/tm.c
modules/tm/tm_load.c
modules/tm/tm_load.h
modules/tm/uac.c
modules/tm/uac.h

index b1898c2..b6e59e4 100644 (file)
@@ -140,7 +140,9 @@ static inline int calculate_hooks(dlg_t* _d)
        } else {
                if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target;
                else _d->hooks.request_uri = &_d->rem_uri;
-               _d->hooks.next_hop = _d->hooks.request_uri;
+               
+               if (_d->dst_uri.s) _d->hooks.next_hop = &_d->dst_uri;
+               else _d->hooks.next_hop = _d->hooks.request_uri;
        }
 
        if ((_d->hooks.request_uri) && (_d->hooks.request_uri->s) && (_d->hooks.request_uri->len)) {
@@ -446,6 +448,11 @@ static inline int response2dlg(struct sip_msg* _m, dlg_t* _d)
                _d->rem_target.s = 0; 
                _d->rem_target.len = 0;
        }
+       if (_d->dst_uri.s) {
+               shm_free(_d->dst_uri.s);
+               _d->dst_uri.s = 0; 
+               _d->dst_uri.len = 0;
+       }
        if (contact.len && str_duplicate(&_d->rem_target, &contact) < 0) return -3;
        
        if (get_to_tag(_m, &rtag) < 0) goto err1;
@@ -601,8 +608,14 @@ static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m,
                if (get_contact_uri(_m, &contact) < 0) return -3;
                     /* If there is a contact URI */
                if (contact.len) {
-                            /* Free old remote target if any */
+                            /* Free old remote target and destination uri if any */
                        if (_d->rem_target.s) shm_free(_d->rem_target.s);
+                       if (_d->dst_uri.s) {
+                               shm_free(_d->dst_uri.s);
+                               _d->dst_uri.s = 0;
+                               _d->dst_uri.len = 0;
+                       }
+                               
                             /* Duplicate new remote target */
                        if (str_duplicate(&_d->rem_target, &contact) < 0) return -4;
                }
@@ -637,7 +650,7 @@ int dlg_response_uac(dlg_t* _d, struct sip_msg* _m,
                return dlg_confirmed_resp_uac(_d, _m, is_target_refresh);
 
        case DLG_DESTROYED:
-               LOG(L_ERR, "dlg_response_uac(): Cannot handle destroyed dialog\n");
+               LOG(L_DBG, "dlg_response_uac(): Cannot handle destroyed dialog\n");
                return -2;
        }
 
@@ -749,7 +762,15 @@ static inline int request2dlg(struct sip_msg* _m, dlg_t* _d)
        }
 
        if (get_contact_uri(_m, &contact) < 0) return -2;
-       if (contact.len && str_duplicate(&_d->rem_target, &contact) < 0) return -3;
+       if (contact.len) {
+               if (_d->rem_target.s) shm_free(_d->rem_target.s);
+               if (_d->dst_uri.s) {
+                       shm_free(_d->dst_uri.s);
+                       _d->dst_uri.s = 0;
+                       _d->dst_uri.len = 0;
+               }
+               if (str_duplicate(&_d->rem_target, &contact) < 0) return -3;
+       }
        
        if (get_from_tag(_m, &rtag) < 0) goto err1;
        if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1;
@@ -803,9 +824,8 @@ int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d)
                return -1;
        }
 
-       if ((_code < 200) || (_code > 299)) {
-               DBG("new_dlg_uas(): Not a 2xx, no dialog created\n");
-               return -2;
+       if (_code > 299) {
+               DBG("new_dlg_uas(): Status code >= 300, no dialog created\n");
        }
 
        res = (dlg_t*)shm_malloc(sizeof(dlg_t));
@@ -822,17 +842,25 @@ int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d)
                return -4;
        }
 
-       tag.s = tm_tags;
-       tag.len = TOTAG_VALUE_LEN;
-       calc_crc_suffix(_req, tm_tag_suffix);
-       if (str_duplicate(&res->id.loc_tag, &tag) < 0) {
-               free_dlg(res);
-               return -5;
+       if (_code > 100) {
+               tag.s = tm_tags;
+               tag.len = TOTAG_VALUE_LEN;
+               calc_crc_suffix(_req, tm_tag_suffix);
+               if (str_duplicate(&res->id.loc_tag, &tag) < 0) {
+                       free_dlg(res);
+                       return -5;
+               }
        }
        
        *_d = res;
 
-       (*_d)->state = DLG_CONFIRMED;
+       if (_code < 100)
+               (*_d)->state = DLG_NEW;
+       else if (_code < 200)
+               (*_d)->state = DLG_EARLY;
+       else
+               (*_d)->state = DLG_CONFIRMED;
+
        if (calculate_hooks(*_d) < 0) {
                LOG(L_ERR, "new_dlg_uas(): Error while calculating hooks\n");
                free_dlg(res);
@@ -842,6 +870,46 @@ int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d)
        return 0;
 }
 
+/*
+ * UAS side - update dialog state and to tag
+ */
+int update_dlg_uas(dlg_t *_d, int _code, str* _tag)
+{
+       if (_d->state == DLG_CONFIRMED) {
+               LOG(L_ERR, "update_dlg_uas(): Dialog is already confirmed\n");
+               return -1;
+       } else if (_d->state == DLG_DESTROYED) {
+               LOG(L_ERR, "update_dlg_uas(): Dialog is already destroyed\n");
+               return -2;
+       }
+
+       if (_tag && _tag->s) {
+               if (_d->id.loc_tag.s) {
+                       if ((_tag->len == _d->id.loc_tag.len)
+                       && (!memcmp(_tag->s, _d->id.loc_tag.s, _tag->len))) {
+                               LOG(L_DBG, "update_dlg_uas(): Local tag is already set\n");
+                       } else {
+                               LOG(L_ERR, "update_dlg_uas(): ERROR: trying to rewrite local tag\n");
+                               return -3;
+                       }
+               } else {
+                       if (str_duplicate(&_d->id.loc_tag, _tag) < 0) {
+                               LOG(L_ERR, "update_dlg_uas(): Not enough memory\n");
+                               return -4;
+                       }
+               }
+       }
+
+       if ((100 < _code) && (_code < 200))
+               _d->state = DLG_EARLY;
+       else if (_code < 300)
+               _d->state = DLG_CONFIRMED;
+       else
+               _d->state = DLG_DESTROYED;
+
+       return 0;
+}
+
 /*
  * UAS side - update a dialog from a request
  */
@@ -881,6 +949,11 @@ int dlg_request_uas(dlg_t* _d, struct sip_msg* _m, target_refresh_t is_target_re
                if (get_contact_uri(_m, &contact) < 0) return -5;
                if (contact.len) {
                        if (_d->rem_target.s) shm_free(_d->rem_target.s);
+                       if (_d->dst_uri.s) {
+                               shm_free(_d->dst_uri.s);
+                               _d->dst_uri.s = 0;
+                               _d->dst_uri.len = 0;
+                       }
                        if (str_duplicate(&_d->rem_target, &contact) < 0) return -6;
                }
 
@@ -985,6 +1058,7 @@ void free_dlg(dlg_t* _d)
        if (_d->loc_uri.s) shm_free(_d->loc_uri.s);
        if (_d->rem_uri.s) shm_free(_d->rem_uri.s);
        if (_d->rem_target.s) shm_free(_d->rem_target.s);
+       if (_d->dst_uri.s) shm_free(_d->dst_uri.s);
 
             /* Free all routes in the route set */
        shm_free_rr(&_d->route_set);
@@ -1008,6 +1082,7 @@ void print_dlg(FILE* out, dlg_t* _d)
        fprintf(out, "loc_uri       : '%.*s'\n", _d->loc_uri.len, _d->loc_uri.s);
        fprintf(out, "rem_uri       : '%.*s'\n", _d->rem_uri.len, _d->rem_uri.s);
        fprintf(out, "rem_target    : '%.*s'\n", _d->rem_target.len, _d->rem_target.s);
+       fprintf(out, "dst_uri       : '%.*s'\n", _d->dst_uri.len, _d->dst_uri.s);
        fprintf(out, "secure:       : %d\n", _d->secure);
        fprintf(out, "state         : ");
        switch(_d->state) {
@@ -1028,3 +1103,33 @@ void print_dlg(FILE* out, dlg_t* _d)
        
        fprintf(out, "====dlg_t====\n");
 }
+
+/*
+ * set dialog's request uri and destination uri (optional)
+ */
+int set_dlg_target(dlg_t* _d, str* _ruri, str* _duri) {
+
+       if (!_d || !_ruri) {
+               LOG(L_ERR, "set_dlg_target(): Invalid parameter value\n");
+               return -1;
+       }
+
+       if (_d->rem_target.s) shm_free(_d->rem_target.s);
+       if (_d->dst_uri.s) {
+               shm_free(_d->dst_uri.s);
+               _d->dst_uri.s = 0;
+               _d->dst_uri.len = 0;
+       }
+
+       if (str_duplicate(&_d->rem_target, _ruri)) return -1;
+       if (_duri && _duri->len) {
+               if (str_duplicate(&_d->dst_uri, _duri)) return -1;
+       }
+
+       if (calculate_hooks(_d)) {
+               LOG(L_ERR, "set_dlg_target(): Error while calculating hooks\n");
+               return -1;
+       }
+
+       return 0;
+}
index d9099fd..1c8af59 100644 (file)
@@ -96,6 +96,7 @@ typedef struct dlg {
        str loc_uri;            /* Local URI */
        str rem_uri;            /* Remote URI */
        str rem_target;         /* Remote target URI */
+       str dst_uri;            /* Destination URI */
        unsigned char secure;   /* Secure flag -- currently not used */
        dlg_state_t state;      /* State of the dialog */
        rr_t* route_set;        /* Route set */
@@ -130,6 +131,11 @@ typedef int (*dlg_response_uac_f)(dlg_t* _d, struct sip_msg* _m, target_refresh_
 int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d);
 typedef int (*new_dlg_uas_f)(struct sip_msg* _req, int _code, dlg_t** _d);
 
+/*
+ * UAS side - update dialog state and to tag
+ */
+int update_dlg_uas(dlg_t *_d, int _code, str* _tag);
+typedef int (*update_dlg_uas_f)(dlg_t *_d, int _code, str* _tag);
 
 /*
  * UAS side - update a dialog from a request
@@ -171,4 +177,10 @@ char* print_routeset(char* buf, dlg_t* _d);
 int w_calculate_hooks(dlg_t* _d);
 typedef int (*calculate_hooks_f)(dlg_t* _d);
 
+/*
+ * set dialog's request uri and destination uri (optional)
+ */
+int set_dlg_target(dlg_t* _d, str* _ruri, str* _duri);
+typedef int (*set_dlg_target_f)(dlg_t* _d, str* _ruri, str* _duri);
+
 #endif /* DLG_H */
index ba8300a..0807ef9 100644 (file)
@@ -67,6 +67,9 @@ void which_cancel( struct cell *t, branch_bm_t *cancel_bm );
 int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags );
 int cancel_branch( struct cell *t, int branch, int flags );
 
+typedef int(*cancel_uacs_f)( struct cell *t, branch_bm_t cancel_bm,
+                                                               int flags );
+
 
 
 /* should be called either with the REPLY_LOCK held or if its known
index e9e92b1..fd1ed4e 100644 (file)
@@ -66,6 +66,7 @@ int add_branch_label( struct cell *trans,
 
 /* releases T-context */
 int t_unref( struct sip_msg *p_msg);
+typedef int (*tunref_f)( struct sip_msg *p_msg);
 
 /* function returns:
  *      -1 - transaction wasn't found
@@ -89,6 +90,7 @@ typedef int (*tislocal_f)(struct sip_msg*);
 typedef int (*tnewtran_f)(struct sip_msg*);
 typedef int (*tget_ti_f)(struct sip_msg*, unsigned int*, unsigned int*);
 typedef int (*tlookup_ident_f)(struct cell**, unsigned int, unsigned int);
+typedef int (*trelease_f)(struct sip_msg*);
 
 int t_is_local(struct sip_msg*);
 int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned int* label);
index d2ade06..6b23e79 100644 (file)
@@ -676,8 +676,8 @@ void inline static free_faked_req(struct sip_msg *faked_req, struct cell *t)
 
 
 /* return 1 if a failure_route processes */
-static inline int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
-                                                                                       int code, int extra_flags)
+int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
+                                       int code, int extra_flags)
 {
        static struct sip_msg faked_req;
        struct sip_msg *shmem_msg = t->uas.request;
@@ -1740,6 +1740,8 @@ int t_reply_with_body( struct cell *trans, unsigned int code,
        s_to_tag.s = to_tag;
        if(to_tag)
                s_to_tag.len = strlen(to_tag);
+       else
+               s_to_tag.len = 0;
 
        /* mark the transaction as replied */
        if (code>=200) set_kr(REQ_RPLD);
index 0a7deea..aa73de4 100644 (file)
@@ -87,6 +87,11 @@ int w_t_reply_wrp(struct sip_msg *m, unsigned int code, char *txt);
  */
 int reply_received( struct sip_msg  *p_msg ) ;
 
+/* return 1 if a failure_route processes */
+int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
+                                       int code, int extra_flags);
+typedef int (*run_failure_handlers_f)(struct cell*, struct sip_msg*, int, int);
+
 
 /* Retransmits the last sent inbound reply.
  * Returns  -1 - error
index 6def098..90f345e 100644 (file)
 #include "t_cancel.h"
 #include "t_fifo.h"
 #include "timer.h"
+#include "t_msgbuilder.h"
 
 MODULE_VERSION
 
@@ -296,12 +297,18 @@ static cmd_export_t cmds[]={
        {"new_dlg_uac",        (cmd_function)new_dlg_uac,       NO_SCRIPT,   0, 0},
        {"dlg_response_uac",   (cmd_function)dlg_response_uac,  NO_SCRIPT,   0, 0},
        {"new_dlg_uas",        (cmd_function)new_dlg_uas,       NO_SCRIPT,   0, 0},
+       {"update_dlg_uas",     (cmd_function)update_dlg_uas,    NO_SCRIPT,   0, 0},
        {"dlg_request_uas",    (cmd_function)dlg_request_uas,   NO_SCRIPT,   0, 0},
+       {"set_dlg_target",     (cmd_function)set_dlg_target,    NO_SCRIPT,   0, 0},
        {"free_dlg",           (cmd_function)free_dlg,          NO_SCRIPT,   0, 0},
        {"print_dlg",          (cmd_function)print_dlg,         NO_SCRIPT,   0, 0},
        {T_GETT,               (cmd_function)get_t,             NO_SCRIPT,   0, 0},
        {"calculate_hooks",    (cmd_function)w_calculate_hooks, NO_SCRIPT,   0, 0},
        {"t_uac",              (cmd_function)t_uac,             NO_SCRIPT,   0, 0},
+       {"t_uac_with_ids",     (cmd_function)t_uac_with_ids,    NO_SCRIPT,   0, 0},
+       {"t_unref",            (cmd_function)t_unref,           NO_SCRIPT,   0, 0},
+       {"run_failure_handlers", (cmd_function)run_failure_handlers, NO_SCRIPT,   0, 0},
+       {"cancel_uacs",        (cmd_function)cancel_uacs,       NO_SCRIPT,   0, 0},
        {0,0,0,0,0}
 };
 
@@ -664,8 +671,10 @@ inline static int w_t_lookup_cancel(struct sip_msg* msg, char* str, char* str2)
                        /* The cell is reffed by t_lookupOriginalT, but T is not set.
                        So we must unref it before returning. */
                        UNREF(ret);
+                       set_t(T_UNDEFINED);
                        return 1;
                }
+               set_t(T_UNDEFINED);
        } else {
                LOG(L_WARN, "WARNING: script error t_lookup_cancel() called for non-CANCEL request\n");
        }
@@ -896,10 +905,15 @@ inline static int w_t_reply(struct sip_msg* msg, char* p1, char* p2)
 inline static int w_t_release(struct sip_msg* msg, char* str, char* str2)
 {
        struct cell *t;
+       int ret;
+       
        if (t_check( msg  , 0  )==-1) return -1;
        t=get_t();
-       if ( t && t!=T_UNDEFINED )
-               return t_release_transaction( t );
+       if ( t && t!=T_UNDEFINED ) {
+               ret = t_release_transaction( t );
+               t_unref(msg);
+               return ret;
+       }
        return 1;
 }
 
index c516452..aba13d7 100644 (file)
@@ -133,11 +133,21 @@ int load_tm( struct tm_binds *tmb)
                LOG( L_ERR, LOAD_ERROR "'new_dlg_uas' not found\n");
                return -1;
        }
+       if (!(tmb->update_dlg_uas=(update_dlg_uas_f)find_export
+       ("update_dlg_uas", NO_SCRIPT, 0)) ) {
+               LOG( L_ERR, LOAD_ERROR "'update_dlg_uas' not found\n");
+               return -1;
+       }
        if (!(tmb->dlg_request_uas=(dlg_request_uas_f)find_export
        ("dlg_request_uas", NO_SCRIPT, 0)) ) {
                LOG( L_ERR, LOAD_ERROR "'dlg_request_uas' not found\n");
                return -1;
        }
+       if (!(tmb->set_dlg_target=(set_dlg_target_f)find_export
+       ("set_dlg_target", NO_SCRIPT, 0)) ) {
+               LOG( L_ERR, LOAD_ERROR "'set_dlg_target' not found\n");
+               return -1;
+       }
        if (!(tmb->free_dlg=(free_dlg_f)find_export("free_dlg", NO_SCRIPT, 0)) ) {
                LOG( L_ERR, LOAD_ERROR "'free_dlg' not found\n");
                return -1;
@@ -158,6 +168,28 @@ int load_tm( struct tm_binds *tmb)
                LOG( L_ERR, LOAD_ERROR "'t_uac' not found\n");
                return -1;
        }
+       if (!(tmb->t_uac_with_ids=(t_uac_with_ids_t)find_export("t_uac_with_ids", NO_SCRIPT, 0)) ) {
+               LOG( L_ERR, LOAD_ERROR "'t_uac_with_ids' not found\n");
+               return -1;
+       }
+       if (!(tmb->t_release=(trelease_f)find_export("t_release",0,0))) {
+               LOG( L_ERR, LOAD_ERROR "'t_release' not found\n");
+               return -1;
+       }
+       if (!(tmb->t_unref=(tunref_f)find_export("t_unref",NO_SCRIPT,0))) {
+               LOG( L_ERR, LOAD_ERROR "'t_unref' not found\n");
+               return -1;
+       }
+       if (!(tmb->run_failure_handlers=
+           (run_failure_handlers_f)find_export("run_failure_handlers",NO_SCRIPT,0))) {
+               LOG( L_ERR, LOAD_ERROR "'run_failure_handlers' not found\n");
+               return -1;
+       }
+       if (!(tmb->cancel_uacs=(cancel_uacs_f)find_export("cancel_uacs",NO_SCRIPT,0))) {
+               LOG( L_ERR, LOAD_ERROR "'cancel_uacs' not found\n");
+               return -1;
+       }
+
        tmb->prepare_request_within = prepare_req_within;
        tmb->send_prepared_request = send_prepared_request;
        
index 5870f4f..40d3780 100644 (file)
@@ -46,6 +46,7 @@
 #include "t_lookup.h"
 #include "t_reply.h"
 #include "dlg.h"
+#include "t_cancel.h"
 
 /* export not usable from scripts */
 #define NO_SCRIPT      -1
@@ -94,12 +95,19 @@ struct tm_binds {
        new_dlg_uac_f      new_dlg_uac;
        dlg_response_uac_f dlg_response_uac;
        new_dlg_uas_f      new_dlg_uas;
+       update_dlg_uas_f   update_dlg_uas;
        dlg_request_uas_f  dlg_request_uas;
+       set_dlg_target_f   set_dlg_target;
        free_dlg_f         free_dlg;
        print_dlg_f        print_dlg;
        tgett_f            t_gett;
        calculate_hooks_f  calculate_hooks;
        t_uac_t            t_uac;
+       t_uac_with_ids_t   t_uac_with_ids;
+       trelease_f         t_release;
+       tunref_f           t_unref;
+       run_failure_handlers_f run_failure_handlers;
+       cancel_uacs_f      cancel_uacs;
        prepare_request_within_f  prepare_request_within;
        send_prepared_request_f   send_prepared_request;
        enum route_mode*   route_mode;
index f81de9f..fb40b12 100644 (file)
@@ -165,8 +165,9 @@ static inline unsigned int dlg2hash( dlg_t* dlg )
        return hashid;
 }
 
-static inline int t_uac_prepare(str* method, str* headers, str* body, dlg_t* dialog,
-         transaction_cb cb, void* cbp, struct retr_buf **dst_req)
+static inline int t_uac_prepare(str* method, str* headers, str* body, 
+               dlg_t* dialog, transaction_cb cb, void* cbp, struct retr_buf **dst_req,
+               struct cell **dst_cell)
 {
        struct dest_info dst;
        struct cell *new_cell;
@@ -174,19 +175,29 @@ static inline int t_uac_prepare(str* method, str* headers, str* body, dlg_t* dia
        char* buf;
         int buf_len, ret, flags;
        unsigned int hi;
+       int is_ack;
 #ifdef USE_DNS_FAILOVER
        struct dns_srv_handle dns_h;
 #endif
 
        ret=-1;
+       hi=0; /* make gcc happy */
        /*if (dst_req) *dst_req = NULL;*/
+       is_ack = (((method->len == 3) && (memcmp("ACK", method->s, 3)==0)) ? 1 : 0);
        
        /*** added by dcm 
         * - needed by external ua to send a request within a dlg
         */
-       if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0)
+       if (w_calculate_hooks(dialog)<0 && !dialog->hooks.next_hop)
                goto error2;
 
+       if (!dialog->loc_seq.is_set) {
+               /* this is the first request in the dialog,
+               set cseq to default value now - Miklos */
+               dialog->loc_seq.value = DEFAULT_CSEQ;
+               dialog->loc_seq.is_set = 1;
+       }
+
        DBG("DEBUG:tm:t_uac: next_hop=<%.*s>\n",dialog->hooks.next_hop->len,
                        dialog->hooks.next_hop->s);
        /* it's a new message, so we will take the default socket */
@@ -260,10 +271,12 @@ static inline int t_uac_prepare(str* method, str* headers, str* body, dlg_t* dia
        
        request->dst = dst;
 
-       hi=dlg2hash(dialog);
-       LOCK_HASH(hi);
-       insert_into_hash_table_unsafe(new_cell, hi);
-       UNLOCK_HASH(hi);
+       if (!is_ack) {
+               hi=dlg2hash(dialog);
+               LOCK_HASH(hi);
+               insert_into_hash_table_unsafe(new_cell, hi);
+               UNLOCK_HASH(hi);
+       }
 
        buf = build_uac_req(method, headers, body, dialog, 0, new_cell,
                &buf_len, &dst);
@@ -281,13 +294,16 @@ static inline int t_uac_prepare(str* method, str* headers, str* body, dlg_t* dia
        new_cell->nr_of_outgoings++;
        
        if (dst_req) *dst_req = request;
+       if (dst_cell) *dst_cell = new_cell;
        
        return 1;
 
  error1:
-       LOCK_HASH(hi);
-       remove_from_hash_table_unsafe(new_cell);
-       UNLOCK_HASH(hi);
+       if (!is_ack) {
+               LOCK_HASH(hi);
+               remove_from_hash_table_unsafe(new_cell);
+               UNLOCK_HASH(hi);
+       }
        free_cell(new_cell);
 error2:
        return ret;
@@ -314,7 +330,7 @@ int prepare_req_within(str* method, str* headers,
        if ((method->len == 6) && (!memcmp("CANCEL", method->s, 6))) goto send;
        dialog->loc_seq.value++; /* Increment CSeq */
  send:
-       return t_uac_prepare(method, headers, body, dialog, completion_cb, cbp, dst_req);
+       return t_uac_prepare(method, headers, body, dialog, completion_cb, cbp, dst_req, 0);
 
  err:
        /* if (cbp) shm_free(cbp); */
@@ -323,19 +339,19 @@ int prepare_req_within(str* method, str* headers,
        return -1;
 }
 
-static inline void send_prepared_request_impl(struct retr_buf *request)
+static inline void send_prepared_request_impl(struct retr_buf *request, int retransmit)
 {
        if (SEND_BUFFER(request) == -1) {
                LOG(L_ERR, "t_uac: Attempt to send to precreated request failed\n");
        }
        
-       if (start_retr(request)!=0)
+       if (retransmit && (start_retr(request)!=0))
                LOG(L_CRIT, "BUG: t_uac: failed to start retr. for %p\n", request);
 }
 
 void send_prepared_request(struct retr_buf *request)
 {
-       send_prepared_request_impl(request);
+       send_prepared_request_impl(request, 1 /* retransmit */);
 }
 
 /*
@@ -345,14 +361,48 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
          transaction_cb cb, void* cbp)
 {
        struct retr_buf *request;
+       struct cell *cell;
        int ret;
+       int is_ack;
 
-       ret = t_uac_prepare(method, headers, body, dialog, cb, cbp, &request);
+       ret = t_uac_prepare(method, headers, body, dialog, cb, cbp, &request, &cell);
        if (ret < 0) return ret;
-       send_prepared_request_impl(request);
+       is_ack = (method->len == 3) && (memcmp("ACK", method->s, 3)==0) ? 1 : 0;
+       send_prepared_request_impl(request, !is_ack /* retransmit */);
+       if (cell && is_ack)
+               free_cell(cell);
        return ret;
 }
 
+/*
+ * Send a request using data from the dialog structure
+ * ret_index and ret_label will identify the new cell
+ */
+int t_uac_with_ids(str* method, str* headers, str* body, dlg_t* dialog,
+       transaction_cb cb, void* cbp,
+       unsigned int *ret_index, unsigned int *ret_label)
+{
+       struct retr_buf *request;
+       struct cell *cell;
+       int ret;
+       int is_ack;
+
+       ret = t_uac_prepare(method, headers, body, dialog, cb, cbp, &request, &cell);
+       if (ret < 0) return ret;
+       is_ack = (method->len == 3) && (memcmp("ACK", method->s, 3)==0) ? 1 : 0;
+       send_prepared_request_impl(request, !is_ack /* retransmit */);
+       if (is_ack) {
+               if (cell) free_cell(cell);
+               if (ret_index && ret_label)
+                       *ret_index = *ret_label = 0;
+       } else {
+               if (ret_index && ret_label) {
+                       *ret_index = cell->hash_index;
+                       *ret_label = cell->label;
+               }
+       }
+       return ret;
+}
 
 /*
  * Send a message within a dialog
@@ -364,11 +414,6 @@ int req_within(str* method, str* headers, str* body, dlg_t* dialog, transaction_
                goto err;
        }
 
-       if (dialog->state != DLG_CONFIRMED) {
-               LOG(L_ERR, "req_within: Dialog is not confirmed yet\n");
-               goto err;
-       }
-
        if ((method->len == 3) && (!memcmp("ACK", method->s, 3))) goto send;
        if ((method->len == 6) && (!memcmp("CANCEL", method->s, 6))) goto send;
        dialog->loc_seq.value++; /* Increment CSeq */
index b503203..5975abe 100644 (file)
@@ -51,6 +51,8 @@ typedef int (*reqwith_t)(str* m, str* h, str* b, dlg_t* d, transaction_cb c, voi
 typedef int (*reqout_t)(str* m, str* t, str* f, str* h, str* b, dlg_t** d, transaction_cb c, void* cp);
 typedef int (*req_t)(str* m, str* ruri, str* t, str* f, str* h, str* b, str *next_hop, transaction_cb c, void* cp);
 typedef int (*t_uac_t)(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp);
+typedef int (*t_uac_with_ids_t)(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp,
+               unsigned int *ret_index, unsigned int *ret_label);
 typedef int (*prepare_request_within_f)(str* method, str* headers, 
                str* body, dlg_t* dialog, transaction_cb cb, void* cbp,
                struct retr_buf **request_dst);
@@ -74,7 +76,12 @@ int uac_init(void);
  */
 int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp);
 
-
+/*
+ * Send a request
+ * ret_index and ret_label will identify the new cell
+ */
+int t_uac_with_ids(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp,
+                       unsigned int *ret_index, unsigned int *ret_label);
 /*
  * Send a message within a dialog
  */