Merge branch 'rpc_async'
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Fri, 18 Sep 2009 11:16:26 +0000 (13:16 +0200)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Fri, 18 Sep 2009 11:16:26 +0000 (13:16 +0200)
* rpc_async:
  tm: async t_uac (t_uac_wait) support
  xmlrpc(s): basic support for delayed replies
  core: rpc capabilities and delayed reply api
  core+tm: moved sip msg clone functions to the core

fix_lumps.h [moved from modules/tm/fix_lumps.h with 99% similarity]
modules/tm/h_table.c
modules/tm/rpc_uac.c
modules/tm/sip_msg.c
modules/tm/t_fwd.c
modules/tm/t_reply.c
modules_s/xmlrpc/xmlrpc.c
rpc.h
sip_msg_clone.c [new file with mode: 0644]
sip_msg_clone.h [new file with mode: 0644]

similarity index 99%
rename from modules/tm/fix_lumps.h
rename to fix_lumps.h
index 359b1b5..6484baf 100644 (file)
@@ -44,7 +44,6 @@
 #ifndef _FIX_LUMPS_H
 #define _FIX_LUMPS_H
 
-#include "defs.h"
 
 
 /* used to delete attached via lumps from msg; msg can
index 3acee65..51f9005 100644 (file)
@@ -63,7 +63,7 @@
 #include "t_cancel.h"
 #include "t_stats.h"
 #include "h_table.h"
-#include "fix_lumps.h" /* free_via_clen_lump */
+#include "../../fix_lumps.h" /* free_via_clen_lump */
 #include "timer.h"
 #include "uac.h" /* free_local_ack */
 
index 043fc65..3dc34a9 100644 (file)
@@ -300,6 +300,156 @@ static char *get_hfblock(str *uri, struct hdr_field *hf, int proto,
 }
 
 
+#define RPC_ROUTE_PREFIX       "Route: "
+#define RPC_ROUTE_PREFIX_LEN   (sizeof(RPC_ROUTE_PREFIX)-1)
+#define RPC_ROUTE_SEPARATOR    ", "
+#define RPC_ROUTE_SEPARATOR_LEN        (sizeof(RPC_ROUTE_SEPARATOR)-1)
+
+
+/** internal print routes into rpc reply function.
+ *  Prints the dialog routes. It's used internally by
+ *  rpx_print_uris (called from rpc_uac_callback()).
+ *  @param rpc
+ *  @param c - rpc context
+ *  @param reply - sip reply
+ */
+static void  rpc_print_routes(rpc_t* rpc, void* c,
+                                                               dlg_t* d)
+{
+       rr_t* ptr;
+       int size;
+       char* buf;
+       char* p;
+       
+       
+       if (d->hooks.first_route == 0){
+               rpc->add(c, "s", "");
+               return;
+       }
+       size=RPC_ROUTE_PREFIX_LEN;
+       for (ptr=d->hooks.first_route; ptr; ptr=ptr->next)
+               size+=ptr->len+(ptr->next!=0)*RPC_ROUTE_SEPARATOR_LEN;
+       if (d->hooks.last_route)
+               size+=RPC_ROUTE_SEPARATOR_LEN + 1 /* '<' */ + 
+                               d->hooks.last_route->len +1 /* '>' */;
+
+       buf=pkg_malloc(size+1);
+       if (buf==0){
+               ERR("out of memory\n");
+               rpc->add(c, "s", "");
+               return;
+       }
+       p=buf;
+       memcpy(p, RPC_ROUTE_PREFIX, RPC_ROUTE_PREFIX_LEN);
+       p+=RPC_ROUTE_PREFIX_LEN;
+       for (ptr=d->hooks.first_route; ptr; ptr=ptr->next){
+               memcpy(p, ptr->nameaddr.name.s, ptr->len);
+               p+=ptr->len;
+               if (ptr->next!=0){
+                       memcpy(p, RPC_ROUTE_SEPARATOR, RPC_ROUTE_SEPARATOR_LEN);
+                       p+=RPC_ROUTE_SEPARATOR_LEN;
+               }
+       }
+       if (d->hooks.last_route){
+               memcpy(p, RPC_ROUTE_SEPARATOR, RPC_ROUTE_SEPARATOR_LEN);
+               p+=RPC_ROUTE_SEPARATOR_LEN;
+               *p='<';
+               p++;
+               memcpy(p, d->hooks.last_route->s, d->hooks.last_route->len);
+               p+=d->hooks.last_route->len;
+               *p='>';
+               p++;
+       }
+       *p=0;
+       rpc->add(c, "s", buf);
+       pkg_free(buf);
+       return;
+}
+
+
+/** internal print uri into rpc reply function.
+ *  Prints the uris into rpc reply. It's used internally by
+ *  rpc_uac_callback().
+ *  @param rpc
+ *  @param c - rpc context
+ *  @param reply - sip reply
+ */
+static void  rpc_print_uris(rpc_t* rpc, void* c, struct sip_msg* reply)
+{
+       dlg_t* dlg;
+       dlg=shm_malloc(sizeof(dlg_t));
+       if (dlg==0){
+               ERR("out of memory (shm)\n");
+               return;
+       }
+       memset(dlg, 0, sizeof(dlg_t));
+       if (dlg_response_uac(dlg, reply, TARGET_REFRESH_UNKNOWN) < 0) {
+               ERR("failure while filling dialog structure\n");
+               free_dlg(dlg);
+               return;
+       }
+       if (dlg->state != DLG_CONFIRMED) {
+               free_dlg(dlg);
+               return;
+       }
+       if (dlg->hooks.request_uri->s){
+               rpc->add(c, "S", dlg->hooks.request_uri);
+       }else{
+               rpc->add(c, "s", "");
+       }
+       if (dlg->hooks.next_hop->s) {
+               rpc->add(c, "S", dlg->hooks.next_hop);
+       } else {
+               rpc->add(c, "s", "");
+       }
+       rpc_print_routes(rpc, c, dlg);
+       free_dlg(dlg);
+       return;
+}
+
+
+
+/* t_uac callback */
+static void rpc_uac_callback(struct cell* t, int type, struct tmcb_params* ps)
+{
+       rpc_delayed_ctx_t* dctx;
+       str text;
+       rpc_t* rpc;
+       void* c;
+       int code;
+       str* preason;
+       
+       dctx=(rpc_delayed_ctx_t*)*ps->param;
+       *ps->param=0;
+       if (dctx==0){
+               BUG("null delayed reply ctx\n");
+               return;
+       }
+       rpc=&dctx->rpc;
+       c=dctx->reply_ctx;
+       if (ps->rpl==FAKED_REPLY) {
+               text.s=error_text(ps->code);
+               text.len=strlen(text.s);
+               code=ps->code;
+               preason=&text;
+               rpc->add(c, "dS", code, preason);
+               rpc->add(c, "s", ""); /* request uri (rpc_print_uris)*/
+               rpc->add(c, "s", ""); /* next hop (rpc_print_uris) */
+               rpc->add(c, "s", ""); /* dialog routes (rpc_print_routes) */
+               rpc->add(c, "s", ""); /* rest of the reply */
+       }else{
+               code=ps->rpl->first_line.u.reply.statuscode;
+               preason=&ps->rpl->first_line.u.reply.reason;
+               rpc->add(c, "dS", code, preason);
+               rpc_print_uris(rpc, c, ps->rpl);
+               /* print all the reply (from the first header) */
+               rpc->add(c, "s", ps->rpl->headers->name.s);
+       }
+       rpc->delayed_ctx_close(dctx);
+       ps->param=0;
+}
+
+
 
 /** rpc t_uac version-
   * It expects the following list of strings as parameters:
@@ -339,11 +489,14 @@ static void rpc_t_uac(rpc_t* rpc, void* c, int reply_wait)
        char err_buf[MAX_REASON_LEN];
        dlg_t dlg;
        uac_req_t uac_req;
+       rpc_delayed_ctx_t* dctx;
        
        body.s=0;
        body.len=0;
-       if (reply_wait){
-               rpc->fault(c, 600, "Reply wait/async mode not supported");
+       if (reply_wait && (rpc->capabilities == 0 ||
+                                               !(rpc->capabilities(c) & RPC_DELAYED_REPLY))) {
+               rpc->fault(c, 600, "Reply wait/async mode not supported"
+                                                       " by this rpc transport");
                return;
        }
        ret=rpc->scan(c, "SSSSS*S",
@@ -442,6 +595,16 @@ static void rpc_t_uac(rpc_t* rpc, void* c, int reply_wait)
        uac_req.headers=&hfb;
        uac_req.body=body.len?&body:0;
        uac_req.dialog=&dlg;
+       if (reply_wait){
+               dctx=rpc->delayed_ctx_new(c);
+               if (dctx==0){
+                       rpc->fault(c, 500, "internal error: failed to create context");
+                       return;
+               }
+               uac_req.cb=rpc_uac_callback;
+               uac_req.cbp=dctx;
+               uac_req.cb_flags=TMCB_LOCAL_COMPLETED;
+       }
        ret = t_uac(&uac_req);
        
        if (ret <= 0) {
index 65c2ac8..e7bebcc 100644 (file)
  *  2007-09-05  A separate memory block is allocated for the lumps
  *              in case of requests in order to allow cloning them
  *              later than the SIP msg. (Miklos)
- */
+ * 2009-07-22  moved most of the functions to core sip_msg_clone.c  (andrei)*/
 
 #include "defs.h"
 
 
-#include <stdio.h>
 #include "sip_msg.h"
 #include "../../dprint.h"
 #include "../../mem/mem.h"
 #include "../../data_lump.h"
 #include "../../data_lump_rpl.h"
 #include "../../ut.h"
-#include "../../parser/digest/digest.h"
-#include "../../parser/parse_to.h"
+#include "../../sip_msg_clone.h"
 
 #ifdef POSTPONE_MSG_CLONING
-#include "../../atomic_ops.h"
-#include "fix_lumps.h"
+#include "../../fix_lumps.h"
 #endif
 
