Sun Mar 16 07:00:01 CET 2003

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@646 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.0
Matteo Brancaleoni 22 years ago
parent d1b666fc56
commit 7640e83360

@ -1,3 +1,4 @@
-- Add experimental "trunk" option to IAX2 for high density VoIP
-- Add experimental "debug channel" command -- Add experimental "debug channel" command
-- Add 'C' flag to dial command to reset call detail record (handy for calling cards) -- Add 'C' flag to dial command to reset call detail record (handy for calling cards)
-- Add NAT and dynamic support to MGCP -- Add NAT and dynamic support to MGCP

@ -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_queue.so app_senddtmf.so app_parkandannounce.so app_striplsd.so \
app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so \ app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so \
app_authenticate.so app_softhangup.so app_lookupblacklist.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_postgres.so
#APPS+=app_sql_odbc.so #APPS+=app_sql_odbc.so

@ -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;
}

@ -383,14 +383,14 @@ static int show_doing(char *title, char *tmp)
return 0; return 0;
} }
static int hide_doing() static int hide_doing(void)
{ {
newtPopWindow(); newtPopWindow();
newtFormDestroy(showform); newtFormDestroy(showform);
return 0; return 0;
} }
static void try_status() static void try_status(void)
{ {
struct message *m; struct message *m;
manager_action("Status", ""); manager_action("Status", "");

@ -33,6 +33,7 @@ ZAPPRI=$(shell [ -f /usr/lib/libpri.so.1 ] && echo "-lpri")
ZAPR2=$(shell [ -f /usr/lib/libmfcr2.so.1 ] && echo "-lmfcr2") 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) 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) 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=chan_alsa.c
ALSA_SRC+=$(shell [ -f alsa-monitor.h ] && echo "alsa-monitor.h") ALSA_SRC+=$(shell [ -f alsa-monitor.h ] && echo "alsa-monitor.h")

