Przeglądaj źródła

- dialog support added
- new functions for sending messages within and outside a dialog
- bugfixes
- neverending fifo functions split in smaller pieces

Jan Janak 22 lat temu
rodzic
commit
c5867ab303

+ 1 - 1
modules/tm/Makefile

@@ -7,6 +7,6 @@
 
 auto_gen=
 NAME=tm.so
-LIBS= 
+LIBS=
 
 include ../../Makefile.modules

+ 3 - 0
modules/tm/config.h

@@ -92,4 +92,7 @@
 /* to-tag separator for stateful processing */
 #define TM_TAG_SEPARATOR '-'
 
+/* FIFO substitution character */
+#define SUBST_CHAR '!'
+
 #endif

+ 68 - 20
modules/tm/dlg.c

@@ -41,6 +41,8 @@
 #include "../../ut.h"
 #include "../../config.h"
 #include "dlg.h"
+#include "t_reply.h"
+#include "../../parser/parser_f.h"
 
 
 #define NORMAL_ORDER 0  /* Create route set in normal order - UAS */
@@ -53,6 +55,31 @@
 #define ROUTE_SEPARATOR_LEN (sizeof(ROUTE_SEPARATOR) - 1)
 
 
+/*** Temporary hack ! */
+/*
+ * This function skips name part
+ * uri parsed by parse_contact must be used
+ * (the uri must not contain any leading or
+ *  trailing part and if angle bracket were
+ *  used, right angle bracket must be the
+ *  last character in the string)
+ *
+ * _s will be modified so it should be a tmp
+ * copy
+ */
+void get_raw_uri(str* _s)
+{
+        char* aq;
+        
+        if (_s->s[_s->len - 1] == '>') {
+                aq = find_not_quoted(_s, '<');
+                _s->len -= aq - _s->s + 2;
+                _s->s = aq + 1;
+        }
+}
+
+
+
 /*
  * Make a copy of a str structure using shm_malloc
  */
@@ -110,6 +137,19 @@ static inline int calculate_hooks(dlg_t* _d)
 		_d->hooks.next_hop = _d->hooks.request_uri;
 	}
 
+	if ((_d->hooks.request_uri) && (_d->hooks.request_uri->s) && (_d->hooks.request_uri->len)) {
+		_d->hooks.ru.s = _d->hooks.request_uri->s;
+		_d->hooks.ru.len = _d->hooks.request_uri->len;
+		_d->hooks.request_uri = &_d->hooks.ru;
+		get_raw_uri(_d->hooks.request_uri);
+	}
+	if ((_d->hooks.next_hop) && (_d->hooks.next_hop->s) && (_d->hooks.next_hop->len)) {
+		_d->hooks.nh.s = _d->hooks.next_hop->s;
+		_d->hooks.nh.len = _d->hooks.next_hop->len;
+		_d->hooks.next_hop = &_d->hooks.nh;
+		get_raw_uri(_d->hooks.next_hop);
+	}
+
 	return 0;
 }
 
@@ -275,7 +315,6 @@ static inline int get_route_set(struct sip_msg* _m, rr_t** _rs, unsigned char _o
 					LOG(L_ERR, "get_route_set(): Error while duplicating rr_t\n");
 					goto error;
 				}
