Merge commit 'origin/andrei/type_conversion'
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 4 May 2009 21:38:12 +0000 (23:38 +0200)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 4 May 2009 21:38:12 +0000 (23:38 +0200)
* commit 'origin/andrei/type_conversion':
  script parsing: fix bug in expression error checking
  core expr eval: various fixes
  news: update (new operators, expr. eval behaviour a.s.o.)
  core: new script operators: eq, ne, ieq, ine
  core expr eval: fix assoc., commut and 0 adding for +, ==
  core expr eval: minor ==/!= optimization
  core expr eval: internal == & != int and str only versions
  core expr eval: special handling for undef cmp expr
  core eval expr: cache undefined results too
  core expr eval:  str automatic conversion to int
  core expr eval: undef conversion to int and str
  core expr eval: defined @select

88 files changed:
action.c
cfg.lex
cfg.y
dset.c
dset.h
forward.c
globals.h
lib/binrpc/binrpc_api.c
lib/binrpc/binrpc_api.h
main.c
modules/tm/README
modules/tm/callid.h
modules/tm/doc/functions.xml
modules/tm/h_table.h
modules/tm/t_cancel.h
modules/tm/t_funcs.c
modules/tm/t_funcs.h
modules/tm/t_fwd.c
modules/tm/t_lookup.c
modules/tm/t_lookup.h
modules/tm/t_reply.c
modules/tm/t_reply.h
modules/tm/t_suspend.c
modules/tm/tm_load.c
modules/tm/tm_load.h
modules/tm/uac.h
modules_k/auth_diameter/auth_diameter.h
modules_k/dialog/dlg_handlers.c
modules_k/dialog/dlg_handlers.h
modules_k/dialog/dlg_hash.c
modules_k/dialog/dlg_hash.h
modules_k/dialog/dlg_req_within.h
modules_k/dialog/dlg_transfer.c
modules_k/dialog/dlg_var.h
modules_k/dispatcher/dispatch.h
modules_k/kex/README
modules_k/kex/doc/kex_admin.xml
modules_k/kex/flags.c [new file with mode: 0644]
modules_k/kex/flags.h [new file with mode: 0644]
modules_k/kex/kex_mod.c
modules_k/kex/km_core.c [new file with mode: 0644]
modules_k/kex/km_core.h [new file with mode: 0644]
modules_k/presence_xml/Makefile
modules_k/pua_dialoginfo/pua_dialoginfo.h
modules_k/pua_usrloc/pua_usrloc.h
modules_k/pv/README
modules_k/pv/doc/pv_admin.xml
modules_k/pv/pv.c
modules_k/pv/pv_core.c
modules_k/pv/pv_trans.c
modules_k/registrar/reg_mod.c
modules_k/registrar/reg_mod.h
modules_k/registrar/save.c
modules_k/sms/libsms_putsms.c
modules_k/sms/sms.c
modules_k/sms/sms_funcs.c
modules_k/tmx/Makefile [new file with mode: 0644]
modules_k/tmx/README [new file with mode: 0644]
modules_k/tmx/doc/Makefile [new file with mode: 0644]
modules_k/tmx/doc/tmx.xml [new file with mode: 0644]
modules_k/tmx/doc/tmx_admin.xml [new file with mode: 0644]
modules_k/tmx/t_mi.c [new file with mode: 0644]
modules_k/tmx/t_mi.h [new file with mode: 0644]
modules_k/tmx/t_var.c [new file with mode: 0644]
modules_k/tmx/t_var.h [new file with mode: 0644]
modules_k/tmx/tmx_mod.c [new file with mode: 0644]
modules_k/tmx/tmx_mod.h [new file with mode: 0644]
modules_s/acc_syslog/README
modules_s/acc_syslog/doc/acc_syslog.xml
modules_s/acc_syslog/doc/params.xml
modules_s/auth/doc/params.xml
modules_s/auth_identity/README [new file with mode: 0644]
modules_s/bdb/README [new file with mode: 0644]
modules_s/blst/README [new file with mode: 0644]
modules_s/cfg_rpc/README [new file with mode: 0644]
modules_s/mangler/sdp_mangler.h
modules_s/registrar/README
modules_s/registrar/doc/registrar.xml
modules_s/rr/avp_cookie.h
modules_s/sms/libsms_putsms.c
modules_s/sms/sms.c
modules_s/sms/sms_funcs.c
modules_s/uri/Makefile
modules_s/uri/checks.c
parser/msg_parser.h
parser/parse_uri.c
rvalue.c
socket_info.c

index 1e89a64..ffc0051 100644 (file)
--- a/action.c
+++ b/action.c
@@ -123,7 +123,6 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
        struct rvalue* rv1;
        struct rval_cache c1;
        str s;
-       int orig_p2t;
 
        /* reset the value of error to E_UNSPEC so avoid unknowledgable
           functions to return with error (status<0) and not setting it
@@ -538,7 +537,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                        ret=1;
                                        break;
                                }
-                               if ((msg->parsed_uri_ok==0) || ((uri.flags & URI_SIP_USER_PHONE)!=0)) {
+                               if (msg->parsed_uri_ok==0) {
                                        if (msg->new_uri.s) {
                                                tmp=msg->new_uri.s;
                                                len=msg->new_uri.len;
@@ -546,18 +545,12 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                                tmp=msg->first_line.u.request.uri.s;
                                                len=msg->first_line.u.request.uri.len;
                                        }
-                                       /* don't convert sip:user=phone to tel, otherwise we loose parameters */
-                                       orig_p2t=phone2tel;
-                                       phone2tel=0;
-                                       msg->parsed_uri_ok=0;
                                        if (parse_uri(tmp, len, &uri)<0){
-                                               phone2tel=orig_p2t;
                                                LOG(L_ERR, "ERROR: do_action: bad uri <%s>, dropping"
                                                                        " packet\n", tmp);
                                                ret=E_UNSPEC;
                                                break;
                                        }
-                                       phone2tel=orig_p2t;
                                } else {
                                        uri=msg->parsed_uri;
                                }
@@ -701,6 +694,17 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                        *crt=':'; crt++;
                                        memcpy(crt,tmp,len);crt+=len;
                                }
+                               /* tel: URI parameters */
+                               if ((uri.type==TEL_URI_T)
+                                       || (uri.type==TELS_URI_T)
+                               ) {
+                                       tmp=uri.params.s;
+                                       if (tmp){
+                                               len=uri.params.len; if(crt+len+1>end) goto error_uri;
+                                               *crt=';'; crt++;
+                                               memcpy(crt,tmp,len);crt+=len;
+                                       }
+                               }
                                /* host */
                                if ((a->type==SET_HOST_T)
                                                || (a->type==SET_HOSTPORT_T)
@@ -747,17 +751,20 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                        memcpy(crt,tmp,len);crt+=len;
                                }
                                /* params */
-                               if ((a->type==SET_HOSTPORTTRANS_T) && uri.transport.s) {
+                               if ((a->type==SET_HOSTPORTTRANS_T)
+                                       && uri.sip_params.s
+                                       && uri.transport.s
+                               ) {
                                        /* bypass the transport parameter */
-                                       if (uri.params.s < uri.transport.s) {
+                                       if (uri.sip_params.s < uri.transport.s) {
                                                /* there are parameters before transport */
-                                               len = uri.transport.s - uri.params.s - 1;
+                                               len = uri.transport.s - uri.sip_params.s - 1;
                                                        /* ignore the ';' at the end */
                                                if (crt+len+1>end) goto error_uri;
                                                *crt=';'; crt++;
-                                               memcpy(crt,uri.params.s,len);crt+=len;
+                                               memcpy(crt,uri.sip_params.s,len);crt+=len;
                                        }
-                                       len = (uri.params.s + uri.params.len) -
+                                       len = (uri.sip_params.s + uri.sip_params.len) -
                                                (uri.transport.s + uri.transport.len);
                                        if (len > 0) {
                                                /* there are parameters after transport */
@@ -766,9 +773,9 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                                memcpy(crt,tmp,len);crt+=len;
                                        }
                                } else {
-                                       tmp=uri.params.s;
+                                       tmp=uri.sip_params.s;
                                        if (tmp){
-                                               len=uri.params.len; if(crt+len+1>end) goto error_uri;
+                                               len=uri.sip_params.len; if(crt+len+1>end) goto error_uri;
                                                *crt=';'; crt++;
                                                memcpy(crt,tmp,len);crt+=len;
                                        }
diff --git a/cfg.lex b/cfg.lex
index 768f3e9..b599d13 100644 (file)
--- a/cfg.lex
+++ b/cfg.lex
@@ -277,6 +277,7 @@ LOGSTDERROR log_stderror
 LOGFACILITY    log_facility
 LISTEN         listen
 ALIAS          alias
+SR_AUTO_ALIASES        auto_aliases
 DNS             dns
 REV_DNS         rev_dns
 DNS_TRY_IPV6   dns_try_ipv6
@@ -554,6 +555,8 @@ EAT_ABLE    [\ \t\b\r]
 <INITIAL>{LOGFACILITY} { yylval.strval=yytext; return LOGFACILITY; }
 <INITIAL>{LISTEN}      { count(); yylval.strval=yytext; return LISTEN; }
 <INITIAL>{ALIAS}       { count(); yylval.strval=yytext; return ALIAS; }
+<INITIAL>{SR_AUTO_ALIASES}     { count(); yylval.strval=yytext;
+                                                                       return SR_AUTO_ALIASES; }
 <INITIAL>{DNS} { count(); yylval.strval=yytext; return DNS; }
 <INITIAL>{REV_DNS}     { count(); yylval.strval=yytext; return REV_DNS; }
 <INITIAL>{DNS_TRY_IPV6}        { count(); yylval.strval=yytext;
diff --git a/cfg.y b/cfg.y
index f703238..18b69e1 100644 (file)
--- a/cfg.y
+++ b/cfg.y
@@ -333,6 +333,7 @@ static int case_check_default(struct case_stms* stms);
 %token LOGFACILITY
 %token LISTEN
 %token ALIAS
+%token SR_AUTO_ALIASES
 %token DNS
 %token REV_DNS
 %token DNS_TRY_IPV6
@@ -1272,6 +1273,8 @@ assign_stm:
                free_socket_id_lst($3);
        }
        | ALIAS  EQUAL error  { yyerror(" hostname expected"); }
+       | SR_AUTO_ALIASES EQUAL NUMBER { sr_auto_aliases=$3; }
+       | SR_AUTO_ALIASES EQUAL error  { yyerror("boolean value expected"); }
        | ADVERTISED_ADDRESS EQUAL listen_id {
                default_global_address.s=$3;
                default_global_address.len=strlen($3);
diff --git a/dset.c b/dset.c
index cbc636b..1770a3c 100644 (file)
--- a/dset.c
+++ b/dset.c
@@ -126,7 +126,7 @@ int resetbflag(unsigned int branch, flag_t flag)
 }
 
 
-int getbflags(flag_t* res, unsigned int branch)
+int getbflagsval(unsigned int branch, flag_t* res)
 {
        flag_t* flags;
        if (res == NULL) return -1;
@@ -155,6 +155,10 @@ void init_branch_iterator(void)
        branch_iterator = 0;
 }
 
+int get_branch_iterator(void)
+{
+       return branch_iterator;
+}
 
 /*
  * Return the next branch from the dset
diff --git a/dset.h b/dset.h
index e350238..175e0c3 100644 (file)
--- a/dset.h
+++ b/dset.h
@@ -53,6 +53,10 @@ int km_append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path,
  */
 void init_branch_iterator(void);
 
+/* 
+ * Return branch iterator position 
+ */
+int get_branch_iterator(void);
 
 /*
  * Get the next branch in the current transaction
@@ -126,11 +130,11 @@ int isbflagset(unsigned int branch, flag_t flag);
  *
  * This function returns the value of all branch flags
  * combined in a single variable.
- * @param res A pointer to a variable to store the result
  * @param branch Number of the branch (0 for the main Request-URI branch)
+ * @param res A pointer to a variable to store the result
  * @return 1 on success, -1 on failure
  */
-int getbflags(flag_t* res, unsigned int branch);
+int getbflagsval(unsigned int branch, flag_t* res);
 
 /**
  * Set the value of all branch flags at once for a given branch.
index 5fca78e..f651120 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -407,7 +407,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
                }
        }
        /* try to send the message until success or all the ips are exhausted
-        *  (if dns lookup is peformed && the dns cache used ) */
+        *  (if dns lookup is performed && the dns cache used ) */
 #ifdef USE_DNS_FAILOVER
        do{
 #endif
index 734c370..f7ef9f8 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -117,6 +117,7 @@ extern int sock_gid;
 extern int sock_mode;
 extern char* chroot_dir;
 extern char* working_dir;
+extern int sr_auto_aliases;
 
 #ifdef USE_MCAST
 extern int mcast_loopback;
index faf82d1..c76267c 100644 (file)
@@ -44,9 +44,9 @@
 #include <time.h> /* time */
 /* #include <stropts.h>  - is this really needed? --andrei */
 
-#include "../../modules/ctl/ctl_defaults.h" /* default socket & port */
-#include "../../modules/ctl/init_socks.h"
-#include "../../modules/ctl/binrpc.c" /* ugly hack */
+#include "../../modules_s/ctl/ctl_defaults.h" /* default socket & port */
+#include "../../modules_s/ctl/init_socks.h"
+#include "../../modules_s/ctl/binrpc.c" /* ugly hack */
 
 #include "binrpc_api.h"
 
index b7a41ed..ef8dfe8 100644 (file)
@@ -34,7 +34,7 @@
 #ifndef BINRPC_API_H_
 #define BINRPC_API_H_
 
-#include "../../modules/ctl/binrpc.h"
+#include "../../modules_s/ctl/binrpc.h"
 
 struct binrpc_handle {
        int socket;
diff --git a/main.c b/main.c
index 4f0169b..4d7fd1f 100644 (file)
--- a/main.c
+++ b/main.c
@@ -348,6 +348,8 @@ int mhomed=0;
 /* use dns and/or rdns or to see if we need to add
    a ;received=x.x.x.x to via: */
 int received_dns = 0;
+/* add or not the rev dns names to aliases list */
+int sr_auto_aliases=1;
 char* working_dir = 0;
 char* chroot_dir = 0;
 char* user=0;
index 87579b1..7b1ce8f 100644 (file)
@@ -838,7 +838,7 @@ t_reply("404", "Not found");
 
    Checks if a transaction exists. Returns a positive value if so,
    negative otherwise. Most likely you will not want to use it, as a
-   typical application of a looku-up is to introduce a new transaction if
+   typical application of a look-up is to introduce a new transaction if
    none was found. However this is safely (atomically) done using
    t_newtran.
 
index 2363abb..e117686 100644 (file)
@@ -49,6 +49,8 @@ int init_callid(void);
 int child_init_callid(int rank);
 
 
+typedef void (*generate_callid_f)(str*);
+
 /*
  * Get a unique Call-ID
  */
index 6571fd3..1c25aeb 100644 (file)
@@ -320,7 +320,7 @@ t_reply("404", "Not found");
        <para>
            Checks if a transaction exists. Returns a positive value if so,
            negative otherwise.  Most likely you will not want to use it, as a
-           typical application of a looku-up is to introduce a new transaction
+           typical application of a look-up is to introduce a new transaction
            if none was found. However this is safely (atomically) done using
            <function>t_newtran</function>.
        </para>
index 37aecc9..dd18820 100644 (file)
@@ -70,6 +70,7 @@
 #include "../../md5utils.h"
 #include "../../usr_avp.h"
 #include "../../timer.h"
+#include "../../flags.h"
 #include "../../atomic_ops.h"
 #include "../../hash_func.h"
 #include "config.h"
@@ -85,6 +86,7 @@ struct entry;
 struct cell;
 struct timer;
 struct retr_buf;
+struct ua_client;
 
 #include "../../mem/shm_mem.h"
 #include "lock.h"
@@ -224,6 +226,7 @@ typedef struct ua_client
        /* internal flags per tm uac */
        unsigned int flags;
 #endif
+       flag_t branch_flags;
 #ifdef WITH_AS_SUPPORT
        /**
         * Resent for every rcvd 2xx reply.
@@ -421,7 +424,8 @@ struct s_table
 
 /* pointer to the big table where all the transaction data
    lives */
-struct s_table*  _tm_table; /* private internal stuff, don't touch directly */
+extern struct s_table*  _tm_table; /* private internal stuff, don't touch
+                                                                         directly */
 
 #define list_entry(ptr, type, member) \
        ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
index 759f4f0..d3ff20a 100644 (file)
@@ -84,6 +84,7 @@ typedef int(*cancel_uacs_f)( struct cell *t, branch_bm_t cancel_bm,
                                                                int flags );
 typedef int (*cancel_all_uacs_f)(struct cell *trans, int how);
 
+typedef void (*which_cancel_f)(struct cell *t, branch_bm_t *cancel_bm );
 
 
 /* 
@@ -113,7 +114,7 @@ inline short static should_cancel_branch( struct cell *t, int b, int noreply )
        return 0;
 }
 
-const char* rpc_cancel_doc[2];
+extern const char* rpc_cancel_doc[2];
 void rpc_cancel(rpc_t* rpc, void* c);
 int cancel_b_flags_fixup(void* handle, str* gname, str* name, void** val);
 int cancel_b_flags_get(unsigned int* f, int m);
index f07b002..8e4d492 100644 (file)
@@ -447,4 +447,7 @@ int fr_inv_avp2timer(unsigned int* timer)
                return 1;
 }
 
-
+void unref_cell(struct cell *t)
+{
+       UNREF(t);
+}
index 5e3c605..994e847 100644 (file)
@@ -150,6 +150,8 @@ int send_pr_buffer( struct retr_buf *rb, void *buf, int len);
 int init_avp_params(char *fr_timer_param, char *fr_inv_timer_param);
 
 
+typedef void (*unref_cell_f)(struct cell *t);
+void unref_cell(struct cell *t);
 /*
  * Get the FR_{INV}_TIMER from corresponding AVP
  */
index 9344e6f..97b36c2 100644 (file)
@@ -190,10 +190,11 @@ static char *print_uac_request( struct cell *t, struct sip_msg *i_req,
        if (unlikely(branch_route)) {
                     /* run branch_route actions if provided */
                set_route_type(BRANCH_ROUTE);
-               
+               tm_ctx_set_branch_index(branch+1);
                if (run_top_route(branch_rt.rlist[branch_route], i_req) < 0) {
                        LOG(L_ERR, "ERROR: print_uac_request: Error in run_top_route\n");
                }
+               tm_ctx_set_branch_index(0);
        }
 
        /* run the specific callbacks for this transaction */
@@ -450,6 +451,7 @@ int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop,
        else if(len==2)
                t->uac[branch].flags = TM_UAC_FLAG_RR|TM_UAC_FLAG_R2;
 #endif
+       getbflagsval(0, &t->uac[branch].branch_flags);
        membar_write(); /* to allow lockless ops (e.g. which_cancel()) we want
                                           to be sure everything above is fully written before
                                           updating branches no. */
@@ -1005,6 +1007,8 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
        int lock_replies;
        str dst_uri;
        struct socket_info* si, *backup_si;
+       flag_t backup_bflags = 0;
+       flag_t bflags = 0;
        
 
        /* make -Wall happy */
@@ -1028,6 +1032,8 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
        }
 
        backup_si = p_msg->force_send_socket;
+       getbflagsval(0, &backup_bflags);
+
        /* if no more specific error code is known, use this */
        lowest_ret=E_UNSPEC;
        /* branches added */
@@ -1072,6 +1078,9 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
        while((current_uri.s=next_branch( &current_uri.len, &q, &dst_uri.s, &dst_uri.len, &si))) {
                try_new++;
                p_msg->force_send_socket = si;
+               getbflagsval(get_branch_iterator(), &bflags);
+               setbflagsval(0, bflags);
+
                branch_ret=add_uac( t, p_msg, &current_uri, 
                                    (dst_uri.len) ? (&dst_uri) : &current_uri, 
                                    proxy, proto);
@@ -1088,6 +1097,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
        clear_branches();
 
        p_msg->force_send_socket = backup_si;
+       setbflagsval(0, backup_bflags);
 
        /* don't forget to clear all branches processed so far */
 
index 8f59e8a..c8e1c9d 100644 (file)
@@ -1869,3 +1869,24 @@ int t_reset_max_lifetime()
        return 1;
 }
 
+#ifdef WITH_TM_CTX
+
+tm_ctx_t _tm_ctx;
+
+tm_ctx_t* tm_ctx_get(void)
+{
+       return &_tm_ctx;
+}
+
+void tm_ctx_init(void)
+{
+       memset(&_tm_ctx, 0, sizeof(tm_ctx_t));
+}
+
+void tm_ctx_set_branch_index(int v)
+{
+       _tm_ctx.branch_index = v;
+}
+
+#endif
+
index 8994999..a9a98e6 100644 (file)
@@ -55,7 +55,10 @@ void init_t();
 int init_rb( struct retr_buf *rb, struct sip_msg *msg );
 struct cell* t_lookupOriginalT( struct sip_msg* p_msg );
 int t_reply_matching( struct sip_msg* , int* );
-int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked,
+
+typedef int (*tlookup_request_f)(struct sip_msg*, int, int*);
+
+int t_lookup_request( struct sip_msg* p_msg, int leave_new_locked,
                                                int* canceled);
 int t_newtran( struct sip_msg* p_msg );
 
@@ -68,6 +71,7 @@ int add_branch_label( struct cell *trans,
 int t_unref( struct sip_msg *p_msg);
 typedef int (*tunref_f)( struct sip_msg *p_msg);
 
+typedef int (*tcheck_f)(struct sip_msg*, int*);
 
 /* old t_check version (no e2eack support) */
 int t_check(struct sip_msg* , int *branch );
@@ -91,6 +95,7 @@ typedef int (*tnewtran_f)(struct sip_msg*);
 typedef int (*tget_ti_f)(struct sip_msg*, unsigned int*, unsigned int*);
 typedef int (*tlookup_ident_f)(struct cell**, unsigned int, unsigned int);
 typedef int (*trelease_f)(struct sip_msg*);
+typedef int (*tlookup_callid_f)(struct cell **, str, str);
 
 int t_is_local(struct sip_msg*);
 int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned int* label);
@@ -118,4 +123,28 @@ typedef int (*t_get_canceled_ident_f)(struct sip_msg *msg,
                unsigned int *hash_index, unsigned int *label);
 #endif /* WITH_AS_SUPPORT */
 
+/**
+ * required by TMX (K/O extensions)
+ */
+#define WITH_TM_CTX
+#ifdef WITH_TM_CTX
+
+typedef struct _tm_ctx {
+       int branch_index;
+} tm_ctx_t;
+
+typedef tm_ctx_t* (*tm_ctx_get_f)(void);
+
+tm_ctx_t* tm_ctx_get(void);
+void tm_ctx_init(void);
+void tm_ctx_set_branch_index(int v);
+
+#else
+
+#define tm_ctx_get() NULL
+#define tm_ctx_init()
+#define tm_ctx_set_branch_index(v)
+
+#endif /* WITH_TM_CTX */
+
 #endif
index 5cb731f..8ab79c2 100644 (file)
@@ -730,7 +730,7 @@ void faked_env( struct cell *t,struct sip_msg *msg)
 
 
 int fake_req(struct sip_msg *faked_req,
-                                                       struct sip_msg *shmem_msg, int extra_flags)
+               struct sip_msg *shmem_msg, int extra_flags, struct ua_client *uac)
 {
        /* on_negative_reply faked msg now copied from shmem msg (as opposed
         * to zero-ing) -- more "read-only" actions (exec in particular) will
@@ -747,6 +747,19 @@ int fake_req(struct sip_msg *faked_req,
        faked_req->parsed_uri_ok = 0;
        
        faked_req->msg_flags|=extra_flags; /* set the extra tm flags */
+
+       /* dst_uri can change ALSO!!! -- make a private copy */
+       if (shmem_msg->dst_uri.s!=0 && shmem_msg->dst_uri.len!=0) {
+               faked_req->dst_uri.s=pkg_malloc(shmem_msg->dst_uri.len+1);
+               if (!faked_req->dst_uri.s) {
+                       LOG(L_ERR, "ERROR: fake_req: no uri/pkg mem\n");
+                       goto error01;
+               }
+               faked_req->dst_uri.len=shmem_msg->dst_uri.len;
+               memcpy( faked_req->dst_uri.s, shmem_msg->dst_uri.s,
+                       faked_req->dst_uri.len);
+               faked_req->dst_uri.s[faked_req->dst_uri.len]=0;
+       }
        /* new_uri can change -- make a private copy */
        if (shmem_msg->new_uri.s!=0 && shmem_msg->new_uri.len!=0) {
                faked_req->new_uri.s=pkg_malloc(shmem_msg->new_uri.len+1);
@@ -759,21 +772,16 @@ int fake_req(struct sip_msg *faked_req,
                        faked_req->new_uri.len);
                faked_req->new_uri.s[faked_req->new_uri.len]=0;
        }
-       /* dst_uri can change ALSO!!! -- make a private copy */
-       if (shmem_msg->dst_uri.s!=0 && shmem_msg->dst_uri.len!=0) {
-               faked_req->dst_uri.s=pkg_malloc(shmem_msg->dst_uri.len+1);
-               if (!faked_req->dst_uri.s) {
-                       LOG(L_ERR, "ERROR: fake_req: no uri/pkg mem\n");
-                       goto error00;
-               }
-               faked_req->dst_uri.len=shmem_msg->dst_uri.len;
-               memcpy( faked_req->dst_uri.s, shmem_msg->dst_uri.s,
-                       faked_req->dst_uri.len);
-               faked_req->dst_uri.s[faked_req->dst_uri.len]=0;
-       }
+       if(uac) setbflagsval(0, uac->branch_flags);
+       else setbflagsval(0, 0);
 
        return 1;
 error00:
+       if (faked_req->dst_uri.s) {
+               pkg_free(faked_req->dst_uri.s);
+               faked_req->dst_uri.s = 0;
+       }
+error01:
        return 0;
 }
 
@@ -836,7 +844,7 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
                return 1;
        }
 
-       if (!fake_req(&faked_req, shmem_msg, extra_flags)) {
+       if (!fake_req(&faked_req, shmem_msg, extra_flags, &t->uac[picked_branch])) {
                LOG(L_ERR, "ERROR: run_failure_handlers: fake_req failed\n");
                return 0;
        }
@@ -1831,6 +1839,7 @@ int reply_received( struct sip_msg  *p_msg )
        if ( (t==0)||(t==T_UNDEFINED))
                goto trans_not_found;
 
+       tm_ctx_set_branch_index(branch);
        cancel_bitmap=0;
        msg_status=p_msg->REPLY_STATUS;
 
@@ -1953,10 +1962,13 @@ int reply_received( struct sip_msg  *p_msg )
                backup_user_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to );
                backup_domain_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from );
                backup_domain_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to );
+               setbflagsval(0, uac->branch_flags);
                if (run_top_route(onreply_rt.rlist[t->on_reply], p_msg)<0)
                        LOG(L_ERR, "ERROR: on_reply processing failed\n");
                /* transfer current message context back to t */
                if (t->uas.request) t->uas.request->flags=p_msg->flags;
+               getbflagsval(0, &uac->branch_flags);
+
                /* restore original avp list */
                set_avp_list( AVP_TRACK_FROM | AVP_CLASS_URI, backup_uri_from );
                set_avp_list( AVP_TRACK_TO | AVP_CLASS_URI, backup_uri_to );
@@ -2065,6 +2077,7 @@ int reply_received( struct sip_msg  *p_msg )
        } /* provisional replies */
 
 done:
+       tm_ctx_set_branch_index(0);
        /* we are done with the transaction, so unref it - the reference
         * was incremented by t_check() function -bogdan*/
        t_unref(p_msg);
index 65b4498..c385697 100644 (file)
@@ -160,7 +160,7 @@ void rpc_reply(rpc_t* rpc, void* c);
 
 void faked_env( struct cell *t,struct sip_msg *msg);
 int fake_req(struct sip_msg *faked_req,
-                       struct sip_msg *shmem_msg, int extra_flags);
+               struct sip_msg *shmem_msg, int extra_flags, struct ua_client *uac);
 
 void free_faked_req(struct sip_msg *faked_req, struct cell *t);
 
index 1c0b729..c1dc1b1 100644 (file)
@@ -109,6 +109,7 @@ int t_continue(unsigned int hash_index, unsigned int label,
        struct cell     *t;
        struct sip_msg  faked_req;
        int     branch;
+       struct ua_client *uac =NULL;
 
        if (t_lookup_ident(&t, hash_index, label) < 0) {
                LOG(L_ERR, "ERROR: t_continue: transaction not found\n");
@@ -136,13 +137,14 @@ int t_continue(unsigned int hash_index, unsigned int label,
                 * a failure rute => deadlock, because both
                 * of them need the reply lock to be held. */
                t->uac[branch].last_received=500;
+               uac = &t->uac[branch];
        }
        /* else
                Not a huge problem, fr timer will fire, but CANCEL
                will not be sent. last_received will be set to 408. */
 
        /* fake the request and the environment, like in failure_route */
-       if (!fake_req(&faked_req, t->uas.request, 0 /* extra flags */)) {
+       if (!fake_req(&faked_req, t->uas.request, 0 /* extra flags */, uac)) {
                LOG(L_ERR, "ERROR: t_continue: fake_req failed\n");
                UNLOCK_REPLIES(t);
                return -1;
index ebdf0a8..22e1782 100644 (file)
@@ -228,5 +228,16 @@ int load_tm( struct tm_binds *tmb)
 
        tmb->t_get_reply_totag = t_get_reply_totag;
        tmb->t_get_picked_branch = t_get_picked_branch;
+       tmb->t_lookup_callid = t_lookup_callid;
+       tmb->generate_callid = generate_callid;
+       tmb->generate_fromtag = generate_fromtag;
+       tmb->t_lookup_request = t_lookup_request;
+       tmb->t_check = t_check;
+       tmb->unref_cell = unref_cell;
+       tmb->which_cancel = which_cancel;
+
+#ifdef WITH_TM_CTX
+       tmb->tm_ctx_get = tm_ctx_get;
+#endif
        return 1;
 }
index bc99256..54c0b9a 100644 (file)
@@ -46,6 +46,7 @@
 #include "t_lookup.h"
 #include "t_reply.h"
 #include "dlg.h"
+#include "callid.h"
 #include "t_cancel.h"
 #include "t_suspend.h"
 
@@ -134,6 +135,18 @@ struct tm_binds {
        t_continue_f    t_continue;
        tget_reply_totag_f t_get_reply_totag;
        tget_picked_f t_get_picked_branch;
+       tlookup_callid_f t_lookup_callid;
+       generate_callid_f generate_callid;
+       generate_fromtag_f generate_fromtag;
+       tlookup_request_f t_lookup_request;
+       tcheck_f t_check;
+       unref_cell_f unref_cell;
+       which_cancel_f which_cancel;
+#ifdef WITH_TM_CTX
+       tm_ctx_get_f tm_ctx_get;
+#else
+       void* reserved5;
+#endif
 };
 
 extern int tm_init;
index f4c14e9..8106727 100644 (file)
@@ -88,7 +88,7 @@ typedef int (*ack_local_uac_f)(struct cell *trans, str *hdrs, str *body);
 typedef int (*prepare_request_within_f)(uac_req_t *uac_r,
                struct retr_buf **dst_req);
 typedef void (*send_prepared_request_f)(struct retr_buf *request_dst);
-
+typedef void (*generate_fromtag_f)(str*, str*);
 
 /*
  * Generate a fromtag based on given Call-ID
index 9ceca00..038edec 100644 (file)
@@ -41,8 +41,8 @@ extern int diameter_client_port;
 /** SL binds */
 extern struct sl_binds slb;
 
-int sockfd;
-int use_domain;
+extern int sockfd;
+extern int use_domain;
 extern rd_buf_t *rb;
 
 
index 995cdab..2b3d53d 100644 (file)
  */
 
 
+/*!
+ * \file
+ * \brief Functions related to dialog handling
+ * \ingroup dialog
+ * Module: \ref dialog
+ */
+
 #include <string.h>
 #include <time.h>
 
 #include "dlg_profile.h"
 #include "dlg_var.h"
 
-static str       rr_param;
-static int       dlg_flag;
-static pv_spec_t *timeout_avp;
-static int       default_timeout;
-static int       seq_match_mode;
-static int       shutdown_done = 0;
+static str       rr_param;             /*!< record-route parameter for matching */
+static int       dlg_flag;             /*!< flag for dialog tracking */
+static pv_spec_t *timeout_avp;         /*!< AVP for timeout setting */
+static int       default_timeout;      /*!< default dialog timeout */
+static int       seq_match_mode;       /*!< dlg_match mode */ 
+static int       shutdown_done = 0;    /*!< 1 when destroy_dlg_handlers was called */
 
-extern struct rr_binds d_rrb;
+extern struct rr_binds d_rrb;          /*!< binding to record-routing module */
 
 /* statistic variables */
-extern stat_var *early_dlgs;
-extern stat_var *processed_dlgs;
-extern stat_var *expired_dlgs;
-extern stat_var *failed_dlgs;
+extern stat_var *early_dlgs;           /*!< number of early dialogs */
+extern stat_var *processed_dlgs;       /*!< number of processed dialogs */
+extern stat_var *expired_dlgs;         /*!< number of expired dialogs */
+extern stat_var *failed_dlgs;          /*!< number of failed dialogs */
+
 
+static unsigned int CURR_DLG_LIFETIME = 0;     /*!< current dialog lifetime */
+static unsigned int CURR_DLG_STATUS = 0;       /*!< current dialog state */
+static unsigned int CURR_DLG_ID  = 0xffffffff; /*!< current dialog id */
 
-static unsigned int CURR_DLG_LIFETIME = 0;
-static unsigned int CURR_DLG_STATUS = 0;
-static unsigned int CURR_DLG_ID  = 0xffffffff;
 
+/*! size of the dialog record-route parameter */
 #define RR_DLG_PARAM_SIZE  (2*2*sizeof(int)+3+MAX_DLG_RR_PARAM_NAME)
+/*! separator inside the record-route paramter */
 #define DLG_SEPARATOR      '.'
 
 
+/*!
+ * \brief Initialize the dialog handlers
+ * \param rr_param_p added record-route parameter
+ * \param dlg_flag_p dialog flag
+ * \param timeout_avp_p AVP for timeout setting
+ * \param default_timeout_p default timeout
+ * \param seq_match_mode_p matching mode
+ */
 void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
                pv_spec_t *timeout_avp_p ,int default_timeout_p,
                int seq_match_mode_p)
@@ -110,14 +128,24 @@ void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
 }
 
 
+/*!
+ * \brief Shutdown operation of the module
+ */
 void destroy_dlg_handlers(void)
 {
        shutdown_done = 1;
 }
 
 
+/*!
+ * \brief Add record-route parameter for dialog tracking
+ * \param req SIP request
+ * \param entry dialog hash entry
+ * \param id dialog hash id
+ * \return 0 on success, -1 on failure
+ */
 static inline int add_dlg_rr_param(struct sip_msg *req, unsigned int entry,
-                                                                                                       unsigned int id)
+               unsigned int id)
 {
        static char buf[RR_DLG_PARAM_SIZE];
        str s;
@@ -152,14 +180,16 @@ static inline int add_dlg_rr_param(struct sip_msg *req, unsigned int entry,
 }
 
 
-/*usage: dlg: the dialog to add cseq, contact & record_route
- *              msg: sip message
- *              flag: 0-for a request(INVITE),
- *                             1- for a reply(200 ok)
+/*!
+ * \brief Parse SIP message and populate leg informations
  *
- *     for a request: get record route in normal order
- *     for a reply  : get in reverse order, skipping the ones from the request and
- *                                the proxies' own
+ * Parse SIP message and populate leg informations. 
+ * \param dlg the dialog to add cseq, contact & record_route
+ * \param msg sip message
+ * \param flag  0-for a request(INVITE), 1- for a reply(200 ok)
+ * \return 0 on success, -1 on failure
+ * \note for a request: get record route in normal order, for a reply get
+ * in reverse order, skipping the ones from the request and the proxies' own
  */
 int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
        struct cell* t, unsigned int leg, str *tag)
@@ -247,14 +277,23 @@ error0:
 }
 
 
+/*!
+ * \brief Function that is registered as TM callback and called on replies
+ *
+ * Function that is registered as TM callback and called on replies. It
+ * parses the reply and set the appropriate event. This is then used to
+ * update the dialog state, run eventual dialog callbacks and save or
+ * update the necessary informations about the dialog.
+ * \see next_state_dlg
+ * \param t transaction, unused
+ * \param type type of the entered callback
+ * \param param saved dialog structure in the callback
+ */
 static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
 {
        struct sip_msg *rpl;
        struct dlg_cell *dlg;
-       int new_state;
-       int old_state;
-       int unref;
-       int event;
+       int new_state, old_state, unref, event;
        str tag;
 
        dlg = (struct dlg_cell *)(*param->param);
@@ -360,8 +399,17 @@ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param)
 }
 
 