@ -44,6 +44,10 @@
#include <unistd.h> #include <unistd.h>
#include <netdb.h> #include <netdb.h>
#include <fcntl.h> #include <fcntl.h>
#ifdef IAX_TRUNKING
#include <sys/ioctl.h>
#include <linux/zaptel.h>
#endif
#include "iax2.h" #include "iax2.h"
@ -59,9 +63,14 @@
#define DEFAULT_RETRY_TIME 1000 #define DEFAULT_RETRY_TIME 1000
#define MEMORY_SIZE 100 #define MEMORY_SIZE 100
#define DEFAULT_DROP 3 #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 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 */ /* Sample over last 100 units to determine historic jitter */
#define GAMMA (0.01) #define GAMMA (0.01)
@ -74,8 +83,10 @@ static char context[80] = "default";
static int max_retries = 4; static int max_retries = 4;
static int ping_time = 20; static int ping_time = 20;
static int lagrq_time = 10; 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 maxjitterbuffer=3000;
static int trunkfreq = 20;
static int iaxdefaultdpcache=10 * 60; /* Cache dialplan entries for 10 minutes by default */ 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 expirey = AST_DEFAULT_REG_EXPIRE;
static int timingfd = -1; /* Timing file descriptor */
static int usecnt; static int usecnt;
static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER; 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 */ char inkeys[80]; /* Key(s) this user can use to authenticate to us */
int amaflags; int amaflags;
int hascallerid; int hascallerid;
int trunk; /* Treat with IAX2 trunking */ int trunk;
char callerid[AST_MAX_EXTENSION]; char callerid[AST_MAX_EXTENSION];
struct ast_ha *ha; struct ast_ha *ha;
struct iax2_context *contexts; struct iax2_context *contexts;
@ -180,6 +193,10 @@ struct iax2_peer {
int capability; /* Capability */ int capability; /* Capability */
int delme; /* I need to be deleted */ int delme; /* I need to be deleted */
int trunk; /* Treat as an IAX trunking */ 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 */ /* Qualification */
int callno; /* Call number of POKE request */ int callno; /* Call number of POKE request */
@ -350,6 +367,7 @@ struct chan_iax2_pvt {
/* Trunk data and length */ /* Trunk data and length */
unsigned char trunkdata[MAX_TRUNKDATA]; unsigned char trunkdata[MAX_TRUNKDATA];
unsigned int trunkdatalen; unsigned int trunkdatalen;
int trunkerror;
struct iax2_dpcache *dpentries; struct iax2_dpcache *dpentries;
}; };
@ -538,7 +556,7 @@ static struct iax2_ie {
{ IAX_IE_VERSION, "VERSION", dump_short }, { IAX_IE_VERSION, "VERSION", dump_short },
{ IAX_IE_ADSICPE, "ADSICPE", dump_short }, { IAX_IE_ADSICPE, "ADSICPE", dump_short },
{ IAX_IE_DNID, "DNID", dump_string }, { 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_CHALLENGE, "CHALLENGE", dump_string },
{ IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string }, { IAX_IE_MD5_RESULT, "MD5 RESULT", dump_string },
{ IAX_IE_RSA_RESULT, "RSA 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 */ /* XXX We probably should use a mutex when working with this XXX */
static struct chan_iax2_pvt *iaxs[AST_IAX2_MAX_CALLS]; static struct chan_iax2_pvt *iaxs[AST_IAX2_MAX_CALLS];
static pthread_mutex_t iaxsl[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(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); 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; 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) static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new)
{ {
int res = 0; int res = 0;
int x; int x;
int start; struct timeval now;
if (new <= NEW_ALLOW) { if (new <= NEW_ALLOW) {
/* Look for an existing connection first */ /* 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]); ast_pthread_mutex_lock(&iaxsl[x]);
if (iaxs[x]) { if (iaxs[x]) {
/* Look for an exact match */ /* 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)) { if ((res < 1) && (new >= NEW_ALLOW)) {
/* Create a new one */ gettimeofday(&now, NULL);
start = nextcallno; for (x=1;x<TRUNK_CALL_START;x++) {
for (x = ((nextcallno + 1) % (AST_IAX2_MAX_CALLS - 1)) + 1; iaxs[x] && (x != start); x = (x + 1) % AST_IAX2_MAX_CALLS) /* Find first unused call number that hasn't been used in a while */
if (x == start) { ast_pthread_mutex_lock(&iaxsl[x]);
ast_log(LOG_WARNING, "Unable to accept more calls\n"); if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) break;
return 0; 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(); iaxs[x] = new_iax();
ast_pthread_mutex_unlock(&iaxsl[x]); ast_pthread_mutex_unlock(&iaxsl[x]);
update_max_nontrunk();
if (iaxs[x]) { if (iaxs[x]) {
if (option_debug) if (option_debug)
ast_log(LOG_DEBUG, "Creating new call structure %d\n", x); 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; return 0;
} }
res = x; res = x;
nextcallno = x;
} }
return res; return res;
} }
@ -1192,6 +1301,7 @@ retry:
ast_pthread_mutex_lock(&iaxsl[callno]); ast_pthread_mutex_lock(&iaxsl[callno]);
pvt = iaxs[callno]; pvt = iaxs[callno];
iaxs[callno] = NULL; iaxs[callno] = NULL;
gettimeofday(&lastused[callno], NULL);
if (pvt) if (pvt)
owner = pvt->owner; owner = pvt->owner;
@ -1245,6 +1355,8 @@ retry:
ast_pthread_mutex_unlock(&owner->lock); ast_pthread_mutex_unlock(&owner->lock);
} }
ast_pthread_mutex_unlock(&iaxsl[callno]); ast_pthread_mutex_unlock(&iaxsl[callno]);
if (callno & 0x4000)
update_max_trunk();
} }
static void iax2_destroy_nolock(int callno) 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; 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 hostent *hp;
struct iax2_peer *p; struct iax2_peer *p;
@ -1694,14 +1806,14 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i
*sendani = 0; *sendani = 0;
if (maxtime) if (maxtime)
*maxtime = 0; *maxtime = 0;
if (trunk)
*trunk = 0;
sin->sin_family = AF_INET; sin->sin_family = AF_INET;
ast_pthread_mutex_lock(&peerl.lock); ast_pthread_mutex_lock(&peerl.lock);
p = peerl.peers; p = peerl.peers;
while(p) { while(p) {
if (!strcasecmp(p->name, peer)) { if (!strcasecmp(p->name, peer)) {
found++; found++;
if (capability)
*capability = p->capability;
if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) && if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
(!p->maxms || ((p->lastms > 0) && (p->lastms <= p->maxms)))) { (!p->maxms || ((p->lastms > 0) && (p->lastms <= p->maxms)))) {
if (sendani) 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 */ *maxtime = p->maxms; /* Max time they should take */
if (context) if (context)
strncpy(context, p->context, AST_MAX_EXTENSION - 1); 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) { if (p->addr.sin_addr.s_addr) {
sin->sin_addr = p->addr.sin_addr; sin->sin_addr = p->addr.sin_addr;
sin->sin_port = p->addr.sin_port; 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, ":"); strsep(&stringp, ":");
portno = 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); ast_log(LOG_WARNING, "No address associated with '%s'\n", hname);
return -1; return -1;
} }
@ -2213,6 +2329,46 @@ static struct ast_channel *ast_iax2_new(struct chan_iax2_pvt *i, int state, int
return tmp; 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) static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts)
{ {
struct timeval tv; 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. 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 */ 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; fakets += ms;
if (fakets <= p2->lastsent) if (fakets <= p2->lastsent)
fakets = p2->lastsent + 1; fakets = p2->lastsent + 1;
@ -2357,20 +2513,34 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
} else } else
res = iax2_transmit(fr); res = iax2_transmit(fr);
} else { } else {
/* Mini-frames have no sequence number */ if (pvt->trunk) {
fr->oseqno = -1; /* Queue for transmission in a meta frame */
fr->iseqno = -1; if ((sizeof(pvt->trunkdata) - pvt->trunkdatalen) >= fr->af.datalen) {
/* Mini frame will do */ memcpy(pvt->trunkdata + pvt->trunkdatalen, fr->af.data, fr->af.datalen);
mh = (struct ast_iax2_mini_hdr *)(fr->af.data - sizeof(struct ast_iax2_mini_hdr)); pvt->trunkdatalen += fr->af.datalen;
mh->callno = htons(fr->callno); res = 0;
mh->ts = htons(fr->ts & 0xFFFF); pvt->trunkerror = 0;
fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr); } else {
fr->data = mh; if (!pvt->trunkerror)
fr->retries = -1; ast_log(LOG_WARNING, "Out of trunk data space on call number %d, dropping\n", pvt->callno);
if (now) { pvt->trunkerror = 1;
res = send_packet(fr); }
} else } else {
res = iax2_transmit(fr); /* 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; 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[]) static int iax2_show_peers(int fd, int argc, char *argv[])
{ {
#define FORMAT2 "%-15.15s %-15.15s %s %-15.15s %-8s %-10s\n" #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; struct iax2_peer *peer;
char name[256] = ""; char name[256] = "";
if (argc != 3) 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->addr.sin_addr.s_addr ? inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",
peer->dynamic ? "(D)" : "(S)", peer->dynamic ? "(D)" : "(S)",
nm, nm,
ntohs(peer->addr.sin_port), status); ntohs(peer->addr.sin_port), peer->trunk ? "(T)" : " ", status);
} }
ast_pthread_mutex_unlock(&peerl.lock); ast_pthread_mutex_unlock(&peerl.lock);
return RESULT_SUCCESS; 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 */ /* Store the requested username if not specified */
if (!strlen(iaxs[callno]->username)) if (!strlen(iaxs[callno]->username))
strncpy(iaxs[callno]->username, user->name, sizeof(iaxs[callno]->username)-1); 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 */ /* And use the default context */
if (!strlen(iaxs[callno]->context)) { if (!strlen(iaxs[callno]->context)) {
if (user->contexts) if (user->contexts)
@ -3627,19 +3799,115 @@ static int parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
return 0; 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) static int socket_read(int *id, int fd, short events, void *cbdata)
{ {
struct sockaddr_in sin; struct sockaddr_in sin;
int res; int res;
int updatehistory=1; int updatehistory=1;
int new = NEW_PREVENT; int new = NEW_PREVENT;
char buf[4096]; char buf[4096], *ptr;
int len = sizeof(sin); int len = sizeof(sin);
int dcallno = 0; int dcallno = 0;
struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)buf; 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_mini_hdr *mh = (struct ast_iax2_mini_hdr *)buf;
struct ast_iax2_meta_hdr *meta = (struct ast_iax2_meta_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_frame f;
struct ast_channel *c; struct ast_channel *c;
struct iax2_dpcache *dp; struct iax2_dpcache *dp;
@ -3649,7 +3917,9 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
int format; int format;
int exists; int exists;
int mm; int mm;
unsigned int ts;
char empty[32]=""; /* Safety measure */ char empty[32]=""; /* Safety measure */
dblbuf[0] = 0; /* Keep GCC from whining */
res = recvfrom(netsocket, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len); res = recvfrom(netsocket, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len);
if (res < 0) { if (res < 0) {
if (errno != ECONNREFUSED) if (errno != ECONNREFUSED)
@ -3663,7 +3933,92 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
} }
if (meta->zeros == 0) { if (meta->zeros == 0) {
/* This is a a meta header */ /* 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; return 1;
} }
#ifdef DEBUG_SUPPORT #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 */ /* Handle implicit ACKing unless this is an INVAL */
if (((f.subclass != AST_IAX2_COMMAND_INVAL)) || if (((f.subclass != AST_IAX2_COMMAND_INVAL)) ||
(f.frametype != AST_FRAME_IAX)) { (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 /* XXX This code is not very efficient. Surely there is a better way which still
properly handles boundary conditions? XXX */ properly handles boundary conditions? XXX */
/* First we have to qualify that the ACKed value is within our window */ /* 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)); ast_log(LOG_NOTICE, "Rejected connect attempt from %s\n", inet_ntoa(sin.sin_addr));
break; 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 */ /* 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); 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)) { 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; struct ast_channel *c;
char *stringp=NULL; char *stringp=NULL;
int capability = iax2_capability; int capability = iax2_capability;
int trunk;
strncpy(s, (char *)data, sizeof(s)-1); strncpy(s, (char *)data, sizeof(s)-1);
/* FIXME The next two lines seem useless */ /* FIXME The next two lines seem useless */
stringp=s; stringp=s;
@ -4513,7 +4873,7 @@ static struct ast_channel *iax2_request(char *type, int format, void *data)
if (!st) if (!st)
st = s; st = s;
/* Populate our address from the given */ /* 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; return NULL;
} }
callno = find_callno(0, 0, &sin, NEW_FORCE); 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; return NULL;
} }
ast_pthread_mutex_lock(&iaxsl[callno]); 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 */ /* Keep track of sendani flag */
iaxs[callno]->sendani = sendani; iaxs[callno]->sendani = sendani;
iaxs[callno]->maxtime = maxtime; iaxs[callno]->maxtime = maxtime;
@ -4554,6 +4918,8 @@ static void *network_thread(void *ignore)
struct ast_iax2_frame *f, *freeme; struct ast_iax2_frame *f, *freeme;
/* Establish I/O callback for socket read */ /* Establish I/O callback for socket read */
ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL); 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(;;) { for(;;) {
/* Go through the queue, sending messages which have not yet been /* Go through the queue, sending messages which have not yet been
sent, and scheduling retransmissions if appropriate */ 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); strncpy(peer->secret, v->value, sizeof(peer->secret)-1);
else if (!strcasecmp(v->name, "mailbox")) else if (!strcasecmp(v->name, "mailbox"))
strncpy(peer->mailbox, v->value, sizeof(peer->mailbox) - 1); strncpy(peer->mailbox, v->value, sizeof(peer->mailbox) - 1);
else if (!strcasecmp(v->name, "trunk")) else if (!strcasecmp(v->name, "trunk")) {
peer->trunk = 1; peer->trunk = ast_true(v->value);
else if (!strcasecmp(v->name, "auth")) { 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); peer->authmethods = get_auth_methods(v->value);
} else if (!strcasecmp(v->name, "host")) { } else if (!strcasecmp(v->name, "host")) {
if (!strcasecmp(v->value, "dynamic")) { 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") || } else if (!strcasecmp(v->name, "permit") ||
!strcasecmp(v->name, "deny")) { !strcasecmp(v->name, "deny")) {
user->ha = ast_append_ha(v->name, v->value, user->ha); 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")) { } else if (!strcasecmp(v->name, "auth")) {
user->authmethods = get_auth_methods(v->value); user->authmethods = get_auth_methods(v->value);
} else if (!strcasecmp(v->name, "secret")) { } else if (!strcasecmp(v->name, "secret")) {
strncpy(user->secret, v->value, sizeof(user->secret)-1); strncpy(user->secret, v->value, sizeof(user->secret)-1);
} else if (!strcasecmp(v->name, "trunk")) {
user->trunk = 1;
} else if (!strcasecmp(v->name, "callerid")) { } else if (!strcasecmp(v->name, "callerid")) {
strncpy(user->callerid, v->value, sizeof(user->callerid)-1); strncpy(user->callerid, v->value, sizeof(user->callerid)-1);
user->hascallerid=1; user->hascallerid=1;
@ -4814,7 +5188,7 @@ static struct iax2_user *build_user(char *name, struct ast_variable *v)
v = v->next; v = v->next;
} }
} }
if (user->authmethods) { if (!user->authmethods) {
if (strlen(user->secret)) { if (strlen(user->secret)) {
user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT; user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
if (strlen(user->inkeys)) if (strlen(user->inkeys))
@ -4898,6 +5272,17 @@ void prune_peers(void){
ast_pthread_mutex_unlock(&peerl.lock); 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){ static int set_config(char *config_file, struct sockaddr_in* sin){
struct ast_config *cfg; 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); inet_aton(v->value, &sin->sin_addr);
else if (!strcasecmp(v->name, "jitterbuffer")) else if (!strcasecmp(v->name, "jitterbuffer"))
use_jitterbuffer = ast_true(v->value); 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")) { if (!strcasecmp(v->value, "low")) {
capability = IAX_CAPABILITY_LOWBANDWIDTH; capability = IAX_CAPABILITY_LOWBANDWIDTH;
} else if (!strcasecmp(v->value, "medium")) { } 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); cat = ast_category_browse(cfg, cat);
} }
ast_destroy(cfg); ast_destroy(cfg);
set_timing();
return capability; return capability;
} }
@ -5102,7 +5492,7 @@ static int cache_get_callno(char *data)
host = st; host = st;
} }
/* Populate our address from the given */ /* 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; return -1;
} }
ast_log(LOG_DEBUG, "host: %s, user: %s, password: %s, context: %s\n", host, username, password, context); 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_port = ntohs(AST_DEFAULT_IAX_PORTNO);
sin.sin_addr.s_addr = INADDR_ANY; 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++) for (x=0;x<AST_IAX2_MAX_CALLS;x++)
ast_pthread_mutex_init(&iaxsl[x]); ast_pthread_mutex_init(&iaxsl[x]);

@ -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_info_with_digit(struct sip_pvt *p, char digit);
static int transmit_message_with_text(struct sip_pvt *p, char *text); 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); 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) 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_via_headers(p, resp, req, "Via");
copy_header(resp, req, "From"); copy_header(resp, req, "From");
ot = get_header(req, "To"); ot = get_header(req, "To");
copy_header(resp, req, "Record-Route");
if (!strstr(ot, "tag=")) { if (!strstr(ot, "tag=")) {
/* Add the proper tag if we don't have it already. If they have specified /* Add the proper tag if we don't have it already. If they have specified
their tag, use it. Otherwise, use our own tag */ 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 /* For registration responses, we also need expirey and
contact info */ contact info */
char tmp[80]; 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); 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, "Expires", tmp);
add_header(resp, "Contact", contact); add_header(resp, "Contact", contact);
} else { } else {
char contact2[256] = "", *c, contact[256]; char contact[256];
/* XXX This isn't exactly right and it's implemented /* XXX This isn't exactly right and it's implemented
very stupidly *sigh* XXX */ very stupidly *sigh* XXX */
strncpy(contact2, get_header(req, "To"), sizeof(contact2)-1); char *c;
c = ditch_braces(contact2); if ((c=getsipuri(ot))) {
snprintf(contact, sizeof(contact), "<%s>", c); 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); add_header(resp, "Contact", contact);
} }
return 0; return 0;
@ -4543,3 +4553,24 @@ char *description()
return desc; 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;
}

