aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormatteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b>2003-03-16 06:00:11 +0000
committermatteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b>2003-03-16 06:00:11 +0000
commit40b9926da3752f8e6f5d1a23d4dd8ae8655df2b1 (patch)
tree9235ce2b731423c7bd45914947a3e092a690abe9
parent30610b61ae18888f54ae12b9cef4a95917e969e6 (diff)
Sun Mar 16 07:00:01 CET 2003
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@646 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-xCHANGES1
-rwxr-xr-xapps/Makefile2
-rwxr-xr-xapps/app_chanisavail.c130
-rwxr-xr-xastman/astman.c4
-rwxr-xr-xchannels/Makefile1
-rwxr-xr-xchannels/chan_iax2.c490
-rwxr-xr-xchannels/chan_sip.c47
-rwxr-xr-xchannels/chan_zap.c11
-rwxr-xr-xchannels/iax2.h4
-rwxr-xr-xconfigs/iax.conf.sample3
-rwxr-xr-xutils/astman.c4
11 files changed, 628 insertions, 69 deletions
diff --git a/CHANGES b/CHANGES
index 3fc4dcc4f..7e4abc313 100755
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,4 @@
+ -- Add experimental "trunk" option to IAX2 for high density VoIP
-- Add experimental "debug channel" command
-- Add 'C' flag to dial command to reset call detail record (handy for calling cards)
-- Add NAT and dynamic support to MGCP
diff --git a/apps/Makefile b/apps/Makefile
index 48087f76c..30e1a9f27 100755
--- a/apps/Makefile
+++ b/apps/Makefile
@@ -19,7 +19,7 @@ APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_intercom.
app_queue.so app_senddtmf.so app_parkandannounce.so app_striplsd.so \
app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so \
app_authenticate.so app_softhangup.so app_lookupblacklist.so \
- app_waitforring.so app_privacy.so app_db.so
+ app_waitforring.so app_privacy.so app_db.so app_chanisavail.so
#APPS+=app_sql_postgres.so
#APPS+=app_sql_odbc.so
diff --git a/apps/app_chanisavail.c b/apps/app_chanisavail.c
new file mode 100755
index 000000000..e2ad6e7e9
--- /dev/null
+++ b/apps/app_chanisavail.c
@@ -0,0 +1,130 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Check if Channel is Available
+ *
+ * Copyright (C) 2003, Digium
+ *
+ * Mark Spencer <markster@digium.com>
+ * James Golovich <james@gnuinter.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ *
+ */
+
+#include <asterisk/lock.h>
+#include <asterisk/file.h>
+#include <asterisk/logger.h>
+#include <asterisk/channel.h>
+#include <asterisk/pbx.h>
+#include <asterisk/module.h>
+#include <asterisk/app.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+
+#include <pthread.h>
+
+static char *tdesc = "Check if channel is available";
+
+static char *app = "ChanIsAvail";
+
+static char *synopsis = "Check if channel is available";
+
+static char *descrip =
+" ChanIsAvail(Technology/resource[&Technology2/resource2...]): \n"
+"Checks is any of the requested channels are available. If none\n"
+"of the requested channels are available the new priority will\n"
+"be n+101 (unless such a priority does not exist, in which case\n"
+"ChanIsAvail will return -1. If any of the requested channels\n"
+"are available, the next priority will be n+1 and ChanIsAvail\n"
+"will return 0.\n";
+
+STANDARD_LOCAL_USER;
+
+LOCAL_USER_DECL;
+
+static int chanavail_exec(struct ast_channel *chan, void *data)
+{
+ int res=-1;
+ struct localuser *u;
+ char info[256], *peers, *tech, *number, *rest, *cur;
+ struct ast_channel *tempchan;
+
+ if (!data) {
+ ast_log(LOG_WARNING, "ChanIsAvail requires an argument (Zap/1&Zap/2)\n");
+ return -1;
+ }
+ LOCAL_USER_ADD(u);
+
+ strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
+ peers = info;
+ if (peers) {
+ cur = peers;
+ do {
+ /* remember where to start next time */
+ rest = strchr(cur, '&');
+ if (rest) {
+ *rest = 0;
+ rest++;
+ }
+ tech = cur;
+ number = strchr(tech, '/');
+ if (!number) {
+ ast_log(LOG_WARNING, "ChanIsAvail argument takes format (Zap/[device])\n");
+ continue;
+ }
+ *number = '\0';
+ number++;
+ if ((tempchan = ast_request(tech, chan->nativeformats, number))) {
+ ast_hangup(tempchan);
+ tempchan = NULL;
+ res = 1;
+ break;
+ }
+ cur = rest;
+ } while (cur);
+ }
+
+ if (res < 1) {
+ if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
+ chan->priority+=100;
+ else
+ return -1;
+ }
+
+ LOCAL_USER_REMOVE(u);
+ return 0;
+}
+
+int unload_module(void)
+{
+ STANDARD_HANGUP_LOCALUSERS;
+ return ast_unregister_application(app);
+}
+
+int load_module(void)
+{
+ return ast_register_application(app, chanavail_exec, synopsis, descrip);
+}
+
+char *description(void)
+{
+ return tdesc;
+}
+
+int usecount(void)
+{
+ int res;
+ STANDARD_USECOUNT(res);
+ return res;
+}
+
+char *key()
+{
+ return ASTERISK_GPL_KEY;
+}
diff --git a/astman/astman.c b/astman/astman.c
index 6fa6b8118..2eb35f68e 100755
--- a/astman/astman.c
+++ b/astman/astman.c
@@ -383,14 +383,14 @@ static int show_doing(char *title, char *tmp)
return 0;
}
-static int hide_doing()
+static int hide_doing(void)
{
newtPopWindow();
newtFormDestroy(showform);
return 0;
}
-static void try_status()
+static void try_status(void)
{
struct message *m;
manager_action("Status", "");
diff --git a/channels/Makefile b/channels/Makefile
index 8105e7821..9bf327b6b 100755
--- a/channels/Makefile
+++ b/channels/Makefile
@@ -33,6 +33,7 @@ ZAPPRI=$(shell [ -f /usr/lib/libpri.so.1 ] && echo "-lpri")
ZAPR2=$(shell [ -f /usr/lib/libmfcr2.so.1 ] && echo "-lmfcr2")
CHANZAP=$(shell if [ -f .oldzap ]; then echo "chan_zap_old.c"; else echo "chan_zap.c"; fi)
ZAPLIB=$(shell if [ -f .oldzap ]; then echo "-lzap"; fi)
+CFLAGS+=$(shell [ -f /usr/include/linux/zaptel.h ] && echo "-DIAX_TRUNKING")
ALSA_SRC=chan_alsa.c
ALSA_SRC+=$(shell [ -f alsa-monitor.h ] && echo "alsa-monitor.h")
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index bd8810720..e73f680b9 100755
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -44,6 +44,10 @@
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
+#ifdef IAX_TRUNKING
+#include <sys/ioctl.h>
+#include <linux/zaptel.h>
+#endif
#include "iax2.h"
@@ -59,9 +63,14 @@
#define DEFAULT_RETRY_TIME 1000
#define MEMORY_SIZE 100
#define DEFAULT_DROP 3
+/* Flag to use with trunk calls, keeping these calls high up. It halves our effective use
+ but keeps the division between trunked and non-trunked better. */
+#define TRUNK_CALL_START 0x4000
#define DEBUG_SUPPORT
+#define MIN_REUSE_TIME 60 /* Don't reuse a call number within 60 seconds */
+
/* Sample over last 100 units to determine historic jitter */
#define GAMMA (0.01)
@@ -74,8 +83,10 @@ static char context[80] = "default";
static int max_retries = 4;
static int ping_time = 20;
static int lagrq_time = 10;
-static int nextcallno = 1;
+static int maxtrunkcall = TRUNK_CALL_START;
+static int maxnontrunkcall = 1;
static int maxjitterbuffer=3000;
+static int trunkfreq = 20;
static int iaxdefaultdpcache=10 * 60; /* Cache dialplan entries for 10 minutes by default */
@@ -87,6 +98,8 @@ static int tos = 0;
static int expirey = AST_DEFAULT_REG_EXPIRE;
+static int timingfd = -1; /* Timing file descriptor */
+
static int usecnt;
static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
@@ -145,7 +158,7 @@ struct iax2_user {
char inkeys[80]; /* Key(s) this user can use to authenticate to us */
int amaflags;
int hascallerid;
- int trunk; /* Treat with IAX2 trunking */
+ int trunk;
char callerid[AST_MAX_EXTENSION];
struct ast_ha *ha;
struct iax2_context *contexts;
@@ -180,6 +193,10 @@ struct iax2_peer {
int capability; /* Capability */
int delme; /* I need to be deleted */
int trunk; /* Treat as an IAX trunking */
+ struct timeval txtrunktime; /* Transmit trunktime */
+ struct timeval rxtrunktime; /* Receive trunktime */
+ struct timeval lasttxtime; /* Last transmitted trunktime */
+ unsigned int lastsent; /* Last sent time */
/* Qualification */
int callno; /* Call number of POKE request */
@@ -350,6 +367,7 @@ struct chan_iax2_pvt {
/* Trunk data and length */
unsigned char trunkdata[MAX_TRUNKDATA];
unsigned int trunkdatalen;
+ int trunkerror;
struct iax2_dpcache *dpentries;
};
@@ -538,7 +556,7 @@ static struct iax2_ie {
{ IAX_IE_VERSION, "VERSION", dump_short },
{ IAX_IE_ADSICPE, "ADSICPE", dump_short },
{ IAX_IE_DNID, "DNID", dump_string },
- { IAX_IE_AUTHMETHODS, "AUTHMETHODS", dump_int },
+ { 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 },
@@ -719,6 +737,8 @@ void showframe(struct ast_iax2_frame *f, struct ast_iax2_full_hdr *fhi, int rx,
/* XXX We probably should use a mutex when working with this XXX */
static struct chan_iax2_pvt *iaxs[AST_IAX2_MAX_CALLS];
static pthread_mutex_t iaxsl[AST_IAX2_MAX_CALLS];
+static struct timeval lastused[AST_IAX2_MAX_CALLS];
+
static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, char *, int, int);
static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, char *, int, int);
@@ -932,14 +952,99 @@ static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short
return 0;
}
+static void update_max_trunk(void)
+{
+ int max = TRUNK_CALL_START;
+ int x;
+ /* XXX Prolly don't need locks here XXX */
+ for (x=TRUNK_CALL_START;x<AST_IAX2_MAX_CALLS - 1; x++) {
+ if (iaxs[x])
+ max = x + 1;
+ }
+ maxtrunkcall = max;
+ if (option_debug)
+ ast_log(LOG_DEBUG, "New max trunk callno is %d\n", max);
+}
+
+static void update_max_nontrunk(void)
+{
+ int max = 1;
+ int x;
+ /* XXX Prolly don't need locks here XXX */
+ for (x=1;x<TRUNK_CALL_START - 1; x++) {
+ if (iaxs[x])
+ max = x + 1;
+ }
+ maxnontrunkcall = max;
+ if (option_debug)
+ ast_log(LOG_DEBUG, "New max nontrunk callno is %d\n", max);
+}
+
+static int make_trunk(unsigned short callno, int locked)
+{
+ int x;
+ int res= 0;
+ struct timeval now;
+ if (iaxs[callno]->oseqno) {
+ ast_log(LOG_WARNING, "Can't make trunk once a call has started!\n");
+ return -1;
+ }
+ if (callno & TRUNK_CALL_START) {
+ ast_log(LOG_WARNING, "Call %d is already a trunk\n", callno);
+ return -1;
+ }
+ gettimeofday(&now, NULL);
+ for (x=TRUNK_CALL_START;x<AST_IAX2_MAX_CALLS - 1; x++) {
+ ast_pthread_mutex_lock(&iaxsl[x]);
+ if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) {
+ iaxs[x] = iaxs[callno];
+ iaxs[x]->callno = x;
+ iaxs[callno] = NULL;
+ /* Update the two timers that should have been started */
+ if (iaxs[x]->pingid > -1)
+ ast_sched_del(sched, iaxs[x]->pingid);
+ if (iaxs[x]->lagid > -1)
+ ast_sched_del(sched, iaxs[x]->lagid);
+ iaxs[x]->pingid = ast_sched_add(sched, ping_time * 1000, send_ping, (void *)x);
+ iaxs[x]->lagid = ast_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)x);
+ if (locked)
+ ast_pthread_mutex_unlock(&iaxsl[callno]);
+ res = x;
+ if (!locked)
+ ast_pthread_mutex_unlock(&iaxsl[x]);
+ break;
+ }
+ ast_pthread_mutex_unlock(&iaxsl[x]);
+ }
+ if (x >= AST_IAX2_MAX_CALLS - 1) {
+ ast_log(LOG_WARNING, "Unable to trunk call: Insufficient space\n");
+ return -1;
+ }
+ ast_log(LOG_DEBUG, "Made call %d into trunk call %d\n", callno, x);
+ /* We move this call from a non-trunked to a trunked call */
+ update_max_trunk();
+ update_max_nontrunk();
+ return res;
+}
+
static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new)
{
int res = 0;
int x;
- int start;
+ struct timeval now;
if (new <= NEW_ALLOW) {
/* Look for an existing connection first */
- for (x=0;(res < 1) && (x<AST_IAX2_MAX_CALLS);x++) {
+ for (x=1;(res < 1) && (x<maxnontrunkcall);x++) {
+ ast_pthread_mutex_lock(&iaxsl[x]);
+ if (iaxs[x]) {
+ /* Look for an exact match */
+ if (match(sin, callno, dcallno, iaxs[x])) {
+ res = x;
+ }
+ }
+ ast_pthread_mutex_unlock(&iaxsl[x]);
+ }
+ for (x=TRUNK_CALL_START;(res < 1) && (x<maxtrunkcall);x++) {
ast_pthread_mutex_lock(&iaxsl[x]);
if (iaxs[x]) {
/* Look for an exact match */
@@ -951,16 +1056,21 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
}
}
if ((res < 1) && (new >= NEW_ALLOW)) {
- /* Create a new one */
- start = nextcallno;
- for (x = ((nextcallno + 1) % (AST_IAX2_MAX_CALLS - 1)) + 1; iaxs[x] && (x != start); x = (x + 1) % AST_IAX2_MAX_CALLS)
- if (x == start) {
- ast_log(LOG_WARNING, "Unable to accept more calls\n");
- return 0;
+ gettimeofday(&now, NULL);
+ for (x=1;x<TRUNK_CALL_START;x++) {
+ /* Find first unused call number that hasn't been used in a while */
+ ast_pthread_mutex_lock(&iaxsl[x]);
+ if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) break;
+ ast_pthread_mutex_unlock(&iaxsl[x]);
+ }
+ /* We've still got lock held if we found a spot */
+ if (x >= TRUNK_CALL_START) {
+ ast_log(LOG_WARNING, "No more space\n");
+ return -1;
}
- ast_pthread_mutex_lock(&iaxsl[x]);
iaxs[x] = new_iax();
ast_pthread_mutex_unlock(&iaxsl[x]);
+ update_max_nontrunk();
if (iaxs[x]) {
if (option_debug)
ast_log(LOG_DEBUG, "Creating new call structure %d\n", x);
@@ -980,7 +1090,6 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
return 0;
}
res = x;
- nextcallno = x;
}
return res;
}
@@ -1192,6 +1301,7 @@ retry:
ast_pthread_mutex_lock(&iaxsl[callno]);
pvt = iaxs[callno];
iaxs[callno] = NULL;
+ gettimeofday(&lastused[callno], NULL);
if (pvt)
owner = pvt->owner;
@@ -1245,6 +1355,8 @@ retry:
ast_pthread_mutex_unlock(&owner->lock);
}
ast_pthread_mutex_unlock(&iaxsl[callno]);
+ if (callno & 0x4000)
+ update_max_trunk();
}
static void iax2_destroy_nolock(int callno)
{
@@ -1685,7 +1797,7 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha
return 0;
}
-static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, int *maxtime, char *peer, char *context)
+static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, int *maxtime, char *peer, char *context, int *trunk)
{
struct hostent *hp;
struct iax2_peer *p;
@@ -1694,14 +1806,14 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i
*sendani = 0;
if (maxtime)
*maxtime = 0;
+ if (trunk)
+ *trunk = 0;
sin->sin_family = AF_INET;
ast_pthread_mutex_lock(&peerl.lock);
p = peerl.peers;
while(p) {
if (!strcasecmp(p->name, peer)) {
found++;
- if (capability)
- *capability = p->capability;
if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
(!p->maxms || ((p->lastms > 0) && (p->lastms <= p->maxms)))) {
if (sendani)
@@ -1710,6 +1822,10 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i
*maxtime = p->maxms; /* Max time they should take */
if (context)
strncpy(context, p->context, AST_MAX_EXTENSION - 1);
+ if (trunk)
+ *trunk = p->trunk;
+ if (capability)
+ *capability = p->capability;
if (p->addr.sin_addr.s_addr) {
sin->sin_addr = p->addr.sin_addr;
sin->sin_port = p->addr.sin_port;
@@ -1847,7 +1963,7 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout)
strsep(&stringp, ":");
portno = strsep(&stringp, ":");
}
- if (create_addr(&sin, NULL, NULL, NULL, hname, context)) {
+ if (create_addr(&sin, NULL, NULL, NULL, hname, context, NULL)) {
ast_log(LOG_WARNING, "No address associated with '%s'\n", hname);
return -1;
}
@@ -2213,6 +2329,46 @@ static struct ast_channel *ast_iax2_new(struct chan_iax2_pvt *i, int state, int
return tmp;
}
+static unsigned int calc_txpeerstamp(struct iax2_peer *peer)
+{
+ struct timeval tv;
+ unsigned int mssincetx;
+ unsigned int ms;
+ gettimeofday(&tv, NULL);
+ mssincetx = (tv.tv_sec - peer->lasttxtime.tv_sec) * 1000 + (tv.tv_usec - peer->lasttxtime.tv_usec) / 1000;
+ if (mssincetx > 5000) {
+ /* If it's been at least 5 seconds since the last time we transmitted on this trunk, reset our timers */
+ peer->txtrunktime.tv_sec = tv.tv_sec;
+ peer->txtrunktime.tv_usec = tv.tv_usec;
+ }
+ /* Update last transmit time now */
+ peer->lasttxtime.tv_sec = tv.tv_sec;
+ peer->lasttxtime.tv_usec = tv.tv_usec;
+
+ /* Calculate ms offset */
+ ms = (tv.tv_sec - peer->txtrunktime.tv_sec) * 1000 + (tv.tv_usec - peer->txtrunktime.tv_usec) / 1000;
+
+ /* We never send the same timestamp twice, so fudge a little if we must */
+ if (ms == peer->lastsent)
+ ms = peer->lastsent + 1;
+ peer->lastsent = ms;
+ return ms;
+}
+
+static unsigned int fix_peerts(struct iax2_peer *peer, int callno, unsigned int ts)
+{
+ long ms; /* NOT unsigned */
+ if (!iaxs[callno]->rxcore.tv_sec && !iaxs[callno]->rxcore.tv_usec) {
+ /* Initialize rxcore time if appropriate */
+ gettimeofday(&iaxs[callno]->rxcore, NULL);
+ }
+ /* Calculate difference between trunk and channel */
+ ms = (peer->rxtrunktime.tv_sec - iaxs[callno]->rxcore.tv_sec) * 1000 +
+ (peer->rxtrunktime.tv_usec - iaxs[callno]->rxcore.tv_usec) / 1000;
+ /* Return as the sum of trunk time and the difference between trunk and real time */
+ return ms + ts;
+}
+
static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts)
{
struct timeval tv;
@@ -2249,7 +2405,7 @@ static unsigned int calc_fakestamp(struct chan_iax2_pvt *p1, struct chan_iax2_pv
Adding rxcore to it gives us when we would want the packet to be delivered normally.
Subtracting txcore of the outgoing channel gives us what we'd expect */
- ms = (p1->rxcore.tv_sec - p2->offset.tv_sec) * 1000 + (p1->rxcore.tv_usec - p1->offset.tv_usec) / 1000;
+ ms = (p1->rxcore.tv_sec - p2->offset.tv_sec) * 1000 + (p1->rxcore.tv_usec - p2->offset.tv_usec) / 1000;
fakets += ms;
if (fakets <= p2->lastsent)
fakets = p2->lastsent + 1;
@@ -2357,20 +2513,34 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
} else
res = iax2_transmit(fr);
} else {
- /* Mini-frames have no sequence number */
- fr->oseqno = -1;
- fr->iseqno = -1;
- /* Mini frame will do */
- mh = (struct ast_iax2_mini_hdr *)(fr->af.data - sizeof(struct ast_iax2_mini_hdr));
- mh->callno = htons(fr->callno);
- mh->ts = htons(fr->ts & 0xFFFF);
- fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr);
- fr->data = mh;
- fr->retries = -1;
- if (now) {
- res = send_packet(fr);
- } else
- res = iax2_transmit(fr);
+ if (pvt->trunk) {
+ /* Queue for transmission in a meta frame */
+ if ((sizeof(pvt->trunkdata) - pvt->trunkdatalen) >= fr->af.datalen) {
+ memcpy(pvt->trunkdata + pvt->trunkdatalen, fr->af.data, fr->af.datalen);
+ pvt->trunkdatalen += fr->af.datalen;
+ res = 0;
+ pvt->trunkerror = 0;
+ } else {
+ if (!pvt->trunkerror)
+ ast_log(LOG_WARNING, "Out of trunk data space on call number %d, dropping\n", pvt->callno);
+ pvt->trunkerror = 1;
+ }
+ } else {
+ /* Mini-frames have no sequence number */
+ fr->oseqno = -1;
+ fr->iseqno = -1;
+ /* Mini frame will do */
+ mh = (struct ast_iax2_mini_hdr *)(fr->af.data - sizeof(struct ast_iax2_mini_hdr));
+ mh->callno = htons(fr->callno);
+ mh->ts = htons(fr->ts & 0xFFFF);
+ fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr);
+ fr->data = mh;
+ fr->retries = -1;
+ if (now) {
+ res = send_packet(fr);
+ } else
+ res = iax2_transmit(fr);
+ }
}
return res;
}
@@ -2400,7 +2570,7 @@ static int iax2_show_users(int fd, int argc, char *argv[])
static int iax2_show_peers(int fd, int argc, char *argv[])
{
#define FORMAT2 "%-15.15s %-15.15s %s %-15.15s %-8s %-10s\n"
-#define FORMAT "%-15.15s %-15.15s %s %-15.15s %-8d %-10s\n"
+#define FORMAT "%-15.15s %-15.15s %s %-15.15s %-5d%s %-10s\n"
struct iax2_peer *peer;
char name[256] = "";
if (argc != 3)
@@ -2430,7 +2600,7 @@ static int iax2_show_peers(int fd, int argc, char *argv[])
peer->addr.sin_addr.s_addr ? inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
peer->dynamic ? "(D)" : "(S)",
nm,
- ntohs(peer->addr.sin_port), status);
+ ntohs(peer->addr.sin_port), peer->trunk ? "(T)" : " ", status);
}
ast_pthread_mutex_unlock(&peerl.lock);
return RESULT_SUCCESS;
@@ -2723,6 +2893,8 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
/* Store the requested username if not specified */
if (!strlen(iaxs[callno]->username))
strncpy(iaxs[callno]->username, user->name, sizeof(iaxs[callno]->username)-1);
+ /* Store whether this is a trunked call, too, of course, and move if appropriate */
+ iaxs[callno]->trunk = user->trunk;
/* And use the default context */
if (!strlen(iaxs[callno]->context)) {
if (user->contexts)
@@ -3627,19 +3799,115 @@ static int parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
return 0;
}
+static int send_trunk(struct iax2_peer *peer)
+{
+ int x;
+ int calls = 0;
+ int res = 0;
+ int firstcall = 0;
+ unsigned char buf[65536 + sizeof(struct ast_iax2_frame)], *ptr;
+ int len = 65536;
+ struct ast_iax2_frame *fr;
+ struct ast_iax2_meta_hdr *meta;
+ struct ast_iax2_meta_trunk_hdr *mth;
+ struct ast_iax2_meta_trunk_entry *met;
+
+ /* Point to frame */
+ fr = (struct ast_iax2_frame *)buf;
+ /* Point to meta data */
+ meta = (struct ast_iax2_meta_hdr *)fr->afdata;
+ mth = (struct ast_iax2_meta_trunk_hdr *)meta->data;
+ /* Point past meta data for first meta trunk entry */
+ ptr = fr->afdata + sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr);
+ len -= sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr);
+
+ /* Search through trunked calls for a match with this peer */
+ for (x=TRUNK_CALL_START;x<maxtrunkcall; x++) {
+ ast_pthread_mutex_lock(&iaxsl[x]);
+ if (iaxs[x] && iaxs[x]->trunk && iaxs[x]->trunkdatalen && !memcmp(&iaxs[x]->addr, &peer->addr, sizeof(iaxs[x]->addr))) {
+ if (len >= iaxs[x]->trunkdatalen + sizeof(struct ast_iax2_meta_trunk_entry)) {
+ met = (struct ast_iax2_meta_trunk_entry *)ptr;
+ /* Store call number and length in meta header */
+ met->callno = htons(x);
+ met->len = htons(iaxs[x]->trunkdatalen);
+ /* Advance pointers/decrease length past trunk entry header */
+ ptr += sizeof(struct ast_iax2_meta_trunk_entry);
+ len -= sizeof(struct ast_iax2_meta_trunk_entry);
+ /* Copy actual trunk data */
+ memcpy(ptr, iaxs[x]->trunkdata, iaxs[x]->trunkdatalen);
+ /* Advance pointeres/decrease length for actual data */
+ ptr += iaxs[x]->trunkdatalen;
+ len -= iaxs[x]->trunkdatalen;
+ } else
+ ast_log(LOG_WARNING, "Out of space in frame for trunking call %d\n", x);
+ iaxs[x]->trunkdatalen = 0;
+ calls++;
+ if (!firstcall)
+ firstcall = x;
+ }
+ ast_pthread_mutex_unlock(&iaxsl[x]);
+ }
+ if (calls) {
+ /* We're actually sending a frame, so fill the meta trunk header and meta header */
+ meta->zeros = 0;
+ meta->metacmd = IAX_META_TRUNK;
+ meta->cmddata = 0;
+ mth->ts = htonl(calc_txpeerstamp(peer));
+ /* And the rest of the ast_iax2 header */
+ fr->direction = DIRECTION_OUTGRESS;
+ fr->retrans = -1;
+ fr->transfer = 0;
+ /* Any appropriate call will do */
+ fr->callno = firstcall;
+ fr->data = fr->afdata;
+ fr->datalen = 65536 - len;
+#if 0
+ ast_log(LOG_DEBUG, "Trunking %d calls in %d bytes, ts=%d\n", calls, fr->datalen, ntohl(mth->ts));
+#endif
+ res = send_packet(fr);
+ }
+ return res;
+}
+
+static int timing_read(int *id, int fd, short events, void *cbdata)
+{
+ char buf[1024];
+ int res;
+ struct iax2_peer *peer;
+ /* Read and ignore from the pseudo channel for timing */
+ res = read(fd, buf, sizeof(buf));
+ if (res > 0) {
+ /* For each peer that supports trunking... */
+ ast_pthread_mutex_lock(&peerl.lock);
+ peer = peerl.peers;
+ while(peer) {
+ if (peer->trunk) {
+ send_trunk(peer);
+ }
+ peer = peer->next;
+ }
+ ast_pthread_mutex_unlock(&peerl.lock);
+ }
+ return 1;
+}
+
static int socket_read(int *id, int fd, short events, void *cbdata)
{
struct sockaddr_in sin;
int res;
int updatehistory=1;
int new = NEW_PREVENT;
- char buf[4096];
+ char buf[4096], *ptr;
int len = sizeof(sin);
int dcallno = 0;
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 ast_iax2_meta_hdr *meta = (struct ast_iax2_meta_hdr *)buf;
- struct ast_iax2_frame fr, *cur;
+ struct ast_iax2_meta_trunk_hdr *mth;
+ struct ast_iax2_meta_trunk_entry *mte;
+ char dblbuf[4096]; /* Declaration of dblbuf must immediately *preceed* fr on the stack */
+ struct ast_iax2_frame fr;
+ struct ast_iax2_frame *cur;
struct ast_frame f;
struct ast_channel *c;
struct iax2_dpcache *dp;
@@ -3649,7 +3917,9 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
int format;
int exists;
int mm;
+ unsigned int ts;
char empty[32]=""; /* Safety measure */
+ dblbuf[0] = 0; /* Keep GCC from whining */
res = recvfrom(netsocket, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len);
if (res < 0) {
if (errno != ECONNREFUSED)
@@ -3663,7 +3933,92 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
}
if (meta->zeros == 0) {
/* This is a a meta header */
- ast_log(LOG_DEBUG, "Meta header Command = %d!\n", meta->metacmd);
+ switch(meta->metacmd) {
+ case IAX_META_TRUNK:
+ if (res < sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr)) {
+ ast_log(LOG_WARNING, "midget meta trunk packet received (%d of %d min)\n", res, sizeof(struct ast_iax2_mini_hdr));
+ return 1;
+ }
+ mth = (struct ast_iax2_meta_trunk_hdr *)(meta->data);
+ ts = ntohl(mth->ts);
+ res -= (sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr));
+ ptr = mth->data;
+ ast_pthread_mutex_lock(&peerl.lock);
+ peer = peerl.peers;
+ while(peer) {
+ if (!memcmp(&peer->addr, &sin, sizeof(peer->addr)))
+ break;
+ peer = peer->next;
+ }
+ ast_pthread_mutex_unlock(&peerl.lock);
+ if (!peer) {
+ ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ return 1;
+ }
+ if (!ts || (!peer->rxtrunktime.tv_sec && !peer->rxtrunktime.tv_usec)) {
+ gettimeofday(&peer->rxtrunktime, NULL);
+ }
+ while(res >= sizeof(struct ast_iax2_meta_trunk_entry)) {
+ /* Process channels */
+ mte = (struct ast_iax2_meta_trunk_entry *)ptr;
+ ptr += sizeof(struct ast_iax2_meta_trunk_entry);
+ res -= sizeof(struct ast_iax2_meta_trunk_entry);
+ len = ntohs(mte->len);
+ /* Stop if we don't have enough data */
+ if (len > res)
+ break;
+ fr.callno = find_callno(ntohs(mte->callno) & ~AST_FLAG_FULL, 0, &sin, NEW_PREVENT);
+ if (fr.callno) {
+ ast_pthread_mutex_lock(&iaxsl[fr.callno]);
+ /* If it's a valid call, deliver the contents. If not, we
+ drop it, since we don't have a scallno to use for an INVAL */
+ /* Process as a mini frame */
+ f.frametype = AST_FRAME_VOICE;
+ if (iaxs[fr.callno]->voiceformat > 0) {
+ f.subclass = iaxs[fr.callno]->voiceformat;
+ f.datalen = len;
+ if (f.datalen >= 0) {
+ if (f.datalen)
+ f.data = ptr;
+ else
+ f.data = NULL;
+ fr.ts = fix_peerts(peer, fr.callno, ts);
+ /* Don't pass any packets until we're started */
+ if ((iaxs[fr.callno]->state & IAX_STATE_STARTED)) {
+ /* Common things */
+ f.src = "IAX2";
+ f.mallocd = 0;
+ f.offset = 0;
+ if (f.datalen && (f.frametype == AST_FRAME_VOICE))
+ f.samples = get_samples(&f);
+ else
+ f.samples = 0;
+ fr.outoforder = 0;
+ ast_iax2_frame_wrap(&fr, &f);
+#ifdef BRIDGE_OPTIMIZATION
+ if (iaxs[fr.callno]->bridgecallno) {
+ forward_delivery(&fr);
+ } else {
+ schedule_delivery(iaxfrdup2(&fr), 1, updatehistory);
+ }
+#else
+ schedule_delivery(iaxfrdup2(&fr), 1, updatehistory);
+#endif
+ }
+ } else {
+ ast_log(LOG_WARNING, "Datalen < 0?\n");
+ }
+ } else {
+ ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n ");
+ iax2_vnak(fr.callno);
+ }
+ ast_pthread_mutex_unlock(&iaxsl[fr.callno]);
+ }
+ ptr += len;
+ res -= len;
+ }
+
+ }
return 1;
}
#ifdef DEBUG_SUPPORT
@@ -3776,7 +4131,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
/* Handle implicit ACKing unless this is an INVAL */
if (((f.subclass != AST_IAX2_COMMAND_INVAL)) ||
(f.frametype != AST_FRAME_IAX)) {
- int x;
+ 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 */
@@ -3903,6 +4258,10 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
ast_log(LOG_NOTICE, "Rejected connect attempt from %s\n", inet_ntoa(sin.sin_addr));
break;
}
+ /* If we're in trunk mode, do it now, and update the trunk number in our frame before continuing */
+ if (iaxs[fr.callno]->trunk) {
+ fr.callno = make_trunk(fr.callno, 1);
+ }
/* This might re-enter the IAX code and need the lock */
exists = ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->callerid);
if (!strlen(iaxs[fr.callno]->secret) && !strlen(iaxs[fr.callno]->inkeys)) {
@@ -4502,6 +4861,7 @@ static struct ast_channel *iax2_request(char *type, int format, void *data)
struct ast_channel *c;
char *stringp=NULL;
int capability = iax2_capability;
+ int trunk;
strncpy(s, (char *)data, sizeof(s)-1);
/* FIXME The next two lines seem useless */
stringp=s;
@@ -4513,7 +4873,7 @@ static struct ast_channel *iax2_request(char *type, int format, void *data)
if (!st)
st = s;
/* Populate our address from the given */
- if (create_addr(&sin, &capability, &sendani, &maxtime, st, NULL)) {
+ if (create_addr(&sin, &capability, &sendani, &maxtime, st, NULL, &trunk)) {
return NULL;
}
callno = find_callno(0, 0, &sin, NEW_FORCE);
@@ -4522,6 +4882,10 @@ static struct ast_channel *iax2_request(char *type, int format, void *data)
return NULL;
}
ast_pthread_mutex_lock(&iaxsl[callno]);
+ /* If this is a trunk, update it now */
+ iaxs[callno]->trunk = trunk;
+ if (trunk)
+ callno = make_trunk(callno, 1);
/* Keep track of sendani flag */
iaxs[callno]->sendani = sendani;
iaxs[callno]->maxtime = maxtime;
@@ -4554,6 +4918,8 @@ static void *network_thread(void *ignore)
struct ast_iax2_frame *f, *freeme;
/* Establish I/O callback for socket read */
ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL);
+ if (timingfd > -1)
+ ast_io_add(io, timingfd, timing_read, AST_IO_IN, NULL);
for(;;) {
/* Go through the queue, sending messages which have not yet been
sent, and scheduling retransmissions if appropriate */
@@ -4674,9 +5040,13 @@ static struct iax2_peer *build_peer(char *name, struct ast_variable *v)
strncpy(peer->secret, v->value, sizeof(peer->secret)-1);
else if (!strcasecmp(v->name, "mailbox"))
strncpy(peer->mailbox, v->value, sizeof(peer->mailbox) - 1);
- else if (!strcasecmp(v->name, "trunk"))
- peer->trunk = 1;
- else if (!strcasecmp(v->name, "auth")) {
+ else if (!strcasecmp(v->name, "trunk")) {
+ peer->trunk = ast_true(v->value);
+ if (peer->trunk && (timingfd < 0)) {
+ ast_log(LOG_WARNING, "Unable to support trunking on peer '%s' without zaptel timing\n", peer->name);
+ peer->trunk = 0;
+ }
+ } else if (!strcasecmp(v->name, "auth")) {
peer->authmethods = get_auth_methods(v->value);
} else if (!strcasecmp(v->name, "host")) {
if (!strcasecmp(v->value, "dynamic")) {
@@ -4789,12 +5159,16 @@ static struct iax2_user *build_user(char *name, struct ast_variable *v)
} else if (!strcasecmp(v->name, "permit") ||
!strcasecmp(v->name, "deny")) {
user->ha = ast_append_ha(v->name, v->value, user->ha);
+ } else if (!strcasecmp(v->name, "trunk")) {
+ user->trunk = ast_true(v->value);
+ if (user->trunk && (timingfd < 0)) {
+ ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without zaptel timing\n", user->name);
+ user->trunk = 0;
+ }
} else if (!strcasecmp(v->name, "auth")) {
user->authmethods = get_auth_methods(v->value);
} else if (!strcasecmp(v->name, "secret")) {
strncpy(user->secret, v->value, sizeof(user->secret)-1);
- } else if (!strcasecmp(v->name, "trunk")) {
- user->trunk = 1;
} else if (!strcasecmp(v->name, "callerid")) {
strncpy(user->callerid, v->value, sizeof(user->callerid)-1);
user->hascallerid=1;
@@ -4814,7 +5188,7 @@ static struct iax2_user *build_user(char *name, struct ast_variable *v)
v = v->next;
}
}
- if (user->authmethods) {
+ if (!user->authmethods) {
if (strlen(user->secret)) {
user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
if (strlen(user->inkeys))
@@ -4898,6 +5272,17 @@ void prune_peers(void){
ast_pthread_mutex_unlock(&peerl.lock);
}
+static void set_timing(void)
+{
+#ifdef IAX_TRUNKING
+ int bs = trunkfreq * 8;
+ if (timingfd > -1) {
+ if (ioctl(timingfd, ZT_SET_BLOCKSIZE, &bs))
+ ast_log(LOG_WARNING, "Unable to set blocksize on timing source\n");
+ }
+#endif
+}
+
static int set_config(char *config_file, struct sockaddr_in* sin){
struct ast_config *cfg;
@@ -4946,7 +5331,11 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
inet_aton(v->value, &sin->sin_addr);
else if (!strcasecmp(v->name, "jitterbuffer"))
use_jitterbuffer = ast_true(v->value);
- else if (!strcasecmp(v->name, "bandwidth")) {
+ else if (!strcasecmp(v->name, "trunkfreq")) {
+ trunkfreq = atoi(v->value);
+ if (trunkfreq < 10)
+ trunkfreq = 10;
+ } else if (!strcasecmp(v->name, "bandwidth")) {
if (!strcasecmp(v->value, "low")) {
capability = IAX_CAPABILITY_LOWBANDWIDTH;
} else if (!strcasecmp(v->value, "medium")) {
@@ -5029,6 +5418,7 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
cat = ast_category_browse(cfg, cat);
}
ast_destroy(cfg);
+ set_timing();
return capability;
}
@@ -5102,7 +5492,7 @@ static int cache_get_callno(char *data)
host = st;
}
/* Populate our address from the given */
- if (create_addr(&sin, NULL, NULL, NULL, host, NULL)) {
+ if (create_addr(&sin, NULL, NULL, NULL, host, NULL, NULL)) {
return -1;
}
ast_log(LOG_DEBUG, "host: %s, user: %s, password: %s, context: %s\n", host, username, password, context);
@@ -5419,6 +5809,12 @@ int load_module(void)
sin.sin_port = ntohs(AST_DEFAULT_IAX_PORTNO);
sin.sin_addr.s_addr = INADDR_ANY;
+#ifdef IAX_TRUNKING
+ timingfd = open("/dev/zap/pseudo", O_RDWR);
+ if (timingfd < 0)
+ ast_log(LOG_WARNING, "Unable to open IAX timing interface: %s\n", strerror(errno));
+#endif
+
for (x=0;x<AST_IAX2_MAX_CALLS;x++)
ast_pthread_mutex_init(&iaxsl[x]);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 385c48389..a13f37158 100755
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -307,6 +307,7 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p, struct ast_rtp *rtp);
static int transmit_info_with_digit(struct sip_pvt *p, char digit);
static int transmit_message_with_text(struct sip_pvt *p, char *text);
static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req);
+char *getsipuri(char *header);
static int __sip_xmit(struct sip_pvt *p, char *data, int len)
{
@@ -1653,6 +1654,7 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
copy_via_headers(p, resp, req, "Via");
copy_header(resp, req, "From");
ot = get_header(req, "To");
+ copy_header(resp, req, "Record-Route");
if (!strstr(ot, "tag=")) {
/* Add the proper tag if we don't have it already. If they have specified
their tag, use it. Otherwise, use our own tag */
@@ -1672,20 +1674,28 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, stru
/* For registration responses, we also need expirey and
contact info */
char tmp[80];
- char contact2[256] = "", *c, contact[256];
+ char contact[256];
+ char *c;
+ if ((c=getsipuri(ot))) {
+ snprintf(contact, sizeof(contact), "<%s@%s>", c, inet_ntoa(p->ourip));
+ free(c);
+ } else {
+ snprintf(contact, sizeof(contact), "<%s>", inet_ntoa(p->ourip));
+ }
snprintf(tmp, sizeof(tmp), "%d", p->expirey);
- strncpy(contact2, get_header(req, "Contact"), sizeof(contact2)-1);
- c = ditch_braces(contact2);
- snprintf(contact, sizeof(contact), "<%s>", c);
add_header(resp, "Expires", tmp);
add_header(resp, "Contact", contact);
} else {
- char contact2[256] = "", *c, contact[256];
+ char contact[256];
/* XXX This isn't exactly right and it's implemented
very stupidly *sigh* XXX */
- strncpy(contact2, get_header(req, "To"), sizeof(contact2)-1);
- c = ditch_braces(contact2);
- snprintf(contact, sizeof(contact), "<%s>", c);
+ char *c;
+ if ((c=getsipuri(ot))) {
+ snprintf(contact, sizeof(contact), "<%s@%s>", c, inet_ntoa(p->ourip));
+ free(c);
+ } else {
+ snprintf(contact, sizeof(contact), "<%s>", inet_ntoa(p->ourip));
+ }
add_header(resp, "Contact", contact);
}
return 0;
@@ -4543,3 +4553,24 @@ char *description()
return desc;
}
+char *getsipuri(char *header)
+{
+ char *c, *d, *retval;
+ int n;
+
+ if (!(c=strstr(header, "sip"))) {
+ return NULL;
+ }
+
+ if (!(d=strchr(c, '@'))) {
+ return NULL;
+ }
+
+ n=d-c;
+
+ retval=(char *)malloc(n+1);
+ strncpy(retval, c, n);
+ *(retval+n)='\0';
+
+ return retval;
+}
diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index 91a1ac533..c76791f4f 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -1315,6 +1315,10 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
} else {
strcpy(p->dop.dialstr, "");
}
+ if (!(p->call = pri_new_call(p->pri->pri))) {
+ ast_log(LOG_WARNING, "Unable to create call on channel %d\n", p->channel);
+ return -1;
+ }
if (pri_call(p->pri->pri, p->call, p->digital ? PRI_TRANS_CAP_DIGITAL : PRI_TRANS_CAP_SPEECH,
p->prioffset, p->pri->nodetype == PRI_NETWORK ? 0 : 1, 1, l, p->pri->dialplan - 1, n,
l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE,
@@ -4932,13 +4936,6 @@ static struct ast_channel *zt_request(char *type, int format, void *data)
p = p->next;
continue;
}
-#ifdef ZAPATA_PRI
- if (p->pri)
- if (!(p->call = pri_new_call(p->pri->pri))) {
- ast_log(LOG_WARNING, "Unable to create call on channel %d\n", p->channel);
- break;
- }
-#endif
callwait = (p->owner != NULL);
if (p->channel == CHAN_PSEUDO) {
p = chandup(p);
diff --git a/channels/iax2.h b/channels/iax2.h
index a51e7cdf1..5d911f750 100755
--- a/channels/iax2.h
+++ b/channels/iax2.h
@@ -138,11 +138,11 @@ struct ast_iax2_meta_hdr {
struct ast_iax2_meta_trunk_hdr {
unsigned int ts; /* 32-bit timestamp for all messages */
unsigned char data[0];
-};
+} __attribute__ ((__packed__));
struct ast_iax2_meta_trunk_entry {
unsigned short callno; /* Call number */
unsigned short len; /* Length of data for this callno */
-};
+} __attribute__ ((__packed__));
#endif
diff --git a/configs/iax.conf.sample b/configs/iax.conf.sample
index 2b089c982..77bd7870c 100755
--- a/configs/iax.conf.sample
+++ b/configs/iax.conf.sample
@@ -47,6 +47,9 @@ disallow=lpc10 ; Icky sound quality... Mr. Roboto.
;maxjitterbuffer=500
;maxexccessbuffer=100
;
+;trunkfreq=20 ; How frequently to send trunk msgs (in ms)
+;
+;
; We can register with another IAX server to let him know where we are
; in case we have a dynamic IP address for example
;
diff --git a/utils/astman.c b/utils/astman.c
index 6fa6b8118..2eb35f68e 100755
--- a/utils/astman.c
+++ b/utils/astman.c
@@ -383,14 +383,14 @@ static int show_doing(char *title, char *tmp)
return 0;
}
-static int hide_doing()
+static int hide_doing(void)
{
newtPopWindow();
newtFormDestroy(showform);
return 0;
}
-static void try_status()
+static void try_status(void)
{
struct message *m;
manager_action("Status", "");