From: Matthew Jordan Date: Wed, 31 Oct 2012 20:22:19 +0000 (+0000) Subject: Multiple revisions 369436,369557,369579,369626,369652,372628 for 1.8.11-cert8 X-Git-Tag: certified/1.8.11-cert8~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f63555e9efb28a69dff1118470a18cd4a6634b1;p=thirdparty%2Fasterisk.git Multiple revisions 369436,369557,369579,369626,369652,372628 for 1.8.11-cert8 ........ r369436 | twilson | 2012-06-27 15:58:51 -0500 (Wed, 27 Jun 2012) | 17 lines AST-2012-010: Clean up after a reinvite that never gets a final response The basic problem is that if a re-INVITE is sent by Asterisk and it receives a provisional response, but no final response, then the dialog is never torn down. In addition to leaking memory, this also leaks file descriptors and will eventually lead to Asterisk no longer being able to process calls. This patch just keeps track of whether there is an outstanding re-INVITE, and if there is goes ahead and cleans up everything as though there was no outstanding reinvite. Review: https://reviewboard.asterisk.org/r/2009/ (closes issue ASTERISK-19992) Reported by: Steve Davies Tested by: Steve Davies, Terry Wilson ........ r369557 | twilson | 2012-07-03 09:27:02 -0500 (Tue, 03 Jul 2012) | 11 lines Better handle re-INVITEs with provisional but no final repsonses A previous attempt at fixing this issue had negative side effects related to attended transfers which this patch should resolve. Many thanks to Steve Davies for all of the good suggestions and testing. (closes issue ASTERISK-19992) Reported by: Steve Davies Tested by: Steve Davies, Terry Wilson Review: https://reviewboard.asterisk.org/r/2009/ ........ r369579 | twilson | 2012-07-03 11:58:16 -0500 (Tue, 03 Jul 2012) | 8 lines More improvements to re-INVITEs timing out after a provisional response There is no need to call check_pendings() on a final response to an INVITE when destroying the scheduler entry as it will be done later during normal processing. (issue ASTERISK-19992) ........ r369626 | mjordan | 2012-07-05 12:01:52 -0500 (Thu, 05 Jul 2012) | 16 lines Do not send a BYE when a provisional response arrives during a re-INVITE Commits r369557 and r369579 were done to improve handling of re-INVITEs when the UA that was supposed to receive the re-INVITE fails to respond. A limitation of those patches occurred when a UA sent a provisional response to the re-INVITE. This triggered a sending of a BYE in check_pending. This patch tweaks the handling of the re-INVITE such that a BYE is not sent in response to those messages. (issue ASTERISK-19992) Reported by: Steve Davies Tested by: Steve Davies patches: (reinvite_tweak.diff license #5012 by Steve Davies) ........ r369652 | kmoore | 2012-07-05 14:01:52 -0500 (Thu, 05 Jul 2012) | 22 lines AST-2012-011: Resolve heap corruption issue with voicemail The heard and deleted arrays in the voicemail state structure were not handled properly following the memory leak fix in r354890 and a fix for an invalid free in r356797. This could result in accessing and writing into freed memory. The allocation for these arrays has been reworked to avoid the possibility of invalid frees, access of freed memory, and crashes that were occurring as a result of this. Locking around accesses and modifications of the voicemail state structure members dh_arraysize, heard, and deleted has been added to prevent simultaneous modification and access when IMAP storage is in use. If IMAP storage is not in use, this locking is not compiled in. Review: https://reviewboard.asterisk.org/r/1994/ (closes issue ASTERISK-19923) Reported by: Dan Delaney Tested by: Dan Delaney, Julian Yap Patches: vm_alloc_fix.diff uploaded by kmoore (license 6273) ........ r372628 | rmudgett | 2012-09-07 17:06:29 -0500 (Fri, 07 Sep 2012) | 5 lines Remove annoying unconditional debug message from INC/DEC functions. (closes issue AST-1001) Reported by: Guenther Kelleter ........ Merged revisions 369436,369557,369579,369626,369652,372628 from http://svn.asterisk.org/svn/asterisk/branches/1.8 git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/1.8.11@375568 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 15a1cf9356..f8da0821ad 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -1803,25 +1803,28 @@ static void free_user(struct ast_vm_user *vmu) static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) { int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg); - if (!vms->dh_arraysize) { - /* initial allocation */ + + /* remove old allocation */ + if (vms->deleted) { + ast_free(vms->deleted); + vms->deleted = NULL; + } + if (vms->heard) { + ast_free(vms->heard); + vms->heard = NULL; + } + vms->dh_arraysize = 0; + + if (arraysize > 0) { if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) { return -1; } if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) { + ast_free(vms->deleted); + vms->deleted = NULL; return -1; } vms->dh_arraysize = arraysize; - } else if (vms->dh_arraysize < arraysize) { - if (!(vms->deleted = ast_realloc(vms->deleted, arraysize * sizeof(int)))) { - return -1; - } - if (!(vms->heard = ast_realloc(vms->heard, arraysize * sizeof(int)))) { - return -1; - } - memset(vms->deleted, 0, arraysize * sizeof(int)); - memset(vms->heard, 0, arraysize * sizeof(int)); - vms->dh_arraysize = arraysize; } return 0; @@ -6919,9 +6922,15 @@ static void adsi_message(struct ast_channel *chan, struct vm_state *vms) name = "Unknown Caller"; /* If deleted, show "undeleted" */ - - if (vms->deleted[vms->curmsg]) - keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11); +#ifdef IMAP_STORAGE + ast_mutex_lock(&vms->lock); +#endif + if (vms->deleted[vms->curmsg]) { + keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11); + } +#ifdef IMAP_STORAGE + ast_mutex_unlock(&vms->lock); +#endif /* Except "Exit" */ keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5); @@ -6974,8 +6983,15 @@ static void adsi_delete(struct ast_channel *chan, struct vm_state *vms) } /* If deleted, show "undeleted" */ - if (vms->deleted[vms->curmsg]) +#ifdef IMAP_STORAGE + ast_mutex_lock(&vms->lock); +#endif + if (vms->deleted[vms->curmsg]) { keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11); + } +#ifdef IMAP_STORAGE + ast_mutex_unlock(&vms->lock); +#endif /* Except "Exit" */ keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5); @@ -8154,8 +8170,12 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc if (!res) { make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg); +#ifdef IMAP_STORAGE + ast_mutex_lock(&vms->lock); +#endif vms->heard[vms->curmsg] = 1; #ifdef IMAP_STORAGE + ast_mutex_unlock(&vms->lock); /*IMAP storage stores any prepended message from a forward * as a separate file from the rest of the message */ @@ -8371,6 +8391,7 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu) } ast_unlock_path(vms->curdir); #else /* defined(IMAP_STORAGE) */ + ast_mutex_lock(&vms->lock); if (vms->deleted) { /* Since we now expunge after each delete, deleting in reverse order * ensures that no reordering occurs between each step. */ @@ -8385,12 +8406,18 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu) #endif done: - if (vms->deleted && last_msg_idx) { + if (vms->deleted) { ast_free(vms->deleted); + vms->deleted = NULL; } - if (vms->heard && last_msg_idx) { + if (vms->heard) { ast_free(vms->heard); + vms->heard = NULL; } + vms->dh_arraysize = 0; +#ifdef IMAP_STORAGE + ast_mutex_unlock(&vms->lock); +#endif return 0; } @@ -9485,14 +9512,25 @@ static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, res = ast_play_and_wait(chan, "vm-next"); } if (!res) { - if (!vms->deleted[vms->curmsg]) + int curmsg_deleted; +#ifdef IMAP_STORAGE + ast_mutex_lock(&vms->lock); +#endif + curmsg_deleted = vms->deleted[vms->curmsg]; +#ifdef IMAP_STORAGE + ast_mutex_unlock(&vms->lock); +#endif + if (!curmsg_deleted) { res = ast_play_and_wait(chan, "vm-delete"); - else + } else { res = ast_play_and_wait(chan, "vm-undelete"); - if (!res) + } + if (!res) { res = ast_play_and_wait(chan, "vm-toforward"); - if (!res) + } + if (!res) { res = ast_play_and_wait(chan, "vm-savemessage"); + } } } if (!res) { @@ -10685,6 +10723,7 @@ static int vm_execmain(struct ast_channel *chan, const char *data) } vms.starting = 1; + vms.curmsg = 0; break; case '3': /* Advanced options */ ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu"); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 9e5c85fc75..40c25fb7e4 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -3933,7 +3933,7 @@ static int __sip_autodestruct(const void *data) ast_debug(3, "Re-scheduled destruction of SIP call %s\n", p->callid ? p->callid : ""); append_history(p, "ReliableXmit", "timeout"); if (sscanf(p->lastmsg, "Tx: %30s", method_str) == 1 || sscanf(p->lastmsg, "Rx: %30s", method_str) == 1) { - if (method_match(SIP_CANCEL, method_str) || method_match(SIP_BYE, method_str)) { + if (p->ongoing_reinvite || method_match(SIP_CANCEL, method_str) || method_match(SIP_BYE, method_str)) { pvt_set_needdestroy(p, "autodestruct"); } } @@ -6304,6 +6304,21 @@ const char *hangup_cause2sip(int cause) return 0; } +static int reinvite_timeout(const void *data) +{ + struct sip_pvt *dialog = (struct sip_pvt *) data; + struct ast_channel *owner = sip_pvt_lock_full(dialog); + dialog->reinviteid = -1; + check_pendings(dialog); + if (owner) { + ast_channel_unlock(owner); + ast_channel_unref(owner); + } + ao2_unlock(dialog); + dialog_unref(dialog, "unref for reinvite timeout"); + return 0; +} + /*! \brief sip_hangup: Hangup SIP call * Part of PBX interface, called from ast_hangup */ static int sip_hangup(struct ast_channel *ast) @@ -6503,8 +6518,16 @@ static int sip_hangup(struct ast_channel *ast) ast_set_flag(&p->flags[0], SIP_PENDINGBYE); ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE); AST_SCHED_DEL_UNREF(sched, p->waitid, dialog_unref(p, "when you delete the waitid sched, you should dec the refcount for the stored dialog ptr")); - if (sip_cancel_destroy(p)) + if (sip_cancel_destroy(p)) { ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n"); + } + /* If we have an ongoing reinvite, there is a chance that we have gotten a provisional + * response, but something weird has happened and we will never receive a final response. + * So, just in case, check for pending actions after a bit of time to trigger the pending + * bye that we are setting above */ + if (p->ongoing_reinvite && p->reinviteid < 0) { + p->reinviteid = ast_sched_add(sched, 32 * p->timer_t1, reinvite_timeout, dialog_ref(p, "ref for reinvite_timeout")); + } } } } @@ -7826,6 +7849,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr, p->method = intended_method; p->initid = -1; p->waitid = -1; + p->reinviteid = -1; p->autokillid = -1; p->request_queue_sched_id = -1; p->provisional_keepalive_sched_id = -1; @@ -11993,7 +12017,7 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int old initialize_initreq(p, &req); p->lastinvite = p->ocseq; ast_set_flag(&p->flags[0], SIP_OUTGOING); /* Change direction of this dialog */ - + p->ongoing_reinvite = 1; return send_request(p, &req, XMIT_CRITICAL, p->ocseq); } @@ -20149,8 +20173,11 @@ static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char static void check_pendings(struct sip_pvt *p) { if (ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) { - /* if we can't BYE, then this is really a pending CANCEL */ - if (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA) { + if (p->reinviteid > -1) { + /* Outstanding p->reinviteid timeout, so wait... */ + return; + } else if (p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA) { + /* if we can't BYE, then this is really a pending CANCEL */ p->invitestate = INV_CANCELLED; transmit_request(p, SIP_CANCEL, p->lastinvite, XMIT_RELIABLE, FALSE); /* If the cancel occurred on an initial invite, cancel the pending BYE */ @@ -20161,8 +20188,9 @@ static void check_pendings(struct sip_pvt *p) INVITE, but do set an autodestruct just in case we never get it. */ } else { /* We have a pending outbound invite, don't send something - new in-transaction */ - if (p->pendinginvite) + * new in-transaction, unless it is a pending reinvite, then + * by the time we are called here, we should probably just hang up. */ + if (p->pendinginvite && !p->ongoing_reinvite) return; if (p->owner) { @@ -20402,9 +20430,17 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest if (resp >= 300 && (p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA )) p->invitestate = INV_COMPLETED; + if ((resp >= 200 && reinvite)) { + p->ongoing_reinvite = 0; + if (p->reinviteid > -1) { + AST_SCHED_DEL_UNREF(sched, p->reinviteid, dialog_unref(p, "unref dialog for reinvite timeout because of a final response")); + } + } + /* Final response, clear out pending invite */ - if ((resp == 200 || resp >= 300) && p->pendinginvite && seqno == p->pendinginvite) + if ((resp == 200 || resp >= 300) && p->pendinginvite && seqno == p->pendinginvite) { p->pendinginvite = 0; + } /* If this is a response to our initial INVITE, we need to set what we can use * for this peer. diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 5e52636b2b..c5c64c19f2 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -1073,6 +1073,7 @@ struct sip_pvt { struct sip_auth_container *peerauth;/*!< Realm authentication credentials */ int noncecount; /*!< Nonce-count */ unsigned int stalenonce:1; /*!< Marks the current nonce as responded too */ + unsigned int ongoing_reinvite:1; /*!< There is a reinvite in progress that might need to be cleaned up */ char lastmsg[256]; /*!< Last Message sent/received */ int amaflags; /*!< AMA Flags */ uint32_t pendinginvite; /*!< Any pending INVITE or state NOTIFY (in subscribe pvt's) ? (seqno of this) */ @@ -1085,6 +1086,7 @@ struct sip_pvt { int initid; /*!< Auto-congest ID if appropriate (scheduler) */ int waitid; /*!< Wait ID for scheduler after 491 or other delays */ + int reinviteid; /*!< Reinvite in case of provisional, but no final response */ int autokillid; /*!< Auto-kill ID (scheduler) */ int t38id; /*!< T.38 Response ID */ struct sip_refer *refer; /*!< REFER: SIP transfer data structure */ diff --git a/funcs/func_math.c b/funcs/func_math.c index e7217c7b3d..daee905339 100644 --- a/funcs/func_math.c +++ b/funcs/func_math.c @@ -421,8 +421,6 @@ static int crement_function_read(struct ast_channel *chan, const char *cmd, modify_orig = 1; } - ast_log(LOG_NOTICE, "The value is now: %d\n", int_value); - if (snprintf(returnvar, sizeof(returnvar), "%d", int_value) > 0) { pbx_builtin_setvar_helper(chan, data, returnvar); if (modify_orig) {