Browse Source

- patch from Miklos Tirpak <[email protected]>:
- tm minor fixes
- tm dialog improvements
- tm_binds extended (more function exported)

Andrei Pelinescu-Onciul 19 years ago
parent
commit
04436036cf
11 changed files with 275 additions and 40 deletions
  1. 119 14
      modules/tm/dlg.c
  2. 12 0
      modules/tm/dlg.h
  3. 3 0
      modules/tm/t_cancel.h
  4. 2 0
      modules/tm/t_lookup.h
  5. 4 2
      modules/tm/t_reply.c
  6. 5 0
      modules/tm/t_reply.h
  7. 16 2
      modules/tm/tm.c
  8. 32 0
      modules/tm/tm_load.c
  9. 8 0
      modules/tm/tm_load.h
  10. 66 21
      modules/tm/uac.c
  11. 8 1
      modules/tm/uac.h

+ 119 - 14
modules/tm/dlg.c

@@ -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;
+}

+ 12 - 0
modules/tm/dlg.h

@@ -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 */

+ 3 - 0
modules/tm/t_cancel.h

@@ -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

+ 2 - 0
modules/tm/t_lookup.h

@@ -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);

+ 4 - 2
modules/tm/t_reply.c

@@ -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);

+ 5 - 0
modules/tm/t_reply.h

@@ -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

+ 16 - 2
modules/tm/tm.c

@@ -114,6 +114,7 @@
 #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;
 }
 

+ 32 - 0
modules/tm/tm_load.c

@@ -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;
 	

+ 8 - 0
modules/tm/tm_load.h

@@ -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;

+ 66 - 21
modules/tm/uac.c

@@ -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 */

+ 8 - 1
modules/tm/uac.h

@@ -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
  */