aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authorqwell <qwell@f38db490-d61c-443f-a65b-d21fe96a405b>2010-09-09 20:06:31 +0000
committerqwell <qwell@f38db490-d61c-443f-a65b-d21fe96a405b>2010-09-09 20:06:31 +0000
commitbbdc6cafb5a4c952b565135ee3470200673b310f (patch)
treebf8e77f6e4f2525aaca5cf79d01143c9973cdbd2 /channels
parent994debde3c3d78011509a53fc68dd6ae27a6024e (diff)
Transmit silence when reading DTMF in ast_readstring.
Otherwise, you could get issues with DTMF timeouts causing hangups. (closes issue #17370) Reported by: makoto Patches: channel-readstring-silence-generator.patch uploaded by makoto (license 38) git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@285742 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_alsa.c37
-rw-r--r--channels/chan_dahdi.c4
-rw-r--r--channels/chan_local.c20
-rw-r--r--channels/chan_misdn.c54
-rw-r--r--channels/chan_oss.c32
-rw-r--r--channels/chan_phone.c76
-rw-r--r--channels/chan_sip.c336
7 files changed, 362 insertions, 197 deletions
diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c
index 3a9a47208..a68c031b1 100644
--- a/channels/chan_alsa.c
+++ b/channels/chan_alsa.c
@@ -277,34 +277,25 @@ static int send_sound(void)
static void *sound_thread(void *unused)
{
- fd_set rfds;
- fd_set wfds;
- int max, res;
+ struct pollfd pfd[3] = { { .fd = sndcmd[0], .events = POLLIN }, { .fd = writedev }, { .fd = readdev } };
+ int res, x;
for (;;) {
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- max = sndcmd[0];
- FD_SET(sndcmd[0], &rfds);
- if (cursound > -1) {
- FD_SET(writedev, &wfds);
- if (writedev > max)
- max = writedev;
+ for (x = 0; x < 3; x++) {
+ pfd[x].revents = 0;
}
+
+ pfd[1].events = cursound > -1 ? POLLOUT : 0;
#ifdef ALSA_MONITOR
- if (!alsa.owner) {
- FD_SET(readdev, &rfds);
- if (readdev > max)
- max = readdev;
- }
+ pfd[2].events = !alsa.owner ? POLLIN : 0;
#endif
- res = ast_select(max + 1, &rfds, &wfds, NULL, NULL);
+ res = ast_poll(pfd, 3, -1);
if (res < 1) {
- ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
+ ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
continue;
}
#ifdef ALSA_MONITOR
- if (FD_ISSET(readdev, &rfds)) {
+ if (pfd[2].revents & POLLIN) {
/* Keep the pipe going with read audio */
snd_pcm_state_t state;
short buf[FRAME_SIZE];
@@ -329,7 +320,7 @@ static void *sound_thread(void *unused)
alsa_monitor_read((char *) buf, r * 2);
}
#endif
- if (FD_ISSET(sndcmd[0], &rfds)) {
+ if (pfd[0].revents & POLLIN) {
if (read(sndcmd[0], &cursound, sizeof(cursound)) < 0) {
ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
}
@@ -337,9 +328,11 @@ static void *sound_thread(void *unused)
offset = 0;
sampsent = 0;
}
- if (FD_ISSET(writedev, &wfds))
- if (send_sound())
+ if (pfd[1].revents & POLLOUT) {
+ if (send_sound()) {
ast_log(LOG_WARNING, "Failed to write sound\n");
+ }
+ }
}
/* Never reached */
return NULL;
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index a4e549a6f..667ee0313 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -5636,7 +5636,7 @@ static int dahdi_indicate(struct ast_channel *chan, int condition, const void *d
ast_log(LOG_DEBUG,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
#ifdef HAVE_PRI
p->digital = 0; /* Digital-only calls isn't allows any inband progress messages */
- if (!p->progress && p->sig==SIG_PRI && p->pri && !p->outgoing) {
+ if (!p->progress && !p->alerting && p->sig==SIG_PRI && p->pri && !p->outgoing) {
if (p->pri->pri) {
if (!pri_grab(p, p->pri)) {
pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
@@ -10066,7 +10066,7 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_CONFIG_ERR:
- ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->trunkgroup, e->err.err);
+ ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->span, e->err.err);
break;
case PRI_EVENT_RESTART_ACK:
chanpos = pri_find_principle(pri, e->restartack.channel);
diff --git a/channels/chan_local.c b/channels/chan_local.c
index 81f16eadf..7fa6968cc 100644
--- a/channels/chan_local.c
+++ b/channels/chan_local.c
@@ -294,6 +294,26 @@ static void check_bridge(struct local_pvt *p)
p->chan->audiohooks = p->owner->audiohooks;
p->owner->audiohooks = audiohooks_swapper;
}
+
+ /* If any Caller ID was set, preserve it after masquerade like above. We must check
+ * to see if Caller ID was set because otherwise we'll mistakingly copy info not
+ * set from the dialplan and will overwrite the real channel Caller ID. The reason
+ * for this whole preswapping action is because the Caller ID is set on the channel
+ * thread (which is the to be masqueraded away local channel) before both local
+ * channels are optimized away.
+ */
+ if (p->owner->cid.cid_dnid || p->owner->cid.cid_num ||
+ p->owner->cid.cid_name || p->owner->cid.cid_ani ||
+ p->owner->cid.cid_rdnis || p->owner->cid.cid_pres ||
+ p->owner->cid.cid_ani2 || p->owner->cid.cid_ton ||
+ p->owner->cid.cid_tns) {
+
+ struct ast_callerid tmpcid;
+ tmpcid = p->owner->cid;
+ p->owner->cid = p->chan->_bridge->cid;
+ p->chan->_bridge->cid = tmpcid;
+ }
+
ast_app_group_update(p->chan, p->owner);
ast_channel_masquerade(p->owner, p->chan->_bridge);
ast_set_flag(p, LOCAL_ALREADY_MASQED);
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index 95aff770a..389bd54e2 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -2763,9 +2763,8 @@ static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame
static struct ast_frame *misdn_read(struct ast_channel *ast)
{
struct chan_list *tmp;
- fd_set rrfs;
- struct timeval tv;
int len, t;
+ struct pollfd pfd = { .fd = -1, .events = POLLIN };
if (!ast) {
chan_misdn_log(1, 0, "misdn_read called without ast\n");
@@ -2781,30 +2780,23 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
return NULL;
}
- tv.tv_sec=0;
- tv.tv_usec=20000;
+ pfd.fd = tmp->pipe[0];
+ t = ast_poll(&pfd, 1, 20);
- FD_ZERO(&rrfs);
- FD_SET(tmp->pipe[0],&rrfs);
-
- t=select(FD_SETSIZE,&rrfs,NULL, NULL,&tv);
-
- if (!t) {
- chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n");
- len=160;
- }
-
- if (t<0) {
- chan_misdn_log(-1, tmp->bc->port, "Select Error (err=%s)\n",strerror(errno));
+ if (t < 0) {
+ chan_misdn_log(-1, tmp->bc->port, "poll() error (err=%s)\n", strerror(errno));
return NULL;
}
- if (FD_ISSET(tmp->pipe[0],&rrfs)) {
- len=read(tmp->pipe[0],tmp->ast_rd_buf,sizeof(tmp->ast_rd_buf));
+ if (!t) {
+ chan_misdn_log(3, tmp->bc->port, "poll() timed out\n");
+ len = 160;
+ } else if (pfd.revents & POLLIN) {
+ len = read(tmp->pipe[0], tmp->ast_rd_buf, sizeof(tmp->ast_rd_buf));
- if (len<=0) {
+ if (len <= 0) {
/* we hangup here, since our pipe is closed */
- chan_misdn_log(2,tmp->bc->port,"misdn_read: Pipe closed, hanging up\n");
+ chan_misdn_log(2, tmp->bc->port, "misdn_read: Pipe closed, hanging up\n");
return NULL;
}
@@ -4910,26 +4902,22 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
if (ch->ast)
ast_queue_frame(ch->ast, &frame);
} else {
- fd_set wrfs;
- struct timeval tv = { 0, 0 };
+ struct pollfd pfd = { .fd = ch->pipe[1], .events = POLLOUT };
int t;
- FD_ZERO(&wrfs);
- FD_SET(ch->pipe[1], &wrfs);
+ t = ast_poll(&pfd, 1, 0);
- t = select(FD_SETSIZE, NULL, &wrfs, NULL, &tv);
-
- if (!t) {
- chan_misdn_log(9, bc->port, "Select Timed out\n");
+ if (t < 0) {
+ chan_misdn_log(-1, bc->port, "poll() error (err=%s)\n", strerror(errno));
break;
}
-
- if (t < 0) {
- chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n", strerror(errno));
+
+ if (!t) {
+ chan_misdn_log(9, bc->port, "poll() timed out\n");
break;
}
-
- if (FD_ISSET(ch->pipe[1], &wrfs)) {
+
+ if (pfd.revents & POLLOUT) {
chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len);
if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) {
chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));
diff --git a/channels/chan_oss.c b/channels/chan_oss.c
index 8f55daa55..f78046780 100644
--- a/channels/chan_oss.c
+++ b/channels/chan_oss.c
@@ -604,38 +604,32 @@ static void *sound_thread(void *arg)
if (read(o->sounddev, ign, sizeof(ign)) < 0) {
}
for (;;) {
- fd_set rfds, wfds;
- int maxfd, res;
+ int res;
+ struct pollfd pfd[2] = { { .fd = o->sndcmd[0], .events = POLLIN }, { .fd = o->sounddev, .events = 0 } };
pthread_testcancel();
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_SET(o->sndcmd[0], &rfds);
- maxfd = o->sndcmd[0]; /* pipe from the main process */
- if (o->cursound > -1 && o->sounddev < 0)
+ if (o->cursound > -1 && o->sounddev < 0) {
setformat(o, O_RDWR); /* need the channel, try to reopen */
- else if (o->cursound == -1 && o->owner == NULL)
+ } else if (o->cursound == -1 && o->owner == NULL) {
setformat(o, O_CLOSE); /* can close */
+ }
if (o->sounddev > -1) {
if (!o->owner) { /* no one owns the audio, so we must drain it */
- FD_SET(o->sounddev, &rfds);
- maxfd = MAX(o->sounddev, maxfd);
+ pfd[1].events |= POLLIN;
}
if (o->cursound > -1) {
- FD_SET(o->sounddev, &wfds);
- maxfd = MAX(o->sounddev, maxfd);
+ pfd[1].events |= POLLOUT;
}
}
- /* ast_select emulates linux behaviour in terms of timeout handling */
- res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL);
+ res = ast_poll(pfd, 2, -1);
pthread_testcancel();
if (res < 1) {
- ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
+ ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
sleep(1);
continue;
}
- if (FD_ISSET(o->sndcmd[0], &rfds)) {
+ if (pfd[0].revents & POLLIN) {
/* read which sound to play from the pipe */
int i, what = -1;
@@ -656,11 +650,13 @@ static void *sound_thread(void *arg)
ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
}
if (o->sounddev > -1) {
- if (FD_ISSET(o->sounddev, &rfds)) /* read and ignore errors */
+ if (pfd[1].revents & POLLIN) { /* read and ignore errors */
if (read(o->sounddev, ign, sizeof(ign)) < 0) {
}
- if (FD_ISSET(o->sounddev, &wfds))
+ }
+ if (pfd[1].revents & POLLOUT) {
send_sound(o);
+ }
}
}
return NULL; /* Never reached */
diff --git a/channels/chan_phone.c b/channels/chan_phone.c
index fd202844b..bd13c78bb 100644
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -997,12 +997,12 @@ static void phone_check_exception(struct phone_pvt *i)
static void *do_monitor(void *data)
{
- fd_set rfds, efds;
- int n, res;
+ struct pollfd *fds = NULL;
+ int nfds = 0, inuse_fds = 0, res;
struct phone_pvt *i;
int tonepos = 0;
/* The tone we're playing this round */
- struct timeval tv = {0,0};
+ struct timeval tv = { 0, 0 };
int dotone;
/* This thread monitors all the frame relay interfaces which are not yet in use
(and thus do not have a separate thread) indefinitely */
@@ -1016,33 +1016,38 @@ static void *do_monitor(void *data)
}
/* Build the stuff we're going to select on, that is the socket of every
phone_pvt that does not have an associated owner channel */
- n = -1;
- FD_ZERO(&rfds);
- FD_ZERO(&efds);
i = iflist;
dotone = 0;
- while (i) {
- if (FD_ISSET(i->fd, &rfds))
- ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev);
+ inuse_fds = 0;
+ for (i = iflist; i; i = i->next) {
if (!i->owner) {
/* This needs to be watched, as it lacks an owner */
- FD_SET(i->fd, &rfds);
- FD_SET(i->fd, &efds);
- if (i->fd > n)
- n = i->fd;
+ if (inuse_fds == nfds) {
+ void *tmp = ast_realloc(fds, (nfds + 1) * sizeof(*fds));
+ if (!tmp) {
+ /* Avoid leaking */
+ continue;
+ }
+ fds = tmp;
+ nfds++;
+ }
+ fds[inuse_fds].fd = i->fd;
+ fds[inuse_fds].events = POLLIN | POLLERR;
+ fds[inuse_fds].revents = 0;
+ inuse_fds++;
+
if (i->dialtone && i->mode != MODE_SIGMA) {
/* Remember we're going to have to come back and play
more dialtones */
if (ast_tvzero(tv)) {
/* If we're due for a dialtone, play one */
- if (write(i->fd, DialTone + tonepos, 240) != 240)
+ if (write(i->fd, DialTone + tonepos, 240) != 240) {
ast_log(LOG_WARNING, "Dial tone write error\n");
+ }
}
dotone++;
}
}
-
- i = i->next;
}
/* Okay, now that we know what to do, release the interface lock */
ast_mutex_unlock(&iflock);
@@ -1051,26 +1056,28 @@ static void *do_monitor(void *data)
if (dotone && i && i->mode != MODE_SIGMA) {
/* If we're ready to recycle the time, set it to 30 ms */
tonepos += 240;
- if (tonepos >= sizeof(DialTone))
- tonepos = 0;
+ if (tonepos >= sizeof(DialTone)) {
+ tonepos = 0;
+ }
if (ast_tvzero(tv)) {
- tv = ast_tv(30000, 0);
+ tv = ast_tv(0, 30000);
}
- res = ast_select(n + 1, &rfds, NULL, &efds, &tv);
+ res = ast_poll2(fds, inuse_fds, &tv);
} else {
- res = ast_select(n + 1, &rfds, NULL, &efds, NULL);
- tv = ast_tv(0,0);
+ res = ast_poll(fds, inuse_fds, -1);
+ tv = ast_tv(0, 0);
tonepos = 0;
}
/* Okay, select has finished. Let's see what happened. */
if (res < 0) {
- ast_log(LOG_DEBUG, "select return %d: %s\n", res, strerror(errno));
+ ast_log(LOG_DEBUG, "poll returned %d: %s\n", res, strerror(errno));
continue;
}
/* If there are no fd's changed, just continue, it's probably time
to play some more dialtones */
- if (!res)
+ if (!res) {
continue;
+ }
/* Alright, lock the interface list again, and let's look and see what has
happened */
if (ast_mutex_lock(&iflock)) {
@@ -1078,15 +1085,27 @@ static void *do_monitor(void *data)
continue;
}
- i = iflist;
- for(; i; i=i->next) {
- if (FD_ISSET(i->fd, &rfds)) {
+ for (i = iflist; i; i = i->next) {
+ int j;
+ /* Find the record */
+ for (j = 0; j < inuse_fds; j++) {
+ if (fds[j].fd == i->fd) {
+ break;
+ }
+ }
+
+ /* Not found? */
+ if (j == inuse_fds) {
+ continue;
+ }
+
+ if (fds[j].revents & POLLIN) {
if (i->owner) {
continue;
}
phone_mini_packet(i);
}
- if (FD_ISSET(i->fd, &efds)) {
+ if (fds[j].revents & POLLERR) {
if (i->owner) {
continue;
}
@@ -1096,7 +1115,6 @@ static void *do_monitor(void *data)
ast_mutex_unlock(&iflock);
}
return NULL;
-
}
static int restart_monitor()
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 631da359d..9063d3fee 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -149,6 +149,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/compiler.h"
#include "asterisk/threadstorage.h"
#include "asterisk/translate.h"
+#include "asterisk/astobj2.h"
#ifndef FALSE
#define FALSE 0
@@ -855,6 +856,12 @@ static int global_t38_capability = T38FAX_VERSION_0 | T38FAX_RATE_2400 | T38FAX_
#define sipdebug_config ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONFIG)
#define sipdebug_console ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE)
+/*! \brief provisional keep alive scheduler item data */
+struct provisional_keepalive_data {
+ struct sip_pvt *pvt;
+ int sched_id;
+};
+
/*! \brief T38 States for a call */
enum t38state {
T38_DISABLED = 0, /*!< Not enabled */
@@ -1044,7 +1051,7 @@ static struct sip_pvt {
struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
AST_LIST_HEAD_NOLOCK(request_queue, sip_request) request_queue; /*!< Requests that arrived but could not be processed immediately */
int request_queue_sched_id; /*!< Scheduler ID of any scheduled action to process queued requests */
- int provisional_keepalive_sched_id; /*!< Scheduler ID for provisional responses that need to be sent out to avoid cancellation */
+ struct provisional_keepalive_data *provisional_keepalive_data; /*!< Scheduler data for provisional responses that need to be sent out to avoid cancellation */
const char *last_provisional; /*!< The last successfully transmitted provisonal response message */
struct sip_pvt *next; /*!< Next dialog in chain */
struct sip_invite_param *options; /*!< Options for INVITE */
@@ -1969,29 +1976,29 @@ static int retrans_pkt(const void *data)
if (pkt->retrans < MAX_RETRANS) {
pkt->retrans++;
- if (!pkt->timer_t1) { /* Re-schedule using timer_a and timer_t1 */
+ if (!pkt->timer_t1) { /* Re-schedule using timer_a and timer_t1 */
if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "SIP TIMER: Not rescheduling id #%d:%s (Method %d) (No timer T1)\n", pkt->retransid, sip_methods[pkt->method].text, pkt->method);
+ ast_log(LOG_DEBUG, "SIP TIMER: Not rescheduling id #%d:%s (Method %d) (No timer T1)\n", pkt->retransid, sip_methods[pkt->method].text, pkt->method);
} else {
- int siptimer_a;
-
- if (sipdebug && option_debug > 3)
- ast_log(LOG_DEBUG, "SIP TIMER: Rescheduling retransmission #%d (%d) %s - %d\n", pkt->retransid, pkt->retrans, sip_methods[pkt->method].text, pkt->method);
- if (!pkt->timer_a)
- pkt->timer_a = 2 ;
- else
- pkt->timer_a = 2 * pkt->timer_a;
-
- /* For non-invites, a maximum of 4 secs */
- siptimer_a = pkt->timer_t1 * pkt->timer_a; /* Double each time */
- if (pkt->method != SIP_INVITE && siptimer_a > 4000)
- siptimer_a = 4000;
-
- /* Reschedule re-transmit */
+ int siptimer_a;
+
+ if (sipdebug && option_debug > 3)
+ ast_log(LOG_DEBUG, "SIP TIMER: Rescheduling retransmission #%d (%d) %s - %d\n", pkt->retransid, pkt->retrans, sip_methods[pkt->method].text, pkt->method);
+ if (!pkt->timer_a)
+ pkt->timer_a = 2 ;
+ else
+ pkt->timer_a = 2 * pkt->timer_a;
+
+ /* For non-invites, a maximum of 4 secs */
+ siptimer_a = pkt->timer_t1 * pkt->timer_a; /* Double each time */
+ if (pkt->method != SIP_INVITE && siptimer_a > 4000)
+ siptimer_a = 4000;
+
+ /* Reschedule re-transmit */
reschedule = siptimer_a;
- if (option_debug > 3)
- ast_log(LOG_DEBUG, "** SIP timers: Rescheduling retransmission %d to %d ms (t1 %d ms (Retrans id #%d)) \n", pkt->retrans +1, siptimer_a, pkt->timer_t1, pkt->retransid);
- }
+ if (option_debug > 3)
+ ast_log(LOG_DEBUG, "** SIP timers: Rescheduling retransmission %d to %d ms (t1 %d ms (Retrans id #%d)) \n", pkt->retrans +1, siptimer_a, pkt->timer_t1, pkt->retransid);
+ }
if (sip_debug_test_pvt(pkt->owner)) {
const struct sockaddr_in *dst = sip_real_dst(pkt->owner);
@@ -2003,12 +2010,13 @@ static int retrans_pkt(const void *data)
append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data);
xmitres = __sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
- ast_mutex_unlock(&pkt->owner->lock);
- if (xmitres == XMIT_ERROR)
+ if (xmitres == XMIT_ERROR) {
ast_log(LOG_WARNING, "Network error on retransmit in dialog %s\n", pkt->owner->callid);
- else
+ } else {
+ ast_mutex_unlock(&pkt->owner->lock);
return reschedule;
- }
+ }
+ }
/* Too many retries */
if (pkt->owner && pkt->method != SIP_OPTIONS && xmitres == 0) {
if (ast_test_flag(pkt, FLAG_FATAL) || sipdebug) /* Tell us if it's critical or if we're debugging */
@@ -2021,7 +2029,7 @@ static int retrans_pkt(const void *data)
append_history(pkt->owner, "XmitErr", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
} else
append_history(pkt->owner, "MaxRetries", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
-
+
pkt->retransid = -1;
if (ast_test_flag(pkt, FLAG_FATAL)) {
@@ -2029,9 +2037,9 @@ static int retrans_pkt(const void *data)
DEADLOCK_AVOIDANCE(&pkt->owner->lock); /* SIP_PVT, not channel */
}
- if (pkt->owner->owner && !pkt->owner->owner->hangupcause)
+ if (pkt->owner->owner && !pkt->owner->owner->hangupcause)
pkt->owner->owner->hangupcause = AST_CAUSE_NO_USER_RESPONSE;
-
+
if (pkt->owner->owner) {
sip_alreadygone(pkt->owner);
ast_log(LOG_WARNING, "Hanging up call %s - no reply to our critical packet (see doc/sip-retransmit.txt).\n", pkt->owner->callid);
@@ -2042,7 +2050,7 @@ static int retrans_pkt(const void *data)
/* Let the peerpoke system expire packets when the timer expires for poke_noanswer */
if (pkt->method != SIP_OPTIONS) {
- ast_set_flag(&pkt->owner->flags[0], SIP_NEEDDESTROY);
+ ast_set_flag(&pkt->owner->flags[0], SIP_NEEDDESTROY);
sip_alreadygone(pkt->owner);
if (option_debug)
append_history(pkt->owner, "DialogKill", "Killing this failed dialog immediately");
@@ -2052,7 +2060,7 @@ static int retrans_pkt(const void *data)
if (pkt->method == SIP_BYE) {
/* We're not getting answers on SIP BYE's. Tear down the call anyway. */
- if (pkt->owner->owner)
+ if (pkt->owner->owner)
ast_channel_unlock(pkt->owner->owner);
append_history(pkt->owner, "ByeFailure", "Remote peer doesn't respond to bye. Destroying call anyway.");
ast_set_flag(&pkt->owner->flags[0], SIP_NEEDDESTROY);
@@ -2166,10 +2174,6 @@ static int __sip_autodestruct(const void *data)
return 10000;
}
- /* If we're destroying a subscription, dereference peer object too */
- if (p->subscribed == MWI_NOTIFICATION && p->relatedpeer)
- ASTOBJ_UNREF(p->relatedpeer,sip_destroy_peer);
-
/* Reset schedule ID */
p->autokillid = -1;
@@ -2335,44 +2339,124 @@ static void add_blank(struct sip_request *req)
}
}
-static int send_provisional_keepalive_full(struct sip_pvt *pvt, int with_sdp)
+/*! \brief This is called by the scheduler to resend the last provisional message in a dialog */
+static int send_provisional_keepalive_full(struct provisional_keepalive_data *data, int with_sdp)
{
const char *msg = NULL;
+ int res = 0;
+ struct sip_pvt *pvt = data->pvt;
- if (!pvt->last_provisional || !strncasecmp(pvt->last_provisional, "100", 3)) {
- msg = "183 Session Progress";
+ if (!pvt) {
+ ao2_ref(data, -1); /* not rescheduling so drop ref. in this case the dialog has already dropped this ref */
+ return res;
}
- if (pvt->invitestate < INV_COMPLETED) {
- if (with_sdp) {
- transmit_response_with_sdp(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq, XMIT_UNRELIABLE);
+ ast_mutex_lock(&pvt->lock);
+ while (pvt->owner && ast_channel_trylock(pvt->owner)) {
+ ast_mutex_unlock(&pvt->lock);
+ sched_yield();
+ if ((pvt = data->pvt)) {
+ ast_mutex_lock(&pvt->lock);
} else {
- transmit_response(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq);
+ ao2_ref(data, -1);
+ return res;
}
- return PROVIS_KEEPALIVE_TIMEOUT;
}
- return 0;
+ if (data->sched_id == -1 || pvt->invitestate >= INV_COMPLETED) {
+ goto provisional_keepalive_cleanup;
+ }
+
+ if (!pvt->last_provisional || !strncasecmp(pvt->last_provisional, "100", 3)) {
+ msg = "183 Session Progress";
+ }
+
+ if (with_sdp) {
+ transmit_response_with_sdp(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq, XMIT_UNRELIABLE);
+ } else {
+ transmit_response(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq);
+ }
+
+ res = PROVIS_KEEPALIVE_TIMEOUT; /* reschedule the keepalive event */
+
+provisional_keepalive_cleanup:
+ if (!res) { /* not rescheduling, so drop ref */
+ data->sched_id = -1; /* if we don't re-schedule, make sure to remove the sched id */
+ ao2_ref(data, -1); /* release the scheduler's reference to this data */
+ }
+
+ if (pvt->owner) {
+ ast_channel_unlock(pvt->owner);
+ }
+ ast_mutex_unlock(&pvt->lock);
+
+ return res;
+}
+
+static int send_provisional_keepalive(const void *data)
+{
+ struct provisional_keepalive_data *d = (struct provisional_keepalive_data *) data;
+
+ return send_provisional_keepalive_full(d, 0);
}
-static int send_provisional_keepalive(const void *data) {
- struct sip_pvt *pvt = (struct sip_pvt *) data;
+static int send_provisional_keepalive_with_sdp(const void *data)
+{
+ struct provisional_keepalive_data *d = (struct provisional_keepalive_data *) data;
- return send_provisional_keepalive_full(pvt, 0);
+ return send_provisional_keepalive_full(d, 1);
}
-static int send_provisional_keepalive_with_sdp(const void *data) {
- struct sip_pvt *pvt = (void *)data;
+static void *unref_provisional_keepalive(struct provisional_keepalive_data *data)
+{
+ if (data) {
+ data->sched_id = -1;
+ data->pvt = NULL;
+ ao2_ref(data, -1);
+ }
+ return NULL;
+}
- return send_provisional_keepalive_full(pvt, 1);
+static void remove_provisional_keepalive_sched(struct sip_pvt *pvt)
+{
+ int res;
+ if (!pvt->provisional_keepalive_data) {
+ return;
+ }
+ res = AST_SCHED_DEL(sched, pvt->provisional_keepalive_data->sched_id);
+ /* If we could not remove this item. remove pvt's reference this data and mark it for removal
+ * for the next time the scheduler uses it. The scheduler has it's own ref to this data
+ * and will detect it should not reschedule the event since the sched_id is -1 and pvt == NULL */
+ if (res == -1) {
+ pvt->provisional_keepalive_data = unref_provisional_keepalive(pvt->provisional_keepalive_data);
+ }
}
static void update_provisional_keepalive(struct sip_pvt *pvt, int with_sdp)
{
- AST_SCHED_DEL(sched, pvt->provisional_keepalive_sched_id);
+ remove_provisional_keepalive_sched(pvt);
+
+ if (!pvt->provisional_keepalive_data) {
+ if (!(pvt->provisional_keepalive_data = ao2_alloc(sizeof(*pvt->provisional_keepalive_data), NULL))) {
+ return; /* alloc error, can not recover */
+ }
+ pvt->provisional_keepalive_data->sched_id = -1;
+ pvt->provisional_keepalive_data->pvt = pvt;
+ }
+
+ /* give the scheduler a ref */
+ ao2_ref(pvt->provisional_keepalive_data, +1);
+
+ /* schedule the provisional keepalive */
+ pvt->provisional_keepalive_data->sched_id = ast_sched_add(sched,
+ PROVIS_KEEPALIVE_TIMEOUT,
+ with_sdp ? send_provisional_keepalive_with_sdp : send_provisional_keepalive,
+ pvt->provisional_keepalive_data);
- pvt->provisional_keepalive_sched_id = ast_sched_add(sched, PROVIS_KEEPALIVE_TIMEOUT,
- with_sdp ? send_provisional_keepalive_with_sdp : send_provisional_keepalive, pvt);
+ /* if schedule was unsuccessful, remove the scheduler's ref */
+ if (pvt->provisional_keepalive_data->sched_id == -1) {
+ ao2_ref(pvt->provisional_keepalive_data, -1);
+ }
}
/*! \brief Transmit response on SIP request*/
@@ -2399,7 +2483,7 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty
/* If we are sending a final response to an INVITE, stop retransmitting provisional responses */
if (p->initreq.method == SIP_INVITE && reliable == XMIT_CRITICAL) {
- AST_SCHED_DEL(sched, p->provisional_keepalive_sched_id);
+ remove_provisional_keepalive_sched(p);
}
res = (reliable) ?
@@ -3297,7 +3381,13 @@ static int __sip_destroy(struct sip_pvt *p, int lockowner)
AST_SCHED_DEL(sched, p->waitid);
AST_SCHED_DEL(sched, p->autokillid);
AST_SCHED_DEL(sched, p->request_queue_sched_id);
- AST_SCHED_DEL(sched, p->provisional_keepalive_sched_id);
+
+ remove_provisional_keepalive_sched(p);
+ if (p->provisional_keepalive_data) {
+ ast_mutex_lock(&p->lock);
+ p->provisional_keepalive_data = unref_provisional_keepalive(p->provisional_keepalive_data);
+ ast_mutex_unlock(&p->lock);
+ }
if (p->rtp) {
ast_rtp_destroy(p->rtp);
@@ -3765,7 +3855,6 @@ static int sip_hangup(struct ast_channel *ast)
if (p->invitestate == INV_CALLING) {
/* We can't send anything in CALLING state */
ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
- __sip_pretend_ack(p);
/* Do we need a timer here if we don't hear from them at all? Yes we do or else we will get hung dialogs and those are no fun. */
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
append_history(p, "DELAY", "Not sending cancel, waiting for timeout");
@@ -3783,7 +3872,7 @@ static int sip_hangup(struct ast_channel *ast)
}
} else { /* Incoming call, not up */
const char *res;
- AST_SCHED_DEL(sched, p->provisional_keepalive_sched_id);
+ remove_provisional_keepalive_sched(p);
if (p->hangupcause && (res = hangup_cause2sip(p->hangupcause)))
transmit_response_reliable(p, res, &p->initreq);
else
@@ -4681,7 +4770,6 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
p->waitid = -1;
p->autokillid = -1;
p->request_queue_sched_id = -1;
- p->provisional_keepalive_sched_id = -1;
p->subscribed = NONE;
p->stateid = -1;
p->prefs = default_prefs; /* Set default codecs for this call */
@@ -12799,7 +12887,11 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
}
}
-/*! \brief Check pending actions on SIP call */
+/*! \brief Check pending actions on SIP call
+ *
+ * \note both sip_pvt and sip_pvt's owner channel (if present)
+ * must be locked for this function.
+ */
static void check_pendings(struct sip_pvt *p)
{
if (ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
@@ -12814,6 +12906,9 @@ static void check_pendings(struct sip_pvt *p)
if (p->pendinginvite)
return;
+ if (p->owner) {
+ ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
+ }
/* Perhaps there is an SD change INVITE outstanding */
transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
}
@@ -12841,12 +12936,22 @@ static void check_pendings(struct sip_pvt *p)
static int sip_reinvite_retry(const void *data)
{
struct sip_pvt *p = (struct sip_pvt *) data;
+ struct ast_channel *owner;
ast_mutex_lock(&p->lock); /* called from schedule thread which requires a lock */
+ while ((owner = p->owner) && ast_channel_trylock(owner)) {
+ ast_mutex_unlock(&p->lock);
+ usleep(1);
+ ast_mutex_lock(&p->lock);
+ }
ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
p->waitid = -1;
check_pendings(p);
ast_mutex_unlock(&p->lock);
+ if (owner) {
+ ast_channel_unlock(owner);
+ }
+
return 0;
}
@@ -16047,7 +16152,6 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
int firststate = AST_EXTENSION_REMOVED;
struct sip_peer *authpeer = NULL;
const char *eventheader = get_header(req, "Event"); /* Get Event package name */
- const char *accept = get_header(req, "Accept");
int resubscribe = (p->subscribed != NONE);
char *temp, *event;
@@ -16174,56 +16278,96 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
if (!strcmp(event, "presence") || !strcmp(event, "dialog")) { /* Presence, RFC 3842 */
unsigned int pidf_xml;
+ const char *accept;
+ int start = 0;
+ enum subscriptiontype subscribed = NONE;
+ const char *unknown_acceptheader = NULL;
if (authpeer) /* No need for authpeer here */
ASTOBJ_UNREF(authpeer, sip_destroy_peer);
/* Header from Xten Eye-beam Accept: multipart/related, application/rlmi+xml, application/pidf+xml, application/xpidf+xml */
+ accept = __get_header(req, "Accept", &start);
+ while ((subscribed == NONE) && !ast_strlen_zero(accept)) {
+ pidf_xml = strstr(accept, "application/pidf+xml") ? 1 : 0;
+
+ /* Older versions of Polycom firmware will claim pidf+xml, but really
+ * they only support xpidf+xml. */
+ if (pidf_xml && strstr(p->useragent, "Polycom")) {
+ subscribed = XPIDF_XML;
+ } else if (pidf_xml) {
+ subscribed = PIDF_XML; /* RFC 3863 format */
+ } else if (strstr(accept, "application/dialog-info+xml")) {
+ subscribed = DIALOG_INFO_XML;
+ /* IETF draft: draft-ietf-sipping-dialog-package-05.txt */
+ } else if (strstr(accept, "application/cpim-pidf+xml")) {
+ subscribed = CPIM_PIDF_XML; /* RFC 3863 format */
+ } else if (strstr(accept, "application/xpidf+xml")) {
+ subscribed = XPIDF_XML; /* Early pre-RFC 3863 format with MSN additions (Microsoft Messenger) */
+ } else {
+ unknown_acceptheader = accept;
+ }
+ /* check to see if there is another Accept header present */
+ accept = __get_header(req, "Accept", &start);
+ }
- pidf_xml = strstr(accept, "application/pidf+xml") ? 1 : 0;
-
- /* Older versions of Polycom firmware will claim pidf+xml, but really
- * they only support xpidf+xml. */
- if (pidf_xml && strstr(p->useragent, "Polycom")) {
- p->subscribed = XPIDF_XML;
- } else if (pidf_xml) {
- p->subscribed = PIDF_XML; /* RFC 3863 format */
- } else if (strstr(accept, "application/dialog-info+xml")) {
- p->subscribed = DIALOG_INFO_XML;
- /* IETF draft: draft-ietf-sipping-dialog-package-05.txt */
- } else if (strstr(accept, "application/cpim-pidf+xml")) {
- p->subscribed = CPIM_PIDF_XML; /* RFC 3863 format */
- } else if (strstr(accept, "application/xpidf+xml")) {
- p->subscribed = XPIDF_XML; /* Early pre-RFC 3863 format with MSN additions (Microsoft Messenger) */
- } else if (ast_strlen_zero(accept)) {
+ if (!start) {
if (p->subscribed == NONE) { /* if the subscribed field is not already set, and there is no accept header... */
transmit_response(p, "489 Bad Event", req);
-
- ast_log(LOG_WARNING,"SUBSCRIBE failure: no Accept header: pvt: stateid: %d, laststate: %d, dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
- p->stateid, p->laststate, p->dialogver, p->subscribecontext, p->subscribeuri);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
+ ast_log(LOG_WARNING,"SUBSCRIBE failure: no Accept header: pvt: "
+ "stateid: %d, laststate: %d, dialogver: %d, subscribecont: "
+ "'%s', subscribeuri: '%s'\n",
+ p->stateid,
+ p->laststate,
+ p->dialogver,
+ p->subscribecontext,
+ p->subscribeuri);
+ ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
return 0;
}
/* if p->subscribed is non-zero, then accept is not obligatory; according to rfc 3265 section 3.1.3, at least.
so, we'll just let it ride, keeping the value from a previous subscription, and not abort the subscription */
- } else {
+ } else if (subscribed == NONE) {
/* Can't find a format for events that we know about */
char mybuf[200];
- snprintf(mybuf,sizeof(mybuf),"489 Bad Event (format %s)", accept);
+ if (!ast_strlen_zero(unknown_acceptheader)) {
+ snprintf(mybuf, sizeof(mybuf), "489 Bad Event (format %s)", unknown_acceptheader);
+ } else {
+ snprintf(mybuf, sizeof(mybuf), "489 Bad Event");
+ }
transmit_response(p, mybuf, req);
-
- ast_log(LOG_WARNING,"SUBSCRIBE failure: unrecognized format: '%s' pvt: subscribed: %d, stateid: %d, laststate: %d, dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
- accept, (int)p->subscribed, p->stateid, p->laststate, p->dialogver, p->subscribecontext, p->subscribeuri);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
+ ast_log(LOG_WARNING,"SUBSCRIBE failure: unrecognized format:"
+ "'%s' pvt: subscribed: %d, stateid: %d, laststate: %d,"
+ "dialogver: %d, subscribecont: '%s', subscribeuri: '%s'\n",
+ unknown_acceptheader,
+ (int)p->subscribed,
+ p->stateid,
+ p->laststate,
+ p->dialogver,
+ p->subscribecontext,
+ p->subscribeuri);
+ ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
return 0;
+ } else {
+ p->subscribed = subscribed;
+ }
+ } else if (!strcmp(event, "message-summary")) {
+ int start = 0;
+ int found_supported = 0;
+ const char *acceptheader;
+
+ acceptheader = __get_header(req, "Accept", &start);
+ while (!found_supported && !ast_strlen_zero(acceptheader)) {
+ found_supported = strcmp(acceptheader, "application/simple-message-summary") ? 0 : 1;
+ if (!found_supported && (option_debug > 2)) {
+ ast_log(LOG_DEBUG, "Received SIP mailbox subscription for unknown format: %s\n", acceptheader);
+ }
+ acceptheader = __get_header(req, "Accept", &start);
}
- } else if (!strcmp(event, "message-summary")) {
- if (!ast_strlen_zero(accept) && strcmp(accept, "application/simple-message-summary")) {
+ if (start && !found_supported) {
/* Format requested that we do not support */
transmit_response(p, "406 Not Acceptable", req);
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "Received SIP mailbox subscription for unknown format: %s\n", accept);
- ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
+ ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
if (authpeer) /* No need for authpeer here */
ASTOBJ_UNREF(authpeer, sip_destroy_peer);
return 0;
@@ -17102,7 +17246,7 @@ static int restart_monitor(void)
static int sip_poke_noanswer(const void *data)
{
struct sip_peer *peer = (struct sip_peer *)data;
-
+
peer->pokeexpire = -1;
if (peer->lastms > -1) {
ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Last qualify: %d\n", peer->name, peer->lastms);
@@ -17114,8 +17258,12 @@ static int sip_poke_noanswer(const void *data)
if (peer->call)
sip_destroy(peer->call);
peer->call = NULL;
- peer->lastms = -1;
- ast_device_state_changed("SIP/%s", peer->name);
+
+ /* Don't send a devstate change if nothing changed. */
+ if (peer->lastms > -1) {
+ peer->lastms = -1;
+ ast_device_state_changed("SIP/%s", peer->name);
+ }
/* This function gets called one place outside of the scheduler ... */
if (!AST_SCHED_DEL(sched, peer->pokeexpire)) {
@@ -18824,6 +18972,8 @@ static int reload_config(enum channelreloadreason reason)
ast_log(LOG_WARNING, "Unable to set SIP TOS to %s\n", ast_tos2str(global_tos_sip));
}
}
+ } else if (setsockopt(sipsock, IPPROTO_IP, IP_TOS, &global_tos_sip, sizeof(global_tos_sip))) {
+ ast_log(LOG_WARNING, "Unable to set SIP TOS to %s\n", ast_tos2str(global_tos_sip));
}
ast_mutex_unlock(&netlock);