-static void dlg_seq_up_onreply(struct cell* t, int type,
-                                                                                                       struct tmcb_params *param)
+/*!
+ * \brief Helper function that run dialog callbacks on forwarded requests
+ * \see dlg_seq_up_onreply
+ * \see dlg_seq_down_onreply
+ * \param t transaction, unused
+ * \param type type of the callback, should be TMCB_RESPONSE_FWDED
+ * \param param saved dialog structure inside the callback
+ * \param direction direction of the request
+ */
+static void dlg_seq_onreply_helper(struct cell* t, int type,
+               struct tmcb_params *param, const int direction)
 {
        struct dlg_cell *dlg;
 
@@ -371,7 +419,7 @@ static void dlg_seq_up_onreply(struct cell* t, int type,
 
        if (type==TMCB_RESPONSE_FWDED) {
                run_dlg_callbacks(DLGCB_RESPONSE_WITHIN, dlg, param->rpl,
-                       DLG_DIR_UPSTREAM, 0);
+                       direction, 0);
                return;
        }
 
@@ -379,26 +427,37 @@ static void dlg_seq_up_onreply(struct cell* t, int type,
 }
 
 
-
-static void dlg_seq_down_onreply(struct cell* t, int type,
-                                                                                                       struct tmcb_params *param)
+/*!
+ * \brief Run dialog callbacks on forwarded requests in upstream direction
+ * \see dlg_seq_onreply_helper
+ * \param t transaction, unused
+ * \param type type of the callback, should be TMCB_RESPONSE_FWDED
+ * \param param saved dialog structure inside the callback
+ */
+static void dlg_seq_up_onreply(struct cell* t, int type, struct tmcb_params *param)
 {
-       struct dlg_cell *dlg;
+       return dlg_seq_onreply_helper(t, type, param, DLG_DIR_UPSTREAM);
+}
 
-       dlg = (struct dlg_cell *)(*param->param);
-       if (shutdown_done || dlg==0)
-               return;
 
-       if (type==TMCB_RESPONSE_FWDED) {
-               run_dlg_callbacks(DLGCB_RESPONSE_WITHIN, dlg, param->rpl,
-                       DLG_DIR_DOWNSTREAM, 0);
-               return;
-       }
-
-       return;
+/*!
+ * \brief Run dialog callbacks on forwarded requests in downstream direction
+ * \see dlg_seq_onreply_helper
+ * \param t transaction, unused
+ * \param type type of the callback, should be TMCB_RESPONSE_FWDED
+ * \param param saved dialog structure inside the callback
+ */
+static void dlg_seq_down_onreply(struct cell* t, int type, struct tmcb_params *param)
+{
+       return dlg_seq_onreply_helper(t, type, param, DLG_DIR_DOWNSTREAM);
 }
 
 
+/*!
+ * \brief Return the timeout for a dialog
+ * \param req SIP message
+ * \return value from timeout AVP if present or default timeout
+ */
 inline static int get_dlg_timeout(struct sip_msg *req)
 {
        pv_value_t pv_val;
@@ -412,7 +471,13 @@ inline static int get_dlg_timeout(struct sip_msg *req)
 }
 
 
-
+/*!
+ * \brief Function that is registered as TM callback and called on requests
+ * \see dlg_new_dialog
+ * \param t transaction, used to created the dialog
+ * \param type type of the entered callback
+ * \param param saved dialog structure in the callback
+ */
 void dlg_onreq(struct cell* t, int type, struct tmcb_params *param)
 {
        struct sip_msg *msg;
@@ -424,7 +489,13 @@ void dlg_onreq(struct cell* t, int type, struct tmcb_params *param)
        dlg_new_dialog(msg, t);
 }
 
-void unref_new_dialog(void *dialog)
+
+/*!
+ * \brief Unreference a new dialog, helper function for dlg_onreq
+ * \see dlg_onreq
+ * \param dialog unreferenced dialog
+ */
+static void unref_new_dialog(void *dialog)
 {
        struct tmcb_params p;
 
@@ -433,11 +504,31 @@ void unref_new_dialog(void *dialog)
 }
 
 
+/*!
+ * \brief Dummy callback just to keep the compiler happy
+ * \param t unused
+ * \param type unused
+ * \param param unused
+ */
 void dlg_tmcb_dummy(struct cell* t, int type, struct tmcb_params *param)
 {
        return;
 }
 
+
+/*!
+ * \brief Create a new dialog from a sip message
+ *
+ * Create a new dialog from a SIP message, register a callback
+ * to keep track of the dialog with help of the tm module.
+ * This function is either called from the request callback, or
+ * from the dlg_manage function in the configuration script.
+ * \see dlg_onreq
+ * \see w_dlg_manage
+ * \param msg SIP message
+ * \param t transaction
+ * \return 0 on success, -1 on failure
+ */ 
 int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
 {
        struct dlg_cell *dlg;
@@ -542,8 +633,15 @@ error:
 }
 
 
-static inline int parse_dlg_rr_param(char *p, char *end,
-                                                                                                       int *h_entry, int *h_id)
+/*!
+ * \brief Parse the record-route parameter, to get dialog information back
+ * \param p start of parameter string
+ * \param end end of parameter string
+ * \param h_entry found dialog hash entry
+ * \param h_id found dialog hash id
+ * \return 0 on success, -1 on failure
+ */
+static inline int parse_dlg_rr_param(char *p, char *end, int *h_entry, int *h_id)
 {
        char *s;
 
@@ -567,8 +665,16 @@ static inline int parse_dlg_rr_param(char *p, char *end,
 }
 
 
+/*!
+ * \brief Helper function to get the necessary content from SIP message
+ * \param req SIP request
+ * \param callid found callid
+ * \param ftag found from tag
+ * \param ttag found to tag
+ * \return 0 on succes, -1 on failure
+ */
 static inline int pre_match_parse( struct sip_msg *req, str *callid,
-                                                                                                               str *ftag, str *ttag)
+               str *ftag, str *ttag)
 {
        if (parse_headers(req,HDR_CALLID_F|HDR_TO_F,0)<0 || !req->callid ||
        !req->to ) {
@@ -597,8 +703,15 @@ static inline int pre_match_parse( struct sip_msg *req, str *callid,
 }
 
 
+/*!
+ * \brief Update the saved CSEQ information in dialog from SIP message
+ * \param dlg updated dialog
+ * \param req SIP request
+ * \param dir direction of request, must DLG_DIR_UPSTREAM or DLG_DIR_DOWNSTREAM
+ * \return 0 on success, -1 on failure
+ */
 static inline int update_cseqs(struct dlg_cell *dlg, struct sip_msg *req,
-                                                                                                                       unsigned int dir)
+               unsigned int dir)
 {
        if ( (!req->cseq && parse_headers(req,HDR_CSEQ_F,0)<0) || !req->cseq ||
        !req->cseq->parsed) {
@@ -617,8 +730,12 @@ static inline int update_cseqs(struct dlg_cell *dlg, struct sip_msg *req,
 }
 
 
-static void
-unreference_dialog(void *dialog)
+/*!
+ * \brief Unreference a dialog, small wrapper to care for shutdown
+ * \see unref_dlg 
+ * \param dialog unreferenced dialog
+ */
+static void unreference_dialog(void *dialog)
 {
        // if the dialog table is gone, it means the system is shutting down.
        if (!d_table)
@@ -627,20 +744,22 @@ unreference_dialog(void *dialog)
 }
 
 
+/*!
+ * \brief Function that is registered as RR callback for dialog tracking
+ * 
+ * Function that is registered as RR callback for dialog tracking. It
+ * sets the appropriate events after the SIP method and run the state
+ * machine to update the dialog state. It updates then the saved
+ * dialogs and also the statistics.
+ * \param req SIP request
+ * \param route_params record-route parameter
+ * \param param unused
+ */
 void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
 {
        struct dlg_cell *dlg;
-       str val;
-       str callid;
-       str ftag;
-       str ttag;
-       int h_entry;
-       int h_id;
-       int new_state;
-       int old_state;
-       int unref;
-       int event;
-       int timeout;
+       str val, callid, ftag, ttag;
+       int h_entry, h_id, new_state, old_state, unref, event, timeout;
        unsigned int dir;
        int ret = 0;
 
@@ -831,19 +950,19 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
 }
 
 
-
-#define get_dlg_tl_payload(_tl_)  ((struct dlg_cell*)((char *)(_tl_)- \
-               (unsigned long)(&((struct dlg_cell*)0)->tl)))
-
+/*!
+ * \brief Timer function that removes expired dialogs, run timeout route
+ * \param tl dialog timer list
+ */
 void dlg_ontimeout( struct dlg_tl *tl)
 {
        struct dlg_cell *dlg;
-       int new_state;
-       int old_state;
-       int unref;
+       int new_state, old_state, unref;
        struct sip_msg *fmsg;
 
-       dlg = get_dlg_tl_payload(tl);
+       /* get the dialog tl payload */
+       dlg = ((struct dlg_cell*)((char *)(tl) -
+               (unsigned long)(&((struct dlg_cell*)0)->tl)));
 
        if(dlg->toroute>0 && dlg->toroute<RT_NO)
        {
@@ -895,9 +1014,14 @@ void dlg_ontimeout( struct dlg_tl *tl)
 }
 
 
-/* item/pseudo-variables functions */
-int pv_get_dlg_lifetime(struct sip_msg *msg, pv_param_t *param,
-               pv_value_t *res)
+/*!
+ * \brief Function that returns the dialog lifetime as pseudo-variable
+ * \param msg SIP message
+ * \param param pseudo-variable parameter
+ * \param res pseudo-variable result
+ * \return 0 on success, -1 on failure
+ */
+int pv_get_dlg_lifetime(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 {
        int l = 0;
        char *ch = NULL;
@@ -920,8 +1044,14 @@ int pv_get_dlg_lifetime(struct sip_msg *msg, pv_param_t *param,
 }
 
 
-int pv_get_dlg_status(struct sip_msg *msg, pv_param_t *param,
-               pv_value_t *res)
+/*!
+ * \brief Function that returns the dialog state as pseudo-variable
+ * \param msg SIP message
+ * \param param pseudo-variable parameter
+ * \param res pseudo-variable result
+ * \return 0 on success, -1 on failure
+ */
+int pv_get_dlg_status(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
 {
        int l = 0;
        char *ch = NULL;
@@ -942,4 +1072,3 @@ int pv_get_dlg_status(struct sip_msg *msg, pv_param_t *param,
 
        return 0;
 }
-
index 9936088..277db0b 100644 (file)
  */
 
 
+/*!
+ * \file
+ * \brief Functions related to dialog handling
+ * \ingroup dialog
+ * Module: \ref dialog
+ */
+
 #ifndef _DIALOG_DLG_HANDLERS_H_
 #define _DIALOG_DLG_HANDLERS_H_
 
 #define SEQ_MATCH_FALLBACK   1
 #define SEQ_MATCH_NO_ID      2
 
+
+/*!
+ * \brief Initialize the dialog handlers
+ * \param rr_param_p added record-route parameter
+ * \param dlg_flag_p dialog flag
+ * \param timeout_avp_p AVP for timeout setting
+ * \param default_timeout_p default timeout
+ * \param seq_match_mode_p matching mode
+ */
 void init_dlg_handlers(char *rr_param, int dlg_flag,
                pv_spec_t *timeout_avp, int default_timeout,
                int seq_match_mode);
 
+
+/*!
+ * \brief Shutdown operation of the module
+ */
 void destroy_dlg_handlers(void);
 
+
+/*!
+ * \brief Parse SIP message and populate leg informations
+ *
+ * Parse SIP message and populate leg informations. 
+ * \param dlg the dialog to add cseq, contact & record_route
+ * \param msg sip message
+ * \param flag  0-for a request(INVITE), 1- for a reply(200 ok)
+ * \return 0 on success, -1 on failure
+ * \note for a request: get record route in normal order, for a reply get
+ * in reverse order, skipping the ones from the request and the proxies' own
+ */
+int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
+       struct cell* t, unsigned int leg, str *tag);
+
+
+/*!
+ * \brief Function that is registered as TM callback and called on requests
+ * \param t transaction, used to created the dialog
+ * \param type type of the entered callback
+ * \param param saved dialog structure in the callback
+ */
 void dlg_onreq(struct cell* t, int type, struct tmcb_params *param);
 
+
+/*!
+ * \brief Function that is registered as RR callback for dialog tracking
+ * 
+ * Function that is registered as RR callback for dialog tracking. It
+ * sets the appropriate events after the SIP method and run the state
+ * machine to update the dialog state. It updates then the saved
+ * dialogs and also the statistics.
+ * \param req SIP request
+ * \param route_params record-route parameter
+ * \param param unused
+ */
 void dlg_onroute(struct sip_msg* req, str *rr_param, void *param);
 
+
+/*!
+ * \brief Timer function that removes expired dialogs, run timeout route
+ * \param tl dialog timer list
+ */
 void dlg_ontimeout( struct dlg_tl *tl);
 
+
+/*!
+ * \brief Create a new dialog from a sip message
+ *
+ * Create a new dialog from a SIP message, register a callback
+ * to keep track of the dialog with help of the tm module.
+ * This function is either called from the request callback, or
+ * from the dlg_manage function in the configuration script.
+ * \see dlg_onreq
+ * \see w_dlg_manage
+ * \param msg SIP message
+ * \param t transaction
+ * \return 0 on success, -1 on failure
+ */ 
 int dlg_new_dialog(struct sip_msg *msg, struct cell *t);
 
-/* item/pseudo-variables functions */
+
+/*!
+ * \brief Function that returns the dialog lifetime as pseudo-variable
+ * \param msg SIP message
+ * \param param pseudo-variable parameter
+ * \param res pseudo-variable result
+ * \return 0 on success, -1 on failure
+ */
 int pv_get_dlg_lifetime(struct sip_msg *msg, pv_param_t *param,
                pv_value_t *res);
 
+
+/*!
+ * \brief Function that returns the dialog state as pseudo-variable
+ * \param msg SIP message
+ * \param param pseudo-variable parameter
+ * \param res pseudo-variable result
+ * \return 0 on success, -1 on failure
+ */
 int pv_get_dlg_status(struct sip_msg *msg, pv_param_t *param,
                pv_value_t *res);
 
+
+/*!
+ * \brief Dummy callback just to keep the compiler happy
+ * \param t unused
+ * \param type unused
+ * \param param unused
+ */
 void dlg_tmcb_dummy(struct cell* t, int type, struct tmcb_params *param);
+
 #endif
index b517f76..65e5876 100644 (file)
  *             CONFIRMED_NA due delayed "200 OK" (bogdan)
  */
 
+
+/*!
+ * \file
+ * \brief Functions related to dialog creation and searching
+ * \ingroup dialog
+ * Module: \ref dialog
+ */
+
 #include <stdlib.h>
 #include <string.h>
 
 #define MIN_LDG_LOCKS  2
 
 
+/*! global dialog table */
 struct dlg_table *d_table = 0;
 
+
+/*!
+ * \brief Initialize the global dialog table
+ * \param size size of the table
+ * \return 0 on success, -1 on failure
+ */
 int init_dlg_table(unsigned int size)
 {
        unsigned int n;
@@ -109,7 +124,10 @@ error0:
 }
 
 
-
+/*!
+ * \brief Destroy a dialog, run callbacks and free memory
+ * \param dlg destroyed dialog
+ */
 inline void destroy_dlg(struct dlg_cell *dlg)
 {
        int ret = 0;
@@ -157,7 +175,9 @@ inline void destroy_dlg(struct dlg_cell *dlg)
 }
 
 
-
+/*!
+ * \brief Destroy the global dialog table
+ */
 void destroy_dlg_table(void)
 {
        struct dlg_cell *dlg, *l_dlg;
@@ -188,9 +208,16 @@ void destroy_dlg_table(void)
 }
 
 
-
+/*!
+ * \brief Create a new dialog structure for a SIP dialog
+ * \param callid dialog callid
+ * \param from_uri dialog from uri
+ * \param to_uri dialog to uri
+ * \param from_tag dialog from tag
+ * \return created dialog structure on success, NULL otherwise
+ */
 struct dlg_cell* build_new_dlg( str *callid, str *from_uri, str *to_uri,
-                                                                                                                               str *from_tag)
+               str *from_tag)
 {
        struct dlg_cell *dlg;
        int len;
@@ -237,7 +264,16 @@ struct dlg_cell* build_new_dlg( str *callid, str *from_uri, str *to_uri,
 }
 
 
-
+/*!
+ * \brief Set the leg information for an existing dialog
+ * \param dlg dialog
+ * \param tag from tag or to tag
+ * \param rr record-routing information
+ * \param contact caller or callee contact
+ * \param cseq CSEQ of caller or callee
+ * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
+ * \return 0 on success, -1 on failure
+ */
 int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
                                        str *cseq, unsigned int leg)
 {
@@ -277,7 +313,13 @@ int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
 }
 
 
-
+/*!
+ * \brief Update or set the CSEQ for an existing dialog
+ * \param dlg dialog
+ * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
+ * \param cseq CSEQ of caller or callee
+ * \return 0 on success, -1 on failure
+ */
 int dlg_update_cseq(struct dlg_cell * dlg, unsigned int leg, str *cseq)
 {
        if ( dlg->cseq[leg].s ) {
@@ -304,7 +346,12 @@ error:
 }
 
 
-
+/*!
+ * \brief Lookup a dialog in the global list
+ * \param h_entry number of the hash table entry
+ * \param h_id id of the hash table entry
+ * \return dialog on success, NULL on failure
+ */
 struct dlg_cell* lookup_dlg( unsigned int h_entry, unsigned int h_id)
 {
        struct dlg_cell *dlg;
@@ -338,7 +385,15 @@ not_found:
 }
 
 
-
+/*!
+ * \brief Helper function to get a dialog corresponding to a SIP message
+ * \see get_dlg
+ * \param callid callid
+ * \param ftag from tag
+ * \param ttag to tag
+ * \param dir direction
+ * \return dialog structure on success, NULL on failure
+ */
 static inline struct dlg_cell* internal_get_dlg(unsigned int h_entry,
                                                str *callid, str *ftag, str *ttag, unsigned int *dir)
 {
@@ -374,11 +429,20 @@ not_found:
 
 
 
-/* Get dialog that correspond to CallId, From Tag and To Tag         */
-/* See RFC 3261, paragraph 4. Overview of Operation:                 */
-/* "The combination of the To tag, From tag, and Call-ID completely  */
-/* defines a peer-to-peer SIP relationship between [two UAs] and is  */
-/* referred to as a dialog."*/
+/*!
+ * \brief Get dialog that correspond to CallId, From Tag and To Tag
+ *
+ * Get dialog that correspond to CallId, From Tag and To Tag.
+ * See RFC 3261, paragraph 4. Overview of Operation:                 
+ * "The combination of the To tag, From tag, and Call-ID completely  
+ * defines a peer-to-peer SIP relationship between [two UAs] and is 
+ * referred to as a dialog."
+ * \param callid callid
+ * \param ftag from tag
+ * \param ttag to tag
+ * \param dir direction
+ * \return dialog structure on success, NULL on failure
+ */
 struct dlg_cell* get_dlg( str *callid, str *ftag, str *ttag, unsigned int *dir)
 {
        struct dlg_cell *dlg;
@@ -394,7 +458,11 @@ struct dlg_cell* get_dlg( str *callid, str *ftag, str *ttag, unsigned int *dir)
 }
 
 
-
+/*!
+ * \brief Link a dialog structure
+ * \param dlg dialog
+ * \param n extra increments for the reference counter
+ */
 void link_dlg(struct dlg_cell *dlg, int n)
 {
        struct dlg_entry *d_entry;
@@ -421,25 +489,54 @@ void link_dlg(struct dlg_cell *dlg, int n)
 }
 
 
-
-inline void unlink_unsafe_dlg(struct dlg_entry *d_entry,
-                                                                                                       struct dlg_cell *dlg)
-{
-       if (dlg->next)
-               dlg->next->prev = dlg->prev;
-       else
-               d_entry->last = dlg->prev;
-       if (dlg->prev)
-               dlg->prev->next = dlg->next;
-       else
-               d_entry->first = dlg->next;
-
-       dlg->next = dlg->prev = 0;
-
-       return;
-}
-
-
+/*!
+ * \brief Reference a dialog without locking
+ * \param _dlg dialog
+ * \param _cnt increment for the reference counter
+ */
+#define ref_dlg_unsafe(_dlg,_cnt)     \
+       do { \
+               (_dlg)->ref += (_cnt); \
+               LM_DBG("ref dlg %p with %d -> %d\n", \
+                       (_dlg),(_cnt),(_dlg)->ref); \
+       }while(0)
+
+
+/*!
+ * \brief Unreference a dialog without locking
+ * \param _dlg dialog
+ * \param _cnt decrement for the reference counter
+ */
+#define unref_dlg_unsafe(_dlg,_cnt,_d_entry)   \
+       do { \
+               (_dlg)->ref -= (_cnt); \
+               LM_DBG("unref dlg %p with %d -> %d\n",\
+                       (_dlg),(_cnt),(_dlg)->ref);\
+               if ((_dlg)->ref<0) {\
+                       LM_CRIT("bogus ref %d with cnt %d for dlg %p [%u:%u] "\
+                               "with clid '%.*s' and tags '%.*s' '%.*s'\n",\
+                               (_dlg)->ref, _cnt, _dlg,\
+                               (_dlg)->h_entry, (_dlg)->h_id,\
+                               (_dlg)->callid.len, (_dlg)->callid.s,\
+                               (_dlg)->tag[DLG_CALLER_LEG].len,\
+                               (_dlg)->tag[DLG_CALLER_LEG].s,\
+                               (_dlg)->tag[DLG_CALLEE_LEG].len,\
+                               (_dlg)->tag[DLG_CALLEE_LEG].s); \
+               }\
+               if ((_dlg)->ref<=0) { \
+                       unlink_unsafe_dlg( _d_entry, _dlg);\
+                       LM_DBG("ref <=0 for dialog %p\n",_dlg);\
+                       destroy_dlg(_dlg);\
+               }\
+       }while(0)
+
+
+/*!
+ * \brief Refefence a dialog with locking
+ * \see ref_dlg_unsafe
+ * \param dlg dialog
+ * \param cnt increment for the reference counter
+ */
 void ref_dlg(struct dlg_cell *dlg, unsigned int cnt)
 {
        struct dlg_entry *d_entry;
@@ -452,6 +549,12 @@ void ref_dlg(struct dlg_cell *dlg, unsigned int cnt)
 }
 
 
+/*!
+ * \brief Unreference a dialog with locking
+ * \see unref_dlg_unsafe
+ * \param dlg dialog
+ * \param cnt decrement for the reference counter
+ */
 void unref_dlg(struct dlg_cell *dlg, unsigned int cnt)
 {
        struct dlg_entry *d_entry;
@@ -464,7 +567,7 @@ void unref_dlg(struct dlg_cell *dlg, unsigned int cnt)
 }
 
 
-/**
+/*!
  * Small logging helper functions for next_state_dlg.
  * \param event logged event
  * \param dlg dialog data
@@ -479,8 +582,21 @@ static inline void log_next_state_dlg(const int event, const struct dlg_cell *dl
 }
 
 
+/*!
+ * \brief Update a dialog state according a event and the old state
+ *
+ * This functions implement the main state machine that update a dialog
+ * state according a processed event and the current state. If necessary
+ * it will delete the processed dialog. The old and new state are also
+ * saved for reference.
+ * \param dlg updated dialog
+ * \param event current event
+ * \param old_state old dialog state
+ * \param new_state new dialog state
+ * \param unref set to 1 when the dialog was deleted, 0 otherwise
+ */
 void next_state_dlg(struct dlg_cell *dlg, int event,
-                                                               int *old_state, int *new_state, int *unref)
+               int *old_state, int *new_state, int *unref)
 {
        struct dlg_entry *d_entry;
 
@@ -620,6 +736,14 @@ void next_state_dlg(struct dlg_cell *dlg, int event,
 
 
 /**************************** MI functions ******************************/
+/*!
+ * \brief Helper method that output a dialog via the MI interface
+ * \see mi_print_dlg
+ * \param rpl MI node that should be filled
+ * \param dlg printed dialog
+ * \param with_context if 1 then the dialog context will be also printed
+ * \return 0 on success, -1 on failure
+ */
 static inline int internal_mi_print_dlg(struct mi_node *rpl,
                                                                        struct dlg_cell *dlg, int with_context)
 {
@@ -747,12 +871,25 @@ error:
 }
 
 
+/*!
+ * \brief Output a dialog via the MI interface
+ * \param rpl MI node that should be filled
+ * \param dlg printed dialog
+ * \param with_context if 1 then the dialog context will be also printed
+ * \return 0 on success, -1 on failure
+ */
 int mi_print_dlg(struct mi_node *rpl, struct dlg_cell *dlg, int with_context)
 {
        return internal_mi_print_dlg( rpl, dlg, with_context);
 }
 
-
+/*!
+ * \brief Helper function that output all dialogs via the MI interface
+ * \see mi_print_dlgs
+ * \param rpl MI node that should be filled
+ * \param with_context if 1 then the dialog context will be also printed
+ * \return 0 on success, -1 on failure
+ */
 static int internal_mi_print_dlgs(struct mi_node *rpl, int with_context)
 {
        struct dlg_cell *dlg;
@@ -832,6 +969,12 @@ static inline struct mi_root* process_mi_params(struct mi_root *cmd_tree,
 }
 
 
+/*!
+ * \brief Output all dialogs via the MI interface
+ * \param cmd_tree MI command tree
+ * \param param unused
+ * \return mi node with the dialog information, or NULL on failure
+ */
 struct mi_root * mi_print_dlgs(struct mi_root *cmd_tree, void *param )
 {
        struct mi_root* rpl_tree= NULL;
@@ -863,6 +1006,12 @@ error:
 }
 
 
+/*!
+ * \brief Print a dialog context via the MI interface
+ * \param cmd_tree MI command tree
+ * \param param unused
+ * \return mi node with the dialog information, or NULL on failure
+ */
 struct mi_root * mi_print_dlgs_ctx(struct mi_root *cmd_tree, void *param )
 {
        struct mi_root* rpl_tree= NULL;
@@ -892,6 +1041,3 @@ error:
        free_mi_tree(rpl_tree);
        return NULL;
 }
-
-
-
index d4cc996..e01c311 100644 (file)
  *             CONFIRMED_NA due delayed "200 OK" (bogdan)
  */
 
+/*!
+ * \file
+ * \brief Functions and definitions related to dialog creation and searching
+ * \ingroup dialog
+ * Module: \ref dialog
+ */
 
 #ifndef _DIALOG_DLG_HASH_H_
 #define _DIALOG_DLG_HASH_H_
 #include "dlg_cb.h"
 
 
-#define DLG_STATE_UNCONFIRMED  1
-#define DLG_STATE_EARLY        2
-#define DLG_STATE_CONFIRMED_NA 3
-#define DLG_STATE_CONFIRMED    4
-#define DLG_STATE_DELETED      5
-
-#define DLG_EVENT_TDEL         1
-#define DLG_EVENT_RPL1xx       2
-#define DLG_EVENT_RPL2xx       3
-#define DLG_EVENT_RPL3xx       4
-#define DLG_EVENT_REQPRACK     5
-#define DLG_EVENT_REQACK       6
-#define DLG_EVENT_REQBYE       7
-#define DLG_EVENT_REQ          8
-
-#define DLG_FLAG_NEW           (1<<0)
-#define DLG_FLAG_CHANGED       (1<<1)
-#define DLG_FLAG_HASBYE        (1<<2)
-#define DLG_FLAG_TOBYE         (1<<3)
-#define DLG_FLAG_CALLERBYE     (1<<4)
-#define DLG_FLAG_CALLEEBYE     (1<<5)
-#define DLG_FLAG_LOCALDLG      (1<<6)
-
-#define DLG_CALLER_LEG         0
-#define DLG_CALLEE_LEG         1
-
-#define DLG_DIR_NONE           0
-#define DLG_DIR_DOWNSTREAM     1
-#define DLG_DIR_UPSTREAM       2
-
-
-
+/* states of a dialog */
+#define DLG_STATE_UNCONFIRMED  1 /*!< unconfirmed dialog */
+#define DLG_STATE_EARLY        2 /*!< early dialog */
+#define DLG_STATE_CONFIRMED_NA 3 /*!< confirmed dialog without a ACK yet */
+#define DLG_STATE_CONFIRMED    4 /*!< confirmed dialog */
+#define DLG_STATE_DELETED      5 /*!< deleted dialog */
+
+/* events for dialog processing */
+#define DLG_EVENT_TDEL         1 /*!< transaction was destroyed */
+#define DLG_EVENT_RPL1xx       2 /*!< 1xx request */
+#define DLG_EVENT_RPL2xx       3 /*!< 2xx request */ 
+#define DLG_EVENT_RPL3xx       4 /*!< 3xx request */
+#define DLG_EVENT_REQPRACK     5 /*!< PRACK request */
+#define DLG_EVENT_REQACK       6 /*!< ACK request */
+#define DLG_EVENT_REQBYE       7 /*!< BYE request */
+#define DLG_EVENT_REQ          8 /*!< other requests */
+
+/* dialog flags */
+#define DLG_FLAG_NEW           (1<<0) /*!< new dialog */
+#define DLG_FLAG_CHANGED       (1<<1) /*!< dialog was changed */
+#define DLG_FLAG_HASBYE        (1<<2) /*!< bye was received */
+#define DLG_FLAG_TOBYE         (1<<3) /*!< flag from dialog context */
+#define DLG_FLAG_CALLERBYE     (1<<4) /*!< bye from caller */
+#define DLG_FLAG_CALLEEBYE     (1<<5) /*!< bye from callee */
+#define DLG_FLAG_LOCALDLG      (1<<6) /*!< local dialog, unused */
+
+#define DLG_CALLER_LEG         0 /*!< attribute that belongs to a caller leg */
+#define DLG_CALLEE_LEG         1 /*!< attribute that belongs to a callee leg */
+
+#define DLG_DIR_NONE           0 /*!< dialog has no direction */
+#define DLG_DIR_DOWNSTREAM     1 /*!< dialog has downstream direction */
+#define DLG_DIR_UPSTREAM       2 /*!< dialog has upstream direction */
+
+
+/*! entries in the dialog list */
 struct dlg_cell
 {
-       volatile int         ref;
-       struct dlg_cell      *next;
-       struct dlg_cell      *prev;
-       unsigned int         h_id;
-       unsigned int         h_entry;
-       unsigned int         state;
-       unsigned int         lifetime;
-       unsigned int         start_ts;    /* start time  (absolute UNIX ts)*/
-       unsigned int         dflags;
-       unsigned int         sflags;
-       unsigned int         toroute;
-       unsigned int         from_rr_nb;
-       struct dlg_tl        tl;
-       str                  callid;
-       str                  from_uri;
-       str                  to_uri;
-       str                  tag[2];
-       str                  cseq[2];
-       str                  route_set[2];
-       str                  contact[2];
-       struct socket_info * bind_addr[2];
-       struct dlg_head_cbl  cbs;
-       struct dlg_profile_link *profile_links;
+       volatile int         ref;               /*!< reference counter */
+       struct dlg_cell      *next;             /*!< next entry in the list */
+       struct dlg_cell      *prev;             /*!< previous entry in the list */
+       unsigned int         h_id;              /*!< id of the hash table entry */
+       unsigned int         h_entry;           /*!< number of hash entry */
+       unsigned int         state;             /*!< dialog state */
+       unsigned int         lifetime;          /*!< dialog lifetime */
+       unsigned int         start_ts;          /*!< start time  (absolute UNIX ts)*/
+       unsigned int         dflags;            /*!< internal dialog flags */
+       unsigned int         sflags;            /*!< script dialog flags */
+       unsigned int         toroute;           /*!< index of route that is executed on timeout */
+       unsigned int         from_rr_nb;        /*!< information from record routing */
+       struct dlg_tl        tl;                /*!< dialog timer list */
+       str                  callid;            /*!< callid from SIP message */
+       str                  from_uri;          /*!< from uri from SIP message */
+       str                  to_uri;            /*!< to uri from SIP message */
+       str                  tag[2];            /*!< from tags of caller and to tag of callee */
+       str                  cseq[2];           /*!< CSEQ of caller and callee */
+       str                  route_set[2];      /*!< route set of caller and callee */
+       str                  contact[2];        /*!< contact of caller and callee */
+       struct socket_info * bind_addr[2];      /*! binded address of caller and callee */
+       struct dlg_head_cbl  cbs;               /*!< dialog callbacks */
+       struct dlg_profile_link *profile_links; /*!< dialog profiles */
 };
 
 
+/*! entries in the main dialog table */
 struct dlg_entry
 {
-       struct dlg_cell    *first;
-       struct dlg_cell    *last;
-       unsigned int        next_id;
-       unsigned int       lock_idx;
+       struct dlg_cell    *first;      /*!< dialog list */
+       struct dlg_cell    *last;       /*!< optimisation, end of the dialog list */
+       unsigned int       next_id;     /*!< next id */
+       unsigned int       lock_idx;    /*!< lock index */
 };
 
 
-
+/*! main dialog table */
 struct dlg_table
 {
-       unsigned int       size;
-       struct dlg_entry   *entries;
-       unsigned int       locks_no;
-       gen_lock_set_t     *locks;
+       unsigned int       size;        /*!< size of the dialog table */
+       struct dlg_entry   *entries;    /*!< dialog hash table */
+       unsigned int       locks_no;    /*!< number of locks */
+       gen_lock_set_t     *locks;      /*!< lock table */
 };
 
 
+/*! global dialog table */
 extern struct dlg_table *d_table;
+/*! point to the current dialog */
 extern struct dlg_cell  *current_dlg_pointer;
 
+
+/*!
+ * \brief Set a dialog lock
+ * \param _table dialog table
+ * \param _entry locked entry
+ */
 #define dlg_lock(_table, _entry) \
                lock_set_get( (_table)->locks, (_entry)->lock_idx);
+
+
+/*!
+ * \brief Release a dialog lock
+ * \param _table dialog table
+ * \param _entry locked entry
+ */
 #define dlg_unlock(_table, _entry) \
                lock_set_release( (_table)->locks, (_entry)->lock_idx);
 
-inline void unlink_unsafe_dlg(struct dlg_entry *d_entry, struct dlg_cell *dlg);
-inline void destroy_dlg(struct dlg_cell *dlg);
 
-#define ref_dlg_unsafe(_dlg,_cnt)     \
-       do { \
-               (_dlg)->ref += (_cnt); \
-               LM_DBG("ref dlg %p with %d -> %d\n", \
-                       (_dlg),(_cnt),(_dlg)->ref); \
-       }while(0)
-
-#define unref_dlg_unsafe(_dlg,_cnt,_d_entry)   \
-       do { \
-               (_dlg)->ref -= (_cnt); \
-               LM_DBG("unref dlg %p with %d -> %d\n",\
-                       (_dlg),(_cnt),(_dlg)->ref);\
-               if ((_dlg)->ref<0) {\
-                       LM_CRIT("bogus ref %d with cnt %d for dlg %p [%u:%u] "\
-                               "with clid '%.*s' and tags '%.*s' '%.*s'\n",\
-                               (_dlg)->ref, _cnt, _dlg,\
-                               (_dlg)->h_entry, (_dlg)->h_id,\
-                               (_dlg)->callid.len, (_dlg)->callid.s,\
-                               (_dlg)->tag[DLG_CALLER_LEG].len,\
-                               (_dlg)->tag[DLG_CALLER_LEG].s,\
-                               (_dlg)->tag[DLG_CALLEE_LEG].len,\
-                               (_dlg)->tag[DLG_CALLEE_LEG].s); \
-               }\
-               if ((_dlg)->ref<=0) { \
-                       unlink_unsafe_dlg( _d_entry, _dlg);\
-                       LM_DBG("ref <=0 for dialog %p\n",_dlg);\
-                       destroy_dlg(_dlg);\
-               }\
-       }while(0)
+/*!
+ * \brief Unlink a dialog from the list without locking
+ * \see unref_dlg_unsafe
+ * \param d_entry unlinked entry
+ * \param dlg unlinked dialog
+ */
+static inline void unlink_unsafe_dlg(struct dlg_entry *d_entry, struct dlg_cell *dlg)
+{
+       if (dlg->next)
+               dlg->next->prev = dlg->prev;
+       else
+               d_entry->last = dlg->prev;
+       if (dlg->prev)
+               dlg->prev->next = dlg->next;
+       else
+               d_entry->first = dlg->next;
+
+       dlg->next = dlg->prev = 0;
+
+       return;
+}
+
+
+/*!
+ * \brief Destroy a dialog, run callbacks and free memory
+ * \param dlg destroyed dialog
+ */
+inline void destroy_dlg(struct dlg_cell *dlg);
 
 
+/*!
+ * \brief Initialize the global dialog table
+ * \param size size of the table
+ * \return 0 on success, -1 on failure
+ */
 int init_dlg_table(unsigned int size);
 
+
+/*!
+ * \brief Destroy the global dialog table
+ */
 void destroy_dlg_table(void);
 
+
+/*!
+ * \brief Create a new dialog structure for a SIP dialog
+ * \param callid dialog callid
+ * \param from_uri dialog from uri
+ * \param to_uri dialog to uri
+ * \param from_tag dialog from tag
+ * \return created dialog structure on success, NULL otherwise
+ */
 struct dlg_cell* build_new_dlg(str *callid, str *from_uri,
                str *to_uri, str *from_tag);
 
+
+/*!
+ * \brief Set the leg information for an existing dialog
+ * \param dlg dialog
+ * \param tag from tag or to tag
+ * \param rr record-routing information
+ * \param contact caller or callee contact
+ * \param cseq CSEQ of caller or callee
+ * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
+ * \return 0 on success, -1 on failure
+ */
 int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
                str *cseq, unsigned int leg);
 
+
+/*!
+ * \brief Update or set the CSEQ for an existing dialog
+ * \param dlg dialog
+ * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
+ * \param cseq CSEQ of caller or callee
+ * \return 0 on success, -1 on failure
+ */
 int dlg_update_cseq(struct dlg_cell *dlg, unsigned int leg, str *cseq);
 
+
+/*!
+ * \brief Lookup a dialog in the global list
+ * \param h_entry number of the hash table entry
+ * \param h_id id of the hash table entry
+ * \return dialog on success, NULL on failure
+ */
 struct dlg_cell* lookup_dlg( unsigned int h_entry, unsigned int h_id);
 
+
+/*!
+ * \brief Get dialog that correspond to CallId, From Tag and To Tag
+ *
+ * Get dialog that correspond to CallId, From Tag and To Tag.
+ * See RFC 3261, paragraph 4. Overview of Operation:                 
+ * "The combination of the To tag, From tag, and Call-ID completely  
+ * defines a peer-to-peer SIP relationship between [two UAs] and is 
+ * referred to as a dialog."
+ * \param callid callid
+ * \param ftag from tag
+ * \param ttag to tag
+ * \param dir direction
+ * \return dialog structure on success, NULL on failure
+ */
 struct dlg_cell* get_dlg(str *callid, str *ftag, str *ttag, unsigned int *dir);
 
+
+/*!
+ * \brief Link a dialog structure
+ * \param dlg dialog
+ * \param n extra increments for the reference counter
+ */
 void link_dlg(struct dlg_cell *dlg, int n);
 
+
+/*!
+ * \brief Unreference a dialog with locking
+ * \see unref_dlg_unsafe
+ * \param dlg dialog
+ * \param cnt decrement for the reference counter
+ */
 void unref_dlg(struct dlg_cell *dlg, unsigned int cnt);
 
+
+/*!
+ * \brief Refefence a dialog with locking
+ * \see ref_dlg_unsafe
+ * \param dlg dialog
+ * \param cnt increment for the reference counter
+ */
 void ref_dlg(struct dlg_cell *dlg, unsigned int cnt);
 
+
+/*!
+ * \brief Update a dialog state according a event and the old state
+ *
+ * This functions implement the main state machine that update a dialog
+ * state according a processed event and the current state. If necessary
+ * it will delete the processed dialog. The old and new state are also
+ * saved for reference.
+ * \param dlg updated dialog
+ * \param event current event
+ * \param old_state old dialog state
+ * \param new_state new dialog state
+ * \param unref set to 1 when the dialog was deleted, 0 otherwise
+ */
 void next_state_dlg(struct dlg_cell *dlg, int event,
                int *old_state, int *new_state, int *unref);
 
+
+/*!
+ * \brief Output all dialogs via the MI interface
+ * \param cmd_tree MI root node
+ * \param param unused
+ * \return a mi node with the dialog information, or NULL on failure
+ */
 struct mi_root * mi_print_dlgs(struct mi_root *cmd, void *param );
+
+
+/*!
+ * \brief Print a dialog context via the MI interface
+ * \param cmd_tree MI command tree
+ * \param param unused
+ * \return mi node with the dialog information, or NULL on failure
+ */
 struct mi_root * mi_print_dlgs_ctx(struct mi_root *cmd, void *param );
 
+
+/*!
+ * \brief Check if a dialog structure matches to a SIP message dialog
+ * \param dlg dialog structure
+ * \param ftag SIP message from tag
+ * \param ttag SIP message to tag
+ * \param dir direction of the message, if DLG_DIR_NONE it will set
+ * \return 1 if dialog structure and message content matches, 0 otherwise
+ */
 static inline int match_dialog(struct dlg_cell *dlg, str *callid,
                                                           str *ftag, str *ttag, unsigned int *dir) {
        if (dlg->tag[DLG_CALLEE_LEG].len == 0) {
@@ -275,6 +414,14 @@ static inline int match_dialog(struct dlg_cell *dlg, str *callid,
        return 0;
 }
 
+
+/*!
+ * \brief Check if a downstream dialog structure matches a SIP message dialog
+ * \param dlg dialog structure
+ * \param callid SIP message callid
+ * \param ftag SIP message from tag
+ * \return 1 if dialog structure matches the SIP dialog, 0 otherwise
+ */
 static inline int match_downstream_dialog(struct dlg_cell *dlg, str *callid, str *ftag)
 {
        if (dlg->callid.len!=callid->len ||
@@ -286,6 +433,13 @@ static inline int match_downstream_dialog(struct dlg_cell *dlg, str *callid, str
 }
 
 
+/*!
+ * \brief Output a dialog via the MI interface
+ * \param rpl MI node that should be filled
+ * \param dlg printed dialog
+ * \param with_context if 1 then the dialog context will be also printed
+ * \return 0 on success, -1 on failure
+ */
 int mi_print_dlg(struct mi_node *rpl, struct dlg_cell *dlg, int with_context);
 
 #endif
index df7d334..732f430 100644 (file)
@@ -49,9 +49,6 @@ struct mi_root * mi_terminate_dlg(struct mi_root *cmd_tree, void *param );
 
 dlg_t* build_dlg_t(struct dlg_cell * cell, int dir);
 int free_tm_dlg(dlg_t *td);
-int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
-       struct cell* t, unsigned int leg, str *tag);
-
 int dlg_bye(struct dlg_cell *dlg, str *hdrs, int side);
 int dlg_bye_all(struct dlg_cell *dlg, str *hdrs);
 
index 2348590..df6f5d1 100644 (file)
@@ -34,6 +34,7 @@
 #include "../../modules/tm/tm_load.h"
 
 #include "dlg_req_within.h"
+#include "dlg_handlers.h"
 #include "dlg_transfer.h"
 
 #define DLG_HOLD_SDP "v=0\r\no=kamailio-bridge 0 0 IN IP4 0.0.0.0\r\ns=kamailio\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 9 RTP/AVP 8 0\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:0 PCMU/8000\r\n"
index a1813f8..c151c19 100644 (file)
@@ -26,6 +26,7 @@
 #include "../../pvar.h"
 #include "dlg_hash.h"
 
+/*! dialog context */
 typedef struct _dlg_ctx {
        int on;
        unsigned int flags;
index a954e0d..e735475 100644 (file)
@@ -76,7 +76,7 @@ extern str ds_setid_pvname;
 extern pv_spec_t ds_setid_pv;
 
 /* Structure containing pointers to TM-functions */
-struct tm_binds tmb;
+extern struct tm_binds tmb;
 extern str ds_ping_method;
 extern str ds_ping_from;
 extern int probing_threshhold; /*!< number of failed requests,
index 444a973..b5e1986 100644 (file)
@@ -12,52 +12,247 @@ Daniel-Constantin Mierla
    <miconda@gmail.com>
 
    Copyright © 2009 Daniel-Constantin Mierla
-     __________________________________________________________
+     __________________________________________________________________
 
    Table of Contents
 
    1. Admin Guide
 
-        1.1. Overview
-        1.2. Dependencies
+        1. Overview
+        2. Dependencies
 
-              1.2.1. Kamailio Modules
-              1.2.2. External Libraries or Applications
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
 
-        1.3. Exported MI Functions
+        3. Exported Functions
 
-              1.3.1. arg
-              1.3.2. kill
-              1.3.3. pwd
-              1.3.4. uptime
-              1.3.5. version
-              1.3.6. which
+              3.1. setsflag(flag)
+              3.2. issflagset(flag)
+              3.3. resetsflag(flag)
+              3.4. setbflag(flag [, branch])
+              3.5. isbflagset(flag [, branch])
+              3.6. resetsflag(flag [, branch])
+              3.7. km_append_branch([uri])
+
+        4. Exported MI Functions
+
+              4.1. arg
+              4.2. kill
+              4.3. pwd
+              4.4. uptime
+              4.5. version
+              4.6. which
+
+   List of Examples
+
+   1.1. setsflag usage
+   1.2. setsflag usage
+   1.3. resetsflag usage
+   1.4. setbflag usage
+   1.5. setbflag usage
+   1.6. resetsflag usage
+   1.7. km_append_branch usage
 
 Chapter 1. Admin Guide
 
-1.1. Overview
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Exported Functions
+
+        3.1. setsflag(flag)
+        3.2. issflagset(flag)
+        3.3. resetsflag(flag)
+        3.4. setbflag(flag [, branch])
+        3.5. isbflagset(flag [, branch])
+        3.6. resetsflag(flag [, branch])
+        3.7. km_append_branch([uri])
+
+   4. Exported MI Functions
+
+        4.1. arg
+        4.2. kill
+        4.3. pwd
+        4.4. uptime
+        4.5. version
+        4.6. which
+
+1. Overview
 
    This module collects extensions from Kamailio core.
 
-   Kamailio Core CookBook is available at:
-   http://kamailio.org/dokuwiki/
+   Kamailio Core CookBook is available at: http://kamailio.org/dokuwiki/
+
+2. Dependencies
 
-1.2. Dependencies
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
 
-1.2.1. Kamailio Modules
+2.1. Kamailio Modules
 
    The following modules must be loaded before this module:
      * No dependencies on other Kamailio modules.
 
-1.2.2. External Libraries or Applications
+2.2. External Libraries or Applications
 
-   The following libraries or applications must be installed
-   before running Kamailio with this module loaded:
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
      * None.
 
-1.3. Exported MI Functions
+3. Exported Functions
+
+   3.1. setsflag(flag)
+   3.2. issflagset(flag)
+   3.3. resetsflag(flag)
+   3.4. setbflag(flag [, branch])
+   3.5. isbflagset(flag [, branch])
+   3.6. resetsflag(flag [, branch])
+   3.7. km_append_branch([uri])
+
+3.1. setsflag(flag)
+
+   Set the script flag.
+
+   Meaning of the parameters is as follows:
+     * flag - the index of the script flag to be set. Can be integer or
+       pseudo-variable with integer value.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.1. setsflag usage
+...
+setsflag("1");
+...
+$var(flag) = 11;
+setsflag("$var(flag)");
+...
+
+3.2. issflagset(flag)
+
+   Return true of the script flag is set.
+
+   Meaning of the parameters is as follows:
+     * flag - the index of the script flag to be tested. Can be integer or
+       pseudo-variable with integer value.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.2. setsflag usage
+...
+if(issflagset("1"))
+{
+    ...
+}
+...
+
+3.3. resetsflag(flag)
+
+   Reset the script flag.
+
+   Meaning of the parameters is as follows:
+     * flag - the index of the script flag to be reset. Can be integer or
+       pseudo-variable with integer value.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.3. resetsflag usage
+...
+resetsflag("1");
+...
+
+3.4. setbflag(flag [, branch])
+
+   Set the branch flag.
+
+   Meaning of the parameters is as follows:
+     * flag - the index of the branch flag to be set. Can be integer or
+       pseudo-variable with integer value.
+     * branch - the index of the branch whose flag to be set. Can be
+       integer or pseudo-variable with integer value. If omitted, then
+       branch 0 is used (R-URI).
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.4. setbflag usage
+...
+setbflag("1");
+...
+$var(flag) = 11;
+setbflag("$var(flag)", "1");
+...
+
+3.5. isbflagset(flag [, branch])
+
+   Return true of the branch flag is set.
+
+   Meaning of the parameters is as follows:
+     * flag - the index of the branch flag to be tested. Can be integer or
+       pseudo-variable with integer value.
+     * branch - the index of the branch whose flag to be set. Can be
+       integer or pseudo-variable with integer value. If omitted, then
+       branch 0 is used (R-URI).
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.5. setbflag usage
+...
+if(isbflagset("1"))
+{
+    ...
+}
+...
+
+3.6. resetsflag(flag [, branch])
+
+   Reset the script flag.
+
+   Meaning of the parameters is as follows:
+     * flag - the index of the script flag to be reset. Can be integer or
+       pseudo-variable with integer value.
+     * branch - the index of the branch whose flag to be set. Can be
+       integer or pseudo-variable with integer value. If omitted, then
+       branch 0 is used (R-URI).
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.6. resetsflag usage
+...
+resetbflag("1");
+...
+
+3.7. km_append_branch([uri])
+
+   Append a new branch to SIP request.
+
+   Meaning of the parameters is as follows:
+     * uri - SIP URI of the new destination. If omitted then the R-URI is
+       used. It can be static string or a string with pseudo-variables
+       that will be evaluated at runtime.
+
+   This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.
+
+   Example 1.7. km_append_branch usage
+...
+km_append_branch();
+...
+km_append_branch("sip:alice@sip-router.org");
+...
+
+4. Exported MI Functions
+
+   4.1. arg
+   4.2. kill
+   4.3. pwd
+   4.4. uptime
+   4.5. version
+   4.6. which
 
-1.3.1.  arg
+4.1.  arg
 
    Print command line arguments.
 
@@ -69,7 +264,7 @@ Chapter 1. Admin Guide
                 :arg:_reply_fifo_file_
                 _empty_line_
 
-1.3.2.  kill
+4.2.  kill
 
    Kill the application.
 
@@ -81,7 +276,7 @@ Chapter 1. Admin Guide
                 :kill:_reply_fifo_file_
                 _empty_line_
 
-1.3.3.  pwd
+4.3.  pwd
 
    Print working directory.
 
@@ -93,7 +288,7 @@ Chapter 1. Admin Guide
                 :pwd:_reply_fifo_file_
                 _empty_line_
 
-1.3.4.  uptime
+4.4.  uptime
 
    Print uptime.
 
@@ -105,7 +300,7 @@ Chapter 1. Admin Guide
                 :uptime:_reply_fifo_file_
                 _empty_line_
 
-1.3.5.  version
+4.5.  version
 
    Print version information.
 
@@ -117,7 +312,7 @@ Chapter 1. Admin Guide
                 :version:_reply_fifo_file_
                 _empty_line_
 
-1.3.6.  which
+4.6.  which
 
    Print list of available MI commands.
 
index f4dc7ac..7fff6a3 100644 (file)
        </section>
        </section>
 
+       <section>
+       <title>Exported Functions</title>
+               <section>
+               <title><function moreinfo="none">setsflag(flag)</function></title>
+               <para>
+                       Set the script flag.
+               </para>
+               <para>Meaning of the parameters is as follows:</para>
+               <itemizedlist>
+               <listitem>
+                       <para>
+                               <emphasis>flag</emphasis> - the index of the script flag to
+                               be set. Can be integer or pseudo-variable with integer value.
+                       </para>
+               </listitem>
+               </itemizedlist>
+               <para>
+               This function can be used from ANY_ROUTE.
+               </para>
+               <example>
+               <title><function>setsflag</function> usage</title>
+               <programlisting format="linespecific">
+...
+setsflag("1");
+...
+$var(flag) = 11;
+setsflag("$var(flag)");
+...
+</programlisting>
+               </example>
+               </section>
+               <section>
+               <title><function moreinfo="none">issflagset(flag)</function></title>
+               <para>
+                       Return true of the script flag is set.
+               </para>
+               <para>Meaning of the parameters is as follows:</para>
+               <itemizedlist>
+               <listitem>
+                       <para>
+                               <emphasis>flag</emphasis> - the index of the script flag to
+                               be tested. Can be integer or pseudo-variable with integer value.
+                       </para>
+               </listitem>
+               </itemizedlist>
+               <para>
+               This function can be used from ANY_ROUTE.
+               </para>
+               <example>
+               <title><function>setsflag</function> usage</title>
+               <programlisting format="linespecific">
+...
+if(issflagset("1"))
+{
+    ...
+}
+...
+</programlisting>
+               </example>
+               </section>
+               <section>
+               <title><function moreinfo="none">resetsflag(flag)</function></title>
+               <para>
+                       Reset the script flag.
+               </para>
+               <para>Meaning of the parameters is as follows:</para>
+               <itemizedlist>
+               <listitem>
+                       <para>
+                               <emphasis>flag</emphasis> - the index of the script flag to
+                               be reset. Can be integer or pseudo-variable with integer value.
+                       </para>
+               </listitem>
+               </itemizedlist>
+               <para>
+               This function can be used from ANY_ROUTE.
+               </para>
+               <example>
+               <title><function>resetsflag</function> usage</title>
+               <programlisting format="linespecific">
+...
+resetsflag("1");
+...
+</programlisting>
+               </example>
+               </section>
+               <section>
+               <title><function moreinfo="none">setbflag(flag [, branch])</function></title>
+               <para>
+                       Set the branch flag.
+               </para>
+               <para>Meaning of the parameters is as follows:</para>
+               <itemizedlist>
+               <listitem>
+                       <para>
+                               <emphasis>flag</emphasis> - the index of the branch flag to
+                               be set. Can be integer or pseudo-variable with integer value.
+                       </para>
+               </listitem>
+               <listitem>
+                       <para>
+                               <emphasis>branch</emphasis> - the index of the branch whose
+                               flag to be set. Can be integer or pseudo-variable with integer
+                               value. If omitted, then branch 0 is used (R-URI).
+                       </para>
+               </listitem>
+               </itemizedlist>
+               <para>
+               This function can be used from ANY_ROUTE.
+               </para>
+               <example>
+               <title><function>setbflag</function> usage</title>
+               <programlisting format="linespecific">
+...
+setbflag("1");
+...
+$var(flag) = 11;
+setbflag("$var(flag)", "1");
+...
+</programlisting>
+               </example>
+               </section>
+               <section>
+               <title><function moreinfo="none">isbflagset(flag [, branch])</function></title>
+               <para>
+                       Return true of the branch flag is set.
+               </para>
+               <para>Meaning of the parameters is as follows:</para>
+               <itemizedlist>
+               <listitem>
+                       <para>
+                               <emphasis>flag</emphasis> - the index of the branch flag to
+                               be tested. Can be integer or pseudo-variable with integer value.
+                       </para>
+               </listitem>
+               <listitem>
+                       <para>
+                               <emphasis>branch</emphasis> - the index of the branch whose
+                               flag to be set. Can be integer or pseudo-variable with integer
+                               value. If omitted, then branch 0 is used (R-URI).
+                       </para>
+               </listitem>
+               </itemizedlist>
+               <para>
+               This function can be used from ANY_ROUTE.
+               </para>
+               <example>
+               <title><function>setbflag</function> usage</title>
+               <programlisting format="linespecific">
+...
+if(isbflagset("1"))
+{
+    ...
+}
+...
+</programlisting>
+               </example>
+               </section>
+               <section>
+               <title><function moreinfo="none">resetsflag(flag [, branch])</function></title>
+               <para>
+                       Reset the script flag.
+               </para>
+               <para>Meaning of the parameters is as follows:</para>
+               <itemizedlist>
+               <listitem>
+                       <para>
+                               <emphasis>flag</emphasis> - the index of the script flag to
+                               be reset. Can be integer or pseudo-variable with integer value.
+                       </para>
+               </listitem>
+               <listitem>
+                       <para>
+                               <emphasis>branch</emphasis> - the index of the branch whose
+                               flag to be set. Can be integer or pseudo-variable with integer
+                               value. If omitted, then branch 0 is used (R-URI).
+                       </para>
+               </listitem>
+               </itemizedlist>
+               <para>
+               This function can be used from ANY_ROUTE.
+               </para>
+               <example>
+               <title><function>resetsflag</function> usage</title>
+               <programlisting format="linespecific">
+...
+resetbflag("1");
+...
+</programlisting>
+               </example>
+               </section>
+               <section>
+               <title><function moreinfo="none">km_append_branch([uri])</function></title>
+               <para>
+                       Append a new branch to SIP request.
+               </para>
+               <para>Meaning of the parameters is as follows:</para>
+               <itemizedlist>
+               <listitem>
+                       <para>
+                               <emphasis>uri</emphasis> - SIP URI of the new destination. If
+                               omitted then the R-URI is used. It can be static string or
+                               a string with pseudo-variables that will be evaluated at
+                               runtime.
+                       </para>
+               </listitem>
+               </itemizedlist>
+               <para>
+               This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.
+               </para>
+               <example>
+               <title><function>km_append_branch</function> usage</title>
+               <programlisting format="linespecific">
+...
+km_append_branch();
+...
+km_append_branch("sip:alice@sip-router.org");
+...
+</programlisting>
+               </example>
+               </section>
+       </section>
+
        <section>
        <title>Exported MI Functions</title>
        <section>
diff --git a/modules_k/kex/flags.c b/modules_k/kex/flags.c
new file mode 100644 (file)
index 0000000..ae539d1
--- /dev/null
@@ -0,0 +1,144 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009
+ *
+ * This file is part of SIP-Router.org, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "../../dprint.h"
+#include "../../flags.h"
+#include "../../dset.h"
+#include "../../mod_fix.h"
+#include "flags.h"
+
+int w_issflagset(struct sip_msg *msg, char *flag, str *s2)
+{
+       int fval=0;
+       if(fixup_get_ivalue(msg, (gparam_p)flag, &fval)!=0)
+       {
+               LM_ERR("no flag value\n");
+               return -1;
+       }
+       if(fval<0 || fval>31)
+               return -1;
+       return issflagset((flag_t)fval);
+}
+
+int w_resetsflag(struct sip_msg *msg, char *flag, str *s2)
+{
+       int fval=0;
+       if(fixup_get_ivalue(msg, (gparam_p)flag, &fval)!=0)
+       {
+               LM_ERR("no flag value\n");
+               return -1;
+       }
+       if(fval<0 || fval>31)
+               return -1;
+       return resetsflag((flag_t)fval);
+}
+
+int w_setsflag(struct sip_msg *msg, char *flag, char *s2)
+{
+       int fval=0;
+       if(fixup_get_ivalue(msg, (gparam_p)flag, &fval)!=0)
+       {
+               LM_ERR("no flag value\n");
+               return -1;
+       }
+       if(fval<0 || fval>31)
+               return -1;
+       return setsflag((flag_t)fval);
+}
+
+int w_isbflagset(struct sip_msg *msg, char *flag, str *idx)
+{
+       int fval=0;
+       int ival=0;
+       if(fixup_get_ivalue(msg, (gparam_p)flag, &fval)!=0)
+       {
+               LM_ERR("no flag value\n");
+               return -1;
+       }
+       if(fval<0 || fval>31)
+               return -1;
+       if(idx!=0)
+       {
+               if(fixup_get_ivalue(msg, (gparam_p)idx, &ival)!=0)
+               {
+                       LM_ERR("no idx value\n");
+                       return -1;
+               }
+               if(ival<0)
+                       return -1;
+       }
+       return isbflagset(ival, (flag_t)fval);
+}
+
+int w_resetbflag(struct sip_msg *msg, char *flag, str *idx)
+{
+               int fval=0;
+       int ival=0;
+       if(fixup_get_ivalue(msg, (gparam_p)flag, &fval)!=0)
+       {
+               LM_ERR("no flag value\n");
+               return -1;
+       }
+       if(fval<0 || fval>31)
+               return -1;
+       if(idx!=0)
+       {
+               if(fixup_get_ivalue(msg, (gparam_p)idx, &ival)!=0)
+               {
+                       LM_ERR("no idx value\n");
+                       return -1;
+               }
+               if(ival<0)
+                       return -1;
+       }
+       return resetbflag(ival, (flag_t)fval);
+
+}
+
+int w_setbflag(struct sip_msg *msg, char *flag, char *idx)
+{
+       int fval=0;
+       int ival=0;
+       if(fixup_get_ivalue(msg, (gparam_p)flag, &fval)!=0)
+       {
+               LM_ERR("no flag value\n");
+               return -1;
+       }
+       if(fval<0 || fval>31)
+               return -1;
+       if(idx!=0)
+       {
+               if(fixup_get_ivalue(msg, (gparam_p)idx, &ival)!=0)
+               {
+                       LM_ERR("no idx value\n");
+                       return -1;
+               }
+               if(ival<0)
+                       return -1;
+       }
+       return setbflag(ival, (flag_t)fval);
+}
+
diff --git a/modules_k/kex/flags.h b/modules_k/kex/flags.h
new file mode 100644 (file)
index 0000000..d0dbad4
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009
+ *
+ * This file is part of SIP-Router.org, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+#ifndef _KEX_FLAGS_H_
+#define _KEX_FLAGS_H_
+
+#include "../../sr_module.h"
+
+int w_issflagset(struct sip_msg *msg, char *flag, str *s2);
+int w_resetsflag(struct sip_msg *msg, char *flag, str *s2);
+int w_setsflag(struct sip_msg *msg, char *flag, char *s2);
+int w_isbflagset(struct sip_msg *msg, char *flag, str *idx);
+int w_resetbflag(struct sip_msg *msg, char *flag, str *idx);
+int w_setbflag(struct sip_msg *msg, char *flag, char *idx);
+
+#endif
index c9c3ae3..9baa48d 100644 (file)
@@ -3,9 +3,9 @@
  *
  * Copyright (C) 2009
  *
- * This file is part of Kamailio, a free SIP server.
+ * This file is part of SIP-Router.org, a free SIP server.
  *
- * Kamailio is free software; you can redistribute it and/or modify
+ * SIP-Router is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
 
 #include "../../sr_module.h"
 #include "../../dprint.h"
+#include "../../flags.h"
+#include "../../dset.h"
+#include "../../mod_fix.h"
 
+#include "flags.h"
+#include "km_core.h"
 #include "mi_core.h"
 #include "core_stats.h"
 
@@ -38,10 +43,32 @@ MODULE_VERSION
 
 /** module functions */
 static int mod_init(void);
-
 void destroy(void);
 
 static cmd_export_t cmds[]={
+       {"setsflag", (cmd_function)w_setsflag,          1,fixup_igp_null,
+                       0, ANY_ROUTE },
+       {"resetsflag", (cmd_function)w_resetsflag,      1,fixup_igp_null,
+                       0, ANY_ROUTE },
+       {"issflagset", (cmd_function)w_issflagset,      1,fixup_igp_null,
+                       0, ANY_ROUTE },
+       {"setbflag", (cmd_function)w_setbflag,          1,fixup_igp_null,
+                       0, ANY_ROUTE },
+       {"setbflag", (cmd_function)w_setbflag,          2,fixup_igp_igp,
+                       0, ANY_ROUTE },
+       {"resetbflag", (cmd_function)w_resetbflag,      1,fixup_igp_null,
+                       0, ANY_ROUTE },
+       {"resetbflag", (cmd_function)w_resetbflag,      2,fixup_igp_igp,
+                       0, ANY_ROUTE },
+       {"isbflagset", (cmd_function)w_isbflagset,      1,fixup_igp_null,
+                       0, ANY_ROUTE },
+       {"isbflagset", (cmd_function)w_isbflagset,      2,fixup_igp_igp,
+                       0, ANY_ROUTE },
+       {"km_append_branch", (cmd_function)w_km_append_branch, 0, 0,
+                       0, REQUEST_ROUTE | FAILURE_ROUTE },
+       {"km_append_branch", (cmd_function)w_km_append_branch, 1, fixup_spve_null,
+                       0, REQUEST_ROUTE | FAILURE_ROUTE },
+
        {0,0,0,0,0,0}
 };
 
@@ -93,3 +120,4 @@ void destroy(void)
        return;
 }
 
+
diff --git a/modules_k/kex/km_core.c b/modules_k/kex/km_core.c
new file mode 100644 (file)
index 0000000..beebb35
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009
+ *
+ * This file is part of SIP-Router.org, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "../../dprint.h"
+#include "../../dset.h"
+#include "../../flags.h"
+#include "../../mod_fix.h"
+#include "km_core.h"
+
+int w_km_append_branch(struct sip_msg *msg, char *uri, str *sq)
+{
+       str suri;
+       int ret;
+       int q = Q_UNSPECIFIED;
+       flag_t branch_flags = 0;
+
+       getbflagsval(0, &branch_flags);
+       if (uri==NULL) {
+               ret = km_append_branch(msg, 0, &msg->dst_uri, &msg->path_vec,
+                       q, branch_flags, msg->force_send_socket);
+               /* reset all branch info */
+               msg->force_send_socket = 0;
+               setbflagsval(0, 0);
+               if(msg->dst_uri.s!=0)
+                       pkg_free(msg->dst_uri.s);
+               msg->dst_uri.s = 0;
+               msg->dst_uri.len = 0;
+               if(msg->path_vec.s!=0)
+                       pkg_free(msg->path_vec.s);
+               msg->path_vec.s = 0;
+               msg->path_vec.len = 0;
+       } else {
+               if(fixup_get_svalue(msg, (gparam_p)uri, &suri)!=0)
+               {
+                       LM_ERR("cannot get the URI parameter\n");
+                       return -1;
+               }
+               ret = km_append_branch(msg, &suri, &msg->dst_uri, 
+                       &msg->path_vec, q, branch_flags,
+                       msg->force_send_socket);
+       }
+       return ret;
+}
+
diff --git a/modules_k/kex/km_core.h b/modules_k/kex/km_core.h
new file mode 100644 (file)
index 0000000..a668c71
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009
+ *
+ * This file is part of SIP-Router.org, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+#ifndef _KEX_CORE_H_
+#define _KEX_CORE_H_
+
+#include "../../sr_module.h"
+
+int w_km_append_branch(struct sip_msg *msg, char *uri, str *s2);
+
+#endif
index 9ae2c1b..451811d 100644 (file)
@@ -18,4 +18,5 @@ DEFS+=-DOPENSER_MOD_INTERFACE
 
 SERLIBPATH=../../lib
 SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
 include ../../Makefile.modules
index 054e550..627fced 100644 (file)
@@ -27,7 +27,7 @@
 #define _PUA_DLGINFO_H
 #include "../pua/pua_bind.h"
 
-send_publish_t pua_send_publish;
+extern send_publish_t pua_send_publish;
 
 void dialog_publish(char *state, str *entity, str *peer, str *callid, 
        unsigned int initiator, unsigned int lifetime, str *localtag, str *remotetag);
index 7be83c0..594c5e1 100644 (file)
@@ -26,8 +26,8 @@
 #define _PUA_UL
 #include "../pua/pua_bind.h"
 
-send_publish_t pua_send_publish;
-send_subscribe_t pua_send_subscribe;
+extern send_publish_t pua_send_publish;
+extern send_subscribe_t pua_send_subscribe;
 void ul_publish(ucontact_t* c, int type, void* param);
 int pua_unset_publish(struct sip_msg* msg , void* param);
 
index 9c6ef99..6b9b892 100644 (file)
@@ -28,6 +28,7 @@ Daniel-Constantin Mierla
 
               3.1. shvset (string)
               3.2. varset (string)
+              3.3. avp_aliases (string)
 
         4. Exported Functions
 
@@ -43,10 +44,11 @@ Daniel-Constantin Mierla
 
    1.1. shvset parameter usage
    1.2. varset parameter usage
-   1.3. pv_isset usage
-   1.4. pv_unset usage
-   1.5. shv_set usage
-   1.6. shv_get usage
+   1.3. avp_aliases parameter usage
+   1.4. pv_isset usage
+   1.5. pv_unset usage
+   1.6. shv_set usage
+   1.7. shv_get usage
 
 Chapter 1. Admin Guide
 
@@ -62,6 +64,7 @@ Chapter 1. Admin Guide
 
         3.1. shvset (string)
         3.2. varset (string)
+        3.3. avp_aliases (string)
 
    4. Exported Functions
 
@@ -99,6 +102,7 @@ Chapter 1. Admin Guide
 
    3.1. shvset (string)
    3.2. varset (string)
+   3.3. avp_aliases (string)
 
 3.1. shvset (string)
 
@@ -142,6 +146,17 @@ modparam("pv", "varset", "init=i:1")
 modparam("pv", "varset", "gw=s:sip:11.11.11.11;transport=tcp")
 ...
 
+3.3. avp_aliases (string)
+
+   Define aliases for PV AVP names.
+
+   Default value is NULL.
+
+   Example 1.3. avp_aliases parameter usage
+...
+modparam("pv","avp_aliases","email=s:email_addr;tmp=i:100")
+...
+
 4. Exported Functions
 
    4.1. pv_isset(pvar)
@@ -156,7 +171,7 @@ modparam("pv", "varset", "gw=s:sip:11.11.11.11;transport=tcp")
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.3. pv_isset usage
+   Example 1.4. pv_isset usage
 ...
 if(pv_isset("$avp("s:x")"))
 {
@@ -173,7 +188,7 @@ if(pv_isset("$avp("s:x")"))
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.4. pv_unset usage
+   Example 1.5. pv_unset usage
 ...
 pv_unset("$avp("s:x")");
 ...
@@ -201,7 +216,7 @@ pv_unset("$avp("s:x")");
                 _value_
                 _empty_line_
 
-   Example 1.5. shv_set usage
+   Example 1.6. shv_set usage
 ...
 $ kamctl fifo shv_set debug int 0
 ...
@@ -219,7 +234,7 @@ $ kamctl fifo shv_set debug int 0
                 _name_
                 _empty_line_
 
-   Example 1.6. shv_get usage
+   Example 1.7. shv_get usage
 ...
 $ kamctl fifo shv_get debug
 $ kamctl fifo shv_get
index f8b50ad..f6d42cf 100644 (file)
@@ -124,6 +124,25 @@ modparam("pv", "varset", "gw=s:sip:11.11.11.11;transport=tcp")
 </programlisting>
            </example>
        </section>
+               <section>
+                       <title><varname>avp_aliases</varname> (string)</title>
+                       <para>
+                       Define aliases for PV AVP names.
+                       </para>
+                       <para>
+                               <emphasis>
+                                       Default value is NULL.
+                               </emphasis>
+                       </para>
+                       <example>
+                               <title><varname>avp_aliases</varname> parameter usage</title>
+                               <programlisting format="linespecific">
+...
+modparam("pv","avp_aliases","email=s:email_addr;tmp=i:100")
+...
+                               </programlisting>
+                       </example>
+               </section>
        </section>
        <section>
        <title>Exported Functions</title>
index 9d7078a..596b618 100644 (file)
@@ -359,9 +359,12 @@ static pv_export_t mod_pvs[] = {
        { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
 };
 
+static int add_avp_aliases(modparam_t type, void* val);
+
 static param_export_t params[]={ 
        {"shvset",              STR_PARAM|USE_FUNC_PARAM, (void*)param_set_shvar },
        {"varset",              STR_PARAM|USE_FUNC_PARAM, (void*)param_set_var },
+       {"avp_aliases",         STR_PARAM|USE_FUNC_PARAM, (void*)add_avp_aliases },
        {0,0,0}
 };
 
@@ -455,3 +458,14 @@ static int pv_unset(struct sip_msg* msg, char* pvid, char *foo)
        return 1;
 }
 
+static int add_avp_aliases(modparam_t type, void* val)
+{
+       if (val!=0 && ((char*)val)[0]!=0)
+       {
+               if ( add_avp_galias_str((char*)val)!=0 )
+                       return -1;
+       }
+
+       return 0;
+}
+
index ead4e78..0203920 100644 (file)
@@ -483,7 +483,7 @@ int pv_get_bflags(struct sip_msg *msg, pv_param_t *param,
                pv_value_t *res)
 {
        flag_t flags;
-       if (getbflags(&flags, 0) < 0) {
+       if (getbflagsval(0, &flags) < 0) {
                ERR("pv_get_bflags: Error while obtainig values of branch flags\n");
                return -1;
        }
@@ -498,7 +498,7 @@ int pv_get_hexbflags(struct sip_msg *msg, pv_param_t *param,
        if(res==NULL)
                return -1;
 
-       if (getbflags(&flags, 0) < 0) {
+       if (getbflagsval(0, &flags) < 0) {
                ERR("pv_get_hexbflags: Error while obtaining values of branch flags\n");
                return -1;
        }
index 4988687..3401edd 100644 (file)
@@ -995,7 +995,12 @@ int tr_eval_tobody(struct sip_msg *msg, tr_param_t *tp, int subtype,
                        if(_tr_tobody.param_lst!=NULL)
                        {
                                val->rs.s = _tr_tobody.param_lst->name.s;
-                               val->rs.len = _tr_tobody.body.s+_tr_tobody.body.len-val->rs.s;
+                               if(_tr_tobody.last_param->value.s!=NULL)
+                                       val->rs.len = _tr_tobody.last_param->value.s
+                                                       +_tr_tobody.last_param->value.len - val->rs.s;
+                               else
+                                       val->rs.len = _tr_tobody.last_param->name.s
+                                                       +_tr_tobody.last_param->name.len - val->rs.s;
                        } else val->rs = _tr_empty;
                        break;
 
index f80d901..735a4e2 100644 (file)
@@ -78,6 +78,7 @@
 
 MODULE_VERSION
 
+usrloc_api_t ul;/*!< Structure containing pointers to usrloc functions*/
 
 /*! \brief Module init & destroy function */
 static int  mod_init(void);
index 33209ee..2d50de6 100644 (file)
@@ -98,7 +98,7 @@ extern int path_use_params;
 extern str sock_hdr_name;
 extern int sock_flag;
 
-usrloc_api_t ul;  /*!< Structure containing pointers to usrloc functions */
+extern usrloc_api_t ul;/*!< Structure containing pointers to usrloc functions*/
 
 extern struct sl_binds slb;
 
index 6f7b747..13e0b49 100644 (file)
@@ -278,7 +278,7 @@ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
 
                /* set flags */
                ci.flags  = _f;
-               getbflags(&ci.flags, 0);
+               getbflagsval(0, &ci.flags);
 
                /* get received */
                if (path_received.len && path_received.s) {
index 89b2d41..8223f0d 100644 (file)
@@ -25,7 +25,6 @@ mailto:s.frings@mail.isis.de
 #include "libsms_modem.h"
 
 
-int  sms_report_type;
 
 static char hexa[16] = {
        '0','1','2','3','4','5','6','7',
index 4d96c80..e482267 100644 (file)
@@ -76,7 +76,6 @@ str    domain;
 int    *queued_msgs    = 0;
 int    use_contact     = 0;
 int    sms_report_type = NO_REPORT;
-struct tm_binds tmb;
 
 
 static proc_export_t sms_procs[] = {
index 4b48a46..b4fd322 100644 (file)
@@ -61,7 +61,6 @@ int nr_of_modems;
 int max_sms_parts;
 int *queued_msgs;
 int use_contact;
-int sms_report_type;
 struct tm_binds tmb;
 
 
diff --git a/modules_k/tmx/Makefile b/modules_k/tmx/Makefile
new file mode 100644 (file)
index 0000000..b88d45e
--- /dev/null
@@ -0,0 +1,19 @@
+# $Id$
+#
+# example module makefile
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=tmx.so
+LIBS=
+
+DEFS+=-DOPENSER_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+
+include ../../Makefile.modules
diff --git a/modules_k/tmx/README b/modules_k/tmx/README
new file mode 100644 (file)
index 0000000..83d6e37
--- /dev/null
@@ -0,0 +1,259 @@
+TMX Module
+
+Daniel-Constantin Mierla
+
+   asipto.com
+   <miconda@gmail.com>
+
+Edited by
+
+Daniel-Constantin Mierla
+
+   <miconda@gmail.com>
+
+   Copyright © 2009 Daniel-Constantin Mierla
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Exported Functions
+
+              3.1. t_cancel_branches(which)
+
+        4. Exported pseudo-variables
+        5. Exported MI Functions
+
+              5.1. t_uac_dlg
+              5.2. t_uac_cancel
+              5.3. t_hash
+              5.4. t_reply
+
+        6. Exported statistics
+
+              6.1. received_replies
+              6.2. relayed_replies
+              6.3. local_replies
+              6.4. UAS_transactions
+              6.5. UAC_transactions
+              6.6. 2xx_transactions
+              6.7. 3xx_transactions
+              6.8. 4xx_transactions
+              6.9. 5xx_transactions
+              6.10. 6xx_transactions
+              6.11. inuse_transactions
+
+   List of Examples
+
+   1.1. t_cancel_branches usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Exported Functions
+
+        3.1. t_cancel_branches(which)
+
+   4. Exported pseudo-variables
+   5. Exported MI Functions
+
+        5.1. t_uac_dlg
+        5.2. t_uac_cancel
+        5.3. t_hash
+        5.4. t_reply
+
+   6. Exported statistics
+
+        6.1. received_replies
+        6.2. relayed_replies
+        6.3. local_replies
+        6.4. UAS_transactions
+        6.5. UAC_transactions
+        6.6. 2xx_transactions
+        6.7. 3xx_transactions
+        6.8. 4xx_transactions
+        6.9. 5xx_transactions
+        6.10. 6xx_transactions
+        6.11. inuse_transactions
+
+1. Overview
+
+   This module collects extensions from Kamailio TM module.
+
+   Kamailio TM (Transaction Management) module documentation is available
+   at: http://www.kamailio.org/docs/modules/1.5.x/tm.html
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * tm - transaction management.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * None.
+
+3. Exported Functions
+
+   3.1. t_cancel_branches(which)
+
+3.1.  t_cancel_branches(which)
+
+   Cancel branches of an active SIP transaction. The function can be
+   called for a SIP reply that will identify the current branch.
+
+   Parameter can be:.
+     * all - cancel all branches.
+     * others - cancel all branches but the current one.
+     * this - cancel current branch.
+
+   This function can be used in ONREPLY_ROUTE.
+
+   Example 1.1. t_cancel_branches usage
+...
+if (t_cancel_branches("all")) {
+        xlog("cancelled all branches\n");
+}
+...
+
+4. Exported pseudo-variables
+
+     * $T_branch_idx
+     * $T_reply_code
+     * $T_req(pv)
+     * $T_rpl(pv)
+
+   Exported pseudo-variables are documented at
+   http://www.kamailio.org/dokuwiki/.
+
+5. Exported MI Functions
+
+   5.1. t_uac_dlg
+   5.2. t_uac_cancel
+   5.3. t_hash
+   5.4. t_reply
+
+5.1.  t_uac_dlg
+
+   Generates and sends a local SIP request.
+
+   Parameters:
+     * method - request method
+     * RURI - request SIP URI
+     * NEXT HOP - next hop SIP URI (OBP); use "." if no value.
+     * socket - local socket to be used for sending the request; use "."
+       if no value.
+     * headers - set of additional headers to be added to the request; at
+       least "From" and "To" headers must be specify)
+     * body - (optional, may not be present) request body (if present,
+       requires the "Content-Type" and "Content-length" headers)
+
+5.2.  t_uac_cancel
+
+   Generates and sends a CANCEL for an existing local SIP request.
+
+   Parameters:
+     * callid - callid of the INVITE request to be cancelled.
+     * cseq - cseq of the INVITE request to be cancelled.
+
+5.3.  t_hash
+
+   Gets information about the load of TM internal hash table.
+
+   Parameters:
+     * none
+
+5.4.  t_reply
+
+   Generates and sends a reply for an existing inbound SIP transaction.
+
+   Parameters:
+     * code - reply code
+     * reason - reason phrase.
+     * trans_id - transaction identifier (has the hash_entry:label format)
+     * to_tag - To tag to be added to TO header
+     * new_headers - extra headers to be appended to the reply; use a dot
+       (".") char only if there are no headers;
+     * body - (optional, may not be present) reply body (if present,
+       requires the "Content-Type" and "Content-length" headers)
+
+6. Exported statistics
+
+   6.1. received_replies
+   6.2. relayed_replies
+   6.3. local_replies
+   6.4. UAS_transactions
+   6.5. UAC_transactions
+   6.6. 2xx_transactions
+   6.7. 3xx_transactions
+   6.8. 4xx_transactions
+   6.9. 5xx_transactions
+   6.10. 6xx_transactions
+   6.11. inuse_transactions
+
+   Exported statistics are listed in the next sections. All statistics
+   except "inuse_transactions" can be reset.
+
+6.1. received_replies
+
+   Total number of total replies received by TM module.
+
+6.2. relayed_replies
+
+   Total number of replies received and relayed by TM module.
+
+6.3. local_replies
+
+   Total number of replies local generated by TM module.
+
+6.4. UAS_transactions
+
+   Total number of transactions created by received requests.
+
+6.5. UAC_transactions
+
+   Total number of transactions created by local generated requests.
+
+6.6. 2xx_transactions
+
+   Total number of transactions completed with 2xx replies.
+
+6.7. 3xx_transactions
+
+   Total number of transactions completed with 3xx replies.
+
+6.8. 4xx_transactions
+
+   Total number of transactions completed with 4xx replies.
+
+6.9. 5xx_transactions
+
+   Total number of transactions completed with 5xx replies.
+
+6.10. 6xx_transactions
+
+   Total number of transactions completed with 6xx replies.
+
+6.11. inuse_transactions
+
+   Number of transactions existing in memory at current time.
diff --git a/modules_k/tmx/doc/Makefile b/modules_k/tmx/doc/Makefile
new file mode 100644 (file)
index 0000000..c97dc70
--- /dev/null
@@ -0,0 +1,4 @@
+docs = tmx.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module
diff --git a/modules_k/tmx/doc/tmx.xml b/modules_k/tmx/doc/tmx.xml
new file mode 100644 (file)
index 0000000..5b625bc
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+       <title>TMX Module</title>
+       <productname class="trade">&kamailioname;</productname>
+       <authorgroup>
+           <author>
+               <firstname>Daniel-Constantin</firstname>
+               <surname>Mierla</surname>
+               <affiliation><orgname>asipto.com</orgname></affiliation>
+               <email>miconda@gmail.com</email>
+               <address>
+               <otheraddr>
+               <ulink url="http://www.asipto.com">http://www.asipto.com</ulink>
+               </otheraddr>
+               </address>
+           </author>
+           <editor>
+               <firstname>Daniel-Constantin</firstname>
+               <surname>Mierla</surname>
+               <email>miconda@gmail.com</email>
+           </editor>
+       </authorgroup>
+       <copyright>
+           <year>2009</year>
+           <holder>Daniel-Constantin Mierla</holder>
+       </copyright>
+    </bookinfo>
+    <toc></toc>
+    
+    <xi:include href="tmx_admin.xml"/>
+    
+    
+</book>
diff --git a/modules_k/tmx/doc/tmx_admin.xml b/modules_k/tmx/doc/tmx_admin.xml
new file mode 100644 (file)
index 0000000..760125c
--- /dev/null
@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+       
+       <title>&adminguide;</title>
+       
+       <section>
+       <title>Overview</title>
+       <para>
+       This module collects extensions from Kamailio TM module.
+       </para>
+       <para>
+       Kamailio TM (Transaction Management) module documentation is available at:
+       <ulink url="http://www.kamailio.org/docs/modules/1.5.x/tm.html">
+       http://www.kamailio.org/docs/modules/1.5.x/tm.html</ulink>
+       </para>
+       </section>
+       
+       <section>
+       <title>Dependencies</title>
+       <section>
+               <title>&kamailio; Modules</title>
+               <para>
+               The following modules must be loaded before this module:
+                       <itemizedlist>
+                       <listitem>
+                       <para>
+                               <emphasis>tm</emphasis> -  transaction management.
+                       </para>
+                       </listitem>
+                       </itemizedlist>
+               </para>
+       </section>
+       <section>
+               <title>External Libraries or Applications</title>
+               <para>
+               The following libraries or applications must be installed before running
+               &kamailio; with this module loaded:
+                       <itemizedlist>
+                       <listitem>
+                       <para>
+                               <emphasis>None</emphasis>.
+                       </para>
+                       </listitem>
+                       </itemizedlist>
+               </para>
+       </section>
+       </section>
+
+       <section>
+       <title>Exported Functions</title>
+       <section>
+               <title>
+               <function moreinfo="none">t_cancel_branches(which)</function>
+               </title>
+               <para>
+               Cancel branches of an active SIP transaction. The function can be
+               called for a SIP reply that will identify the current branch.
+               </para>
+               <para>
+               Parameter can be:.
+               </para>
+               <itemizedlist>
+                       <listitem><para>
+                               <emphasis>all</emphasis> - cancel all branches.
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>others</emphasis> - cancel all branches but
+                               the current one.
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>this</emphasis> - cancel current branch.
+                       </para></listitem>
+               </itemizedlist>
+               <para>
+               This function can be used in ONREPLY_ROUTE.
+               </para>
+               <example>
+               <title><function>t_cancel_branches</function> usage</title>
+               <programlisting format="linespecific">
+...
+if (t_cancel_branches("all")) {
+       xlog("cancelled all branches\n");
+}
+...
+</programlisting>
+               </example>
+       </section>
+       </section>
+
+       <section>
+               <title>Exported pseudo-variables</title>
+               <itemizedlist>
+                       <listitem><para>
+                               <emphasis>$T_branch_idx</emphasis>
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>$T_reply_code</emphasis>
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>$T_req(pv)</emphasis>
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>$T_rpl(pv)</emphasis>
+                       </para></listitem>
+               </itemizedlist>
+               <para>
+               Exported pseudo-variables are documented at &kamwikilink;.
+               </para>
+       </section>
+
+
+       <section>
+       <title>Exported MI Functions</title>
+
+       <section>
+               <title>
+               <function moreinfo="none">t_uac_dlg</function>
+               </title>
+               <para>
+               Generates and sends a local SIP request.
+               </para>
+               <para>Parameters: </para>
+               <itemizedlist>
+                       <listitem><para>
+                               <emphasis>method</emphasis> - request method
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>RURI</emphasis> - request SIP URI
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>NEXT HOP</emphasis> - next hop SIP URI (OBP);
+                               use <quote>.</quote> if no value.
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>socket</emphasis> - local socket to be used for
+                               sending the request; use <quote>.</quote> if no value.
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>headers</emphasis> - set of additional headers to
+                               be added to the request; at least 
+                               <quote>From</quote> and <quote>To</quote> headers must be
+                               specify)
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>body</emphasis> - (optional, may not be present)
+                               request body (if present, requires the 
+                               <quote>Content-Type</quote> and <quote>Content-length</quote>
+                               headers)
+                       </para></listitem>
+               </itemizedlist>
+       </section>
+
+       <section>
+               <title>
+               <function moreinfo="none">t_uac_cancel</function>
+               </title>
+               <para>
+               Generates and sends a CANCEL for an existing local SIP request.
+               </para>
+               <para>Parameters: </para>
+               <itemizedlist>
+                       <listitem><para>
+                               <emphasis>callid</emphasis> - callid of the INVITE request
+                               to be cancelled.
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>cseq</emphasis> - cseq of the INVITE request to be
+                               cancelled.
+                       </para></listitem>
+               </itemizedlist>
+       </section>
+
+       <section>
+               <title>
+               <function moreinfo="none">t_hash</function>
+               </title>
+               <para>
+               Gets information about the load of TM internal hash table.
+               </para>
+               <para>Parameters: </para>
+               <itemizedlist>
+                       <listitem><para>
+                               <emphasis>none</emphasis>
+                       </para></listitem>
+               </itemizedlist>
+       </section>
+
+       <section>
+               <title>
+               <function moreinfo="none">t_reply</function>
+               </title>
+               <para>
+               Generates and sends a reply for an existing inbound SIP transaction.
+               </para>
+               <para>Parameters: </para>
+               <itemizedlist>
+                       <listitem><para>
+                               <emphasis>code</emphasis> - reply code
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>reason</emphasis> - reason phrase.
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>trans_id</emphasis> - transaction identifier
+                               (has the hash_entry:label format)
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>to_tag</emphasis> - To tag to be added to TO header
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>new_headers</emphasis> - extra headers to be
+                               appended to the reply; use a dot (<quote>.</quote>) char 
+                               only if there are no headers;
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>body</emphasis> - (optional, may not be present)
+                               reply body (if present, requires the 
+                               <quote>Content-Type</quote> and <quote>Content-length</quote>
+                               headers)
+                       </para></listitem>
+               </itemizedlist>
+       </section>
+
+       </section>
+
+
+       <section>
+               <title>Exported statistics</title>
+               <para>
+               Exported statistics are listed in the next sections. All statistics
+               except <quote>inuse_transactions</quote> can be reset.
+               </para>
+               <section>
+               <title>received_replies</title>
+                       <para>
+                       Total number of total replies received by TM module.
+                       </para>
+               </section>
+               <section>
+               <title>relayed_replies</title>
+                       <para>
+                       Total number of replies received and relayed by TM module.
+                       </para>
+               </section>
+               <section>
+               <title>local_replies</title>
+                       <para>
+                       Total number of replies local generated by TM module.
+                       </para>
+               </section>
+               <section>
+               <title>UAS_transactions</title>
+                       <para>
+                       Total number of transactions created by received requests.
+                       </para>
+               </section>
+               <section>
+               <title>UAC_transactions</title>
+                       <para>
+                       Total number of transactions created by local generated requests.
+                       </para>
+               </section>
+               <section>
+               <title>2xx_transactions</title>
+                       <para>
+                       Total number of transactions completed with 2xx replies.
+                       </para>
+               </section>
+               <section>
+               <title>3xx_transactions</title>
+                       <para>
+                       Total number of transactions completed with 3xx replies.
+                       </para>
+               </section>
+               <section>
+               <title>4xx_transactions</title>
+                       <para>
+                       Total number of transactions completed with 4xx replies.
+                       </para>
+               </section>
+               <section>
+               <title>5xx_transactions</title>
+                       <para>
+                       Total number of transactions completed with 5xx replies.
+                       </para>
+               </section>
+               <section>
+               <title>6xx_transactions</title>
+                       <para>
+                       Total number of transactions completed with 6xx replies.
+                       </para>
+               </section>
+               <section>
+               <title>inuse_transactions</title>
+                       <para>
+                       Number of transactions existing in memory at current time.
+                       </para>
+               </section>
+       </section>
+</chapter>
+
diff --git a/modules_k/tmx/t_mi.c b/modules_k/tmx/t_mi.c
new file mode 100644 (file)
index 0000000..89f2270
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+ * $Id: mi.c 5299 2008-12-04 18:12:33Z henningw $
+ *
+ * Header file for TM MI functions
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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:
+ * --------
+ *  2006-12-04  created (bogdan)
+ */
+
+/*! \file
+ * \brief TM :: MI functions
+ *
+ * \ingroup tm
+ * - Module: \ref tm
+ */
+
+#include <stdlib.h>
+#include "../../parser/parse_from.h"
+#include "../../modules/tm/ut.h"
+#include "tmx_mod.h"
+
+/*! simple string list */
+struct str_list {
+       str s;
+       struct str_list *next;
+};
+
+/*! Which header fields should be skipped */
+#define skip_hf(_hf) \
+       (((_hf)->type == HDR_FROM_T)  || \
+       ((_hf)->type == HDR_TO_T)     || \
+       ((_hf)->type == HDR_CALLID_T) || \
+       ((_hf)->type == HDR_CSEQ_T))
+
+
+/*!
+ * \brief Convert a URI into socket address.
+ *
+ * Convert a URI into a socket address. Create a temporary proxy.
+ * \param uri input URI
+ * \param to_su target structure
+ * \param proto protocol
+ * \return choosen protocol
+ */
+static inline int uri2su(str *uri, union sockaddr_union *to_su, int proto)
+{
+       struct proxy_l *proxy;
+
+       proxy = uri2proxy(uri, proto);
+       if (!proxy) {
+               ser_error = E_BAD_ADDRESS;
+               LM_ERR("failed create a dst proxy\n");
+               return -1;
+       }
+
+       hostent2su(to_su, &proxy->host, proxy->addr_idx, 
+               (proxy->port) ? proxy->port : SIP_PORT);
+       proto = proxy->proto;
+
+       free_proxy(proxy);
+       pkg_free(proxy);
+       return proto;
+}
+
+/* should be replaced by tm's uri2dst instead */
+static inline struct socket_info *uri2sock(struct sip_msg* msg, str *uri,
+                                                                       union sockaddr_union *to_su, int proto)
+{
+       struct socket_info* send_sock;
+
+       if ( (proto=uri2su(uri, to_su, proto))==-1 )
+               return 0;
+
+       send_sock = get_send_socket(msg, to_su, proto);
+       if (!send_sock) {
+               LM_ERR("no corresponding socket for af %d\n", to_su->s.sa_family);
+               ser_error = E_NO_SOCKET;
+       }
+
+       return send_sock;
+}
+
+
+/************** Helper functions (from previous FIFO impl) *****************/
+
+/*!
+ * \brief Check if the request pushed via MI is correctly formed
+ *
+ * Check if the request pushed via MI is correctly formed. Test if
+ * necessary SIP header fileds are included, could be parsed and the
+ * CSEQ is correct.
+ * \param msg SIP message
+ * \param method SIP method
+ * \param body SIP body
+ * \param cseq SIP CSEQ value
+ * \param callid SIP callid, optional
+ * \return zero on success, or a mi_root with an error message included otherwise
+ */
+static inline struct mi_root* mi_check_msg(struct sip_msg* msg, str* method,
+                                                                               str* body, int* cseq, str* callid)
+{
+       struct cseq_body *parsed_cseq;
+
+       if (body && body->len && !msg->content_type)
+               return init_mi_tree( 400, "Content-Type missing", 19);
+
+       if (body && body->len && msg->content_length)
+               return init_mi_tree( 400, "Content-Length disallowed", 24);
+
+       if (!msg->to)
+               return init_mi_tree( 400, "To missing", 10);
+
+       if (!msg->from)
+               return init_mi_tree( 400, "From missing", 12);
+
+       /* we also need to know if there is from-tag and add it otherwise */
+       if (parse_from_header(msg) < 0)
+               return init_mi_tree( 400, "Error in From", 13);
+
+       if (msg->cseq && (parsed_cseq = get_cseq(msg))) {
+               if (str2int( &parsed_cseq->number, (unsigned int*)cseq)!=0)
+                       return init_mi_tree( 400, "Bad CSeq number", 15);
+
+               if (parsed_cseq->method.len != method->len
+               || memcmp(parsed_cseq->method.s, method->s, method->len) !=0 )
+                       return init_mi_tree( 400, "CSeq method mismatch", 20);
+       } else {
+               *cseq = -1;
+       }
+
+       if (msg->callid) {
+               callid->s = msg->callid->body.s;
+               callid->len = msg->callid->body.len;
+       } else {
+               callid->s = 0;
+               callid->len = 0;
+       }
+
+       return 0;
+}
+
+/*!
+ * \brief Allocate a new str on a str list
+ *
+ * Allocate a new str in pkg_mem and attach it to a str list. Update
+ * the total number of list elements.
+ * \param s char array
+ * \param len length of the char array
+ * \param last last list element
+ * \param total total number of list elements
+ * \return pointer to the new list element
+ */
+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) {
+               LM_ERR("no more pkg mem\n");
+               return 0;
+       }
+       new->s.s=s;
+       new->s.len=len;
+       new->next=0;
+
+       (*last)->next=new;
+       *last=new;
+       *total+=len;
+
+       return new;
+}
+
+/*!
+ * \brief Convert a header field block to char array
+ *
+ * Convert a header field block to char array, allocated in
+ * pkg_mem.
+ * \param uri SIP URI
+ * \param hf header field
+ * \param l
+ * \param send_sock socket information
+ * \return new allocated char array on success, zero otherwise
+ */
+static inline char *get_hfblock( str *uri, struct hdr_field *hf, int *l, struct socket_info** send_sock)
+{
+       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;
+
+       ret=0; /* pessimist: 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) {
+                                                       if (*send_sock==0){
+                                                               *send_sock=uri2sock(0, uri, &to_su,PROTO_NONE);
+                                                               if (!*send_sock) {
+                                                                       LM_ERR("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; */
+               LM_DBG("one more hf processed\n");
+       } /* header loop */
+
+
+       /* construct a single header block now */
+       ret=pkg_malloc(total_len);
+       if (!ret) {
+               LM_ERR("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;
+}
+
+
+/*!
+ * \brief Print routes
+ *
+ * Print route to MI node, allocate temporary memory in pkg_mem.
+ * \param node MI node
+ * \param dlg route set
+ */
+static inline void mi_print_routes( struct mi_node *node, dlg_t* dlg)
+{
+#define MI_ROUTE_PREFIX_S       "Route: "
+#define MI_ROUTE_PREFIX_LEN     (sizeof(MI_ROUTE_PREFIX_S)-1)
+#define MI_ROUTE_SEPARATOR_S    ", "
+#define MI_ROUTE_SEPARATOR_LEN  (sizeof(MI_ROUTE_SEPARATOR_S)-1)
+       rr_t* ptr;
+       int len;
+       char *p, *s;
+
+       ptr = dlg->hooks.first_route;
+
+       if (ptr==NULL) {
+               add_mi_node_child( node, 0, 0, 0, ".",1);
+               return;
+       }
+
+       len = MI_ROUTE_PREFIX_LEN;
+       for( ; ptr ; ptr=ptr->next)
+               len += ptr->len + MI_ROUTE_SEPARATOR_LEN*(ptr->next!=NULL);
+       if (dlg->hooks.last_route)
+               len += dlg->hooks.last_route->len + 2;
+
+
+       s = pkg_malloc( len );
+       if (s==0) {
+               LM_ERR("no more pkg mem\n");
+               return;
+       }
+
+
+       p = s;
+       memcpy( p, MI_ROUTE_PREFIX_S, MI_ROUTE_PREFIX_LEN);
+       p += MI_ROUTE_PREFIX_LEN;
+
+       for( ptr = dlg->hooks.first_route ; ptr ; ptr=ptr->next) {
+               memcpy( p, ptr->nameaddr.name.s, ptr->len);
+               p += ptr->len;
+               if (ptr->next) {
+                       memcpy( p, MI_ROUTE_SEPARATOR_S, MI_ROUTE_SEPARATOR_LEN);
+                       p += MI_ROUTE_SEPARATOR_LEN;
+               }
+       }
+
+       if (dlg->hooks.last_route) {
+               *(p++) = '<';
+               memcpy( p, dlg->hooks.last_route->s, dlg->hooks.last_route->len);
+               p += dlg->hooks.last_route->len;
+               *(p++) = '>';
+       }
+
+       add_mi_node_child( node, MI_DUP_VALUE, 0, 0, s, len);
+       pkg_free(s);
+}
+
+
+/*!
+ * \brief Print URIs
+ *
+ * Print URIs to MI node, allocate temporary memory in shm_mem.
+ * \param node MI node
+ * \param reply SIP reply
+ * \return zero on success, -1 on errors
+ */
+static inline int mi_print_uris( struct mi_node *node, struct sip_msg* reply)
+{
+       dlg_t* dlg;
+
+       if (reply==0)
+               goto empty;
+
+       dlg = (dlg_t*)shm_malloc(sizeof(dlg_t));
+       if (!dlg) {
+               LM_ERR("no shm memory left\n");
+               return -1;
+       }
+
+       memset(dlg, 0, sizeof(dlg_t));
+       if (_tmx_tmb.dlg_response_uac(dlg, reply, TARGET_REFRESH_UNKNOWN) < 0) {
+               LM_ERR("failed to create dialog\n");
+               _tmx_tmb.free_dlg(dlg);
+               return -1;
+       }
+
+       if (dlg->state != DLG_CONFIRMED) {
+               _tmx_tmb.free_dlg(dlg);
+               goto empty;
+       }
+
+       if (dlg->hooks.request_uri->s) {
+               add_mi_node_child( node, MI_DUP_VALUE, 0, 0,
+                       dlg->hooks.request_uri->s, dlg->hooks.request_uri->len);
+       } else {
+               add_mi_node_child( node, 0, 0, 0, ".",1);
+       }
+       if (dlg->hooks.next_hop->s) {
+               add_mi_node_child( node, MI_DUP_VALUE, 0, 0,
+                       dlg->hooks.next_hop->s, dlg->hooks.next_hop->len);
+       } else {
+               add_mi_node_child( node, 0, 0, 0, ".",1);
+       }
+
+       mi_print_routes( node, dlg);
+
+       _tmx_tmb.free_dlg(dlg);
+       return 0;
+empty:
+       add_mi_node_child( node, 0, 0, 0, ".",1);
+       add_mi_node_child( node, 0, 0, 0, ".",1);
+       add_mi_node_child( node, 0, 0, 0, ".",1);
+       return 0;
+}
+
+
+static void mi_uac_dlg_hdl( struct cell *t, int type, struct tmcb_params *ps )
+{
+       struct mi_handler *mi_hdl;
+       struct mi_root *rpl_tree;
+       str text;
+
+       LM_DBG("MI UAC generated status %d\n", ps->code);
+       if (!*ps->param)
+               return;
+
+       mi_hdl = (struct mi_handler *)(*ps->param);
+
+       rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
+       if (rpl_tree==0)
+               goto done;
+
+       if (ps->rpl==FAKED_REPLY) {
+               get_reply_status( &text, ps->rpl, ps->code);
+               if (text.s==0) {
+                       LM_ERR("get_reply_status failed\n");
+                       rpl_tree = 0;
+                       goto done;
+               }
+               add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, 0, 0,
+                       text.s, text.len);
+               pkg_free(text.s);
+               mi_print_uris( &rpl_tree->node, 0 );
+               add_mi_node_child( &rpl_tree->node, 0, 0, 0, ".",1);
+       } else { 
+               addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%d %.*s",
+                       ps->rpl->first_line.u.reply.statuscode,
+                       ps->rpl->first_line.u.reply.reason.len,
+                       ps->rpl->first_line.u.reply.reason.s);
+               mi_print_uris( &rpl_tree->node, ps->rpl);
+               add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, 0, 0,
+                       ps->rpl->headers->name.s,
+                       ps->rpl->len-(ps->rpl->headers->name.s - ps->rpl->buf));
+       }
+
+       LM_DBG("mi_callback successfully completed\n");
+done:
+       if (ps->code >= 200) {
+               mi_hdl->handler_f( rpl_tree, mi_hdl, 1 /*done*/ );
+               *ps->param = 0;
+       } else {
+               mi_hdl->handler_f( rpl_tree, mi_hdl, 0 );
+       }
+}
+
+
+
+/**************************** MI functions ********************************/
+
+
+/*
+  Syntax of "t_uac_dlg" :
+    method
+    RURI
+    NEXT_HOP
+    socket
+    headers
+    [Body]
+*/
+struct mi_root*  mi_tm_uac_dlg(struct mi_root* cmd_tree, void* param)
+{
+       static char err_buf[MAX_REASON_LEN];
+       static struct sip_msg tmp_msg;
+       static dlg_t dlg;
+       struct mi_root *rpl_tree;
+       struct mi_node *node;
+       struct sip_uri pruri;
+       struct sip_uri pnexthop;
+       struct socket_info* sock;
+       str *method;
+       str *ruri;
+       str *nexthop;
+       str *socket;
+       str *hdrs;
+       str *body;
+       str s;
+       str callid = {0,0};
+       int sip_error;
+       int proto;
+       int port;
+       int cseq;
+       int n;
+       uac_req_t uac_r;
+
+       for( n=0,node = cmd_tree->node.kids; n<6 && node ; n++,node=node->next );
+       if ( !(n==5 || n==6) || node!=0)
+               return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+
+       /* method name (param 1) */
+       node = cmd_tree->node.kids;
+       method = &node->value;
+
+       /* RURI (param 2) */
+       node = node->next;
+       ruri = &node->value;
+       if (parse_uri( ruri->s, ruri->len, &pruri) < 0 )
+               return init_mi_tree( 400, "Invalid RURI", 12);
+
+       /* nexthop RURI (param 3) */
+       node = node->next;
+       nexthop = &node->value;
+       if (nexthop->len==1 && nexthop->s[0]=='.') {
+               nexthop = 0;
+       } else {
+               if (parse_uri( nexthop->s, nexthop->len, &pnexthop) < 0 )
+                       return init_mi_tree( 400, "Invalid NEXTHOP", 15);
+       }
+
+       /* socket (param 4) */
+       node = node->next;
+       socket = &node->value;
+       if (socket->len==1 && socket->s[0]=='.' ) {
+               sock = 0;
+       } else {
+               if (parse_phostport( socket->s, &s.s, &s.len,
+               &port,&proto)!=0)
+                       return init_mi_tree( 404, "Invalid local socket", 20);
+               sock = grep_sock_info( &s, (unsigned short)port, proto);
+               if (sock==0)
+                       return init_mi_tree( 404, "Local socket not found", 22);
+       }
+
+       /* new headers (param 5) */
+       node = node->next;
+       if (node->value.len==1 && node->value.s[0]=='.')
+               hdrs = 0;
+       else {
+               hdrs = &node->value;
+               /* use SIP parser to look at what is in the FIFO request */
+               memset( &tmp_msg, 0, sizeof(struct sip_msg));
+               tmp_msg.len = hdrs->len; 
+               tmp_msg.buf = tmp_msg.unparsed = hdrs->s;
+               if (parse_headers( &tmp_msg, HDR_EOH_F, 0) == -1 )
+                       return init_mi_tree( 400, "Bad headers", 11);
+       }
+
+       /* body (param 5 - optional) */
+       node = node->next;
+       if (node)
+               body = &node->value;
+       else
+               body = 0;
+
+       /* at this moment, we collected all the things we got, let's
+        * verify user has not forgotten something */
+       rpl_tree = mi_check_msg( &tmp_msg, method, body, &cseq, &callid);
+       if (rpl_tree) {
+               if (tmp_msg.headers) free_hdr_field_lst(tmp_msg.headers);
+               return rpl_tree;
+       }
+
+       s.s = get_hfblock( nexthop ? nexthop : ruri,
+                       tmp_msg.headers, &s.len, &sock);
+       if (s.s==0) {
+               if (tmp_msg.headers) free_hdr_field_lst(tmp_msg.headers);
+               return 0;
+       }
+
+       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
+               _tmx_tmb.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 (!(get_from(&tmp_msg)->tag_value.len&&get_from(&tmp_msg)->tag_value.s))
+               _tmx_tmb.generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);
+
+       /* Fill in CSeq */
+       if (cseq!=-1)
+               dlg.loc_seq.value = cseq;
+       else
+               dlg.loc_seq.value = DEFAULT_CSEQ;
+       dlg.loc_seq.is_set = 1;
+
+       dlg.loc_uri = tmp_msg.from->body;
+       dlg.rem_uri = tmp_msg.to->body;
+       dlg.hooks.request_uri = ruri;
+       dlg.hooks.next_hop = (nexthop ? nexthop : ruri);
+       dlg.send_sock = sock;
+
+       memset(&uac_r, 0, sizeof(uac_req_t));
+       uac_r.method = method;
+       uac_r.body = body;
+       uac_r.headers = &s;
+       uac_r.dialog = &dlg;
+       if (cmd_tree->async_hdl!=NULL)
+       {
+               uac_r.cb = mi_uac_dlg_hdl;
+               uac_r.cbp = (void*)cmd_tree->async_hdl;
+       }
+       n = _tmx_tmb.t_uac(&uac_r);
+
+       pkg_free(s.s);
+       if (tmp_msg.headers) free_hdr_field_lst(tmp_msg.headers);
+
+       if (n<=0) {
+               /* error */
+               rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
+               if (rpl_tree==0)
+                       return 0;
+
+               n = err2reason_phrase( n, &sip_error, err_buf, sizeof(err_buf),
+                       "MI/UAC") ;
+               if (n > 0 )
+                       addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%d %.*s",
+                               sip_error, n, err_buf);
+               else
+                       add_mi_node_child( &rpl_tree->node, 0, 0, 0,
+                               "500 MI/UAC failed", 17);
+
+               return rpl_tree;
+       } else {
+               if (cmd_tree->async_hdl==NULL)
+                       return init_mi_tree( 202, "Accepted", 8);
+               else
+                       return MI_ROOT_ASYNC_RPL;
+       }
+}
+
+
+/*
+  Syntax of "t_uac_cancel" :
+    callid
+    cseq
+*/
+struct mi_root* mi_tm_cancel(struct mi_root* cmd_tree, void* param)
+{
+       struct mi_node *node;
+       struct cell *trans;
+
+       node =  cmd_tree->node.kids;
+       if ( !node || !node->next || node->next->next)
+               return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+
+       if( _tmx_tmb.t_lookup_callid( &trans, node->value, node->next->value) < 0 )
+               return init_mi_tree( 481, "No such transaction", 19);
+
+       /* cancel the call */
+       LM_DBG("cancelling transaction %p\n",trans);
+
+       _tmx_tmb.cancel_uacs( trans, ~0/*all branches*/, 0);
+
+       _tmx_tmb.unref_cell(trans);
+
+       return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
+}
+
+
+/*
+  Syntax of "t_hash" :
+    no nodes
+*/
+struct mi_root* mi_tm_hash(struct mi_root* cmd_tree, void* param)
+{
+       struct mi_root* rpl_tree= NULL;
+       struct mi_node* rpl;
+       struct mi_node* node;
+#ifdef TM_HASH_STATS
+       struct mi_attr* attr;
+#endif
+       struct s_table* tm_t;
+       char *p;
+       int i;
+       int len;
+
+       rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
+       if (rpl_tree==0)
+               return 0;
+       rpl = &rpl_tree->node;
+       tm_t = get_tm_table();
+
+       for (i=0; i<TABLE_ENTRIES; i++) {
+               p = int2str((unsigned long)i, &len );
+               node = add_mi_node_child(rpl, MI_DUP_VALUE , 0, 0, p, len);
+               if(node == NULL)
+                       goto error;
+
+#ifdef TM_HASH_STATS
+               p = int2str((unsigned long)tm_t->entries[i].cur_entries, &len );
+               attr = add_mi_attr(node, MI_DUP_VALUE, "Current", 7, p, len );
+               if(attr == NULL)
+                       goto error;
+
+               p = int2str((unsigned long)tm_t->entries[i].acc_entries, &len );
+               attr = add_mi_attr(node, MI_DUP_VALUE, "Total", 5, p, len );
+               if(attr == NULL)
+                       goto error;
+#endif
+       }
+
+       return rpl_tree;
+error:
+       free_mi_tree(rpl_tree);
+       return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
+}
+
+
+/*
+  Syntax of "t_reply" :
+  code
+  reason
+  trans_id
+  to_tag
+  new headers
+  [Body]
+*/
+struct mi_root* mi_tm_reply(struct mi_root* cmd_tree, void* param)
+{
+       struct mi_node* node;
+       unsigned int hash_index;
+       unsigned int hash_label;
+       unsigned int rpl_code;
+       struct cell *trans;
+       char *reason;
+       char *totag;
+       char *new_hdrs;
+       char *body;
+       str tmp;
+       char *p;
+       int n;
+
+       for( n=0,node = cmd_tree->node.kids; n<6 && node ; n++,node=node->next );
+       if ( !(n==5 || n==6) || node!=0)
+               return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
+
+       /* get all info from the command */
+
+       /* reply code (param 1) */
+       node = cmd_tree->node.kids;
+       if (str2int( &node->value, &rpl_code)!=0 || rpl_code>=700)
+               return init_mi_tree( 400, "Invalid reply code", 18);
+
+       /* reason text (param 2) */
+       node = node->next;
+       reason = as_asciiz(&node->value);
+
+       /* trans_id (param 3) */
+       node = node->next;
+       tmp = node->value;
+       p = memchr( tmp.s, ':', tmp.len);
+       if ( p==NULL)
+               return init_mi_tree( 400, "Invalid trans_id", 16);
+
+       tmp.len = p-tmp.s;
+       if( str2int( &tmp, &hash_index)!=0 )
+               return init_mi_tree( 400, "Invalid index in trans_id", 25);
+
+       tmp.s = p+1;
+       tmp.len = (node->value.s+node->value.len) - tmp.s;
+       if( str2int( &tmp, &hash_label)!=0 )
+               return init_mi_tree( 400, "Invalid label in trans_id", 25);
+
+       if( _tmx_tmb.t_lookup_ident( &trans, hash_index, hash_label)<0 )
+               return init_mi_tree( 404, "Transaction not found", 21);
+
+       /* to_tag (param 4) */
+       node = node->next;
+       totag = as_asciiz(&node->value);
+
+       /* new headers (param 5) */
+       node = node->next;
+       if (node->value.len==1 && node->value.s[0]=='.')
+               new_hdrs = 0;
+       else 
+               new_hdrs = as_asciiz(&node->value);
+
+       /* body (param 5 - optional) */
+       node = node->next;
+       if (node)
+               body = as_asciiz(&node->value);
+       else
+               body = 0;
+
+       /* it's refcounted now, t_reply_with body unrefs for me -- I can 
+        * continue but may not use T anymore  */
+       n = _tmx_tmb.t_reply_with_body( trans, rpl_code, reason, body,
+                       new_hdrs, totag);
+
+       if (n<0)
+               return init_mi_tree( 500, "Reply failed", 12);
+
+       return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
+}
+
diff --git a/modules_k/tmx/t_mi.h b/modules_k/tmx/t_mi.h
new file mode 100644 (file)
index 0000000..23c4f9f
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * $Id: mi.h 4518 2008-07-28 15:39:28Z henningw $
+ *
+ * Header file for TM MI functions
+ *
+ * Copyright (C) 2006 Voice Sistem SRL
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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:
+ * --------
+ *  2006-12-04  created (bogdan)
+ */
+
+/*! \file
+ * \brief TM :: MI functions
+ *
+ * \ingroup tm
+ * - Module: \ref tm
+ * - \ref mi.c
+ */
+
+#ifndef _TM_MI_H_
+#define _TM_MI_H_
+
+#include "../../lib/kmi/mi.h"
+
+#define MI_TM_UAC      "t_uac_dlg"
+#define MI_TM_CANCEL   "t_uac_cancel"
+#define MI_TM_HASH     "t_hash"
+#define MI_TM_REPLY    "t_reply"
+
+struct mi_root* mi_tm_uac_dlg(struct mi_root* cmd_tree, void* param);
+
+struct mi_root* mi_tm_cancel(struct mi_root* cmd_tree, void* param);
+
+struct mi_root* mi_tm_hash(struct mi_root* cmd_tree, void* param);
+
+struct mi_root* mi_tm_reply(struct mi_root* cmd_tree, void* param);
+
+#endif
diff --git a/modules_k/tmx/t_var.c b/modules_k/tmx/t_var.c
new file mode 100644 (file)
index 0000000..f97f980
--- /dev/null
@@ -0,0 +1,321 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2008 Elena-Ramona Modroiu (asipto.com)
+ *
+ * This file is part of kamailio, a free SIP server.
+ *
+ * openser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * openser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+#include "../../mem/mem.h"
+
+#include "tmx_mod.h"
+#include "t_var.h"
+
+static struct cell *_pv_T_req = NULL;
+static struct cell *_pv_T_rpl = NULL;
+static struct sip_msg _pv_treq;
+static struct sip_msg _pv_trpl;
+static struct sip_msg *_pv_treq_p = NULL;
+static struct sip_msg *_pv_trpl_p = NULL;
+static unsigned int _pv_treq_id = 0;
+static unsigned int _pv_trpl_id = 0;
+static char *_pv_treq_buf = NULL;
+static char *_pv_trpl_buf = NULL;
+static unsigned int _pv_treq_size = 0;
+static unsigned int _pv_trpl_size = 0;
+
+int pv_t_copy_msg(struct sip_msg *src, struct sip_msg *dst)
+{
+       dst->id = src->id;
+       dst->rcv = src->rcv;
+       dst->set_global_address=src->set_global_address;
+       dst->set_global_port=src->set_global_port;
+
+       if (parse_msg(dst->buf, dst->len, dst)!=0)
+       {
+               LM_ERR("parse msg failed\n");
+               return -1;
+       }
+       return 0;
+}
+
+int pv_t_update_req(struct sip_msg *msg)
+{
+       struct cell * t;
+       int branch;
+
+       if(msg==NULL)
+               return 1;
+
+       if(msg!=FAKED_REPLY && msg->first_line.type!=SIP_REPLY)
+               return 1;
+
+       t = _tmx_tmb.t_gett();
+
+       if(t==NULL || t==T_UNDEFINED)
+       {
+               if(msg==FAKED_REPLY)
+                       return 1;
+               branch=-1;
+               if (_tmx_tmb.t_check(msg, &branch ) == -1)
+                       return 1;
+               t = _tmx_tmb.t_gett();
+               if ((t == 0) || (t == T_UNDEFINED))
+                       return 1;
+
+       }
+
+       if(t->uas.request==NULL)
+               return 1;
+
+       if(_pv_T_req==t && t->uas.request==_pv_treq_p
+                       && t->uas.request->id==_pv_treq_id)
+               return 0;
+
+       /* make a copy */
+       if(_pv_treq_buf==NULL || _pv_treq_size<t->uas.request->len+1)
+       {
+               if(_pv_treq_buf!=NULL)
+                       pkg_free(_pv_treq_buf);
+               if(_pv_treq_p)
+                       free_sip_msg(&_pv_treq);
+               _pv_treq_p = NULL;
+               _pv_treq_id = 0;
+               _pv_T_req = NULL;
+               _pv_treq_size = t->uas.request->len+1;
+               _pv_treq_buf = (char*)pkg_malloc(_pv_treq_size*sizeof(char));
+               if(_pv_treq_buf==NULL)
+               {
+                       LM_ERR("no more pkg\n");
+                       _pv_treq_size = 0;
+                       return -1;
+               }
+       }
+       memset(&_pv_treq, 0, sizeof(struct sip_msg));
+       memcpy(_pv_treq_buf, t->uas.request->buf, t->uas.request->len);
+       _pv_treq_buf[t->uas.request->len] = '\0';
+       _pv_treq.len = t->uas.request->len;
+       _pv_treq.buf = _pv_treq_buf;
+       _pv_treq_p = t->uas.request;
+       _pv_treq_id = t->uas.request->id;
+       _pv_T_req = t;
+
+
+       pv_t_copy_msg(t->uas.request, &_pv_treq);
+
+       return 0;
+}
+
+int pv_t_update_rpl(struct sip_msg *msg)
+{
+       struct cell * t;
+       int branch;
+       int cancel;
+
+       if(msg==NULL)
+               return 1;
+
+       if(msg==FAKED_REPLY || msg->first_line.type!=SIP_REQUEST)
+               return 1;
+
+       t = _tmx_tmb.t_gett();
+
+       if(t==NULL || t==T_UNDEFINED)
+       {
+               if(_tmx_tmb.t_lookup_request(msg, 0, &cancel)<=0)
+                       return 1;
+               t = _tmx_tmb.t_gett();
+
+               if(t==NULL || t==T_UNDEFINED)
+                       return 1;
+       }
+       if ( (branch=_tmx_tmb.t_get_picked_branch())<0 )
+               return 1;
+       if(t->uac[branch].reply==NULL || t->uac[branch].reply==FAKED_REPLY)
+               return 1;
+
+       if(_pv_T_rpl==t && t->uac[branch].reply==_pv_trpl_p
+                       && t->uac[branch].reply->id==_pv_trpl_id)
+               return 0;
+
+       /* make a copy */
+       if(_pv_trpl_buf==NULL || _pv_trpl_size<t->uac[branch].reply->len+1)
+       {
+               if(_pv_trpl_buf!=NULL)
+                       pkg_free(_pv_trpl_buf);
+               if(_pv_trpl_p)
+                       free_sip_msg(&_pv_trpl);
+               _pv_trpl_p = NULL;
+               _pv_trpl_id = 0;
+               _pv_T_rpl = NULL;
+               _pv_trpl_size = t->uac[branch].reply->len+1;
+               _pv_trpl_buf = (char*)pkg_malloc(_pv_trpl_size*sizeof(char));
+               if(_pv_trpl_buf==NULL)
+               {
+                       LM_ERR("no more pkg\n");
+                       _pv_trpl_size = 0;
+                       return -1;
+               }
+       }
+       memset(&_pv_trpl, 0, sizeof(struct sip_msg));
+       memcpy(_pv_trpl_buf, t->uac[branch].reply->buf, t->uac[branch].reply->len);
+       _pv_trpl_buf[t->uac[branch].reply->len] = '\0';
+       _pv_trpl.len = t->uac[branch].reply->len;
+       _pv_trpl.buf = _pv_trpl_buf;
+       _pv_trpl_p = t->uac[branch].reply;
+       _pv_trpl_id = t->uac[branch].reply->id;
+       _pv_T_rpl = t;
+
+       pv_t_copy_msg(t->uac[branch].reply, &_pv_trpl);
+
+       return 0;
+}
+
+int pv_get_t_var_req(struct sip_msg *msg,  pv_param_t *param,
+               pv_value_t *res)
+{
+       pv_spec_t *pv=NULL;
+
+       if(pv_t_update_req(msg))
+               return pv_get_null(msg, param, res);
+
+       pv = (pv_spec_t*)param->pvn.u.dname;
+       if(pv==NULL || pv_alter_context(pv))
+               return pv_get_null(msg, param, res);
+
+       return pv_get_spec_value(&_pv_treq, pv, res);
+}
+
+int pv_get_t_var_rpl(struct sip_msg *msg,  pv_param_t *param,
+               pv_value_t *res)
+{
+       pv_spec_t *pv=NULL;
+
+       if(pv_t_update_rpl(msg))
+               return pv_get_null(msg, param, res);
+
+       pv = (pv_spec_t*)param->pvn.u.dname;
+       if(pv==NULL || pv_alter_context(pv))
+               return pv_get_null(msg, param, res);
+
+       return pv_get_spec_value(&_pv_trpl, pv, res);
+}
+
+int pv_parse_t_var_name(pv_spec_p sp, str *in)
+{
+       pv_spec_t *pv=NULL;
+
+       if(in->s==NULL || in->len<=0)
+               return -1;
+
+       pv = (pv_spec_t*)pkg_malloc(sizeof(pv_spec_t));
+       if(pv==NULL)
+               return -1;
+
+       memset(pv, 0, sizeof(pv_spec_t));
+
+       if(pv_parse_spec(in, pv)==NULL)
+               goto error;
+
+       sp->pvp.pvn.u.dname = (void*)pv;
+       sp->pvp.pvn.type = PV_NAME_PVAR;
+       return 0;
+
+error:
+       LM_ERR("invalid pv name [%.*s]\n", in->len, in->s);
+       if(pv!=NULL)
+               pkg_free(pv);
+       return -1;
+}
+
+/* item functions */
+int pv_get_tm_branch_idx(struct sip_msg *msg, pv_param_t *param,
+               pv_value_t *res)
+{
+       int l = 0;
+       char *ch = NULL;
+       tm_ctx_t *tcx = 0;
+       int idx = 0;
+
+       if(msg==NULL || res==NULL)
+               return -1;
+
+       tcx = _tmx_tmb.tm_ctx_get();
+       if(tcx != NULL)
+               idx = tcx->branch_index;
+       
+       ch = int2str(idx, &l);
+
+       res->rs.s = ch;
+       res->rs.len = l;
+
+       res->ri = idx;
+       res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
+
+       return 0;
+}
+
+int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
+               pv_value_t *res)
+{
+       struct cell *t;
+       int code;
+       int branch;
+
+       if(msg==NULL || res==NULL)
+               return -1;
+
+       /* first get the transaction */
+       if (_tmx_tmb.t_check( msg , 0 )==-1) return -1;
+       if ( (t=_tmx_tmb.t_gett())==0) {
+               /* no T */
+               code = 0;
+       } else {
+               switch (route_type) {
+                       case REQUEST_ROUTE:
+                               /* use the status of the last sent reply */
+                               code = t->uas.status;
+                               break;
+                       case ONREPLY_ROUTE:
+                               /* use the status of the current reply */
+                               code = msg->first_line.u.reply.statuscode;
+                               break;
+                       case FAILURE_ROUTE:
+                               /* use the status of the winning reply */
+                               if ( (branch=_tmx_tmb.t_get_picked_branch())<0 ) {
+                                       LM_CRIT("no picked branch (%d) for a final response"
+                                                       " in MODE_ONFAILURE\n", branch);
+                                       code = 0;
+                               } else {
+                                       code = t->uac[branch].last_received;
+                               }
+                               break;
+                       default:
+                               LM_ERR("unsupported route_type %d\n", route_type);
+                               code = 0;
+               }
+       }
+
+       LM_DBG("reply code is <%d>\n",code);
+
+       res->rs.s = int2str( code, &res->rs.len);
+
+       res->ri = code;
+       res->flags = PV_VAL_STR|PV_VAL_INT|PV_TYPE_INT;
+       return 0;
+}
+
diff --git a/modules_k/tmx/t_var.h b/modules_k/tmx/t_var.h
new file mode 100644 (file)
index 0000000..68479d1
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2008 Elena-Ramona Modroiu (asipto.com)
+ *
+ * This file is part of kamailio, a free SIP server.
+ *
+ * openser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * openser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+                      
+#ifndef _T_VAR_H_
+#define _T_VAR_H_
+
+#include "../../pvar.h"
+
+int pv_get_t_var_req(struct sip_msg *msg,  pv_param_t *param,
+               pv_value_t *res);
+int pv_get_t_var_rpl(struct sip_msg *msg,  pv_param_t *param,
+               pv_value_t *res);
+
+int pv_parse_t_var_name(pv_spec_p sp, str *in);
+
+int pv_get_tm_branch_idx(struct sip_msg *msg, pv_param_t *param,
+               pv_value_t *res);
+int pv_get_tm_reply_code(struct sip_msg *msg, pv_param_t *param,
+               pv_value_t *res);
+
+#endif
diff --git a/modules_k/tmx/tmx_mod.c b/modules_k/tmx/tmx_mod.c
new file mode 100644 (file)
index 0000000..711e966
--- /dev/null
@@ -0,0 +1,237 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009
+ *
+ * This file is part of SIP-Router.org, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../modules/tm/tm_load.h"
+
+#include "t_var.h"
+#include "t_mi.h"
+
+MODULE_VERSION
+
+
+/** TM bind */
+struct tm_binds _tmx_tmb;
+
+/** parameters */
+
+/** module functions */
+static int mod_init(void);
+void destroy(void);
+
+static int t_cancel_branches(struct sip_msg* msg, char *k, char *s2);
+static int fixup_cancel_branches(void** param, int param_no);
+
+/* statistic variables */
+stat_var *tm_rcv_rpls;
+stat_var *tm_rld_rpls;
+stat_var *tm_loc_rpls;
+stat_var *tm_uas_trans;
+stat_var *tm_uac_trans;
+stat_var *tm_trans_2xx;
+stat_var *tm_trans_3xx;
+stat_var *tm_trans_4xx;
+stat_var *tm_trans_5xx;
+stat_var *tm_trans_6xx;
+stat_var *tm_trans_inuse;
+
+#ifdef STATISTICS
+static stat_export_t mod_stats[] = {
+       {"received_replies" ,    0,              &tm_rcv_rpls    },
+       {"relayed_replies" ,     0,              &tm_rld_rpls    },
+       {"local_replies" ,       0,              &tm_loc_rpls    },
+       {"UAS_transactions" ,    0,              &tm_uas_trans   },
+       {"UAC_transactions" ,    0,              &tm_uac_trans   },
+       {"2xx_transactions" ,    0,              &tm_trans_2xx   },
+       {"3xx_transactions" ,    0,              &tm_trans_3xx   },
+       {"4xx_transactions" ,    0,              &tm_trans_4xx   },
+       {"5xx_transactions" ,    0,              &tm_trans_5xx   },
+       {"6xx_transactions" ,    0,              &tm_trans_6xx   },
+       {"inuse_transactions" ,  STAT_NO_RESET,  &tm_trans_inuse },
+       {0,0,0}
+};
+#endif
+
+/**
+ * pseudo-variables exported by TM module
+ */
+static pv_export_t mod_pvs[] = {
+       { {"T_branch_idx", sizeof("T_branch_idx")-1}, PVT_OTHER,
+               pv_get_tm_branch_idx, 0,
+                0, 0, 0, 0 },
+       { {"T_reply_code", sizeof("T_reply_code")-1}, PVT_OTHER,
+               pv_get_tm_reply_code, 0,
+                0, 0, 0, 0 },
+       { {"T_req", sizeof("T_req")-1}, PVT_OTHER, pv_get_t_var_req, 0,
+               pv_parse_t_var_name, 0, 0, 0 },
+       { {"T_rpl", sizeof("T_rpl")-1}, PVT_OTHER, pv_get_t_var_rpl, 0,
+               pv_parse_t_var_name, 0, 0, 0 },
+       { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static mi_export_t mi_cmds [] = {
+       {MI_TM_UAC,     mi_tm_uac_dlg,   MI_ASYNC_RPL_FLAG,  0,  0 },
+       {MI_TM_CANCEL,  mi_tm_cancel,    0,                  0,  0 },
+       {MI_TM_HASH,    mi_tm_hash,      MI_NO_INPUT_FLAG,   0,  0 },
+       {MI_TM_REPLY,   mi_tm_reply,     0,                  0,  0 },
+       {0,0,0,0,0}
+};
+
+
+static cmd_export_t cmds[]={
+       {"t_cancel_branches", (cmd_function)t_cancel_branches,  1,
+               fixup_cancel_branches, 0, ONREPLY_ROUTE },
+       {0,0,0,0,0,0}
+};
+
+static param_export_t params[]={
+       {0,0,0}
+};
+
+
+/** module exports */
+struct module_exports exports= {
+       "tmx",
+       DEFAULT_DLFLAGS, /* dlopen flags */
+       cmds,
+       params,
+#ifdef STATISTICS
+       mod_stats,  /* exported statistics */
+#else
+       0,
+#endif
+       mi_cmds,    /* exported MI functions */
+       mod_pvs,    /* exported pseudo-variables */
+       0,          /* extra processes */
+       mod_init,   /* module initialization function */
+       0,
+       (destroy_function) destroy,
+       0           /* per-child init function */
+};
+
+/**
+ * init module function
+ */
+static int mod_init(void)
+{
+       /* load the TM API */
+       if (load_tm_api(&_tmx_tmb)!=0) {
+               LM_ERR("can't load TM API\n");
+               return -1;
+       }
+
+       if(register_mi_mod(exports.name, mi_cmds)!=0)
+       {
+               LM_ERR("failed to register MI commands\n");
+               return -1;
+       }
+#ifdef STATISTICS
+       /* register statistics */
+       if (register_module_stats( exports.name, mod_stats)!=0 ) {
+               LM_ERR("failed to register statistics\n");
+               return -1;
+       }
+#endif
+       return 0;
+}
+
+/**
+ * destroy function
+ */
+void destroy(void)
+{
+       return;
+}
+
+static int fixup_cancel_branches(void** param, int param_no)
+{
+       char *val;
+       int n = 0;
+
+       if (param_no==1) {
+               val = (char*)*param;
+               if (strcasecmp(val,"all")==0) {
+                       n = 0;
+               } else if (strcasecmp(val,"others")==0) {
+                       n = 1;
+               } else if (strcasecmp(val,"this")==0) {
+                       n = 2;
+               } else {
+                       LM_ERR("invalid param \"%s\"\n", val);
+                       return E_CFG;
+               }
+               pkg_free(*param);
+               *param=(void*)(long)n;
+       } else {
+               LM_ERR("called with parameter != 1\n");
+               return E_BUG;
+       }
+       return 0;
+}
+
+static int t_cancel_branches(struct sip_msg* msg, char *k, char *s2)
+{
+       branch_bm_t cb = 0;
+       struct cell *t = 0;
+       tm_ctx_t *tcx = 0;
+       int n=0;
+       int idx = 0;
+       t=_tmx_tmb.t_gett();
+       if (t==NULL || t==T_UNDEFINED || !is_invite(t))
+               return -1;
+       tcx = _tmx_tmb.tm_ctx_get();
+       if(tcx != NULL)
+               idx = tcx->branch_index;
+       n = (int)k;
+       switch(n) {
+               case 1:
+                       LOCK_REPLIES(t);
+                       _tmx_tmb.which_cancel(t, &cb);
+                       if(t->uac[idx].local_cancel.buffer==BUSY_BUFFER)
+                               t->uac[idx].local_cancel.buffer=NULL;
+                       UNLOCK_REPLIES(t);
+                       cb &= ~(1<<idx);
+               case 2:
+                       if(msg->first_line.u.reply.statuscode>=200)
+                               break;
+                       cb = 1<<idx;
+               break;
+               default:
+                       LOCK_REPLIES(t);
+                       _tmx_tmb.which_cancel(t, &cb);
+                       UNLOCK_REPLIES(t);
+                       if (msg->first_line.u.reply.statuscode>=200)
+                               cb &= ~(1<<idx);
+       }
+       LM_DBG("canceling %d/%d\n", n, (int)cb);
+       if(cb==0)
+               return -1;
+       _tmx_tmb.cancel_uacs(t, cb, 0);
+       return 1;
+}
+
diff --git a/modules_k/tmx/tmx_mod.h b/modules_k/tmx/tmx_mod.h
new file mode 100644 (file)
index 0000000..0dfde33
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2009
+ *
+ * This file is part of SIP-Router.org, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+#ifndef _TMX_MOD_H_
+#define _TMX_MOD_H_
+
+#include "../../modules/tm/tm_load.h"
+
+/** TM bind */
+extern struct tm_binds _tmx_tmb;
+
+#endif
index 6d33c73..68d3b67 100644 (file)
@@ -14,26 +14,25 @@ Jiri Kuthan
    1.2. Dependencies
    1.3. Parameters
 
-        1.3.1. secret (string)
-        1.3.2. log_level (integer)
-        1.3.3. log_fmt (string)
-        1.3.4. early_media (integer)
-        1.3.5. failed_transactions (integer)
-        1.3.6. log_flag (integer)
-        1.3.7. log_missed_flag (integer)
-        1.3.8. report_ack (integer)
-        1.3.9. report_cancels (integer)
-        1.3.10. radius_config (string)
-        1.3.11. service_type (integer)
-        1.3.12. radius_flag (integer)
-        1.3.13. radius_missed_flag (integer)
-        1.3.14. db_url (string)
-        1.3.15. db_flag (integer)
-        1.3.16. db_missed_flag (integer)
-        1.3.17. diameter_flag (integer)
-        1.3.18. diameter_missed_flag (integer)
-        1.3.19. diameter_client_host (string)
-        1.3.20. diameter_client_port (int)
+        1.3.1. log_level (integer)
+        1.3.2. log_fmt (string)
+        1.3.3. early_media (integer)
+        1.3.4. failed_transactions (integer)
+        1.3.5. log_flag (integer)
+        1.3.6. log_missed_flag (integer)
+        1.3.7. report_ack (integer)
+        1.3.8. report_cancels (integer)
+        1.3.9. radius_config (string)
+        1.3.10. service_type (integer)
+        1.3.11. radius_flag (integer)
+        1.3.12. radius_missed_flag (integer)
+        1.3.13. db_url (string)
+        1.3.14. db_flag (integer)
+        1.3.15. db_missed_flag (integer)
+        1.3.16. diameter_flag (integer)
+        1.3.17. diameter_missed_flag (integer)
+        1.3.18. diameter_client_host (string)
+        1.3.19. diameter_client_port (int)
 
    1.4. Functions
 
@@ -97,10 +96,8 @@ Note
    http://developer.berlios.de/projects/radiusclient-ng/. The radius
    client needs to be configured properly. To do so, use the template in
    sip_router/etc/radiusclient.conf and make sure that module's
-   radius_config parameter points to its location. In particular,
-   accounting secret must match that one configured in server and proper
-   dictionary is used (one is available in ). Uses along with FreeRADIUS
-   and Radiator servers have been reported to us.
+   radius_config parameter points to its location. Uses along with
+   FreeRADIUS and Radiator servers have been reported to us.
 
    Both mysql and radius libraries must be dynamically linkable. You need
    to configure your OS so that SER, when started, will find them.
@@ -142,75 +139,63 @@ if (uri=~"sip:+49") /* calls to Germany */ {
    Revision History
    Revision $Revision$ $Date$
 
-1.3.1. secret (string)
-
-   The secret string used to generate nonce. Inclusion of this string in
-   nonce ensures that only the proxy server that knows the secret string
-   will be able to generate the nonce and verify it later when received
-   from the user agent.
-
-   Default value is randomly generated string.
-
-   Example 2. Setting secret module parameter
-modparam("auth", "secret", "johndoessecretphrase")
-
-1.3.2. log_level (integer)
+1.3.1. log_level (integer)
 
    Log level at which accounting messages are issued to syslog.
 
    Default value is L_NOTICE.
 
-   Example 3. log_level example
+   Example 2. log_level example
 modparam("acc", "log_level", 2)   # Set log_level to 2
 
-1.3.3. log_fmt (string)
+1.3.2. log_fmt (string)
 
    Defines what parts of header fields will be printed to syslog, see
    "overview" for list of accepted values.
 
    Default value is "miocfs".
 
-   Example 4. log_fmt example
+   Example 3. log_fmt example
 modparam("acc", "log_fmt", "mfs")
 
-1.3.4. early_media (integer)
+1.3.3. early_media (integer)
 
    Should be early media (183) accounted too ?
 
    Default value is 0 (no).
 
-   Example 5. early_media example
+   Example 4. early_media example
 modparam("acc", "early_media", 1)
 
-1.3.5. failed_transactions (integer)
+1.3.4. failed_transactions (integer)
 
    This parameter controls whether failed transactions (with final reply
    >= 300) should be accounted too.
 
    Default value is 0 (no).
 
-   Example 6. failed_transactions example
+   Example 5. failed_transactions example
 modparam("acc", "failed_transactions", 1)
 
-1.3.6. log_flag (integer)
+1.3.5. log_flag (integer)
 
    Request flag which needs to be set to account a transaction.
 
    Default value is 1.
 
-   Example 7. log_flag example
+   Example 6. log_flag example
 modparam("acc", "log_flag", 2)
 
-1.3.7. log_missed_flag (integer)
+1.3.6. log_missed_flag (integer)
 
    Request flag which needs to be set to account missed calls.
 
    Default value is 2.
 
-   Example 8. log_missed_flag example
+   Example 7. log_missed_flag example
 modparam("acc", "log_missed_flag", 3)
 
-1.3.8. report_ack (integer)
+1.3.7. report_ack (integer)
 
    Shall acc attempt to account e2e ACKs too ? Note that this is really
    only an attempt, as e2e ACKs may take a different path (unless RR
@@ -219,10 +204,10 @@ modparam("acc", "log_missed_flag", 3)
 
    Default value is 1 (yes).
 
-   Example 9. report_ack example
+   Example 8. report_ack example
 modparam("acc", "report_ack", 0)
 
-1.3.9. report_cancels (integer)
+1.3.8. report_cancels (integer)
 
    By default, CANCEL reporting is disabled -- most accounting
    applications are happy to see INVITE's cancellation status. Turn on if
@@ -230,10 +215,10 @@ modparam("acc", "report_ack", 0)
 
    Default value is 0 (no).
 
-   Example 10. report_cancels example
+   Example 9. report_cancels example
 modparam("acc", "report_cancels", 1)
 
-1.3.10. radius_config (string)
+1.3.9. radius_config (string)
 
    This parameter is radius specific. Path to radius client configuration
    file, set the referred config file correctly and specify there address
@@ -243,105 +228,105 @@ modparam("acc", "report_cancels", 1)
 
    Default value is "/usr/local/etc/radiusclient/radiusclient.conf".
 
-   Example 11. radius_config example
+   Example 10. radius_config example
 modparam("acc", "radius_config", "/etc/radiusclient/radiusclient.conf")
 
-1.3.11. service_type (integer)
+1.3.10. service_type (integer)
 
    Radius service type used for accounting.
 
    Default value is 15 (SIP).
 
-   Example 12. service_type example
+   Example 11. service_type example
 modparam("acc", "service_type", 16)
 
-1.3.12. radius_flag (integer)
+1.3.11. radius_flag (integer)
 
    Request flag which needs to be set to account a transaction -- RADIUS
    specific.
 
    Default value is 1.
 
-   Example 13. radius_flag example
+   Example 12. radius_flag example
                 modparam("acc", "radius_flag", 2)
 
-1.3.13. radius_missed_flag (integer)
+1.3.12. radius_missed_flag (integer)
 
    Request flag which needs to be set to account missed calls -- RADIUS
    specific.
 
    Default value is 2.
 
-   Example 14. radius_missed_flag example
+   Example 13. radius_missed_flag example
 modparam("acc", "radius_missed_flag", 3)
 
-1.3.14. db_url (string)
+1.3.13. db_url (string)
 
    SQL address -- database specific.
 
    Default value is "mysql://ser:heslo@localhost/ser"
 
-   Example 15. db_url example
+   Example 14. db_url example
 modparam("acc", "db_url", "mysql://user:password@localhost/ser")
 
-1.3.15. db_flag (integer)
+1.3.14. db_flag (integer)
 
    Request flag which needs to be set to account a transaction -- database
    specific.
 
    Default value is 1.
 
-   Example 16. db_flag example
+   Example 15. db_flag example
 modparam("acc", "db_flag", 2)
 
-1.3.16. db_missed_flag (integer)
+1.3.15. db_missed_flag (integer)
 
    Request flag which needs to be set to account missed calls -- database
    specific.
 
    Default value is 2.
 
-   Example 17. db_missed_flag example
+   Example 16. db_missed_flag example
 modparam("acc", "db_missed_flag", 3)
 
-1.3.17. diameter_flag (integer)
+1.3.16. diameter_flag (integer)
 
    Request flag which needs to be set to account a transaction -- DIAMETER
    specific.
 
    Default value is 1.
 
-   Example 18. diameter_flag example
+   Example 17. diameter_flag example
 modparam("acc", "diameter_flag", 2)
 
-1.3.18. diameter_missed_flag (integer)
+1.3.17. diameter_missed_flag (integer)
 
    Request flag which needs to be set to account missed calls -- DIAMETER
    specific.
 
    Default value is 2.
 
-   Example 19. diameter_missed_flag example
+   Example 18. diameter_missed_flag example
 modparam("acc", "diameter_missed_flag", 3)
 
-1.3.19. diameter_client_host (string)
+1.3.18. diameter_client_host (string)
 
    Hostname of the machine where the DIAMETER Client is running --
    DIAMETER specific.
 
    Default value is "localhost".
 
-   Example 20. diameter_client_host example
+   Example 19. diameter_client_host example
 modparam("acc", "diameter_client_host", "iptel.org")
 
-1.3.20. diameter_client_port (int)
+1.3.19. diameter_client_port (int)
 
    Port number where the Diameter Client is listening -- DIAMETER
    specific.
 
    Default value is 3000.
 
-   Example 21. diameter_client_host example
+   Example 20. diameter_client_host example
 modparam("acc", "diameter_client_port", 3000)
 
 1.4. Functions
@@ -359,7 +344,7 @@ modparam("acc", "diameter_client_port", 3000)
    Meaning of the parameters is as follows:
      * comment - Comment to be appended.
 
-   Example 22. acc_log_request usage
+   Example 21. acc_log_request usage
 ...
 acc_log_request("Some comment");
 ...
@@ -374,7 +359,7 @@ acc_log_request("Some comment");
      * comment - Comment to be appended.
      * table - Database table to be used.
 
-   Example 23. acc_db_request usage
+   Example 22. acc_db_request usage
 ...
 acc_log_request("Some comment", "Some table");
 ...
@@ -387,7 +372,7 @@ acc_log_request("Some comment", "Some table");
    Meaning of the parameters is as follows:
      * comment - Comment to be appended.
 
-   Example 24. acc_rad_request usage
+   Example 23. acc_rad_request usage
 ...
 acc_rad_request("Some comment");
 ...
@@ -400,7 +385,7 @@ acc_rad_request("Some comment");
    Meaning of the parameters is as follows:
      * comment - Comment to be appended.
 
-   Example 25. acc_diam_request usage
+   Example 24. acc_diam_request usage
 ...
 acc_diam_request("Some comment");
 ...
index a19fe97..26f0539 100644 (file)
            radius client needs to be configured properly. To do so, use the
            template in <filename>sip_router/etc/radiusclient.conf</filename>
            and make sure that module's <varname>radius_config</varname>
-           parameter points to its location.  In particular, accounting secret
+           parameter points to its location.
+           <!-- FIXME In particular, accounting secret
            must match that one configured in server and proper dictionary is
-           used (one is available in ). Uses along with <ulink
+           used (one is available in ). -->
+           Uses along with <ulink
            url="http://www.freeradius.org">FreeRADIUS</ulink> and <ulink
            url="http://www.open.com.au/radiator">Radiator</ulink> servers have
            been reported to us.
index 1765cd9..d7bb1ce 100644 (file)
 
     <title>Parameters</title>
 
-    <section id="secret">
-       <title><varname>secret</varname> (string)</title>
-       <para>
-           The secret string used to generate nonce. Inclusion of this string
-           in nonce ensures that only the proxy server that knows the secret
-           string will be able to generate the nonce and verify it later when
-           received from the user agent.
-       </para>
-       <para>
-           Default value is randomly generated string.
-       </para>
-       <example>
-           <title>Setting secret module parameter</title>
-           <programlisting>
-modparam("auth", "secret", "johndoessecretphrase")
-           </programlisting>
-       </example>
-    </section>
-
     <section id="log_level">
        <title><varname>log_level</varname> (integer)</title>
        <para>
index 8a84cac..403de2c 100644 (file)
@@ -24,7 +24,7 @@
            These three module parameters control which optional integrity
          checks will be performed on the SIP message carrying digest response
         during digest authentication. <varname>auth_check_register</varname>
-        controls integrity checks to be peformed on REGISTER messages,
+        controls integrity checks to be performed on REGISTER messages,
         <varname>auth_checks_no_dlg</varname> controls which optional
         integrity checks will be performed on SIP requests that have no To
         header field or no To tag (in other words the requests either
diff --git a/modules_s/auth_identity/README b/modules_s/auth_identity/README
new file mode 100644 (file)
index 0000000..70deb13
--- /dev/null
@@ -0,0 +1,404 @@
+1. Auth Identity Module
+
+Gergely Kovacs
+
+   Iptel.org
+
+   Copyright © 2007 Iptel.org
+     __________________________________________________________________
+
+   1.1. Overview
+   1.2. Dependencies
+   1.3. Compilation
+   1.4. Installation And Running
+   1.5. Authorizer service parameters
+
+        1.5.1. privatekey_path (string)
+        1.5.2. certificate_path (string)
+        1.5.3. certificate_url (string)
+        1.5.4. msg_timeout (integer)
+
+   1.6. Authorizer service functions
+
+        1.6.1. auth_date_proc()
+
+              1.6.1.1. Dependencies
+
+        1.6.2. auth_add_identity()
+
+              1.6.2.1. Dependencies
+
+   1.7. Authorizer service examples
+   1.8. Verifier service parameters
+
+        1.8.1. auth_validity_time (integer)
+        1.8.2. callid_cache_limit (integer)
+        1.8.3. certificate_cache_limit (integer)
+        1.8.4. cainfo_path (string)
+        1.8.5. accept_pem_certs ([0|1])
+
+   1.9. Verifier service functions
+
+        1.9.1. vrfy_check_date()
+
+              1.9.1.1. Dependencies
+
+        1.9.2. vrfy_get_certificate()
+
+              1.9.2.1. Dependencies
+
+        1.9.3. vrfy_check_certificate()
+
+              1.9.3.1. Dependencies
+
+        1.9.4. vrfy_check_msgvalidity()
+
+              1.9.4.1. Dependencies
+
+        1.9.5. vrfy_check_callid()
+
+              1.9.5.1. Dependencies
+
+   1.10. Verifier service examples
+
+1.1. Overview
+
+   Auth Identity module provides functionalities for securely identifying
+   originators of SIP messages. This module has two basic service:
+     * authorizer - authorizes a message and adds Identity and
+       Identity-Info headers
+     * verifier - verifies an authorized message
+
+   Known limitations in this version:
+     * authorizer and verifier support only SIP requests except for CANCEL
+       and REGISTER
+     * verifier does not support the subjectAltName extension of
+       certificates
+
+1.2. Dependencies
+
+   This module does not depend any other module.
+
+1.3. Compilation
+
+   This module needs the following headers and libraries:
+     * OpenSSL (version 0.9.8 or higher) for cryptographic functions
+     * libcURL for HTTP, HTTPS functions
+
+   If you'd like to use TLS module too then use the corresponding LIB line
+   in auth_identity's Makefile
+
+1.4. Installation And Running
+
+   Authorizer service needs an opportunity to make the public key, which
+   conveyed in a certificate, available over HTTPS or HTTP for verifiers.
+   The domain the authorizer is responsible for and the domain part of the
+   URL of the certificate must be the same. This service needs its private
+   key too.
+
+1.5. Authorizer service parameters
+
+1.5.1. privatekey_path (string)
+
+   The path of private key of the authentication service. The key must be
+   in PEM format.
+
+   This parameter is required by authentication service.
+
+   Example 1. Set privatekey_path parameter
+...
+modparam("auth_identity","privatekey_path","/etc/ssl/private/key.pem")
+...
+
+1.5.2. certificate_path (string)
+
+   The path of certificate of the authentication service. The certificate
+   must be in PEM format.
+
+   This parameter is required by authentication service.
+
+   Example 2. Set certificate_path parameter
+...
+modparam("auth_identity","certificate_path","/var/www/ssl/mycert.pem")
+...
+
+1.5.3. certificate_url (string)
+
+   The url where certificate is available for other verifier services.
+   (value of Identity-info header) The certificate should be in DER
+   format.
+
+   This parameter is required by authentication service.
+
+   Example 3. Set certificate_url parameter
+...
+modparam("auth_identity","certificate_url","https://foo.bar/mycert.der")
+...
+
+1.5.4. msg_timeout (integer)
+
+   If the Date header of message which is needed to be authenticated
+   contains a time different by more than this seconds from the current
+   time noted by the authentication service then it rejects the message.
+
+   This parameter is optional. The default value is "600".
+
+   Example 4. Set msg_timeout parameter
+...
+modparam("auth_identity","msg_timeout",600)
+...
+
+1.6. Authorizer service functions
+
+1.6.1.  auth_date_proc()
+
+   If a message, the auth service should authorize, contains Date header
+   then this function checks whether it falls in message timeout (set by
+   msg_timeout parameter). If there is not any Date header then adds one.
+   This function also checks whether the certificate of auth service (set
+   by certificate_path parameter) has not been expired.
+
+1.6.1.1. Dependencies
+
+   No dependencies
+
+1.6.2.  auth_add_identity()
+
+   Assembles digest-string from the message, calculates its SHA1 hash,
+   encrypt it with the private key (set by privatekey_path parameter) of
+   authorizer service, base64 encodes it and adds to the outgoing message
+   as the value of Identity header. This function also adds Identity-Info
+   header which contains an URI (set by certificate_url parameter) from
+   which the certificate of auth service can be acquired.
+
+   Note: this function needs the final outgoing message for authorization,
+   so no module may modify any digest string related headers (From, To,
+   Call-ID, CSeq, Date, Contact) and body after auth_add_identity()'s been
+   called
+
+1.6.2.1. Dependencies
+
+   auth_date_proc() must be called before
+
+1.7. Authorizer service examples
+
+...
+route[INIT]
+{
+        # we process new transactions only
+        if (!t_newtran()) {
+                sl_reply("500", "Internal error newtran");
+                drop;
+        }
+...
+route[OUTBOUND]
+{
+        # If we are responsible for the domain of the sender of this message
+        if ($f.did && !$t.did) {
+                # Authentication service
+                if (method=="INVITE" || method=="BYE"
+                        || method=="OPTION" || method=="ACK") {
+                        # Identity and Identity-info headers must not exist
+                        if (@identity) {
+                                t_reply("403", "Invalid Identity header");
+                                drop;
+                        }
+                        if (@identity_info) {
+                                t_reply("403", "Invalid Identity-info header");
+                                drop;
+                        }
+
+                        if (!auth_date_proc()) {
+                                t_reply("403", "Invalid Date value");
+                                drop;
+                        }
+
+                        if (!auth_add_identity()) {
+                                t_reply("480", "Authentication error");
+                                drop;
+                        }
+                }
+                route(FORWARD);
+        }
+}
+...
+
+1.8. Verifier service parameters
+
+1.8.1. auth_validity_time (integer)
+
+   The validity time of an authenticated message. The message will be
+   refused if it contains a time different by more than this seconds from
+   the current time noted by the verification service.
+
+   This parameter is optional. The default value is "3600".
+
+   Example 5. Set auth_validity_time parameter
+...
+modparam("auth_identity","auth_validity_time",3600)
+...
+
+1.8.2. callid_cache_limit (integer)
+
+   The number of Call-IDs stored in order to recognize call replay
+   attacks. A Call-ID is stored auth_validity_time long and uses
+   approximately 100 bytes memory.
+
+   This parameter is optional. The default value is "32768". (you should
+   increase the size of shared memory with -m command line switch if you
+   liked to store more callid than 10000)
+
+   Example 6. Set auth_validity_time parameter
+...
+modparam("auth_identity","callid_cache_limit",32768)
+...
+
+1.8.3. certificate_cache_limit (integer)
+
+   The number of certificates stored in order to avoid needless download.
+   A certificate is stored until its expiration date and uses
+   approximately 600 bytes memory.
+
+   This parameter is optional. The default value is "4096".
+
+   Example 7. Set certificate_cache_limit parameter
+...
+modparam("auth_identity","certificate_cache_limit",4096)
+...
+
+1.8.4. cainfo_path (string)
+
+   A file of trusted certificates. The file should contain multiple
+   certificates in PEM format concatenated together. It could be useful
+   for verifying a certificate not signed by a trusted CA.
+
+   This parameter is optional. It has not got default value.
+
+   Example 8. Set cainfo_path parameter
+...
+modparam("auth_identity","cainfo_path","/etc/ssl/certs/ca-certificates.crt")
+...
+
+1.8.5. accept_pem_certs ([0|1])
+
+   Enables the acquired certificate processing if it is in PEM format.
+
+   This parameter is optional. The default value is "0".
+
+   Example 9. Set accept_pem_certs parameter
+...
+modparam("auth_identity","accept_pem_certs",1)
+...
+
+1.9. Verifier service functions
+
+1.9.1.  vrfy_check_date()
+
+   Checks Date header of the incoming message whether falls in validity
+   time (set by auth_validity_time parameter)
+
+1.9.1.1. Dependencies
+
+   No dependencies
+
+1.9.2.  vrfy_get_certificate()
+
+   Tries to get certificate defined by the value of Identity-info header
+   from certificate table (which size is set by certificate_cache_limit
+   parameter). If the required certificate is not found there then this
+   function downloads it.
+
+1.9.2.1. Dependencies
+
+   No dependencies
+
+1.9.3.  vrfy_check_certificate()
+
+   Checks whether the downloaded certificate is valid (is not expired, its
+   subject and the domain part of the URL are the same) and adds it to
+   certificate table.
+
+1.9.3.1. Dependencies
+
+   vrfy_get_certificate() must be called before
+
+1.9.4.  vrfy_check_msgvalidity()
+
+   Assembles digest-string from the message, create SHA1 hash and compares
+   it with the decrypted value of Identity header.
+
+1.9.4.1. Dependencies
+
+   vrfy_get_certificate() must be called before and
+   vrfy_check_certificate() should be called before
+
+1.9.5.  vrfy_check_callid()
+
+   Checks whether the current call's been already processed in validity
+   time (set by auth_validity_time) to recognize call replay attacks. If
+   this call (identified by Call-id, Cseq, and tag of From header triple)
+   has not been replayed then adds it to callid table (which size is set
+   by callid_cache_limit parameter).
+
+1.9.5.1. Dependencies
+
+   This function should be called for the last time.
+
+1.10. Verifier service examples
+
+...
+route[INIT]
+{
+        # we process new transactions only
+        if (!t_newtran()) {
+                sl_reply("500", "Internal error newtran");
+                drop;
+        }
+...
+route[VERIFY]
+{
+        # if we've already processed this message then we drop it
+        if (!t_newtran()) {
+                sl_reply("500", "Internal error newtran");
+                drop;
+        }
+
+        if (method=="INVITE" || method=="BYE"
+                || method=="OPTION" || method=="ACK") {
+                # Identity and Identity-info are required for verification
+                if (!@identity) {
+                        t_reply("428", "Use Identity Header");
+                        drop;
+                }
+                if (!@identity_info) {
+                        t_reply("436", "Bad Identity-Info");
+                        drop;
+                }
+
+                if (!vrfy_check_date()) {
+                        t_reply("403", "Outdated Date header value");
+                        drop;
+                }
+
+                if (!vrfy_get_certificate()) {
+                        t_reply("436", "Bad Identity-Info");
+                        drop;
+                }
+
+                if (!vrfy_check_certificate()) {
+                        t_reply("437", "Unsupported Certificate");
+                        drop;
+                }
+
+                if (!vrfy_check_msgvalidity()) {
+                        t_reply("438", "Invalid Identity Header");
+                        drop;
+                }
+
+                if (!vrfy_check_callid()) {
+                        t_reply("403", "Message is replayed");
+                        drop;
+                }
+        }
+}
+...
diff --git a/modules_s/bdb/README b/modules_s/bdb/README
new file mode 100644 (file)
index 0000000..4817972
--- /dev/null
@@ -0,0 +1,199 @@
+1. BDB Module
+
+   Sippy Software, Inc.
+
+   Copyright © 2006 Sippy Software, Inc.
+   Revision History
+   Revision $Revision$ $Date$
+     __________________________________________________________________
+
+   1.1. Overview
+
+        1.1.1. Design of DBD Engine
+
+   1.2. Dependencies
+
+        1.2.1. External libraries or applications
+
+   1.3. Exported parameters
+
+        1.3.1. describe_table (string)
+
+   1.4. Constrains and limitations
+   1.5. Installation and running
+
+        1.5.1. Using BDB With Basic SER Configuration
+
+1.1. Overview
+
+   The SER (SIP Express Router) supports several different persistent
+   storage backends (flatfile, dbtext and several SQL servers). However,
+   in certain cases those existing backends don't satisfy conditions.
+   Particularly, SQL server-based backends typically provide good
+   performance and scalability, but at the same time require considerable
+   efforts to configure and manage and also have significant memory and
+   on-disk footprint, while simpler storage backends (flatfile, dbtext)
+   are lighter and simpler to setup and manage, but scale poorly and don't
+   provide sufficient performance. For certain types of applications (i.e.
+   embedded SIP applications, SIP load balancing farms etc), different
+   solution that would combine some of the non-overlapping properties of
+   those two existing classes of backends is necessary.
+
+   Berkeley DB is widely regarded as industry-leading open source,
+   embeddable database engine that provides developers with fast,
+   reliable, local persistence with almost zero administration.
+
+1.1.1. Design of DBD Engine
+
+   The dbtext database system architecture:
+     * A database is represented by a directory in the local file system
+       where BDB environment is located.
+
+Note
+       When using BDB driver in SER, the database URL for modules must be
+       the path to the directory where the BDB environment is located,
+       prefixed by "bdb://", e.g., "bdb:///var/db/ser". If there is no "/"
+       after "bdb://" then "CFG_DIR/" (the OS-specific path defined at
+       SER's compile time) is inserted at the beginning of the database
+       path automatically. So that, either an absolute path to database
+       directory, or one relative to "CFG_DIR" directory should be
+       provided in the URL.
+     * The individual tables internaly are represented by binary files
+       inside environment directory.
+
+Note
+       The BDB driver uses BTree access method.
+       On-disk storage format has been developed to be as simple as
+       possible, while meeting performance requirements set forth above.
+       It is not compatible with on-disk format of any other BDB-based DB
+       engine (e.g. MySQL's BDB table handler).
+
+1.2. Dependencies
+
+1.2.1. External libraries or applications
+
+   The next libraries or applications must be installed before running SER
+   with this module:
+     * Berkeley DB 4.X
+
+1.3. Exported parameters
+
+1.3.1. describe_table (string)
+
+   Define the table and its structure. Each table that will be used by
+   other modules has to be defined. The format of the parameter is:
+   table_name:column_name_1(column_type_1)[column_name_2(column_type_2)[..
+   . column_name_N(column_type_N)]]
+
+   The names of table and columns must not include white spaces.
+
+   The first column in definition is used as index.
+
+   Between name of table and name of first column must be ":".
+
+   Between two columns definitions must be exactly one white space.
+
+   Type of column has to be enclosed into parentheses.
+
+   Supported column types are:
+     * int
+     * float
+     * double
+     * string
+     * str
+     * datetime
+     * blob
+     * bitmap
+
+1.4. Constrains and limitations
+
+   Use of indexes:
+     * Effective SELECT, UPDATE and DELETE operations on a structured
+       storage that contains any more or less decent number of records are
+       impossible without using some kind of indexing scheme. Since
+       Berkley DB is relatively simple storage engine it provides only
+       basic support for indexing, nearly not as rich as usually expected
+       by an average SQL user. Therefore, it has been decided to limit
+       number of indexes supported to one per table. This is sufficient
+       for most of the uses in the SER (for example: usrloc, auth_db etc).
+     * SELECT/UPDATE/DELETE records matching criteria. Due to its
+       simplicity, Berkley DB only supports exact match on indexed field.
+       In order to support <, >, <= and >= operations mandated by the SIP
+       DB API it is necessary to fall back to sequental scan of the index
+       values, which obviously has significant negative impact on
+       performance. Fortunately those advanced records matching criterias
+       are not required neither by the usrloc module nor by auth_db
+       module.
+     * BDB driver uses index only if key column appears in search clause
+       at least once and records matching operator associated with it is
+       '='.
+     * It is not allowed to set index value to NULL or an empty string.
+     * It is not allowed to update index value. The DELETE followed by
+       INSERT should be used instead.
+
+   BDB driver does not support db_raw_query() method.
+
+   BDB driver does not support ORDER BY clause of db_query() method.
+
+1.5. Installation and running
+
+   Compile the module and load it instead of mysql or other DB modules.
+
+   Example 1. Load the bdb module
+...
+loadmodule "/path/to/ser/modules/dbb.so"
+...
+modparam("module_name", "db_url", "bdb:///path/to/bdb/database")
+...
+
+   Example 2. definition of the standard version table
+...
+modparam("bdb", "describe_table", "version:table_name(str) table_version(int)")
+...
+
+1.5.1. Using BDB With Basic SER Configuration
+
+   Here are the definitions for tables used by usrloc module as well as a
+   part of basic configuration file to use BDB driver with SER. The table
+   structures may change in future releases, so that some adjustment to
+   example below may be necessary. That example corresponds to SER v0.9.4
+
+   According to the configuration file below, the table files will be
+   placed in the //var/db/ser/ directory.
+
+   The table version should be populated manually before the SER is
+   started. To do this version.dump file located in the directotry of BDB
+   driver sources and db_load utility from Berkeley BD distribution should
+   be used as follows:
+
+   Example 3. Population of version table
+$ db_load -h /var/db/ser -f version.dump version
+
+   Example 4. Configuration file
+# ---------- global configuration parameters ------------------------
+
+# [skip]
+
+# ---------- module loading -----------------------------------------
+
+loadmodule "/usr/local/lib/ser/modules/usrloc.so"
+loadmodule "/usr/local/lib/ser/modules/bdb.so"
+
+# ---------- module-specific configuration parameteres --------------
+
+modparam("usrloc", "db_mode", 2)
+modparam("usrloc", "timer_interval", 3)
+modparam("usrloc", "db_url", "bdb:///var/db/ser")
+
+modparam("bdb", "describe_table", "version:table_name(str) table_version(int)")
+
+modparam("bdb", "describe_table", "location:username(str) domain(str) contact(st
+r) i_env(int) expires(datetime) q(double) callid(str) cseq(int) method(str) flag
+s(int) user_agent(str) received(str)")
+modparam("bdb", "describe_table", "aliases:username(str) domain(str) contact(str
+) i_env(int) expires(datetime) q(double) callid(str) cseq(int) method(str) flags
+(int) user_agent(str) received(str)")
+
+# ---------- request routing logic ----------------------------------
+
+# [skip]
diff --git a/modules_s/blst/README b/modules_s/blst/README
new file mode 100644 (file)
index 0000000..8387e98
--- /dev/null
@@ -0,0 +1,82 @@
+1. Blst Module
+
+Andrei Pelinescu-Onciul
+
+   iptelorg GmbH
+
+   Copyright © 2007 iptelorg GmbH
+   Revision History
+   Revision $Revision$ $Date$
+     __________________________________________________________________
+
+   1.1. Overview
+   1.2. Functions
+
+        1.2.1. blst_add([timeout])
+        1.2.2. blst_add_retry_after(min, max)
+        1.2.3. blst_del()
+        1.2.4. blst_is_blacklisted()
+
+1.1. Overview
+
+   This module exports blacklist related functions to the script.
+
+1.2. Functions
+
+   Revision History
+   Revision $Revision$ $Date$
+
+1.2.1.  blst_add([timeout])
+
+   Adds the source of the current message to the blacklist for timeout
+   seconds. If timeout is missing or 0 it uses the default blacklist
+   timeout (dst_blacklist_expire).
+
+   Example 1. blst_add usage
+...
+if (src_ip==10.0.0.0/9)
+    blst_add(30); # 30 s
+else
+    blst_add();  # use default blacklist timeout
+...
+
+1.2.2.  blst_add_retry_after(min, max)
+
+   Adds the source of the current message to the blacklist for the time
+   interval specified in the Retry-After header. If the Retry-After header
+   is missing, it will fail (returns false). If the Retry-After value is
+   less then min, then min seconds will be used instead. If the
+   Retry-After value is greater then max, then max seconds will be used
+   instead.
+
+   Example 2. blst_add_retry_after usage
+...
+# on_reply route
+if (msg_status==503){ # blacklist 503 source for Retry-After seconds
+    if (! blst_add_retry_after(30, 3600))
+        blst_add(60); # if no retry_after header add it for 60s
+}
+...
+
+1.2.3.  blst_del()
+
+   Removes the source of the current message from the blacklist. If the
+   address is not present in the blacklist at the time of the call it
+   returns false.
+
+   Example 3. blst_del usage
+...
+    blst_del();
+...
+
+1.2.4.  blst_is_blacklisted()
+
+   Returns true if the source of the current message is blacklisted.
+
+   Example 4. blst_is_blacklisted usage
+...
+    if (blst_is_blacklisted()){
+        log("message from a blacklisted source");
+        drop;
+   }
+...
diff --git a/modules_s/cfg_rpc/README b/modules_s/cfg_rpc/README
new file mode 100644 (file)
index 0000000..7e457da
--- /dev/null
@@ -0,0 +1,45 @@
+1. cfg_rpc Module
+
+Miklos Tirpak
+
+   <miklos@iptel.org>
+
+   Copyright © 2007 iptelorg GmbH
+     __________________________________________________________________
+
+   1.1. Overview
+   1.2. RPC Interface
+
+1.1. Overview
+
+   The module implements RPC functions to set and get configuration
+   variables on-the-fly, that are declared by SER core and by the modules.
+   It can be used to fine-tune or debug SER without the need of restart.
+
+1.2. RPC Interface
+
+   The module implements the following RPC interface commands:
+     * cfg_rpc.set_now_int - Set the value of a configuration variable and
+       commit the change immediately. The function accepts three
+       parameters: group name, variable name, integer value.
+     * cfg_rpc.set_now_string - Set the value of a configuration variable
+       and commit the change immediately. The function accepts three
+       parameters: group name, variable name, string value.
+     * cfg_rpc.set_delayed_int - Prepare the change of a configuration
+       variable, but does not commit the new value yet. The function
+       accepts three parameters: group name, variable name, integer value.
+     * cfg_rpc.set_delayed_string - Prepare the change of a configuration
+       variable, but does not commit the new value yet. The function
+       accepts three parameters: group name, variable name, string value.
+     * cfg_rpc.commit - Commit the previously prepared configuration
+       changes. The function does not have any parameters.
+     * cfg_rpc.rollback - Drop the prepared configuration changed. The
+       function does not have any parameters.
+     * cfg_rpc.get - Get the value of a configuration variable. The
+       function accepts two parameters: group name, variable name.
+     * cfg_rpc.help - Print the description of a configuration variable.
+       The function accepts two parameters: group name, variable name.
+     * cfg_rpc.list - List the configuration variables. The function does
+       not have any parameters.
+     * cfg_rpc.diff - List the pending configuration changes that have not
+       been committed yet. The function does not have any parameters.
index 093b9fc..a9488d7 100644 (file)
@@ -70,8 +70,8 @@ from the last group
 
 
 
-regex_t *portExpression;
-regex_t *ipExpression;
+extern regex_t *portExpression;
+extern regex_t *ipExpression;
 
 
 
index 102fe58..0bb62ee 100644 (file)
@@ -70,12 +70,12 @@ UA2 ---- NAT2 ----| 5090    |
    Registrar and usrloc would store the public IP of NAT with each
    registered contact, thus it would know how to reach both user agents.
 
-   In addition to the publi IP and port of the NAT device, registrar would
-   also remember the destination IP and port of the REGISTER request (the
-   IP and port used in SER). If registrar did not store this information,
-   it would not know what outbound socket it should use when sending SIP
-   messages to the registered contact. It would use the default port
-   number (often 5060) for such outgoing requests.
+   In addition to the public IP and port of the NAT device, registrar
+   would also remember the destination IP and port of the REGISTER request
+   (the IP and port used in SER). If registrar did not store this
+   information, it would not know what outbound socket it should use when
+   sending SIP messages to the registered contact. It would use the
+   default port number (often 5060) for such outgoing requests.
 
    When an INVITE for UA1 comes, everything would work because UA1 used
    port 5060 when registering and that is also the destination port in the
@@ -98,7 +98,7 @@ UA1 ---- NAT1        +------ |  5060  | <---------------
 UA2 ---- NAT2 X <----+       |  5090  |
                              +--------+
 
-   That is the reason why registrar and usrloc also need to remmember the
+   That is the reason why registrar and usrloc also need to remember the
    IP and port used on the server side, that information would be used
    later when forwarding INVITEs:
                                  SER
index da8e93e..b553f0a 100644 (file)
@@ -72,7 +72,7 @@ UA2 ---- NAT2 ----| 5090    |
            agents.
        </para>
        <para>
-           In addition to the publi IP and port of the NAT device, registrar
+           In addition to the public IP and port of the NAT device, registrar
            would also remember the destination IP and port of the REGISTER
            request (the IP and port used in SER). If registrar did not store
            this information, it would not know what outbound socket it should
@@ -111,7 +111,7 @@ UA2 ---- NAT2 X <----+       |  5090  |
 ]]>
        </programlisting>
        <para>
-           That is the reason why registrar and usrloc also need to remmember
+           That is the reason why registrar and usrloc also need to remember
            the IP and port used on the server side, that information would be
            used later when forwarding INVITEs:
        </para>
index 1781389..86b4118 100644 (file)
@@ -46,7 +46,7 @@ typedef struct avp_save_item_t {
 
 extern regex_t* cookie_filter_re;
 extern unsigned short crc_secret;
-avp_flags_t avp_flag_dialog;
+extern avp_flags_t avp_flag_dialog;
 
 int rr_add_avp_cookie(struct sip_msg *msg, char *param1, char *param2);
 str *rr_get_avp_cookies(void);
index 468da0d..efd619d 100644 (file)
@@ -25,7 +25,6 @@ mailto:s.frings@mail.isis.de
 #include "libsms_modem.h"
 
 
-int  sms_report_type;
 
 static char hexa[16] = {
        '0','1','2','3','4','5','6','7',
index e7beb64..db4ea66 100644 (file)
@@ -84,7 +84,6 @@ str    domain;
 int    *queued_msgs    = 0;
 int    use_contact     = 0;
 int    sms_report_type = NO_REPORT;
-struct tm_binds tmb;
 
 
 static cmd_export_t cmds[]={
index 1f4f18e..51696f7 100644 (file)
@@ -68,7 +68,6 @@ int nr_of_modems;
 int max_sms_parts;
 int *queued_msgs;
 int use_contact;
-int sms_report_type;
 struct tm_binds tmb;
 
 
index a609c52..d7d185f 100644 (file)
@@ -13,6 +13,6 @@ LIBS=
 DEFS+=-DSER_MOD_INTERFACE
 
 SERLIBPATH=../../lib
-SER_LIBS+=$(SERLIBPATH)/srdb2/srdb2
+#SER_LIBS+=$(SERLIBPATH)/srdb2/srdb2
 include ../../Makefile.modules
 
index 23e98c1..9d5a1c6 100644 (file)
@@ -43,7 +43,7 @@
 #include "../../parser/parse_uri.h"
 #include "../../parser/parse_param.h"
 #include "../../ut.h"                   /* Handy utilities */
-#include "../../lib/srdb2/db.h"                /* Database API */
+//#include "../../lib/srdb2/db.h"                /* Database API */
 #include "../../dset.h"
 #include "uri_mod.h"
 #include "checks.h"
index b8edc6b..ece6b18 100644 (file)
@@ -188,6 +188,11 @@ struct sip_uri {
        str host;     /* Host name */
        str port;     /* Port number */
        str params;   /* Parameters */
+       str sip_params; /* Parameters of the sip: URI.
+                         * (If a tel: URI is embedded in a sip: URI, then
+                         * params points to the parameters of the tel: URI,
+                         * and sip_params to the parameters of the sip: URI. 
+                         */
        str headers;
        unsigned short port_no;
        unsigned short proto; /* from transport */
index 85328f8..5b29710 100644 (file)
@@ -1102,6 +1102,8 @@ int parse_uri(char* buf, int len, struct sip_uri* uri)
        switch(uri->type){
                case SIPS_URI_T:
                case SIP_URI_T:
+                       /* save the original sip: URI parameters in sip_params */
+                       uri->sip_params=uri->params;
                        if ((phone2tel) &&
                             (uri->user_param_val.len == 5) &&
                                 (strncmp(uri->user_param_val.s, "phone", 5) == 0)
@@ -1120,6 +1122,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri)
                                        uri->params.len=uri->user.s+uri->user.len-uri->params.s;
                                        uri->user.len=p-uri->user.s;
                                } else {
+                                       uri->params.s=0;
                                        uri->params.len=0;
                                }
                        } else {
index 55456a1..b874ced 100644 (file)
--- a/rvalue.c
+++ b/rvalue.c
@@ -773,8 +773,8 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
                        break;
                case RV_ACTION_ST:
                        if (rv->v.action)
-                               *i=run_actions(h, rv->v.action, msg);
-                       else 
+                               *i=(run_actions(h, rv->v.action, msg)>0);
+                       else
                                *i=0;
                        break;
                case RV_SEL:
@@ -914,8 +914,8 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
                        break;
                case RV_ACTION_ST:
                        if (rv->v.action)
-                               i=run_actions(h, rv->v.action, msg);
-                       else 
+                               i=(run_actions(h, rv->v.action, msg)>0);
+                       else
                                i=0;
                        tmpv->s=int2str(i, &tmpv->len);
                        break;
index 8fa909b..ac2c82f 100644 (file)
@@ -822,7 +822,8 @@ static int fix_hostname(str* name, struct ip_addr* address, str* address_str,
        }
        /* check if we got the official name */
        if (strcasecmp(he->h_name, name->s)!=0){
-               if (add_alias(name->s, name->len, s->port_no, s->proto)<0){
+               if (sr_auto_aliases && 
+                               add_alias(name->s, name->len, s->port_no, s->proto)<0){
                        LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
                }
                /* change the official name */
@@ -836,9 +837,9 @@ static int fix_hostname(str* name, struct ip_addr* address, str* address_str,
                strncpy(name->s, he->h_name, name->len+1);
        }
        /* add the aliases*/
-       for(h=he->h_aliases; h && *h; h++)
+       for(h=he->h_aliases; sr_auto_aliases && h && *h; h++)
                if (add_alias(*h, strlen(*h), s->port_no, s->proto)<0){
-                               LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
+                       LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
                }
        hostent2ip_addr(address, he, 0); /*convert to ip_addr format*/
        if (type_flags){
@@ -853,7 +854,7 @@ static int fix_hostname(str* name, struct ip_addr* address, str* address_str,
        strncpy(address_str->s, tmp, strlen(tmp)+1);
        /* set is_ip (1 if name is an ip address, 0 otherwise) */
        address_str->len=strlen(tmp);
-       if ((address_str->len==name->len) &&
+       if (sr_auto_aliases && (address_str->len==name->len) &&
                (strncasecmp(address_str->s, name->s, address_str->len)==0)){
                *flags|=SI_IS_IP;
                /* do rev. DNS on it (for aliases)*/