diff options
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r-- | channels/chan_sip.c | 336 |
1 files changed, 243 insertions, 93 deletions
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); |