-
-/* rounds to the first 4 byte multiple on 32 bit archs
- * and to the first 8 byte multiple on 64 bit archs */
-#define ROUND4(s) \
-       (((s)+(sizeof(char*)-1))&(~(sizeof(char*)-1)))
-
-#define lump_len( _lump) \
-       (ROUND4(sizeof(struct lump)) +\
-       ROUND4(((_lump)->op==LUMP_ADD)?(_lump)->len:0))
-#define lump_clone( _new,_old,_ptr) \
-       {\
-               (_new) = (struct lump*)(_ptr);\
-               memcpy( (_new), (_old), sizeof(struct lump) );\
-               (_new)->flags|=LUMPFLAG_SHMEM; \
-               (_ptr)+=ROUND4(sizeof(struct lump));\
-               if ( (_old)->op==LUMP_ADD) {\
-                       (_new)->u.value = (char*)(_ptr);\
-                       memcpy( (_new)->u.value , (_old)->u.value , (_old)->len);\
-                       (_ptr)+=ROUND4((_old)->len);}\
-       }
-
-/* length of the data lump structures */
-#define LUMP_LIST_LEN(len, list) \
-do { \
-        struct lump* tmp, *chain; \
-       chain = (list); \
-       while (chain) \
-       { \
-               (len) += lump_len(chain); \
-               tmp = chain->before; \
-               while ( tmp ) \
-               { \
-                       (len) += lump_len( tmp ); \
-                       tmp = tmp->before; \
-               } \
-               tmp = chain->after; \
-               while ( tmp ) \
-               { \
-                       (len) += lump_len( tmp ); \
-                       tmp = tmp->after; \
-               } \
-               chain = chain->next; \
-       } \
-} while(0);
-
-/* length of the reply lump structure */
-#define RPL_LUMP_LIST_LEN(len, list) \
-do { \
-       struct lump_rpl* rpl_lump; \
-       for(rpl_lump=(list);rpl_lump;rpl_lump=rpl_lump->next) \
-               (len)+=ROUND4(sizeof(struct lump_rpl))+ROUND4(rpl_lump->text.len); \
-} while(0);
-
-/* clones data lumps */
-#define CLONE_LUMP_LIST(anchor, list, _ptr) \
-do { \
-       struct lump* lump_tmp, *l; \
-       struct lump** lump_anchor2, **a; \
-       a = (anchor); \
-       l = (list); \
-       while (l) \
-       { \
-               lump_clone( (*a) , l , (_ptr) ); \
-               /*before list*/ \
-               lump_tmp = l->before; \
-               lump_anchor2 = &((*a)->before); \
-               while ( lump_tmp ) \
-               { \
-                       lump_clone( (*lump_anchor2) , lump_tmp , (_ptr) ); \
-                       lump_anchor2 = &((*lump_anchor2)->before); \
-                       lump_tmp = lump_tmp->before; \
-               } \
-               /*after list*/ \
-               lump_tmp = l->after; \
-               lump_anchor2 = &((*a)->after); \
-               while ( lump_tmp ) \
-               { \
-                       lump_clone( (*lump_anchor2) , lump_tmp , (_ptr) ); \
-                       lump_anchor2 = &((*lump_anchor2)->after); \
-                       lump_tmp = lump_tmp->after; \
-               } \
-               a = &((*a)->next); \
-               l = l->next; \
-       } \
-} while(0)
-
-/* clones reply lumps */
-#define CLONE_RPL_LUMP_LIST(anchor, list, _ptr) \
-do { \
-       struct lump_rpl* rpl_lump; \
-       struct lump_rpl** rpl_lump_anchor; \
-       rpl_lump_anchor = (anchor); \
-       for(rpl_lump=(list);rpl_lump;rpl_lump=rpl_lump->next) \
-       { \
-               *(rpl_lump_anchor)=(struct lump_rpl*)(_ptr); \
-               (_ptr)+=ROUND4(sizeof( struct lump_rpl )); \
-               (*rpl_lump_anchor)->flags = LUMP_RPL_SHMEM | \
-                       (rpl_lump->flags&(~(LUMP_RPL_NODUP|LUMP_RPL_NOFREE))); \
-               (*rpl_lump_anchor)->text.len = rpl_lump->text.len; \
-               (*rpl_lump_anchor)->text.s=(_ptr); \
-               (_ptr)+=ROUND4(rpl_lump->text.len); \
-               memcpy((*rpl_lump_anchor)->text.s,rpl_lump->text.s,rpl_lump->text.len); \
-               (*rpl_lump_anchor)->next=0; \
-               rpl_lump_anchor = &((*rpl_lump_anchor)->next); \
-       } \
-} while (0)
-
-inline struct via_body* via_body_cloner( char* new_buf,
-                                       char *org_buf, struct via_body *param_org_via, char **p)
-{
-       struct via_body *new_via;
-       struct via_body *first_via, *last_via;
-       struct via_body *org_via;
-
-       first_via = last_via = 0;
-       org_via = param_org_via;
-
-       do
-       {
-               /* clones the via_body structure */
-               new_via = (struct via_body*)(*p);
-               memcpy( new_via , org_via , sizeof( struct via_body) );
-               (*p) += ROUND4(sizeof( struct via_body ));
-
-               /* hdr (str type) */
-               new_via->hdr.s=translate_pointer(new_buf,org_buf,org_via->hdr.s);
-               /* name (str type) */
-               new_via->name.s=translate_pointer(new_buf,org_buf,org_via->name.s);
-               /* version (str type) */
-               new_via->version.s=
-                       translate_pointer(new_buf,org_buf,org_via->version.s);
-               /* transport (str type) */
-               new_via->transport.s=
-                       translate_pointer(new_buf,org_buf,org_via->transport.s);
-               /* host (str type) */
-               new_via->host.s=translate_pointer(new_buf,org_buf,org_via->host.s);
-               /* port_str (str type) */
-               new_via->port_str.s=
-                       translate_pointer(new_buf,org_buf,org_via->port_str.s);
-               /* params (str type) */
-               new_via->params.s=translate_pointer(new_buf,org_buf,org_via->params.s);
-               /* transaction id */
-               new_via->tid.s=
-                       translate_pointer(new_buf, org_buf, org_via->tid.s);
-               /* comment (str type) */
-               new_via->comment.s=
-                       translate_pointer(new_buf,org_buf,org_via->comment.s);
-
-               if ( org_via->param_lst )
-               {
-                       struct via_param *vp, *new_vp, *last_new_vp;
-                       for( vp=org_via->param_lst, last_new_vp=0 ; vp ; vp=vp->next )
-                       {
-                               new_vp = (struct via_param*)(*p);
-                               memcpy( new_vp , vp , sizeof(struct via_param));
-                               (*p) += ROUND4(sizeof(struct via_param));
-                               new_vp->name.s=translate_pointer(new_buf,org_buf,vp->name.s);
-                               new_vp->value.s=translate_pointer(new_buf,org_buf,vp->value.s);
-                               new_vp->start=translate_pointer(new_buf,org_buf,vp->start);
-
-                               /* "translate" the shortcuts */
-                               switch(new_vp->type){
-                                       case PARAM_BRANCH:
-                                                       new_via->branch = new_vp;
-                                                       break;
-                                       case PARAM_RECEIVED:
-                                                       new_via->received = new_vp;
-                                                       break;
-                                       case PARAM_RPORT:
-                                                       new_via->rport = new_vp;
-                                                       break;
-                                       case PARAM_I:
-                                                       new_via->i = new_vp;
-                                                       break;
-                                       case PARAM_ALIAS:
-                                                       new_via->alias = new_vp;
-                                                       break;
-
-#ifdef USE_COMP
-                                       case PARAM_COMP:
-                                                       new_via->comp = new_vp;
-                                                       break;
-#endif
-                               }
-
-                               if (last_new_vp)
-                                       last_new_vp->next = new_vp;
-                               else
-                                       new_via->param_lst = new_vp;
-
-                               last_new_vp = new_vp;
-                               last_new_vp->next = NULL;
-                       }
-                       new_via->last_param = new_vp;
-               }/*end if via has params */
-
-               if (last_via)
-                       last_via->next = new_via;
-               else
-                       first_via = new_via;
-               last_via = new_via;
-               org_via = org_via->next;
-       }while(org_via);
-
-       return first_via;
-}
-
-
-static void uri_trans(char *new_buf, char *org_buf, struct sip_uri *uri)
-{
-       uri->user.s=translate_pointer(new_buf,org_buf,uri->user.s);
-       uri->passwd.s=translate_pointer(new_buf,org_buf,uri->passwd.s);
-       uri->host.s=translate_pointer(new_buf,org_buf,uri->host.s);
-       uri->port.s=translate_pointer(new_buf,org_buf,uri->port.s);
-       uri->params.s=translate_pointer(new_buf,org_buf,uri->params.s);
-       uri->headers.s=translate_pointer(new_buf,org_buf,uri->headers.s);
-       /* parameters */
-       uri->transport.s=translate_pointer(new_buf,org_buf,uri->transport.s);
-       uri->ttl.s=translate_pointer(new_buf,org_buf,uri->ttl.s);
-       uri->user_param.s=translate_pointer(new_buf,org_buf,uri->user_param.s);
-       uri->maddr.s=translate_pointer(new_buf,org_buf,uri->maddr.s);
-       uri->method.s=translate_pointer(new_buf,org_buf,uri->method.s);
-       uri->lr.s=translate_pointer(new_buf,org_buf,uri->lr.s);
-       uri->r2.s=translate_pointer(new_buf,org_buf,uri->r2.s);
-       /* values */
-       uri->transport_val.s
-               =translate_pointer(new_buf,org_buf,uri->transport_val.s);
-       uri->ttl_val.s=translate_pointer(new_buf,org_buf,uri->ttl_val.s);
-       uri->user_param_val.s
-               =translate_pointer(new_buf,org_buf,uri->user_param_val.s);
-       uri->maddr_val.s=translate_pointer(new_buf,org_buf,uri->maddr_val.s);
-       uri->method_val.s=translate_pointer(new_buf,org_buf,uri->method_val.s);
-       uri->lr_val.s=translate_pointer(new_buf,org_buf,uri->lr_val.s);
-       uri->r2_val.s=translate_pointer(new_buf,org_buf,uri->r2_val.s);
-}
-
-
-static inline struct auth_body* auth_body_cloner(char* new_buf, char *org_buf, struct auth_body *auth, char **p)
-{
-       struct auth_body* new_auth;
-
-       new_auth = (struct auth_body*)(*p);
-       memcpy(new_auth , auth , sizeof(struct auth_body));
-       (*p) += ROUND4(sizeof(struct auth_body));
-
-       /* authorized field must be cloned elsewhere */
-       new_auth->digest.username.whole.s =
-               translate_pointer(new_buf, org_buf, auth->digest.username.whole.s);
-       new_auth->digest.username.user.s =
-               translate_pointer(new_buf, org_buf, auth->digest.username.user.s);
-       new_auth->digest.username.domain.s =
-               translate_pointer(new_buf, org_buf, auth->digest.username.domain.s);
-       new_auth->digest.realm.s =
-               translate_pointer(new_buf, org_buf, auth->digest.realm.s);
-       new_auth->digest.nonce.s =
-               translate_pointer(new_buf, org_buf, auth->digest.nonce.s);
-       new_auth->digest.uri.s =
-               translate_pointer(new_buf, org_buf, auth->digest.uri.s);
-       new_auth->digest.response.s =
-               translate_pointer(new_buf, org_buf, auth->digest.response.s);
-       new_auth->digest.alg.alg_str.s =
-               translate_pointer(new_buf, org_buf, auth->digest.alg.alg_str.s);
-       new_auth->digest.cnonce.s =
-               translate_pointer(new_buf, org_buf, auth->digest.cnonce.s);
-       new_auth->digest.opaque.s =
-               translate_pointer(new_buf, org_buf, auth->digest.opaque.s);
-       new_auth->digest.qop.qop_str.s =
-               translate_pointer(new_buf, org_buf, auth->digest.qop.qop_str.s);
-       new_auth->digest.nc.s =
-               translate_pointer(new_buf, org_buf, auth->digest.nc.s);
-       return new_auth;
-}
-
-
-static inline int clone_authorized_hooks(struct sip_msg* new,
-                                        struct sip_msg* old)
-{
-       struct hdr_field* ptr, *new_ptr, *hook1, *hook2;
-       char stop = 0;
-
-       get_authorized_cred(old->authorization, &hook1);
-       if (!hook1) stop = 1;
-
-       get_authorized_cred(old->proxy_auth, &hook2);
-       if (!hook2) stop |= 2;
-
-       ptr = old->headers;
-       new_ptr = new->headers;
-
-       while(ptr) {
-               if (ptr == hook1) {
-                       if (!new->authorization || !new->authorization->parsed) {
-                               LOG(L_CRIT, "BUG: Error in message cloner (authorization)\n");
-                               return -1;
-                       }
-                       ((struct auth_body*)new->authorization->parsed)->authorized =
-                               new_ptr;
-                       stop |= 1;
-               }
-
-               if (ptr == hook2) {
-                       if (!new->proxy_auth || !new->proxy_auth->parsed) {
-                               LOG(L_CRIT, "BUG: Error in message cloner (proxy_auth)\n");
-                               return -1;
-                       }
-                       ((struct auth_body*)new->proxy_auth->parsed)->authorized =
-                               new_ptr;
-                       stop |= 2;
-               }
-
-               if (stop == 3) break;
-
-               ptr = ptr->next;
-               new_ptr = new_ptr->next;
-       }
-       return 0;
-}
-
-
-#define AUTH_BODY_SIZE sizeof(struct auth_body)
-
-#define HOOK_SET(hook) (new_msg->hook != org_msg->hook)
-
 /* Warning: Cloner does not clone all hdr_field headers (From, To, etc.). Pointers will reference pkg memory. Dereferencing will crash ser!!! */
 
 struct sip_msg*  sip_msg_cloner( struct sip_msg *org_msg, int *sip_msg_len )
 {
-       unsigned int      len;
-       struct hdr_field  *hdr,*new_hdr,*last_hdr;
-       struct via_body   *via;
-       struct via_param  *prm;
-       struct to_param   *to_prm,*new_to_prm;
-       struct sip_msg    *new_msg;
-       char              *p;
-
-       /*computing the length of entire sip_msg structure*/
-       len = ROUND4(sizeof( struct sip_msg ));
-       /*we will keep only the original msg +ZT */
-       len += ROUND4(org_msg->len + 1);
-       /*the new uri (if any)*/
-       if (org_msg->new_uri.s && org_msg->new_uri.len)
-               len+= ROUND4(org_msg->new_uri.len);
-       /*the dst uri (if any)*/
-       if (org_msg->dst_uri.s && org_msg->dst_uri.len)
-               len+= ROUND4(org_msg->dst_uri.len);
-       /*all the headers*/
-       for( hdr=org_msg->headers ; hdr ; hdr=hdr->next )
-       {
-               /*size of header struct*/
-               len += ROUND4(sizeof( struct hdr_field));
-               switch (hdr->type) {
-                            /* Safely ignore auxiliary header types */
-               case HDR_ERROR_T:
-               case HDR_OTHER_T:
-               case HDR_VIA2_T:
-               case HDR_EOH_T:
-                       break;
-
-               case HDR_VIA_T:
-                       for (via=(struct via_body*)hdr->parsed;via;via=via->next) {
-                               len+=ROUND4(sizeof(struct via_body));
-                                    /*via param*/
-                               for(prm=via->param_lst;prm;prm=prm->next)
-                                       len+=ROUND4(sizeof(struct via_param ));
-                       }
-                       break;
-
-               case HDR_TO_T:
-               case HDR_FROM_T:
-                            /* From header might be unparsed */
-                       if (hdr->parsed) {
-                               len+=ROUND4(sizeof(struct to_body));
-                                    /*to param*/
-                               to_prm = ((struct to_body*)(hdr->parsed))->param_lst;
-                               for(;to_prm;to_prm=to_prm->next)
-                                       len+=ROUND4(sizeof(struct to_param ));
-                       }
-                       break;
-
-               case HDR_CSEQ_T:
-                       len+=ROUND4(sizeof(struct cseq_body));
-                       break;
-
-
-               case HDR_AUTHORIZATION_T:
-               case HDR_PROXYAUTH_T:
-                       if (hdr->parsed) {
-                               len += ROUND4(AUTH_BODY_SIZE);
-                       }
-                       break;
-
-               case HDR_CALLID_T:
-               case HDR_CONTACT_T:
-               case HDR_MAXFORWARDS_T:
-               case HDR_ROUTE_T:
-               case HDR_RECORDROUTE_T:
-               case HDR_CONTENTTYPE_T:
-               case HDR_CONTENTLENGTH_T:
-               case HDR_RETRY_AFTER_T:
-               case HDR_EXPIRES_T:
-               case HDR_SUPPORTED_T:
-               case HDR_REQUIRE_T:
-               case HDR_PROXYREQUIRE_T:
-               case HDR_UNSUPPORTED_T:
-               case HDR_ALLOW_T:
-               case HDR_EVENT_T:
-               case HDR_ACCEPT_T:
-               case HDR_ACCEPTLANGUAGE_T:
-               case HDR_ORGANIZATION_T:
-               case HDR_PRIORITY_T:
-               case HDR_SUBJECT_T:
-               case HDR_USERAGENT_T:
-               case HDR_SERVER_T:
-               case HDR_ACCEPTDISPOSITION_T:
-               case HDR_CONTENTDISPOSITION_T:
-               case HDR_DIVERSION_T:
-               case HDR_RPID_T:
-               case HDR_REFER_TO_T:
-               case HDR_SIPIFMATCH_T:
-               case HDR_SESSIONEXPIRES_T:
-               case HDR_MIN_SE_T:
-               case HDR_SUBSCRIPTION_STATE_T:
-               case HDR_ACCEPTCONTACT_T:
-               case HDR_ALLOWEVENTS_T:
-               case HDR_CONTENTENCODING_T:
-               case HDR_REFERREDBY_T:
-               case HDR_REJECTCONTACT_T:
-               case HDR_REQUESTDISPOSITION_T:
-               case HDR_WWW_AUTHENTICATE_T:
-               case HDR_PROXY_AUTHENTICATE_T:
-               case HDR_DATE_T:
-               case HDR_IDENTITY_T:
-               case HDR_IDENTITY_INFO_T:
-               case HDR_PPI_T:
-               case HDR_PAI_T:
-               case HDR_PATH_T:
-               case HDR_PRIVACY_T:
-                       /* we ignore them for now even if they have something parsed*/
-                       break;
-               }/*switch*/
-       }/*for all headers*/
-
 #ifdef POSTPONE_MSG_CLONING
-       /* take care of the lumps only for replies if the msg cloning is postponed */
-       if (org_msg->first_line.type==SIP_REPLY) {
-#endif
-               /* calculate the length of the data and reply lump structures */
-               LUMP_LIST_LEN(len, org_msg->add_rm);
-               LUMP_LIST_LEN(len, org_msg->body_lumps);
-               RPL_LUMP_LIST_LEN(len, org_msg->reply_lump);
-
-#ifdef POSTPONE_MSG_CLONING
-       }
-#endif
-
-       p=(char *)shm_malloc(len);
-       if (!p)
-       {
-               LOG(L_ERR , "ERROR: sip_msg_cloner: cannot allocate memory\n" );
-               return 0;
-       }
-       if (sip_msg_len)
-               *sip_msg_len = len;
-
-       /* filling up the new structure */
-       new_msg = (struct sip_msg*)p;
-       /* sip msg structure */
-       memcpy( new_msg , org_msg , sizeof(struct sip_msg) );
-
-       new_msg->msg_flags |= FL_SHM_CLONE;
-       p += ROUND4(sizeof(struct sip_msg));
-       new_msg->body = 0;
-       new_msg->add_rm = 0;
-       new_msg->body_lumps = 0;
-       new_msg->reply_lump = 0;
-       /* new_uri */
-       if (org_msg->new_uri.s && org_msg->new_uri.len)
-       {
-               new_msg->new_uri.s = p;
-               memcpy( p , org_msg->new_uri.s , org_msg->new_uri.len);
-               p += ROUND4(org_msg->new_uri.len);
-       }
-       /* dst_uri */
-       if (org_msg->dst_uri.s && org_msg->dst_uri.len)
-       {
-               new_msg->dst_uri.s = p;
-               memcpy( p , org_msg->dst_uri.s , org_msg->dst_uri.len);
-               p += ROUND4(org_msg->dst_uri.len);
-       }
-       /* message buffers(org and scratch pad) */
-       memcpy( p , org_msg->buf, org_msg->len);
-       /* ZT to be safer */
-       *(p+org_msg->len)=0;
-       new_msg->buf = p;
-       p += ROUND4(new_msg->len+1);
-       /* unparsed and eoh pointer */
-       new_msg->unparsed = translate_pointer(new_msg->buf ,org_msg->buf,
-               org_msg->unparsed );
-       new_msg->eoh = translate_pointer(new_msg->buf,org_msg->buf,org_msg->eoh);
-       /* first line, updating the pointers*/
-       if ( org_msg->first_line.type==SIP_REQUEST )
-       {
-               new_msg->first_line.u.request.method.s =
-                       translate_pointer( new_msg->buf , org_msg->buf ,
-                       org_msg->first_line.u.request.method.s );
-               new_msg->first_line.u.request.uri.s =
-                       translate_pointer( new_msg->buf , org_msg->buf ,
-                       org_msg->first_line.u.request.uri.s );
-               new_msg->first_line.u.request.version.s =
-                       translate_pointer( new_msg->buf , org_msg->buf ,
-                       org_msg->first_line.u.request.version.s );
-               uri_trans(new_msg->buf, org_msg->buf, &new_msg->parsed_orig_ruri);
-               if (org_msg->new_uri.s && org_msg->new_uri.len)
-                       uri_trans(new_msg->new_uri.s, org_msg->new_uri.s,
-                                                                                       &new_msg->parsed_uri);
-               else
-                       uri_trans(new_msg->buf, org_msg->buf, &new_msg->parsed_uri);
-       }
-       else if ( org_msg->first_line.type==SIP_REPLY )
-       {
-               new_msg->first_line.u.reply.version.s =
-                       translate_pointer( new_msg->buf , org_msg->buf ,
-                       org_msg->first_line.u.reply.version.s );
-               new_msg->first_line.u.reply.status.s =
-                       translate_pointer( new_msg->buf , org_msg->buf ,
-                       org_msg->first_line.u.reply.status.s );
-               new_msg->first_line.u.reply.reason.s =
-                       translate_pointer( new_msg->buf , org_msg->buf ,
-                       org_msg->first_line.u.reply.reason.s );
-       }
-
-       /*headers list*/
-       new_msg->via1=0;
-       new_msg->via2=0;
-
-       for( hdr=org_msg->headers,last_hdr=0 ; hdr ; hdr=hdr->next )
-       {
-               new_hdr = (struct hdr_field*)p;
-               memcpy(new_hdr, hdr, sizeof(struct hdr_field) );
-               p += ROUND4(sizeof( struct hdr_field));
-               new_hdr->name.s = translate_pointer(new_msg->buf, org_msg->buf,
-                       hdr->name.s);
-               new_hdr->body.s = translate_pointer(new_msg->buf, org_msg->buf,
-                       hdr->body.s);
-               /* by default, we assume we don't understand this header in TM
-                  and better set it to zero; if we do, we will set a specific
-                  value in the following switch statement
-               */
-               new_hdr->parsed=0;
-
-               switch (hdr->type)
-               {
-                            /* Ignore auxiliary header types */
-               case HDR_ERROR_T:
-               case HDR_OTHER_T:
-               case HDR_VIA2_T:
-               case HDR_EOH_T:
-               case HDR_ACCEPTCONTACT_T:
-               case HDR_ALLOWEVENTS_T:
-               case HDR_CONTENTENCODING_T:
-               case HDR_REFERREDBY_T:
-               case HDR_REJECTCONTACT_T:
-               case HDR_REQUESTDISPOSITION_T:
-               case HDR_WWW_AUTHENTICATE_T:
-               case HDR_PROXY_AUTHENTICATE_T:
-               case HDR_DATE_T:
-               case HDR_IDENTITY_T:
-               case HDR_IDENTITY_INFO_T:
-               case HDR_RETRY_AFTER_T:
-                       break;
-
-               case HDR_VIA_T:
-                       if ( !new_msg->via1 ) {
-                               new_msg->h_via1 = new_hdr;
-                               new_msg->via1 = via_body_cloner(new_msg->buf,
-                                                               org_msg->buf, (struct via_body*)hdr->parsed, &p);
-                               new_hdr->parsed  = (void*)new_msg->via1;
-                               if ( new_msg->via1->next ) {
-                                       new_msg->via2 = new_msg->via1->next;
-                               }
-                       } else if ( !new_msg->via2 && new_msg->via1 ) {
-                               new_msg->h_via2 = new_hdr;
-                               if ( new_msg->via1->next ) {
-                                       new_hdr->parsed = (void*)new_msg->via1->next;
-                               } else {
-                                       new_msg->via2 = via_body_cloner( new_msg->buf,
-                                                                        org_msg->buf, (struct via_body*)hdr->parsed, &p);
-                                       new_hdr->parsed  = (void*)new_msg->via2;
-                               }
-                       } else if ( new_msg->via2 && new_msg->via1 ) {
-                               new_hdr->parsed = via_body_cloner( new_msg->buf , org_msg->buf ,
-                                                                  (struct via_body*)hdr->parsed , &p);
-                       }
-                       break;
-               case HDR_CSEQ_T:
-                       new_hdr->parsed = p;
-                       p +=ROUND4(sizeof(struct cseq_body));
-                       memcpy(new_hdr->parsed, hdr->parsed, sizeof(struct cseq_body));
-                       ((struct cseq_body*)new_hdr->parsed)->number.s =
-                               translate_pointer(new_msg->buf ,org_msg->buf,
-                                                 ((struct cseq_body*)hdr->parsed)->number.s );
-                       ((struct cseq_body*)new_hdr->parsed)->method.s =
-                               translate_pointer(new_msg->buf ,org_msg->buf,
-                                                 ((struct cseq_body*)hdr->parsed)->method.s );
-                       if (!HOOK_SET(cseq)) new_msg->cseq = new_hdr;
-                       break;
-               case HDR_TO_T:
-               case HDR_FROM_T:
-                       if (hdr->type == HDR_TO_T) {
-                               if (!HOOK_SET(to)) new_msg->to = new_hdr;
-                       } else {
-                               if (!HOOK_SET(from)) new_msg->from = new_hdr;
-                       }
-                            /* From header might be unparsed */
-                       if (!hdr->parsed) break;
-                       new_hdr->parsed = p;
-                       p +=ROUND4(sizeof(struct to_body));
-                       memcpy(new_hdr->parsed, hdr->parsed, sizeof(struct to_body));
-                       ((struct to_body*)new_hdr->parsed)->body.s =
-                               translate_pointer( new_msg->buf , org_msg->buf ,
-                                                  ((struct to_body*)hdr->parsed)->body.s );
-                       ((struct to_body*)new_hdr->parsed)->display.s =
-                               translate_pointer( new_msg->buf, org_msg->buf,
-                                                  ((struct to_body*)hdr->parsed)->display.s);
-                       ((struct to_body*)new_hdr->parsed)->uri.s =
-                               translate_pointer( new_msg->buf , org_msg->buf ,
-                                                  ((struct to_body*)hdr->parsed)->uri.s );
-                       if ( ((struct to_body*)hdr->parsed)->tag_value.s )
-                               ((struct to_body*)new_hdr->parsed)->tag_value.s =
-                                       translate_pointer( new_msg->buf , org_msg->buf ,
-                                                          ((struct to_body*)hdr->parsed)->tag_value.s );
-                       if ( (((struct to_body*)new_hdr->parsed)->parsed_uri.user.s)
-                               || (((struct to_body*)new_hdr->parsed)->parsed_uri.host.s) )
-                                       uri_trans(new_msg->buf, org_msg->buf,
-                                                       &((struct to_body*)new_hdr->parsed)->parsed_uri);
-                            /*to params*/
-                       to_prm = ((struct to_body*)(hdr->parsed))->param_lst;
-                       for(;to_prm;to_prm=to_prm->next) {
-                                    /*alloc*/
-                               new_to_prm = (struct to_param*)p;
-                               p +=ROUND4(sizeof(struct to_param ));
-                                    /*coping*/
-                               memcpy( new_to_prm, to_prm, sizeof(struct to_param ));
-                               ((struct to_body*)new_hdr->parsed)->param_lst = 0;
-                               new_to_prm->name.s = translate_pointer( new_msg->buf,
-                                                                       org_msg->buf , to_prm->name.s );
-                               new_to_prm->value.s = translate_pointer( new_msg->buf,
-                                                                        org_msg->buf , to_prm->value.s );
-                                    /*linking*/
-                               if ( !((struct to_body*)new_hdr->parsed)->param_lst )
-                                       ((struct to_body*)new_hdr->parsed)->param_lst
-                                               = new_to_prm;
-                               else
-                                       ((struct to_body*)new_hdr->parsed)->last_param->next
-                                               = new_to_prm;
-                               ((struct to_body*)new_hdr->parsed)->last_param
-                                       = new_to_prm;
-                       }
-                       break;
-               case HDR_CALLID_T:
-                       if (!HOOK_SET(callid)) {
-                               new_msg->callid = new_hdr;
-                       }
-                       break;
-               case HDR_CONTACT_T:
-                       if (!HOOK_SET(contact)) {
-                               new_msg->contact = new_hdr;
-                       }
-                       break;
-               case HDR_MAXFORWARDS_T:
-                       if (!HOOK_SET(maxforwards)) {
-                               new_msg->maxforwards = new_hdr;
-                       }
-                       break;
-               case HDR_ROUTE_T:
-                       if (!HOOK_SET(route)) {
-                               new_msg->route = new_hdr;
-                       }
-                       break;
-               case HDR_RECORDROUTE_T:
-                       if (!HOOK_SET(record_route)) {
-                               new_msg->record_route = new_hdr;
-                       }
-                       break;
-               case HDR_CONTENTTYPE_T:
-                       if (!HOOK_SET(content_type)) {
-                               new_msg->content_type = new_hdr;
-                               new_msg->content_type->parsed = hdr->parsed;
-                       }
-                       break;
-               case HDR_CONTENTLENGTH_T:
-                       if (!HOOK_SET(content_length)) {
-                               new_msg->content_length = new_hdr;
-                               new_msg->content_length->parsed = hdr->parsed;
-                       }
-                       break;
-               case HDR_AUTHORIZATION_T:
-                       if (!HOOK_SET(authorization)) {
-                               new_msg->authorization = new_hdr;
-                       }
-                       if (hdr->parsed) {
-                               new_hdr->parsed = auth_body_cloner(new_msg->buf ,
-                                                                  org_msg->buf , (struct auth_body*)hdr->parsed , &p);
-                       }
-                       break;
-               case HDR_EXPIRES_T:
-                       if (!HOOK_SET(expires)) {
-                               new_msg->expires = new_hdr;
-                       }
-                       break;
-               case HDR_PROXYAUTH_T:
-                       if (!HOOK_SET(proxy_auth)) {
-                               new_msg->proxy_auth = new_hdr;
-                       }
-                       if (hdr->parsed) {
-                               new_hdr->parsed = auth_body_cloner(new_msg->buf ,
-                                                                  org_msg->buf , (struct auth_body*)hdr->parsed , &p);
-                       }
-                       break;
-               case HDR_SUPPORTED_T:
-                       if (!HOOK_SET(supported)) {
-                               new_msg->supported = new_hdr;
-                       }
-                       break;
-               case HDR_REQUIRE_T:
-                       if (!HOOK_SET(require)) {
-                               new_msg->require = new_hdr;
-                       }
-                       break;
-               case HDR_PROXYREQUIRE_T:
-                       if (!HOOK_SET(proxy_require)) {
-                               new_msg->proxy_require = new_hdr;
-                       }
-                       break;
-               case HDR_UNSUPPORTED_T:
-                       if (!HOOK_SET(unsupported)) {
-                               new_msg->unsupported = new_hdr;
-                       }
-                       break;
-               case HDR_ALLOW_T:
-                       if (!HOOK_SET(allow)) {
-                               new_msg->allow = new_hdr;
-                       }
-                       break;
-               case HDR_EVENT_T:
-                       if (!HOOK_SET(event)) {
-                               new_msg->event = new_hdr;
-                       }
-                       break;
-               case HDR_ACCEPT_T:
-                       if (!HOOK_SET(accept)) {
-                               new_msg->accept = new_hdr;
-                       }
-                       break;
-               case HDR_ACCEPTLANGUAGE_T:
-                       if (!HOOK_SET(accept_language)) {
-                               new_msg->accept_language = new_hdr;
-                       }
-                       break;
-               case HDR_ORGANIZATION_T:
-                       if (!HOOK_SET(organization)) {
-                               new_msg->organization = new_hdr;
-                       }
-                       break;
-               case HDR_PRIORITY_T:
-                       if (!HOOK_SET(priority)) {
-                               new_msg->priority = new_hdr;
-                       }
-                       break;
-               case HDR_SUBJECT_T:
-                       if (!HOOK_SET(subject)) {
-                               new_msg->subject = new_hdr;
-                       }
-                       break;
-               case HDR_USERAGENT_T:
-                       if (!HOOK_SET(user_agent)) {
-                               new_msg->user_agent = new_hdr;
-                       }
-                       break;
-               case HDR_SERVER_T:
-                       if (!HOOK_SET(server)) {
-                               new_msg->server = new_hdr;
-                       }
-                       break;
-               case HDR_ACCEPTDISPOSITION_T:
-                       if (!HOOK_SET(accept_disposition)) {
-                               new_msg->accept_disposition = new_hdr;
-                       }
-                       break;
-               case HDR_CONTENTDISPOSITION_T:
-                       if (!HOOK_SET(content_disposition)) {
-                               new_msg->content_disposition = new_hdr;
-                       }
-                       break;
-               case HDR_DIVERSION_T:
-                       if (!HOOK_SET(diversion)) {
-                               new_msg->diversion = new_hdr;
-                       }
-                       break;
-               case HDR_RPID_T:
-                       if (!HOOK_SET(rpid)) {
-                               new_msg->rpid = new_hdr;
-                       }
-                       break;
-               case HDR_REFER_TO_T:
-                       if (!HOOK_SET(refer_to)) {
-                               new_msg->refer_to = new_hdr;
-                       }
-                       break;
-               case HDR_SESSIONEXPIRES_T:
-                       if (!HOOK_SET(session_expires)) {
-                               new_msg->session_expires = new_hdr;
-                       }
-                       break;
-               case HDR_MIN_SE_T:
-                       if (!HOOK_SET(min_se)) {
-                               new_msg->min_se = new_hdr;
-                       }
-                       break;
-               case HDR_SUBSCRIPTION_STATE_T:
-                       if (!HOOK_SET(subscription_state)) {
-                               new_msg->subscription_state = new_hdr;
-                       }
-                       break;
-               case HDR_SIPIFMATCH_T:
-                       if (!HOOK_SET(sipifmatch)) {
-                               new_msg->sipifmatch = new_hdr;
-                       }
-                       break;
-               case HDR_PPI_T:
-                       if (!HOOK_SET(ppi)) {
-                               new_msg->ppi = new_hdr;
-                       }
-                       break;
-               case HDR_PAI_T:
-                       if (!HOOK_SET(pai)) {
-                               new_msg->pai = new_hdr;
-                       }
-                       break;
-               case HDR_PATH_T:
-                       if (!HOOK_SET(path)) {
-                               new_msg->path = new_hdr;
-                       }
-                       break;
-               case HDR_PRIVACY_T:
-                       if (!HOOK_SET(privacy)) {
-                               new_msg->privacy = new_hdr;
-                       }
-                       break;
-               }/*switch*/
-
-               if ( last_hdr )
-               {
-                       last_hdr->next = new_hdr;
-                       last_hdr=last_hdr->next;
-               }
-               else
-               {
-                       last_hdr=new_hdr;
-                       new_msg->headers =new_hdr;
-               }
-               last_hdr->next = 0;
-               new_msg->last_header = last_hdr;
-       }
-
-#ifdef POSTPONE_MSG_CLONING
-       /* take care of the lumps only for replies if the msg cloning is postponed */
-       if (org_msg->first_line.type==SIP_REPLY) {
-#endif
-               /*cloning data and reply lump structures*/
-               CLONE_LUMP_LIST(&(new_msg->add_rm), org_msg->add_rm, p);
-               CLONE_LUMP_LIST(&(new_msg->body_lumps), org_msg->body_lumps, p);
-               CLONE_RPL_LUMP_LIST(&(new_msg->reply_lump), org_msg->reply_lump, p);
-
+       /* take care of the lumps only for replies if the msg cloning is 
+          postponed */
+       if (org_msg->first_line.type==SIP_REPLY)
+#endif /* POSTPONE_MSG_CLONING */
+               /*cloning all the lumps*/
+               return sip_msg_shm_clone(org_msg, sip_msg_len, 1);
 #ifdef POSTPONE_MSG_CLONING
-       }
-#endif
-
-       if (clone_authorized_hooks(new_msg, org_msg) < 0) {
-               shm_free(new_msg);
-               return 0;
-       }
-
-       return new_msg;
+       /* don't clone the lumps */
+       return sip_msg_shm_clone(org_msg, sip_msg_len, 0);
+#endif /* POSTPONE_MSG_CLONING */
 }
 
 #ifdef POSTPONE_MSG_CLONING
 /* indicates wheter we have already cloned the msg lumps or not */
 unsigned char lumps_are_cloned = 0;
 
