Merged revisions 56740 via svnmerge from
[asterisk/asterisk.git] / channels / iax2-parser.c
index 1da3c4d..5e76dd8 100644 (file)
@@ -39,6 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/frame.h"
 #include "asterisk/utils.h"
 #include "asterisk/unaligned.h"
+#include "asterisk/config.h"
 #include "asterisk/lock.h"
 #include "asterisk/threadstorage.h"
 
@@ -50,6 +51,7 @@ static int frames = 0;
 static int iframes = 0;
 static int oframes = 0;
 
+#if !defined(LOW_MEMORY)
 static void frame_cache_cleanup(void *data);
 
 /*! \brief A per-thread cache of iax_frame structures */
@@ -58,6 +60,7 @@ AST_THREADSTORAGE_CUSTOM(frame_cache, NULL, frame_cache_cleanup);
 /*! \brief This is just so iax_frames, a list head struct for holding a list of
  *  iax_frame structures, is defined. */
 AST_LIST_HEAD_NOLOCK(iax_frames, iax_frame);
+#endif
 
 static void internaloutput(const char *str)
 {
@@ -260,6 +263,7 @@ static struct iax2_ie {
        { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
        { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
        { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
+       { IAX_IE_VARIABLE, "VARIABLE", dump_string },
 };
 
 static struct iax2_ie prov_ies[] = {
@@ -611,7 +615,8 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
        /* Parse data into information elements */
        int len;
        int ie;
-       char tmp[256];
+       char tmp[256], *tmp2;
+       struct ast_variable *var, *var2, *prev;
        memset(ies, 0, (int)sizeof(struct iax_ies));
        ies->msgcount = -1;
        ies->firmwarever = -1;
@@ -896,6 +901,35 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
                                ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
                        }
                        break;
+               case IAX_IE_VARIABLE:
+                       ast_copy_string(tmp, (char *)data + 2, len + 1);
+                       tmp2 = strchr(tmp, '=');
+                       if (tmp2)
+                               *tmp2++ = '\0';
+                       else
+                               tmp2 = "";
+                       /* Existing variable or new variable? */
+                       for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) {
+                               if (strcmp(tmp, var2->name) == 0) {
+                                       int len = strlen(var2->value) + strlen(tmp2) + 1;
+                                       char *tmp3 = alloca(len);
+                                       snprintf(tmp3, len, "%s%s", var2->value, tmp2);
+                                       var = ast_variable_new(tmp, tmp3);
+                                       var->next = var2->next;
+                                       if (prev)
+                                               prev->next = var;
+                                       else
+                                               ies->vars = var;
+                                       free(var2);
+                                       break;
+                               }
+                       }
+                       if (!var2) {
+                               var = ast_variable_new(tmp, tmp2);
+                               var->next = ies->vars;
+                               ies->vars = var;
+                       }
+                       break;
                default:
                        snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
                        outputf(tmp);
@@ -937,9 +971,11 @@ void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
        }
 }
 
-struct iax_frame *iax_frame_new(int direction, int datalen)
+struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
 {
        struct iax_frame *fr = NULL;
+
+#if !defined(LOW_MEMORY)
        struct iax_frames *iax_frames;
 
        /* Attempt to get a frame from this thread's cache */
@@ -955,27 +991,37 @@ struct iax_frame *iax_frame_new(int direction, int datalen)
                }
                AST_LIST_TRAVERSE_SAFE_END
        }
-
        if (!fr) {
                if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen)))
                        return NULL;
                fr->mallocd_datalen = datalen;
        }
+#else
+       if (!(fr = ast_calloc(1, sizeof(*fr) + datalen)))
+               return NULL;
+       fr->mallocd_datalen = datalen;
+#endif
+
 
        fr->direction = direction;
        fr->retrans = -1;
+       fr->cacheable = cacheable;
        
        if (fr->direction == DIRECTION_INGRESS)
                ast_atomic_fetchadd_int(&iframes, 1);
        else
                ast_atomic_fetchadd_int(&oframes, 1);
        
+       ast_atomic_fetchadd_int(&frames, 1);
+
        return fr;
 }
 
 void iax_frame_free(struct iax_frame *fr)
 {
+#if !defined(LOW_MEMORY)
        struct iax_frames *iax_frames;
+#endif
 
        /* Note: does not remove from scheduler! */
        if (fr->direction == DIRECTION_INGRESS)
@@ -986,17 +1032,22 @@ void iax_frame_free(struct iax_frame *fr)
                errorf("Attempt to double free frame detected\n");
                return;
        }
-       fr->direction = 0;
        ast_atomic_fetchadd_int(&frames, -1);
 
-       if (!(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
+#if !defined(LOW_MEMORY)
+       if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
                free(fr);
                return;
        }
 
+       fr->direction = 0;
        AST_LIST_INSERT_HEAD(iax_frames, fr, list);
+#else
+       free(fr);
+#endif
 }
 
+#if !defined(LOW_MEMORY)
 static void frame_cache_cleanup(void *data)
 {
        struct iax_frames *frames = data;
@@ -1007,6 +1058,7 @@ static void frame_cache_cleanup(void *data)
 
        free(frames);
 }
+#endif
 
 int iax_get_frames(void) { return frames; }
 int iax_get_iframes(void) { return iframes; }