dect
/
asterisk
Archived
13
0
Fork 0

Merge 192.168.0.100:/repos/git/asterisk

This commit is contained in:
Patrick McHardy 2011-06-08 14:20:40 +02:00
commit 84c94e92c1
182 changed files with 14928 additions and 4680 deletions

61
CHANGES
View File

@ -12,9 +12,23 @@
--- Functionality changes from Asterisk 1.8 to Asterisk 1.10 -----------------
------------------------------------------------------------------------------
Text Messaging
--------------
* Asterisk now has protocol independent support for processing text messages
outside of a call. Messages are routed through the Asterisk dialplan.
SIP MESSAGE and XMPP are currently supported. There are options in
jabber.conf and sip.conf to allow enabling these features.
-> jabber.conf: see the "sendtodialplan" and "context" options.
-> sip.conf: see the "accept_outofcall_message" and "auth_message_requests"
options.
The MESSAGE() dialplan function and MessageSend() application have been
added to go along with this functionality. More detailed usage information
can be found on the Asterisk wiki (http://wiki.asterisk.org/).
Parking
-------
* parkedmusicclass can now be set for non-default parking lots.
* ParkedCall application can now specify a specific parkinglot.
Asterisk Manager Interface
--------------------------
@ -23,6 +37,10 @@ Asterisk Manager Interface
for chan_dahdi ISDN channels.
* Added new action MeetmeListRooms to list active conferences (shows same
data as "meetme list" at the CLI).
* DAHDIShowChannels, SIPshowpeer, SIPpeers, and IAXpeers now contains a
Description field that is set by 'description' in the channel configuration
file.
* Added Uniqueid header to UserEvent.
Asterisk HTTP Server
--------------------------
@ -41,6 +59,9 @@ CLI Changes
alternate configuration file to use.
* 'dialplan add extension' command will now automatically create a context if
the specified context does not exist with a message indicated it did so.
* 'sip show peers', 'iax show peers', and 'dahdi show peers' now contains a
Description field which can be populated with 'description' in the channel
configuration files (sip.conf, iax2.conf, and chan_dahdi.conf).
CDR
--------------------------
@ -52,6 +73,13 @@ CODECS
* Ability to define custom SILK formats in codecs.conf.
* Addition of speex32 audio format with translation.
ConfBridge
--------------------------
* New highly optimized and customizable ConfBridge application capable of
mixing audio at sample rates ranging from 8khz-96khz.
* CONFBRIDGE dialplan function capable of creating dynamic ConfBridge user
and bridge profiles on a channel.
Dialplan Variables
------------------
* Added ASTETCDIR, ASTMODDIR, ASTVARLIBDIR, ASTDBDIR, ASTKEYDIR, ASTDATADIR,
@ -60,8 +88,16 @@ Dialplan Variables
Dialplan Functions
------------------
* Addition of the JITTERBUFFER dialplan function. This function allows
for jitterbuffering to occur on the read side of a channel. By using
this function conference applications such as ConfBridge and MeetMe can
have the rx streams jitterbuffered before conference mixing occurs.
* Added DB_KEYS, which lists the next set of keys in the Asterisk database
hierarchy.
* Added STRREPLACE function. This function let's the user search a variable
for a given string to replace with another string as many times as the
user specifies or just throughout the whole string.
* Added option to CHANNEL(pickupgroup) allow reading and setting the pickupgroup of channel.
libpri channel driver (chan_dahdi) DAHDI changes
--------------------------
@ -76,6 +112,8 @@ Calendaring
--------------------------
* Added setvar option to calendar.conf to allow setting channel variables on
notification channels.
* Added "calendar show types" CLI command to list registered calendar
connectors.
MixMonitor
--------------------------
@ -91,6 +129,24 @@ FollowMe
compatability for a FollowMe call with certain dialplan apps, options, and
functions.
CEL
--------------------------
* cel_pgsql now supports the 'extra' column for data added using the
CELGenUserEvent() application.
pbx_lua
--------------------------
* Support for defining hints has been added to pbx_lua. See the 'hints' table
in the sample extensions.lua file for syntax details.
* Applications that perform jumps in the dialplan such as Goto will now
execute properly. When pbx_lua detects that the context, extension, or
priority we are executing on has changed it will immediatly return control
to the asterisk PBX engine. Currently the engine cannot detect a Goto to
the priority after the currently executing priority.
* An autoservice is now started by default for pbx_lua channels. It can be
stopped and restarted using the autoservice_stop() and autoservice_start()
functions.
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 1.6.2 to Asterisk 1.8 ----------------
------------------------------------------------------------------------------
@ -160,6 +216,7 @@ SIP Changes
res_stun_monitor module support in chan_sip.
* Addition of the 'auth_options_requests' option for turning on and off
authentication for OPTIONS requests in chan_sip.
* Add T38 support for REJECTED state where T.38 Negotiation is explicitly rejected.
IAX2 Changes
@ -266,6 +323,8 @@ Applications
* Added 'D' command to ExternalIVR full details in doc/externalivr.txt
* Added 'v' option to MeetMe to play voicemail greetings when a user joins/leaves
a MeetMe conference
* Added ability to include '@parkinglot' to ParkedCall extension in order to specify
a specific parkinglot on which to search the extension.
Dialplan Functions
------------------
@ -521,6 +580,8 @@ Asterisk Manager Interface
* Added a new eventfilter option per user to allow whitelisting and blacklisting
of events.
* Added optional parkinglot variable for park command.
* Added ConnectedLineNum and ConnectedLineName headers to AMI events/responses
if CallerIDNum and CallerIDName headers are also present.
Channel Event Logging
---------------------

View File

@ -222,6 +222,8 @@ ClearIT AB, Sweden - res_mutestream, queue_exists and various other patches (dev
Despegar.com, Argentina - AstData API implementation, also sponsored by Google as part of the
gsoc/2009 program (developed by Eliel)
Philippe Lindheimer - DEV_STATE additions to CCSS
=== OTHER CONTRIBUTIONS ===
John Todd - Monkey sounds and associated teletorture prompt
Michael Jerris - bug marshaling

View File

@ -545,7 +545,6 @@ installdirs:
$(INSTALL) -d "$(DESTDIR)$(ASTLOGDIR)"
$(INSTALL) -d "$(DESTDIR)$(ASTLOGDIR)/cdr-csv"
$(INSTALL) -d "$(DESTDIR)$(ASTLOGDIR)/cdr-custom"
$(INSTALL) -d "$(DESTDIR)$(ASTLOGDIR)/cel-csv"
$(INSTALL) -d "$(DESTDIR)$(ASTLOGDIR)/cel-custom"
$(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)"
$(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/documentation"
@ -925,7 +924,7 @@ menuselect/nmenuselect: menuselect/makeopts
menuselect/makeopts: makeopts
+$(MAKE_MENUSELECT) makeopts
menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure
menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure makeopts
@echo "Generating input for menuselect ..."
@echo "<?xml version=\"1.0\"?>" > $@
@echo >> $@

View File

@ -133,6 +133,14 @@ From 1.6.2 to 1.8:
* The default value for the pedantic option in sip.conf has been changed
from "no" to "yes".
* The ConnectedLineNum and ConnectedLineName headers were added to many AMI
events/responses if the CallerIDNum/CallerIDName headers were also present.
The addition of connected line support changes the behavior of the channel
caller ID somewhat. The channel caller ID value no longer time shares with
the connected line ID on outgoing call legs. The timing of some AMI
events/responses output the connected line ID as caller ID. These party ID's
are now separate.
From 1.6.1 to 1.6.2:
* SIP no longer sends the 183 progress message for early media by

View File

@ -21,6 +21,14 @@
From 1.8 to 1.10:
cel_pgsql:
- This module now expects an 'extra' column in the database for data added
using the CELGenUserEvent() application.
ConfBridge
- ConfBridge's dialplan arguments have changed and are not
backwards compatible.
HTTP:
- A bindaddr must be specified in order for the HTTP server
to run. Previous versions would default to 0.0.0.0 if no
@ -34,5 +42,13 @@ chan_dahdi:
- The mohinterpret=passthrough setting is deprecated in favor of
moh_signaling=notify.
pbx_lua:
- Execution no longer continues after applications that do dialplan jumps
(such as app.goto). Now when an application such as app.goto() is called,
control is returned back to the pbx engine and the current extension
function stops executing.
- the autoservice now defaults to being on by default
- autoservice_start() and autoservice_start() no longer return a value.
===========================================================
===========================================================

View File

@ -546,7 +546,10 @@ static int MYSQL_exec(struct ast_channel *chan, const char *data)
result = 0;
if (autoclear) {
struct ast_datastore *mysql_store = ast_channel_datastore_find(chan, &mysql_ds_info, NULL);
struct ast_datastore *mysql_store = NULL;
ast_channel_lock(chan);
mysql_store = ast_channel_datastore_find(chan, &mysql_ds_info, NULL);
if (!mysql_store) {
if (!(mysql_store = ast_datastore_alloc(&mysql_ds_info, NULL))) {
ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
@ -555,6 +558,7 @@ static int MYSQL_exec(struct ast_channel *chan, const char *data)
ast_channel_datastore_add(chan, mysql_store);
}
}
ast_channel_unlock(chan);
}
ast_mutex_lock(&_mysql_mutex);

View File

@ -325,7 +325,7 @@ db_reconnect:
ast_str_make_space(&escape, (valsz = strlen(value)) * 2 + 1);
mysql_real_escape_string(&mysql, ast_str_buffer(escape), value, valsz);
ast_str_append(&sql1, 0, "%s", entry->name);
ast_str_append(&sql1, 0, "`%s`", entry->name);
ast_str_append(&sql2, 0, "'%s'", ast_str_buffer(escape));
}
}

View File

@ -1185,7 +1185,7 @@ static int mbl_devicestate(void *data)
int res = AST_DEVICE_INVALID;
struct mbl_pvt *pvt;
device = ast_strdupa(S_OR(data, ""));
device = ast_strdupa(S_OR((char *) data, ""));
ast_debug(1, "Checking device state for device %s\n", device);

View File

@ -143,7 +143,7 @@ static struct ooh323_pvt {
int faxmode;
int t38_tx_enable;
int t38_init;
struct sockaddr_in udptlredirip;
struct ast_sockaddr udptlredirip;
time_t lastTxT38;
int chmodepend;
@ -212,7 +212,7 @@ struct ooh323_user{
int t38support;
int rtptimeout;
int mUseIP; /* Use IP address or H323-ID to search user */
char mIP[20];
char mIP[4*8+7+2]; /* Max for IPv6 - 2 brackets, 8 4hex, 7 - : */
struct OOH323Regex *rtpmask;
char rtpmaskstr[120];
int rtdrcount, rtdrinterval;
@ -235,7 +235,7 @@ struct ooh323_peer{
int dtmfcodec;
int t38support;
int mFriend; /* indicates defined as friend */
char ip[20];
char ip[4*8+7+2]; /* Max for IPv6 - 2 brackets, 8 4hex, 7 - : */
int port;
char *h323id; /* H323-ID alias, which asterisk will register with gk to reach this peer*/
char *email; /* Email alias, which asterisk will register with gk to reach this peer*/
@ -286,7 +286,9 @@ void onModeChanged(ooCallData *call, int t38mode);
static char gLogFile[256] = DEFAULT_LOGFILE;
static int gPort = 1720;
static char gIP[20];
static char gIP[2+8*4+7]; /* Max for IPv6 addr */
struct ast_sockaddr bindaddr;
int v6mode = 0;
static char gCallerID[AST_MAX_EXTENSION] = "";
static struct ooAliases *gAliasList;
static struct ast_format_cap *gCap;
@ -373,10 +375,6 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
ast_format_copy(&ch->rawwriteformat, &tmpfmt);
ast_format_copy(&ch->rawreadformat, &tmpfmt);
ast_channel_set_fd(ch, 0, ast_rtp_instance_fd(i->rtp, 0));
ast_channel_set_fd(ch, 1, ast_rtp_instance_fd(i->rtp, 1));
ast_channel_set_fd(ch, 5, ast_udptl_fd(i->udptl));
ast_jb_configure(ch, &global_jbconf);
if (state == AST_STATE_RING)
@ -468,9 +466,7 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
{
struct ooh323_pvt *pvt = NULL;
struct sockaddr_in ouraddr;
struct ast_sockaddr tmp;
struct in_addr ipAddr;
if (gH323Debug)
ast_verbose("--- ooh323_alloc\n");
@ -487,40 +483,6 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
ast_mutex_init(&pvt->lock);
ast_mutex_lock(&pvt->lock);
if (!inet_aton(gIP, &ipAddr)) {
ast_log(LOG_ERROR, "Invalid OOH323 driver ip address\n");
ast_mutex_unlock(&pvt->lock);
ast_mutex_destroy(&pvt->lock);
ast_free(pvt);
return NULL;
}
ouraddr.sin_family = AF_INET;
ouraddr.sin_addr = ipAddr;
ast_sockaddr_from_sin(&tmp, &ouraddr);
if (!(pvt->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
ast_log(LOG_WARNING, "Unable to create RTP session: %s\n",
strerror(errno));
ast_mutex_unlock(&pvt->lock);
ast_mutex_destroy(&pvt->lock);
ast_free(pvt);
return NULL;
}
ast_rtp_instance_set_qos(pvt->rtp, gTOS, 0, "ooh323-rtp");
if (!(pvt->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, &tmp))) {
ast_log(LOG_WARNING, "Unable to create UDPTL session: %s\n",
strerror(errno));
ast_mutex_unlock(&pvt->lock);
ast_mutex_destroy(&pvt->lock);
ast_free(pvt);
return NULL;
}
ast_udptl_set_error_correction_scheme(pvt->udptl, UDPTL_ERROR_CORRECTION_NONE);
ast_udptl_set_far_max_datagram(pvt->udptl, 144);
pvt->faxmode = 0;
pvt->t38support = gT38Support;
pvt->rtptimeout = gRTPTimeout;
@ -1046,13 +1008,13 @@ static int ooh323_hangup(struct ast_channel *ast)
if (gH323Debug)
ast_verbose(" hanging %s with cause: %d\n", p->username, q931cause);
ast->tech_pvt = NULL;
ast->tech_pvt = NULL;
if (!ast_test_flag(p, H323_ALREADYGONE)) {
ooHangCall(p->callToken,
ooHangCall(p->callToken,
ooh323_convert_hangupcause_asteriskToH323(q931cause), q931cause);
ast_set_flag(p, H323_ALREADYGONE);
/* ast_mutex_unlock(&p->lock); */
} else
} else
ast_set_flag(p, H323_NEEDDESTROY);
/* detach channel here */
if (p->owner) {
@ -1068,11 +1030,11 @@ static int ooh323_hangup(struct ast_channel *ast)
/* Notify the module monitors that use count for resource has changed */
ast_update_use_count();
} else {
ast_debug(1, "No call to hangup\n" );
}
if (gH323Debug)
ast_verbose("+++ ooh323_hangup\n");
@ -1082,6 +1044,7 @@ static int ooh323_hangup(struct ast_channel *ast)
static int ooh323_answer(struct ast_channel *ast)
{
struct ooh323_pvt *p = ast->tech_pvt;
char *callToken = (char *)NULL;
if (gH323Debug)
ast_verbose("--- ooh323_answer\n");
@ -1089,10 +1052,21 @@ static int ooh323_answer(struct ast_channel *ast)
if (p) {
ast_mutex_lock(&p->lock);
callToken = (p->callToken ? strdup(p->callToken) : NULL);
if (ast->_state != AST_STATE_UP) {
ast_channel_lock(ast);
if (!p->alertsent) {
if (gH323Debug) {
ast_debug(1, "Sending forced ringback for %s, res = %d\n",
callToken, ooManualRingback(callToken));
} else {
ooManualRingback(callToken);
}
p->alertsent = 1;
}
ast_setstate(ast, AST_STATE_UP);
ast_debug(1, "ooh323_answer(%s)\n", ast->name);
if (option_debug)
ast_debug(1, "ooh323_answer(%s)\n", ast->name);
ast_channel_unlock(ast);
ooAnswerCall(p->callToken);
}
@ -1141,10 +1115,11 @@ static int ooh323_write(struct ast_channel *ast, struct ast_frame *f)
return res;
}
if (f->frametype == AST_FRAME_VOICE) {
/* sending progress for first */
if (!ast_test_flag(p, H323_OUTGOING) && !p->progsent &&
p->callToken) {
p->callToken) {
ooManualProgress(p->callToken);
p->progsent = 1;
}
@ -1209,39 +1184,39 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
if (gH323Debug)
ast_verbose("----- ooh323_indicate %d on call %s\n", condition, callToken);
ast_mutex_lock(&p->lock);
ast_mutex_lock(&p->lock);
switch (condition) {
case AST_CONTROL_CONGESTION:
if (!ast_test_flag(p, H323_ALREADYGONE)) {
ooHangCall(callToken, OO_REASON_LOCAL_CONGESTED,
ooHangCall(callToken, OO_REASON_LOCAL_CONGESTED,
AST_CAUSE_SWITCH_CONGESTION);
ast_set_flag(p, H323_ALREADYGONE);
}
break;
case AST_CONTROL_BUSY:
if (!ast_test_flag(p, H323_ALREADYGONE)) {
ooHangCall(callToken, OO_REASON_LOCAL_BUSY, AST_CAUSE_USER_BUSY);
ooHangCall(callToken, OO_REASON_LOCAL_BUSY, AST_CAUSE_USER_BUSY);
ast_set_flag(p, H323_ALREADYGONE);
}
break;
case AST_CONTROL_HOLD:
ast_moh_start(ast, data, NULL);
ast_moh_start(ast, data, NULL);
break;
case AST_CONTROL_UNHOLD:
ast_moh_stop(ast);
break;
case AST_CONTROL_PROGRESS:
if (ast->_state != AST_STATE_UP) {
if (!p->progsent) {
if (gH323Debug) {
if (!p->progsent) {
if (gH323Debug) {
ast_debug(1, "Sending manual progress for %s, res = %d\n", callToken,
ooManualProgress(callToken));
ooManualProgress(callToken));
} else {
ooManualProgress(callToken);
ooManualProgress(callToken);
}
p->progsent = 1;
}
p->progsent = 1;
}
}
break;
case AST_CONTROL_RINGING:
@ -1256,6 +1231,7 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
}
p->alertsent = 1;
}
p->alertsent = 1;
}
break;
case AST_CONTROL_SRCUPDATE:
@ -1393,8 +1369,8 @@ static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, i
if (gH323Debug)
ast_verbose("+++++ ooh323_queryoption %d on channel %s\n", option, ast->name);
ast_mutex_unlock(&p->lock);
ast_mutex_unlock(&p->lock);
return res;
}
@ -1438,9 +1414,9 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
char formats[FORMAT_STRING_SIZE];
if (gH323Debug)
ast_verbose("--- ooh323_update_writeformat %s/%d\n",
ast_verbose("--- ooh323_update_writeformat %s/%d\n",
ast_getformatname(fmt), txframes);
p = find_call(call);
if (!p) {
ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken);
@ -1453,7 +1429,7 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
if (p->owner) {
while (p->owner && ast_channel_trylock(p->owner)) {
ast_debug(1, "Failed to grab lock, trying again\n");
ast_debug(1,"Failed to grab lock, trying again\n");
DEADLOCK_AVOIDANCE(&p->lock);
}
if (!p->owner) {
@ -1462,7 +1438,7 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
return;
}
if (gH323Debug)
ast_verbose("Writeformat before update %s/%s\n",
ast_verbose("Writeformat before update %s/%s\n",
ast_getformatname(&p->owner->writeformat),
ast_getformatname_multiple(formats, sizeof(formats), p->owner->nativeformats));
if (txframes)
@ -1498,7 +1474,7 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
if (gH323Debug)
ast_verbose("--- ooh323_update_readformat %s\n",
ast_getformatname(fmt));
p = find_call(call);
if (!p) {
ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken);
@ -1511,7 +1487,7 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
if (p->owner) {
while (p->owner && ast_channel_trylock(p->owner)) {
ast_debug(1, "Failed to grab lock, trying again\n");
ast_debug(1,"Failed to grab lock, trying again\n");
DEADLOCK_AVOIDANCE(&p->lock);
}
if (!p->owner) {
@ -1521,12 +1497,12 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
}
if (gH323Debug)
ast_verbose("Readformat before update %s\n",
ast_verbose("Readformat before update %s\n",
ast_getformatname(&p->owner->readformat));
ast_format_cap_set(p->owner->nativeformats, fmt);
ast_set_read_format(p->owner, &p->owner->readformat);
ast_set_read_format(p->owner, &p->owner->readformat);
ast_channel_unlock(p->owner);
} else
} else
ast_log(LOG_ERROR, "No owner found\n");
ast_mutex_unlock(&p->lock);
@ -1544,12 +1520,12 @@ int onAlerting(ooCallData *call)
if (gH323Debug)
ast_verbose("--- onAlerting %s\n", call->callToken);
p = find_call(call);
p = find_call(call);
if(!p) {
if(!p) {
ast_log(LOG_ERROR, "No matching call found\n");
return -1;
}
}
ast_mutex_lock(&p->lock);
if (!p->owner) {
ast_mutex_unlock(&p->lock);
@ -1600,12 +1576,12 @@ int onProgress(ooCallData *call)
if (gH323Debug)
ast_verbose("--- onProgress %s\n", call->callToken);
p = find_call(call);
p = find_call(call);
if(!p) {
if(!p) {
ast_log(LOG_ERROR, "No matching call found\n");
return -1;
}
}
ast_mutex_lock(&p->lock);
if (!p->owner) {
ast_mutex_unlock(&p->lock);
@ -1639,8 +1615,8 @@ int onProgress(ooCallData *call)
ast_setstate(c, AST_STATE_RINGING);
ast_queue_control(c, AST_CONTROL_PROGRESS);
ast_channel_unlock(c);
ast_mutex_unlock(&p->lock);
ast_channel_unlock(c);
ast_mutex_unlock(&p->lock);
if (gH323Debug)
ast_verbose("+++ onProgress %s\n", call->callToken);
@ -1819,10 +1795,14 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
} else {
ast_mutex_unlock(&p->lock);
ast_log(LOG_ERROR, "Unacceptable ip %s\n", call->remoteIP);
if (!user)
if (!user) {
ooHangCall(call->callToken, ooh323_convert_hangupcause_asteriskToH323(AST_CAUSE_CALL_REJECTED), AST_CAUSE_CALL_REJECTED);
else
call->callEndReason = OO_REASON_REMOTE_REJECTED;
}
else {
ooHangCall(call->callToken, ooh323_convert_hangupcause_asteriskToH323(AST_CAUSE_NORMAL_CIRCUIT_CONGESTION), AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
call->callEndReason = OO_REASON_REMOTE_REJECTED;
}
ast_set_flag(p, H323_NEEDDESTROY);
return -1;
}
@ -1830,15 +1810,19 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
ooh323c_set_capability_for_call(call, &p->prefs, p->cap, p->dtmfmode, p->dtmfcodec,
p->t38support, p->g729onlyA);
configure_local_rtp(p, call);
/* Incoming call */
c = ooh323_new(p, AST_STATE_RING, p->username, 0, NULL);
if(!c) {
ast_mutex_unlock(&p->lock);
ast_log(LOG_ERROR, "Could not create ast_channel\n");
return -1;
}
}
if (!configure_local_rtp(p, call)) {
ast_mutex_unlock(&p->lock);
ast_log(LOG_ERROR, "Couldn't create rtp structure\n");
return -1;
}
ast_mutex_unlock(&p->lock);
if (gH323Debug)
@ -1909,6 +1893,11 @@ int onOutgoingCall(ooCallData *call)
ast_copy_string(call->rtpMaskStr, p->rtpmaskstr, sizeof(call->rtpMaskStr));
}
if (!configure_local_rtp(p, call)) {
ast_mutex_unlock(&p->lock);
return OO_FAILED;
}
ast_mutex_unlock(&p->lock);
}
@ -1998,7 +1987,7 @@ int onNewCallCreated(ooCallData *call)
ooh323c_set_capability_for_call(call, &p->prefs, p->cap,
p->dtmfmode, p->dtmfcodec, p->t38support, p->g729onlyA);
configure_local_rtp(p, call);
/* configure_local_rtp(p, call); */
ast_mutex_unlock(&p->lock);
}
@ -2021,14 +2010,14 @@ int onCallEstablished(ooCallData *call)
return -1;
}
if(ast_test_flag(p, H323_OUTGOING)) {
if(ast_test_flag(p, H323_OUTGOING)) {
ast_mutex_lock(&p->lock);
if (!p->owner) {
ast_mutex_unlock(&p->lock);
ast_log(LOG_ERROR, "Channel has no owner\n");
return -1;
}
while (p->owner && ast_channel_trylock(p->owner)) {
ast_debug(1, "Failed to grab lock, trying again\n");
DEADLOCK_AVOIDANCE(&p->lock);
@ -2050,7 +2039,7 @@ int onCallEstablished(ooCallData *call)
}
ast_queue_control(c, AST_CONTROL_ANSWER);
ast_channel_unlock(p->owner);
ast_channel_unlock(p->owner);
manager_event(EVENT_FLAG_SYSTEM,"ChannelUpdate","Channel: %s\r\nChanneltype: %s\r\n"
"CallRef: %d\r\n", c->name, "OOH323", p->call_reference);
}
@ -2075,42 +2064,42 @@ int onCallCleared(ooCallData *call)
if ((p = find_call(call))) {
ast_mutex_lock(&p->lock);
while (p->owner) {
if (ast_channel_trylock(p->owner)) {
ooTrace(OOTRCLVLINFO, "Failed to grab lock, trying again\n");
ast_debug(1, "Failed to grab lock, trying again\n");
ast_debug(1, "Failed to grab lock, trying again\n");
DEADLOCK_AVOIDANCE(&p->lock);
} else {
ownerLock = 1; break;
ownerLock = 1; break;
}
}
if (ownerLock) {
if (!ast_test_flag(p, H323_ALREADYGONE)) {
if (!ast_test_flag(p, H323_ALREADYGONE)) {
ast_set_flag(p, H323_ALREADYGONE);
p->owner->hangupcause = call->q931cause;
p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
ast_queue_hangup_with_cause(p->owner,call->q931cause);
}
}
}
if(p->owner) {
p->owner->tech_pvt = NULL;
if(p->owner) {
p->owner->tech_pvt = NULL;
ast_channel_unlock(p->owner);
p->owner = NULL;
p->owner = NULL;
ast_module_unref(myself);
}
ast_set_flag(p, H323_NEEDDESTROY);
ooh323c_stop_call_thread(call);
ooh323c_stop_call_thread(call);
ast_mutex_unlock(&p->lock);
ast_mutex_lock(&usecnt_lock);
usecnt--;
ast_mutex_unlock(&usecnt_lock);
ast_mutex_lock(&usecnt_lock);
usecnt--;
ast_mutex_unlock(&usecnt_lock);
}
@ -2265,12 +2254,14 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
user->cap, tcodecs, 1);
} else if (!strcasecmp(v->name, "amaflags")) {
user->amaflags = ast_cdr_amaflags2int(v->value);
} else if (!strcasecmp(v->name, "ip")) {
strncpy(user->mIP, v->value, sizeof(user->mIP)-1);
} else if (!strcasecmp(v->name, "ip") || !strcasecmp(v->name, "host")) {
struct ast_sockaddr p;
if (!ast_parse_arg(v->value, PARSE_ADDR, &p)) {
ast_copy_string(user->mIP, ast_sockaddr_stringify_addr(&p), sizeof(user->mIP)-1);
} else {
ast_copy_string(user->mIP, v->value, sizeof(user->mIP)-1);
}
user->mUseIP = 1;
} else if (!strcasecmp(v->name, "host")) {
strncpy(user->mIP, v->value, sizeof(user->mIP)-1);
user->mUseIP = 1;
} else if (!strcasecmp(v->name, "dtmfmode")) {
if (!strcasecmp(v->value, "rfc2833"))
user->dtmfmode = H323_DTMF_RFC2833;
@ -2371,10 +2362,14 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v,
}
} else if (!strcasecmp(v->name, "port")) {
peer->port = atoi(v->value);
} else if (!strcasecmp(v->name, "ip")) {
ast_copy_string(peer->ip, v->value, sizeof(peer->ip));
} else if (!strcasecmp(v->name, "host")) {
ast_copy_string(peer->ip, v->value, sizeof(peer->ip));
} else if (!strcasecmp(v->name, "host") || !strcasecmp(v->name, "ip")) {
struct ast_sockaddr p;
if (!ast_parse_arg(v->value, PARSE_ADDR, &p)) {
ast_copy_string(peer->ip, ast_sockaddr_stringify_host(&p), sizeof(peer->ip));
} else {
ast_copy_string(peer->ip, v->value, sizeof(peer->ip));
}
} else if (!strcasecmp(v->name, "outgoinglimit")) {
peer->outgoinglimit = atoi(v->value);
if (peer->outgoinglimit < 0)
@ -2583,6 +2578,13 @@ int reload_config(int reload)
gPort = (int)strtol(v->value, NULL, 10);
} else if (!strcasecmp(v->name, "bindaddr")) {
ast_copy_string(gIP, v->value, sizeof(gIP));
if (ast_parse_arg(v->value, PARSE_ADDR, &bindaddr)) {
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
return 1;
}
if (ast_sockaddr_is_ipv6(&bindaddr)) {
v6mode = 1;
}
} else if (!strcasecmp(v->name, "h225portrange")) {
char* endlimit = 0;
char temp[512];
@ -2802,7 +2804,7 @@ int reload_config(int reload)
/* Determine ip address if neccessary */
if (ast_strlen_zero(gIP)) {
ooGetLocalIPAddress(gIP);
if (!strcmp(gIP, "127.0.0.1")) {
if (!strcmp(gIP, "127.0.0.1") || !strcmp(gIP, "::1")) {
ast_log(LOG_NOTICE, "Failed to determine local ip address. Please "
"specify it in ooh323.conf. OOH323 Disabled\n");
return 1;
@ -3320,6 +3322,9 @@ static int load_module(void)
ooH323EpSetH225MsgCallbacks(h225Callbacks);
ooH323EpSetTraceLevel(gTRCLVL);
ooH323EpSetLocalAddress(gIP, gPort);
if (v6mode) {
ast_debug(1, "OOH323 channel is in IP6 mode\n");
}
ooH323EpSetCallerID(gCallerID);
if(ooH323EpSetTCPPortRange(ooconfig.mTCPPortStart,
@ -3557,7 +3562,7 @@ int ooh323_destroy(struct ooh323_pvt *p)
free(cur->callerid_name);
cur->callerid_name = 0;
}
if (cur->callerid_num) {
free(cur->callerid_num);
cur->callerid_num = 0;
@ -3572,20 +3577,20 @@ int ooh323_destroy(struct ooh323_pvt *p)
ast_udptl_destroy(cur->udptl);
cur->udptl = NULL;
}
/* Unlink us from the owner if we have one */
if (cur->owner) {
while(ast_channel_trylock(cur->owner)) {
ast_debug(1, "Failed to grab lock, trying again\n");
while(ast_channel_trylock(cur->owner)) {
ast_debug(1, "Failed to grab lock, trying again\n");
DEADLOCK_AVOIDANCE(&cur->lock);
}
}
ast_debug(1, "Detaching from %s\n", cur->owner->name);
cur->owner->tech_pvt = NULL;
ast_channel_unlock(cur->owner);
cur->owner = NULL;
ast_module_unref(myself);
}
if (cur->vad) {
ast_dsp_free(cur->vad);
cur->vad = NULL;
@ -3910,8 +3915,6 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance
{
/* XXX Deal with Video */
struct ooh323_pvt *p;
struct sockaddr_in them;
struct sockaddr_in us;
struct ast_sockaddr tmp;
int mode;
@ -3929,10 +3932,13 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance
return -1;
}
ast_rtp_instance_get_remote_address(rtp, &tmp);
ast_sockaddr_to_sin(&tmp, &them);
ast_rtp_instance_get_local_address(rtp, &tmp);
ast_sockaddr_to_sin(&tmp, &us);
return 0;
/* May 20101003 */
/* What we should to do here? */
}
@ -3940,7 +3946,7 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance
int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
{
struct sockaddr_in us;
char lhost[INET6_ADDRSTRLEN], *lport=NULL;
struct ast_sockaddr tmp;
ooMediaInfo mediaInfo;
int x;
@ -3951,6 +3957,46 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
if (gH323Debug)
ast_verbose("--- configure_local_rtp\n");
if (ast_parse_arg(call->localIP, PARSE_ADDR, &tmp)) {
ast_sockaddr_copy(&tmp, &bindaddr);
}
if (!(p->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
ast_log(LOG_WARNING, "Unable to create RTP session: %s\n",
strerror(errno));
return 0;
}
ast_rtp_instance_set_qos(p->rtp, gTOS, 0, "ooh323-rtp");
if (!(p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, &tmp))) {
ast_log(LOG_WARNING, "Unable to create UDPTL session: %s\n",
strerror(errno));
return 0;
}
ast_udptl_set_far_max_datagram(p->udptl, 144);
if (p->owner) {
while (p->owner && ast_channel_trylock(p->owner)) {
ast_debug(1,"Failed to grab lock, trying again\n");
DEADLOCK_AVOIDANCE(&p->lock);
}
if (!p->owner) {
ast_mutex_unlock(&p->lock);
ast_log(LOG_ERROR, "Channel has no owner\n");
return 0;
}
} else {
ast_log(LOG_ERROR, "Channel has no owner\n");
return 0;
}
ast_channel_set_fd(p->owner, 0, ast_rtp_instance_fd(p->rtp, 0));
ast_channel_set_fd(p->owner, 1, ast_rtp_instance_fd(p->rtp, 1));
ast_channel_set_fd(p->owner, 5, ast_udptl_fd(p->udptl));
ast_channel_unlock(p->owner);
if (p->rtp) {
ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs);
if (p->dtmfmode & H323_DTMF_RFC2833 && p->dtmfcodec) {
@ -3965,7 +4011,8 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
}
/* figure out our local RTP port and tell the H.323 stack about it*/
ast_rtp_instance_get_local_address(p->rtp, &tmp);
ast_sockaddr_to_sin(&tmp, &us);
strncpy(lhost, ast_sockaddr_stringify_addr(&tmp), sizeof(lhost));
lport = ast_sockaddr_stringify_port(&tmp);
if (p->rtptimeout) {
ast_rtp_instance_set_timeout(p->rtp, p->rtptimeout);
@ -3982,8 +4029,8 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
}
ast_copy_string(mediaInfo.lMediaIP, ast_inet_ntoa(us.sin_addr), sizeof(mediaInfo.lMediaIP));
mediaInfo.lMediaPort = ntohs(us.sin_port);
ast_copy_string(mediaInfo.lMediaIP, lhost, sizeof(mediaInfo.lMediaIP));
mediaInfo.lMediaPort = atoi(lport);
mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort +1;
for (x = 0; ast_codec_pref_index(&p->prefs, x, &tmpfmt); x++) {
strcpy(mediaInfo.dir, "transmit");
@ -4007,19 +4054,18 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
}
if (p->udptl) {
struct ast_sockaddr us_tmp;
ast_sockaddr_from_sin(&us_tmp, &us);
ast_udptl_get_us(p->udptl, &us_tmp);
ast_sockaddr_to_sin(&us_tmp, &us);
ast_udptl_get_us(p->udptl, &tmp);
strncpy(lhost, ast_sockaddr_stringify_addr(&tmp), sizeof(lhost));
lport = ast_sockaddr_stringify_port(&tmp);
ast_copy_string(mediaInfo.lMediaIP, lhost, sizeof(mediaInfo.lMediaIP));
mediaInfo.lMediaPort = atoi(lport);
mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort +1;
mediaInfo.cap = OO_T38;
strcpy(mediaInfo.dir, "transmit");
ooAddMediaInfo(call, mediaInfo);
strcpy(mediaInfo.dir, "receive");
ooAddMediaInfo(call, mediaInfo);
}
ast_copy_string(mediaInfo.lMediaIP, ast_inet_ntoa(us.sin_addr), sizeof(mediaInfo.lMediaIP));
mediaInfo.lMediaPort = ntohs(us.sin_port);
mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort +1;
mediaInfo.cap = OO_T38;
strcpy(mediaInfo.dir, "transmit");
ooAddMediaInfo(call, mediaInfo);
strcpy(mediaInfo.dir, "receive");
ooAddMediaInfo(call, mediaInfo);
if (gH323Debug)
ast_verbose("+++ configure_local_rtp\n");
@ -4031,7 +4077,6 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp,
int remotePort)
{
struct ooh323_pvt *p = NULL;
struct sockaddr_in them;
struct ast_sockaddr tmp;
if (gH323Debug)
@ -4045,10 +4090,8 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp,
return;
}
them.sin_family = AF_INET;
them.sin_addr.s_addr = inet_addr(remoteIp); /* only works for IPv4 */
them.sin_port = htons(remotePort);
ast_sockaddr_from_sin(&tmp, &them);
ast_parse_arg(remoteIp, PARSE_ADDR, &tmp);
ast_sockaddr_set_port(&tmp, remotePort);
ast_rtp_instance_set_remote_address(p->rtp, &tmp);
if (p->writeformat.id == AST_FORMAT_G726_AAL2)
@ -4114,10 +4157,9 @@ static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udp
if (!p)
return -1;
ast_mutex_lock(&p->lock);
if (udptl) {
struct ast_sockaddr udptl_addr;
ast_udptl_get_peer(udptl, &udptl_addr);
ast_sockaddr_to_sin(&udptl_addr, &p->udptlredirip);
ast_udptl_get_peer(udptl, &p->udptlredirip);
} else
memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
@ -4130,14 +4172,13 @@ void setup_udptl_connection(ooCallData *call, const char *remoteIp,
int remotePort)
{
struct ooh323_pvt *p = NULL;
struct sockaddr_in them;
struct ast_sockaddr them_addr;
struct ast_sockaddr them;
if (gH323Debug)
ast_verbose("--- setup_udptl_connection\n");
/* Find the call or allocate a private structure if call not found */
p = find_call(call);
p = find_call(call);
if (!p) {
ast_log(LOG_ERROR, "Something is wrong: rtp\n");
@ -4161,11 +4202,10 @@ void setup_udptl_connection(ooCallData *call, const char *remoteIp,
return;
}
them.sin_family = AF_INET;
them.sin_addr.s_addr = inet_addr(remoteIp); /* only works for IPv4 */
them.sin_port = htons(remotePort);
ast_sockaddr_from_sin(&them_addr, &them);
ast_udptl_set_peer(p->udptl, &them_addr);
ast_parse_arg(remoteIp, PARSE_ADDR, &them);
ast_sockaddr_set_port(&them, remotePort);
ast_udptl_set_peer(p->udptl, &them);
ast_udptl_set_tag(p->udptl, "%s", p->owner->name);
p->t38_tx_enable = 1;
p->lastTxT38 = time(NULL);
@ -4177,8 +4217,8 @@ void setup_udptl_connection(ooCallData *call, const char *remoteIp,
ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
}
if (gH323Debug)
ast_debug(1, "Receiving UDPTL %s:%d\n", ast_inet_ntoa(them.sin_addr),
ntohs(them.sin_port));
ast_debug(1, "Receiving UDPTL %s:%s\n", ast_sockaddr_stringify_host(&them),
ast_sockaddr_stringify_port(&them));
ast_channel_unlock(p->owner);
ast_mutex_unlock(&p->lock);
@ -4193,12 +4233,12 @@ void close_udptl_connection(ooCallData *call)
{
struct ooh323_pvt *p = NULL;
if(gH323Debug)
if(gH323Debug)
ast_verbose("--- close_udptl_connection\n");
p = find_call(call);
if (!p) {
ast_log(LOG_ERROR, "Couldn't find matching call to close udptl "
ast_log(LOG_ERROR, "Couldn't find matching call to close udptl "
"connection\n");
return;
}
@ -4287,7 +4327,7 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
case 5:
f = ast_udptl_read(p->udptl); /* UDPTL t.38 data */
if (gH323Debug) {
ast_debug(1, "Got UDPTL %d/%d len %d for %s\n",
ast_debug(1, "Got UDPTL %d/%d len %d for %s\n",
f->frametype, f->subclass.integer, f->datalen, ast->name);
}
break;
@ -4300,7 +4340,7 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
/* We already hold the channel lock */
if (f->frametype == AST_FRAME_VOICE && !p->faxmode) {
if (!(ast_format_cap_iscompatible(p->owner->nativeformats, &f->subclass.format))) {
ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(&f->subclass.format));
ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(&f->subclass.format));
ast_format_cap_set(p->owner->nativeformats, &f->subclass.format);
ast_set_read_format(p->owner, &p->owner->readformat);
ast_set_write_format(p->owner, &p->owner->writeformat);
@ -4310,8 +4350,8 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
(f->subclass.format.id == AST_FORMAT_SLINEAR || f->subclass.format.id == AST_FORMAT_ALAW ||
f->subclass.format.id == AST_FORMAT_ULAW)) {
f = ast_dsp_process(p->owner, p->vad, f);
if (f && (f->frametype == AST_FRAME_DTMF)) {
ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.integer);
if (f && (f->frametype == AST_FRAME_DTMF)) {
ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.integer);
}
}
}
@ -4330,15 +4370,13 @@ void onModeChanged(ooCallData *call, int t38mode) {
ast_mutex_lock(&p->lock);
if (gH323Debug) {
ast_debug(1, "change mode to %d for %s\n", t38mode, call->callToken);
}
if (gH323Debug)
ast_debug(1, "change mode to %d for %s\n", t38mode, call->callToken);
if (t38mode == p->faxmode) {
if (gH323Debug) {
if (gH323Debug)
ast_debug(1, "mode for %s is already %d\n", call->callToken,
t38mode);
}
ast_mutex_unlock(&p->lock);
return;
}

View File

@ -97,7 +97,7 @@ typedef struct OOMediaInfo{
int cap;
int lMediaPort;
int lMediaCntrlPort;
char lMediaIP[20];
char lMediaIP[2+8*4+7];
struct OOMediaInfo *next;
} OOMediaInfo;
@ -179,12 +179,13 @@ typedef struct OOH323CallData {
int dtmfcodec;
OOMediaInfo *mediaInfo;
OOCallFwdData *pCallFwdData;
char localIP[20];/* Local IP address */
char localIP[2+8*4+7];/* Local IP address */
int versionIP; /* IP Address family 6 or 4 */
OOH323Channel* pH225Channel;
OOH323Channel* pH245Channel;
OOSOCKET *h245listener;
int *h245listenport;
char remoteIP[20];/* Remote IP address */
char remoteIP[2+8*4+7];/* Remote IP address */
int remotePort;
int remoteH245Port;
char *remoteDisplayName;

View File

@ -22,6 +22,7 @@
*/
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/netsock2.h"
#include "ooGkClient.h"
#include "ootypes.h"
@ -261,7 +262,7 @@ int ooGkClientCreateChannel(ooGkClient *pGkClient)
int ret=0;
OOIPADDR ipaddrs;
/* Create socket */
if((ret=ooSocketCreateUDP(&pGkClient->rasSocket))!=ASN_OK)
if((ret=ooSocketCreateUDP(&pGkClient->rasSocket, 4))!=ASN_OK)
{
OOTRACEERR1("Failed to create RAS socket\n");
pGkClient->state = GkClientFailed;
@ -269,7 +270,7 @@ int ooGkClientCreateChannel(ooGkClient *pGkClient)
}
if(pGkClient->localRASPort)
{
ret= ooSocketStrToAddr (pGkClient->localRASIP, &ipaddrs);
inet_pton(AF_INET, pGkClient->localRASIP, &ipaddrs);
if( (ret=ooSocketBind( pGkClient->rasSocket, ipaddrs,
pGkClient->localRASPort))!=ASN_OK )
{
@ -295,7 +296,7 @@ int ooGkClientCreateChannel(ooGkClient *pGkClient)
OOTRACEDBGA1("Determining ip address for RAS channel "
"multihomed mode. \n");
ret = ooSocketGetIpAndPort(pGkClient->rasSocket, pGkClient->localRASIP,
20, &pGkClient->localRASPort);
20, &pGkClient->localRASPort, NULL);
if(ret != ASN_OK)
{
OOTRACEERR1("Error:Failed to retrieve local ip and port from "
@ -666,7 +667,7 @@ int ooGkClientSendGRQ(ooGkClient *pGkClient)
}
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pRasAddress->ip.data);
inet_pton(AF_INET, pGkClient->localRASIP, pRasAddress->ip.data);
pRasAddress->ip.numocts = 4;
pRasAddress->port = pGkClient->localRASPort;
@ -932,7 +933,7 @@ int ooGkClientSendRRQ(ooGkClient *pGkClient, ASN1BOOL keepAlive)
}
pTransportAddress->t = T_H225TransportAddress_ipAddress;
pTransportAddress->u.ipAddress = pIpAddress;
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpAddress->ip.data);
inet_pton(AF_INET, pGkClient->localRASIP, pIpAddress->ip.data);
pIpAddress->ip.numocts = 4;
pIpAddress->port = gH323ep.listenPort;
@ -960,7 +961,7 @@ int ooGkClientSendRRQ(ooGkClient *pGkClient, ASN1BOOL keepAlive)
pTransportAddress->t = T_H225TransportAddress_ipAddress;
pTransportAddress->u.ipAddress = pIpAddress;
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpAddress->ip.data);
inet_pton(AF_INET, pGkClient->localRASIP, pIpAddress->ip.data);
pIpAddress->ip.numocts = 4;
pIpAddress->port = pGkClient->localRASPort;
@ -1430,7 +1431,7 @@ int ooGkClientSendURQ(ooGkClient *pGkClient, ooAliases *aliases)
}
pTransportAddress->t = T_H225TransportAddress_ipAddress;
pTransportAddress->u.ipAddress = pIpAddress;
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpAddress->ip.data);
inet_pton(AF_INET, pGkClient->localRASIP, pIpAddress->ip.data);
pIpAddress->ip.numocts = 4;
pIpAddress->port = gH323ep.listenPort;
@ -1645,14 +1646,14 @@ int ooGkClientSendAdmissionRequest
ast_mutex_unlock(&pGkClient->Lock);
return OO_FAILED;
}
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpAddressLocal->ip.data);
inet_pton(AF_INET, pGkClient->localRASIP, pIpAddressLocal->ip.data);
pIpAddressLocal->ip.numocts = 4;
pIpAddressLocal->port = gH323ep.listenPort;
if(!ooUtilsIsStrEmpty(call->remoteIP))
{
ooSocketConvertIpToNwAddr(call->remoteIP, pIpAddressRemote->ip.data);
inet_pton(AF_INET, call->remoteIP, pIpAddressRemote->ip.data);
pIpAddressRemote->ip.numocts = 4;
pIpAddressRemote->port = call->remotePort;
}
@ -2153,7 +2154,7 @@ int ooGkClientSendIRR
ast_mutex_unlock(&pGkClient->Lock);
return OO_FAILED;
}
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpAddressLocal->ip.data);
inet_pton(AF_INET, pGkClient->localRASIP, pIpAddressLocal->ip.data);
pIpAddressLocal->ip.numocts = 4;
pIpAddressLocal->port = gH323ep.listenPort;
@ -2184,7 +2185,7 @@ int ooGkClientSendIRR
pIpRasAddress->ip.numocts = 4;
pIpRasAddress->port = pGkClient->localRASPort;
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpRasAddress->ip.data);
inet_pton(AF_INET, pGkClient->localRASIP, pIpRasAddress->ip.data);
pIRR->rasAddress.u.ipAddress = pIpRasAddress;
pIRR->rasAddress.t=T_H225TransportAddress_ipAddress; /* IPv4 address */
@ -2283,11 +2284,11 @@ int ooGkClientSendIRR
return OO_FAILED;
}
pLocalAddr->ip.numocts = 4;
ooSocketConvertIpToNwAddr(call->localIP, pLocalAddr->ip.data);
inet_pton(AF_INET, call->localIP, pLocalAddr->ip.data);
pLocalAddr->port = (call->pH225Channel->port) ? call->pH225Channel->port : gH323ep.listenPort;
pRemoteAddr->ip.numocts = 4;
ooSocketConvertIpToNwAddr(call->remoteIP, pRemoteAddr->ip.data);
inet_pton(AF_INET, call->remoteIP, pRemoteAddr->ip.data);
pRemoteAddr->port = call->remotePort;
perCallInfo->callSignaling.m.sendAddressPresent = TRUE;

View File

@ -47,7 +47,7 @@ extern "C" {
#define MAX_IP_LEN 18
#define MAX_IP_LEN 2+8*4+7
#define DEFAULT_GKPORT 1719
#define MULTICAST_GKADDRESS "224.0.1.41"
#define MULTICAST_GKPORT 1718
@ -181,9 +181,9 @@ typedef struct ooGkClient{
OOCTXT msgCtxt;
OOSOCKET rasSocket;
int localRASPort;
char localRASIP[20];
char gkRasIP[20];
char gkCallSignallingIP[20];
char localRASIP[2+8*4+7];
char gkRasIP[2+8*4+7];
char gkCallSignallingIP[2+8*4+7];
RasGatekeeperInfo gkInfo;
int gkRasPort;
int gkCallSignallingPort;

View File

@ -82,7 +82,7 @@ OOLogicalChannel* ooAddNewLogicalChannel(OOH323CallData *call, int channelNo,
/* If user application has not specified a specific ip and is using
multihomed mode, substitute appropriate ip.
*/
if(!strcmp(pMediaInfo->lMediaIP, "0.0.0.0"))
if(!strcmp(pMediaInfo->lMediaIP, "0.0.0.0") || !strcmp(pMediaInfo->lMediaIP, "::"))
strcpy(pNewChannel->localIP, call->localIP);
else
strcpy(pNewChannel->localIP, pMediaInfo->lMediaIP);

View File

@ -53,12 +53,12 @@ typedef struct OOLogicalChannel {
int sessionID;
enum OOCapType type;
char dir[10]; /* receive/transmit */
char remoteIP[20];
char remoteIP[2+8*4+7];
int remoteMediaPort;
int remoteMediaControlPort;
int localRtpPort;
int localRtcpPort;
char localIP[20];
char localIP[2+8*4+7];
OOLogicalChannelState state;
struct ooH323EpCapability *chanCap;
struct OOLogicalChannel *next;

View File

@ -21,9 +21,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/network.h"
#include "asterisk/netsock2.h"
#include "asterisk/config.h"
#include "ooSocket.h"
#include "ootrace.h"
#include "ooh323ep.h"
/** Global endpoint structure */
extern OOH323EndPoint gH323ep;
#if defined(_WIN32_WCE)
static int inited = 0;
#define SEND_FLAGS 0
@ -188,17 +195,25 @@ typedef int OOSOCKLEN;
typedef socklen_t OOSOCKLEN;
#endif
int ooSocketCreate (OOSOCKET* psocket)
int ooSocketCreate (OOSOCKET* psocket, int family)
{
int on;
OOSOCKET sock;
int keepalive = 1;
#ifdef __linux__
int keepcnt = 24, keepidle = 120, keepintvl = 30;
#endif
struct linger linger;
OOSOCKET sock = socket (AF_INET,
SOCK_STREAM,
0);
if (family == 6) {
sock = socket (AF_INET6,
SOCK_STREAM,
0);
} else {
sock = socket (AF_INET,
SOCK_STREAM,
0);
}
if (sock == OOSOCKET_INVALID){
OOTRACEERR1("Error:Failed to create TCP socket\n");
@ -231,12 +246,18 @@ int ooSocketCreate (OOSOCKET* psocket)
return ASN_OK;
}
int ooSocketCreateUDP (OOSOCKET* psocket)
int ooSocketCreateUDP (OOSOCKET* psocket, int family)
{
int on;
struct linger linger;
OOSOCKET sock;
OOSOCKET sock = socket (AF_INET,
if (family == 6)
sock = socket (AF_INET6,
SOCK_DGRAM,
0);
else
sock = socket (AF_INET,
SOCK_DGRAM,
0);
@ -272,7 +293,10 @@ int ooSocketClose (OOSOCKET socket)
int ooSocketBind (OOSOCKET socket, OOIPADDR addr, int port)
{
struct sockaddr_in m_addr;
struct ast_sockaddr m_addr;
memset(&m_addr, 0, sizeof(m_addr));
if (socket == OOSOCKET_INVALID)
{
@ -280,14 +304,10 @@ int ooSocketBind (OOSOCKET socket, OOIPADDR addr, int port)
return ASN_E_INVSOCKET;
}
memset (&m_addr, 0, sizeof (m_addr));
m_addr.sin_family = AF_INET;
m_addr.sin_addr.s_addr = (addr == 0) ? INADDR_ANY : htonl (addr);
m_addr.sin_port = htons ((unsigned short)port);
ast_sockaddr_copy(&m_addr, &addr);
ast_sockaddr_set_port(&m_addr, port);
if (bind (socket, (struct sockaddr *) (void*) &m_addr,
sizeof (m_addr)) == -1)
{
if (ast_bind(socket, &m_addr) < 0) {
if (errno != EADDRINUSE) {
perror ("bind");
OOTRACEERR2("Error:Bind failed, error: %d\n", errno);
@ -311,20 +331,17 @@ int ooSocketGetSockName(OOSOCKET socket, struct sockaddr_in *name, socklen_t *si
}
}
int ooSocketGetIpAndPort(OOSOCKET socket, char *ip, int len, int *port)
int ooSocketGetIpAndPort(OOSOCKET socket, char *ip, int len, int *port, int *family)
{
int ret=ASN_OK;
socklen_t size;
struct sockaddr_in addr;
struct ast_sockaddr addr;
const char *host=NULL;
size = sizeof(addr);
ret = ooSocketGetSockName(socket, &addr, &size);
ret = ast_getsockname(socket, &addr);
if(ret != 0)
return ASN_E_INVSOCKET;
host = ast_inet_ntoa(addr.sin_addr);
host = ast_sockaddr_stringify_addr(&addr);
if(host && strlen(host) < (unsigned)len)
strcpy(ip, host);
@ -333,8 +350,14 @@ int ooSocketGetIpAndPort(OOSOCKET socket, char *ip, int len, int *port)
"ooSocketGetIpAndPort\n");
return -1;
}
*port = addr.sin_port;
*port = ast_sockaddr_port(&addr);
if (family) {
if (ast_sockaddr_is_ipv6(&addr) && !ast_sockaddr_is_ipv4_mapped(&addr))
*family = 6;
else
*family = 4;
}
return ASN_OK;
}
@ -350,29 +373,30 @@ int ooSocketListen (OOSOCKET socket, int maxConnection)
}
int ooSocketAccept (OOSOCKET socket, OOSOCKET *pNewSocket,
OOIPADDR* destAddr, int* destPort)
char* destAddr, int* destPort)
{
struct sockaddr_in m_addr;
OOSOCKLEN addr_length = sizeof (m_addr);
struct ast_sockaddr addr;
char* host = NULL;
if (socket == OOSOCKET_INVALID) return ASN_E_INVSOCKET;
if (pNewSocket == 0) return ASN_E_INVPARAM;
*pNewSocket = accept (socket, (struct sockaddr *) (void*) &m_addr,
&addr_length);
*pNewSocket = ast_accept (socket, &addr);
if (*pNewSocket <= 0) return ASN_E_INVSOCKET;
if (destAddr != 0)
*destAddr = ntohl (m_addr.sin_addr.s_addr);
if (destAddr != 0) {
if ((host = ast_sockaddr_stringify_addr(&addr)) != NULL);
strncpy(destAddr, host, strlen(host));
}
if (destPort != 0)
*destPort = ntohs (m_addr.sin_port);
*destPort = ast_sockaddr_port(&addr);
return ASN_OK;
}
int ooSocketConnect (OOSOCKET socket, const char* host, int port)
{
struct sockaddr_in m_addr;
struct ast_sockaddr m_addr;
if (socket == OOSOCKET_INVALID)
{
@ -380,13 +404,10 @@ int ooSocketConnect (OOSOCKET socket, const char* host, int port)
}
memset (&m_addr, 0, sizeof (m_addr));
ast_parse_arg(host, PARSE_ADDR, &m_addr);
ast_sockaddr_set_port(&m_addr, port);
m_addr.sin_family = AF_INET;
m_addr.sin_port = htons ((unsigned short)port);
m_addr.sin_addr.s_addr = inet_addr (host);
if (connect (socket, (struct sockaddr *) (void*) &m_addr,
sizeof (struct sockaddr_in)) == -1)
if (ast_connect(socket, &m_addr))
{
return ASN_E_INVSOCKET;
}
@ -522,10 +543,18 @@ int ooGetLocalIPAddress(char * pIPAddrs)
ret = gethostname(hostname, 100);
if(ret == 0)
{
if (!(hp = ast_gethostbyname(hostname, &phost))) {
struct in_addr i;
memcpy(&i, hp->h_addr, sizeof(i));
strcpy(pIPAddrs, (ast_inet_ntoa(i) == NULL) ? "127.0.0.1" : ast_inet_ntoa(i));
if ((hp = ast_gethostbyname(hostname, &phost))) {
if (hp->h_addrtype == AF_INET6) {
struct in6_addr i;
memcpy(&i, hp->h_addr, sizeof(i));
strcpy(pIPAddrs, (inet_ntop(AF_INET6, &i,
hostname, sizeof(hostname))) == NULL ? "::1" :
inet_ntop(AF_INET6, &i, hostname, sizeof(hostname)));
} else {
struct in_addr i;
memcpy(&i, hp->h_addr, sizeof(i));
strcpy(pIPAddrs, (ast_inet_ntoa(i) == NULL) ? "127.0.0.1" : ast_inet_ntoa(i));
}
} else {
return -1;
}
@ -536,7 +565,7 @@ int ooGetLocalIPAddress(char * pIPAddrs)
return ASN_OK;
}
int ooSocketStrToAddr (const char* pIPAddrStr, OOIPADDR* pIPAddr)
/* int ooSocketStrToAddr (const char* pIPAddrStr, OOIPADDR* pIPAddr)
{
int b1, b2, b3, b4;
int rv = sscanf (pIPAddrStr, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
@ -589,7 +618,7 @@ int ooSocketAddrToStr (OOIPADDR ipAddr, char* pbuf, int bufsize)
return ASN_E_BUFOVFLW;
sprintf (pbuf, "%s.%s.%s.%s", buf1, buf2, buf3, buf4);
return ASN_OK;
}
} */
int ooSocketsCleanup (void)
{
@ -623,7 +652,7 @@ int ooSocketGetInterfaceList(OOCTXT *pctxt, OOInterface **ifList)
struct sockaddr_in sin;
OOTRACEDBGA1("Retrieving local interfaces\n");
if(ooSocketCreateUDP(&sock)!= ASN_OK)
if(ooSocketCreateUDP(&sock, 4)!= ASN_OK)
{
OOTRACEERR1("Error:Failed to create udp socket - "
"ooSocketGetInterfaceList\n");

View File

@ -81,7 +81,8 @@ typedef int OOSOCKET; /**< Socket's handle */
* address. The least significant 8 bits represent the last number of the IP
* address.
*/
typedef unsigned long OOIPADDR;
/* typedef unsigned long OOIPADDR; */
typedef struct ast_sockaddr OOIPADDR;
#define OOIPADDR_ANY ((OOIPADDR)0)
#define OOIPADDR_LOCAL ((OOIPADDR)0x7f000001UL) /* 127.0.0.1 */
@ -115,7 +116,7 @@ typedef struct OOInterface{
* negative return value is error.
*/
EXTERN int ooSocketAccept (OOSOCKET socket, OOSOCKET *pNewSocket,
OOIPADDR* destAddr, int* destPort);
char* destAddr, int* destPort);
/**
* This function converts an IP address to its string representation.
@ -177,10 +178,11 @@ EXTERN int ooSocketConnect (OOSOCKET socket, const char* host, int port);
*
* @param psocket The pointer to the socket's handle variable to receive
* the handle of new socket.
* @param family Which family socket will created
* @return Completion status of operation: 0 (ASN_OK) = success,
* negative return value is error.
*/
EXTERN int ooSocketCreate (OOSOCKET* psocket);
EXTERN int ooSocketCreate (OOSOCKET* psocket, int family);
/**
* This function creates a UDP datagram socket.
@ -190,7 +192,7 @@ EXTERN int ooSocketCreate (OOSOCKET* psocket);
* @return Completion status of operation: 0 (ASN_OK) = success,
* negative return value is error.
*/
EXTERN int ooSocketCreateUDP (OOSOCKET* psocket);
EXTERN int ooSocketCreateUDP (OOSOCKET* psocket, int family);
/**
* This function initiates use of sockets by an application. This function must
@ -351,7 +353,7 @@ EXTERN int ooPDWrite(struct pollfd *pfds, int nfds, int fd);
* @return Completion status of operation: 0 (ASN_OK) = success,
* negative return value is error.
*/
EXTERN int ooSocketStrToAddr (const char* pIPAddrStr, OOIPADDR* pIPAddr);
/* EXTERN int ooSocketStrToAddr (const char* pIPAddrStr, OOIPADDR* pIPAddr); */
/**
* This function converts an internet dotted ip address to network address
@ -364,7 +366,7 @@ EXTERN int ooSocketStrToAddr (const char* pIPAddrStr, OOIPADDR* pIPAddr);
* @return Completion status of operation: 0 (ASN_OK) = success,
* negative return value is error.
*/
EXTERN int ooSocketConvertIpToNwAddr(char *inetIp, unsigned char *netIp);
/* EXTERN int ooSocketConvertIpToNwAddr(char *inetIp, unsigned char *netIp); */
/**
* This function retrives the IP address of the local host.
@ -393,10 +395,11 @@ EXTERN short ooSocketHTONS(short val);
* @param ip Buffer in which ip address will be returned.
* @param len Length of the ip address buffer.
* @param port Pointer to integer in which port number will be returned.
* @param family Pointer to integer in which IP family (4 or 6) will be returned
*
* @return ASN_OK, on success; -ve on failed.
*/
EXTERN int ooSocketGetIpAndPort(OOSOCKET socket, char *ip, int len, int *port);
EXTERN int ooSocketGetIpAndPort(OOSOCKET socket, char *ip, int len, int *port, int *family);
EXTERN int ooSocketGetInterfaceList(OOCTXT *pctxt, OOInterface **ifList);

View File

@ -16,6 +16,8 @@
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/poll-compat.h"
#include "asterisk/config.h"
#include "asterisk/netsock2.h"
#include "ooports.h"
#include "oochannels.h"
@ -31,6 +33,7 @@
#include "ooh323ep.h"
#include "ooStackCmds.h"
#include "ooCmdChannel.h"
#include "ooSocket.h"
#include "ootypes.h"
@ -60,7 +63,7 @@ int ooCreateH245Listener(OOH323CallData *call)
int ret=0;
OOSOCKET channelSocket=0;
OOTRACEINFO1("Creating H245 listener\n");
if((ret=ooSocketCreate (&channelSocket))!=ASN_OK)
if((ret=ooSocketCreate (&channelSocket, call->versionIP))!=ASN_OK)
{
OOTRACEERR3("ERROR: Failed to create socket for H245 listener "
"(%s, %s)\n", call->callType, call->callToken);
@ -97,7 +100,7 @@ int ooCreateH245Connection(OOH323CallData *call)
ooTimerCallback *cbData=NULL;
OOTRACEINFO1("Creating H245 Connection\n");
if((ret=ooSocketCreate (&channelSocket))!=ASN_OK)
if((ret=ooSocketCreate (&channelSocket, call->versionIP))!=ASN_OK)
{
OOTRACEERR3("ERROR:Failed to create socket for H245 connection "
"(%s, %s)\n", call->callType, call->callToken);
@ -241,7 +244,7 @@ int ooCreateH225Connection(OOH323CallData *call)
int ret=0, i;
OOSOCKET channelSocket=0;
for (i=0;i<3;i++) {
if((ret=ooSocketCreate (&channelSocket))!=ASN_OK)
if((ret=ooSocketCreate (&channelSocket, call->versionIP))!=ASN_OK)
{
OOTRACEERR3("Failed to create socket for transmit H2250 channel (%s, %s)"
"\n", call->callType, call->callToken);
@ -285,9 +288,9 @@ int ooCreateH225Connection(OOH323CallData *call)
}
call->pH225Channel->port = ret;
OOTRACEINFO5("Trying to connect to remote endpoint(%s:%d) to setup "
OOTRACEINFO6("Trying to connect to remote endpoint(%s:%d) (IPv%d) to setup "
"H2250 channel (%s, %s)\n", call->remoteIP,
call->remotePort, call->callType, call->callToken);
call->remotePort, call->versionIP, call->callType, call->callToken);
if((ret=ooSocketConnect(channelSocket, call->remoteIP,
call->remotePort))==ASN_OK)
@ -298,13 +301,13 @@ int ooCreateH225Connection(OOH323CallData *call)
"(%s, %s)\n", call->callType, call->callToken);
/* If multihomed, get ip from socket */
if(!strcmp(call->localIP, "0.0.0.0"))
if(!strcmp(call->localIP, "0.0.0.0") || !strcmp(call->localIP, "::"))
{
OOTRACEDBGA3("Determining IP address for outgoing call in "
"multihomed mode. (%s, %s)\n", call->callType,
call->callToken);
ret = ooSocketGetIpAndPort(channelSocket, call->localIP, 20,
&call->pH225Channel->port);
ret = ooSocketGetIpAndPort(channelSocket, call->localIP, 2+8*4+7,
&call->pH225Channel->port, NULL);
if(ret != ASN_OK)
{
OOTRACEERR3("ERROR:Failed to retrieve local ip and port from "
@ -367,12 +370,13 @@ int ooCreateH323Listener()
OOIPADDR ipaddrs;
/* Create socket */
if((ret=ooSocketCreate (&channelSocket))!=ASN_OK)
ret = ast_parse_arg(gH323ep.signallingIP, PARSE_ADDR, &ipaddrs);
if((ret=ooSocketCreate (&channelSocket, ast_sockaddr_is_ipv6(&ipaddrs) ? 6 : 4))
!=ASN_OK)
{
OOTRACEERR1("Failed to create socket for H323 Listener\n");
return OO_FAILED;
}
ret= ooSocketStrToAddr (gH323ep.signallingIP, &ipaddrs);
if((ret=ooSocketBind (channelSocket, ipaddrs,
gH323ep.listenPort))==ASN_OK)
{
@ -397,9 +401,12 @@ int ooAcceptH225Connection()
OOH323CallData * call;
int ret;
char callToken[20];
char remoteIP[2+8*4+7];
OOSOCKET h225Channel=0;
memset(remoteIP, 0, sizeof(remoteIP));
ret = ooSocketAccept (*(gH323ep.listener), &h225Channel,
NULL, NULL);
remoteIP, NULL);
if(ret != ASN_OK)
{
OOTRACEERR1("Error:Accepting h225 connection\n");
@ -421,29 +428,33 @@ int ooAcceptH225Connection()
call->pH225Channel->sock = h225Channel;
/* If multihomed, get ip from socket */
if(!strcmp(call->localIP, "0.0.0.0"))
if(!strcmp(call->localIP, "0.0.0.0") || !strcmp(call->localIP,"::"))
{
OOTRACEDBGA3("Determining IP address for incoming call in multihomed "
"mode (%s, %s)\n", call->callType, call->callToken);
ret = ooSocketGetIpAndPort(h225Channel, call->localIP, 20,
&call->pH225Channel->port);
if(ret != ASN_OK)
{
OOTRACEERR3("Error:Failed to retrieve local ip and port from "
"socket for multihomed mode.(%s, %s)\n",
call->callType, call->callToken);
if(call->callState < OO_CALL_CLEAR)
{ /* transport failure */
call->callState = OO_CALL_CLEAR;
call->callEndReason = OO_REASON_TRANSPORTFAILURE;
}
ast_mutex_unlock(&call->Lock);
return OO_FAILED;
}
ret = ooSocketGetIpAndPort(h225Channel, call->localIP, 2+8*4+7,
&call->pH225Channel->port, &call->versionIP);
if(ret != ASN_OK)
{
OOTRACEERR3("Error:Failed to retrieve local ip and port from "
"socket for multihomed mode.(%s, %s)\n",
call->callType, call->callToken);
if(call->callState < OO_CALL_CLEAR)
{ /* transport failure */
call->callState = OO_CALL_CLEAR;
call->callEndReason = OO_REASON_TRANSPORTFAILURE;
}
OOTRACEDBGA4("Using Local IP address %s for incoming call in multihomed "
"mode. (%s, %s)\n", call->localIP, call->callType,
call->callToken);
ast_mutex_unlock(&call->Lock);
return OO_FAILED;
}
OOTRACEDBGA5("Using Local IP address %s (IPv%d) for incoming call "
"(%s, %s)\n", call->localIP, call->versionIP, call->callType,
call->callToken);
if (remoteIP[0]) {
strncpy(call->remoteIP, remoteIP, strlen(remoteIP));
}
ast_mutex_unlock(&call->Lock);
@ -658,7 +669,7 @@ int ooProcessCallFDSETsAndTimers
"(%s, %s)\n", call->callType, call->callToken);
if(call->callState < OO_CALL_CLEAR)
{
call->callEndReason = OO_REASON_INVALIDMESSAGE;
if (!call->callEndReason) call->callEndReason = OO_REASON_INVALIDMESSAGE;
call->callState = OO_CALL_CLEAR;
}
}
@ -671,10 +682,11 @@ int ooProcessCallFDSETsAndTimers
if (0 != call->pH245Channel && 0 != call->pH245Channel->sock)
{
if(call->pH245Channel->outQueue.count>0)
{
if(ooPDWrite(pfds, nfds, call->pH245Channel->sock))
ooSendMsg(call, OOH245MSG);
if(ooPDWrite(pfds, nfds, call->pH245Channel->sock)) {
while (call->pH245Channel->outQueue.count>0) {
if (ooSendMsg(call, OOH245MSG) != OO_OK)
break;
}
}
}
else if(call->h245listener)
@ -691,20 +703,23 @@ int ooProcessCallFDSETsAndTimers
{
if(ooPDWrite(pfds, nfds, call->pH225Channel->sock))
{
if(call->pH225Channel->outQueue.count>0)
while (call->pH225Channel->outQueue.count>0)
{
OOTRACEDBGC3("Sending H225 message (%s, %s)\n",
call->callType, call->callToken);
ooSendMsg(call, OOQ931MSG);
if (ooSendMsg(call, OOQ931MSG) != OO_OK)
break;
}
if(call->pH245Channel &&
call->pH245Channel->outQueue.count>0 &&
OO_TESTFLAG (call->flags, OO_M_TUNNELING))
{
OO_TESTFLAG (call->flags, OO_M_TUNNELING)) {
while (call->pH245Channel->outQueue.count>0) {
OOTRACEDBGC3("H245 message needs to be tunneled. "
"(%s, %s)\n", call->callType,
call->callToken);
ooSendMsg(call, OOH245MSG);
if (ooSendMsg(call, OOH245MSG) != OO_OK)
break;
}
}
}
}
@ -1319,7 +1334,7 @@ int ooSendMsg(OOH323CallData *call, int type)
{
OOTRACEDBGA3("Warning:Call marked for cleanup. Can not send message."
"(%s, %s)\n", call->callType, call->callToken);
return OO_OK;
return OO_FAILED;
}
if(type == OOQ931MSG)
@ -1393,7 +1408,8 @@ int ooSendMsg(OOH323CallData *call, int type)
{
call->callEndReason = OO_REASON_TRANSPORTFAILURE;
call->callState = OO_CALL_CLEAR;
}
} else if (call->callState == OO_CALL_CLEAR)
call->callState = OO_CALL_CLEAR_RELEASESENT;
return OO_FAILED;
}
}/* end of type==OOQ931MSG */

View File

@ -1559,7 +1559,8 @@ int ooHandleOpenLogicalChannel_helper(OOH323CallData *call,
H245H2250LogicalChannelAckParameters *h2250lcap=NULL;
OOCTXT *pctxt;
H245UnicastAddress *unicastAddrs, *unicastAddrs1;
H245UnicastAddress_iPAddress *iPAddress, *iPAddress1;
H245UnicastAddress_iPAddress *iPAddress = NULL, *iPAddress1 = NULL;
H245UnicastAddress_iP6Address *iP6Address = NULL, *iP6Address1 = NULL;
ooLogicalChannel *pLogicalChannel = NULL;
H245H2250LogicalChannelParameters *h2250lcp=NULL;
H245OpenLogicalChannel_forwardLogicalChannelParameters *flcp =
@ -1637,11 +1638,20 @@ int ooHandleOpenLogicalChannel_helper(OOH323CallData *call,
unicastAddrs = h2250lcap->mediaChannel.u.unicastAddress;
memset(unicastAddrs, 0, sizeof(H245UnicastAddress));
unicastAddrs->t = T_H245UnicastAddress_iPAddress;
unicastAddrs->u.iPAddress = (H245UnicastAddress_iPAddress*)
if (call->versionIP == 6) {
unicastAddrs->t = T_H245UnicastAddress_iP6Address;
unicastAddrs->u.iP6Address = (H245UnicastAddress_iP6Address*)
memAlloc(pctxt, sizeof(H245UnicastAddress_iP6Address));
iP6Address = unicastAddrs->u.iP6Address;
memset(iP6Address, 0, sizeof(H245UnicastAddress_iP6Address));
} else {
unicastAddrs->t = T_H245UnicastAddress_iPAddress;
unicastAddrs->u.iPAddress = (H245UnicastAddress_iPAddress*)
memAlloc(pctxt, sizeof(H245UnicastAddress_iPAddress));
iPAddress = unicastAddrs->u.iPAddress;
memset(iPAddress, 0, sizeof(H245UnicastAddress_iPAddress));
iPAddress = unicastAddrs->u.iPAddress;
memset(iPAddress, 0, sizeof(H245UnicastAddress_iPAddress));
}
pLogicalChannel = ooAddNewLogicalChannel(call,
olc->forwardLogicalChannelNumber, h2250lcap->sessionID,
@ -1652,10 +1662,16 @@ int ooHandleOpenLogicalChannel_helper(OOH323CallData *call,
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
ooSocketConvertIpToNwAddr(call->localIP, iPAddress->network.data);
iPAddress->network.numocts = 4;
iPAddress->tsapIdentifier = pLogicalChannel->localRtpPort;
if (call->versionIP == 6) {
inet_pton(AF_INET6, call->localIP, iP6Address->network.data);
iP6Address->network.numocts = 16;
iP6Address->tsapIdentifier = pLogicalChannel->localRtpPort;
} else {
inet_pton(AF_INET, call->localIP, iPAddress->network.data);
iPAddress->network.numocts = 4;
iPAddress->tsapIdentifier = pLogicalChannel->localRtpPort;
}
/* media contrcol channel */
h2250lcap->mediaControlChannel.t =
@ -1664,17 +1680,28 @@ int ooHandleOpenLogicalChannel_helper(OOH323CallData *call,
ASN1MALLOC(pctxt, sizeof(H245UnicastAddress));
unicastAddrs1 = h2250lcap->mediaControlChannel.u.unicastAddress;
memset(unicastAddrs1, 0, sizeof(H245UnicastAddress));
unicastAddrs1->t = T_H245UnicastAddress_iPAddress;
unicastAddrs1->u.iPAddress = (H245UnicastAddress_iPAddress*)
memAlloc(pctxt, sizeof(H245UnicastAddress_iPAddress));
iPAddress1 = unicastAddrs1->u.iPAddress;
memset(iPAddress1, 0, sizeof(H245UnicastAddress_iPAddress));
if (call->versionIP == 6) {
unicastAddrs1->t = T_H245UnicastAddress_iP6Address;
unicastAddrs1->u.iP6Address = (H245UnicastAddress_iP6Address*)
memAlloc(pctxt, sizeof(H245UnicastAddress_iP6Address));
iP6Address1 = unicastAddrs1->u.iP6Address;
memset(iP6Address1, 0, sizeof(H245UnicastAddress_iP6Address));
inet_pton(AF_INET6, call->localIP, iP6Address1->network.data);
iP6Address1->network.numocts = 16;
iP6Address1->tsapIdentifier = pLogicalChannel->localRtcpPort;
} else {
unicastAddrs1->t = T_H245UnicastAddress_iPAddress;
unicastAddrs1->u.iPAddress = (H245UnicastAddress_iPAddress*)
memAlloc(pctxt, sizeof(H245UnicastAddress_iPAddress));
iPAddress1 = unicastAddrs1->u.iPAddress;
memset(iPAddress1, 0, sizeof(H245UnicastAddress_iPAddress));
ooSocketConvertIpToNwAddr(call->localIP, iPAddress1->network.data);
iPAddress1->network.numocts = 4;
iPAddress1->tsapIdentifier = pLogicalChannel->localRtcpPort;
inet_pton(AF_INET, call->localIP, iPAddress1->network.data);
iPAddress1->network.numocts = 4;
iPAddress1->tsapIdentifier = pLogicalChannel->localRtcpPort;
}
OOTRACEDBGA3("Built OpenLogicalChannelAck (%s, %s)\n", call->callType,
call->callToken);
@ -1765,14 +1792,16 @@ int ooSendOpenLogicalChannelReject
int ooOnReceivedOpenLogicalChannelAck(OOH323CallData *call,
H245OpenLogicalChannelAck *olcAck)
{
char remoteip[20];
char remoteip[2+8*4+7];
regmatch_t pmatch[1];
ooLogicalChannel *pLogicalChannel;
H245H2250LogicalChannelAckParameters *h2250lcap;
H245UnicastAddress *unicastAddr;
H245UnicastAddress_iPAddress *iPAddress;
H245UnicastAddress_iPAddress *iPAddress = NULL;
H245UnicastAddress_iP6Address *iP6Address = NULL;
H245UnicastAddress *unicastAddr1;
H245UnicastAddress_iPAddress *iPAddress1 = NULL;
H245UnicastAddress_iP6Address *iP6Address1 = NULL;
if(!((olcAck->m.forwardMultiplexAckParametersPresent == 1) &&
(olcAck->forwardMultiplexAckParameters.t ==
@ -1802,19 +1831,28 @@ int ooOnReceivedOpenLogicalChannelAck(OOH323CallData *call,
}
unicastAddr = h2250lcap->mediaChannel.u.unicastAddress;
if(unicastAddr->t != T_H245UnicastAddress_iPAddress)
{
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media channel "
if (call->versionIP == 6) {
if(unicastAddr->t != T_H245UnicastAddress_iP6Address)
{
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media channel "
"address type is not IP6 (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
iP6Address = unicastAddr->u.iP6Address;
inet_ntop(AF_INET6, iP6Address->network.data, remoteip, sizeof(remoteip));
} else {
if(unicastAddr->t != T_H245UnicastAddress_iPAddress)
{
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media channel "
"address type is not IP (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
return OO_FAILED;
}
iPAddress = unicastAddr->u.iPAddress;
inet_ntop(AF_INET, iPAddress->network.data, remoteip, sizeof(remoteip));
}
iPAddress = unicastAddr->u.iPAddress;
sprintf(remoteip,"%d.%d.%d.%d", iPAddress->network.data[0],
iPAddress->network.data[1],
iPAddress->network.data[2],
iPAddress->network.data[3]);
/* Extract media control channel address */
if(h2250lcap->m.mediaControlChannelPresent == 1) {
@ -1828,14 +1866,23 @@ int ooOnReceivedOpenLogicalChannelAck(OOH323CallData *call,
}
unicastAddr1 = h2250lcap->mediaControlChannel.u.unicastAddress;
if(unicastAddr1->t != T_H245UnicastAddress_iPAddress) {
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control "
"channel address type is not IP (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
iPAddress1 = unicastAddr1->u.iPAddress;
if (call->versionIP == 6) {
if(unicastAddr1->t != T_H245UnicastAddress_iP6Address) {
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control "
"channel address type is not IP6 (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
iP6Address1 = unicastAddr1->u.iP6Address;
} else {
if(unicastAddr1->t != T_H245UnicastAddress_iPAddress) {
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control "
"channel address type is not IP (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
iPAddress1 = unicastAddr1->u.iPAddress;
}
} else {
OOTRACEDBGA3("Warning: Processing OpenLogicalChannelAck - Missing media "
"control channel (%s, %s)\n", call->callType, call->callToken);
@ -1870,10 +1917,15 @@ int ooOnReceivedOpenLogicalChannelAck(OOH323CallData *call,
}
strcpy(pLogicalChannel->remoteIP, remoteip);
pLogicalChannel->remoteMediaPort = iPAddress->tsapIdentifier;
if (iPAddress1)
pLogicalChannel->remoteMediaControlPort = iPAddress1->tsapIdentifier;
if (call->versionIP == 6) {
pLogicalChannel->remoteMediaPort = iP6Address->tsapIdentifier;
if (iP6Address1)
pLogicalChannel->remoteMediaControlPort = iP6Address1->tsapIdentifier;
} else {
pLogicalChannel->remoteMediaPort = iPAddress->tsapIdentifier;
if (iPAddress1)
pLogicalChannel->remoteMediaControlPort = iPAddress1->tsapIdentifier;
}
if(pLogicalChannel->chanCap->startTransmitChannel)
{
pLogicalChannel->chanCap->startTransmitChannel(call, pLogicalChannel);
@ -2074,6 +2126,8 @@ int ooHandleH245Command(OOH323CallData *call,
ooClearAllLogicalChannels(call);
}
ooSendEndSessionCommand(call);
if (call->callState < OO_CALL_CLEAR)
call->callState = OO_CALL_CLEAR;
}
@ -3613,6 +3667,7 @@ int ooOpenChannel(OOH323CallData* call, ooH323EpCapability *epCap)
H245H2250LogicalChannelParameters *h2250lcp = NULL;
H245UnicastAddress *unicastAddrs = NULL;
H245UnicastAddress_iPAddress *iPAddress = NULL;
H245UnicastAddress_iP6Address *iP6Address = NULL;
unsigned session_id=0;
ooLogicalChannel *pLogicalChannel = NULL;
@ -3756,16 +3811,27 @@ int ooOpenChannel(OOH323CallData* call, ooH323EpCapability *epCap)
unicastAddrs = h2250lcp->mediaControlChannel.u.unicastAddress;
memset(unicastAddrs, 0, sizeof(H245UnicastAddress));
unicastAddrs->t = T_H245UnicastAddress_iPAddress;
unicastAddrs->u.iPAddress = (H245UnicastAddress_iPAddress*)
if (call->versionIP == 6) {
unicastAddrs->t = T_H245UnicastAddress_iP6Address;
unicastAddrs->u.iP6Address = (H245UnicastAddress_iP6Address*)
ASN1MALLOC(pctxt, sizeof(H245UnicastAddress_iP6Address));
iP6Address = unicastAddrs->u.iP6Address;
memset(iP6Address, 0, sizeof(H245UnicastAddress_iP6Address));
inet_pton(AF_INET6, pLogicalChannel->localIP, iP6Address->network.data);
iP6Address->network.numocts = 16;
iP6Address->tsapIdentifier = pLogicalChannel->localRtcpPort;
} else {
unicastAddrs->t = T_H245UnicastAddress_iPAddress;
unicastAddrs->u.iPAddress = (H245UnicastAddress_iPAddress*)
ASN1MALLOC(pctxt, sizeof(H245UnicastAddress_iPAddress));
iPAddress = unicastAddrs->u.iPAddress;
memset(iPAddress, 0, sizeof(H245UnicastAddress_iPAddress));
iPAddress = unicastAddrs->u.iPAddress;
memset(iPAddress, 0, sizeof(H245UnicastAddress_iPAddress));
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,iPAddress->network.data);
iPAddress->network.numocts = 4;
iPAddress->tsapIdentifier = pLogicalChannel->localRtcpPort;
inet_pton(AF_INET, pLogicalChannel->localIP, iPAddress->network.data);
iPAddress->network.numocts = 4;
iPAddress->tsapIdentifier = pLogicalChannel->localRtcpPort;
}
pLogicalChannel->state = OO_LOGICALCHAN_PROPOSED;
OOTRACEDBGA4("Built OpenLogicalChannel-%s (%s, %s)\n",
ooGetCapTypeText(epCap->cap), call->callType,
@ -3798,6 +3864,7 @@ int ooBuildFastStartOLC
H245H2250LogicalChannelParameters *pH2250lcp1=NULL, *pH2250lcp2=NULL;
H245UnicastAddress *pUnicastAddrs=NULL, *pUniAddrs=NULL;
H245UnicastAddress_iPAddress *pIpAddrs=NULL, *pUniIpAddrs=NULL;
H245UnicastAddress_iP6Address *pIp6Addrs=NULL, *pUniIp6Addrs=NULL;
unsigned session_id = 0;
ooLogicalChannel *pLogicalChannel = NULL;
int outgoing=FALSE;
@ -3880,17 +3947,29 @@ int ooBuildFastStartOLC
sizeof(H245UnicastAddress));
memset(pUniAddrs, 0, sizeof(H245UnicastAddress));
pH2250lcp1->mediaChannel.u.unicastAddress = pUniAddrs;
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
pUniIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
sizeof(H245UnicastAddress_iPAddress));
memset(pUniIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
pUniAddrs->u.iPAddress = pUniIpAddrs;
if (call->versionIP == 6) {
pUniAddrs->t = T_H245UnicastAddress_iP6Address;
pUniIp6Addrs = (H245UnicastAddress_iP6Address*) ASN1MALLOC(pctxt,
sizeof(H245UnicastAddress_iP6Address));
memset(pUniIp6Addrs, 0, sizeof(H245UnicastAddress_iP6Address));
pUniAddrs->u.iP6Address = pUniIp6Addrs;
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
pUniIpAddrs->network.data);
inet_pton(AF_INET6, pLogicalChannel->localIP, pUniIp6Addrs->network.data);
pUniIpAddrs->network.numocts = 4;
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
pUniIp6Addrs->network.numocts = 16;
pUniIp6Addrs->tsapIdentifier = pLogicalChannel->localRtpPort;
} else {
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
pUniIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
sizeof(H245UnicastAddress_iPAddress));
memset(pUniIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
pUniAddrs->u.iPAddress = pUniIpAddrs;
inet_pton(AF_INET, pLogicalChannel->localIP, pUniIpAddrs->network.data);
pUniIpAddrs->network.numocts = 4;
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
}
}
pH2250lcp1->m.mediaControlChannelPresent = 1;
pH2250lcp1->mediaControlChannel.t =
@ -3899,17 +3978,30 @@ int ooBuildFastStartOLC
sizeof(H245UnicastAddress));
memset(pUnicastAddrs, 0, sizeof(H245UnicastAddress));
pH2250lcp1->mediaControlChannel.u.unicastAddress = pUnicastAddrs;
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
pIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
sizeof(H245UnicastAddress_iPAddress));
memset(pIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
pUnicastAddrs->u.iPAddress = pIpAddrs;
if (call->versionIP == 6) {
pUnicastAddrs->t = T_H245UnicastAddress_iP6Address;
pIp6Addrs = (H245UnicastAddress_iP6Address*) ASN1MALLOC(pctxt,
sizeof(H245UnicastAddress_iP6Address));
memset(pIp6Addrs, 0, sizeof(H245UnicastAddress_iP6Address));
pUnicastAddrs->u.iP6Address = pIp6Addrs;
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
pIpAddrs->network.data);
inet_pton(AF_INET6, pLogicalChannel->localIP, pIp6Addrs->network.data);
pIp6Addrs->network.numocts = 16;
pIp6Addrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
} else {
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
pIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
sizeof(H245UnicastAddress_iPAddress));
memset(pIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
pUnicastAddrs->u.iPAddress = pIpAddrs;
inet_pton(AF_INET, pLogicalChannel->localIP, pIpAddrs->network.data);
pIpAddrs->network.numocts = 4;
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
}
pIpAddrs->network.numocts = 4;
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
if(!outgoing)
{
if(epCap->startReceiveChannel)
@ -3972,18 +4064,33 @@ int ooBuildFastStartOLC
sizeof(H245UnicastAddress));
memset(pUnicastAddrs, 0, sizeof(H245UnicastAddress));
pH2250lcp2->mediaChannel.u.unicastAddress = pUnicastAddrs;
/* May 20101022 */
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
pIpAddrs = (H245UnicastAddress_iPAddress*) memAlloc(pctxt,
if (call->versionIP == 6) {
pUnicastAddrs->t = T_H245UnicastAddress_iP6Address;
pIp6Addrs = (H245UnicastAddress_iP6Address*) ASN1MALLOC(pctxt,
sizeof(H245UnicastAddress_iP6Address));
memset(pIp6Addrs, 0, sizeof(H245UnicastAddress_iP6Address));
pUnicastAddrs->u.iP6Address = pIp6Addrs;
inet_pton(AF_INET6, pLogicalChannel->localIP, pIp6Addrs->network.data);
pIp6Addrs->network.numocts = 16;
pIp6Addrs->tsapIdentifier = pLogicalChannel->localRtpPort;
} else {
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
pIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
sizeof(H245UnicastAddress_iPAddress));
memset(pIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
pUnicastAddrs->u.iPAddress = pIpAddrs;
memset(pIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
pUnicastAddrs->u.iPAddress = pIpAddrs;
inet_pton(AF_INET, pLogicalChannel->localIP, pIpAddrs->network.data);
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
pIpAddrs->network.data);
pIpAddrs->network.numocts = 4;
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
}
pIpAddrs->network.numocts = 4;
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
}
pH2250lcp2->m.mediaControlChannelPresent = 1;
pH2250lcp2->mediaControlChannel.t =
@ -3993,17 +4100,32 @@ int ooBuildFastStartOLC
memset(pUniAddrs, 0, sizeof(H245UnicastAddress));
pH2250lcp2->mediaControlChannel.u.unicastAddress = pUniAddrs;
/* May 20101023 */
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
pUniIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt, sizeof(H245UnicastAddress_iPAddress));
memset(pUniIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
pUniAddrs->u.iPAddress = pUniIpAddrs;
if (call->versionIP == 6) {
pUniAddrs->t = T_H245UnicastAddress_iP6Address;
pUniIp6Addrs = (H245UnicastAddress_iP6Address*) ASN1MALLOC(pctxt,
sizeof(H245UnicastAddress_iP6Address));
memset(pUniIp6Addrs, 0, sizeof(H245UnicastAddress_iP6Address));
pUniAddrs->u.iP6Address = pUniIp6Addrs;
inet_pton(AF_INET6, pLogicalChannel->localIP, pUniIp6Addrs->network.data);
pUniIp6Addrs->network.numocts = 16;
pUniIp6Addrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
} else {
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
pUniIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
sizeof(H245UnicastAddress_iPAddress));
memset(pUniIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
pUniAddrs->u.iPAddress = pUniIpAddrs;
inet_pton(AF_INET, pLogicalChannel->localIP, pUniIpAddrs->network.data);
pUniIpAddrs->network.numocts = 4;
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
}
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
pUniIpAddrs->network.data);
pUniIpAddrs->network.numocts = 4;
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
/*
In case of fast start, the local endpoint need to be ready to
receive all the media types proposed in the fast connect, before
@ -4201,6 +4323,7 @@ int ooGetIpPortFromH245TransportAddress
{
H245UnicastAddress *unicastAddress = NULL;
H245UnicastAddress_iPAddress *ipAddress = NULL;
H245UnicastAddress_iP6Address *ip6Address = NULL;
regmatch_t pmatch[1];
if(h245Address->t != T_H245TransportAddress_unicastAddress)
@ -4211,7 +4334,17 @@ int ooGetIpPortFromH245TransportAddress
}
unicastAddress = h245Address->u.unicastAddress;
if(unicastAddress->t != T_H245UnicastAddress_iPAddress)
if (call->versionIP == 6) {
if (unicastAddress->t != T_H245UnicastAddress_iP6Address) {
OOTRACEERR3("ERROR:H245 Address type is not IP6"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
ip6Address = unicastAddress->u.iP6Address;
*port = ip6Address->tsapIdentifier;
inet_ntop(AF_INET6, ip6Address->network.data, ip, INET6_ADDRSTRLEN);
} else { if(unicastAddress->t != T_H245UnicastAddress_iPAddress)
{
OOTRACEERR3("ERROR:H245 Address type is not IP"
"(%s, %s)\n", call->callType, call->callToken);
@ -4220,11 +4353,8 @@ int ooGetIpPortFromH245TransportAddress
ipAddress = unicastAddress->u.iPAddress;
*port = ipAddress->tsapIdentifier;
sprintf(ip, "%d.%d.%d.%d", ipAddress->network.data[0],
ipAddress->network.data[1],
ipAddress->network.data[2],
ipAddress->network.data[3]);
inet_ntop(AF_INET, ipAddress->network.data, ip, INET_ADDRSTRLEN);
}
if (call->rtpMaskStr[0]) {
if (regexec(&call->rtpMask->regex, ip, 1, pmatch, 0)) {
OOTRACEERR5("ERROR:H245 Address is not matched with filter %s/%s"
@ -4232,7 +4362,6 @@ int ooGetIpPortFromH245TransportAddress
return OO_FAILED;
}
}
return OO_OK;
}
@ -4247,6 +4376,7 @@ int ooPrepareFastStartResponseOLC
H245H2250LogicalChannelParameters *pH2250lcp1=NULL, *pH2250lcp2=NULL;
H245UnicastAddress *pUnicastAddrs=NULL, *pUniAddrs=NULL;
H245UnicastAddress_iPAddress *pIpAddrs=NULL, *pUniIpAddrs=NULL;
H245UnicastAddress_iP6Address *pIp6Addrs=NULL, *pUniIp6Addrs=NULL;
unsigned session_id = 0;
ooLogicalChannel *pLogicalChannel = NULL;
@ -4292,53 +4422,82 @@ int ooPrepareFastStartResponseOLC
pH2250lcp1->m.mediaChannelPresent = 1;
pH2250lcp1->mediaChannel.t = T_H245TransportAddress_unicastAddress;
pUniAddrs = (H245UnicastAddress*) memAlloc(pctxt,
pUniAddrs = (H245UnicastAddress*) memAllocZ(pctxt,
sizeof(H245UnicastAddress));
pUniIpAddrs = (H245UnicastAddress_iPAddress*) memAlloc(pctxt,
pH2250lcp1->mediaChannel.u.unicastAddress = pUniAddrs;
if (call->versionIP == 6) {
pUniIp6Addrs = (H245UnicastAddress_iP6Address*) memAllocZ(pctxt,
sizeof(H245UnicastAddress_iP6Address));
if(!pUniAddrs || !pUniIpAddrs) {
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - pUniAddrs"
"/pUniIpAddrs (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
pUniAddrs->t = T_H245UnicastAddress_iP6Address;
pUniAddrs->u.iP6Address = pUniIp6Addrs;
inet_pton(AF_INET6, pLogicalChannel->localIP, pUniIp6Addrs->network.data);
pUniIp6Addrs->network.numocts = 16;
pUniIp6Addrs->tsapIdentifier = pLogicalChannel->localRtpPort;
} else {
pUniIpAddrs = (H245UnicastAddress_iPAddress*) memAllocZ(pctxt,
sizeof(H245UnicastAddress_iPAddress));
if(!pUniAddrs || !pUniIpAddrs)
{
if(!pUniAddrs || !pUniIpAddrs) {
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - pUniAddrs"
"/pUniIpAddrs (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
pUniAddrs->u.iPAddress = pUniIpAddrs;
inet_pton(AF_INET, pLogicalChannel->localIP, pUniIpAddrs->network.data);
pUniIpAddrs->network.numocts = 4;
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
}
pH2250lcp1->mediaChannel.u.unicastAddress = pUniAddrs;
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
pUniAddrs->u.iPAddress = pUniIpAddrs;
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
pUniIpAddrs->network.data);
pUniIpAddrs->network.numocts = 4;
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
pH2250lcp1->m.mediaControlChannelPresent = 1;
pH2250lcp1->mediaControlChannel.t =
T_H245TransportAddress_unicastAddress;
pUnicastAddrs = (H245UnicastAddress*) memAlloc(pctxt,
pUnicastAddrs = (H245UnicastAddress*) memAllocZ(pctxt,
sizeof(H245UnicastAddress));
pIpAddrs = (H245UnicastAddress_iPAddress*) memAlloc(pctxt,
sizeof(H245UnicastAddress_iPAddress));
if(!pUnicastAddrs || !pIpAddrs)
{
pH2250lcp1->mediaControlChannel.u.unicastAddress = pUnicastAddrs;
if (call->versionIP == 6) {
pIp6Addrs = (H245UnicastAddress_iP6Address*) memAllocZ(pctxt,
sizeof(H245UnicastAddress_iP6Address));
if(!pUnicastAddrs || !pIp6Addrs) {
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - "
"pUnicastAddrs/pIpAddrs (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
memset(pUnicastAddrs, 0, sizeof(H245UnicastAddress));
pH2250lcp1->mediaControlChannel.u.unicastAddress = pUnicastAddrs;
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
pUnicastAddrs->u.iPAddress = pIpAddrs;
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
pIpAddrs->network.data);
}
pUnicastAddrs->t = T_H245UnicastAddress_iP6Address;
pUnicastAddrs->u.iP6Address = pIp6Addrs;
inet_pton(AF_INET6, pLogicalChannel->localIP, pIp6Addrs->network.data);
pIp6Addrs->network.numocts = 16;
pIp6Addrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
} else {
pIpAddrs->network.numocts = 4;
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
pIpAddrs = (H245UnicastAddress_iPAddress*) memAllocZ(pctxt,
sizeof(H245UnicastAddress_iPAddress));
if(!pUnicastAddrs || !pIpAddrs) {
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - "
"pUnicastAddrs/pIpAddrs (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
pUnicastAddrs->u.iPAddress = pIpAddrs;
inet_pton(AF_INET, pLogicalChannel->localIP, pIpAddrs->network.data);
pIpAddrs->network.numocts = 4;
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
}
}
if(reverse)
@ -4357,26 +4516,42 @@ int ooPrepareFastStartResponseOLC
T_H245TransportAddress_unicastAddress;
pUniAddrs = (H245UnicastAddress*) memAlloc(pctxt,
sizeof(H245UnicastAddress));
pUniIpAddrs = (H245UnicastAddress_iPAddress*) memAlloc(pctxt,
sizeof(H245UnicastAddress_iPAddress));
if(!pUniAddrs || !pUniIpAddrs)
{
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - "
pH2250lcp2->mediaControlChannel.u.unicastAddress = pUniAddrs;
if (call->versionIP == 6) {
pUniIp6Addrs = (H245UnicastAddress_iP6Address*) memAlloc(pctxt,
sizeof(H245UnicastAddress_iP6Address));
if(!pUniAddrs || !pUniIp6Addrs) {
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - "
"pUniAddrs/pUniIpAddrs (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
}
pH2250lcp2->mediaControlChannel.u.unicastAddress = pUniAddrs;
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
pUniAddrs->t = T_H245UnicastAddress_iP6Address;
pUniAddrs->u.iP6Address = pUniIp6Addrs;
inet_pton(AF_INET6, pLogicalChannel->localIP, pUniIp6Addrs->network.data);
pUniIp6Addrs->network.numocts = 16;
pUniIp6Addrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
} else {
pUniIpAddrs = (H245UnicastAddress_iPAddress*) memAlloc(pctxt,
sizeof(H245UnicastAddress_iPAddress));
if(!pUniAddrs || !pUniIpAddrs) {
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - "
"pUniAddrs/pUniIpAddrs (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
pUniAddrs->u.iPAddress = pUniIpAddrs;
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
pUniIpAddrs->network.data);
pUniIpAddrs->network.numocts = 4;
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
pH2250lcp2->mediaControlChannel.u.unicastAddress = pUniAddrs;
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
pUniAddrs->u.iPAddress = pUniIpAddrs;
inet_pton(AF_INET, pLogicalChannel->localIP, pUniIpAddrs->network.data);
pUniIpAddrs->network.numocts = 4;
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
}
}

View File

@ -226,7 +226,7 @@ int ooHandleFastStart(OOH323CallData *call, H225Facility_UUIE *facility)
if(ret != OO_OK)
{
OOTRACEERR3("Error: Unknown H245 address type in received "
"CallProceeding message (%s, %s)", call->callType,
"Facility message (%s, %s)", call->callType,
call->callToken);
/* Mark call for clearing */
if(call->callState < OO_CALL_CLEAR)
@ -368,8 +368,10 @@ int ooOnReceivedSetup(OOH323CallData *call, Q931Message *q931Msg)
H245OpenLogicalChannel* olc;
ASN1OCTET msgbuf[MAXMSGLEN];
H225TransportAddress_ipAddress_ip *ip = NULL;
H225TransportAddress_ip6Address_ip *ip6 = NULL;
Q931InformationElement* pDisplayIE=NULL;
OOAliases *pAlias=NULL;
char remoteIP[2+8*4+7];
call->callReference = q931Msg->callReference;
@ -507,18 +509,26 @@ int ooOnReceivedSetup(OOH323CallData *call, Q931Message *q931Msg)
"setup (%s, %s)\n", call->callType, call->callToken);
}
else{
if(setup->sourceCallSignalAddress.t != T_H225TransportAddress_ipAddress)
{
OOTRACEERR3("ERROR: Source call signalling address type not ip "
if(setup->sourceCallSignalAddress.t == T_H225TransportAddress_ip6Address) {
ip6 = &setup->sourceCallSignalAddress.u.ip6Address->ip;
inet_ntop(AF_INET6, ip6->data, remoteIP, INET6_ADDRSTRLEN);
call->remotePort = setup->sourceCallSignalAddress.u.ip6Address->port;
} else if(setup->sourceCallSignalAddress.t == T_H225TransportAddress_ipAddress) {
ip = &setup->sourceCallSignalAddress.u.ipAddress->ip;
sprintf(remoteIP, "%d.%d.%d.%d", ip->data[0], ip->data[1],
ip->data[2], ip->data[3]);
call->remotePort = setup->sourceCallSignalAddress.u.ipAddress->port;
} else {
OOTRACEERR3("ERROR: Source call signalling address type not ip4 nor ip6 "
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
}
ip = &setup->sourceCallSignalAddress.u.ipAddress->ip;
sprintf(call->remoteIP, "%d.%d.%d.%d", ip->data[0], ip->data[1],
ip->data[2], ip->data[3]);
call->remotePort = setup->sourceCallSignalAddress.u.ipAddress->port;
if (strncmp(remoteIP, call->remoteIP, strlen(remoteIP))) {
OOTRACEERR5("ERROR: Security denial remote sig IP isn't a socket ip, %s not %s "
"(%s, %s)\n", remoteIP, call->remoteIP, call->callType,
call->callToken);
}
/* check for fast start */
@ -1814,6 +1824,7 @@ int ooOnReceivedFacility(OOH323CallData *call, Q931Message * pQ931Msg)
H225Facility_UUIE * facility = NULL;
int ret;
H225TransportAddress_ipAddress_ip *ip = NULL;
H225TransportAddress_ip6Address_ip *ip6 = NULL;
OOTRACEDBGC3("Received Facility Message.(%s, %s)\n", call->callType,
call->callToken);
@ -1899,6 +1910,21 @@ int ooOnReceivedFacility(OOH323CallData *call, Q931Message * pQ931Msg)
call->pCallFwdData->aliases = NULL;
if(facility->m.alternativeAddressPresent)
{
if (call->versionIP == 6) {
if(facility->alternativeAddress.t !=
T_H225TransportAddress_ip6Address)
{
OOTRACEERR3("ERROR: Source call signalling address type not ip6 "
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
ip6 = &facility->alternativeAddress.u.ip6Address->ip;
inet_ntop(AF_INET6, ip6->data, call->pCallFwdData->ip, INET6_ADDRSTRLEN);
call->pCallFwdData->port =
facility->alternativeAddress.u.ip6Address->port;
} else {
if(facility->alternativeAddress.t !=
T_H225TransportAddress_ipAddress)
{
@ -1913,6 +1939,7 @@ int ooOnReceivedFacility(OOH323CallData *call, Q931Message * pQ931Msg)
ip->data[1], ip->data[2], ip->data[3]);
call->pCallFwdData->port =
facility->alternativeAddress.u.ipAddress->port;
}
}
if(facility->m.alternativeAliasAddressPresent)
@ -1969,6 +1996,7 @@ int ooHandleStartH245FacilityMessage
(OOH323CallData *call, H225Facility_UUIE *facility)
{
H225TransportAddress_ipAddress *ipAddress = NULL;
H225TransportAddress_ip6Address *ip6Address = NULL;
int ret;
/* Extract H245 address */
@ -1978,25 +2006,43 @@ int ooHandleStartH245FacilityMessage
"address (%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
if(facility->h245Address.t != T_H225TransportAddress_ipAddress)
{
if (call->versionIP == 6) {
if(facility->h245Address.t != T_H225TransportAddress_ip6Address)
{
OOTRACEERR3("ERROR:Unknown H245 address type in received startH245 "
"facility message (%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
ipAddress = facility->h245Address.u.ipAddress;
if(!ipAddress)
{
}
ip6Address = facility->h245Address.u.ip6Address;
if(!ip6Address)
{
OOTRACEERR3("ERROR:Invalid startH245 facility message. No H245 ip6 "
"address found. (%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
inet_ntop(AF_INET6, ip6Address->ip.data, call->remoteIP, INET6_ADDRSTRLEN);
call->remoteH245Port = ip6Address->port;
} else {
if(facility->h245Address.t != T_H225TransportAddress_ipAddress)
{
OOTRACEERR3("ERROR:Unknown H245 address type in received startH245 "
"facility message (%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
ipAddress = facility->h245Address.u.ipAddress;
if(!ipAddress)
{
OOTRACEERR3("ERROR:Invalid startH245 facility message. No H245 ip "
"address found. (%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
}
sprintf(call->remoteIP, "%d.%d.%d.%d", ipAddress->ip.data[0],
sprintf(call->remoteIP, "%d.%d.%d.%d", ipAddress->ip.data[0],
ipAddress->ip.data[1],
ipAddress->ip.data[2],
ipAddress->ip.data[3]);
call->remoteH245Port = ipAddress->port;
call->remoteH245Port = ipAddress->port;
}
/* disable tunneling for this call */
OO_CLRFLAG (call->flags, OO_M_TUNNELING);
@ -2178,15 +2224,16 @@ int ooH323RetrieveAliases
newAlias->value[strlen(pAliasAddress->u.url_ID)*sizeof(char)]='\0';
break;
case T_H225AliasAddress_transportID:
newAlias->type = T_H225AliasAddress_transportID;
pTransportAddrss = pAliasAddress->u.transportID;
if(pTransportAddrss->t != T_H225TransportAddress_ipAddress)
{
OOTRACEERR3("Error:Alias transportID not an IP address"
"(%s, %s)\n", call->callType, call->callToken);
memFreePtr(call->pctxt, newAlias);
break;
}
newAlias->type = T_H225AliasAddress_transportID;
pTransportAddrss = pAliasAddress->u.transportID;
if(pTransportAddrss->t == T_H225TransportAddress_ip6Address) {
/* hopefully ip:port value can't exceed more than 30
characters */
newAlias->value = (char*)memAlloc(call->pctxt,
INET6_ADDRSTRLEN*sizeof(char)*2);
inet_ntop(AF_INET6, pTransportAddrss->u.ip6Address->ip.data, newAlias->value, INET6_ADDRSTRLEN);
sprintf(newAlias->value+strlen(newAlias->value), ":%d", pTransportAddrss->u.ip6Address->port);
} else if(pTransportAddrss->t == T_H225TransportAddress_ipAddress) {
/* hopefully ip:port value can't exceed more than 30
characters */
newAlias->value = (char*)memAlloc(call->pctxt,
@ -2197,7 +2244,12 @@ int ooH323RetrieveAliases
pTransportAddrss->u.ipAddress->ip.data[2],
pTransportAddrss->u.ipAddress->ip.data[3],
pTransportAddrss->u.ipAddress->port);
break;
} else {
OOTRACEERR3("Error:Alias transportID not an IP4 nor IP6 address"
"(%s, %s)\n", call->callType, call->callToken);
memFreePtr(call->pctxt, newAlias);
}
break;
case T_H225AliasAddress_email_ID:
newAlias->type = T_H225AliasAddress_email_ID;
newAlias->value = (char*)memAlloc(call->pctxt,
@ -2471,22 +2523,29 @@ OOAliases* ooH323AddAliasToList
case T_H225AliasAddress_transportID:
newAlias->type = T_H225AliasAddress_transportID;
pTransportAddrss = pAliasAddress->u.transportID;
if(pTransportAddrss->t != T_H225TransportAddress_ipAddress)
{
OOTRACEERR1("Error:Alias transportID not an IP address\n");
memFreePtr(pctxt, newAlias);
return NULL;
}
/* hopefully ip:port value can't exceed more than 30
if(pTransportAddrss->t == T_H225TransportAddress_ip6Address) {
/* hopefully ip:port value can't exceed more than 30
characters */
newAlias->value = (char*)memAlloc(pctxt,
newAlias->value = (char*)memAlloc(pctxt,
INET6_ADDRSTRLEN*sizeof(char)*2);
inet_ntop(AF_INET6, pTransportAddrss->u.ip6Address->ip.data, newAlias->value, INET6_ADDRSTRLEN);
sprintf(newAlias->value+strlen(newAlias->value), ":%d", pTransportAddrss->u.ip6Address->port);
} else if(pTransportAddrss->t == T_H225TransportAddress_ipAddress) {
/* hopefully ip:port value can't exceed more than 30
characters */
newAlias->value = (char*)memAlloc(pctxt,
30*sizeof(char));
sprintf(newAlias->value, "%d.%d.%d.%d:%d",
sprintf(newAlias->value, "%d.%d.%d.%d:%d",
pTransportAddrss->u.ipAddress->ip.data[0],
pTransportAddrss->u.ipAddress->ip.data[1],
pTransportAddrss->u.ipAddress->ip.data[2],
pTransportAddrss->u.ipAddress->ip.data[3],
pTransportAddrss->u.ipAddress->port);
} else {
OOTRACEERR1("Error:Alias transportID not an IP4 nor IP6 address\n");
memFreePtr(pctxt, newAlias);
return NULL;
}
break;
case T_H225AliasAddress_email_ID:
newAlias->type = T_H225AliasAddress_email_ID;
@ -2509,6 +2568,17 @@ OOAliases* ooH323AddAliasToList
int ooH323GetIpPortFromH225TransportAddress(struct OOH323CallData *call,
H225TransportAddress *h225Address, char *ip, int *port)
{
if (call->versionIP == 6) {
if(h225Address->t != T_H225TransportAddress_ip6Address)
{
OOTRACEERR3("Error: Unknown H225 address type. (%s, %s)", call->callType,
call->callToken);
return OO_FAILED;
}
inet_ntop(AF_INET6, h225Address->u.ip6Address->ip.data, ip, INET6_ADDRSTRLEN);
*port = h225Address->u.ip6Address->port;
return OO_OK;
}
if(h225Address->t != T_H225TransportAddress_ipAddress)
{
OOTRACEERR3("Error: Unknown H225 address type. (%s, %s)", call->callType,

View File

@ -130,7 +130,7 @@ typedef struct OOH323EndPoint {
int noOfCaps;
OOH225MsgCallbacks h225Callbacks;
OOH323CALLBACKS h323Callbacks;
char signallingIP[20];
char signallingIP[2+8*4+7];
int listenPort;
OOSOCKET *listener;
OOH323CallData *callList;
@ -148,6 +148,7 @@ typedef struct OOH323EndPoint {
OOInterface *ifList; /* interface list for the host we are running on*/
OOBOOL isGateway;
OOSOCKET cmdSock;
OOBOOL v6Mode;
} OOH323EndPoint;
#define ooEndPoint OOH323EndPoint

View File

@ -16,6 +16,8 @@
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/netsock2.h"
#include "asterisk/config.h"
#include "ooports.h"
#include "ooh323ep.h"
@ -71,7 +73,7 @@ int ooBindPort (OOH323PortType type, OOSOCKET socket, char *ip)
initialPort = ooGetNextPort (type);
bindPort = initialPort;
ret= ooSocketStrToAddr (ip, &ipAddrs);
ret=ast_parse_arg(ip, PARSE_ADDR, &ipAddrs);
while(1)
{

View File

@ -17,6 +17,8 @@
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/config.h"
#include "asterisk/netsock2.h"
#include <time.h>
#include "ooq931.h"
@ -854,7 +856,7 @@ int ooSetFastStartResponse(OOH323CallData *pCall, Q931Message *pQ931msg,
/* OOCTXT *pctxt = &gH323ep.msgctxt; */
OOCTXT *pctxt = pCall->msgctxt;
int ret = 0, i=0, j=0, remoteMediaPort=0, remoteMediaControlPort = 0, dir=0;
char remoteMediaIP[20], remoteMediaControlIP[20];
char remoteMediaIP[2+8*4+7], remoteMediaControlIP[2+8*4+7];
DListNode *pNode = NULL;
H245OpenLogicalChannel *olc = NULL, printOlc;
ooH323EpCapability *epCap = NULL;
@ -1473,6 +1475,7 @@ int ooSendProgress(OOH323CallData *call)
H225VendorIdentifier *vendor;
Q931Message *q931msg=NULL;
H225TransportAddress_ipAddress *h245IpAddr;
H225TransportAddress_ip6Address *h245Ip6Addr;
OOCTXT *pctxt = call->msgctxt;
ret = ooCreateQ931Message(pctxt, &q931msg, Q931ProgressMsg);
@ -1569,6 +1572,23 @@ int ooSendProgress(OOH323CallData *call)
!OO_TESTFLAG (call->flags, OO_M_TUNNELING) &&
!call->h245listener && ooCreateH245Listener(call) == OO_OK)
{
if (call->versionIP == 6) {
progress->m.h245AddressPresent = TRUE;
progress->h245Address.t = T_H225TransportAddress_ip6Address;
h245Ip6Addr = (H225TransportAddress_ip6Address*)
memAllocZ (pctxt, sizeof(H225TransportAddress_ip6Address));
if(!h245Ip6Addr)
{
OOTRACEERR3("Error:Memory - ooSendProgress - h245Ip6Addr"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
inet_pton(AF_INET6, call->localIP, h245Ip6Addr->ip.data);
h245Ip6Addr->ip.numocts=16;
h245Ip6Addr->port = *(call->h245listenport);
progress->h245Address.u.ip6Address = h245Ip6Addr;
} else {
progress->m.h245AddressPresent = TRUE;
progress->h245Address.t = T_H225TransportAddress_ipAddress;
@ -1576,14 +1596,15 @@ int ooSendProgress(OOH323CallData *call)
memAllocZ (pctxt, sizeof(H225TransportAddress_ipAddress));
if(!h245IpAddr)
{
OOTRACEERR3("Error:Memory - ooAcceptCall - h245IpAddr"
OOTRACEERR3("Error:Memory - ooSendProgress - h245IpAddr"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
ooSocketConvertIpToNwAddr(call->localIP, h245IpAddr->ip.data);
inet_pton(AF_INET, call->localIP, h245IpAddr->ip.data);
h245IpAddr->ip.numocts=4;
h245IpAddr->port = *(call->h245listenport);
progress->h245Address.u.ipAddress = h245IpAddr;
}
}
OOTRACEDBGA3("Built Progress (%s, %s)\n", call->callType, call->callToken);
@ -1614,6 +1635,7 @@ int ooSendStartH245Facility(OOH323CallData *call)
/* OOCTXT *pctxt = &gH323ep.msgctxt; */
OOCTXT *pctxt = call->msgctxt;
H225TransportAddress_ipAddress *h245IpAddr;
H225TransportAddress_ip6Address *h245Ip6Addr;
OOTRACEDBGA3("Building Facility message (%s, %s)\n", call->callType,
call->callToken);
@ -1674,19 +1696,35 @@ int ooSendStartH245Facility(OOH323CallData *call)
}
facility->m.h245AddressPresent = TRUE;
facility->h245Address.t = T_H225TransportAddress_ipAddress;
if (call->versionIP == 6) {
facility->h245Address.t = T_H225TransportAddress_ip6Address;
h245IpAddr = (H225TransportAddress_ipAddress*)
h245Ip6Addr = (H225TransportAddress_ip6Address*)
memAllocZ (pctxt, sizeof(H225TransportAddress_ip6Address));
if(!h245Ip6Addr) {
OOTRACEERR3("Error:Memory - ooSendFacility - h245Ip6Addr"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
inet_pton(AF_INET6, call->localIP, h245Ip6Addr->ip.data);
h245Ip6Addr->ip.numocts=16;
h245Ip6Addr->port = *(call->h245listenport);
facility->h245Address.u.ip6Address = h245Ip6Addr;
} else {
facility->h245Address.t = T_H225TransportAddress_ipAddress;
h245IpAddr = (H225TransportAddress_ipAddress*)
memAllocZ (pctxt, sizeof(H225TransportAddress_ipAddress));
if(!h245IpAddr) {
if(!h245IpAddr) {
OOTRACEERR3("Error:Memory - ooSendFacility - h245IpAddr"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
inet_pton(AF_INET, call->localIP, h245IpAddr->ip.data);
h245IpAddr->ip.numocts=4;
h245IpAddr->port = *(call->h245listenport);
facility->h245Address.u.ipAddress = h245IpAddr;
}
ooSocketConvertIpToNwAddr(call->localIP, h245IpAddr->ip.data);
h245IpAddr->ip.numocts=4;
h245IpAddr->port = *(call->h245listenport);
facility->h245Address.u.ipAddress = h245IpAddr;
OOTRACEDBGA3("Built Facility message to send (%s, %s)\n", call->callType,
call->callToken);
@ -1818,6 +1856,7 @@ int ooAcceptCall(OOH323CallData *call)
int ret = 0, i=0;
H225Connect_UUIE *connect;
H225TransportAddress_ipAddress *h245IpAddr;
H225TransportAddress_ip6Address *h245Ip6Addr;
H225VendorIdentifier *vendor;
Q931Message *q931msg=NULL;
/* OOCTXT *pctxt = &gH323ep.msgctxt; */
@ -1980,20 +2019,37 @@ int ooAcceptCall(OOH323CallData *call)
!call->pH245Channel))
{
connect->m.h245AddressPresent = TRUE;
connect->h245Address.t = T_H225TransportAddress_ipAddress;
if (call->versionIP == 6) {
connect->h245Address.t = T_H225TransportAddress_ip6Address;
h245IpAddr = (H225TransportAddress_ipAddress*)
h245Ip6Addr = (H225TransportAddress_ip6Address*)
memAllocZ (pctxt, sizeof(H225TransportAddress_ip6Address));
if(!h245Ip6Addr)
{
OOTRACEERR3("Error:Memory - ooAcceptCall - h245Ip6Addr"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
inet_pton(AF_INET6, call->localIP, h245Ip6Addr->ip.data);
h245Ip6Addr->ip.numocts=16;
h245Ip6Addr->port = *(call->h245listenport);
connect->h245Address.u.ip6Address = h245Ip6Addr;
} else {
connect->h245Address.t = T_H225TransportAddress_ipAddress;
h245IpAddr = (H225TransportAddress_ipAddress*)
memAllocZ (pctxt, sizeof(H225TransportAddress_ipAddress));
if(!h245IpAddr)
{
if(!h245IpAddr)
{
OOTRACEERR3("Error:Memory - ooAcceptCall - h245IpAddr"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
inet_pton(AF_INET, call->localIP, h245IpAddr->ip.data);
h245IpAddr->ip.numocts=4;
h245IpAddr->port = *(call->h245listenport);
connect->h245Address.u.ipAddress = h245IpAddr;
}
ooSocketConvertIpToNwAddr(call->localIP, h245IpAddr->ip.data);
h245IpAddr->ip.numocts=4;
h245IpAddr->port = *(call->h245listenport);
connect->h245Address.u.ipAddress = h245IpAddr;
}
OOTRACEDBGA3("Built H.225 Connect message (%s, %s)\n", call->callType,
@ -2126,10 +2182,11 @@ int ooH323MakeCall(char *dest, char *callToken, ooCallOptions *opts)
OOCTXT *pctxt;
OOH323CallData *call;
int ret=OO_OK, i=0, irand=0;
char tmp[30]="\0";
char tmp[2+8*4+7]="\0";
char *ip=NULL, *port = NULL;
struct timeval tv;
struct timespec ts;
struct ast_sockaddr m_addr;
if(!dest)
{
@ -2173,7 +2230,7 @@ int ooH323MakeCall(char *dest, char *callToken, ooCallOptions *opts)
}
ret = ooParseDestination(call, dest, tmp, 24, &call->remoteAliases);
ret = ooParseDestination(call, dest, tmp, 2+8*4+7, &call->remoteAliases);
if(ret != OO_OK)
{
OOTRACEERR2("Error: Failed to parse the destination string %s for "
@ -2185,10 +2242,15 @@ int ooH323MakeCall(char *dest, char *callToken, ooCallOptions *opts)
/* Check whether we have ip address */
if(!ooUtilsIsStrEmpty(tmp)) {
ip = tmp;
port = strchr(tmp, ':');
port = strrchr(tmp, ':');
*port = '\0';
port++;
strcpy(call->remoteIP, ip);
ast_parse_arg(ip, PARSE_ADDR, &m_addr);
if (ast_sockaddr_is_ipv6(&m_addr))
call->versionIP = 6;
else
call->versionIP = 4;
call->remotePort = atoi(port);
}
@ -2261,7 +2323,16 @@ int ooH323CallAdmitted(OOH323CallData *call)
if(gH323ep.h323Callbacks.onOutgoingCall) {
/* Outgoing call callback function */
gH323ep.h323Callbacks.onOutgoingCall(call);
if (gH323ep.h323Callbacks.onOutgoingCall(call) != OO_OK) {
OOTRACEERR3("ERROR:Failed to setup media to (%s,%d)\n",
call->callType, call->callToken);
if(call->callState< OO_CALL_CLEAR)
{
call->callState = OO_CALL_CLEAR;
call->callEndReason = OO_REASON_UNKNOWN;
}
return OO_FAILED;
}
}
ret = ooH323MakeCall_helper(call);
@ -2294,9 +2365,8 @@ int ooH323MakeCall_helper(OOH323CallData *call)
H225Setup_UUIE *setup;
ASN1DynOctStr *pFS=NULL;
H225TransportAddress_ipAddress *destCallSignalIpAddress;
H225TransportAddress_ipAddress *srcCallSignalIpAddress;
H225TransportAddress_ipAddress *destCallSignalIpAddress,*srcCallSignalIpAddress;
H225TransportAddress_ip6Address *destCallSignalIp6Address,*srcCallSignalIp6Address;
ooH323EpCapability *epCap=NULL;
OOCTXT *pctxt = NULL;
H245OpenLogicalChannel *olc, printOlc;
@ -2465,41 +2535,77 @@ int ooH323MakeCall_helper(OOH323CallData *call)
setup->sourceInfo.undefinedNode = FALSE;
/* Populate the destination Call Signal Address */
setup->destCallSignalAddress.t=T_H225TransportAddress_ipAddress;
destCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
setup->m.destCallSignalAddressPresent=TRUE;
setup->activeMC=FALSE;
if (call->versionIP == 6) {
setup->destCallSignalAddress.t=T_H225TransportAddress_ip6Address;
destCallSignalIp6Address = (H225TransportAddress_ip6Address*)memAlloc(pctxt,
sizeof(H225TransportAddress_ip6Address));
if(!destCallSignalIp6Address)
{
OOTRACEERR3("Error:Memory - ooH323MakeCall_helper - "
"destCallSignal6Address. (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
inet_pton(AF_INET6, call->remoteIP, destCallSignalIp6Address->ip.data);
destCallSignalIp6Address->ip.numocts=16;
destCallSignalIp6Address->port = call->remotePort;
setup->destCallSignalAddress.u.ip6Address = destCallSignalIp6Address;
} else {
setup->destCallSignalAddress.t=T_H225TransportAddress_ipAddress;
destCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
sizeof(H225TransportAddress_ipAddress));
if(!destCallSignalIpAddress)
{
if(!destCallSignalIpAddress)
{
OOTRACEERR3("Error:Memory - ooH323MakeCall_helper - "
"destCallSignalAddress. (%s, %s)\n", call->callType,
call->callToken);
return OO_FAILED;
}
inet_pton(AF_INET, call->remoteIP, destCallSignalIpAddress->ip.data);
destCallSignalIpAddress->ip.numocts=4;
destCallSignalIpAddress->port = call->remotePort;
setup->destCallSignalAddress.u.ipAddress = destCallSignalIpAddress;
}
ooSocketConvertIpToNwAddr(call->remoteIP, destCallSignalIpAddress->ip.data);
destCallSignalIpAddress->ip.numocts=4;
destCallSignalIpAddress->port = call->remotePort;
setup->destCallSignalAddress.u.ipAddress = destCallSignalIpAddress;
setup->m.destCallSignalAddressPresent=TRUE;
setup->activeMC=FALSE;
/* Populate the source Call Signal Address */
setup->sourceCallSignalAddress.t=T_H225TransportAddress_ipAddress;
srcCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
setup->m.sourceCallSignalAddressPresent=TRUE;
if (call->versionIP == 6) {
setup->sourceCallSignalAddress.t=T_H225TransportAddress_ip6Address;
srcCallSignalIp6Address = (H225TransportAddress_ip6Address*)memAlloc(pctxt,
sizeof(H225TransportAddress_ip6Address));
if(!srcCallSignalIp6Address)
{
OOTRACEERR3("Error:Memory - ooH323MakeCall_helper - srcCallSignal6Address"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
inet_pton(AF_INET6, call->localIP, srcCallSignalIp6Address->ip.data);
srcCallSignalIp6Address->ip.numocts=16;
srcCallSignalIp6Address->port= call->pH225Channel->port;
setup->sourceCallSignalAddress.u.ip6Address = srcCallSignalIp6Address;
} else {
setup->sourceCallSignalAddress.t=T_H225TransportAddress_ipAddress;
srcCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
sizeof(H225TransportAddress_ipAddress));
if(!srcCallSignalIpAddress)
{
if(!srcCallSignalIpAddress)
{
OOTRACEERR3("Error:Memory - ooH323MakeCall_helper - srcCallSignalAddress"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
ooSocketConvertIpToNwAddr(call->localIP, srcCallSignalIpAddress->ip.data);
}
inet_pton(AF_INET, call->localIP, srcCallSignalIpAddress->ip.data);
srcCallSignalIpAddress->ip.numocts=4;
srcCallSignalIpAddress->port= call->pH225Channel->port;
setup->sourceCallSignalAddress.u.ipAddress = srcCallSignalIpAddress;
setup->m.sourceCallSignalAddressPresent=TRUE;
srcCallSignalIpAddress->ip.numocts=4;
srcCallSignalIpAddress->port= call->pH225Channel->port;
setup->sourceCallSignalAddress.u.ipAddress = srcCallSignalIpAddress;
}
/* No fast start */
if(!OO_TESTFLAG(call->flags, OO_M_FASTSTART))
{
@ -2845,8 +2951,9 @@ int ooH323ForwardCall(char* callToken, char *dest)
H225Facility_UUIE *facility=NULL;
OOCTXT *pctxt = &gH323ep.msgctxt;
OOH323CallData *call;
char ip[30]="\0", *pcPort=NULL;
char ip[2+8*4+7]="\0", *pcPort=NULL;
H225TransportAddress_ipAddress *fwdCallSignalIpAddress;
H225TransportAddress_ip6Address *fwdCallSignalIp6Address;
call= ooFindCallByToken(callToken);
if(!call)
@ -2865,7 +2972,7 @@ int ooH323ForwardCall(char* callToken, char *dest)
return OO_FAILED;
}
ret = ooParseDestination(call, dest, ip, 20,
ret = ooParseDestination(call, dest, ip, 2+8*4+7,
&call->pCallFwdData->aliases);
if(ret != OO_OK)
{
@ -2877,7 +2984,7 @@ int ooH323ForwardCall(char* callToken, char *dest)
if(!ooUtilsIsStrEmpty(ip))
{
pcPort = strchr(ip, ':');
pcPort = strrchr(ip, ':');
if(pcPort)
{
*pcPort = '\0';
@ -2941,21 +3048,39 @@ int ooH323ForwardCall(char* callToken, char *dest)
if(!ooUtilsIsStrEmpty(call->pCallFwdData->ip))
{
facility->m.alternativeAddressPresent = TRUE;
facility->alternativeAddress.t=T_H225TransportAddress_ipAddress;
fwdCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
if (call->versionIP == 6) {
facility->alternativeAddress.t=T_H225TransportAddress_ip6Address;
fwdCallSignalIp6Address = (H225TransportAddress_ip6Address*)memAlloc(pctxt,
sizeof(H225TransportAddress_ip6Address));
if(!fwdCallSignalIp6Address)
{
OOTRACEERR3("Error:Memory - ooH323ForwardCall - fwdCallSignal6Address"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
inet_pton(AF_INET6, call->pCallFwdData->ip,
fwdCallSignalIp6Address->ip.data);
fwdCallSignalIp6Address->ip.numocts=16;
fwdCallSignalIp6Address->port = call->pCallFwdData->port;
facility->alternativeAddress.u.ip6Address = fwdCallSignalIp6Address;
} else {
facility->alternativeAddress.t=T_H225TransportAddress_ipAddress;
fwdCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
sizeof(H225TransportAddress_ipAddress));
if(!fwdCallSignalIpAddress)
{
if(!fwdCallSignalIpAddress)
{
OOTRACEERR3("Error:Memory - ooH323ForwardCall - fwdCallSignalAddress"
"(%s, %s)\n", call->callType, call->callToken);
return OO_FAILED;
}
ooSocketConvertIpToNwAddr(call->pCallFwdData->ip,
}
inet_pton(AF_INET, call->pCallFwdData->ip,
fwdCallSignalIpAddress->ip.data);
fwdCallSignalIpAddress->ip.numocts=4;
fwdCallSignalIpAddress->port = call->pCallFwdData->port;
facility->alternativeAddress.u.ipAddress = fwdCallSignalIpAddress;
fwdCallSignalIpAddress->ip.numocts=4;
fwdCallSignalIpAddress->port = call->pCallFwdData->port;
facility->alternativeAddress.u.ipAddress = fwdCallSignalIpAddress;
}
}
if(call->pCallFwdData->aliases)
@ -3469,6 +3594,7 @@ int ooParseDestination
char tmp[256], buf[30];
char *alias=NULL;
OOCTXT *pctxt = call->pctxt;
struct ast_sockaddr tmpaddr;
parsedIP[0] = '\0';
OOTRACEINFO2("Parsing destination %s\n", dest);
@ -3498,6 +3624,19 @@ int ooParseDestination
return OO_OK;
}
if (!ast_parse_arg(dest, PARSE_ADDR, &tmpaddr)) {
if(strlen(dest)+7>len)
{
OOTRACEERR1("Error:Insufficient buffer space for parsed ip - "
"ooParseDestination\n");
return OO_FAILED;
}
strcpy(parsedIP, ast_sockaddr_stringify_addr(&tmpaddr));
strcat(parsedIP, ":");
strcat(parsedIP, ast_sockaddr_stringify_port(&tmpaddr));
return OO_OK;
}
/* alias@host */
strncpy(tmp, dest, sizeof(tmp)-1);
tmp[sizeof(tmp)-1]='\0';

View File

@ -143,7 +143,7 @@ typedef enum OOCallClearReason {
#define OOTERMTYPE 60
/** Maximum length of an IP address (xxx.xxx.xxx.xxx). */
#define MAX_IP_LENGTH 15
#define MAX_IP_LENGTH 2+8*4+7
/** Maximum length of a log file message */
#define MAXLOGMSGLEN 2048

View File

@ -398,7 +398,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
} else if (ast_strlen_zero(row[i])) {
row[i] = " ";
}
for (stringp = ast_strdupa(row[i]), chunk = strsep(&stringp, ";"); chunk; chunk = strsep(&stringp, ";")) {
for (stringp = row[i], chunk = strsep(&stringp, ";"); chunk; chunk = strsep(&stringp, ";")) {
if (prev) {
if ((prev->next = ast_variable_new(fields[i].name, decode_chunk(chunk), ""))) {
prev = prev->next;
@ -524,7 +524,7 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
for (i = 0; i < numFields; i++) {
if (ast_strlen_zero(row[i]))
continue;
for (stringp = ast_strdupa(row[i]), chunk = strsep(&stringp, ";"); chunk; chunk = strsep(&stringp, ";")) {
for (stringp = row[i], chunk = strsep(&stringp, ";"); chunk; chunk = strsep(&stringp, ";")) {
if (chunk && !ast_strlen_zero(decode_chunk(ast_strip(chunk)))) {
if (initfield && !strcmp(initfield, fields[i].name)) {
ast_category_rename(cat, chunk);
@ -608,7 +608,7 @@ static int update_mysql(const char *database, const char *tablename, const char
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
ESCAPE_STRING(buf, newval);
ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(buf));
ast_str_set(&sql, 0, "UPDATE %s SET `%s` = '%s'", tablename, newparam, ast_str_buffer(buf));
/* If the column length isn't long enough, give a chance to lengthen it. */
if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
@ -625,7 +625,7 @@ static int update_mysql(const char *database, const char *tablename, const char
}
ESCAPE_STRING(buf, newval);
ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(buf));
ast_str_append(&sql, 0, ", `%s` = '%s'", newparam, ast_str_buffer(buf));
/* If the column length isn't long enough, give a chance to lengthen it. */
if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
@ -635,7 +635,7 @@ static int update_mysql(const char *database, const char *tablename, const char
va_end(ap);
ESCAPE_STRING(buf, lookup);
ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, ast_str_buffer(buf));
ast_str_append(&sql, 0, " WHERE `%s` = '%s'", keyfield, ast_str_buffer(buf));
ast_debug(1, "MySQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
@ -719,7 +719,7 @@ static int update2_mysql(const char *database, const char *tablename, va_list ap
return -1;
}
ESCAPE_STRING(buf, newval);
ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(buf));
ast_str_append(&where, 0, "%s `%s` = '%s'", first ? "" : " AND", newparam, ast_str_buffer(buf));
first = 0;
/* If the column length isn't long enough, give a chance to lengthen it. */
@ -744,7 +744,7 @@ static int update2_mysql(const char *database, const char *tablename, va_list ap
}
ESCAPE_STRING(buf, newval);
ast_str_append(&sql, 0, "%s %s = '%s'", first ? "" : ",", newparam, ast_str_buffer(buf));
ast_str_append(&sql, 0, "%s `%s` = '%s'", first ? "" : ",", newparam, ast_str_buffer(buf));
first = 0;
/* If the column length isn't long enough, give a chance to lengthen it. */
@ -816,7 +816,7 @@ static int store_mysql(const char *database, const char *table, va_list ap)
/* Create the first part of the query using the first parameter/value pairs we just extracted
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
ESCAPE_STRING(buf, newval);
ast_str_set(&sql, 0, "INSERT INTO %s (%s", table, newparam);
ast_str_set(&sql, 0, "INSERT INTO %s (`%s`", table, newparam);
ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
internal_require(database, table, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
@ -828,7 +828,7 @@ static int store_mysql(const char *database, const char *table, va_list ap)
ast_str_reset(buf);
}
if (internal_require(database, table, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL) == 0) {
ast_str_append(&sql, 0, ", %s", newparam);
ast_str_append(&sql, 0, ", `%s`", newparam);
ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
}
}
@ -894,11 +894,11 @@ static int destroy_mysql(const char *database, const char *table, const char *ke
/* Create the first part of the query using the first parameter/value pairs we just extracted
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
ESCAPE_STRING(buf, lookup);
ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, keyfield, ast_str_buffer(buf));
ast_str_set(&sql, 0, "DELETE FROM %s WHERE `%s` = '%s'", table, keyfield, ast_str_buffer(buf));
while ((newparam = va_arg(ap, const char *))) {
newval = va_arg(ap, const char *);
ESCAPE_STRING(buf, newval);
ast_str_append(&sql, 0, " AND %s = '%s'", newparam, ast_str_buffer(buf));
ast_str_append(&sql, 0, " AND `%s` = '%s'", newparam, ast_str_buffer(buf));
}
va_end(ap);
@ -1074,7 +1074,7 @@ static int modify_mysql(const char *database, const char *tablename, struct colu
res = -1;
break;
}
ast_str_set(&sql, 0, "ALTER TABLE %s MODIFY %s %s", tablename, column->name, ast_str_buffer(typestr));
ast_str_set(&sql, 0, "ALTER TABLE %s MODIFY `%s` %s", tablename, column->name, ast_str_buffer(typestr));
if (!column->null) {
ast_str_append(&sql, 0, " NOT NULL");
}

View File

@ -27,6 +27,12 @@ all: _all
include $(ASTTOPDIR)/Makefile.moddir_rules
clean::
rm -f confbridge/*.o confbridge/*.i
$(if $(filter app_confbridge,$(EMBEDDED_MODS)),modules.link,app_confbridge.so): $(subst .c,.o,$(wildcard confbridge/*.c))
$(subst .c,.o,$(wildcard confbridge/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,app_confbridge)
ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
LIBS+= -lres_features.so -lres_ael_share.so -lres_monitor.so -lres_speech.so
LIBS+= -lres_smdi.so

View File

@ -157,7 +157,6 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
int iTotalTime = 0;
int iWordsCount = 0;
int currentState = STATE_IN_WORD;
int previousState = STATE_IN_SILENCE;
int consecutiveVoiceDuration = 0;
char amdCause[256] = "", amdStatus[256] = "";
char *parse = ast_strdupa(data);
@ -303,7 +302,6 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
if (silenceDuration >= betweenWordsSilence) {
if (currentState != STATE_IN_SILENCE ) {
previousState = currentState;
ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", chan->name);
}
/* Find words less than word duration */
@ -343,7 +341,6 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) {
iWordsCount++;
ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", chan->name, iWordsCount);
previousState = currentState;
currentState = STATE_IN_WORD;
}
if (consecutiveVoiceDuration >= maximumWordLength){

View File

@ -404,6 +404,7 @@ struct chanspy_translation_helper {
struct ast_audiohook bridge_whisper_audiohook;
int fd;
int volfactor;
struct ast_flags flags;
};
struct spy_dtmf_options {
@ -438,7 +439,7 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl
return -1;
}
if (ast_test_flag(&csth->spy_audiohook, OPTION_READONLY)) {
if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
/* Option 'o' was set, so don't mix channel audio */
f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, &format_slin);
} else {
@ -539,7 +540,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
spyer_name, name);
memset(&csth, 0, sizeof(csth));
ast_copy_flags(&csth.spy_audiohook, flags, AST_FLAGS_ALL);
ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);

File diff suppressed because it is too large Load Diff

View File

@ -768,12 +768,16 @@ static void senddialevent(struct ast_channel *src, struct ast_channel *dst, cons
"Destination: %s\r\n"
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n"
"UniqueID: %s\r\n"
"DestUniqueID: %s\r\n"
"Dialstring: %s\r\n",
src->name, dst->name,
S_COR(src->caller.id.number.valid, src->caller.id.number.str, "<unknown>"),
S_COR(src->caller.id.name.valid, src->caller.id.name.str, "<unknown>"),
S_COR(src->connected.id.number.valid, src->connected.id.number.str, "<unknown>"),
S_COR(src->connected.id.name.valid, src->connected.id.name.str, "<unknown>"),
src->uniqueid, dst->uniqueid,
dialstring ? dialstring : "");
}
@ -1244,14 +1248,17 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
/* Setup early media if appropriate */
if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
ast_channel_early_bridge(in, c);
if (!ast_test_flag64(outgoing, OPT_RINGBACK))
if (!ast_test_flag64(outgoing, OPT_RINGBACK)) {
if (single || (!single && !pa->sentringing)) {
ast_indicate(in, AST_CONTROL_PROGRESS);
}
if(!ast_strlen_zero(dtmf_progress)) {
ast_verb(3, "Sending DTMF '%s' to the called party as result of receiving a PROGRESS message.\n", dtmf_progress);
ast_dtmf_stream(c, in, dtmf_progress, 250, 0);
}
}
if (!ast_strlen_zero(dtmf_progress)) {
ast_verb(3,
"Sending DTMF '%s' to the called party as result of receiving a PROGRESS message.\n",
dtmf_progress);
ast_dtmf_stream(c, in, dtmf_progress, 250, 0);
}
break;
case AST_CONTROL_VIDUPDATE:
ast_verb(3, "%s requested a video update, passing it to %s\n", c->name, in->name);
@ -1418,12 +1425,17 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
}
}
if (single) {
/* Send the frame from the in channel to all outgoing channels. */
for (o = outgoing; o; o = o->next) {
if (!o->chan || !ast_test_flag64(o, DIAL_STILLGOING)) {
/* This outgoing channel has died so don't send the frame to it. */
continue;
}
switch (f->frametype) {
case AST_FRAME_HTML:
/* Forward HTML stuff */
if (!ast_test_flag64(outgoing, DIAL_NOFORWARDHTML)
&& ast_channel_sendhtml(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen) == -1) {
if (!ast_test_flag64(o, DIAL_NOFORWARDHTML)
&& ast_channel_sendhtml(o->chan, f->subclass.integer, f->data.ptr, f->datalen) == -1) {
ast_log(LOG_WARNING, "Unable to send URL\n");
}
break;
@ -1432,7 +1444,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
case AST_FRAME_TEXT:
case AST_FRAME_DTMF_BEGIN:
case AST_FRAME_DTMF_END:
if (ast_write(outgoing->chan, f)) {
if (ast_write(o->chan, f)) {
ast_log(LOG_WARNING, "Unable to forward frametype: %d\n",
f->frametype);
}
@ -1443,17 +1455,18 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
case AST_CONTROL_UNHOLD:
case AST_CONTROL_VIDUPDATE:
case AST_CONTROL_SRCUPDATE:
ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass.integer, outgoing->chan->name);
ast_indicate_data(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen);
ast_verb(3, "%s requested special control %d, passing it to %s\n",
in->name, f->subclass.integer, o->chan->name);
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
break;
case AST_CONTROL_CONNECTED_LINE:
if (ast_channel_connected_line_macro(in, outgoing->chan, f, 0, 1)) {
ast_indicate_data(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen);
if (ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
}
break;
case AST_CONTROL_REDIRECTING:
if (ast_channel_redirecting_macro(in, outgoing->chan, f, 0, 1)) {
ast_indicate_data(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen);
if (ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
}
break;
default:
@ -1939,7 +1952,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
goto done;
}
ast_verb(3, "Setting call duration limit to %.3lf milliseconds.\n", calldurationlimit.tv_sec + calldurationlimit.tv_usec / 1000000.0);
ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", calldurationlimit.tv_sec + calldurationlimit.tv_usec / 1000000.0);
}
if (ast_test_flag64(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) {
@ -2234,6 +2247,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
* No hint name available. We have a connected name supplied by
* the dialplan we can use instead.
*/
caller.id.name.valid = 1;
caller.id.name = chan->connected.id.name;
}
ast_channel_set_caller_event(tc, &caller, NULL);
@ -2247,6 +2261,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
* We have a connected name supplied by the dialplan we can
* use instead.
*/
caller.id.name.valid = 1;
caller.id.name = chan->connected.id.name;
ast_channel_set_caller_event(tc, &caller, NULL);
}
@ -2390,8 +2405,11 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
* to which the datastore was moved hangs up, it will attempt to free this
* datastore again, causing a crash
*/
if (!ast_channel_datastore_remove(chan, datastore))
ast_channel_lock(chan);
if (!ast_channel_datastore_remove(chan, datastore)) {
ast_datastore_free(datastore);
}
ast_channel_unlock(chan);
if (!peer) {
if (result) {
res = result;

View File

@ -97,60 +97,17 @@ static const char app[] = "Pickup";
static const char app2[] = "PickupChan";
/*! \todo This application should return a result code, like PICKUPRESULT */
/* Perform actual pickup between two channels */
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
{
int res = 0;
struct ast_party_connected_line connected_caller;
struct ast_channel *chans[2] = { chan, target };
ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
ast_party_connected_line_init(&connected_caller);
ast_party_connected_line_copy(&connected_caller, &target->connected);
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
ast_channel_update_connected_line(chan, &connected_caller, NULL);
}
ast_party_connected_line_free(&connected_caller);
ast_channel_lock(chan);
ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
ast_channel_unlock(chan);
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
ast_party_connected_line_free(&connected_caller);
if ((res = ast_answer(chan))) {
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
return -1;
}
if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {
ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
return -1;
}
if ((res = ast_channel_masquerade(target, chan))) {
ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
return -1;
}
/* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
"Channel: %s\r\nTargetChannel: %s\r\n", chan->name, target->name);
return res;
}
/* Helper function that determines whether a channel is capable of being picked up */
static int can_pickup(struct ast_channel *chan)
{
if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
if (!chan->pbx && !chan->masq &&
!ast_test_flag(chan, AST_FLAG_ZOMBIE) &&
(chan->_state == AST_STATE_RINGING ||
chan->_state == AST_STATE_RING ||
chan->_state == AST_STATE_DOWN)) {
return 1;
else
return 0;
}
return 0;
}
struct pickup_by_name_args {
@ -160,15 +117,15 @@ struct pickup_by_name_args {
static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
{
struct ast_channel *chan = obj;
struct ast_channel *target = obj;/*!< Potential pickup target */
struct pickup_by_name_args *args = data;
ast_channel_lock(chan);
if (!strncasecmp(chan->name, args->name, args->len) && can_pickup(chan)) {
ast_channel_lock(target);
if (!strncasecmp(target->name, args->name, args->len) && can_pickup(target)) {
/* Return with the channel still locked on purpose */
return CMP_MATCH | CMP_STOP;
}
ast_channel_unlock(chan);
ast_channel_unlock(target);
return 0;
}
@ -201,31 +158,29 @@ static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channam
return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
}
/*! \brief Attempt to pick up specified channel named , does not use context */
/*! \brief Attempt to pick up named channel, does not use context */
static int pickup_by_channel(struct ast_channel *chan, char *pickup)
{
int res = 0;
struct ast_channel *target;
int res = -1;
struct ast_channel *target;/*!< Potential pickup target */
if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
return -1;
target = my_ast_get_channel_by_name_locked(pickup);
if (target) {
/* Just check that we are not picking up the SAME as target. (i.e. ourself) */
if (chan != target) {
res = ast_do_pickup(chan, target);
}
ast_channel_unlock(target);
target = ast_channel_unref(target);
}
/* Just check that we are not picking up the SAME as target */
if (chan != target) {
res = pickup_do(chan, target);
}
ast_channel_unlock(target);
target = ast_channel_unref(target);
return res;
}
/* Attempt to pick up specified extension with context */
static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
{
struct ast_channel *target = NULL;
struct ast_channel *target = NULL;/*!< Potential pickup target */
struct ast_channel_iterator *iter;
int res = -1;
@ -236,6 +191,7 @@ static int pickup_by_exten(struct ast_channel *chan, const char *exten, const ch
while ((target = ast_channel_iterator_next(iter))) {
ast_channel_lock(target);
if ((chan != target) && can_pickup(target)) {
ast_log(LOG_NOTICE, "%s pickup by %s\n", target->name, chan->name);
break;
}
ast_channel_unlock(target);
@ -245,7 +201,7 @@ static int pickup_by_exten(struct ast_channel *chan, const char *exten, const ch
ast_channel_iterator_destroy(iter);
if (target) {
res = pickup_do(chan, target);
res = ast_do_pickup(chan, target);
ast_channel_unlock(target);
target = ast_channel_unref(target);
}
@ -255,31 +211,63 @@ static int pickup_by_exten(struct ast_channel *chan, const char *exten, const ch
static int find_by_mark(void *obj, void *arg, void *data, int flags)
{
struct ast_channel *c = obj;
struct ast_channel *target = obj;/*!< Potential pickup target */
const char *mark = data;
const char *tmp;
int res;
ast_channel_lock(c);
ast_channel_lock(target);
tmp = pbx_builtin_getvar_helper(target, PICKUPMARK);
if (tmp && !strcasecmp(tmp, mark) && can_pickup(target)) {
/* Return with the channel still locked on purpose */
return CMP_MATCH | CMP_STOP;
}
ast_channel_unlock(target);
res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
!strcasecmp(tmp, mark) &&
can_pickup(c);
ast_channel_unlock(c);
return res ? CMP_MATCH | CMP_STOP : 0;
return 0;
}
/* Attempt to pick up specified mark */
static int pickup_by_mark(struct ast_channel *chan, const char *mark)
{
struct ast_channel *target;
struct ast_channel *target;/*!< Potential pickup target */
int res = -1;
if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
ast_channel_lock(target);
res = pickup_do(chan, target);
/* The found channel is already locked. */
target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0);
if (target) {
res = ast_do_pickup(chan, target);
ast_channel_unlock(target);
target = ast_channel_unref(target);
}
return res;
}
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
{
struct ast_channel *target = obj;/*!< Potential pickup target */
struct ast_channel *chan = data;/*!< Channel wanting to pickup call */
ast_channel_lock(target);
if (chan != target && (chan->pickupgroup & target->callgroup) && can_pickup(target)) {
/* Return with the channel still locked on purpose */
return CMP_MATCH | CMP_STOP;
}
ast_channel_unlock(target);
return 0;
}
static int pickup_by_group(struct ast_channel *chan)
{
struct ast_channel *target;/*!< Potential pickup target */
int res = -1;
/* The found channel is already locked. */
target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
if (target) {
ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
res = ast_do_pickup(chan, target);
ast_channel_unlock(target);
target = ast_channel_unref(target);
}
@ -290,58 +278,63 @@ static int pickup_by_mark(struct ast_channel *chan, const char *mark)
/* application entry point for Pickup() */
static int pickup_exec(struct ast_channel *chan, const char *data)
{
int res = 0;
char *tmp = ast_strdupa(data);
char *exten = NULL, *context = NULL;
if (ast_strlen_zero(data)) {
res = ast_pickup_call(chan);
return res;
return pickup_by_group(chan) ? 0 : -1;
}
/* Parse extension (and context if there) */
while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
if ((context = strchr(exten, '@')))
*context++ = '\0';
if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
if (!pickup_by_mark(chan, exten))
break;
if (!pickup_by_mark(chan, exten)) {
/* Pickup successful. Stop the dialplan this channel is a zombie. */
return -1;
}
} else {
if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
break;
if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context)) {
/* Pickup successful. Stop the dialplan this channel is a zombie. */
return -1;
}
}
ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
}
return res;
/* Pickup failed. Keep going in the dialplan. */
return 0;
}
/* Find channel for pick up specified by partial channel name */
static int find_by_part(void *obj, void *arg, void *data, int flags)
{
struct ast_channel *c = obj;
struct ast_channel *target = obj;/*!< Potential pickup target */
const char *part = data;
int res = 0;
int len = strlen(part);
ast_channel_lock(c);
if (len <= strlen(c->name)) {
res = !(strncmp(c->name, part, len)) && (can_pickup(c));
ast_channel_lock(target);
if (len <= strlen(target->name) && !strncmp(target->name, part, len)
&& can_pickup(target)) {
/* Return with the channel still locked on purpose */
return CMP_MATCH | CMP_STOP;
}
ast_channel_unlock(c);
ast_channel_unlock(target);
return res ? CMP_MATCH | CMP_STOP : 0;
return 0;
}
/* Attempt to pick up specified by partial channel name */
static int pickup_by_part(struct ast_channel *chan, const char *part)
{
struct ast_channel *target;
struct ast_channel *target;/*!< Potential pickup target */
int res = -1;
if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
ast_channel_lock(target);
res = pickup_do(chan, target);
/* The found channel is already locked. */
target = ast_channel_callback(find_by_part, NULL, (char *) part, 0);
if (target) {
res = ast_do_pickup(chan, target);
ast_channel_unlock(target);
target = ast_channel_unref(target);
}
@ -352,7 +345,6 @@ static int pickup_by_part(struct ast_channel *chan, const char *part)
/* application entry point for PickupChan() */
static int pickupchan_exec(struct ast_channel *chan, const char *data)
{
int res = 0;
int partial_pickup = 0;
char *pickup = NULL;
char *parse = ast_strdupa(data);
@ -364,7 +356,8 @@ static int pickupchan_exec(struct ast_channel *chan, const char *data)
if (ast_strlen_zero(args.channel)) {
ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
return -1;
/* Pickup failed. Keep going in the dialplan. */
return 0;
}
if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
@ -378,16 +371,19 @@ static int pickupchan_exec(struct ast_channel *chan, const char *data)
} else {
if (partial_pickup) {
if (!pickup_by_part(chan, pickup)) {
break;
/* Pickup successful. Stop the dialplan this channel is a zombie. */
return -1;
}
} else if (!pickup_by_channel(chan, pickup)) {
break;
/* Pickup successful. Stop the dialplan this channel is a zombie. */
return -1;
}
ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
}
}
return res;
/* Pickup failed. Keep going in the dialplan. */
return 0;
}
static int unload_module(void)

View File

@ -36,6 +36,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/app.h"
#include "asterisk/translate.h"
/*** DOCUMENTATION
<application name="DumpChan" language="en_US">
@ -67,9 +68,11 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
struct timeval now;
long elapsed_seconds = 0;
int hour = 0, min = 0, sec = 0;
char cgrp[BUFSIZ/2];
char pgrp[BUFSIZ/2];
char formatbuf[BUFSIZ/2];
char nf[256];
char cgrp[256];
char pgrp[256];
struct ast_str *write_transpath = ast_str_alloca(256);
struct ast_str *read_transpath = ast_str_alloca(256);
now = ast_tvnow();
memset(buf, 0, size);
@ -84,65 +87,83 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
}
snprintf(buf,size,
"Name= %s\n"
"Type= %s\n"
"UniqueID= %s\n"
"CallerIDNum= %s\n"
"CallerIDName= %s\n"
"DNIDDigits= %s\n"
"RDNIS= %s\n"
"Parkinglot= %s\n"
"Language= %s\n"
"State= %s (%d)\n"
"Rings= %d\n"
"NativeFormat= %s\n"
"WriteFormat= %s\n"
"ReadFormat= %s\n"
"RawWriteFormat= %s\n"
"RawReadFormat= %s\n"
"1stFileDescriptor= %d\n"
"Framesin= %d %s\n"
"Framesout= %d %s\n"
"TimetoHangup= %ld\n"
"ElapsedTime= %dh%dm%ds\n"
"Context= %s\n"
"Extension= %s\n"
"Priority= %d\n"
"CallGroup= %s\n"
"PickupGroup= %s\n"
"Application= %s\n"
"Data= %s\n"
"Blocking_in= %s\n",
c->name,
c->tech->type,
c->uniqueid,
S_COR(c->caller.id.number.valid, c->caller.id.number.str, "(N/A)"),
S_COR(c->caller.id.name.valid, c->caller.id.name.str, "(N/A)"),
S_OR(c->dialed.number.str, "(N/A)"),
S_COR(c->redirecting.from.number.valid, c->redirecting.from.number.str, "(N/A)"),
c->parkinglot,
c->language,
ast_state2str(c->_state),
c->_state,
c->rings,
ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->nativeformats),
ast_getformatname(&c->writeformat),
ast_getformatname(&c->readformat),
ast_getformatname(&c->rawwriteformat),
ast_getformatname(&c->rawreadformat),
c->fds[0], c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", (long)c->whentohangup.tv_sec,
hour,
min,
sec,
c->context,
c->exten,
c->priority,
ast_print_group(cgrp, sizeof(cgrp), c->callgroup),
ast_print_group(pgrp, sizeof(pgrp), c->pickupgroup),
( c->appl ? c->appl : "(N/A)" ),
( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
(ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
"Name= %s\n"
"Type= %s\n"
"UniqueID= %s\n"
"LinkedID= %s\n"
"CallerIDNum= %s\n"
"CallerIDName= %s\n"
"ConnectedLineIDNum= %s\n"
"ConnectedLineIDName=%s\n"
"DNIDDigits= %s\n"
"RDNIS= %s\n"
"Parkinglot= %s\n"
"Language= %s\n"
"State= %s (%d)\n"
"Rings= %d\n"
"NativeFormat= %s\n"
"WriteFormat= %s\n"
"ReadFormat= %s\n"
"RawWriteFormat= %s\n"
"RawReadFormat= %s\n"
"WriteTranscode= %s %s\n"
"ReadTranscode= %s %s\n"
"1stFileDescriptor= %d\n"
"Framesin= %d %s\n"
"Framesout= %d %s\n"
"TimetoHangup= %ld\n"
"ElapsedTime= %dh%dm%ds\n"
"DirectBridge= %s\n"
"IndirectBridge= %s\n"
"Context= %s\n"
"Extension= %s\n"
"Priority= %d\n"
"CallGroup= %s\n"
"PickupGroup= %s\n"
"Application= %s\n"
"Data= %s\n"
"Blocking_in= %s\n",
c->name,
c->tech->type,
c->uniqueid,
c->linkedid,
S_COR(c->caller.id.number.valid, c->caller.id.number.str, "(N/A)"),
S_COR(c->caller.id.name.valid, c->caller.id.name.str, "(N/A)"),
S_COR(c->connected.id.number.valid, c->connected.id.number.str, "(N/A)"),
S_COR(c->connected.id.name.valid, c->connected.id.name.str, "(N/A)"),
S_OR(c->dialed.number.str, "(N/A)"),
S_COR(c->redirecting.from.number.valid, c->redirecting.from.number.str, "(N/A)"),
c->parkinglot,
c->language,
ast_state2str(c->_state),
c->_state,
c->rings,
ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats),
ast_getformatname(&c->writeformat),
ast_getformatname(&c->readformat),
ast_getformatname(&c->rawwriteformat),
ast_getformatname(&c->rawreadformat),
c->writetrans ? "Yes" : "No",
ast_translate_path_to_str(c->writetrans, &write_transpath),
c->readtrans ? "Yes" : "No",
ast_translate_path_to_str(c->readtrans, &read_transpath),
c->fds[0],
c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
(long)c->whentohangup.tv_sec,
hour,
min,
sec,
c->_bridge ? c->_bridge->name : "<none>",
ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "<none>",
c->context,
c->exten,
c->priority,
ast_print_group(cgrp, sizeof(cgrp), c->callgroup),
ast_print_group(pgrp, sizeof(pgrp), c->pickupgroup),
c->appl ? c->appl : "(N/A)",
c->data ? S_OR(c->data, "(Empty)") : "(None)",
(ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
return 0;
}
@ -150,7 +171,7 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
static int dumpchan_exec(struct ast_channel *chan, const char *data)
{
struct ast_str *vars = ast_str_thread_get(&ast_str_thread_global_buf, 16);
char info[1024];
char info[2048];
int level = 0;
static char *line = "================================================================================";
@ -160,7 +181,13 @@ static int dumpchan_exec(struct ast_channel *chan, const char *data)
if (option_verbose >= level) {
serialize_showchan(chan, info, sizeof(info));
pbx_builtin_serialize_variables(chan, &vars);
ast_verbose("\nDumping Info For Channel: %s:\n%s\nInfo:\n%s\nVariables:\n%s%s\n", chan->name, line, info, ast_str_buffer(vars), line);
ast_verbose("\n"
"Dumping Info For Channel: %s:\n"
"%s\n"
"Info:\n"
"%s\n"
"Variables:\n"
"%s%s\n", chan->name, line, info, ast_str_buffer(vars), line);
}
return 0;

View File

@ -255,6 +255,9 @@ static void phase_e_handler(t30_state_t *f, void *user_data, int result)
"Channel: %s\r\n"
"Exten: %s\r\n"
"CallerID: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n"
"RemoteStationID: %s\r\n"
"LocalStationID: %s\r\n"
"PagesTransferred: %d\r\n"
@ -264,6 +267,9 @@ static void phase_e_handler(t30_state_t *f, void *user_data, int result)
s->chan->name,
s->chan->exten,
S_COR(s->chan->caller.id.number.valid, s->chan->caller.id.number.str, ""),
S_COR(s->chan->caller.id.name.valid, s->chan->caller.id.name.str, ""),
S_COR(s->chan->connected.id.number.valid, s->chan->connected.id.number.str, ""),
S_COR(s->chan->connected.id.name.valid, s->chan->connected.id.name.str, ""),
far_ident,
local_ident,
pages_transferred,

View File

@ -163,7 +163,6 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
{
int res = 0;
int fds[2];
int pid = -1;
int needed = 0;
struct ast_format owriteformat;
struct ast_frame *f;
@ -196,7 +195,6 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
res = send_waveform_to_fd(waveform, length, fds[1]);
if (res >= 0) {
pid = res;
/* Order is important -- there's almost always going to be mp3... we want to prioritize the
user */
for (;;) {
@ -258,10 +256,6 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
close(fds[0]);
close(fds[1]);
#if 0
if (pid > -1)
kill(pid, SIGKILL);
#endif
if (!res && owriteformat.id)
ast_set_write_format(chan, &owriteformat);
return res;
@ -285,7 +279,6 @@ static int festival_exec(struct ast_channel *chan, const char *vdata)
char ack[4];
char *waveform;
int filesize;
int wave;
char bigstring[MAXFESTLEN];
int i;
struct MD5Context md5ctx;
@ -494,7 +487,6 @@ static int festival_exec(struct ast_channel *chan, const char *vdata)
/* Read back info from server */
/* This assumes only one waveform will come back, also LP is unlikely */
wave = 0;
do {
int read_data;
for (n = 0; n < 3; ) {

View File

@ -804,7 +804,6 @@ static void findmeexec(struct fm_args *tpargs)
char *rest, *number;
struct findme_user *tmpuser;
struct findme_user *fmuser;
struct findme_user *headuser;
struct findme_user_listptr *findme_user_list;
int status;
@ -915,7 +914,6 @@ static void findmeexec(struct fm_args *tpargs)
fmuser = NULL;
tmpuser = NULL;
headuser = NULL;
if (winner)
break;

View File

@ -112,7 +112,6 @@ static int ices_exec(struct ast_channel *chan, const char *data)
int pid = -1;
int flags;
struct ast_format oreadformat;
struct timeval last;
struct ast_frame *f;
char filename[256]="";
char *c;
@ -123,8 +122,6 @@ static int ices_exec(struct ast_channel *chan, const char *data)
return -1;
}
last = ast_tv(0, 0);
if (pipe(fds)) {
ast_log(LOG_WARNING, "Unable to create pipe\n");
return -1;

View File

@ -626,8 +626,9 @@ enum {
CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31),
};
/* !If set play an intro announcement at start of conference */
#define CONFFLAG_INTROMSG ((uint64_t)1 << 32)
/* These flags are defined separately because we ran out of bits that an enum can be used to represent.
If you add new flags, be sure to do it in the same way that CONFFLAG_INTROMSG is. */
#define CONFFLAG_INTROMSG ((uint64_t)1 << 32) /*!< If set play an intro announcement at start of conference */
#define CONFFLAG_INTROUSER_VMREC ((uint64_t)1 << 33)
enum {
@ -779,13 +780,13 @@ struct ast_conf_user {
char usrvalue[50]; /*!< Custom User Value */
char namerecloc[PATH_MAX]; /*!< Name Recorded file Location */
time_t jointime; /*!< Time the user joined the conference */
time_t kicktime; /*!< Time the user will be kicked from the conference */
struct timeval start_time; /*!< Time the user entered into the conference */
long timelimit; /*!< Time limit for the user to be in the conference L(x:y:z) */
long play_warning; /*!< Play a warning when 'y' ms are left */
long warning_freq; /*!< Repeat the warning every 'z' ms */
const char *warning_sound; /*!< File to play as warning if 'y' is defined */
const char *end_sound; /*!< File to play when time is up. */
time_t kicktime; /*!< Time the user will be kicked from the conference */
struct timeval start_time; /*!< Time the user entered into the conference */
long timelimit; /*!< Time limit for the user to be in the conference L(x:y:z) */
long play_warning; /*!< Play a warning when 'y' ms are left */
long warning_freq; /*!< Repeat the warning every 'z' ms */
const char *warning_sound; /*!< File to play as warning if 'y' is defined */
const char *end_sound; /*!< File to play when time is up. */
struct volume talk;
struct volume listen;
AST_LIST_ENTRY(ast_conf_user) list;
@ -1370,6 +1371,7 @@ static char *complete_meetmecmd(const char *line, const char *word, int pos, int
AST_LIST_UNLOCK(&confs);
return usr ? ast_strdup(usrno) : NULL;
}
AST_LIST_UNLOCK(&confs);
}
}
@ -2245,7 +2247,6 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
int talkreq_manager = 0;
int using_pseudo = 0;
int duration = 20;
int hr, min, sec;
int sent_event = 0;
int checked = 0;
int announcement_played = 0;
@ -2732,7 +2733,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
ao2_ref(item, -1);
}
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED && !conf->markedusers))
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
dahdic.confmode = DAHDI_CONF_CONF;
else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
@ -2755,11 +2756,15 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
"Meetme: %s\r\n"
"Usernum: %d\r\n"
"CallerIDnum: %s\r\n"
"CallerIDname: %s\r\n",
"CallerIDname: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n",
chan->name, chan->uniqueid, conf->confno,
user->user_no,
S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>")
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>"),
S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<unknown>")
);
sent_event = 1;
}
@ -2917,6 +2922,11 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
res = ast_streamfile(chan, user->end_sound, chan->language);
res = ast_waitstream(chan, "");
}
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
ret = 0;
} else {
ret = -1;
}
break;
}
@ -3802,9 +3812,6 @@ bailoutandtrynormal:
if (user->user_no) {
/* Only cleanup users who really joined! */
now = ast_tvnow();
hr = (now.tv_sec - user->jointime) / 3600;
min = ((now.tv_sec - user->jointime) % 3600) / 60;
sec = (now.tv_sec - user->jointime) % 60;
if (sent_event) {
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeLeave",
@ -3814,11 +3821,15 @@ bailoutandtrynormal:
"Usernum: %d\r\n"
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n"
"Duration: %ld\r\n",
chan->name, chan->uniqueid, conf->confno,
user->user_no,
S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>"),
S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<unknown>"),
(long)(now.tv_sec - user->jointime));
}
@ -3906,7 +3917,7 @@ static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char
ast_localtime(&now, &tm, NULL);
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
ast_debug(1, "Looking for conference %s that starts after %s\n", confno, currenttime);
var = ast_load_realtime("meetme", "confno",
confno, "starttime <= ", currenttime, "endtime >= ",
@ -4880,6 +4891,8 @@ static int action_meetmelist(struct mansession *s, const struct message *m)
"UserNumber: %d\r\n"
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n"
"Channel: %s\r\n"
"Admin: %s\r\n"
"Role: %s\r\n"
@ -4892,6 +4905,8 @@ static int action_meetmelist(struct mansession *s, const struct message *m)
user->user_no,
S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<no name>"),
user->chan->name,
ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
@ -6453,7 +6468,6 @@ static int sla_trunk_exec(struct ast_channel *chan, const char *data)
AST_APP_ARG(options);
);
char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
struct ast_flags opt_flags = { 0 };
char *parse;
@ -6516,7 +6530,6 @@ static int sla_trunk_exec(struct ast_channel *chan, const char *data)
if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
ast_indicate(chan, -1);
ast_set_flag64(&conf_flags, CONFFLAG_MOH);
conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
} else
ast_indicate(chan, AST_CONTROL_RINGING);

View File

@ -1229,7 +1229,7 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
struct ast_tm tm;
struct minivm_zone *the_zone = NULL;
struct ast_channel *ast;
char *finalfilename;
char *finalfilename = "";
struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
char *fromaddress;
char *fromemail;
@ -1266,13 +1266,22 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
char tmpcmd[PATH_MAX];
int tmpfd;
/**
* XXX
* /bug tmpfd is a leaked fd. The file is also never unlinked.
* See app_voicemail.c for how the code works there that
* doesn't have this bug.
*/
ast_copy_string(newtmp, "/tmp/XXXXXX", sizeof(newtmp));
ast_debug(3, "newtmp: %s\n", newtmp);
tmpfd = mkstemp(newtmp);
snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, filename, format, newtmp, format);
ast_safe_system(tmpcmd);
finalfilename = newtmp;
ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", filename, format, vmu->volgain, vmu->username);
if (tmpfd > -1) {
snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, filename, format, newtmp, format);
ast_safe_system(tmpcmd);
finalfilename = newtmp;
ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", filename, format, vmu->volgain, vmu->username);
}
} else {
finalfilename = ast_strdupa(filename);
}
@ -1828,7 +1837,6 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
char callerid[256];
FILE *txt;
int res = 0, txtdes;
int msgnum;
int duration = 0;
char date[256];
char tmpdir[PATH_MAX];
@ -1871,7 +1879,6 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
return res;
}
msgnum = 0;
userdir = check_dirpath(tmpdir, sizeof(tmpdir), vmu->domain, username, "tmp");
@ -2452,7 +2459,6 @@ static int minivm_accmess_exec(struct ast_channel *chan, const char *data)
char *message = NULL;
char *prompt = NULL;
int duration;
int cmd;
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "MinivmAccmess needs at least two arguments: account and option\n");
@ -2526,7 +2532,7 @@ static int minivm_accmess_exec(struct ast_channel *chan, const char *data)
}
snprintf(filename,sizeof(filename), "%s%s/%s/%s", MVM_SPOOL_DIR, vmu->domain, vmu->username, message);
/* Maybe we should check the result of play_record_review ? */
cmd = play_record_review(chan, prompt, filename, global_maxgreet, default_vmformat, 0, vmu, &duration, NULL, FALSE);
play_record_review(chan, prompt, filename, global_maxgreet, default_vmformat, 0, vmu, &duration, NULL, FALSE);
ast_debug(1, "Recorded new %s message in %s (duration %d)\n", message, filename, duration);
@ -3238,12 +3244,10 @@ static int minivm_account_func_read(struct ast_channel *chan, const char *cmd, c
check_dirpath(buf, len, vmu->domain, vmu->username, NULL);
} else { /* Look in channel variables */
struct ast_variable *var;
int found = 0;
for (var = vmu->chanvars ; var ; var = var->next)
if (!strcmp(var->name, colname)) {
ast_copy_string(buf, var->value, len);
found = 1;
break;
}
}

View File

@ -101,7 +101,6 @@ static int originate_exec(struct ast_channel *chan, const char *data)
char *parse;
char *chantech, *chandata;
int res = -1;
int outgoing_res = 0;
int outgoing_status = 0;
static const unsigned int timeout = 30;
static const char default_exten[] = "s";
@ -154,14 +153,14 @@ static int originate_exec(struct ast_channel *chan, const char *data)
ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n",
chantech, chandata, args.arg1, exten, priority);
outgoing_res = ast_pbx_outgoing_exten(chantech, cap_slin, chandata,
ast_pbx_outgoing_exten(chantech, cap_slin, chandata,
timeout * 1000, args.arg1, exten, priority, &outgoing_status, 0, NULL,
NULL, NULL, NULL, NULL);
} else if (!strcasecmp(args.type, "app")) {
ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
chantech, chandata, args.arg1, S_OR(args.arg2, ""));
outgoing_res = ast_pbx_outgoing_app(chantech, cap_slin, chandata,
ast_pbx_outgoing_app(chantech, cap_slin, chandata,
timeout * 1000, args.arg1, args.arg2, &outgoing_status, 0, NULL,
NULL, NULL, NULL, NULL);
} else {

View File

@ -53,6 +53,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<parameter name="minlength">
<para>Minimum allowable digits in the input callerid number. Defaults to <literal>10</literal>.</para>
</parameter>
<parameter name="options">
<para>Position reserved for options.</para>
</parameter>
<parameter name="context">
<para>Context to check the given callerid against patterns.</para>
</parameter>

View File

@ -999,7 +999,7 @@ struct callattempt {
struct queue_ent {
struct call_queue *parent; /*!< What queue is our parent */
char moh[80]; /*!< Name of musiconhold to be used */
char announce[80]; /*!< Announcement to play for member when call is answered */
char announce[PATH_MAX]; /*!< Announcement to play for member when call is answered */
char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
@ -2072,9 +2072,9 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
* \brief Find rt member record to update otherwise create one.
*
* Search for member in queue, if found update penalty/paused state,
* if no member exists create one flag it as a RT member and add to queue member list.
* if no member exists create one flag it as a RT member and add to queue member list.
*/
static void rt_handle_member_record(struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
static void rt_handle_member_record(struct call_queue *q, char *interface, struct ast_config *member_config)
{
struct member *m;
struct ao2_iterator mem_iter;
@ -2082,6 +2082,12 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, const
int paused = 0;
int found = 0;
const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid");
const char *membername = S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface);
const char *state_interface = S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface);
const char *penalty_str = ast_variable_retrieve(member_config, interface, "penalty");
const char *paused_str = ast_variable_retrieve(member_config, interface, "paused");
if (ast_strlen_zero(rt_uniqueid)) {
ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
return;
@ -2299,12 +2305,7 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
ao2_iterator_destroy(&mem_iter);
while ((interface = ast_category_browse(member_config, interface))) {
rt_handle_member_record(q, interface,
ast_variable_retrieve(member_config, interface, "uniqueid"),
S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
ast_variable_retrieve(member_config, interface, "penalty"),
ast_variable_retrieve(member_config, interface, "paused"),
S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
rt_handle_member_record(q, interface, member_config);
}
/* Delete all realtime members that have been deleted in DB. */
@ -2426,12 +2427,7 @@ static void update_realtime_members(struct call_queue *q)
ao2_iterator_destroy(&mem_iter);
while ((interface = ast_category_browse(member_config, interface))) {
rt_handle_member_record(q, interface,
ast_variable_retrieve(member_config, interface, "uniqueid"),
S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
ast_variable_retrieve(member_config, interface, "penalty"),
ast_variable_retrieve(member_config, interface, "paused"),
S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
rt_handle_member_record(q, interface, member_config);
}
/* Delete all realtime members that have been deleted in DB. */
@ -2515,10 +2511,20 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
q->count++;
res = 0;
ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
"Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
"Channel: %s\r\n"
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n"
"Queue: %s\r\n"
"Position: %d\r\n"
"Count: %d\r\n"
"Uniqueid: %s\r\n",
qe->chan->name,
S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
q->name, qe->pos, q->count, qe->chan->uniqueid );
ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
}
@ -3152,6 +3158,8 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
"DestinationChannel: %s\r\n"
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n"
"Context: %s\r\n"
"Extension: %s\r\n"
"Priority: %d\r\n"
@ -3160,6 +3168,8 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
S_COR(tmp->chan->caller.id.number.valid, tmp->chan->caller.id.number.str, "unknown"),
S_COR(tmp->chan->caller.id.name.valid, tmp->chan->caller.id.name.str, "unknown"),
S_COR(tmp->chan->connected.id.number.valid, tmp->chan->connected.id.number.str, "unknown"),
S_COR(tmp->chan->connected.id.name.valid, tmp->chan->connected.id.name.str, "unknown"),
qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
ast_verb(3, "Called %s\n", tmp->interface);
@ -4323,7 +4333,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
char *agiexec = NULL;
char *macroexec = NULL;
char *gosubexec = NULL;
int ret = 0;
const char *monitorfilename;
const char *monitor_exec;
const char *monitor_options;
@ -4849,7 +4858,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
/* We purposely lock the CDR so that pbx_exec does not update the application data */
if (qe->chan->cdr)
ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
pbx_exec(qe->chan, mixmonapp, mixmonargs);
if (qe->chan->cdr)
ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
@ -4981,7 +4990,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
application = pbx_findapp("agi");
if (application) {
agiexec = ast_strdupa(agi);
ret = pbx_exec(qe->chan, application, agiexec);
pbx_exec(qe->chan, application, agiexec);
} else
ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
}
@ -7248,12 +7257,16 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
"Uniqueid: %s\r\n"
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n"
"Wait: %ld\r\n"
"%s"
"\r\n",
q->name, pos++, qe->chan->name, qe->chan->uniqueid,
S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
(long) (now - qe->start), idText);
}
}

View File

@ -1975,7 +1975,11 @@ unsigned int seq;
return;
}
n = finddelim(astr,astrs,100);
if (n < 1) return;
if (n < 1) {
ast_free(str);
ast_free(astr);
return;
}
ast_mutex_lock(&myrpt->statpost_lock);
seq = ++myrpt->statpost_seqno;
ast_mutex_unlock(&myrpt->statpost_lock);
@ -12218,7 +12222,7 @@ struct ast_format_cap *cap = NULL;
// ctcss code autopatch initiate
if (strstr((char *)f->data.ptr,"/M/")&& !myrpt->macropatch)
{
char value[16];
char value[16] = "";
strcat(value,"*6");
myrpt->macropatch=1;
rpt_mutex_lock(&myrpt->lock);

View File

@ -85,7 +85,12 @@ static int userevent_exec(struct ast_channel *chan, const char *data)
ast_str_append(&body, 0, "%s\r\n", args.extra[x]);
}
manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", args.eventname, ast_str_buffer(body));
manager_event(EVENT_FLAG_USER, "UserEvent",
"UserEvent: %s\r\n"
"Uniqueid: %s\r\n"
"%s",
args.eventname, chan->uniqueid, ast_str_buffer(body));
ast_free(body);
return 0;

View File

@ -2177,11 +2177,16 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char
int ret; /* for better error checking */
char *imap_flags = NIL;
int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
int box = NEW_FOLDER;
/* Back out early if this is a greeting and we don't want to store greetings in IMAP */
if (msgnum < 0 && !imapgreetings) {
return 0;
}
/* Back out early if this is a greeting and we don't want to store greetings in IMAP */
if (msgnum < 0) {
if(!imapgreetings) {
return 0;
} else {
box = GREETINGS_FOLDER;
}
}
if (imap_check_limits(chan, vms, vmu, msgcount)) {
return -1;
@ -2264,9 +2269,9 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char
}
((char *) buf)[len] = '\0';
INIT(&str, mail_string, buf, len);
ret = init_mailstream(vms, NEW_FOLDER);
ret = init_mailstream(vms, box);
if (ret == 0) {
imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1);
imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
ast_mutex_lock(&vms->lock);
if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
@ -4734,6 +4739,7 @@ static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format,
char fname[256];
char tmpcmd[256];
int tmpfd = -1;
int soxstatus = 0;
/* Eww. We want formats to tell us their own MIME type */
char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
@ -4745,7 +4751,6 @@ static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format,
chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
ast_debug(3, "newtmp: %s\n", newtmp);
if (tmpfd > -1) {
int soxstatus;
snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
attach = newtmp;
@ -4773,7 +4778,9 @@ static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format,
if (last)
fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
if (tmpfd > -1) {
unlink(fname);
if (soxstatus == 0) {
unlink(fname);
}
close(tmpfd);
unlink(newtmp);
}
@ -6696,7 +6703,21 @@ static int get_folder(struct ast_channel *chan, int start)
if (d)
return d;
snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x)); /* Folder name */
d = vm_play_folder_name(chan, fn);
/* The inbox folder can have its name changed under certain conditions
* so this checks if the sound file exists for the inbox folder name and
* if it doesn't, plays the default name instead. */
if (x == 0) {
if (ast_fileexists(fn, NULL, NULL)) {
d = vm_play_folder_name(chan, fn);
} else {
ast_verb(1, "failed to find %s\n", fn);
d = vm_play_folder_name(chan, "vm-INBOX");
}
} else {
d = vm_play_folder_name(chan, fn);
}
if (d)
return d;
d = ast_waitfordigit(chan, 500);
@ -7061,7 +7082,6 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
char *dir;
int curmsg;
char urgent_str[7] = "";
char tmptxtfile[PATH_MAX];
int prompt_played = 0;
#ifndef IMAP_STORAGE
char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
@ -7074,7 +7094,6 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
dir = vms->curdir;
curmsg = vms->curmsg;
tmptxtfile[0] = '\0';
while (!res && !valid_extensions) {
int use_directory = 0;
if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
@ -12129,6 +12148,9 @@ static int load_config(int reload)
if (ucfg) {
for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
if (!strcasecmp(cat, "general")) {
continue;
}
if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
continue;
if ((current = find_or_create(userscontext, cat))) {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,320 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2011, Digium, Inc.
*
* David Vossel <dvossel@digium.com>
* Joshua Colp <jcolp@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#ifndef _CONFBRIDGE_H
#define _CONFBRIDGE_H
#include "asterisk.h"
#include "asterisk/app.h"
#include "asterisk/logger.h"
#include "asterisk/linkedlists.h"
#include "asterisk/channel.h"
#include "asterisk/bridging.h"
#include "asterisk/bridging_features.h"
/* Maximum length of a conference bridge name */
#define MAX_CONF_NAME 32
/* Maximum length of a conference pin */
#define MAX_PIN 80
#define DEFAULT_USER_PROFILE "default_user"
#define DEFAULT_BRIDGE_PROFILE "default_bridge"
#define DEFAULT_TALKING_THRESHOLD 160
#define DEFAULT_SILENCE_THRESHOLD 2500
enum user_profile_flags {
USER_OPT_ADMIN = (1 << 0), /*!< Set if the caller is an administrator */
USER_OPT_NOONLYPERSON = (1 << 1), /*!< Set if the "you are currently the only person in this conference" sound file should not be played */
USER_OPT_MARKEDUSER = (1 << 2), /*!< Set if the caller is a marked user */
USER_OPT_STARTMUTED = (1 << 3), /*!< Set if the caller should be initially set muted */
USER_OPT_MUSICONHOLD = (1 << 4), /*!< Set if music on hold should be played if nobody else is in the conference bridge */
USER_OPT_QUIET = (1 << 5), /*!< Set if no audio prompts should be played */
USER_OPT_ANNOUNCEUSERCOUNT = (1 << 6), /*!< Set if the number of users should be announced to the caller */
USER_OPT_WAITMARKED = (1 << 7), /*!< Set if the user must wait for a marked user before starting */
USER_OPT_ENDMARKED = (1 << 8), /*!< Set if the user should be kicked after the last Marked user exits */
USER_OPT_DENOISE = (1 << 9), /*!< Sets if denoise filter should be used on audio before mixing. */
USER_OPT_ANNOUNCE_JOIN_LEAVE = (1 << 10), /*!< Sets if the user's name should be recorded and announced on join and leave. */
USER_OPT_TALKER_DETECT = (1 << 11), /*!< Sets if start and stop talking events should generated for this user over AMI. */
USER_OPT_DROP_SILENCE = (1 << 12), /*!< Sets if silence should be dropped from the mix or not. */
USER_OPT_DTMF_PASS = (1 << 13), /*!< Sets if dtmf should be passed into the conference or not */
USER_OPT_ANNOUNCEUSERCOUNTALL = (1 << 14), /*!< Sets if the number of users should be announced to everyone. */
USER_OPT_JITTERBUFFER = (1 << 15), /*!< Places a jitterbuffer on the user. */
};
enum bridge_profile_flags {
BRIDGE_OPT_RECORD_CONFERENCE = (1 << 0), /*!< Set if the conference should be recorded */
};
enum conf_menu_action_id {
MENU_ACTION_TOGGLE_MUTE = 1,
MENU_ACTION_PLAYBACK,
MENU_ACTION_PLAYBACK_AND_CONTINUE,
MENU_ACTION_INCREASE_LISTENING,
MENU_ACTION_DECREASE_LISTENING,
MENU_ACTION_RESET_LISTENING,
MENU_ACTION_RESET_TALKING,
MENU_ACTION_INCREASE_TALKING,
MENU_ACTION_DECREASE_TALKING,
MENU_ACTION_DIALPLAN_EXEC,
MENU_ACTION_ADMIN_TOGGLE_LOCK,
MENU_ACTION_ADMIN_KICK_LAST,
MENU_ACTION_LEAVE,
MENU_ACTION_NOOP,
};
/*! The conference menu action contains both
* the action id that represents the action that
* must take place, along with any data associated
* with that action. */
struct conf_menu_action {
enum conf_menu_action_id id;
union {
char playback_file[PATH_MAX];
struct {
char context[AST_MAX_CONTEXT];
char exten[AST_MAX_EXTENSION];
int priority;
} dialplan_args;
} data;
AST_LIST_ENTRY(conf_menu_action) action;
};
/*! Conference menu entries contain the DTMF sequence
* and the list of actions that are associated with that
* sequence. */
struct conf_menu_entry {
/*! the DTMF sequence that triggers the actions */
char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
/*! The actions associated with this menu entry. */
AST_LIST_HEAD_NOLOCK(, conf_menu_action) actions;
AST_LIST_ENTRY(conf_menu_entry) entry;
};
/*! Conference menu structure. Contains a list
* of DTMF sequences coupled with the actions those
* sequences invoke.*/
struct conf_menu {
char name[128];
int delme;
AST_LIST_HEAD_NOLOCK(, conf_menu_entry) entries;
};
struct user_profile {
char name[128];
char pin[MAX_PIN];
char moh_class[128];
unsigned int flags;
unsigned int announce_user_count_all_after;
/*! The time in ms of talking before a user is considered to be talking by the dsp. */
unsigned int talking_threshold;
/*! The time in ms of silence before a user is considered to be silent by the dsp. */
unsigned int silence_threshold;
int delme;
};
enum conf_sounds {
CONF_SOUND_HAS_JOINED,
CONF_SOUND_HAS_LEFT,
CONF_SOUND_KICKED,
CONF_SOUND_MUTED,
CONF_SOUND_UNMUTED,
CONF_SOUND_ONLY_ONE,
CONF_SOUND_THERE_ARE,
CONF_SOUND_OTHER_IN_PARTY,
CONF_SOUND_PLACE_IN_CONF,
CONF_SOUND_WAIT_FOR_LEADER,
CONF_SOUND_LEADER_HAS_LEFT,
CONF_SOUND_GET_PIN,
CONF_SOUND_INVALID_PIN,
CONF_SOUND_ONLY_PERSON,
CONF_SOUND_LOCKED,
CONF_SOUND_LOCKED_NOW,
CONF_SOUND_UNLOCKED_NOW,
CONF_SOUND_ERROR_MENU,
CONF_SOUND_JOIN,
CONF_SOUND_LEAVE,
};
struct bridge_profile_sounds {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(hasjoin);
AST_STRING_FIELD(hasleft);
AST_STRING_FIELD(kicked);
AST_STRING_FIELD(muted);
AST_STRING_FIELD(unmuted);
AST_STRING_FIELD(onlyone);
AST_STRING_FIELD(thereare);
AST_STRING_FIELD(otherinparty);
AST_STRING_FIELD(placeintoconf);
AST_STRING_FIELD(waitforleader);
AST_STRING_FIELD(leaderhasleft);
AST_STRING_FIELD(getpin);
AST_STRING_FIELD(invalidpin);
AST_STRING_FIELD(onlyperson);
AST_STRING_FIELD(locked);
AST_STRING_FIELD(lockednow);
AST_STRING_FIELD(unlockednow);
AST_STRING_FIELD(errormenu);
AST_STRING_FIELD(leave);
AST_STRING_FIELD(join);
);
};
struct bridge_profile {
char name[64];
char rec_file[PATH_MAX];
unsigned int flags;
unsigned int max_members; /*!< The maximum number of participants allowed in the conference */
unsigned int internal_sample_rate; /*!< The internal sample rate of the bridge. 0 when set to auto adjust mode. */
unsigned int mix_interval; /*!< The internal mixing interval used by the bridge. When set to 0 the bridgewill use a default interval. */
struct bridge_profile_sounds *sounds;
int delme;
};
/*! \brief The structure that represents a conference bridge */
struct conference_bridge {
char name[MAX_CONF_NAME]; /*!< Name of the conference bridge */
struct ast_bridge *bridge; /*!< Bridge structure doing the mixing */
struct bridge_profile b_profile; /*!< The Bridge Configuration Profile */
unsigned int users; /*!< Number of users present */
unsigned int markedusers; /*!< Number of marked users present */
unsigned int locked:1; /*!< Is this conference bridge locked? */
struct ast_channel *playback_chan; /*!< Channel used for playback into the conference bridge */
struct ast_channel *record_chan; /*!< Channel used for recording the conference */
pthread_t record_thread; /*!< The thread the recording chan lives in */
ast_mutex_t playback_lock; /*!< Lock used for playback channel */
AST_LIST_HEAD_NOLOCK(, conference_bridge_user) users_list; /*!< List of users participating in the conference bridge */
};
/*! \brief The structure that represents a conference bridge user */
struct conference_bridge_user {
struct conference_bridge *conference_bridge; /*!< Conference bridge they are participating in */
struct bridge_profile b_profile; /*!< The Bridge Configuration Profile */
struct user_profile u_profile; /*!< The User Configuration Profile */
char menu_name[64]; /*!< The name of the DTMF menu assigned to this user */
char name_rec_location[PATH_MAX]; /*!< Location of the User's name recorded file if it exists */
struct ast_channel *chan; /*!< Asterisk channel participating */
struct ast_bridge_features features; /*!< Bridge features structure */
struct ast_bridge_tech_optimizations tech_args; /*!< Bridge technology optimizations for talk detection */
unsigned int kicked:1; /*!< User has been kicked from the conference */
AST_LIST_ENTRY(conference_bridge_user) list; /*!< Linked list information */
};
/*! \brief load confbridge.conf file */
int conf_load_config(int reload);
/*! \brief destroy the information loaded from the confbridge.conf file*/
void conf_destroy_config(void);
/*!
* \brief find a user profile given a user profile's name and store
* that profile in result structure.
*
* \details This function first attempts to find any custom user
* profile that might exist on a channel datastore, if that doesn't
* exist it looks up the provided user profile name, if that doesn't
* exist either the default_user profile is used.
* \retval user profile on success
* \retval NULL on failure
*/
const struct user_profile *conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result);
/*!
* \brief Find a bridge profile
*
* \details Any bridge profile found using this function must be
* destroyed using conf_bridge_profile_destroy. This function first
* attempts to find any custom bridge profile that might exist on
* a channel datastore, if that doesn't exist it looks up the
* provided bridge profile name, if that doesn't exist either
* the default_bridge profile is used.
*
* \retval Bridge profile on success
* \retval NULL on failure
*/
const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result);
/*!
* \brief Destroy a bridge profile found by 'conf_find_bridge_profile'
*/
void conf_bridge_profile_destroy(struct bridge_profile *b_profile);
/*!
* \brief copies a bridge profile
* \note conf_bridge_profile_destroy must be called on the dst structure
*/
void conf_bridge_profile_copy(struct bridge_profile *dst, struct bridge_profile *src);
/*!
* \brief Set a DTMF menu to a conference user by menu name.
*
* \retval 0 on success, menu was found and set
* \retval -1 on error, menu was not found
*/
int conf_set_menu_to_user(const char *menu_name, struct conference_bridge_user *conference_bridge_user);
/*!
* \brief Finds a menu_entry in a menu structure matched by DTMF sequence.
*
* \note the menu entry found must be destroyed using conf_menu_entry_destroy()
*
* \retval 1 success, entry is found and stored in result
* \retval 0 failure, no entry found for given DTMF sequence
*/
int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu *menu, struct conf_menu_entry *result);
/*!
* \brief Destroys and frees all the actions stored in a menu_entry structure
*/
void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry);
/*!
* \brief Once a DTMF sequence matches a sequence in the user's DTMF menu, this function will get
* called to perform the menu action.
*
* \param bridge_channel, Bridged channel this is involving
* \param conference_bridge_user, the conference user to perform the action on.
* \param menu_entry, the menu entry that invoked this callback to occur.
* \param menu, an AO2 referenced pointer to the entire menu structure the menu_entry
* derived from.
*
* \note The menu_entry is a deep copy of the entry found in the menu structure. This allows
* for the menu_entry to be accessed without requiring the menu lock. If the menu must
* be accessed, the menu lock must be held. Reference counting of the menu structure is
* handled outside of the scope of this function.
*
* \retval 0 success
* \retval -1 failure
*/
int conf_handle_dtmf(
struct ast_bridge_channel *bridge_channel,
struct conference_bridge_user *conference_bridge_user,
struct conf_menu_entry *menu_entry,
struct conf_menu *menu);
/*! \brief Looks to see if sound file is stored in bridge profile sounds, if not
* default sound is provided.*/
const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds *custom_sounds);
int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value);
#endif

View File

@ -205,9 +205,9 @@ AC_DEFUN([AST_CHECK_PWLIB_VERSION], [
$2_VER=$((${$2_MAJOR_VERSION}*10000+${$2_MINOR_VERSION}*100+${$2_BUILD_NUMBER}))
$2_REQ=$(($4*10000+$5*100+$6))
if test "x$10" = "x"; then
let $2_MAX=9999999
$2_MAX=9999999
else
let $2_MAX=$8*10000+$9*100+$10
$2_MAX=$(($8*10000+$9*100+$10))
fi
AC_MSG_CHECKING(if $1 version ${$2_VERSION} is compatible with chan_h323)

View File

@ -198,12 +198,12 @@ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridg
ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP,
(attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL);
ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"),
attended_threeway_transfer, NULL);
attended_threeway_transfer, NULL, NULL);
ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"),
attended_abort_transfer, NULL);
attended_abort_transfer, NULL, NULL);
/* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */
attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features);
attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features, NULL);
/* Since the above returned the caller features structure is of no more use */
ast_bridge_features_cleanup(&caller_features);

View File

@ -1,9 +1,10 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2007, Digium, Inc.
* Copyright (C) 2011, Digium, Inc.
*
* Joshua Colp <jcolp@digium.com>
* David Vossel <dvossel@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
@ -21,12 +22,9 @@
* \brief Multi-party software based channel mixing
*
* \author Joshua Colp <jcolp@digium.com>
* \author David Vossel <dvossel@digium.com>
*
* \ingroup bridges
*
* \todo This bridge operates in 8 kHz mode unless a define is uncommented.
* This needs to be improved so the bridge moves between the dominant codec as needed depending
* on channels present in the bridge and transcoding capabilities.
*/
#include "asterisk.h"
@ -51,20 +49,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/slinfactory.h"
#include "asterisk/astobj2.h"
#include "asterisk/timing.h"
#include "asterisk/translate.h"
#define MAX_DATALEN 3840
#define MAX_DATALEN 8096
/*! \brief Interval at which mixing will take place. Valid options are 10, 20, and 40. */
#define SOFTMIX_INTERVAL 20
#define DEFAULT_SOFTMIX_INTERVAL 20
/*! \brief Size of the buffer used for sample manipulation */
#define SOFTMIX_DATALEN(rate) ((rate/50) * (SOFTMIX_INTERVAL / 10))
#define SOFTMIX_DATALEN(rate, interval) ((rate/50) * (interval / 10))
/*! \brief Number of samples we are dealing with */
#define SOFTMIX_SAMPLES(rate) (SOFTMIX_DATALEN(rate) / 2)
#define SOFTMIX_SAMPLES(rate, interval) (SOFTMIX_DATALEN(rate, interval) / 2)
/*! \brief Define used to turn on 16 kHz audio support */
/* #define SOFTMIX_16_SUPPORT */
/*! \brief Number of mixing iterations to perform between gathering statistics. */
#define SOFTMIX_STAT_INTERVAL 100
/* This is the threshold in ms at which a channel's own audio will stop getting
* mixed out its own write audio stream because it is not talking. */
#define DEFAULT_SOFTMIX_SILENCE_THRESHOLD 2500
#define DEFAULT_SOFTMIX_TALKING_THRESHOLD 160
/*! \brief Structure which contains per-channel mixing information */
struct softmix_channel {
@ -73,7 +77,14 @@ struct softmix_channel {
/*! Factory which contains audio read in from the channel */
struct ast_slinfactory factory;
/*! Frame that contains mixed audio to be written out to the channel */
struct ast_frame frame;
struct ast_frame write_frame;
/*! Frame that contains mixed audio read from the channel */
struct ast_frame read_frame;
/*! DSP for detecting silence */
struct ast_dsp *dsp;
/*! Bit used to indicate if a channel is talking or not. This affects how
* the channel's audio is mixed back to it. */
int talking:1;
/*! Bit used to indicate that the channel provided audio for this mixing interval */
int have_audio:1;
/*! Bit used to indicate that a frame is available to be written out to the channel */
@ -87,66 +98,268 @@ struct softmix_channel {
struct softmix_bridge_data {
struct ast_timer *timer;
unsigned int internal_rate;
unsigned int internal_mixing_interval;
};
struct softmix_stats {
/*! Each index represents a sample rate used above the internal rate. */
unsigned int sample_rates[16];
/*! Each index represents the number of channels using the same index in the sample_rates array. */
unsigned int num_channels[16];
/*! the number of channels above the internal sample rate */
unsigned int num_above_internal_rate;
/*! the number of channels at the internal sample rate */
unsigned int num_at_internal_rate;
/*! the absolute highest sample rate supported by any channel in the bridge */
unsigned int highest_supported_rate;
/*! Is the sample rate locked by the bridge, if so what is that rate.*/
unsigned int locked_rate;
};
struct softmix_mixing_array {
int max_num_entries;
int used_entries;
int16_t **buffers;
};
struct softmix_translate_helper_entry {
int num_times_requested; /*!< Once this entry is no longer requested, free the trans_pvt
and re-init if it was usable. */
struct ast_format dst_format; /*!< The destination format for this helper */
struct ast_trans_pvt *trans_pvt; /*!< the translator for this slot. */
struct ast_frame *out_frame; /*!< The output frame from the last translation */
AST_LIST_ENTRY(softmix_translate_helper_entry) entry;
};
struct softmix_translate_helper {
struct ast_format slin_src; /*!< the source format expected for all the translators */
AST_LIST_HEAD_NOLOCK(, softmix_translate_helper_entry) entries;
};
static struct softmix_translate_helper_entry *softmix_translate_helper_entry_alloc(struct ast_format *dst)
{
struct softmix_translate_helper_entry *entry;
if (!(entry = ast_calloc(1, sizeof(*entry)))) {
return NULL;
}
ast_format_copy(&entry->dst_format, dst);
return entry;
}
static void *softmix_translate_helper_free_entry(struct softmix_translate_helper_entry *entry)
{
if (entry->trans_pvt) {
ast_translator_free_path(entry->trans_pvt);
}
if (entry->out_frame) {
ast_frfree(entry->out_frame);
}
ast_free(entry);
return NULL;
}
static void softmix_translate_helper_init(struct softmix_translate_helper *trans_helper, unsigned int sample_rate)
{
memset(trans_helper, 0, sizeof(*trans_helper));
ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0);
}
static void softmix_translate_helper_destroy(struct softmix_translate_helper *trans_helper)
{
struct softmix_translate_helper_entry *entry;
while ((entry = AST_LIST_REMOVE_HEAD(&trans_helper->entries, entry))) {
softmix_translate_helper_free_entry(entry);
}
}
static void softmix_translate_helper_change_rate(struct softmix_translate_helper *trans_helper, unsigned int sample_rate)
{
struct softmix_translate_helper_entry *entry;
ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0);
AST_LIST_TRAVERSE_SAFE_BEGIN(&trans_helper->entries, entry, entry) {
if (entry->trans_pvt) {
ast_translator_free_path(entry->trans_pvt);
if (!(entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src))) {
AST_LIST_REMOVE_CURRENT(entry);
entry = softmix_translate_helper_free_entry(entry);
}
}
}
AST_LIST_TRAVERSE_SAFE_END;
}
/*!
* \internal
* \brief Get the next available audio on the softmix channel's read stream
* and determine if it should be mixed out or not on the write stream.
*
* \retval pointer to buffer containing the exact number of samples requested on success.
* \retval NULL if no samples are present
*/
static int16_t *softmix_process_read_audio(struct softmix_channel *sc, unsigned int num_samples)
{
if ((ast_slinfactory_available(&sc->factory) >= num_samples) &&
ast_slinfactory_read(&sc->factory, sc->our_buf, num_samples)) {
sc->have_audio = 1;
return sc->our_buf;
}
sc->have_audio = 0;
return NULL;
}
/*!
* \internal
* \brief Process a softmix channel's write audio
*
* \details This function will remove the channel's talking from its own audio if present and
* possibly even do the channel's write translation for it depending on how many other
* channels use the same write format.
*/
static void softmix_process_write_audio(struct softmix_translate_helper *trans_helper,
struct ast_format *raw_write_fmt,
struct softmix_channel *sc)
{
struct softmix_translate_helper_entry *entry = NULL;
int i;
/* If we provided audio that was not determined to be silence,
* then take it out while in slinear format. */
if (sc->have_audio && sc->talking) {
for (i = 0; i < sc->write_frame.samples; i++) {
ast_slinear_saturated_subtract(&sc->final_buf[i], &sc->our_buf[i]);
}
/* do not do any special write translate optimization if we had to make
* a special mix for them to remove their own audio. */
return;
}
AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
if (ast_format_cmp(&entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) {
entry->num_times_requested++;
} else {
continue;
}
if (!entry->trans_pvt && (entry->num_times_requested > 1)) {
entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src);
}
if (entry->trans_pvt && !entry->out_frame) {
entry->out_frame = ast_translate(entry->trans_pvt, &sc->write_frame, 0);
}
if (entry->out_frame && (entry->out_frame->datalen < MAX_DATALEN)) {
ast_format_copy(&sc->write_frame.subclass.format, &entry->out_frame->subclass.format);
memcpy(sc->final_buf, entry->out_frame->data.ptr, entry->out_frame->datalen);
sc->write_frame.datalen = entry->out_frame->datalen;
sc->write_frame.samples = entry->out_frame->samples;
}
break;
}
/* add new entry into list if this format destination was not matched. */
if (!entry && (entry = softmix_translate_helper_entry_alloc(raw_write_fmt))) {
AST_LIST_INSERT_HEAD(&trans_helper->entries, entry, entry);
}
}
static void softmix_translate_helper_cleanup(struct softmix_translate_helper *trans_helper)
{
struct softmix_translate_helper_entry *entry = NULL;
AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
if (entry->out_frame) {
ast_frfree(entry->out_frame);
entry->out_frame = NULL;
}
entry->num_times_requested = 0;
}
}
static void softmix_bridge_data_destroy(void *obj)
{
struct softmix_bridge_data *softmix_data = obj;
ast_timer_close(softmix_data->timer);
}
/*! \brief Function called when a bridge is created */
static int softmix_bridge_create(struct ast_bridge *bridge)
{
struct softmix_bridge_data *bridge_data;
struct softmix_bridge_data *softmix_data;
if (!(bridge_data = ast_calloc(1, sizeof(*bridge_data)))) {
if (!(softmix_data = ao2_alloc(sizeof(*softmix_data), softmix_bridge_data_destroy))) {
return -1;
}
if (!(bridge_data->timer = ast_timer_open())) {
ast_free(bridge_data);
if (!(softmix_data->timer = ast_timer_open())) {
ao2_ref(softmix_data, -1);
return -1;
}
/* start at 8khz, let it grow from there */
bridge_data->internal_rate = 8000;
softmix_data->internal_rate = 8000;
softmix_data->internal_mixing_interval = DEFAULT_SOFTMIX_INTERVAL;
bridge->bridge_pvt = bridge_data;
bridge->bridge_pvt = softmix_data;
return 0;
}
/*! \brief Function called when a bridge is destroyed */
static int softmix_bridge_destroy(struct ast_bridge *bridge)
{
struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
if (!bridge->bridge_pvt) {
return -1;
}
ast_timer_close(bridge_data->timer);
ast_free(bridge_data);
ao2_ref(softmix_data, -1);
bridge->bridge_pvt = NULL;
return 0;
}
static void set_softmix_bridge_data(int rate, struct ast_bridge_channel *bridge_channel, int reset)
static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_channel *bridge_channel, int reset)
{
struct softmix_channel *sc = bridge_channel->bridge_pvt;
unsigned int channel_read_rate = ast_format_rate(&bridge_channel->chan->rawreadformat);
ast_mutex_lock(&sc->lock);
if (reset) {
ast_slinfactory_destroy(&sc->factory);
ast_dsp_free(sc->dsp);
}
/* Setup frame parameters */
sc->frame.frametype = AST_FRAME_VOICE;
/* Setup read/write frame parameters */
sc->write_frame.frametype = AST_FRAME_VOICE;
ast_format_set(&sc->write_frame.subclass.format, ast_format_slin_by_rate(rate), 0);
sc->write_frame.data.ptr = sc->final_buf;
sc->write_frame.datalen = SOFTMIX_DATALEN(rate, interval);
sc->write_frame.samples = SOFTMIX_SAMPLES(rate, interval);
ast_format_set(&sc->frame.subclass.format, ast_format_slin_by_rate(rate), 0);
sc->frame.data.ptr = sc->final_buf;
sc->frame.datalen = SOFTMIX_DATALEN(rate);
sc->frame.samples = SOFTMIX_SAMPLES(rate);
sc->read_frame.frametype = AST_FRAME_VOICE;
ast_format_set(&sc->read_frame.subclass.format, ast_format_slin_by_rate(channel_read_rate), 0);
sc->read_frame.data.ptr = sc->our_buf;
sc->read_frame.datalen = SOFTMIX_DATALEN(channel_read_rate, interval);
sc->read_frame.samples = SOFTMIX_SAMPLES(channel_read_rate, interval);
/* Setup smoother */
ast_slinfactory_init_with_format(&sc->factory, &sc->frame.subclass.format);
ast_slinfactory_init_with_format(&sc->factory, &sc->write_frame.subclass.format);
ast_set_read_format(bridge_channel->chan, &sc->frame.subclass.format);
ast_set_write_format(bridge_channel->chan, &sc->frame.subclass.format);
/* set new read and write formats on channel. */
ast_set_read_format(bridge_channel->chan, &sc->read_frame.subclass.format);
ast_set_write_format(bridge_channel->chan, &sc->write_frame.subclass.format);
/* set up new DSP. This is on the read side only right before the read frame enters the smoother. */
sc->dsp = ast_dsp_new_with_rate(channel_read_rate);
/* we want to aggressively detect silence to avoid feedback */
if (bridge_channel->tech_args.talking_threshold) {
ast_dsp_set_threshold(sc->dsp, bridge_channel->tech_args.talking_threshold);
} else {
ast_dsp_set_threshold(sc->dsp, DEFAULT_SOFTMIX_TALKING_THRESHOLD);
}
ast_mutex_unlock(&sc->lock);
}
/*! \brief Function called when a channel is joined into the bridge */
static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
{
struct softmix_channel *sc = NULL;
struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
/* Create a new softmix_channel structure and allocate various things on it */
if (!(sc = ast_calloc(1, sizeof(*sc)))) {
@ -159,7 +372,9 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan
/* Can't forget to record our pvt structure within the bridged channel structure */
bridge_channel->bridge_pvt = sc;
set_softmix_bridge_data(bridge_data->internal_rate, bridge_channel, 0);
set_softmix_bridge_data(softmix_data->internal_rate,
softmix_data->internal_mixing_interval ? softmix_data->internal_mixing_interval : DEFAULT_SOFTMIX_INTERVAL,
bridge_channel, 0);
return 0;
}
@ -169,45 +384,121 @@ static int softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_cha
{
struct softmix_channel *sc = bridge_channel->bridge_pvt;
if (!(bridge_channel->bridge_pvt)) {
return 0;
}
bridge_channel->bridge_pvt = NULL;
/* Drop mutex lock */
ast_mutex_destroy(&sc->lock);
/* Drop the factory */
ast_slinfactory_destroy(&sc->factory);
/* Drop the DSP */
ast_dsp_free(sc->dsp);
/* Eep! drop ourselves */
ast_free(sc);
return 0;
}
/*!
* \internal
* \brief If the bridging core passes DTMF to us, then they want it to be distributed out to all memebers. Do that here.
*/
static void softmix_pass_dtmf(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
{
struct ast_bridge_channel *tmp;
AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) {
if (tmp == bridge_channel) {
continue;
}
ast_write(tmp->chan, frame);
}
}
/*! \brief Function called when a channel writes a frame into the bridge */
static enum ast_bridge_write_result softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
{
struct softmix_channel *sc = bridge_channel->bridge_pvt;
struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
int totalsilence = 0;
int silence_threshold = bridge_channel->tech_args.silence_threshold ?
bridge_channel->tech_args.silence_threshold :
DEFAULT_SOFTMIX_SILENCE_THRESHOLD;
char update_talking = -1; /* if this is set to 0 or 1, tell the bridge that the channel has started or stopped talking. */
int res = AST_BRIDGE_WRITE_SUCCESS;
/* Only accept audio frames, all others are unsupported */
if (frame->frametype != AST_FRAME_VOICE) {
return AST_BRIDGE_WRITE_UNSUPPORTED;
if (frame->frametype == AST_FRAME_DTMF_END || frame->frametype == AST_FRAME_DTMF_BEGIN) {
softmix_pass_dtmf(bridge, bridge_channel, frame);
goto no_audio;
} else if (frame->frametype != AST_FRAME_VOICE) {
res = AST_BRIDGE_WRITE_UNSUPPORTED;
goto no_audio;
} else if (frame->datalen == 0) {
goto no_audio;
}
/* If we made it here, we are going to write the frame into the conference */
ast_mutex_lock(&sc->lock);
/* If a frame was provided add it to the smoother */
if (frame->frametype == AST_FRAME_VOICE && ast_format_is_slinear(&frame->subclass.format)) {
ast_dsp_silence(sc->dsp, frame, &totalsilence);
if (totalsilence < silence_threshold) {
if (!sc->talking) {
update_talking = 1;
}
sc->talking = 1; /* tell the write process we have audio to be mixed out */
} else {
if (sc->talking) {
update_talking = 0;
}
sc->talking = 0;
}
/* Before adding audio in, make sure we haven't fallen behind. If audio has fallen
* behind 4 times the amount of samples mixed on every iteration of the mixer, Re-sync
* the audio by flushing the buffer before adding new audio in. */
if (ast_slinfactory_available(&sc->factory) > (4 * SOFTMIX_SAMPLES(softmix_data->internal_rate, softmix_data->internal_mixing_interval))) {
ast_slinfactory_flush(&sc->factory);
}
/* If a frame was provided add it to the smoother, unless drop silence is enabled and this frame
* is not determined to be talking. */
if (!(bridge_channel->tech_args.drop_silence && !sc->talking) &&
(frame->frametype == AST_FRAME_VOICE && ast_format_is_slinear(&frame->subclass.format))) {
ast_slinfactory_feed(&sc->factory, frame);
}
/* If a frame is ready to be written out, do so */
if (sc->have_frame) {
ast_write(bridge_channel->chan, &sc->frame);
ast_write(bridge_channel->chan, &sc->write_frame);
sc->have_frame = 0;
}
/* Alllll done */
ast_mutex_unlock(&sc->lock);
return AST_BRIDGE_WRITE_SUCCESS;
if (update_talking != -1) {
ast_bridge_notify_talking(bridge, bridge_channel, update_talking);
}
return res;
no_audio:
/* Even though the frame is not being written into the conference because it is not audio,
* we should use this opportunity to check to see if a frame is ready to be written out from
* the conference to the channel. */
ast_mutex_lock(&sc->lock);
if (sc->have_frame) {
ast_write(bridge_channel->chan, &sc->write_frame);
sc->have_frame = 0;
}
ast_mutex_unlock(&sc->lock);
return res;
}
/*! \brief Function called when the channel's thread is poked */
@ -218,7 +509,7 @@ static int softmix_bridge_poke(struct ast_bridge *bridge, struct ast_bridge_chan
ast_mutex_lock(&sc->lock);
if (sc->have_frame) {
ast_write(bridge_channel->chan, &sc->frame);
ast_write(bridge_channel->chan, &sc->write_frame);
sc->have_frame = 0;
}
@ -227,167 +518,306 @@ static int softmix_bridge_poke(struct ast_bridge *bridge, struct ast_bridge_chan
return 0;
}
static void gather_softmix_stats(struct softmix_stats *stats,
const struct softmix_bridge_data *softmix_data,
struct ast_bridge_channel *bridge_channel)
{
int channel_native_rate;
int i;
/* Gather stats about channel sample rates. */
channel_native_rate = MAX(ast_format_rate(&bridge_channel->chan->rawwriteformat),
ast_format_rate(&bridge_channel->chan->rawreadformat));
if (channel_native_rate > stats->highest_supported_rate) {
stats->highest_supported_rate = channel_native_rate;
}
if (channel_native_rate > softmix_data->internal_rate) {
for (i = 0; i < ARRAY_LEN(stats->sample_rates); i++) {
if (stats->sample_rates[i] == channel_native_rate) {
stats->num_channels[i]++;
break;
} else if (!stats->sample_rates[i]) {
stats->sample_rates[i] = channel_native_rate;
stats->num_channels[i]++;
break;
}
}
stats->num_above_internal_rate++;
} else if (channel_native_rate == softmix_data->internal_rate) {
stats->num_at_internal_rate++;
}
}
/*!
* \internal
* \brief Analyse mixing statistics and change bridges internal rate
* if necessary.
*
* \retval 0, no changes to internal rate
* \ratval 1, internal rate was changed, update all the channels on the next mixing iteration.
*/
static unsigned int analyse_softmix_stats(struct softmix_stats *stats, struct softmix_bridge_data *softmix_data)
{
int i;
/* Re-adjust the internal bridge sample rate if
* 1. The bridge's internal sample rate is locked in at a sample
* rate other than the current sample rate being used.
* 2. two or more channels support a higher sample rate
* 3. no channels support the current sample rate or a higher rate
*/
if (stats->locked_rate) {
/* if the rate is locked by the bridge, only update it if it differs
* from the current rate we are using. */
if (softmix_data->internal_rate != stats->locked_rate) {
softmix_data->internal_rate = stats->locked_rate;
ast_debug(1, " Bridge is locked in at sample rate %d\n", softmix_data->internal_rate);
return 1;
}
} else if (stats->num_above_internal_rate >= 2) {
/* the highest rate is just used as a starting point */
unsigned int best_rate = stats->highest_supported_rate;
int best_index = -1;
for (i = 0; i < ARRAY_LEN(stats->num_channels); i++) {
if (stats->num_channels[i]) {
break;
}
/* best_rate starts out being the first sample rate
* greater than the internal sample rate that 2 or
* more channels support. */
if (stats->num_channels[i] >= 2 && (best_index == -1)) {
best_rate = stats->sample_rates[i];
best_index = i;
/* If it has been detected that multiple rates above
* the internal rate are present, compare those rates
* to each other and pick the highest one two or more
* channels support. */
} else if (((best_index != -1) &&
(stats->num_channels[i] >= 2) &&
(stats->sample_rates[best_index] < stats->sample_rates[i]))) {
best_rate = stats->sample_rates[i];
best_index = i;
/* It is possible that multiple channels exist with native sample
* rates above the internal sample rate, but none of those channels
* have the same rate in common. In this case, the lowest sample
* rate among those channels is picked. Over time as additional
* statistic runs are made the internal sample rate number will
* adjust to the most optimal sample rate, but it may take multiple
* iterations. */
} else if (best_index == -1) {
best_rate = MIN(best_rate, stats->sample_rates[i]);
}
}
ast_debug(1, " Bridge changed from %d To %d\n", softmix_data->internal_rate, best_rate);
softmix_data->internal_rate = best_rate;
return 1;
} else if (!stats->num_at_internal_rate && !stats->num_above_internal_rate) {
/* In this case, the highest supported rate is actually lower than the internal rate */
softmix_data->internal_rate = stats->highest_supported_rate;
ast_debug(1, " Bridge changed from %d to %d\n", softmix_data->internal_rate, stats->highest_supported_rate);
return 1;
}
return 0;
}
static int softmix_mixing_array_init(struct softmix_mixing_array *mixing_array, unsigned int starting_num_entries)
{
memset(mixing_array, 0, sizeof(*mixing_array));
mixing_array->max_num_entries = starting_num_entries;
if (!(mixing_array->buffers = ast_calloc(mixing_array->max_num_entries, sizeof(int16_t *)))) {
ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure. \n");
return -1;
}
return 0;
}
static void softmix_mixing_array_destroy(struct softmix_mixing_array *mixing_array)
{
ast_free(mixing_array->buffers);
}
static int softmix_mixing_array_grow(struct softmix_mixing_array *mixing_array, unsigned int num_entries)
{
int16_t **tmp;
/* give it some room to grow since memory is cheap but allocations can be expensive */
mixing_array->max_num_entries = num_entries;
if (!(tmp = ast_realloc(mixing_array->buffers, (mixing_array->max_num_entries * sizeof(int16_t *))))) {
ast_log(LOG_NOTICE, "Failed to re-allocate softmix mixing structure. \n");
return -1;
}
mixing_array->buffers = tmp;
return 0;
}
/*! \brief Function which acts as the mixing thread */
static int softmix_bridge_thread(struct ast_bridge *bridge)
{
struct {
/*! Each index represents a sample rate used above the internal rate. */
unsigned int sample_rates[8];
/*! Each index represents the number of channels using the same index in the sample_rates array. */
unsigned int num_channels[8];
/*! the number of channels above the internal sample rate */
unsigned int num_above_internal_rate;
/*! the number of channels at the internal sample rate */
unsigned int num_at_internal_rate;
/*! the absolute highest sample rate supported by any channel in the bridge */
unsigned int highest_supported_rate;
} stats;
struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
struct ast_timer *timer = bridge_data->timer;
int timingfd = ast_timer_fd(timer);
struct softmix_stats stats = { { 0 }, };
struct softmix_mixing_array mixing_array;
struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
struct ast_timer *timer;
struct softmix_translate_helper trans_helper;
int16_t buf[MAX_DATALEN] = { 0, };
unsigned int stat_iteration_counter = 0; /* counts down, gather stats at zero and reset. */
int timingfd;
int update_all_rates = 0; /* set this when the internal sample rate has changed */
int i;
int i, x;
int res = -1;
ast_timer_set_rate(timer, (1000 / SOFTMIX_INTERVAL));
if (!(softmix_data = bridge->bridge_pvt)) {
goto softmix_cleanup;
}
ao2_ref(softmix_data, 1);
timer = softmix_data->timer;
timingfd = ast_timer_fd(timer);
softmix_translate_helper_init(&trans_helper, softmix_data->internal_rate);
ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval));
/* Give the mixing array room to grow, memory is cheap but allocations are expensive. */
if (softmix_mixing_array_init(&mixing_array, bridge->num + 10)) {
ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure. \n");
goto softmix_cleanup;
}
while (!bridge->stop && !bridge->refresh && bridge->array_num) {
struct ast_bridge_channel *bridge_channel = NULL;
short buf[MAX_DATALEN] = {0, };
int timeout = -1;
enum ast_format_id cur_slin_id = ast_format_slin_by_rate(softmix_data->internal_rate);
unsigned int softmix_samples = SOFTMIX_SAMPLES(softmix_data->internal_rate, softmix_data->internal_mixing_interval);
unsigned int softmix_datalen = SOFTMIX_DATALEN(softmix_data->internal_rate, softmix_data->internal_mixing_interval);
/* these variables help determine if a rate change is required */
memset(&stats, 0, sizeof(stats));
stats.highest_supported_rate = 8000;
if (softmix_datalen > MAX_DATALEN) {
/* This should NEVER happen, but if it does we need to know about it. Almost
* all the memcpys used during this process depend on this assumption. Rather
* than checking this over and over again through out the code, this single
* verification is done on each iteration. */
ast_log(LOG_WARNING, "Conference mixing error, requested mixing length greater than mixing buffer.\n");
goto softmix_cleanup;
}
/* Grow the mixing array buffer as participants are added. */
if (mixing_array.max_num_entries < bridge->num && softmix_mixing_array_grow(&mixing_array, bridge->num + 5)) {
goto softmix_cleanup;
}
/* init the number of buffers stored in the mixing array to 0.
* As buffers are added for mixing, this number is incremented. */
mixing_array.used_entries = 0;
/* These variables help determine if a rate change is required */
if (!stat_iteration_counter) {
memset(&stats, 0, sizeof(stats));
stats.locked_rate = bridge->internal_sample_rate;
}
/* If the sample rate has changed, update the translator helper */
if (update_all_rates) {
softmix_translate_helper_change_rate(&trans_helper, softmix_data->internal_rate);
}
/* Go through pulling audio from each factory that has it available */
AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
struct softmix_channel *sc = bridge_channel->bridge_pvt;
int channel_native_rate;
ast_mutex_lock(&sc->lock);
/* Update the sample rate to match the bridge's native sample rate if necessary. */
if (update_all_rates) {
set_softmix_bridge_data(bridge_data->internal_rate, bridge_channel, 1);
set_softmix_bridge_data(softmix_data->internal_rate, softmix_data->internal_mixing_interval, bridge_channel, 1);
}
/* If stat_iteration_counter is 0, then collect statistics during this mixing interation */
if (!stat_iteration_counter) {
gather_softmix_stats(&stats, softmix_data, bridge_channel);
}
/* if the channel is suspended, don't check for audio, but still gather stats */
if (bridge_channel->suspended) {
continue;
}
/* Try to get audio from the factory if available */
if (ast_slinfactory_available(&sc->factory) >= SOFTMIX_SAMPLES(bridge_data->internal_rate) &&
ast_slinfactory_read(&sc->factory, sc->our_buf, SOFTMIX_SAMPLES(bridge_data->internal_rate))) {
short *data1, *data2;
int i;
/* Put into the local final buffer */
for (i = 0, data1 = buf, data2 = sc->our_buf; i < SOFTMIX_DATALEN(bridge_data->internal_rate); i++, data1++, data2++)
ast_slinear_saturated_add(data1, data2);
/* Yay we have our own audio */
sc->have_audio = 1;
} else {
/* Awww we don't have audio ;( */
sc->have_audio = 0;
ast_mutex_lock(&sc->lock);
if ((mixing_array.buffers[mixing_array.used_entries] = softmix_process_read_audio(sc, softmix_samples))) {
mixing_array.used_entries++;
}
/* Gather stats about channel sample rates. */
channel_native_rate = MAX(ast_format_rate(&bridge_channel->chan->rawwriteformat),
ast_format_rate(&bridge_channel->chan->rawreadformat));
if (channel_native_rate > stats.highest_supported_rate) {
stats.highest_supported_rate = channel_native_rate;
}
if (channel_native_rate > bridge_data->internal_rate) {
for (i = 0; i < ARRAY_LEN(stats.sample_rates); i++) {
if (stats.sample_rates[i] == channel_native_rate) {
stats.num_channels[i]++;
break;
} else if (!stats.sample_rates[i]) {
stats.sample_rates[i] = channel_native_rate;
stats.num_channels[i]++;
break;
}
}
stats.num_above_internal_rate++;
} else if (channel_native_rate == bridge_data->internal_rate) {
stats.num_at_internal_rate++;
}
ast_mutex_unlock(&sc->lock);
}
/* mix it like crazy */
memset(buf, 0, softmix_datalen);
for (i = 0; i < mixing_array.used_entries; i++) {
for (x = 0; x < softmix_samples; x++) {
ast_slinear_saturated_add(buf + x, mixing_array.buffers[i] + x);
}
}
/* Next step go through removing the channel's own audio and creating a good frame... */
AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
struct softmix_channel *sc = bridge_channel->bridge_pvt;
int i = 0;
/* Copy from local final buffer to our final buffer */
memcpy(sc->final_buf, buf, sizeof(sc->final_buf));
/* If we provided audio then take it out */
if (sc->have_audio) {
for (i = 0; i < SOFTMIX_DATALEN(bridge_data->internal_rate); i++) {
ast_slinear_saturated_subtract(&sc->final_buf[i], &sc->our_buf[i]);
}
if (bridge_channel->suspended) {
continue;
}
ast_mutex_lock(&sc->lock);
/* Make SLINEAR write frame from local buffer */
if (sc->write_frame.subclass.format.id != cur_slin_id) {
ast_format_set(&sc->write_frame.subclass.format, cur_slin_id, 0);
}
sc->write_frame.datalen = softmix_datalen;
sc->write_frame.samples = softmix_samples;
memcpy(sc->final_buf, buf, softmix_datalen);
/* process the softmix channel's new write audio */
softmix_process_write_audio(&trans_helper, &bridge_channel->chan->rawwriteformat, sc);
/* The frame is now ready for use... */
sc->have_frame = 1;
ast_mutex_unlock(&sc->lock);
/* Poke bridged channel thread just in case */
pthread_kill(bridge_channel->thread, SIGURG);
}
/* Re-adjust the internal bridge sample rate if
* 1. two or more channels support a higher sample rate
* 2. no channels support the current sample rate or a higher rate
*/
if (stats.num_above_internal_rate >= 2) {
/* the highest rate is just used as a starting point */
unsigned int best_rate = stats.highest_supported_rate;
int best_index = -1;
/* 1. pick the best sample rate two or more channels support
* 2. if two or more channels do not support the same rate, pick the
* lowest sample rate that is still above the internal rate. */
for (i = 0; ((i < ARRAY_LEN(stats.num_channels)) && stats.num_channels[i]); i++) {
if ((stats.num_channels[i] >= 2 && (best_index == -1)) ||
((best_index != -1) &&
(stats.num_channels[i] >= 2) &&
(stats.sample_rates[best_index] < stats.sample_rates[i]))) {
best_rate = stats.sample_rates[i];
best_index = i;
} else if (best_index == -1) {
best_rate = MIN(best_rate, stats.sample_rates[i]);
}
}
ast_debug(1, " Bridge changed from %d To %d\n", bridge_data->internal_rate, best_rate);
bridge_data->internal_rate = best_rate;
update_all_rates = 1;
} else if (!stats.num_at_internal_rate && !stats.num_above_internal_rate) {
update_all_rates = 1;
/* in this case, the highest supported rate is actually lower than the internal rate */
bridge_data->internal_rate = stats.highest_supported_rate;
ast_debug(1, " Bridge changed from %d to %d\n", bridge_data->internal_rate, stats.highest_supported_rate);
update_all_rates = 1;
} else {
update_all_rates = 0;
update_all_rates = 0;
if (!stat_iteration_counter) {
update_all_rates = analyse_softmix_stats(&stats, softmix_data);
stat_iteration_counter = SOFTMIX_STAT_INTERVAL;
}
stat_iteration_counter--;
ao2_unlock(bridge);
/* cleanup any translation frame data from the previous mixing iteration. */
softmix_translate_helper_cleanup(&trans_helper);
/* Wait for the timing source to tell us to wake up and get things done */
ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL);
ast_timer_ack(timer, 1);
ao2_lock(bridge);
/* make sure to detect mixing interval changes if they occur. */
if (bridge->internal_mixing_interval && (bridge->internal_mixing_interval != softmix_data->internal_mixing_interval)) {
softmix_data->internal_mixing_interval = bridge->internal_mixing_interval;
ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval));
update_all_rates = 1; /* if the interval changes, the rates must be adjusted as well just to be notified new interval.*/
}
}
return 0;
res = 0;
softmix_cleanup:
softmix_translate_helper_destroy(&trans_helper);
softmix_mixing_array_destroy(&mixing_array);
if (softmix_data) {
ao2_ref(softmix_data, -1);
}
return res;
}
static struct ast_bridge_technology softmix_bridge = {
.name = "softmix",
.capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX | AST_BRIDGE_CAPABILITY_THREAD | AST_BRIDGE_CAPABILITY_MULTITHREADED,
.capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX | AST_BRIDGE_CAPABILITY_THREAD | AST_BRIDGE_CAPABILITY_MULTITHREADED | AST_BRIDGE_CAPABILITY_OPTIMIZE,
.preference = AST_BRIDGE_PREFERENCE_LOW,
.create = softmix_bridge_create,
.destroy = softmix_bridge_destroy,
@ -410,11 +840,7 @@ static int load_module(void)
if (!(softmix_bridge.format_capabilities = ast_format_cap_alloc())) {
return AST_MODULE_LOAD_DECLINE;
}
#ifdef SOFTMIX_16_SUPPORT
ast_format_cap_add(softmix_bridge.format_capabilities, ast_format_set(&tmp, AST_FORMAT_SLINEAR16, 0));
#else
ast_format_cap_add(softmix_bridge.format_capabilities, ast_format_set(&tmp, AST_FORMAT_SLINEAR, 0));
#endif
return ast_bridge_technology_register(&softmix_bridge);
}

View File

@ -224,6 +224,10 @@ return_cleanup:
static int unload_module(void)
{
ast_cdr_unregister(name);
if (rh) {
rc_destroy(rh);
rh = NULL;
}
return 0;
}
@ -231,7 +235,6 @@ static int load_module(void)
{
struct ast_config *cfg;
struct ast_flags config_flags = { 0 };
int res;
const char *tmp;
if ((cfg = ast_config_load(cdr_config, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
@ -244,8 +247,17 @@ static int load_module(void)
} else
return AST_MODULE_LOAD_DECLINE;
/* start logging */
rc_openlog("asterisk");
/*
* start logging
*
* NOTE: Yes this causes a slight memory leak if the module is
* unloaded. However, it is better than a crash if cdr_radius
* and cel_radius are both loaded.
*/
tmp = ast_strdup("asterisk");
if (tmp) {
rc_openlog((char *) tmp);
}
/* read radiusclient-ng config file */
if (!(rh = rc_read_config(radiuscfg))) {
@ -256,11 +268,18 @@ static int load_module(void)
/* read radiusclient-ng dictionaries */
if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
rc_destroy(rh);
rh = NULL;
return AST_MODULE_LOAD_DECLINE;
}
res = ast_cdr_register(name, desc, radius_log);
return AST_MODULE_LOAD_SUCCESS;
if (ast_cdr_register(name, desc, radius_log)) {
rc_destroy(rh);
rh = NULL;
return AST_MODULE_LOAD_DECLINE;
} else {
return AST_MODULE_LOAD_SUCCESS;
}
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RADIUS CDR Backend",

View File

@ -264,8 +264,10 @@ static int reload(void)
return AST_MODULE_LOAD_DECLINE;
}
free_config();
res = load_config(1);
if ((res = load_config(1))) {
free_config();
}
AST_RWLIST_UNLOCK(&sinks);
return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;

View File

@ -751,11 +751,15 @@ static int unload_module(void)
free_config();
AST_RWLIST_UNLOCK(&odbc_tables);
AST_RWLIST_HEAD_DESTROY(&odbc_tables);
return 0;
}
static int load_module(void)
{
AST_RWLIST_HEAD_INIT(&odbc_tables);
if (AST_RWLIST_WRLOCK(&odbc_tables)) {
ast_log(LOG_ERROR, "Unable to lock column list. Load failed.\n");
return 0;

View File

@ -239,6 +239,8 @@ static void pgsql_log(const struct ast_event *event, void *userdata)
value = record.user_field;
} else if (strcmp(cur->name, "peer") == 0) {
value = record.peer;
} else if (strcmp(cur->name, "extra") == 0) {
value = record.extra;
} else {
value = NULL;
}
@ -535,7 +537,6 @@ static int process_my_load_module(struct ast_config *cfg)
static int my_load_module(int reload)
{
struct ast_config *cfg;
int res;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
if ((cfg = ast_config_load(config, config_flags)) == NULL || cfg == CONFIG_STATUS_FILEINVALID) {
@ -545,7 +546,7 @@ static int my_load_module(int reload)
return AST_MODULE_LOAD_SUCCESS;
}
res = process_my_load_module(cfg);
process_my_load_module(cfg);
ast_config_destroy(cfg);
event_sub = ast_event_subscribe(AST_EVENT_CEL, pgsql_log, "CEL PGSQL backend", NULL, AST_EVENT_IE_END);

View File

@ -206,6 +206,10 @@ static int unload_module(void)
if (event_sub) {
event_sub = ast_event_unsubscribe(event_sub);
}
if (rh) {
rc_destroy(rh);
rh = NULL;
}
return AST_MODULE_LOAD_SUCCESS;
}
@ -225,8 +229,17 @@ static int load_module(void)
return AST_MODULE_LOAD_DECLINE;
}
/* start logging */
rc_openlog("asterisk");
/*
* start logging
*
* NOTE: Yes this causes a slight memory leak if the module is
* unloaded. However, it is better than a crash if cdr_radius
* and cel_radius are both loaded.
*/
tmp = ast_strdup("asterisk");
if (tmp) {
rc_openlog((char *) tmp);
}
/* read radiusclient-ng config file */
if (!(rh = rc_read_config(radiuscfg))) {
@ -237,12 +250,15 @@ static int load_module(void)
/* read radiusclient-ng dictionaries */
if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
rc_destroy(rh);
rh = NULL;
return AST_MODULE_LOAD_DECLINE;
}
event_sub = ast_event_subscribe(AST_EVENT_CEL, radius_log, "CEL Radius Logging", NULL, AST_EVENT_IE_END);
if (!event_sub) {
rc_destroy(rh);
rh = NULL;
return AST_MODULE_LOAD_DECLINE;
} else {
return AST_MODULE_LOAD_SUCCESS;

View File

@ -269,9 +269,9 @@ struct agent_pvt {
char agent[AST_MAX_AGENT]; /*!< Agent ID */
char password[AST_MAX_AGENT]; /*!< Password for Agent login */
char name[AST_MAX_AGENT];
ast_mutex_t app_lock; /**< Synchronization between owning applications */
int app_lock_flag;
ast_cond_t app_complete_cond;
ast_cond_t login_wait_cond;
volatile int app_sleep_cond; /**< Sleep condition for the login app */
struct ast_channel *owner; /**< Agent */
char logincallerid[80]; /**< Caller ID they had when they logged in */
@ -429,8 +429,8 @@ static struct agent_pvt *add_agent(const char *agent, int pending)
return NULL;
ast_copy_string(p->agent, agt, sizeof(p->agent));
ast_mutex_init(&p->lock);
ast_mutex_init(&p->app_lock);
ast_cond_init(&p->app_complete_cond, NULL);
ast_cond_init(&p->login_wait_cond, NULL);
p->app_lock_flag = 0;
p->app_sleep_cond = 1;
p->group = group;
@ -483,20 +483,23 @@ static struct agent_pvt *add_agent(const char *agent, int pending)
*/
static int agent_cleanup(struct agent_pvt *p)
{
struct ast_channel *chan = p->owner;
struct ast_channel *chan = NULL;
ast_mutex_lock(&p->lock);
chan = p->owner;
p->owner = NULL;
chan->tech_pvt = NULL;
p->app_sleep_cond = 1;
/* Release ownership of the agent to other threads (presumably running the login app). */
p->app_sleep_cond = 1;
p->app_lock_flag = 0;
ast_cond_signal(&p->app_complete_cond);
if (chan) {
chan = ast_channel_release(chan);
}
if (p->dead) {
ast_mutex_unlock(&p->lock);
ast_mutex_destroy(&p->lock);
ast_mutex_destroy(&p->app_lock);
ast_cond_destroy(&p->app_complete_cond);
ast_cond_destroy(&p->login_wait_cond);
ast_free(p);
}
return 0;
@ -773,30 +776,42 @@ static int agent_call(struct ast_channel *ast, char *dest, int timeout)
struct agent_pvt *p = ast->tech_pvt;
int res = -1;
int newstate=0;
struct ast_channel *chan;
ast_mutex_lock(&p->lock);
p->acknowledged = 0;
if (!p->chan) {
if (p->pending) {
ast_debug(1, "Pretending to dial on pending agent\n");
newstate = AST_STATE_DIALING;
res = 0;
} else {
ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
res = -1;
}
if (p->pending) {
ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
ast_mutex_unlock(&p->lock);
ast_setstate(ast, AST_STATE_DIALING);
return 0;
}
if (!p->chan) {
ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
ast_mutex_unlock(&p->lock);
if (newstate)
ast_setstate(ast, newstate);
return res;
}
ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language);
res = ast_streamfile(p->chan, beep, p->chan->language);
chan = p->chan;
ast_mutex_unlock(&p->lock);
res = ast_streamfile(chan, beep, chan->language);
ast_debug(3, "Played beep, result '%d'\n", res);
if (!res) {
res = ast_waitstream(p->chan, "");
res = ast_waitstream(chan, "");
ast_debug(3, "Waited for stream, result '%d'\n", res);
}
ast_mutex_lock(&p->lock);
if (!p->chan) {
/* chan went away while we were streaming, this shouldn't be possible */
res = -1;
}
if (!res) {
struct ast_format tmpfmt;
res = ast_set_read_format_from_cap(p->chan, p->chan->nativeformats);
@ -872,7 +887,6 @@ int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base)
static int agent_hangup(struct ast_channel *ast)
{
struct agent_pvt *p = ast->tech_pvt;
int howlong = 0;
ast_mutex_lock(&p->lock);
p->owner = NULL;
@ -880,6 +894,10 @@ static int agent_hangup(struct ast_channel *ast)
p->app_sleep_cond = 1;
p->acknowledged = 0;
/* Release ownership of the agent to other threads (presumably running the login app). */
p->app_lock_flag = 0;
ast_cond_signal(&p->app_complete_cond);
/* if they really are hung up then set start to 0 so the test
* later if we're called on an already downed channel
* doesn't cause an agent to be logged out like when
@ -889,11 +907,8 @@ static int agent_hangup(struct ast_channel *ast)
ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
if (p->start && (ast->_state != AST_STATE_UP)) {
howlong = time(NULL) - p->start;
p->start = 0;
} else if (ast->_state == AST_STATE_RESERVED)
howlong = 0;
else
} else
p->start = 0;
if (p->chan) {
p->chan->_bridge = NULL;
@ -930,8 +945,8 @@ static int agent_hangup(struct ast_channel *ast)
p->abouttograb = 0;
} else if (p->dead) {
ast_mutex_destroy(&p->lock);
ast_mutex_destroy(&p->app_lock);
ast_cond_destroy(&p->app_complete_cond);
ast_cond_destroy(&p->login_wait_cond);
ast_free(p);
} else {
if (p->chan) {
@ -941,9 +956,6 @@ static int agent_hangup(struct ast_channel *ast)
p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
ast_mutex_unlock(&p->lock);
}
/* Release ownership of the agent to other threads (presumably running the login app). */
p->app_lock_flag = 0;
ast_cond_signal(&p->app_complete_cond);
}
return 0;
}
@ -1030,7 +1042,6 @@ static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct
static struct ast_channel *agent_new(struct agent_pvt *p, int state, const char *linkedid)
{
struct ast_channel *tmp;
int alreadylocked;
#if 0
if (!p->chan) {
ast_log(LOG_WARNING, "No channel? :(\n");
@ -1068,38 +1079,6 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state, const char
tmp->tech_pvt = p;
p->owner = tmp;
tmp->priority = 1;
/* Wake up and wait for other applications (by definition the login app)
* to release this channel). Takes ownership of the agent channel
* to this thread only.
* For signalling the other thread, ast_queue_frame is used until we
* can safely use signals for this purpose. The pselect() needs to be
* implemented in the kernel for this.
*/
p->app_sleep_cond = 0;
alreadylocked = p->app_lock_flag;
p->app_lock_flag = 1;
if (alreadylocked) {
if (p->chan) {
ast_queue_frame(p->chan, &ast_null_frame);
ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
p->app_lock_flag = 1;
ast_mutex_lock(&p->lock);
} else {
ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
p->owner = NULL;
tmp->tech_pvt = NULL;
p->app_sleep_cond = 1;
tmp = ast_channel_release(tmp);
ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
p->app_lock_flag = 0;
ast_cond_signal(&p->app_complete_cond);
return NULL;
}
}
if (p->chan)
ast_indicate(p->chan, AST_CONTROL_UNHOLD);
return tmp;
}
@ -1257,8 +1236,8 @@ static int read_agent_config(int reload)
if (!p->owner) {
if (!p->chan) {
ast_mutex_destroy(&p->lock);
ast_mutex_destroy(&p->app_lock);
ast_cond_destroy(&p->app_complete_cond);
ast_cond_destroy(&p->login_wait_cond);
ast_free(p);
} else {
/* Cause them to hang up */
@ -1459,6 +1438,45 @@ static struct ast_channel *agent_request(const char *type, struct ast_format_cap
}
*cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
AST_LIST_UNLOCK(&agents);
if (chan) {
ast_mutex_lock(&p->lock);
if (p->pending) {
ast_mutex_unlock(&p->lock);
return chan;
}
if (!p->chan) {
ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
*cause = AST_CAUSE_UNREGISTERED;
ast_mutex_unlock(&p->lock);
agent_hangup(chan);
return NULL;
}
/* we need to take control of the channel from the login app
* thread */
p->app_sleep_cond = 0;
p->app_lock_flag = 1;
ast_queue_frame(p->chan, &ast_null_frame);
ast_cond_wait(&p->login_wait_cond, &p->lock);
if (!p->chan) {
ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
p->app_sleep_cond = 1;
p->app_lock_flag = 0;
ast_cond_signal(&p->app_complete_cond);
ast_mutex_unlock(&p->lock);
*cause = AST_CAUSE_UNREGISTERED;
agent_hangup(chan);
return NULL;
}
ast_indicate(p->chan, AST_CONTROL_UNHOLD);
ast_mutex_unlock(&p->lock);
}
return chan;
}
@ -1834,7 +1852,6 @@ static int login_exec(struct ast_channel *chan, const char *data)
int max_login_tries = maxlogintries;
struct agent_pvt *p;
struct ast_module_user *u;
int login_state = 0;
char user[AST_MAX_AGENT] = "";
char pass[AST_MAX_AGENT];
char agent[AST_MAX_AGENT] = "";
@ -1928,7 +1945,6 @@ static int login_exec(struct ast_channel *chan, const char *data)
ast_mutex_lock(&p->lock);
if (!strcmp(p->agent, user) &&
!strcmp(p->password, pass) && !p->pending) {
login_state = 1; /* Successful Login */
/* Ensure we can't be gotten until we're done */
p->lastdisc = ast_tvnow();
@ -2070,13 +2086,13 @@ static int login_exec(struct ast_channel *chan, const char *data)
}
ast_mutex_unlock(&p->lock);
AST_LIST_UNLOCK(&agents);
/* Synchronize channel ownership between call to agent and itself. */
ast_mutex_lock(&p->app_lock);
if (p->app_lock_flag == 1) {
ast_cond_wait(&p->app_complete_cond, &p->app_lock);
}
ast_mutex_unlock(&p->app_lock);
ast_mutex_lock(&p->lock);
if (p->app_lock_flag == 1) {
ast_cond_signal(&p->login_wait_cond);
ast_cond_wait(&p->app_complete_cond, &p->lock);
}
ast_mutex_unlock(&p->lock);
if (p->ackcall) {
res = agent_ack_sleep(p);
@ -2094,12 +2110,20 @@ static int login_exec(struct ast_channel *chan, const char *data)
sched_yield();
}
ast_mutex_lock(&p->lock);
if (res && p->owner)
ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
/* Log us off if appropriate */
if (p->chan == chan) {
p->chan = NULL;
}
/* Synchronize channel ownership between call to agent and itself. */
if (p->app_lock_flag == 1) {
ast_cond_signal(&p->login_wait_cond);
ast_cond_wait(&p->app_complete_cond, &p->lock);
}
if (res && p->owner)
ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
p->acknowledged = 0;
logintime = time(NULL) - p->loginstart;
p->loginstart = 0;
@ -2115,8 +2139,8 @@ static int login_exec(struct ast_channel *chan, const char *data)
ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
if (p->dead && !p->owner) {
ast_mutex_destroy(&p->lock);
ast_mutex_destroy(&p->app_lock);
ast_cond_destroy(&p->app_complete_cond);
ast_cond_destroy(&p->login_wait_cond);
ast_free(p);
}
}

View File

@ -57,13 +57,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/musiconhold.h"
#include "asterisk/poll-compat.h"
/*! Global jitterbuffer configuration - by default, jb is disabled */
/*! Global jitterbuffer configuration - by default, jb is disabled
* \note Values shown here match the defaults shown in alsa.conf.sample */
static struct ast_jb_conf default_jbconf = {
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = "",
.target_extra = -1,
.max_size = 200,
.resync_threshold = 1000,
.impl = "fixed",
.target_extra = 40,
};
static struct ast_jb_conf global_jbconf;
@ -382,7 +383,6 @@ static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
static char sizbuf[8000];
static int sizpos = 0;
int len = sizpos;
int pos;
int res = 0;
/* size_t frames = 0; */
snd_pcm_state_t state;
@ -396,7 +396,6 @@ static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
} else {
memcpy(sizbuf + sizpos, f->data.ptr, f->datalen);
len += f->datalen;
pos = 0;
state = snd_pcm_state(alsa.ocard);
if (state == SND_PCM_STATE_XRUN)
snd_pcm_prepare(alsa.ocard);

View File

@ -172,13 +172,14 @@ AST_RWLOCK_DEFINE_STATIC(active_lock);
* \brief Global jitterbuffer configuration
*
* \note Disabled by default.
* \note Values shown here match the defaults shown in console.conf.sample
*/
static struct ast_jb_conf default_jbconf = {
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = "",
.target_extra = -1,
.max_size = 200,
.resync_threshold = 1000,
.impl = "fixed",
.target_extra = 40,
};
static struct ast_jb_conf global_jbconf;
@ -725,7 +726,7 @@ static char *cli_console_autoanswer(struct ast_cli_entry *e, int cmd,
unref_pvt(pvt);
return CLI_SUCCESS;
return res;
}
static char *cli_console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

View File

@ -235,7 +235,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
<parameter name="DAHDIChannel" required="true" />
<parameter name="DAHDIChannel">
<para>Specify the specific channel to show. Show all channels if zero or not present.</para>
</parameter>
</syntax>
<description>
</description>
@ -250,6 +252,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<description>
</description>
</manager>
<manager name="PRIShowSpans" language="en_US">
<synopsis>
Show status of PRI spans.
</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
<parameter name="Span">
<para>Specify the specific span to show. Show all spans if zero or not present.</para>
</parameter>
</syntax>
<description>
</description>
</manager>
***/
#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
@ -265,14 +280,15 @@ static const char * const lbostr[] = {
"-22.5db (CSU)"
};
/*! Global jitterbuffer configuration - by default, jb is disabled */
/*! Global jitterbuffer configuration - by default, jb is disabled
* \note Values shown here match the defaults shown in chan_dahdi.conf.sample */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = "",
.target_extra = -1,
.max_size = 200,
.resync_threshold = 1000,
.impl = "fixed",
.target_extra = 40,
};
static struct ast_jb_conf global_jbconf;
@ -979,6 +995,11 @@ struct dahdi_pvt {
* \note The "context" string read in from chan_dahdi.conf
*/
char context[AST_MAX_CONTEXT];
/*!
* \brief A description for the channel configuration
* \note The "description" string read in from chan_dahdi.conf
*/
char description[32];
/*!
* \brief Saved context string.
*/
@ -1276,6 +1297,7 @@ struct dahdi_pvt {
MEMBER(dahdi_pvt, use_smdi, AST_DATA_BOOLEAN) \
MEMBER(dahdi_pvt, context, AST_DATA_STRING) \
MEMBER(dahdi_pvt, defcontext, AST_DATA_STRING) \
MEMBER(dahdi_pvt, description, AST_DATA_STRING) \
MEMBER(dahdi_pvt, exten, AST_DATA_STRING) \
MEMBER(dahdi_pvt, language, AST_DATA_STRING) \
MEMBER(dahdi_pvt, mohinterpret, AST_DATA_STRING) \
@ -2937,18 +2959,21 @@ static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoper
return -1;
}
if (sub != ANALOG_SUB_REAL)
printf("Trying to dial digits on sub %d\n", sub);
if (sub != ANALOG_SUB_REAL) {
ast_log(LOG_ERROR, "Trying to dial_digits '%s' on channel %d subchannel %d\n",
dop->dialstr, p->channel, sub);
return -1;
}
ddop.op = DAHDI_DIAL_OP_REPLACE;
strncpy(ddop.dialstr, dop->dialstr, sizeof(ddop.dialstr));
ast_copy_string(ddop.dialstr, dop->dialstr, sizeof(ddop.dialstr));
printf("Dialing %s on %d\n", ddop.dialstr, p->channel);
ast_debug(1, "Channel %d: Sending '%s' to DAHDI_DIAL.\n", p->channel, ddop.dialstr);
res = ioctl(p->subs[index].dfd, DAHDI_DIAL, &ddop);
if (res == -1)
if (res == -1) {
ast_debug(1, "DAHDI_DIAL ioctl failed on %s: %s\n", p->owner->name, strerror(errno));
}
return res;
}
@ -6111,46 +6136,73 @@ static int dahdi_hangup(struct ast_channel *ast)
p->cid_subaddr[0] = '\0';
}
#ifdef HAVE_PRI
#if defined(HAVE_PRI)
if (dahdi_sig_pri_lib_handles(p->sig)) {
x = 1;
ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
dahdi_confmute(p, 0);
p->muting = 0;
restore_gains(p);
if (p->dsp) {
ast_dsp_free(p->dsp);
p->dsp = NULL;
}
p->ignoredtmf = 0;
revert_fax_buffers(p, ast);
dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
p->law = p->law_default;
law = p->law_default;
res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
dahdi_disable_ec(p);
update_conf(p);
reset_conf(p);
sig_pri_hangup(p->sig_pvt, ast);
p->subs[SUB_REAL].owner = NULL;
p->subs[SUB_REAL].needbusy = 0;
p->owner = NULL;
p->cid_tag[0] = '\0';
p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
p->outgoing = 0;
p->digital = 0;
p->faxhandled = 0;
p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
goto hangup_out;
}
#endif
#if defined(HAVE_SS7)
if (p->sig == SIG_SS7) {
x = 1;
ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
dahdi_confmute(p, 0);
p->muting = 0;
restore_gains(p);
if (p->dsp) {
ast_dsp_free(p->dsp);
p->dsp = NULL;
}
p->ignoredtmf = 0;
/* Real channel, do some fixup */
p->subs[SUB_REAL].owner = NULL;
p->subs[SUB_REAL].needbusy = 0;
dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
p->owner = NULL;
p->cid_tag[0] = '\0';
p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
p->outgoing = 0;
p->digital = 0;
p->faxhandled = 0;
p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
revert_fax_buffers(p, ast);
p->law = p->law_default;
law = p->law_default;
res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
p->channel, strerror(errno));
}
sig_pri_hangup(p->sig_pvt, ast);
tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
dahdi_disable_ec(p);
x = 0;
ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
p->rdnis[0] = '\0';
update_conf(p);
reset_conf(p);
/* Restore data mode */
x = 0;
ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
if (num_restart_pending == 0) {
restart_monitor();
}
goto hangup_out;
}
#endif /* defined(HAVE_PRI) */
#if defined(HAVE_SS7)
if (p->sig == SIG_SS7) {
x = 1;
ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
dahdi_confmute(p, 0);
p->muting = 0;
@ -6164,7 +6216,6 @@ static int dahdi_hangup(struct ast_channel *ast)
/* Real channel, do some fixup */
p->subs[SUB_REAL].owner = NULL;
p->subs[SUB_REAL].needbusy = 0;
p->polarity = POLARITY_IDLE;
dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
p->owner = NULL;
@ -6181,28 +6232,30 @@ static int dahdi_hangup(struct ast_channel *ast)
p->law = p->law_default;
law = p->law_default;
res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
if (res < 0)
ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
p->channel, strerror(errno));
}
sig_ss7_hangup(p->sig_pvt, ast);
tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
dahdi_disable_ec(p);
x = 0;
ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
update_conf(p);
reset_conf(p);
/* Restore data mode */
x = 0;
ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
if (num_restart_pending == 0)
if (num_restart_pending == 0) {
restart_monitor();
ast->tech_pvt = NULL;
}
goto hangup_out;
}
#endif /* defined(HAVE_SS7) */
@ -6416,6 +6469,7 @@ static int dahdi_hangup(struct ast_channel *ast)
break;
default:
tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
break;
}
if (p->sig)
dahdi_disable_ec(p);
@ -6449,8 +6503,8 @@ static int dahdi_hangup(struct ast_channel *ast)
p->cidcwexpire = 0;
p->cid_suppress_expire = 0;
p->oprmode = 0;
ast->tech_pvt = NULL;
hangup_out:
ast->tech_pvt = NULL;
ast_free(p->cidspill);
p->cidspill = NULL;
@ -9986,7 +10040,10 @@ static void *analog_ss_thread(void *data)
/* some switches require a minimum guard time between
the last FGD wink and something that answers
immediately. This ensures it */
if (ast_safe_sleep(chan,100)) goto quit;
if (ast_safe_sleep(chan, 100)) {
ast_hangup(chan);
goto quit;
}
}
dahdi_enable_ec(p);
if (NEED_MFDETECT(p)) {
@ -12135,6 +12192,12 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
if (tmp) {
int chan_sig = conf->chan.sig;
/* If there are variables in tmp before it is updated to match the new config, clear them */
if (reloading && tmp->vars) {
ast_variables_destroy(tmp->vars);
tmp->vars = NULL;
}
if (!here) {
/* Can only get here if this is a new channel interface being created. */
if ((channel != CHAN_PSEUDO)) {
@ -12439,6 +12502,9 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
ast_copy_string(pris[span].pri.mwi_mailboxes,
conf->pri.pri.mwi_mailboxes,
sizeof(pris[span].pri.mwi_mailboxes));
ast_copy_string(pris[span].pri.mwi_vm_numbers,
conf->pri.pri.mwi_vm_numbers,
sizeof(pris[span].pri.mwi_vm_numbers));
#endif /* defined(HAVE_PRI_MWI) */
ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));
ast_copy_string(pris[span].pri.idleext, conf->pri.pri.idleext, sizeof(pris[span].pri.idleext));
@ -12456,6 +12522,9 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
#if defined(HAVE_PRI_MCID)
pris[span].pri.mcid_send = conf->pri.pri.mcid_send;
#endif /* defined(HAVE_PRI_MCID) */
#if defined(HAVE_PRI_DATETIME_SEND)
pris[span].pri.datetime_send = conf->pri.pri.datetime_send;
#endif /* defined(HAVE_PRI_DATETIME_SEND) */
for (x = 0; x < PRI_MAX_TIMERS; x++) {
pris[span].pri.pritimers[x] = conf->pri.pri.pritimers[x];
@ -12673,6 +12742,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
ast_copy_string(tmp->description, conf->chan.description, sizeof(tmp->description));
ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
tmp->cid_ton = 0;
if (analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
@ -13476,6 +13546,7 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
}
}
p->distinctivering = 0;
/* Make special notes */
switch (start.opt) {
case '\0':
@ -14986,8 +15057,8 @@ static int action_dahdirestart(struct mansession *s, const struct message *m)
static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
#define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
#define FORMAT2 "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
#define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s %-32.32s\n"
#define FORMAT2 "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s %-32.32s\n"
unsigned int targetnum = 0;
int filtertype = 0;
struct dahdi_pvt *tmp = NULL;
@ -15024,7 +15095,7 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
}
}
ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State");
ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State", "Description");
ast_mutex_lock(&iflock);
for (tmp = iflist; tmp; tmp = tmp->next) {
if (filtertype) {
@ -15062,7 +15133,7 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
snprintf(statestr, sizeof(statestr), "%s", "In Service");
ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr);
ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr, tmp->description);
}
ast_mutex_unlock(&iflock);
return CLI_SUCCESS;
@ -15098,6 +15169,7 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli
for (tmp = iflist; tmp; tmp = tmp->next) {
if (tmp->channel == channel) {
ast_cli(a->fd, "Channel: %d\n", tmp->channel);
ast_cli(a->fd, "Description: %s\n", tmp->description);
ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
ast_cli(a->fd, "Span: %d\n", tmp->span);
ast_cli(a->fd, "Extension: %s\n", tmp->exten);
@ -15803,6 +15875,7 @@ static int action_dahdishowchannels(struct mansession *s, const struct message *
"Context: %s\r\n"
"DND: %s\r\n"
"Alarm: %s\r\n"
"Description: %s\r\n"
"%s"
"\r\n",
tmp->channel,
@ -15813,7 +15886,8 @@ static int action_dahdishowchannels(struct mansession *s, const struct message *
tmp->sig,
tmp->context,
dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
alarm2str(alm), idText);
alarm2str(alm),
tmp->description, idText);
} else {
astman_append(s,
"Event: DAHDIShowChannels\r\n"
@ -15823,12 +15897,14 @@ static int action_dahdishowchannels(struct mansession *s, const struct message *
"Context: %s\r\n"
"DND: %s\r\n"
"Alarm: %s\r\n"
"Description: %s\r\n"
"%s"
"\r\n",
tmp->channel, sig2str(tmp->sig), tmp->sig,
tmp->context,
dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
alarm2str(alm), idText);
alarm2str(alm),
tmp->description, idText);
}
}
}
@ -15845,6 +15921,60 @@ static int action_dahdishowchannels(struct mansession *s, const struct message *
return 0;
}
#if defined(HAVE_PRI)
static int action_prishowspans(struct mansession *s, const struct message *m)
{
int count;
int idx;
int span_query;
struct dahdi_pri *dspan;
const char *id = astman_get_header(m, "ActionID");
const char *span_str = astman_get_header(m, "Span");
char action_id[256];
const char *show_cmd = "PRIShowSpans";
/* NOTE: Asking for span 0 gets all spans. */
if (!ast_strlen_zero(span_str)) {
span_query = atoi(span_str);
} else {
span_query = 0;
}
if (!ast_strlen_zero(id)) {
snprintf(action_id, sizeof(action_id), "ActionID: %s\r\n", id);
} else {
action_id[0] = '\0';
}
astman_send_ack(s, m, "Span status will follow");
count = 0;
for (idx = 0; idx < ARRAY_LEN(pris); ++idx) {
dspan = &pris[idx];
/* If a specific span is asked for, only deliver status for that span. */
if (0 < span_query && dspan->pri.span != span_query) {
continue;
}
if (dspan->pri.pri) {
count += sig_pri_ami_show_spans(s, show_cmd, &dspan->pri, dspan->dchannels,
action_id);
}
}
astman_append(s,
"Event: %sComplete\r\n"
"Items: %d\r\n"
"%s"
"\r\n",
show_cmd,
count,
action_id);
return 0;
}
#endif /* defined(HAVE_PRI) */
#if defined(HAVE_SS7)
static int linkset_addsigchan(int sigchan)
{
@ -16420,6 +16550,9 @@ static int __unload_module(void)
ast_manager_unregister("DAHDIDNDon");
ast_manager_unregister("DAHDIShowChannels");
ast_manager_unregister("DAHDIRestart");
#if defined(HAVE_PRI)
ast_manager_unregister("PRIShowSpans");
#endif /* defined(HAVE_PRI) */
ast_data_unregister(NULL);
ast_channel_unregister(&dahdi_tech);
@ -16683,6 +16816,40 @@ static unsigned long dahdi_display_text_option(const char *value)
#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
#endif /* defined(HAVE_PRI) */
#if defined(HAVE_PRI)
#if defined(HAVE_PRI_DATETIME_SEND)
/*!
* \internal
* \brief Determine the configured date/time send policy option.
* \since 1.10
*
* \param value Configuration value string.
*
* \return Configured date/time send policy option.
*/
static int dahdi_datetime_send_option(const char *value)
{
int option;
option = PRI_DATE_TIME_SEND_DEFAULT;
if (ast_false(value)) {
option = PRI_DATE_TIME_SEND_NO;
} else if (!strcasecmp(value, "date")) {
option = PRI_DATE_TIME_SEND_DATE;
} else if (!strcasecmp(value, "date_hh")) {
option = PRI_DATE_TIME_SEND_DATE_HH;
} else if (!strcasecmp(value, "date_hhmm")) {
option = PRI_DATE_TIME_SEND_DATE_HHMM;
} else if (!strcasecmp(value, "date_hhmmss")) {
option = PRI_DATE_TIME_SEND_DATE_HHMMSS;
}
return option;
}
#endif /* defined(HAVE_PRI_DATETIME_SEND) */
#endif /* defined(HAVE_PRI) */
/*! process_dahdi() - ignore keyword 'channel' and similar */
#define PROC_DAHDI_OPT_NOCHAN (1 << 0)
/*! process_dahdi() - No warnings on non-existing cofiguration keywords */
@ -16827,6 +16994,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
confp->chan.dtmfrelax = 0;
} else if (!strcasecmp(v->name, "mailbox")) {
ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
} else if (!strcasecmp(v->name, "description")) {
ast_copy_string(confp->chan.description, v->value, sizeof(confp->chan.description));
} else if (!strcasecmp(v->name, "hasvoicemail")) {
if (ast_true(v->value) && ast_strlen_zero(confp->chan.mailbox)) {
ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
@ -17485,6 +17654,9 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
} else if (!strcasecmp(v->name, "mwi_mailboxes")) {
ast_copy_string(confp->pri.pri.mwi_mailboxes, v->value,
sizeof(confp->pri.pri.mwi_mailboxes));
} else if (!strcasecmp(v->name, "mwi_vm_numbers")) {
ast_copy_string(confp->pri.pri.mwi_vm_numbers, v->value,
sizeof(confp->pri.pri.mwi_vm_numbers));
#endif /* defined(HAVE_PRI_MWI) */
} else if (!strcasecmp(v->name, "append_msn_to_cid_tag")) {
confp->pri.pri.append_msn_to_user_tag = ast_true(v->value);
@ -17498,6 +17670,10 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
} else if (!strcasecmp(v->name, "mcid_send")) {
confp->pri.pri.mcid_send = ast_true(v->value);
#endif /* defined(HAVE_PRI_MCID) */
#if defined(HAVE_PRI_DATETIME_SEND)
} else if (!strcasecmp(v->name, "datetime_send")) {
confp->pri.pri.datetime_send = dahdi_datetime_send_option(v->value);
#endif /* defined(HAVE_PRI_DATETIME_SEND) */
#endif /* HAVE_PRI */
#if defined(HAVE_SS7)
} else if (!strcasecmp(v->name, "ss7type")) {
@ -17814,6 +17990,13 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
} else if (!(options & PROC_DAHDI_OPT_NOWARN) )
ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
}
/* Since confp has already filled invidual dahdi_pvt objects with channels at this point, clear the variables in confp's pvt. */
if (confp->chan.vars) {
ast_variables_destroy(confp->chan.vars);
confp->chan.vars = NULL;
}
if (dahdichan[0]) {
/* The user has set 'dahdichan' */
/*< \todo pass proper line number instead of 0 */
@ -18390,6 +18573,9 @@ static int load_module(void)
ast_manager_register_xml("DAHDIDNDoff", 0, action_dahdidndoff);
ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels);
ast_manager_register_xml("DAHDIRestart", 0, action_dahdirestart);
#if defined(HAVE_PRI)
ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans);
#endif /* defined(HAVE_PRI) */
ast_cond_init(&ss_thread_complete, NULL);

View File

@ -114,14 +114,15 @@ onhold_cb on_hold;
int h323debug; /*!< global debug flag */
/*! \brief Global jitterbuffer configuration - by default, jb is disabled */
/*! \brief Global jitterbuffer configuration - by default, jb is disabled
* \note Values shown here match the defaults shown in h323.conf.sample */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = "",
.target_extra = -1,
.max_size = 200,
.resync_threshold = 1000,
.impl = "fixed",
.target_extra = 40,
};
static struct ast_jb_conf global_jbconf;

View File

@ -484,6 +484,7 @@ struct iax2_peer {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(name);
AST_STRING_FIELD(username);
AST_STRING_FIELD(description); /*!< Description of the peer */
AST_STRING_FIELD(secret);
AST_STRING_FIELD(dbsecret);
AST_STRING_FIELD(outkey); /*!< What key we use to talk to this peer */
@ -1281,10 +1282,7 @@ static void network_change_event_subscribe(void)
{
if (!network_change_event_subscription) {
network_change_event_subscription = ast_event_subscribe(AST_EVENT_NETWORK_CHANGE,
network_change_event_cb,
"SIP Network Change ",
NULL,
AST_EVENT_IE_END);
network_change_event_cb, "IAX2 Network Change", NULL, AST_EVENT_IE_END);
}
}
@ -3837,6 +3835,7 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
encmethods_to_str(peer->encmethods, encmethods);
ast_cli(a->fd, "\n\n");
ast_cli(a->fd, " * Name : %s\n", peer->name);
ast_cli(a->fd, " Description : %s\n", peer->description);
ast_cli(a->fd, " Secret : %s\n", ast_strlen_zero(peer->secret) ? "<Not set>" : "<Set>");
ast_cli(a->fd, " Context : %s\n", peer->context);
ast_cli(a->fd, " Parking lot : %s\n", peer->parkinglot);
@ -4636,7 +4635,9 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka
return -1;
}
ast_sockaddr_to_sin(&sin_tmp, sin);
sin->sin_port = htons(IAX_DEFAULT_PORTNO);
if (sin->sin_port == 0) {
sin->sin_port = htons(IAX_DEFAULT_PORTNO);
}
/* use global iax prefs for unknown peer/user */
/* But move the calling channel's native codec to the top of the preference list */
memcpy(&ourprefs, &prefs, sizeof(ourprefs));
@ -5432,7 +5433,7 @@ static int iax2_queryoption(struct ast_channel *c, int option, void *data, int *
static struct ast_frame *iax2_read(struct ast_channel *c)
{
ast_log(LOG_NOTICE, "I should never be called!\n");
ast_debug(1, "I should never be called!\n");
return &ast_null_frame;
}
@ -6159,7 +6160,6 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
struct iax2_trunk_peer *tpeer;
void *tmp, *ptr;
struct timeval now;
int res;
struct ast_iax2_meta_trunk_entry *met;
struct ast_iax2_meta_trunk_mini *mtm;
@ -6215,7 +6215,7 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
/* if we have enough for a full MTU, ship it now without waiting */
if (global_max_trunk_mtu > 0 && tpeer->trunkdatalen + f->datalen + 4 >= global_max_trunk_mtu) {
now = ast_tvnow();
res = send_trunk(tpeer, &now);
send_trunk(tpeer, &now);
trunk_untimed ++;
}
@ -6712,8 +6712,8 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
int unmonitored_peers = 0;
struct ao2_iterator i;
#define FORMAT2 "%-15.15s %-15.15s %s %-15.15s %-8s %s %-10s\n"
#define FORMAT "%-15.15s %-15.15s %s %-15.15s %-5d%s %s %-10s\n"
#define FORMAT2 "%-15.15s %-15.15s %s %-15.15s %-8s %s %-11s %-32.32s\n"
#define FORMAT "%-15.15s %-15.15s %s %-15.15s %-5d%s %s %-11s %-32.32s\n"
struct iax2_peer *peer = NULL;
char name[256];
@ -6755,7 +6755,7 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
if (!s)
ast_cli(fd, FORMAT2, "Name/Username", "Host", " ", "Mask", "Port", " ", "Status");
ast_cli(fd, FORMAT2, "Name/Username", "Host", " ", "Mask", "Port", " ", "Status", "Description");
i = ao2_iterator_init(peers, 0);
for (peer = ao2_iterator_next(&i); peer;
@ -6801,7 +6801,8 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
"Dynamic: %s\r\n"
"Trunk: %s\r\n"
"Encryption: %s\r\n"
"Status: %s\r\n\r\n",
"Status: %s\r\n"
"Description: %s\r\n\r\n",
idtext,
name,
ast_sockaddr_stringify_addr(&peer->addr),
@ -6809,7 +6810,8 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
ast_test_flag64(peer, IAX_DYNAMIC) ? "yes" : "no",
ast_test_flag64(peer, IAX_TRUNK) ? "yes" : "no",
peer->encmethods ? ast_str_buffer(encmethods) : "no",
status);
status,
peer->description);
} else {
ast_cli(fd, FORMAT, name,
ast_sockaddr_stringify_addr(&peer->addr),
@ -6818,7 +6820,8 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
ast_sockaddr_port(&peer->addr),
ast_test_flag64(peer, IAX_TRUNK) ? "(T)" : " ",
peer->encmethods ? "(E)" : " ",
status);
status,
peer->description);
}
total_peers++;
}
@ -9345,7 +9348,6 @@ static void *iax_park_thread(void *stuff)
struct iax_dual *d;
struct ast_frame *f;
int ext;
int res;
d = stuff;
chan1 = d->chan1;
chan2 = d->chan2;
@ -9353,7 +9355,7 @@ static void *iax_park_thread(void *stuff)
f = ast_read(chan1);
if (f)
ast_frfree(f);
res = ast_park_call(chan1, chan2, 0, d->parkexten, &ext);
ast_park_call(chan1, chan2, 0, d->parkexten, &ext);
ast_hangup(chan2);
ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext);
return NULL;
@ -12459,6 +12461,8 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
ast_string_field_set(peer, mohsuggest, v->value);
} else if (!strcasecmp(v->name, "dbsecret")) {
ast_string_field_set(peer, dbsecret, v->value);
} else if (!strcasecmp(v->name, "description")) {
ast_string_field_set(peer, description, v->value);
} else if (!strcasecmp(v->name, "trunk")) {
ast_set2_flag64(peer, ast_true(v->value), IAX_TRUNK);
if (ast_test_flag64(peer, IAX_TRUNK) && !timer) {

View File

@ -587,7 +587,6 @@ static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p,
struct ast_sockaddr sin_tmp;
struct ast_sockaddr us_tmp;
struct ast_sockaddr bindaddr_tmp;
struct sockaddr_in dest;
struct in_addr us;
struct in_addr externaddr;
iks *iq, *jingle, *content, *transport, *candidate;
@ -668,9 +667,6 @@ static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p,
ours2 = NULL;
}
ours1 = NULL;
dest.sin_addr = __ourip;
dest.sin_port = sin.sin_port;
for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
snprintf(component, sizeof(component), "%u", tmp->component);

View File

@ -154,68 +154,124 @@ struct local_pvt {
#define LOCAL_BRIDGE (1 << 3) /*!< Report back the "true" channel as being bridged to */
#define LOCAL_MOH_PASSTHRU (1 << 4) /*!< Pass through music on hold start/stop frames */
static int local_setoption(struct ast_channel *chan, int option, void * data, int datalen)
/*
* \brief Send a pvt in with no locks held and get all locks
*
* \note NO locks should be held prior to calling this function
* \note The pvt must have a ref held before calling this function
* \note if outchan or outowner is set != NULL after calling this function
* those channels are locked and reffed.
* \note Batman.
*/
static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
{
int res;
struct local_pvt *p;
struct ast_channel *otherchan;
struct ast_channel *chan = NULL;
struct ast_channel *owner = NULL;
for (;;) {
ao2_lock(p);
if (p->chan) {
chan = p->chan;
ast_channel_ref(chan);
}
if (p->owner) {
owner = p->owner;
ast_channel_ref(owner);
}
ao2_unlock(p);
/* if we don't have both channels, then this is very easy */
if (!owner || !chan) {
if (owner) {
ast_channel_lock(owner);
} else if(chan) {
ast_channel_lock(chan);
}
ao2_lock(p);
} else {
/* lock both channels first, then get the pvt lock */
ast_channel_lock(chan);
while (ast_channel_trylock(owner)) {
CHANNEL_DEADLOCK_AVOIDANCE(chan);
}
ao2_lock(p);
}
/* Now that we have all the locks, validate that nothing changed */
if (p->owner != owner || p->chan != chan) {
if (owner) {
ast_channel_unlock(owner);
owner = ast_channel_unref(owner);
}
if (chan) {
ast_channel_unlock(chan);
chan = ast_channel_unref(chan);
}
ao2_unlock(p);
continue;
}
break;
}
*outowner = p->owner;
*outchan = p->chan;
}
static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen)
{
int res = 0;
struct local_pvt *p = NULL;
struct ast_channel *otherchan = NULL;
ast_chan_write_info_t *write_info;
if (option != AST_OPTION_CHANNEL_WRITE) {
return -1;
res = -1;
goto setoption_cleanup;
}
write_info = data;
if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
return -1;
res = -1;
goto setoption_cleanup;
}
startover:
ast_channel_lock(chan);
p = chan->tech_pvt;
if (!p) {
ast_channel_unlock(chan);
ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
return -1;
}
while (ao2_trylock(p)) {
ast_channel_unlock(chan);
sched_yield();
ast_channel_lock(chan);
p = chan->tech_pvt;
if (!p) {
ast_channel_unlock(chan);
ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
return -1;
}
/* get the tech pvt */
ast_channel_lock(ast);
if (!(p = ast->tech_pvt)) {
ast_channel_unlock(ast);
res = -1;
goto setoption_cleanup;
}
ao2_ref(p, 1);
ast_channel_unlock(ast);
/* get the channel we are supposed to write to */
ao2_lock(p);
otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
if (!otherchan || otherchan == write_info->chan) {
res = -1;
otherchan = NULL;
ao2_unlock(p);
ast_channel_unlock(chan);
ast_log(LOG_WARNING, "Could not update other side of %s, other side went away.\n", chan->name);
return 0;
goto setoption_cleanup;
}
ast_channel_ref(otherchan);
if (ast_channel_trylock(otherchan)) {
ao2_unlock(p);
ast_channel_unlock(chan);
goto startover;
}
res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
ast_channel_unlock(otherchan);
/* clear the pvt lock before grabbing the channel */
ao2_unlock(p);
ast_channel_unlock(chan);
ast_channel_lock(otherchan);
res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
ast_channel_unlock(otherchan);
setoption_cleanup:
if (p) {
ao2_ref(p, -1);
}
if (otherchan) {
ast_channel_unref(otherchan);
}
return res;
}
@ -294,57 +350,51 @@ static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct
static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
{
struct local_pvt *p = ast->tech_pvt;
struct ast_channel *chan, *bridged;
int res;
if (!p) {
return -1;
}
struct local_pvt *p;
struct ast_channel *bridged = NULL;
struct ast_channel *tmp = NULL;
int res = 0;
if (option != AST_OPTION_T38_STATE) {
/* AST_OPTION_T38_STATE is the only supported option at this time */
return -1;
}
/* for some reason the channel is not locked in channel.c when this function is called */
ast_channel_lock(ast);
if (!(p = ast->tech_pvt)) {
ast_channel_unlock(ast);
return -1;
}
ao2_lock(p);
chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
try_again:
if (!chan) {
if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
ao2_unlock(p);
ast_channel_unlock(ast);
return -1;
}
if (ast_channel_trylock(chan)) {
ao2_unlock(p);
sched_yield();
ao2_lock(p);
chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
goto try_again;
}
bridged = ast_bridged_channel(chan);
if (!bridged) {
/* can't query channel unless we are bridged */
ao2_unlock(p);
ast_channel_unlock(chan);
return -1;
}
if (ast_channel_trylock(bridged)) {
ast_channel_unlock(chan);
ao2_unlock(p);
sched_yield();
ao2_lock(p);
chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
goto try_again;
}
res = ast_channel_queryoption(bridged, option, data, datalen, 0);
ast_channel_ref(tmp);
ao2_unlock(p);
ast_channel_unlock(chan);
ast_channel_unlock(bridged);
ast_channel_unlock(ast);
ast_channel_lock(tmp);
if (!(bridged = ast_bridged_channel(tmp))) {
res = -1;
ast_channel_unlock(tmp);
goto query_cleanup;
}
ast_channel_ref(bridged);
ast_channel_unlock(tmp);
query_cleanup:
if (bridged) {
res = ast_channel_queryoption(bridged, option, data, datalen, 0);
bridged = ast_channel_unref(bridged);
}
if (tmp) {
tmp = ast_channel_unref(tmp);
}
return res;
}
@ -373,31 +423,24 @@ static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_fra
return 0;
}
/* Ensure that we have both channels locked */
while (other && ast_channel_trylock(other)) {
int res;
if ((res = ao2_unlock(p))) {
ast_log(LOG_ERROR, "chan_local bug! '&p->lock' was not locked when entering local_queue_frame! (%s)\n", strerror(res));
return -1;
}
if (us && us_locked) {
do {
CHANNEL_DEADLOCK_AVOIDANCE(us);
} while (ao2_trylock(p));
} else {
usleep(1);
ao2_lock(p);
}
other = isoutbound ? p->owner : p->chan;
/* grab a ref on the channel before unlocking the pvt,
* other can not go away from us now regardless of locking */
ast_channel_ref(other);
if (us && us_locked) {
ast_channel_unlock(us);
}
ao2_unlock(p);
if (other) {
if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
ast_setstate(other, AST_STATE_RINGING);
}
ast_queue_frame(other, f);
ast_channel_unlock(other);
if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
ast_setstate(other, AST_STATE_RINGING);
}
ast_queue_frame(other, f);
other = ast_channel_unref(other);
if (us && us_locked) {
ast_channel_lock(us);
}
ao2_lock(p);
return 0;
}
@ -429,12 +472,38 @@ static int local_answer(struct ast_channel *ast)
/*!
* \internal
* \note This function assumes that we're only called from the "outbound" local channel side
*
* \note it is assummed p is locked and reffed before entering this function
*/
static void check_bridge(struct local_pvt *p)
{
struct ast_channel_monitor *tmp;
if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan)))
struct ast_channel *chan = NULL;
struct ast_channel *bridged_chan = NULL;
/* Do a few conditional checks early on just to see if this optimization is possible */
if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) {
return;
}
if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || !p->chan || !p->owner) {
return;
}
/* Safely get the channel bridged to p->chan */
chan = ast_channel_ref(p->chan);
ao2_unlock(p); /* don't call bridged channel with the pvt locked */
bridged_chan = ast_bridged_channel(chan);
ao2_lock(p);
chan = ast_channel_unref(chan);
/* since we had to unlock p to get the bridged chan, validate our
* data once again and verify the bridged channel is what we expect
* it to be in order to perform this optimization */
if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || !p->owner || !p->chan || (p->chan->_bridge != bridged_chan)) {
return;
}
/* only do the masquerade if we are being called on the outbound channel,
if it has been bridged to another channel and if there are no pending
@ -504,8 +573,8 @@ static void check_bridge(struct local_pvt *p)
}
ast_channel_unlock(p->owner);
}
ast_channel_unlock(p->chan->_bridge);
}
ast_channel_unlock(p->chan->_bridge);
}
}
}
@ -521,18 +590,22 @@ static int local_write(struct ast_channel *ast, struct ast_frame *f)
int res = -1;
int isoutbound;
if (!p)
if (!p) {
return -1;
}
/* Just queue for delivery to the other side */
ao2_lock(p);
ao2_ref(p, 1); /* ref for local_queue_frame */
ao2_lock(p);
isoutbound = IS_OUTBOUND(ast, p);
if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
check_bridge(p);
if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
}
if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) {
res = local_queue_frame(p, isoutbound, f, ast, 1);
else {
} else {
ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
res = 0;
}
@ -562,7 +635,7 @@ static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
p->chan = newchan;
/* Do not let a masquerade cause a Local channel to be bridged to itself! */
if (!ast_check_hangup(newchan) && (p->owner->_bridge == p->chan || p->chan->_bridge == p->owner)) {
if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) {
ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
ao2_unlock(p);
ast_queue_hangup(newchan);
@ -731,46 +804,38 @@ static int local_sendhtml(struct ast_channel *ast, int subclass, const char *dat
static int local_call(struct ast_channel *ast, char *dest, int timeout)
{
struct local_pvt *p = ast->tech_pvt;
int pvt_locked = 0;
struct ast_channel *owner = NULL;
struct ast_channel *chan = NULL;
int res;
struct ast_var_t *varptr = NULL, *new;
size_t len, namelen;
char *reduced_dest = ast_strdupa(dest);
char *slash;
const char *exten;
const char *context;
if (!p || p->owner != ast) {
if (!p) {
return -1;
}
/* since we are letting go of channel locks that were locked coming into
* this function, then we need to give the tech pvt a ref */
ao2_ref(p, 1);
ast_channel_unlock(ast);
while (ao2_trylock(p)) {
ast_channel_unlock(ast);
sched_yield();
ast_channel_lock(ast);
}
while ((p->chan && p->owner) && ast_channel_trylock(p->chan)) {
ao2_unlock(p);
if (p->owner) {
ast_channel_unlock(p->owner);
}
sched_yield();
if (p->owner) {
ast_channel_lock(p->owner);
}
ao2_lock(p);
awesome_locking(p, &chan, &owner);
pvt_locked = 1;
if (owner != ast) {
res = -1;
goto return_cleanup;
}
if (!p->owner || !p->chan) {
/* someone went away during the locking madness.
* time to bail. */
if (p->chan) {
ast_channel_unlock(p->chan);
}
ao2_unlock(p);
ao2_ref(p,-1);
return -1;
if (!owner || !chan) {
res = -1;
goto return_cleanup;
}
/*
@ -780,37 +845,37 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout)
* All these failure points just return -1. The individual strings will
* be cleared when we destroy the channel.
*/
ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting);
ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting);
ast_party_dialed_copy(&p->chan->dialed, &p->owner->dialed);
ast_party_dialed_copy(&chan->dialed, &owner->dialed);
ast_connected_line_copy_to_caller(&p->chan->caller, &p->owner->connected);
ast_connected_line_copy_from_caller(&p->chan->connected, &p->owner->caller);
ast_connected_line_copy_to_caller(&chan->caller, &owner->connected);
ast_connected_line_copy_from_caller(&chan->connected, &owner->caller);
ast_string_field_set(p->chan, language, p->owner->language);
ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
ast_cdr_update(p->chan);
ast_string_field_set(chan, language, owner->language);
ast_string_field_set(chan, accountcode, owner->accountcode);
ast_string_field_set(chan, musicclass, owner->musicclass);
ast_cdr_update(chan);
ast_channel_cc_params_init(p->chan, ast_channel_get_cc_config_params(p->owner));
ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));
/* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */
if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
}
/* copy the channel variables from the incoming channel to the outgoing channel */
/* Note that due to certain assumptions, they MUST be in the same order */
AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) {
namelen = strlen(varptr->name);
len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
if ((new = ast_calloc(1, len))) {
memcpy(new, varptr, len);
new->value = &(new->name[0]) + namelen + 1;
AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
AST_LIST_INSERT_TAIL(&chan->varshead, new, entries);
}
}
ast_channel_datastore_inherit(p->owner, p->chan);
ast_channel_datastore_inherit(owner, chan);
/* If the local channel has /n or /b on the end of it,
* we need to lop that off for our argument to setting
* up the CC_INTERFACES variable
@ -818,24 +883,57 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout)
if ((slash = strrchr(reduced_dest, '/'))) {
*slash = '\0';
}
ast_set_cc_interfaces_chanvar(p->chan, reduced_dest);
ast_set_cc_interfaces_chanvar(chan, reduced_dest);
if (!ast_exists_extension(p->chan, p->chan->context, p->chan->exten, 1,
S_COR(p->owner->caller.id.number.valid, p->owner->caller.id.number.str, NULL))) {
ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
ao2_unlock(p);
ast_channel_unlock(p->chan);
ao2_ref(p, -1);
return -1;
exten = ast_strdupa(chan->exten);
context = ast_strdupa(chan->context);
ao2_unlock(p);
pvt_locked = 0;
ast_channel_unlock(chan);
if (!ast_exists_extension(chan, context, exten, 1,
S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) {
ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context);
res = -1;
chan = ast_channel_unref(chan); /* we already unlocked it, so clear it hear so the cleanup label won't touch it. */
goto return_cleanup;
}
/* Start switch on sub channel */
if (!(res = ast_pbx_start(p->chan)))
if (!(res = ast_pbx_start(chan))) {
ao2_lock(p);
ast_set_flag(p, LOCAL_LAUNCHED_PBX);
ao2_unlock(p);
}
chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */
return_cleanup:
if (p) {
if (pvt_locked) {
ao2_unlock(p);
}
ao2_ref(p, -1);
}
if (chan) {
ast_channel_unlock(chan);
chan = ast_channel_unref(chan);
}
/* owner is supposed to be == to ast, if it
* is, don't unlock it because ast must exit locked */
if (owner) {
if (owner != ast) {
ast_channel_unlock(owner);
ast_channel_lock(ast);
}
owner = ast_channel_unref(owner);
} else {
/* we have to exit with ast locked */
ast_channel_lock(ast);
}
ao2_unlock(p);
ast_channel_unlock(p->chan);
ao2_ref(p, -1);
return res;
}
@ -844,19 +942,31 @@ static int local_hangup(struct ast_channel *ast)
{
struct local_pvt *p = ast->tech_pvt;
int isoutbound;
int hangup_chan = 0;
int res = 0;
struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause };
struct ast_channel *ochan = NULL;
struct ast_channel *owner = NULL;
struct ast_channel *chan = NULL;
if (!p)
if (!p) {
return -1;
}
/* we MUST give the tech_pvt a ref here since we are unlocking the
* channel during deadlock avoidance. */
/* give the pvt a ref since we are unlocking the channel. */
ao2_ref(p, 1);
ao2_lock(p);
/* the pvt isn't going anywhere, we gave it a ref */
ast_channel_unlock(ast);
isoutbound = IS_OUTBOUND(ast, p);
/* lock everything */
awesome_locking(p, &chan, &owner);
if (ast != chan && ast != owner) {
res = -1;
goto local_hangup_cleanup;
}
isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */
if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
@ -866,92 +976,59 @@ static int local_hangup(struct ast_channel *ast)
if (isoutbound) {
const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
if ((status) && (p->owner)) {
/* Deadlock avoidance */
while (p->owner && ast_channel_trylock(p->owner)) {
ao2_unlock(p);
if (p->chan) {
ast_channel_unlock(p->chan);
}
sched_yield();
if (p->chan) {
ast_channel_lock(p->chan);
}
ao2_lock(p);
}
if (p->owner) {
p->owner->hangupcause = p->chan->hangupcause;
pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
ast_channel_unlock(p->owner);
}
}
if (!p->chan) {
/* chan was == to ast and was !NULL before deadlock avoidance started, if chan
* is NULL now, then we should bail because that channel
* hungup already. This is possible because we let go of the
* lock given to the ast channel passed to this function during
* deadlock avoidance. */
ao2_unlock(p);
ao2_ref(p, -1);
return 0;
}
p->chan = NULL;
ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
ast_module_user_remove(p->u_chan);
} else {
ast_module_user_remove(p->u_owner);
while (p->chan && ast_channel_trylock(p->chan)) {
ao2_unlock(p);
if (p->owner) {
ast_channel_unlock(p->owner);
}
sched_yield();
if (p->owner) {
ast_channel_lock(p->owner);
}
ao2_lock(p);
}
if (p->chan) {
ast_queue_hangup(p->chan);
ast_channel_unlock(p->chan);
p->owner->hangupcause = p->chan->hangupcause;
pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
}
if (!p->owner) {
/* owner was == to ast and was !NULL before deadlock avoidance started, if
* owner is NULL now, then we should bail because that channel
* hungup already. This is possible because we let go of the
* lock given to the ast channel passed to this function during
* deadlock avoidance. */
ao2_unlock(p);
ao2_ref(p, -1);
return 0;
ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
ast_module_user_remove(p->u_chan);
p->chan = NULL;
} else {
ast_module_user_remove(p->u_owner);
if (p->chan) {
ast_queue_hangup(p->chan);
}
p->owner = NULL;
}
ast->tech_pvt = NULL;
ast->tech_pvt = NULL; /* this is one of our locked channels, doesn't matter which */
if (!p->owner && !p->chan) {
ao2_unlock(p);
/* Remove from list */
ao2_unlink(locals, p);
ao2_ref(p, -1);
return 0;
p = NULL;
res = 0;
goto local_hangup_cleanup;
}
if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
/* Need to actually hangup since there is no PBX */
ochan = p->chan;
hangup_chan = 1;
} else {
local_queue_frame(p, isoutbound, &f, NULL, 1);
local_queue_frame(p, isoutbound, &f, NULL, 0);
}
ao2_unlock(p);
if (ochan) {
ast_hangup(ochan);
local_hangup_cleanup:
if (p) {
ao2_unlock(p);
ao2_ref(p, -1);
}
if (chan) {
ast_channel_unlock(chan);
if (hangup_chan) {
ast_hangup(chan);
}
chan = ast_channel_unref(chan);
}
if (owner) {
ast_channel_unlock(owner);
owner = ast_channel_unref(owner);
}
ao2_ref(p, -1);
return 0;
/* leave with the same stupid channel locked that came in */
ast_channel_lock(ast);
return res;
}
static void local_destroy(void *obj)

View File

@ -93,14 +93,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define INADDR_NONE (in_addr_t)(-1)
#endif
/*! Global jitterbuffer configuration - by default, jb is disabled */
/*! Global jitterbuffer configuration - by default, jb is disabled
* \note Values shown here match the defaults shown in mgcp.conf.sample */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = "",
.target_extra = -1,
.max_size = 200,
.resync_threshold = 1000,
.impl = "fixed",
.target_extra = 40,
};
static struct ast_jb_conf global_jbconf;
@ -3770,7 +3771,7 @@ static void *do_monitor(void *data)
{
int res;
int reloading;
struct mgcp_gateway *g, *gprev, *gnext;
struct mgcp_gateway *g, *gprev;
/*struct mgcp_gateway *g;*/
/*struct mgcp_endpoint *e;*/
/*time_t thispass = 0, lastpass = 0;*/
@ -3840,12 +3841,10 @@ static void *do_monitor(void *data)
g = gateways;
gprev = NULL;
while(g) {
gnext = g->next;
if(g->realtime) {
if(mgcp_prune_realtime_gateway(g)) {
if(gprev) {
gprev->next = gnext;
gprev = g;
gprev->next = g->next;
} else {
gateways = g->next;
}
@ -3859,7 +3858,7 @@ static void *do_monitor(void *data)
} else {
gprev = g;
}
g = gnext;
g = g->next;
}
ast_mutex_unlock(&gatelock);
lastrun = time(NULL);
@ -4748,7 +4747,7 @@ static int reload_config(int reload)
memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
}
if (!ntohs(bindaddr.sin_port))
bindaddr.sin_port = ntohs(DEFAULT_MGCP_CA_PORT);
bindaddr.sin_port = htons(DEFAULT_MGCP_CA_PORT);
bindaddr.sin_family = AF_INET;
ast_mutex_lock(&netlock);
if (mgcpsock > -1)

View File

@ -65,14 +65,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "console_video.h"
/*! Global jitterbuffer configuration - by default, jb is disabled */
/*! Global jitterbuffer configuration - by default, jb is disabled
* \note Values shown here match the defaults shown in oss.conf.sample */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = "",
.target_extra = -1,
.max_size = 200,
.resync_threshold = 1000,
.impl = "fixed",
.target_extra = 40,
};
static struct ast_jb_conf global_jbconf;

View File

@ -295,12 +295,10 @@ static int phone_call(struct ast_channel *ast, char *dest, int timeout)
ast_localtime(&UtcTime, &tm, NULL);
memset(&cid, 0, sizeof(PHONE_CID));
if(&tm != NULL) {
snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1));
snprintf(cid.day, sizeof(cid.day), "%02d", tm.tm_mday);
snprintf(cid.hour, sizeof(cid.hour), "%02d", tm.tm_hour);
snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min);
}
snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1));
snprintf(cid.day, sizeof(cid.day), "%02d", tm.tm_mday);
snprintf(cid.hour, sizeof(cid.hour), "%02d", tm.tm_hour);
snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min);
/* the standard format of ast->callerid is: "name" <number>, but not always complete */
if (!ast->connected.id.name.valid
|| ast_strlen_zero(ast->connected.id.name.str)) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -187,14 +187,15 @@ static void dummy(char *unused, ...)
return;
}
/*! \brief Global jitterbuffer configuration - by default, jb is disabled */
/*! \brief Global jitterbuffer configuration - by default, jb is disabled
* \note Values shown here match the defaults shown in unistim.conf.sample */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = "",
.target_extra = -1,
.max_size = 200,
.resync_threshold = 1000,
.impl = "fixed",
.target_extra = 40,
};
static struct ast_jb_conf global_jbconf;
@ -1324,7 +1325,7 @@ send_select_output(struct unistimsession *pte, unsigned char output, unsigned ch
change_favorite_icon(pte, FAV_ICON_SPEAKER_OFFHOOK_BLACK);
}
} else
ast_log(LOG_WARNING, "Invalid ouput (%d)\n", output);
ast_log(LOG_WARNING, "Invalid output (%d)\n", output);
if (output != pte->device->output)
pte->device->previous_output = pte->device->output;
pte->device->output = output;
@ -1924,7 +1925,7 @@ static int attempt_transfer(struct unistim_subchannel *p1, struct unistim_subcha
int res = 0;
struct ast_channel
*chana = NULL, *chanb = NULL, *bridgea = NULL, *bridgeb = NULL, *peera =
NULL, *peerb = NULL, *peerc = NULL, *peerd = NULL;
NULL, *peerb = NULL, *peerc = NULL;
if (!p1->owner || !p2->owner) {
ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
@ -1939,12 +1940,10 @@ static int attempt_transfer(struct unistim_subchannel *p1, struct unistim_subcha
peera = chana;
peerb = chanb;
peerc = bridgea;
peerd = bridgeb;
} else if (bridgeb) {
peera = chanb;
peerb = chana;
peerc = bridgeb;
peerd = bridgea;
}
if (peera && peerb && peerc && (peerb != peerc)) {

View File

@ -187,14 +187,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define EEPROM_TXCTCSSADJ 15
#define EEPROM_RXSQUELCHADJ 16
/*! Global jitterbuffer configuration - by default, jb is disabled */
/*! Global jitterbuffer configuration - by default, jb is disabled
* \note Values shown here match the defaults shown in usbradio.conf.sample */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = "",
.target_extra = -1,
.max_size = 200,
.resync_threshold = 1000,
.impl = "fixed",
.target_extra = 40,
};
static struct ast_jb_conf global_jbconf;

View File

@ -110,7 +110,6 @@ static unsigned int iax_str2flags(const char *buf)
{
int x;
int len;
int found;
unsigned int flags = 0;
char *e;
while(buf && *buf) {
@ -119,7 +118,6 @@ static unsigned int iax_str2flags(const char *buf)
len = e - buf;
else
len = 0;
found = 0;
for (x = 0; x < ARRAY_LEN(iax_flags); x++) {
if ((len && !strncasecmp(iax_flags[x].name, buf, len)) ||
(!len && !strcasecmp(iax_flags[x].name, buf))) {

View File

@ -1173,7 +1173,7 @@ int setup_bc(struct misdn_bchannel *bc)
cb_log(4, stack->port," --> Channel is %d\n", bc->channel);
if (bc->nodsp) {
if (bc->nodsp && !bc->hdlc) {
cb_log(2, stack->port," --> TRANSPARENT Mode (no DSP, no HDLC)\n");
pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
pid.protocol[2] = ISDN_PID_L2_B_TRANS;

View File

@ -47,14 +47,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define NUM_GEN_ELEMENTS (sizeof(gen_spec) / sizeof(struct misdn_cfg_spec))
#define NUM_PORT_ELEMENTS (sizeof(port_spec) / sizeof(struct misdn_cfg_spec))
/*! Global jitterbuffer configuration - by default, jb is disabled */
/*! Global jitterbuffer configuration - by default, jb is disabled
* \note Values shown here match the defaults shown in misdn.conf.sample */
static struct ast_jb_conf default_jbconf =
{
.flags = 0,
.max_size = -1,
.resync_threshold = -1,
.impl = "",
.target_extra = -1,
.max_size = 200,
.resync_threshold = 1000,
.impl = "fixed",
.target_extra = 40,
};
static struct ast_jb_conf global_jbconf;

View File

@ -1470,7 +1470,6 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
}
analog_stop_callwait(p);
ast->tech_pvt = NULL;
ast_verb(3, "Hanging up on '%s'\n", ast->name);
@ -2010,10 +2009,13 @@ static void *__analog_ss_thread(void *data)
}
if ((p->sig == ANALOG_SIG_FEATDMF) || (p->sig == ANALOG_SIG_FEATDMF_TA)) {
analog_wink(p, idx);
/* some switches require a minimum guard time between
the last FGD wink and something that answers
immediately. This ensures it */
if (ast_safe_sleep(chan,100)) {
/*
* Some switches require a minimum guard time between the last
* FGD wink and something that answers immediately. This
* ensures it.
*/
if (ast_safe_sleep(chan, 100)) {
ast_hangup(chan);
goto quit;
}
}

View File

@ -6242,18 +6242,29 @@ static void *pri_dchannel(void *vpri)
e->ringing.call);
sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCNR);
sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
sig_pri_lock_owner(pri, chanpos);
if (pri->pvts[chanpos]->owner) {
ast_setstate(pri->pvts[chanpos]->owner, AST_STATE_RINGING);
ast_channel_unlock(pri->pvts[chanpos]->owner);
}
pri_queue_control(pri, chanpos, AST_CONTROL_RINGING);
if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_ALERTING) {
pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_ALERTING;
}
if (
if (!pri->pvts[chanpos]->progress
&& !pri->pvts[chanpos]->no_b_channel
#ifdef PRI_PROGRESS_MASK
e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE
&& (e->ringing.progressmask
& (PRI_PROG_CALL_NOT_E2E_ISDN | PRI_PROG_INBAND_AVAILABLE))
#else
e->ringing.progress == 8
&& e->ringing.progress == 8
#endif
) {
/* Bring voice path up */
pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
pri->pvts[chanpos]->progress = 1;
sig_pri_set_dialing(pri->pvts[chanpos], 0);
sig_pri_open_media(pri->pvts[chanpos]);
}
@ -6305,7 +6316,8 @@ static void *pri_dchannel(void *vpri)
if (!pri->pvts[chanpos]->progress
&& !pri->pvts[chanpos]->no_b_channel
#ifdef PRI_PROGRESS_MASK
&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
&& (e->proceeding.progressmask
& (PRI_PROG_CALL_NOT_E2E_ISDN | PRI_PROG_INBAND_AVAILABLE))
#else
&& e->proceeding.progress == 8
#endif
@ -6347,7 +6359,8 @@ static void *pri_dchannel(void *vpri)
if (!pri->pvts[chanpos]->progress
&& !pri->pvts[chanpos]->no_b_channel
#ifdef PRI_PROGRESS_MASK
&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
&& (e->proceeding.progressmask
& (PRI_PROG_CALL_NOT_E2E_ISDN | PRI_PROG_INBAND_AVAILABLE))
#else
&& e->proceeding.progress == 8
#endif
@ -6355,9 +6368,9 @@ static void *pri_dchannel(void *vpri)
/* Bring voice path up */
pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
pri->pvts[chanpos]->progress = 1;
sig_pri_set_dialing(pri->pvts[chanpos], 0);
sig_pri_open_media(pri->pvts[chanpos]);
}
sig_pri_set_dialing(pri->pvts[chanpos], 0);
sig_pri_unlock_private(pri->pvts[chanpos]);
break;
case PRI_EVENT_FACILITY:
@ -7040,6 +7053,52 @@ static void *pri_dchannel(void *vpri)
return NULL;
}
/*!
* \brief Output AMI show spans response events for the given PRI span.
* \since 1.10
*
* \param show_cmd AMI command name
* \param s AMI session to output span information.
* \param pri PRI span control structure.
* \param dchannels Array of D channel channel numbers.
* \param action_id Action ID line to use.
*
* \return Number of D channels on this span.
*/
int sig_pri_ami_show_spans(struct mansession *s, const char *show_cmd, struct sig_pri_span *pri, const int *dchannels, const char *action_id)
{
int count;
int x;
count = 0;
for (x = 0; x < ARRAY_LEN(pri->dchans); ++x) {
if (pri->dchans[x]) {
++count;
astman_append(s,
"Event: %s\r\n"
"Span: %d\r\n"
"DChannel: %d\r\n"
"Order: %s\r\n"
"Active: %s\r\n"
"Alarm: %s\r\n"
"Up: %s\r\n"
"%s"
"\r\n",
show_cmd,
pri->span,
dchannels[x],
pri_order(x),
(pri->dchans[x] == pri->pri) ? "Yes" : "No",
(pri->dchanavail[x] & DCHAN_NOTINALARM) ? "No" : "Yes",
(pri->dchanavail[x] & DCHAN_UP) ? "Yes" : "No",
action_id
);
}
}
return count;
}
void sig_pri_init_pri(struct sig_pri_span *pri)
{
int i;
@ -7133,8 +7192,6 @@ int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
sig_pri_span_devstate_changed(p->pri);
pri_rel(p->pri);
ast->tech_pvt = NULL;
return 0;
}
@ -8145,18 +8202,20 @@ int sig_pri_digit_begin(struct sig_pri_chan *pvt, struct ast_channel *ast, char
* \since 1.8
*
* \param pri PRI span control structure.
* \param vm_number Voicemail controlling number (NULL if not present).
* \param mbox_number Mailbox number
* \param mbox_context Mailbox context
* \param num_messages Number of messages waiting.
*
* \return Nothing
*/
static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *mbox_number, const char *mbox_context, int num_messages)
static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *vm_number, const char *mbox_number, const char *mbox_context, int num_messages)
{
struct pri_party_id voicemail;
struct pri_party_id mailbox;
ast_debug(1, "Send MWI indication for %s@%s num_messages:%d\n", mbox_number,
mbox_context, num_messages);
ast_debug(1, "Send MWI indication for %s@%s vm_number:%s num_messages:%d\n",
mbox_number, mbox_context, S_OR(vm_number, "<not-present>"), num_messages);
memset(&mailbox, 0, sizeof(mailbox));
mailbox.number.valid = 1;
@ -8164,8 +8223,21 @@ static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *mb
mailbox.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_UNKNOWN;
ast_copy_string(mailbox.number.str, mbox_number, sizeof(mailbox.number.str));
memset(&voicemail, 0, sizeof(voicemail));
voicemail.number.valid = 1;
voicemail.number.presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
voicemail.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_UNKNOWN;
if (vm_number) {
ast_copy_string(voicemail.number.str, vm_number, sizeof(voicemail.number.str));
}
ast_mutex_lock(&pri->lock);
#if defined(HAVE_PRI_MWI_V2)
pri_mwi_indicate_v2(pri->pri, &mailbox, &voicemail, 1 /* speech */, num_messages,
NULL, NULL, -1, 0);
#else /* !defined(HAVE_PRI_MWI_V2) */
pri_mwi_indicate(pri->pri, &mailbox, 1 /* speech */, num_messages, NULL, NULL, -1, 0);
#endif /* !defined(HAVE_PRI_MWI_V2) */
ast_mutex_unlock(&pri->lock);
}
#endif /* defined(HAVE_PRI_MWI) */
@ -8187,6 +8259,7 @@ static void sig_pri_mwi_event_cb(const struct ast_event *event, void *userdata)
const char *mbox_context;
const char *mbox_number;
int num_messages;
int idx;
mbox_number = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
if (ast_strlen_zero(mbox_number)) {
@ -8197,7 +8270,20 @@ static void sig_pri_mwi_event_cb(const struct ast_event *event, void *userdata)
return;
}
num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
sig_pri_send_mwi_indication(pri, mbox_number, mbox_context, num_messages);
for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
if (!pri->mbox[idx].sub) {
/* Mailbox slot is empty */
continue;
}
if (!strcmp(pri->mbox[idx].number, mbox_number)
&& !strcmp(pri->mbox[idx].context, mbox_context)) {
/* Found the mailbox. */
sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number, mbox_number,
mbox_context, num_messages);
break;
}
}
}
#endif /* defined(HAVE_PRI_MWI) */
@ -8219,8 +8305,8 @@ static void sig_pri_mwi_cache_update(struct sig_pri_span *pri)
for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
if (!pri->mbox[idx].sub) {
/* There are no more mailboxes on this span. */
break;
/* Mailbox slot is empty */
continue;
}
event = ast_event_get_cached(AST_EVENT_MWI,
@ -8232,8 +8318,8 @@ static void sig_pri_mwi_cache_update(struct sig_pri_span *pri)
continue;
}
num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
sig_pri_send_mwi_indication(pri, pri->mbox[idx].number, pri->mbox[idx].context,
num_messages);
sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number, pri->mbox[idx].number,
pri->mbox[idx].context, num_messages);
ast_event_destroy(event);
}
}
@ -8318,8 +8404,7 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
int i;
#if defined(HAVE_PRI_MWI)
char *saveptr;
char *mbox_number;
char *mbox_context;
char *prev_vm_number;
struct ast_str *mwi_description = ast_str_alloca(64);
#endif /* defined(HAVE_PRI_MWI) */
@ -8336,15 +8421,41 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
sig_pri_sort_pri_chans(pri);
#if defined(HAVE_PRI_MWI)
/*
* Split the mwi_vm_numbers configuration string into the mbox[].vm_number:
* vm_number{,vm_number}
*/
prev_vm_number = NULL;
saveptr = pri->mwi_vm_numbers;
for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
char *vm_number;
vm_number = strsep(&saveptr, ",");
if (vm_number) {
vm_number = ast_strip(vm_number);
}
if (ast_strlen_zero(vm_number)) {
/* There was no number so reuse the previous number. */
vm_number = prev_vm_number;
} else {
/* We have a new number. */
prev_vm_number = vm_number;
}
pri->mbox[i].vm_number = vm_number;
}
/*
* Split the mwi_mailboxes configuration string into the mbox[]:
* mailbox_number[@context]{,mailbox_number[@context]}
*/
i = 0;
saveptr = pri->mwi_mailboxes;
while (i < ARRAY_LEN(pri->mbox)) {
for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
char *mbox_number;
char *mbox_context;
mbox_number = strsep(&saveptr, ",");
if (!mbox_number) {
/* No more defined mailboxes. */
break;
}
/* Split the mailbox_number and context */
@ -8364,6 +8475,8 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
}
/* Fill the mbox[] element. */
pri->mbox[i].number = mbox_number;
pri->mbox[i].context = mbox_context;
ast_str_set(&mwi_description, -1, "%s span %d[%d] MWI mailbox %s@%s",
sig_pri_cc_type_name, pri->span, i, mbox_number, mbox_context);
pri->mbox[i].sub = ast_event_subscribe(AST_EVENT_MWI, sig_pri_mwi_event_cb,
@ -8374,11 +8487,13 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
if (!pri->mbox[i].sub) {
ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s@%s.",
sig_pri_cc_type_name, pri->span, mbox_number, mbox_context);
continue;
}
pri->mbox[i].number = mbox_number;
pri->mbox[i].context = mbox_context;
++i;
#if defined(HAVE_PRI_MWI_V2)
if (ast_strlen_zero(pri->mbox[i].vm_number)) {
ast_log(LOG_WARNING, "%s span %d MWI voicemail number for %s@%s is empty.\n",
sig_pri_cc_type_name, pri->span, mbox_number, mbox_context);
}
#endif /* defined(HAVE_PRI_MWI_V2) */
}
#endif /* defined(HAVE_PRI_MWI) */
@ -8465,6 +8580,9 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
pri_display_options_send(pri->pri, pri->display_flags_send);
pri_display_options_receive(pri->pri, pri->display_flags_receive);
#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
#if defined(HAVE_PRI_DATETIME_SEND)
pri_date_time_send_option(pri->pri, pri->datetime_send);
#endif /* defined(HAVE_PRI_DATETIME_SEND) */
pri->resetpos = -1;
if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) {
@ -8610,18 +8728,10 @@ static void build_status(char *s, size_t len, int status, int active)
if (!s || len < 1) {
return;
}
s[0] = '\0';
if (!(status & DCHAN_NOTINALARM))
strncat(s, "In Alarm, ", len - strlen(s) - 1);
if (status & DCHAN_UP)
strncat(s, "Up", len - strlen(s) - 1);
else
strncat(s, "Down", len - strlen(s) - 1);
if (active)
strncat(s, ", Active", len - strlen(s) - 1);
else
strncat(s, ", Standby", len - strlen(s) - 1);
s[len - 1] = '\0';
snprintf(s, len, "%s%s, %s",
(status & DCHAN_NOTINALARM) ? "" : "In Alarm, ",
(status & DCHAN_UP) ? "Up" : "Down",
(active) ? "Active" : "Standby");
}
void sig_pri_cli_show_spans(int fd, int span, struct sig_pri_span *pri)

View File

@ -359,12 +359,22 @@ struct sig_pri_chan {
#if defined(HAVE_PRI_MWI)
/*! Maximum number of mailboxes per span. */
#define SIG_PRI_MAX_MWI_MAILBOXES 8
/*! Typical maximum length of mwi voicemail controlling number */
#define SIG_PRI_MAX_MWI_VM_NUMBER_LEN 10 /* digits in number */
/*! Typical maximum length of mwi mailbox number */
#define SIG_PRI_MAX_MWI_MBOX_NUMBER_LEN 10 /* digits in number */
/*! Typical maximum length of mwi mailbox context */
#define SIG_PRI_MAX_MWI_CONTEXT_LEN 10
/*!
* \brief Maximum mwi_mailbox string length.
* \brief Maximum mwi_vm_numbers string length.
* \details
* max_length = #mailboxes * (vm_number + ',')
* The last ',' is a null terminator instead.
*/
#define SIG_PRI_MAX_MWI_VM_NUMBER_STR (SIG_PRI_MAX_MWI_MAILBOXES \
* (SIG_PRI_MAX_MWI_VM_NUMBER_LEN + 1))
/*!
* \brief Maximum mwi_mailboxs string length.
* \details
* max_length = #mailboxes * (mbox_number + '@' + context + ',')
* The last ',' is a null terminator instead.
@ -382,6 +392,8 @@ struct sig_pri_mbox {
const char *number;
/*! \brief Mailbox context. */
const char *context;
/*! \brief Voicemail controlling number. */
const char *vm_number;
};
#endif /* defined(HAVE_PRI_MWI) */
@ -429,6 +441,10 @@ struct sig_pri_span {
/*! \brief TRUE if allow sending MCID request on this span. */
unsigned int mcid_send:1;
#endif /* defined(HAVE_PRI_MCID) */
#if defined(HAVE_PRI_DATETIME_SEND)
/*! \brief Configured date/time ie send policy option. */
int datetime_send;
#endif /* defined(HAVE_PRI_DATETIME_SEND) */
int dialplan; /*!< Dialing plan */
int localdialplan; /*!< Local dialing plan */
int cpndialplan; /*!< Connected party dialing plan */
@ -453,6 +469,12 @@ struct sig_pri_span {
* \note String is split apart when span is started.
*/
char mwi_mailboxes[SIG_PRI_MAX_MWI_MAILBOX_STR];
/*!
* \brief Comma separated list of voicemail access controlling numbers for MWI.
* \note Format: vm_number{,vm_number}
* \note String is split apart when span is started.
*/
char mwi_vm_numbers[SIG_PRI_MAX_MWI_VM_NUMBER_STR];
#endif /* defined(HAVE_PRI_MWI) */
/*!
* \brief Initial user tag for party id's sent from this device driver.
@ -597,6 +619,9 @@ void sig_pri_chan_delete(struct sig_pri_chan *doomed);
int pri_is_up(struct sig_pri_span *pri);
struct mansession;
int sig_pri_ami_show_spans(struct mansession *s, const char *show_cmd, struct sig_pri_span *pri, const int *dchannels, const char *action_id);
void sig_pri_cli_show_channels_header(int fd);
void sig_pri_cli_show_channels(int fd, struct sig_pri_span *pri);
void sig_pri_cli_show_spans(int fd, int span, struct sig_pri_span *pri);

View File

@ -697,6 +697,11 @@ void *ss7_linkset(void *data)
if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
}
sig_ss7_lock_owner(linkset, chanpos);
if (p->owner) {
ast_setstate(p->owner, AST_STATE_RINGING);
ast_channel_unlock(p->owner);
}
sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
break;
case CPG_EVENT_PROGRESS:
@ -948,6 +953,11 @@ void *ss7_linkset(void *data)
if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
}
sig_ss7_lock_owner(linkset, chanpos);
if (p->owner) {
ast_setstate(p->owner, AST_STATE_RINGING);
ast_channel_unlock(p->owner);
}
sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
}
sig_ss7_unlock_private(p);

View File

@ -59,6 +59,9 @@
#define DEFAULT_REGISTRATION_TIMEOUT 20
#define DEFAULT_MAX_FORWARDS 70
#define DEFAULT_AUTHLIMIT 100
#define DEFAULT_AUTHTIMEOUT 30
/* guard limit must be larger than guard secs */
/* guard min must be < 1000, and should be >= 250 */
#define EXPIRY_GUARD_SECS 15 /*!< How long before expiry do we reregister */
@ -208,7 +211,10 @@
#define DEFAULT_CALLEVENTS FALSE /*!< Extra manager SIP call events */
#define DEFAULT_ALWAYSAUTHREJECT TRUE /*!< Don't reject authentication requests always */
#define DEFAULT_AUTH_OPTIONS FALSE
#define DEFAULT_AUTH_MESSAGE TRUE
#define DEFAULT_ACCEPT_OUTOFCALL_MESSAGE TRUE
#define DEFAULT_REGEXTENONQUALIFY FALSE
#define DEFAULT_LEGACY_USEROPTION_PARSING FALSE
#define DEFAULT_T1MIN 100 /*!< 100 MS for minimal roundtrip time */
#define DEFAULT_MAX_CALL_BITRATE (384) /*!< Max bitrate for video */
#ifndef DEFAULT_USERAGENT
@ -591,7 +597,8 @@ enum t38state {
T38_DISABLED = 0, /*!< Not enabled */
T38_LOCAL_REINVITE, /*!< Offered from local - REINVITE */
T38_PEER_REINVITE, /*!< Offered from peer - REINVITE */
T38_ENABLED /*!< Negotiated (enabled) */
T38_ENABLED, /*!< Negotiated (enabled) */
T38_REJECTED /*!< Refused */
};
/*! \brief Parameters to know status of transfer */
@ -675,10 +682,13 @@ struct sip_settings {
int allowguest; /*!< allow unauthenticated peers to connect? */
int alwaysauthreject; /*!< Send 401 Unauthorized for all failing requests */
int auth_options_requests; /*!< Authenticate OPTIONS requests */
int auth_message_requests; /*!< Authenticate MESSAGE requests */
int accept_outofcall_message; /*!< Accept MESSAGE outside of a call */
int compactheaders; /*!< send compact sip headers */
int allow_external_domains; /*!< Accept calls to external SIP domains? */
int callevents; /*!< Whether we send manager events or not */
int regextenonqualify; /*!< Whether to add/remove regexten when qualifying peers */
int legacy_useroption_parsing; /*!< Whether to strip useroptions in URI via semicolons */
int matchexternaddrlocally; /*!< Match externaddr/externhost setting against localnet setting */
char regcontext[AST_MAX_CONTEXT]; /*!< Context for auto-extensions */
unsigned int disallowed_methods; /*!< methods that we should never try to use */
@ -743,6 +753,7 @@ struct sip_request {
char debug; /*!< print extra debugging if non zero */
char has_to_tag; /*!< non-zero if packet has To: tag */
char ignore; /*!< if non-zero This is a re-transmit, ignore it */
char authenticated; /*!< non-zero if this request was authenticated */
ptrdiff_t header[SIP_MAX_HEADERS]; /*!< Array of offsets into the request string of each SIP header*/
ptrdiff_t line[SIP_MAX_LINES]; /*!< Array of offsets into the request string of each SDP line*/
struct ast_str *data;
@ -959,6 +970,7 @@ struct sip_pvt {
AST_STRING_FIELD(parkinglot); /*!< Parkinglot */
AST_STRING_FIELD(engine); /*!< RTP engine to use */
AST_STRING_FIELD(dialstring); /*!< The dialstring used to call this SIP endpoint */
AST_STRING_FIELD(msg_body); /*!< Text for a MESSAGE body */
);
char via[128]; /*!< Via: header */
int maxforwards; /*!< SIP Loop prevention */
@ -1157,6 +1169,7 @@ struct sip_peer {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(secret); /*!< Password for inbound auth */
AST_STRING_FIELD(md5secret); /*!< Password in MD5 */
AST_STRING_FIELD(description); /*!< Description of this peer */
AST_STRING_FIELD(remotesecret); /*!< Remote secret (trunks, remote devices) */
AST_STRING_FIELD(context); /*!< Default context for incoming calls */
AST_STRING_FIELD(subscribecontext); /*!< Default context for subscriptions */

View File

@ -42,6 +42,27 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
char *c = NULL;
int error = 0;
/*
* Initialize requested strings - some functions don't care if parse_uri fails
* and will attempt to use string pointers passed into parse_uri even after a
* parse_uri failure
*/
if (user) {
*user = "";
}
if (pass) {
*pass = "";
}
if (domain) {
*domain = "";
}
if (headers) {
*headers = "";
}
if (residue) {
*residue = "";
}
/* check for valid input */
if (ast_strlen_zero(uri)) {
return -1;
@ -2253,10 +2274,7 @@ void free_via(struct sip_via *v)
return;
}
if (v->via) {
ast_free(v->via);
}
ast_free(v->via);
ast_free(v);
}
@ -2305,8 +2323,9 @@ struct sip_via *parse_via(const char *header)
}
v->sent_by = ast_skip_blanks(v->sent_by);
/* store the port */
if ((parm = strchr(v->sent_by, ':'))) {
/* store the port, we have to handle ipv6 addresses containing ':'
* characters gracefully */
if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (parm = strchr(v->sent_by, ':'))) {
char *endptr;
v->port = strtol(++parm, &endptr, 10);
@ -2392,6 +2411,13 @@ AST_TEST_DEFINE(parse_via_test)
.expected_maddr = "224.0.0.1",
.expected_ttl = 1,
};
struct testdata t7 = {
.in = "SIP/2.0/UDP [::1]:5060",
.expected_protocol = "SIP/2.0/UDP",
.expected_sent_by = "[::1]:5060",
.expected_port = 5060,
.expected_branch = "",
};
switch (cmd) {
case TEST_INIT:
info->name = "parse_via_test";
@ -2411,6 +2437,7 @@ AST_TEST_DEFINE(parse_via_test)
AST_LIST_INSERT_TAIL(&testdatalist, &t4, list);
AST_LIST_INSERT_TAIL(&testdatalist, &t5, list);
AST_LIST_INSERT_TAIL(&testdatalist, &t6, list);
AST_LIST_INSERT_TAIL(&testdatalist, &t7, list);
AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {

View File

@ -191,7 +191,6 @@ err:
int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp)
{
char *str = NULL;
char *name = NULL;
char *tag = NULL;
char *suite = NULL;
char *key_params = NULL;
@ -211,7 +210,7 @@ int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_in
str = ast_strdupa(attr);
name = strsep(&str, ":");
strsep(&str, ":");
tag = strsep(&str, " ");
suite = strsep(&str, " ");
key_params = strsep(&str, " ");

View File

@ -56,6 +56,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define G723_SAMPLES 240
#define G729_SAMPLES 160
#ifndef DAHDI_FORMAT_MAX_AUDIO
#define DAHDI_FORMAT_G723_1 (1 << 0)
#define DAHDI_FORMAT_GSM (1 << 1)
#define DAHDI_FORMAT_ULAW (1 << 2)
#define DAHDI_FORMAT_ALAW (1 << 3)
#define DAHDI_FORMAT_G726 (1 << 4)
#define DAHDI_FORMAT_ADPCM (1 << 5)
#define DAHDI_FORMAT_SLINEAR (1 << 6)
#define DAHDI_FORMAT_LPC10 (1 << 7)
#define DAHDI_FORMAT_G729A (1 << 8)
#define DAHDI_FORMAT_SPEEX (1 << 9)
#define DAHDI_FORMAT_ILBC (1 << 10)
#endif
static struct channel_usage {
int total;
int encoders;
@ -598,13 +612,13 @@ static int find_transcoders(void)
* module. Also, do not allow direct ulaw/alaw to complex
* codec translation, since that will prevent the generic PLC
* functions from working. */
if (info.dstfmts & (AST_FORMAT_ULAW | AST_FORMAT_ALAW)) {
info.dstfmts |= AST_FORMAT_SLINEAR;
info.dstfmts &= ~(AST_FORMAT_ULAW | AST_FORMAT_ALAW);
if (info.dstfmts & (DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW)) {
info.dstfmts |= DAHDI_FORMAT_SLINEAR;
info.dstfmts &= ~(DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW);
}
if (info.srcfmts & (AST_FORMAT_ULAW | AST_FORMAT_ALAW)) {
info.srcfmts |= AST_FORMAT_SLINEAR;
info.srcfmts &= ~(AST_FORMAT_ULAW | AST_FORMAT_ALAW);
if (info.srcfmts & (DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW)) {
info.srcfmts |= DAHDI_FORMAT_SLINEAR;
info.srcfmts &= ~(DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW);
}
build_translators(&map, info.dstfmts, info.srcfmts);

View File

@ -71,7 +71,12 @@ static int resamp_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
{
SpeexResamplerState *resamp_pvt = pvt->pvt;
unsigned int out_samples = (OUTBUF_SIZE / sizeof(int16_t)) - pvt->samples;
unsigned int in_samples = f->samples;
unsigned int in_samples;
if (!f->datalen) {
return -1;
}
in_samples = f->datalen / 2;
speex_resampler_process_int(resamp_pvt,
0,

View File

@ -143,7 +143,7 @@ extern struct {
/* Local variables */
integer pbar;
real sbar;
integer path[2], iptr, i__, j;
integer iptr, i__, j;
real alpha, minsc, maxsc;
/* Arguments */
@ -389,7 +389,6 @@ n*/
for (i__ = 1; i__ <= 2; ++i__) {
j = j % 2 + 1;
*pitch = p[*pitch + j * 60 - 61];
path[i__ - 1] = *pitch;
}
/* The following statement subtracts one from IPOINT, mod DEPTH. I

View File

@ -6,12 +6,54 @@
;
[general]
; There is only a single option that may be defined in this file.
; The cc_max_requests option is a global limit on the number of
; CC requests that may be in the Asterisk system at any time.
;
;cc_max_requests = 20
;
; The cc_STATE_devstate variables listed below can be used to change the
; default mapping of the internal state machine tracking the state of
; call completion to an Asterisk Device State value. The acceptable values
; that can be provided are as follows, with a description of what the
; equivalent device BLF that this maps to:
;
; UNKNOWN ; Device is valid but channel didn't know state
; NOT_INUSE ; Device is not used
; INUSE ; Device is in use
; BUSY ; Device is busy
; INVALID ; Device is invalid
; UNAVAILABLE ; Device is unavailable
; RINGING ; Device is ringing
; RINGINUSE ; Device is ringing *and* in use
; ONHOLD ; Device is on hold
;
; These states are used to generate DEVICE_STATE information that can be
; included with Asterisk hints for phones to subscribe to the state information
; or dialplan to check the state using the EXTENSION_STATE() function or
; the DEVICE_STATE() function.
;
; The states are in the format of: "ccss:TECH/ID" so an example of device
; SIP/3000 making a CallCompletionRequest() could be checked by looking at
; DEVICE_STATE(ccss:SIP/3000) or an Asterisk Hint could be generated such as
;
; [hint-context]
; exten => *843000,hint,ccss:SIP/3000
;
; and then accessed with EXTENSION_STATE(*843000@hint-context)
; or subscribed to with a BLF button on a phone.
;
; The available state mapping and default values are:
;
; cc_available_devstate = NOT_INUSE
; cc_offered_devstate = NOT_INUSE
; cc_caller_requested_devstate = NOT_INUSE
; cc_active_devstate = INUSE
; cc_callee_ready_devstate = INUSE
; cc_caller_busy_devstate = ONHOLD
; cc_recalling_devstate = RINGING
; cc_complete_devstate = NOT_INUSE
; cc_failed_devstate = NOT_INUSE
;
;============================================
; PLEASE READ THIS!!!

View File

@ -4,7 +4,7 @@
; Channel Event Logging is a mechanism to provide fine-grained event information
; that can be used to generate billing information. Such event information can
; be recorded to databases and files via pluggable backend modules.
; be recorded to various backend modules.
;
[general]

View File

@ -51,7 +51,7 @@
; amaflag (an int)
; userfield
; peer
; extra
[global]
;hostname=localhost

View File

@ -236,6 +236,19 @@
;
;mcid_send=yes
; Send ISDN date/time IE in CONNECT message option. Only valid on NT spans.
;
; no: Do not send date/time IE in CONNECT message.
; date: Send date only.
; date_hh Send date and hour.
; date_hhmm Send date, hour, and minute.
; date_hhmmss Send date, hour, minute, and second.
;
; Default is an empty string which lets libpri pick the default
; date/time IE send policy.
;
;datetime_send=
; Allow inband audio (progress) when a call is DISCONNECTed by the far end of a PRI
;
;inbanddisconnect=yes
@ -581,13 +594,28 @@ callwaiting=yes
; Allow incoming ISDN call waiting calls.
; A call waiting call is a SETUP message with no B channel selected.
;allow_call_waiting_calls=no
;
; Configure the ISDN span to indicate MWI for the list of mailboxes.
; You can give a comma separated list of up to 8 mailboxes per span.
; An empty list disables MWI.
; The default is an empty list.
;mwi_mailboxes=mailbox_number[@context]{,mailbox_number[@context]}
;
; Configure the ISDN span voicemail numbers for MWI mailboxes. What number
; to call for a user to retrieve voicemail messages.
;
; You can give a comma separated list of numbers. The position of the number
; corresponds to the position in mwi_mailboxes. If a position is empty then
; the last number is reused.
;
; For example:
; mwi_vm_numbers=700,,800,,900
; is equivalent to:
; mwi_vm_numbers=700,700,800,800,900
;
; The default is no number.
;mwi_vm_numbers=
; Whether or not restrict outgoing caller ID (will be sent as ANI only, not
; available for the user)
; Mostly use with FXS ports
@ -820,6 +848,11 @@ pickupgroup=1
;
;useincomingcalleridondahditransfer = yes
;
; Add a description for the channel which can be shown through the Asterisk
; console when executing the 'dahdi show channels' command is run.
;
;description=Phone located in lobby
;
; AMA flags affects the recording of Call Detail Records. If specified
; it may be 'default', 'omit', 'billing', or 'documentation'.
;
@ -1068,10 +1101,13 @@ pickupgroup=1
;
;
;callerid="Green Phone"<(256) 428-6121>
;description=Reception Phone ; add a description for 'dahdi show channels'
;channel => 1
;callerid="Black Phone"<(256) 428-6122>
;description=Courtesy Phone
;channel => 2
;callerid="CallerID Phone" <(630) 372-1564>
;description= ; reset the description for following channels
;channel => 3
;callerid="Pac Tel Phone" <(256) 428-6124>
;channel => 4

View File

@ -0,0 +1,302 @@
[general]
; The general section of this config
; is not currently used, but reserved
; for future use.
;
; --- Default Information ---
; The default_user and default_bridge sections are applied
; automatically to all ConfBridge instances invoked without
; a user, or bridge argument. No menu is applied by default.
;
; --- ConfBridge User Profile Options ---
[default_user]
type=user
;admin=yes ; Sets if the user is an admin or not. Off by default.
;marked=yes ; Sets if this is a marked user or not. Off by default.
;startmuted=yes; Sets if all users should start out muted. Off by default
;music_on_hold_when_empty=yes ; Sets whether MOH should be played when only
; one person is in the conference or when the
; the user is waiting on a marked user to enter
; the conference. Off by default.
;music_on_hold_class=default ; The MOH class to use for this user.
;quiet=yes ; When enabled enter/leave prompts and user intros are not played.
; There are some prompts, such as the prompt to enter a PIN number,
; that must be played regardless of what this option is set to.
; Off by default
;announce_user_count=yes ; Sets if the number of users should be announced to the
; caller. Off by default.
;announce_user_count_all=yes ; Sets if the number of users should be announced to
; all the other users in the conference when someone joins.
; This option can be either set to 'yes' or a number.
; When set to a number, the announcement will only occur
; once the user count is above the specified number.
;announce_only_user=yes ; Sets if the only user announcement should be played
; when a channel enters a empty conference. On by default.
;wait_marked=yes ; Sets if the user must wait for a marked user to enter before
; joining the conference. Off by default.
;end_marked=yes ; This option will kick every user with this option set in their
; user profile after the last Marked user exists the conference.
;dsp_drop_silence=yes ; This option drops what Asterisk detects as silence from
; entering into the bridge. Enabling this option will drastically
; improve performance and help remove the buildup of background
; noise from the conference. Highly recommended for large conferences
; due to its performance enhancements.
;dsp_talking_threshold=128 ; The time in milliseconds of sound above what the dsp has
; established as base line silence for a user before a user
; is considered to be talking. This value affects several
; operations and should not be changed unless the impact on
; call quality is fully understood.
;
; What this value affects internally:
;
; 1. Audio is only mixed out of a user's incoming audio stream
; if talking is detected. If this value is set too
; loose the user will hear themselves briefly each
; time they begin talking until the dsp has time to
; establish that they are in fact talking.
; 2. When talk detection AMI events are enabled, this value
; determines when talking has begun which results in
; an AMI event to fire. If this value is set too tight
; AMI events may be falsely triggered by variants in
; room noise.
; 3. The drop_silence option depends on this value to determine
; when the user's audio should be mixed into the bridge
; after periods of silence. If this value is too loose
; the beginning of a user's speech will get cut off as they
; transition from silence to talking.
;
; By default this value is 160 ms. Valid values are 1 through 2^31
;dsp_silence_threshold=2000 ; The time in milliseconds of sound falling within the what
; the dsp has established as baseline silence before a user
; is considered be silent. This value affects several
; operations and should not be changed unless the impact
; on call quality is fully understood.
;
; What this value affects internally:
;
; 1. When talk detection AMI events are enabled, this value
; determines when the user has stopped talking after a
; period of talking. If this value is set too low
; AMI events indicating the user has stopped talking
; may get falsely sent out when the user briefly pauses
; during mid sentence.
; 2. The drop_silence option depends on this value to
; determine when the user's audio should begin to be
; dropped from the conference bridge after the user
; stops talking. If this value is set too low the user's
; audio stream may sound choppy to the other participants.
; This is caused by the user transitioning constantly from
; silence to talking during mid sentence.
;
; The best way to approach this option is to set it slightly above
; the maximum amount of ms of silence a user may generate during
; natural speech.
;
; By default this value is 2500ms. Valid values are 1 through 2^31
;talk_detection_events=yes ; This option sets whether or not notifications of when a user
; begins and ends talking should be sent out as events over AMI.
; By default this option is off.
;denoise=yes ; Sets whether or not a denoise filter should be applied
; to the audio before mixing or not. Off by default. Requires
; codec_speex to be built and installed. Do not confuse this option
; with drop_silence. Denoise is useful if there is a lot of background
; noise for a user as it attempts to remove the noise while preserving
; the speech. This option does NOT remove silence from being mixed into
; the conference and does come at the cost of a slight performance hit.
;jitterbuffer=yes ; Enabling this option places a jitterbuffer on the user's audio stream
; before audio mixing is performed. This is highly recommended but will
; add a slight delay to the audio. This option is using the JITTERBUFFER
; dialplan function's default adaptive jitterbuffer. For a more fine tuned
; jitterbuffer, disable this option and use the JITTERBUFFER dialplan function
; on the user before entering the ConfBridge application.
;pin=1234 ; Sets if this user must enter a PIN number before entering
; the conference. The PIN will be prompted for.
;announce_join_leave=yes ; When enabled, this option will prompt the user for a
; name when entering the conference. After the name is
; recorded, it will be played as the user enters and exists
; the conference. This option is off by default.
;dtmf_passthrough=yes ; Sets whether or not DTMF should pass through the conference.
; This option is off by default.
; --- ConfBridge Bridge Profile Options ---
[default_bridge]
type=bridge
;max_members=50 ; This option limits the number of participants for a single
; conference to a specific number. By default conferences
; have no participant limit. After the limit is reached, the
; conference will be locked until someone leaves. Note however
; that an Admin user will always be alowed to join the conference
; regardless if this limit is reached or not.
;record_conference=yes ; Records the conference call starting when the first user
; enters the room, and ending when the last user exits the room.
; The default recorded filename is
; 'confbridge-<name of conference bridge>-<start time>.wav
; and the default format is 8khz slinear. This file will be
; located in the configured monitoring directory in asterisk.conf.
;record_file=</path/to/file> ; When record_conference is set to yes, the specific name of the
; record file can be set using this option. Note that since multiple
; conferences may use the same bridge profile, this may cause issues
; depending on the configuration. It is recommended to only use this
; option dynamically with the CONFBRIDGE() dialplan function. This
; allows the record name to be specified and a unique name to be chosen.
; By default, the record_file is stored in Asterisk's spool/monitor directory
; with a unique filename starting with the 'confbridge' prefix.
;internal_sample_rate=auto ; Sets the internal native sample rate the
; conference is mixed at. This is set to automatically
; adjust the sample rate to the best quality by default.
; Other values can be anything from 8000-192000. If a
; sample rate is set that Asterisk does not support, the
; closest sample rate Asterisk does support to the one requested
; will be used.
;mixing_interval=40 ; Sets the internal mixing interval in milliseconds for the bridge. This
; number reflects how tight or loose the mixing will be for the conference.
; In order to improve performance a larger mixing interval such as 40ms may
; be chosen. Using a larger mixing interval comes at the cost of introducing
; larger amounts of delay into the bridge. Valid values here are 10, 20, 40,
; or 80. By default 20ms is used.
; All sounds in the conference are customizable using the bridge profile options below.
; Simply state the option followed by the filename or full path of the filename after
; the option. Example: sound_had_joined=conf-hasjoin This will play the conf-hasjoin
; sound file found in the sounds directory when announcing someone's name is joining the
; conference.
;sound_join ; The sound played to everyone when someone enters the conference.
;sound_leave ; The sound played to everyone when someone leaves the conference.
;sound_has_joined ; The sound played before announcing someone's name has
; joined the conference. This is used for user intros.
; Example "_____ has joined the conference"
;sound_has_left ; The sound played when announcing someone's name has
; left the conference. This is used for user intros.
; Example "_____ has left the conference"
;sound_kicked ; The sound played to a user who has been kicked from the conference.
;sound_muted ; The sound played when the mute option it toggled on.
;sound_unmuted ; The sound played when the mute option it toggled off.
;sound_only_person ; The sound played when the user is the only person in the conference.
;sound_only_one ; The sound played to a user when there is only one other
; person is in the conference.
;sound_there_are ; The sound played when announcing how many users there
; are in a conference.
;sound_other_in_party; ; This file is used in conjunction with 'sound_there_are"
; when announcing how many users there are in the conference.
; The sounds are stringed together like this.
; "sound_there_are" <number of participants> "sound_other_in_party"
;sound_place_into_conference ; The sound played when someone is placed into the conference
; after waiting for a marked user.
;sound_wait_for_leader ; The sound played when a user is placed into a conference that
; can not start until a marked user enters.
;sound_leader_has_left ; The sound played when the last marked user leaves the conference.
;sound_get_pin ; The sound played when prompting for a conference pin number.
;sound_invalid_pin ; The sound played when an invalid pin is entered too many times.
;sound_locked ; The sound played to a user trying to join a locked conference.
;sound_locked_now ; The sound played to an admin after toggling the conference to locked mode.
;sound_unlocked_now; The sound played to an admin after toggling the conference to unlocked mode.
;sound_error_menu ; The sound played when an invalid menu option is entered.
; --- ConfBridge Menu Options ---
; The ConfBridge application also has the ability to
; apply custom DTMF menus to each channel using the
; application. Like the User and Bridge profiles
; a menu is passed in to ConfBridge as an argument in
; the dialplan.
;
; Below is a list of menu actions that can be assigned
; to a DTMF sequence.
;
; A single DTMF sequence can have multiple actions associated with it. This is
; accomplished by stringing the actions together and using a ',' as the delimiter.
; Example: Both listening and talking volume is reset when '5' is pressed.
; 5=reset_talking_volume, reset_listening_volume
;
; playback(<name of audio file>&<name of audio file>)
; Playback will play back an audio file to a channel
; and then immediately return to the conference.
; This file can not be interupted by DTMF.
; Mutliple files can be chained together using the
; '&' character.
; playback_and_continue(<name of playback prompt>&<name of playback prompt>)
; playback_and_continue will
; play back a prompt while continuing to
; collect the dtmf sequence. This is useful
; when using a menu prompt that describes all
; the menu options. Note however that any DTMF
; during this action will terminate the prompts
; playback. Prompt files can be chained together
; using the '&' character as a delimiter.
; toggle_mute ; Toggle turning on and off mute. Mute will make the user silent
; to everyone else, but the user will still be able to listen in.
; continue to collect the dtmf sequence.
; no_op ; This action does nothing (No Operation). Its only real purpose exists for
; being able to reserve a sequence in the config as a menu exit sequence.
; decrease_listening_volume ; Decreases the channel's listening volume.
; increase_listening_volume ; Increases the channel's listening volume.
; reset_listening_volume ; Reset channel's listening volume to default level.
; decrease_talking_volume ; Decreases the channel's talking volume.
; increase_talking_volume ; Icreases the channel's talking volume.
; reset_talking_volume ; Reset channel's talking volume to default level.
;
; dialplan_exec(context,exten,priority) ; The dialplan_exec action allows a user
; to escape from the conference and execute
; commands in the dialplan. Once the dialplan
; exits the user will be put back into the
; conference. The possibilities are endless!
; leave_conference ; This action allows a user to exit the conference and continue
; execution in the dialplan.
;
; admin_kick_last ; This action allows an Admin to kick the last participant from the
; conference. This action will only work for admins which allows
; a single menu to be used for both users and admins.
;
; admin_toggle_conference_lock ; This action allows an Admin to toggle locking and
; unlocking the conference. Non admins can not use
; this action even if it is in their menu.
[sample_user_menu]
type=menu
*=playback_and_continue(conf-usermenu)
*1=toggle_mute
1=toggle_mute
*4=decrease_listening_volume
4=decrease_listening_volume
*6=increase_listening_volume
6=increase_listening_volume
*7=decrease_talking_volume
7=decrease_talking_volume
*8=no_op
8=no_op
*9=increase_talking_volume
9=increase_talking_volume
[sample_admin_menu]
type=menu
*=playback_and_continue(conf-adminmenu)
*1=toggle_mute
1=toggle_mute
*2=admin_toggle_conference_lock ; only applied to admin users
2=admin_toggle_conference_lock ; only applied to admin users
*3=admin_kick_last ; only applied to admin users
3=admin_kick_last ; only applied to admin users
*4=decrease_listening_volume
4=decrease_listening_volume
*6=increase_listening_volume
6=increase_listening_volume
*7=decrease_talking_volume
7=decrease_talking_volume
*8=no_op
8=no_op
*9=increase_talking_volume
9=increase_talking_volume

View File

@ -88,12 +88,14 @@ TRUNKMSD = 1
--
-- More examples can be found below.
--
-- Before starting long running operations, an autoservice should be started
-- using the autoservice_start() function. This autoservice will automatically
-- be stopped before executing applications and dialplan functions and will be
-- restarted afterwards. The autoservice can be stopped using
-- autoservice_stop() and the autoservice_status() function will return true if
-- an autoservice is currently running.
-- An autoservice is automatically run while lua code is executing. The
-- autoservice can be stopped and restarted using the autoservice_stop() and
-- autoservice_start() functions. The autservice should be running before
-- starting long running operations. The autoservice will automatically be
-- stopped before executing applications and dialplan functions and will be
-- restarted afterwards. The autoservice_status() function can be used to
-- check the current status of the autoservice and will return true if an
-- autoservice is currently running.
--
function outgoing_local(c, e)

View File

@ -83,6 +83,9 @@ context => parkedcalls ; Which context parked calls are in (default parking lot
; You can set parkinglot with the CHANNEL dialplan function
; or by setting 'parkinglot' directly in the channel configuration file.
;
; (Note: Leading '0's and any non-numerical characters on parkpos extensions
; will be ignored. Parkext on the other hand can be any string.)
;
;[parkinglot_edvina]
;context => edvinapark
;parkext => 799

View File

@ -34,6 +34,11 @@ bindaddr=127.0.0.1
;
;prefix=asterisk
;
; sessionlimit specifies the maximum number of httpsessions that will be
; allowed to exist at any given time. (default: 100)
;
;sessionlimit=100
;
; Whether Asterisk should serve static content from http-static
; Default is no.
;

View File

@ -504,6 +504,7 @@ type=peer
username=asterisk
secret=supersecret
host=216.207.245.47
description=Demo System At Digium ; Description of this peer, as listed by 'iax2 show peers'
;sendani=no
;host=asterisk.linux-support.net
;port=5036
@ -544,6 +545,7 @@ host=216.207.245.47
;[biggateway]
;type=peer
;host=192.168.0.1
;description=Gateway to PSTN
;context=*
;secret=myscret
;trunk=yes ; Use IAX2 trunking with this host

View File

@ -34,3 +34,6 @@
; Messages stored longer than this value will be deleted by Asterisk.
; This option applies to incoming messages only, which are intended to
; be processed by the JABBER_RECEIVE dialplan function.
;sendtodialplan=yes ; Send incoming messages into the dialplan. Off by default.
;context=messages ; Dialplan context to send incoming messages to. If not set,
; "default" will be used.

View File

@ -318,6 +318,8 @@ monitor-type = MixMonitor
;queue-callswaiting = queue-callswaiting
; ("The current est. holdtime is")
;queue-holdtime = queue-holdtime
; ("minute.")
;queue-minute = queue-minute
; ("minutes.")
;queue-minutes = queue-minutes
; ("seconds.")

View File

@ -202,6 +202,16 @@ tcpbindaddr=0.0.0.0 ; IP address for TCP server to bind to (0.0.0.0
; For details how to construct a certificate for SIP see
; http://tools.ietf.org/html/draft-ietf-sip-domain-certs
;tcpauthtimeout = 30 ; tcpauthtimeout specifies the maximum number
; of seconds a client has to authenticate. If
; the client does not authenticate beofre this
; timeout expires, the client will be
; disconnected. (default: 30 seconds)
;tcpauthlimit = 100 ; tcpauthlimit specifies the maximum number of
; unauthenticated sessions that will be allowed
; to connect at any given time. (default: 100)
srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; Note: Asterisk only uses the first host
; in SRV records
@ -375,6 +385,16 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;auth_options_requests = yes ; Enabling this option will authenticate OPTIONS requests just like
; INVITE requests are. By default this option is disabled.
;accept_outofcall_message = no ; Disable this option to reject all MESSAGE requests outside of a
; call. By default, this option is enabled. When enabled, MESSAGE
; requests are passed in to the dialplan.
;auth_message_requests = yes ; Enabling this option will authenticate MESSAGE requests.
; By default this option is enabled. However, it can be disabled
; should an application desire to not load the Asterisk server with
; doing authentication and implement end to end security in the
; message body.
;g726nonstandard = yes ; If the peer negotiates G726-32 audio, use AAL2 packing
; order instead of RFC3551 packing order (this is required
; for Sipura and Grandstream ATAs, among others). This is
@ -422,6 +442,14 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; If you have qualify on and the peer becomes unreachable
; this setting will enforce inactivation of the regexten
; extension for the peer
;legacy_useroption_parsing=yes ; Default "no" ; If you have this option enabled and there are semicolons
; in the user field of a sip URI, the field be truncated
; at the first semicolon seen. This effectively makes
; semicolon a non-usable character for peer names, extensions,
; and maybe other, less tested things. This can be useful
; for improving compatability with devices that like to use
; user options for whatever reason. The behavior is similar to
; how SIP URI's were typically handled in 1.6.2, hence the name.
; The shrinkcallerid function removes '(', ' ', ')', non-trailing '.', and '-' not
; in square brackets. For example, the caller id value 555.5555 becomes 5555555
@ -1100,6 +1128,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; use_q850_reason
; maxforwards
; encryption
; description ; Used to provide a description of the peer in console output
;[sip_proxy]
; For incoming calls only. Example: FWD (Free World Dialup)
@ -1195,6 +1224,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;context=from-sip ; Where to start in the dialplan when this phone calls
;callerid=John Doe <1234> ; Full caller ID, to override the phones config
; on incoming calls to Asterisk
;description=Courtesy Phone ; Description of the peer. Shown when doing 'sip show peers'.
;host=192.168.0.23 ; we have a static but private IP address
; No registration allowed
;nat=no ; there is not NAT between phone and Asterisk

View File

@ -44,7 +44,7 @@ Event=>report
Event=>check-sync\;reboot=false
[snom-reboot]
Event=>reboot
Event=>check-sync\;reboot=true
; Cisco

View File

@ -9,6 +9,15 @@ dateformat=M-D-Y ; M,D,Y in any order (6 chars max)
; Use M for month, D for day, Y for year, A for 12-hour time.
keepalive=120
;authtimeout = 30 ; authtimeout specifies the maximum number of seconds a
; client has to authenticate. If the client does not
; authenticate beofre this timeout expires, the client
; will be disconnected. (default: 30 seconds)
;authlimit = 50 ; authlimit specifies the maximum number of
; unauthenticated sessions that will be allowed to
; connect at any given time. (default: 50)
;vmexten=8500 ; Systemwide voicemailmain pilot number
; It must be in the same context as the calling
; device/line

View File

@ -87,6 +87,8 @@ pickupgroup = 1
;[6000]
;fullname = Joe User
;description = Courtesy Phone In Lobby ; Used to provide a description of the
; peer in console output
;email = joe@foo.bar
;secret = 1234
;dahdichan = 1

1312
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -415,6 +415,8 @@ AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
AST_EXT_LIB_SETUP([POPT], [popt], [popt])
AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio])
AST_EXT_LIB_SETUP([PRI], [ISDN PRI], [pri])
AST_EXT_LIB_SETUP_DEPENDENT([PRI_DATETIME_SEND], [ISDN PRI Date/time ie send policy], [PRI], [pri])
AST_EXT_LIB_SETUP_DEPENDENT([PRI_MWI_V2], [ISDN PRI Message Waiting Indication (Fixed)], [PRI], [pri])
AST_EXT_LIB_SETUP_DEPENDENT([PRI_DISPLAY_TEXT], [ISDN PRI user display text IE contents during call], [PRI], [pri])
AST_EXT_LIB_SETUP_DEPENDENT([PRI_MWI], [ISDN PRI Message Waiting Indication], [PRI], [pri])
AST_EXT_LIB_SETUP_DEPENDENT([PRI_MCID], [ISDN PRI Malicious Call ID], [PRI], [pri])
@ -1141,6 +1143,8 @@ if test "${USE_GSM}" != "no"; then
fi
AST_EXT_LIB_CHECK([ICONV], [iconv], [iconv_open], [iconv.h])
# GNU libiconv #define's iconv_open to libiconv_open, so we need to search for that symbol
AST_EXT_LIB_CHECK([ICONV], [iconv], [libiconv_open], [iconv.h])
# Some versions of Linux package iconv in glibc
AST_EXT_LIB_CHECK([ICONV], [c], [iconv_close], [iconv.h])
@ -1823,6 +1827,8 @@ AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h])
AST_EXT_LIB_CHECK([PORTAUDIO], [portaudio], [Pa_GetDeviceCount], [portaudio.h])
AST_EXT_LIB_CHECK([PRI], [pri], [pri_connected_line_update], [libpri.h])
AST_EXT_LIB_CHECK([PRI_DATETIME_SEND], [pri], [pri_date_time_send_option], [libpri.h])
AST_EXT_LIB_CHECK([PRI_MWI_V2], [pri], [pri_mwi_indicate_v2], [libpri.h])
AST_EXT_LIB_CHECK([PRI_DISPLAY_TEXT], [pri], [pri_display_text], [libpri.h])
AST_EXT_LIB_CHECK([PRI_MWI], [pri], [pri_mwi_indicate], [libpri.h])
AST_EXT_LIB_CHECK([PRI_MCID], [pri], [pri_mcid_enable], [libpri.h])
@ -1971,7 +1977,7 @@ AST_EXT_LIB_CHECK([CRYPTO], [crypto], [AES_encrypt], [openssl/aes.h])
if test "$PBX_CRYPTO" = "1";
then
AST_EXT_LIB_CHECK([OPENSSL], [ssl], [ssl2_connect], [openssl/ssl.h], [-lcrypto])
AST_EXT_LIB_CHECK([OPENSSL], [ssl], [SSL_connect], [openssl/ssl.h], [-lcrypto])
fi
if test "$PBX_OPENSSL" = "1";
@ -2017,20 +2023,19 @@ then
fi
AST_EXT_TOOL_CHECK([GMIME], [gmime-config], [], [], [#include <gmime/gmime.h>], [gboolean q = g_mime_check_version(0,0,0);])
if test "x${PBX_GMIME}" = "x0"; then
if test "x${PBX_GMIME}" = "x0" -a "${PKGCONFIG}" != "No"; then
# Later versions of GMime use pkg-config
if test "x${PKGCONFIG}" = xNo; then :; else
GMIME_INCLUDE=$(${PKGCONFIG} gmime-2.0 --cflags 2>/dev/null)
GMIME_LIB=$(${PKGCONFIG} gmime-2.0 --libs)
if test "x${GMIME_INCLUDE}${GMIME_LIB}" = "x"; then
GMIME_INCLUDE=$(${PKGCONFIG} gmime-2.2 --cflags 2>/dev/null)
GMIME_LIB=$(${PKGCONFIG} gmime-2.2 --libs)
for ver in 2.0 2.2 2.4; do
if ! ${PKGCONFIG} --exists gmime-$ver; then
continue
fi
if test "x${GMIME_INCLUDE}${GMIME_LIB}" != "x"; then
PBX_GMIME=1
AC_DEFINE([HAVE_GMIME], 1, [Define if your system has the GMIME libraries.])
fi
fi
# If we got here, we have this version:
GMIME_INCLUDE=$(${PKGCONFIG} gmime-$ver --cflags 2>/dev/null)
GMIME_LIB=$(${PKGCONFIG} gmime-$ver --libs)
PBX_GMIME=1
AC_DEFINE([HAVE_GMIME], 1, [Define if your system has the GMIME libraries.])
break;
done
fi
AST_EXT_LIB_CHECK([HOARD], [hoard], [malloc], [])
@ -2172,7 +2177,7 @@ fi
AC_SUBST(PBX_LAUNCHD)
PBX_GTK2=0
if test ! "x${PKGCONFIG}" = xNo; then
if test "${PKGCONFIG}" != "No"; then
GTK2_INCLUDE=$(${PKGCONFIG} gtk+-2.0 --cflags 2>/dev/null)
GTK2_LIB=$(${PKGCONFIG} gtk+-2.0 --libs)
PBX_GTK2=1

View File

@ -132,9 +132,12 @@ case "$1" in
$0 start
# "restart|force-reload" starts Asterisk and returns 0 even if Asterisk was stopped (as LSB expects).
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $N {start|stop|restart|reload|force-reload|status}" >&2
exit 1
;;
esac

View File

@ -15,7 +15,7 @@ CREATE TABLE meetme (
recordingformat char(10) NULL,
maxusers int(11) NULL,
members integer DEFAULT 0 NOT NULL,
index confno (confno,starttime,endtime)
PRIMARY KEY (bookid),
index confno (confno,starttime,endtime),
PRIMARY KEY (bookid)
);

Some files were not shown because too many files have changed in this diff Show More