- dialog support added
authorJan Janak <jan@iptel.org>
Wed, 30 Apr 2003 18:50:58 +0000 (18:50 +0000)
committerJan Janak <jan@iptel.org>
Wed, 30 Apr 2003 18:50:58 +0000 (18:50 +0000)
- new functions for sending messages within and outside a dialog
- bugfixes
- neverending fifo functions split in smaller pieces

20 files changed:
modules/tm/Makefile
modules/tm/config.h
modules/tm/dlg.c
modules/tm/dlg.h
modules/tm/t_cancel.c
modules/tm/t_fwd.c
modules/tm/t_fwd.h
modules/tm/t_lookup.c
modules/tm/t_msgbuilder.c
modules/tm/t_msgbuilder.h
modules/tm/t_reply.c
modules/tm/t_reply.h
modules/tm/tm.c
modules/tm/tm_load.c
modules/tm/tm_load.h
modules/tm/uac.c
modules/tm/uac.h
modules/tm/uac_fifo.c [new file with mode: 0644]
modules/tm/uac_fifo.h [new file with mode: 0644]
modules/tm/ut.h

index 4852bf5..2d199f7 100644 (file)
@@ -7,6 +7,6 @@
 
 auto_gen=
 NAME=tm.so
-LIBS= 
+LIBS=
 
 include ../../Makefile.modules
index 95e9d54..8447eb8 100644 (file)
@@ -92,4 +92,7 @@
 /* to-tag separator for stateful processing */
 #define TM_TAG_SEPARATOR '-'
 
+/* FIFO substitution character */
+#define SUBST_CHAR '!'
+
 #endif
index c7244dd..42a0f4a 100644 (file)
@@ -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 */
 #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;
index cf5aadc..98c3453 100644 (file)
@@ -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);
 
 
 /*
index 43ed544..9a97ec2 100644 (file)
@@ -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;
        }
 
index 70b16b5..61e1dca 100644 (file)
@@ -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;
index c82f1a4..8511ca9 100644 (file)
@@ -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,
index fe86632..6d2c47f 100644 (file)
@@ -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");
index 30e4892..521c584 100644 (file)
@@ -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;
 }
 
 
index 4d23ea0..dbec283 100644 (file)
@@ -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,
index f7cd0d7..22d7a78 100644 (file)
@@ -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;
index 94c383f..c12d364 100644 (file)
@@ -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;
index d7388d7..3a6b438 100644 (file)
 #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
index 4970632..7765f09 100644 (file)
@@ -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;
-
 }
index b1092b5..4d1fdb5 100644 (file)
 #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;
 };
 
 
index 9c20a77..96ed2f2 100644 (file)
  * 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)
  *  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:foo@foo.bar"; /* 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:joe@192.168.2.1 \
-       . \ # no outbound proxy
-       'From:sender@iptel.org;tagd=123'  \ # no to-tag -> ephemeral
-       'To:sender@iptel.org' \
-       'Foo: sip:user@!! '  \ # expansion here
-       'CSEQ: 11 MESSAGE   ' \
-       . \ # EoH
-       .       # empty body
----
-U 192.168.2.16:5060 -> 192.168.2.1:5060
-MESSAGE sip:joe@192.168.2.1 SIP/2.0..
-Via: SIP/2.0/UDP 192.168.2.16;branch=z9hG4bK760c.922ea6a1.0..
-To: sender@iptel.org..
-From: sender@iptel.org;tagd=123;tag=5405e669bc2980663aed2624dc31396f-fa77..
-CSeq: 11 MESSAGE..
-Call-ID: e863bf56-22255@192.168.2.16..
-Content-Length: 0..
-User-Agent: Sip EXpress router (0.8.11pre4-tcp1-locking (i386/linux))..
-Foo: sip:user@192.168.2.16: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;
 }
index 1e3f19a..3b0611a 100644 (file)
  * 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
diff --git a/modules/tm/uac_fifo.c b/modules/tm/uac_fifo.c
new file mode 100644 (file)
index 0000000..e2b2032
--- /dev/null
@@ -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:joe@192.168.2.1 \
+       . \ # no outbound proxy
+       'From:sender@iptel.org;tagd=123'  \ # no to-tag -> ephemeral
+       'To:sender@iptel.org' \
+       'Foo: sip:user@!! '  \ # expansion here
+       'CSEQ: 11 MESSAGE   ' \
+       . \ # EoH
+       .       # empty body
+---
+U 192.168.2.16:5060 -> 192.168.2.1:5060
+MESSAGE sip:joe@192.168.2.1 SIP/2.0..
+Via: SIP/2.0/UDP 192.168.2.16;branch=z9hG4bK760c.922ea6a1.0..
+To: sender@iptel.org..
+From: sender@iptel.org;tagd=123;tag=5405e669bc2980663aed2624dc31396f-fa77..
+CSeq: 11 MESSAGE..
+Call-ID: e863bf56-22255@192.168.2.16..
+Content-Length: 0..
+User-Agent: Sip EXpress router (0.8.11pre4-tcp1-locking (i386/linux))..
+Foo: sip:user@192.168.2.16: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;
+}
diff --git a/modules/tm/uac_fifo.h b/modules/tm/uac_fifo.h
new file mode 100644 (file)
index 0000000..7d1493b
--- /dev/null
@@ -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 */
index 2258b6f..90d2899 100644 (file)
  * 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 */