dect
/
asterisk
Archived
13
0
Fork 0

Sun Feb 16 07:00:01 CET 2003

git-svn-id: http://svn.digium.com/svn/asterisk/trunk@616 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
matteo 2003-02-16 06:00:12 +00:00
parent dae2009f95
commit 175c755fef
12 changed files with 660 additions and 49 deletions

View File

@ -1,3 +1,9 @@
-- Make HOLD on SIP make use of asterisk MOH
-- Add supervised transfer (tested with Pingtel only)
-- Allow maxexpirey and defaultexpirey to be runtime configurable for SIP
-- Preliminary codec 13 support (RFC3389)
-- Add app_authenticate for general purpose authentication
-- Optimize RTP and smoother
-- Create special variable "EXTEN-n" where it is extension stripped by n MSD
-- Fix uninitialized frame pointer in channel.c
-- Add global variables support under [globals] of extensions.conf

View File

@ -144,7 +144,7 @@ datafiles: all
exit 1; \
fi; \
done
for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep* sounds/dir-* sounds/conf-* sounds/agent-* sounds/invalid* sounds/tt-*; do \
for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep* sounds/dir-* sounds/conf-* sounds/agent-* sounds/invalid* sounds/tt-* sounds/auth-*; do \
if grep -q "^%`basename $$x`%" sounds.txt; then \
install $$x $(ASTVARLIBDIR)/sounds ; \
else \

View File

@ -17,7 +17,8 @@ APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_intercom.
app_agi.so app_qcall.so app_adsiprog.so app_getcpeid.so app_milliwatt.so \
app_zapateller.so app_datetime.so app_setcallerid.so app_festival.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
#APPS+=app_sql_postgres.so
#APPS+=app_sql_odbc.so

154
apps/app_authenticate.c Executable file
View File