-/* clones the data and reply lumps from pkg_msg to shm_msg
- * A new memory block is allocated for the lumps which is linked
- * to shm_msg
- *
- * Note: the new memory block is linked to shm_msg->add_rm if
- * at least one data lump is set, else it is linked to shm_msg->body_lumps
- * if at least one body lump is set, otherwise it is linked to
- * shm_msg->reply_lump
- */
-static int msg_lump_cloner( struct sip_msg *shm_msg, struct sip_msg *pkg_msg)
-{
-       unsigned int    len;
-       char            *p;
-       struct lump     *add_rm, *body_lumps;
-       struct lump_rpl *reply_lump;
-
-       /* calculate the length of the lumps */
-       len = 0;
-       LUMP_LIST_LEN(len, pkg_msg->add_rm);
-       LUMP_LIST_LEN(len, pkg_msg->body_lumps);
-       RPL_LUMP_LIST_LEN(len, pkg_msg->reply_lump);
-
-       if (!len)
-               return 0; /* nothing to do */
-
-       p=(char *)shm_malloc(len);
-       if (!p)
-       {
-               LOG(L_ERR, "ERROR: msg_lump_cloner: cannot allocate memory\n" );
-               return -1;
-       }
-
-       /* clone the lumps
-        *
-        * Better not to modify the lump structures of shm_msg directly
-        * because no lock is held while they are read. We have to prepare
-        * the lumps in separate lists, and fush the cache
-        * with membar_write() before linking the lists to shm_msg.
-        */
-       add_rm = body_lumps = 0;
-       reply_lump = 0;
-
-       CLONE_LUMP_LIST(&add_rm, pkg_msg->add_rm, p);
-       CLONE_LUMP_LIST(&body_lumps, pkg_msg->body_lumps, p);
-       CLONE_RPL_LUMP_LIST(&reply_lump, pkg_msg->reply_lump, p);
-       membar_write();
 
-       shm_msg->add_rm = add_rm;
-       shm_msg->body_lumps = body_lumps;
-       shm_msg->reply_lump = reply_lump;
-
-       return 0;       
-}
 
 /* wrapper function for msg_lump_cloner() with some additional sanity checks */
 int save_msg_lumps( struct sip_msg *shm_msg, struct sip_msg *pkg_msg)
 {
+       int ret;
+       struct lump* add_rm;
+       struct lump* body_lumps;
+       struct lump_rpl* reply_lump;
+       
        /* make sure that we do not clone the lumps twice */
        if (lumps_are_cloned) {
                LOG(L_DBG, "DEBUG: save_msg_lumps: lumps have been already cloned\n" );
@@ -1044,6 +125,15 @@ int save_msg_lumps( struct sip_msg *shm_msg, struct sip_msg *pkg_msg)
        free_via_clen_lump(&pkg_msg->add_rm);
 
        lumps_are_cloned = 1;
-       return msg_lump_cloner(shm_msg, pkg_msg);
+       ret=msg_lump_cloner(pkg_msg, &add_rm, &body_lumps, &reply_lump);
+       if (likely(ret==0)){
+               /* make sure the lumps are fully written before adding them to
+                  shm_msg (in case someone accesses it in the same time) */
+               membar_write();
+               shm_msg->add_rm = add_rm;
+               shm_msg->body_lumps = body_lumps;
+               shm_msg->reply_lump = reply_lump;
+       }
+       return ret<0?-1:0;
 }
 #endif /* POSTPONE_MSG_CLONING */
index 5f5cb42..5933ad6 100644 (file)
 #include "t_cancel.h"
 #include "t_lookup.h"
 #include "t_fwd.h"
-#include "fix_lumps.h"
+#include "../../fix_lumps.h"
 #include "config.h"
 #ifdef USE_DNS_FAILOVER
 #include "../../dns_cache.h"
index ea5db73..981efd2 100644 (file)
 #include "t_msgbuilder.h"
 #include "t_lookup.h"
 #include "t_fwd.h"
-#include "fix_lumps.h"
+#include "../../fix_lumps.h"
 #include "t_stats.h"
 #include "uac.h"
 
index c140626..f386a88 100644 (file)
@@ -60,6 +60,7 @@
 #include "../../action.h" /* run_actions */
 #include "../../script_cb.h" /* exec_*_script_cb */
 #include "../../route.h" /* route_get */
+#include "../../sip_msg_clone.h" /* sip_msg_shm_clone */
 #include "http.h"
 
 /** @addtogroup xmlrpc
@@ -316,6 +317,8 @@ typedef struct rpc_ctx {
                                                          received */
        struct xmlrpc_reply reply;  /**< XML-RPC reply to be sent to the client */
        struct rpc_struct* structs; /**< Structures to be added to the reply */
+       int msg_shm_block_size; /**< non-zero for delayed reply contexts with
+                                                               shm cloned msgs */
        int reply_sent;             /**< The flag is set after a reply is sent,
                                                                   this prevents a single reply being sent
                                                                   twice */
@@ -330,6 +333,11 @@ typedef struct rpc_ctx {
 } rpc_ctx_t;
 
 
+/* extra rpc_ctx_t flags */
+/* first 8 bits reserved for rpc flags (e.g. RET_ARRAY) */
+#define XMLRPC_DELAYED_CTX_F   256
+#define XMLRPC_DELAYED_REPLY_F 512
+
 /** The structure represents a XML-RPC document structure.
  *
  * This is the data structure that represents XML-RPC structures that are sent
@@ -424,6 +432,9 @@ struct module_exports exports = {
 #define ESC_AMP "&amp;"
 
 
+static void clean_context(rpc_ctx_t* ctx);
+
+
 /** Adds arbitrary text to the XML-RPC reply being constructed, special
  * characters < and & will be escaped.
  *
@@ -606,6 +617,21 @@ static int init_xmlrpc_reply(struct xmlrpc_reply* reply)
 }
 
 
+
+/* if this a delayed reply context, and it's never been use before, fix it */
+static int fix_delayed_reply_ctx(rpc_ctx_t* ctx)
+{
+       if  ((ctx->flags & XMLRPC_DELAYED_CTX_F) && (ctx->reply.buf.s==0)){
+               if (init_xmlrpc_reply(&ctx->reply) <0) return -1;
+               add_xmlrpc_reply(&ctx->reply, &success_prefix);
+               if (ctx->flags & RET_ARRAY)
+                       return add_xmlrpc_reply(&ctx->reply, &array_prefix);
+       }
+       return 0;
+}
+
+
+
 /** Free all memory used by the XML-RPC reply structure. */
 static void clean_xmlrpc_reply(struct xmlrpc_reply* reply)
 {
@@ -990,6 +1016,7 @@ static int rpc_add(rpc_ctx_t* ctx, char* fmt, ...)
        struct xmlrpc_reply* reply;
        struct rpc_struct* p;
 
+       fix_delayed_reply_ctx(ctx);
        va_start(ap, fmt);
        reply = &ctx->reply;
 
@@ -1479,6 +1506,7 @@ static int rpc_printf(rpc_ctx_t* ctx, char* fmt, ...)
        str s;
        struct xmlrpc_reply* reply;
 
+       fix_delayed_reply_ctx(ctx);
        reply = &ctx->reply;
        buf = (char*)pkg_malloc(RPC_BUF_SIZE);
        if (!buf) {
@@ -1746,6 +1774,111 @@ static int rpc_struct_scan(struct rpc_struct* s, char* fmt, ...)
 }
 
 
+/** Returns the RPC capabilities supported by the xmlrpc driver.
+ */
+static rpc_capabilities_t rpc_capabilities(rpc_ctx_t* ctx)
+{
+       return RPC_DELAYED_REPLY;
+}
+
+
+/** Returns a new "delayed reply" context.
+ * Creates a new delayed reply context in shm and returns it.
+ * @return 0 - not supported, already replied, or no more memory;
+ *         !=0 pointer to the special delayed ctx.
+ * Note1: one should use the returned ctx reply context to build a reply and
+ *  when finished call rpc_delayed_ctx_close().
+ * Note2: adding pieces to the reply in different processes is not supported.
+ */
+static struct rpc_delayed_ctx* rpc_delayed_ctx_new(rpc_ctx_t* ctx)
+{
+       struct rpc_delayed_ctx* ret;
+       int size;
+       rpc_ctx_t* r_ctx;
+       struct sip_msg* shm_msg;
+       int len;
+       
+       ret=0;
+       shm_msg=0;
+       
+       if (ctx->reply_sent)
+               return 0; /* no delayed reply if already replied */
+       /* clone the sip msg */
+       shm_msg=sip_msg_shm_clone(ctx->msg, &len, 1);
+       if (shm_msg==0)
+               goto error;
+       
+       /* alloc into one block */
+       size=ROUND_POINTER(sizeof(*ret))+sizeof(rpc_ctx_t);
+       if ((ret=shm_malloc(size))==0)
+               goto error;
+       memset(ret, 0, size);
+       ret->rpc=func_param;
+       ret->reply_ctx=(char*)ret+ROUND_POINTER(sizeof(*ret));
+       r_ctx=ret->reply_ctx;
+       r_ctx->flags=ctx->flags | XMLRPC_DELAYED_CTX_F;
+       ctx->flags |= XMLRPC_DELAYED_REPLY_F;
+       r_ctx->msg=shm_msg;
+       r_ctx->msg_shm_block_size=len;
+       
+       return ret;
+error:
+       if (shm_msg)
+               shm_free(shm_msg);
+       if (ret)
+               shm_free(ret);
+       return 0;
+}
+
+
+
+/** Closes a "delayed reply" context and sends the reply.
+ * If no reply has been sent the reply will be built and sent automatically.
+ * See the notes from rpc_new_delayed_ctx()
+ */
+static void rpc_delayed_ctx_close(struct rpc_delayed_ctx* dctx)
+{
+       rpc_ctx_t* r_ctx;
+       struct hdr_field* hdr;
+       
+       r_ctx=dctx->reply_ctx;
+       if (unlikely(!(r_ctx->flags & XMLRPC_DELAYED_CTX_F))){
+               BUG("reply ctx not marked as async/delayed\n");
+               goto error;
+       }
+       if (fix_delayed_reply_ctx(r_ctx)<0)
+               goto error;
+       if (!r_ctx->reply_sent){
+               rpc_send(r_ctx);
+       }
+error:
+       clean_context(r_ctx);
+       /* collect possible garbage (e.g. generated by structures) */
+       collect_garbage();
+       /* free added lumps (rpc_send adds a body lump) */
+       del_nonshm_lump( &(r_ctx->msg->add_rm) );
+       del_nonshm_lump( &(r_ctx->msg->body_lumps) );
+       del_nonshm_lump_rpl( &(r_ctx->msg->reply_lump) );
+       /* free header's parsed structures that were added by failure handlers */
+       for( hdr=r_ctx->msg->headers ; hdr ; hdr=hdr->next ) {
+               if ( hdr->parsed && hdr_allocs_parse(hdr) &&
+               (hdr->parsed<(void*)r_ctx->msg ||
+               hdr->parsed>=(void*)(r_ctx->msg+r_ctx->msg_shm_block_size))) {
+                       /* header parsed filed doesn't point inside uas.request memory
+                        * chunck -> it was added by failure funcs.-> free it as pkg */
+                       DBG("DBG:free_faked_req: removing hdr->parsed %d\n",
+                                       hdr->type);
+                       clean_hdr_field(hdr);
+                       hdr->parsed = 0;
+               }
+       }
+       shm_free(r_ctx->msg);
+       r_ctx->msg=0;
+       dctx->reply_ctx=0;
+       shm_free(dctx);
+}
+
+
 /** Starts parsing XML-RPC document, get the name of the method to be called
  * and position the cursor at the first parameter in the document.
  */
@@ -1832,6 +1965,7 @@ static void close_doc(rpc_ctx_t* ctx)
 static int init_context(rpc_ctx_t* ctx, sip_msg_t* msg)
 {
        ctx->msg = msg;
+       ctx->msg_shm_block_size=0;
        ctx->method = 0;
        ctx->reply_sent = 0;
        ctx->act_param = 0;
@@ -2066,7 +2200,7 @@ static int dispatch_rpc(sip_msg_t* msg, char* s1, char* s2)
 
  skip:
             /* The function may have sent the reply itself */
-       if (!ctx.reply_sent) {
+       if (!ctx.reply_sent && !(ctx.flags&XMLRPC_DELAYED_REPLY_F)) {
                ret = rpc_send(&ctx);
        }
        clean_context(&ctx);
@@ -2212,6 +2346,10 @@ static int mod_init(void)
        func_param.struct_add = (rpc_struct_add_f)rpc_struct_add;
        func_param.struct_scan = (rpc_struct_scan_f)rpc_struct_scan;
        func_param.struct_printf = (rpc_struct_printf_f)rpc_struct_printf;
+       func_param.capabilities = (rpc_capabilities_f)rpc_capabilities;
+       func_param.delayed_ctx_new = (rpc_delayed_ctx_new_f)rpc_delayed_ctx_new;
+       func_param.delayed_ctx_close =
+               (rpc_delayed_ctx_close_f)rpc_delayed_ctx_close;
        register_select_table(xmlrpc_sel);
        
        /* register non-sip hooks */
diff --git a/rpc.h b/rpc.h
index 18e767e..1434146 100644 (file)
--- a/rpc.h
+++ b/rpc.h
@@ -37,7 +37,13 @@ enum rpc_flags {
        RET_ARRAY = (1 << 0),
        RET_VALUE = (1 << 1)
 };
-       
+
+typedef enum rpc_capabilities {
+       RPC_DELAYED_REPLY = (1 <<0)  /* delayed reply support */
+} rpc_capabilities_t;
+
+struct rpc_delayed_ctx;
+
 
 /* Send the result to the caller */
 typedef int (*rpc_send_f)(void* ctx);                                      /* Send the reply to the client */
@@ -49,6 +55,13 @@ typedef int (*rpc_struct_add_f)(void* ctx, char* fmt, ...);                /* Cr
 typedef int (*rpc_struct_scan_f)(void* ctx, char* fmt, ...);               /* Scan attributes of a structure */
 typedef int (*rpc_struct_printf_f)(void* ctx, char* name, char* fmt, ...); /* Struct version of rpc_printf */
 
+/* returns the supported capabilities */
+typedef rpc_capabilities_t (*rpc_capabilities_f)(void* ctx);
+/* create a special "context" for delayed replies */
+typedef struct rpc_delayed_ctx* (*rpc_delayed_ctx_new_f)(void* ctx);
+/* close the special "context" for delayed replies */
+typedef void (*rpc_delayed_ctx_close_f)(struct rpc_delayed_ctx* dctx);
+
 /*
  * RPC context, this is what RPC functions get as a parameter and use
  * it to obtain the value of the parameters of the call and reference
@@ -63,9 +76,19 @@ typedef struct rpc {
        rpc_struct_add_f struct_add;
        rpc_struct_scan_f struct_scan;
        rpc_struct_printf_f struct_printf;
+       rpc_capabilities_f capabilities;
+       rpc_delayed_ctx_new_f delayed_ctx_new;
+       rpc_delayed_ctx_close_f delayed_ctx_close;
 } rpc_t;
 
 
+typedef struct rpc_delayed_ctx{
+       rpc_t rpc;
+       void* reply_ctx;
+       /* more private data might follow */
+} rpc_delayed_ctx_t;
+
+
 /*
  * RPC Function Prototype
  */
diff --git a/sip_msg_clone.c b/sip_msg_clone.c
new file mode 100644 (file)
index 0000000..620094f
--- /dev/null
@@ -0,0 +1,976 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2009 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * sip_msg_clone.c - moved sip msg clone-in-shm functions from tm
+ */
+/*
+ * History:
+ * --------
+ *  2009-07-22  initial version: functions moved from tm/sip_msg.c (andrei)
+*/
+
+#include "sip_msg_clone.h"
+
+
+#include "dprint.h"
+#include "mem/mem.h"
+#include "data_lump.h"
+#include "data_lump_rpl.h"
+#include "ut.h"
+#include "parser/digest/digest.h"
+#include "parser/parse_to.h"
+#include "atomic_ops.h"
+
+/* rounds to the first 4 byte multiple on 32 bit archs
+ * and to the first 8 byte multiple on 64 bit archs */
+#define ROUND4(s) \
+       (((s)+(sizeof(char*)-1))&(~(sizeof(char*)-1)))
+
+#define lump_len( _lump) \
+       (ROUND4(sizeof(struct lump)) +\
+       ROUND4(((_lump)->op==LUMP_ADD)?(_lump)->len:0))
+#define lump_clone( _new,_old,_ptr) \
+       {\
+               (_new) = (struct lump*)(_ptr);\
+               memcpy( (_new), (_old), sizeof(struct lump) );\
+               (_new)->flags|=LUMPFLAG_SHMEM; \
+               (_ptr)+=ROUND4(sizeof(struct lump));\
+               if ( (_old)->op==LUMP_ADD) {\
+                       (_new)->u.value = (char*)(_ptr);\
+                       memcpy( (_new)->u.value , (_old)->u.value , (_old)->len);\
+                       (_ptr)+=ROUND4((_old)->len);}\
+       }
+
+/* length of the data lump structures */
+#define LUMP_LIST_LEN(len, list) \
+do { \
+        struct lump* tmp, *chain; \
+       chain = (list); \
+       while (chain) \
+       { \
+               (len) += lump_len(chain); \
+               tmp = chain->before; \
+               while ( tmp ) \
+               { \
+                       (len) += lump_len( tmp ); \
+                       tmp = tmp->before; \
+               } \
+               tmp = chain->after; \
+               while ( tmp ) \
+               { \
+                       (len) += lump_len( tmp ); \
+                       tmp = tmp->after; \
+               } \
+               chain = chain->next; \
+       } \
+} while(0);
+
+/* length of the reply lump structure */
+#define RPL_LUMP_LIST_LEN(len, list) \
+do { \
+       struct lump_rpl* rpl_lump; \
+       for(rpl_lump=(list);rpl_lump;rpl_lump=rpl_lump->next) \
+               (len)+=ROUND4(sizeof(struct lump_rpl))+ROUND4(rpl_lump->text.len); \
+} while(0);
+
+/* clones data lumps */
+#define CLONE_LUMP_LIST(anchor, list, _ptr) \
+do { \
+       struct lump* lump_tmp, *l; \
+       struct lump** lump_anchor2, **a; \
+       a = (anchor); \
+       l = (list); \
+       while (l) \
+       { \
+               lump_clone( (*a) , l , (_ptr) ); \
+               /*before list*/ \
+               lump_tmp = l->before; \
+               lump_anchor2 = &((*a)->before); \
+               while ( lump_tmp ) \
+               { \
+                       lump_clone( (*lump_anchor2) , lump_tmp , (_ptr) ); \
+                       lump_anchor2 = &((*lump_anchor2)->before); \
+                       lump_tmp = lump_tmp->before; \
+               } \
+               /*after list*/ \
+               lump_tmp = l->after; \
+               lump_anchor2 = &((*a)->after); \
+               while ( lump_tmp ) \
+               { \
+                       lump_clone( (*lump_anchor2) , lump_tmp , (_ptr) ); \
+                       lump_anchor2 = &((*lump_anchor2)->after); \
+                       lump_tmp = lump_tmp->after; \
+               } \
+               a = &((*a)->next); \
+               l = l->next; \
+       } \
+} while(0)
+
+/* clones reply lumps */
+#define CLONE_RPL_LUMP_LIST(anchor, list, _ptr) \
+do { \
+       struct lump_rpl* rpl_lump; \
+       struct lump_rpl** rpl_lump_anchor; \
+       rpl_lump_anchor = (anchor); \
+       for(rpl_lump=(list);rpl_lump;rpl_lump=rpl_lump->next) \
+       { \
+               *(rpl_lump_anchor)=(struct lump_rpl*)(_ptr); \
+               (_ptr)+=ROUND4(sizeof( struct lump_rpl )); \
+               (*rpl_lump_anchor)->flags = LUMP_RPL_SHMEM | \
+                       (rpl_lump->flags&(~(LUMP_RPL_NODUP|LUMP_RPL_NOFREE))); \
+               (*rpl_lump_anchor)->text.len = rpl_lump->text.len; \
+               (*rpl_lump_anchor)->text.s=(_ptr); \
+               (_ptr)+=ROUND4(rpl_lump->text.len); \
+               memcpy((*rpl_lump_anchor)->text.s,rpl_lump->text.s,rpl_lump->text.len); \
+               (*rpl_lump_anchor)->next=0; \
+               rpl_lump_anchor = &((*rpl_lump_anchor)->next); \
+       } \
+} while (0)
+
+
+
+inline struct via_body* via_body_cloner( char* new_buf,
+                                       char *org_buf, struct via_body *param_org_via, char **p)
+{
+       struct via_body *new_via;
+       struct via_body *first_via, *last_via;
+       struct via_body *org_via;
+
+       first_via = last_via = 0;
+       org_via = param_org_via;
+
+       do
+       {
+               /* clones the via_body structure */
+               new_via = (struct via_body*)(*p);
+               memcpy( new_via , org_via , sizeof( struct via_body) );
+               (*p) += ROUND4(sizeof( struct via_body ));
+
+               /* hdr (str type) */
+               new_via->hdr.s=translate_pointer(new_buf,org_buf,org_via->hdr.s);
+               /* name (str type) */
+               new_via->name.s=translate_pointer(new_buf,org_buf,org_via->name.s);
+               /* version (str type) */
+               new_via->version.s=
+                       translate_pointer(new_buf,org_buf,org_via->version.s);
+               /* transport (str type) */
+               new_via->transport.s=
+                       translate_pointer(new_buf,org_buf,org_via->transport.s);
+               /* host (str type) */
+               new_via->host.s=translate_pointer(new_buf,org_buf,org_via->host.s);
+               /* port_str (str type) */
+               new_via->port_str.s=
+                       translate_pointer(new_buf,org_buf,org_via->port_str.s);
+               /* params (str type) */
+               new_via->params.s=translate_pointer(new_buf,org_buf,org_via->params.s);
+               /* transaction id */
+               new_via->tid.s=
+                       translate_pointer(new_buf, org_buf, org_via->tid.s);
+               /* comment (str type) */
+               new_via->comment.s=
+                       translate_pointer(new_buf,org_buf,org_via->comment.s);
+
+               if ( org_via->param_lst )
+               {
+                       struct via_param *vp, *new_vp, *last_new_vp;
+                       for( vp=org_via->param_lst, last_new_vp=0 ; vp ; vp=vp->next )
+                       {
+                               new_vp = (struct via_param*)(*p);
+                               memcpy( new_vp , vp , sizeof(struct via_param));
+                               (*p) += ROUND4(sizeof(struct via_param));
+                               new_vp->name.s=translate_pointer(new_buf,org_buf,vp->name.s);
+                               new_vp->value.s=translate_pointer(new_buf,org_buf,vp->value.s);
+                               new_vp->start=translate_pointer(new_buf,org_buf,vp->start);
+
+                               /* "translate" the shortcuts */
+                               switch(new_vp->type){
+                                       case PARAM_BRANCH:
+                                                       new_via->branch = new_vp;
+                                                       break;
+                                       case PARAM_RECEIVED:
+                                                       new_via->received = new_vp;
+                                                       break;
+                                       case PARAM_RPORT:
+                                                       new_via->rport = new_vp;
+                                                       break;
+                                       case PARAM_I:
+                                                       new_via->i = new_vp;
+                                                       break;
+                                       case PARAM_ALIAS:
+                                                       new_via->alias = new_vp;
+                                                       break;
+
+#ifdef USE_COMP
+                                       case PARAM_COMP:
+                                                       new_via->comp = new_vp;
+                                                       break;
+#endif
+                               }
+
+                               if (last_new_vp)
+                                       last_new_vp->next = new_vp;
+                               else
+                                       new_via->param_lst = new_vp;
+
+                               last_new_vp = new_vp;
+                               last_new_vp->next = NULL;
+                       }
+                       new_via->last_param = new_vp;
+               }/*end if via has params */
+
+               if (last_via)
+                       last_via->next = new_via;
+               else
+                       first_via = new_via;
+               last_via = new_via;
+               org_via = org_via->next;
+       }while(org_via);
+
+       return first_via;
+}
+
+
+static void uri_trans(char *new_buf, char *org_buf, struct sip_uri *uri)
+{
+       uri->user.s=translate_pointer(new_buf,org_buf,uri->user.s);
+       uri->passwd.s=translate_pointer(new_buf,org_buf,uri->passwd.s);
+       uri->host.s=translate_pointer(new_buf,org_buf,uri->host.s);
+       uri->port.s=translate_pointer(new_buf,org_buf,uri->port.s);
+       uri->params.s=translate_pointer(new_buf,org_buf,uri->params.s);
+       uri->headers.s=translate_pointer(new_buf,org_buf,uri->headers.s);
+       /* parameters */
+       uri->transport.s=translate_pointer(new_buf,org_buf,uri->transport.s);
+       uri->ttl.s=translate_pointer(new_buf,org_buf,uri->ttl.s);
+       uri->user_param.s=translate_pointer(new_buf,org_buf,uri->user_param.s);
+       uri->maddr.s=translate_pointer(new_buf,org_buf,uri->maddr.s);
+       uri->method.s=translate_pointer(new_buf,org_buf,uri->method.s);
+       uri->lr.s=translate_pointer(new_buf,org_buf,uri->lr.s);
+       uri->r2.s=translate_pointer(new_buf,org_buf,uri->r2.s);
+       /* values */
+       uri->transport_val.s
+               =translate_pointer(new_buf,org_buf,uri->transport_val.s);
+       uri->ttl_val.s=translate_pointer(new_buf,org_buf,uri->ttl_val.s);
+       uri->user_param_val.s
+               =translate_pointer(new_buf,org_buf,uri->user_param_val.s);
+       uri->maddr_val.s=translate_pointer(new_buf,org_buf,uri->maddr_val.s);
+       uri->method_val.s=translate_pointer(new_buf,org_buf,uri->method_val.s);
+       uri->lr_val.s=translate_pointer(new_buf,org_buf,uri->lr_val.s);
+       uri->r2_val.s=translate_pointer(new_buf,org_buf,uri->r2_val.s);
+}
+
+
+static inline struct auth_body* auth_body_cloner(char* new_buf, char *org_buf, struct auth_body *auth, char **p)
+{
+       struct auth_body* new_auth;
+
+       new_auth = (struct auth_body*)(*p);
+       memcpy(new_auth , auth , sizeof(struct auth_body));
+       (*p) += ROUND4(sizeof(struct auth_body));
+
+       /* authorized field must be cloned elsewhere */
+       new_auth->digest.username.whole.s =
+               translate_pointer(new_buf, org_buf, auth->digest.username.whole.s);
+       new_auth->digest.username.user.s =
+               translate_pointer(new_buf, org_buf, auth->digest.username.user.s);
+       new_auth->digest.username.domain.s =
+               translate_pointer(new_buf, org_buf, auth->digest.username.domain.s);
+       new_auth->digest.realm.s =
+               translate_pointer(new_buf, org_buf, auth->digest.realm.s);
+       new_auth->digest.nonce.s =
+               translate_pointer(new_buf, org_buf, auth->digest.nonce.s);
+       new_auth->digest.uri.s =
+               translate_pointer(new_buf, org_buf, auth->digest.uri.s);
+       new_auth->digest.response.s =
+               translate_pointer(new_buf, org_buf, auth->digest.response.s);
+       new_auth->digest.alg.alg_str.s =
+               translate_pointer(new_buf, org_buf, auth->digest.alg.alg_str.s);
+       new_auth->digest.cnonce.s =
+               translate_pointer(new_buf, org_buf, auth->digest.cnonce.s);
+       new_auth->digest.opaque.s =
+               translate_pointer(new_buf, org_buf, auth->digest.opaque.s);
+       new_auth->digest.qop.qop_str.s =
+               translate_pointer(new_buf, org_buf, auth->digest.qop.qop_str.s);
+       new_auth->digest.nc.s =
+               translate_pointer(new_buf, org_buf, auth->digest.nc.s);
+       return new_auth;
+}
+
+
+static inline int clone_authorized_hooks(struct sip_msg* new,
+                                        struct sip_msg* old)
+{
+       struct hdr_field* ptr, *new_ptr, *hook1, *hook2;
+       char stop = 0;
+
+       get_authorized_cred(old->authorization, &hook1);
+       if (!hook1) stop = 1;
+
+       get_authorized_cred(old->proxy_auth, &hook2);
+       if (!hook2) stop |= 2;
+
+       ptr = old->headers;
+       new_ptr = new->headers;
+
+       while(ptr) {
+               if (ptr == hook1) {
+                       if (!new->authorization || !new->authorization->parsed) {
+                               LOG(L_CRIT, "BUG: Error in message cloner (authorization)\n");
+                               return -1;
+                       }
+                       ((struct auth_body*)new->authorization->parsed)->authorized =
+                               new_ptr;
+                       stop |= 1;
+               }
+
+               if (ptr == hook2) {
+                       if (!new->proxy_auth || !new->proxy_auth->parsed) {
+                               LOG(L_CRIT, "BUG: Error in message cloner (proxy_auth)\n");
+                               return -1;
+                       }
+                       ((struct auth_body*)new->proxy_auth->parsed)->authorized =
+                               new_ptr;
+                       stop |= 2;
+               }
+
+               if (stop == 3) break;
+
+               ptr = ptr->next;
+               new_ptr = new_ptr->next;
+       }
+       return 0;
+}
+
+
+#define AUTH_BODY_SIZE sizeof(struct auth_body)
+
+#define HOOK_SET(hook) (new_msg->hook != org_msg->hook)
+
+
+
+/** Creates a shm clone for a sip_msg.
+ * org_msg is cloned along with most of its headers and lumps into one
+ * shm memory block (so that a shm_free() on the result will free everything)
+ * @return shm malloced sip_msg on success, 0 on error
+ * Warning: Cloner does not clone all hdr_field headers (From, To, etc.).
+ */
+struct sip_msg*  sip_msg_shm_clone( struct sip_msg *org_msg, int *sip_msg_len,
+                                                                       int clone_lumps)
+{
+       unsigned int      len;
+       struct hdr_field  *hdr,*new_hdr,*last_hdr;
+       struct via_body   *via;
+       struct via_param  *prm;
+       struct to_param   *to_prm,*new_to_prm;
+       struct sip_msg    *new_msg;
+       char              *p;
+
+       /*computing the length of entire sip_msg structure*/
+       len = ROUND4(sizeof( struct sip_msg ));
+       /*we will keep only the original msg +ZT */
+       len += ROUND4(org_msg->len + 1);
+       /*the new uri (if any)*/
+       if (org_msg->new_uri.s && org_msg->new_uri.len)
+               len+= ROUND4(org_msg->new_uri.len);
+       /*the dst uri (if any)*/
+       if (org_msg->dst_uri.s && org_msg->dst_uri.len)
+               len+= ROUND4(org_msg->dst_uri.len);
+       /*all the headers*/
+       for( hdr=org_msg->headers ; hdr ; hdr=hdr->next )
+       {
+               /*size of header struct*/
+               len += ROUND4(sizeof( struct hdr_field));
+               switch (hdr->type) {
+                            /* Safely ignore auxiliary header types */
+               case HDR_ERROR_T:
+               case HDR_OTHER_T:
+               case HDR_VIA2_T:
+               case HDR_EOH_T:
+                       break;
+
+               case HDR_VIA_T:
+                       for (via=(struct via_body*)hdr->parsed;via;via=via->next) {
+                               len+=ROUND4(sizeof(struct via_body));
+                                    /*via param*/
+                               for(prm=via->param_lst;prm;prm=prm->next)
+                                       len+=ROUND4(sizeof(struct via_param ));
+                       }
+                       break;
+
+               case HDR_TO_T:
+               case HDR_FROM_T:
+                            /* From header might be unparsed */
+                       if (hdr->parsed) {
+                               len+=ROUND4(sizeof(struct to_body));
+                                    /*to param*/
+                               to_prm = ((struct to_body*)(hdr->parsed))->param_lst;
+                               for(;to_prm;to_prm=to_prm->next)
+                                       len+=ROUND4(sizeof(struct to_param ));
+                       }
+                       break;
+
+               case HDR_CSEQ_T:
+                       len+=ROUND4(sizeof(struct cseq_body));
+                       break;
+
+
+               case HDR_AUTHORIZATION_T:
+               case HDR_PROXYAUTH_T:
+                       if (hdr->parsed) {
+                               len += ROUND4(AUTH_BODY_SIZE);
+                       }
+                       break;
+
+               case HDR_CALLID_T:
+               case HDR_CONTACT_T:
+               case HDR_MAXFORWARDS_T:
+               case HDR_ROUTE_T:
+               case HDR_RECORDROUTE_T:
+               case HDR_CONTENTTYPE_T:
+               case HDR_CONTENTLENGTH_T:
+               case HDR_RETRY_AFTER_T:
+               case HDR_EXPIRES_T:
+               case HDR_SUPPORTED_T:
+               case HDR_REQUIRE_T:
+               case HDR_PROXYREQUIRE_T:
+               case HDR_UNSUPPORTED_T:
+               case HDR_ALLOW_T:
+               case HDR_EVENT_T:
+               case HDR_ACCEPT_T:
+               case HDR_ACCEPTLANGUAGE_T:
+               case HDR_ORGANIZATION_T:
+               case HDR_PRIORITY_T:
+               case HDR_SUBJECT_T:
+               case HDR_USERAGENT_T:
+               case HDR_SERVER_T:
+               case HDR_ACCEPTDISPOSITION_T:
+               case HDR_CONTENTDISPOSITION_T:
+               case HDR_DIVERSION_T:
+               case HDR_RPID_T:
+               case HDR_REFER_TO_T:
+               case HDR_SIPIFMATCH_T:
+               case HDR_SESSIONEXPIRES_T:
+               case HDR_MIN_SE_T:
+               case HDR_SUBSCRIPTION_STATE_T:
+               case HDR_ACCEPTCONTACT_T:
+               case HDR_ALLOWEVENTS_T:
+               case HDR_CONTENTENCODING_T:
+               case HDR_REFERREDBY_T:
+               case HDR_REJECTCONTACT_T:
+               case HDR_REQUESTDISPOSITION_T:
+               case HDR_WWW_AUTHENTICATE_T:
+               case HDR_PROXY_AUTHENTICATE_T:
+               case HDR_DATE_T:
+               case HDR_IDENTITY_T:
+               case HDR_IDENTITY_INFO_T:
+               case HDR_PPI_T:
+               case HDR_PAI_T:
+               case HDR_PATH_T:
+               case HDR_PRIVACY_T:
+                       /* we ignore them for now even if they have something parsed*/
+                       break;
+               }/*switch*/
+       }/*for all headers*/
+       
+       if (clone_lumps) {
+               /* calculate the length of the data and reply lump structures */
+               LUMP_LIST_LEN(len, org_msg->add_rm);
+               LUMP_LIST_LEN(len, org_msg->body_lumps);
+               RPL_LUMP_LIST_LEN(len, org_msg->reply_lump);
+       }
+       
+       p=(char *)shm_malloc(len);
+       if (!p)
+       {
+               LOG(L_ERR , "ERROR: sip_msg_cloner: cannot allocate memory\n" );
+               return 0;
+       }
+       if (sip_msg_len)
+               *sip_msg_len = len;
+
+       /* filling up the new structure */
+       new_msg = (struct sip_msg*)p;
+       /* sip msg structure */
+       memcpy( new_msg , org_msg , sizeof(struct sip_msg) );
+
+       new_msg->msg_flags |= FL_SHM_CLONE;
+       p += ROUND4(sizeof(struct sip_msg));
+       new_msg->body = 0;
+       new_msg->add_rm = 0;
+       new_msg->body_lumps = 0;
+       new_msg->reply_lump = 0;
+       /* new_uri */
+       if (org_msg->new_uri.s && org_msg->new_uri.len)
+       {
+               new_msg->new_uri.s = p;
+               memcpy( p , org_msg->new_uri.s , org_msg->new_uri.len);
+               p += ROUND4(org_msg->new_uri.len);
+       }
+       /* dst_uri */
+       if (org_msg->dst_uri.s && org_msg->dst_uri.len)
+       {
+               new_msg->dst_uri.s = p;
+               memcpy( p , org_msg->dst_uri.s , org_msg->dst_uri.len);
+               p += ROUND4(org_msg->dst_uri.len);
+       }
+       /* message buffers(org and scratch pad) */
+       memcpy( p , org_msg->buf, org_msg->len);
+       /* ZT to be safer */
+       *(p+org_msg->len)=0;
+       new_msg->buf = p;
+       p += ROUND4(new_msg->len+1);
+       /* unparsed and eoh pointer */
+       new_msg->unparsed = translate_pointer(new_msg->buf ,org_msg->buf,
+               org_msg->unparsed );
+       new_msg->eoh = translate_pointer(new_msg->buf,org_msg->buf,org_msg->eoh);
+       /* first line, updating the pointers*/
+       if ( org_msg->first_line.type==SIP_REQUEST )
+       {
+               new_msg->first_line.u.request.method.s =
+                       translate_pointer( new_msg->buf , org_msg->buf ,
+                       org_msg->first_line.u.request.method.s );
+               new_msg->first_line.u.request.uri.s =
+                       translate_pointer( new_msg->buf , org_msg->buf ,
+                       org_msg->first_line.u.request.uri.s );
+               new_msg->first_line.u.request.version.s =
+                       translate_pointer( new_msg->buf , org_msg->buf ,
+                       org_msg->first_line.u.request.version.s );
+               uri_trans(new_msg->buf, org_msg->buf, &new_msg->parsed_orig_ruri);
+               if (org_msg->new_uri.s && org_msg->new_uri.len)
+                       uri_trans(new_msg->new_uri.s, org_msg->new_uri.s,
+                                                                                       &new_msg->parsed_uri);
+               else
+                       uri_trans(new_msg->buf, org_msg->buf, &new_msg->parsed_uri);
+       }
+       else if ( org_msg->first_line.type==SIP_REPLY )
+       {
+               new_msg->first_line.u.reply.version.s =
+                       translate_pointer( new_msg->buf , org_msg->buf ,
+                       org_msg->first_line.u.reply.version.s );
+               new_msg->first_line.u.reply.status.s =
+                       translate_pointer( new_msg->buf , org_msg->buf ,
+                       org_msg->first_line.u.reply.status.s );
+               new_msg->first_line.u.reply.reason.s =
+                       translate_pointer( new_msg->buf , org_msg->buf ,
+                       org_msg->first_line.u.reply.reason.s );
+       }
+
+       /*headers list*/
+       new_msg->via1=0;
+       new_msg->via2=0;
+
+       for( hdr=org_msg->headers,last_hdr=0 ; hdr ; hdr=hdr->next )
+       {
+               new_hdr = (struct hdr_field*)p;
+               memcpy(new_hdr, hdr, sizeof(struct hdr_field) );
+               p += ROUND4(sizeof( struct hdr_field));
+               new_hdr->name.s = translate_pointer(new_msg->buf, org_msg->buf,
+                       hdr->name.s);
+               new_hdr->body.s = translate_pointer(new_msg->buf, org_msg->buf,
+                       hdr->body.s);
+               /* by default, we assume we don't understand this header in TM
+                  and better set it to zero; if we do, we will set a specific
+                  value in the following switch statement
+               */
+               new_hdr->parsed=0;
+
+               switch (hdr->type)
+               {
+                            /* Ignore auxiliary header types */
+               case HDR_ERROR_T:
+               case HDR_OTHER_T:
+               case HDR_VIA2_T:
+               case HDR_EOH_T:
+               case HDR_ACCEPTCONTACT_T:
+               case HDR_ALLOWEVENTS_T:
+               case HDR_CONTENTENCODING_T:
+               case HDR_REFERREDBY_T:
+               case HDR_REJECTCONTACT_T:
+               case HDR_REQUESTDISPOSITION_T:
+               case HDR_WWW_AUTHENTICATE_T:
+               case HDR_PROXY_AUTHENTICATE_T:
+               case HDR_DATE_T:
+               case HDR_IDENTITY_T:
+               case HDR_IDENTITY_INFO_T:
+               case HDR_RETRY_AFTER_T:
+                       break;
+
+               case HDR_VIA_T:
+                       if ( !new_msg->via1 ) {
+                               new_msg->h_via1 = new_hdr;
+                               new_msg->via1 = via_body_cloner(new_msg->buf,
+                                                               org_msg->buf, (struct via_body*)hdr->parsed, &p);
+                               new_hdr->parsed  = (void*)new_msg->via1;
+                               if ( new_msg->via1->next ) {
+                                       new_msg->via2 = new_msg->via1->next;
+                               }
+                       } else if ( !new_msg->via2 && new_msg->via1 ) {
+                               new_msg->h_via2 = new_hdr;
+                               if ( new_msg->via1->next ) {
+                                       new_hdr->parsed = (void*)new_msg->via1->next;
+                               } else {
+                                       new_msg->via2 = via_body_cloner( new_msg->buf,
+                                                                        org_msg->buf, (struct via_body*)hdr->parsed, &p);
+                                       new_hdr->parsed  = (void*)new_msg->via2;
+                               }
+                       } else if ( new_msg->via2 && new_msg->via1 ) {
+                               new_hdr->parsed = via_body_cloner( new_msg->buf , org_msg->buf ,
+                                                                  (struct via_body*)hdr->parsed , &p);
+                       }
+                       break;
+               case HDR_CSEQ_T:
+                       new_hdr->parsed = p;
+                       p +=ROUND4(sizeof(struct cseq_body));
+                       memcpy(new_hdr->parsed, hdr->parsed, sizeof(struct cseq_body));
+                       ((struct cseq_body*)new_hdr->parsed)->number.s =
+                               translate_pointer(new_msg->buf ,org_msg->buf,
+                                                 ((struct cseq_body*)hdr->parsed)->number.s );
+                       ((struct cseq_body*)new_hdr->parsed)->method.s =
+                               translate_pointer(new_msg->buf ,org_msg->buf,
+                                                 ((struct cseq_body*)hdr->parsed)->method.s );
+                       if (!HOOK_SET(cseq)) new_msg->cseq = new_hdr;
+                       break;
+               case HDR_TO_T:
+               case HDR_FROM_T:
+                       if (hdr->type == HDR_TO_T) {
+                               if (!HOOK_SET(to)) new_msg->to = new_hdr;
+                       } else {
+                               if (!HOOK_SET(from)) new_msg->from = new_hdr;
+                       }
+                            /* From header might be unparsed */
+                       if (!hdr->parsed) break;
+                       new_hdr->parsed = p;
+                       p +=ROUND4(sizeof(struct to_body));
+                       memcpy(new_hdr->parsed, hdr->parsed, sizeof(struct to_body));
+                       ((struct to_body*)new_hdr->parsed)->body.s =
+                               translate_pointer( new_msg->buf , org_msg->buf ,
+                                                  ((struct to_body*)hdr->parsed)->body.s );
+                       ((struct to_body*)new_hdr->parsed)->display.s =
+                               translate_pointer( new_msg->buf, org_msg->buf,
+                                                  ((struct to_body*)hdr->parsed)->display.s);
+                       ((struct to_body*)new_hdr->parsed)->uri.s =
+                               translate_pointer( new_msg->buf , org_msg->buf ,
+                                                  ((struct to_body*)hdr->parsed)->uri.s );
+                       if ( ((struct to_body*)hdr->parsed)->tag_value.s )
+                               ((struct to_body*)new_hdr->parsed)->tag_value.s =
+                                       translate_pointer( new_msg->buf , org_msg->buf ,
+                                                          ((struct to_body*)hdr->parsed)->tag_value.s );
+                       if ( (((struct to_body*)new_hdr->parsed)->parsed_uri.user.s)
+                               || (((struct to_body*)new_hdr->parsed)->parsed_uri.host.s) )
+                                       uri_trans(new_msg->buf, org_msg->buf,
+                                                       &((struct to_body*)new_hdr->parsed)->parsed_uri);
+                            /*to params*/
+                       to_prm = ((struct to_body*)(hdr->parsed))->param_lst;
+                       for(;to_prm;to_prm=to_prm->next) {
+                                    /*alloc*/
+                               new_to_prm = (struct to_param*)p;
+                               p +=ROUND4(sizeof(struct to_param ));
+                                    /*coping*/
+                               memcpy( new_to_prm, to_prm, sizeof(struct to_param ));
+                               ((struct to_body*)new_hdr->parsed)->param_lst = 0;
+                               new_to_prm->name.s = translate_pointer( new_msg->buf,
+                                                                       org_msg->buf , to_prm->name.s );
+                               new_to_prm->value.s = translate_pointer( new_msg->buf,
+                                                                        org_msg->buf , to_prm->value.s );
+                                    /*linking*/
+                               if ( !((struct to_body*)new_hdr->parsed)->param_lst )
+                                       ((struct to_body*)new_hdr->parsed)->param_lst
+                                               = new_to_prm;
+                               else
+                                       ((struct to_body*)new_hdr->parsed)->last_param->next
+                                               = new_to_prm;
+                               ((struct to_body*)new_hdr->parsed)->last_param
+                                       = new_to_prm;
+                       }
+                       break;
+               case HDR_CALLID_T:
+                       if (!HOOK_SET(callid)) {
+                               new_msg->callid = new_hdr;
+                       }
+                       break;
+               case HDR_CONTACT_T:
+                       if (!HOOK_SET(contact)) {
+                               new_msg->contact = new_hdr;
+                       }
+                       break;
+               case HDR_MAXFORWARDS_T:
+                       if (!HOOK_SET(maxforwards)) {
+                               new_msg->maxforwards = new_hdr;
+                       }
+                       break;
+               case HDR_ROUTE_T:
+                       if (!HOOK_SET(route)) {
+                               new_msg->route = new_hdr;
+                       }
+                       break;
+               case HDR_RECORDROUTE_T:
+                       if (!HOOK_SET(record_route)) {
+                               new_msg->record_route = new_hdr;
+                       }
+                       break;
+               case HDR_CONTENTTYPE_T:
+                       if (!HOOK_SET(content_type)) {
+                               new_msg->content_type = new_hdr;
+                               new_msg->content_type->parsed = hdr->parsed;
+                       }
+                       break;
+               case HDR_CONTENTLENGTH_T:
+                       if (!HOOK_SET(content_length)) {
+                               new_msg->content_length = new_hdr;
+                               new_msg->content_length->parsed = hdr->parsed;
+                       }
+                       break;
+               case HDR_AUTHORIZATION_T:
+                       if (!HOOK_SET(authorization)) {
+                               new_msg->authorization = new_hdr;
+                       }
+                       if (hdr->parsed) {
+                               new_hdr->parsed = auth_body_cloner(new_msg->buf ,
+                                                                  org_msg->buf , (struct auth_body*)hdr->parsed , &p);
+                       }
+                       break;
+               case HDR_EXPIRES_T:
+                       if (!HOOK_SET(expires)) {
+                               new_msg->expires = new_hdr;
+                       }
+                       break;
+               case HDR_PROXYAUTH_T:
+                       if (!HOOK_SET(proxy_auth)) {
+                               new_msg->proxy_auth = new_hdr;
+                       }
+                       if (hdr->parsed) {
+                               new_hdr->parsed = auth_body_cloner(new_msg->buf ,
+                                                                  org_msg->buf , (struct auth_body*)hdr->parsed , &p);
+                       }
+                       break;
+               case HDR_SUPPORTED_T:
+                       if (!HOOK_SET(supported)) {
+                               new_msg->supported = new_hdr;
+                       }
+                       break;
+               case HDR_REQUIRE_T:
+                       if (!HOOK_SET(require)) {
+                               new_msg->require = new_hdr;
+                       }
+                       break;
+               case HDR_PROXYREQUIRE_T:
+                       if (!HOOK_SET(proxy_require)) {
+                               new_msg->proxy_require = new_hdr;
+                       }
+                       break;
+               case HDR_UNSUPPORTED_T:
+                       if (!HOOK_SET(unsupported)) {
+                               new_msg->unsupported = new_hdr;
+                       }
+                       break;
+               case HDR_ALLOW_T:
+                       if (!HOOK_SET(allow)) {
+                               new_msg->allow = new_hdr;
+                       }
+                       break;
+               case HDR_EVENT_T:
+                       if (!HOOK_SET(event)) {
+                               new_msg->event = new_hdr;
+                       }
+                       break;
+               case HDR_ACCEPT_T:
+                       if (!HOOK_SET(accept)) {
+                               new_msg->accept = new_hdr;
+                       }
+                       break;
+               case HDR_ACCEPTLANGUAGE_T:
+                       if (!HOOK_SET(accept_language)) {
+                               new_msg->accept_language = new_hdr;
+                       }
+                       break;
+               case HDR_ORGANIZATION_T:
+                       if (!HOOK_SET(organization)) {
+                               new_msg->organization = new_hdr;
+                       }
+                       break;
+               case HDR_PRIORITY_T:
+                       if (!HOOK_SET(priority)) {
+                               new_msg->priority = new_hdr;
+                       }
+                       break;
+               case HDR_SUBJECT_T:
+                       if (!HOOK_SET(subject)) {
+                               new_msg->subject = new_hdr;
+                       }
+                       break;
+               case HDR_USERAGENT_T:
+                       if (!HOOK_SET(user_agent)) {
+                               new_msg->user_agent = new_hdr;
+                       }
+                       break;
+               case HDR_SERVER_T:
+                       if (!HOOK_SET(server)) {
+                               new_msg->server = new_hdr;
+                       }
+                       break;
+               case HDR_ACCEPTDISPOSITION_T:
+                       if (!HOOK_SET(accept_disposition)) {
+                               new_msg->accept_disposition = new_hdr;
+                       }
+                       break;
+               case HDR_CONTENTDISPOSITION_T:
+                       if (!HOOK_SET(content_disposition)) {
+                               new_msg->content_disposition = new_hdr;
+                       }
+                       break;
+               case HDR_DIVERSION_T:
+                       if (!HOOK_SET(diversion)) {
+                               new_msg->diversion = new_hdr;
+                       }
+                       break;
+               case HDR_RPID_T:
+                       if (!HOOK_SET(rpid)) {
+                               new_msg->rpid = new_hdr;
+                       }
+                       break;
+               case HDR_REFER_TO_T:
+                       if (!HOOK_SET(refer_to)) {
+                               new_msg->refer_to = new_hdr;
+                       }
+                       break;
+               case HDR_SESSIONEXPIRES_T:
+                       if (!HOOK_SET(session_expires)) {
+                               new_msg->session_expires = new_hdr;
+                       }
+                       break;
+               case HDR_MIN_SE_T:
+                       if (!HOOK_SET(min_se)) {
+                               new_msg->min_se = new_hdr;
+                       }
+                       break;
+               case HDR_SUBSCRIPTION_STATE_T:
+                       if (!HOOK_SET(subscription_state)) {
+                               new_msg->subscription_state = new_hdr;
+                       }
+                       break;
+               case HDR_SIPIFMATCH_T:
+                       if (!HOOK_SET(sipifmatch)) {
+                               new_msg->sipifmatch = new_hdr;
+                       }
+                       break;
+               case HDR_PPI_T:
+                       if (!HOOK_SET(ppi)) {
+                               new_msg->ppi = new_hdr;
+                       }
+                       break;
+               case HDR_PAI_T:
+                       if (!HOOK_SET(pai)) {
+                               new_msg->pai = new_hdr;
+                       }
+                       break;
+               case HDR_PATH_T:
+                       if (!HOOK_SET(path)) {
+                               new_msg->path = new_hdr;
+                       }
+                       break;
+               case HDR_PRIVACY_T:
+                       if (!HOOK_SET(privacy)) {
+                               new_msg->privacy = new_hdr;
+                       }
+                       break;
+               }/*switch*/
+
+               if ( last_hdr )
+               {
+                       last_hdr->next = new_hdr;
+                       last_hdr=last_hdr->next;
+               }
+               else
+               {
+                       last_hdr=new_hdr;
+                       new_msg->headers =new_hdr;
+               }
+               last_hdr->next = 0;
+               new_msg->last_header = last_hdr;
+       }
+       if (clone_lumps) {
+               /*cloning data and reply lump structures*/
+               CLONE_LUMP_LIST(&(new_msg->add_rm), org_msg->add_rm, p);
+               CLONE_LUMP_LIST(&(new_msg->body_lumps), org_msg->body_lumps, p);
+               CLONE_RPL_LUMP_LIST(&(new_msg->reply_lump), org_msg->reply_lump, p);
+       }
+       
+       if (clone_authorized_hooks(new_msg, org_msg) < 0) {
+               shm_free(new_msg);
+               return 0;
+       }
+
+       return new_msg;
+}
+
+
+
+/** clones the data and reply lumps from pkg_msg to shm_msg.
+ * A new memory block is allocated for the lumps (the lumps will point
+ * into it).
+ * Note: the new memory block is linked to add_rm if
+ * at least one data lump is set, else it is linked to body_lumps
+ * if at least one body lump is set, otherwise it is linked to
+ * shm_msg->reply_lump.
+ * @param pkg_msg - sip msg whoes lumps will be cloned
+ * @param add_rm - result parameter, filled with the list of cloned
+ *                 add_rm lumps (corresp. to msg->add_rm)
+ * @param body_lumps - result parameter, filled with the list of cloned
+ *                 body lumps (corresp. to msg->body_lumps)
+ * @param reply_lump - result parameter, filled with the list of cloned
+ *                 reply lumps (corresp. to msg->reply_lump)
+ * @return 0 or 1 on success: 0 - lumps cloned), 1 - nothing to do and 
+ *         -1 on error
+ */
+int msg_lump_cloner(struct sip_msg *pkg_msg,
+                                       struct lump** add_rm,
+                                       struct lump** body_lumps,
+                                       struct lump_rpl** reply_lump)
+{
+       unsigned int    len;
+       char            *p;
+
+       *add_rm = *body_lumps = 0;
+       *reply_lump = 0;
+
+       /* calculate the length of the lumps */
+       len = 0;
+       LUMP_LIST_LEN(len, pkg_msg->add_rm);
+       LUMP_LIST_LEN(len, pkg_msg->body_lumps);
+       RPL_LUMP_LIST_LEN(len, pkg_msg->reply_lump);
+
+       if (!len)
+               return 1; /* nothing to do */
+
+       p=(char *)shm_malloc(len);
+       if (!p)
+       {
+               LOG(L_ERR, "ERROR: msg_lump_cloner: cannot allocate memory\n" );
+               return -1;
+       }
+
+       /* clone the lumps */
+       CLONE_LUMP_LIST(add_rm, pkg_msg->add_rm, p);
+       CLONE_LUMP_LIST(body_lumps, pkg_msg->body_lumps, p);
+       CLONE_RPL_LUMP_LIST(reply_lump, pkg_msg->reply_lump, p);
+
+       return 0;
+}
+
+
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
diff --git a/sip_msg_clone.h b/sip_msg_clone.h
new file mode 100644 (file)
index 0000000..e823af6
--- /dev/null
@@ -0,0 +1,44 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2009 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * /home/andrei/sr.git/sip_msg_clone.h
+ */
+/*
+ * History:
+ * --------
+ *  2009-07-22  initial version (andrei)
+*/
+
+#ifndef __sip_msg_clone_h
+#define __sip_msg_clone_h
+
+#include "parser/msg_parser.h"
+
+struct sip_msg*  sip_msg_shm_clone(    struct sip_msg *org_msg,
+                                                                       int *sip_msg_len,
+                                                                       int clone_lumps);
+
+int msg_lump_cloner(struct sip_msg *pkg_msg,
+                                       struct lump** add_rm,
+                                       struct lump** body_lumps,
+                                       struct lump_rpl** reply_lump);
+
+
+#endif /*__sip_msg_clone_h*/
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */