[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