-				
 				if (_order == NORMAL_ORDER) {
 					if (!*_rs) *_rs = t;
 					if (last) last->next = t;
@@ -310,7 +349,7 @@ static inline int response2dlg(struct sip_msg* _m, dlg_t* _d)
 
 	     /* Parse the whole message, we will need all Record-Route headers */
 	if (parse_headers(_m, HDR_EOH, 0) == -1) {
-		LOG(L_ERR, "dlg_new_resp_uac(): Error while parsing headers\n");
+		LOG(L_ERR, "response2dlg(): Error while parsing headers\n");
 		return -1;
 	}
 	
@@ -558,7 +597,7 @@ static inline int get_cseq_value(struct sip_msg* _m, unsigned int* _cs)
  */
 static inline int get_dlg_uri(struct hdr_field* _h, str* _s)
 {
-	struct to_param* ptr;
+	struct to_param* ptr, *prev;
 	struct to_body* body;
 	char* tag = 0; /* Makes gcc happy */
 	int tag_len = 0, len;
@@ -575,35 +614,42 @@ static inline int get_dlg_uri(struct hdr_field* _h, str* _s)
 	body = (struct to_body*)_h->parsed;
 
 	ptr = body->param_lst;
+	prev = 0;
 	while(ptr) {
 		if (ptr->type == TAG_PARAM) break;
+		prev = ptr;
 		ptr = ptr->next;
 	}
 
 	if (ptr) {
-	     /* Tag param found */
-		tag = ptr->name.s;
+		     /* Tag param found */
+		if (prev) {
+			tag = prev->value.s + prev->value.len;
+		} else {
+			tag = body->body.s + body->body.len;
+		}
+		
 		if (ptr->next) {
 			tag_len = ptr->next->name.s - tag;
 		} else {
-			tag_len = body->body.s + body->body.len - tag;
+			tag_len = _h->body.s + _h->body.len - tag;
 		}
 	}
 
-	_s->s = shm_malloc(body->body.len - tag_len);
+	_s->s = shm_malloc(_h->body.len - tag_len);
 	if (!_s->s) {
 		LOG(L_ERR, "get_dlg_uri(): No memory left\n");
 		return -1;
 	}
 
 	if (tag_len) {
-		len = tag - body->body.s;
-		memcpy(_s->s, body->body.s, len);
-		memcpy(_s->s + len, tag + tag_len, body->body.len - len - tag_len);
-		_s->len = body->body.len - tag_len;
+		len = tag - _h->body.s;
+		memcpy(_s->s, _h->body.s, len);
+		memcpy(_s->s + len, tag + tag_len, _h->body.len - len - tag_len);
+		_s->len = _h->body.len - tag_len;
 	} else {
-		memcpy(_s->s, body->body.s, body->body.len);
-		_s->len = body->body.len;
+		memcpy(_s->s, _h->body.s, _h->body.len);
+		_s->len = _h->body.len;
 	}
 
 	return 0;
@@ -668,11 +714,12 @@ static inline int request2dlg(struct sip_msg* _m, dlg_t* _d)
 /*
  * Establishing a new dialog, UAS side
  */
-int new_dlg_uas(struct sip_msg* _req, int _code, str* _tag, dlg_t** _d)
+int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d)
 {
 	dlg_t* res;
+	str tag;
 
-	if (!_req || !_tag || !_d) {
+	if (!_req || /*!_tag ||*/ !_d) {
 		LOG(L_ERR, "new_dlg_uas(): Invalid parameter value\n");
 		return -1;
 	}
@@ -695,11 +742,12 @@ int new_dlg_uas(struct sip_msg* _req, int _code, str* _tag, dlg_t** _d)
 		return -4;
 	}
 
-	if (_tag->len) {
-		if (str_duplicate(&res->id.loc_tag, _tag) < 0) {
-			free_dlg(res);
-			return -5;
-		}
+	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;

+ 9 - 2
modules/tm/dlg.h

@@ -77,6 +77,8 @@ typedef struct dlg_id {
  * message within dialog
  */
 typedef struct dlg_hooks {
+	str ru;
+	str nh;
 	str* request_uri;   /* This should be put into Request-URI */
 	str* next_hop;      /* Where the message should be really sent */
 	rr_t* first_route;  /* First route to be printed into the message */
@@ -108,36 +110,41 @@ typedef struct dlg {
  * Create a new dialog
  */
 int new_dlg_uac(str* _cid, str* _ltag, unsigned int _lseq, str* _luri, str* _ruri, dlg_t** _d);
+typedef int (*new_dlg_uac_f)(str* _cid, str* _ltag, unsigned int _lseq, str* _luri, str* _ruri, dlg_t** _d);
 
 
 /*
  * A response arrived, update dialog
  */
 int dlg_response_uac(dlg_t* _d, struct sip_msg* _m);
-
+typedef int (*dlg_response_uac_f)(dlg_t* _d, struct sip_msg* _m);
 
 /*
  * Establishing a new dialog, UAS side
  */
-int new_dlg_uas(struct sip_msg* _req, int _code, str* _tag, dlg_t** _d);
+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 a dialog from a request
  */
 int dlg_request_uas(dlg_t* _d, struct sip_msg* _m);
+typedef int (*dlg_request_uas_f)(dlg_t* _d, struct sip_msg* _m);
 
 
 /*
  * Destroy a dialog state
  */
 void free_dlg(dlg_t* _d);
+typedef void (*free_dlg_f)(dlg_t* _d);
 
 
 /*
  * Print a dialog structure, just for debugging
  */
 void print_dlg(FILE* out, dlg_t* _d);
+typedef void (*print_dlg_f)(FILE* out, dlg_t* _d);
 
 
 /*

+ 1 - 1
modules/tm/t_cancel.c

@@ -94,7 +94,7 @@ void cancel_branch( struct cell *t, int branch )
 
 	if (t->uac[branch].last_received<100) {
 		DBG("DEBUG: cancel_branch: no response ever received: "
-			"giving up on cancel\n");
+		    "giving up on cancel\n");
 		return;
 	}
 

+ 1 - 1
modules/tm/t_fwd.c

@@ -219,7 +219,7 @@ int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop,
 
 	/* now message printing starts ... */
 	shbuf=print_uac_request( t, request, branch, uri, 
-		&len, send_sock, proxy->proto);
+		&len, send_sock, proxy->proto );
 	if (!shbuf) {
 		ret=ser_error=E_OUT_OF_MEM;
 		goto error01;

+ 1 - 1
modules/tm/t_fwd.h

@@ -45,7 +45,7 @@ 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,
     int branch, str *uri, unsigned int *len, struct socket_info *send_sock,
-	enum sip_protos proto);
+    enum sip_protos proto);
 void e2e_cancel( struct sip_msg *cancel_msg, struct cell *t_cancel, struct cell *t_invite );
 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, str* next_hop,

+ 3 - 2
modules/tm/t_lookup.c

@@ -989,9 +989,10 @@ static inline int new_t(struct sip_msg *p_msg)
 */
 int t_newtran( struct sip_msg* p_msg )
 {
-
 	int lret, my_err;
 
+	ret=1;
+
 	/* is T still up-to-date ? */
 	DBG("DEBUG: t_addifnew: msg id=%d , global msg id=%d ,"
 		" T on entrance=%p\n",p_msg->id,global_msg_id,T);
@@ -1161,7 +1162,7 @@ int t_lookup_ident(struct cell ** trans, unsigned int hash_index, unsigned int l
     {
 		if(p_cell->label == label){
 			REF_UNSAFE(p_cell);
-    		UNLOCK_HASH(hash_index);
+    			UNLOCK_HASH(hash_index);
 			set_t(p_cell);
 			*trans=p_cell;
 			DBG("DEBUG: t_lookup_ident: transaction found\n");

+ 201 - 127
modules/tm/t_msgbuilder.c

@@ -31,7 +31,7 @@
  * ----------
  * 2003-01-27  next baby-step to removing ZT - PRESERVE_ZT (jiri)
  * 2003-02-13  build_uac_request uses proto (andrei)
- * 2003-02-28 scratchpad compatibility abandoned (jiri)
+ * 2003-02-28  scratchpad compatibility abandoned (jiri)
  * 2003-04-14  build_local no longer checks reply status as it
  *             is now called before reply status is updated to
  *             avoid late ACK sending (jiri)
@@ -177,188 +177,262 @@ error:
 }
 
 
-
-char *build_uac_request_dlg(str* msg,           /* Method */
-			    str* ruri,          /* Request-URI */
-			    str* to,            /* To */
-			    str* from,          /* From */
-			    str* totag,         /* To header tag */
-			    str* fromtag,       /* From header tag */
-			    unsigned int cseq,  /* CSeq number */
-			    str* callid,        /* Call-ID */
-			    str* headers,       /* Headers to be appended */
-			    str* body,          /* Body of the message */
-			    int branch,         /* Branch */
-			    struct cell *t,     
-			    unsigned int *len,
-				struct socket_info* send_sock
-				)
+/*
+ * Convert lenght of body into asciiz
+ */
+static inline int print_content_length(str* dest, str* body)
 {
-	char *via, *buf, *w, content_len[10], cseq_str[10], branch_buf[MAX_BRANCH_PARAM_LEN];
-	char *tmp;
-	int content_len_len, cseq_str_len, branch_len;
-	str branch_str;
-	unsigned int via_len;
+	static char content_length[10];
+	int len;
+	char* tmp;
 
-	buf=0;
-	content_len_len = 0; /* Makes gcc happy */
-
-	     /* 
-	      * Print Content-Length
-	      */
+	     /* Print Content-Length */
 	if (body) {
-		tmp=int2str(body->len, &content_len_len);
-		if (content_len_len>=sizeof(content_len)) {
-			LOG(L_ERR, "ERROR: build_uac_request_dlg: content_len too big\n");
-			return 0;
+		tmp = int2str(body->len, &len);
+		if (len >= sizeof(content_length)) {
+			LOG(L_ERR, "ERROR: print_content_length: content_len too big\n");
+			return -1;
 		}
-		memcpy(content_len, tmp, content_len_len); 
+		memcpy(content_length, tmp, len); 
+		dest->s = content_length;
+		dest->len = len;
+	} else {
+		dest->s = 0;
+		dest->len = 0;
 	}
-	
-	     /* 
-	      * Print CSeq 
-	      */
-	tmp=int2str(cseq, &cseq_str_len);
-	if (cseq_str_len >= sizeof(cseq_str)) {
-		LOG(L_ERR, "ERROR: build_uac_request_dlg: cseq too big\n");
-		return 0;
+	return 0;
+}
+
+
+/*
+ * Convert CSeq number into asciiz
+ */
+static inline int print_cseq_num(str* _s, dlg_t* _d)
+{
+	static char cseq[10];
+	char* tmp;
+	int len;
+
+	tmp = int2str(_d->loc_seq.value, &len);
+	if (len >= sizeof(cseq)) {
+		LOG(L_ERR, "print_cseq_num: cseq too big\n");
+		return -1;
 	}
-	memcpy(cseq_str, tmp, cseq_str_len);
 	
-	*len = msg->len + 1 + ruri->len + 1 + SIP_VERSION_LEN + CRLF_LEN;
+	memcpy(cseq, tmp, len);
+	_s->s = cseq;
+	_s->len = len;
+	return 0;
+}
 
-	if (!t_calc_branch(t, branch, branch_buf, &branch_len)) {
-		LOG(L_ERR, "ERROR: build_uac_request_dlg: branch calculation failed\n");
-		goto error;
+
+/*
+ * Create Via header
+ */
+static inline int assemble_via(str* dest, struct cell* t, struct socket_info* sock, int branch)
+{
+	static char branch_buf[MAX_BRANCH_PARAM_LEN];
+	char* via;
+	int len, via_len;
+	str branch_str;
+
+	if (!t_calc_branch(t, branch, branch_buf, &len)) {
+		LOG(L_ERR, "ERROR: build_via: branch calculation failed\n");
+		return -1;
 	}
 	
-	branch_str.s=branch_buf;
-	branch_str.len=branch_len;
-	via = via_builder(&via_len, send_sock,
-			&branch_str, 0, send_sock->proto);
+	branch_str.s = branch_buf;
+	branch_str.len = len;
+
+	printf("!!!proto: %d\n", sock->proto);
+
+	via = via_builder(&via_len, sock, &branch_str, 0, sock->proto);
 	if (!via) {
-		LOG(L_ERR, "ERROR: build_uac_request_dlg: via building failed\n");
-		goto error;
+		LOG(L_ERR, "build_via: via building failed\n");
+		return -2;
 	}
 	
-	*len += via_len;
-	
-	/* header names and separators */
-	*len +=   TO_LEN + CRLF_LEN
-		+ FROM_LEN + CRLF_LEN
-		+ CSEQ_LEN + CRLF_LEN
-		+ CALLID_LEN + CRLF_LEN
-		+ ((body) ? (CONTENT_LENGTH_LEN + CRLF_LEN) : 0)
-		+ (server_signature ? USER_AGENT_LEN + CRLF_LEN : 0)
-		+ CRLF_LEN; /* EoM */
-	
-	     /* header field value and body length */
-	*len +=   to->len + 
-			((totag && totag->len) ? (TOTAG_LEN + totag->len) : 0) /* To */
-		+ from->len +  /* From */
-			((fromtag && fromtag->len) ? FROMTAG_LEN + fromtag->len:0)
-		+ cseq_str_len + 1 + msg->len                        /* CSeq */
-		+ callid->len                                        /* Call-ID */
-		+ ((body) ? (content_len_len) : 0)                   /* Content-Length */
-		+ ((headers) ? (headers->len) : 0)                   /* Headers */
-		+ ((body) ? (body->len) : 0);                        /* Body */
-	
-	buf = shm_malloc(*len + 1);
-	if (!buf) {
-		LOG(L_ERR, "ERROR: build_uac_request_dlg: no shmem\n");
-		goto error1;
-	}
-	
-	w = buf;
+	dest->s = via;
+	dest->len = via_len;
+	return 0;
+}
+
 
-	     /* First line */
-	memapp(w, msg->s, msg->len); 
+/*
+ * Print Request-URI
+ */
+static inline char* print_request_uri(char* w, str* method, dlg_t* dialog, struct cell* t, int branch)
+{
+	memapp(w, method->s, method->len); 
 	memapp(w, " ", 1); 
 
 	t->uac[branch].uri.s = w; 
-	t->uac[branch].uri.len = ruri->len;
+	t->uac[branch].uri.len = dialog->hooks.request_uri->len;
 
-	memapp(w, ruri->s, ruri->len); 
+	memapp(w, dialog->hooks.request_uri->s, dialog->hooks.request_uri->len); 
 	memapp(w, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);
 
-	     /* First Via */
-	memapp(w, via, via_len);
+	return w;
+}
+
 
-	     /* To */
+/*
+ * Print To header field
+ */
+static inline char* print_to(char* w, dlg_t* dialog, struct cell* t)
+{
 	t->to.s = w;
-	t->to.len= TO_LEN+to->len+CRLF_LEN;
+	t->to.len = TO_LEN + dialog->rem_uri.len + CRLF_LEN;
+
 	memapp(w, TO, TO_LEN);
-	memapp(w, to->s, to->len);
-	if (totag && totag->len ) {
-		t->to.len += TOTAG_LEN + totag->len ;
+	memapp(w, dialog->rem_uri.s, dialog->rem_uri.len);
+
+	if (dialog->id.rem_tag.len) {
+		t->to.len += TOTAG_LEN + dialog->id.rem_tag.len ;
 		memapp(w, TOTAG, TOTAG_LEN);
-		memapp(w, totag->s, totag->len);
+		memapp(w, dialog->id.rem_tag.s, dialog->id.rem_tag.len);
 	}
+
 	memapp(w, CRLF, CRLF_LEN);
+	return w;
+}
+
 
-	     /* From */
+/*
+ * Print From header field
+ */
+static inline char* print_from(char* w, dlg_t* dialog, struct cell* t)
+{
 	t->from.s = w;
-	t->from.len = FROM_LEN + from->len + CRLF_LEN;
+	t->from.len = FROM_LEN + dialog->loc_uri.len + CRLF_LEN;
+
 	memapp(w, FROM, FROM_LEN);
-	memapp(w, from->s, from->len);
-  	if (fromtag && fromtag->len ) { 
-		t->from.len+= FROMTAG_LEN + fromtag->len;
+	memapp(w, dialog->loc_uri.s, dialog->loc_uri.len);
+
+	if (dialog->id.loc_tag.len) {
+		t->from.len += FROMTAG_LEN + dialog->id.loc_tag.len;
 		memapp(w, FROMTAG, FROMTAG_LEN);
-		memapp(w, fromtag->s, fromtag->len);
+		memapp(w, dialog->id.loc_tag.s, dialog->id.loc_tag.len);
 	}
+
 	memapp(w, CRLF, CRLF_LEN);
-	
-	     /* CSeq */
+	return w;
+}
+
+
+/*
+ * Print CSeq header field
+ */
+static inline char* print_cseq(char* w, str* cseq, str* method, struct cell* t)
+{
 	t->cseq_n.s = w; 
 	/* don't include method name and CRLF -- subsequent
 	 * local reuqests ACK/CANCEl will add their own */
-	t->cseq_n.len = CSEQ_LEN + cseq_str_len; 
+	t->cseq_n.len = CSEQ_LEN + cseq->len; 
 
 	memapp(w, CSEQ, CSEQ_LEN);
-	memapp(w, cseq_str, cseq_str_len);
+	memapp(w, cseq->s, cseq->len);
 	memapp(w, " ", 1);
-	memapp(w, msg->s, msg->len);
+	memapp(w, method->s, method->len);
+	return w;
+}
+
 
-	     /* Call-ID */
+/*
+ * Print Call-ID header field
+ */
+static inline char* print_callid(char* w, dlg_t* dialog, struct cell* t)
+{
 	t->callid.s = w + CRLF_LEN; 
-	t->callid.len = CALLID_LEN + callid->len + CRLF_LEN;
+	t->callid.len = CALLID_LEN + dialog->id.call_id.len + CRLF_LEN;
 	memapp(w, CRLF CALLID, CRLF_LEN + CALLID_LEN);
-	memapp(w, callid->s, callid->len);
+	memapp(w, dialog->id.call_id.s, dialog->id.call_id.len);
 	memapp(w, CRLF, CRLF_LEN);
+	return w;
+}
+
+
+/*
+ * Create a request
+ */
+char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, int branch, 
+			struct cell *t, int* len, struct socket_info* send_sock)
+{
+	char* buf, *w;
+	str content_length, cseq, via;
+
+	if (!method || !dialog) {
+		LOG(L_ERR, "build_uac_req(): Invalid parameter value\n");
+		return 0;
+	}
+	if (print_content_length(&content_length, body) < 0) {
+		LOG(L_ERR, "build_uac_req(): Error while printing content-length\n");
+		return 0;
+	}
+	if (print_cseq_num(&cseq, dialog) < 0) {
+		LOG(L_ERR, "build_uac_req(): Error while printing CSeq number\n");
+		return 0;
+	}
+	*len = method->len + 1 + dialog->hooks.request_uri->len + 1 + SIP_VERSION_LEN + CRLF_LEN;
+
+	if (assemble_via(&via, t, send_sock, branch) < 0) {
+		LOG(L_ERR, "build_uac_req(): Error while assembling Via\n");
+		return 0;
+	}
+	*len += via.len;
+
+	*len += TO_LEN + dialog->rem_uri.len
+		+ (dialog->id.rem_tag.len ? (TOTAG_LEN + dialog->id.rem_tag.len) : 0) + CRLF_LEN;    /* To */
+	*len += FROM_LEN + dialog->loc_uri.len
+		+ (dialog->id.loc_tag.len ? (FROMTAG_LEN + dialog->id.loc_tag.len) : 0) + CRLF_LEN;  /* From */
+	*len += CALLID_LEN + dialog->id.call_id.len + CRLF_LEN;                                      /* Call-ID */
+	*len += CSEQ_LEN + cseq.len + 1 + method->len + CRLF_LEN;                                    /* CSeq */
+	*len += calculate_routeset_length(dialog);                                                   /* Route set */
+	*len += (body ? (CONTENT_LENGTH_LEN + content_length.len + CRLF_LEN) : 0);                   /* Content-Length */
+	*len += (server_signature ? (USER_AGENT_LEN + CRLF_LEN) : 0);                                /* Signature */
+	*len += (headers ? headers->len : 0);                                                        /* Additional headers */
+	*len += (body ? body->len : 0);                                                              /* Message body */
+	*len += CRLF_LEN;                                                                            /* End of Header */
+
+	buf = shm_malloc(*len + 1);
+	if (!buf) {
+		LOG(L_ERR, "build_uac_req(): no shmem\n");
+		goto error;
+	}
 	
+	w = buf;
+
+	w = print_request_uri(w, method, dialog, t, branch);  /* Request-URI */
+	memapp(w, via.s, via.len);                            /* Top-most Via */
+	w = print_to(w, dialog, t);                           /* To */
+	w = print_from(w, dialog, t);                         /* From */
+	w = print_cseq(w, &cseq, method, t);                  /* CSeq */
+	w = print_callid(w, dialog, t);                       /* Call-ID */
+	w = print_routeset(w, dialog);                        /* Route set */
+
 	     /* Content-Length */
 	if (body) {
 		memapp(w, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
-		memapp(w, content_len, content_len_len);
+		memapp(w, content_length.s, content_length.len);
 		memapp(w, CRLF, CRLF_LEN);
 	}
 	
 	     /* Server signature */
-	if (server_signature) {
-		memapp(w, USER_AGENT CRLF, USER_AGENT_LEN + CRLF_LEN);
-	}
-
-	     /* Headers */
-	if (headers) {
-		memapp(w, headers->s, headers->len);
-	}
-
-	     /* EoH */
+	if (server_signature) memapp(w, USER_AGENT CRLF, USER_AGENT_LEN + CRLF_LEN);
+	if (headers) memapp(w, headers->s, headers->len);
 	memapp(w, CRLF, CRLF_LEN);
-	
-	     /* Body */
-	if (body) {
-		memapp(w, body->s, body->len);
-	}
+     	if (body) memapp(w, body->s, body->len);
 
 #ifdef EXTRA_DEBUG
 	if (w-buf != *len ) abort();
 #endif
-	
- error1:
-	pkg_free(via);	
- error:
+
+	pkg_free(via.s);
 	return buf;
+
+ error:
+	pkg_free(via.s);
+	return 0;
 }
 
 

+ 6 - 16
modules/tm/t_msgbuilder.h

@@ -31,8 +31,8 @@
 #define _MSGBUILDER_H
 
 #include "../../ip_addr.h"
-
 #include "defs.h"
+#include "dlg.h"
 
 
 #define CSEQ "CSeq: "
@@ -71,21 +71,11 @@ char *build_uac_request(  str msg_type, str dst, str from,
 	struct cell *t, unsigned int *len);
 
 
-char *build_uac_request_dlg(str* msg,            /* Method */
-	                    str* ruri,           /* Request-URI */
-	                    str* to,             /* To header field w/o tag */
-	                    str* from,           /* From header field w/o tag */
-	                    str* totag,          /* To tag */
-	                    str* fromtag,        /* From tag */
-	                    unsigned int cseq,  /* CSeq number */
-	                    str* callid,         /* Call-ID */
-	                    str* headers,        /* Headers to be appended including CRLF */
-	                    str* body,           /* Body of the message */
-	                    int branch,         /* Branch */
-	                    struct cell *t,
-	                    unsigned int *len,
-						struct socket_info *send_sock
-	                   );
+/*
+ * Create a request
+ */
+char* build_uac_req(str* method, str* headers, str* body, dlg_t* dialog, int branch, 
+		    struct cell *t, int* len, struct socket_info* send_sock);
 
 
 int t_calc_branch(struct cell *t,

+ 1 - 1
modules/tm/t_reply.c

@@ -83,7 +83,7 @@ enum route_mode rmode=MODE_REQUEST;
 /* private place where we create to-tags for replies */
 /* janakj: made public, I need to access this value to store it in dialogs */
 char tm_tags[TOTAG_VALUE_LEN];
-static char *tm_tag_suffix;
+char *tm_tag_suffix;
 
 /* where to go if there is no positive reply */
 static int goto_on_negative=0;

+ 1 - 0
modules/tm/t_reply.h

@@ -52,6 +52,7 @@ enum rps {
 };
 
 extern char tm_tags[TOTAG_VALUE_LEN];
+extern char *tm_tag_suffix;
 
 enum route_mode { MODE_REQUEST=1, MODE_ONREPLY, MODE_ONFAILURE };
 extern enum route_mode rmode;

+ 32 - 27
modules/tm/tm.c

@@ -90,14 +90,14 @@
 #include "ut.h"
 #include "t_reply.h"
 #include "uac.h"
+#include "uac_fifo.h"
 #include "t_fwd.h"
 #include "t_lookup.h"
 #include "t_stats.h"
+#include "callid.h"
 
 MODULE_VERSION
 
-
-
 inline static int w_t_check(struct sip_msg* msg, char* str, char* str2);
 inline static int w_t_reply(struct sip_msg* msg, char* str, char* str2);
 
@@ -106,21 +106,20 @@ inline static int fixup_t_send_reply(void** param, int param_no);
 inline static int fixup_str2int( void** param, int param_no);
 inline static int w_t_retransmit_reply(struct sip_msg* p_msg, char* foo, char* bar );
 inline static int w_t_newtran(struct sip_msg* p_msg, char* foo, char* bar );
-inline static int w_t_newdlg( struct sip_msg* p_msg, char* foo, char* bar );
 inline static int w_t_relay( struct sip_msg  *p_msg , char *_foo, char *_bar);
 inline static int w_t_relay_to_udp( struct sip_msg  *p_msg , char *proxy, 
-									char *);
+				    char *);
 inline static int w_t_relay_to_tcp( struct sip_msg  *p_msg , char *proxy,
-									char *);
+				    char *);
 inline static int w_t_replicate( struct sip_msg  *p_msg , 
-							char *proxy, /* struct proxy_l *proxy expected */
-							char *_foo       /* nothing expected */ );
+				 char *proxy, /* struct proxy_l *proxy expected */
+				 char *_foo       /* nothing expected */ );
 inline static int w_t_replicate_udp( struct sip_msg  *p_msg , 
-							char *proxy, /* struct proxy_l *proxy expected */
-							char *_foo       /* nothing expected */ );
+				     char *proxy, /* struct proxy_l *proxy expected */
+				     char *_foo       /* nothing expected */ );
 inline static int w_t_replicate_tcp( struct sip_msg  *p_msg , 
-							char *proxy, /* struct proxy_l *proxy expected */
-							char *_foo       /* nothing expected */ );
+				     char *proxy, /* struct proxy_l *proxy expected */
+				     char *_foo       /* nothing expected */ );
 inline static int w_t_forward_nonack(struct sip_msg* msg, char* str, char* );
 inline static int w_t_forward_nonack_udp(struct sip_msg* msg, char* str,char*);
 inline static int w_t_forward_nonack_tcp(struct sip_msg* msg, char* str,char*);
@@ -157,14 +156,21 @@ static cmd_export_t cmds[]={
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
 	/* not applicable from the script */
 	{"register_tmcb",      (cmd_function)register_tmcb,     NO_SCRIPT,     0, 0},
-	{T_UAC_DLG,            (cmd_function)t_uac_dlg,         NO_SCRIPT,     0, 0},
 	{"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,     0, 0},
 	{T_REPLY_WB,           (cmd_function)t_reply_with_body, NO_SCRIPT,     0, 0},
 	{T_IS_LOCAL,           (cmd_function)t_is_local,        NO_SCRIPT,     0, 0},
 	{T_GET_TI,             (cmd_function)t_get_trans_ident, NO_SCRIPT,     0, 0},
 	{T_LOOKUP_IDENT,       (cmd_function)t_lookup_ident,    NO_SCRIPT,     0, 0},
 	{T_ADDBLIND,           (cmd_function)add_blind_uac,     NO_SCRIPT,     0, 0},
-	{"t_newdlg",           (cmd_function)w_t_newdlg,        0,             0, 0},
+	{"t_request_within",   (cmd_function)req_within,        NO_SCRIPT,     0, 0},
+	{"t_request_outside",  (cmd_function)req_outside,       NO_SCRIPT,     0, 0},
+	{"t_request",          (cmd_function)request,           NO_SCRIPT,     0, 0},
+	{"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},
+	{"dlg_request_uas",    (cmd_function)dlg_request_uas,   NO_SCRIPT,     0, 0},
+	{"free_dlg",           (cmd_function)free_dlg,          NO_SCRIPT,     0, 0},
+	{"print_dlg",          (cmd_function)print_dlg,         NO_SCRIPT,     0, 0},
 	{0,0,0,0,0}
 };
 
@@ -179,6 +185,7 @@ static param_export_t params[]={
 	{"retr_timer1p3", INT_PARAM, &(timer_id2timeout[RT_T1_TO_3])        },
 	{"retr_timer2",   INT_PARAM, &(timer_id2timeout[RT_T2])             },
 	{"noisy_ctimer",  INT_PARAM, &noisy_ctimer                          },
+	{"uac_from",      STR_PARAM, &uac_from                              },
 	{0,0,0}
 };
 
@@ -261,11 +268,16 @@ static int mod_init(void)
 		return -1;
 	}
 
+	if (init_callid() < 0) {
+		LOG(L_CRIT, "Error while initializin Call-ID generator\n");
+		return -1;
+	}
 
-	if (register_fifo_cmd(fifo_uac_dlg, "t_uac_dlg", 0)<0) {
-		LOG(L_CRIT, "cannot register fifo uac\n");
+	if (register_fifo_cmd(fifo_uac, "t_uac_dlg", 0) < 0) {
+		LOG(L_CRIT, "cannot register fifo t_uac\n");
 		return -1;
 	}
+
 	if (register_fifo_cmd(fifo_hash, "t_hash", 0)<0) {
 		LOG(L_CRIT, "cannot register hash\n");
 		return -1;
@@ -317,11 +329,12 @@ static int mod_init(void)
 }
 
 static int child_init(int rank) {
-	if (uac_child_init(rank)==-1) {
-		LOG(L_ERR, "ERROR: child_init: uac_child_init error\n");
-		return -1;
+	if (child_init_callid(rank) < 0) {
+		LOG(L_ERR, "ERROR: child_init: Error while initializing Call-ID generator\n");
+		return -2;
 	}
-	return 1;
+
+	return 0;
 }
 
 
@@ -507,14 +520,6 @@ inline static int w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char*
 }
 
 
-
-
-
-inline static int w_t_newdlg( struct sip_msg* p_msg, char* foo, char* bar ) 
-{
-	return t_newdlg( p_msg );
-}
-
 inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar ) 
 {
 	/* t_newtran returns 0 on error (negative value means

+ 37 - 6
modules/tm/tm_load.c

@@ -58,10 +58,6 @@ int load_tm( struct tm_binds *tmb)
 		LOG(L_ERR, LOAD_ERROR "'t_relay' not found\n");
 		return -1;
 	}
-	if (!(tmb->t_uac_dlg=(tuacdlg_f)find_export(T_UAC_DLG, NO_SCRIPT, 0)) ) {
-		LOG( L_ERR, LOAD_ERROR "'t_uac_dlg' not found\n");
-		return -1;
-	}
 	if (!(tmb->t_reply=(treply_f)find_export(T_REPLY, 2, 0)) ) {
 		LOG( L_ERR, LOAD_ERROR "'t_reply' not found\n");
 		return -1;
@@ -90,7 +86,42 @@ int load_tm( struct tm_binds *tmb)
 		LOG( L_ERR, LOAD_ERROR "'t_forward_nonack' not found\n");
 		return -1;
 	}
-
+	if (!(tmb->t_request_within=(reqwith_t)find_export("t_request_within", NO_SCRIPT, 0)) ) {
+		LOG( L_ERR, LOAD_ERROR "'t_request_within' not found\n");
+		return -1;
+	}
+	if (!(tmb->t_request_outside=(reqout_t)find_export("t_request_outside", NO_SCRIPT, 0)) ) {
+		LOG( L_ERR, LOAD_ERROR "'t_request_outside' not found\n");
+		return -1;
+	}
+	if (!(tmb->t_request=(req_t)find_export("t_request", NO_SCRIPT, 0)) ) {
+		LOG( L_ERR, LOAD_ERROR "'t_request' not found\n");
+		return -1;
+	}
+	if (!(tmb->new_dlg_uac=(new_dlg_uac_f)find_export("new_dlg_uac", NO_SCRIPT, 0)) ) {
+		LOG( L_ERR, LOAD_ERROR "'new_dlg_uac' not found\n");
+		return -1;
+	}
+        if (!(tmb->dlg_response_uac=(dlg_response_uac_f)find_export("dlg_response_uac", NO_SCRIPT, 0)) ) {
+		LOG( L_ERR, LOAD_ERROR "'dlg_response_uac' not found\n");
+		return -1;
+        }
+        if (!(tmb->new_dlg_uas=(new_dlg_uas_f)find_export("new_dlg_uas", NO_SCRIPT, 0)) ) {
+		LOG( L_ERR, LOAD_ERROR "'new_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->free_dlg=(free_dlg_f)find_export("free_dlg", NO_SCRIPT, 0)) ) {
+		LOG( L_ERR, LOAD_ERROR "'free_dlg' not found\n");
+		return -1;
+	}
+	if (!(tmb->print_dlg=(print_dlg_f)find_export("print_dlg", NO_SCRIPT, 0)) ) {
+		LOG( L_ERR, LOAD_ERROR "'print_dlg' not found\n");
+		return -1;
+	}
+	
 	return 1;
-
 }

+ 38 - 28
modules/tm/tm_load.h

@@ -44,45 +44,55 @@
 #include "t_fwd.h"
 #include "t_reply.h"
 #include "t_lookup.h"
+#include "dlg.h"
 
 /* export not usable from scripts */
 #define NO_SCRIPT	-1
 
-#define T_RELAY_TO "t_relay_to"
-#define T_RELAY_TO_UDP "t_relay_to_udp"
-#define T_RELAY_TO_TCP "t_relay_to_tcp"
-#define T_RELAY "t_relay"
-#define T_RELAY_UDP "t_relay_udp"
-#define T_RELAY_TCP "t_relay_tcp"
-#define T_UAC_DLG "t_uac_dlg"
-#define T_REPLY "t_reply"
-#define T_REPLY_WB "t_reply_with_body"
-#define T_ADDBLIND "t_add_blind"
-#define T_REPLY_UNSAFE "t_reply_unsafe"
-#define T_FORWARD_NONACK "t_forward_nonack"
+#define T_RELAY_TO           "t_relay_to"
+#define T_RELAY_TO_UDP       "t_relay_to_udp"
+#define T_RELAY_TO_TCP       "t_relay_to_tcp"
+#define T_RELAY              "t_relay"
+#define T_RELAY_UDP          "t_relay_udp"
+#define T_RELAY_TCP          "t_relay_tcp"
+#define T_REPLY              "t_reply"
+#define T_REPLY_WB           "t_reply_with_body"
+#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"
-
+#define T_GET_TI             "t_get_trans_ident"
+#define T_LOOKUP_IDENT       "t_lookup_ident"
+#define T_IS_LOCAL           "t_is_local"
+#define T_REQUEST_WITHIN     "request_within"
+#define T_REQUEST_OUTSIDE    "request_outside"
 
 
 
 struct tm_binds {
-	register_tmcb_f	register_tmcb;
-	cmd_function	t_relay_to_udp;
-	cmd_function	t_relay_to_tcp;
-	cmd_function 	t_relay;
-	tuacdlg_f		t_uac_dlg;
-	treply_f		t_reply;
-	treply_wb_f		t_reply_with_body;
-	tislocal_f		t_is_local;
-	tget_ti_f		t_get_trans_ident;
+	register_tmcb_f register_tmcb;
+	cmd_function    t_relay_to_udp;
+	cmd_function    t_relay_to_tcp;
+	cmd_function    t_relay;
+	treply_f        t_reply;
+	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;
+	taddblind_f     t_addblind;
+	treply_f        t_reply_unsafe;
+	tfwd_f          t_forward_nonack;
+	reqwith_t       t_request_within;
+	reqout_t        t_request_outside;
+	req_t           t_request;
+	
+	new_dlg_uac_f      new_dlg_uac;
+	dlg_response_uac_f dlg_response_uac;
+	new_dlg_uas_f      new_dlg_uas;
+	dlg_request_uas_f  dlg_request_uas;
+	free_dlg_f         free_dlg;
+	print_dlg_f        print_dlg;
 };
 
 

+ 150 - 718
modules/tm/uac.c

@@ -30,18 +30,6 @@
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * ***************************************************
- *             IMPORTANT NOTE
- *
- *    All UACs but t_uac_dlg are being deprecated now
- *    and will be removed from future versions of TM
- *    module. Eliminate all dependancies on them asap.
- *    For backwards compatibility (NOT RECOMMENDED)
- *    turn off DEPRECATE_OLD_STUFF in defs.h. Similarly,
- *    there is a new FIFO UAC.
- *
- * ****************************************************
- *
  * History:
  * --------
  *  2003-01-23  t_uac_dlg now uses get_out_socket (jiri)
@@ -54,816 +42,260 @@
  *  2003-03-01  kr set through a function now (jiri)
  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
  *  2003-04-02  port_no_str does not contain a leading ':' anymore (andrei)
- *  2003-04-15  t_uac_dlg now uses get_send_socket(get_out_socket doesn't
- *               work for tcp) (andrei)
- *  
  */
 
-
-#include "../../comp_defs.h"
-#include "defs.h"
-
-
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <limits.h>
 #include <string.h>
-#include "../../parser/parse_from.h"
-#include "../../parser/msg_parser.h"
+#include "../../mem/shm_mem.h"
 #include "../../dprint.h"
-#include "../../ut.h"
-#include "../../hash_func.h"
-#include "../../md5utils.h"
-#include "../../mem/mem.h"
-#include "../../fifo_server.h"
-#include "../../error.h"
-#include "../../pt.h"
+#include "../../globals.h"
+#include "../../md5.h"
 #include "../../crc.h"
-#include "t_funcs.h"
-#include "config.h"
-#include "sip_msg.h"
+#include "../../ip_addr.h"
 #include "ut.h"
+#include "h_table.h"
+#include "t_hooks.h"
+#include "t_funcs.h"
 #include "t_msgbuilder.h"
+#include "callid.h"
 #include "uac.h"
 
-/* header fields which are explicitely processed and are not copied
- * from FIFO line-by-line
- */
-#define skip_hf(_hf) (((_hf)->type==HDR_FROM) || ((_hf)->type==HDR_TO) \
-	|| ((_hf)->type==HDR_CALLID) || ((_hf)->type==HDR_CSEQ))
-
-/* Call-ID has the following form: <callid_nr>-<pid>@<ip>
- * callid_nr is initialized as a random number and continually
- * increases; -<pid>@<ip> is kept in callid_suffix
- */
-
-#define CALLID_SUFFIX_LEN (1 /* - */ + 5 /* pid */ \
-	+ 42 /* embedded v4inv6 address can be looong '128.' */ \
-	+ 2 /* parenthessis [] */ + 1 /* ZT 0 */ \
-	+ 16 /* one never knows ;-) */ )
-#define CALLID_NR_LEN 20
-
-/* the character which separates random from constant part */
-#define CID_SEP	'-'
-
-/* length of FROM tags */
-#define FROM_TAG_LEN (MD5_LEN +1 /* - */ + CRC16_LEN)
-
-struct str_list {
-	str s;
-	struct str_list *next;
-};
 
-static unsigned long callid_nr;
-static char *callid_suffix;
-static int callid_suffix_len;
-static int rand_len;	/* number of chars to display max rand */
-static char callid[CALLID_NR_LEN+CALLID_SUFFIX_LEN];
+#define FROM_TAG_LEN (MD5_LEN + 1 /* - */ + CRC16_LEN) /* length of FROM tags */
 
-static char from_tag[ FROM_TAG_LEN+1 ];
+static char from_tag[FROM_TAG_LEN + 1];
 
+char* uac_from = "sip:[email protected]"; /* Module parameter */
 
 
-int uac_init() {
-
-	int i; 
-	unsigned long uli;
-	int rand_len_bits;
-	int rand_cnt; /* number of rands() to be long enough */
-	int rand_bits; /* length of rands() in bits */
+/*
+ * Initialize UAC
+ */
+int uac_init(void) 
+{
 	str src[3];
 
-	if (RAND_MAX<TABLE_ENTRIES) {
+	if (RAND_MAX < TABLE_ENTRIES) {
 		LOG(L_WARN, "Warning: uac does not spread "
-			"accross the whole hash table\n");
-	}
-
-	/* calculate the initial call-id */
-
-	/* how many bits and chars do we need to display the 
-	 * whole ULONG number */
-	for (rand_len_bits=0,uli=ULONG_MAX;uli;
-			uli>>=1, rand_len_bits++ );
-	rand_len=rand_len_bits/4;
-	if (rand_len>CALLID_NR_LEN) {
-		LOG(L_ERR, "ERROR: Too small callid buffer\n");
-		return -1;
-	}
-
-	/* how long are the rand()s ? */
-	for (rand_bits=0,i=RAND_MAX;i;i>>=1,rand_bits++);
-	/* how many rands() fit in the ULONG ? */
-	rand_cnt=rand_len_bits / rand_bits;
-
-	/* now fill in the callid with as many random
-	 * numbers as you can + 1 */
-	callid_nr=rand(); /* this is the + 1 */
-	while(rand_cnt) {
-		rand_cnt--;
-		callid_nr<<=rand_bits;
-		callid_nr|=rand();
+		    "accross the whole hash table\n");
 	}
-	callid_suffix=callid+rand_len;
-	DBG("CALLID initialization: %lx (len=%d)\n", 
-			callid_nr, rand_len );
-	DBG("CALLID0=%0*lx\n", rand_len, callid_nr );
-
 
 	/* calculate the initial From tag */
-
-	src[0].s="Long live SER server";
-	src[0].len=strlen(src[0].s);
-	src[1].s=sock_info[bind_idx].address_str.s;
-	src[1].len=strlen(src[1].s);
-	src[2].s=sock_info[bind_idx].port_no_str.s;
-	src[2].len=strlen(src[2].s);
-
-	MDStringArray( from_tag, src, 3 );
-	from_tag[MD5_LEN]=CID_SEP;
-
+	src[0].s = "Long live SER server";
+	src[0].len = strlen(src[0].s);
+	src[1].s = sock_info[bind_idx].address_str.s;
+	src[1].len = strlen(src[1].s);
+	src[2].s = sock_info[bind_idx].port_no_str.s;
+	src[2].len = strlen(src[2].s);
+
+	MDStringArray(from_tag, src, 3);
+	from_tag[MD5_LEN] = '-';
 	return 1;
 }
 
 
-int uac_child_init( int rank ) 
+/*
+ * Generate a From tag
+ */
+void generate_fromtag(str* tag, str* callid)
 {
-	callid_suffix_len=snprintf(callid_suffix,CALLID_SUFFIX_LEN,
-			"%c%d@%.*s", CID_SEP, my_pid(), 
-			sock_info[bind_idx].address_str.len,
-			sock_info[bind_idx].address_str.s );
-	if (callid_suffix_len==-1 || callid_suffix_len>=CALLID_SUFFIX_LEN) {
-		LOG(L_ERR, "ERROR: uac_child_init: buffer too small\n");
-		return -1;
-	}
-	DBG("DEBUG: callid_suffix: %s\n", callid_suffix );
-	return 1;
+	     /* calculate from tag from callid */
+	crcitt_string_array(&from_tag[MD5_LEN + 1], callid, 1);
+	tag->s = from_tag; 
+	tag->len = FROM_TAG_LEN;
 }
 
-static struct socket_info *uri2sock( str *uri, union sockaddr_union *to_su,
-									 int proto )
-{
-	struct proxy_l *proxy;
-	struct socket_info* send_sock;
 
-	proxy = uri2proxy(uri, proto);
-	if (proxy == 0) {
-		ser_error = E_BAD_ADDRESS;
-		LOG(L_ERR, "ERROR: uri2sock: Can't create a dst proxy\n");
-		return 0;
+/*
+ * Check value of parameters
+ */
+static inline int check_params(str* method, str* to, str* from, dlg_t** dialog)
+{
+	if (!method || !to || !from || !dialog) {
+		LOG(L_ERR, "check_params(): Invalid parameter value\n");
+		return -1;
 	}
 
-	hostent2su(to_su, &proxy->host, proxy->addr_idx, 
-			(proxy->port) ? proxy->port : SIP_PORT);
-	send_sock=get_send_socket(to_su, proxy->proto);
-	if (send_sock == 0) {
-		LOG(L_ERR, "ERROR: uri2sock: no corresponding socket for af %d,"
-				"proto %d\n", to_su->s.sa_family , proto);
-		ser_error = E_NO_SOCKET;
+	if (!method->s || !method->len) {
+		LOG(L_ERR, "check_params(): Invalid request method\n");
+		return -2;
 	}
 
+	if (!to->s || !to->len) {
+		LOG(L_ERR, "check_params(): Invalid request method\n");
+		return -4;
+	}
 
-	free_proxy(proxy);
-	pkg_free(proxy);
-	return send_sock;
+	if (!from->s || !from->len) {
+		LOG(L_ERR, "check_params(): Invalid request method\n");
+		return -5;
+	}
+	return 0;
 }
-	
 
 
 /*
- * Send a request within a dialog
- * 
- * Some parameters are required, some are optional (i.e., ephemeral,
- * default or empty values are created if 0 is passed as parameter). The
- * optional parameters are typically used to set some header fields
- * to dialog-related values (as opposed to having them set to
- * ephemeral values).
- *
- * Required:
- * - msg ..   specifies type of message, such as "OPTIONS"
- * - ruri ..  specifies request URI; 
- * - from ..  value of From header field (if it already includes from tag, 
- *            the fromtag parameter MUST point to en empty string; if 
- *            fromtag is 0, an ephemeral tag is always appended)
- * - to ...   value of To header field (if it already includes to tag in it,
- *            or you do not wish to set a to-tag the totag parameter MUST be 0)
- * 
- * Optional:
- * - dst     transport destination (expressed as URI) -- if present,
- *           request is physically forwarded to address indicated in it,
- *           overriding the transport address in ruri; useful for use with 
- *           outbound proxies or loose routers (that is where the first 
- *           element of route set comes in)
- * - fromtag from HF tag -- dialog-less applications do not to set it (==0),
- *           in which case an ephemeral value is created; if fromtag present,
- *           its appended to the From header field; it may be also present 
- *           and point to an empty string -- that only makes sense if
- *           application includes the tag in From and does not care to
- *           separate the tag from the rest of header field
- * - totag   To HF tag; if 0, no to-tag is appended (unless it is already
- *           part of to)
- * - cid ..  callid; if 0, ephemeral value is created; transactions
- *           within a dialog need to set this value to dialog's callid
- * - cseq .. CSeq; if 0, default value (DEFAULT_CSEQ) is used; transactions
- *           within a dialog need to set this value to current local cseq,
- *           which grows continously with transactions sent
- * - headers .. block of header fields that will be included in the
- *           message. It MAY NOT include header fields already described
- *           in other parameters (From, to, cid, cseq) or created 
- *           automatically   (Content_length)   otherwise the parameter
- *           would appear multiple times. It MUST include all additional
- *           header fields required for a given SIP message, like Content-Type 
- *           for any messages including a body or Contact for INVITEs.
- * - body .. if present, body and Content-Length is appended to the 
- *           SIP message; Content-Type then needs to be present inside
- *           'headers' parameter
- * - cb ..   callback to be called when transaction completes; if none
- *           present, no callback will be called
- * - cbp ..  callback parameter -- value stored in transaction context
- *           
- *
+ * Send a request using data from the dialog structure
  */
-int t_uac_dlg(str* msg,                     /* Type of the message - MESSAGE, OPTIONS etc. */
-	      str* dst,                     /* Real destination (can be different than R-URI) */
-		  int proto,
-	      str* ruri,                    /* Request-URI */
-	      str* to,                      /* To - w/o tag*/
-	      str* from,                    /* From - w/o tag*/
-	      str* totag,                   /* To tag */
-	      str* fromtag,                 /* From tag */
-	      int* cseq,                    /* Variable holding CSeq */
-	      str* cid,                     /* Call-ID */
-	      str* headers,                 /* Optional headers including CRLF */
-	      str* body,                    /* Message body */
-	      transaction_cb completion_cb, /* Callback parameter */
-	      void* cbp                     /* Callback pointer */
-	      )
+int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp)
 {
-
-	int r, branch, ret;
-	unsigned int req_len;
-	char *buf;
-	struct cell *new_cell;
 	struct socket_info* send_sock;
-	struct retr_buf *request;
-	str callid_s, ftag, tmp;
 	union sockaddr_union to_su;
+	struct cell *new_cell;
+	struct retr_buf *request;
+	char* buf;
+	int buf_len;
 
-	/* make -Wall shut up */
-	ret=0;
-
-	/* check for invalid parameter */
-	if (!msg || !msg->s
-				|| !ruri || !ruri->s
-				|| !from || !from->s
-				|| !to || !to->s ) {
-		LOG(L_ERR, "ERROR: t_uac_dlg: invalid parameters\n");
-		ser_error = ret = E_INVALID_PARAMS;
-#ifdef XL_DEBUG
-		abort();
-#endif
-		goto done;
-	}
-
-	send_sock=uri2sock( dst? dst: ruri, &to_su, proto );
-	if (send_sock==0) {
-		LOG(L_ERR, "ERROR: t_uac_dlg: no socket found\n");
-		goto error00;
-	}
-
-	branch=0;
-	     /* No Call-ID given, calculate it */
-	if (cid == 0) {
-		callid_nr++;
-		r = snprintf(callid, rand_len + 1, "%0*lx", rand_len, callid_nr);
-		if (r == -1 || r>=rand_len+1) {
-			LOG(L_CRIT, "BUG: SORRY, callid calculation failed\n");
-			goto error00;
-		}
-
-		     /* fix the ZT 0 */
-		callid[rand_len] = CID_SEP;
-		callid_s.s = callid;
-		callid_s.len = rand_len + callid_suffix_len;
-	}
+	send_sock = uri2sock(dialog->hooks.next_hop, &to_su, PROTO_NONE);
+	if (!send_sock) {
+		LOG(L_ERR, "t_uac: no socket found\n");
+		goto error2;
+	}	
 
 	new_cell = build_cell(0); 
 	if (!new_cell) {
-		ret = E_OUT_OF_MEM;
-		LOG(L_ERR, "ERROR: t_uac: short of cell shmem\n");
-		goto error00;
+		LOG(L_ERR, "t_uac: short of cell shmem\n");
+		goto error2;
 	}
 
-	new_cell->completion_cb = completion_cb;
+	new_cell->completion_cb = cb;
 	new_cell->cbp = cbp;
-
-	/* cbp is installed -- tell error handling bellow not to free it */
+	
+	     /* cbp is installed -- tell error handling bellow not to free it */
 	cbp = 0;
 
-	new_cell->is_invite = msg->len == INVITE_LEN && memcmp(msg->s, INVITE, INVITE_LEN) == 0;
-	new_cell->local= 1 ;
+	new_cell->is_invite = method->len == INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN) == 0;
+	new_cell->local= 1;
 	set_kr(REQ_FWDED);
-
-	request = &new_cell->uac[branch].request;
+	
+	request = &new_cell->uac[0].request;
 	request->dst.to = to_su;
 	request->dst.send_sock = send_sock;
 	request->dst.proto = send_sock->proto;
 	request->dst.proto_reserved1 = 0;
 
-	/* need to put in table to calculate label which is needed for printing */
+	     /* need to put in table to calculate label which is needed for printing */
 	LOCK_HASH(new_cell->hash_index);
 	insert_into_hash_table_unsafe(new_cell);
 	UNLOCK_HASH(new_cell->hash_index);
 
-	if (fromtag == 0) {
-		     /* calculate from tag from callid */
-		crcitt_string_array(&from_tag[MD5_LEN + 1], (cid) ? (cid) : (&callid_s), 1);
-		ftag.s = from_tag; 
-		ftag.len = FROM_TAG_LEN;
-	}
-
-	buf = build_uac_request_dlg(msg, 
-				    ruri,
-				    to, 
-				    from,
-				    totag,
-				    (fromtag) ? (fromtag) : (&ftag), 
-				    (cseq) ? (*cseq) : DEFAULT_CSEQ, 
-				    (cid) ? (cid) : (&callid_s), 
-				    headers, 
-				    body, 
-				    branch,
-				    new_cell,
-				    &req_len,
-					send_sock);
+	buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len, send_sock);
 	if (!buf) {
-		ret = E_OUT_OF_MEM;
-		LOG(L_ERR, "ERROR: t_uac: short of req shmem\n");
-		goto error01;
+		LOG(L_ERR, "t_uac: Error while building message\n");
+		goto error1;
 	}
+
 	new_cell->method.s = buf;
-	new_cell->method.len = msg->len;
+	new_cell->method.len = method->len;
 
 	request->buffer = buf;
-	request->buffer_len = req_len;
+	request->buffer_len = buf_len;
 	new_cell->nr_of_outgoings++;
-
-/*
-	proxy->tx++;
-	proxy->tx_bytes += req_len;
-*/
-
+	
 	if (SEND_BUFFER(request) == -1) {
-		if (dst) {
-			tmp = *dst;
-		} else {
-			tmp = *ruri;
-		}
-		LOG(L_ERR, "ERROR: t_uac: UAC sending to \'%.*s\' failed\n", tmp.len, tmp.s);
-/*
-		proxy->errors++;
-		proxy->ok = 0;
-*/
+		LOG(L_ERR, "t_uac: Attempt to send to '%.*s' failed\n", 
+		    dialog->hooks.next_hop->len,
+		    dialog->hooks.next_hop->s
+		    );
 	}
 	
 	start_retr(request);
-
-	/* success */
 	return 1;
 
-error01:
+ error1:
 	LOCK_HASH(new_cell->hash_index);
 	remove_from_hash_table_unsafe(new_cell);
 	UNLOCK_HASH(new_cell->hash_index);
 	free_cell(new_cell);
 
-error00:
-/*
-	free_proxy(proxy);
-	pkg_free(proxy);
-*/
-
-done: 
-	/* if we did not install cbp, release it now */
+ error2:
+	     /* if we did not install cbp, release it now */
 	if (cbp) shm_free(cbp);
-	return ser_error = ret;
+	return -1;
 }
 
 
-static void fifo_callback( struct cell *t, struct sip_msg *reply,
-	int code, void *param)
+/*
+ * Send a message within a dialog
+ */
+int req_within(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb completion_cb, void* cbp)
 {
-
-	char *filename;
-	str text;
-
-	DBG("DEBUG: fifo UAC completed with status %d\n", code);
-	if (!t->cbp) {
-		LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", code);
-		return;
+	if (!method || !dialog) {
+		LOG(L_ERR, "req_within: Invalid parameter value\n");
+		goto err;
 	}
 
-	filename=(char *)(t->cbp);
-	if (reply==FAKED_REPLY) {
-		get_reply_status(&text,reply,code);
-		if (text.s==0) {
-			LOG(L_ERR, "ERROR: fifo_callback: get_reply_status failed\n");
-			fifo_reply(filename, "500 fifo_callback: get_reply_status failed\n");
-			return;
-		}
-		fifo_reply(filename, "%.*s\n", text.len, text.s );
-		pkg_free(text.s);
-	} else {
-		text.s=reply->first_line.u.reply.status.s;
-		text.len=reply->len-(reply->first_line.u.reply.status.s-reply->buf);
-		fifo_reply(filename, "%.*s", text.len, text.s );
+	if (dialog->state != DLG_CONFIRMED) {
+		LOG(L_ERR, "req_within: Dialog is not confirmed yet\n");
+		goto err;
 	}
-	DBG("DEBUG: fifo_callback sucesssfuly completed\n");
-}	
 
-static struct str_list *new_str(char *s, int len, struct str_list **last, int *total)
-{
-	struct str_list *new;
-	new=pkg_malloc(sizeof(struct str_list));
-	if (!new) {
-		LOG(L_ERR, "ERROR: get_hfblock: not enough mem\n");
-		return 0;
-	}
-	new->s.s=s;
-	new->s.len=len;
-	new->next=0;
+	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 */
+ send:
+	return t_uac(method, headers, body, dialog, completion_cb, cbp);
 
-	(*last)->next=new;
-	*last=new;
-	*total+=len;
-
-	return new;
+ err:
+	if (cbp) shm_free(cbp);
+	return -1;
 }
 
 
-static char *get_hfblock(str *uri, struct hdr_field *hf, int *l, int proto) 
-{
-	struct str_list sl, *last, *new, *i, *foo;
-	int hf_avail, frag_len, total_len;
-	char *begin, *needle, *dst, *ret, *d;
-	str *sock_name, *portname;
-	union sockaddr_union to_su;
-	struct socket_info* send_sock;
-
-	ret=0; /* pesimist: assume failure */
-	total_len=0;
-	last=&sl;
-	last->next=0;
-	portname=sock_name=0;
-
-	for (; hf; hf=hf->next) {
-		if (skip_hf(hf)) continue;
-
-		begin=needle=hf->name.s; 
-		hf_avail=hf->len;
-
-		/* substitution loop */
-		while(hf_avail) {
-			d=memchr(needle, SUBST_CHAR, hf_avail);
-			if (!d || d+1>=needle+hf_avail) { /* nothing to substitute */
-				new=new_str(begin, hf_avail, &last, &total_len); 
-				if (!new) goto error;
-				break;
-			} else {
-				frag_len=d-begin;
-				d++; /* d not at the second substitution char */
-				switch(*d) {
-					case SUBST_CHAR:	/* double SUBST_CHAR: IP */
-						/* string before substitute */
-						new=new_str(begin, frag_len, &last, &total_len); 
-						if (!new) goto error;
-						/* substitute */
-						if (!sock_name) {
-							send_sock=uri2sock( uri, &to_su, proto );
-							if (!send_sock) {
-								LOG(L_ERR, "ERROR: get_hf_block: send_sock failed\n");
-								goto error;
-							}
-							sock_name=&send_sock->address_str;
-							portname=&send_sock->port_no_str;
-						}
-						new=new_str(sock_name->s, sock_name->len,
-								&last, &total_len );
-						if (!new) goto error;
-						/* inefficient - FIXME --andrei*/
-						new=new_str(":", 1, &last, &total_len);
-						if (!new) goto error;
-						new=new_str(portname->s, portname->len,
-								&last, &total_len );
-						if (!new) goto error;
-						/* keep going ... */
-						begin=needle=d+1;hf_avail-=frag_len+2;
-						continue;
-					default:
-						/* no valid substitution char -- keep going */
-						hf_avail-=frag_len+1;
-						needle=d;
-				}
-			} /* possible substitute */
-		} /* substitution loop */
-		/* proceed to next header */
-		/* new=new_str(CRLF, CRLF_LEN, &last, &total_len );
-		if (!new) goto error; */
-		DBG("DEBUG: get_hf_block: one more hf processed\n");
-	} /* header loop */
-
-
-	/* construct a single header block now */
-	ret=pkg_malloc(total_len);
-	if (!ret) {
-		LOG(L_ERR, "ERROR: get_hf_block no pkg mem for hf block\n");
-		goto error;
-	}
-	i=sl.next;
-	dst=ret;
-	while(i) {
-		foo=i;
-		i=i->next;
-		memcpy(dst, foo->s.s, foo->s.len);
-		dst+=foo->s.len;
-		pkg_free(foo);
-	}
-	*l=total_len;
-	return ret;
-
-error:
-	i=sl.next;
-	while(i) {
-		foo=i;
-		i=i->next;
-		pkg_free(foo);
-	}
-	*l=0;
-	return 0;
-}
-
-static void fifo_uac_error(char *reply_fifo, int code, char *msg)
+/*
+ * Send an initial request that will start a dialog
+ */
+int req_outside(str* method, str* to, str* from, str* headers, str* body, dlg_t** dialog, transaction_cb cb, void* cbp)
 {
-	LOG(L_ERR, "ERROR: fifo_uac: %s\n", msg ); 
-	fifo_reply(reply_fifo, "%d fifo_uac: %s", code, msg);
-}
+	str callid, fromtag;
 
-/* syntax:
-
-	:t_uac_dlg:[file] EOL
-	method EOL
-	r-uri EOL 
-	dst EOL 				// ("." if no outbound server used)
-							// must be used with dialogs/lr
-	<EOL separated HFs>+	// From and To must be present at least;
-							// dialog-apps must include tag in From
- 							// (an ephemeral is appended otherwise)
-							// and supply CSeq/CallId
-	.[EOL]
-	[body] 
-	.EOL
-
-
-	there is also the possibility to have server placed its
-    hostname:portnumber in header fields -- just put double
-	exclamation mark in any of the optional header fields
-	(i.e., any but From/To/CallID,CSeq), they will be 
-	substituted hn:pn
-
-Example:
-
-sc fifo t_uac_dlg MESSAGE sip:[email protected] \
-	. \ # no outbound proxy
-	'From:[email protected];tagd=123'  \ # no to-tag -> ephemeral
-	'To:[email protected]' \
-	'Foo: sip:user@!! '  \ # expansion here
-	'CSEQ: 11 MESSAGE   ' \
-	. \ # EoH
-	.	# empty body
----
-U 192.168.2.16:5060 -> 192.168.2.1:5060
-MESSAGE sip:[email protected] SIP/2.0..
-Via: SIP/2.0/UDP 192.168.2.16;branch=z9hG4bK760c.922ea6a1.0..
-To: [email protected]..
-From: [email protected];tagd=123;tag=5405e669bc2980663aed2624dc31396f-fa77..
-CSeq: 11 MESSAGE..
-Call-ID: [email protected]..
-Content-Length: 0..
-User-Agent: Sip EXpress router (0.8.11pre4-tcp1-locking (i386/linux))..
-Foo: sip:[email protected]:5060..
-..
-
-
-*/
-
-int fifo_uac_dlg( FILE *stream, char *response_file ) 
-{
-	char method_buf[MAX_METHOD];
-	char ruri_buf[MAX_URI_SIZE];
-	char outbound_buf[MAX_URI_SIZE];
-	char header_buf[MAX_HEADER]; 
-	char body_buf[MAX_BODY]; 
-	str method, ruri, outbound, header, body;
-	str hfb; /* header field block */
-	struct sip_uri parsed_ruri, parsed_outbound;
-	str dummy_empty;
-	int fromtag;
-	int cseq;
-	struct cseq_body *parsed_cseq;
-	int i;
-	char c;
-	struct to_body *parsed_from;
-
-
-	char *shmem_file;
-	int fn_len;
-	int ret;
-	int sip_error;
-	char err_buf[MAX_REASON_LEN];
-	int err_ret;
-	struct sip_msg faked_msg;
-
-
-	if (!read_line(method_buf, MAX_METHOD, stream,&method.len)
-					||method.len==0) {
-		/* line breaking must have failed -- consume the rest
-		   and proceed to a new request
-		*/
-		fifo_uac_error(response_file, 400, "method expected");
-		return 1;
-	}
-	method.s=method_buf;
-	DBG("DEBUG: fifo_uac: method: %.*s\n", method.len, method.s );
+	if (check_params(method, to, from, dialog) < 0) goto err;
+	
+	generate_callid(&callid);
+	generate_fromtag(&fromtag, &callid);
 
-	if (!read_line(ruri_buf, MAX_URI_SIZE, stream, &ruri.len)
-					|| ruri.len==0) {
-		fifo_uac_error(response_file, 400, "ruri expected");
-		return 1;
-	}
-	if (parse_uri(ruri_buf, ruri.len, &parsed_ruri) < 0 ) {
-		fifo_uac_error(response_file, 400, "ruri invalid\n");
-		return 1;
+	if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, dialog) < 0) {
+		LOG(L_ERR, "req_outside(): Error while creating new dialog\n");
+		goto err;
 	}
-	ruri.s=ruri_buf;
-	DBG("DEBUG: fifo_uac:  ruri: %.*s\n", ruri.len, ruri.s);
 
-	if (!read_line(outbound_buf, MAX_URI_SIZE, stream, &outbound.len)
-					||outbound.len==0) {
-		fifo_uac_error(response_file, 400, "outbound address expected\n");
-		return 1;
-	}
-	if (outbound.len==1 && outbound_buf[0]=='.' ) {
-		DBG("DEBUG: fifo_uac: outbound empty\n");
-		outbound.s=0; outbound.len=0;
-	} else if (parse_uri(outbound_buf, outbound.len, 
-							&parsed_outbound) < 0 ) {
-		fifo_uac_error(response_file, 400, "outbound uri invalid\n");
-		return 1;
-	} else {
-		outbound.s=outbound_buf;
-		DBG("DEBUG: fifo_uac:  dst: %.*s\n", outbound.len, outbound.s);
-	}
+	return t_uac(method, headers, body, *dialog, cb, cbp);
 
+ err:
+	if (cbp) shm_free(cbp);
+	return -1;
+}
 
-	/* now read and parse header fields */
-	if (!read_line_set(header_buf, MAX_HEADER, stream, &header.len)
-					|| header.len==0 ) {
-		fifo_uac_error(response_file, 400, "HFs expected");
-		return 1;
-	}
-	header.s=header_buf;
-	DBG("DEBUG: fifo_uac: header: %.*s\n", header.len, header.s );
-	/* use SIP parser to look at what is in the FIFO request */
-	memset(&faked_msg, 0, sizeof(struct sip_msg));
-	faked_msg.len=header.len; 
-	faked_msg.buf=faked_msg.unparsed=header_buf;
-	if (parse_headers(&faked_msg, HDR_EOH, 0)==-1 ) {
-			DBG("DEBUG: fifo_uac: parse_headers failed\n");
-			fifo_uac_error(response_file, 400, "HFs unparseable");
-			goto error;
-	}
-	DBG("DEBUG: fifo_uac: parse_headers succeeded\n");
 
-	/* and eventually body */
-	if (!read_body(body_buf, MAX_BODY, stream, &body.len)) {
-		fifo_uac_error(response_file, 400, "body expected");
-		goto error;
-	}
-	body.s=body_buf;
-	DBG("DEBUG: fifo_uac: body: %.*s\n", body.len, body.s );
+/*
+ * Send a transactional request, no dialogs involved
+ */
+int request(str* m, str* ruri, str* to, str* from, str* h, str* b, transaction_cb c, void* cp)
+{
+	str callid, fromtag;
+	dlg_t* dialog;
+	int res;
 
+	if (check_params(m, to, from, &dialog) < 0) goto err;
 
-	/* at this moment, we collected all the things we got, let's
-	 * verify user has not forgotten something */
-	if (body.len && !faked_msg.content_type) {
-		fifo_uac_error(response_file, 400, "Content_type missing");
-		goto error;
-	}
-	if (body.len && faked_msg.content_length) {
-		fifo_uac_error(response_file, 400, "Content_length disallowed");
-		goto error;
-	}
-	if (!faked_msg.to) {
-		fifo_uac_error(response_file, 400, "To missing");
-		goto error;
-	}
-	if (!faked_msg.from) {
-		fifo_uac_error(response_file, 400, "From missing");
-		goto error;
-	}
-	/* we also need to know if there is from-tag and add it otherwise */
-	if (parse_from_header(&faked_msg)<0) {
-		fifo_uac_error(response_file, 400, "Error in From");
-		goto error;
-	}
-	parsed_from=(struct to_body*)faked_msg.from->parsed;
-	fromtag=parsed_from->tag_value.s &&
-			parsed_from->tag_value.len;
-	cseq=0;
-	if (faked_msg.cseq && (parsed_cseq=get_cseq(&faked_msg))) {
-		for (i=0; i<parsed_cseq->number.len; i++ ) {
-			c=parsed_cseq->number.s[i];
-			if (c>='0' && c<'9' ) cseq=cseq*10+c-'0';
-			else {
-				fifo_uac_error(response_file, 400, "non-nummerical CSeq");
-				goto error;
-			}
-		}
-		if (parsed_cseq->method.len!=method.len 
-				|| memcmp(parsed_cseq->method.s, method.s, method.len)!=0) {
-			fifo_uac_error(response_file, 400, "CSeq method mismatch");
-			goto error;
-		}
-	}
+	generate_callid(&callid);
+	generate_fromtag(&fromtag, &callid);
 
-	hfb.s=get_hfblock(outbound.len ? &outbound : &ruri, 
-					faked_msg.headers, &hfb.len, PROTO_UDP);
-	if (!hfb.s) {
-		fifo_uac_error(response_file, 500, "no mem for hf block");
-		goto error;
+	if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, &dialog) < 0) {
+		LOG(L_ERR, "req_outside(): Error while creating temorary dialog\n");
+		goto err;
 	}
 
-
-	DBG("DEBUG: fifo_uac: EoL -- proceeding to transaction creation\n");
-	/* we got it all, initiate transaction now! */
-	if (response_file) {
-		fn_len=strlen(response_file)+1;
-		shmem_file=shm_malloc(fn_len);
-		if (shmem_file==0) {
-			fifo_uac_error(response_file, 500, "no shmem");
-			goto error01;
-		}
-		memcpy(shmem_file, response_file, fn_len );
-	} else {
-		shmem_file=0;
-	}
-	/* HACK: there is yet a shortcoming -- if t_uac fails, callback
-	   will not be triggered and no feedback will be printed
-	   to shmem_file
-	*/
-	dummy_empty.s=0; dummy_empty.len=0;
-	ret=t_uac_dlg( &method, 
-		outbound.len ? &outbound: 0,
-		PROTO_UDP,
-		&ruri, 
-		&faked_msg.to->body,	/* possibly w/to-tag in it */
-		&faked_msg.from->body,
-		&dummy_empty,			/* if present, to-tag passed in to */
-		fromtag ? 				/* if fromtag present, ... */
-			&dummy_empty: 		/* ... pass it in from ... */
-			0,					/* use ephemeral otherwise */
-		cseq ? &cseq : 0,
-		faked_msg.callid ?
-			&faked_msg.callid->body:
-			0,
-		&hfb, 						/* headers -- TBD */
-		&body,
-		fifo_callback, shmem_file );
-
-
-	if (ret<=0) {
-		err_ret=err2reason_phrase(ret, &sip_error, err_buf,
-				sizeof(err_buf), "FIFO/UAC" ) ;
-		if (err_ret > 0 )
-		{
-
-			fifo_uac_error(response_file, sip_error, err_buf);
-		} else {
-			fifo_uac_error(response_file, 500, "FIFO/UAC error" );
-		}
+	if (ruri) {
+		dialog->rem_target.s = ruri->s;
+		dialog->rem_target.len = ruri->len;
+		dialog->hooks.request_uri = &dialog->rem_target;
 	}
 
-error01:
-	pkg_free(hfb.s);
+	res = t_uac(m, h, b, dialog, c, cp);
+	free_dlg(dialog);
+	return res;
 
-error:
-	/* free_sip_msg(&faked_msg); */
-	if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);
-	return 1;
+ err:
+	if (cp) shm_free(cp);
+	return -1;
 }

+ 41 - 42
modules/tm/uac.h

@@ -30,62 +30,61 @@
  * 2003-02-28 protocolization of t_uac_dlg completed (jiri)
  */
 
-
 #ifndef _UAC_H
 #define _UAC_H
 
-#include "defs.h"
+#include <stdio.h>
+#include "../../str.h"
+#include "dlg.h"
+#include "t_hooks.h"
 
+#define DEFAULT_CSEQ 10 /* Default CSeq number */
 
-#include <stdio.h>
-#include "config.h"
-#include "t_dlg.h"
+extern char *uac_from;  /* UAC From parameter */
+
+
+/*
+ * Function prototypes
+ */
+typedef int (*reqwith_t)(str* m, str* h, str* b, dlg_t* d, transaction_cb c, void* cp);
+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, transaction_cb c, void* cp);
+
+
+/*
+ * Generate a fromtag based on given Call-ID
+ */
+void generate_fromtag(str* tag, str* callid);
 
-/* substitution character for FIFO UAC */
-#define SUBST_CHAR '!'
 
-#define DEFAULT_CSEQ	10
+/*
+ * Initialization function
+ */
+int uac_init(void);
+
 
-extern char *uac_from;
-extern char *fifo;
-extern int fifo_mode;
+/*
+ * Send a request
+ */
+int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp);
 
-int uac_init();
-int uac_child_init( int rank );
 
-typedef int (*tuac_f)(str *msg_type, str *dst, str *headers,str *body,
-	str *from, transaction_cb completion_cb, void *cbp,
-	struct dialog *dlg );
+/*
+ * Send a message within a dialog
+ */
+int req_within(str* m, str* h, str* b, dlg_t* d, transaction_cb c, void* cp);
+
+
+/*
+ * Send an initial request that will start a dialog
+ */
+int req_outside(str* m, str* t, str* f, str* h, str* b, dlg_t** d, transaction_cb c, void* cp);
 
-typedef int (*tuacdlg_f)(str* msg_type, str* dst, int proto, str* ruri, str* to,
-			 str* from, str* totag, str* fromtag, int* cseq,
-			 str* callid, str* headers, str* body,
-			 transaction_cb completion_cb, void* cbp
-			 );
 
-/* look at uac.c for usage guidelines */
 /*
- * Send a request within a dialog
+ * Send a transactional request, no dialogs involved
  */
-int t_uac_dlg(str* msg,                     /* Type of the message - MESSAGE, OPTIONS etc. */
-	      str* dst,                     /* Real destination (can be different 
-										   than R-URI */
-		  int proto,
-	      str* ruri,                    /* Request-URI */
-	      str* to,                      /* To - including tag */
-	      str* from,                    /* From - including tag */
-	      str* totag,                   /* To tag */
-	      str* fromtag,                 /* From tag */
-	      int* cseq,                    /* CSeq */
-	      str* cid,                     /* Call-ID */
-	      str* headers,                 /* Optional headers including CRLF */
-	      str* body,                    /* Message body */
-	      transaction_cb completion_cb, /* Callback parameter */
-	      void* cbp                     /* Callback pointer */
-	      );
-
-
-int fifo_uac_dlg( FILE *stream, char *response_file );
+int request(str* m, str* ruri, str* to, str* from, str* h, str* b, transaction_cb c, void* cp);
 
 
 #endif

+ 640 - 0
modules/tm/uac_fifo.c

@@ -0,0 +1,640 @@
+/*
+ * $Id$
+ */
+
+#include <string.h>
+#include "../../mem/shm_mem.h"
+#include "../../mem/mem.h"
+#include "../../dprint.h"
+#include "../../fifo_server.h"
+#include "../../str.h"
+#include "../../parser/msg_parser.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_uri.h"
+#include "../../ip_addr.h"
+#include "config.h"
+#include "ut.h"
+#include "uac.h"
+#include "dlg.h"
+#include "callid.h"
+#include "h_table.h"
+#include "uac_fifo.h"
+
+
+/*
+ * Callback data structure
+ */
+struct cb_data {
+	dlg_t* dialog;
+	char filename[1];
+};
+
+
+struct str_list {
+        str s;
+        struct str_list *next;
+};
+
+
+#define skip_hf(_hf) (             \
+    ((_hf)->type == HDR_FROM)   || \
+    ((_hf)->type == HDR_TO)     || \
+    ((_hf)->type == HDR_CALLID) || \
+    ((_hf)->type == HDR_CSEQ)      \
+)
+
+
+/*
+ * Report an error to syslog and FIFO output file
+ */
+static inline void fifo_uac_error(char *reply_fifo, int code, char *msg)
+{
+	LOG(L_ERR, "ERROR: fifo_uac: %s\n", msg ); 
+	fifo_reply(reply_fifo, "%d fifo_uac: %s", code, msg);
+}
+
+
+/*
+ * Get the Request URI from the FIFO stream and parse it
+ */
+static inline int fifo_get_ruri(FILE* stream, char* response_file, str* ruri, struct sip_uri* puri)
+{
+	static char ruri_buf[MAX_URI_SIZE];
+
+	if (!read_line(ruri_buf, MAX_URI_SIZE, stream, &ruri->len) || !ruri->len) {
+		fifo_uac_error(response_file, 400, "ruri expected");
+		return -1;
+	}
+	
+	if (parse_uri(ruri_buf, ruri->len, puri) < 0 ) {
+		fifo_uac_error(response_file, 400, "ruri invalid\n");
+		return -2;
+	}
+	ruri->s = ruri_buf;
+	DBG("DEBUG: fifo_get_ruri: '%.*s'\n", ruri->len, ruri->s);
+	return 0;
+}
+
+
+/*
+ * Get and parse next hop URI
+ */
+static inline int fifo_get_nexthop(FILE* stream, char* response_file, str* nexthop, struct sip_uri* pnexthop)
+{
+	static char nexthop_buf[MAX_URI_SIZE];
+
+	if (!read_line(nexthop_buf, MAX_URI_SIZE, stream, &nexthop->len) || !nexthop->len) {
+		fifo_uac_error(response_file, 400, "next hop address expected\n");
+		return -1;
+	}
+
+	if (nexthop->len == 1 && nexthop_buf[0] == '.' ) {
+		DBG("DEBUG: fifo_get_nexthop: next hop empty\n");
+		nexthop->s = 0; 
+		nexthop->len = 0;
+	} else if (parse_uri(nexthop_buf, nexthop->len, pnexthop) < 0 ) {
+		fifo_uac_error(response_file, 400, "next hop uri invalid\n");
+		return -2;
+	} else {
+		nexthop->s = nexthop_buf;
+		DBG("DEBUG: fifo_get_nexthop: hop: '%.*s'\n", nexthop->len, nexthop->s);
+	}
+
+	return 0;
+}
+
+
+/*
+ * Get method name from FIFO stream
+ */
+static inline int fifo_get_method(FILE* stream, char* response_file, str* method)
+{
+	static char method_buf[MAX_METHOD];
+
+	if (!read_line(method_buf, MAX_METHOD, stream, &method->len) || !method->len) {
+		     /* line breaking must have failed -- consume the rest
+			and proceed to a new request
+		     */
+		fifo_uac_error(response_file, 400, "method expected");
+		return -1;
+	}
+	method->s = method_buf;
+	DBG("fifo_get_method: method: '%.*s'\n", method->len, method->s);
+	return 0;
+}
+
+
+/*
+ * Get message body from FIFO stream
+ */
+static inline int fifo_get_body(FILE* stream, char* response_file, str* body)
+{
+	static char body_buf[MAX_BODY];
+
+	if (!read_body(body_buf, MAX_BODY, stream, &body->len)) {
+		fifo_uac_error(response_file, 400, "body expected");
+		return -1;
+	}
+	body->s = body_buf;
+	DBG("fifo_get_body: body: %.*s\n", body->len,  body->s);
+	return 0;
+}
+
+
+/*
+ * Get message headers from FIFO stream
+ */
+static inline int fifo_get_headers(FILE* stream, char* response_file, str* headers)
+{
+	static char headers_buf[MAX_HEADER];
+
+	     /* now read and parse header fields */
+	if (!read_line_set(headers_buf, MAX_HEADER, stream, &headers->len) || !headers->len) {
+		fifo_uac_error(response_file, 400, "HFs expected");
+		return -1;
+	}
+	headers->s = headers_buf;
+	DBG("fifo_get_headers: headers: %.*s\n", headers->len, headers->s);
+	return 0;
+}
+
+
+/*
+ * Create shm_copy of filename
+ */
+static inline int fifo_cbp(char** shm_file, char* response_file)
+{
+	int fn_len;
+
+	if (response_file) {
+		fn_len = strlen(response_file) + 1;
+		*shm_file = shm_malloc(fn_len);
+		if (!*shm_file) {
+			fifo_uac_error(response_file, 500, "no shmem");
+			return -1;
+		}
+		memcpy(*shm_file, response_file, fn_len);
+	} else {
+		shm_file = 0;
+	}
+	return 0;
+}
+
+
+static inline struct str_list *new_str(char *s, int len, struct str_list **last, int *total)
+{
+	struct str_list *new;
+	new=pkg_malloc(sizeof(struct str_list));
+	if (!new) {
+		LOG(L_ERR, "ERROR: get_hfblock: not enough mem\n");
+		return 0;
+	}
+	new->s.s=s;
+	new->s.len=len;
+	new->next=0;
+
+	(*last)->next=new;
+	*last=new;
+	*total+=len;
+
+	return new;
+}
+
+
+static char *get_hfblock(str *uri, struct hdr_field *hf, int *l, int proto) 
+{
+	struct str_list sl, *last, *new, *i, *foo;
+	int hf_avail, frag_len, total_len;
+	char *begin, *needle, *dst, *ret, *d;
+	str *sock_name, *portname;
+	union sockaddr_union to_su;
+	struct socket_info* send_sock;
+
+	ret=0; /* pesimist: assume failure */
+	total_len=0;
+	last=&sl;
+	last->next=0;
+	portname=sock_name=0;
+
+	for (; hf; hf=hf->next) {
+		if (skip_hf(hf)) continue;
+
+		begin=needle=hf->name.s; 
+		hf_avail=hf->len;
+
+		/* substitution loop */
+		while(hf_avail) {
+			d=memchr(needle, SUBST_CHAR, hf_avail);
+			if (!d || d+1>=needle+hf_avail) { /* nothing to substitute */
+				new=new_str(begin, hf_avail, &last, &total_len); 
+				if (!new) goto error;
+				break;
+			} else {
+				frag_len=d-begin;
+				d++; /* d not at the second substitution char */
+				switch(*d) {
+					case SUBST_CHAR:	/* double SUBST_CHAR: IP */
+						/* string before substitute */
+						new=new_str(begin, frag_len, &last, &total_len); 
+						if (!new) goto error;
+						/* substitute */
+						if (!sock_name) {
+							send_sock=uri2sock( uri, &to_su, proto );
+							if (!send_sock) {
+								LOG(L_ERR, "ERROR: get_hf_block: send_sock failed\n");
+								goto error;
+							}
+							sock_name=&send_sock->address_str;
+							portname=&send_sock->port_no_str;
+						}
+						new=new_str(sock_name->s, sock_name->len,
+								&last, &total_len );
+						if (!new) goto error;
+						/* inefficient - FIXME --andrei*/
+						new=new_str(":", 1, &last, &total_len);
+						if (!new) goto error;
+						new=new_str(portname->s, portname->len,
+								&last, &total_len );
+						if (!new) goto error;
+						/* keep going ... */
+						begin=needle=d+1;hf_avail-=frag_len+2;
+						continue;
+					default:
+						/* no valid substitution char -- keep going */
+						hf_avail-=frag_len+1;
+						needle=d;
+				}
+			} /* possible substitute */
+		} /* substitution loop */
+		/* proceed to next header */
+		/* new=new_str(CRLF, CRLF_LEN, &last, &total_len );
+		if (!new) goto error; */
+		DBG("DEBUG: get_hf_block: one more hf processed\n");
+	} /* header loop */
+
+
+	/* construct a single header block now */
+	ret=pkg_malloc(total_len);
+	if (!ret) {
+		LOG(L_ERR, "ERROR: get_hf_block no pkg mem for hf block\n");
+		goto error;
+	}
+	i=sl.next;
+	dst=ret;
+	while(i) {
+		foo=i;
+		i=i->next;
+		memcpy(dst, foo->s.s, foo->s.len);
+		dst+=foo->s.len;
+		pkg_free(foo);
+	}
+	*l=total_len;
+	return ret;
+
+error:
+	i=sl.next;
+	while(i) {
+		foo=i;
+		i=i->next;
+		pkg_free(foo);
+	}
+	*l=0;
+	return 0;
+}
+
+
+/* syntax:
+
+	:t_uac:[file] EOL
+	method EOL
+	r-uri EOL 
+	dst EOL 				// ("." if no outbound server used)
+							// must be used with dialogs/lr
+	<EOL separated HFs>+	// From and To must be present at least;
+							// dialog-apps must include tag in From
+ 							// (an ephemeral is appended otherwise)
+							// and supply CSeq/CallId
+	.[EOL]
+	[body] 
+	.EOL
+
+
+	there is also the possibility to have server placed its
+    hostname:portnumber in header fields -- just put double
+	exclamation mark in any of the optional header fields
+	(i.e., any but From/To/CallID,CSeq), they will be 
+	substituted hn:pn
+
+Example:
+
+sc fifo t_uac_dlg MESSAGE sip:[email protected] \
+	. \ # no outbound proxy
+	'From:[email protected];tagd=123'  \ # no to-tag -> ephemeral
+	'To:[email protected]' \
+	'Foo: sip:user@!! '  \ # expansion here
+	'CSEQ: 11 MESSAGE   ' \
+	. \ # EoH
+	.	# empty body
+---
+U 192.168.2.16:5060 -> 192.168.2.1:5060
+MESSAGE sip:[email protected] SIP/2.0..
+Via: SIP/2.0/UDP 192.168.2.16;branch=z9hG4bK760c.922ea6a1.0..
+To: [email protected]..
+From: [email protected];tagd=123;tag=5405e669bc2980663aed2624dc31396f-fa77..
+CSeq: 11 MESSAGE..
+Call-ID: [email protected]..
+Content-Length: 0..
+User-Agent: Sip EXpress router (0.8.11pre4-tcp1-locking (i386/linux))..
+Foo: sip:[email protected]:5060..
+..
+
+
+*/
+
+
+/*
+ * Make sure that the FIFO user created the message
+ * correctly
+ */
+static inline int fifo_check_msg(struct sip_msg* msg, str* method, char* resp, str* body, 
+				 int* fromtag, int *cseq_is, int* cseq, str* callid)
+{
+	struct to_body* parsed_from;
+	struct cseq_body *parsed_cseq;
+	int i;
+	char c;
+
+	if (body->len && !msg->content_type) {
+		fifo_uac_error(resp, 400, "Content-Type missing");
+		return -1;
+	}
+
+	if (body->len && msg->content_length) {
+		fifo_uac_error(resp, 400, "Content-Length disallowed");
+		return -2;
+	}
+
+	if (!msg->to) {
+		fifo_uac_error(resp, 400, "To missing");
+		return -3;
+	}
+
+	if (!msg->from) {
+		fifo_uac_error(resp, 400, "From missing");
+		return -4;
+	}
+
+	     /* we also need to know if there is from-tag and add it otherwise */
+	if (parse_from_header(msg) < 0) {
+		fifo_uac_error(resp, 400, "Error in From");
+		return -5;
+	}
+
+	parsed_from = (struct to_body*)msg->from->parsed;
+	*fromtag = parsed_from->tag_value.s && parsed_from->tag_value.len;
+
+	*cseq = 0;
+	if (msg->cseq && (parsed_cseq = get_cseq(msg))) {
+		*cseq_is = 1;
+		for (i = 0; i < parsed_cseq->number.len; i++) {
+			c = parsed_cseq->number.s[i];
+			if (c >= '0' && c < '9' ) *cseq = (*cseq) * 10 + c - '0';
+			else {
+				fifo_uac_error(resp, 400, "non-nummerical CSeq");
+				return -6;
+			}
+		}
+		
+		if (parsed_cseq->method.len != method->len 
+		    || memcmp(parsed_cseq->method.s, method->s, method->len) !=0 ) {
+			fifo_uac_error(resp, 400, "CSeq method mismatch");
+			return -7;
+		}
+	} else {
+		*cseq_is = 0;
+	}
+
+	if (msg->callid) {
+		callid->s = msg->callid->body.s;
+		callid->len = msg->callid->body.len;
+	} else {
+		callid->s = 0;
+		callid->len = 0;
+	}
+
+	return 0;
+}
+
+
+#define FIFO_ROUTE_PREFIX "Route: "
+#define FIFO_ROUTE_SEPARATOR ", "
+
+static inline void print_routes(FILE* out, dlg_t* _d)
+{
+	rr_t* ptr;
+
+	ptr = _d->hooks.first_route;
+
+	if (ptr) {
+		fprintf(out, FIFO_ROUTE_PREFIX);
+	} else {
+		fprintf(out, ".\n");
+		return;
+	}
+
+	while(ptr) {
+		fprintf(out, "%.*s", ptr->len, ptr->nameaddr.name.s);
+
+		ptr = ptr->next;
+		if (ptr) {
+			fprintf(out, FIFO_ROUTE_SEPARATOR);
+		}
+	} 
+
+	if (_d->hooks.last_route) {
+		fprintf(out, FIFO_ROUTE_SEPARATOR "<");
+		fprintf(out, "%.*s", _d->hooks.last_route->len, _d->hooks.last_route->s);
+		fprintf(out, ">");
+	}
+
+	if (_d->hooks.first_route) {
+		fprintf(out, CRLF);
+	}
+}
+
+
+static inline int print_uris(FILE* out, struct sip_msg* reply)
+{
+	dlg_t* dlg;
+	
+	dlg = (dlg_t*)shm_malloc(sizeof(dlg_t));
+	if (!dlg) {
+		LOG(L_ERR, "print_routes(): No memory left\n");
+		return -1;
+	}
+
+	memset(dlg, 0, sizeof(dlg_t));
+	if (dlg_response_uac(dlg, reply) < 0) {
+		LOG(L_ERR, "print_routes(): Error while creating dialog structure\n");
+		return -2;
+	}
+
+	if (dlg->state != DLG_CONFIRMED) {
+		fprintf(out, ".\n.\n.\n");
+		free_dlg(dlg);
+		return 0;
+	}
+
+	if (dlg->hooks.request_uri->s) {	
+		fprintf(out, "%.*s\n", dlg->hooks.request_uri->len, dlg->hooks.request_uri->s);
+	} else {
+		fprintf(out, ".\n");
+	}
+	if (dlg->hooks.next_hop->s) {
+		fprintf(out, "%.*s\n", dlg->hooks.next_hop->len, dlg->hooks.next_hop->s);
+	} else {
+		fprintf(out, ".\n");
+	}
+	print_routes(out, dlg);
+	free_dlg(dlg);
+	return 0;
+}
+
+
+static void fifo_callback(struct cell *t, struct sip_msg *reply,
+			  int code, void *param)
+{
+	
+	char *filename;
+	FILE* f;
+	str text;
+
+	DBG("!!!!! ref_counter: %d\n", t->ref_count);
+
+	DBG("DEBUG: fifo UAC completed with status %d\n", code);
+	if (!t->cbp) {
+		LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", code);
+		return;
+	}
+
+	filename=(char *)(t->cbp);
+	if (reply==FAKED_REPLY) {
+		get_reply_status(&text,reply,code);
+		if (text.s==0) {
+			LOG(L_ERR, "ERROR: fifo_callback: get_reply_status failed\n");
+			fifo_reply(filename, "500 fifo_callback: get_reply_status failed\n");
+			return;
+		}
+		fifo_reply(filename, "%.*s\n", text.len, text.s );
+		pkg_free(text.s);
+	} else {
+		text.s=reply->first_line.u.reply.reason.s;
+		text.len=reply->first_line.u.reply.reason.len;
+
+		f = fopen(filename, "wt");
+		if (!f) return;
+		fprintf(f, "%d %.*s\n", reply->first_line.u.reply.statuscode, text.len, text.s);
+		print_uris(f, reply);
+		fprintf(f, "%s\n", reply->headers->name.s);
+		fclose(f);
+	}
+	DBG("DEBUG: fifo_callback sucesssfuly completed\n");
+}	
+
+
+int fifo_uac(FILE *stream, char *response_file)
+{
+	str method, ruri, nexthop, headers, body, hfb, callid;
+	struct sip_uri puri, pnexthop;
+	struct sip_msg faked_msg;
+	int ret, sip_error, err_ret;
+	int fromtag, cseq_is, cseq;
+	struct cb_data;
+	char err_buf[MAX_REASON_LEN];
+	char* shm_file;
+	dlg_t dlg;
+
+	if (fifo_get_method(stream, response_file, &method) < 0) return 1;
+	if (fifo_get_ruri(stream, response_file, &ruri, &puri) < 0) return 1;
+	if (fifo_get_nexthop(stream, response_file, &nexthop, &pnexthop) < 0) return 1;
+	if (fifo_get_headers(stream, response_file, &headers) < 0) return 1;
+
+	/* use SIP parser to look at what is in the FIFO request */
+	memset(&faked_msg, 0, sizeof(struct sip_msg));
+	faked_msg.len = headers.len; 
+	faked_msg.buf = faked_msg.unparsed = headers.s;
+	if (parse_headers(&faked_msg, HDR_EOH, 0) == -1 ) {
+		DBG("DEBUG: fifo_uac: parse_headers failed\n");
+		fifo_uac_error(response_file, 400, "HFs unparseable");
+		goto error;
+	}
+	DBG("DEBUG: fifo_uac: parse_headers succeeded\n");
+
+	if (fifo_get_body(stream, response_file, &body) < 0) goto error;
+	
+	     /* at this moment, we collected all the things we got, let's
+	      * verify user has not forgotten something */
+	if (fifo_check_msg(&faked_msg, &method, response_file, &body, &fromtag, 
+			   &cseq_is, &cseq, &callid) < 0) goto error;
+
+	hfb.s = get_hfblock(nexthop.len ? &nexthop : &ruri, 
+			    faked_msg.headers, &hfb.len, PROTO_UDP);
+	if (!hfb.s) {
+		fifo_uac_error(response_file, 500, "no mem for hf block");
+		goto error;
+	}
+
+	DBG("DEBUG: fifo_uac: EoL -- proceeding to transaction creation\n");
+
+	memset(&dlg, 0, sizeof(dlg_t));
+	     /* Fill in Call-ID, use given Call-ID if
+	      * present and generate it if not present
+	      */
+	if (callid.s && callid.len) dlg.id.call_id = callid;
+	else generate_callid(&dlg.id.call_id);
+	
+	     /* We will not fill in dlg->id.rem_tag because
+	      * if present it will be printed within To HF
+	      */
+	
+	     /* Generate fromtag if not present */
+	if (!fromtag) {
+		generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);
+	}
+
+	     /* Fill in CSeq */
+	if (cseq_is) dlg.loc_seq.value = cseq;
+	else dlg.loc_seq.value = DEFAULT_CSEQ;
+	dlg.loc_seq.is_set = 1;
+
+	dlg.loc_uri = faked_msg.from->body;
+	dlg.rem_uri = faked_msg.to->body;
+	dlg.hooks.request_uri = &ruri;
+	dlg.hooks.next_hop = (nexthop.len ? &nexthop : &ruri);
+
+	print_dlg(stderr, &dlg);
+
+	/* we got it all, initiate transaction now! */
+	if (fifo_cbp(&shm_file, response_file) < 0) goto error01;
+
+	ret = t_uac(&method, &hfb, &body, &dlg, fifo_callback, shm_file);
+
+	if (ret <= 0) {
+		err_ret = err2reason_phrase(ret, &sip_error, err_buf,
+					    sizeof(err_buf), "FIFO/UAC") ;
+		if (err_ret > 0 )
+		{
+			fifo_uac_error(response_file, sip_error, err_buf);
+		} else {
+			fifo_uac_error(response_file, 500, "FIFO/UAC error");
+		}
+	}
+	
+ error01:
+	pkg_free(hfb.s);
+	
+ error:
+	     /* free_sip_msg(&faked_msg); */
+	if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);
+	return 1;
+}

+ 17 - 0
modules/tm/uac_fifo.h

@@ -0,0 +1,17 @@
+/*
+ * UAC FIFO interface
+ */
+
+#ifndef UAC_FIFO_H
+#define UAC_FIFO_H
+
+#include <stdio.h>
+
+
+/*
+ * FIFO function for sending messages
+ */
+int fifo_uac(FILE *stream, char *response_file);
+
+
+#endif /* UAC_FIFO_H */

+ 78 - 59
modules/tm/ut.h

@@ -26,99 +26,118 @@
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/*
+ *
  * History:
  * -------
  *  2003-02-13  added proto to uri2proxy (andrei)
+ *  2003-04-09  uri2sock moved from uac.c (janakj)
  *  2003-04-14  added get_proto to determine protocol from uri unless
  *              specified explicitely (jiri)
-*/
+ */
 
 
 #ifndef _TM_UT_H
 #define _TM_UT_H
 
-#include "defs.h"
-#include "../../ip_addr.h"
-
 
+#include "../../proxy.h"
+#include "../../str.h"
+#include "../../parser/parse_uri.h"
 #include "../../dprint.h"
-#include "../../error.h"
 #include "../../ut.h"
-#include "../../str.h"
+#include "../../ip_addr.h"
+#include "../../error.h"
+#include "../../forward.h"
+#include "../../mem/mem.h"
 #include "../../parser/msg_parser.h"
 
-
 inline static enum sip_protos get_proto(enum sip_protos force_proto,
-	struct sip_uri *u)
+       struct sip_uri *u)
 {
-	/* calculate transport protocol */
-	switch(force_proto) {
-		case PROTO_NONE: 	/* no protocol has been forced -- look at uri */
-			switch(u->proto) {
-				case PROTO_NONE: /* uri default to UDP */
-					return PROTO_UDP;
-				case PROTO_UDP: /* transport specified explicitely */
+       /* calculate transport protocol */
+       switch(force_proto) {
+               case PROTO_NONE:        /* no protocol has been forced -- look at uri */
+                       switch(u->proto) {
+                               case PROTO_NONE: /* uri default to UDP */
+                                       return PROTO_UDP;
+                               case PROTO_UDP: /* transport specified explicitely */
 #ifdef USE_TCP
-				case PROTO_TCP:
+                               case PROTO_TCP:
 #endif
-					return u->proto;
-				default:
-					LOG(L_ERR, "ERROR: get_proto: unsupported transport: %d\n",
-						u->proto );
-					return PROTO_NONE;
-			}
-		case PROTO_UDP: /* some protocol has been forced -- take it */
+                                       return u->proto;
+                               default:
+                                       LOG(L_ERR, "ERROR: get_proto: unsupported transport: %d\n",
+                                               u->proto );
+                                       return PROTO_NONE;
+                       }
+               case PROTO_UDP: /* some protocol has been forced -- take it */
 #ifdef USE_TCP
-		case PROTO_TCP:
+               case PROTO_TCP:
 #endif
-			return force_proto;
-		default:
-			LOG(L_ERR, "ERROR: get_proto: unsupported forced protocol: "
-				"%d\n", force_proto);
-			return PROTO_NONE;
-	}
+                       return force_proto;
+               default:
+                       LOG(L_ERR, "ERROR: get_proto: unsupported forced protocol: "
+                               "%d\n", force_proto);
+                       return PROTO_NONE;
+       }
 }
 
+
+
+/*
+ * Convert a URI into a proxy structure
+ */
 inline static struct proxy_l *uri2proxy( str *uri, int proto )
 {
 	struct sip_uri parsed_uri;
-	unsigned int  port; 
 	struct proxy_l *p;
-	int err;
-	enum sip_protos out_proto;
 
-	if (parse_uri(uri->s, uri->len, &parsed_uri)<0) {
-		LOG(L_ERR, "ERROR: t_relay: bad_uri: %.*s\n",
-			uri->len, uri->s );
+	if (parse_uri(uri->s, uri->len, &parsed_uri) < 0) {
+		LOG(L_ERR, "ERROR: uri2proxy: bad_uri: %.*s\n",
+		    uri->len, uri->s );
 		return 0;
 	}
-	if (parsed_uri.port.s){ 
-		port=str2s(parsed_uri.port.s, parsed_uri.port.len, &err);
-		if (err){
-			LOG(L_ERR, "ERROR: t_relay: bad port in uri: <%.*s>\n",
-				parsed_uri.port.len, parsed_uri.port.s);
-			return 0;
-		}
-	/* fixed use of SRV resolver
-	} else port=SIP_PORT; */
-	} else port=0;
-
-	out_proto=get_proto(proto,&parsed_uri);
-	if (out_proto==PROTO_NONE) {
-		LOG(L_ERR, "ERROR: uri2proxy: transport can't be determined "
-			"for URI <%.*s>\n", uri->len, uri->s );
+	
+	p = mk_proxy(&parsed_uri.host, 
+		      parsed_uri.port_no, 
+		      get_proto(proto, &parsed_uri));
+	if (p == 0) {
+		LOG(L_ERR, "ERROR: uri2proxy: bad host name in URI <%.*s>\n",
+		    uri->len, ZSW(uri->s));
 		return 0;
 	}
+	
+	return p;
+}
+
+
+/*
+ * Convert a URI into socket_info
+ */
+static inline struct socket_info *uri2sock(str *uri, union sockaddr_union *to_su, int proto)
+{
+	struct proxy_l *proxy;
+	struct socket_info* send_sock;
 
-	p=mk_proxy(&(parsed_uri.host), port, out_proto);
-	if (p==0) {
-		LOG(L_ERR, "ERROR: t_relay: bad host name in URI <%.*s>\n",
-			uri->len, uri->s);
+	proxy = uri2proxy(uri, proto);
+	if (!proxy) {
+		ser_error = E_BAD_ADDRESS;
+		LOG(L_ERR, "ERROR: uri2sock: Can't create a dst proxy\n");
 		return 0;
 	}
-	return p;
+	
+	hostent2su(to_su, &proxy->host, proxy->addr_idx, 
+		   (proxy->port) ? proxy->port : SIP_PORT);
+	send_sock = get_send_socket(to_su, proxy->proto);
+	if (!send_sock) {
+		LOG(L_ERR, "ERROR: uri2sock: no corresponding socket for af %d\n", 
+		    to_su->s.sa_family);
+		ser_error = E_NO_SOCKET;
+	}
+
+	free_proxy(proxy);
+	pkg_free(proxy);
+	return send_sock;
 }
 
-#endif
+#endif /* _TM_UT_H */