parser: const-correctness for some module utility functions
[sip-router] / dset.c
diff --git a/dset.c b/dset.c
index ab58dca..4ba5ccf 100644 (file)
--- a/dset.c
+++ b/dset.c
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/** destination set / branches support.
+ * @file dset.c
+ * @ingroup core
+ * Module: @ref core
+ */
+
 #include <string.h>
 #include "dprint.h"
 #include "config.h"
 #define Q_PARAM ">;q="
 #define Q_PARAM_LEN (sizeof(Q_PARAM) - 1)
 
-struct branch
-{
-       char uri[MAX_URI_SIZE];
-       unsigned int len;
-
-            /* Real destination of the request */
-       char dst_uri[MAX_URI_SIZE];
-       unsigned int dst_uri_len;
-
-       int q; /* Preference of the contact among
-               * contact within the array */
-       struct socket_info* force_send_socket;
-};
-
 
 /* 
  * Where we store URIs of additional transaction branches
@@ -75,8 +67,118 @@ unsigned int nr_branches = 0;
 /* branch iterator */
 static int branch_iterator = 0;
 
+/* used to mark ruris "consumed" when branching (1 new, 0 consumed) */
+int ruri_is_new = 0;
+
 /* The q parameter of the Request-URI */
-static qvalue_t ruri_q = Q_UNSPECIFIED; 
+static qvalue_t ruri_q = Q_UNSPECIFIED;
+
+/* Branch flags of the Request-URI */
+static flag_t ruri_bflags;
+
+
+/*! \brief
+ * Return pointer to branch[idx] structure
+ * @param idx - branch index
+ *
+ * @return  pointer to branch or NULL if invalid branch
+ */
+branch_t *get_sip_branch(int idx)
+{
+       if(nr_branches==0)
+               return NULL;
+       if(idx<0)
+       {
+               if(nr_branches + idx >= 0)
+                       return &branches[nr_branches+idx];
+               return NULL;
+       }
+       if(idx < nr_branches)
+               return &branches[idx];
+       return 0;
+}
+
+/*! \brief
+ * Drop branch[idx]
+ * @param idx - branch index
+ *
+ * @return  0 on success, -1 on error
+ */
+int drop_sip_branch(int idx)
+{
+       if(nr_branches==0 || idx>=nr_branches)
+               return 0;
+       if(idx<0 && nr_branches+idx<0)
+               return 0;
+       /* last branch */
+       if(idx==nr_branches-1)
+       {
+               nr_branches--;
+               return 0;
+       }
+       if(idx<0)
+               idx = nr_branches+idx;
+       /* shift back one position */
+       for(; idx<nr_branches-1; idx++)
+               memcpy(&branches[idx], &branches[idx+1], sizeof(branch_t));
+       nr_branches--;
+       return 0;
+}
+
+static inline flag_t* get_bflags_ptr(unsigned int branch)
+{
+       if (branch == 0) return &ruri_bflags;
+       if (branch - 1 < nr_branches) return &branches[branch - 1].flags;
+       return NULL;
+}
+
+
+int setbflag(unsigned int branch, flag_t flag)
+{
+       flag_t* flags;
+
+       if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
+       (*flags) |= 1 << flag;
+       return 1;
+}
+
+
+int isbflagset(unsigned int branch, flag_t flag)
+{
+       flag_t* flags;
+
+       if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
+       return ((*flags) & (1 << flag)) ? 1 : -1;
+}
+
+
+int resetbflag(unsigned int branch, flag_t flag)
+{
+       flag_t* flags;
+
+       if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
+       (*flags) &= ~ (1 << flag);
+       return 1;
+}
+
+
+int getbflagsval(unsigned int branch, flag_t* res)
+{
+       flag_t* flags;
+       if (res == NULL) return -1;
+       if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
+       *res = *flags;
+       return 1;
+}
+
+
+int setbflagsval(unsigned int branch, flag_t val)
+{
+       flag_t* flags;
+       if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
+       *flags = val;
+       return 1;
+}
 
 
 /*
@@ -89,44 +191,85 @@ void init_branch_iterator(void)
        branch_iterator = 0;
 }
 
+/**
+ * return the value of current branch iterator
+ */
+int get_branch_iterator(void)
+{
+       return branch_iterator;
+}
 
-/*
- * Return the next branch from the dset
+/**
+ * set the value of current branch interator
+ */
+void set_branch_iterator(int n)
+{
+       branch_iterator = n;
+}
+
+
+/** \brief Get a branch from the destination set
+ * \return Return the 'i' branch from the dset
  * array, 0 is returned if there are no
  * more branches
  */