@ -1315,6 +1315,10 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
} else { } else {
strcpy(p->dop.dialstr, ""); 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, 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, 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, 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; p = p->next;
continue; 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); callwait = (p->owner != NULL);
if (p->channel == CHAN_PSEUDO) { if (p->channel == CHAN_PSEUDO) {
p = chandup(p); p = chandup(p);

@ -138,11 +138,11 @@ struct ast_iax2_meta_hdr {
struct ast_iax2_meta_trunk_hdr { struct ast_iax2_meta_trunk_hdr {
unsigned int ts; /* 32-bit timestamp for all messages */ unsigned int ts; /* 32-bit timestamp for all messages */
unsigned char data[0]; unsigned char data[0];
}; } __attribute__ ((__packed__));
struct ast_iax2_meta_trunk_entry { struct ast_iax2_meta_trunk_entry {
unsigned short callno; /* Call number */ unsigned short callno; /* Call number */
unsigned short len; /* Length of data for this callno */ unsigned short len; /* Length of data for this callno */
}; } __attribute__ ((__packed__));
#endif #endif

@ -47,6 +47,9 @@ disallow=lpc10 ; Icky sound quality... Mr. Roboto.
;maxjitterbuffer=500 ;maxjitterbuffer=500
;maxexccessbuffer=100 ;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 ; We can register with another IAX server to let him know where we are
; in case we have a dynamic IP address for example ; in case we have a dynamic IP address for example
; ;

@ -383,14 +383,14 @@ static int show_doing(char *title, char *tmp)
return 0; return 0;
} }
static int hide_doing() static int hide_doing(void)
{ {
newtPopWindow(); newtPopWindow();
newtFormDestroy(showform); newtFormDestroy(showform);
return 0; return 0;
} }
static void try_status() static void try_status(void)
{ {
struct message *m; struct message *m;
manager_action("Status", ""); manager_action("Status", "");

Loading…
Cancel
Save