[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->subclass = fh->csub;
+ e->datalen = datalen;
+ if (datalen) {
+ memcpy(e->data, fh->iedata, datalen);
+ }
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case AST_HTML_LDCOMPLETE:
+ e->etype = IAX_EVENT_LDCOMPLETE;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case AST_HTML_UNLINK:
+ e->etype = IAX_EVENT_UNLINK;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ case AST_HTML_LINKREJECT:
+ e->etype = IAX_EVENT_LINKREJECT;
+ e = schedule_delivery(e, ts, updatehistory);
+ break;
+ default:
+ DEBU(G "Don't know how to handle HTML type %d frames\n", fh->csub);
+ free(e);
+ return NULL;
+ }
+ break;
+ default:
+ DEBU(G "Don't know what to do with frame type %d\n", fh->type);
+ free(e);
+ return NULL;
+ }
+ } else
+ DEBU(G "Out of memory\n");
+
+ /* Already ack'd iax frames */
+ if (session->aseqno != session->iseqno) {
+ send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, ts, NULL, 0, fh->iseqno);
+ }
+ return e;
+}
+
+static struct iax_event *iax_miniheader_to_event(struct iax_session *session,
+ struct ast_iax2_mini_hdr *mh,
+ int datalen)
+{
+ struct iax_event *e;
+ time_in_ms_t ts;
+ int updatehistory = 1;
+ e = (struct iax_event *)malloc(sizeof(struct iax_event) + datalen);
+ if (e) {
+ if (session->voiceformat > 0) {
+ e->etype = IAX_EVENT_VOICE;
+ e->session = session;
+ e->subclass = session->voiceformat;
+ e->datalen = datalen;
+ if (datalen) {
+#ifdef EXTREME_DEBUG
+ DEBU(G "%d bytes of voice\n", datalen);
+#endif
+ memcpy(e->data, mh->data, datalen);
+ }
+ ts = (session->last_ts & 0xFFFF0000) | ntohs(mh->ts);
+ return schedule_delivery(e, ts, updatehistory);
+ } else {
+ DEBU(G "No last format received on session %d\n", session->callno);
+ free(e);
+ e = NULL;
+ }
+ } else
+ DEBU(G "Out of memory\n");
+ return e;
+}
+
+void iax_destroy(struct iax_session *session)
+{
+ iax_mutex_lock(session_mutex);
+ destroy_session(session);
+ iax_mutex_unlock(session_mutex);
+}
+
+static struct iax_event *iax_net_read(void)
+{
+ unsigned char buf[65536];
+ int res, sinlen;
+ struct sockaddr_in sin;
+
+ sinlen = sizeof(sin);
+ res = iax_recvfrom(netfd, buf, sizeof(buf), 0, (struct sockaddr *) &sin, &sinlen);
+
+ if (res < 0) {
+#ifdef WIN32
+ if (WSAGetLastError() != WSAEWOULDBLOCK) {
+ DEBU(G "Error on read: %d\n", WSAGetLastError());
+ IAXERROR "Read error on network socket: %s", strerror(errno));
+ }
+#else
+ if (errno != EAGAIN) {
+ DEBU(G "Error on read: %s\n", strerror(errno));
+ IAXERROR "Read error on network socket: %s", strerror(errno));
+ }
+#endif
+ return NULL;
+ }
+ return iax_net_process(buf, res, &sin);
+}
+
+static struct iax_session *iax_txcnt_session(struct ast_iax2_full_hdr *fh, int datalen,
+ struct sockaddr_in *sin, short callno, short dcallno)
+{
+ int subclass = uncompress_subclass(fh->csub);
+ unsigned char buf[ 65536 ]; /* allocated on stack with same size as iax_net_read() */
+ struct iax_ies ies;
+ struct iax_session *cur;
+
+ if ((fh->type != AST_FRAME_IAX) || (subclass != IAX_COMMAND_TXCNT) || (!datalen)) {
+ return NULL; /* special handling for TXCNT only */
+ }
+ memcpy(buf, fh->iedata, datalen); /* prepare local buf for iax_parse_ies() */
+
+ if (iax_parse_ies(&ies, buf, datalen)) {
+ return NULL; /* Unable to parse IE's */
+ }
+ if (!ies.transferid) {
+ return NULL; /* TXCNT without proper IAX_IE_TRANSFERID */
+ }
+ iax_mutex_lock(session_mutex);
+ for( cur=sessions; cur; cur=cur->next ) {
+ if ((cur->transferring) && (cur->transferid == ies.transferid) &&
+ (cur->callno == dcallno) && (cur->transfercallno == callno)) {
+ /* We're transferring ---
+ * skip address/port checking which would fail while remote peer behind symmetric NAT
+ * verify transferid instead
+ */
+ cur->transfer.sin_addr.s_addr = sin->sin_addr.s_addr; /* setup for further handling */
+ cur->transfer.sin_port = sin->sin_port;
+ break;
+ }
+ }
+ iax_mutex_unlock(session_mutex);
+ return cur;
+}
+
+struct iax_event *iax_net_process(unsigned char *buf, int len, struct sockaddr_in *sin)
+{
+ struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)buf;
+ struct ast_iax2_mini_hdr *mh = (struct ast_iax2_mini_hdr *)buf;
+ struct iax_session *session;
+
+ if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
+ int subclass = uncompress_subclass(fh->csub);
+ int makenew = 0;
+
+ /* Full size header */
+ if (len < sizeof(struct ast_iax2_full_hdr)) {
+ DEBU(G "Short header received from %s\n", inet_ntoa(sin->sin_addr));
+ IAXERROR "Short header received from %s\n", inet_ntoa(sin->sin_addr));
+ return NULL;
+ }
+ /* Only allow it to make new sessions on types where that makes sense */
+ if ((fh->type == AST_FRAME_IAX) && ((subclass == IAX_COMMAND_NEW) ||
+ (subclass == IAX_COMMAND_POKE) ||
+ (subclass == IAX_COMMAND_REGREL) ||
+ (subclass == IAX_COMMAND_REGREQ))) {
+ makenew = 1;
+ }
+
+ /* We have a full header, process appropriately */
+ session = iax_find_session(sin, ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, makenew);
+ if (!session)
+ session = iax_txcnt_session(fh, len-sizeof(struct ast_iax2_full_hdr), sin, ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS);
+ if (session)
+ return iax_header_to_event(session, fh, len - sizeof(struct ast_iax2_full_hdr), sin);
+ /* if we get here, the frame was invalid for some reason, we should probably send IAX_COMMAND_INVAL (as long as the subclass was not already IAX_COMMAND_INVAL) */
+ DEBU(G "No session?\n");
+ return NULL;
+ } else {
+ if (len < sizeof(struct ast_iax2_mini_hdr)) {
+ DEBU(G "Short header received from %s\n", inet_ntoa(sin->sin_addr));
+ IAXERROR "Short header received from %s\n", inet_ntoa(sin->sin_addr));
+ return NULL;
+ }
+ /* Miniature, voice frame */
+ session = iax_find_session(sin, ntohs(fh->scallno), 0, 0);
+ if (session)
+ return iax_miniheader_to_event(session, mh, len - sizeof(struct ast_iax2_mini_hdr));
+ DEBU(G "No session?\n");
+ return NULL;
+ }
+}
+
+static struct iax_sched *iax_get_sched(time_in_ms_t time_in_ms)
+{
+ struct iax_sched *cur, *prev=NULL;
+ iax_mutex_lock(sched_mutex);
+ cur = schedq;
+ /* Check the event schedule first. */
+ while(cur) {
+ if (time_in_ms > cur->when) {
+ /* Take it out of the event queue */
+ if (prev) {
+ prev->next = cur->next;
+ } else {
+ schedq = cur->next;
+ }
+ iax_mutex_unlock(sched_mutex);
+ return cur;
+ }
+ cur = cur->next;
+ }
+ iax_mutex_unlock(sched_mutex);
+ return NULL;
+}
+
+struct iax_event *iax_get_event(int blocking)
+{
+ struct iax_event *event;
+ struct iax_frame *frame;
+ time_in_ms_t time_in_ms;
+ struct iax_sched *cur;
+
+ if (do_shutdown) {
+ __iax_shutdown();
+ do_shutdown = 0;
+ return NULL;
+ }
+ time_in_ms = current_time_in_ms();
+ while((cur = iax_get_sched(time_in_ms))) {
+
+ event = cur->event;
+ frame = cur->frame;
+ if (event) {
+
+ /* See if this is an event we need to handle */
+ event = handle_event(event);
+ if (event) {
+ free(cur);
+ return event;
+ }
+ } else if(frame) {
+ /* It's a frame, transmit it and schedule a retry */
+ if (frame->retries < 0) {
+ /* It's been acked. No need to send it. Destroy the old
+ frame. If final, destroy the session. */
+ if (frame->final) {
+ iax_mutex_lock(session_mutex);
+ destroy_session(frame->session);
+ iax_mutex_unlock(session_mutex);
+ }
+ if (frame->data)
+ free(frame->data);
+ free(frame);
+ } else if (frame->retries == 0) {
+ if (frame->transfer) {
+ /* Send a transfer reject since we weren't able to connect */
+ iax_send_txrej(frame->session);
+ if (frame->data)
+ free(frame->data);
+ free(frame);
+ free(cur);
+ break;
+ } else {
+ /* We haven't been able to get an ACK on this packet. If a
+ final frame, destroy the session, otherwise, pass up timeout */
+ if (frame->final) {
+ iax_mutex_lock(session_mutex);
+ destroy_session(frame->session);
+ iax_mutex_unlock(session_mutex);
+ if (frame->data)
+ free(frame->data);
+ free(frame);
+ } else {
+ event = (struct iax_event *)malloc(sizeof(struct iax_event));
+ if (event) {
+ event->etype = IAX_EVENT_TIMEOUT;
+ event->session = frame->session;
+ if (frame->data)
+ free(frame->data);
+ free(frame);
+ free(cur);
+ return handle_event(event);
+ }
+ }
+ }
+ } else {
+ struct ast_iax2_full_hdr *fh;
+ /* Decrement remaining retries */
+ frame->retries--;
+ /* Multiply next retry time by 4, not above MAX_RETRY_TIME though */
+ frame->retrytime *= 4;
+ /* Keep under 1000 ms if this is a transfer packet */
+ if (!frame->transfer) {
+ if (frame->retrytime > MAX_RETRY_TIME)
+ frame->retrytime = MAX_RETRY_TIME;
+ } else if (frame->retrytime > 1000)
+ frame->retrytime = 1000;
+ fh = (struct ast_iax2_full_hdr *)(frame->data);
+ fh->dcallno = htons(IAX_FLAG_RETRANS | frame->dcallno);
+ iax_xmit_frame(frame);
+ /* Schedule another retransmission */
+ DEBU(G "Scheduling retransmission %d\n", frame->retries);
+ iax_sched_add(NULL, frame, NULL, NULL, frame->retrytime);
+ }
+ } else if (cur->func) {
+ cur->func(cur->arg);
+ }
+ free(cur);
+ }
+
+#ifdef NEWJB
+ /* get jitterbuffer-scheduled events */
+ {
+ struct iax_session *cur;
+ jb_frame frame;
+ iax_mutex_lock(session_mutex);
+ for(cur=sessions; cur; cur=cur->next) {
+ int ret;
+ time_in_ms_t now;
+ time_in_ms_t next;
+
+ now = time_in_ms - cur->rxcore;
+ if(now > (next = jb_next(cur->jb))) {
+ ret = jb_get(cur->jb,&frame,now,get_interp_len(cur->voiceformat));
+ switch(ret) {
+ case JB_OK:
+ // if(frame.type == JB_TYPE_VOICE && next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next);
+ event = frame.data;
+ event = handle_event(event);
+ if (event) {
+ iax_mutex_unlock(session_mutex);
+ return event;
+ }
+ break;
+ case JB_INTERP:
+ // if(next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next);
+ /* create an interpolation frame */
+ //fprintf(stderr, "Making Interpolation frame\n");
+ event = (struct iax_event *)malloc(sizeof(struct iax_event));
+ if (event) {
+ event->etype = IAX_EVENT_VOICE;
+ event->subclass = cur->voiceformat;
+ event->ts = now; /* XXX: ??? applications probably ignore this anyway */
+ event->session = cur;
+ event->datalen = 0;
+ event = handle_event(event);
+ if(event) {
+ iax_mutex_unlock(session_mutex);
+ return event;
+ }
+ }
+ break;
+ case JB_DROP:
+ // if(next != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not next %ld!\n", jb_next(cur->jb), next);
+ iax_event_free(frame.data);
+ break;
+ case JB_NOFRAME:
+ case JB_EMPTY:
+ /* do nothing */
+ break;
+ default:
+ /* shouldn't happen */
+ break;
+ }
+ }
+ }
+ iax_mutex_unlock(session_mutex);
+ }
+
+#endif
+ /* Now look for networking events */
+ if (blocking) {
+ /* Block until there is data if desired */
+ fd_set fds;
+ time_in_ms_t nextEventTime;
+
+ FD_ZERO(&fds);
+ FD_SET(netfd, &fds);
+
+ nextEventTime = iax_time_to_next_event();
+ if(nextEventTime < 0 && blocking > 1) {
+ nextEventTime = blocking;
+ }
+ if(nextEventTime < 0)
+ select(netfd + 1, &fds, NULL, NULL, NULL);
+ else
+ {
+ struct timeval nextEvent;
+
+ nextEvent.tv_sec = (long)(nextEventTime / 1000);
+ nextEvent.tv_usec = (long)((nextEventTime % 1000) * 1000);
+
+ select(netfd + 1, &fds, NULL, NULL, &nextEvent);
+ }
+
+ }
+ event = iax_net_read();
+
+ return handle_event(event);
+}
+
+struct sockaddr_in iax_get_peer_addr(struct iax_session *session)
+{
+ return session->peeraddr;
+}
+
+char *iax_get_peer_ip(struct iax_session *session)
+{
+ return inet_ntoa(session->peeraddr.sin_addr);
+}
+
+char *iax_event_get_apparent_ip(struct iax_event *event)
+{
+ return inet_ntoa(event->ies.apparent_addr->sin_addr);
+}
+
+void iax_session_destroy(struct iax_session **session)
+{
+ iax_mutex_lock(session_mutex);
+ destroy_session(*session);
+ *session = NULL;
+ iax_mutex_unlock(session_mutex);
+}
+
+void iax_event_free(struct iax_event *event)
+{
+ /*
+ We gave the user a chance to play with the session now we need to destroy it
+ if you are not calling this function on every event you read you are now going
+ to leak sessions as well as events!
+ */
+ switch(event->etype) {
+ case IAX_EVENT_REJECT:
+ case IAX_EVENT_HANGUP:
+ /* Destroy this session -- it's no longer valid */
+ if (event->session) { /* maybe the user did it already */
+ iax_mutex_lock(session_mutex);
+ destroy_session(event->session);
+ iax_mutex_unlock(session_mutex);
+ }
+ break;
+ }
+ free(event);
+}
+
+int iax_get_fd(void)
+{
+ /* Return our network file descriptor. The client can select on this (probably with other
+ things, or can add it to a network add sort of gtk_input_add for example */
+ return netfd;
+}
+
+int iax_quelch_moh(struct iax_session *session, int MOH)
+{
+
+ struct iax_ie_data ied; //IE Data Structure (Stuff To Send)
+ memset(&ied, 0, sizeof(ied));
+
+ // You can't quelch the quelched
+ if (session->quelch == 1)
+ return -1;
+
+ if (MOH) {
+ iax_ie_append(&ied, IAX_IE_MUSICONHOLD);
+ session->transfer_moh = 1;
+ }
+
+ return send_command(session, AST_FRAME_IAX, IAX_COMMAND_QUELCH, 0, ied.buf, ied.pos, -1);
+}
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax.h Thu May 8 19:25:36 2008
@@ -0,0 +1,86 @@
+/*
+ * libIAX
+ *
+ * Implementation of Inter-IAXerisk 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 (Library) General Public License
+ */
+
+#ifndef _IAX_H
+#define _IAX_H
+
+/* Max version of IAX protocol we support */
+#define IAX_PROTO_VERSION 1
+
+#define IAX_MAX_CALLS 32768
+
+#define IAX_FLAG_FULL 0x8000
+
+#define IAX_FLAG_SC_LOG 0x80
+
+#define IAX_MAX_SHIFT 0x1F
+
+/* Maximum size of an IAX frame (max size of UDP frame) */
+#define IAX_MAX_BUF_SIZE 65536
+
+/* Subclass for IAX_FRAME_IAX */
+#define IAX_COMMAND_NEW 1
+#define IAX_COMMAND_PING 2
+#define IAX_COMMAND_PONG 3
+#define IAX_COMMAND_ACK 4
+#define IAX_COMMAND_HANGUP 5
+#define IAX_COMMAND_REJECT 6
+#define IAX_COMMAND_ACCEPT 7
+#define IAX_COMMAND_AUTHREQ 8
+#define IAX_COMMAND_AUTHREP 9
+#define IAX_COMMAND_INVAL 10
+#define IAX_COMMAND_LAGRQ 11
+#define IAX_COMMAND_LAGRP 12
+#define IAX_COMMAND_REGREQ 13 /* Registration request */
+#define IAX_COMMAND_REGAUTH 14 /* Registration authentication required */
+#define IAX_COMMAND_REGACK 15 /* Registration accepted */
+#define IAX_COMMAND_REGREJ 16 /* Registration rejected */
+#define IAX_COMMAND_REGREL 17 /* Force release of registration */
+#define IAX_COMMAND_VNAK 18 /* If we receive voice before valid first voice frame, send this */
+#define IAX_COMMAND_DPREQ 19 /* Request status of a dialplan entry */
+#define IAX_COMMAND_DPREP 20 /* Request status of a dialplan entry */
+#define IAX_COMMAND_DIAL 21 /* Request a dial on channel brought up TBD */
+#define IAX_COMMAND_TXREQ 22 /* Transfer Request */
+#define IAX_COMMAND_TXCNT 23 /* Transfer Connect */
+#define IAX_COMMAND_TXACC 24 /* Transfer Accepted */
+#define IAX_COMMAND_TXREADY 25 /* Transfer ready */
+#define IAX_COMMAND_TXREL 26 /* Transfer release */
+#define IAX_COMMAND_TXREJ 27 /* Transfer reject */
+#define IAX_COMMAND_QUELCH 28 /* Stop audio/video transmission */
+#define IAX_COMMAND_UNQUELCH 29 /* Resume audio/video transmission */
+
+#define IAX_DEFAULT_REG_EXPIRE 60
+
+#define IAX_DEFAULT_PORTNO 5036
+
+/* Full frames are always delivered reliably */
+struct iax_full_hdr {
+ short callno; /* Source call number -- high bit must be 1 */
+ short dcallno; /* Destination call number */
+ unsigned int ts; /* 32-bit timestamp in milliseconds */
+ unsigned short seqno; /* Packet number */
+ char type; /* Frame type */
+ unsigned char csub; /* Compressed subclass */
+ char data[];
+};
+
+/* Mini header is used only for voice frames -- delivered unreliably */
+struct iax_mini_hdr {
+ short callno; /* Source call number -- high bit must be 0 */
+ unsigned short ts; /* 16-bit Timestamp (high 16 bits from last IAX_full_hdr) */
+ /* Frametype implicitly VOICE_FRAME */
+ /* subclass implicit from last IAX_full_hdr */
+ char data[];
+};
+
+#endif
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.c Thu May 8 19:25:36 2008
@@ -0,0 +1,840 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Inter-Asterisk eXchange
+ *
+ * Copyright (C) 2003-2004, Digium
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ */
+
+#ifdef WIN32
+#include <winsock.h>
+#define snprintf _snprintf
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "frame.h"
+#include "iax2.h"
+#include "iax2-parser.h"
+
+static int frames = 0;
+static int iframes = 0;
+static int oframes = 0;
+
+#ifdef ALIGN32
+static unsigned int get_uint32(unsigned char *p)
+{
+ return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+}
+
+static unsigned short get_uint16(unsigned char *p)
+{
+ return (p[0] << 8) | p[1] ;
+}
+
+#else
+#define get_uint32(p) (*((unsigned int *)(p)))
+#define get_uint16(p) (*((unsigned short *)(p)))
+#endif
+
+
+static void internaloutput(const char *str)
+{
+ printf(str);
+}
+
+static void internalerror(const char *str)
+{
+ fprintf(stderr, "WARNING: %s", str);
+}
+
+static void (*outputf)(const char *str) = internaloutput;
+static void (*errorf)(const char *str) = internalerror;
+
+static void dump_addr(char *output, int maxlen, void *value, int len)
+{
+ struct sockaddr_in sin;
+ if (len == sizeof(sin)) {
+ memcpy(&sin, value, len);
+ snprintf(output, maxlen, "IPV4 %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ } else {
+ snprintf(output, maxlen, "Invalid Address");
+ }
+}
+
+static void dump_string(char *output, int maxlen, void *value, int len)
+{
+ maxlen--;
+ if (maxlen > len)
+ maxlen = len;
+ strncpy(output,value, maxlen);
+ output[maxlen] = '\0';
+}
+
+static void dump_int(char *output, int maxlen, void *value, int len)
+{
+ if (len == (int)sizeof(unsigned int))
+ snprintf(output, maxlen, "%lu", (unsigned long)ntohl(get_uint32(value)));
+ else
+ snprintf(output, maxlen, "Invalid INT");
+}
+
+static void dump_short(char *output, int maxlen, void *value, int len)
+{
+ if (len == (int)sizeof(unsigned short))
+ snprintf(output, maxlen, "%d", ntohs(get_uint16(value)));
+ else
+ snprintf(output, maxlen, "Invalid SHORT");
+}
+
+static void dump_byte(char *output, int maxlen, void *value, int len)
+{
+ if (len == (int)sizeof(unsigned char))
+ snprintf(output, maxlen, "%d", *((unsigned char *)value));
+ else
+ snprintf(output, maxlen, "Invalid BYTE");
+}
+
+#if 0
+static void dump_ipaddr(char *output, int maxlen, void *value, int len)
+{
+ struct sockaddr_in sin;
+ if (len == (int)sizeof(unsigned int)) {
+ memcpy(&sin.sin_addr, value, len);
+ snprintf(output, maxlen, "%s", inet_ntoa(sin.sin_addr));
+ } else
+ snprintf(output, maxlen, "Invalid IPADDR");
+}
+
+static void dump_prov_flags(char *output, int maxlen, void *value, int len)
+{
+ if (len == (int)sizeof(unsigned int))
+ snprintf(output, maxlen, "%lu (%s)", (unsigned long)ntohl(get_uint32(value)),
+ "PROVISION_PARSING_NOT_IMPLEMENTED");
+ else
+ snprintf(output, maxlen, "Invalid INT");
+}
+#endif
+
+static void dump_samprate(char *output, int maxlen, void *value, int len)
+{
+ char tmp[256]="";
+ int sr;
+ if (len == (int)sizeof(unsigned short)) {
+ sr = ntohs(*((unsigned short *)value));
+ if (sr & IAX_RATE_8KHZ)
+ strcat(tmp, ",8khz");
+ if (sr & IAX_RATE_11KHZ)
+ strcat(tmp, ",11.025khz");
+ if (sr & IAX_RATE_16KHZ)
+ strcat(tmp, ",16khz");
+ if (sr & IAX_RATE_32KHZ)
+ strcat(tmp, ",32khz");
+ if (sr & IAX_RATE_22KHZ)
+ strcat(tmp, ",22.05khz");
+ if (sr & IAX_RATE_44KHZ)
+ strcat(tmp, ",44.1khz");
+ if (sr & IAX_RATE_48KHZ)
+ strcat(tmp, ",48khz");
+ if (strlen(tmp))
+ strncpy(output, &tmp[1], maxlen - 1);
+ else
+ strncpy(output, "None specified!\n", maxlen - 1);
+ } else
+ snprintf(output, maxlen, "Invalid SHORT");
+
+}
+
+static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len);
+static void dump_prov(char *output, int maxlen, void *value, int len)
+{
+ dump_prov_ies(output, maxlen, value, len);
+}
+
+static struct iax2_ie {
+ int ie;
+ char *name;
+ void (*dump)(char *output, int maxlen, void *value, int len);
+} ies[] = {
+ { IAX_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string },
+ { IAX_IE_CALLING_NUMBER, "CALLING NUMBER", dump_string },
+ { IAX_IE_CALLING_ANI, "ANI", dump_string },
+ { IAX_IE_CALLING_NAME, "CALLING NAME", dump_string },
+ { IAX_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string },
+ { IAX_IE_USERNAME, "USERNAME", dump_string },
+ { IAX_IE_PASSWORD, "PASSWORD", dump_string },
+ { IAX_IE_CAPABILITY, "CAPABILITY", dump_int },
+ { IAX_IE_FORMAT, "FORMAT", dump_int },
+ { IAX_IE_LANGUAGE, "LANGUAGE", dump_string },
+ { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_string },
+ { IAX_IE_VERSION, "VERSION", dump_short },
+ { IAX_IE_ADSICPE, "ADSICPE", dump_short },
+ { IAX_IE_DNID, "DNID", dump_string },
+ { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_short },
+ { IAX_IE_CHALLENGE, "CHALLENGE", dump_string },
+ { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
+ { IAX_IE_RSA_RESULT, "RSA RESULT", dump_string },
+ { IAX_IE_APPARENT_ADDR, "APPARENT ADDRESS", dump_addr },
+ { IAX_IE_REFRESH, "REFRESH", dump_short },
+ { IAX_IE_DPSTATUS, "DIALPLAN STATUS", dump_short },
+ { IAX_IE_CALLNO, "CALL NUMBER", dump_short },
+ { IAX_IE_CAUSE, "CAUSE", dump_string },
+ { IAX_IE_IAX_UNKNOWN, "UNKNOWN IAX CMD", dump_byte },
+ { IAX_IE_MSGCOUNT, "MESSAGE COUNT", dump_short },
+ { IAX_IE_AUTOANSWER, "AUTO ANSWER REQ" },
+ { IAX_IE_TRANSFERID, "TRANSFER ID", dump_int },
+ { IAX_IE_RDNIS, "REFERRING DNIS", dump_string },
+ { IAX_IE_PROVISIONING, "PROVISIONING", dump_prov },
+ { IAX_IE_AESPROVISIONING, "AES PROVISIONG" },
+ { IAX_IE_DATETIME, "DATE TIME", dump_int },
+ { IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
+ { IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
+ { IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
+ { IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
+ { IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
+ { IAX_IE_PROVVER, "PROVISIONG VER", dump_int },
+ { IAX_IE_CALLINGPRES, "CALLING PRESNTN", dump_byte },
+ { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte },
+ { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short },
+ { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate },
+ { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
+ { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
+ { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
+ { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
+ { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
+ { IAX_IE_RR_OOO, "RR_OOO", dump_int },
+};
+
+const char *iax_ie2str(int ie)
+{
+ int x;
+ for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
+ if (ies[x].ie == ie)
+ return ies[x].name;
+ }
+ return "Unknown IE";
+}
+
+
+static void dump_prov_ies(char *output, int maxlen, unsigned char *iedata, int len)
+{
+ int ielen;
+ int ie;
+ int found;
+ char tmp[256];
+ if (len < 2)
+ return;
+ strcpy(output, "\n");
+ maxlen -= (int)strlen(output); output += strlen(output);
+ while(len > 2) {
+ ie = iedata[0];
+ ielen = iedata[1];
+ if (ielen + 2> len) {
+ snprintf(tmp, (int)sizeof(tmp), "Total Prov IE length of %d bytes exceeds remaining prov frame length of %d bytes\n", ielen + 2, len);
+ strncpy(output, tmp, maxlen - 1);
+ maxlen -= (int)strlen(output); output += strlen(output);
+ return;
+ }
+ found = 0;
+ if (!found) {
+ snprintf(tmp, (int)sizeof(tmp), " Unknown Prov IE %03d : Present\n", ie);
+ strncpy(output, tmp, maxlen - 1);
+ maxlen -= (int)strlen(output); output += strlen(output);
+ }
+ iedata += (2 + ielen);
+ len -= (2 + ielen);
+ }
+}
+
+static void dump_ies(unsigned char *iedata, int len)
+{
+ int ielen;
+ int ie;
+ int x;
+ int found;
+ char interp[1024];
+ char tmp[1024];
+ if (len < 2)
+ return;
+ while(len > 2) {
+ ie = iedata[0];
+ ielen = iedata[1];
+ if (ielen + 2> len) {
+ snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len);
+ outputf(tmp);
+ return;
+ }
+ found = 0;
+ for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) {
+ if (ies[x].ie == ie) {
+ if (ies[x].dump) {
+ ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen);
+ snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
+ outputf(tmp);
+ } else {
+ if (ielen)
+ snprintf(interp, (int)sizeof(interp), "%d bytes", ielen);
+ else
+ strcpy(interp, "Present");
+ snprintf(tmp, (int)sizeof(tmp), " %-15.15s : %s\n", ies[x].name, interp);
+ outputf(tmp);
+ }
+ found++;
+ }
+ }
+ if (!found) {
+ snprintf(tmp, (int)sizeof(tmp), " Unknown IE %03d : Present\n", ie);
+ outputf(tmp);
+ }
+ iedata += (2 + ielen);
+ len -= (2 + ielen);
+ }
+ outputf("\n");
+}
+
+void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
+{
+ const char *frames[] = {
+ "(0?)",
+ "DTMF ",
+ "VOICE ",
+ "VIDEO ",
+ "CONTROL",
+ "NULL ",
+ "IAX ",
+ "TEXT ",
+ "IMAGE " };
+ const char *iaxs[] = {
+ "(0?)",
+ "NEW ",
+ "PING ",
+ "PONG ",
+ "ACK ",
+ "HANGUP ",
+ "REJECT ",
+ "ACCEPT ",
+ "AUTHREQ",
+ "AUTHREP",
+ "INVAL ",
+ "LAGRQ ",
+ "LAGRP ",
+ "REGREQ ",
+ "REGAUTH",
+ "REGACK ",
+ "REGREJ ",
+ "REGREL ",
+ "VNAK ",
+ "DPREQ ",
+ "DPREP ",
+ "DIAL ",
+ "TXREQ ",
+ "TXCNT ",
+ "TXACC ",
+ "TXREADY",
+ "TXREL ",
+ "TXREJ ",
+ "QUELCH ",
+ "UNQULCH",
+ "POKE",
+ "PAGE",
+ "MWI",
+ "UNSUPPORTED",
+ "TRANSFER",
+ "PROVISION",
+ "FWDOWNLD",
+ "FWDATA"
+ };
+ const char *cmds[] = {
+ "(0?)",
+ "HANGUP ",
+ "RING ",
+ "RINGING",
+ "ANSWER ",
+ "BUSY ",
+ "TKOFFHK ",
+ "OFFHOOK" };
+ struct ast_iax2_full_hdr *fh;
+ char retries[20];
+ char class2[20];
+ char subclass2[20];
+ const char *class;
+ const char *subclass;
+ char tmp[256];
+
+ if (f) {
+ fh = f->data;
+ snprintf(retries, (int)sizeof(retries), "%03d", f->retries);
+ } else {
+ fh = fhi;
+ if (ntohs(fh->dcallno) & IAX_FLAG_RETRANS)
+ strcpy(retries, "Yes");
+ else
+ strcpy(retries, " No");
+ }
+ if (!(ntohs(fh->scallno) & IAX_FLAG_FULL)) {
+ /* Don't mess with mini-frames */
+ return;
+ }
+ if (fh->type > (int)sizeof(frames)/(int)sizeof(char *)) {
+ snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type);
+ class = class2;
+ } else {
+ class = frames[(int)fh->type];
+ }
+ if (fh->type == AST_FRAME_DTMF) {
+ sprintf(subclass2, "%c", fh->csub);
+ subclass = subclass2;
+ } else if (fh->type == AST_FRAME_IAX) {
+ if (fh->csub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) {
+ snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
+ subclass = subclass2;
+ } else {
+ subclass = iaxs[(int)fh->csub];
+ }
+ } else if (fh->type == AST_FRAME_CONTROL) {
+ if (fh->csub > (int)sizeof(cmds)/(int)sizeof(char *)) {
+ snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub);
+ subclass = subclass2;
+ } else {
+ subclass = cmds[(int)fh->csub];
+ }
+ } else {
+ snprintf(subclass2, (int)sizeof(subclass2), "%d", fh->csub);
+ subclass = subclass2;
+ }
+snprintf(tmp, (int)sizeof(tmp),
+"%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
+ (rx ? "Rx" : "Tx"),
+ retries, fh->oseqno, fh->iseqno, class, subclass);
+ outputf(tmp);
+snprintf(tmp, (int)sizeof(tmp),
+" Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n",
+ (unsigned long)ntohl(fh->ts),
+ ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
+ inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+ outputf(tmp);
+ if (fh->type == AST_FRAME_IAX)
+ dump_ies(fh->iedata, datalen);
+}
+
+int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
+{
+ char tmp[256];
+ if (datalen > ((int)sizeof(ied->buf) - ied->pos)) {
+ snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", iax_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos);
+ errorf(tmp);
+ return -1;
+ }
+ ied->buf[ied->pos++] = ie;
+ ied->buf[ied->pos++] = datalen;
+ memcpy(ied->buf + ied->pos, data, datalen);
+ ied->pos += datalen;
+ return 0;
+}
+
+int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)
+{
+ return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
+}
+
+int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value)
+{
+ unsigned int newval;
+ newval = htonl(value);
+ return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
+}
+
+int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value)
+{
+ unsigned short newval;
+ newval = htons(value);
+ return iax_ie_append_raw(ied, ie, &newval, (int)sizeof(newval));
+}
+
+int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const unsigned char *str)
+{
+ return iax_ie_append_raw(ied, ie, str, (int)strlen((char *) str));
+}
+
+int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat)
+{
+ return iax_ie_append_raw(ied, ie, &dat, 1);
+}
+
+int iax_ie_append(struct iax_ie_data *ied, unsigned char ie)
+{
+ return iax_ie_append_raw(ied, ie, NULL, 0);
+}
+
+void iax_set_output(void (*func)(const char *))
+{
+ outputf = func;
+}
+
+void iax_set_error(void (*func)(const char *))
+{
+ errorf = func;
+}
+
+int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
+{
+ /* Parse data into information elements */
+ int len;
+ int ie;
+ char tmp[256];
+ memset(ies, 0, (int)sizeof(struct iax_ies));
+ ies->msgcount = -1;
+ ies->firmwarever = -1;
+ ies->calling_ton = -1;
+ ies->calling_tns = -1;
+ ies->calling_pres = -1;
+ ies->samprate = IAX_RATE_8KHZ;
+ while(datalen >= 2) {
+ ie = data[0];
+ len = data[1];
+ if (len > datalen - 2) {
+ errorf("Information element length exceeds message size\n");
+ return -1;
+ }
+ switch(ie) {
+ case IAX_IE_CALLED_NUMBER:
+ ies->called_number = (char *) data + 2;
+ break;
+ case IAX_IE_CALLING_NUMBER:
+ ies->calling_number = (char *) data + 2;
+ break;
+ case IAX_IE_CALLING_ANI:
+ ies->calling_ani = (char *) data + 2;
+ break;
+ case IAX_IE_CALLING_NAME:
+ ies->calling_name = (char *) data + 2;
+ break;
+ case IAX_IE_CALLED_CONTEXT:
+ ies->called_context = (char *) data + 2;
+ break;
+ case IAX_IE_USERNAME:
+ ies->username = (char *) data + 2;
+ break;
+ case IAX_IE_PASSWORD:
+ ies->password = (char *) data + 2;
+ break;
+ case IAX_IE_CAPABILITY:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else
+ ies->capability = ntohl(get_uint32(data + 2));
+ break;
+ case IAX_IE_FORMAT:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else
+ ies->format = ntohl(get_uint32(data + 2));
+ break;
+ case IAX_IE_LANGUAGE:
+ ies->language = (char *) data + 2;
+ break;
+ case IAX_IE_CODEC_PREFS:
+ ies->codec_prefs = (char *) data + 2;
+ break;
+ case IAX_IE_VERSION:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->version = ntohs(get_uint16(data + 2));
+ break;
+ case IAX_IE_ADSICPE:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->adsicpe = ntohs(get_uint16(data + 2));
+ break;
+ case IAX_IE_SAMPLINGRATE:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting samplingrate to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->samprate = ntohs(get_uint16(data + 2));
+ break;
+ case IAX_IE_DNID:
+ ies->dnid = (char *) data + 2;
+ break;
+ case IAX_IE_RDNIS:
+ ies->rdnis = (char *) data + 2;
+ break;
+ case IAX_IE_AUTHMETHODS:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->authmethods = ntohs(get_uint16(data + 2));
+ break;
+ case IAX_IE_CHALLENGE:
+ ies->challenge = (char *) data + 2;
+ break;
+ case IAX_IE_MD5_RESULT:
+ ies->md5_result = (char *) data + 2;
+ break;
+ case IAX_IE_RSA_RESULT:
+ ies->rsa_result = (char *) data + 2;
+ break;
+ case IAX_IE_APPARENT_ADDR:
+ ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
+ break;
+ case IAX_IE_REFRESH:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting refresh to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->refresh = ntohs(get_uint16(data + 2));
+ break;
+ case IAX_IE_DPSTATUS:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting dpstatus to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->dpstatus = ntohs(get_uint16(data + 2));
+ break;
+ case IAX_IE_CALLNO:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting callno to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->callno = ntohs(get_uint16(data + 2));
+ break;
+ case IAX_IE_CAUSE:
+ ies->cause = (char *) data + 2;
+ break;
+ case IAX_IE_CAUSECODE:
+ if (len != 1) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting causecode to be single byte but was %d\n", len);
+ errorf(tmp);
+ } else {
+ ies->causecode = data[2];
+ }
+ break;
+ case IAX_IE_IAX_UNKNOWN:
+ if (len == 1)
+ ies->iax_unknown = data[2];
+ else {
+ snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
+ errorf(tmp);
+ }
+ break;
+ case IAX_IE_MSGCOUNT:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->msgcount = ntohs(get_uint16(data + 2));
+ break;
+ case IAX_IE_AUTOANSWER:
+ ies->autoanswer = 1;
+ break;
+ case IAX_IE_MUSICONHOLD:
+ ies->musiconhold = 1;
+ break;
+ case IAX_IE_TRANSFERID:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else
+ ies->transferid = ntohl(get_uint32(data + 2));
+ break;
+ case IAX_IE_DATETIME:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else
+ ies->datetime = ntohl(get_uint32(data + 2));
+ break;
+ case IAX_IE_FIRMWAREVER:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->firmwarever = ntohs(get_uint16(data + 2));
+ break;
+ case IAX_IE_DEVICETYPE:
+ ies->devicetype = (char *) data + 2;
+ break;
+ case IAX_IE_SERVICEIDENT:
+ ies->serviceident = (char *) data + 2;
+ break;
+ case IAX_IE_FWBLOCKDESC:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else
+ ies->fwdesc = ntohl(get_uint32(data + 2));
+ break;
+ case IAX_IE_FWBLOCKDATA:
+ ies->fwdata = data + 2;
+ ies->fwdatalen = len;
+ break;
+ case IAX_IE_PROVVER:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expected provisioning version to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else {
+ ies->provverpres = 1;
+ ies->provver = ntohl(get_uint32(data + 2));
+ }
+ break;
+ case IAX_IE_CALLINGPRES:
+ if (len == 1)
+ ies->calling_pres = data[2];
+ else {
+ snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
+ errorf(tmp);
+ }
+ break;
+ case IAX_IE_CALLINGTON:
+ if (len == 1)
+ ies->calling_ton = data[2];
+ else {
+ snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
+ errorf(tmp);
+ }
+ break;
+ case IAX_IE_CALLINGTNS:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else
+ ies->calling_tns = ntohs(get_uint16(data + 2));
+ break;
+ case IAX_IE_RR_JITTER:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else {
+ ies->rr_jitter = ntohl(get_uint32(data + 2));
+ }
+ break;
+ case IAX_IE_RR_LOSS:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else {
+ ies->rr_loss = ntohl(get_uint32(data + 2));
+ }
+ break;
+ case IAX_IE_RR_PKTS:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else {
+ ies->rr_pkts = ntohl(get_uint32(data + 2));
+ }
+ break;
+ case IAX_IE_RR_DELAY:
+ if (len != (int)sizeof(unsigned short)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+ errorf(tmp);
+ } else {
+ ies->rr_delay = ntohs(get_uint16(data + 2));
+ }
+ break;
+ case IAX_IE_RR_DROPPED:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else {
+ ies->rr_dropped = ntohl(get_uint32(data + 2));
+ }
+ break;
+ case IAX_IE_RR_OOO:
+ if (len != (int)sizeof(unsigned int)) {
+ snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+ errorf(tmp);
+ } else {
+ ies->rr_ooo = ntohl(get_uint32(data + 2));
+ }
+ break;
+ default:
+ snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
+ outputf(tmp);
+ }
+ /* Overwrite information element with 0, to null terminate previous portion */
+ data[0] = 0;
+ datalen -= (len + 2);
+ data += (len + 2);
+ }
+ /* Null-terminate last field */
+ *data = '\0';
+ if (datalen) {
+ errorf("Invalid information element contents, strange boundary\n");
+ return -1;
+ }
+ return 0;
+}
+
+void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
+{
+ fr->af.frametype = f->frametype;
+ fr->af.subclass = f->subclass;
+ fr->af.mallocd = 0; /* Our frame is static relative to the container */
+ fr->af.datalen = f->datalen;
+ fr->af.samples = f->samples;
+ fr->af.offset = AST_FRIENDLY_OFFSET;
+ fr->af.src = f->src;
+ fr->af.data = fr->afdata;
+ if (fr->af.datalen)
+ memcpy(fr->af.data, f->data, fr->af.datalen);
+}
+
+struct iax_frame *iax_frame_new(int direction, int datalen)
+{
+ struct iax_frame *fr;
+ fr = malloc((int)sizeof(struct iax_frame) + datalen);
+ if (fr) {
+ fr->direction = direction;
+ fr->retrans = -1;
+ frames++;
+ if (fr->direction == DIRECTION_INGRESS)
+ iframes++;
+ else
+ oframes++;
+ }
+ return fr;
+}
+
+void iax_frame_free(struct iax_frame *fr)
+{
+ /* Note: does not remove from scheduler! */
+ if (fr->direction == DIRECTION_INGRESS)
+ iframes--;
+ else if (fr->direction == DIRECTION_OUTGRESS)
+ oframes--;
+ else {
+ errorf("Attempt to double free frame detected\n");
+ return;
+ }
+ fr->direction = 0;
+ free(fr);
+ frames--;
+}
+
+int iax_get_frames(void) { return frames; }
+int iax_get_iframes(void) { return iframes; }
+int iax_get_oframes(void) { return oframes; }
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.h Thu May 8 19:25:36 2008
@@ -0,0 +1,145 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Inter-Asterisk eXchange
+ *
+ * Copyright (C) 2003, Digium
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ */
+
+#ifndef _IAX2_PARSER_H
+#define _IAX2_PARSER_H
+
+struct iax_ies {
+ char *called_number;
+ char *calling_number;
+ char *calling_ani;
+ char *calling_name;
+ int calling_ton;
+ int calling_tns;
+ int calling_pres;
+ char *called_context;
+ char *username;
+ char *password;
+ unsigned int capability;
+ unsigned int format;
+ char *codec_prefs;
+ char *language;
+ int version;
+ unsigned short adsicpe;
+ char *dnid;
+ char *rdnis;
+ unsigned int authmethods;
+ char *challenge;
+ char *md5_result;
+ char *rsa_result;
+ struct sockaddr_in *apparent_addr;
+ unsigned short refresh;
+ unsigned short dpstatus;
+ unsigned short callno;
+ char *cause;
+ unsigned char causecode;
+ unsigned char iax_unknown;
+ int msgcount;
+ int autoanswer;
+ int musiconhold;
+ unsigned int transferid;
+ unsigned int datetime;
+ char *devicetype;
+ char *serviceident;
+ int firmwarever;
+ unsigned int fwdesc;
+ unsigned char *fwdata;
+ unsigned char fwdatalen;
+ unsigned int provver;
+ unsigned short samprate;
+ unsigned int provverpres;
+ unsigned int rr_jitter;
+ unsigned int rr_loss;
+ unsigned int rr_pkts;
+ unsigned short rr_delay;
+ unsigned int rr_dropped;
+ unsigned int rr_ooo;
+};
+
+#define DIRECTION_INGRESS 1
+#define DIRECTION_OUTGRESS 2
+
+struct iax_frame {
+#ifdef LIBIAX
+ struct iax_session *session;
+ struct iax_event *event;
+#endif
+
+ /* /Our/ call number */
+ unsigned short callno;
+ /* /Their/ call number */
+ unsigned short dcallno;
+ /* Start of raw frame (outgoing only) */
+ void *data;
+ /* Length of frame (outgoing only) */
+ int datalen;
+ /* How many retries so far? */
+ int retries;
+ /* Outgoing relative timestamp (ms) */
+ time_in_ms_t ts;
+ /* How long to wait before retrying */
+ time_in_ms_t retrytime;
+ /* Are we received out of order? */
+ int outoforder;
+ /* Have we been sent at all yet? */
+ int sentyet;
+ /* Outgoing Packet sequence number */
+ int oseqno;
+ /* Next expected incoming packet sequence number */
+ int iseqno;
+ /* Non-zero if should be sent to transfer peer */
+ int transfer;
+ /* Non-zero if this is the final message */
+ int final;
+ /* Ingress or outgres */
+ int direction;
+ /* Retransmission ID */
+ int retrans;
+ /* Easy linking */
+ struct iax_frame *next;
+ struct iax_frame *prev;
+ /* Actual, isolated frame header */
+ struct ast_frame af;
+ unsigned char unused[AST_FRIENDLY_OFFSET];
+ unsigned char afdata[]; /* Data for frame */
+};
+
+struct iax_ie_data {
+ unsigned char buf[1024];
+ int pos;
+};
+
+/* Choose a different function for output */
+extern void iax_set_output(void (*output)(const char *data));
+/* Choose a different function for errors */
+extern void iax_set_error(void (*output)(const char *data));
+extern void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen);
+
+extern const char *iax_ie2str(int ie);
+
+extern int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen);
+extern int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, struct sockaddr_in *sin);
+extern int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value);
+extern int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value);
+extern int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, const unsigned char *str);
+extern int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat);
+extern int iax_ie_append(struct iax_ie_data *ied, unsigned char ie);
+extern int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen);
+
+extern int iax_get_frames(void);
+extern int iax_get_iframes(void);
+extern int iax_get_oframes(void);
+extern void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f);
+extern struct iax_frame *iax_frame_new(int direction, int datalen);
+extern void iax_frame_free(struct iax_frame *fr);
+#endif
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax2.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax2.h Thu May 8 19:25:36 2008
@@ -0,0 +1,236 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Inter-Asterisk eXchange
+ *
+ * Copyright (C) 2003, Digium
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ */
+
+#ifndef _IAX2_H
+#define _IAX2_H
+
+typedef long long time_in_ms_t;
+#define iax_abs(x) ((x) >= 0 ? (x) : -(x))
+
+/* Max version of IAX protocol we support */
+#define IAX_PROTO_VERSION 2
+
+#define IAX_MAX_CALLS 32768
+
+#define IAX_FLAG_FULL 0x8000
+
+#define IAX_FLAG_RETRANS 0x8000
+
+#define IAX_FLAG_SC_LOG 0x80
+
+#define IAX_MAX_SHIFT 0x1F
+
+#define IAX_WINDOW 64
+
+/* Subclass for AST_FRAME_IAX */
+#define IAX_COMMAND_NEW 1
+#define IAX_COMMAND_PING 2
+#define IAX_COMMAND_PONG 3
+#define IAX_COMMAND_ACK 4
+#define IAX_COMMAND_HANGUP 5
+#define IAX_COMMAND_REJECT 6
+#define IAX_COMMAND_ACCEPT 7
+#define IAX_COMMAND_AUTHREQ 8
+#define IAX_COMMAND_AUTHREP 9
+#define IAX_COMMAND_INVAL 10
+#define IAX_COMMAND_LAGRQ 11
+#define IAX_COMMAND_LAGRP 12
+#define IAX_COMMAND_REGREQ 13 /* Registration request */
+#define IAX_COMMAND_REGAUTH 14 /* Registration authentication required */
+#define IAX_COMMAND_REGACK 15 /* Registration accepted */
+#define IAX_COMMAND_REGREJ 16 /* Registration rejected */
+#define IAX_COMMAND_REGREL 17 /* Force release of registration */
+#define IAX_COMMAND_VNAK 18 /* If we receive voice before valid first voice frame, send this */
+#define IAX_COMMAND_DPREQ 19 /* Request status of a dialplan entry */
+#define IAX_COMMAND_DPREP 20 /* Request status of a dialplan entry */
+#define IAX_COMMAND_DIAL 21 /* Request a dial on channel brought up TBD */
+#define IAX_COMMAND_TXREQ 22 /* Transfer Request */
+#define IAX_COMMAND_TXCNT 23 /* Transfer Connect */
+#define IAX_COMMAND_TXACC 24 /* Transfer Accepted */
+#define IAX_COMMAND_TXREADY 25 /* Transfer ready */
+#define IAX_COMMAND_TXREL 26 /* Transfer release */
+#define IAX_COMMAND_TXREJ 27 /* Transfer reject */
+#define IAX_COMMAND_QUELCH 28 /* Stop audio/video transmission */
+#define IAX_COMMAND_UNQUELCH 29 /* Resume audio/video transmission */
+#define IAX_COMMAND_POKE 30 /* Like ping, but does not require an open connection */
+#define IAX_COMMAND_PAGE 31 /* Paging description */
+#define IAX_COMMAND_MWI 32 /* Stand-alone message waiting indicator */
+#define IAX_COMMAND_UNSUPPORT 33 /* Unsupported message received */
+#define IAX_COMMAND_TRANSFER 34 /* Request remote transfer */
+#define IAX_COMMAND_PROVISION 35 /* Provision device */
+#define IAX_COMMAND_FWDOWNL 36 /* Download firmware */
+#define IAX_COMMAND_FWDATA 37 /* Firmware Data */
+
+#define IAX_DEFAULT_REG_EXPIRE 60 /* By default require re-registration once per minute */
+
+#define IAX_LINGER_TIMEOUT 10 /* How long to wait before closing bridged call */
+
+#define IAX_DEFAULT_PORTNO 4569
+
+/* IAX Information elements */
+#define IAX_IE_CALLED_NUMBER 1 /* Number/extension being called - string */
+#define IAX_IE_CALLING_NUMBER 2 /* Calling number - string */
+#define IAX_IE_CALLING_ANI 3 /* Calling number ANI for billing - string */
+#define IAX_IE_CALLING_NAME 4 /* Name of caller - string */
+#define IAX_IE_CALLED_CONTEXT 5 /* Context for number - string */
+#define IAX_IE_USERNAME 6 /* Username (peer or user) for authentication - string */
+#define IAX_IE_PASSWORD 7 /* Password for authentication - string */
+#define IAX_IE_CAPABILITY 8 /* Actual codec capability - unsigned int */
+#define IAX_IE_FORMAT 9 /* Desired codec format - unsigned int */
+#define IAX_IE_LANGUAGE 10 /* Desired language - string */
+#define IAX_IE_VERSION 11 /* Protocol version - short */
+#define IAX_IE_ADSICPE 12 /* CPE ADSI capability - short */
+#define IAX_IE_DNID 13 /* Originally dialed DNID - string */
+#define IAX_IE_AUTHMETHODS 14 /* Authentication method(s) - short */
+#define IAX_IE_CHALLENGE 15 /* Challenge data for MD5/RSA - string */
+#define IAX_IE_MD5_RESULT 16 /* MD5 challenge result - string */
+#define IAX_IE_RSA_RESULT 17 /* RSA challenge result - string */
+#define IAX_IE_APPARENT_ADDR 18 /* Apparent address of peer - struct sockaddr_in */
+#define IAX_IE_REFRESH 19 /* When to refresh registration - short */
+#define IAX_IE_DPSTATUS 20 /* Dialplan status - short */
+#define IAX_IE_CALLNO 21 /* Call number of peer - short */
+#define IAX_IE_CAUSE 22 /* Cause - string */
+#define IAX_IE_IAX_UNKNOWN 23 /* Unknown IAX command - byte */
+#define IAX_IE_MSGCOUNT 24 /* How many messages waiting - short */
+#define IAX_IE_AUTOANSWER 25 /* Request auto-answering -- none */
+#define IAX_IE_MUSICONHOLD 26 /* Request musiconhold with QUELCH -- none or string */
+#define IAX_IE_TRANSFERID 27 /* Transfer Request Identifier -- int */
+#define IAX_IE_RDNIS 28 /* Referring DNIS -- string */
+#define IAX_IE_PROVISIONING 29 /* Provisioning info */
+#define IAX_IE_AESPROVISIONING 30 /* AES Provisioning info */
+#define IAX_IE_DATETIME 31 /* Date/Time */
+#define IAX_IE_DEVICETYPE 32 /* Device Type -- string */
+#define IAX_IE_SERVICEIDENT 33 /* Service Identifier -- string */
+#define IAX_IE_FIRMWAREVER 34 /* Firmware revision -- u16 */
+#define IAX_IE_FWBLOCKDESC 35 /* Firmware block description -- u32 */
+#define IAX_IE_FWBLOCKDATA 36 /* Firmware block of data -- raw */
+#define IAX_IE_PROVVER 37 /* Provisioning Version (u32) */
+#define IAX_IE_CALLINGPRES 38 /* Calling presentation (u8) */
+#define IAX_IE_CALLINGTON 39 /* Calling type of number (u8) */
+#define IAX_IE_CALLINGTNS 40 /* Calling transit network select (u16) */
+#define IAX_IE_SAMPLINGRATE 41 /* Supported sampling rates (u16) */
+#define IAX_IE_CAUSECODE 42 /* Hangup cause (u8) */
+#define IAX_IE_ENCRYPTION 43 /* Encryption format (u16) */
+#define IAX_IE_ENCKEY 44 /* Encryption key (raw) */
+#define IAX_IE_CODEC_PREFS 45 /* Codec Negotiation */
+
+#define IAX_IE_RR_JITTER 46 /* Received jitter (as in RFC1889) u32 */
+#define IAX_IE_RR_LOSS 47 /* Received loss (high byte loss pct, low 24 bits loss count, as in rfc1889 */
+#define IAX_IE_RR_PKTS 48 /* Received frames (total frames received) u32 */
+#define IAX_IE_RR_DELAY 49 /* Max playout delay for received frames (in ms) u16 */
+#define IAX_IE_RR_DROPPED 50 /* Dropped frames (presumably by jitterbuf) u32 */
+#define IAX_IE_RR_OOO 51 /* Frames received Out of Order u32 */
+
+
+
+#define IAX_AUTH_PLAINTEXT (1 << 0)
+#define IAX_AUTH_MD5 (1 << 1)
+#define IAX_AUTH_RSA (1 << 2)
+
+#define IAX_META_TRUNK 1 /* Trunk meta-message */
+#define IAX_META_VIDEO 2 /* Video frame */
+
+#define IAX_RATE_8KHZ (1 << 0) /* 8khz sampling (default if absent) */
+#define IAX_RATE_11KHZ (1 << 1) /* 11.025khz sampling */
+#define IAX_RATE_16KHZ (1 << 2) /* 16khz sampling */
+#define IAX_RATE_22KHZ (1 << 3) /* 22.05khz sampling */
+#define IAX_RATE_44KHZ (1 << 4) /* 44.1khz sampling */
+#define IAX_RATE_48KHZ (1 << 5) /* 48khz sampling */
+#define IAX_RATE_32KHZ (1 << 6) /* 32khz sampling */
+
+#define IAX_DPSTATUS_EXISTS (1 << 0)
+#define IAX_DPSTATUS_CANEXIST (1 << 1)
+#define IAX_DPSTATUS_NONEXISTANT (1 << 2)
+#define IAX_DPSTATUS_IGNOREPAT (1 << 14)
+#define IAX_DPSTATUS_MATCHMORE (1 << 15)
+
+#if defined __GNUC__
+#define __PACKED __attribute__ ((__packed__))
+#else
+#if defined (_MSC_VER)
+#pragma pack(push,1)
+#define __PACKED
+#else
+#pragma pack(1)
+#define __PACKED
+#endif
+#endif
+
+/* Full frames are always delivered reliably */
+struct ast_iax2_full_hdr {
+ unsigned short scallno; /* Source call number -- high bit must be 1 */
+ unsigned short dcallno; /* Destination call number -- high bit is 1 if retransmission */
+ unsigned int ts; /* 32-bit timestamp in milliseconds (from 1st transmission) */
+ unsigned char oseqno; /* Packet number (outgoing) */
+ unsigned char iseqno; /* Packet number (next incoming expected) */
+ char type; /* Frame type */
+ unsigned char csub; /* Compressed subclass */
+ unsigned char iedata[];
+} __PACKED;
+
+/* Mini header is used only for voice frames -- delivered unreliably */
+struct ast_iax2_mini_hdr {
+ unsigned short callno; /* Source call number -- high bit must be 0, rest must be non-zero */
+ unsigned short ts; /* 16-bit Timestamp (high 16 bits from last ast_iax2_full_hdr) */
+ /* Frametype implicitly VOICE_FRAME */
+ /* subclass implicit from last ast_iax2_full_hdr */
+ unsigned char data[];
+} __PACKED;
+
+struct ast_iax2_meta_hdr {
+ unsigned short zeros; /* Zeros field -- must be zero */
+ unsigned char metacmd; /* Meta command */
+ unsigned char cmddata; /* Command Data */
+ unsigned char data[];
+} __PACKED;
+
+struct ast_iax2_video_hdr {
+ unsigned short zeros; /* Zeros field -- must be zero */
+ unsigned short callno; /* Video call number */
+ unsigned short ts; /* Timestamp and mark if present */
+ unsigned char data[];
+} __PACKED;
+
+struct ast_iax2_meta_trunk_hdr {
+ unsigned int ts; /* 32-bit timestamp for all messages */
+ unsigned char data[];
+} __PACKED;
+
+struct ast_iax2_meta_trunk_entry {
+ unsigned short callno; /* Call number */
+ unsigned short len; /* Length of data for this callno */
+} __PACKED;
+
+#define IAX_FIRMWARE_MAGIC 0x69617879
+
+struct ast_iax2_firmware_header {
+ unsigned int magic; /* Magic number */
+ unsigned short version; /* Software version */
+ unsigned char devname[16]; /* Device */
+ unsigned int datalen; /* Data length of file beyond header */
+ unsigned char chksum[16]; /* Checksum of all data */
+ unsigned char data[];
+} __PACKED;
+
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#else
+#ifndef __GNUC__
+#pragma pack()
+#endif
+#endif
+
+#undef __PACKED
+
+#endif
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.c Thu May 8 19:25:36 2008
@@ -0,0 +1,834 @@
+/*
+ * jitterbuf: an application-independent jitterbuffer
+ *
+ * Copyrights:
+ * Copyright (C) 2004-2005, Horizon Wimba, Inc.
+ *
+ * Contributors:
+ * Steve Kann <stevek at stevek.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ */
+
+#include "iax2.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "jitterbuf.h"
+
+/* define these here, just for ancient compiler systems */
+#define JB_LONGMAX 2147483647L
+#define JB_LONGMIN (-JB_LONGMAX - 1L)
+
+/* MS VC can't do __VA_ARGS__ */
+#if (defined(WIN32) || defined(_WIN32_WCE)) && defined(_MSC_VER)
+#define jb_warn if (warnf) warnf
+#define jb_err if (errf) errf
+#define jb_dbg if (dbgf) dbgf
+
+#ifdef DEEP_DEBUG
+ #define jb_dbg2 if (dbgf) dbgf
+#else
+ #define jb_dbg2 if (0) dbgf
+#endif
+
+#else
+
+#define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0)
+#define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0)
+#define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
+
+#ifdef DEEP_DEBUG
+#define jb_dbg2(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
+#else
+#define jb_dbg2(...) ((void)0)
+#endif
+
+#endif
+
+static jb_output_function_t warnf, errf, dbgf;
+
+void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg)
+{
+ errf = err;
+ warnf = warn;
+ dbgf = dbg;
+}
+
+static void increment_losspct(jitterbuf *jb)
+{
+ jb->info.losspct = (100000 + 499 * jb->info.losspct)/500;
+}
+
+static void decrement_losspct(jitterbuf *jb)
+{
+ jb->info.losspct = (499 * jb->info.losspct)/500;
+}
+
+void jb_reset(jitterbuf *jb)
+{
+ /* only save settings */
+ jb_conf s = jb->info.conf;
+ memset(jb, 0, sizeof(*jb));
+ jb->info.conf = s;
+
+ /* initialize length, using the configured value */
+ jb->info.current = jb->info.target = jb->info.conf.target_extra;
+ jb->info.silence_begin_ts = -1;
+}
+
+jitterbuf * jb_new()
+{
+ jitterbuf *jb;
+
+ if (!(jb = (jitterbuf *)malloc(sizeof(*jb))))
+ return NULL;
+
+ jb->info.conf.target_extra = JB_TARGET_EXTRA;
+
+ jb_reset(jb);
+
+ jb_dbg2("jb_new() = %x\n", jb);
+ return jb;
+}
+
+void jb_destroy(jitterbuf *jb)
+{
+ jb_frame *frame;
+ jb_dbg2("jb_destroy(%x)\n", jb);
+
+ /* free all the frames on the "free list" */
+ frame = jb->free;
+ while (frame != NULL) {
+ jb_frame *next = frame->next;
+ free(frame);
+ frame = next;
+ }
+
+ /* free ourselves! */
+ free(jb);
+}
+
+
+
+#if 0
+static int longcmp(const void *a, const void *b)
+{
+ return *(long *)a - *(long *)b;
+}
+#endif
+
+/* simple history manipulation */
+/* maybe later we can make the history buckets variable size, or something? */
+/* drop parameter determines whether we will drop outliers to minimize
+ * delay */
+static int history_put(jitterbuf *jb, time_in_ms_t ts, time_in_ms_t now, long ms)
+{
+ time_in_ms_t delay = now - (ts - jb->info.resync_offset);
+ time_in_ms_t threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
+ time_in_ms_t kicked;
+
+ /* don't add special/negative times to history */
+ if (ts <= 0)
+ return 0;
+
+ /* check for drastic change in delay */
+ if (jb->info.conf.resync_threshold != -1) {
+ if (iax_abs(delay - jb->info.last_delay) > threshold) {
+ jb->info.cnt_delay_discont++;
+ if (jb->info.cnt_delay_discont > 3) {
+ /* resync the jitterbuffer */
+ jb->info.cnt_delay_discont = 0;
+ jb->hist_ptr = 0;
+ jb->hist_maxbuf_valid = 0;
+
+ jb_warn("Resyncing the jb. last_delay %ld, this delay %ld, threshold %ld, new offset %ld\n", jb->info.last_delay, delay, threshold, ts - now);
+ jb->info.resync_offset = ts - now;
+ jb->info.last_delay = delay = 0; /* after resync, frame is right on time */
+ } else {
+ return -1;
+ }
+ } else {
+ jb->info.last_delay = delay;
+ jb->info.cnt_delay_discont = 0;
+ }
+ }
+
+ kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ];
+
+ jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;
+
+ /* optimization; the max/min buffers don't need to be recalculated,
+ * if this packet's entry doesn't change them. This happens if this
+ * packet is not involved, _and_ any packet that got kicked out of
+ * the history is also not involved. We do a number of comparisons,
+ * but it's probably still worthwhile, because it will usually
+ * succeed, and should be a lot faster than going through all 500
+ * packets in history */
+ if (!jb->hist_maxbuf_valid)
+ return 0;
+
+ /* don't do this until we've filled history
+ * (reduces some edge cases below) */
+ if (jb->hist_ptr < JB_HISTORY_SZ)
+ goto invalidate;
+
+ /* if the new delay would go into min */
+ if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
+ goto invalidate;
+
+ /* or max.. */
+ if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
+ goto invalidate;
+
+ /* or the kicked delay would be in min */
+ if (kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
+ goto invalidate;
+
+ if (kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
+ goto invalidate;
+
+ /* if we got here, we don't need to invalidate, 'cause this delay didn't
+ * affect things */
+ return 0;
+ /* end optimization */
+
+
+invalidate:
+ jb->hist_maxbuf_valid = 0;
+ return 0;
+}
+
+static void history_calc_maxbuf(jitterbuf *jb)
+{
+ int i,j;
+
+ if (jb->hist_ptr == 0)
+ return;
+
+
+ /* initialize maxbuf/minbuf to the latest value */
+ for (i=0;i<JB_HISTORY_MAXBUF_SZ;i++) {
+ /*
+ * jb->hist_maxbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
+ * jb->hist_minbuf[i] = jb->history[(jb->hist_ptr-1) % JB_HISTORY_SZ];
+ */
+ jb->hist_maxbuf[i] = JB_LONGMIN;
+ jb->hist_minbuf[i] = JB_LONGMAX;
+ }
+
+ /* use insertion sort to populate maxbuf */
+ /* we want it to be the top "n" values, in order */
+
+ /* start at the beginning, or JB_HISTORY_SZ frames ago */
+ i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0;
+
+ for (;i<jb->hist_ptr;i++) {
+ time_in_ms_t toins = jb->history[i % JB_HISTORY_SZ];
+
+ /* if the maxbuf should get this */
+ if (toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) {
+
+ /* insertion-sort it into the maxbuf */
+ for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
+ /* found where it fits */
+ if (toins > jb->hist_maxbuf[j]) {
+ /* move over */
+ memmove(jb->hist_maxbuf + j + 1, jb->hist_maxbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_maxbuf[0]));
+ /* insert */
+ jb->hist_maxbuf[j] = toins;
+
+ break;
+ }
+ }
+ }
+
+ /* if the minbuf should get this */
+ if (toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) {
+
+ /* insertion-sort it into the maxbuf */
+ for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
+ /* found where it fits */
+ if (toins < jb->hist_minbuf[j]) {
+ /* move over */
+ memmove(jb->hist_minbuf + j + 1, jb->hist_minbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_minbuf[0]));
+ /* insert */
+ jb->hist_minbuf[j] = toins;
+
+ break;
+ }
+ }
+ }
+
+#if 0
+ int k;
+ fprintf(stderr, "toins = %ld\n", toins);
+ fprintf(stderr, "maxbuf =");
+ for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++)
+ fprintf(stderr, "%ld ", jb->hist_maxbuf[k]);
+ fprintf(stderr, "\nminbuf =");
+ for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++)
+ fprintf(stderr, "%ld ", jb->hist_minbuf[k]);
+ fprintf(stderr, "\n");
+#endif
+ }
+
+ jb->hist_maxbuf_valid = 1;
+}
+
+static void history_get(jitterbuf *jb)
+{
+ time_in_ms_t max, min, jitter;
+ int index;
+ int count;
+
+ if (!jb->hist_maxbuf_valid)
+ history_calc_maxbuf(jb);
+
+ /* count is how many items in history we're examining */
+ count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ;
+
+ /* index is the "n"ths highest/lowest that we'll look for */
+ index = count * JB_HISTORY_DROPPCT / 100;
+
+ /* sanity checks for index */
+ if (index > (JB_HISTORY_MAXBUF_SZ - 1))
+ index = JB_HISTORY_MAXBUF_SZ - 1;
+
+
+ if (index < 0) {
+ jb->info.min = 0;
+ jb->info.jitter = 0;
+ return;
+ }
+
+ max = jb->hist_maxbuf[index];
+ min = jb->hist_minbuf[index];
+
+ jitter = max - min;
+
+ /* these debug stmts compare the difference between looking at the absolute jitter, and the
+ * values we get by throwing away the outliers */
+ /*
+ fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", index, min, max, jitter);
+ fprintf(stderr, "[%d] min=%d, max=%d, jitter=%d\n", 0, jb->hist_minbuf[0], jb->hist_maxbuf[0], jb->hist_maxbuf[0]-jb->hist_minbuf[0]);
+ */
+
+ jb->info.min = min;
+ jb->info.jitter = jitter;
+}
+
+/* returns 1 if frame was inserted into head of queue, 0 otherwise */
+static int queue_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts)
+{
+ jb_frame *frame;
+ jb_frame *p;
+ int head = 0;
+ time_in_ms_t resync_ts = ts - jb->info.resync_offset;
+
+ if ((frame = jb->free)) {
+ jb->free = frame->next;
+ } else if (!(frame = (jb_frame *)malloc(sizeof(*frame)))) {
+ jb_err("cannot allocate frame\n");
+ return 0;
+ }
+
+ jb->info.frames_cur++;
+
+ frame->data = data;
+ frame->ts = resync_ts;
+ frame->ms = ms;
+ frame->type = type;
+
+ /*
+ * frames are a circular list, jb-frames points to to the lowest ts,
+ * jb->frames->prev points to the highest ts
+ */
+
+ if (!jb->frames) { /* queue is empty */
+ jb->frames = frame;
+ frame->next = frame;
+ frame->prev = frame;
+ head = 1;
+ } else if (resync_ts < jb->frames->ts) {
+ frame->next = jb->frames;
+ frame->prev = jb->frames->prev;
+
+ frame->next->prev = frame;
+ frame->prev->next = frame;
+
+ /* frame is out of order */
+ jb->info.frames_ooo++;
+
+ jb->frames = frame;
+ head = 1;
+ } else {
+ p = jb->frames;
+
+ /* frame is out of order */
+ if (resync_ts < p->prev->ts) jb->info.frames_ooo++;
+
+ while (resync_ts < p->prev->ts && p->prev != jb->frames)
+ p = p->prev;
+
+ frame->next = p;
+ frame->prev = p->prev;
+
+ frame->next->prev = frame;
+ frame->prev->next = frame;
+ }
+ return head;
+}
+
+static time_in_ms_t queue_next(jitterbuf *jb)
+{
+ if (jb->frames)
+ return jb->frames->ts;
+ else
+ return -1;
+}
+
+static time_in_ms_t queue_last(jitterbuf *jb)
+{
+ if (jb->frames)
+ return jb->frames->prev->ts;
+ else
+ return -1;
+}
+
+static jb_frame *_queue_get(jitterbuf *jb, time_in_ms_t ts, int all)
+{
+ jb_frame *frame;
+ frame = jb->frames;
+
+ if (!frame)
+ return NULL;
+
+ /*jb_warn("queue_get: ASK %ld FIRST %ld\n", ts, frame->ts); */
+
+ if (all || ts >= frame->ts) {
+ /* remove this frame */
+ frame->prev->next = frame->next;
+ frame->next->prev = frame->prev;
+
+ if (frame->next == frame)
+ jb->frames = NULL;
+ else
+ jb->frames = frame->next;
+
+
+ /* insert onto "free" single-linked list */
+ frame->next = jb->free;
+ jb->free = frame;
+
+ jb->info.frames_cur--;
+
+ /* we return the frame pointer, even though it's on free list,
+ * but caller must copy data */
+ return frame;
+ }
+
+ return NULL;
+}
+
+static jb_frame *queue_get(jitterbuf *jb, time_in_ms_t ts)
+{
+ return _queue_get(jb,ts,0);
+}
+
+static jb_frame *queue_getall(jitterbuf *jb)
+{
+ return _queue_get(jb,0,1);
+}
+
+#if 0
+/* some diagnostics */
+static void jb_dbginfo(jitterbuf *jb)
+{
+ if (dbgf == NULL)
+ return;
+
+ jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n",
+ jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur);
+
+ jb_dbg("jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
+ jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min,
+ jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8);
+ if (jb->info.frames_in > 0)
+ jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
+ jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost),
+ jb->info.frames_late * 100/jb->info.frames_in);
+ jb_dbg("jb info: queue %d -> %d. last_ts %d (queue len: %d) last_ms %d\n",
+ queue_next(jb),
+ queue_last(jb),
+ jb->info.next_voice_ts,
+ queue_last(jb) - queue_next(jb),
+ jb->info.last_voice_ms);
+}
+#endif
+
+#ifdef DEEP_DEBUG
+static void jb_chkqueue(jitterbuf *jb)
+{
+ int i=0;
+ jb_frame *p = jb->frames;
+
+ if (!p) {
+ return;
+ }
+
+ do {
+ if (p->next == NULL) {
+ jb_err("Queue is BROKEN at item [%d]", i);
+ }
+ i++;
+ p=p->next;
+ } while (p->next != jb->frames);
+}
+
+static void jb_dbgqueue(jitterbuf *jb)
+{
+ int i=0;
+ jb_frame *p = jb->frames;
+
+ jb_dbg("queue: ");
+
+ if (!p) {
+ jb_dbg("EMPTY\n");
+ return;
+ }
+
+ do {
+ jb_dbg("[%d]=%ld ", i++, p->ts);
+ p=p->next;
+ } while (p->next != jb->frames);
+
+ jb_dbg("\n");
+}
+#endif
+
+enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts, time_in_ms_t now)
+{
+ jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
+
+ jb->info.frames_in++;
+
+ if (type == JB_TYPE_VOICE) {
+ /* presently, I'm only adding VOICE frames to history and drift
+ * calculations; mostly because with the IAX integrations, I'm
+ * sending retransmitted control frames with their awkward
+ * timestamps through
+ */
+ if (history_put(jb,ts,now,ms))
+ return JB_DROP;
+ }
+
+ /* if put into head of queue, caller needs to reschedule */
+ if (queue_put(jb,data,type,ms,ts)) {
+ return JB_SCHED;
+ }
+
+ return JB_OK;
+}
+
+
+static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl)
+{
+ jb_frame *frame;
+ time_in_ms_t diff;
+
+ /*if ((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */
+ /* get jitter info */
+ history_get(jb);
+
+
+ /* target */
+ jb->info.target = jb->info.jitter + jb->info.min + jb->info.conf.target_extra;
+
+ /* if a hard clamp was requested, use it */
+ if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
+ jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf);
+ jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf;
+ }
+
+ diff = jb->info.target - jb->info.current;
+
+ /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff, */
+ /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */
+
+ /* let's work on non-silent case first */
+ if (!jb->info.silence_begin_ts) {
+ /* we want to grow */
+ if ((diff > 0) &&
+ /* we haven't grown in the delay length */
+ (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) ||
+ /* we need to grow more than the "length" we have left */
+ (diff > queue_last(jb) - queue_next(jb)) ) ) {
+ /* grow by interp frame length */
+ jb->info.current += interpl;
+ jb->info.next_voice_ts += interpl;
+ jb->info.last_voice_ms = interpl;
+ jb->info.last_adjustment = now;
+ jb->info.cnt_contig_interp++;
+ /* assume silence instead of continuing to interpolate */
+ if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
+ jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
+ }
+ jb_dbg("G");
+ return JB_INTERP;
+ }
+
+ frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current);
+
+ /* not a voice frame; just return it. */
+ if (frame && frame->type != JB_TYPE_VOICE) {
+ /* track start of silence */
+ if (frame->type == JB_TYPE_SILENCE) {
+ jb->info.silence_begin_ts = frame->ts;
+ jb->info.cnt_contig_interp = 0;
+ }
+
+ *frameout = *frame;
+ jb->info.frames_out++;
+ jb_dbg("o");
+ return JB_OK;
+ }
+
+ /* voice frame is later than expected */
+ if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
+ if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
+ /* either we interpolated past this frame in the last jb_get */
+ /* or the frame is still in order, but came a little too quick */
+ *frameout = *frame;
+ /* reset expectation for next frame */
+ jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
+ jb->info.frames_out++;
+ decrement_losspct(jb);
+ jb->info.cnt_contig_interp = 0;
+ jb_dbg("v");
+ return JB_OK;
+ } else {
+ /* voice frame is late */
+ *frameout = *frame;
+ jb->info.frames_out++;
+ decrement_losspct(jb);
+ jb->info.frames_late++;
+ jb->info.frames_lost--;
+ jb_dbg("l");
+ /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
+ jb_warninfo(jb); */
+ return JB_DROP;
+ }
+ }
+
+ /* keep track of frame sizes, to allow for variable sized-frames */
+ if (frame && frame->ms > 0) {
+ jb->info.last_voice_ms = frame->ms;
+ }
+
+ /* we want to shrink; shrink at 1 frame / 500ms */
+ /* unless we don't have a frame, then shrink 1 frame */
+ /* every 80ms (though perhaps we can shrink even faster */
+ /* in this case) */
+ if (diff < -jb->info.conf.target_extra &&
+ ((!frame && jb->info.last_adjustment + 80 < now) ||
+ (jb->info.last_adjustment + 500 < now))) {
+
+ jb->info.last_adjustment = now;
+ jb->info.cnt_contig_interp = 0;
+
+ if (frame) {
+ *frameout = *frame;
+ /* shrink by frame size we're throwing out */
+ jb->info.current -= frame->ms;
+ jb->info.frames_out++;
+ decrement_losspct(jb);
+ jb->info.frames_dropped++;
+ jb_dbg("s");
+ return JB_DROP;
+ } else {
+ /* shrink by last_voice_ms */
+ jb->info.current -= jb->info.last_voice_ms;
+ jb->info.frames_lost++;
+ increment_losspct(jb);
+ jb_dbg("S");
+ return JB_NOFRAME;
+ }
+ }
+
+ /* lost frame */
+ if (!frame) {
+ /* this is a bit of a hack for now, but if we're close to
+ * target, and we find a missing frame, it makes sense to
+ * grow, because the frame might just be a bit late;
+ * otherwise, we presently get into a pattern where we return
+ * INTERP for the lost frame, then it shows up next, and we
+ * throw it away because it's late */
+ /* I've recently only been able to replicate this using
+ * iaxclient talking to app_echo on asterisk. In this case,
+ * my outgoing packets go through asterisk's (old)
+ * jitterbuffer, and then might get an unusual increasing delay
+ * there if it decides to grow?? */
+ /* Update: that might have been a different bug, that has been fixed..
+ * But, this still seemed like a good idea, except that it ended up making a single actual
+ * lost frame get interpolated two or more times, when there was "room" to grow, so it might
+ * be a bit of a bad idea overall */
+ /*if (diff > -1 * jb->info.last_voice_ms) {
+ jb->info.current += jb->info.last_voice_ms;
+ jb->info.last_adjustment = now;
+ jb_warn("g");
+ return JB_INTERP;
+ } */
+ jb->info.frames_lost++;
+ increment_losspct(jb);
+ jb->info.next_voice_ts += interpl;
+ jb->info.last_voice_ms = interpl;
+ jb->info.cnt_contig_interp++;
+ /* assume silence instead of continuing to interpolate */
+ if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
+ jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
+ }
+ jb_dbg("L");
+ return JB_INTERP;
+ }
+
+ /* normal case; return the frame, increment stuff */
+ *frameout = *frame;
+ jb->info.next_voice_ts += frame->ms;
+ jb->info.frames_out++;
+ jb->info.cnt_contig_interp = 0;
+ decrement_losspct(jb);
+ jb_dbg("v");
+ return JB_OK;
+ } else {
+ /* TODO: after we get the non-silent case down, we'll make the
+ * silent case -- basically, we'll just grow and shrink faster
+ * here, plus handle next_voice_ts a bit differently */
+
+ /* to disable silent special case altogether, just uncomment this: */
+ /* jb->info.silence_begin_ts = 0; */
+
+ /* shrink interpl len every 10ms during silence */
+ if (diff < -jb->info.conf.target_extra &&
+ jb->info.last_adjustment + 10 <= now) {
+ jb->info.current -= interpl;
+ jb->info.last_adjustment = now;
+ }
+
+ frame = queue_get(jb, now - jb->info.current);
+ if (!frame) {
+ return JB_NOFRAME;
+ } else if (frame->type != JB_TYPE_VOICE) {
+ /* normal case; in silent mode, got a non-voice frame */
+ *frameout = *frame;
+ jb->info.frames_out++;
+ return JB_OK;
+ }
+ if (frame->ts < jb->info.silence_begin_ts) {
+ /* voice frame is late */
+ *frameout = *frame;
+ jb->info.frames_out++;
+ decrement_losspct(jb);
+ jb->info.frames_late++;
+ jb->info.frames_lost--;
+ jb_dbg("l");
+ /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb));
+ jb_warninfo(jb); */
+ return JB_DROP;
+ } else {
+ /* voice frame */
+ /* try setting current to target right away here */
+ jb->info.current = jb->info.target;
+ jb->info.silence_begin_ts = 0;
+ jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
+ jb->info.last_voice_ms = frame->ms;
+ jb->info.frames_out++;
+ decrement_losspct(jb);
+ *frameout = *frame;
+ jb_dbg("V");
+ return JB_OK;
+ }
+ }
+}
+
+time_in_ms_t jb_next(jitterbuf *jb)
+{
+ if (jb->info.silence_begin_ts) {
+ if (jb->frames) {
+ time_in_ms_t next = queue_next(jb);
+ history_get(jb);
+ /* shrink during silence */
+ if (jb->info.target - jb->info.current < -jb->info.conf.target_extra)
+ return jb->info.last_adjustment + 10;
+ return next + jb->info.target;
+ }
+ else
+ return JB_LONGMAX;
+ } else {
+ return jb->info.next_voice_ts;
+ }
+}
+
+enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frameout, time_in_ms_t now, long interpl)
+{
+ enum jb_return_code ret = _jb_get(jb, frameout, now, interpl);
+#if 0
+ static int lastts=0;
+ int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
+ jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists);
+ if (thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n");
+ lastts = thists;
+#endif
+ return ret;
+}
+
+enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout)
+{
+ jb_frame *frame;
+ frame = queue_getall(jb);
+
+ if (!frame) {
+ return JB_NOFRAME;
+ }
+
+ *frameout = *frame;
+ return JB_OK;
+}
+
+
+enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats)
+{
+ history_get(jb);
+
+ *stats = jb->info;
+
+ return JB_OK;
+}
+
+enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf)
+{
+ /* take selected settings from the struct */
+
+ jb->info.conf.max_jitterbuf = conf->max_jitterbuf;
+ jb->info.conf.resync_threshold = conf->resync_threshold;
+ jb->info.conf.max_contig_interp = conf->max_contig_interp;
+
+ /* -1 indicates use of the default JB_TARGET_EXTRA value */
+ jb->info.conf.target_extra = ( conf->target_extra == -1 )
+ ? JB_TARGET_EXTRA
+ : conf->target_extra
+ ;
+
+ /* update these to match new target_extra setting */
+ jb->info.current = jb->info.conf.target_extra;
+ jb->info.target = jb->info.conf.target_extra;
+
+ return JB_OK;
+}
+
+
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.h Thu May 8 19:25:36 2008
@@ -0,0 +1,162 @@
+/*
+ * jitterbuf: an application-independent jitterbuffer
+ *
+ * Copyrights:
+ * Copyright (C) 2004-2005, Horizon Wimba, Inc.
+ *
+ * Contributors:
+ * Steve Kann <stevek at stevek.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ */
+
+#ifndef _JITTERBUF_H_
+#define _JITTERBUF_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* configuration constants */
+ /* Number of historical timestamps to use in calculating jitter and drift */
+#define JB_HISTORY_SZ 500
+ /* what percentage of timestamps should we drop from the history when we examine it;
+ * this might eventually be something made configurable */
+#define JB_HISTORY_DROPPCT 3
+ /* the maximum droppct we can handle (say it was configurable). */
+#define JB_HISTORY_DROPPCT_MAX 4
+ /* the size of the buffer we use to keep the top and botton timestamps for dropping */
+#define JB_HISTORY_MAXBUF_SZ JB_HISTORY_SZ * JB_HISTORY_DROPPCT_MAX / 100
+ /* amount of additional jitterbuffer adjustment */
+#define JB_TARGET_EXTRA 40
+ /* ms between growing and shrinking; may not be honored if jitterbuffer runs out of space */
+#define JB_ADJUST_DELAY 40
+
+enum jb_return_code {
+ /* return codes */
+ JB_OK, /* 0 */
+ JB_EMPTY, /* 1 */
+ JB_NOFRAME, /* 2 */
+ JB_INTERP, /* 3 */
+ JB_DROP, /* 4 */
+ JB_SCHED /* 5 */
+};
+
+enum jb_frame_type {
+/* frame types */
+ JB_TYPE_CONTROL, /* 0 */
+ JB_TYPE_VOICE, /* 1 */
+ JB_TYPE_VIDEO, /* 2 - reserved */
+ JB_TYPE_SILENCE /* 3 */
+};
+
+typedef struct jb_conf {
+ /* settings */
+ long max_jitterbuf; /* defines a hard clamp to use in setting the jitter buffer delay */
+ long resync_threshold; /* the jb will resync when delay increases to (2 * jitter) + this param */
+ long max_contig_interp; /* the max interp frames to return in a row */
+ long target_extra; /* amount of additional jitterbuffer adjustment, overrides JB_TARGET_EXTRA */
+} jb_conf;
+
+typedef struct jb_info {
+ jb_conf conf;
+
+ /* statistics */
+ long frames_in; /* number of frames input to the jitterbuffer.*/
+ long frames_out; /* number of frames output from the jitterbuffer.*/
+ long frames_late; /* number of frames which were too late, and dropped.*/
+ long frames_lost; /* number of missing frames.*/
+ long frames_dropped; /* number of frames dropped (shrinkage) */
+ long frames_ooo; /* number of frames received out-of-order */
+ long frames_cur; /* number of frames presently in jb, awaiting delivery.*/
+ time_in_ms_t jitter; /* jitter measured within current history interval*/
+ time_in_ms_t min; /* minimum lateness within current history interval */
+ time_in_ms_t current; /* the present jitterbuffer adjustment */
+ time_in_ms_t target; /* the target jitterbuffer adjustment */
+ long losspct; /* recent lost frame percentage (* 1000) */
+ time_in_ms_t next_voice_ts; /* the ts of the next frame to be read from the jb - in receiver's time */
+ long last_voice_ms; /* the duration of the last voice frame */
+ time_in_ms_t silence_begin_ts; /* the time of the last CNG frame, when in silence */
+ time_in_ms_t last_adjustment; /* the time of the last adjustment */
+ time_in_ms_t last_delay; /* the last now added to history */
+ long cnt_delay_discont; /* the count of discontinuous delays */
+ time_in_ms_t resync_offset; /* the amount to offset ts to support resyncs */
+ long cnt_contig_interp; /* the number of contiguous interp frames returned */
+} jb_info;
+
+typedef struct jb_frame {
+ void *data; /* the frame data */
+ time_in_ms_t ts; /* the relative delivery time expected */
+ long ms; /* the time covered by this frame, in sec/8000 */
+ enum jb_frame_type type; /* the type of frame */
+ struct jb_frame *next, *prev;
+} jb_frame;
+
+typedef struct jitterbuf {
+ jb_info info;
+
+ /* history */
+ time_in_ms_t history[JB_HISTORY_SZ]; /* history */
+ int hist_ptr; /* points to index in history for next entry */
+ time_in_ms_t hist_maxbuf[JB_HISTORY_MAXBUF_SZ]; /* a sorted buffer of the max delays (highest first) */
+ time_in_ms_t hist_minbuf[JB_HISTORY_MAXBUF_SZ]; /* a sorted buffer of the min delays (lowest first) */
+ int hist_maxbuf_valid; /* are the "maxbuf"/minbuf valid? */
+
+ jb_frame *frames; /* queued frames */
+ jb_frame *free; /* free frames (avoid malloc?) */
+} jitterbuf;
+
+
+/* new jitterbuf */
+jitterbuf * jb_new(void);
+
+/* destroy jitterbuf */
+void jb_destroy(jitterbuf *jb);
+
+/* reset jitterbuf */
+/* NOTE: The jitterbuffer should be empty before you call this, otherwise
+ * you will leak queued frames, and some internal structures */
+void jb_reset(jitterbuf *jb);
+
+/* queue a frame data=frame data, timings (in ms): ms=length of frame (for voice), ts=ts (sender's time)
+ * now=now (in receiver's time) return value is one of
+ * JB_OK: Frame added. Last call to jb_next() still valid
+ * JB_DROP: Drop this frame immediately
+ * JB_SCHED: Frame added. Call jb_next() to get a new time for the next frame
+ */
+enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, time_in_ms_t ts, time_in_ms_t now);
+
+/* get a frame for time now (receiver's time) return value is one of
+ * JB_OK: You've got frame!
+ * JB_DROP: Here's an audio frame you should just drop. Ask me again for this time..
+ * JB_NOFRAME: There's no frame scheduled for this time.
+ * JB_INTERP: Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame)
+ * JB_EMPTY: The jb is empty.
+ */
+enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frame, time_in_ms_t now, long interpl);
+
+/* unconditionally get frames from jitterbuf until empty */
+enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout);
+
+/* when is the next frame due out, in receiver's time (0=EMPTY)
+ * This value may change as frames are added (esp non-audio frames) */
+time_in_ms_t jb_next(jitterbuf *jb);
+
+/* get jitterbuf info: only "statistics" may be valid */
+enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats);
+
+/* set jitterbuf conf */
+enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf);
+
+typedef void (*jb_output_function_t)(const char *fmt, ...);
+extern void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/md5.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/md5.c Thu May 8 19:25:36 2008
@@ -0,0 +1,297 @@
+/* MD5 checksum routines used for authentication. Not covered by GPL, but
+ in the public domain as per the copyright below */
+
+#ifdef FREEBSD
+# include <machine/endian.h>
+#elif defined(LINUX)
+# include <endian.h>
+# include <features.h>
+# include <sys/types.h>
+#elif defined(SOLARIS)
+ /* each solaris is different -- this won't work on 2.6 or 2.7 */
+# include <sys/isa_defs.h> /* Defines either _LITTLE_ENDIAN or _BIG_ENDIAN */
+# define __BIG_ENDIAN 4321
+# define __LITTLE_ENDIAN 1234
+# define BIG_ENDIAN 4321
+# define LITTLE_ENDIAN 1234
+# ifdef _LITTLE_ENDIAN
+# define __BYTE_ORDER __LITTLE_ENDIAN
+# define BYTE_ORDER LITTLE_ENDIAN
+# else
+# define __BYTE_ORDER __BIG_ENDIAN
+# define BYTE_ORDER BIG_ENDIAN
+# endif
+#endif
+
+#ifdef _MSC_VER
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#endif
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN || BYTE_ORDER == BIG_ENDIAN
+# define HIGHFIRST 1
+#elif __BYTE_ORDER == __LITTLE_ENDIAN || BYTE_ORDER == LITLE_ENDIAN
+# undef HIGHFIRST
+#else
+# error "Please fix <bits/endian.h>"
+#endif
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#include <string.h> /* for memcpy() */
+#include "md5.h"
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len) /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) ctx->in)[14] = ctx->bits[0];
+ ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#endif
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/md5.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/md5.h Thu May 8 19:25:36 2008
@@ -0,0 +1,27 @@
+#ifndef MD5_H
+#define MD5_H
+
+#if defined(__alpha) || defined(__x86_64)
+typedef unsigned int uint32;
+#else
+typedef unsigned long uint32;
+#endif
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+ unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* !MD5_H */
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/winiphone.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/winiphone.c Thu May 8 19:25:36 2008
@@ -0,0 +1,761 @@
+/*
+ * Miniphone: A simple, command line telephone
+ *
+ * IAX Support for talking to Asterisk and other Gnophone clients
+ *
+ * Copyright (C) 1999, Linux Support Services, Inc.
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+/* #define PRINTCHUCK /* enable this to indicate chucked incomming packets */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <io.h>
+#include <conio.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <process.h>
+#include <windows.h>
+#include <winsock.h>
+#include <mmsystem.h>
+#include <malloc.h>
+#include "gsm.h"
+#include "iax-client.h"
+#include "frame.h"
+#include "miniphone.h"
+
+
+struct peer {
+ int time;
+ gsm gsmin;
+ gsm gsmout;
+
+ struct iax_session *session;
+ struct peer *next;
+};
+
+static struct peer *peers;
+static int answered_call = 0;
+
+/* stuff for wave audio device */
+HWAVEOUT wout;
+HWAVEIN win;
+
+typedef struct whout {
+ WAVEHDR w;
+ short data[160];
+ struct whout *next;
+} WHOUT;
+
+WHOUT *outqueue = NULL;
+
+/* parameters for audio in */
+#define NWHIN 8 /* number of input buffer entries */
+/* NOTE the OUT_INTERVAL parameter *SHOULD* be more around 18 to 20 or so, since the packets should
+be spaced by 20 milliseconds. However, in practice, especially in Windoze-95, setting it that high
+caused underruns. 10 is just ever so slightly agressive, and the receiver has to chuck a packet
+every now and then. Thats about the way it should be to be happy. */
+#define OUT_INTERVAL 10 /* number of ms to wait before sending more data to peer */
+/* parameters for audio out */
+#define OUT_DEPTH 12 /* number of outbut buffer entries */
+#define OUT_PAUSE_THRESHOLD 2 /* number of active entries needed to start output (for smoothing) */
+
+/* audio input buffer headers */
+WAVEHDR whin[NWHIN];
+/* audio input buffers */
+char bufin[NWHIN][320];
+
+/* initialize the sequence variables for the audio in stuff */
+unsigned int whinserial = 1,nextwhin = 1;
+
+static struct peer *find_peer(struct iax_session *);
+static void parse_args(FILE *, unsigned char *);
+void do_iax_event(FILE *);
+void call(FILE *, char *);
+void answer_call(void);
+void reject_call(void);
+static void handle_event(FILE *, struct iax_event *e, struct peer *p);
+void parse_cmd(FILE *, int, char **);
+void issue_prompt(FILE *);
+void dump_array(FILE *, char **);
+
+static char *help[] = {
+"Welcome to the miniphone telephony client, the commands are as follows:\n",
+"Help\t\t-\tDisplays this screen.",
+"Call <Number>\t-\tDials the number supplied.",
+"Answer\t\t-\tAnswers an Inbound call.",
+"Reject\t\t-\tRejects an Inbound call.",
+"Dump\t\t-\tDumps (disconnects) the current call.",
+"Dtmf <Digit>\t-\tSends specified DTMF digit.",
+"Status\t\t-\tLists the current sessions and their current status.",
+"Quit\t\t-\tShuts down the client.",
+"",
+0
+};
+
+static struct peer *most_recent_answer;
+static struct iax_session *newcall = 0;
+
+/* holder of the time, relative to startup in system ticks. See our
+gettimeofday() implementation */
+time_t startuptime;
+
+/* routine called at exit to shutdown audio I/O and close nicely.
+NOTE: If all this isnt done, the system doesnt not handle this
+cleanly and has to be rebooted. What a pile of doo doo!! */
+void killem(void)
+{
+ waveInStop(win);
+ waveInReset(win);
+ waveInClose(win);
+ waveOutReset(wout);
+ waveOutClose(wout);
+ WSACleanup(); /* dont forget socket stuff too */
+ return;
+}
+
+/* Win-doze doenst have gettimeofday(). This sux. So, what we did is
+provide some gettimeofday-like functionality that works for our purposes.
+In the main(), we take a sample of the system tick counter (into startuptime).
+This function returns the relative time since program startup, more or less,
+which is certainly good enough for our purposes. */
+void gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ long l = startuptime + GetTickCount();
+
+ tv->tv_sec = l / 1000;
+ tv->tv_usec = (l % 1000) * 1000;
+ return;
+}
+
+
+static struct peer *find_peer(struct iax_session *session)
+{
+ struct peer *cur = peers;
+ while(cur) {
+ if (cur->session == session)
+ return cur;
+ cur = cur->next;
+ }
+ return NULL;
+}
+
+void
+parse_args(FILE *f, unsigned char *cmd)
+{
+ static char *argv[MAXARGS];
+ unsigned char *parse = cmd;
+ int argc = 0, t = 0;
+
+ // Don't mess with anything that doesn't exist...
+ if(!*parse)
+ return;
+
+ memset(argv, 0, sizeof(argv));
+ while(*parse) {
+ if(*parse < 33 || *parse > 128) {
+ *parse = 0, t++;
+ if(t > MAXARG) {
+ fprintf(f, "Warning: Argument exceeds maximum argument size, command ignored!\n");
+ return;
+ }
+ } else if(t || !argc) {
+ if(argc == MAXARGS) {
+ fprintf(f, "Warning: Command ignored, too many arguments\n");
+ return;
+ }
+ argv[argc++] = parse;
+ t = 0;
+ }
+
+ parse++;
+ }
+
+ if(argc)
+ parse_cmd(f, argc, argv);
+}
+
+/* handle all network requests, and a pending scheduled event, if any */
+void service_network(int netfd, FILE *f)
+{
+ fd_set readfd;
+ struct timeval dumbtimer;
+
+ /* set up a timer that falls-through */
+ dumbtimer.tv_sec = 0;
+ dumbtimer.tv_usec = 0;
+
+
+ for(;;) /* suck everything outa network stuff */
+ {
+ FD_ZERO(&readfd);
+ FD_SET(netfd, &readfd);
+ if (select(netfd + 1, &readfd, 0, 0, &dumbtimer) > 0)
+ {
+ if (FD_ISSET(netfd,&readfd))
+ {
+ do_iax_event(f);
+ (void) iax_time_to_next_event();
+ } else break;
+ } else break;
+ }
+ do_iax_event(f); /* do pending event if any */
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int port;
+ int netfd;
+ int c, i;
+ FILE *f;
+ char rcmd[RBUFSIZE];
+ gsm_frame fo;
+ WSADATA foop;
+ time_t t;
+ WAVEFORMATEX wf;
+ WHOUT *wh,*wh1,*wh2;
+ unsigned long lastouttick = 0;
+
+
+
+ /* get time of day in milliseconds, offset by tick count (see our
+ gettimeofday() implementation) */
+ time(&t);
+ startuptime = ((t % 86400) * 1000) - GetTickCount();
+
+ f = stdout;
+ _dup2(fileno(stdout),fileno(stderr));
+
+ /* start up the windoze-socket layer stuff */
+ if (WSAStartup(0x0101,&foop)) {
+ fprintf(stderr,"Fatal error: Falied to startup windows sockets\n");
+ return -1;
+ }
+
+
+ /* setup the format for opening audio channels */
+ wf.wFormatTag = WAVE_FORMAT_PCM;
+ wf.nChannels = 1;
+ wf.nSamplesPerSec = 8000;
+ wf.nAvgBytesPerSec = 16000;
+ wf.nBlockAlign = 2;
+ wf.wBitsPerSample = 16;
+ wf.cbSize = 0;
+ /* open the audio out channel */
+ if (waveOutOpen(&wout,0,&wf,0,0,CALLBACK_NULL) != MMSYSERR_NOERROR)
+ {
+ fprintf(stderr,"Fatal Error: Failed to open wave output device\n");
+ return -1;
+ }
+ /* open the audio in channel */
+ if (waveInOpen(&win,0,&wf,0,0,CALLBACK_NULL) != MMSYSERR_NOERROR)
+ {
+ fprintf(stderr,"Fatal Error: Failed to open wave input device\n");
+ waveOutReset(wout);
+ waveOutClose(wout);
+ return -1;
+ }
+ /* activate the exit handler */
+ atexit(killem);
+ /* initialize the audio in buffer structures */
+ memset(&whin,0,sizeof(whin));
+
+ if ( (port = iax_init(0) < 0)) {
+ fprintf(stderr, "Fatal error: failed to initialize iax with port %d\n", port);
+ return -1;
+ }
+
+
+ iax_set_formats(AST_FORMAT_GSM);
+ netfd = iax_get_fd();
+
+ fprintf(f, "Text Based Telephony Client.\n\n");
+ issue_prompt(f);
+
+ /* main tight loop */
+ while(1) {
+ /* service the network stuff */
+ service_network(netfd,f);
+ if (outqueue) /* if stuff in audio output queue, free it up if its available */
+ {
+ /* go through audio output queue */
+ for(wh = outqueue,wh1 = wh2 = NULL,i = 0; wh != NULL; wh = wh->next)
+ {
+ service_network(netfd,f); /* service network here for better performance */
+ /* if last one was removed from queue, zot it here */
+ if (i && wh1)
+ {
+ free(wh1);
+ wh1 = wh2;
+ }
+ i = 0; /* reset "last one removed" flag */
+ if (wh->w.dwFlags & WHDR_DONE) /* if this one is done */
+ {
+ /* prepare audio header */
+ if ((c = waveOutUnprepareHeader(wout,&wh->w,sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
+ {
+ fprintf(stderr,"Cannot unprepare audio out header, error %d\n",c);
+ exit(255);
+ }
+ if (wh1 != NULL) /* if there was a last one */
+ {
+ wh1->next = wh->next;
+ }
+ if (outqueue == wh) /* is first one, so set outqueue to next one */
+ {
+ outqueue = wh->next;
+ }
+ i = 1; /* set 'to free' flag */
+ }
+ wh2 = wh1; /* save old,old wh pointer */
+ wh1 = wh; /* save the old wh pointer */
+ }
+ }
+ /* go through all audio in buffers, and prepare and queue ones that are currently idle */
+ for(i = 0; i < NWHIN; i++)
+ {
+ service_network(netfd,f); /* service network stuff here for better performance */
+ if (!(whin[i].dwFlags & WHDR_PREPARED)) /* if not prepared, do so */
+ {
+ /* setup this input buffer header */
+ memset(&whin[i],0,sizeof(WAVEHDR));
+ whin[i].lpData = bufin[i];
+ whin[i].dwBufferLength = 320;
+ whin[i].dwUser = whinserial++; /* set 'user data' to current serial number */
+ /* prepare the buffer */
+ if (waveInPrepareHeader(win,&whin[i],sizeof(WAVEHDR)))
+ {
+ fprintf(stderr,"Unable to prepare header for input\n");
+ return -1;
+ }
+ /* add it to device (queue) */
+ if (waveInAddBuffer(win,&whin[i],sizeof(WAVEHDR)))
+ {
+ fprintf(stderr,"Unable to prepare header for input\n");
+ return -1;
+ }
+ }
+ waveInStart(win); /* start it (if not already started) */
+ }
+
+ /* if key pressed, do command stuff */
+ if(_kbhit())
+ {
+ if ( ( fgets(&*rcmd, 256, stdin))) {
+ rcmd[strlen(rcmd)-1] = 0;
+ parse_args(f, &*rcmd);
+ } else fprintf(f, "Fatal error: failed to read data!\n");
+
+ issue_prompt(f);
+ }
+ /* do audio input stuff for buffers that have received data from audio in device already. Must
+ do them in serial number order (the order in which they were originally queued). */
+ if(answered_call) /* send audio only if call answered */
+ {
+ for(;;) /* loop until all are found */
+ {
+ for(i = 0; i < NWHIN; i++) /* find an available one that's the one we are looking for */
+ {
+ service_network(netfd,f); /* service network here for better performance */
+ /* if not time to send any more, dont */
+ if (GetTickCount() < (lastouttick + OUT_INTERVAL))
+ {
+ i = NWHIN; /* set to value that WILL exit loop */
+ break;
+ }
+ if ((whin[i].dwUser == nextwhin) && (whin[i].dwFlags & WHDR_DONE)) { /* if audio is ready */
+
+ /* must have read exactly 320 bytes */
+ if (whin[i].dwBytesRecorded != whin[i].dwBufferLength)
+ {
+ fprintf(stderr,"Short audio read, got %d bytes, expected %d bytes\n", whin[i].dwBytesRecorded,
+ whin[i].dwBufferLength);
+ return -1;
+ }
+ if(!most_recent_answer->gsmout)
+ most_recent_answer->gsmout = gsm_create();
+
+ service_network(netfd,f); /* service network here for better performance */
+ /* encode the audio from the buffer into GSM format */
+ gsm_encode(most_recent_answer->gsmout, (short *) ((char *) whin[i].lpData), fo);
+ if(iax_send_voice(most_recent_answer->session,
+ AST_FORMAT_GSM, (char *)fo, sizeof(gsm_frame)) == -1)
+ puts("Failed to send voice!");
+ lastouttick = GetTickCount(); /* save time of last output */
+
+ /* unprepare (free) the header */
+ waveInUnprepareHeader(win,&whin[i],sizeof(WAVEHDR));
+ /* initialize the buffer */
+ memset(&whin[i],0,sizeof(WAVEHDR));
+ /* bump the serial number to look for the next time */
+ nextwhin++;
+ /* exit the loop so that we can start at lowest buffer again */
+ break;
+ }
+ }
+ if (i >= NWHIN) break; /* if all found, get out of loop */
+ }
+ }
+
+ }
+ return 0;
+}
+
+void
+do_iax_event(FILE *f) {
+ int sessions = 0;
+ struct iax_event *e = 0;
+ struct peer *peer;
+
+ while ( (e = iax_get_event(0))) {
+ peer = find_peer(e->session);
+ if(peer) {
+ handle_event(f, e, peer);
+ } else {
+ if(e->etype != IAX_EVENT_CONNECT) {
+ fprintf(stderr, "Huh? This is an event for a non-existant session?\n");
+ }
+ sessions++;
+
+ if(sessions >= MAX_SESSIONS) {
+ fprintf(f, "Missed a call... too many sessions open.\n");
+ }
+
+
+ if(e->event.connect.callerid && e->event.connect.dnid)
+ fprintf(f, "Call from '%s' for '%s'", e->event.connect.callerid,
+ e->event.connect.dnid);
+ else if(e->event.connect.dnid) {
+ fprintf(f, "Call from '%s'", e->event.connect.dnid);
+ } else if(e->event.connect.callerid) {
+ fprintf(f, "Call from '%s'", e->event.connect.callerid);
+ } else printf("Call from");
+ fprintf(f, " (%s)\n", inet_ntoa(iax_get_peer_addr(e->session).sin_addr));
+
+ if(most_recent_answer) {
+ fprintf(f, "Incoming call ignored, there's already a call waiting for answer... \
+please accept or reject first\n");
+ iax_reject(e->session, "Too many calls, we're busy!");
+ } else {
+ if ( !(peer = malloc(sizeof(struct peer)))) {
+ fprintf(f, "Warning: Unable to allocate memory!\n");
+ return;
+ }
+
+ peer->time = time(0);
+ peer->session = e->session;
+ peer->gsmin = 0;
+ peer->gsmout = 0;
+
+ peer->next = peers;
+ peers = peer;
+
+ iax_accept(peer->session);
+ iax_ring_announce(peer->session);
+ most_recent_answer = peer;
+ fprintf(f, "Incoming call!\n");
+ }
+ iax_event_free(e);
+ issue_prompt(f);
+ }
+ }
+}
+
+void
+call(FILE *f, char *num)
+{
+ struct peer *peer;
+
+ if(!newcall)
+ newcall = iax_session_new();
+ else {
+ fprintf(f, "Already attempting to call somewhere, please cancel first!\n");
+ return;
+ }
+
+ if ( !(peer = malloc(sizeof(struct peer)))) {
+ fprintf(f, "Warning: Unable to allocate memory!\n");
+ return;
+ }
+
+ peer->time = time(0);
+ peer->session = newcall;
+ peer->gsmin = 0;
+ peer->gsmout = 0;
+
+ peer->next = peers;
+ peers = peer;
+
+ most_recent_answer = peer;
+
+ iax_call(peer->session, num, 10);
+}
+
+void
+answer_call(void)
+{
+ if(most_recent_answer)
+ iax_answer(most_recent_answer->session);
+ printf("Answering call!\n");
+ answered_call = 1;
+}
+
+void
+dump_call(void)
+{
+ if(most_recent_answer)
+ {
+ iax_hangup(most_recent_answer->session,"");
+ free(most_recent_answer);
+ }
+ printf("Dumping call!\n");
+ answered_call = 0;
+ most_recent_answer = 0;
+ answered_call = 0;
+ peers = 0;
+ newcall = 0;
+}
+
+void
+reject_call(void)
+{
+ iax_reject(most_recent_answer->session, "Call rejected manually.");
+ most_recent_answer = 0;
+}
+
+void
+handle_event(FILE *f, struct iax_event *e, struct peer *p)
+{
+ int len,n;
+ WHOUT *wh,*wh1;
+ short fr[160];
+ static paused_xmit = 0;
+
+
+ switch(e->etype) {
+ case IAX_EVENT_HANGUP:
+ iax_hangup(most_recent_answer->session, "Byeee!");
+ fprintf(f, "Call disconnected by peer\n");
+ free(most_recent_answer);
+ most_recent_answer = 0;
+ answered_call = 0;
+ peers = 0;
+ newcall = 0;
+
+ break;
+
+ case IAX_EVENT_REJECT:
+ fprintf(f, "Authentication was rejected\n");
+ break;
+ case IAX_EVENT_ACCEPT:
+ fprintf(f, "Waiting for answer... RING RING\n");
+ issue_prompt(f);
+ break;
+ case IAX_EVENT_ANSWER:
+ answer_call();
+ break;
+ case IAX_EVENT_VOICE:
+ switch(e->event.voice.format) {
+ case AST_FORMAT_GSM:
+ if(e->event.voice.datalen % 33) {
+ fprintf(stderr, "Weird gsm frame, not a multiple of 33.\n");
+ break;
+ }
+
+ if (!p->gsmin)
+ p->gsmin = gsm_create();
+
+ len = 0;
+ while(len < e->event.voice.datalen) {
+ if(gsm_decode(p->gsmin, (char *) e->event.voice.data + len, fr)) {
+ fprintf(stderr, "Bad GSM data\n");
+ break;
+ } else { /* its an audio packet to be output to user */
+
+ /* get count of pending items in audio output queue */
+ n = 0;
+ if (outqueue)
+ { /* determine number of pending out queue items */
+ for(wh = outqueue; wh != NULL; wh = wh->next)
+ {
+ if (!(wh->w.dwFlags & WHDR_DONE)) n++;
+ }
+ }
+ /* if not too many, send to user, otherwise chuck packet */
+ if (n <= OUT_DEPTH) /* if not to chuck packet */
+ {
+ /* malloc the memory for the queue item */
+ wh = (WHOUT *) malloc(sizeof(WHOUT));
+ if (wh == (WHOUT *) NULL) /* if error, bail */
+ {
+ fprintf(stderr,"Outa memory!!!!\n");
+ exit(255);
+ }
+ /* initialize the queue entry */
+ memset(wh,0,sizeof(WHOUT));
+ /* copy the PCM data from the gsm conversion buffer */
+ memcpy((char *)wh->data,(char *)fr,sizeof(fr));
+ /* set parameters for data */
+ wh->w.lpData = (char *) wh->data;
+ wh->w.dwBufferLength = 320;
+
+ /* prepare buffer for output */
+ if (waveOutPrepareHeader(wout,&wh->w,sizeof(WAVEHDR)))
+ {
+ fprintf(stderr,"Cannot prepare header for audio out\n");
+ exit(255);
+ }
+ /* if not currently transmitting, hold off a couple of packets for
+ smooth sounding output */
+ if ((!n) && (!paused_xmit))
+ {
+ /* pause output (before starting) */
+ waveOutPause(wout);
+ /* indicate as such */
+ paused_xmit = 1;
+ }
+ /* queue packet for output on audio device */
+ if (waveOutWrite(wout,&wh->w,sizeof(WAVEHDR)))
+ {
+ fprintf(stderr,"Cannot output to wave output device\n");
+ exit(255);
+ }
+ /* if we are paused, and we have enough packets, start audio */
+ if ((n > OUT_PAUSE_THRESHOLD) && paused_xmit)
+ {
+ /* start the output */
+ waveOutRestart(wout);
+ /* indicate as such */
+ paused_xmit = 0;
+ }
+ /* insert it onto tail of outqueue */
+ if (outqueue == NULL) /* if empty queue */
+ outqueue = wh; /* point queue to new entry */
+ else /* otherwise is non-empty queue */
+ {
+ wh1 = outqueue;
+ while(wh1->next) wh1 = wh1->next; /* find last entry in queue */
+ wh1->next = wh; /* point it to new entry */
+ }
+ }
+#ifdef PRINTCHUCK
+ else printf("Chucking packet!!\n");
+#endif
+ }
+ len += 33;
+ }
+ break;
+ default :
+ fprintf(f, "Don't know how to handle that format %d\n", e->event.voice.format);
+ }
+ break;
+ case IAX_EVENT_RINGA:
+ break;
+ default:
+ fprintf(f, "Unknown event: %d\n", e->etype);
+ break;
+ }
+}
+
+void
+parse_cmd(FILE *f, int argc, char **argv)
+{
+ _strupr(argv[0]);
+ if(!strcmp(argv[0], "HELP")) {
+ if(argc == 1)
+ dump_array(f, help);
+ else if(argc == 2) {
+ if(!strcmp(argv[1], "HELP"))
+ fprintf(f, "Help <Command>\t-\tDisplays general help or specific help on command if supplied an arguement\n");
+ else if(!strcmp(argv[1], "QUIT"))
+ fprintf(f, "Quit\t\t-\tShuts down the miniphone\n");
+ else fprintf(f, "No help available on %s\n", argv[1]);
+ } else {
+ fprintf(f, "Too many arguements for command help.\n");
+ }
+ } else if(!strcmp(argv[0], "STATUS")) {
+ if(argc == 1) {
+ int c = 0;
+ struct peer *peerptr = peers;
+
+ if(!peerptr)
+ fprintf(f, "No session matches found.\n");
+ else while(peerptr) {
+ fprintf(f, "Listing sessions:\n\n");
+ fprintf(f, "Session %d\n", ++c);
+ fprintf(f, "Session existed for %d seconds\n", (int)time(0)-peerptr->time);
+ if(answered_call)
+ fprintf(f, "Call answered.\n");
+ else fprintf(f, "Call ringing.\n");
+
+ peerptr = peerptr->next;
+ }
+ } else fprintf(f, "Too many arguments for command status.\n");
+ } else if(!strcmp(argv[0], "ANSWER")) {
+ if(argc > 1)
+ fprintf(f, "Too many arguements for command answer\n");
+ else answer_call();
+ } else if(!strcmp(argv[0], "REJECT")) {
+ if(argc > 1)
+ fprintf(f, "Too many arguements for command reject\n");
+ else {
+ fprintf(f, "Rejecting current phone call.\n");
+ reject_call();
+ }
+ } else if(!strcmp(argv[0], "CALL")) {
+ if(argc > 2)
+ fprintf(f, "Too many arguements for command call\n");
+ else {
+ call(f, argv[1]);
+ }
+ } else if(!strcmp(argv[0], "DUMP")) {
+ if(argc > 1)
+ fprintf(f, "Too many arguements for command dump\n");
+ else {
+ dump_call();
+ }
+ } else if(!strcmp(argv[0], "DTMF")) {
+ if(argc > 2)
+ {
+ fprintf(f, "Too many arguements for command dtmf\n");
+ return;
+ }
+ if (argc < 1)
+ {
+ fprintf(f, "Too many arguements for command dtmf\n");
+ return;
+ }
+ if(most_recent_answer)
+ iax_send_dtmf(most_recent_answer->session,*argv[1]);
+ } else if(!strcmp(argv[0], "QUIT")) {
+ if(argc > 1)
+ fprintf(f, "Too many arguements for command quit\n");
+ else {
+ fprintf(f, "Good bye!\n");
+ exit(1);
+ }
+ } else fprintf(f, "Unknown command of %s\n", argv[0]);
+}
+
+void
+issue_prompt(FILE *f)
+{
+ fprintf(f, "TeleClient> ");
+ fflush(f);
+}
+
+void
+dump_array(FILE *f, char **array) {
+ while(*array)
+ fprintf(f, "%s\n", *array++);
+}
Added: freeswitch/trunk/src/mod/endpoints/mod_iax/winpoop.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/winpoop.h Thu May 8 19:25:36 2008
@@ -0,0 +1,40 @@
+/*
+ * Functions Windows doesn't have... but should
+ * Copyright(C) 2001, Linux Support Services, Inc.
+ *
+ * Distributed under GNU LGPL.
+ *
+ * These are NOT fully compliant with BSD 4.3 and are not
+ * threadsafe.
+ *
+ */
+
+#ifndef _winpoop_h
+#define _winpoop_h
+
+#if defined(_MSC_VER)
+#define INLINE __inline
+#else
+#define INLINE inline
+#endif
+
+#include <winsock.h>
+
+void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
+
+static INLINE int inet_aton(char *cp, struct in_addr *inp)
+{
+ int a1, a2, a3, a4;
+ unsigned int saddr;
+ if (sscanf(cp, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) != 4)
+ return 0;
+ a1 &= 0xff;
+ a2 &= 0xff;
+ a3 &= 0xff;
+ a4 &= 0xff;
+ saddr = (a1 << 24) | (a2 << 16) | (a3 << 8) | a4;
+ inp->s_addr = htonl(saddr);
+ return 1;
+}
+
+#endif
More information about the Freeswitch-svn
mailing list