-char* next_branch(int* len, qvalue_t* q, char** dst_uri, int* dst_len, struct socket_info** force_socket)
+char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
+                                str* path, unsigned int *flags,
+                                struct socket_info** force_socket)
 {
-       unsigned int i;
-
-       i = branch_iterator;
        if (i < nr_branches) {
-               branch_iterator++;
                *len = branches[i].len;
                *q = branches[i].q;
-               if (dst_uri && dst_len) {
-                       *dst_uri = branches[i].dst_uri;
-                       *dst_len = branches[i].dst_uri_len;
+               if (dst_uri) {
+                       dst_uri->len = branches[i].dst_uri_len;
+                       dst_uri->s = (dst_uri->len)?branches[i].dst_uri:0;
                }
-               if (force_socket) {
-                       *force_socket = branches[i].force_send_socket;
+               if (path) {
+                       path->len = branches[i].path_len;
+                       path->s = (path->len)?branches[i].path:0;
                }
+               if (force_socket)
+                       *force_socket = branches[i].force_send_socket;
+               if (flags)
+                       *flags = branches[i].flags;
                return branches[i].uri;
        } else {
                *len = 0;
                *q = Q_UNSPECIFIED;
-               if (dst_uri && dst_len) {
-                       *dst_uri = 0;
-                       *dst_len = 0;
+               if (dst_uri) {
+                       dst_uri->s = 0;
+                       dst_uri->len = 0;
                }
-               if (force_socket) {
-                       *force_socket = 0;
+               if (path) {
+                       path->s = 0;
+                       path->len = 0;
                }
+               if (force_socket)
+                       *force_socket = 0;
+               if (flags)
+                       *flags = 0;
                return 0;
        }
 }
 
 
+
+/** Return the next branch from the dset array.
+ * 0 is returned if there are no more branches
+ */
+char* next_branch(int* len, qvalue_t* q, str* dst_uri, str* path,
+                                       unsigned int* flags, struct socket_info** force_socket)
+{
+       char* ret;
+       
+       ret=get_branch(branch_iterator, len, q, dst_uri, path, flags,
+                                       force_socket);
+       if (likely(ret))
+               branch_iterator++;
+       return ret;
+}
+
+
 /*
  * Empty the dset array
  */
@@ -134,64 +277,89 @@ void clear_branches(void)
 {
        nr_branches = 0;
        ruri_q = Q_UNSPECIFIED;
+       ruri_bflags = 0;
+       ruri_mark_consumed();
 }
 
 
-/* 
- * Add a new branch to current transaction 
+
+/**  Add a new branch to the current transaction.
+ * @param msg - sip message, used for getting the uri if not specified (0).
+ * @param uri - uri, can be 0 (in which case the uri is taken from msg)
+ * @param dst_uri - destination uri, can be 0.
+ * @param path - path vector (passed in a string), can be 0.
+ * @param q  - q value.
+ * @param flags - per branch flags.
+ * @param force_socket - socket that should be used when sending.
+ *
+ * @return  <0 (-1) on failure, 1 on success (script convention).
  */
-int append_branch(struct sip_msg* msg, char* uri, int uri_len, char* dst_uri, int dst_uri_len, 
-                 qvalue_t q, struct socket_info* force_socket)
+int append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path,
+               qvalue_t q, unsigned int flags, struct socket_info* force_socket)
 {
-            /* if we have already set up the maximum number
-             * of branches, don't try new ones 
-             */
-       if (nr_branches == MAX_BRANCHES - 1) {
-               LOG(L_ERR, "ERROR: append_branch: max nr of branches exceeded\n");
+       str luri;
+
+       /* if we have already set up the maximum number
+        * of branches, don't try new ones 
+        */
+       if (unlikely(nr_branches == MAX_BRANCHES - 1)) {
+               LOG(L_ERR, "max nr of branches exceeded\n");
                ser_error = E_TOO_MANY_BRANCHES;
                return -1;
        }
 
-       if (uri_len > MAX_URI_SIZE - 1) {
-               LOG(L_ERR, "ERROR: append_branch: too long uri: %.*s\n",
-                   uri_len, uri);
-               return -1;
+       /* if not parameterized, take current uri */
+       if (uri==0 || uri->len==0 || uri->s==0) {
+               if (msg->new_uri.s)
+                       luri = msg->new_uri;
+               else
+                       luri = msg->first_line.u.request.uri;
+       } else {
+               luri = *uri;
        }
-       
-       if (dst_uri_len > MAX_URI_SIZE - 1) {
-               LOG(L_ERR, "ERROR: append_branch: too long dst_uri: %.*s\n",
-                   dst_uri_len, ZSW(dst_uri));
+
+       if (unlikely(luri.len > MAX_URI_SIZE - 1)) {
+               LOG(L_ERR, "too long uri: %.*s\n", luri.len, luri.s);
                return -1;
        }
 
-            /* if not parameterized, take current uri */
-       if (uri == 0) {
-               if (msg->new_uri.s) { 
-                       uri = msg->new_uri.s;
-                       uri_len = msg->new_uri.len;
-               } else {
-                       uri = msg->first_line.u.request.uri.s;
-                       uri_len = msg->first_line.u.request.uri.len;
+       /* copy the dst_uri */
+       if (dst_uri && dst_uri->len && dst_uri->s) {
+               if (unlikely(dst_uri->len > MAX_URI_SIZE - 1)) {
+                       LOG(L_ERR, "too long dst_uri: %.*s\n", dst_uri->len, dst_uri->s);
+                       return -1;
                }
+               memcpy(branches[nr_branches].dst_uri, dst_uri->s, dst_uri->len);
+               branches[nr_branches].dst_uri[dst_uri->len] = 0;
+               branches[nr_branches].dst_uri_len = dst_uri->len;
+       } else {
+               branches[nr_branches].dst_uri[0] = '\0';
+               branches[nr_branches].dst_uri_len = 0;
        }
-       
-       memcpy(branches[nr_branches].uri, uri, uri_len);
-            /* be safe -- add zero termination */
-       branches[nr_branches].uri[uri_len] = 0;
-       branches[nr_branches].len = uri_len;
-       branches[nr_branches].q = q;
-       
-       if (dst_uri && dst_uri_len) {
-               memcpy(branches[nr_branches].dst_uri, dst_uri, dst_uri_len);
-               branches[nr_branches].dst_uri[dst_uri_len] = 0;
-               branches[nr_branches].dst_uri_len = dst_uri_len;
-       } else {
-               branches[nr_branches].dst_uri[0] = '\0';
-               branches[nr_branches].dst_uri_len = 0;
+
+       /* copy the path string */
+       if (unlikely(path && path->len && path->s)) {
+               if (unlikely(path->len > MAX_PATH_SIZE - 1)) {
+                       LOG(L_ERR, "too long path: %.*s\n", path->len, path->s);
+                       return -1;
+               }
+               memcpy(branches[nr_branches].path, path->s, path->len);
+               branches[nr_branches].path[path->len] = 0;
+               branches[nr_branches].path_len = path->len;
+       } else {
+               branches[nr_branches].path[0] = '\0';
+               branches[nr_branches].path_len = 0;
        }
 
+       /* copy the ruri */
+       memcpy(branches[nr_branches].uri, luri.s, luri.len);
+       branches[nr_branches].uri[luri.len] = 0;
+       branches[nr_branches].len = luri.len;
+       branches[nr_branches].q = q;
+
        branches[nr_branches].force_send_socket = force_socket;
-       
+       branches[nr_branches].flags = flags;
+
        nr_branches++;
        return 1;
 }
@@ -208,6 +376,7 @@ char* print_dset(struct sip_msg* msg, int* len)
        qvalue_t q;
        str uri;
        char* p, *qbuf;
+       int crt_branch;
        static char dset[MAX_REDIRECTION_LEN];
 
        if (msg->new_uri.s) {
@@ -221,8 +390,11 @@ char* print_dset(struct sip_msg* msg, int* len)
                *len = 0;
        }
 
+       /* backup current branch index to restore it later */
+       crt_branch = get_branch_iterator();
+
        init_branch_iterator();
-       while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0))) {
+       while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0))) {
                cnt++;
                *len += uri.len;
                if (q != Q_UNSPECIFIED) {
@@ -236,7 +408,7 @@ char* print_dset(struct sip_msg* msg, int* len)
 
        if (*len + 1 > MAX_REDIRECTION_LEN) {
                LOG(L_ERR, "ERROR: redirection buffer length exceed\n");
-               return 0;
+               goto error;
        }
 
        memcpy(dset, CONTACT, CONTACT_LEN);
@@ -263,7 +435,7 @@ char* print_dset(struct sip_msg* msg, int* len)
        }
 
        init_branch_iterator();
-       while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0))) {
+       while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0))) {
                if (i) {
                        memcpy(p, CONTACT_DELIM, CONTACT_DELIM_LEN);
                        p += CONTACT_DELIM_LEN;
@@ -287,7 +459,12 @@ char* print_dset(struct sip_msg* msg, int* len)
        }
 
        memcpy(p, CRLF " ", CRLF_LEN + 1);
+       set_branch_iterator(crt_branch);
        return dset;
+
+error:
+       set_branch_iterator(crt_branch);
+       return 0;
 }
 
 
@@ -310,24 +487,6 @@ qvalue_t get_ruri_q(void)
 
 
 
-/*
- * Get actual Request-URI
- */
-int get_request_uri(struct sip_msg* _m, str* _u)
-{
-            /* Use new_uri if present */
-       if (_m->new_uri.s) {
-               _u->s = _m->new_uri.s;
-               _u->len = _m->new_uri.len;
-       } else {
-               _u->s = _m->first_line.u.request.uri.s;
-               _u->len = _m->first_line.u.request.uri.len;
-       }
-
-       return 0;
-}
-
-
 /*
  * Rewrite Request-URI
  */
@@ -351,9 +510,9 @@ int rewrite_uri(struct sip_msg* _m, str* _s)
 
         _m->new_uri.s = buf;
         _m->new_uri.len = _s->len;
+        /* mark ruri as new and available for forking */
+        ruri_mark_new();
 
-        DBG("rewrite_uri: Rewriting Request-URI with '%.*s'\n", _s->len, 
-                                                                                                                                                  buf);
         return 1;
 }