@ -0,0 +1,154 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Execute arbitrary authenticate commands
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.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 <string.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
static char *tdesc = "Authentication Application";
static char *app = "Authenticate";
static char *synopsis = "Authenticate a user";
static char *descrip =
" Authenticate(password[|options]): Requires a user to enter a"
"given password in order to continue execution. If the\n"
"password begins with the '/' character, it is interpreted as\n"
"a file which contains a list of valid passwords (1 per line).\n"
"an optional set of opions may be provided by concatenating any\n"
"of the following letters:\n"
" a - Set account code to the password that is entered\n"
"\n"
"Returns 0 if the user enters a valid password within three\n"
"tries, or -1 otherwise (or on hangup).\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int auth_exec(struct ast_channel *chan, void *data)
{
int res=0;
int retries;
struct localuser *u;
char password[256]="";
char passwd[256];
char *opts;
char *prompt;
if (!data || !strlen(data)) {
ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
return -1;
}
LOCAL_USER_ADD(u);
if (chan->_state != AST_STATE_UP) {
res = ast_answer(chan);
if (res) {
LOCAL_USER_REMOVE(u);
return -1;
}
}
strncpy(password, data, sizeof(password) - 1);
opts=strchr(password, '|');
if (opts) {
*opts = 0;
opts++;
} else
opts = "";
/* Start asking for password */
prompt = "agent-pass";
for (retries = 0; retries < 3; retries++) {
res = ast_app_getdata(chan, prompt, passwd, sizeof(passwd) - 2, 0);
if (res < 0)
break;
res = 0;
if (password[0] == '/') {
/* Compare against a file */
char tmp[80];
FILE *f;
f = fopen(password, "r");
if (f) {
char buf[256] = "";
while(!feof(f)) {
fgets(buf, sizeof(buf), f);
if (!feof(f) && strlen(buf)) {
buf[strlen(buf) - 1] = '\0';
if (strlen(buf) && !strcmp(passwd, buf))
break;
}
}
fclose(f);
if (strlen(buf) && !strcmp(passwd, buf))
break;
} else
ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", password, strerror(errno));
} else {
/* Compare against a fixed password */
if (!strcmp(passwd, password))
break;
}
prompt="auth-incorrect";
}
if ((retries < 3) && !res) {
if (strchr(opts, 'a'))
ast_cdr_setaccount(chan, passwd);
} else {
if (!res)
res = ast_streamfile(chan, "vm-goodbye", chan->language);
if (!res)
res = ast_waitstream(chan, "");
res = -1;
}
LOCAL_USER_REMOVE(u);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
return ast_register_application(app, auth_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@ -131,6 +131,7 @@ struct mgcp_endpoint {
int outgoing;
struct ast_channel *owner;
struct ast_rtp *rtp;
struct sockaddr_in tmpdest;
struct mgcp_endpoint *next;
struct mgcp_gateway *parent;
};
@ -317,6 +318,7 @@ static int mgcp_hangup(struct ast_channel *ast)
p->owner = NULL;
if (strlen(p->cxident))
transmit_connection_del(p);
strcpy(p->cxident, "");
if (!p->alreadygone && (!p->outgoing || (ast->_state == AST_STATE_UP)))
transmit_notify_request(p, "ro", 1);
else
@ -324,8 +326,9 @@ static int mgcp_hangup(struct ast_channel *ast)
ast->pvt->pvt = NULL;
p->alreadygone = 0;
p->outgoing = 0;
strcpy(p->cxident, "");
strcpy(p->callid, "");
/* Reset temporary destination */
memset(&p->tmpdest, 0, sizeof(p->tmpdest));
if (p->rtp) {
ast_rtp_destroy(p->rtp);
p->rtp = NULL;
@ -515,6 +518,7 @@ static struct ast_channel *mgcp_new(struct mgcp_endpoint *i, int state)
tmp->pvt->indicate = mgcp_indicate;
tmp->pvt->fixup = mgcp_fixup;
tmp->pvt->send_digit = mgcp_senddigit;
tmp->pvt->bridge = ast_rtp_bridge;
if (strlen(i->language))
strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
i->owner = tmp;
@ -951,8 +955,15 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_endpoint *p, struct as
if (rtp) {
ast_rtp_get_peer(rtp, &dest);
} else {
dest.sin_addr = p->parent->ourip;
dest.sin_port = sin.sin_port;
if (p->tmpdest.sin_addr.s_addr) {
dest.sin_addr = p->tmpdest.sin_addr;
dest.sin_port = p->tmpdest.sin_port;
/* Reset temporary destination */
memset(&p->tmpdest, 0, sizeof(p->tmpdest));
} else {
dest.sin_addr = p->parent->ourip;
dest.sin_port = sin.sin_port;
}
}
printf("We're at %s port %d\n", inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
snprintf(v, sizeof(v), "v=0\r\n");
@ -991,6 +1002,12 @@ static int transmit_modify_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rtp
char local[256];
char tmp[80];
int x;
if (!strlen(p->cxident) && rtp) {
/* We don't have a CXident yet, store the destination and
wait a bit */
ast_rtp_get_peer(rtp, &p->tmpdest);
return 0;
}
snprintf(local, sizeof(local), "p:20");
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
if (p->capability & x) {
@ -1003,6 +1020,7 @@ static int transmit_modify_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rtp
add_header(&resp, "L", local);
add_header(&resp, "M", "sendrecv");
add_header(&resp, "X", p->txident);
add_header(&resp, "I", p->cxident);
add_header(&resp, "S", "");
add_sdp(&resp, p, rtp);
p->lastout = oseq;
@ -1278,8 +1296,14 @@ static int mgcpsock_read(int *id, int fd, short events, void *ignore)
p = find_endpoint(NULL, ident, &sin);
if (p) {
handle_response(p, result, ident);
if ((c = get_header(&req, "I")))
strncpy(p->cxident, c, sizeof(p->cxident) - 1);
if ((c = get_header(&req, "I"))) {
if (strlen(c)) {
strncpy(p->cxident, c, sizeof(p->cxident) - 1);
if (p->tmpdest.sin_addr.s_addr) {
transmit_modify_with_sdp(p, NULL);
}
}
}
if (req.lines)
process_sdp(p, &req);
}
@ -1483,6 +1507,31 @@ struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
return gw;
}
static struct ast_rtp *mgcp_get_rtp_peer(struct ast_channel *chan)
{
struct mgcp_endpoint *p;
p = chan->pvt->pvt;
if (p && p->rtp)
return p->rtp;
return NULL;
}
static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp)
{
struct mgcp_endpoint *p;
p = chan->pvt->pvt;
if (p) {
transmit_modify_with_sdp(p, rtp);
return 0;
}
return -1;
}
static struct ast_rtp_protocol mgcp_rtp = {
get_rtp_info: mgcp_get_rtp_peer,
set_rtp_peer: mgcp_set_rtp_peer,
};
int load_module()
{
struct ast_config *cfg;
@ -1590,6 +1639,8 @@ int load_module()
ast_destroy(cfg);
return -1;
}
mgcp_rtp.type = type;
ast_rtp_proto_register(&mgcp_rtp);
ast_cli_register(&cli_show_endpoints);
/* And start the monitor for the first time */
restart_monitor();

View File

@ -32,6 +32,7 @@
#include <asterisk/cli.h>
#include <asterisk/md5.h>
#include <asterisk/app.h>
#include <asterisk/musiconhold.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
@ -47,8 +48,12 @@
/* #define VOCAL_DATA_HACK */
#define SIPDUMPER
#define DEFAULT_EXPIREY 120
#define MAX_EXPIREY 3600
#define DEFAULT_DEFAULT_EXPIREY 120
#define DEFAULT_MAX_EXPIREY 3600
static int max_expirey = DEFAULT_MAX_EXPIREY;
static int default_expirey = DEFAULT_DEFAULT_EXPIREY;
#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
@ -142,6 +147,7 @@ static struct sip_pvt {
char refer_to[AST_MAX_EXTENSION]; /* Place to store REFER-TO extension */
char referred_by[AST_MAX_EXTENSION];/* Place to store REFERRED-BY extension */
char refer_contact[AST_MAX_EXTENSION];/* Place to store Contact info from a REFER extension */
struct sip_pvt *refer_call; /* Call we are referring */
char record_route[256];
char record_route_info[256];
char remote_party_id[256];
@ -728,6 +734,7 @@ static int sip_indicate(struct ast_channel *ast, int condition)
}
#if 0
static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
{
struct sip_pvt *p0, *p1;
@ -742,6 +749,7 @@ static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
ast_pthread_mutex_lock(&c1->lock);
p0 = c0->pvt->pvt;
p1 = c1->pvt->pvt;
ast_log(LOG_DEBUG, "Reinvite? %s: %s, %s: %s\n", c0->name, p0->canreinvite ? "yes" : "no", c1->name, p1->canreinvite ? "yes" : "no");
if (!p0->canreinvite || !p1->canreinvite) {
/* Not gonna support reinvite */
ast_pthread_mutex_unlock(&c0->lock);
@ -796,6 +804,7 @@ static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
}
return -1;
}
#endif
static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
{
@ -808,7 +817,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
tmp->nativeformats = capability;
fmt = ast_best_codec(tmp->nativeformats);
if (title)
snprintf(tmp->name, sizeof(tmp->name), "SIP/%s", title);
snprintf(tmp->name, sizeof(tmp->name), "SIP/%s-%04x", title, rand() & 0xffff);
else
snprintf(tmp->name, sizeof(tmp->name), "SIP/%s:%d", inet_ntoa(i->sa.sin_addr), ntohs(i->sa.sin_port));
tmp->type = type;
@ -830,7 +839,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
tmp->pvt->indicate = sip_indicate;
tmp->pvt->fixup = sip_fixup;
tmp->pvt->send_digit = sip_senddigit;
tmp->pvt->bridge = sip_bridge;
tmp->pvt->bridge = ast_rtp_bridge;
if (strlen(i->language))
strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
i->owner = tmp;
@ -1087,7 +1096,7 @@ static int sip_register(char *value, int lineno)
if (secret)
strncpy(reg->secret, secret, sizeof(reg->secret)-1);
reg->expire = -1;
reg->refresh = DEFAULT_EXPIREY;
reg->refresh = default_expirey;
reg->addr.sin_family = AF_INET;
memcpy(&reg->addr.sin_addr, hp->h_addr, sizeof(&reg->addr.sin_addr));
reg->addr.sin_port = porta ? htons(atoi(porta)) : htons(DEFAULT_SIP_PORT);
@ -1237,11 +1246,21 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_log(LOG_WARNING, "No compatible codecs!\n");
return -1;
}
if (p->owner && !(p->owner->nativeformats & p->capability)) {
ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %d and not %d\n", p->capability, p->owner->nativeformats);
p->owner->nativeformats = p->capability;
ast_set_read_format(p->owner, p->owner->readformat);
ast_set_write_format(p->owner, p->owner->writeformat);
if (p->owner) {
if (p->owner->nativeformats & p->capability) {
ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %d and not %d\n", p->capability, p->owner->nativeformats);
p->owner->nativeformats = p->capability;
ast_set_read_format(p->owner, p->owner->readformat);
ast_set_write_format(p->owner, p->owner->writeformat);
}
if (p->owner->bridge) {
/* Turn on/off music on hold if we are holding/unholding */
if (sin.sin_addr.s_addr) {
ast_moh_stop(p->owner->bridge);
} else {
ast_moh_start(p->owner->bridge, NULL);
}
}
}
return 0;
@ -1830,7 +1849,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth)
if (auth)
add_header(&req, "Authorization", auth);
snprintf(tmp, sizeof(tmp), "%d", DEFAULT_EXPIREY);
snprintf(tmp, sizeof(tmp), "%d", default_expirey);
add_header(&req, "Expires", tmp);
add_header(&req, "Event", "registration");
copy_request(&p->initreq, &req);
@ -1933,8 +1952,8 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
strcpy(p->username, "");
if (p->expire > -1)
ast_sched_del(sched, p->expire);
if ((expirey < 1) || (expirey > MAX_EXPIREY))
expirey = DEFAULT_EXPIREY;
if ((expirey < 1) || (expirey > max_expirey))
expirey = max_expirey;
p->expire = ast_sched_add(sched, expirey * 1000, expire_register, p);
pvt->expirey = expirey;
if (memcmp(&p->addr, &oldsin, sizeof(oldsin))) {
@ -2130,7 +2149,9 @@ static int get_refer_info(struct sip_pvt *p, struct sip_request *oreq)
char tmp2[256] = "", *c2, *a2;
char tmp3[256];
char tmp4[256];
char tmp5[256] = ""; /* CallID to replace */
struct sip_request *req;
struct sip_pvt *p2;
req = oreq;
if (!req)
@ -2151,32 +2172,81 @@ static int get_refer_info(struct sip_pvt *p, struct sip_request *oreq)
}
c += 4;
c2 += 4;
if ((a = strchr(c, '@')) || (a = strchr(c, ';'))) {
if ((a = strchr(c, '?'))) {
/* Search for arguemnts */
*a = '\0';
a++;
if (!strncasecmp(a, "REPLACES=", strlen("REPLACES="))) {
strncpy(tmp5, a + strlen("REPLACES="), sizeof(tmp5) - 1);
if ((a = strchr(tmp5, '%'))) {
/* Yuck! Pingtel converts the '@' to a %40, icky icky! Convert
back to an '@' */
if ((a[1] == '4') && (a[2] == '0')) {
*a = '@';
memmove(a + 1, a+3, strlen(a + 3));
}
}
if ((a = strchr(tmp5, '%')))
*a = '\0';
}
}
if ((a2 = strchr(c2, '@')) || (a2 = strchr(c2, ';'))) {
if ((a = strchr(c, '@')))
*a = '\0';
if ((a = strchr(c, ';')))
*a = '\0';
if ((a2 = strchr(c2, '@')))
*a2 = '\0';
}
if ((a2 = strchr(c2, ';')))
*a2 = '\0';
if (sipdebug)
ast_verbose("Looking for %s in %s\n", c, p->context);
ast_verbose("Looking for %s in %s\n", c2, p->context);
if (ast_exists_extension(NULL, p->context, c, 1, NULL) && ast_exists_extension(NULL, p->context, c2, 1, NULL)) {
if (!oreq)
ast_log(LOG_DEBUG,"Something is wrong with this line.\n"); //This line is ignored for some reason....
ast_log(LOG_DEBUG,"Assigning Extension %s to REFER-TO\n", c);
ast_log(LOG_DEBUG,"Assigning Extension %s to REFERRED-BY\n", c2);
ast_log(LOG_DEBUG,"Assigning Contact Info %s to REFER_CONTACT\n", tmp3);
ast_log(LOG_DEBUG,"Assigning Remote-Party-ID Info %s to REMOTE_PARTY_ID\n",tmp4);
strncpy(p->refer_to, c, sizeof(p->refer_to) - 1);
strncpy(p->referred_by, c2, sizeof(p->referred_by) - 1);
strncpy(p->refer_contact, tmp3, sizeof(p->refer_contact) - 1);
strncpy(p->remote_party_id, tmp4, sizeof(p->remote_party_id) - 1);
if (strlen(tmp5)) {
/* This is a supervised transfer */
ast_log(LOG_DEBUG,"Assigning Replace-Call-ID Info %s to REPLACE_CALL_ID\n",tmp5);
strncpy(p->refer_to, "", sizeof(p->refer_to) - 1);
strncpy(p->referred_by, "", sizeof(p->referred_by) - 1);
strncpy(p->refer_contact, "", sizeof(p->refer_contact) - 1);
strncpy(p->remote_party_id, "", sizeof(p->remote_party_id) - 1);
p->refer_call = NULL;
ast_pthread_mutex_lock(&iflock);
/* Search interfaces and find the match */
p2 = iflist;
while(p2) {
if (!strcmp(p2->callid, tmp5)) {
/* Go ahead and lock it before returning */
ast_pthread_mutex_lock(&p2->lock);
p->refer_call = p2;
break;
}
p2 = p2->next;
}
ast_pthread_mutex_unlock(&iflock);
if (p->refer_call)
return 0;
}
if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) {
else
ast_log(LOG_NOTICE, "Supervised transfer requested, but unable to find callid '%s'\n", tmp5);
} else if (ast_exists_extension(NULL, p->context, c, 1, NULL) && ast_exists_extension(NULL, p->context, c2, 1, NULL)) {
/* This is an unsupervised transfer */
ast_log(LOG_DEBUG,"Assigning Extension %s to REFER-TO\n", c);
ast_log(LOG_DEBUG,"Assigning Extension %s to REFERRED-BY\n", c2);
ast_log(LOG_DEBUG,"Assigning Contact Info %s to REFER_CONTACT\n", tmp3);
ast_log(LOG_DEBUG,"Assigning Remote-Party-ID Info %s to REMOTE_PARTY_ID\n",tmp4);
strncpy(p->refer_to, c, sizeof(p->refer_to) - 1);
strncpy(p->referred_by, c2, sizeof(p->referred_by) - 1);
strncpy(p->refer_contact, tmp3, sizeof(p->refer_contact) - 1);
strncpy(p->remote_party_id, tmp4, sizeof(p->remote_party_id) - 1);
p->refer_call = NULL;
return 0;
} else if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) {
return 1;
}
@ -2735,7 +2805,7 @@ retrylock:
if (r->expire != -1)
ast_sched_del(sched, r->expire);
expires=atoi(get_header(req, "expires"));
if (!expires) expires=DEFAULT_EXPIREY;
if (!expires) expires=default_expirey;
r->expire=ast_sched_add(sched, (expires-2)*1000, sip_reregister, r);
}
@ -2879,6 +2949,37 @@ static int determine_firstline_parts( struct sip_request *req ) {
return 1;
}
static int attempt_transfer(struct sip_pvt *p1, struct sip_pvt *p2)
{
if (!p1->owner || !p2->owner) {
ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
return -1;
}
if (p1->owner->bridge) {
if (p2->owner->bridge)
ast_moh_stop(p2->owner->bridge);
ast_moh_stop(p1->owner->bridge);
ast_moh_stop(p1->owner);
ast_moh_stop(p2->owner);
if (ast_channel_masquerade(p2->owner, p1->owner->bridge)) {
ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p2->owner->name, p1->owner->bridge->name);
return -1;
}
} else if (p2->owner->bridge) {
ast_moh_stop(p2->owner->bridge);
ast_moh_stop(p2->owner);
ast_moh_stop(p1->owner);
if (ast_channel_masquerade(p1->owner, p2->owner->bridge)) {
ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p1->owner->name, p2->owner->bridge->name);
return -1;
}
} else {
ast_log(LOG_NOTICE, "Transfer attempted with no bridged calls to transfer\n");
return -1;
}
return 0;
}
static int handle_request(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin)
{
struct sip_request resp;
@ -3048,16 +3149,23 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
transmit_response_with_allow(p, "404 Not Found", req);
else if (res > 0)
transmit_response_with_allow(p, "484 Address Incomplete", req);
else
else {
transmit_response(p, "202 Accepted", req);
ast_log(LOG_DEBUG,"202 Accepted\n");
c = p->owner;
if (c) {
transfer_to = c->bridge;
if (transfer_to)
ast_async_goto(transfer_to,"", p->refer_to,1, 1);
if (p->refer_call) {
ast_log(LOG_DEBUG,"202 Accepted (supervised)\n");
attempt_transfer(p, p->refer_call);
ast_pthread_mutex_unlock(&p->refer_call->lock);
p->refer_call = NULL;
} else {
ast_log(LOG_DEBUG,"202 Accepted (blind)\n");
c = p->owner;
if (c) {
transfer_to = c->bridge;
if (transfer_to)
ast_async_goto(transfer_to,"", p->refer_to,1, 1);
}
}
}
} else if (!strcasecmp(cmd, "CANCEL") || !strcasecmp(cmd, "BYE")) {
copy_request(&p->initreq, req);
p->alreadygone = 1;
@ -3140,7 +3248,7 @@ static int sipsock_read(int *id, int fd, short events, void *ignore)
/* Must have at least two headers */
return 1;
}
/* Process request, with iflock held */
/* Process request, with netlock held */
ast_pthread_mutex_lock(&netlock);
p = find_call(&req, &sin);
if (p) {
@ -3495,6 +3603,8 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
peer->expirey = expirey;
}
peer->capability = capability;
/* Assume can reinvite */
peer->canreinvite = 1;
while(v) {
if (!strcasecmp(v->name, "secret"))
strncpy(peer->secret, v->value, sizeof(peer->secret)-1);
@ -3619,6 +3729,14 @@ static int reload_config()
strncpy(context, v->value, sizeof(context)-1);
} else if (!strcasecmp(v->name, "language")) {
strncpy(language, v->value, sizeof(language)-1);
} else if (!strcasecmp(v->name, "maxexpirey")) {
max_expirey = atoi(v->value);
if (max_expirey < 1)
max_expirey = DEFAULT_MAX_EXPIREY;
} else if (!strcasecmp(v->name, "defaultexpirey")) {
default_expirey = atoi(v->value);
if (default_expirey < 1)
default_expirey = DEFAULT_DEFAULT_EXPIREY;
} else if (!strcasecmp(v->name, "bindaddr")) {
if (!(hp = gethostbyname(v->value))) {
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
@ -3743,6 +3861,31 @@ static int reload_config()
return 0;
}
static struct ast_rtp *sip_get_rtp_peer(struct ast_channel *chan)
{
struct sip_pvt *p;
p = chan->pvt->pvt;
if (p && p->rtp && p->canreinvite)
return p->rtp;
return NULL;
}
static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp)
{
struct sip_pvt *p;
p = chan->pvt->pvt;
if (p) {
transmit_reinvite_with_sdp(p, rtp);
return 0;
}
return -1;
}
static struct ast_rtp_protocol sip_rtp = {
get_rtp_info: sip_get_rtp_peer,
set_rtp_peer: sip_set_rtp_peer,
};
int load_module()
{
int res;
@ -3761,6 +3904,8 @@ int load_module()
ast_cli_register(&cli_show_registry);
ast_cli_register(&cli_debug);
ast_cli_register(&cli_no_debug);
sip_rtp.type = type;
ast_rtp_proto_register(&sip_rtp);
sched = sched_context_create();
if (!sched) {
ast_log(LOG_WARNING, "Unable to create schedule context\n");

View File

@ -7,6 +7,8 @@ bindaddr = 0.0.0.0 ; Address to bind to
context = default ; Default for incoming calls
;tos=lowdelay
;tos=184
;maxexpirey=3600 ; Max length of incoming registration we allow
;defaultexpirey=120 ; Default length of incoming/outoing registration
;[snomsip]
;type=friend

33
frame.c
View File

@ -35,10 +35,12 @@ struct ast_smoother {
int size;
int format;
int readdata;
int optimizablestream;
float samplesperbyte;
struct ast_frame f;
char data[SMOOTHER_SIZE];
char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
struct ast_frame *opt;
int len;
};
@ -76,6 +78,28 @@ int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
ast_log(LOG_WARNING, "Out of smoother space\n");
return -1;
}
if ((f->datalen == s->size) && !s->opt) {
if (!s->len) {
/* Optimize by sending the frame we just got
on the next read, thus eliminating the douple
copy */
s->opt = f;
return 0;
} else {
s->optimizablestream++;
if (s->optimizablestream > 10) {
/* For the past 10 rounds, we have input and output
frames of the correct size for this smoother, yet
we were unable to optimize because there was still
some cruft left over. Lets just drop the cruft so
we can move to a fully optimized path */
s->len = 0;
s->opt = f;
return 0;
}
}
} else
s->optimizablestream = 0;
memcpy(s->data + s->len, f->data, f->datalen);
s->len += f->datalen;
return 0;
@ -83,6 +107,15 @@ int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
struct ast_frame *ast_smoother_read(struct ast_smoother *s)
{
struct ast_frame *opt;
/* IF we have an optimization frame, send it */
if (s->opt) {
opt = s->opt;
s->opt = NULL;
return opt;
}
/* Make sure we have enough data */
if (s->len < s->size) {
return NULL;

View File

@ -17,6 +17,7 @@
#include <asterisk/frame.h>
#include <asterisk/io.h>
#include <asterisk/sched.h>
#include <asterisk/channel.h>
#include <netinet/in.h>
@ -24,6 +25,14 @@
extern "C" {
#endif
struct ast_rtp_protocol {
struct ast_rtp *(*get_rtp_info)(struct ast_channel *chan); /* Get RTP struct, or NULL if unwilling to transfer */
int (*set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer); /* Set RTP peer */
int (*get_rtp_willing)(struct ast_channel *chan); /* Willing to native bridge */
char *type;
struct ast_rtp_protocol *next;
};
struct ast_rtp;
typedef int (*ast_rtp_callback)(struct ast_rtp *rtp, struct ast_frame *f, void *data);
@ -58,6 +67,12 @@ int rtp2ast(int id);
char *ast2rtpn(int id);
int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
int ast_rtp_proto_register(struct ast_rtp_protocol *proto);
void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

204
rtp.c
View File

@ -30,6 +30,7 @@
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/channel_pvt.h>
#define TYPE_SILENCE 0x2
#define TYPE_HIGH 0x0
@ -47,6 +48,7 @@ struct ast_rtp {
unsigned int lastts;
unsigned int lastrxts;
int lasttxformat;
int lastrxformat;
int dtmfcount;
struct sockaddr_in us;
struct sockaddr_in them;
@ -61,6 +63,8 @@ struct ast_rtp {
ast_rtp_callback callback;
};
static struct ast_rtp_protocol *protos = NULL;
int ast_rtp_fd(struct ast_rtp *rtp)
{
return rtp->s;
@ -151,6 +155,49 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
return f;
}
static struct ast_frame *process_rfc3389(struct ast_rtp *rtp, unsigned char *data, int len)
{
struct ast_frame *f = NULL;
/* Convert comfort noise into audio with various codecs. Unfortunately this doesn't
totally help us out becuase we don't have an engine to keep it going and we are not
guaranteed to have it every 20ms or anything */
#if 0
printf("RFC3389: %d bytes, format is %d\n", len, rtp->lastrxformat);
#endif
ast_log(LOG_NOTICE, "RFC3389 support incomplete. Turn off on client if possible\n");
if (!rtp->lastrxformat)
return NULL;
switch(rtp->lastrxformat) {
case AST_FORMAT_ULAW:
rtp->f.frametype = AST_FRAME_VOICE;
rtp->f.subclass = AST_FORMAT_ULAW;
rtp->f.datalen = 160;
rtp->f.samples = 160;
memset(rtp->f.data, 0x7f, rtp->f.datalen);
f = &rtp->f;
break;
case AST_FORMAT_ALAW:
rtp->f.frametype = AST_FRAME_VOICE;
rtp->f.subclass = AST_FORMAT_ALAW;
rtp->f.datalen = 160;
rtp->f.samples = 160;
memset(rtp->f.data, 0x7e, rtp->f.datalen); /* XXX Is this right? XXX */
f = &rtp->f;
break;
case AST_FORMAT_SLINEAR:
rtp->f.frametype = AST_FRAME_VOICE;
rtp->f.subclass = AST_FORMAT_SLINEAR;
rtp->f.datalen = 320;
rtp->f.samples = 160;
memset(rtp->f.data, 0x00, rtp->f.datalen);
f = &rtp->f;
break;
default:
ast_log(LOG_NOTICE, "Don't know how to handle RFC3389 for receive codec %d\n", rtp->lastrxformat);
}
return f;
}
static struct ast_frame *process_type121(struct ast_rtp *rtp, unsigned char *data, int len)
{
char resp = 0;
@ -247,6 +294,8 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
} else if (payloadtype == 100) {
/* CISCO's notso proprietary DTMF bridge */
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
} else if (payloadtype == 13) {
f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
} else {
ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
}
@ -254,7 +303,8 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
return f;
else
return &null_frame;
}
} else
rtp->lastrxformat = rtp->f.subclass;
if (!rtp->lastrxts)
rtp->lastrxts = timestamp;
@ -651,3 +701,155 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
return 0;
}
void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto)
{
struct ast_rtp_protocol *cur, *prev;
cur = protos;
prev = NULL;
while(cur) {
if (cur == proto) {
if (prev)
prev->next = proto->next;
else
protos = proto->next;
return;
}
prev = cur;
cur = cur->next;
}
}
int ast_rtp_proto_register(struct ast_rtp_protocol *proto)
{
struct ast_rtp_protocol *cur;
cur = protos;
while(cur) {
if (cur->type == proto->type) {
ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
return -1;
}
cur = cur->next;
}
proto->next = protos;
protos = proto;
return 0;
}
static struct ast_rtp_protocol *get_proto(struct ast_channel *chan)
{
struct ast_rtp_protocol *cur;
cur = protos;
while(cur) {
if (cur->type == chan->type) {
return cur;
}
cur = cur->next;
}
return NULL;
}
int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
{
struct ast_frame *f;
struct ast_channel *who, *cs[3];
struct ast_rtp *p0, *p1;
struct ast_rtp_protocol *pr0, *pr1;
void *pvt0, *pvt1;
int to;
/* XXX Wait a half a second for things to settle up
this really should be fixed XXX */
ast_autoservice_start(c0);
ast_autoservice_start(c1);
usleep(500000);
ast_autoservice_stop(c0);
ast_autoservice_stop(c1);
/* if need DTMF, cant native bridge */
if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
return -2;
ast_pthread_mutex_lock(&c0->lock);
ast_pthread_mutex_lock(&c1->lock);
pr0 = get_proto(c0);
pr1 = get_proto(c1);
if (!pr0) {
ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name);
ast_pthread_mutex_unlock(&c0->lock);
ast_pthread_mutex_unlock(&c1->lock);
return -1;
}
if (!pr1) {
ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name);
ast_pthread_mutex_unlock(&c0->lock);
ast_pthread_mutex_unlock(&c1->lock);
return -1;
}
pvt0 = c0->pvt->pvt;
pvt1 = c1->pvt->pvt;
p0 = pr0->get_rtp_info(c0);
p1 = pr1->get_rtp_info(c1);
if (!p0 || !p1) {
/* Somebody doesn't want to play... */
ast_pthread_mutex_unlock(&c0->lock);
ast_pthread_mutex_unlock(&c1->lock);
return -2;
}
if (pr0->set_rtp_peer(c0, p1))
ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
if (pr1->set_rtp_peer(c1, p0))
ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name);
ast_pthread_mutex_unlock(&c0->lock);
ast_pthread_mutex_unlock(&c1->lock);
cs[0] = c0;
cs[1] = c1;
cs[2] = NULL;
for (;;) {
if ((c0->pvt->pvt != pvt0) ||
(c1->pvt->pvt != pvt1) ||
(c0->masq || c0->masqr || c1->masq || c1->masqr)) {
ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
if (c0->pvt->pvt == pvt0) {
if (pr0->set_rtp_peer(c0, NULL))
ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
}
if (c1->pvt->pvt == pvt1) {
if (pr1->set_rtp_peer(c1, NULL))
ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
}
/* Tell it to try again later */
return -3;
}
to = -1;
who = ast_waitfor_n(cs, 2, &to);
if (!who) {
ast_log(LOG_DEBUG, "Ooh, empty read...\n");
continue;
}
f = ast_read(who);
if (!f || ((f->frametype == AST_FRAME_DTMF) &&
(((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
*fo = f;
*rc = who;
ast_log(LOG_DEBUG, "Oooh, got a %s\n", f ? "digit" : "hangup");
if ((c0->pvt->pvt == pvt0) && (!c0->_softhangup)) {
if (pr0->set_rtp_peer(c0, NULL))
ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
}
if ((c1->pvt->pvt == pvt1) && (!c1->_softhangup)) {
if (pr1->set_rtp_peer(c1, NULL))
ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
}
/* That's all we needed */
return 0;
} else
ast_frfree(f);
/* Swap priority not that it's a big deal at this point */
cs[2] = cs[0];
cs[0] = cs[1];
cs[1] = cs[2];
}
return -1;
}

View File

@ -14,6 +14,8 @@
%agent-user.gsm%Agent login. Please enter your agent number followed by the pound key.
%auth-incorrect.gsm%Login incorrect. Please enter your password followed by the pound key.
%beep.gsm%(this is a simple beep tone)
%conf-getconfno.gsm%Please enter your conference number followed by the pound key.

BIN
sounds/auth-incorrect.gsm Executable file

Binary file not shown.