[Pkg-voip-commits] r5826 - in /asterisk/branches/etch/debian: changelog patches/00list patches/AST-2008-008.dpatch patches/security-IAX2-performance.dpatch
paravoid at alioth.debian.org
paravoid at alioth.debian.org
Thu Jun 5 01:52:37 UTC 2008
Author: paravoid
Date: Thu Jun 5 01:52:37 2008
New Revision: 5826
URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=5826
Log:
Fix chan_iax2 performance regression introduced by upstream in the
previous security update (Closes: #482997).
Added:
asterisk/branches/etch/debian/patches/security-IAX2-performance.dpatch
Modified:
asterisk/branches/etch/debian/changelog
asterisk/branches/etch/debian/patches/00list
asterisk/branches/etch/debian/patches/AST-2008-008.dpatch
Modified: asterisk/branches/etch/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/etch/debian/changelog?rev=5826&op=diff
==============================================================================
--- asterisk/branches/etch/debian/changelog (original)
+++ asterisk/branches/etch/debian/changelog Thu Jun 5 01:52:37 2008
@@ -1,9 +1,11 @@
-asterisk (1:1.2.13~dfsg-2etch4) UNRELEASED; urgency=low
+asterisk (1:1.2.13~dfsg-2etch5) stable-security; urgency=high
* Fix a remote crash vulnerability in chan_sip when running in pedantic
mode (AST-2008-008/CVE-2008-2119).
-
- -- Faidon Liambotis <paravoid at debian.org> Thu, 05 Jun 2008 04:06:09 +0300
+ * Fix chan_iax2 performance regression introduced by upstream in the
+ previous security update (Closes: #482997).
+
+ -- Faidon Liambotis <paravoid at debian.org> Thu, 05 Jun 2008 04:36:50 +0300
asterisk (1:1.2.13~dfsg-2etch4) stable-security; urgency=high
Modified: asterisk/branches/etch/debian/patches/00list
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/etch/debian/patches/00list?rev=5826&op=diff
==============================================================================
--- asterisk/branches/etch/debian/patches/00list (original)
+++ asterisk/branches/etch/debian/patches/00list Thu Jun 5 01:52:37 2008
@@ -12,6 +12,7 @@
AST-2008-003.dpatch
AST-2008-004.dpatch
AST-2008-006.dpatch
+security-IAX2-performance.dpatch
AST-2008-008.dpatch
# ukcid probably conflicts with bristuff
ukcid
Modified: asterisk/branches/etch/debian/patches/AST-2008-008.dpatch
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/etch/debian/patches/AST-2008-008.dpatch?rev=5826&op=diff
==============================================================================
--- asterisk/branches/etch/debian/patches/AST-2008-008.dpatch (original)
+++ asterisk/branches/etch/debian/patches/AST-2008-008.dpatch Thu Jun 5 01:52:37 2008
@@ -10,8 +10,8 @@
@DPATCH@
Index: channels/chan_sip.c
===================================================================
---- channels/chan_sip.c (revision 120108)
-+++ channels/chan_sip.c (revision 120109)
+--- a/channels/chan_sip.c (revision 120108)
++++ b/channels/chan_sip.c (revision 120109)
@@ -6831,12 +6831,14 @@
return -1;
}
Added: asterisk/branches/etch/debian/patches/security-IAX2-performance.dpatch
URL: http://svn.debian.org/wsvn/pkg-voip/asterisk/branches/etch/debian/patches/security-IAX2-performance.dpatch?rev=5826&op=file
==============================================================================
--- asterisk/branches/etch/debian/patches/security-IAX2-performance.dpatch (added)
+++ asterisk/branches/etch/debian/patches/security-IAX2-performance.dpatch Thu Jun 5 01:52:37 2008
@@ -1,0 +1,1956 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## security-IAX2-performance.dpatch by Faidon Liambotis <paravoid at debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Fix regressions caused by the chan_iax2 security fix
+## DP: r115296, r115511, r115564, r119008, r119237
+
+ at DPATCH@
+diff -urNad asterisk-1.2.13~dfsg~/Makefile asterisk-1.2.13~dfsg/Makefile
+--- asterisk-1.2.13~dfsg~/Makefile 2006-09-06 23:09:10.000000000 +0300
++++ asterisk-1.2.13~dfsg/Makefile 2008-06-05 04:17:50.000000000 +0300
+@@ -354,7 +354,7 @@
+ astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
+ utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
+ netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
+- cryptostub.o
++ cryptostub.o astobj2.o
+
+ ifeq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/sys/poll.h),)
+ OBJS+= poll.o
+diff -urNad asterisk-1.2.13~dfsg~/astobj2.c asterisk-1.2.13~dfsg/astobj2.c
+--- asterisk-1.2.13~dfsg~/astobj2.c 1970-01-01 02:00:00.000000000 +0200
++++ asterisk-1.2.13~dfsg/astobj2.c 2008-06-05 04:17:50.000000000 +0300
+@@ -0,0 +1,722 @@
++/*
++ * astobj2 - replacement containers for asterisk data structures.
++ *
++ * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2. See the LICENSE file
++ * at the top of the source tree.
++ */
++
++/*
++ * Function implementing astobj2 objects.
++ */
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include <stdlib.h>
++
++#include "asterisk/astobj2.h"
++#include "asterisk/utils.h"
++#include "asterisk/cli.h"
++#include "asterisk/linkedlists.h"
++
++/*!
++ * astobj2 objects are always prepended this data structure,
++ * which contains a lock, a reference counter,
++ * the flags and a pointer to a destructor.
++ * The refcount is used to decide when it is time to
++ * invoke the destructor.
++ * The magic number is used for consistency check.
++ * XXX the lock is not always needed, and its initialization may be
++ * expensive. Consider making it external.
++ */
++struct __priv_data {
++ ast_mutex_t lock;
++ int ref_counter;
++ ao2_destructor_fn destructor_fn;
++ /*! for stats */
++ size_t data_size;
++ /*! magic number. This is used to verify that a pointer passed in is a
++ * valid astobj2 */
++ uint32_t magic;
++};
++
++#define AO2_MAGIC 0xa570b123
++
++/*!
++ * What an astobj2 object looks like: fixed-size private data
++ * followed by variable-size user data.
++ */
++struct astobj2 {
++ struct __priv_data priv_data;
++ void *user_data[0];
++};
++
++#ifdef AST_DEVMODE
++#define AO2_DEBUG 1
++#endif
++
++#ifdef AO2_DEBUG
++struct ao2_stats {
++ volatile int total_objects;
++ volatile int total_mem;
++ volatile int total_containers;
++ volatile int total_refs;
++ volatile int total_locked;
++};
++
++static struct ao2_stats ao2;
++#endif
++
++#ifndef HAVE_BKTR /* backtrace support */
++void ao2_bt(void) {}
++#else
++#include <execinfo.h> /* for backtrace */
++
++void ao2_bt(void)
++{
++ int c, i;
++#define N1 20
++ void *addresses[N1];
++ char **strings;
++
++ c = backtrace(addresses, N1);
++ strings = backtrace_symbols(addresses,c);
++ ast_verbose("backtrace returned: %d\n", c);
++ for(i = 0; i < c; i++) {
++ ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]);
++ }
++ free(strings);
++}
++#endif
++
++/*!
++ * \brief convert from a pointer _p to a user-defined object
++ *
++ * \return the pointer to the astobj2 structure
++ */
++static inline struct astobj2 *INTERNAL_OBJ(void *user_data)
++{
++ struct astobj2 *p;
++
++ if (!user_data) {
++ ast_log(LOG_ERROR, "user_data is NULL\n");
++ return NULL;
++ }
++
++ p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
++ if (AO2_MAGIC != (p->priv_data.magic) ) {
++ ast_log(LOG_ERROR, "bad magic number 0x%x for %p\n", p->priv_data.magic, p);
++ p = NULL;
++ }
++
++ return p;
++}
++
++/*!
++ * \brief convert from a pointer _p to an astobj2 object
++ *
++ * \return the pointer to the user-defined portion.
++ */
++#define EXTERNAL_OBJ(_p) ((_p) == NULL ? NULL : (_p)->user_data)
++
++int ao2_lock(void *user_data)
++{
++ struct astobj2 *p = INTERNAL_OBJ(user_data);
++
++ if (p == NULL)
++ return -1;
++
++#ifdef AO2_DEBUG
++ ast_atomic_fetchadd_int(&ao2.total_locked, 1);
++#endif
++
++ return ast_mutex_lock(&p->priv_data.lock);
++}
++
++int ao2_unlock(void *user_data)
++{
++ struct astobj2 *p = INTERNAL_OBJ(user_data);
++
++ if (p == NULL)
++ return -1;
++
++#ifdef AO2_DEBUG
++ ast_atomic_fetchadd_int(&ao2.total_locked, -1);
++#endif
++
++ return ast_mutex_unlock(&p->priv_data.lock);
++}
++
++/*
++ * The argument is a pointer to the user portion.
++ */
++int ao2_ref(void *user_data, const int delta)
++{
++ int current_value;
++ int ret;
++ struct astobj2 *obj = INTERNAL_OBJ(user_data);
++
++ if (obj == NULL)
++ return -1;
++
++ /* if delta is 0, just return the refcount */
++ if (delta == 0)
++ return (obj->priv_data.ref_counter);
++
++ /* we modify with an atomic operation the reference counter */
++ ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
++ current_value = ret + delta;
++
++#ifdef AO2_DEBUG
++ ast_atomic_fetchadd_int(&ao2.total_refs, delta);
++#endif
++
++ /* this case must never happen */
++ if (current_value < 0)
++ ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data);
++
++ if (current_value <= 0) { /* last reference, destroy the object */
++ if (obj->priv_data.destructor_fn != NULL)
++ obj->priv_data.destructor_fn(user_data);
++
++ ast_mutex_destroy(&obj->priv_data.lock);
++#ifdef AO2_DEBUG
++ ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
++ ast_atomic_fetchadd_int(&ao2.total_objects, -1);
++#endif
++ /* for safety, zero-out the astobj2 header and also the
++ * first word of the user-data, which we make sure is always
++ * allocated. */
++ bzero(obj, sizeof(struct astobj2 *) + sizeof(void *) );
++ free(obj);
++ }
++
++ return ret;
++}
++
++/*
++ * We always alloc at least the size of a void *,
++ * for debugging purposes.
++ */
++void *ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn)
++{
++ /* allocation */
++ struct astobj2 *obj;
++
++ if (data_size < sizeof(void *))
++ data_size = sizeof(void *);
++
++ obj = calloc(1, sizeof(*obj) + data_size);
++
++ if (obj == NULL)
++ return NULL;
++
++ ast_mutex_init(&obj->priv_data.lock);
++ obj->priv_data.magic = AO2_MAGIC;
++ obj->priv_data.data_size = data_size;
++ obj->priv_data.ref_counter = 1;
++ obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */
++
++#ifdef AO2_DEBUG
++ ast_atomic_fetchadd_int(&ao2.total_objects, 1);
++ ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
++ ast_atomic_fetchadd_int(&ao2.total_refs, 1);
++#endif
++
++ /* return a pointer to the user data */
++ return EXTERNAL_OBJ(obj);
++}
++
++/* internal callback to destroy a container. */
++static void container_destruct(void *c);
++
++/* each bucket in the container is a tailq. */
++AST_LIST_HEAD_NOLOCK(bucket, bucket_list);
++
++/*!
++ * A container; stores the hash and callback functions, information on
++ * the size, the hash bucket heads, and a version number, starting at 0
++ * (for a newly created, empty container)
++ * and incremented every time an object is inserted or deleted.
++ * The assumption is that an object is never moved in a container,
++ * but removed and readded with the new number.
++ * The version number is especially useful when implementing iterators.
++ * In fact, we can associate a unique, monotonically increasing number to
++ * each object, which means that, within an iterator, we can store the
++ * version number of the current object, and easily look for the next one,
++ * which is the next one in the list with a higher number.
++ * Since all objects have a version >0, we can use 0 as a marker for
++ * 'we need the first object in the bucket'.
++ *
++ * \todo Linking and unlink objects is typically expensive, as it
++ * involves a malloc() of a small object which is very inefficient.
++ * To optimize this, we allocate larger arrays of bucket_list's
++ * when we run out of them, and then manage our own freelist.
++ * This will be more efficient as we can do the freelist management while
++ * we hold the lock (that we need anyways).
++ */
++struct ao2_container {
++ ao2_hash_fn hash_fn;
++ ao2_callback_fn cmp_fn;
++ int n_buckets;
++ /*! Number of elements in the container */
++ int elements;
++ /*! described above */
++ int version;
++ /*! variable size */
++ struct bucket buckets[0];
++};
++
++/*!
++ * \brief always zero hash function
++ *
++ * it is convenient to have a hash function that always returns 0.
++ * This is basically used when we want to have a container that is
++ * a simple linked list.
++ *
++ * \returns 0
++ */
++static int hash_zero(const void *user_obj, const int flags)
++{
++ return 0;
++}
++
++/*
++ * A container is just an object, after all!
++ */
++struct ao2_container *
++ao2_container_alloc(const uint n_buckets, ao2_hash_fn hash_fn,
++ ao2_callback_fn cmp_fn)
++{
++ /* XXX maybe consistency check on arguments ? */
++ /* compute the container size */
++ size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
++
++ struct ao2_container *c = ao2_alloc(container_size, container_destruct);
++
++ if (!c)
++ return NULL;
++
++ c->version = 1; /* 0 is a reserved value here */
++ c->n_buckets = n_buckets;
++ c->hash_fn = hash_fn ? hash_fn : hash_zero;
++ c->cmp_fn = cmp_fn;
++
++#ifdef AO2_DEBUG
++ ast_atomic_fetchadd_int(&ao2.total_containers, 1);
++#endif
++
++ return c;
++}
++
++/*!
++ * return the number of elements in the container
++ */
++int ao2_container_count(struct ao2_container *c)
++{
++ return c->elements;
++}
++
++/*!
++ * A structure to create a linked list of entries,
++ * used within a bucket.
++ * XXX \todo this should be private to the container code
++ */
++struct bucket_list {
++ AST_LIST_ENTRY(bucket_list) entry;
++ int version;
++ struct astobj2 *astobj; /* pointer to internal data */
++};
++
++/*
++ * link an object to a container
++ */
++void *__ao2_link(struct ao2_container *c, void *user_data, int iax2_hack)
++{
++ int i;
++ /* create a new list entry */
++ struct bucket_list *p;
++ struct astobj2 *obj = INTERNAL_OBJ(user_data);
++
++ if (!obj)
++ return NULL;
++
++ if (INTERNAL_OBJ(c) == NULL)
++ return NULL;
++
++ p = calloc(1, sizeof(*p));
++ if (!p)
++ return NULL;
++
++ i = c->hash_fn(user_data, OBJ_POINTER);
++
++ ao2_lock(c);
++ i %= c->n_buckets;
++ p->astobj = obj;
++ p->version = ast_atomic_fetchadd_int(&c->version, 1);
++ if (iax2_hack)
++ AST_LIST_INSERT_HEAD(&c->buckets[i], p, entry);
++ else
++ AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
++ ast_atomic_fetchadd_int(&c->elements, 1);
++ ao2_ref(user_data, +1);
++ ao2_unlock(c);
++
++ return p;
++}
++
++/*!
++ * \brief another convenience function is a callback that matches on address
++ */
++int ao2_match_by_addr(void *user_data, void *arg, int flags)
++{
++ return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
++}
++
++/*
++ * Unlink an object from the container
++ * and destroy the associated * ao2_bucket_list structure.
++ */
++void *ao2_unlink(struct ao2_container *c, void *user_data)
++{
++ if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
++ return NULL;
++
++ ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
++
++ return NULL;
++}
++
++/*!
++ * \brief special callback that matches all
++ */
++static int cb_true(void *user_data, void *arg, int flags)
++{
++ return CMP_MATCH;
++}
++
++/*!
++ * Browse the container using different stategies accoding the flags.
++ * \return Is a pointer to an object or to a list of object if OBJ_MULTIPLE is
++ * specified.
++ */
++void *ao2_callback(struct ao2_container *c,
++ const enum search_flags flags,
++ ao2_callback_fn cb_fn, void *arg)
++{
++ int i, last; /* search boundaries */
++ void *ret = NULL;
++
++ if (INTERNAL_OBJ(c) == NULL) /* safety check on the argument */
++ return NULL;
++
++ if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
++ ast_log(LOG_WARNING, "multiple data return not implemented yet (flags %x)\n", flags);
++ return NULL;
++ }
++
++ /* override the match function if necessary */
++#if 0
++ /* Removing this slightly changes the meaning of OBJ_POINTER, but makes it
++ * do what I want it to. I'd like to hint to ao2_callback that the arg is
++ * of the same object type, so it can be passed to the hash function.
++ * However, I don't want to imply that this is the object being searched for. */
++ if (flags & OBJ_POINTER)
++ cb_fn = match_by_addr;
++ else
++#endif
++ if (cb_fn == NULL) /* if NULL, match everything */
++ cb_fn = cb_true;
++ /*
++ * XXX this can be optimized.
++ * If we have a hash function and lookup by pointer,
++ * run the hash function. Otherwise, scan the whole container
++ * (this only for the time being. We need to optimize this.)
++ */
++ if ((flags & OBJ_POINTER)) /* we know hash can handle this case */
++ i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets;
++ else /* don't know, let's scan all buckets */
++ i = -1; /* XXX this must be fixed later. */
++
++ /* determine the search boundaries: i..last-1 */
++ if (i < 0) {
++ i = 0;
++ last = c->n_buckets;
++ } else {
++ last = i + 1;
++ }
++
++ ao2_lock(c); /* avoid modifications to the content */
++
++ for (; i < last ; i++) {
++ /* scan the list with prev-cur pointers */
++ struct bucket_list *cur;
++
++ AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) {
++ int match = cb_fn(EXTERNAL_OBJ(cur->astobj), arg, flags) & (CMP_MATCH | CMP_STOP);
++
++ /* we found the object, performing operations according flags */
++ if (match == 0) { /* no match, no stop, continue */
++ continue;
++ } else if (match == CMP_STOP) { /* no match but stop, we are done */
++ i = last;
++ break;
++ }
++ /* we have a match (CMP_MATCH) here */
++ if (!(flags & OBJ_NODATA)) { /* if must return the object, record the value */
++ /* it is important to handle this case before the unlink */
++ ret = EXTERNAL_OBJ(cur->astobj);
++ ao2_ref(ret, 1);
++ }
++
++ if (flags & OBJ_UNLINK) { /* must unlink */
++ struct bucket_list *x = cur;
++
++ /* we are going to modify the container, so update version */
++ ast_atomic_fetchadd_int(&c->version, 1);
++ AST_LIST_REMOVE_CURRENT(&c->buckets[i], entry);
++ /* update number of elements and version */
++ ast_atomic_fetchadd_int(&c->elements, -1);
++ ao2_ref(EXTERNAL_OBJ(x->astobj), -1);
++ free(x); /* free the link record */
++ }
++
++ if ((match & CMP_STOP) || (flags & OBJ_MULTIPLE) == 0) {
++ /* We found the only match we need */
++ i = last; /* force exit from outer loop */
++ break;
++ }
++ if (!(flags & OBJ_NODATA)) {
++#if 0 /* XXX to be completed */
++ /*
++ * This is the multiple-return case. We need to link
++ * the object in a list. The refcount is already increased.
++ */
++#endif
++ }
++ }
++ AST_LIST_TRAVERSE_SAFE_END
++ }
++ ao2_unlock(c);
++ return ret;
++}
++
++/*!
++ * the find function just invokes the default callback with some reasonable flags.
++ */
++void *ao2_find(struct ao2_container *c, void *arg, enum search_flags flags)
++{
++ return ao2_callback(c, flags, c->cmp_fn, arg);
++}
++
++/*!
++ * initialize an iterator so we start from the first object
++ */
++struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
++{
++ struct ao2_iterator a = {
++ .c = c,
++ .flags = flags
++ };
++
++ return a;
++}
++
++/*
++ * move to the next element in the container.
++ */
++void * ao2_iterator_next(struct ao2_iterator *a)
++{
++ int lim;
++ struct bucket_list *p = NULL;
++ void *ret = NULL;
++
++ if (INTERNAL_OBJ(a->c) == NULL)
++ return NULL;
++
++ if (!(a->flags & F_AO2I_DONTLOCK))
++ ao2_lock(a->c);
++
++ /* optimization. If the container is unchanged and
++ * we have a pointer, try follow it
++ */
++ if (a->c->version == a->c_version && (p = a->obj) ) {
++ if ( (p = AST_LIST_NEXT(p, entry)) )
++ goto found;
++ /* nope, start from the next bucket */
++ a->bucket++;
++ a->version = 0;
++ a->obj = NULL;
++ }
++
++ lim = a->c->n_buckets;
++
++ /* Browse the buckets array, moving to the next
++ * buckets if we don't find the entry in the current one.
++ * Stop when we find an element with version number greater
++ * than the current one (we reset the version to 0 when we
++ * switch buckets).
++ */
++ for (; a->bucket < lim; a->bucket++, a->version = 0) {
++ /* scan the current bucket */
++ AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) {
++ if (p->version > a->version)
++ goto found;
++ }
++ }
++
++found:
++ if (p) {
++ a->version = p->version;
++ a->obj = p;
++ a->c_version = a->c->version;
++ ret = EXTERNAL_OBJ(p->astobj);
++ /* inc refcount of returned object */
++ ao2_ref(ret, 1);
++ }
++
++ if (!(a->flags & F_AO2I_DONTLOCK))
++ ao2_unlock(a->c);
++
++ return ret;
++}
++
++/* callback for destroying container.
++ * we can make it simple as we know what it does
++ */
++static int cd_cb(void *obj, void *arg, int flag)
++{
++ ao2_ref(obj, -1);
++ return 0;
++}
++
++static void container_destruct(void *_c)
++{
++ struct ao2_container *c = _c;
++
++ ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
++
++#ifdef AO2_DEBUG
++ ast_atomic_fetchadd_int(&ao2.total_containers, -1);
++#endif
++}
++
++#ifdef AO2_DEBUG
++static int print_cb(void *obj, void *arg, int flag)
++{
++ int *fd = arg;
++ char *s = (char *)obj;
++
++ ast_cli(*fd, "string <%s>\n", s);
++ return 0;
++}
++
++/*
++ * Print stats
++ */
++static int handle_astobj2_stats(int fd, int argc, char *argv[])
++{
++ ast_cli(fd, "Objects : %d\n", ao2.total_objects);
++ ast_cli(fd, "Containers : %d\n", ao2.total_containers);
++ ast_cli(fd, "Memory : %d\n", ao2.total_mem);
++ ast_cli(fd, "Locked : %d\n", ao2.total_locked);
++ ast_cli(fd, "Refs : %d\n", ao2.total_refs);
++ return 0;
++}
++
++/*
++ * This is testing code for astobj
++ */
++static int handle_astobj2_test(int fd, int argc, char *argv[])
++{
++ struct ao2_container *c1;
++ int i, lim;
++ char *obj;
++ static int prof_id = -1;
++
++ if (prof_id == -1)
++ prof_id = ast_add_profile("ao2_alloc", 0);
++
++ ast_cli(fd, "argc %d argv %s %s %s\n", argc, argv[0], argv[1], argv[2]);
++ lim = atoi(argv[2]);
++ ast_cli(fd, "called astobj_test\n");
++
++ handle_astobj2_stats(fd, 0, NULL);
++ /*
++ * allocate a container with no default callback, and no hash function.
++ * No hash means everything goes in the same bucket.
++ */
++ c1 = ao2_container_alloc(100, NULL /* no callback */, NULL /* no hash */);
++ ast_cli(fd, "container allocated as %p\n", c1);
++
++ /*
++ * fill the container with objects.
++ * ao2_alloc() gives us a reference which we pass to the
++ * container when we do the insert.
++ */
++ for (i = 0; i < lim; i++) {
++ ast_mark(prof_id, 1 /* start */);
++ obj = ao2_alloc(80, NULL);
++ ast_mark(prof_id, 0 /* stop */);
++ ast_cli(fd, "object %d allocated as %p\n", i, obj);
++ sprintf(obj, "-- this is obj %d --", i);
++ ao2_link(c1, obj);
++ }
++ ast_cli(fd, "testing callbacks\n");
++ ao2_callback(c1, 0, print_cb, &fd);
++
++ ast_cli(fd, "testing iterators, remove every second object\n");
++ {
++ struct ao2_iterator ai;
++ int x = 0;
++
++ ai = ao2_iterator_init(c1, 0);
++ while ( (obj = ao2_iterator_next(&ai)) ) {
++ ast_cli(fd, "iterator on <%s>\n", obj);
++ if (x++ & 1)
++ ao2_unlink(c1, obj);
++ ao2_ref(obj, -1);
++ }
++ ast_cli(fd, "testing iterators again\n");
++ ai = ao2_iterator_init(c1, 0);
++ while ( (obj = ao2_iterator_next(&ai)) ) {
++ ast_cli(fd, "iterator on <%s>\n", obj);
++ ao2_ref(obj, -1);
++ }
++ }
++ ast_cli(fd, "testing callbacks again\n");
++ ao2_callback(c1, 0, print_cb, &fd);
++
++ ast_verbose("now you should see an error message:\n");
++ ao2_ref(&i, -1); /* i is not a valid object so we print an error here */
++
++ ast_cli(fd, "destroy container\n");
++ ao2_ref(c1, -1); /* destroy container */
++ handle_astobj2_stats(fd, 0, NULL);
++ return 0;
++}
++
++static struct ast_cli_entry cli_astobj2[] = {
++ { { "astobj2", "stats", NULL },
++ handle_astobj2_stats, "Print astobj2 statistics", },
++ { { "astobj2", "test", NULL } , handle_astobj2_test, "Test astobj2", },
++};
++#endif /* AO2_DEBUG */
++
++int astobj2_init(void)
++{
++#ifdef AO2_DEBUG
++ ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
++#endif
++
++ return 0;
++}
+diff -urNad asterisk-1.2.13~dfsg~/channels/chan_iax2.c asterisk-1.2.13~dfsg/channels/chan_iax2.c
+--- asterisk-1.2.13~dfsg~/channels/chan_iax2.c 2008-06-05 04:11:46.000000000 +0300
++++ asterisk-1.2.13~dfsg/channels/chan_iax2.c 2008-06-05 04:17:50.000000000 +0300
+@@ -89,6 +89,7 @@
+ #include "asterisk/dnsmgr.h"
+ #include "asterisk/devicestate.h"
+ #include "asterisk/netsock.h"
++#include "asterisk/astobj2.h"
+
+ #include "iax2.h"
+ #include "iax2-parser.h"
+@@ -727,6 +728,16 @@
+ static ast_mutex_t iaxsl[IAX_MAX_CALLS];
+ static struct timeval lastused[IAX_MAX_CALLS];
+
++/*!
++ * \brief Another container of iax2_pvt structures
++ *
++ * Active IAX2 pvt structs are also stored in this container, if they are a part
++ * of an active call where we know the remote side's call number. The reason
++ * for this is that incoming media frames do not contain our call number. So,
++ * instead of having to iterate the entire iaxs array, we use this container to
++ * look up calls where the remote side is using a given call number.
++ */
++static struct ao2_container *iax_peercallno_pvts;
+
+ static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
+ static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int);
+@@ -786,15 +797,27 @@
+ static int send_ping(void *data)
+ {
+ int callno = (long)data;
++ int res = 0;
++
+ /* Ping only if it's real, not if it's bridged */
+- if (iaxs[callno]) {
++
++ ast_mutex_lock(&iaxsl[callno]);
++
++ while (iaxs[callno]) {
++ res = 1;
++ if (!iaxs[callno]->peercallno) {
++ break;
++ }
+ #ifdef BRIDGE_OPTIMIZATION
+ if (!iaxs[callno]->bridgecallno)
+ #endif
+ send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
+- return 1;
+- } else
+- return 0;
++ break;
++ }
++
++ ast_mutex_unlock(&iaxsl[callno]);
++
++ return res;
+ }
+
+ static int get_encrypt_methods(const char *s)
+@@ -812,15 +835,27 @@
+ static int send_lagrq(void *data)
+ {
+ int callno = (long)data;
++ int res = 0;
++
+ /* Ping only if it's real not if it's bridged */
+- if (iaxs[callno]) {
++
++ ast_mutex_lock(&iaxsl[callno]);
++
++ while (iaxs[callno]) {
++ res = 1;
++ if (!iaxs[callno]->peercallno) {
++ break;
++ }
+ #ifdef BRIDGE_OPTIMIZATION
+ if (!iaxs[callno]->bridgecallno)
+ #endif
+ send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
+- return 1;
+- } else
+- return 0;
++ break;
++ }
++
++ ast_mutex_unlock(&iaxsl[callno]);
++
++ return res;
+ }
+
+ static unsigned char compress_subclass(int subclass)
+@@ -904,17 +939,188 @@
+ return res;
+ }
+
++static void update_max_trunk(void)
++{
++ int max = TRUNK_CALL_START;
++ int x;
++ /* XXX Prolly don't need locks here XXX */
++ for (x=TRUNK_CALL_START;x<IAX_MAX_CALLS - 1; x++) {
++ if (iaxs[x])
++ max = x + 1;
++ }
++ maxtrunkcall = max;
++ if (option_debug && iaxdebug)
++ ast_log(LOG_DEBUG, "New max trunk callno is %d\n", max);
++}
++
++static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
++{
++ if (ast_test_flag(pvt, IAX_MAXAUTHREQ)) {
++ struct iax2_user *user;
++
++ ast_mutex_lock(&userl.lock);
++ user = userl.users;
++ while (user) {
++ if (!strcmp(user->name, pvt->username)) {
++ user->curauthreq--;
++ break;
++ }
++ user = user->next;
++ }
++ ast_mutex_unlock(&userl.lock);
++ }
++
++ /* No more pings or lagrq's */
++ if (pvt->pingid > -1)
++ ast_sched_del(sched, pvt->pingid);
++ if (pvt->lagid > -1)
++ ast_sched_del(sched, pvt->lagid);
++ if (pvt->autoid > -1)
++ ast_sched_del(sched, pvt->autoid);
++ if (pvt->authid > -1)
++ ast_sched_del(sched, pvt->authid);
++ if (pvt->initid > -1)
++ ast_sched_del(sched, pvt->initid);
++#ifdef NEWJB
++ if (pvt->jbid > -1)
++ ast_sched_del(sched, pvt->jbid);
++ pvt->jbid = -1;
++#endif
++ pvt->pingid = -1;
++ pvt->lagid = -1;
++ pvt->autoid = -1;
++ pvt->authid = -1;
++ pvt->initid = -1;
++}
++
++static void store_by_peercallno(struct chan_iax2_pvt *pvt)
++{
++ if (!pvt->peercallno) {
++ ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");
++ return;
++ }
++
++ ao2_link(iax_peercallno_pvts, pvt);
++}
++
++static void remove_by_peercallno(struct chan_iax2_pvt *pvt)
++{
++ if (!pvt->peercallno) {
++ ast_log(LOG_ERROR, "This should not be called without a peer call number.\n");
++ return;
++ }
++
++ ao2_unlink(iax_peercallno_pvts, pvt);
++}
++
++
++
++static void iax2_destroy(int callno)
++{
++ struct chan_iax2_pvt *pvt;
++ struct ast_channel *owner;
++
++retry:
++ ast_mutex_lock(&iaxsl[callno]);
++ pvt = iaxs[callno];
++ gettimeofday(&lastused[callno], NULL);
++
++ if (pvt)
++ owner = pvt->owner;
++ else
++ owner = NULL;
++ if (owner) {
++ if (ast_mutex_trylock(&owner->lock)) {
++ ast_log(LOG_NOTICE, "Avoiding IAX destroy deadlock\n");
++ ast_mutex_unlock(&iaxsl[callno]);
++ usleep(1);
++ goto retry;
++ }
++ }
++ if (!owner)
++ iaxs[callno] = NULL;
++ if (pvt) {
++ if (owner) {
++ /* If there's an owner, prod it to give up */
++ owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ ast_queue_hangup(owner);
++ } else {
++ pvt->owner = NULL;
++ }
++
++ if (pvt->peercallno) {
++ remove_by_peercallno(pvt);
++ }
++
++ if (!owner) {
++ ao2_ref(pvt, -1);
++ pvt = NULL;
++ }
++ }
++
++ if (owner) {
++ ast_mutex_unlock(&owner->lock);
++ }
++
++ ast_mutex_unlock(&iaxsl[callno]);
++
++ if (callno & 0x4000) {
++ update_max_trunk();
++ }
++}
++
++static void iax2_frame_free(struct iax_frame *fr)
++{
++ if (fr->retrans > -1)
++ ast_sched_del(sched, fr->retrans);
++ iax_frame_free(fr);
++}
++
++static void pvt_destructor(void *obj)
++{
++ struct chan_iax2_pvt *pvt = obj;
++ struct iax_frame *cur;
++
++ iax2_destroy_helper(pvt);
++
++ if (pvt->bridgetrans)
++ ast_translator_free_path(pvt->bridgetrans);
++ pvt->bridgetrans = NULL;
++
++ /* Already gone */
++ ast_set_flag(pvt, IAX_ALREADYGONE);
++
++ for (cur = iaxq.head; cur ; cur = cur->next) {
++ /* Cancel any pending transmissions */
++ if (cur->callno == pvt->callno)
++ cur->retries = -1;
++ }
++ if (pvt->reg) {
++ pvt->reg->callno = 0;
++ }
++ if (!pvt->owner) {
++ if (pvt->vars) {
++ ast_variables_destroy(pvt->vars);
++ pvt->vars = NULL;
++ }
++#ifdef NEWJB
++ {
++ jb_frame frame;
++ while (jb_getall(pvt->jb,&frame) == JB_OK)
++ iax2_frame_free(frame.data);
++ jb_destroy(pvt->jb);
++ }
++#endif
++ }
++}
++
+ static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer, const char *host)
+ {
+ struct chan_iax2_pvt *tmp;
+- tmp = malloc(sizeof(struct chan_iax2_pvt));
++
++ tmp = ao2_alloc(sizeof(*tmp), pvt_destructor);
+ if (tmp) {
+- memset(tmp, 0, sizeof(struct chan_iax2_pvt));
+ tmp->prefs = prefs;
+- tmp->callno = 0;
+- tmp->peercallno = 0;
+- tmp->transfercallno = 0;
+- tmp->bridgecallno = 0;
+ tmp->pingid = -1;
+ tmp->lagid = -1;
+ tmp->autoid = -1;
+@@ -958,13 +1164,13 @@
+ #define NEW_ALLOW 1
+ #define NEW_FORCE 2
+
+-static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, struct chan_iax2_pvt *cur, int full_frame)
++static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, struct chan_iax2_pvt *cur, int check_dcallno)
+ {
+ if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+ (cur->addr.sin_port == sin->sin_port)) {
+ /* This is the main host */
+ if ( (cur->peercallno == 0 || cur->peercallno == callno) &&
+- (full_frame ? dcallno == cur->callno : 1) ) {
++ (check_dcallno ? dcallno == cur->callno : 1) ) {
+ /* That's us. Be sure we keep track of the peer call number */
+ return 1;
+ }
+@@ -978,20 +1184,6 @@
+ return 0;
+ }
+
+-static void update_max_trunk(void)
+-{
+- int max = TRUNK_CALL_START;
+- int x;
+- /* XXX Prolly don't need locks here XXX */
+- for (x=TRUNK_CALL_START;x<IAX_MAX_CALLS - 1; x++) {
+- if (iaxs[x])
+- max = x + 1;
+- }
+- maxtrunkcall = max;
+- if (option_debug && iaxdebug)
+- ast_log(LOG_DEBUG, "New max trunk callno is %d\n", max);
+-}
+-
+ static void update_max_nontrunk(void)
+ {
+ int max = 1;
+@@ -1053,7 +1245,7 @@
+ return res;
+ }
+
+-static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int lockpeer, int sockfd, int full_frame)
++static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int lockpeer, int sockfd, int check_dcallno)
+ {
+ int res = 0;
+ int x;
+@@ -1061,12 +1253,31 @@
+ char iabuf[INET_ADDRSTRLEN];
+ char host[80];
+ if (new <= NEW_ALLOW) {
++ if (callno) {
++ struct chan_iax2_pvt *pvt;
++ struct chan_iax2_pvt tmp_pvt = {
++ .callno = dcallno,
++ .peercallno = callno,
++ /* hack!! */
++ .frames_received = check_dcallno,
++ };
++
++ memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
++
++ if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
++ res = pvt->callno;
++ ao2_ref(pvt, -1);
++ pvt = NULL;
++ return res;
++ }
++ }
++
+ /* Look for an existing connection first */
+ for (x=1;(res < 1) && (x<maxnontrunkcall);x++) {
+ ast_mutex_lock(&iaxsl[x]);
+ if (iaxs[x]) {
+ /* Look for an exact match */
+- if (match(sin, callno, dcallno, iaxs[x], full_frame)) {
++ if (match(sin, callno, dcallno, iaxs[x], check_dcallno)) {
+ res = x;
+ }
+ }
+@@ -1076,7 +1287,7 @@
+ ast_mutex_lock(&iaxsl[x]);
+ if (iaxs[x]) {
+ /* Look for an exact match */
+- if (match(sin, callno, dcallno, iaxs[x], full_frame)) {
++ if (match(sin, callno, dcallno, iaxs[x], check_dcallno)) {
+ res = x;
+ }
+ }
+@@ -1133,6 +1344,9 @@
+ iaxs[x]->amaflags = amaflags;
+ ast_copy_flags(iaxs[x], (&globalflags), IAX_NOTRANSFER | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
+ ast_copy_string(iaxs[x]->accountcode, accountcode, sizeof(iaxs[x]->accountcode));
++ if (iaxs[x]->peercallno) {
++ store_by_peercallno(iaxs[x]);
++ }
+ } else {
+ ast_log(LOG_WARNING, "Out of resources\n");
+ ast_mutex_unlock(&iaxsl[x]);
+@@ -1144,13 +1358,6 @@
+ return res;
+ }
+
+-static void iax2_frame_free(struct iax_frame *fr)
+-{
+- if (fr->retrans > -1)
+- ast_sched_del(sched, fr->retrans);
+- iax_frame_free(fr);
+-}
+-
+ static int iax2_queue_frame(int callno, struct ast_frame *f)
+ {
+ /* Assumes lock for callno is already held... */
+@@ -1624,112 +1831,7 @@
+ return res;
+ }
+
+-static void iax2_destroy(int callno)
+-{
+- struct chan_iax2_pvt *pvt;
+- struct iax_frame *cur;
+- struct ast_channel *owner;
+- struct iax2_user *user;
+
+-retry:
+- ast_mutex_lock(&iaxsl[callno]);
+- pvt = iaxs[callno];
+- gettimeofday(&lastused[callno], NULL);
+-
+- if (pvt)
+- owner = pvt->owner;
+- else
+- owner = NULL;
+- if (owner) {
+- if (ast_mutex_trylock(&owner->lock)) {
+- ast_log(LOG_NOTICE, "Avoiding IAX destroy deadlock\n");
+- ast_mutex_unlock(&iaxsl[callno]);
+- usleep(1);
+- goto retry;
+- }
+- }
+- if (!owner)
+- iaxs[callno] = NULL;
+- if (pvt) {
+- if (!owner)
+- pvt->owner = NULL;
+- if (ast_test_flag(pvt, IAX_MAXAUTHREQ)) {
+- ast_mutex_lock(&userl.lock);
+- user = userl.users;
+- while (user) {
+- if (!strcmp(user->name, pvt->username)) {
+- user->curauthreq--;
+- break;
+- }
+- user = user->next;
+- }
+- ast_mutex_unlock(&userl.lock);
+- }
+- /* No more pings or lagrq's */
+- if (pvt->pingid > -1)
+- ast_sched_del(sched, pvt->pingid);
+- if (pvt->lagid > -1)
+- ast_sched_del(sched, pvt->lagid);
+- if (pvt->autoid > -1)
+- ast_sched_del(sched, pvt->autoid);
+- if (pvt->authid > -1)
+- ast_sched_del(sched, pvt->authid);
+- if (pvt->initid > -1)
+- ast_sched_del(sched, pvt->initid);
+-#ifdef NEWJB
+- if (pvt->jbid > -1)
+- ast_sched_del(sched, pvt->jbid);
+- pvt->jbid = -1;
+-#endif
+- pvt->pingid = -1;
+- pvt->lagid = -1;
+- pvt->autoid = -1;
+- pvt->authid = -1;
+- pvt->initid = -1;
+- if (pvt->bridgetrans)
+- ast_translator_free_path(pvt->bridgetrans);
+- pvt->bridgetrans = NULL;
+-
+- /* Already gone */
+- ast_set_flag(pvt, IAX_ALREADYGONE);
+-
+- if (owner) {
+- /* If there's an owner, prod it to give up */
+- owner->_softhangup |= AST_SOFTHANGUP_DEV;
+- ast_queue_hangup(owner);
+- }
+-
+- for (cur = iaxq.head; cur ; cur = cur->next) {
+- /* Cancel any pending transmissions */
+- if (cur->callno == pvt->callno)
+- cur->retries = -1;
+- }
+- if (pvt->reg) {
+- pvt->reg->callno = 0;
+- }
+- if (!owner) {
+- if (pvt->vars) {
+- ast_variables_destroy(pvt->vars);
+- pvt->vars = NULL;
+- }
+-#ifdef NEWJB
+- {
+- jb_frame frame;
+- while(jb_getall(pvt->jb,&frame) == JB_OK)
+- iax2_frame_free(frame.data);
+- jb_destroy(pvt->jb);
+- }
+-#endif
+- free(pvt);
+- }
+- }
+- if (owner) {
+- ast_mutex_unlock(&owner->lock);
+- }
+- ast_mutex_unlock(&iaxsl[callno]);
+- if (callno & 0x4000)
+- update_max_trunk();
+-}
+ static void iax2_destroy_nolock(int callno)
+ {
+ /* Actually it's easier to unlock, kill it, and relock */
+@@ -3452,9 +3554,41 @@
+ static int iax2_indicate(struct ast_channel *c, int condition)
+ {
+ unsigned short callno = PTR_TO_CALLNO(c->tech_pvt);
++ struct chan_iax2_pvt *pvt;
++ int res;
++
+ if (option_debug && iaxdebug)
+ ast_log(LOG_DEBUG, "Indicating condition %d\n", condition);
+- return send_command_locked(callno, AST_FRAME_CONTROL, condition, 0, NULL, 0, -1);
++
++ ast_mutex_lock(&iaxsl[callno]);
++
++ pvt = iaxs[callno];
++
++ if (!pvt->peercallno) {
++ /* We don't know the remote side's call number, yet. :( */
++ int count = 10;
++ while (count-- && pvt && !pvt->peercallno) {
++ ast_mutex_unlock(&iaxsl[callno]);
++ usleep(1);
++ ast_mutex_lock(&iaxsl[callno]);
++ pvt = iaxs[callno];
++ }
++
++ if (!pvt->peercallno) {
++ /* Even after waiting, we still haven't completed a handshake with
++ * our peer, so we can't send this frame. Bail out. */
++ res = -1;
++ goto done;
++ }
++ }
++
++
++ res = send_command(iaxs[callno], AST_FRAME_CONTROL, condition, 0, NULL, 0, -1);
++
++done:
++ ast_mutex_unlock(&iaxsl[callno]);
++
++ return res;
+ }
+
+ static int iax2_transfer(struct ast_channel *c, const char *dest)
+@@ -5554,7 +5688,13 @@
+ pvt->rseqno = 0;
+ pvt->iseqno = 0;
+ pvt->aseqno = 0;
++
++ if (pvt->peercallno) {
++ remove_by_peercallno(pvt);
++ }
+ pvt->peercallno = peercallno;
++ store_by_peercallno(pvt);
++
+ pvt->transferring = TRANSFER_NONE;
+ pvt->svoiceformat = -1;
+ pvt->voiceformat = 0;
+@@ -6659,8 +6799,27 @@
+ f.subclass = 0;
+ }
+
+- if (!fr->callno)
+- fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, 1, fd, ntohs(mh->callno) & IAX_FLAG_FULL);
++ if (!fr->callno) {
++ int check_dcallno = 0;
++
++ /*
++ * We enforce accurate destination call numbers for all full frames except
++ * LAGRQ and PING commands. This is because older versions of Asterisk
++ * schedule these commands to get sent very quickly, and they will sometimes
++ * be sent before they receive the first frame from the other side. When
++ * that happens, it doesn't contain the destination call number. However,
++ * not checking it for these frames is safe.
++ *
++ * Discussed in the following thread:
++ * http://lists.digium.com/pipermail/asterisk-dev/2008-May/033217.html
++ */
++
++ if (ntohs(mh->callno) & IAX_FLAG_FULL) {
++ check_dcallno = f.frametype == AST_FRAME_IAX ? (f.subclass != IAX_COMMAND_PING && f.subclass != IAX_COMMAND_LAGRQ) : 1;
++ }
++
++ fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, 1, fd, check_dcallno);
++ }
+
+ if (fr->callno > 0)
+ ast_mutex_lock(&iaxsl[fr->callno]);
+@@ -6699,8 +6858,18 @@
+
+ if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) && !minivid &&
+ f.subclass != IAX_COMMAND_TXCNT && /* for attended transfer */
+- f.subclass != IAX_COMMAND_TXACC) /* for attended transfer */
+- iaxs[fr->callno]->peercallno = (unsigned short)(ntohs(mh->callno) & ~IAX_FLAG_FULL);
++ f.subclass != IAX_COMMAND_TXACC) { /* for attended transfer */
++ unsigned short new_peercallno;
++
++ new_peercallno = (unsigned short) (ntohs(mh->callno) & ~IAX_FLAG_FULL);
++ if (new_peercallno && new_peercallno != iaxs[fr->callno]->peercallno) {
++ if (iaxs[fr->callno]->peercallno) {
++ remove_by_peercallno(iaxs[fr->callno]);
++ }
++ iaxs[fr->callno]->peercallno = new_peercallno;
++ store_by_peercallno(iaxs[fr->callno]);
++ }
++ }
+ if (ntohs(mh->callno) & IAX_FLAG_FULL) {
+ if (option_debug && iaxdebug)
+ ast_log(LOG_DEBUG, "Received packet %d, (%d, %d)\n", fh->oseqno, f.frametype, f.subclass);
+@@ -8033,6 +8202,8 @@
+ } else
+ peer->pokeexpire = ast_sched_add(sched, DEFAULT_MAXMS * 2, iax2_poke_noanswer, peer);
+
++ ao2_ref(iax_peercallno_pvts, -1);
++
+ return 0;
+ }
+
+@@ -9748,6 +9919,23 @@
+ return __unload_module();
+ }
+
++static int pvt_hash_cb(const void *obj, const int flags)
++{
++ const struct chan_iax2_pvt *pvt = obj;
++
++ return pvt->peercallno;
++}
++
++static int pvt_cmp_cb(void *obj, void *arg, int flags)
++{
++ struct chan_iax2_pvt *pvt = obj, *pvt2 = arg;
++
++ /* The frames_received field is used to hold whether we're matching
++ * against a full frame or not ... */
++
++ return match(&pvt2->addr, pvt2->peercallno, pvt2->callno, pvt,
++ pvt2->frames_received) ? CMP_MATCH : 0;
++}
+
+ /*--- load_module: Load IAX2 module, load configuraiton ---*/
+ int load_module(void)
+@@ -9828,6 +10016,11 @@
+ ast_netsock_release(netsock);
+ }
+
++ iax_peercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, pvt_hash_cb, pvt_cmp_cb);
++ if (!iax_peercallno_pvts) {
++ res = -1;
++ }
++
+ for (reg = registrations; reg; reg = reg->next)
+ iax2_do_register(reg);
+ ast_mutex_lock(&peerl.lock);
+diff -urNad asterisk-1.2.13~dfsg~/include/asterisk/astobj2.h asterisk-1.2.13~dfsg/include/asterisk/astobj2.h
+--- asterisk-1.2.13~dfsg~/include/asterisk/astobj2.h 1970-01-01 02:00:00.000000000 +0200
++++ asterisk-1.2.13~dfsg/include/asterisk/astobj2.h 2008-06-05 04:17:50.000000000 +0300
+@@ -0,0 +1,541 @@
++/*
++ * astobj2 - replacement containers for asterisk data structures.
++ *
++ * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2. See the LICENSE file
++ * at the top of the source tree.
++ */
++
++#ifndef _ASTERISK_ASTOBJ2_H
++#define _ASTERISK_ASTOBJ2_H
++
++/*! \file
++ *
++ * \brief Object Model implementing objects and containers.
++
++These functions implement an abstraction for objects (with
++locks and reference counts) and containers for these user-defined objects,
++supporting locking, reference counting and callbacks.
++
++The internal implementation of the container is opaque to the user,
++so we can use different data structures as needs arise.
++
++At the moment, however, the only internal data structure is a hash
++table. When other structures will be implemented, the initialization
++function may change.
++
++USAGE - OBJECTS
++
++An object is a block of memory that must be allocated with the
++function ao2_alloc(), and for which the system keeps track (with
++abit of help from the programmer) of the number of references around.
++When an object has no more references, it is destroyed, by first
++invoking whatever 'destructor' function the programmer specifies
++(it can be NULL), and then freeing the memory.
++This way objects can be shared without worrying who is in charge
++of freeing them.
++
++Basically, creating an object requires the size of the object and
++and a pointer to the destructor function:
++
++ struct foo *o;
++
++ o = ao2_alloc(sizeof(struct foo), my_destructor_fn);
++
++The object returned has a refcount = 1.
++Note that the memory for the object is allocated and zeroed.
++- We cannot realloc() the object itself.
++- We cannot call free(o) to dispose of the object; rather we
++ tell the system that we do not need the reference anymore:
++
++ ao2_ref(o, -1)
++
++ causing the destructor to be called (and then memory freed) when
++ the refcount goes to 0. This is also available as ao2_unref(o),
++ and returns NULL as a convenience, so you can do things like
++ o = ao2_unref(o);
++ and clean the original pointer to prevent errors.
++
++- ao2_ref(o, +1) can be used to modify the refcount on the
++ object in case we want to pass it around.
++
++
++- other calls on the object are ao2_lock(obj), ao2_unlock(),
++ ao2_trylock(), to manipulate the lock.
++
++
++USAGE - CONTAINERS
++
++A containers is an abstract data structure where we can store
++objects, search them (hopefully in an efficient way), and iterate
++or apply a callback function to them. A container is just an object
++itself.
++
++A container must first be allocated, specifying the initial
++parameters. At the moment, this is done as follows:
++
++ <b>Sample Usage:</b>
++ \code
++
++ struct ao2_container *c;
++
++ c = ao2_container_alloc(MAX_BUCKETS, my_hash_fn, my_cmp_fn);
++
++where
++- MAX_BUCKETS is the number of buckets in the hash table,
++- my_hash_fn() is the (user-supplied) function that returns a
++ hash key for the object (further reduced moduly MAX_BUCKETS
++ by the container's code);
++- my_cmp_fn() is the default comparison function used when doing
++ searches on the container,
++
++A container knows little or nothing about the object itself,
++other than the fact that it has been created by ao2_alloc()
++All knowledge of the (user-defined) internals of the object
++is left to the (user-supplied) functions passed as arguments
++to ao2_container_alloc().
++
++If we want to insert the object in the container, we should
++initialize its fields -- especially, those used by my_hash_fn() --
++to compute the bucket to use.
++Once done, we can link an object to a container with
++
++ ao2_link(c, o);
++
++The function returns NULL in case of errors (and the object
++is not inserted in the container). Other values mean success
++(we are not supposed to use the value as a pointer to anything).
++
++\note While an object o is in a container, we expect that
++my_hash_fn(o) will always return the same value. The function
++does not lock the object to be computed, so modifications of
++those fields that affect the computation of the hash should
++be done by extractiong the object from the container, and
++reinserting it after the change (this is not terribly expensive).
++
++\note A container with a single buckets is effectively a linked
++list. However there is no ordering among elements.
++
++Objects implement a reference counter keeping the count
++of the number of references that reference an object.
++
++When this number becomes zero the destructor will be
++called and the object will be free'd.
++ */
++
++/*!
++ * Invoked just before freeing the memory for the object.
++ * It is passed a pointer to user data.
++ */
++typedef void (*ao2_destructor_fn)(void *);
++
++void ao2_bt(void); /* backtrace */
++/*!
++ * Allocate and initialize an object.
++ *
++ * \param data_size The sizeof() of user-defined structure.
++ * \param destructor_fn The function destructor (can be NULL)
++ * \return A pointer to user data.
++ *
++ * Allocates a struct astobj2 with sufficient space for the
++ * user-defined structure.
++ * \notes:
++ * - storage is zeroed; XXX maybe we want a flag to enable/disable this.
++ * - the refcount of the object just created is 1
++ * - the returned pointer cannot be free()'d or realloc()'ed;
++ * rather, we just call ao2_ref(o, -1);
++ */
++void *ao2_alloc(const size_t data_size, ao2_destructor_fn destructor_fn);
++
++/*!
++ * Reference/unreference an object and return the old refcount.
++ *
++ * \param o A pointer to the object
++ * \param delta Value to add to the reference counter.
++ * \return The value of the reference counter before the operation.
++ *
++ * Increase/decrease the reference counter according
++ * the value of delta.
++ *
++ * If the refcount goes to zero, the object is destroyed.
++ *
++ * \note The object must not be locked by the caller of this function, as
++ * it is invalid to try to unlock it after releasing the reference.
++ *
++ * \note if we know the pointer to an object, it is because we
++ * have a reference count to it, so the only case when the object
++ * can go away is when we release our reference, and it is
++ * the last one in existence.
++ */
++int ao2_ref(void *o, int delta);
++
++/*!
++ * Lock an object.
++ *
++ * \param a A pointer to the object we want lock.
++ * \return 0 on success, other values on error.
++ */
++int ao2_lock(void *a);
++
++/*!
++ * Unlock an object.
++ *
++ * \param a A pointer to the object we want unlock.
++ * \return 0 on success, other values on error.
++ */
++int ao2_unlock(void *a);
++
++/*!
++ *
++ * Containers
++
++containers are data structures meant to store several objects,
++and perform various operations on them.
++Internally, objects are stored in lists, hash tables or other
++data structures depending on the needs.
++
++NOTA BENE: at the moment the only container we support is the
++hash table and its degenerate form, the list.
++
++Operations on container include:
++
++ c = ao2_container_alloc(size, cmp_fn, hash_fn)
++ allocate a container with desired size and default compare
++ and hash function
++
++ ao2_find(c, arg, flags)
++ returns zero or more element matching a given criteria
++ (specified as arg). Flags indicate how many results we
++ want (only one or all matching entries), and whether we
++ should unlink the object from the container.
++
++ ao2_callback(c, flags, fn, arg)
++ apply fn(obj, arg) to all objects in the container.
++ Similar to find. fn() can tell when to stop, and
++ do anything with the object including unlinking it.
++ Note that the entire operation is run with the container
++ locked, so noone else can change its content while we work on it.
++ However, we pay this with the fact that doing
++ anything blocking in the callback keeps the container
++ blocked.
++ The mechanism is very flexible because the callback function fn()
++ can do basically anything e.g. counting, deleting records, etc.
++ possibly using arg to store the results.
++
++ iterate on a container
++ this is done with the following sequence
++
++ struct ao2_container *c = ... // our container
++ struct ao2_iterator i;
++ void *o;
++
++ i = ao2_iterator_init(c, flags);
++
++ while ( (o = ao2_iterator_next(&i)) ) {
++ ... do something on o ...
++ ao2_ref(o, -1);
++ }
++
++ The difference with the callback is that the control
++ on how to iterate is left to us.
++
++ ao2_ref(c, -1)
++ dropping a reference to a container destroys it, very simple!
++
++Containers are astobj2 object themselves, and this is why their
++implementation is simple too.
++
++ */
++
++/*!
++ * We can perform different operation on an object. We do this
++ * according the following flags.
++ */
++enum search_flags {
++ /*! unlink the object found */
++ OBJ_UNLINK = (1 << 0),
++ /*! on match, don't return the object or increase its reference count. */
++ OBJ_NODATA = (1 << 1),
++ /*! don't stop at the first match
++ * \note This is not fully implemented. */
++ OBJ_MULTIPLE = (1 << 2),
++ /*! obj is an object of the same type as the one being searched for.
++ * This implies that it can be passed to the object's hash function
++ * for optimized searching. */
++ OBJ_POINTER = (1 << 3),
++};
++
++/*!
++ * Type of a generic function to generate a hash value from an object.
++ *
++ */
++typedef int (*ao2_hash_fn)(const void *obj, const int flags);
++
++/*!
++ * valid callback results:
++ * We return a combination of
++ * CMP_MATCH when the object matches the request,
++ * and CMP_STOP when we should not continue the search further.
++ */
++enum _cb_results {
++ CMP_MATCH = 0x1,
++ CMP_STOP = 0x2,
++};
++
++/*!
++ * generic function to compare objects.
++ * This, as other callbacks, should return a combination of
++ * _cb_results as described above.
++ *
++ * \param o object from container
++ * \param arg search parameters (directly from ao2_find)
++ * \param flags passed directly from ao2_find
++ * XXX explain.
++ */
++
++/*!
++ * Type of a generic callback function
++ * \param obj pointer to the (user-defined part) of an object.
++ * \param arg callback argument from ao2_callback()
++ * \param flags flags from ao2_callback()
++ * The return values are the same as a compare function.
++ * In fact, they are the same thing.
++ */
++typedef int (*ao2_callback_fn)(void *obj, void *arg, int flags);
++
++/*!
++ * Here start declarations of containers.
++ */
++struct ao2_container;
++
++/*!
++ * Allocate and initialize a container
++ * with the desired number of buckets.
++ *
++ * We allocate space for a struct astobj_container, struct container
++ * and the buckets[] array.
++ *
++ * \param my_hash_fn Pointer to a function computing a hash value.
++ * \param my_cmp_fn Pointer to a function comparating key-value
++ * with a string. (can be NULL)
++ * \return A pointer to a struct container.
++ *
++ * destructor is set implicitly.
++ */
++struct ao2_container *ao2_container_alloc(const uint n_buckets,
++ ao2_hash_fn hash_fn, ao2_callback_fn cmp_fn);
++
++/*!
++ * Returns the number of elements in a container.
++ */
++int ao2_container_count(struct ao2_container *c);
++
++/*
++ * Here we have functions to manage objects.
++ *
++ * We can use the functions below on any kind of
++ * object defined by the user.
++ */
++
++/*!
++ * \brief Add an object to a container.
++ *
++ * \param c the container to operate on.
++ * \param newobj the object to be added.
++ *
++ * \return NULL on errors, other values on success.
++ *
++ * This function inserts an object in a container according its key.
++ *
++ * \note Remember to set the key before calling this function.
++ *
++ * \note This function automatically increases the reference count to
++ * account for the reference to the object that the container now holds.
++ *
++ * For Asterisk 1.4 only, there is a dirty hack here to ensure that chan_iax2
++ * can have objects linked in to the container at the head instead of tail
++ * when it is just a linked list. This is to maintain some existing behavior
++ * where the order must be maintained as it was before this conversion so that
++ * matching behavior doesn't change.
++ */
++#define ao2_link(c, o) __ao2_link(c, o, 0)
++void *__ao2_link(struct ao2_container *c, void *newobj, int iax2_hack);
++
++/*!
++ * \brief Remove an object from the container
++ *
++ * \arg c the container
++ * \arg obj the object to unlink
++ *
++ * \retval NULL, always
++ *
++ * \note The object requested to be unlinked must be valid. However, if it turns
++ * out that it is not in the container, this function is still safe to
++ * be called.
++ *
++ * \note If the object gets unlinked from the container, the container's
++ * reference to the object will be automatically released.
++ */
++void *ao2_unlink(struct ao2_container *c, void *obj);
++
++/*! \struct Used as return value if the flag OBJ_MULTIPLE is set */
++struct ao2_list {
++ struct ao2_list *next;
++ void *obj; /* pointer to the user portion of the object */
++};
++
++/*!
++ * ao2_callback() and astob2_find() are the same thing with only one difference:
++ * the latter uses as a callback the function passed as my_cmp_f() at
++ * the time of the creation of the container.
++ *
++ * \param c A pointer to the container to operate on.
++ * \param arg passed to the callback.
++ * \param flags A set of flags specifying the operation to perform,
++ partially used by the container code, but also passed to
++ the callback.
++ * \return A pointer to the object found/marked,
++ * a pointer to a list of objects matching comparison function,
++ * NULL if not found.
++ * If the function returns any objects, their refcount is incremented,
++ * and the caller is in charge of decrementing them once done.
++ * Also, in case of multiple values returned, the list used
++ * to store the objects must be freed by the caller.
++ *
++ * This function searches through a container and performs operations
++ * on objects according on flags passed.
++ * XXX describe better
++ * The comparison is done calling the compare function set implicitly.
++ * The p pointer can be a pointer to an object or to a key,
++ * we can say this looking at flags value.
++ * If p points to an object we will search for the object pointed
++ * by this value, otherwise we serch for a key value.
++ * If the key is not uniq we only find the first matching valued.
++ * If we use the OBJ_MARK flags, we mark all the objects matching
++ * the condition.
++ *
++ * The use of flags argument is the follow:
++ *
++ * OBJ_UNLINK unlinks the object found
++ * OBJ_NODATA on match, do return an object
++ * Callbacks use OBJ_NODATA as a default
++ * functions such as find() do
++ * OBJ_MULTIPLE return multiple matches
++ * Default for _find() is no.
++ * to a key (not yet supported)
++ * OBJ_POINTER the pointer is an object pointer
++ *
++ * In case we return a list, the callee must take care to destroy
++ * that list when no longer used.
++ *
++ * \note When the returned object is no longer in use, ao2_ref() should
++ * be used to free the additional reference possibly created by this function.
++ */
++/* XXX order of arguments to find */
++void *ao2_find(struct ao2_container *c, void *arg, enum search_flags flags);
++void *ao2_callback(struct ao2_container *c,
++ enum search_flags flags,
++ ao2_callback_fn cb_fn, void *arg);
++
++int ao2_match_by_addr(void *user_data, void *arg, int flags);
++/*!
++ *
++ *
++ * When we need to walk through a container, we use
++ * ao2_iterator to keep track of the current position.
++ *
++ * Because the navigation is typically done without holding the
++ * lock on the container across the loop,
++ * objects can be inserted or deleted or moved
++ * while we work. As a consequence, there is no guarantee that
++ * the we manage to touch all the elements on the list, or it
++ * is possible that we touch the same object multiple times.
++ * However, within the current hash table container, the following is true:
++ * - It is not possible to miss an object in the container while iterating
++ * unless it gets added after the iteration begins and is added to a bucket
++ * that is before the one the current object is in. In this case, even if
++ * you locked the container around the entire iteration loop, you still would
++ * not see this object, because it would still be waiting on the container
++ * lock so that it can be added.
++ * - It would be extremely rare to see an object twice. The only way this can
++ * happen is if an object got unlinked from the container and added again
++ * during the same iteration. Furthermore, when the object gets added back,
++ * it has to be in the current or later bucket for it to be seen again.
++ *
++ * An iterator must be first initialized with ao2_iterator_init(),
++ * then we can use o = ao2_iterator_next() to move from one
++ * element to the next. Remember that the object returned by
++ * ao2_iterator_next() has its refcount incremented,
++ * and the reference must be explicitly released when done with it.
++ *
++ * Example:
++ *
++ * \code
++ *
++ * struct ao2_container *c = ... // the container we want to iterate on
++ * struct ao2_iterator i;
++ * struct my_obj *o;
++ *
++ * i = ao2_iterator_init(c, flags);
++ *
++ * while ( (o = ao2_iterator_next(&i)) ) {
++ * ... do something on o ...
++ * ao2_ref(o, -1);
++ * }
++ *
++ * \endcode
++ *
++ */
++
++/*!
++ * You are not supposed to know the internals of an iterator!
++ * We would like the iterator to be opaque, unfortunately
++ * its size needs to be known if we want to store it around
++ * without too much trouble.
++ * Anyways...
++ * The iterator has a pointer to the container, and a flags
++ * field specifying various things e.g. whether the container
++ * should be locked or not while navigating on it.
++ * The iterator "points" to the current object, which is identified
++ * by three values:
++ * - a bucket number;
++ * - the object_id, which is also the container version number
++ * when the object was inserted. This identifies the object
++ * univoquely, however reaching the desired object requires
++ * scanning a list.
++ * - a pointer, and a container version when we saved the pointer.
++ * If the container has not changed its version number, then we
++ * can safely follow the pointer to reach the object in constant time.
++ * Details are in the implementation of ao2_iterator_next()
++ * A freshly-initialized iterator has bucket=0, version = 0.
++ */
++
++struct ao2_iterator {
++ /*! the container */
++ struct ao2_container *c;
++ /*! operation flags */
++ int flags;
++#define F_AO2I_DONTLOCK 1 /*!< don't lock when iterating */
++ /*! current bucket */
++ int bucket;
++ /*! container version */
++ uint c_version;
++ /*! pointer to the current object */
++ void *obj;
++ /*! container version when the object was created */
++ uint version;
++};
++
++struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags);
++
++void *ao2_iterator_next(struct ao2_iterator *a);
++
++#endif /* _ASTERISK_ASTOBJ2_H */
More information about the Pkg-voip-commits
mailing list