Merge experimental codec preferences for IAX2 (bug #2971)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4727 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Spencer
2005-01-09 10:32:53 +00:00
parent 88979c2a4a
commit 4038178ccb
6 changed files with 244 additions and 54 deletions

View File

@@ -100,6 +100,8 @@
/* 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)
static struct ast_codec_pref prefs;
static char *desc = "Inter Asterisk eXchange (Ver 2)"; static char *desc = "Inter Asterisk eXchange (Ver 2)";
static char *tdesc = "Inter Asterisk eXchange Driver (Ver 2)"; static char *tdesc = "Inter Asterisk eXchange Driver (Ver 2)";
static char *channeltype = "IAX2"; static char *channeltype = "IAX2";
@@ -201,6 +203,9 @@ struct iax2_context {
#define IAX_QUELCH (1 << 11) /* Whether or not we quelch audio */ #define IAX_QUELCH (1 << 11) /* Whether or not we quelch audio */
#define IAX_ENCRYPTED (1 << 12) /* Whether we should assume encrypted tx/rx */ #define IAX_ENCRYPTED (1 << 12) /* Whether we should assume encrypted tx/rx */
#define IAX_KEYPOPULATED (1 << 13) /* Whether we have a key populated */ #define IAX_KEYPOPULATED (1 << 13) /* Whether we have a key populated */
#define IAX_CODEC_USER_FIRST (1 << 14) /* are we willing to let the other guy choose the codec? */
static struct iax2_peer *realtime_peer(const char *peername);
struct iax2_user { struct iax2_user {
char name[80]; char name[80];
@@ -216,6 +221,7 @@ struct iax2_user {
int capability; int capability;
char cid_num[AST_MAX_EXTENSION]; char cid_num[AST_MAX_EXTENSION];
char cid_name[AST_MAX_EXTENSION]; char cid_name[AST_MAX_EXTENSION];
struct ast_codec_pref prefs;
struct ast_ha *ha; struct ast_ha *ha;
struct iax2_context *contexts; struct iax2_context *contexts;
struct iax2_user *next; struct iax2_user *next;
@@ -232,6 +238,7 @@ struct iax2_peer {
char regexten[AST_MAX_EXTENSION]; /* Extension to register (if regcontext is used) */ char regexten[AST_MAX_EXTENSION]; /* Extension to register (if regcontext is used) */
char peercontext[AST_MAX_EXTENSION]; /* Context to pass to peer */ char peercontext[AST_MAX_EXTENSION]; /* Context to pass to peer */
char mailbox[AST_MAX_EXTENSION]; /* Mailbox */ char mailbox[AST_MAX_EXTENSION]; /* Mailbox */
struct ast_codec_pref prefs;
struct sockaddr_in addr; struct sockaddr_in addr;
int formats; int formats;
struct in_addr mask; struct in_addr mask;
@@ -370,6 +377,7 @@ struct chan_iax2_pvt {
int maxtime; int maxtime;
/* Peer Address */ /* Peer Address */
struct sockaddr_in addr; struct sockaddr_in addr;
struct ast_codec_pref prefs;
/* Our call number */ /* Our call number */
unsigned short callno; unsigned short callno;
/* Peer callno */ /* Peer callno */
@@ -639,6 +647,23 @@ static int uncompress_subclass(unsigned char csub)
return csub; return csub;
} }
static struct iax2_peer *find_peer(const char *name)
{
struct iax2_peer *peer;
struct iax2_peer *prev;
ast_mutex_lock(&peerl.lock);
for(peer = peerl.peers; peer; peer = peer->next) {
if (!strcasecmp(peer->name, name)) {
break;
}
prev = peer;
}
ast_mutex_unlock(&peerl.lock);
if(!peer)
peer = realtime_peer(name);
return peer;
}
static int iax2_getpeername(struct sockaddr_in sin, char *host, int len, int lockpeer) static int iax2_getpeername(struct sockaddr_in sin, char *host, int len, int lockpeer)
{ {
struct iax2_peer *peer; struct iax2_peer *peer;
@@ -666,6 +691,7 @@ static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer, cons
tmp = malloc(sizeof(struct chan_iax2_pvt)); tmp = malloc(sizeof(struct chan_iax2_pvt));
if (tmp) { if (tmp) {
memset(tmp, 0, sizeof(struct chan_iax2_pvt)); memset(tmp, 0, sizeof(struct chan_iax2_pvt));
tmp->prefs = prefs;
tmp->callno = 0; tmp->callno = 0;
tmp->peercallno = 0; tmp->peercallno = 0;
tmp->transfercallno = 0; tmp->transfercallno = 0;
@@ -1590,6 +1616,73 @@ static char jitter_usage[] =
"to establish the maximum excess jitter buffer that is permitted before the jitter\n" "to establish the maximum excess jitter buffer that is permitted before the jitter\n"
"buffer size is reduced."; "buffer size is reduced.";
/*--- iax2_show_peer: Show one peer in detail ---*/
static int iax2_show_peer(int fd, int argc, char *argv[])
{
char status[30] = "";
char cbuf[256];
char iabuf[INET_ADDRSTRLEN];
struct iax2_peer *peer;
char codec_buf[512];
int x = 0, codec = 0;
if (argc != 4)
return RESULT_SHOWUSAGE;
ast_mutex_lock(&peerl.lock);
peer = find_peer(argv[3]);
if (peer) {
ast_cli(fd,"\n\n");
ast_cli(fd, " * Name : %s\n", peer->name);
ast_cli(fd, " Secret : %s\n", ast_strlen_zero(peer->secret)?"<Not set>":"<Set>");
ast_cli(fd, " Context : %s\n", peer->context);
ast_cli(fd, " Mailbox : %s\n", peer->mailbox);
ast_cli(fd, " Dynamic : %s\n", ast_test_flag(peer, IAX_DYNAMIC) ? "Yes":"No");
ast_cli(fd, " Callerid : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "<unspecified>"));
ast_cli(fd, " Expire : %d\n", peer->expire);
ast_cli(fd, " ACL : %s\n", (peer->ha?"Yes":"No"));
ast_cli(fd, " Addr->IP : %s Port %d\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port));
ast_cli(fd, " Defaddr->IP : %s Port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
ast_cli(fd, " Username : %s\n", peer->username);
ast_cli(fd, " Codecs : ");
ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
ast_cli(fd, "%s\n", codec_buf);
ast_cli(fd, " Codec Order : (");
for(x = 0; x < 32 ; x++) {
codec = ast_codec_pref_index(&peer->prefs,x);
if(!codec)
break;
ast_cli(fd, "%s", ast_getformatname(codec));
if(x < 31 && ast_codec_pref_index(&peer->prefs,x+1))
ast_cli(fd, "|");
}
if (!x)
ast_cli(fd, "none");
ast_cli(fd, ")\n");
ast_cli(fd, " Status : ");
if (peer->lastms < 0)
strncpy(status, "UNREACHABLE", sizeof(status) - 1);
else if (peer->lastms > peer->maxms)
snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms);
else if (peer->lastms)
snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms);
else
strncpy(status, "UNKNOWN", sizeof(status) - 1);
ast_cli(fd, "%s\n",status);
ast_cli(fd,"\n");
} else {
ast_cli(fd,"Peer %s not found.\n", argv[3]);
ast_cli(fd,"\n");
}
ast_mutex_unlock(&peerl.lock);
return RESULT_SUCCESS;
}
static int iax2_show_stats(int fd, int argc, char *argv[]) static int iax2_show_stats(int fd, int argc, char *argv[])
{ {
struct iax_frame *cur; struct iax_frame *cur;
@@ -1673,6 +1766,10 @@ static char show_cache_usage[] =
"Usage: iax show cache\n" "Usage: iax show cache\n"
" Display currently cached IAX Dialplan results.\n"; " Display currently cached IAX Dialplan results.\n";
static char show_peer_usage[] =
"Usage: iax show peer <name>\n"
" Display details on specific IAX peer\n";
static struct ast_cli_entry cli_set_jitter = static struct ast_cli_entry cli_set_jitter =
{ { "iax2", "set", "jitter", NULL }, iax2_set_jitter, "Sets IAX jitter buffer", jitter_usage }; { { "iax2", "set", "jitter", NULL }, iax2_set_jitter, "Sets IAX jitter buffer", jitter_usage };
@@ -1682,6 +1779,8 @@ static struct ast_cli_entry cli_show_stats =
static struct ast_cli_entry cli_show_cache = static struct ast_cli_entry cli_show_cache =
{ { "iax2", "show", "cache", NULL }, iax2_show_cache, "Display IAX cached dialplan", show_cache_usage }; { { "iax2", "show", "cache", NULL }, iax2_show_cache, "Display IAX cached dialplan", show_cache_usage };
static struct ast_cli_entry cli_show_peer =
{ { "iax2", "show", "peer", NULL }, iax2_show_peer, "Show details on specific IAX peer", show_peer_usage };
static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset); static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset);
@@ -2118,7 +2217,7 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani,
int *maxtime, char *peer, char *context, int *trunk, int *maxtime, char *peer, char *context, int *trunk,
int *notransfer, int *usejitterbuf, int *encmethods, int *notransfer, int *usejitterbuf, int *encmethods,
char *username, int usernlen, char *secret, int seclen, char *username, int usernlen, char *secret, int seclen,
int *ofound, char *peercontext, char *timezone, int tzlen) int *ofound, char *peercontext, char *timezone, int tzlen, char *pref_str, size_t pref_size)
{ {
struct ast_hostent ahp; struct hostent *hp; struct ast_hostent ahp; struct hostent *hp;
struct iax2_peer *p; struct iax2_peer *p;
@@ -2145,6 +2244,10 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani,
found++; found++;
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(pref_str) {
ast_codec_pref_convert(&p->prefs, pref_str, pref_size, 1);
}
if (sendani) if (sendani)
*sendani = ast_test_flag(p, IAX_SENDANI); /* Whether we transmit ANI */ *sendani = ast_test_flag(p, IAX_SENDANI); /* Whether we transmit ANI */
if (maxtime) if (maxtime)
@@ -2203,6 +2306,10 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani,
if (ofound) if (ofound)
*ofound = found; *ofound = found;
if (!p && !found) { if (!p && !found) {
if(pref_str) { /* use global iax prefs for unknown peer/user */
ast_codec_pref_convert(&prefs, pref_str, pref_size, 1);
}
hp = ast_gethostbyname(peer, &ahp); hp = ast_gethostbyname(peer, &ahp);
if (hp) { if (hp) {
memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr)); memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
@@ -2272,6 +2379,10 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout)
char *stringp=NULL; char *stringp=NULL;
char storedusern[80], storedsecret[80]; char storedusern[80], storedsecret[80];
char tz[80] = ""; char tz[80] = "";
char out_prefs[32];
memset(out_prefs,0,32);
if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) { if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) {
ast_log(LOG_WARNING, "Line is already in use (%s)?\n", c->name); ast_log(LOG_WARNING, "Line is already in use (%s)?\n", c->name);
return -1; return -1;
@@ -2313,7 +2424,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, NULL, NULL, NULL, &encmethods, storedusern, sizeof(storedusern) - 1, storedsecret, sizeof(storedsecret) - 1, NULL, peercontext, tz, sizeof(tz))) { if (create_addr(&sin, NULL, NULL, NULL, hname, context, NULL, NULL, NULL, &encmethods, storedusern, sizeof(storedusern) - 1, storedsecret, sizeof(storedsecret) - 1, NULL, peercontext, tz, sizeof(tz), out_prefs, sizeof(out_prefs))) {
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;
} }
@@ -2333,6 +2444,8 @@ static int iax2_call(struct ast_channel *c, char *dest, int timeout)
/* Request auto answer */ /* Request auto answer */
iax_ie_append(&ied, IAX_IE_AUTOANSWER); iax_ie_append(&ied, IAX_IE_AUTOANSWER);
} }
iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, out_prefs);
if (l) { if (l) {
iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l); iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l);
iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres); iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres);
@@ -3391,14 +3504,14 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
static int iax2_show_users(int fd, int argc, char *argv[]) static int iax2_show_users(int fd, int argc, char *argv[])
{ {
#define FORMAT "%-15.15s %-20.20s %-15.15s %-15.15s %-5.5s\n" #define FORMAT "%-15.15s %-20.20s %-15.15s %-15.15s %-5.5s %-5.5s\n"
#define FORMAT2 "%-15.15s %-20.20s %-15.15d %-15.15s %-5.5s\n" #define FORMAT2 "%-15.15s %-20.20s %-15.15d %-15.15s %-5.5s %-5.5s\n"
struct iax2_user *user; struct iax2_user *user;
char auth[90] = ""; char auth[90] = "";
if (argc != 3) if (argc != 3)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
ast_mutex_lock(&userl.lock); ast_mutex_lock(&userl.lock);
ast_cli(fd, FORMAT, "Username", "Secret", "Authen", "Def.Context", "A/C"); ast_cli(fd, FORMAT, "Username", "Secret", "Authen", "Def.Context", "A/C","Codec Pref");
for(user=userl.users;user;user=user->next) { for(user=userl.users;user;user=user->next) {
if (!ast_strlen_zero(user->secret)) { if (!ast_strlen_zero(user->secret)) {
strncpy(auth,user->secret,sizeof(auth)-1); strncpy(auth,user->secret,sizeof(auth)-1);
@@ -3408,7 +3521,7 @@ static int iax2_show_users(int fd, int argc, char *argv[])
strncpy(auth, "-no secret-", sizeof(auth) - 1); strncpy(auth, "-no secret-", sizeof(auth) - 1);
ast_cli(fd, FORMAT2, user->name, auth, user->authmethods, ast_cli(fd, FORMAT2, user->name, auth, user->authmethods,
user->contexts ? user->contexts->context : context, user->contexts ? user->contexts->context : context,
user->ha ? "Yes" : "No"); user->ha ? "Yes" : "No", ast_test_flag(user,IAX_CODEC_USER_FIRST) ? "Caller" : "Host");
} }
ast_mutex_unlock(&userl.lock); ast_mutex_unlock(&userl.lock);
return RESULT_SUCCESS; return RESULT_SUCCESS;
@@ -3854,6 +3967,10 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
} }
if (ies->version) if (ies->version)
version = ies->version; version = ies->version;
if(ies->codec_prefs)
ast_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0);
if (!gotcapability) if (!gotcapability)
iaxs[callno]->peercapability = iaxs[callno]->peerformat; iaxs[callno]->peercapability = iaxs[callno]->peerformat;
if (version > IAX_PROTO_VERSION) { if (version > IAX_PROTO_VERSION) {
@@ -3926,8 +4043,8 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
iaxs[callno]->vars = tmpvar; iaxs[callno]->vars = tmpvar;
} }
} }
iaxs[callno]->prefs = user->prefs;
ast_copy_flags(iaxs[callno], user, IAX_CODEC_USER_FIRST);
iaxs[callno]->encmethods = user->encmethods; iaxs[callno]->encmethods = user->encmethods;
/* Store the requested username if not specified */ /* Store the requested username if not specified */
if (ast_strlen_zero(iaxs[callno]->username)) if (ast_strlen_zero(iaxs[callno]->username))
@@ -5298,6 +5415,10 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
unsigned int ts; unsigned int ts;
char empty[32]=""; /* Safety measure */ char empty[32]=""; /* Safety measure */
struct iax_frame *duped_fr; struct iax_frame *duped_fr;
char host_pref_buf[128];
char caller_pref_buf[128];
struct ast_codec_pref pref,rpref;
char *using_prefs = "mine";
dblbuf[0] = 0; /* Keep GCC from whining */ dblbuf[0] = 0; /* Keep GCC from whining */
fr.callno = 0; fr.callno = 0;
@@ -5734,9 +5855,26 @@ retryowner:
ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context); ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context);
} else { } else {
/* Select an appropriate format */ /* Select an appropriate format */
format = iaxs[fr.callno]->peerformat & iaxs[fr.callno]->capability; if(ies.codec_prefs) {
ast_codec_pref_convert(&rpref, ies.codec_prefs, 32, 0);
/* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
using_prefs = "mine";
if (ast_test_flag(iaxs[fr.callno], IAX_CODEC_USER_FIRST)) {
pref = rpref;
using_prefs = "caller";
} else {
pref = iaxs[fr.callno]->prefs;
}
} else
pref = iaxs[fr.callno]->prefs;
format = ast_codec_choose(&pref, iaxs[fr.callno]->capability & iaxs[fr.callno]->peercapability, 0);
ast_codec_pref_string(&rpref, caller_pref_buf, sizeof(caller_pref_buf) - 1);
ast_codec_pref_string(&iaxs[fr.callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
if (!format) { if (!format) {
format = iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability; format = iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability;
if (!format) { if (!format) {
memset(&ied0, 0, sizeof(ied0)); memset(&ied0, 0, sizeof(ied0));
iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec"); iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
@@ -5746,7 +5884,19 @@ retryowner:
ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iaxs[fr.callno]->capability); ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iaxs[fr.callno]->capability);
} else { } else {
/* Pick one... */ /* Pick one... */
format = ast_best_codec(iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability); using_prefs = "mine";
if(ies.codec_prefs) {
/* Do the opposite of what we tried above. */
if (ast_test_flag(iaxs[fr.callno], IAX_CODEC_USER_FIRST)) {
pref = iaxs[fr.callno]->prefs;
} else {
pref = rpref;
using_prefs = "caller";
}
format = ast_codec_choose(&pref, iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability, 1);
} else /* if no codec_prefs IE do it the old way */
format = ast_best_codec(iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability);
if (!format) { if (!format) {
memset(&ied0, 0, sizeof(ied0)); memset(&ied0, 0, sizeof(ied0));
iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec"); iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
@@ -5768,8 +5918,8 @@ retryowner:
if (strcmp(iaxs[fr.callno]->exten, "TBD")) { if (strcmp(iaxs[fr.callno]->exten, "TBD")) {
iaxs[fr.callno]->state |= IAX_STATE_STARTED; iaxs[fr.callno]->state |= IAX_STATE_STARTED;
if (option_verbose > 2) if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Accepting unauthenticated call from %s, requested format = %d, actual format = %d\n", ast_verbose(VERBOSE_PREFIX_3 "Accepting unauthenticated call from %s, requested format = %s, requested prefs = %s, actual format = %s, my prefs = %s priority = %s \n",
ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat,format); ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ast_getformatname(iaxs[fr.callno]->peerformat), caller_pref_buf, ast_getformatname(format), host_pref_buf, using_prefs);
if(!(c = ast_iax2_new(fr.callno, AST_STATE_RING, format))) if(!(c = ast_iax2_new(fr.callno, AST_STATE_RING, format)))
iax2_destroy_nolock(fr.callno); iax2_destroy_nolock(fr.callno);
} else { } else {
@@ -6041,10 +6191,28 @@ retryowner2:
send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
} else { } else {
/* Select an appropriate format */ /* Select an appropriate format */
format = iaxs[fr.callno]->peerformat & iaxs[fr.callno]->capability; using_prefs = "mine";
if(ies.codec_prefs) {
/* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
ast_codec_pref_convert(&rpref, ies.codec_prefs, 32, 0);
if (ast_test_flag(iaxs[fr.callno], IAX_CODEC_USER_FIRST)) {
ast_codec_pref_convert(&pref, ies.codec_prefs, 32, 0);
using_prefs = "caller";
} else {
pref = iaxs[fr.callno]->prefs;
}
} else /* if no codec_prefs IE do it the old way */
pref = iaxs[fr.callno]->prefs;
format = ast_codec_choose(&pref, iaxs[fr.callno]->capability & iaxs[fr.callno]->peercapability, 0);
ast_codec_pref_string(&rpref, caller_pref_buf, sizeof(caller_pref_buf) - 1);
ast_codec_pref_string(&iaxs[fr.callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
if (!format) { if (!format) {
ast_log(LOG_DEBUG, "We don't do requested format %s, falling back to peer capability %d\n", ast_getformatname(iaxs[fr.callno]->peerformat), iaxs[fr.callno]->peercapability); ast_log(LOG_DEBUG, "We don't do requested format %s, falling back to peer capability %d\n", ast_getformatname(iaxs[fr.callno]->peerformat), iaxs[fr.callno]->peercapability);
format = iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability; format = iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability;
if (!format) { if (!format) {
if (authdebug) if (authdebug)
ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iaxs[fr.callno]->capability); ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iaxs[fr.callno]->capability);
@@ -6054,7 +6222,19 @@ retryowner2:
send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
} else { } else {
/* Pick one... */ /* Pick one... */
format = ast_best_codec(iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability); using_prefs = "mine";
if(ies.codec_prefs) {
/* Do the opposite of what we tried above. */
if (ast_test_flag(iaxs[fr.callno], IAX_CODEC_USER_FIRST)) {
pref = iaxs[fr.callno]->prefs;
} else {
pref = rpref;
using_prefs = "caller";
}
format = ast_codec_choose(&pref, iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability, 1);
} else /* if no codec_prefs IE do it the old way */
format = ast_best_codec(iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability);
if (!format) { if (!format) {
ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability); ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability);
if (authdebug) if (authdebug)
@@ -6074,8 +6254,9 @@ retryowner2:
if (strcmp(iaxs[fr.callno]->exten, "TBD")) { if (strcmp(iaxs[fr.callno]->exten, "TBD")) {
iaxs[fr.callno]->state |= IAX_STATE_STARTED; iaxs[fr.callno]->state |= IAX_STATE_STARTED;
if (option_verbose > 2) if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Accepting AUTHENTICATED call from %s, requested format = %d, actual format = %d\n", ast_verbose(VERBOSE_PREFIX_3 "Accepting AUTHENTICATED call from %s, requested format = %s, requested prefs = %s, actual format = %s, my prefs = %s priority = %s\n",
ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat,format); ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ast_getformatname(iaxs[fr.callno]->peerformat),
caller_pref_buf, ast_getformatname(format), host_pref_buf, using_prefs);
iaxs[fr.callno]->state |= IAX_STATE_STARTED; iaxs[fr.callno]->state |= IAX_STATE_STARTED;
if(!(c = ast_iax2_new(fr.callno, AST_STATE_RING, format))) if(!(c = ast_iax2_new(fr.callno, AST_STATE_RING, format)))
iax2_destroy_nolock(fr.callno); iax2_destroy_nolock(fr.callno);
@@ -6412,7 +6593,7 @@ static int iax2_provision(struct sockaddr_in *end, char *dest, const char *templ
if (end) if (end)
memcpy(&sin, end, sizeof(sin)); memcpy(&sin, end, sizeof(sin));
else { else {
if (create_addr(&sin, NULL, NULL, NULL, dest, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0)) if (create_addr(&sin, NULL, NULL, NULL, dest, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0, NULL, 0))
return -1; return -1;
} }
/* Build the rest of the message */ /* Build the rest of the message */
@@ -6606,7 +6787,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data
} }
/* Populate our address from the given */ /* Populate our address from the given */
if (create_addr(&sin, &capability, &sendani, &maxtime, hostname, NULL, &trunk, &notransfer, &usejitterbuf, NULL, NULL, 0, NULL, 0, &found, NULL, NULL, 0)) { if (create_addr(&sin, &capability, &sendani, &maxtime, hostname, NULL, &trunk, &notransfer, &usejitterbuf, NULL, NULL, 0, NULL, 0, &found, NULL, NULL, 0, NULL, 0)) {
*cause = AST_CAUSE_UNREGISTERED; *cause = AST_CAUSE_UNREGISTERED;
return NULL; return NULL;
} }
@@ -6739,13 +6920,13 @@ static int get_auth_methods(char *value)
return methods; return methods;
} }
static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, int temponly) static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, int temponly)
{ {
struct iax2_peer *peer; struct iax2_peer *peer;
struct iax2_peer *prev; struct iax2_peer *prev;
struct ast_ha *oldha = NULL; struct ast_ha *oldha = NULL;
int maskfound=0; int maskfound=0;
int format;
int found=0; int found=0;
prev = NULL; prev = NULL;
ast_mutex_lock(&peerl.lock); ast_mutex_lock(&peerl.lock);
@@ -6789,6 +6970,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO); peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO);
peer->expirey = expirey; peer->expirey = expirey;
} }
peer->prefs = prefs;
peer->capability = iax2_capability; peer->capability = iax2_capability;
while(v) { while(v) {
if (!strcasecmp(v->name, "secret")) { if (!strcasecmp(v->name, "secret")) {
@@ -6871,17 +7053,9 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
} else if (!strcasecmp(v->name, "username")) { } else if (!strcasecmp(v->name, "username")) {
strncpy(peer->username, v->value, sizeof(peer->username)-1); strncpy(peer->username, v->value, sizeof(peer->username)-1);
} else if (!strcasecmp(v->name, "allow")) { } else if (!strcasecmp(v->name, "allow")) {
format = ast_getformatbyname(v->value); ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 1);
if (format < 1)
ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
else
peer->capability |= format;
} else if (!strcasecmp(v->name, "disallow")) { } else if (!strcasecmp(v->name, "disallow")) {
format = ast_getformatbyname(v->value); ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 0);
if (format < 1)
ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
else
peer->capability &= ~format;
} else if (!strcasecmp(v->name, "callerid")) { } else if (!strcasecmp(v->name, "callerid")) {
ast_callerid_split(v->value, peer->cid_name, sizeof(peer->cid_name), ast_callerid_split(v->value, peer->cid_name, sizeof(peer->cid_name),
peer->cid_num, sizeof(peer->cid_num)); peer->cid_num, sizeof(peer->cid_num));
@@ -6966,6 +7140,7 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
if (user) { if (user) {
memset(user, 0, sizeof(struct iax2_user)); memset(user, 0, sizeof(struct iax2_user));
user->prefs = prefs;
user->capability = iax2_capability; user->capability = iax2_capability;
user->encmethods = iax2_encryption; user->encmethods = iax2_encryption;
strncpy(user->name, name, sizeof(user->name)-1); strncpy(user->name, name, sizeof(user->name)-1);
@@ -6995,17 +7170,9 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
} }
} }
} else if (!strcasecmp(v->name, "allow")) { } else if (!strcasecmp(v->name, "allow")) {
format = ast_getformatbyname(v->value); ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1);
if (format < 1)
ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
else
user->capability |= format;
} else if (!strcasecmp(v->name, "disallow")) { } else if (!strcasecmp(v->name, "disallow")) {
format = ast_getformatbyname(v->value); ast_parse_allow_disallow(&user->prefs, &user->capability,v->value, 0);
if (format < 1)
ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
else
user->capability &= ~format;
} else if (!strcasecmp(v->name, "trunk")) { } else if (!strcasecmp(v->name, "trunk")) {
ast_set2_flag(user, ast_true(v->value), IAX_TRUNK); ast_set2_flag(user, ast_true(v->value), IAX_TRUNK);
if (ast_test_flag(user, IAX_TRUNK) && (timingfd < 0)) { if (ast_test_flag(user, IAX_TRUNK) && (timingfd < 0)) {
@@ -7018,6 +7185,8 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
user->encmethods = get_encrypt_methods(v->value); user->encmethods = get_encrypt_methods(v->value);
} else if (!strcasecmp(v->name, "notransfer")) { } else if (!strcasecmp(v->name, "notransfer")) {
ast_set2_flag(user, ast_true(v->value), IAX_NOTRANSFER); ast_set2_flag(user, ast_true(v->value), IAX_NOTRANSFER);
} else if (!strcasecmp(v->name, "codecpriority") && !strcasecmp(v->value, "caller")) {
ast_set_flag(user, IAX_CODEC_USER_FIRST);
} else if (!strcasecmp(v->name, "jitterbuffer")) { } else if (!strcasecmp(v->name, "jitterbuffer")) {
ast_set2_flag(user, ast_true(v->value), IAX_USEJITTERBUF); ast_set2_flag(user, ast_true(v->value), IAX_USEJITTERBUF);
} else if (!strcasecmp(v->name, "dbsecret")) { } else if (!strcasecmp(v->name, "dbsecret")) {
@@ -7215,6 +7384,7 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
ast_log(LOG_ERROR, "Unable to load config %s\n", config_file); ast_log(LOG_ERROR, "Unable to load config %s\n", config_file);
return -1; return -1;
} }
memset(&prefs, 0 , sizeof(struct ast_codec_pref));
v = ast_variable_browse(cfg, "general"); v = ast_variable_browse(cfg, "general");
while(v) { while(v) {
if (!strcasecmp(v->name, "bindport")){ if (!strcasecmp(v->name, "bindport")){
@@ -7283,17 +7453,9 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
} else } else
ast_log(LOG_WARNING, "bandwidth must be either low, medium, or high\n"); ast_log(LOG_WARNING, "bandwidth must be either low, medium, or high\n");
} else if (!strcasecmp(v->name, "allow")) { } else if (!strcasecmp(v->name, "allow")) {
format = ast_getformatbyname(v->value); ast_parse_allow_disallow(&prefs, &capability, v->value, 1);
if (format < 1)
ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
else
capability |= format;
} else if (!strcasecmp(v->name, "disallow")) { } else if (!strcasecmp(v->name, "disallow")) {
format = ast_getformatbyname(v->value); ast_parse_allow_disallow(&prefs, &capability, v->value, 0);
if (format < 1)
ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
else
capability &= ~format;
} else if (!strcasecmp(v->name, "register")) { } else if (!strcasecmp(v->name, "register")) {
iax2_register(v->value, v->lineno); iax2_register(v->value, v->lineno);
} else if (!strcasecmp(v->name, "iaxcompat")) { } else if (!strcasecmp(v->name, "iaxcompat")) {
@@ -7451,7 +7613,7 @@ static int cache_get_callno_locked(const 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, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0)) { if (create_addr(&sin, NULL, NULL, NULL, host, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0, NULL, 0)) {
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);
@@ -7793,6 +7955,7 @@ static int __unload_module(void)
ast_cli_unregister(&cli_set_jitter); ast_cli_unregister(&cli_set_jitter);
ast_cli_unregister(&cli_show_stats); ast_cli_unregister(&cli_show_stats);
ast_cli_unregister(&cli_show_cache); ast_cli_unregister(&cli_show_cache);
ast_cli_unregister(&cli_show_peer);
ast_unregister_switch(&iax2_switch); ast_unregister_switch(&iax2_switch);
ast_channel_unregister(channeltype); ast_channel_unregister(channeltype);
delete_users(); delete_users();
@@ -7820,6 +7983,7 @@ int load_module(void)
struct sockaddr_in sin; struct sockaddr_in sin;
iax_set_output(iax_debug_output); iax_set_output(iax_debug_output);
iax_set_error(iax_error_output); iax_set_error(iax_error_output);
@@ -7871,6 +8035,7 @@ int load_module(void)
ast_cli_register(&cli_set_jitter); ast_cli_register(&cli_set_jitter);
ast_cli_register(&cli_show_stats); ast_cli_register(&cli_show_stats);
ast_cli_register(&cli_show_cache); ast_cli_register(&cli_show_cache);
ast_cli_register(&cli_show_peer);
ast_register_application(papp, iax2_prov_app, psyn, pdescrip); ast_register_application(papp, iax2_prov_app, psyn, pdescrip);

View File

@@ -80,6 +80,25 @@ static void dump_string(char *output, int maxlen, void *value, int len)
output[maxlen] = '\0'; output[maxlen] = '\0';
} }
static void dump_prefs(char *output, int maxlen, void *value, int len)
{
struct ast_codec_pref pref;
int total_len = 0;
maxlen--;
total_len = maxlen;
if (maxlen > len)
maxlen = len;
strncpy(output,value, maxlen);
output[maxlen] = '\0';
ast_codec_pref_convert(&pref, output, total_len, 0);
memset(output,0,total_len);
ast_codec_pref_string(&pref, output, total_len);
}
static void dump_int(char *output, int maxlen, void *value, int len) static void dump_int(char *output, int maxlen, void *value, int len)
{ {
if (len == (int)sizeof(unsigned int)) if (len == (int)sizeof(unsigned int))
@@ -208,6 +227,7 @@ static struct iax2_ie {
{ IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte }, { IAX_IE_CAUSECODE, "CAUSE CODE", dump_byte },
{ IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short }, { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
{ IAX_IE_ENCKEY, "ENCRYPTION KEY" }, { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
{ IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
}; };
static struct iax2_ie prov_ies[] = { static struct iax2_ie prov_ies[] = {
@@ -564,6 +584,9 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
case IAX_IE_PASSWORD: case IAX_IE_PASSWORD:
ies->password = data + 2; ies->password = data + 2;
break; break;
case IAX_IE_CODEC_PREFS:
ies->codec_prefs = data + 2;
break;
case IAX_IE_CAPABILITY: case IAX_IE_CAPABILITY:
if (len != (int)sizeof(unsigned int)) { 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); snprintf(tmp, (int)sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);

View File

@@ -27,6 +27,7 @@ struct iax_ies {
char *password; char *password;
unsigned int capability; unsigned int capability;
unsigned int format; unsigned int format;
char *codec_prefs;
char *language; char *language;
int version; int version;
unsigned short adsicpe; unsigned short adsicpe;

View File

@@ -119,6 +119,7 @@
#define IAX_IE_CAUSECODE 42 /* Hangup cause (u8) */ #define IAX_IE_CAUSECODE 42 /* Hangup cause (u8) */
#define IAX_IE_ENCRYPTION 43 /* Encryption format (u16) */ #define IAX_IE_ENCRYPTION 43 /* Encryption format (u16) */
#define IAX_IE_ENCKEY 44 /* Encryption key (raw) */ #define IAX_IE_ENCKEY 44 /* Encryption key (raw) */
#define IAX_IE_CODEC_PREFS 45 /* Codec Negotiation */
#define IAX_AUTH_PLAINTEXT (1 << 0) #define IAX_AUTH_PLAINTEXT (1 << 0)
#define IAX_AUTH_MD5 (1 << 1) #define IAX_AUTH_MD5 (1 << 1)

View File

@@ -810,9 +810,9 @@ int init_framer(void)
return 0; return 0;
} }
void ast_codec_pref_shift(struct ast_codec_pref *pref, char *buf, size_t size, int right) void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
{ {
int x = 0, differential = 65, mem = 0; int x = 0, differential = (int) 'A', mem = 0;
char *from = NULL, *to = NULL; char *from = NULL, *to = NULL;
if(right) { if(right) {

View File

@@ -408,7 +408,7 @@ extern void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, cha
extern int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size); extern int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size);
/* Shift a codec preference list up or down 65 bytes so that it becomes an ASCII string */ /* Shift a codec preference list up or down 65 bytes so that it becomes an ASCII string */
extern void ast_codec_pref_shift(struct ast_codec_pref *pref, char *buf, size_t size, int right); extern void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right);
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} }