[Freeswitch-svn] [commit] r8321 - in freeswitch/trunk: . libs/iax src/mod/endpoints/mod_iax
Freeswitch SVN
anthm at freeswitch.org
Thu May 8 19:25:36 EDT 2008
Author: anthm
Date: Thu May 8 19:25:36 2008
New Revision: 8321
Added:
freeswitch/trunk/src/mod/endpoints/mod_iax/answer.h
freeswitch/trunk/src/mod/endpoints/mod_iax/frame.h
freeswitch/trunk/src/mod/endpoints/mod_iax/iax-client.h
freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.c
freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.h
freeswitch/trunk/src/mod/endpoints/mod_iax/iax.c
freeswitch/trunk/src/mod/endpoints/mod_iax/iax.h
freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.c
freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.h
freeswitch/trunk/src/mod/endpoints/mod_iax/iax2.h
freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.c
freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.h
freeswitch/trunk/src/mod/endpoints/mod_iax/md5.c
freeswitch/trunk/src/mod/endpoints/mod_iax/md5.h
freeswitch/trunk/src/mod/endpoints/mod_iax/winiphone.c
freeswitch/trunk/src/mod/endpoints/mod_iax/winpoop.h
Removed:
freeswitch/trunk/libs/iax/
Modified:
freeswitch/trunk/configure.in
freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile
Log:
slim down iax build
Modified: freeswitch/trunk/configure.in
==============================================================================
--- freeswitch/trunk/configure.in (original)
+++ freeswitch/trunk/configure.in Thu May 8 19:25:36 2008
@@ -593,7 +593,6 @@
AC_CONFIG_SUBDIRS(libs/voipcodecs)
AC_CONFIG_SUBDIRS(libs/codec/ilbc)
AC_CONFIG_SUBDIRS(libs/curl)
-AC_CONFIG_SUBDIRS(libs/iax)
AC_CONFIG_SUBDIRS(libs/iksemel)
AC_CONFIG_SUBDIRS(libs/js/nsprpub)
AC_CONFIG_SUBDIRS(libs/js)
Modified: freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile (original)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile Thu May 8 19:25:36 2008
@@ -1,11 +1,6 @@
BASE=../../../..
+LOCAL_CFLAGS=-I. -DNEWJB -DLIBIAX
+LOCAL_OBJS=iax2-parser.o iax.o md5.o jitterbuf.o iax-mutex.o
-IAX_DIR=$(BASE)/libs/iax
-IAXLA=$(IAX_DIR)/src/libiax.la
-LOCAL_CFLAGS=-I$(IAX_DIR)/src
-LOCAL_LIBADD=$(IAXLA)
include $(BASE)/build/modmake.rules
-$(IAXLA): $(IAX_DIR) $(IAX_DIR)/.update
- cd $(IAX_DIR) && $(MAKE)
-
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/answer.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/answer.h Thu May 8 19:25:36 2008
@@ -0,0 +1,237 @@
+/*
+ * Signed 16-bit audio data
+ *
+ * Source: answer.raw
+ *
+ * Copyright (C) 1999, Mark Spencer and Linux Support Services
+ *
+ * Distributed under the terms of the GNU General Public License
+ *
+ */
+
+static signed short answer[] = {
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 0x19b7, 0x0245, 0xeee5, 0xb875, 0xd9a4, 0x6018, 0x660a, 0xc3c6,
+0x8741, 0xff55, 0x4c2e, 0x2146, 0xfed2, 0xf079, 0xcbd4, 0xe561, 0x3c41, 0x3166,
+0xd425, 0xdc59, 0x2748, 0x087d, 0xc72b, 0xfe3a, 0x4681, 0x14c6, 0xcf45, 0xdd38,
+0xf8dd, 0x0a39, 0x3a5a, 0x32b9, 0xbfec, 0x957f, 0x15a3, 0x70f4, 0x1d95, 0xbfc4,
+0xd367, 0xfda0, 0x0dc0, 0x29eb, 0x1fc2, 0xd684, 0xcab1, 0x19c7, 0x29ef, 0xe679,
+0xe9d0, 0x2b82, 0x151a, 0xca9f, 0xdb68, 0x1f4a, 0x271c, 0x0e2a, 0xfb32, 0xd1b2,
+0xc8ff, 0x2382, 0x6380, 0x0a52, 0xa118, 0xccbf, 0x2ddc, 0x33fd, 0x0964, 0xf2a4,
+0xdd81, 0xe092, 0x1a00, 0x325c, 0xf5e3, 0xd6a1, 0x0b6c, 0x1c75, 0xe4f8, 0xe07c,
+0x2082, 0x2b3e, 0xf445, 0xdaa9, 0xea13, 0xff3c, 0x245c, 0x35c1, 0xf308, 0xab53,
+0xdf59, 0x4698, 0x3f3b, 0xe7f7, 0xca84, 0xed4d, 0x0c3f, 0x1e94, 0x1c2d, 0xf06f,
+0xd4df, 0xff34, 0x23d8, 0x001e, 0xe3f1, 0x0b15, 0x2113, 0xf3fd, 0xd768, 0xf9a0,
+0x1d31, 0x1c6e, 0x0797, 0xe3a0, 0xce6c, 0xfd7b, 0x422a, 0x2c4c, 0xd364, 0xbf42,
+0x0278, 0x303e, 0x1c51, 0xf737, 0xe25a, 0xe75f, 0x0a8f, 0x22ab, 0x05f4, 0xe3f9,
+0xf8c4, 0x1705, 0x0162, 0xe49f, 0xfb8b, 0x1e2b, 0x13ac, 0xf044, 0xe07b, 0xf01a,
+0x1567, 0x2cbf, 0x0b75, 0xd01b, 0xd206, 0x1563, 0x38d7, 0x0f2e, 0xdb32, 0xdc30,
+0x023b, 0x1e44, 0x16eb, 0xf5f7, 0xe425, 0xfa33, 0x14d5, 0x0968, 0xeff2, 0xf762,
+0x1137, 0x0e59, 0xf13a, 0xe651, 0xff41, 0x1d60, 0x18fd, 0xf1e6, 0xd75f, 0xf097,
+0x20ec, 0x27fa, 0xfba4, 0xd5b8, 0xe68e, 0x1657, 0x2518, 0x04f6, 0xe5a3, 0xe976,
+0x0578, 0x18fa, 0x0a92, 0xec0a, 0xef2a, 0x111f, 0x12f4, 0xeec3, 0xe95e, 0x0d3a,
+0x18fd, 0xff72, 0xeefc, 0xf114, 0xfaaa, 0x14ee, 0x21db, 0xf56e, 0xcb49, 0xf621,
+0x3323, 0x1947, 0xe017, 0xe7e9, 0x0819, 0x0707, 0x084c, 0x0f57, 0xf152, 0xdf92,
+0x104a, 0x28eb, 0xedcc, 0xd4ad, 0x1415, 0x296d, 0xed9a, 0xdf57, 0x0cc2, 0x0d95,
+0xf7b5, 0x0deb, 0x0b34, 0xd713, 0xea08, 0x38d6, 0x216d, 0xc727, 0xdc32, 0x2cd2,
+0x1822, 0xe2d5, 0xfeb3, 0x106c, 0xe6e5, 0xf81e, 0x2fe8, 0x01af, 0xc180, 0x037a,
+0x42d8, 0xf88d, 0xc344, 0x0a4f, 0x2c4e, 0xf19d, 0xebeb, 0x162c, 0xf9e9, 0xde93,
+0x1b56, 0x2c60, 0xd8aa, 0xce3e, 0x2a41, 0x2eeb, 0xdab1, 0xde32, 0x1c32, 0x0aba,
+0xeabe, 0x1008, 0x136d, 0xda2f, 0xec3b, 0x31dd, 0x1130, 0xca79, 0xf5b8, 0x3423,
+0x0274, 0xd27d, 0x035e, 0x1e68, 0xf641, 0xf904, 0x1691, 0xef7d, 0xd57a, 0x1c3b,
+0x3c23, 0xe881, 0xc274, 0x0af5, 0x2962, 0xfa34, 0xf676, 0x0f71, 0xefcc, 0xe01f,
+0x19e7, 0x276f, 0xe694, 0xe134, 0x1c3a, 0x0e8b, 0xd8e7, 0xfa81, 0x2f8b, 0x07c5,
+0xd904, 0xf6fa, 0x0ca5, 0xf9a2, 0x0dc7, 0x2623, 0xec54, 0xbe23, 0x02b6, 0x4296,
+0x10cd, 0xda61, 0xf11c, 0x0103, 0xf41c, 0x10b4, 0x2a03, 0xf63c, 0xce1a, 0xfdbd,
+0x1fb4, 0xfc51, 0xf727, 0x1c8a, 0x04ff, 0xcf41, 0xec05, 0x2913, 0x1ce8, 0xf70c,
+0xf744, 0xede8, 0xdd77, 0x0d99, 0x43f1, 0x119c, 0xc14f, 0xd60e, 0x17cb, 0x1e19,
+0x0d4e, 0x0c95, 0xeed1, 0xcdf4, 0xf7a5, 0x331f, 0x1cd0, 0xeb17, 0xf082, 0xfb19,
+0xe899, 0xfdeb, 0x323c, 0x2036, 0xdad3, 0xd134, 0xfd03, 0x1345, 0x1c10, 0x2239,
+0xf656, 0xbc22, 0xdc3f, 0x3392, 0x3d59, 0xfd77, 0xdb4d, 0xe23f, 0xedbe, 0x0f7e,
+0x35cc, 0x1947, 0xd5dc, 0xd1bf, 0x035d, 0x16fc, 0x1174, 0x1675, 0x0249, 0xd2d4,
+0xd851, 0x184d, 0x32fe, 0x0f91, 0xee14, 0xe1e6, 0xdf9b, 0x016b, 0x3668, 0x2b2b,
+0xe20c, 0xc554, 0xf257, 0x1c05, 0x1fc5, 0x14f0, 0xf891, 0xd41c, 0xdf83, 0x1865,
+0x2de1, 0x0b16, 0xed58, 0xea0c, 0xea79, 0xfbd9, 0x22af, 0x2732, 0xf62f, 0xd389,
+0xe7d9, 0x0b39, 0x1cdc, 0x1de3, 0x038a, 0xd809, 0xd5f7, 0x0b55, 0x305e, 0x1910,
+0xf02e, 0xe089, 0xe7c7, 0x0195, 0x2265, 0x21da, 0xf743, 0xd8f2, 0xe978, 0x09a1,
+0x190a, 0x17c5, 0x045a, 0xe46d, 0xdd06, 0xffb2, 0x2293, 0x1cfe, 0xfd4d, 0xe4f9,
+0xe310, 0xfaf1, 0x1d22, 0x2376, 0x0113, 0xde3a, 0xe21b, 0x0204, 0x1ba1, 0x1bd6,
+0x0333, 0xe563, 0xe104, 0xfd51, 0x1bc1, 0x1ccf, 0x0285, 0xe757, 0xe35e, 0xfaf2,
+0x185d, 0x1d46, 0x06b7, 0xec13, 0xe108, 0xef6e, 0x121d, 0x2a17, 0x16a6, 0xe32c,
+0xc9a9, 0xf070, 0x2f48, 0x3788, 0xfa4e, 0xc32a, 0xd9c2, 0x1fa1, 0x36fe, 0x07fa,
+0xd9e4, 0xe577, 0x0e5e, 0x1755, 0xfb53, 0xed71, 0x0540, 0x19e0, 0x0301, 0xdc97,
+0xe391, 0x1937, 0x367c, 0x0bc9, 0xca4c, 0xc96b, 0x105d, 0x461f, 0x2416, 0xd481,
+0xbc97, 0xf8b7, 0x39af, 0x2ec9, 0xecc6, 0xcb50, 0xeee3, 0x1ffe, 0x1e8e, 0xf700,
+0xe66a, 0xff58, 0x149f, 0x02e5, 0xe792, 0xf2d8, 0x1a4d, 0x225a, 0xf642, 0xce7f,
+0xe6a6, 0x25e2, 0x38f5, 0x01d0, 0xc50f, 0xd243, 0x19bd, 0x3fc6, 0x14f0, 0xd2d7,
+0xcdb6, 0x069a, 0x2ffe, 0x1847, 0xe6f8, 0xdf0a, 0x0337, 0x1a90, 0x067a, 0xeb5b,
+0xf541, 0x143b, 0x14f2, 0xf092, 0xdc02, 0xfb91, 0x28a3, 0x2274, 0xeaa8, 0xc9e7,
+0xef48, 0x2d01, 0x322e, 0xf6d2, 0xc7cb, 0xe13b, 0x1fda, 0x3217, 0x0458, 0xd690,
+0xe2bf, 0x11c4, 0x21d5, 0x0291, 0xe5c8, 0xf3a9, 0x12ba, 0x11aa, 0xf22b, 0xe627,
+0x03ec, 0x219a, 0x1036, 0xe2f2, 0xd93f, 0x059c, 0x2ed6, 0x1b75, 0xe227, 0xce55,
+0xfb19, 0x2de0, 0x2477, 0xed08, 0xd148, 0xf307, 0x21d4, 0x2002, 0xf543, 0xdeac,
+0xf7f9, 0x18a9, 0x11d6, 0xf0ef, 0xe8e4, 0x05ea, 0x1ba5, 0x0727, 0xe448, 0xe748,
+0x100e, 0x265e, 0x07fc, 0xdbae, 0xde78, 0x0efa, 0x2ce0, 0x0f94, 0xddf1, 0xd9ea,
+0x0797, 0x28f6, 0x12eb, 0xe60c, 0xdf46, 0x0469, 0x1fbb, 0x0ced, 0xe9f6, 0xe95f,
+0x09fe, 0x1ab9, 0x02cb, 0xe5a4, 0xef2a, 0x1327, 0x1d7b, 0xfd07, 0xde3d, 0xed9c,
+0x17e5, 0x22e7, 0xfe3a, 0xdb38, 0xe9b9, 0x161a, 0x2416, 0x0175, 0xde3d, 0xe9de,
+0x1294, 0x1fc9, 0x00ea, 0xe2a7, 0xeee2, 0x1298, 0x1a7d, 0xfc1d, 0xe3bb, 0xf47a,
+0x1642, 0x185e, 0xf727, 0xe1af, 0xf709, 0x19c3, 0x18e7, 0xf50d, 0xe010, 0xf75b,
+0x1a9c, 0x18d8, 0xf4c5, 0xe0c9, 0xf865, 0x1a1c, 0x16d5, 0xf3a6, 0xe257, 0xfaf2,
+0x1a44, 0x14d5, 0xf34f, 0xe4b6, 0xfc77, 0x17d5, 0x0ff8, 0xf133, 0xe8b7, 0x0344,
+0x1a37, 0x0ad5, 0xe95e, 0xe61a, 0x08a5, 0x227e, 0x0e33, 0xe4a7, 0xdd70, 0x03b0,
+0x25f4, 0x17b2, 0xec0a, 0xdb4e, 0xf898, 0x1ba3, 0x18f6, 0xf973, 0xe87f, 0xf77a,
+0x0b93, 0x096c, 0xfb0e, 0xfb03, 0x0896, 0x0940, 0xf51d, 0xe904, 0xfdc7, 0x1dda,
+0x1bf9, 0xf29b, 0xd37f, 0xea1b, 0x1f37, 0x3175, 0x07eb, 0xd3f7, 0xd46b, 0x077d,
+0x2eeb, 0x1e67, 0xeeae, 0xd8c7, 0xef85, 0x1119, 0x18d3, 0x088e, 0xf953, 0xf5ad,
+0xf556, 0xf63d, 0x0234, 0x167a, 0x19a1, 0xfbf9, 0xd873, 0xdd4b, 0x0f06, 0x3748,
+0x21e6, 0xe181, 0xc032, 0xe79a, 0x2bec, 0x3e76, 0x0b1b, 0xce41, 0xcb23, 0xff96,
+0x2d79, 0x26d1, 0xfcc7, 0xdf8a, 0xe525, 0xfd83, 0x10f1, 0x16d7, 0x0f50, 0xfaea,
+0xe3f1, 0xe20f, 0x0158, 0x27d9, 0x2866, 0xf96f, 0xcb34, 0xd563, 0x11d6, 0x3d25,
+0x2424, 0xe254, 0xc2c9, 0xe7cd, 0x248d, 0x34f5, 0x0c42, 0xdcd0, 0xd827, 0xfa65,
+0x19eb, 0x1b50, 0x0721, 0xf396, 0xeb9c, 0xefde, 0x0016, 0x1594, 0x1cc1, 0x0658,
+0xe22b, 0xd852, 0xfb3e, 0x2923, 0x2c78, 0xfc87, 0xcdb5, 0xd69c, 0x0e3c, 0x3527,
+0x201f, 0xe993, 0xcf9e, 0xeb21, 0x183f, 0x25ea, 0x0c93, 0xed4d, 0xe5f9, 0xf548,
+0x07fb, 0x117c, 0x0ff2, 0x0398, 0xf08c, 0xe628, 0xf489, 0x143b, 0x2419, 0x0ccf,
+0xe2cc, 0xd5a6, 0xf861, 0x2615, 0x2a1b, 0xfeb4, 0xd543, 0xdc53, 0x09b4, 0x2901,
+0x19ff, 0xf24a, 0xde86, 0xeec4, 0x0b7b, 0x1733, 0x0d0a, 0xfc24, 0xf1bb, 0xf110,
+0xfa03, 0x0a0f, 0x15d4, 0x0e21, 0xf435, 0xe17e, 0xee90, 0x1225, 0x2527, 0x0efa,
+0xe61f, 0xd916, 0xf7b8, 0x1f50, 0x2326, 0x0099, 0xe01e, 0xe473, 0x0491, 0x1b37,
+0x1360, 0xfb17, 0xecd9, 0xf20d, 0x0051, 0x0aec, 0x0d4a, 0x073d, 0xfa5a, 0xeeb8,
+0xf165, 0x0516, 0x17dc, 0x12da, 0xf71b, 0xe213, 0xed85, 0x0eef, 0x20c8, 0x0e09,
+0xebcc, 0xe0d4, 0xf848, 0x1637, 0x19d6, 0x026b, 0xec09, 0xed00, 0xff9b, 0x0e5a,
+0x0d6b, 0x026c, 0xf865, 0xf4da, 0xf888, 0x025a, 0x0cbb, 0x0d53, 0xff96, 0xeefa,
+0xee80, 0x021c, 0x15d6, 0x126a, 0xf9c1, 0xe724, 0xf017, 0x0aa1, 0x18b6, 0x0b4e,
+0xf2d7, 0xea91, 0xf957, 0x0cac, 0x1061, 0x03f4, 0xf6ad, 0xf476, 0xfbdf, 0x0489,
+0x08b1, 0x06df, 0xffcf, 0xf766, 0xf537, 0xfddf, 0x0ad4, 0x0e15, 0x01da, 0xf205,
+0xf0a0, 0x0082, 0x1066, 0x0e41, 0xfc71, 0xef1b, 0xf4ad, 0x05cd, 0x0f32, 0x07ed,
+0xf9c8, 0xf401, 0xfa93, 0x04af, 0x088c, 0x04a7, 0xfe15, 0xf9f1, 0xfa64, 0xff1e,
+0x0539, 0x078c, 0x02af, 0xfa1a, 0xf69d, 0xfd09, 0x075b, 0x0a3d, 0x01f2, 0xf761,
+0xf642, 0xffa7, 0x08f3, 0x0830, 0xff05, 0xf7db, 0xf9bc, 0x0174, 0x068b, 0x04b2,
+0xfeff, 0xfb39, 0xfc1a, 000000, 0x0371, 0x03d7, 0x00fe, 0xfd37, 0xfbe0, 0xfe78,
+0x02af, 0x044a, 0x0180, 0xfd43, 0xfc00, 0xfed1, 0x02aa, 0x0346, 0x00dd, 0xfde0,
+0xfbfe, 0x0114, 0x0987, 0x04bc, 0xf49d, 0xf23a, 0x06ab, 0x162e, 0x0544, 0xe76b,
+0xea25, 0x1015, 0x2474, 0x0431, 0xd7d3, 0xe1ec, 0x1923, 0x2df5, 0x01cd, 0xd386,
+0xe3d9, 0x1b9d, 0x2c62, 0xfeb8, 0xd31a, 0xe6ba, 0x1dbd, 0x2abb, 0xfbab, 0xd2ed,
+0xe9ab, 0x1fa7, 0x28ef, 0xf8b3, 0xd2f5, 0xeca5, 0x2160, 0x26fd, 0xf5d7, 0xd334,
+0xefa1, 0x22e5, 0x24ea, 0xf31b, 0xd3a9, 0xf29f, 0x2435, 0x22b6, 0xf07e, 0xd44e,
+0xf59b, 0x2551, 0x2067, 0xee08, 0xd527, 0xf88e, 0x2639, 0x1e00, 0xebb6, 0xd62d,
+0xfb77, 0x26eb, 0x1b85, 0xe98b, 0xd75f, 0xfe51, 0x276b, 0x18f9, 0xe78e, 0xd8b9,
+0x011a, 0x27b6, 0x1660, 0xe5bb, 0xda3a, 0x03cc, 0x27cf, 0x13bd, 0xe415, 0xdbdf,
+0x066a, 0x27b7, 0x1117, 0xe29e, 0xdda5, 0x08ec, 0x276e, 0x0e6d, 0xe154, 0xdf89,
+0x0b52, 0x26f6, 0x0bc7, 0xe039, 0xe185, 0x0d96, 0x2653, 0x0924, 0xdf4e, 0xe399,
+0x0fb9, 0x2584, 0x068b, 0xde93, 0xe5c0, 0x11b8, 0x248e, 0x03fd, 0xde08, 0xe7f8,
+0x1390, 0x2372, 0x0180, 0xddaa, 0xea3c, 0x1544, 0x2231, 0xff12, 0xdd7a, 0xec89,
+0x16cf, 0x20d0, 0xfcb9, 0xdd77, 0xeedb, 0x1831, 0x1f52, 0xfa77, 0xdd9f, 0xf132,
+0x1969, 0x1db7, 0xf850, 0xddf1, 0xf385, 0x1a75, 0x1c06, 0xf645, 0xde6b, 0xf5d7,
+0x1b5b, 0x1a3f, 0xf457, 0xdf0d, 0xf820, 0x1c13, 0x1867, 0xf288, 0xdfd2, 0xfa5f,
+0x1ca1, 0x167f, 0xf0db, 0xe0ba, 0xfc92, 0x1d06, 0x148b, 0xef50, 0xe1c1, 0xfeb5,
+0x1d43, 0x1290, 0xede9, 0xe2e6, 0x00c6, 0x1d58, 0x108e, 0xeca7, 0xe426, 0x02c4,
+0x1d45, 0x0e8a, 0xeb8a, 0xe57f, 0x04a9, 0x1d0e, 0x0c87, 0xea92, 0xe6ec, 0x0677,
+0x1cb2, 0x0a87, 0xe9be, 0xe86e, 0x082a, 0x1c34, 0x088b, 0xe912, 0xe9fe, 0x09c1,
+0x1b95, 0x069c, 0xe88c, 0xeb9c, 0x0b3a, 0x1ad9, 0x04b6, 0xe82a, 0xed43, 0x0c96,
+0x1a00, 0x02df, 0xe7eb, 0xeef3, 0x0dd0, 0x190d, 0x0116, 0xe7d0, 0xf0a8, 0x0eec,
+0x1804, 0xff61, 0xe7d8, 0xf25d, 0x0fe6, 0x16e3, 0xfdc0, 0xe800, 0xf412, 0x10bf,
+0x15b1, 0xfc36, 0xe848, 0xf5c5, 0x1176, 0x146e, 0xfac2, 0xe8ad, 0xf771, 0x120d,
+0x1320, 0xf969, 0xe92e, 0xf913, 0x1282, 0x11c4, 0xf828, 0xe9cb, 0xfaac, 0x12d8,
+0x1062, 0xf703, 0xea7e, 0xfc38, 0x130e, 0x0efa, 0xf5fb, 0xeb49, 0xfdb5, 0x1325,
+0x0d8e, 0xf50e, 0xec26, 0xff20, 0x131e, 0x0c21, 0xf43f, 0xed15, 0x007a, 0x12fa,
+0x0ab6, 0xf38d, 0xee15, 0x01be, 0x12bd, 0x094f, 0xf2f9, 0xef22, 0x02ef, 0x1265,
+0x07f0, 0xf283, 0xf037, 0x0408, 0x11f6, 0x0699, 0xf226, 0xf156, 0x050a, 0x1170,
+0x054b, 0xf1e8, 0xf27a, 0x05f4, 0x10d8, 0x040c, 0xf1c5, 0xf3a3, 0x06c2, 0x102c,
+0x02da, 0xf1bc, 0xf4cc, 0x0779, 0x0f71, 0x01b7, 0xf1cc, 0xf5f5, 0x0815, 0x0ea7,
+0x00a8, 0xf1f4, 0xf719, 0x0899, 0x0dd2, 0xffab, 0xf233, 0xf839, 0x0902, 0x0cf4,
+0xfec0, 0xf288, 0xf950, 0x0952, 0x0c0e, 0xfdec, 0xf2ee, 0xfa5d, 0x0989, 0x0b23,
+0xfd2d, 0xf368, 0xfb62, 0x09a7, 0x0a35, 0xfc85, 0xf3f1, 0xfc58, 0x09af, 0x0946,
+0xfbf2, 0xf488, 0xfd3f, 0x09a1, 0x0859, 0xfb77, 0xf52c, 0xfe17, 0x097d, 0x076f,
+0xfb14, 0xf5d8, 0xfede, 0x0945, 0x068a, 0xfac6, 0xf68d, 0xff93, 0x08fb, 0x05ad,
+0xfa8e, 0xf747, 0x0034, 0x08a1, 0x04da, 0xfa6f, 0xf805, 0x00c2, 0x0836, 0x0410,
+0xfa63, 0xf8c6, 0x013c, 0x07bf, 0x0354, 0xfa6c, 0xf985, 0x01a1, 0x073b, 0x02a4,
+0xfa8a, 0xfa43, 0x01f1, 0x06af, 0x0204, 0xfab9, 0xfafc, 0x022c, 0x0619, 0x0175,
+0xfafa, 0xfbae, 0x0252, 0x057f, 0x00f6, 0xfb4b, 0xfc5a, 0x0263, 0x04e0, 0x008b,
+0xfbaa, 0xfcfa, 0x0262, 0x0440, 0x0032, 0xfc16, 0xfd90, 0x024b, 0x03a0, 0xffec,
+0xfc8c, 0xfe19, 0x0225, 0x0301, 0xffb9, 0xfd0c, 0xfe93, 0x01ea, 0x0267, 0xff9c,
+0xfd95, 0xfefe, 0x01a0, 0x01d3, 0xff90, 0xfe22, 0xff5a, 0x0147, 0x0145, 0xff99,
+0xfeb3, 0xffa1, 0x00e0, 0x00c3, 0xffb6, 0xff46, 0xffd9, 0x006d, 0x004b, 0xffe5,
+0xffda, 0xfffc, 000000, 0xfffe, 000000, 0xffff, 000000, 0xffff, 0xffff, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000,
+000000 };
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/frame.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/frame.h Thu May 8 19:25:36 2008
@@ -0,0 +1,134 @@
+/*
+ * libiax: An implementation of the Inter-Asterisk eXchange protocol
+ *
+ * Asterisk internal frame definitions.
+ *
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser General Public License. Other components of
+ * Asterisk are distributed under The GNU General Public License
+ * only.
+ */
+
+#ifndef _LIBIAX_FRAME_H
+#define _LIBIAX_FRAME_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Frame types */
+#define AST_FRAME_DTMF 1 /* A DTMF digit, subclass is the digit */
+#define AST_FRAME_VOICE 2 /* Voice data, subclass is AST_FORMAT_* */
+#define AST_FRAME_VIDEO 3 /* Video frame, maybe?? :) */
+#define AST_FRAME_CONTROL 4 /* A control frame, subclass is AST_CONTROL_* */
+#define AST_FRAME_NULL 5 /* An empty, useless frame */
+#define AST_FRAME_IAX 6 /* Inter Aterisk Exchange private frame type */
+#define AST_FRAME_TEXT 7 /* Text messages */
+#define AST_FRAME_IMAGE 8 /* Image Frames */
+#define AST_FRAME_HTML 9 /* HTML Frames */
+#define AST_FRAME_CNG 10 /* Comfort Noise frame (subclass is level of CNG in -dBov) */
+
+/* HTML subclasses */
+#define AST_HTML_URL 1 /* Sending a URL */
+#define AST_HTML_DATA 2 /* Data frame */
+#define AST_HTML_BEGIN 4 /* Beginning frame */
+#define AST_HTML_END 8 /* End frame */
+#define AST_HTML_LDCOMPLETE 16 /* Load is complete */
+#define AST_HTML_NOSUPPORT 17 /* Peer is unable to support HTML */
+#define AST_HTML_LINKURL 18 /* Send URL and track */
+#define AST_HTML_UNLINK 19 /* Request no more linkage */
+#define AST_HTML_LINKREJECT 20 /* Reject LINKURL */
+
+/* Data formats for capabilities and frames alike */
+/*! G.723.1 compression */
+#define AST_FORMAT_G723_1 (1 << 0)
+ /*! GSM compression */
+#define AST_FORMAT_GSM (1 << 1)
+ /*! Raw mu-law data (G.711) */
+#define AST_FORMAT_ULAW (1 << 2)
+ /*! Raw A-law data (G.711) */
+#define AST_FORMAT_ALAW (1 << 3)
+ /*! ADPCM (G.726, 32kbps) */
+#define AST_FORMAT_G726 (1 << 4)
+ /*! ADPCM (IMA) */
+#define AST_FORMAT_ADPCM (1 << 5)
+ /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+#define AST_FORMAT_SLINEAR (1 << 6)
+ /*! LPC10, 180 samples/frame */
+#define AST_FORMAT_LPC10 (1 << 7)
+ /*! G.729A audio */
+#define AST_FORMAT_G729A (1 << 8)
+ /*! SpeeX Free Compression */
+#define AST_FORMAT_SPEEX (1 << 9)
+ /*! iLBC Free Compression */
+#define AST_FORMAT_ILBC (1 << 10)
+ /*! Maximum audio format */
+#define AST_FORMAT_MAX_AUDIO (1 << 15)
+ /*! JPEG Images */
+#define AST_FORMAT_JPEG (1 << 16)
+ /*! PNG Images */
+#define AST_FORMAT_PNG (1 << 17)
+ /*! H.261 Video */
+#define AST_FORMAT_H261 (1 << 18)
+ /*! H.263 Video */
+#define AST_FORMAT_H263 (1 << 19)
+ /*! Max one */
+#define AST_FORMAT_MAX_VIDEO (1 << 24)
+
+/* Control frame types */
+#define AST_CONTROL_HANGUP 1 /* Other end has hungup */
+#define AST_CONTROL_RING 2 /* Local ring */
+#define AST_CONTROL_RINGING 3 /* Remote end is ringing */
+#define AST_CONTROL_ANSWER 4 /* Remote end has answered */
+#define AST_CONTROL_BUSY 5 /* Remote end is busy */
+#define AST_CONTROL_TAKEOFFHOOK 6 /* Make it go off hook */
+#define AST_CONTROL_OFFHOOK 7 /* Line is off hook */
+#define AST_CONTROL_CONGESTION 8 /* Congestion (circuits busy) */
+#define AST_CONTROL_FLASH 9 /* Flash hook */
+#define AST_CONTROL_WINK 10 /* Wink */
+#define AST_CONTROL_OPTION 11 /* Set an option */
+
+#define AST_FRIENDLY_OFFSET 64 /* Reserved header space */
+
+struct ast_frame {
+ /*! Kind of frame */
+ int frametype;
+ /*! Subclass, frame dependent */
+ int subclass;
+ /*! Length of data */
+ int datalen;
+ /*! Number of 8khz samples in this frame */
+ int samples;
+ /*! Was the data malloc'd? i.e. should we free it when we discard the f
+rame? */
+ int mallocd;
+ /*! How far into "data" the data really starts */
+ int offset;
+ /*! Optional source of frame for debugging */
+ char *src;
+ /*! Pointer to actual data */
+ void *data;
+ /*! Next/Prev for linking stand alone frames */
+ struct ast_frame *prev;
+ /*! Next/Prev for linking stand alone frames */
+ struct ast_frame *next;
+ /* Unused except
+ if debugging is turned on, but left
+ in the struct
+ so that it can be turned on without
+ requiring a r
+ecompile of the whole thing */
+};
+
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+
+#endif
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax-client.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax-client.h Thu May 8 19:25:36 2008
@@ -0,0 +1,244 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Inter-Asterisk eXchange
+ *
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser General Public License (LGPL)
+ */
+
+#ifndef _ASTERISK_IAX_CLIENT_H
+#define _ASTERISK_IAX_CLIENT_H
+
+#ifdef WIN32_TIME_GET_TIME
+#include <Mmsystem.h>
+#endif
+
+#if defined(_MSC_VER)
+/* disable zero-sized array in struct/union warning */
+#pragma warning(disable:4200)
+#endif
+
+#if !defined(LINUX) && !defined(NETBSD)
+#define socklen_t int
+#endif
+
+#include "frame.h"
+#include "iax2.h"
+#include "iax2-parser.h"
+
+#define MAXSTRLEN 80
+
+#define IAX_AUTHMETHOD_PLAINTEXT IAX_AUTH_PLAINTEXT
+#define IAX_AUTHMETHOD_MD5 IAX_AUTH_MD5
+
+extern char iax_errstr[];
+
+struct iax_session;
+
+
+#define IAX_EVENT_CONNECT 0 /* Connect a new call */
+#define IAX_EVENT_ACCEPT 1 /* Accept a call */
+#define IAX_EVENT_HANGUP 2 /* Hang up a call */
+#define IAX_EVENT_REJECT 3 /* Rejected call */
+#define IAX_EVENT_VOICE 4 /* Voice Data */
+#define IAX_EVENT_DTMF 5 /* A DTMF Tone */
+#define IAX_EVENT_TIMEOUT 6 /* Connection timeout... session will be
+ a pointer to free()'d memory! */
+#define IAX_EVENT_LAGRQ 7 /* Lag request -- Internal use only */
+#define IAX_EVENT_LAGRP 8 /* Lag Measurement. See event.lag */
+#define IAX_EVENT_RINGA 9 /* Announce we/they are ringing */
+#define IAX_EVENT_PING 10 /* Ping -- internal use only */
+#define IAX_EVENT_PONG 11 /* Pong -- internal use only */
+#define IAX_EVENT_BUSY 12 /* Report a line busy */
+#define IAX_EVENT_ANSWER 13 /* Answer the line */
+
+#define IAX_EVENT_IMAGE 14 /* Send/Receive an image */
+#define IAX_EVENT_AUTHRQ 15 /* Authentication request */
+#define IAX_EVENT_AUTHRP 16 /* Authentication reply */
+
+#define IAX_EVENT_REGREQ 17 /* Registration request */
+#define IAX_EVENT_REGACK 18 /* Registration reply */
+#define IAX_EVENT_URL 19 /* URL received */
+#define IAX_EVENT_LDCOMPLETE 20 /* URL loading complete */
+
+#define IAX_EVENT_TRANSFER 21 /* Transfer has taken place */
+
+#define IAX_EVENT_DPREQ 22 /* Dialplan request */
+#define IAX_EVENT_DPREP 23 /* Dialplan reply */
+#define IAX_EVENT_DIAL 24 /* Dial on a TBD call */
+
+#define IAX_EVENT_QUELCH 25 /* Quelch Audio */
+#define IAX_EVENT_UNQUELCH 26 /* Unquelch Audio */
+
+#define IAX_EVENT_UNLINK 27 /* Unlink */
+#define IAX_EVENT_LINKREJECT 28 /* Link Rejection */
+#define IAX_EVENT_TEXT 29 /* Text Frame :-) */
+#define IAX_EVENT_REGREJ 30 /* Registration reply */
+#define IAX_EVENT_LINKURL 31 /* Unlink */
+#define IAX_EVENT_CNG 32 /* Comfort-noise (almost silence) */
+#define IAX_EVENT_POKE 33
+
+/* moved from iax.c to support attended transfer */
+#define IAX_EVENT_REREQUEST 999
+#define IAX_EVENT_TXREPLY 1000
+#define IAX_EVENT_TXREJECT 1001
+#define IAX_EVENT_TXACCEPT 1002
+#define IAX_EVENT_TXREADY 1003
+
+#define IAX_SCHEDULE_FUZZ 0 /* ms of fuzz to drop */
+
+#ifdef WIN32
+#if defined(_MSC_VER)
+typedef int (__stdcall *sendto_t)(SOCKET, const char *, int, int, const struct sockaddr *, int);
+typedef int (__stdcall *recvfrom_t)(SOCKET, char *, int, int, struct sockaddr *, int *);
+#else
+typedef int PASCAL (*sendto_t)(SOCKET, const char *, int, int, const struct sockaddr *, int);
+typedef int PASCAL (*recvfrom_t)(SOCKET, char *buf, int len, int flags, struct sockaddr *from, int *fromlen);
+#endif
+#else
+typedef int (*sendto_t)(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
+typedef int (*recvfrom_t)(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
+#endif
+
+struct iax_event {
+ int etype; /* Type of event */
+ int subclass; /* Subclass data (event specific) */
+ time_in_ms_t ts; /* Timestamp */
+ struct iax_session *session; /* Applicable session */
+ int datalen; /* Length of raw data */
+ struct iax_ies ies; /* IE's for IAX2 frames */
+ unsigned char data[]; /* Raw data if applicable */
+};
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* All functions return 0 on success and -1 on failure unless otherwise
+ specified */
+
+/* Called to initialize IAX structures and sockets. Returns actual
+ portnumber (which it will try preferred portno first, but if not
+ take what it can get */
+extern int iax_init(char *ip, int preferredportno);
+
+extern int iax_shutdown(void);
+
+/* Get filedescriptor for IAX to use with select or gtk_input_add */
+extern int iax_get_fd(void);
+
+/* Find out how many milliseconds until the next scheduled event */
+extern time_in_ms_t iax_time_to_next_event(void);
+
+/* Generate a new IAX session */
+extern struct iax_session *iax_session_new(void);
+
+/* Return exactly one iax event (if there is one pending). If blocking is
+ non-zero, IAX will block until some event is received */
+extern struct iax_event *iax_get_event(int blocking);
+
+
+extern int iax_auth_reply(struct iax_session *session, char *password,
+ char *challenge, int methods);
+
+/* Free an event */
+extern void iax_event_free(struct iax_event *event);
+
+struct sockaddr_in;
+
+/* Front ends for sending events */
+extern int iax_send_dtmf(struct iax_session *session, char digit);
+extern int iax_send_voice(struct iax_session *session, int format, unsigned char *data, int datalen, int samples);
+extern int iax_send_cng(struct iax_session *session, int level, unsigned char *data, int datalen);
+extern int iax_send_image(struct iax_session *session, int format, unsigned char *data, int datalen);
+extern int iax_send_url(struct iax_session *session, char *url, int link);
+extern int iax_send_text(struct iax_session *session, char *text);
+extern int iax_send_ping(struct iax_session *session);
+extern int iax_load_complete(struct iax_session *session);
+extern int iax_reject(struct iax_session *session, const char *reason);
+int iax_reject_registration(struct iax_session *session, char *reason);
+int iax_ack_registration(struct iax_session *session);
+int iax_auth_registration(struct iax_session *session);
+extern int iax_busy(struct iax_session *session);
+extern int iax_congestion(struct iax_session *session);
+extern int iax_hangup(struct iax_session *session, char *byemsg);
+extern int iax_call(struct iax_session *session, const char *cidnum, const char *cidname, char *ich, char *lang, int wait, int format, int capability);
+extern int iax_accept(struct iax_session *session, int format);
+extern int iax_answer(struct iax_session *session);
+extern int iax_sendurl(struct iax_session *session, char *url);
+extern int iax_send_unlink(struct iax_session *session);
+extern int iax_send_link_reject(struct iax_session *session);
+extern int iax_ring_announce(struct iax_session *session);
+extern struct sockaddr_in iax_get_peer_addr(struct iax_session *session);
+extern int iax_register(struct iax_session *session, char *hostname, char *peer, char *secret, int refresh);
+extern int iax_lag_request(struct iax_session *session);
+extern int iax_dial(struct iax_session *session, char *number); /* Dial on a TBD call */
+extern int iax_dialplan_request(struct iax_session *session, char *number); /* Request dialplan status for number */
+extern int iax_quelch(struct iax_session *session);
+extern int iax_unquelch(struct iax_session * session);
+extern int iax_transfer(struct iax_session *session, char *number);
+extern int iax_quelch_moh(struct iax_session *session, int MOH);
+
+extern void iax_destroy(struct iax_session * session);
+
+extern void iax_enable_debug(void);
+extern void iax_disable_debug(void);
+
+/* For attended transfer, application create a new session,
+ * make a call on the new session.
+ * On answer of the new session, call iax_setup_transfer and wait for
+ * IAX_EVENT_TXREADY when both sides are completed succefully or
+ * IAX_EVENT_TXREJECT for either side.
+ * If there are music on hold the it will be stopped by this library.
+ */
+extern int iax_setup_transfer(struct iax_session *s0, struct iax_session *s1);
+
+struct iax_netstat {
+ time_in_ms_t jitter;
+ int losspct;
+ int losscnt;
+ int packets;
+ time_in_ms_t delay;
+ int dropped;
+ int ooo;
+};
+/* fills in rtt, and an iax_netstat structure for each of local/remote directions of call */
+extern int iax_get_netstats(struct iax_session *s, time_in_ms_t *rtt, struct iax_netstat *local, struct iax_netstat *remote);
+
+
+extern void iax_set_private(struct iax_session *s, void *pvt);
+extern void *iax_get_private(struct iax_session *s);
+extern void iax_set_sendto(struct iax_session *s, sendto_t sendto);
+
+/* to use application networking instead of internal, set call this instead of iax_init,
+ * and pass in sendto and recvfrom replacements. blocking reads may not be implemented */
+extern void iax_set_networking(sendto_t st, recvfrom_t rf);
+
+/* destroy an iax session */
+extern void iax_session_destroy(struct iax_session **session);
+
+/* Handle externally received frames */
+struct iax_event *iax_net_process(unsigned char *buf, int len, struct sockaddr_in *sin);
+extern unsigned int iax_session_get_capability(struct iax_session *s);
+extern char iax_pref_codec_add(struct iax_session *session, unsigned int format);
+extern void iax_pref_codec_del(struct iax_session *session, unsigned int format);
+extern int iax_pref_codec_get(struct iax_session *session, unsigned int *array, int len);
+
+/* Fine tune jitterbuffer */
+extern void iax_set_jb_target_extra( long value );
+
+extern char *iax_get_peer_ip(struct iax_session *session);
+extern char *iax_event_get_apparent_ip(struct iax_event *event);
+extern void iax_set_samplerate(struct iax_session *session, unsigned short samplemask);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _ASTERISK_IAX_CLIENT_H */
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.c Thu May 8 19:25:36 2008
@@ -0,0 +1,124 @@
+/*
+ * Simple Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer.
+ *
+ */
+
+#define _XOPEN_SOURCE 600
+#include <stdlib.h>
+#include "iax-mutex.h"
+
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+struct mutex {
+ CRITICAL_SECTION mutex;
+};
+
+#else
+
+#include <pthread.h>
+struct mutex {
+ pthread_mutex_t mutex;
+};
+
+#endif
+
+
+mutex_status_t iax_mutex_create(mutex_t **mutex)
+{
+ mutex_status_t status = MUTEX_FAILURE;
+#ifndef WIN32
+ pthread_mutexattr_t attr;
+#endif
+ mutex_t *check = NULL;
+
+ check = (mutex_t *)malloc(sizeof(**mutex));
+ if (!check)
+ goto done;
+#ifdef WIN32
+ InitializeCriticalSection(&check->mutex);
+#else
+ if (pthread_mutexattr_init(&attr))
+ goto done;
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
+ goto fail;
+
+ if (pthread_mutex_init(&check->mutex, &attr))
+ goto fail;
+
+ goto success;
+
+fail:
+ pthread_mutexattr_destroy(&attr);
+ goto done;
+
+success:
+#endif
+ *mutex = check;
+ status = MUTEX_SUCCESS;
+
+done:
+ return status;
+}
+
+mutex_status_t iax_mutex_destroy(mutex_t *mutex)
+{
+#ifdef WIN32
+ DeleteCriticalSection(&mutex->mutex);
+#else
+ if (pthread_mutex_destroy(&mutex->mutex))
+ return MUTEX_FAILURE;
+#endif
+ free(mutex);
+ return MUTEX_SUCCESS;
+}
+
+mutex_status_t iax_mutex_lock(mutex_t *mutex)
+{
+#ifdef WIN32
+ EnterCriticalSection(&mutex->mutex);
+#else
+ if (pthread_mutex_lock(&mutex->mutex))
+ return MUTEX_FAILURE;
+#endif
+ return MUTEX_SUCCESS;
+}
+
+mutex_status_t iax_mutex_trylock(mutex_t *mutex)
+{
+#ifdef WIN32
+ if (!TryEnterCriticalSection(&mutex->mutex))
+ return MUTEX_FAILURE;
+#else
+ if (pthread_mutex_trylock(&mutex->mutex))
+ return MUTEX_FAILURE;
+#endif
+ return MUTEX_SUCCESS;
+}
+
+mutex_status_t iax_mutex_unlock(mutex_t *mutex)
+{
+#ifdef WIN32
+ LeaveCriticalSection(&mutex->mutex);
+#else
+ if (pthread_mutex_unlock(&mutex->mutex))
+ return MUTEX_FAILURE;
+#endif
+ return MUTEX_SUCCESS;
+}
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.h Thu May 8 19:25:36 2008
@@ -0,0 +1,37 @@
+/*
+ * Simple Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer.
+ *
+ */
+
+
+#ifndef _SIMPLE_ABSTRACT_MUTEX_H
+#define _SIMPLE_ABSTRACT_MUTEX_H
+
+typedef struct mutex mutex_t;
+
+typedef enum mutex_status {
+ MUTEX_SUCCESS,
+ MUTEX_FAILURE
+} mutex_status_t;
+
+mutex_status_t iax_mutex_create(mutex_t **mutex);
+mutex_status_t iax_mutex_destroy(mutex_t *mutex);
+mutex_status_t iax_mutex_lock(mutex_t *mutex);
+mutex_status_t iax_mutex_trylock(mutex_t *mutex);
+mutex_status_t iax_mutex_unlock(mutex_t *mutex);
+
+#endif
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax.c Thu May 8 19:25:36 2008
@@ -0,0 +1,3366 @@
+ /*
+ * libiax: An implementation of Inter-Asterisk eXchange
+ *
+ * Copyright (C) 2001, Linux Support Services, Inc.
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ */
+
+#ifdef WIN32
+#undef __STRICT_ANSI__ //for strdup with ms
+
+#include <string.h>
+#include <process.h>
+#include <windows.h>
+#include <winsock.h>
+#include <time.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+#include <errno.h>
+#include <limits.h>
+
+
+#define snprintf _snprintf
+
+#if defined(_MSC_VER)
+#define close _close
+#define inline __inline
+#define strdup _strdup
+#endif
+
+void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
+#include "winpoop.h"
+
+#else
+
+#define _BSD_SOURCE 1
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <time.h>
+
+#endif
+
+#include "iax2.h"
+#include "iax-client.h"
+#include "md5.h"
+
+#ifdef NEWJB
+#include "jitterbuf.h"
+#endif
+#include "iax-mutex.h"
+/*
+ work around jitter-buffer shrinking in asterisk:
+ channels/chan_iax2.c:schedule_delivery() shrinks jitter buffer by 2.
+ this causes frames timestamped 1ms apart to ( sometimes ) be delivered
+ out of order, and results in garbled audio. our temporary fix is to increase
+ the minimum number of ( timestamped ) milliseconds between frames to 3 ( 2 + 1 ).
+*/
+#define IAX_MIN_TIMESTAMP_INCREMENT 3
+
+/* Define socket options for IAX2 sockets, based on platform
+ * availability of flags */
+#ifdef WIN32
+ #define IAX_SOCKOPTS 0
+#else
+ #ifdef LINUX
+ #define IAX_SOCKOPTS MSG_DONTWAIT | MSG_NOSIGNAL
+ #else
+ #define IAX_SOCKOPTS MSG_DONTWAIT
+ #endif
+#endif
+
+
+
+#ifdef SNOM_HACK
+/* The snom phone seems to improperly execute memset in some cases */
+#include "../../snom_phonecore2/include/snom_memset.h"
+#endif
+
+/* Voice TS Prediction causes libiax2 to clean up the timestamps on
+ * outgoing frames. It works best with either continuous voice, or
+ * callers who call iax_send_cng to indicate DTX for silence */
+#define USE_VOICE_TS_PREDICTION
+
+/* Define Voice Smoothing to try to make some judgements and adjust timestamps
+ on incoming packets to what they "ought to be" */
+
+#define VOICE_SMOOTHING
+#undef VOICE_SMOOTHING
+
+/* Define Drop Whole Frames to make IAX shrink its jitter buffer by dropping entire
+ frames rather than simply delivering them faster. Dropping encoded frames,
+ before they're decoded, usually leads to better results than dropping
+ decoded frames. */
+
+#define DROP_WHOLE_FRAMES
+
+#define MIN_RETRY_TIME 10
+#define MAX_RETRY_TIME 4000
+#define MEMORY_SIZE 1000
+
+#define TRANSFER_NONE 0
+#define TRANSFER_BEGIN 1
+#define TRANSFER_READY 2
+#define TRANSFER_REL 3
+
+#ifndef NEWJB
+/* No more than 4 seconds of jitter buffer */
+static int max_jitterbuffer = 4000;
+/* No more than 50 extra milliseconds of jitterbuffer than needed */
+static int max_extra_jitterbuffer = 50;
+/* To use or not to use the jitterbuffer */
+static int iax_use_jitterbuffer = 1;
+
+/* Dropcount (in per-MEMORY_SIZE) usually percent */
+static int iax_dropcount = 3;
+#endif
+
+/* UDP Socket (file descriptor) */
+static int netfd = -1;
+
+/* Max timeouts */
+static int maxretries = 10;
+
+/* configurable jitterbuffer options */
+static long jb_target_extra = -1;
+
+static int do_shutdown = 0;
+
+/* external global networking replacements */
+static sendto_t iax_sendto = (sendto_t) sendto;
+static recvfrom_t iax_recvfrom = (recvfrom_t) recvfrom;
+
+/* ping interval (seconds) */
+static int ping_time = 10;
+static void send_ping(void *session);
+
+struct iax_session {
+ /* Private data */
+ void *pvt;
+ /* session-local Sendto function */
+ sendto_t sendto;
+ /* Is voice quelched (e.g. hold) */
+ int quelch;
+ /* Codec Pref Order */
+ char codec_order[32];
+ /* Codec Pref Order Index*/
+ int codec_order_len;
+ /* Last received voice format */
+ int voiceformat;
+ /* Last transmitted voice format */
+ int svoiceformat;
+ /* Per session capability */
+ int capability;
+ /* Last received timestamp */
+ time_in_ms_t last_ts;
+ /* Last transmitted timestamp */
+ time_in_ms_t lastsent;
+ /* Last transmitted voice timestamp */
+ unsigned int lastvoicets;
+ /* Next predicted voice ts */
+ time_in_ms_t nextpred;
+ /* True if the last voice we transmitted was not silence/CNG */
+ int notsilenttx;
+ /* Our last measured ping time */
+ time_in_ms_t pingtime;
+ /* Address of peer */
+ struct sockaddr_in peeraddr;
+ /* Our call number */
+ int callno;
+ /* Peer's call number */
+ int peercallno;
+ /* Our next outgoing sequence number */
+ unsigned char oseqno;
+ /* Next sequence number they have not yet acknowledged */
+ unsigned char rseqno;
+ /* Our last received incoming sequence number */
+ unsigned char iseqno;
+ /* Last acknowledged sequence number */
+ unsigned char aseqno;
+ /* Peer supported formats */
+ int peerformats;
+ /* Time value that we base our transmission on */
+ time_in_ms_t offset;
+ /* Time value we base our delivery on */
+ time_in_ms_t rxcore;
+ /* History of lags */
+ int history[MEMORY_SIZE];
+ /* Current base jitterbuffer */
+ int jitterbuffer;
+ /* Informational jitter */
+ int jitter;
+ /* Measured lag */
+ int lag;
+ /* Current link state */
+ int state;
+ /* Peer name */
+ char peer[MAXSTRLEN];
+ /* Default Context */
+ char context[MAXSTRLEN];
+ /* Caller ID if available */
+ char callerid[MAXSTRLEN];
+ /* DNID */
+ char dnid[MAXSTRLEN];
+ /* Requested Extension */
+ char exten[MAXSTRLEN];
+ /* Expected Username */
+ char username[MAXSTRLEN];
+ /* Expected Secret */
+ char secret[MAXSTRLEN];
+ /* permitted authentication methods */
+ char methods[MAXSTRLEN];
+ /* MD5 challenge */
+ char challenge[12];
+#ifdef VOICE_SMOOTHING
+ unsigned int lastts;
+#endif
+ /* Refresh if applicable */
+ int refresh;
+
+ /* ping scheduler id */
+ int pingid;
+
+ /* Transfer stuff */
+ struct sockaddr_in transfer;
+ int transferring;
+ int transfercallno;
+ int transferid;
+ int transferpeer; /* for attended transfer */
+ int transfer_moh; /* for music on hold while performing attended transfer */
+
+#ifdef NEWJB
+ jitterbuf *jb;
+#endif
+ struct iax_netstat remote_netstats;
+
+ unsigned short samplemask;
+ /* For linking if there are multiple connections */
+ struct iax_session *next;
+};
+
+char iax_errstr[256];
+
+static void destroy_session(struct iax_session *session);
+
+#define IAXERROR snprintf(iax_errstr, sizeof(iax_errstr),
+
+#ifdef DEBUG_SUPPORT
+
+#ifdef DEBUG_DEFAULT
+static int debug = 1;
+#else
+static int debug = 0;
+#endif
+
+void iax_enable_debug(void)
+{
+ debug = 1;
+}
+
+void iax_disable_debug(void)
+{
+ debug = 0;
+}
+
+/* This is a little strange, but to debug you call DEBU(G "Hello World!\n"); */
+#ifdef WIN32
+#define G __FILE__, __LINE__, __FUNCTION__,
+#else
+#define G __FILE__, __LINE__, (const char *)__func__,
+#endif
+
+#define DEBU __debug
+static int __debug(char *file, int lineno, const char *func, char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ if (debug) {
+ fprintf(stderr, "%s line %d in %s: ", file, lineno, func);
+ vfprintf(stderr, fmt, args);
+ }
+ va_end(args);
+ return 0;
+}
+
+#else /* No debug support */
+
+#ifdef WIN32
+#define DEBU
+#else
+#define DEBU(...) (void)(0)
+#endif
+#define G
+#endif
+
+typedef void (*sched_func)(void *);
+
+struct iax_sched {
+ /* These are scheduled things to be delivered */
+ time_in_ms_t when;
+ /* If event is non-NULL then we're delivering an event */
+ struct iax_event *event;
+ /* If frame is non-NULL then we're transmitting a frame */
+ struct iax_frame *frame;
+ /* If func is non-NULL then we should call it */
+ sched_func func;
+ /* and pass it this argument */
+ void *arg;
+ /* Easy linking */
+ struct iax_sched *next;
+};
+
+static mutex_t *sched_mutex = NULL;
+static mutex_t *session_mutex = NULL;
+static struct iax_sched *schedq = NULL;
+static struct iax_session *sessions = NULL;
+static int callnums = 1;
+static int transfer_id = 1; /* for attended transfer */
+static int time_init = 0;
+
+static void init_time(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+ timeBeginPeriod(1);
+#endif
+ time_init = 1;
+}
+
+static void time_end(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+ timeEndPeriod(1);
+#endif
+ time_init = 0;
+}
+
+static time_in_ms_t current_time_in_ms(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+ return timeGetTime();
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+#endif
+}
+
+void iax_set_private(struct iax_session *s, void *ptr)
+{
+ s->pvt = ptr;
+}
+
+void *iax_get_private(struct iax_session *s)
+{
+ return s->pvt;
+}
+
+void iax_set_sendto(struct iax_session *s, sendto_t ptr)
+{
+ s->sendto = ptr;
+}
+
+
+unsigned int iax_session_get_capability(struct iax_session *s)
+{
+ return s->capability;
+}
+
+
+static int inaddrcmp(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
+{
+ return (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) || (sin1->sin_port != sin2->sin_port);
+}
+
+static int iax_sched_add(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, time_in_ms_t ms)
+{
+
+ /* Schedule event to be delivered to the client
+ in ms milliseconds from now, or a reliable frame to be retransmitted */
+ struct iax_sched *sched, *cur, *prev = NULL;
+
+ if (!event && !frame && !func) {
+ DEBU(G "No event, no frame, no func? what are we scheduling?\n");
+ return -1;
+ }
+
+
+ sched = (struct iax_sched*)malloc(sizeof(struct iax_sched));
+ if (sched) {
+ memset(sched, 0, sizeof(struct iax_sched));
+ sched->when = current_time_in_ms() + ms;
+ sched->event = event;
+ sched->frame = frame;
+ sched->func = func;
+ sched->arg = arg;
+ /* Put it in the list, in order */
+ iax_mutex_lock(sched_mutex);
+ cur = schedq;
+ while(cur && cur->when <= sched->when) {
+ prev = cur;
+ cur = cur->next;
+ }
+ sched->next = cur;
+ if (prev) {
+ prev->next = sched;
+ } else {
+ schedq = sched;
+ }
+ iax_mutex_unlock(sched_mutex);
+ return 0;
+ } else {
+ DEBU(G "Out of memory!\n");
+ return -1;
+ }
+}
+
+static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int all)
+{
+ struct iax_sched *cur, *tmp, *prev = NULL;
+ int ret = 0;
+
+ iax_mutex_lock(sched_mutex);
+ cur = schedq;
+ while (cur) {
+ if (cur->event == event && cur->frame == frame && cur->func == func && cur->arg == arg) {
+ if (prev)
+ prev->next = cur->next;
+ else
+ schedq = cur->next;
+ tmp = cur;
+ cur = cur->next;
+ free(tmp);
+ if (!all) {
+ ret = -1;
+ goto done;
+ }
+ } else {
+ prev = cur;
+ cur = cur->next;
+ }
+ }
+ done:
+ iax_mutex_unlock(sched_mutex);
+
+ return 0;
+
+}
+
+
+time_in_ms_t iax_time_to_next_event(void)
+{
+ struct iax_sched *cur = NULL;
+ time_in_ms_t minimum = 999999999;
+
+ iax_mutex_lock(sched_mutex);
+ cur = schedq;
+
+ /* If there are no pending events, we don't need to timeout */
+ if (!cur) {
+ iax_mutex_unlock(sched_mutex);
+ return -1;
+ }
+ while(cur) {
+ if (cur->when < minimum) {
+ minimum = cur->when;
+ }
+ cur = cur->next;
+ }
+ iax_mutex_unlock(sched_mutex);
+
+ if (minimum <= 0) {
+ return -1;
+ }
+
+
+
+ return minimum - current_time_in_ms();
+}
+
+struct iax_session *iax_session_new(void)
+{
+ struct iax_session *s;
+ s = (struct iax_session *)malloc(sizeof(struct iax_session));
+ if (s) {
+ memset(s, 0, sizeof(struct iax_session));
+ /* Initialize important fields */
+ s->voiceformat = -1;
+ s->svoiceformat = -1;
+ /* Default pingtime to 30 ms */
+ s->pingtime = 30;
+ /* XXX Not quite right -- make sure it's not in use, but that won't matter
+ unless you've had at least 65k calls. XXX */
+ s->callno = callnums++;
+ if (callnums > 32767)
+ callnums = 1;
+ s->peercallno = 0;
+ s->transferpeer = 0; /* for attended transfer */
+
+ s->sendto = iax_sendto;
+ s->pingid = -1;
+#ifdef NEWJB
+ s->jb = jb_new();
+ {
+ jb_conf jbconf;
+ jbconf.max_jitterbuf = 0;
+ jbconf.resync_threshold = 1000;
+ jbconf.max_contig_interp = 0;
+ jbconf.target_extra = jb_target_extra;
+ jb_setconf(s->jb, &jbconf);
+ }
+#endif
+ iax_mutex_lock(session_mutex);
+ s->next = sessions;
+ sessions = s;
+ iax_mutex_unlock(session_mutex);
+ }
+ return s;
+}
+
+static int iax_session_valid(struct iax_session *session)
+{
+ /* Return -1 on a valid iax session pointer, 0 on a failure */
+ struct iax_session *cur;
+
+ iax_mutex_lock(session_mutex);
+ cur = sessions;
+ while(cur) {
+ if (session == cur) {
+ iax_mutex_unlock(session_mutex);
+ return -1;
+ }
+ cur = cur->next;
+ }
+ iax_mutex_unlock(session_mutex);
+
+ return 0;
+}
+
+int iax_get_netstats(struct iax_session *session, time_in_ms_t *rtt, struct iax_netstat *local, struct iax_netstat *remote) {
+
+ if(!iax_session_valid(session)) return -1;
+
+ *rtt = session->pingtime;
+
+ *remote = session->remote_netstats;
+
+#ifdef NEWJB
+ {
+ jb_info stats;
+ jb_getinfo(session->jb, &stats);
+
+ local->jitter = stats.jitter;
+ /* XXX: should be short-term loss pct.. */
+ if(stats.frames_in == 0) stats.frames_in = 1;
+ local->losspct = stats.losspct/1000;
+ local->losscnt = stats.frames_lost;
+ local->packets = stats.frames_in;
+ local->delay = stats.current - stats.min;
+ local->dropped = stats.frames_dropped;
+ local->ooo = stats.frames_ooo;
+ }
+#endif
+ return 0;
+}
+
+static time_in_ms_t calc_timestamp(struct iax_session *session, time_in_ms_t ts, struct ast_frame *f)
+{
+ time_in_ms_t ms;
+ time_in_ms_t time_in_ms;
+ int voice = 0;
+ int genuine = 0;
+
+ if (f && f->frametype == AST_FRAME_VOICE) {
+ voice = 1;
+ } else if (!f || f->frametype == AST_FRAME_IAX) {
+ genuine = 1;
+ }
+
+ /* If this is the first packet we're sending, get our
+ offset now. */
+ if (!session->offset) {
+ session->offset = current_time_in_ms();
+ }
+ /* If the timestamp is specified, just use their specified
+ timestamp no matter what. Usually this is done for
+ special cases. */
+ if (ts) {
+ return ts;
+ }
+ /* Otherwise calculate the timestamp from the current time */
+ time_in_ms = current_time_in_ms();
+
+
+ /* Calculate the number of milliseconds since we sent the first packet */
+ ms = time_in_ms - session->offset;
+
+ if (ms < 0) {
+ ms = 0;
+ }
+
+ if(voice) {
+#ifdef USE_VOICE_TS_PREDICTION
+
+ /* If we haven't most recently sent silence, and we're
+ * close in time, use predicted time */
+ if(session->notsilenttx && iax_abs(ms - session->nextpred) <= 240) {
+ /* Adjust our txcore, keeping voice and non-voice
+ * synchronized */
+ session->offset += (int)(ms - session->nextpred)/10;
+
+ if(!session->nextpred) {
+ session->nextpred = ms;
+ }
+ ms = session->nextpred;
+ } else {
+ /* in this case, just use the actual time, since
+ * we're either way off (shouldn't happen), or we're
+ * ending a silent period -- and seed the next predicted
+ * time. Also, round ms to the next multiple of
+ * frame size (so our silent periods are multiples
+ * of frame size too) */
+ time_in_ms_t diff = ms % (f->samples / 8);
+ if(diff)
+ ms += f->samples/8 - diff;
+ session->nextpred = ms;
+ }
+#else
+ if(ms <= session->lastsent)
+ ms = session->lastsent + 3;
+#endif
+ session->notsilenttx = 1;
+ } else {
+ /* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking)
+ if appropriate unless it's a genuine frame */
+ if (genuine) {
+ if (ms <= session->lastsent)
+ ms = session->lastsent + 3;
+ } else if (iax_abs(ms - session->lastsent) <= 240) {
+ ms = session->lastsent + 3;
+ }
+
+ }
+
+ /* Record the last sent packet for future reference */
+ /* unless an AST_FRAME_IAX */
+ if (!genuine)
+ session->lastsent = ms;
+
+#ifdef USE_VOICE_TS_PREDICTION
+ /* set next predicted ts based on 8khz samples */
+ if(voice)
+ session->nextpred = session->nextpred + f->samples / 8;
+#endif
+
+ return ms;
+}
+
+#ifdef NEWJB
+static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
+{
+ int byte = bit / 8; /* byte containing first bit */
+ int rem = 8 - (bit % 8); /* remaining bits in first byte */
+ unsigned char ret = 0;
+
+ if (n <= 0 || n > 8)
+ return 0;
+
+ if (rem < n) {
+ ret = (data[byte] << (n - rem));
+ ret |= (data[byte + 1] >> (8 - n + rem));
+ } else {
+ ret = (data[byte] >> (rem - n));
+ }
+
+ return (ret & (0xff >> (8 - n)));
+}
+
+static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
+{
+ static int SpeexWBSubModeSz[] = {
+ 0, 36, 112, 192,
+ 352, 0, 0, 0 };
+ int off = bit;
+ unsigned char c;
+
+ /* skip up to two wideband frames */
+ if (((len * 8 - off) >= 5) &&
+ get_n_bits_at(data, 1, off)) {
+ c = get_n_bits_at(data, 3, off + 1);
+ off += SpeexWBSubModeSz[c];
+
+ if (((len * 8 - off) >= 5) &&
+ get_n_bits_at(data, 1, off)) {
+ c = get_n_bits_at(data, 3, off + 1);
+ off += SpeexWBSubModeSz[c];
+
+ if (((len * 8 - off) >= 5) &&
+ get_n_bits_at(data, 1, off)) {
+ /* too many in a row */
+ DEBU(G "\tCORRUPT too many wideband streams in a row\n");
+ return -1;
+ }
+ }
+
+ }
+ return off - bit;
+}
+
+static int speex_get_samples(unsigned char *data, int len)
+{
+ static int SpeexSubModeSz[] = {
+ 0, 43, 119, 160,
+ 220, 300, 364, 492,
+ 79, 0, 0, 0,
+ 0, 0, 0, 0 };
+ static int SpeexInBandSz[] = {
+ 1, 1, 4, 4,
+ 4, 4, 4, 4,
+ 8, 8, 16, 16,
+ 32, 32, 64, 64 };
+ int bit = 0;
+ int cnt = 0;
+ int off = 0;
+ unsigned char c;
+
+ DEBU(G "speex_get_samples(%d)\n", len);
+ while ((len * 8 - bit) >= 5) {
+ /* skip wideband frames */
+ off = speex_get_wb_sz_at(data, len, bit);
+ if (off < 0) {
+ DEBU(G "\tERROR reading wideband frames\n");
+ break;
+ }
+ bit += off;
+
+ if ((len * 8 - bit) < 5) {
+ DEBU(G "\tERROR not enough bits left after wb\n");
+ break;
+ }
+
+ /* get control bits */
+ c = get_n_bits_at(data, 5, bit);
+ DEBU(G "\tCONTROL: %d at %d\n", c, bit);
+ bit += 5;
+
+ if (c == 15) {
+ DEBU(G "\tTERMINATOR\n");
+ break;
+ } else if (c == 14) {
+ /* in-band signal; next 4 bits contain signal id */
+ c = get_n_bits_at(data, 4, bit);
+ bit += 4;
+ DEBU(G "\tIN-BAND %d bits\n", SpeexInBandSz[c]);
+ bit += SpeexInBandSz[c];
+ } else if (c == 13) {
+ /* user in-band; next 5 bits contain msg len */
+ c = get_n_bits_at(data, 5, bit);
+ bit += 5;
+ DEBU(G "\tUSER-BAND %d bytes\n", c);
+ bit += c * 8;
+ } else if (c > 8) {
+ DEBU(G "\tUNKNOWN sub-mode %d\n", c);
+ break;
+ } else {
+ /* skip number bits for submode (less the 5 control bits) */
+ DEBU(G "\tSUBMODE %d %d bits\n", c, SpeexSubModeSz[c]);
+ bit += SpeexSubModeSz[c] - 5;
+
+ cnt += 160; /* new frame */
+ }
+ }
+ DEBU(G "\tSAMPLES: %d\n", cnt);
+ return cnt;
+}
+
+static inline int get_interp_len(int format)
+{
+ return (format == AST_FORMAT_ILBC) ? 30 : 20;
+}
+
+static int get_sample_cnt(struct iax_event *e)
+{
+ int cnt = 0;
+
+ /*
+ * In the case of zero length frames, do not return a cnt of 0
+ */
+ if ( e->datalen == 0 ) {
+ return get_interp_len( e->subclass ) * 8;
+ }
+
+ switch (e->subclass) {
+ case AST_FORMAT_SPEEX:
+ cnt = speex_get_samples(e->data, e->datalen);
+ break;
+ case AST_FORMAT_G723_1:
+ cnt = 240; /* FIXME Not always the case */
+ break;
+ case AST_FORMAT_ILBC:
+ cnt = 240 * (e->datalen / 50);
+ break;
+ case AST_FORMAT_GSM:
+ cnt = 160 * (e->datalen / 33);
+ break;
+ case AST_FORMAT_G729A:
+ cnt = 160 * (e->datalen / 20);
+ break;
+ case AST_FORMAT_SLINEAR:
+ cnt = e->datalen / 2;
+ break;
+ case AST_FORMAT_LPC10:
+ cnt = 22 * 8 + (((char *)(e->data))[7] & 0x1) * 8;
+ break;
+ case AST_FORMAT_ULAW:
+ case AST_FORMAT_ALAW:
+ cnt = e->datalen;
+ break;
+ case AST_FORMAT_ADPCM:
+ case AST_FORMAT_G726:
+ cnt = e->datalen * 2;
+ break;
+ default:
+ return 0;
+ }
+ return cnt;
+}
+#endif
+
+static int iax_xmit_frame(struct iax_frame *f)
+{
+ /* Send the frame raw */
+#ifdef DEBUG_SUPPORT
+ struct ast_iax2_full_hdr *h = (f->data);
+ if (ntohs(h->scallno) & IAX_FLAG_FULL)
+ iax_showframe(f, NULL, 0, f->transfer ?
+ &(f->session->transfer) :
+ &(f->session->peeraddr), f->datalen - sizeof(struct ast_iax2_full_hdr));
+#endif
+
+ return f->session->sendto(netfd, (const char *) f->data, f->datalen,
+ IAX_SOCKOPTS,
+ f->transfer ?
+ (struct sockaddr *)&(f->session->transfer) :
+ (struct sockaddr *)&(f->session->peeraddr), sizeof(f->session->peeraddr));
+}
+
+static int iax_reliable_xmit(struct iax_frame *f)
+{
+ struct iax_frame *fc;
+ struct ast_iax2_full_hdr *fh;
+ fh = (struct ast_iax2_full_hdr *) f->data;
+ if (!fh->type) {
+ DEBU(G "Asked to reliably transmit a non-packet. Crashing.\n");
+ *((char *)0)=0;
+ }
+ fc = (struct iax_frame *)malloc(sizeof(struct iax_frame));
+ if (fc) {
+ /* Make a copy of the frame */
+ memcpy(fc, f, sizeof(struct iax_frame));
+ /* And a copy of the data if applicable */
+ if (!fc->data || !fc->datalen) {
+ IAXERROR "No frame data?");
+ DEBU(G "No frame data?\n");
+ return -1;
+ } else {
+ fc->data = (char *)malloc(fc->datalen);
+ if (!fc->data) {
+ DEBU(G "Out of memory\n");
+ IAXERROR "Out of memory\n");
+ return -1;
+ }
+ memcpy(fc->data, f->data, f->datalen);
+ iax_sched_add(NULL, fc, NULL, NULL, fc->retrytime);
+ return iax_xmit_frame(fc);
+ }
+ } else
+ return -1;
+}
+
+void iax_set_networking(sendto_t st, recvfrom_t rf)
+{
+
+ init_time();
+ iax_sendto = st;
+ iax_recvfrom = rf;
+}
+
+int __iax_shutdown(void)
+{
+ struct iax_sched *sp, *fp;
+
+ /* Hangup Calls */
+ if (sessions) {
+ struct iax_session *sp = NULL, *fp = NULL;
+ iax_mutex_lock(session_mutex);
+ for(sp = sessions; sp ;) {
+ iax_hangup(sp, "System Shutdown");
+ fp = sp;
+ sp = sp->next;
+ destroy_session(fp);
+ }
+ iax_mutex_unlock(session_mutex);
+ }
+
+ /* Clear Scheduler */
+ iax_mutex_lock(sched_mutex);
+ for(sp = schedq; sp ;) {
+ fp = sp;
+ sp = sp->next;
+ free(fp);
+ }
+ iax_mutex_unlock(sched_mutex);
+
+ if (netfd > -1) {
+ shutdown(netfd, 2);
+ close(netfd);
+ }
+
+ time_end();
+
+ iax_mutex_destroy(sched_mutex);
+ iax_mutex_destroy(session_mutex);
+
+ return 0;
+}
+
+int iax_shutdown(void)
+{
+ return do_shutdown++;
+}
+
+void iax_set_jb_target_extra( long value )
+{
+ /* store in jb_target_extra, a static global */
+ jb_target_extra = value ;
+}
+
+int iax_init(char *ip, int preferredportno)
+{
+ int portno = preferredportno;
+ struct sockaddr_in sin;
+ unsigned int sinlen;
+ int flags;
+
+ init_time();
+
+ iax_mutex_create(&sched_mutex);
+ iax_mutex_create(&session_mutex);
+
+ if(iax_recvfrom == (recvfrom_t) recvfrom) {
+ if (netfd > -1) {
+ /* Sokay, just don't do anything */
+ DEBU(G "Already initialized.");
+ return 0;
+ }
+ netfd = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (netfd < 0) {
+ DEBU(G "Unable to allocate UDP socket\n");
+ IAXERROR "Unable to allocate UDP socket\n");
+ return -1;
+ }
+
+ if (preferredportno == 0) preferredportno = IAX_DEFAULT_PORTNO;
+ if (preferredportno < 0) preferredportno = 0;
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = 0;
+ sin.sin_port = htons((short)preferredportno);
+ if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0)
+ {
+#if defined(WIN32) || defined(_WIN32_WCE)
+ if (WSAGetLastError() == WSAEADDRINUSE)
+#else
+ if (errno == EADDRINUSE)
+#endif
+ {
+ /*the port is already in use, so bind to a free port chosen by the IP stack*/
+ DEBU(G "Unable to bind to preferred port - port is in use. Trying to bind to a free one");
+ sin.sin_port = htons((short)0);
+ if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0)
+ {
+ IAXERROR "Unable to bind UDP socket\n");
+ return -1;
+ }
+ } else
+ {
+ IAXERROR "Unable to bind UDP socket\n");
+ return -1;
+ }
+ }
+ sinlen = sizeof(sin);
+ if (getsockname(netfd, (struct sockaddr *) &sin, &sinlen) < 0) {
+ close(netfd);
+ netfd = -1;
+ DEBU(G "Unable to figure out what I'm bound to.");
+ IAXERROR "Unable to determine bound port number.");
+ }
+#ifdef WIN32
+ flags = 1;
+ if (ioctlsocket(netfd,FIONBIO,(unsigned long *) &flags)) {
+ closesocket(netfd);
+ netfd = -1;
+ DEBU(G "Unable to set non-blocking mode.");
+ IAXERROR "Unable to set non-blocking mode.");
+ }
+
+#else
+ if ((flags = fcntl(netfd, F_GETFL)) < 0) {
+ close(netfd);
+ netfd = -1;
+ DEBU(G "Unable to retrieve socket flags.");
+ IAXERROR "Unable to retrieve socket flags.");
+ }
+ if (fcntl(netfd, F_SETFL, flags | O_NONBLOCK) < 0) {
+ close(netfd);
+ netfd = -1;
+ DEBU(G "Unable to set non-blocking mode.");
+ IAXERROR "Unable to set non-blocking mode.");
+ }
+#endif
+ portno = ntohs(sin.sin_port);
+ }
+ srand((unsigned int)time(NULL));
+ callnums = rand() % 32767 + 1;
+ transfer_id = rand() % 32767 + 1;
+ DEBU(G "Started on port %d\n", portno);
+ return portno;
+}
+
+
+
+static void convert_reply(char *out, unsigned char *in)
+{
+ int x;
+ for (x=0;x<16;x++)
+ out += sprintf(out, "%2.2x", (int)in[x]);
+}
+
+static unsigned char compress_subclass(int subclass)
+{
+ int x;
+ int power=-1;
+ /* If it's 128 or smaller, just return it */
+ if (subclass < IAX_FLAG_SC_LOG)
+ return subclass;
+ /* Otherwise find its power */
+ for (x = 0; x < IAX_MAX_SHIFT; x++) {
+ if (subclass & (1 << x)) {
+ if (power > -1) {
+ DEBU(G "Can't compress subclass %d\n", subclass);
+ return 0;
+ } else
+ power = x;
+ }
+ }
+ return power | IAX_FLAG_SC_LOG;
+}
+
+static int iax_send(struct iax_session *pvt, struct ast_frame *f, time_in_ms_t ts, int seqno, int now, int transfer, int final)
+{
+ /* Queue a packet for delivery on a given private structure. Use "ts" for
+ timestamp, or calculate if ts is 0. Send immediately without retransmission
+ or delayed, with retransmission */
+ struct ast_iax2_full_hdr *fh;
+ struct ast_iax2_mini_hdr *mh;
+ unsigned char buf[5120];
+ struct iax_frame *fr;
+ int res;
+ int sendmini=0;
+ time_in_ms_t lastsent;
+ time_in_ms_t fts;
+
+ if (!pvt) {
+ IAXERROR "No private structure for packet?\n");
+ return -1;
+ }
+
+ /* this must come before the next call to calc_timestamp() since
+ calc_timestamp() will change lastsent to the returned value */
+ lastsent = pvt->lastsent;
+
+ /* Calculate actual timestamp */
+ fts = calc_timestamp(pvt, ts, f);
+
+ if (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L))
+ /* High two bits are the same on timestamp, or sending on a trunk */ &&
+ (f->frametype == AST_FRAME_VOICE)
+ /* is a voice frame */ &&
+ (f->subclass == pvt->svoiceformat)
+ /* is the same type */ ) {
+ /* Force immediate rather than delayed transmission */
+ now = 1;
+ /* Mark that mini-style frame is appropriate */
+ sendmini = 1;
+ }
+ /* Allocate an iax_frame */
+ if (now) {
+ fr = (struct iax_frame *) buf;
+ } else
+ fr = iax_frame_new(DIRECTION_OUTGRESS, f->datalen);
+ if (!fr) {
+ IAXERROR "Out of memory\n");
+ return -1;
+ }
+ /* Copy our prospective frame into our immediate or retransmitted wrapper */
+ iax_frame_wrap(fr, f);
+
+ fr->ts = fts;
+ if (!fr->ts) {
+ IAXERROR "timestamp is 0?\n");
+ if (!now)
+ iax_frame_free(fr);
+ return -1;
+ }
+
+ fr->callno = pvt->callno;
+ fr->transfer = transfer;
+ fr->final = final;
+ fr->session = pvt;
+ if (!sendmini) {
+ /* We need a full frame */
+ if (seqno > -1)
+ fr->oseqno = seqno;
+ else
+ fr->oseqno = pvt->oseqno++;
+ fr->iseqno = pvt->iseqno;
+ fh = (struct ast_iax2_full_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_full_hdr));
+ fh->scallno = htons(fr->callno | IAX_FLAG_FULL);
+ fh->ts = htonl((long)(fr->ts));
+ fh->oseqno = fr->oseqno;
+ if (transfer) {
+ fh->iseqno = 0;
+ } else
+ fh->iseqno = fr->iseqno;
+ /* Keep track of the last thing we've acknowledged */
+ pvt->aseqno = fr->iseqno;
+ fh->type = fr->af.frametype & 0xFF;
+ fh->csub = compress_subclass(fr->af.subclass);
+ if (transfer) {
+ fr->dcallno = pvt->transfercallno;
+ } else
+ fr->dcallno = pvt->peercallno;
+ fh->dcallno = htons(fr->dcallno);
+ fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_full_hdr);
+ fr->data = fh;
+ fr->retries = maxretries;
+ /* Retry after 2x the ping time has passed */
+ fr->retrytime = pvt->pingtime * 2;
+ if (fr->retrytime < MIN_RETRY_TIME)
+ fr->retrytime = MIN_RETRY_TIME;
+ if (fr->retrytime > MAX_RETRY_TIME)
+ fr->retrytime = MAX_RETRY_TIME;
+ /* Acks' don't get retried */
+ if ((f->frametype == AST_FRAME_IAX) && (f->subclass == IAX_COMMAND_ACK))
+ fr->retries = -1;
+ if (f->frametype == AST_FRAME_VOICE) {
+ pvt->svoiceformat = f->subclass;
+ }
+ if (now) {
+ res = iax_xmit_frame(fr);
+ } else
+ res = iax_reliable_xmit(fr);
+ } else {
+ /* Mini-frames have no sequence number */
+ fr->oseqno = -1;
+ fr->iseqno = -1;
+ /* Mini frame will do */
+ mh = (struct ast_iax2_mini_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_mini_hdr));
+ mh->callno = htons(fr->callno);
+ mh->ts = htons((short)(fr->ts & 0xFFFF));
+ fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr);
+ fr->data = mh;
+ fr->retries = -1;
+ res = iax_xmit_frame(fr);
+ }
+ if( !now && fr!=NULL )
+ iax_frame_free( fr );
+ return res;
+}
+
+#if 0
+static int iax_predestroy(struct iax_session *pvt)
+{
+ if (!pvt) {
+ return -1;
+ }
+ if (!pvt->alreadygone) {
+ /* 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->initid > -1)
+ ast_sched_del(sched, pvt->initid);
+ pvt->pingid = -1;
+ pvt->lagid = -1;
+ pvt->autoid = -1;
+ pvt->initid = -1;
+ pvt->alreadygone = 1;
+ }
+ return 0;
+}
+#endif
+
+static int __send_command(struct iax_session *i, char type, int command, time_in_ms_t ts, unsigned char *data, int datalen, int seqno,
+ int now, int transfer, int final, int samples)
+{
+ struct ast_frame f;
+ f.frametype = type;
+ f.subclass = command;
+ f.datalen = datalen;
+ f.samples = samples;
+ f.mallocd = 0;
+ f.offset = 0;
+#ifdef __GNUC__
+ f.src = (char *) __FUNCTION__;
+#else
+ f.src = (char *) __FILE__;
+#endif
+ f.data = data;
+ return iax_send(i, &f, ts, seqno, now, transfer, final);
+}
+
+static int send_command(struct iax_session *i, char type, int command, time_in_ms_t ts, unsigned char *data, int datalen, int seqno)
+{
+ return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, 0);
+}
+
+static int send_command_final(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno)
+{
+#if 0
+ /* It is assumed that the callno has already been locked */
+ iax_predestroy(i);
+#endif
+ int r;
+ r = __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0);
+ if (r >= 0) {
+ iax_mutex_lock(session_mutex);
+ destroy_session(i);
+ iax_mutex_unlock(session_mutex);
+ }
+ return r;
+}
+
+static int send_command_immediate(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno)
+{
+ return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0, 0);
+}
+
+static int send_command_transfer(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen)
+{
+ return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0, 0);
+}
+
+static int send_command_samples(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno, int samples)
+{
+ return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, samples);
+}
+
+
+int iax_transfer(struct iax_session *session, char *number)
+{
+ static int res; //Return Code
+ struct iax_ie_data ied; //IE Data Structure (Stuff To Send)
+
+ // Clear The Memory Used For IE Buffer
+ memset(&ied, 0, sizeof(ied));
+
+ // Copy The Transfer Destination Into The IE Structure
+ iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) number);
+
+ // Send The Transfer Command - Asterisk Will Handle The Rest!
+ res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
+
+ // Return Success
+ return 0;
+}
+
+static void stop_transfer(struct iax_session *session)
+{
+ struct iax_sched *sch;
+
+ iax_mutex_lock(sched_mutex);
+ sch = schedq;
+ while(sch) {
+ if (sch->frame && (sch->frame->session == session))
+ sch->frame->retries = -1;
+ sch = sch->next;
+ }
+ iax_mutex_unlock(sched_mutex);
+} /* stop_transfer */
+
+static void complete_transfer(struct iax_session *session, int peercallno, int xfr2peer, int preserveSeq)
+{
+ session->peercallno = peercallno;
+ /* Change from transfer to session now */
+ if (xfr2peer) {
+ memcpy(&session->peeraddr, &session->transfer, sizeof(session->peeraddr));
+ memset(&session->transfer, 0, sizeof(session->transfer));
+ session->transferring = TRANSFER_NONE;
+ session->transferpeer = 0;
+ session->transfer_moh = 0;
+ /* Force retransmission of a real voice packet, and reset all timing */
+ session->svoiceformat = -1;
+ session->voiceformat = 0;
+ }
+ session->rxcore = session->offset = 0;
+ memset(&session->history, 0, sizeof(session->history));
+#ifdef NEWJB
+ { /* Reset jitterbuffer */
+ jb_frame frame;
+ while(jb_getall(session->jb,&frame) == JB_OK)
+ iax_event_free(frame.data);
+
+ jb_reset(session->jb);
+ }
+#endif
+ session->jitterbuffer = 0;
+ session->jitter = 0;
+ session->lag = 0;
+
+ if (! preserveSeq)
+ {
+ /* Reset sequence numbers */
+ session->aseqno = 0;
+ session->oseqno = 0;
+ session->iseqno = 0;
+ }
+
+ session->lastsent = 0;
+ session->last_ts = 0;
+ session->lastvoicets = 0;
+ session->pingtime = 30;
+ /* We have to dump anything we were going to (re)transmit now that we've been
+ transferred since they're all invalid and for the old host. */
+ stop_transfer(session);
+} /* complete_transfer */
+
+int iax_setup_transfer(struct iax_session *org_session, struct iax_session *new_session)
+{
+ int res;
+ struct iax_ie_data ied0;
+ struct iax_ie_data ied1;
+
+ struct iax_session *s0 = org_session;
+ struct iax_session *s1 = new_session;
+
+ memset(&ied0, 0, sizeof(ied0));
+ memset(&ied1, 0, sizeof(ied1));
+
+ /* reversed setup */
+ iax_ie_append_addr(&ied0, IAX_IE_APPARENT_ADDR, &s1->peeraddr);
+ iax_ie_append_short(&ied0, IAX_IE_CALLNO, s1->peercallno);
+ iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, transfer_id);
+
+ iax_ie_append_addr(&ied1, IAX_IE_APPARENT_ADDR, &s0->peeraddr);
+ iax_ie_append_short(&ied1, IAX_IE_CALLNO, s0->peercallno);
+ iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, transfer_id);
+
+ s0->transfer = s1->peeraddr;
+ s1->transfer = s0->peeraddr;
+
+ s0->transferid = transfer_id;
+ s1->transferid = transfer_id;
+
+ s0->transfercallno = s0->peercallno;
+ s1->transfercallno = s1->peercallno;
+
+ s0->transferring = TRANSFER_BEGIN;
+ s1->transferring = TRANSFER_BEGIN;
+
+ s0->transferpeer = s1->callno;
+ s1->transferpeer = s0->callno;
+
+ transfer_id++;
+
+ if (transfer_id > 32767)
+ transfer_id = 1;
+
+ res = send_command(s0, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1);
+ if (res < 0) {
+ return -1;
+ }
+
+ res = send_command(s1, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1);
+ if (res < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int iax_finish_transfer(struct iax_session *s, short new_peer)
+{
+ int res;
+ struct iax_ie_data ied;
+
+ memset(&ied, 0, sizeof(ied));
+
+ iax_ie_append_short(&ied, IAX_IE_CALLNO, new_peer);
+
+ res = send_command(s, AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied.buf, ied.pos, -1);
+
+ complete_transfer(s, new_peer, 0, 1);
+
+ return res;
+
+}
+
+static struct iax_session *iax_find_session2(short callno)
+{
+ struct iax_session *cur;
+
+ iax_mutex_lock(session_mutex);
+ cur = sessions;
+ while(cur) {
+ if (callno == cur->callno && callno != 0) {
+ iax_mutex_unlock(session_mutex);
+ return cur;
+ }
+ cur = cur->next;
+ }
+ iax_mutex_unlock(session_mutex);
+
+ return NULL;
+}
+
+static int iax_handle_txready(struct iax_session *s)
+{
+ struct iax_session *s0, *s1;
+ short s0_org_peer, s1_org_peer;
+
+ if (s->transfer_moh) {
+ s->transfer_moh = 0;
+ iax_unquelch(s);
+ }
+
+ complete_transfer(s, s->peercallno, 0, 1);
+
+ s->transferring = TRANSFER_REL;
+
+ s0 = s;
+ s1 = iax_find_session2(s0->transferpeer);
+
+ if (s1 != NULL &&
+ s1->callno == s0->transferpeer &&
+ s0->transferring == TRANSFER_REL &&
+ s1->transferring == TRANSFER_REL) {
+
+ s0_org_peer = s0->peercallno;
+ s1_org_peer = s1->peercallno;
+
+ iax_finish_transfer(s0, s1_org_peer);
+ iax_finish_transfer(s1, s0_org_peer);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void iax_handle_txreject(struct iax_session *s)
+{
+ struct iax_session *s0, *s1;
+
+ s0 = s;
+ s1 = iax_find_session2(s0->transferpeer);
+ if (s1 != NULL &&
+ s0->transferpeer == s1->callno &&
+ s1->transferring) {
+ if (s1->transfer_moh) {
+ s1->transfer_moh = 0;
+ send_command_immediate(s1, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, s1->iseqno);
+ }
+ }
+ if (s0->transfer_moh) {
+ s0->transfer_moh = 0;
+ send_command_immediate(s0, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, s0->iseqno);
+ }
+
+ memset(&s->transfer, 0, sizeof(s->transfer));
+ s->transferring = TRANSFER_NONE;
+ s->transferpeer = 0;
+ s->transfer_moh = 0;
+}
+
+static void destroy_session(struct iax_session *session)
+{
+ struct iax_session *cur, *prev=NULL;
+ struct iax_sched *curs, *prevs=NULL, *nexts=NULL;
+ int loop_cnt=0;
+
+ iax_mutex_lock(sched_mutex);
+ curs = schedq;
+ while(curs) {
+ nexts = curs->next;
+ if (curs->frame && curs->frame->session == session) {
+ /* Just mark these frames as if they've been sent */
+ curs->frame->retries = -1;
+ } else if (curs->event && curs->event->session == session) {
+ if (prevs)
+ prevs->next = nexts;
+ else
+ schedq = nexts;
+ if (curs->event)
+ iax_event_free(curs->event);
+ free(curs);
+ } else {
+ prevs = curs;
+ }
+ curs = nexts;
+ loop_cnt++;
+ }
+ iax_mutex_unlock(sched_mutex);
+
+
+ cur = sessions;
+ while(cur) {
+ if (cur == session) {
+ if (prev)
+ prev->next = session->next;
+ else
+ sessions = session->next;
+#ifdef NEWJB
+ {
+ jb_frame frame;
+ while(jb_getall(session->jb,&frame) == JB_OK)
+ iax_event_free(frame.data);
+
+ jb_destroy(session->jb);
+ }
+#endif
+ free(session);
+ return;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+}
+
+static int iax_send_lagrp(struct iax_session *session, time_in_ms_t ts);
+static int iax_send_pong(struct iax_session *session, time_in_ms_t ts);
+
+static struct iax_event *handle_event(struct iax_event *event)
+{
+ /* We have a candidate event to be delievered. Be sure
+ the session still exists. */
+ if (event) {
+ if (iax_session_valid(event->session)) {
+ /* Lag requests are never actually sent to the client, but
+ other than that are handled as normal packets */
+ switch(event->etype) {
+ /* the user on the outside may need to look at the session so we will not free
+ it here anymore we will test for hangup event in iax_event_free and do it
+ there.
+ */
+ case IAX_EVENT_REJECT:
+ case IAX_EVENT_HANGUP:
+ return event;
+ case IAX_EVENT_LAGRQ:
+ event->etype = IAX_EVENT_LAGRP;
+ iax_send_lagrp(event->session, event->ts);
+ iax_event_free(event);
+ break;
+ case IAX_EVENT_PING:
+ event->etype = IAX_EVENT_PONG;
+ iax_send_pong(event->session, event->ts);
+ iax_event_free(event);
+ break;
+ case IAX_EVENT_POKE:
+ event->etype = IAX_EVENT_PONG;
+ iax_send_pong(event->session, event->ts);
+ iax_destroy(event->session);
+ iax_event_free(event);
+ break;
+ default:
+ return event;
+ }
+ } else
+ iax_event_free(event);
+ }
+ return NULL;
+}
+
+static int iax2_vnak(struct iax_session *session)
+{
+ return send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_VNAK, 0, NULL, 0, session->iseqno);
+}
+
+int iax_send_dtmf(struct iax_session *session, char digit)
+{
+ return send_command(session, AST_FRAME_DTMF, digit, 0, NULL, 0, -1);
+}
+
+int iax_send_voice(struct iax_session *session, int format, unsigned char *data, int datalen, int samples)
+{
+ /* Send a (possibly compressed) voice frame */
+ if (!session->quelch)
+ return send_command_samples(session, AST_FRAME_VOICE, format, 0, data, datalen, -1, samples);
+ return 0;
+}
+
+int iax_send_cng(struct iax_session *session, int level, unsigned char *data, int datalen)
+{
+ session->notsilenttx = 0;
+ return send_command(session, AST_FRAME_CNG, level, 0, data, datalen, -1);
+}
+
+int iax_send_image(struct iax_session *session, int format, unsigned char *data, int datalen)
+{
+ /* Send an image frame */
+ return send_command(session, AST_FRAME_IMAGE, format, 0, data, datalen, -1);
+}
+
+int iax_register(struct iax_session *session, char *server, char *peer, char *secret, int refresh)
+{
+ /* Send a registration request */
+ char tmp[256];
+ char *p;
+ int res;
+ int portno = IAX_DEFAULT_PORTNO;
+ struct iax_ie_data ied;
+ struct hostent *hp;
+
+ tmp[255] = '\0';
+ strncpy(tmp, server, sizeof(tmp) - 1);
+ p = strchr(tmp, ':');
+ if (p) {
+ *p = '\0';
+ portno = atoi(p+1);
+ }
+
+ memset(&ied, 0, sizeof(ied));
+ if (secret)
+ strncpy(session->secret, secret, sizeof(session->secret) - 1);
+ else
+ strcpy(session->secret, "");
+
+ /* Connect first */
+ hp = gethostbyname(tmp);
+ if (!hp) {
+ snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", tmp);
+ return -1;
+ }
+ memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr));
+ session->peeraddr.sin_port = htons(portno);
+ session->peeraddr.sin_family = AF_INET;
+ strncpy(session->username, peer, sizeof(session->username) - 1);
+ session->refresh = refresh;
+ iax_ie_append_str(&ied, IAX_IE_USERNAME, (unsigned char *) peer);
+ iax_ie_append_short(&ied, IAX_IE_REFRESH, refresh);
+ res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
+ return res;
+}
+
+int iax_reject_registration(struct iax_session *session, char *reason)
+{
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_str(&ied, IAX_IE_CAUSE, reason ? (unsigned char *) reason : (unsigned char *) "Unspecified");
+ return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGREJ, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_ack_registration(struct iax_session *session)
+{
+ return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, NULL, 0, -1);
+}
+
+int iax_auth_registration(struct iax_session *session)
+{
+ return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, NULL, 0, -1);
+}
+
+int iax_reject(struct iax_session *session, const char *reason)
+{
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_str(&ied, IAX_IE_CAUSE, reason ? (unsigned char *) reason : (unsigned char *) "Unspecified");
+ return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_hangup(struct iax_session *session, char *byemsg)
+{
+ struct iax_ie_data ied;
+ iax_sched_del(NULL, NULL, send_ping, (void *) session, 1);
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_str(&ied, IAX_IE_CAUSE, byemsg ? (unsigned char *) byemsg : (unsigned char *) "Normal clearing");
+ return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_HANGUP, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_sendurl(struct iax_session *session, char *url)
+{
+ return send_command(session, AST_FRAME_HTML, AST_HTML_URL, 0, (unsigned char *) url, (int)strlen(url), -1);
+}
+
+int iax_ring_announce(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_RINGING, 0, NULL, 0, -1);
+}
+
+int iax_lag_request(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
+}
+
+int iax_busy(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_BUSY, 0, NULL, 0, -1);
+}
+
+int iax_congestion(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_CONGESTION, 0, NULL, 0, -1);
+}
+
+
+int iax_accept(struct iax_session *session, int format)
+{
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_int(&ied, IAX_IE_FORMAT, format);
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_answer(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
+}
+
+int iax_load_complete(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_HTML, AST_HTML_LDCOMPLETE, 0, NULL, 0, -1);
+}
+
+int iax_send_url(struct iax_session *session, char *url, int link)
+{
+ return send_command(session, AST_FRAME_HTML, link ? AST_HTML_LINKURL : AST_HTML_URL, 0, (unsigned char *) url, (int)strlen(url), -1);
+}
+
+int iax_send_text(struct iax_session *session, char *text)
+{
+ return send_command(session, AST_FRAME_TEXT, 0, 0, (unsigned char *) text, (int)strlen(text) + 1, -1);
+}
+
+int iax_send_unlink(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_HTML, AST_HTML_UNLINK, 0, NULL, 0, -1);
+}
+
+int iax_send_link_reject(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_HTML, AST_HTML_LINKREJECT, 0, NULL, 0, -1);
+}
+
+static int iax_send_pong(struct iax_session *session, time_in_ms_t ts)
+{
+ struct iax_ie_data ied;
+
+ memset(&ied, 0, sizeof(ied));
+#ifdef NEWJB
+ {
+ jb_info stats;
+ jb_getinfo(session->jb, &stats);
+
+ iax_ie_append_int(&ied,IAX_IE_RR_JITTER, (int)stats.jitter);
+ /* XXX: should be short-term loss pct.. */
+ if(stats.frames_in == 0) stats.frames_in = 1;
+ iax_ie_append_int(&ied,IAX_IE_RR_LOSS,
+ ((0xff & (stats.losspct/1000)) << 24 | (stats.frames_lost & 0x00ffffff)));
+ iax_ie_append_int(&ied,IAX_IE_RR_PKTS, stats.frames_in);
+ iax_ie_append_short(&ied,IAX_IE_RR_DELAY, (unsigned short)(stats.current - stats.min));
+ iax_ie_append_int(&ied,IAX_IE_RR_DROPPED, stats.frames_dropped);
+ iax_ie_append_int(&ied,IAX_IE_RR_OOO, stats.frames_ooo);
+ }
+#else
+ iax_ie_append_int(&ied,IAX_IE_RR_JITTER, session->jitter);
+ /* don't know, don't send! iax_ie_append_int(&ied,IAX_IE_RR_LOSS, 0); */
+ /* don't know, don't send! iax_ie_append_int(&ied,IAX_IE_RR_PKTS, stats.frames_in); */
+ /* don't know, don't send! iax_ie_append_short(&ied,IAX_IE_RR_DELAY, stats.current - stats.min); */
+#endif
+
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_PONG, ts, ied.buf, ied.pos, -1);
+}
+
+/* external API; deprecated since we send pings ourselves now (finally) */
+int iax_send_ping(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
+}
+
+/* scheduled ping sender; sends ping, then reschedules */
+static void send_ping(void *s)
+{
+ struct iax_session *session = (struct iax_session *)s;
+
+ /* important, eh? */
+ if(!iax_session_valid(session)) return;
+
+ send_command(session, AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
+ session->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)session, ping_time * 1000);
+ return;
+}
+
+static int iax_send_lagrp(struct iax_session *session, time_in_ms_t ts)
+{
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_LAGRP, ts, NULL, 0, -1);
+}
+
+static int iax_send_txcnt(struct iax_session *session)
+{
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_int(&ied, IAX_IE_TRANSFERID, session->transferid);
+ return send_command_transfer(session, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
+}
+
+static int iax_send_txrej(struct iax_session *session)
+{
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_int(&ied, IAX_IE_TRANSFERID, session->transferid);
+ return send_command_transfer(session, AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied.buf, ied.pos);
+}
+
+static int iax_send_txaccept(struct iax_session *session)
+{
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_int(&ied, IAX_IE_TRANSFERID, session->transferid);
+ return send_command_transfer(session, AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, ied.buf, ied.pos);
+}
+
+static int iax_send_txready(struct iax_session *session)
+{
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ /* see asterisk chan_iax2.c */
+ iax_ie_append_short(&ied, IAX_IE_CALLNO, session->callno);
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_auth_reply(struct iax_session *session, char *password, char *challenge, int methods)
+{
+ char reply[16];
+ struct MD5Context md5;
+ char realreply[256];
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ if ((methods & IAX_AUTH_MD5) && challenge) {
+ MD5Init(&md5);
+ MD5Update(&md5, (const unsigned char *) challenge, (unsigned int)strlen(challenge));
+ MD5Update(&md5, (const unsigned char *) password, (unsigned int)strlen(password));
+ MD5Final((unsigned char *) reply, &md5);
+ memset(realreply, 0, sizeof(realreply));
+ convert_reply(realreply, (unsigned char *) reply);
+ iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, (unsigned char *) realreply);
+ } else {
+ iax_ie_append_str(&ied, IAX_IE_PASSWORD, (unsigned char *) password);
+ }
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_AUTHREP, 0, ied.buf, ied.pos, -1);
+}
+
+static int iax_regauth_reply(struct iax_session *session, char *password, char *challenge, int methods)
+{
+ char reply[16];
+ struct MD5Context md5;
+ char realreply[256];
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_str(&ied, IAX_IE_USERNAME, (unsigned char *) session->username);
+ iax_ie_append_short(&ied, IAX_IE_REFRESH, session->refresh);
+ if ((methods & IAX_AUTHMETHOD_MD5) && challenge) {
+ MD5Init(&md5);
+ MD5Update(&md5, (const unsigned char *) challenge, (unsigned int)strlen(challenge));
+ MD5Update(&md5, (const unsigned char *) password, (unsigned int)strlen(password));
+ MD5Final((unsigned char *) reply, &md5);
+ memset(realreply, 0, sizeof(realreply));
+ convert_reply(realreply, (unsigned char *) reply);
+ iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, (unsigned char *) realreply);
+ } else {
+ iax_ie_append_str(&ied, IAX_IE_PASSWORD, (unsigned char *) password);
+ }
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
+}
+
+
+int iax_dial(struct iax_session *session, char *number)
+{
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) number);
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_DIAL, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_quelch(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_QUELCH, 0, NULL, 0, -1);
+}
+
+int iax_unquelch(struct iax_session *session)
+{
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, -1);
+}
+
+int iax_dialplan_request(struct iax_session *session, char *number)
+{
+ struct iax_ie_data ied;
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) number);
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_DPREQ, 0, ied.buf, ied.pos, -1);
+}
+
+static inline int which_bit(unsigned int i)
+{
+ char x;
+ for(x = 0; x < 32; x++) {
+ if ((1 << x) == i) {
+ return x + 1;
+ }
+ }
+ return 0;
+}
+
+char iax_pref_codec_add(struct iax_session *session, unsigned int format)
+{
+ int diff = (int) 'A';
+ session->codec_order[session->codec_order_len++] = (which_bit(format)) + diff;
+ session->codec_order[session->codec_order_len] = '\0';
+ return session->codec_order[session->codec_order_len-1];
+}
+
+
+void iax_pref_codec_del(struct iax_session *session, unsigned int format)
+{
+ int diff = (int) 'A';
+ size_t x;
+ char old[32];
+ char remove = which_bit(format) + diff;
+
+ strncpy(old, session->codec_order, sizeof(old));
+ session->codec_order_len = 0;
+
+ for (x = 0; x < strlen(old) ; x++) {
+ if (old[x] != remove) {
+ session->codec_order[session->codec_order_len++] = old[x];
+ }
+ }
+ session->codec_order[session->codec_order_len] = '\0';
+}
+
+int iax_pref_codec_get(struct iax_session *session, unsigned int *array, int len)
+{
+ int diff = (int) 'A';
+ int x;
+
+ for (x = 0; x < session->codec_order_len && x < len; x++) {
+ array[x] = (1 << (session->codec_order[x] - diff - 1));
+ }
+
+ return x;
+}
+
+void iax_set_samplerate(struct iax_session *session, unsigned short samplemask)
+{
+ session->samplemask = samplemask;
+}
+
+
+int iax_call(struct iax_session *session, const char *cidnum, const char *cidname, char *ich, char *lang, int wait, int formats, int capabilities)
+{
+ char tmp[256]="";
+ char *part1, *part2;
+ int res;
+ int portno;
+ char *username, *hostname, *secret, *context, *exten, *dnid;
+ struct iax_ie_data ied;
+ struct hostent *hp;
+ /* We start by parsing up the temporary variable which is of the form of:
+ [user@]peer[:portno][/exten[@context]] */
+ if (!ich) {
+ IAXERROR "Invalid IAX Call Handle\n");
+ DEBU(G "Invalid IAX Call Handle\n");
+ return -1;
+ }
+ memset(&ied, 0, sizeof(ied));
+ strncpy(tmp, ich, sizeof(tmp) - 1);
+
+ iax_ie_append_short(&ied, IAX_IE_VERSION, IAX_PROTO_VERSION);
+ if (session->samplemask) {
+ iax_ie_append_short(&ied, IAX_IE_SAMPLINGRATE, session->samplemask);
+ }
+ if (cidnum)
+ iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, (unsigned char *) cidnum);
+ if (cidname)
+ iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, (unsigned char *) cidname);
+
+ if (session->codec_order_len) {
+ iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, (unsigned char *) session->codec_order);
+ }
+
+ session->capability = capabilities;
+ session->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)session, 2 * 1000);
+
+ /* XXX We should have a preferred format XXX */
+ iax_ie_append_int(&ied, IAX_IE_FORMAT, formats);
+ iax_ie_append_int(&ied, IAX_IE_CAPABILITY, capabilities);
+ if (lang)
+ iax_ie_append_str(&ied, IAX_IE_LANGUAGE, (unsigned char *) lang);
+
+ /* Part 1 is [user[:password]@]peer[:port] */
+ part1 = strtok(tmp, "/");
+
+ /* Part 2 is exten[@context] if it is anything all */
+ part2 = strtok(NULL, "/");
+
+ if (strchr(part1, '@')) {
+ username = strtok(part1, "@");
+ hostname = strtok(NULL, "@");
+ } else {
+ username = NULL;
+ hostname = part1;
+ }
+
+ if (username && strchr(username, ':')) {
+ username = strtok(username, ":");
+ secret = strtok(NULL, ":");
+ } else
+ secret = NULL;
+
+ if(username)
+ strncpy(session->username, username, sizeof(session->username) - 1);
+
+ if(secret)
+ strncpy(session->secret, secret, sizeof(session->secret) - 1);
+
+ if (strchr(hostname, ':')) {
+ strtok(hostname, ":");
+ portno = atoi(strtok(NULL, ":"));
+ } else {
+ portno = IAX_DEFAULT_PORTNO;
+ }
+ if (part2) {
+ exten = strtok(part2, "@");
+ dnid = exten;
+ context = strtok(NULL, "@");
+ } else {
+ exten = NULL;
+ dnid = NULL;
+ context = NULL;
+ }
+ if (username)
+ iax_ie_append_str(&ied, IAX_IE_USERNAME, (unsigned char *) username);
+ if (exten && strlen(exten))
+ iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) exten);
+ if (dnid && strlen(dnid))
+ iax_ie_append_str(&ied, IAX_IE_DNID, (unsigned char *) dnid);
+ if (context && strlen(context))
+ iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, (unsigned char *) context);
+
+ /* Setup host connection */
+ hp = gethostbyname(hostname);
+ if (!hp) {
+ snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", hostname);
+ return -1;
+ }
+ memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr));
+ session->peeraddr.sin_port = htons(portno);
+ session->peeraddr.sin_family = AF_INET;
+ res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_NEW, 0, ied.buf, ied.pos, -1);
+ if (res < 0)
+ return res;
+ if (wait) {
+ DEBU(G "Waiting not yet implemented\n");
+ return -1;
+ }
+ return res;
+}
+
+static time_in_ms_t calc_rxstamp(struct iax_session *session)
+{
+ time_in_ms_t time_in_ms;
+
+ time_in_ms = current_time_in_ms();
+
+ if (!session->rxcore) {
+ session->rxcore = time_in_ms;
+ }
+
+ return time_in_ms - session->rxcore;
+}
+
+#ifdef notdef_cruft
+static int match(struct sockaddr_in *sin, short callno, short dcallno, struct iax_session *cur)
+{
+ if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+ (cur->peeraddr.sin_port == sin->sin_port)) {
+ /* This is the main host */
+ if ((cur->peercallno == callno) ||
+ ((dcallno == cur->callno) && !cur->peercallno)) {
+ /* That's us. Be sure we keep track of the peer call number */
+ cur->peercallno = callno;
+ return 1;
+ }
+ }
+ if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+ (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+ /* We're transferring */
+ if (dcallno == cur->callno)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/* splitted match into 2 passes otherwise causing problem of matching
+ up the wrong session using the dcallno and the peercallno because
+ during a transfer (2 IAX channels on the same client/system) the
+ same peercallno (from two different asterisks) exist in more than
+ one session.
+ */
+static int forward_match(struct sockaddr_in *sin, short callno, short dcallno, struct iax_session *cur)
+{
+ if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+ (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+ /* We're transferring */
+ if (dcallno == cur->callno)
+ {
+ return 1;
+ }
+ }
+
+ if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+ (cur->peeraddr.sin_port == sin->sin_port)) {
+ if (dcallno == cur->callno && dcallno != 0) {
+ /* That's us. Be sure we keep track of the peer call number */
+ if (cur->peercallno == 0) {
+ cur->peercallno = callno;
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int reverse_match(struct sockaddr_in *sin, short callno, struct iax_session *cur)
+{
+ if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+ (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+ /* We're transferring */
+ if (callno == cur->peercallno) {
+ return 1;
+ }
+ }
+ if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+ (cur->peeraddr.sin_port == sin->sin_port)) {
+ if (callno == cur->peercallno) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static struct iax_session *iax_find_session(struct sockaddr_in *sin,
+ short callno,
+ short dcallno,
+ int makenew)
+{
+ struct iax_session *cur;
+
+ iax_mutex_lock(session_mutex);
+ cur = sessions;
+ while(cur) {
+ if (forward_match(sin, callno, dcallno, cur)) {
+ iax_mutex_unlock(session_mutex);
+ return cur;
+ }
+ cur = cur->next;
+ }
+
+ cur = sessions;
+ while(cur) {
+ if (reverse_match(sin, callno, cur)) {
+ iax_mutex_unlock(session_mutex);
+ return cur;
+ }
+ cur = cur->next;
+ }
+
+ iax_mutex_unlock(session_mutex);
+
+ if (makenew && !dcallno) {
+ cur = iax_session_new();
+ cur->peercallno = callno;
+ cur->peeraddr.sin_addr.s_addr = sin->sin_addr.s_addr;
+ cur->peeraddr.sin_port = sin->sin_port;
+ cur->peeraddr.sin_family = AF_INET;
+ cur->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)cur, 2 * 1000);
+ DEBU(G "Making new session, peer callno %d, our callno %d\n", callno, cur->callno);
+ } else {
+ DEBU(G "No session, peer = %d, us = %d\n", callno, dcallno);
+ }
+
+ return cur;
+}
+
+#ifdef EXTREME_DEBUG
+static int display_time(int ms)
+{
+ static int oldms = -1;
+ if (oldms < 0) {
+ DEBU(G "First measure\n");
+ oldms = ms;
+ return 0;
+ }
+ DEBU(G "Time from last frame is %d ms\n", ms - oldms);
+ oldms = ms;
+ return 0;
+}
+#endif
+
+#define FUDGE 1
+
+#ifdef NEWJB
+/* From chan_iax2/steve davies: need to get permission from steve or digium, I guess */
+static time_in_ms_t unwrap_timestamp(time_in_ms_t ts, time_in_ms_t last)
+{
+ time_in_ms_t x;
+
+ if ( (ts & 0xFFFF0000) == (last & 0xFFFF0000) ) {
+ x = ts - last;
+ if (x < -50000) {
+ /* Sudden big jump backwards in timestamp:
+ What likely happened here is that miniframe timestamp has circled but we haven't
+ gotten the update from the main packet. We'll just pretend that we did, and
+ update the timestamp appropriately. */
+ ts = ( (last & 0xFFFF0000) + 0x10000) | (ts & 0xFFFF);
+ DEBU(G "schedule_delivery: pushed forward timestamp\n");
+ }
+ if (x > 50000) {
+ /* Sudden apparent big jump forwards in timestamp:
+ What's likely happened is this is an old miniframe belonging to the previous
+ top-16-bit timestamp that has turned up out of order.
+ Adjust the timestamp appropriately. */
+ ts = ( (last & 0xFFFF0000) - 0x10000) | (ts & 0xFFFF);
+ DEBU(G "schedule_delivery: pushed back timestamp\n");
+ }
+ }
+ return ts;
+}
+#endif
+
+
+static struct iax_event *schedule_delivery(struct iax_event *e, time_in_ms_t ts, int updatehistory)
+{
+ /*
+ * This is the core of the IAX jitterbuffer delivery mechanism:
+ * Dynamically adjust the jitterbuffer and decide how time_in_ms_t to wait
+ * before delivering the packet.
+ */
+#ifndef NEWJB
+ int ms, x;
+ int drops[MEMORY_SIZE];
+ int min, max=0, maxone=0, y, z, match;
+#endif
+
+#ifdef EXTREME_DEBUG
+ DEBU(G "[%p] We are at %d, packet is for %d\n", e->session, calc_rxstamp(e->session), ts);
+#endif
+
+#ifdef VOICE_SMOOTHING
+ if (e->etype == IAX_EVENT_VOICE) {
+ /* Smooth voices if we know enough about the format */
+ switch(e->event.voice.format) {
+ case AST_FORMAT_GSM:
+ /* GSM frames are 20 ms long, although there could be periods of
+ silence. If the time is < 50 ms, assume it ought to be 20 ms */
+ if (ts - e->session->lastts < 50)
+ ts = e->session->lastts + 20;
+#ifdef EXTREME_DEBUG
+ display_time(ts);
+#endif
+ break;
+ default:
+ /* Can't do anything */
+ }
+ e->session->lastts = ts;
+ }
+#endif
+
+#ifdef NEWJB
+ {
+ int type = JB_TYPE_CONTROL;
+ int len = 0;
+
+ if(e->etype == IAX_EVENT_VOICE) {
+ type = JB_TYPE_VOICE;
+ len = get_sample_cnt(e) / 8;
+ } else if(e->etype == IAX_EVENT_CNG) {
+ type = JB_TYPE_SILENCE;
+ }
+
+ /* unwrap timestamp */
+ ts = unwrap_timestamp(ts,e->session->last_ts);
+
+ /* move forward last_ts if it's greater. We do this _after_ unwrapping, because
+ * asterisk _still_ has cases where it doesn't send full frames when it ought to */
+ if(ts > e->session->last_ts) {
+ e->session->last_ts = ts;
+ }
+
+
+ /* insert into jitterbuffer */
+ /* TODO: Perhaps we could act immediately if it's not droppable and late */
+ if(jb_put(e->session->jb, e, type, len, ts, calc_rxstamp(e->session)) == JB_DROP) {
+ iax_event_free(e);
+ }
+
+ }
+#else
+
+ /* How many ms from now should this packet be delivered? (remember
+ this can be a negative number, too */
+ ms = (int)(calc_rxstamp(e->session) - ts);
+
+ /*
+ Drop voice frame if timestamp is way off
+ if ((e->etype == IAX_EVENT_VOICE) && ((ms > 65536) || (ms < -65536))) {
+ DEBU(G "Dropping a voice packet with odd ts (ts = %d; ms = %d)\n", ts, ms);
+ free(e);
+ return NULL;
+ }
+ */
+
+ /* Adjust if voice frame timestamp is off by a step */
+ if (ms > 32768) {
+ /* What likely happened here is that our counter has circled but we haven't
+ gotten the update from the main packet. We'll just pretend that we did, and
+ update the timestamp appropriately. */
+ ms -= 65536;
+ }
+ if (ms < -32768) {
+ /* We got this packet out of order. Lets add 65536 to it to bring it into our new
+ time frame */
+ ms += 65536;
+ }
+
+#if 0
+ printf("rxstamp is %d, timestamp is %d, ms is %d\n", calc_rxstamp(e->session), ts, ms);
+#endif
+ /* Rotate history queue. Leading 0's are irrelevant. */
+ if (updatehistory) {
+ for (x=0; x < MEMORY_SIZE - 1; x++)
+ e->session->history[x] = e->session->history[x+1];
+
+ /* Add new entry for this time */
+ e->session->history[x] = ms;
+ }
+
+ /* We have to find the maximum and minimum time delay we've had to deliver. */
+ min = e->session->history[0];
+ for (z=0;z < iax_dropcount + 1; z++) {
+ /* We drop the top iax_dropcount entries. iax_dropcount represents
+ a tradeoff between quality of voice and latency. 3% drop seems to
+ be unnoticable to the client and can significantly improve latency.
+ We add one more to our droplist, but that's the one we actually use,
+ and don't drop. */
+ max = -99999999;
+ for (x=0;x<MEMORY_SIZE;x++) {
+ if (max < e->session->history[x]) {
+ /* New candidate value. Make sure we haven't dropped it. */
+ match=0;
+ for(y=0;!match && (y<z); y++)
+ match |= (drops[y] == x);
+ /* If there is no match, this is our new maximum */
+ if (!match) {
+ max = e->session->history[x];
+ maxone = x;
+ }
+ }
+ if (!z) {
+ /* First pass, calcualte our minimum, too */
+ if (min > e->session->history[x])
+ min = e->session->history[x];
+ }
+ }
+ drops[z] = maxone;
+ }
+ /* Again, just for reference. The "jitter buffer" is the max. The difference
+ is the perceived jitter correction. */
+ e->session->jitter = max - min;
+
+ /* If the jitter buffer is substantially too large, shrink it, slowly enough
+ that the client won't notice ;-) . */
+ if (max < e->session->jitterbuffer - max_extra_jitterbuffer) {
+#ifdef EXTREME_DEBUG
+ DEBU(G "Shrinking jitterbuffer (target = %d, current = %d...\n", max, e->session->jitterbuffer);
+#endif
+ e->session->jitterbuffer -= 1;
+ }
+
+ /* Keep the jitter buffer from becoming unreasonably large */
+ if (max > min + max_jitterbuffer) {
+ DEBU(G "Constraining jitter buffer (min = %d, max = %d)...\n", min, max);
+ max = min + max_jitterbuffer;
+ }
+
+ /* If the jitter buffer is too small, we immediately grow our buffer to
+ accomodate */
+ if (max > e->session->jitterbuffer)
+ e->session->jitterbuffer = max;
+
+ /* Start with our jitter buffer delay, and subtract the lateness (or earliness).
+ Remember these times are all relative to the first packet, so their absolute
+ values are really irrelevant. */
+ ms = e->session->jitterbuffer - ms - IAX_SCHEDULE_FUZZ;
+
+ /* If the jitterbuffer is disabled, always deliver immediately */
+ if (!iax_use_jitterbuffer)
+ ms = 0;
+
+ if (ms < 1) {
+#ifdef EXTREME_DEBUG
+ DEBU(G "Calculated delay is only %d\n", ms);
+#endif
+ if ((ms > -4) || (e->etype != IAX_EVENT_VOICE)) {
+ /* Return the event immediately if it's it's less than 3 milliseconds
+ too late, or if it's not voice (believe me, you don't want to
+ just drop a hangup frame because it's late, or a ping, or some such.
+ That kinda ruins retransmissions too ;-) */
+ /* Queue for immediate delivery */
+ iax_sched_add(e, NULL, NULL, NULL, 0);
+ return NULL;
+ //return e;
+ }
+ DEBU(G "(not so) Silently dropping a packet (ms = %d)\n", ms);
+ /* Silently discard this as if it were to be delivered */
+ free(e);
+ return NULL;
+ }
+ /* We need this to be delivered in the future, so we use our scheduler */
+ iax_sched_add(e, NULL, NULL, NULL, ms);
+#ifdef EXTREME_DEBUG
+ DEBU(G "Delivering packet in %d ms\n", ms);
+#endif
+#endif /* NEWJB */
+ return NULL;
+
+}
+
+static int uncompress_subclass(unsigned char csub)
+{
+ /* If the SC_LOG flag is set, return 2^csub otherwise csub */
+ if (csub & IAX_FLAG_SC_LOG)
+ return 1 << (csub & ~IAX_FLAG_SC_LOG & IAX_MAX_SHIFT);
+ else
+ return csub;
+}
+
+static inline char *extract(char *src, char *string)
+{
+ /* Extract and duplicate what we need from a string */
+ char *s, *t;
+ s = strstr(src, string);
+ if (s) {
+ s += strlen(string);
+ s = strdup(s);
+ /* End at ; */
+ t = strchr(s, ';');
+ if (t) {
+ *t = '\0';
+ }
+ }
+ return s;
+
+}
+
+static struct iax_event *iax_header_to_event(struct iax_session *session,
+ struct ast_iax2_full_hdr *fh,
+ int datalen, struct sockaddr_in *sin)
+{
+ struct iax_event *e;
+ struct iax_sched *sch;
+ unsigned int ts;
+ int subclass = uncompress_subclass(fh->csub);
+ time_in_ms_t nowts;
+ int updatehistory = 1;
+ ts = ntohl(fh->ts);
+ /* don't run last_ts backwards; i.e. for retransmits and the like */
+ if (ts > session->last_ts &&
+ (fh->type == AST_FRAME_IAX &&
+ subclass != IAX_COMMAND_ACK &&
+ subclass != IAX_COMMAND_PONG &&
+ subclass != IAX_COMMAND_LAGRP)) {
+ session->last_ts = ts;
+ }
+
+
+#ifdef DEBUG_SUPPORT
+ iax_showframe(NULL, fh, 1, sin, datalen);
+#endif
+
+ /* Get things going with it, timestamp wise, if we
+ haven't already. */
+
+ /* Handle implicit ACKing unless this is an INVAL, and only if this is
+ from the real peer, not the transfer peer */
+ if (!inaddrcmp(sin, &session->peeraddr) &&
+ (((subclass != IAX_COMMAND_INVAL)) ||
+ (fh->type != AST_FRAME_IAX))) {
+ unsigned char x;
+ /* XXX This code is not very efficient. Surely there is a better way which still
+ properly handles boundary conditions? XXX */
+ /* First we have to qualify that the ACKed value is within our window */
+ for (x=session->rseqno; x != session->oseqno; x++)
+ if (fh->iseqno == x)
+ break;
+ if ((x != session->oseqno) || (session->oseqno == fh->iseqno)) {
+ /* The acknowledgement is within our window. Time to acknowledge everything
+ that it says to */
+ for (x=session->rseqno; x != fh->iseqno; x++) {
+ /* Ack the packet with the given timestamp */
+ DEBU(G "Cancelling transmission of packet %d\n", x);
+ iax_mutex_lock(sched_mutex);
+ sch = schedq;
+ while(sch) {
+ if (sch->frame && (sch->frame->session == session) &&
+ (sch->frame->oseqno == x))
+ sch->frame->retries = -1;
+ sch = sch->next;
+ }
+ iax_mutex_unlock(sched_mutex);
+ }
+ /* Note how much we've received acknowledgement for */
+ session->rseqno = fh->iseqno;
+ } else
+ DEBU(G "Received iseqno %d not within window %d->%d\n", fh->iseqno, session->rseqno, session->oseqno);
+ }
+
+ /* Check where we are */
+ if ((ntohs(fh->dcallno) & IAX_FLAG_RETRANS) || (fh->type != AST_FRAME_VOICE))
+ updatehistory = 0;
+ if ((session->iseqno != fh->oseqno) &&
+ (session->iseqno ||
+ ((subclass != IAX_COMMAND_TXREADY) &&
+ (subclass != IAX_COMMAND_TXREL) &&
+ (subclass != IAX_COMMAND_TXCNT) &&
+ (subclass != IAX_COMMAND_TXACC)) ||
+ (fh->type != AST_FRAME_IAX))) {
+ if (
+ ((subclass != IAX_COMMAND_ACK) &&
+ (subclass != IAX_COMMAND_INVAL) &&
+ (subclass != IAX_COMMAND_TXREADY) &&
+ (subclass != IAX_COMMAND_TXREL) &&
+ (subclass != IAX_COMMAND_TXCNT) &&
+ (subclass != IAX_COMMAND_TXACC) &&
+ (subclass != IAX_COMMAND_VNAK)) ||
+ (fh->type != AST_FRAME_IAX)) {
+ /* If it's not an ACK packet, it's out of order. */
+ DEBU(G "Packet arrived out of order (expecting %d, got %d) (frametype = %d, subclass = %d)\n",
+ session->iseqno, fh->oseqno, fh->type, subclass);
+ if (session->iseqno > fh->oseqno) {
+ /* If we've already seen it, ack it XXX There's a border condition here XXX */
+ if ((fh->type != AST_FRAME_IAX) ||
+ ((subclass != IAX_COMMAND_ACK) && (subclass != IAX_COMMAND_INVAL))) {
+ DEBU(G "Acking anyway\n");
+ /* XXX Maybe we should handle its ack to us, but then again, it's probably outdated anyway, and if
+ we have anything to send, we'll retransmit and get an ACK back anyway XXX */
+ send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, ts, NULL, 0,fh->iseqno);
+ }
+ } else {
+ /* Send a VNAK requesting retransmission */
+ iax2_vnak(session);
+ }
+ return NULL;
+ }
+ } else {
+ /* Increment unless it's an ACK or VNAK */
+ if (((subclass != IAX_COMMAND_ACK) &&
+ (subclass != IAX_COMMAND_INVAL) &&
+ (subclass != IAX_COMMAND_TXCNT) &&
+ (subclass != IAX_COMMAND_TXACC) &&
+ (subclass != IAX_COMMAND_VNAK)) ||
+ (fh->type != AST_FRAME_IAX))
+ session->iseqno++;
+ }
+
+ e = (struct iax_event *)malloc(sizeof(struct iax_event) + datalen + 1);
+
+ if (e) {
+ memset(e, 0, sizeof(struct iax_event) + datalen);
+ /* Set etype to some unknown value so do not inavertently
+ sending IAX_EVENT_CONNECT event, which is 0 to application.
+ */
+ e->etype = -1;
+ e->session = session;
+ switch(fh->type) {
+ case AST_FRAME_DTMF:
+ e->etype = IAX_EVENT_DTMF;
+ e->subclass = subclass;
+ /*
+ We want the DTMF event deliver immediately so all I/O can be
+ terminate quickly in an IVR system.
+ e = schedule_delivery(e, ts, updatehistory); */
+ break;
+ case AST_FRAME_VOICE:
+ e->etype = IAX_EVENT_VOICE;
+ e->subclass = subclass;
+ session->voiceformat = subclass;
+ if (datalen) {
+ memcpy(e->data, fh->iedata, datalen);
+ e->datalen = datalen;
+ }
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case AST_FRAME_CNG:
+ e->etype = IAX_EVENT_CNG;
+ e->subclass = subclass;
+ if (datalen) {
+ memcpy(e->data, fh->iedata, datalen);
+ e->datalen = datalen;
+ }
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case AST_FRAME_IAX:
+ /* Parse IE's */
+ if (datalen) {
+ memcpy(e->data, fh->iedata, datalen);
+ e->datalen = datalen;
+ }
+ if (iax_parse_ies(&e->ies, e->data, e->datalen)) {
+ IAXERROR "Unable to parse IE's");
+ free(e);
+ e = NULL;
+ break;
+ }
+ switch(subclass) {
+ case IAX_COMMAND_NEW:
+ /* This is a new, incoming call */
+ /* save the capability for validation */
+ session->capability = e->ies.capability;
+ if (e->ies.codec_prefs) {
+ strncpy(session->codec_order, e->ies.codec_prefs, sizeof(session->codec_order));
+ session->codec_order_len = (int)strlen(session->codec_order);
+ }
+ e->etype = IAX_EVENT_CONNECT;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_AUTHREQ:
+ /* This is a request for a call */
+ e->etype = IAX_EVENT_AUTHRQ;
+ if (strlen(session->username) && !strcmp(e->ies.username, session->username) &&
+ strlen(session->secret)) {
+ /* Hey, we already know this one */
+ iax_auth_reply(session, session->secret, e->ies.challenge, e->ies.authmethods);
+ free(e);
+ e = NULL;
+ break;
+ }
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_HANGUP:
+ e->etype = IAX_EVENT_HANGUP;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_INVAL:
+ e->etype = IAX_EVENT_HANGUP;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_REJECT:
+ e->etype = IAX_EVENT_REJECT;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_ACK:
+ free(e);
+ e = NULL;
+ break;
+ case IAX_COMMAND_LAGRQ:
+ /* Pass this atime_in_ms_t for later handling */
+ e->etype = IAX_EVENT_LAGRQ;
+ e->ts = ts;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_POKE:
+ e->etype = IAX_EVENT_POKE;
+ e->ts = ts;
+ break;
+ case IAX_COMMAND_PING:
+ /* PINGS and PONGS don't get scheduled; */
+ e->etype = IAX_EVENT_PING;
+ e->ts = ts;
+ break;
+ case IAX_COMMAND_PONG:
+ e->etype = IAX_EVENT_PONG;
+ /* track weighted average of ping time */
+ session->pingtime = ((2 * session->pingtime) + (calc_timestamp(session,0,NULL) - ts)) / 3;
+ session->remote_netstats.jitter = e->ies.rr_jitter;
+ session->remote_netstats.losspct = e->ies.rr_loss >> 24;;
+ session->remote_netstats.losscnt = e->ies.rr_loss & 0xffffff;
+ session->remote_netstats.packets = e->ies.rr_pkts;
+ session->remote_netstats.delay = e->ies.rr_delay;
+ session->remote_netstats.dropped = e->ies.rr_dropped;
+ session->remote_netstats.ooo = e->ies.rr_ooo;
+ break;
+ case IAX_COMMAND_ACCEPT:
+ if (e->ies.format & session->capability) {
+ e->etype = IAX_EVENT_ACCEPT;
+ }
+ else {
+ struct iax_ie_data ied;
+ /* Although this should not happen, we added this to make sure
+ the negotiation protocol is enforced.
+ For lack of event to notify the application we use the defined
+ REJECT event.
+ */
+ memset(&ied, 0, sizeof(ied));
+ iax_ie_append_str(&ied, IAX_IE_CAUSE, (unsigned char *) "Unable to negotiate codec");
+ send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied.buf, ied.pos, -1);
+ e->etype = IAX_EVENT_REJECT;
+ }
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_REGREQ:
+ e->etype = IAX_EVENT_REGREQ;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_REGREL:
+ e->etype = IAX_EVENT_REGREQ;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_REGACK:
+ e->etype = IAX_EVENT_REGACK;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_REGAUTH:
+ iax_regauth_reply(session, session->secret, e->ies.challenge, e->ies.authmethods);
+ free(e);
+ e = NULL;
+ break;
+ case IAX_COMMAND_REGREJ:
+ e->etype = IAX_EVENT_REGREJ;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_LAGRP:
+ e->etype = IAX_EVENT_LAGRP;
+ nowts = calc_timestamp(session, 0, NULL);
+ e->ts = nowts - ts;
+ e->subclass = session->jitter;
+ /* Can't call schedule_delivery since timestamp is non-normal */
+ break;;
+ case IAX_COMMAND_TXREQ:
+ /* added check for defensive programming
+ * - in case the asterisk server
+ * or another client does not send the
+ * apparent transfer address
+ */
+ if (e->ies.apparent_addr != NULL) {
+ /* so a full voice frame is sent on the
+ next voice output */
+ session->svoiceformat = -1;
+ session->transfer = *e->ies.apparent_addr;
+ session->transfer.sin_family = AF_INET;
+ session->transfercallno = e->ies.callno;
+ session->transferring = TRANSFER_BEGIN;
+ session->transferid = e->ies.transferid;
+ iax_send_txcnt(session);
+ }
+ free(e);
+ e = NULL;
+ break;
+ case IAX_COMMAND_DPREP:
+ /* Received dialplan reply */
+ e->etype = IAX_EVENT_DPREP;
+ /* Return immediately, makes no sense to schedule */
+ break;
+ case IAX_COMMAND_TXCNT:
+ if (session->transferring) {
+ session->transfer = *sin;
+ iax_send_txaccept(session);
+ }
+ free(e);
+ e = NULL;
+ break;
+ case IAX_COMMAND_TXACC:
+ if (session->transferring) {
+ stop_transfer(session);
+ session->transferring = TRANSFER_READY;
+ iax_send_txready(session);
+ }
+ free(e);
+ e = NULL;
+ break;
+ case IAX_COMMAND_TXREL:
+ /* Release the transfer */
+ send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, fh->ts, NULL, 0, fh->iseqno);
+ if (session->transferring) {
+ complete_transfer(session, e->ies.callno, 1, 0);
+ }
+ else {
+ complete_transfer(session, session->peercallno, 0, 1);
+ }
+ e->etype = IAX_EVENT_TRANSFER;
+ /* notify that asterisk no longer sitting between peers */
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case IAX_COMMAND_QUELCH:
+ e->etype = IAX_EVENT_QUELCH;
+ session->quelch = 1;
+ break;
+ case IAX_COMMAND_UNQUELCH:
+ e->etype = IAX_EVENT_UNQUELCH;
+ session->quelch = 0;
+ break;
+ case IAX_COMMAND_TXREJ:
+ e->etype = IAX_EVENT_TXREJECT;
+ iax_handle_txreject(session);
+ break;
+
+ case IAX_COMMAND_TXREADY:
+ send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, ts, NULL, 0, fh->iseqno);
+ if (iax_handle_txready(session)) {
+ e->etype = IAX_EVENT_TXREADY;
+ }
+ else {
+ free(e);
+ e = NULL;
+ }
+ break;
+ default:
+ DEBU(G "Don't know what to do with IAX command %d\n", subclass);
+ free(e);
+ e = NULL;
+ }
+ break;
+ case AST_FRAME_CONTROL:
+ switch(subclass) {
+ case AST_CONTROL_ANSWER:
+ e->etype = IAX_EVENT_ANSWER;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case AST_CONTROL_CONGESTION:
+ case AST_CONTROL_BUSY:
+ e->etype = IAX_EVENT_BUSY;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case AST_CONTROL_RINGING:
+ e->etype = IAX_EVENT_RINGA;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ default:
+ DEBU(G "Don't know what to do with AST control %d\n", subclass);
+ free(e);
+ return NULL;
+ }
+ break;
+ case AST_FRAME_IMAGE:
+ e->etype = IAX_EVENT_IMAGE;
+ e->subclass = subclass;
+ if (datalen) {
+ memcpy(e->data, fh->iedata, datalen);
+ }
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+
+ case AST_FRAME_TEXT:
+ e->etype = IAX_EVENT_TEXT;
+ if (datalen) {
+ memcpy(e->data, fh->iedata, datalen);
+ }
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+
+ case AST_FRAME_HTML:
+ switch(fh->csub) {
+ case AST_HTML_LINKURL:
+ e->etype = IAX_EVENT_LINKURL;
+ /* Fall through */
+ case AST_HTML_URL:
+ if (e->etype == -1)
+ e->etype = IAX_EVENT_URL;
+ e->