summaryrefslogtreecommitdiff
path: root/channels
diff options
context:
space:
mode:
authorTerry Wilson <twilson@digium.com>2011-06-16 22:49:49 +0000
committerTerry Wilson <twilson@digium.com>2011-06-16 22:49:49 +0000
commit34e2305ae7c6aabdd27ddc454db9449c07845ee1 (patch)
treeb2aaf8bd69e1f83f2b40fa94e3fddeb927b658b9 /channels
parentab0c2cf44187b593cfc0be645a1f2b8b1f3089cb (diff)
Merged revisions 324048 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r324048 | twilson | 2011-06-16 17:35:41 -0500 (Thu, 16 Jun 2011) | 8 lines Lock the channel before calling the setoption callback The channel needs to be locked before calling these callback functions. Also, sip_setoption needs to lock the pvt and a check p->rtp is non-null before using it. Review: https://reviewboard.asterisk.org/r/1220/ ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@324050 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_local.c22
-rw-r--r--channels/chan_sip.c26
2 files changed, 27 insertions, 21 deletions
diff --git a/channels/chan_local.c b/channels/chan_local.c
index 0ceb432b0..3c16fc51a 100644
--- a/channels/chan_local.c
+++ b/channels/chan_local.c
@@ -217,6 +217,7 @@ static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, s
*outchan = p->chan;
}
+/* Called with ast locked */
static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen)
{
int res = 0;
@@ -225,27 +226,22 @@ static int local_setoption(struct ast_channel *ast, int option, void * data, int
ast_chan_write_info_t *write_info;
if (option != AST_OPTION_CHANNEL_WRITE) {
- res = -1;
- goto setoption_cleanup;
+ return -1;
}
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");
- res = -1;
- goto setoption_cleanup;
+ return -1;
}
/* get the tech pvt */
- ast_channel_lock(ast);
if (!(p = ast->tech_pvt)) {
- ast_channel_unlock(ast);
- res = -1;
- goto setoption_cleanup;
+ return -1;
}
ao2_ref(p, 1);
- ast_channel_unlock(ast);
+ ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
/* get the channel we are supposed to write to */
ao2_lock(p);
@@ -272,6 +268,7 @@ setoption_cleanup:
if (otherchan) {
ast_channel_unref(otherchan);
}
+ ast_channel_lock(ast); /* Lock back before we leave */
return res;
}
@@ -348,6 +345,7 @@ static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct
return bridged;
}
+/* Called with ast locked */
static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
{
struct local_pvt *p;
@@ -361,21 +359,18 @@ static int local_queryoption(struct ast_channel *ast, int option, void *data, in
}
/* 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);
if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
ao2_unlock(p);
- ast_channel_unlock(ast);
return -1;
}
ast_channel_ref(tmp);
ao2_unlock(p);
- ast_channel_unlock(ast);
+ ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
ast_channel_lock(tmp);
if (!(bridged = ast_bridged_channel(tmp))) {
@@ -394,6 +389,7 @@ query_cleanup:
if (tmp) {
tmp = ast_channel_unref(tmp);
}
+ ast_channel_lock(ast); /* Lock back before we leave */
return res;
}
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 7940b0157..4c0e2a66c 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -4262,15 +4262,23 @@ static int sip_setoption(struct ast_channel *chan, int option, void *data, int d
int res = -1;
struct sip_pvt *p = chan->tech_pvt;
+ sip_pvt_lock(p);
+
switch (option) {
case AST_OPTION_FORMAT_READ:
- res = ast_rtp_instance_set_read_format(p->rtp, (struct ast_format *) data);
+ if (p->rtp) {
+ res = ast_rtp_instance_set_read_format(p->rtp, (struct ast_format *) data);
+ }
break;
case AST_OPTION_FORMAT_WRITE:
- res = ast_rtp_instance_set_write_format(p->rtp, (struct ast_format *) data);
+ if (p->rtp) {
+ res = ast_rtp_instance_set_write_format(p->rtp, (struct ast_format *) data);
+ }
break;
case AST_OPTION_MAKE_COMPATIBLE:
- res = ast_rtp_instance_make_compatible(chan, p->rtp, (struct ast_channel *) data);
+ if (p->rtp) {
+ res = ast_rtp_instance_make_compatible(chan, p->rtp, (struct ast_channel *) data);
+ }
break;
case AST_OPTION_DIGIT_DETECT:
if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) ||
@@ -4298,6 +4306,8 @@ static int sip_setoption(struct ast_channel *chan, int option, void *data, int d
break;
}
+ sip_pvt_unlock(p);
+
return res;
}
@@ -4309,16 +4319,16 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
struct sip_pvt *p = (struct sip_pvt *) chan->tech_pvt;
char *cp;
+ sip_pvt_lock(p);
+
switch (option) {
case AST_OPTION_T38_STATE:
/* Make sure we got an ast_t38_state enum passed in */
if (*datalen != sizeof(enum ast_t38_state)) {
ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option. Expected %d, got %d\n", (int)sizeof(enum ast_t38_state), *datalen);
- return -1;
+ break;
}
- sip_pvt_lock(p);
-
/* Now if T38 support is enabled we need to look and see what the current state is to get what we want to report back */
if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) {
switch (p->t38.state) {
@@ -4337,8 +4347,6 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
}
}
- sip_pvt_unlock(p);
-
*((enum ast_t38_state *) data) = state;
res = 0;
@@ -4370,6 +4378,8 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
break;
}
+ sip_pvt_unlock(p);
+
return res;
}