From f3f2ac35f45b8d81e9dd8e468fb792523c4d982d Mon Sep 17 00:00:00 2001 From: Jason Parker Date: Mon, 11 Jun 2012 21:53:41 +0000 Subject: [PATCH] Multiple revisions 365155,365160,365299,365320,365399,365475,365478,365575,365632,365701,365898,365990,366049,366053,366106,366168,366241,366297,366390,366412,366591,366598,366741,366792,366881,366884,366948,367003,367028,367267,367299,367369,367417,367470,367562,367679,367731,367782,367844,367907,367978,367981,368042,368093,368267,368310,368407,368470,368499,368524,368536,368568,368587 ........ r365155 | may | 2012-05-03 09:27:00 -0500 (Thu, 03 May 2012) | 11 lines Fix coverity static analysis warning, allocate full ie structure instead of without data buffer (close issue ASTERISK-19674) Reported by: Matt Jordan Patches: ASTERISK-19674.patch (License #5415) ........ Merged revisions 365143 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365160 | may | 2012-05-03 10:01:14 -0500 (Thu, 03 May 2012) | 11 lines Fix warning of Coverity Static analysis, change H225ProtocolIdentifier from value to pointer per functions that use this. (close issue ASTERISK-19670) Reported by: Matt Jordan Patches: ASTERISK-19670.patch (License #5415) ........ Merged revisions 365159 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365299 | mmichelson | 2012-05-04 10:51:04 -0500 (Fri, 04 May 2012) | 12 lines Fix core FINDING 2, FINDING 3, and FINDING 4 from Coverity's CONSTANT_EXPRESSION_RESULT report. These three all are in RTP code that attempts to print the number of sequence number cycles in an RTCP RR report. The code was masking out the upper 16 bits and then shifting the number right by 16 bits. This led to an all zero result in all cases. The fix is to do the shift without the bit masking. (issue ASTERISK-19649) ........ Merged revisions 365298 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365320 | rmudgett | 2012-05-04 11:28:06 -0500 (Fri, 04 May 2012) | 30 lines Fix local channel chains optimizing themselves out of a call. * Made chan_local.c:check_bridge() check the return value of ast_channel_masquerade(). In long chains of local channels, the masquerade occasionally fails to get setup because there is another masquerade already setup on an adjacent local channel in the chain. * Made the outgoing local channel (the ;2 channel) flush one voice or video frame per optimization attempt. * Made sure that the outgoing local channel also does not have any frames in its queue before the masquerade. * Made do the masquerade immediately to minimize the chance that the outgoing channel queue does not get any new frames added and thus unconditionally flushed. * Made block indication -1 (Stop tones) event when the local channel is going to optimize itself out. When the call is answered, a chain of local channels pass down a -1 indication for each bridge. This blizzard of -1 events really slows down the optimization process. (closes issue ASTERISK-16711) Reported by: Alec Davis Tested by: rmudgett, Alec Davis Review: https://reviewboard.asterisk.org/r/1894/ ........ Merged revisions 365313 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365399 | kmoore | 2012-05-04 17:15:05 -0500 (Fri, 04 May 2012) | 13 lines Fix many issues from the NULL_RETURNS Coverity report Most of the changes here are trivial NULL checks. There are a couple optimizations to remove the need to check for NULL and outboundproxy parsing in chan_sip.c was rewritten to avoid use of strtok. Additionally, a bug was found and fixed with the parsing of outboundproxy when "outboundproxy=," was set. (Closes issue ASTERISK-19654) ........ Merged revisions 365398 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365475 | mjordan | 2012-05-07 13:39:10 -0500 (Mon, 07 May 2012) | 20 lines Support VoiceMail d() option when extension does not exist in channel's context The VoiceMail d([c]) option is documented to accept digits for a new extension in context , if played during the greeting. This option works fine if the extension being redirected to has an extension with the same initial digit in the channel's current context. If that digit did not happen to exist in some extension, a dialplan match would fail and the user would not be redirected. This patch fixes it such that if the option is used, the extensions are matched in that context as opposed to the caller's original context. (closes issue ASTERISK-18243) Reported by: mjordan Tested by: mjordan Review: https://reviewboard.asterisk.org/r/1892 ........ Merged revisions 365474 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365478 | rmudgett | 2012-05-07 13:43:08 -0500 (Mon, 07 May 2012) | 5 lines Fix type punned compiler warning in test_config.c ........ Merged revisions 365476 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365575 | mmichelson | 2012-05-08 10:51:13 -0500 (Tue, 08 May 2012) | 22 lines Send more accurate identification information in dialog-info SIP NOTIFYs. This uses the calling channel's caller ID and connected line information to populate the remote and local identities in the dialog-info NOTIFY when an extension is ringing. There is a bit of an oddity here, and that is that we seed the remote target with the To header of the outbound call rather than the from header. This is because it was reported that seeding with the from header caused hints to be broken with certain SNOM devices. A comment has been added to the code to explain this. (closes issue ASTERISK-16735) reported by Maciej Krajewski patches: local_remote_hint2.diff uploaded by Mark Michelson (license #5049) 16735_tweak1.diff uploaded by Mark Michelson (license #5049) Tested by Niccolo Belli ........ Merged revisions 365574 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365632 | rmudgett | 2012-05-08 13:08:01 -0500 (Tue, 08 May 2012) | 13 lines * Fix accept/decline DTMF buffer overwrite in FollowMe. * Made use MAX_YN_STRING define to make all accept/decline DTMF buffers the same size. Just using 20 isn't good enough when someone didn't get the memo. * Fix stupid use of a global variable in FollowMe. (ynlongest) * Fix bit field declarations in FollowMe. ........ Merged revisions 365631 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365701 | rmudgett | 2012-05-08 15:25:08 -0500 (Tue, 08 May 2012) | 12 lines * Fix FollowMe memory leak on error paths in app_exec(). * Fix FollowMe leaving recorded caller name file on error paths in app_exec(). * Use correct buffer dimension define in struct call_followme.moh[] and struct fm_args.namerecloc[]. This fixes unexpected namerecloc filename length restriction. ........ Merged revisions 365692 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365898 | mmichelson | 2012-05-09 11:15:28 -0500 (Wed, 09 May 2012) | 29 lines Prevent sip_pvt refleak when an ast_channel outlasts its corresponding sip_pvt. chan_sip was coded under the assumption that a SIP dialog with an owner channel will always be destroyed after the owner channel has been hung up. However, there are situations where the SIP dialog can time out and auto destruct before the corresponding channel has hung up. A typical example of this would be if the 'h' extension in the dialplan takes a long time to complete. In such cases, __sip_autodestruct() would complain about the dialog being auto destroyed with an owner channel still in place. The problem is that even once the owner channel was hung up, the sip_pvt would still be linked in its ao2_container because nothing would ever unlink it. The fix for this is that if __sip_autodestruct() is called for a sip_pvt that still has an owner channel in place, the destruction is rescheduled for 10 seconds in the future. This will continue until the owner channel is finally hung up. (closes issue ASTERISK-19425) reported by David Cunningham Patches: ASTERISK-19425.patch uploaded by Mark Michelson (License #5049) (closes issue ASTERISK-19455) reported by Dean Vesvuio Tested by Dean Vesvuio ........ Merged revisions 365896 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r365990 | jrose | 2012-05-09 14:12:32 -0500 (Wed, 09 May 2012) | 18 lines Block on frameout if the hardware has enough samples to complete a frame. Fixes some problems with skipping audio in elaborate scenarios involving multiple codecs by making codec_dahdi operate in a more synchronous fashion similar to codec_g729. This change also fixes the use of file conversion tools from Asterisk's CLI. This change may cause the thread responsible for transcoding audio to block briefly (Shaun Ruffell describes this as 'several milliseconds') while waiting for the hardware transcoder. (closes issue ASTERISK-19643) reported by: Shaun Ruffell Patches: 0001-codec_dahdi-Block-on-frameout-the-hardware-has-enoug.patch uploaded by Shaun Ruffell (license 5417) ........ Merged revisions 365989 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366049 | jrose | 2012-05-10 10:43:06 -0500 (Thu, 10 May 2012) | 9 lines Coverity Report: Fix issues for error type UNINIT in Core supported modules (issue ASTERISK-19652) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/1909/ ........ Merged revisions 366048 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366053 | mmichelson | 2012-05-10 11:13:06 -0500 (Thu, 10 May 2012) | 9 lines Close the proper tcptls_session when session creation fails. (issue AST-998) Reported by: Thomas Arimont Tested by: Thomas Arimont ........ Merged revisions 366052 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366106 | jrose | 2012-05-10 11:55:22 -0500 (Thu, 10 May 2012) | 9 lines Coverity Report: Fix issues for error type CHECKED_RETURN for core (issue ASTERISK-19658) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/1905/ ........ Merged revisions 366094 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366168 | kmoore | 2012-05-10 15:54:08 -0500 (Thu, 10 May 2012) | 13 lines Resolve FORWARD_NULL static analysis warnings This resolves core findings from ASTERISK-19650 numbers 0-2, 6, 7, 9-11, 14-20, 22-24, 28, 30-32, 34-36, 42-56, 82-84, 87, 89-90, 93-102, 104, 105, 109-111, and 115. Finding numbers 26, 33, and 29 were already resolved. Those skipped were either extended/deprecated or in areas of code that shouldn't be disturbed. (Closes issue ASTERISK-19650) ........ Merged revisions 366167 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366241 | rmudgett | 2012-05-10 18:42:43 -0500 (Thu, 10 May 2012) | 7 lines * Made ast_change_name() hold the channels container lock while changing the channel name. * Eliminate redundant list not empty check in clone_variables(). ........ Merged revisions 366240 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366297 | russell | 2012-05-11 18:59:35 -0500 (Fri, 11 May 2012) | 19 lines format_mp3: Fix a possible crash mp3_read(). This patch fixes a potential crash in mp3_read() by not assuming that dbuf has enough data to finish filling up the output buffer. The patch also makes sure that the dbuf state gets reset after we know we read everything out of it already. In passing, this patch includes some other cleanups of this module, including stripping trailing whitespace, formatting fixes based on coding guidelines, and removing a number of unused members from the private state struct. (closes issue ASTERISK-19761) Reported by: Chris Maciejewsk Tested by: Chris Maciejewsk ........ Merged revisions 366296 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366390 | mmichelson | 2012-05-14 14:16:36 -0500 (Mon, 14 May 2012) | 25 lines Fix broken reinvite glare scenario. To make a long story short, reinvite glares were broken because Asterisk would invert the To and From headers when ACKing a 491 response. The reason was because the initreq of the dialog was being changed to the incoming glared reinvite instead of being set to the outgoing glared reinvite. This change has three parts * In handle_incoming, we never will reject an ACK because it has a to-tag present, even if we think the request may be out of dialog. * In handle_request_invite, we do not change the initreq when receiving a reinvite to which we will respond with a 491. * In handle_request_invite, several superflous settings up pendinginvite have been removed since this is dones automatically by transmit_response_reliable Review: https://reviewboard.asterisk.org/r/1911 ........ Merged revisions 366389 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366412 | mmichelson | 2012-05-14 15:06:58 -0500 (Mon, 14 May 2012) | 19 lines Fix two more coverity constant expression result findings. These correspond to findings 0 and 1 in the core findings of ASTERISK-19649. After contacting Mark Spencer, he was unsure of what the intent behind these lines of code were, so they are being axed. For Asterisk 1.8 and 10, the output of debugging DUNDi frames will not be changed, but for trunk the "Retry" portion will be omitted since it does not properly distinguish retransmissions from initial frames. (closes issue ASTERISK-19649) Reported by Matthew Jordan ........ Merged revisions 366409 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366591 | jrose | 2012-05-15 15:44:59 -0500 (Tue, 15 May 2012) | 15 lines chan_sip: Check the right channel's host address for directmediapermit/deny Prior to this patch, when checking the addresses for directmediapermit and denydirectmediadeny, Asterisk would check the host address of the channel permit/deny was specified, which defers from the expectations of both our users and the development team. Instead, directmediapermit/deny now checks against the address of the channel that the peer with the ACL is connected to. (issue AST-876) Review: https://reviewboard.asterisk.org/r/1899/ ........ Merged revisions 366547 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366598 | mmichelson | 2012-05-15 18:39:06 -0500 (Tue, 15 May 2012) | 8 lines Correct misuse of ast_strip_quoted() when getting a Diversion header's reason parameter. The use here was assuming that the pointer would be updated, but the updated string is actually returned by ast_strip_quoted() instead. ........ Merged revisions 366597 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366741 | mjordan | 2012-05-17 07:57:30 -0500 (Thu, 17 May 2012) | 23 lines Fix checking bounds of array index after using it; improper sizeof This patch fixes two problems pointed out by a static analysis tool. * In chan_dahdi, when an event is handled the index of the sub channel is first obtained. In very off nominal cases, the method that determines the index can return a negative value. In the event handling code, whether or not the index returned is valid was being checked after that value was used to index into an array. This patch makes it so the value is checked before any indexing is done. * In res_calendar_ews, sizeof was being passed a pointer instead of the struct to determine the amount of memory to allocate. (issue ASTERISK-19651) Reported by: Matt Jordan (closes issue ASTERISK-19671) Reported by: Matt Jordan ........ Merged revisions 366740 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366792 | jrose | 2012-05-17 09:41:13 -0500 (Thu, 17 May 2012) | 10 lines chan_sip: Fix missed locking of opposing pvt for directmedia acl from r366547 It also required deadlock avoidance since two sip_pvts structs needed to be locked simultaneously. Trunk handles it differently, so this is a 1.8 and 10 patch only. ........ (issue AST-876) Merged revisions 366791 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366881 | mjordan | 2012-05-18 09:01:56 -0500 (Fri, 18 May 2012) | 65 lines Fix a variety of memory leaks This patch addresses a number of memory leaks in a variety of modules that were found by a static analysis tool. A brief summary of the changes: * app_minivm: free ast_str objects on off nominal paths * app_page: free the ast_dial object if the requested channel technology cannot be appended to the dialing structure * app_queue: if a penalty rule failed to match any existing rule list names, the created rule would not be inserted and its memory would be leaked * app_read: dispose of the created silence detector in the presence of off nominal circumstances * app_voicemail: dispose of an allocated unique ID field for MWI event un-subscribe requests in off nominal paths; dispose of configuration objects when using the secret.conf option * chan_dahdi: dispose of the allocated frame produced by ast_dsp_process * chan_iax2: properly unref peer in CLI command "iax2 unregister" * chan_sip: dispose of the allocated frame produced by sip_rtp_read's call of ast_dsp_process; free memory in parse unit tests * func_dialgroup: properly deref ao2 object grhead in nominal path of dialgroup_read * func_odbc: free resultset in off nominal paths of odbc_read * cli: free match_list in off nominal paths of CLI match completion * config: free comment_buffer/list_buffer when configuration file load is unchanged; free the same buffers any time they were created and config files were processed * data: free XML nodes in various places * enum: free context buffer in off nominal paths * features: free ast_call_feature in off nominal paths of applicationmap config processing * netsock2: users of ast_sockaddr_resolve pass in an ast_sockaddr struct that is allocated by the method. Failures in ast_sockaddr_resolve could result in the users of the method not knowing whether or not the buffer was allocated. The method will now not allocate the ast_sockaddr struct if it will return failure. * pbx: cleanup hash table traversals in off nominal paths; free ignore pattern buffer if it already exists for the specified context * xmldoc: cleanup various nodes when we no longer need them * main/editline: various cleanup of pointers not being freed before being assigned to other memory, cleanup along off nominal paths * menuselect/mxml: cleanup of value buffer for an attribute when that attribute did not specify a value * res_calendar*: responses are allocated via the various *_request method returns and should not be allocated in the various write_event methods; ensure attendee buffer is freed if no data exists in the parsed node; ensure that calendar objects are de-ref'd appropriately * res_jabber: free buffer in off nominal path * res_musiconhold: close the DIR* object in off nominal paths * res_rtp_asterisk: if we run out of ports, close the rtp socket object and free the rtp object * res_srtp: if we fail to create the session in libsrtp, destroy the temporary ast_srtp object (issue ASTERISK-19665) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/1922 ........ Merged revisions 366880 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366884 | kmoore | 2012-05-18 09:18:47 -0500 (Fri, 18 May 2012) | 9 lines Reorder and renumber tests appropriately It appears that a patch did not apply properly when adding tests 12 and 13 and test 11 was duplicated. These tests have been reordered and renumbered such that they make sense. ........ Merged revisions 366882 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r366948 | mjordan | 2012-05-18 10:45:42 -0500 (Fri, 18 May 2012) | 20 lines Fix more memory leaks This patch adds to what was fixed in r366880. Specifically, it addresses the following: * chan_sip: dispose of an allocated frame in off nominal code paths in sip_rtp_read * func_odbc: when disposing of an allocated resultset, ensure that any rows that were appended to that resultset are also disposed of * cli: free the created return string buffer in another off nominal code path (issue ASTERISK-19665) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/1922/ ........ Merged revisions 366944 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367003 | mmichelson | 2012-05-18 12:00:14 -0500 (Fri, 18 May 2012) | 19 lines Fix memory leak of SSL_CTX structures in TLS core. SSL_CTX structures were allocated but never freed. This was a bigger issue for clients than servers since new SSL_CTX structures could be allocated for each connection. Servers, on the other hand, typically set up a single SSL_CTX for their lifetime. This is solved in two ways: 1. In __ssl_setup(), if a tcptls_cfg has an ssl_ctx on it, it is freed so that a new one can take its place. 2. A companion to ast_ssl_setup() called ast_ssl_teardown() has been added so that servers can properly free their SSL_CTXs. (issue ASTERISK-19278) ........ Merged revisions 367002 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367028 | mmichelson | 2012-05-18 12:50:18 -0500 (Fri, 18 May 2012) | 18 lines Address MISSING_BREAK static analysis reports some more. This addresses core findings 4 and 6. Moises Silva helped me by stating that a break could be safely added to the case where it is added in chan_dahdi.c In say.c, I have added a comment indicating that static analysis complains but that it is currently unknown if this is correct. This fixes all core findings of this type. (closes issue ASTERISK-19662) reported by Matthew Jordan ........ Merged revisions 367027 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367267 | twilson | 2012-05-22 11:17:46 -0500 (Tue, 22 May 2012) | 14 lines Resolve crash in subscribing for MWI notifications ASTOBJ_UNREF sets the variable to NULL after unreffing it, so the variable should definitely not be used after that. To solve this in the two cases that affect subscribing for MWI notifications, we instead save the ref locally, and unref them in the error conditions. (closes issue ASTERISK-19827) Reported by: B. R Review: https://reviewboard.asterisk.org/r/1940/ ........ Merged revisions 367266 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367299 | twilson | 2012-05-22 12:21:51 -0500 (Tue, 22 May 2012) | 21 lines Fix race condition for CEL LINKEDID_END event This patch fixes to situations that could cause the CEL LINKEDID_END event to be missed. 1) During a core stop gracefully, modules are unloaded when ast_active_channels == 0. The LINKDEDID_END event fires during the channel destructor. This means that occasionally, the cel_* module will be unloaded before the channel is destroyed. It seemed generally useful to wait until the refcount of all channels == 0 before unloading, so I added a channel counter and used it in the shutdown code. 2) During a masquerade, ast_channel_change_linkedid is called. It calls ast_cel_check_retire_linkedid which unrefs the linkedid in the linkedids container in cel.c. It didn't ref the new linkedid. Now it does. Review: https://reviewboard.asterisk.org/r/1900/ ........ Merged revisions 367292 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367369 | mjordan | 2012-05-23 08:25:04 -0500 (Wed, 23 May 2012) | 26 lines Re-add LastMsgsSent value for SIP peers Previously, MWI logic utilized a counter called 'lastmsgssent' to know whether or not MWI NOTIFY requests had been sent to a specific peer. When MWI notifications were changed to use the internal event framework, this value was no longer needed for its original purpose. Hence, it was no longer updated with the new/old message counts for a peer. The value was previously removed for Asterisk 10; however, since it was still present in Asterisk 1.8 and still useful for reporting purposes, it was decided to re-add the value. This patch re-adds the 'LastMsgsSent' field in the response to an AMI/CLI 'sip show peer [peer]' command, and makes it so that the value of lastmsgssent is updated appropriately. The value should now display the new/old message counts for a particular peer. (closes issue ASTERISK-17866) Reported by: Steve Davies patches by: ast-17866-rb1272.patch (License #5041 by irroot) Modified slightly for this commit Review: https://reviewboard.asterisk.org/r/1939 ........ Merged revisions 367362 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367417 | mmichelson | 2012-05-23 15:29:03 -0500 (Wed, 23 May 2012) | 7 lines Only call SSL_CTX_free if DO_SSL is defined. Thanks to Paul Belanger for pointing out this error. ........ Merged revisions 367416 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367470 | rmudgett | 2012-05-23 18:16:49 -0500 (Wed, 23 May 2012) | 9 lines Fix WaitExten(x,m(musicclass)) string termination. The AST_CONTROL_HOLD MOH class from the WaitExten application can now be queued onto a channel, passed over local channels with the /m option, and passed over IAX channels. ........ Merged revisions 367469 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367562 | mjordan | 2012-05-24 08:32:33 -0500 (Thu, 24 May 2012) | 24 lines Fix crash in ConfBridge when user announcement is played for more than 2 users A patch introduced in r354938 made it so that ConfBridge would not attempt to play sound files if those files did not exist. Unfortunately, ConfBridge uses the same underlying function, play_sound_helper, to playback both sound files and numbers to callers. When a number is being played back, the name of the sound file is expected to be NULL. This NULL value was passed into a function that tested for the existance of a sound file and is not tolerant to NULL file names, causing a crash. This patch fixes the behavior, such that if a sound file does not exist we do not attempt to play it, but we only attempt that check if the a sound file was specified in the first place. If a sound file was not specified, we use the 'play number' logic in the helper function. (closes issue ASTERISK-19899) Reported by: Florian Gilcher Tested by: Florian Gilcher patches: asterisk-19899.diff uploaded by mjordan (license 6283) ........ r367679 | rmudgett | 2012-05-24 17:29:23 -0500 (Thu, 24 May 2012) | 34 lines Fix Dial I option ignored if dial forked and one fork redirects. The Dial and Queue I option is intended to block connected line updates and redirecting updates. However, it is a feature that when a call is locally redirected, the I option is disabled if the redirected call runs as a local channel so the administrator can have an opportunity to setup new connected line information. Unfortunately, the Dial and Queue I option is disabled for *all* forked calls if one of those calls is redirected. * Make the Dial and Queue I option apply to each outgoing call leg independently. Now if one outgoing call leg is locally redirected, the other outgoing calls are not affected. * Made Dial not pass any redirecting updates when forking calls. Redirecting updates do not make sense for this scenario. * Made Queue not pass any redirecting updates when using the ringall strategy. Redirecting updates do not make sense for this scenario. * Fixed deadlock potential with chan_local when Dial and Queue send redirecting updates for a local redirect. * Converted the Queue stillgoing flag to a boolean bitfield. (closes issue ASTERISK-19511) Reported by: rmudgett Tested by: rmudgett Review: https://reviewboard.asterisk.org/r/1920/ ........ Merged revisions 367678 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367731 | elguero | 2012-05-24 21:29:26 -0500 (Thu, 24 May 2012) | 20 lines Fix pvt_sip for inbound call to use peer's allowtransfer setting The pvt_sip allowtransfer was not being set to that of the peer's setting. Therefore, the global allowtransfer setting was being used instead which would lead to calls not being transfered if the global setting was set to 'no' despite the setting on the peer being 'yes' and vice versa, calls would be allowed to transfer even if the peer's setting was 'no' but the global setting was 'yes'. (Closes issue ASTERISK-19856) Reported by: Jacek Tested by: Michael L. Young, Jacek Patches: issue-asterisk-19856-branch10-v3.diff uploaded by Michael L. Young (license 5026) Review: https://reviewboard.asterisk.org/r/1923/ ........ Merged revisions 367730 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367782 | rmudgett | 2012-05-25 11:30:55 -0500 (Fri, 25 May 2012) | 18 lines AST-2012-007: Fix IAX receiving HOLD without suggested MOH class crash. * Made schedule_delivery() set the received frame f->data.ptr to NULL if the datalen is zero. * Fix queue_signalling() memcpy() size error. * Made queue_signalling() not use C++ keyword variable names. (closes issue ASTERISK-19597) Reported by: mgrobecker Patches: jira_asterisk_19597_v1.8.patch (license #5621) patch uploaded by rmudgett Tested by: rmudgett, Michael L. Young ........ Merged revisions 367781 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367844 | mjordan | 2012-05-29 13:33:20 -0500 (Tue, 29 May 2012) | 21 lines AST-2012-008: Fix remote crash vulnerability in chan_skinny When a skinny session is unregistered, the corresponding device pointer is set to NULL in the channel private data. If the client was not in the on-hook state at the time the connection was closed, the device pointer can later be dereferened if a message or channel event attempts to use a line's pointer to said device. The patches prevent this from occurring by checking the line's pointer in message handlers and channel callbacks that can fire after an unregistration attempt. (closes issue ASTERISK-19905) Reported by: Christoph Hebeisen Tested by: mjordan, Damien Wedhorn Patches: AST-2012-008-1.8.diff uploaded by mjordan (license 6283) AST-2012-008-10.diff uploaded by mjordan (licesen 6283) ........ r367907 | rmudgett | 2012-05-29 17:28:55 -0500 (Tue, 29 May 2012) | 17 lines Coverity Report: Fix issues for error type REVERSE_INULL (deprecated modules) * Fix only issue pointed out by deprecated_REVERSE_INULL.txt for app_meetme.c in find_user(). * Change use of %i to %d in sscanf() in find_user(). The use of %i gives unexpected parsing because it can accept hex, octal, and decimal integer formats. * Changed other uses of %i in app_meetme() to use %d for consistency. (issue ASTERISK-19648) Reported by: Matt Jordan ........ Merged revisions 367906 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367978 | rmudgett | 2012-05-30 12:39:24 -0500 (Wed, 30 May 2012) | 19 lines Fix deadlock when executing CLI "pri show channels" and "ss7 show channels" commands. * Fix sig_pri_lock_owner() to avoid deadlock properly. * Code pri_grab() better. * Fix sig_ss7_lock_owner() to avoid deadlock properly. * Code ss7_grab() better. (closes issue ASTERISK-19854) Reported by: Jaxon Patches: jira_asterisk_19854_v1.8.6.patch (license #5621) patch uploaded by rmudgett (Modified to do the same thing to sig_ss7) Tested by: Jaxon ........ Merged revisions 367976 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r367981 | rmudgett | 2012-05-30 13:07:28 -0500 (Wed, 30 May 2012) | 7 lines Use the DEADLOCK_AVOIDANCE() macro instead. (issue ASTERISK-19854) ........ Merged revisions 367980 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368042 | rmudgett | 2012-05-31 13:20:15 -0500 (Thu, 31 May 2012) | 10 lines Coverity Report: Fix issues for error type REVERSE_INULL (core modules) * Fixes findings: 0-2,5,7-15,24-26,28-31 (issue ASTERISK-19648) Reported by: Matt Jordan ........ Merged revisions 368039 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368093 | elguero | 2012-05-31 22:28:09 -0500 (Thu, 31 May 2012) | 17 lines Add documentation to function CHANNEL for options echocan_mode and buffers The ability to set "echocan_mode" and "buffers" through the dialplan was added to chan_dahdi some time ago. This patch adds some documentation to func_channel. (Closes issue ASTERISK-19911) Reported by: Dale Noll Tested by: Michael L. Young Patches: asterisk-19911-branch18.diff uploaded by Michael L. Young (license 5026) Review: https://reviewboard.asterisk.org/r/1949/ ........ Merged revisions 368092 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368267 | kpfleming | 2012-06-01 15:22:44 -0500 (Fri, 01 Jun 2012) | 20 lines Improve SDP parsing warning messages * 'Unsupported media type' is only reported when that is in fact the case, not when a supported media type is included in an 'm' line that has an invalid format. * All warning messages related to parsing 'm' lines now include the 'm' line contents. * (minor bugfix) newline added to port-number-zero warning messages. * Warning messages improved to use RFC-specified terminology for various items. * Warnings for offers that include more than one port for a single media type now include the media type. Review: https://reviewboard.asterisk.org/r/1811/ ........ Merged revisions 368218 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368310 | rmudgett | 2012-06-01 18:24:25 -0500 (Fri, 01 Jun 2012) | 15 lines Fix deadlock when Gosub used with alternate dialplan switches. Attempting to remove a channel from autoservice with the channel lock held will result in deadlock. * Restructured gosub_exec() to not call ast_parseable_goto() and ast_exists_extension() with the channel lock held. (closes issue ASTERISK-19764) Reported by: rmudgett Tested by: rmudgett ........ Merged revisions 368308 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368407 | rmudgett | 2012-06-04 14:08:52 -0500 (Mon, 04 Jun 2012) | 23 lines Fix potential deadlock between masquerade and chan_local. * Restructure ast_do_masquerade() to not hold channel locks while it calls ast_indicate(). * Simplify many calls to ast_do_masquerade() since it will never return a failure now. If it does fail internally because a channel driver callback operation failed, the only thing ast_do_masquerade() can do is generate a warning message about strange things may happen and press on. * Fixed the call to ast_bridged_channel() in ast_do_masquerade(). This change fixes half of the deadlock reported in ASTERISK-19801 between masquerades and chan_iax. (closes issue ASTERISK-19537) Reported by: rmudgett Tested by: rmudgett Review: https://reviewboard.asterisk.org/r/1915/ ........ Merged revisions 368405 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368470 | rmudgett | 2012-06-04 16:11:42 -0500 (Mon, 04 Jun 2012) | 10 lines Document BLINDTRANSFER behavior change. (issue ASTERISK-19322) (closes issue ASTERISK-19875) Reported by: call ........ Merged revisions 368469 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368499 | mmichelson | 2012-06-04 17:02:26 -0500 (Mon, 04 Jun 2012) | 16 lines Relay proper SIP responses on calling side. Revision 351130 broke corect HANGUPCAUSE setting for the 404 case in chan_sip. Other cases were also potentially broken. This patch fixes the relaying of causes to be what they used to be. (closes issue ASTERISK-19914) Reported by Pavel Troller Tested by Walter Doekes (via a reviewboard test to be committed later) Patches: chan_sip.diff uploaded by Pavel Troller (license #6302) ........ Merged revisions 368498 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368524 | kmoore | 2012-06-05 10:19:58 -0500 (Tue, 05 Jun 2012) | 11 lines Ensure that pages and emails are sent using RFC822-compliant date format When localization was added to app_voicemail, these headers were altered when they should have remained in en_US format for RFC compliance. This reverts the changes to those two lines. (closes issue ASTERISK-19876) ........ Merged revisions 368520 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368536 | kmoore | 2012-06-05 10:27:01 -0500 (Tue, 05 Jun 2012) | 8 lines Resolve some build warnings My newly upgraded compiler caught these usages of uninitialized values. They weren't actually used. ........ Merged revisions 368533 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368568 | rmudgett | 2012-06-05 20:10:10 -0500 (Tue, 05 Jun 2012) | 15 lines Fix parked call performing a DTMF blind transfer after being retrieved. When a parked call was retrieved from the parking lot, it could not do a blind transfer because it caused the involved calls to be hung up unconditionally. * Made the ParkedCall application return the ast_bridge_call() return value. (closes issue ABE-2862) Reported by: Vlad Povorozniuc ........ Merged revisions 368567 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ r368587 | kmoore | 2012-06-06 11:09:10 -0500 (Wed, 06 Jun 2012) | 12 lines Ensure overlapping hold flags do not conflict When changing between different modes of hold, the flags were not being cleared out properly causing a failure to change hold states. (closes issue ASTERISK-19919) Patch-by: Morten Tryfoss Reported-by: Morten Tryfoss ........ Merged revisions 368586 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 365155,365160,365299,365320,365399,365475,365478,365575,365632,365701,365898,365990,366049,366053,366106,366168,366241,366297,366390,366412,366591,366598,366741,366792,366881,366884,366948,367003,367028,367267,367299,367369,367417,367470,367562,367679,367731,367782,367844,367907,367978,367981,368042,368093,368267,368310,368407,368470,368499,368524,368536,368568,368587 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/10-digiumphones@368781 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- CHANGES | 16 + UPGRADE.txt | 6 + addons/format_mp3.c | 83 +-- addons/ooh323c/src/h323/H323-MESSAGES.h | 2 +- addons/ooh323c/src/h323/H323-MESSAGESEnc.c | 44 +- addons/ooh323c/src/ooh323.c | 22 +- addons/ooh323c/src/ooq931.c | 2 +- apps/app_chanspy.c | 41 +- apps/app_confbridge.c | 8 +- apps/app_dial.c | 171 +++-- apps/app_disa.c | 7 +- apps/app_followme.c | 95 ++- apps/app_meetme.c | 65 +- apps/app_minivm.c | 10 +- apps/app_page.c | 6 + apps/app_queue.c | 191 ++++-- apps/app_record.c | 8 +- apps/app_stack.c | 158 +++-- apps/app_voicemail.c | 86 ++- channels/chan_agent.c | 18 +- channels/chan_dahdi.c | 22 +- channels/chan_iax2.c | 96 ++- channels/chan_local.c | 219 +++--- channels/chan_sip.c | 758 +++++++++++++-------- channels/chan_skinny.c | 29 +- channels/iax2-parser.c | 2 +- channels/iax2-provision.c | 6 +- channels/sig_analog.c | 5 +- channels/sig_pri.c | 36 +- channels/sig_ss7.c | 34 +- channels/sip/config_parser.c | 91 +-- channels/sip/include/sip.h | 1 + channels/sip/reqresp_parser.c | 163 +---- codecs/codec_dahdi.c | 33 +- funcs/func_aes.c | 4 + funcs/func_cdr.c | 2 +- funcs/func_channel.c | 20 + funcs/func_devstate.c | 1 + funcs/func_dialgroup.c | 1 + funcs/func_lock.c | 46 +- funcs/func_math.c | 4 +- funcs/func_odbc.c | 12 +- funcs/func_speex.c | 14 +- include/asterisk/cel.h | 9 + include/asterisk/channel.h | 5 +- include/asterisk/tcptls.h | 17 + main/acl.c | 6 +- main/app.c | 13 +- main/asterisk.c | 13 +- main/cdr.c | 9 +- main/cel.c | 43 +- main/channel.c | 373 +++++----- main/cli.c | 10 +- main/config.c | 18 +- main/data.c | 24 +- main/devicestate.c | 2 - main/editline/readline.c | 8 +- main/editline/term.c | 16 +- main/editline/tokenizer.c | 9 +- main/enum.c | 3 + main/event.c | 3 +- main/features.c | 350 +++++----- main/manager.c | 22 +- main/netsock2.c | 4 + main/pbx.c | 42 +- main/say.c | 3 + main/tcptls.c | 40 +- main/xmldoc.c | 40 +- pbx/dundi-parser.c | 22 +- pbx/pbx_config.c | 18 +- pbx/pbx_dundi.c | 2 +- res/ael/ael.flex | 8 +- res/ael/pval.c | 21 +- res/res_calendar.c | 14 +- res/res_calendar_caldav.c | 13 +- res/res_calendar_ews.c | 2 +- res/res_calendar_exchange.c | 5 +- res/res_calendar_icalendar.c | 9 +- res/res_config_odbc.c | 8 +- res/res_jabber.c | 1 + res/res_monitor.c | 4 +- res/res_musiconhold.c | 2 + res/res_odbc.c | 4 + res/res_rtp_asterisk.c | 8 +- res/res_srtp.c | 4 +- tests/test_config.c | 9 +- 86 files changed, 2338 insertions(+), 1536 deletions(-) diff --git a/CHANGES b/CHANGES index e66e02035f..de188581ac 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,22 @@ === ============================================================================== +------------------------------------------------------------------------------ +--- Functionality changes since Asterisk 10.5.0 ------------------------------ +------------------------------------------------------------------------------ + +SIP Changes +------------- + * In previous versions of Asterisk, a SIP peer's LastMsgsSent value was + presented as part of the response to an AMI or CLI 'sip show peer [peer]'. + This was removed in Asterisk 10 as the variable was no longer used for its + original internal purpose of determining whether or not MWI notifications had + been sent to a peer; however, it was determined that the value is still + useful for reporting purposes. + + The LastMsgsSent value has been re-added with the same functionality as in + previous versions of Asterisk. + ------------------------------------------------------------------------------ --- Functionality changes since Asterisk 10.3.0 ------------------------------ ------------------------------------------------------------------------------ diff --git a/UPGRADE.txt b/UPGRADE.txt index 565a0dd808..ec4c072345 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -31,6 +31,12 @@ From 10.3 to 10.4: From 10.2 to 10.3: +* The BLINDTRANSFER channel variable is deleted from a channel when it is + bridged to prevent subtle bugs in the parking feature. The channel + variable is used by Asterisk internally for the Park application to work + properly. If you were using it for your own purposes, copy it to your + own channel variable before the channel is bridged. + * If no transport is specified in sip.conf, transport will default to UDP. Also, if multiple transport= lines are used, only the last will be used. diff --git a/addons/format_mp3.c b/addons/format_mp3.c index 5584f3e061..78fcc28c53 100644 --- a/addons/format_mp3.c +++ b/addons/format_mp3.c @@ -9,7 +9,7 @@ * Thanks to mpglib from http://www.mpg123.org/ * and Chris Stenton [jacs@gnome.co.uk] * for coding the ability to play stereo and non-8khz files - + * 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; @@ -48,20 +48,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define MP3_DCACHE 8192 struct mp3_private { - char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */ - char empty; /* Empty character */ - int lasttimeout; - int maxlen; - struct timeval last; + /*! state for the mp3 decoder */ struct mpstr mp; + /*! buffer to hold mp3 data after read from disk */ char sbuf[MP3_SCACHE]; + /*! buffer for slinear audio after being decoded out of sbuf */ char dbuf[MP3_DCACHE]; + /*! how much data has been written to the output buffer in the ast_filestream */ int buflen; + /*! how much data has been written to sbuf */ int sbuflen; + /*! how much data is left to be read out of dbuf, starting at dbufoffset */ int dbuflen; + /*! current offset for reading data out of dbuf */ int dbufoffset; - int sbufoffset; - int lastseek; int offset; long seek; }; @@ -107,17 +107,17 @@ static int mp3_open(struct ast_filestream *s) static void mp3_close(struct ast_filestream *s) { struct mp3_private *p = s->_private; - + ExitMP3(&p->mp); return; } -static int mp3_squeue(struct ast_filestream *s) +static int mp3_squeue(struct ast_filestream *s) { struct mp3_private *p = s->_private; int res=0; - - p->lastseek = ftell(s->f); + + res = ftell(s->f); p->sbuflen = fread(p->sbuf, 1, MP3_SCACHE, s->f); if(p->sbuflen < 0) { ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", p->sbuflen, strerror(errno)); @@ -131,11 +131,11 @@ static int mp3_squeue(struct ast_filestream *s) return 0; } -static int mp3_dqueue(struct ast_filestream *s) +static int mp3_dqueue(struct ast_filestream *s) { struct mp3_private *p = s->_private; int res=0; - + if((res = decodeMP3(&p->mp,NULL,0,p->dbuf,MP3_DCACHE,&p->dbuflen)) == MP3_OK) { p->sbuflen -= p->dbuflen; p->dbufoffset = 0; @@ -147,7 +147,7 @@ static int mp3_queue(struct ast_filestream *s) { struct mp3_private *p = s->_private; int res = 0, bytes = 0; - + if(p->seek) { ExitMP3(&p->mp); InitMP3(&p->mp, OUTSCALE); @@ -167,7 +167,7 @@ static int mp3_queue(struct ast_filestream *s) if(res == MP3_ERR) return -1; } - + p->seek = 0; return 0; } @@ -181,7 +181,7 @@ static int mp3_queue(struct ast_filestream *s) if(mp3_squeue(s)) return -1; } - + } return 0; @@ -194,36 +194,41 @@ static struct ast_frame *mp3_read(struct ast_filestream *s, int *whennext) int delay =0; int save=0; - /* Send a frame from the file to the appropriate channel */ - - if(mp3_queue(s)) + /* Pre-populate the buffer that holds audio to be returned (dbuf) */ + if (mp3_queue(s)) { return NULL; + } - if(p->dbuflen) { - for(p->buflen=0; p->buflen < MP3_BUFLEN && p->buflen < p->dbuflen; p->buflen++) { - s->buf[p->buflen + AST_FRIENDLY_OFFSET] = p->dbuf[p->buflen+p->dbufoffset]; - p->sbufoffset++; + if (p->dbuflen) { + /* Read out what's waiting in dbuf */ + for (p->buflen = 0; p->buflen < MP3_BUFLEN && p->buflen < p->dbuflen; p->buflen++) { + s->buf[p->buflen + AST_FRIENDLY_OFFSET] = p->dbuf[p->buflen + p->dbufoffset]; } p->dbufoffset += p->buflen; p->dbuflen -= p->buflen; + } + + if (p->buflen < MP3_BUFLEN) { + /* dbuf didn't have enough, so reset dbuf, fill it back up and continue */ + p->dbuflen = p->dbufoffset = 0; - if(p->buflen < MP3_BUFLEN) { - if(mp3_queue(s)) - return NULL; + if (mp3_queue(s)) { + return NULL; + } - for(save = p->buflen; p->buflen < MP3_BUFLEN; p->buflen++) { - s->buf[p->buflen + AST_FRIENDLY_OFFSET] = p->dbuf[(p->buflen-save)+p->dbufoffset]; - p->sbufoffset++; + /* Make sure dbuf has enough to complete this read attempt */ + if (p->dbuflen >= (MP3_BUFLEN - p->buflen)) { + for (save = p->buflen; p->buflen < MP3_BUFLEN; p->buflen++) { + s->buf[p->buflen + AST_FRIENDLY_OFFSET] = p->dbuf[(p->buflen - save) + p->dbufoffset]; } p->dbufoffset += (MP3_BUFLEN - save); p->dbuflen -= (MP3_BUFLEN - save); - - } + } } - + p->offset += p->buflen; - delay = p->buflen/2; + delay = p->buflen / 2; s->fr.frametype = AST_FRAME_VOICE; ast_format_set(&s->fr.subclass.format, AST_FORMAT_SLINEAR, 0); AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, p->buflen); @@ -266,16 +271,16 @@ static int mp3_seek(struct ast_filestream *s, off_t sample_offset, int whence) p->seek = offset; return fseek(s->f, offset, SEEK_SET); - + } -static int mp3_rewrite(struct ast_filestream *s, const char *comment) +static int mp3_rewrite(struct ast_filestream *s, const char *comment) { ast_log(LOG_ERROR,"I Can't write MP3 only read them.\n"); return -1; } -static int mp3_trunc(struct ast_filestream *s) +static int mp3_trunc(struct ast_filestream *s) { ast_log(LOG_ERROR,"I Can't write MP3 only read them.\n"); @@ -285,7 +290,7 @@ static int mp3_trunc(struct ast_filestream *s) static off_t mp3_tell(struct ast_filestream *s) { struct mp3_private *p = s->_private; - + return p->offset/2; } @@ -321,6 +326,6 @@ static int load_module(void) static int unload_module(void) { return ast_format_def_unregister(name); -} +} AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "MP3 format [Any rate but 8000hz mono is optimal]"); diff --git a/addons/ooh323c/src/h323/H323-MESSAGES.h b/addons/ooh323c/src/h323/H323-MESSAGES.h index fbd87b3368..733b58f862 100644 --- a/addons/ooh323c/src/h323/H323-MESSAGES.h +++ b/addons/ooh323c/src/h323/H323-MESSAGES.h @@ -169,7 +169,7 @@ EXTERN int asn1PD_H225EndpointIdentifier (OOCTXT* pctxt, H225EndpointIdentifier* typedef ASN1OBJID H225ProtocolIdentifier; -EXTERN int asn1PE_H225ProtocolIdentifier (OOCTXT* pctxt, H225ProtocolIdentifier value); +EXTERN int asn1PE_H225ProtocolIdentifier (OOCTXT* pctxt, H225ProtocolIdentifier* value); EXTERN int asn1PD_H225ProtocolIdentifier (OOCTXT* pctxt, H225ProtocolIdentifier* pvalue); diff --git a/addons/ooh323c/src/h323/H323-MESSAGESEnc.c b/addons/ooh323c/src/h323/H323-MESSAGESEnc.c index 62a2cd0068..f818fb20c9 100644 --- a/addons/ooh323c/src/h323/H323-MESSAGESEnc.c +++ b/addons/ooh323c/src/h323/H323-MESSAGESEnc.c @@ -223,11 +223,11 @@ EXTERN int asn1PE_H225EndpointIdentifier (OOCTXT* pctxt, H225EndpointIdentifier /* */ /**************************************************************/ -EXTERN int asn1PE_H225ProtocolIdentifier (OOCTXT* pctxt, H225ProtocolIdentifier value) +EXTERN int asn1PE_H225ProtocolIdentifier (OOCTXT* pctxt, H225ProtocolIdentifier* value) { int stat = ASN_OK; - stat = encodeObjectIdentifier (pctxt, &value); + stat = encodeObjectIdentifier (pctxt, value); if (stat != ASN_OK) return stat; return (stat); @@ -6371,7 +6371,7 @@ EXTERN int asn1PE_H225Setup_UUIE (OOCTXT* pctxt, H225Setup_UUIE* pvalue) /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode h245Address */ @@ -7112,7 +7112,7 @@ EXTERN int asn1PE_H225CallProceeding_UUIE (OOCTXT* pctxt, H225CallProceeding_UUI /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode destinationInfo */ @@ -7414,7 +7414,7 @@ EXTERN int asn1PE_H225Connect_UUIE (OOCTXT* pctxt, H225Connect_UUIE* pvalue) /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode h245Address */ @@ -7811,7 +7811,7 @@ EXTERN int asn1PE_H225Alerting_UUIE (OOCTXT* pctxt, H225Alerting_UUIE* pvalue) /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode destinationInfo */ @@ -8173,7 +8173,7 @@ EXTERN int asn1PE_H225Information_UUIE (OOCTXT* pctxt, H225Information_UUIE* pva /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; if (extbit) { @@ -8672,7 +8672,7 @@ EXTERN int asn1PE_H225ReleaseComplete_UUIE (OOCTXT* pctxt, H225ReleaseComplete_U /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode reason */ @@ -9157,7 +9157,7 @@ EXTERN int asn1PE_H225Facility_UUIE (OOCTXT* pctxt, H225Facility_UUIE* pvalue) /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode alternativeAddress */ @@ -9580,7 +9580,7 @@ EXTERN int asn1PE_H225Progress_UUIE (OOCTXT* pctxt, H225Progress_UUIE* pvalue) /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode destinationInfo */ @@ -9726,7 +9726,7 @@ EXTERN int asn1PE_H225Status_UUIE (OOCTXT* pctxt, H225Status_UUIE* pvalue) /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode callIdentifier */ @@ -9774,7 +9774,7 @@ EXTERN int asn1PE_H225StatusInquiry_UUIE (OOCTXT* pctxt, H225StatusInquiry_UUIE* /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode callIdentifier */ @@ -9822,7 +9822,7 @@ EXTERN int asn1PE_H225SetupAcknowledge_UUIE (OOCTXT* pctxt, H225SetupAcknowledge /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode callIdentifier */ @@ -9870,7 +9870,7 @@ EXTERN int asn1PE_H225Notify_UUIE (OOCTXT* pctxt, H225Notify_UUIE* pvalue) /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode callIdentifier */ @@ -12236,7 +12236,7 @@ EXTERN int asn1PE_H225GatekeeperRequest (OOCTXT* pctxt, H225GatekeeperRequest* p /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode nonStandardData */ @@ -12530,7 +12530,7 @@ EXTERN int asn1PE_H225GatekeeperConfirm (OOCTXT* pctxt, H225GatekeeperConfirm* p /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode nonStandardData */ @@ -12892,7 +12892,7 @@ EXTERN int asn1PE_H225GatekeeperReject (OOCTXT* pctxt, H225GatekeeperReject* pva /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode nonStandardData */ @@ -13168,7 +13168,7 @@ EXTERN int asn1PE_H225RegistrationRequest (OOCTXT* pctxt, H225RegistrationReques /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode nonStandardData */ @@ -13913,7 +13913,7 @@ EXTERN int asn1PE_H225RegistrationConfirm (OOCTXT* pctxt, H225RegistrationConfir /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode nonStandardData */ @@ -14551,7 +14551,7 @@ EXTERN int asn1PE_H225RegistrationReject (OOCTXT* pctxt, H225RegistrationReject* /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode nonStandardData */ @@ -21566,7 +21566,7 @@ EXTERN int asn1PE_H225ResourcesAvailableIndicate (OOCTXT* pctxt, H225ResourcesAv /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode nonStandardData */ @@ -21702,7 +21702,7 @@ EXTERN int asn1PE_H225ResourcesAvailableConfirm (OOCTXT* pctxt, H225ResourcesAva /* encode protocolIdentifier */ - stat = asn1PE_H225ProtocolIdentifier (pctxt, pvalue->protocolIdentifier); + stat = asn1PE_H225ProtocolIdentifier (pctxt, &pvalue->protocolIdentifier); if (stat != ASN_OK) return stat; /* encode nonStandardData */ diff --git a/addons/ooh323c/src/ooh323.c b/addons/ooh323c/src/ooh323.c index 2b8dcf1397..cdf187dad6 100644 --- a/addons/ooh323c/src/ooh323.c +++ b/addons/ooh323c/src/ooh323.c @@ -40,7 +40,7 @@ int ooOnReceivedCallProceeding(OOH323CallData *call, Q931Message *q931Msg); int ooOnReceivedAlerting(OOH323CallData *call, Q931Message *q931Msg); int ooOnReceivedProgress(OOH323CallData *call, Q931Message *q931Msg); int ooHandleDisplayIE(OOH323CallData *call, Q931Message *q931Msg); -int ooHandleH2250ID (OOH323CallData *call, H225ProtocolIdentifier protocolIdentifier); +int ooHandleH2250ID (OOH323CallData *call, H225ProtocolIdentifier* protocolIdentifier); int ooHandleDisplayIE(OOH323CallData *call, Q931Message *q931Msg) { Q931InformationElement* pDisplayIE; @@ -58,10 +58,10 @@ int ooHandleDisplayIE(OOH323CallData *call, Q931Message *q931Msg) { return OO_OK; } -int ooHandleH2250ID (OOH323CallData *call, H225ProtocolIdentifier protocolIdentifier) { - if (!call->h225version && (protocolIdentifier.numids >= 6) && - (protocolIdentifier.subid[3] == 2250)) { - call->h225version = protocolIdentifier.subid[5]; +int ooHandleH2250ID (OOH323CallData *call, H225ProtocolIdentifier* protocolIdentifier) { + if (!call->h225version && (protocolIdentifier->numids >= 6) && + (protocolIdentifier->subid[3] == 2250)) { + call->h225version = protocolIdentifier->subid[5]; OOTRACEDBGC4("Extract H.225 remote version, it's %d, (%s, %s)\n", call->h225version, call->callType, call->callToken); @@ -388,7 +388,7 @@ int ooOnReceivedSetup(OOH323CallData *call, Q931Message *q931Msg) "%s\n", call->callType, call->callToken); return OO_FAILED; } - ooHandleH2250ID(call, setup->protocolIdentifier); + ooHandleH2250ID(call, &setup->protocolIdentifier); memcpy(call->callIdentifier.guid.data, setup->callIdentifier.guid.data, setup->callIdentifier.guid.numocts); call->callIdentifier.guid.numocts = setup->callIdentifier.guid.numocts; @@ -644,7 +644,7 @@ int ooOnReceivedCallProceeding(OOH323CallData *call, Q931Message *q931Msg) return OO_FAILED; } - ooHandleH2250ID(call, callProceeding->protocolIdentifier); + ooHandleH2250ID(call, &callProceeding->protocolIdentifier); /* Handle fast-start */ if(OO_TESTFLAG (call->flags, OO_M_FASTSTART)) { @@ -873,7 +873,7 @@ int ooOnReceivedAlerting(OOH323CallData *call, Q931Message *q931Msg) } return OO_FAILED; } - ooHandleH2250ID(call, alerting->protocolIdentifier); + ooHandleH2250ID(call, &alerting->protocolIdentifier); /*Handle fast-start */ if(OO_TESTFLAG (call->flags, OO_M_FASTSTART) && !OO_TESTFLAG(call->flags, OO_M_FASTSTARTANSWERED)) @@ -1110,7 +1110,7 @@ int ooOnReceivedProgress(OOH323CallData *call, Q931Message *q931Msg) } return OO_FAILED; } - ooHandleH2250ID(call, progress->protocolIdentifier); + ooHandleH2250ID(call, &progress->protocolIdentifier); /*Handle fast-start */ if(OO_TESTFLAG (call->flags, OO_M_FASTSTART) && !OO_TESTFLAG(call->flags, OO_M_FASTSTARTANSWERED)) @@ -1354,7 +1354,7 @@ int ooOnReceivedSignalConnect(OOH323CallData* call, Q931Message *q931Msg) } return OO_FAILED; } - ooHandleH2250ID(call, connect->protocolIdentifier); + ooHandleH2250ID(call, &connect->protocolIdentifier); /*Handle fast-start */ if(OO_TESTFLAG (call->flags, OO_M_FASTSTART) && !OO_TESTFLAG (call->flags, OO_M_FASTSTARTANSWERED)) @@ -1853,7 +1853,7 @@ int ooOnReceivedFacility(OOH323CallData *call, Q931Message * pQ931Msg) facility = pH323UUPdu->h323_message_body.u.facility; if(facility) { - ooHandleH2250ID(call, facility->protocolIdentifier); + ooHandleH2250ID(call, &facility->protocolIdentifier); /* Depending on the reason of facility message handle the message */ if(facility->reason.t == T_H225FacilityReason_transportedInformation) { diff --git a/addons/ooh323c/src/ooq931.c b/addons/ooh323c/src/ooq931.c index ee13d7b023..202595f5dd 100644 --- a/addons/ooh323c/src/ooq931.c +++ b/addons/ooh323c/src/ooq931.c @@ -142,7 +142,7 @@ EXTERN int ooQ931Decode } else { ie = (Q931InformationElement*) memAlloc (pctxt, - sizeof(*ie) - sizeof(ie->data)); + sizeof(*ie)); if(!ie) { OOTRACEERR3("Error:Memory - ooQ931Decode - ie(%s, %s)\n", diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 95ff8a40d8..d2c86eeca1 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -768,13 +768,10 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, const char *context, const char *mailbox, const char *name_context) { char nameprefix[AST_NAME_STRLEN]; - char peer_name[AST_NAME_STRLEN + 5]; char exitcontext[AST_MAX_CONTEXT] = ""; signed char zero_volume = 0; int waitms; int res; - char *ptr; - int num; int num_spyed_upon = 1; struct ast_channel_iterator *iter = NULL; @@ -864,7 +861,6 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, next_channel(iter, autochan, chan), next_autochan = NULL) { int igrp = !mygroup; int ienf = !myenforced; - char *s; if (autochan->chan == prev) { ast_autochan_destroy(autochan); @@ -949,22 +945,34 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, continue; } - strcpy(peer_name, "spy-"); - strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1); - ptr = strchr(peer_name, '/'); - *ptr++ = '\0'; - ptr = strsep(&ptr, "-"); - - for (s = peer_name; s < ptr; s++) - *s = tolower(*s); if (!ast_test_flag(flags, OPTION_QUIET)) { + char peer_name[AST_NAME_STRLEN + 5]; + char *ptr, *s; + + strcpy(peer_name, "spy-"); + strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1); + if ((ptr = strchr(peer_name, '/'))) { + *ptr++ = '\0'; + for (s = peer_name; s < ptr; s++) { + *s = tolower(*s); + } + if ((s = strchr(ptr, '-'))) { + *s = '\0'; + } + } + if (ast_test_flag(flags, OPTION_NAME)) { const char *local_context = S_OR(name_context, "default"); const char *local_mailbox = S_OR(mailbox, ptr); - res = ast_app_sayname(chan, local_mailbox, local_context); + if (local_mailbox) { + res = ast_app_sayname(chan, local_mailbox, local_context); + } else { + res = -1; + } } if (!ast_test_flag(flags, OPTION_NAME) || res < 0) { + int num; if (!ast_test_flag(flags, OPTION_NOTECH)) { if (ast_fileexists(peer_name, NULL, NULL) > 0) { res = ast_streamfile(chan, peer_name, chan->language); @@ -979,8 +987,9 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, res = ast_say_character_str(chan, peer_name, "", chan->language); } } - if ((num = atoi(ptr))) - ast_say_digits(chan, atoi(ptr), "", chan->language); + if (ptr && (num = atoi(ptr))) { + ast_say_digits(chan, num, "", chan->language); + } } } @@ -1246,6 +1255,7 @@ static int extenspy_exec(struct ast_channel *chan, const char *data) } } else { + /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ ast_clear_flag(&flags, AST_FLAGS_ALL); } @@ -1290,6 +1300,7 @@ static int dahdiscan_exec(struct ast_channel *chan, const char *data) int res; char *mygroup = NULL; + /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ ast_clear_flag(&flags, AST_FLAGS_ALL); ast_format_clear(&oldwf); if (!ast_strlen_zero(data)) { diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index d07edf1339..22064e3d97 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1144,8 +1144,8 @@ static int play_sound_helper(struct conference_bridge *conference_bridge, const struct ast_channel *underlying_channel; /* Do not waste resources trying to play files that do not exist */ - if (!ast_fileexists(filename, NULL, NULL)) { - ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename); + if (!ast_strlen_zero(filename) && !ast_fileexists(filename, NULL, NULL)) { + ast_log(LOG_WARNING, "File %s does not exist in any format\n", !ast_strlen_zero(filename) ? filename : ""); return 0; } @@ -1165,7 +1165,7 @@ static int play_sound_helper(struct conference_bridge *conference_bridge, const /* The channel is all under our control, in goes the prompt */ if (!ast_strlen_zero(filename)) { ast_stream_and_wait(conference_bridge->playback_chan, filename, ""); - } else { + } else if (say_number >= 0) { ast_say_number(conference_bridge->playback_chan, say_number, "", conference_bridge->playback_chan->language, NULL); } @@ -1188,7 +1188,7 @@ static int play_sound_helper(struct conference_bridge *conference_bridge, const */ static int play_sound_file(struct conference_bridge *conference_bridge, const char *filename) { - return play_sound_helper(conference_bridge, filename, 0); + return play_sound_helper(conference_bridge, filename, -1); } /*! diff --git a/apps/app_dial.c b/apps/app_dial.c index 63bcbab544..e09a3c2ff3 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -823,7 +823,8 @@ static void senddialendevent(struct ast_channel *src, const char *dialstatus) * \param o Outgoing call channel list. * \param num Incoming call channel cause accumulation * \param peerflags Dial option flags - * \param single_caller_bored From wait_for_answer: single && !caller_entertained + * \param single TRUE if there is only one outgoing call. + * \param caller_entertained TRUE if the caller is being entertained by MOH or ringback. * \param to Remaining call timeout time. * \param forced_clid OPT_FORCECLID caller id to send * \param stored_clid Caller id representing the called party if needed @@ -833,8 +834,8 @@ static void senddialendevent(struct ast_channel *src, const char *dialstatus) * * \todo eventually this function should be intergrated into and replaced by ast_call_forward() */ -static void do_forward(struct chanlist *o, - struct cause_args *num, struct ast_flags64 *peerflags, int single_caller_bored, int *to, +static void do_forward(struct chanlist *o, struct cause_args *num, + struct ast_flags64 *peerflags, int single, int caller_entertained, int *to, struct ast_party_id *forced_clid, struct ast_party_id *stored_clid) { char tmpchan[256]; @@ -862,6 +863,14 @@ static void do_forward(struct chanlist *o, stuff = tmpchan; tech = "Local"; } + if (!strcasecmp(tech, "Local")) { + /* + * Drop the connected line update block for local channels since + * this is going to run dialplan and the user can change his + * mind about what connected line information he wants to send. + */ + ast_clear_flag64(o, OPT_IGNORE_CONNECTEDLINE); + } ast_cel_report_event(in, AST_CEL_FORWARD, NULL, c->call_forward, NULL); @@ -876,11 +885,14 @@ static void do_forward(struct chanlist *o, /* Setup parameters */ c = o->chan = ast_request(tech, in->nativeformats, in, stuff, &cause); if (c) { - if (single_caller_bored) { + if (single && !caller_entertained) { ast_channel_make_compatible(o->chan, in); } + ast_channel_lock_both(in, o->chan); ast_channel_inherit_variables(in, o->chan); ast_channel_datastore_inherit(in, o->chan); + ast_channel_unlock(in); + ast_channel_unlock(o->chan); /* When a call is forwarded, we don't want to track new interfaces * dialed for CC purposes. Setting the done flag will ensure that * any Dial operations that happen later won't record CC interfaces. @@ -897,17 +909,17 @@ static void do_forward(struct chanlist *o, handle_cause(cause, num); ast_hangup(original); } else { - struct ast_party_redirecting redirecting; + ast_channel_lock_both(c, original); + ast_party_redirecting_copy(&c->redirecting, &original->redirecting); + ast_channel_unlock(c); + ast_channel_unlock(original); + + ast_channel_lock_both(c, in); - if (single_caller_bored && CAN_EARLY_BRIDGE(peerflags, c, in)) { + if (single && !caller_entertained && CAN_EARLY_BRIDGE(peerflags, c, in)) { ast_rtp_instance_early_bridge_make_compatible(c, in); } - ast_channel_set_redirecting(c, &original->redirecting, NULL); - ast_channel_lock(c); - while (ast_channel_trylock(in)) { - CHANNEL_DEADLOCK_AVOIDANCE(c); - } if (!c->redirecting.from.number.valid || ast_strlen_zero(c->redirecting.from.number.str)) { /* @@ -928,6 +940,7 @@ static void do_forward(struct chanlist *o, if (ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) { caller.id = *stored_clid; ast_channel_set_caller_event(c, &caller, NULL); + ast_set_flag64(o, DIAL_CALLERID_ABSENT); } else if (ast_strlen_zero(S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) { /* @@ -936,6 +949,9 @@ static void do_forward(struct chanlist *o, */ caller.id = *stored_clid; ast_channel_set_caller_event(c, &caller, NULL); + ast_set_flag64(o, DIAL_CALLERID_ABSENT); + } else { + ast_clear_flag64(o, DIAL_CALLERID_ABSENT); } /* Determine CallerID for outgoing channel to send. */ @@ -953,22 +969,32 @@ static void do_forward(struct chanlist *o, c->appl = "AppDial"; c->data = "(Outgoing Line)"; - /* - * We must unlock c before calling ast_channel_redirecting_macro, because - * we put c into autoservice there. That is pretty much a guaranteed - * deadlock. This is why the handling of c's lock may seem a bit unusual - * here. - */ - ast_party_redirecting_init(&redirecting); - ast_party_redirecting_copy(&redirecting, &c->redirecting); - ast_channel_unlock(c); - if (ast_channel_redirecting_macro(c, in, &redirecting, 1, 0)) { - ast_channel_update_redirecting(in, &redirecting, NULL); - } - ast_party_redirecting_free(&redirecting); + ast_channel_unlock(in); + if (single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) { + struct ast_party_redirecting redirecting; + + /* + * Redirecting updates to the caller make sense only on single + * calls. + * + * We must unlock c before calling + * ast_channel_redirecting_macro, because we put c into + * autoservice there. That is pretty much a guaranteed + * deadlock. This is why the handling of c's lock may seem a + * bit unusual here. + */ + ast_party_redirecting_init(&redirecting); + ast_party_redirecting_copy(&redirecting, &c->redirecting); + ast_channel_unlock(c); + if (ast_channel_redirecting_macro(c, in, &redirecting, 1, 0)) { + ast_channel_update_redirecting(in, &redirecting, NULL); + } + ast_party_redirecting_free(&redirecting); + } else { + ast_channel_unlock(c); + } - ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE); if (ast_test_flag64(peerflags, OPT_CANCEL_TIMEOUT)) { *to = -1; } @@ -982,17 +1008,14 @@ static void do_forward(struct chanlist *o, c = o->chan = NULL; num->nochan++; } else { - ast_channel_lock(c); - while (ast_channel_trylock(in)) { - CHANNEL_DEADLOCK_AVOIDANCE(c); - } + ast_channel_lock_both(c, in); senddialevent(in, c, stuff); ast_channel_unlock(in); ast_channel_unlock(c); /* Hangup the original channel now, in case we needed it */ ast_hangup(original); } - if (single_caller_bored) { + if (single && !caller_entertained) { ast_indicate(in, -1); } } @@ -1052,7 +1075,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, } } - if (!ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE) && !ast_test_flag64(outgoing, DIAL_CALLERID_ABSENT)) { + if (!ast_test_flag64(outgoing, OPT_IGNORE_CONNECTEDLINE) + && !ast_test_flag64(outgoing, DIAL_CALLERID_ABSENT)) { ast_channel_lock(outgoing->chan); ast_connected_line_copy_from_caller(&connected_caller, &outgoing->chan->caller); ast_channel_unlock(outgoing->chan); @@ -1113,7 +1137,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) { if (!peer) { ast_verb(3, "%s answered %s\n", c->name, in->name); - if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { + if (!single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) { if (o->pending_connected_update) { if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) { ast_channel_update_connected_line(in, &o->connected, NULL); @@ -1164,8 +1188,35 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, } ast_frfree(f); } - do_forward(o, &num, peerflags, single && !caller_entertained, to, + + if (o->pending_connected_update) { + /* + * Re-seed the chanlist's connected line information with + * previously acquired connected line info from the incoming + * channel. The previously acquired connected line info could + * have been set through the CONNECTED_LINE dialplan function. + */ + o->pending_connected_update = 0; + ast_channel_lock(in); + ast_party_connected_line_copy(&o->connected, &in->connected); + ast_channel_unlock(in); + } + + do_forward(o, &num, peerflags, single, caller_entertained, to, forced_clid, stored_clid); + + if (single && o->chan + && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE) + && !ast_test_flag64(o, DIAL_CALLERID_ABSENT)) { + ast_channel_lock(o->chan); + ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); + ast_channel_unlock(o->chan); + connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; + if (ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) { + ast_channel_update_connected_line(in, &connected_caller, NULL); + } + ast_party_connected_line_free(&connected_caller); + } continue; } f = ast_read(winner); @@ -1187,7 +1238,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, /* This is our guy if someone answered. */ if (!peer) { ast_verb(3, "%s answered %s\n", c->name, in->name); - if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { + if (!single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) { if (o->pending_connected_update) { if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) { ast_channel_update_connected_line(in, &o->connected, NULL); @@ -1319,20 +1370,24 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_indicate(in, f->subclass.integer); break; case AST_CONTROL_CONNECTED_LINE: - if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { + if (ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) { ast_verb(3, "Connected line update to %s prevented.\n", in->name); - } else if (!single) { + break; + } + if (!single) { struct ast_party_connected_line connected; - ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", c->name, in->name); + + ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", + c->name, in->name); ast_party_connected_line_set_init(&connected, &o->connected); ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected); ast_party_connected_line_set(&o->connected, &connected, NULL); ast_party_connected_line_free(&connected); o->pending_connected_update = 1; - } else { - if (ast_channel_connected_line_macro(c, in, f, 1, 1)) { - ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); - } + break; + } + if (ast_channel_connected_line_macro(c, in, f, 1, 1)) { + ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); } break; case AST_CONTROL_AOC: @@ -1347,15 +1402,23 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, } break; case AST_CONTROL_REDIRECTING: - if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { + if (!single) { + /* + * Redirecting updates to the caller make sense only on single + * calls. + */ + break; + } + if (ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) { ast_verb(3, "Redirecting update to %s prevented.\n", in->name); - } else if (single) { - ast_verb(3, "%s redirecting info has changed, passing it to %s\n", c->name, in->name); - if (ast_channel_redirecting_macro(c, in, f, 1, 1)) { - ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); - } - pa->sentringing = 0; + break; } + ast_verb(3, "%s redirecting info has changed, passing it to %s\n", + c->name, in->name); + if (ast_channel_redirecting_macro(c, in, f, 1, 1)) { + ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); + } + pa->sentringing = 0; break; case AST_CONTROL_PROCEEDING: ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name); @@ -2162,9 +2225,12 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast } else if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"))) { outbound_group = ast_strdupa(outbound_group); } - ast_channel_unlock(chan); - ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_IGNORE_CONNECTEDLINE | - OPT_CANCEL_TIMEOUT | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB | OPT_FORCECLID); + ast_channel_unlock(chan); + + /* Set per dial instance flags. These flags are also passed back to RetryDial. */ + ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID + | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_CANCEL_TIMEOUT + | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB | OPT_FORCECLID); /* loop through the list of dial destinations */ rest = args.peers; @@ -2186,6 +2252,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast if (!(tmp = ast_calloc(1, sizeof(*tmp)))) goto out; if (opts.flags) { + /* Set per outgoing call leg options. */ ast_copy_flags64(tmp, &opts, OPT_CANCEL_ELSEWHERE | OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | @@ -2193,7 +2260,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | OPT_CALLER_PARK | OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | - OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID); + OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID | OPT_IGNORE_CONNECTEDLINE); ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML); } ast_copy_string(numsubst, number, sizeof(numsubst)); diff --git a/apps/app_disa.c b/apps/app_disa.c index 3ca0800096..c3aa8976c2 100644 --- a/apps/app_disa.c +++ b/apps/app_disa.c @@ -181,8 +181,13 @@ static int disa_exec(struct ast_channel *chan, const char *data) args.context = "disa"; if (ast_strlen_zero(args.mailbox)) args.mailbox = ""; - if (!ast_strlen_zero(args.options)) + if (!ast_strlen_zero(args.options)) { ast_app_parse_options(app_opts, &flags, NULL, args.options); + } else { + /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ + ast_clear_flag(&flags, AST_FLAGS_ALL); + } + ast_debug(1, "Mailbox: %s\n",args.mailbox); diff --git a/apps/app_followme.c b/apps/app_followme.c index e373355e6b..9590469061 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -118,6 +118,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static char *app = "FollowMe"; +/*! Maximum accept/decline DTMF string plus terminator. */ +#define MAX_YN_STRING 20 + /*! \brief Number structure */ struct number { char number[512]; /*!< Phone Number(s) and/or Extension(s) */ @@ -130,12 +133,12 @@ struct number { struct call_followme { ast_mutex_t lock; char name[AST_MAX_EXTENSION]; /*!< Name - FollowMeID */ - char moh[AST_MAX_CONTEXT]; /*!< Music On Hold Class to be used */ + char moh[MAX_MUSICCLASS]; /*!< Music On Hold Class to be used */ char context[AST_MAX_CONTEXT]; /*!< Context to dial from */ unsigned int active; /*!< Profile is active (1), or disabled (0). */ int realtime; /*!< Cached from realtime */ - char takecall[20]; /*!< Digit mapping to take a call */ - char nextindp[20]; /*!< Digit mapping to decline a call */ + char takecall[MAX_YN_STRING]; /*!< Digit mapping to take a call */ + char nextindp[MAX_YN_STRING]; /*!< Digit mapping to decline a call */ char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */ char norecordingprompt[PATH_MAX]; /*!< Sound prompt name and path */ char optionsprompt[PATH_MAX]; /*!< Sound prompt name and path */ @@ -161,14 +164,14 @@ struct fm_args { /*! Accumulated connected line information from outbound call. */ struct ast_party_connected_line connected_out; /*! TRUE if connected line information from inbound call changed. */ - int pending_in_connected_update:1; + unsigned int pending_in_connected_update:1; /*! TRUE if connected line information from outbound call is available. */ - int pending_out_connected_update:1; + unsigned int pending_out_connected_update:1; int status; char context[AST_MAX_CONTEXT]; - char namerecloc[AST_MAX_CONTEXT]; - char takecall[20]; /*!< Digit mapping to take a call */ - char nextindp[20]; /*!< Digit mapping to decline a call */ + char namerecloc[PATH_MAX]; + char takecall[MAX_YN_STRING]; /*!< Digit mapping to take a call */ + char nextindp[MAX_YN_STRING]; /*!< Digit mapping to decline a call */ char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */ char norecordingprompt[PATH_MAX]; /*!< Sound prompt name and path */ char optionsprompt[PATH_MAX]; /*!< Sound prompt name and path */ @@ -186,11 +189,12 @@ struct findme_user { int ynidx; int state; char dialarg[256]; - char yn[10]; + /*! Collected digits to accept/decline the call. */ + char yn[MAX_YN_STRING]; /*! TRUE if call cleared. */ - int cleared:1; + unsigned int cleared:1; /*! TRUE if connected line information is available. */ - int pending_connected_update:1; + unsigned int pending_connected_update:1; AST_LIST_ENTRY(findme_user) entry; }; @@ -214,13 +218,12 @@ AST_APP_OPTIONS(followme_opts, { AST_APP_OPTION('s', FOLLOWMEFLAG_STATUSMSG), }); -static int ynlongest = 0; - static const char *featuredigittostr; static int featuredigittimeout = 5000; /*!< Feature Digit Timeout */ static const char *defaultmoh = "default"; /*!< Default Music-On-Hold Class */ -static char takecall[20] = "1", nextindp[20] = "2"; +static char takecall[MAX_YN_STRING] = "1"; +static char nextindp[MAX_YN_STRING] = "2"; static char callfromprompt[PATH_MAX] = "followme/call-from"; static char norecordingprompt[PATH_MAX] = "followme/no-recording"; static char optionsprompt[PATH_MAX] = "followme/options"; @@ -842,21 +845,19 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us ast_stopstream(winner); tmpuser->digts = 0; ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer); - tmpuser->yn[tmpuser->ynidx] = (char) f->subclass.integer; - tmpuser->ynidx++; + if (tmpuser->ynidx < ARRAY_LEN(tmpuser->yn) - 1) { + tmpuser->yn[tmpuser->ynidx++] = (char) f->subclass.integer; + } ast_debug(1, "DTMF string: %s\n", tmpuser->yn); - if (tmpuser->ynidx >= ynlongest) { - ast_debug(1, "reached longest possible match - doing evals\n"); - if (!strcmp(tmpuser->yn, tpargs->takecall)) { - ast_debug(1, "Match to take the call!\n"); - ast_frfree(f); - return tmpuser->ochan; - } - if (!strcmp(tmpuser->yn, tpargs->nextindp)) { - ast_debug(1, "Next in dial plan step requested.\n"); - ast_frfree(f); - return NULL; - } + if (!strcmp(tmpuser->yn, tpargs->takecall)) { + ast_debug(1, "Match to take the call!\n"); + ast_frfree(f); + return tmpuser->ochan; + } + if (!strcmp(tmpuser->yn, tpargs->nextindp)) { + ast_debug(1, "Next in dial plan step requested.\n"); + ast_frfree(f); + return NULL; } } @@ -904,16 +905,11 @@ static void findmeexec(struct fm_args *tpargs) struct findme_user_listptr *findme_user_list; findme_user_list = ast_calloc(1, sizeof(*findme_user_list)); - AST_LIST_HEAD_INIT_NOLOCK(findme_user_list); - - /* We're going to figure out what the longest possible string of digits to collect is */ - ynlongest = 0; - if (strlen(tpargs->takecall) > ynlongest) { - ynlongest = strlen(tpargs->takecall); - } - if (strlen(tpargs->nextindp) > ynlongest) { - ynlongest = strlen(tpargs->nextindp); + if (!findme_user_list) { + ast_log(LOG_WARNING, "Failed to allocate memory for findme_user_list\n"); + return; } + AST_LIST_HEAD_INIT_NOLOCK(findme_user_list); caller = tpargs->chan; for (idx = 1; !ast_check_hangup(caller); ++idx) { @@ -1155,7 +1151,6 @@ static int app_exec(struct ast_channel *chan, const char *data) struct number *nm, *newnm; int res = 0; char *argstr; - char namerecloc[255]; struct ast_channel *caller; struct ast_channel *outbound; AST_DECLARE_APP_ARGS(args, @@ -1227,7 +1222,6 @@ static int app_exec(struct ast_channel *chan, const char *data) ast_clear_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER); } - namerecloc[0] = '\0'; if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) { ast_indicate(chan, AST_CONTROL_RINGING); } else { @@ -1242,14 +1236,14 @@ static int app_exec(struct ast_channel *chan, const char *data) if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) { int duration = 5; - snprintf(namerecloc, sizeof(namerecloc), "%s/followme.%s", + snprintf(targs.namerecloc, sizeof(targs.namerecloc), "%s/followme.%s", ast_config_AST_SPOOL_DIR, chan->uniqueid); - if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, + if (ast_play_and_record(chan, "vm-rec-name", targs.namerecloc, 5, "sln", &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) { goto outrun; } - if (!ast_fileexists(namerecloc, NULL, chan->language)) { - namerecloc[0] = '\0'; + if (!ast_fileexists(targs.namerecloc, NULL, chan->language)) { + targs.namerecloc[0] = '\0'; } } @@ -1264,19 +1258,11 @@ static int app_exec(struct ast_channel *chan, const char *data) targs.status = 0; targs.chan = chan; - ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc)); ast_channel_lock(chan); ast_connected_line_copy_from_caller(&targs.connected_in, &chan->caller); ast_channel_unlock(chan); findmeexec(&targs); - - while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry))) - ast_free(nm); - - if (!ast_strlen_zero(namerecloc)) - unlink(namerecloc); - if (targs.status != 100) { if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) { if (chan->_state != AST_STATE_UP) { @@ -1339,8 +1325,15 @@ static int app_exec(struct ast_channel *chan, const char *data) } outrun: + while ((nm = AST_LIST_REMOVE_HEAD(&targs.cnumbers, entry))) { + ast_free(nm); + } + if (!ast_strlen_zero(targs.namerecloc)) { + unlink(targs.namerecloc); + } ast_party_connected_line_free(&targs.connected_in); ast_party_connected_line_free(&targs.connected_out); + if (f->realtime) { /* Not in list */ free_numbers(f); diff --git a/apps/app_meetme.c b/apps/app_meetme.c index e6e465e05e..588c3d6851 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -2173,12 +2173,12 @@ static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags) static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking) { ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "Meetme: %s\r\n" - "Usernum: %d\r\n" - "Status: %s\r\n", - chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off"); + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "Meetme: %s\r\n" + "Usernum: %d\r\n" + "Status: %s\r\n", + chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off"); } static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor) @@ -3127,12 +3127,12 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc } ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "Meetme: %s\r\n" - "Usernum: %i\r\n" - "Status: on\r\n", - chan->name, chan->uniqueid, conf->confno, user->user_no); + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "Meetme: %s\r\n" + "Usernum: %d\r\n" + "Status: on\r\n", + chan->name, chan->uniqueid, conf->confno, user->user_no); } /* If I should be un-muted but am not talker, un-mute me */ @@ -3145,12 +3145,12 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc } ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "Meetme: %s\r\n" - "Usernum: %i\r\n" - "Status: off\r\n", - chan->name, chan->uniqueid, conf->confno, user->user_no); + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "Meetme: %s\r\n" + "Usernum: %d\r\n" + "Status: off\r\n", + chan->name, chan->uniqueid, conf->confno, user->user_no); } if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && @@ -3158,12 +3158,12 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc talkreq_manager = 1; ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "Meetme: %s\r\n" - "Usernum: %i\r\n" - "Status: on\r\n", - chan->name, chan->uniqueid, conf->confno, user->user_no); + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "Meetme: %s\r\n" + "Usernum: %d\r\n" + "Status: on\r\n", + chan->name, chan->uniqueid, conf->confno, user->user_no); } @@ -3171,12 +3171,12 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) { talkreq_manager = 0; ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "Meetme: %s\r\n" - "Usernum: %i\r\n" - "Status: off\r\n", - chan->name, chan->uniqueid, conf->confno, user->user_no); + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "Meetme: %s\r\n" + "Usernum: %d\r\n" + "Status: off\r\n", + chan->name, chan->uniqueid, conf->confno, user->user_no); } /* If I have been kicked, exit the conference */ @@ -4550,9 +4550,8 @@ static struct ast_conf_user *find_user(struct ast_conference *conf, const char * { struct ast_conf_user *user = NULL; int cid; - - sscanf(callerident, "%30i", &cid); - if (conf && callerident) { + + if (conf && callerident && sscanf(callerident, "%30d", &cid) == 1) { user = ao2_find(conf->usercontainer, &cid, 0); /* reference decremented later in admin_exec */ return user; diff --git a/apps/app_minivm.c b/apps/app_minivm.c index edffd4d3f4..dc81d3f15a 100644 --- a/apps/app_minivm.c +++ b/apps/app_minivm.c @@ -1255,6 +1255,8 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu if (ast_strlen_zero(email)) { ast_log(LOG_WARNING, "No address to send message to.\n"); + ast_free(str1); + ast_free(str2); return -1; } @@ -1309,11 +1311,15 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu } if (!p) { ast_log(LOG_WARNING, "Unable to open temporary file '%s'\n", tmp); + ast_free(str1); + ast_free(str2); return -1; } /* Allocate channel used for chanvar substitution */ ast = ast_dummy_channel_alloc(); if (!ast) { + ast_free(str1); + ast_free(str2); return -1; } @@ -2085,7 +2091,7 @@ static int minivm_notify_exec(struct ast_channel *chan, const char *data) char *domain; char *tmpptr; struct minivm_account *vmu; - char *username = argv[0]; + char *username; const char *template = ""; const char *filename; const char *format; @@ -2459,7 +2465,7 @@ static int minivm_accmess_exec(struct ast_channel *chan, const char *data) char *domain; char *tmpptr = NULL; struct minivm_account *vmu; - char *username = argv[0]; + char *username; struct ast_flags flags = { 0 }; char *opts[OPT_ARG_ARRAY_SIZE]; int error = FALSE; diff --git a/apps/app_page.c b/apps/app_page.c index 40b102da71..2a8f85a7b7 100644 --- a/apps/app_page.c +++ b/apps/app_page.c @@ -177,6 +177,11 @@ static int page_exec(struct ast_channel *chan, const char *data) if (!ast_strlen_zero(args.options)) { ast_app_parse_options(page_opts, &flags, opts, args.options); + } else { + /* opts must be initialized if there wasn't an options string. */ + for (i = 0; i < OPT_ARG_ARRAY_SIZE; i++) { + opts[i] = NULL; + } } if (!ast_strlen_zero(args.timeout)) { @@ -243,6 +248,7 @@ static int page_exec(struct ast_channel *chan, const char *data) /* Append technology and resource */ if (ast_dial_append(dial, tech, resource) == -1) { ast_log(LOG_ERROR, "Failed to add %s to outbound dial\n", tech); + ast_dial_destroy(dial); continue; } diff --git a/apps/app_queue.c b/apps/app_queue.c index e3ff606c37..8ae9552980 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -1004,7 +1004,6 @@ struct callattempt { struct callattempt *call_next; struct ast_channel *chan; char interface[256]; - int stillgoing; int metric; time_t lastcall; struct call_queue *lastqueue; @@ -1013,8 +1012,12 @@ struct callattempt { struct ast_party_connected_line connected; /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */ unsigned int pending_connected_update:1; + /*! TRUE if the connected line update is blocked. */ + unsigned int block_connected_update:1; /*! TRUE if caller id is not available for connected line */ unsigned int dial_callerid_absent:1; + /*! TRUE if the call is still active */ + unsigned int stillgoing:1; struct ast_aoc_decoded *aoc_s_rate_list; }; @@ -1857,9 +1860,17 @@ static int insert_penaltychange(const char *list_name, const char *content, cons if (!inserted) { AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list); + inserted = 1; } + + break; } + if (!inserted) { + ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name); + ast_free(rule); + return -1; + } return 0; } @@ -2534,11 +2545,11 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result * */ if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) { insert_entry(q, prev, qe, &pos); + inserted = 1; /*pos is incremented inside insert_entry, so don't need to add 1 here*/ if (position < pos) { ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos); } - inserted = 1; } cur->pos = ++pos; prev = cur; @@ -3509,15 +3520,13 @@ static void rna(int rnatime, struct queue_ent *qe, char *interface, char *member * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue() - * \param[in] update_connectedline Allow connected line and redirecting updates to pass through. * * \todo eventually all call forward logic should be intergerated into and replaced by ast_call_forward() */ -static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int update_connectedline) +static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed) { const char *queue = qe->parent->name; struct callattempt *o, *start = NULL, *prev = NULL; - int res; int status; int numbusies = prebusies; int numnochan = 0; @@ -3598,10 +3607,11 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte /* Service all of the outgoing channels */ for (o = start; o; o = o->call_next) { - /* We go with a static buffer here instead of using ast_strdupa. Using + /* We go with a fixed buffer here instead of using ast_strdupa. Using * ast_strdupa in a loop like this one can cause a stack overflow */ char ochan_name[AST_CHANNEL_NAME]; + if (o->chan) { ast_channel_lock(o->chan); ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name)); @@ -3610,7 +3620,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { if (!peer) { ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); - if (update_connectedline) { + if (!o->block_connected_update) { if (o->pending_connected_update) { if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { ast_channel_update_connected_line(in, &o->connected, NULL); @@ -3641,6 +3651,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte ast_copy_string(on, o->member->interface, sizeof(on)); ast_copy_string(membername, o->member->membername, sizeof(membername)); + /* Before processing channel, go ahead and check for forwarding */ if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward); numnochan++; @@ -3662,10 +3673,17 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte stuff = tmpchan; tech = "Local"; } + if (!strcasecmp(tech, "Local")) { + /* + * Drop the connected line update block for local channels since + * this is going to run dialplan and the user can change his + * mind about what connected line information he wants to send. + */ + o->block_connected_update = 0; + } ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL); - /* Before processing channel, go ahead and check for forwarding */ ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name); /* Setup parameters */ o->chan = ast_request(tech, in->nativeformats, in, stuff, &status); @@ -3676,15 +3694,28 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte o->stillgoing = 0; numnochan++; } else { - struct ast_party_redirecting redirecting; + ast_channel_lock_both(o->chan, original); + ast_party_redirecting_copy(&o->chan->redirecting, &original->redirecting); + ast_channel_unlock(o->chan); + ast_channel_unlock(original); ast_channel_lock_both(o->chan, in); ast_channel_inherit_variables(in, o->chan); ast_channel_datastore_inherit(in, o->chan); + if (o->pending_connected_update) { + /* + * Re-seed the callattempt's connected line information with + * previously acquired connected line info from the queued + * channel. The previously acquired connected line info could + * have been set through the CONNECTED_LINE dialplan function. + */ + o->pending_connected_update = 0; + ast_party_connected_line_copy(&o->connected, &in->connected); + } + ast_string_field_set(o->chan, accountcode, in->accountcode); - ast_channel_set_redirecting(o->chan, &original->redirecting, NULL); if (!o->chan->redirecting.from.number.valid || ast_strlen_zero(o->chan->redirecting.from.number.str)) { /* @@ -3700,27 +3731,35 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte o->chan->dialed.transit_network_select = in->dialed.transit_network_select; - ast_party_caller_copy(&o->chan->caller, &in->caller); - ast_party_connected_line_copy(&o->chan->connected, &original->connected); + o->dial_callerid_absent = !o->chan->caller.id.number.valid + || ast_strlen_zero(o->chan->caller.id.number.str); + ast_connected_line_copy_from_caller(&o->chan->connected, &in->caller); - /* - * We must unlock o->chan before calling - * ast_channel_redirecting_macro, because we put o->chan into - * autoservice there. That is pretty much a guaranteed - * deadlock. This is why the handling of o->chan's lock may - * seem a bit unusual here. - */ - ast_party_redirecting_init(&redirecting); - ast_party_redirecting_copy(&redirecting, &o->chan->redirecting); - ast_channel_unlock(o->chan); - res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0); - if (res) { - ast_channel_update_redirecting(in, &redirecting, NULL); - } - ast_party_redirecting_free(&redirecting); ast_channel_unlock(in); + if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL + && !o->block_connected_update) { + struct ast_party_redirecting redirecting; - update_connectedline = 1; + /* + * Redirecting updates to the caller make sense only on single + * call at a time strategies. + * + * We must unlock o->chan before calling + * ast_channel_redirecting_macro, because we put o->chan into + * autoservice there. That is pretty much a guaranteed + * deadlock. This is why the handling of o->chan's lock may + * seem a bit unusual here. + */ + ast_party_redirecting_init(&redirecting); + ast_party_redirecting_copy(&redirecting, &o->chan->redirecting); + ast_channel_unlock(o->chan); + if (ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) { + ast_channel_update_redirecting(in, &redirecting, NULL); + } + ast_party_redirecting_free(&redirecting); + } else { + ast_channel_unlock(o->chan); + } if (ast_call(o->chan, stuff, 0)) { ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n", @@ -3741,7 +3780,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte /* This is our guy if someone answered. */ if (!peer) { ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); - if (update_connectedline) { + if (!o->block_connected_update) { if (o->pending_connected_update) { if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { ast_channel_update_connected_line(in, &o->connected, NULL); @@ -3818,20 +3857,30 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte /* Ignore going off hook */ break; case AST_CONTROL_CONNECTED_LINE: - if (!update_connectedline) { + if (o->block_connected_update) { ast_verb(3, "Connected line update to %s prevented.\n", inchan_name); - } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { + break; + } + if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { struct ast_party_connected_line connected; + ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name); ast_party_connected_line_set_init(&connected, &o->connected); ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected); ast_party_connected_line_set(&o->connected, &connected, NULL); ast_party_connected_line_free(&connected); o->pending_connected_update = 1; - } else { - if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) { - ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); - } + break; + } + + /* + * Prevent using the CallerID from the outgoing channel since we + * got a connected line update from it. + */ + o->dial_callerid_absent = 1; + + if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) { + ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); } break; case AST_CONTROL_AOC: @@ -3846,13 +3895,22 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte } break; case AST_CONTROL_REDIRECTING: - if (!update_connectedline) { - ast_verb(3, "Redirecting update to %s prevented\n", inchan_name); - } else if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { - ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name); - if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) { - ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); - } + if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { + /* + * Redirecting updates to the caller make sense only on single + * call at a time strategies. + */ + break; + } + if (o->block_connected_update) { + ast_verb(3, "Redirecting update to %s prevented\n", + inchan_name); + break; + } + ast_verb(3, "%s redirecting info has changed, passing it to %s\n", + ochan_name, inchan_name); + if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) { + ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); } break; default: @@ -3891,6 +3949,14 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte } return NULL; } + + /*! + * \todo + * XXX Queue like Dial really should send any connected line + * updates (AST_CONTROL_CONNECTED_LINE) from the caller to each + * ringing queue member. + */ + if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) { ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer); *to = 0; @@ -4325,6 +4391,7 @@ static struct ast_datastore *setup_transfer_datastore(struct queue_ent *qe, stru ast_channel_lock(qe->chan); if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) { ast_channel_unlock(qe->chan); + ast_free(qtds); ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); return NULL; } @@ -4428,7 +4495,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce char *p; char vars[2048]; int forwardsallowed = 1; - int update_connectedline = 1; + int block_connected_line = 0; int callcompletedinsl; struct ao2_iterator memi; struct ast_datastore *datastore, *transfer_ds; @@ -4495,7 +4562,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce forwardsallowed = 0; break; case 'I': - update_connectedline = 0; + block_connected_line = 1; break; case 'x': ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON); @@ -4595,17 +4662,18 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce AST_LIST_UNLOCK(dialed_interfaces); } - ast_channel_lock(qe->chan); /* * Seed the callattempt's connected line information with previously * acquired connected line info from the queued channel. The * previously acquired connected line info could have been set * through the CONNECTED_LINE dialplan function. */ + ast_channel_lock(qe->chan); ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected); ast_channel_unlock(qe->chan); - tmp->stillgoing = -1; + tmp->block_connected_update = block_connected_line; + tmp->stillgoing = 1; tmp->member = cur;/* Place the reference for cur into callattempt. */ tmp->lastcall = cur->lastcall; tmp->lastqueue = cur->lastqueue; @@ -4647,7 +4715,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce ++qe->pending; ao2_unlock(qe->parent); ring_one(qe, outgoing, &numbusies); - lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline); + lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, + ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), + forwardsallowed); /* The ast_channel_datastore_remove() function could fail here if the * datastore was moved to another channel during a masquerade. If this is * the case, don't free the datastore here because later, when the channel @@ -4723,7 +4793,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); } if (!res2 && announce) { - play_file(peer, announce); + if (play_file(peer, announce) < 0) { + ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, peer->name); + } } if (!res2 && qe->parent->reportholdtime) { if (!play_file(peer, qe->parent->sound_reporthold)) { @@ -4734,11 +4806,15 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce holdtimesecs = abs((now - qe->start) % 60); if (holdtime > 0) { ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); - play_file(peer, qe->parent->sound_minutes); + if (play_file(peer, qe->parent->sound_minutes) < 0) { + ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, peer->name); + } } if (holdtimesecs > 1) { ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL); - play_file(peer, qe->parent->sound_seconds); + if (play_file(peer, qe->parent->sound_seconds) < 0) { + ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, peer->name); + } } } } @@ -6062,6 +6138,8 @@ static int queue_exec(struct ast_channel *chan, const char *data) set_queue_result(chan, reason); return 0; } + ast_assert(qe.parent != NULL); + ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d", S_OR(args.url, ""), S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""), @@ -6216,12 +6294,13 @@ stop: if (reason != QUEUE_UNKNOWN) set_queue_result(chan, reason); - if (qe.parent) { - /* every queue_ent is given a reference to it's parent call_queue when it joins the queue. - * This ref must be taken away right before the queue_ent is destroyed. In this case - * the queue_ent is about to be returned on the stack */ - qe.parent = queue_unref(qe.parent); - } + /* + * every queue_ent is given a reference to it's parent + * call_queue when it joins the queue. This ref must be taken + * away right before the queue_ent is destroyed. In this case + * the queue_ent is about to be returned on the stack + */ + qe.parent = queue_unref(qe.parent); return res; } diff --git a/apps/app_record.c b/apps/app_record.c index 6098ca7290..91fbd984b4 100644 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -415,12 +415,14 @@ static int record_exec(struct ast_channel *chan, const char *data) out: if ((silence > 0) && rfmt.id) { res = ast_set_read_format(chan, &rfmt); - if (res) + if (res) { ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); - if (sildet) - ast_dsp_free(sildet); + } } + if (sildet) { + ast_dsp_free(sildet); + } return res; } diff --git a/apps/app_stack.c b/apps/app_stack.c index 32cdc88b36..828f72fdaf 100644 --- a/apps/app_stack.c +++ b/apps/app_stack.c @@ -370,9 +370,20 @@ static int gosub_exec(struct ast_channel *chan, const char *data) { struct ast_datastore *stack_store; AST_LIST_HEAD(, gosub_stack_frame) *oldlist; - struct gosub_stack_frame *newframe, *lastframe; - char argname[15], *tmp = ast_strdupa(data), *label, *endparen; - int i, max_argc = 0; + struct gosub_stack_frame *newframe; + struct gosub_stack_frame *lastframe; + char argname[15]; + char *parse; + char *label; + char *caller_id; + char *orig_context; + char *orig_exten; + char *dest_context; + char *dest_exten; + int orig_priority; + int dest_priority; + int i; + int max_argc = 0; AST_DECLARE_APP_ARGS(args2, AST_APP_ARG(argval)[100]; ); @@ -382,26 +393,83 @@ static int gosub_exec(struct ast_channel *chan, const char *data) return -1; } + /* + * Separate the arguments from the label + * + * NOTE: You cannot use ast_app_separate_args for this, because + * '(' cannot be used as a delimiter. + */ + parse = ast_strdupa(data); + label = strsep(&parse, "("); + if (parse) { + char *endparen; + + endparen = strrchr(parse, ')'); + if (endparen) { + *endparen = '\0'; + } else { + ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", data); + } + AST_STANDARD_RAW_ARGS(args2, parse); + } else { + args2.argc = 0; + } + + ast_channel_lock(chan); + orig_context = ast_strdupa(chan->context); + orig_exten = ast_strdupa(chan->exten); + orig_priority = chan->priority; + ast_channel_unlock(chan); + + if (ast_parseable_goto(chan, label)) { + ast_log(LOG_ERROR, "%s address is invalid: '%s'\n", app_gosub, data); + goto error_exit; + } + + ast_channel_lock(chan); + dest_context = ast_strdupa(chan->context); + dest_exten = ast_strdupa(chan->exten); + dest_priority = chan->priority; + if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP)) { + ++dest_priority; + } + caller_id = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL); + if (caller_id) { + caller_id = ast_strdupa(caller_id); + } + ast_channel_unlock(chan); + + if (!ast_exists_extension(chan, dest_context, dest_exten, dest_priority, caller_id)) { + ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for %s: (Context:%s, Extension:%s, Priority:%d)\n", + app_gosub, dest_context, dest_exten, dest_priority); + goto error_exit; + } + + /* Now we know that we're going to a new location */ + ast_channel_lock(chan); + + /* Find stack datastore return list. */ if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) { - ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", chan->name); + ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", + chan->name); stack_store = ast_datastore_alloc(&stack_info, NULL); if (!stack_store) { - ast_log(LOG_ERROR, "Unable to allocate new datastore. Gosub will fail.\n"); - ast_channel_unlock(chan); - return -1; + ast_log(LOG_ERROR, "Unable to allocate new datastore. %s failed.\n", + app_gosub); + goto error_exit_locked; } oldlist = ast_calloc(1, sizeof(*oldlist)); if (!oldlist) { - ast_log(LOG_ERROR, "Unable to allocate datastore list head. Gosub will fail.\n"); + ast_log(LOG_ERROR, "Unable to allocate datastore list head. %s failed.\n", + app_gosub); ast_datastore_free(stack_store); - ast_channel_unlock(chan); - return -1; + goto error_exit_locked; } + AST_LIST_HEAD_INIT(oldlist); stack_store->data = oldlist; - AST_LIST_HEAD_INIT(oldlist); ast_channel_datastore_add(chan, stack_store); } else { oldlist = stack_store->data; @@ -411,53 +479,18 @@ static int gosub_exec(struct ast_channel *chan, const char *data) max_argc = lastframe->arguments; } - /* Separate the arguments from the label */ - /* NOTE: you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */ - label = strsep(&tmp, "("); - if (tmp) { - endparen = strrchr(tmp, ')'); - if (endparen) - *endparen = '\0'; - else - ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", (char *)data); - AST_STANDARD_RAW_ARGS(args2, tmp); - } else - args2.argc = 0; - - /* Mask out previous arguments in this invocation */ + /* Mask out previous Gosub arguments in this invocation */ if (args2.argc > max_argc) { max_argc = args2.argc; } - /* Create the return address, but don't save it until we know that the Gosub destination exists */ - newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, max_argc); - + /* Create the return address */ + newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, max_argc); if (!newframe) { - ast_channel_unlock(chan); - return -1; - } - - if (ast_parseable_goto(chan, label)) { - ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data); - ast_free(newframe); - ast_channel_unlock(chan); - return -1; - } - - if (!ast_exists_extension(chan, chan->context, chan->exten, - ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP) ? chan->priority + 1 : chan->priority, - S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { - ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n", - chan->context, chan->exten, ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP) ? chan->priority + 1 : chan->priority); - ast_copy_string(chan->context, newframe->context, sizeof(chan->context)); - ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten)); - chan->priority = newframe->priority - 1; - ast_free(newframe); - ast_channel_unlock(chan); - return -1; + goto error_exit_locked; } - /* Now that we know for certain that we're going to a new location, set our arguments */ + /* Set our arguments */ for (i = 0; i < max_argc; i++) { snprintf(argname, sizeof(argname), "ARG%d", i + 1); frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : ""); @@ -467,13 +500,23 @@ static int gosub_exec(struct ast_channel *chan, const char *data) frame_set_var(chan, newframe, "ARGC", argname); /* And finally, save our return address */ - oldlist = stack_store->data; AST_LIST_LOCK(oldlist); AST_LIST_INSERT_HEAD(oldlist, newframe, entries); AST_LIST_UNLOCK(oldlist); ast_channel_unlock(chan); return 0; + +error_exit: + ast_channel_lock(chan); + +error_exit_locked: + /* Restore the original dialplan location. */ + ast_copy_string(chan->context, orig_context, sizeof(chan->context)); + ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); + chan->priority = orig_priority; + ast_channel_unlock(chan); + return -1; } static int gosubif_exec(struct ast_channel *chan, const char *data) @@ -764,8 +807,15 @@ static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char struct ast_pbx *pbx = chan->pbx; struct ast_pbx_args args; struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); - AST_LIST_HEAD(, gosub_stack_frame) *oldlist = stack_store->data; - struct gosub_stack_frame *cur = AST_LIST_FIRST(oldlist); + AST_LIST_HEAD(, gosub_stack_frame) *oldlist; + struct gosub_stack_frame *cur; + if (!stack_store) { + ast_log(LOG_WARNING, "No GoSub stack remaining after AGI GoSub execution.\n"); + ast_free(gosub_args); + return RESULT_FAILURE; + } + oldlist = stack_store->data; + cur = AST_LIST_FIRST(oldlist); cur->is_agi = 1; memset(&args, 0, sizeof(args)); diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index a52d9cb82b..836b576abd 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -4588,7 +4588,7 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in } snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60); - ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL)); + ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm)); fprintf(p, "Date: %s" ENDL, date); /* Set date format for voicemail mail */ @@ -4946,7 +4946,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char snprintf(who, sizeof(who), "%s@%s", srcemail, host); } snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60); - ast_strftime_locale(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL)); + ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm)); fprintf(p, "Date: %s\n", date); /* Reformat for custom pager format */ @@ -6063,8 +6063,9 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ char e[2] = ""; e[0] = *code; if (strchr(ecodes, e[0]) == NULL - && ast_canmatch_extension(chan, chan->context, e, 1, - S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { + && ast_canmatch_extension(chan, + (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context), + e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1); } } @@ -6158,11 +6159,12 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ /* Allow all other digits to exit Voicemail and return to the dialplan */ if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) { - if (!ast_strlen_zero(options->exitcontext)) + if (!ast_strlen_zero(options->exitcontext)) { ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context)); + } free_user(vmu); - pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT"); ast_free(tmp); + pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT"); return res; } @@ -7226,7 +7228,10 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, strncat(vms->introfn, "intro", sizeof(vms->introfn)); ast_play_and_wait(chan, INTRO); ast_play_and_wait(chan, "beep"); - play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag); + cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag); + if (cmd == -1) { + break; + } cmd = 't'; #else @@ -9790,7 +9795,10 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st retries = 0; RETRIEVE(prefile, -1, vmu->mailbox, vmu->context); if (ast_fileexists(prefile, NULL, NULL) <= 0) { - play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL); + cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL); + if (cmd == -1) { + break; + } cmd = 't'; } else { switch (cmd) { @@ -11656,13 +11664,15 @@ static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struc AST_LIST_UNLOCK(&users); return CLI_FAILURE; } - if (a->argc == 3) + if (!context) { ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg"); - else { + } else { int count = 0; AST_LIST_TRAVERSE(&users, vmu, list) { - if (!strcmp(context, vmu->context)) + if (!strcmp(context, vmu->context)) { count++; + break; + } } if (count) { ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg"); @@ -11676,7 +11686,7 @@ static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struc int newmsgs = 0, oldmsgs = 0; char count[12], tmp[256] = ""; - if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) { + if (!context || !strcmp(context, vmu->context)) { snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context); inboxcount(tmp, &newmsgs, &oldmsgs); snprintf(count, sizeof(count), "%d", newmsgs); @@ -12011,11 +12021,21 @@ static int handle_subscribe(void *datap) static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata) { uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid)); - if (ast_event_get_type(event) != AST_EVENT_UNSUB) + + if (!uniqueid) { + ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n"); return; + } - if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) + if (ast_event_get_type(event) != AST_EVENT_UNSUB) { + ast_free(uniqueid); return; + } + + if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) { + ast_free(uniqueid); + return; + } u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID); *uniqueid = u; @@ -12049,6 +12069,7 @@ static void mwi_sub_event_cb(const struct ast_event *event, void *userdata) static void start_poll_thread(void) { + int errcode; mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL, AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI, AST_EVENT_IE_END); @@ -12062,7 +12083,9 @@ static void start_poll_thread(void) poll_thread_run = 1; - ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL); + if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) { + ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode)); + } } static void stop_poll_thread(void) @@ -12997,8 +13020,10 @@ static void read_password_from_file(const char *secretfn, char *password, int pa const char *val = ast_variable_retrieve(pwconf, "general", "password"); if (val) { ast_copy_string(password, val, passwordlen); - return; + ast_config_destroy(pwconf); + return; } + ast_config_destroy(pwconf); } ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn); } @@ -13007,26 +13032,33 @@ static int write_password_to_file(const char *secretfn, const char *password) { struct ast_config *conf; struct ast_category *cat; struct ast_variable *var; + int res = -1; - if (!(conf=ast_config_new())) { + if (!(conf = ast_config_new())) { ast_log(LOG_ERROR, "Error creating new config structure\n"); - return -1; + return res; } - if (!(cat=ast_category_new("general","",1))) { + if (!(cat = ast_category_new("general", "", 1))) { ast_log(LOG_ERROR, "Error creating new category structure\n"); - return -1; + ast_config_destroy(conf); + return res; } - if (!(var=ast_variable_new("password",password,""))) { + if (!(var = ast_variable_new("password", password, ""))) { ast_log(LOG_ERROR, "Error creating new variable structure\n"); - return -1; + ast_config_destroy(conf); + ast_category_destroy(cat); + return res; } - ast_category_append(conf,cat); - ast_variable_append(cat,var); - if (ast_config_text_file_save(secretfn, conf, "app_voicemail")) { + ast_category_append(conf, cat); + ast_variable_append(cat, var); + if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) { + res = 0; + } else { ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn); - return -1; } - return 0; + + ast_config_destroy(conf); + return res; } static int vmsayname_exec(struct ast_channel *chan, const char *data) diff --git a/channels/chan_agent.c b/channels/chan_agent.c index 1acbc82e49..49ed7f9818 100644 --- a/channels/chan_agent.c +++ b/channels/chan_agent.c @@ -516,21 +516,27 @@ static struct agent_pvt *add_agent(const char *agent, int pending) /*! * Deletes an agent after doing some clean up. * Further documentation: How safe is this function ? What state should the agent be to be cleaned. + * + * \warning XXX This function seems to be very unsafe. + * Potential for double free and use after free among other + * problems. + * * \param p Agent to be deleted. * \returns Always 0. */ static int agent_cleanup(struct agent_pvt *p) { - struct ast_channel *chan = NULL; + struct ast_channel *chan; + ast_mutex_lock(&p->lock); chan = p->owner; p->owner = NULL; - chan->tech_pvt = NULL; /* 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->tech_pvt = NULL; chan = ast_channel_release(chan); } if (p->dead) { @@ -539,7 +545,9 @@ static int agent_cleanup(struct agent_pvt *p) ast_cond_destroy(&p->app_complete_cond); ast_cond_destroy(&p->login_wait_cond); ast_free(p); - } + } else { + ast_mutex_unlock(&p->lock); + } return 0; } @@ -667,7 +675,9 @@ static struct ast_frame *agent_read(struct ast_channel *ast) break; case AST_FRAME_DTMF_END: if (!p->acknowledged && (f->subclass.integer == p->acceptdtmf)) { - ast_verb(3, "%s acknowledged\n", p->chan->name); + if (p->chan) { + ast_verb(3, "%s acknowledged\n", p->chan->name); + } p->acknowledged = 1; ast_frfree(f); f = &answer_frame; diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 23dd52d63e..5eddc3f604 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -7954,6 +7954,9 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast) struct ast_frame *f; idx = dahdi_get_index(ast, p, 0); + if (idx < 0) { + return &ast_null_frame; + } mysig = p->sig; if (p->outsigmod > -1) mysig = p->outsigmod; @@ -7967,8 +7970,6 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast) p->subs[idx].f.data.ptr = NULL; f = &p->subs[idx].f; - if (idx < 0) - return &p->subs[idx].f; if (p->fake_event) { res = p->fake_event; p->fake_event = 0; @@ -8048,6 +8049,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast) #else ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig)); #endif + break; case DAHDI_EVENT_PULSE_START: /* Stop tone if there's a pulse start and the PBX isn't started */ if (!ast->pbx) @@ -8935,7 +8937,9 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast) ast_debug(1, "Exception on %d, channel %d\n", ast->fds[0],p->channel); /* If it's not us, return NULL immediately */ if (ast != p->owner) { - ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name); + if (p->owner) { + ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name); + } f = &p->subs[idx].f; return f; } @@ -9301,6 +9305,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) if ((ast->_state == AST_STATE_UP) && !p->outgoing) { /* Treat this as a "hangup" instead of a "busy" on the assumption that a busy */ + ast_frfree(f); f = NULL; } } else if (f->frametype == AST_FRAME_DTMF_BEGIN @@ -9326,7 +9331,8 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) if (ast_tvdiff_ms(ast_tvnow(), p->waitingfordt) >= p->waitfordialtone ) { p->waitingfordt.tv_sec = 0; ast_log(LOG_WARNING, "Never saw dialtone on channel %d\n", p->channel); - f=NULL; + ast_frfree(f); + f = NULL; } else if (f->frametype == AST_FRAME_VOICE) { f->frametype = AST_FRAME_NULL; f->subclass.integer = 0; @@ -9341,6 +9347,7 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d\n", p->channel); p->dop.dialstr[0] = '\0'; ast_mutex_unlock(&p->lock); + ast_frfree(f); return NULL; } else { ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr); @@ -11760,14 +11767,13 @@ static void *do_monitor(void *data) count = 0; for (i = iflist; i; i = i->next) { ast_mutex_lock(&i->lock); - if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) { + if (pfds && (i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) { if (analog_lib_handles(i->sig, i->radio, i->oprmode)) { struct analog_pvt *p = i->sig_pvt; - if (!p) + if (!p) { ast_log(LOG_ERROR, "No sig_pvt?\n"); - - if (!p->owner && !p->subs[SUB_REAL].owner) { + } else if (!p->owner && !p->subs[SUB_REAL].owner) { /* This needs to be watched, as it lacks an owner */ pfds[count].fd = i->subs[SUB_REAL].dfd; pfds[count].events = POLLPRI; diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index b273b4fac4..36369e58c2 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -1922,24 +1922,25 @@ static void send_signaling(struct chan_iax2_pvt *pvt) * we have received a destination call number. */ static int queue_signalling(struct chan_iax2_pvt *pvt, struct ast_frame *f) { - struct signaling_queue_entry *new; + struct signaling_queue_entry *qe; if (f->frametype == AST_FRAME_IAX || !pvt->hold_signaling) { return 1; /* do not queue this frame */ - } else if (!(new = ast_calloc(1, sizeof(struct signaling_queue_entry)))) { + } else if (!(qe = ast_calloc(1, sizeof(struct signaling_queue_entry)))) { return -1; /* out of memory */ } - memcpy(&new->f, f, sizeof(new->f)); /* copy ast_frame into our queue entry */ - - if (new->f.datalen) { /* if there is data in this frame copy it over as well */ - if (!(new->f.data.ptr = ast_calloc(1, new->f.datalen))) { - free_signaling_queue_entry(new); + /* copy ast_frame into our queue entry */ + qe->f = *f; + if (qe->f.datalen) { + /* if there is data in this frame copy it over as well */ + if (!(qe->f.data.ptr = ast_malloc(qe->f.datalen))) { + free_signaling_queue_entry(qe); return -1; } - memcpy(new->f.data.ptr, f->data.ptr, sizeof(*new->f.data.ptr)); + memcpy(qe->f.data.ptr, f->data.ptr, qe->f.datalen); } - AST_LIST_INSERT_TAIL(&pvt->signaling_queue, new, next); + AST_LIST_INSERT_TAIL(&pvt->signaling_queue, qe, next); return 0; } @@ -2483,19 +2484,20 @@ static void peercnt_remove(struct peercnt *peercnt) .sin_addr.s_addr = peercnt->addr, }; - if (peercnt) { - /* Container locked here since peercnt may be unlinked from list. If left unlocked, - * peercnt_add could try and grab this entry from the table and modify it at the - * "same time" this thread attemps to unlink it.*/ - ao2_lock(peercnts); - peercnt->cur--; - ast_debug(1, "ip callno count decremented to %d for %s\n", peercnt->cur, ast_inet_ntoa(sin.sin_addr)); - /* if this was the last connection from the peer remove it from table */ - if (peercnt->cur == 0) { - ao2_unlink(peercnts, peercnt);/* decrements ref from table, last ref is left to scheduler */ - } - ao2_unlock(peercnts); + /* + * Container locked here since peercnt may be unlinked from + * list. If left unlocked, peercnt_add could try and grab this + * entry from the table and modify it at the "same time" this + * thread attemps to unlink it. + */ + ao2_lock(peercnts); + peercnt->cur--; + ast_debug(1, "ip callno count decremented to %d for %s\n", peercnt->cur, ast_inet_ntoa(sin.sin_addr)); + /* if this was the last connection from the peer remove it from table */ + if (peercnt->cur == 0) { + ao2_unlink(peercnts, peercnt);/* decrements ref from table, last ref is left to scheduler */ } + ao2_unlock(peercnts); } /*! @@ -4244,6 +4246,15 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr struct ast_channel *owner = NULL; struct ast_channel *bridge = NULL; + /* + * Clear fr->af.data if there is no data in the buffer. Things + * like AST_CONTROL_HOLD without a suggested music class must + * have a NULL pointer. + */ + if (!fr->af.datalen) { + memset(&fr->af.data, 0, sizeof(fr->af.data)); + } + /* Attempt to recover wrapped timestamps */ unwrap_timestamp(fr); @@ -4473,11 +4484,13 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in /* Whoops, we weren't supposed to exist! */ peer = peer_unref(peer); break; - } + } } else if (!strcasecmp(tmp->name, "regseconds")) { ast_get_time_t(tmp->value, ®seconds, 0, NULL); } else if (!strcasecmp(tmp->name, "ipaddr")) { - ast_sockaddr_parse(&peer->addr, tmp->value, PARSE_PORT_IGNORE); + if (!ast_sockaddr_parse(&peer->addr, tmp->value, PARSE_PORT_IGNORE)) { + ast_log(LOG_WARNING, "Failed to parse sockaddr '%s' for ipaddr of realtime peer '%s'\n", tmp->value, tmp->name); + } } else if (!strcasecmp(tmp->name, "port")) { ast_sockaddr_set_port(&peer->addr, atoi(tmp->value)); } else if (!strcasecmp(tmp->name, "host")) { @@ -5374,7 +5387,7 @@ static int wait_for_peercallno(struct chan_iax2_pvt *pvt) DEADLOCK_AVOIDANCE(&iaxsl[callno]); pvt = iaxs[callno]; } - if (!pvt->peercallno) { + if (!pvt || !pvt->peercallno) { return -1; } } @@ -6004,16 +6017,15 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str The "genuine" distinction is needed because genuine frames must get a clock-based timestamp, the others need a timestamp slaved to the voice frames so that they go in sequence */ - if (f) { - if (f->frametype == AST_FRAME_VOICE) { - voice = 1; - delivery = &f->delivery; - } else if (f->frametype == AST_FRAME_IAX) { - genuine = 1; - } else if (f->frametype == AST_FRAME_CNG) { - p->notsilenttx = 0; - } + if (f->frametype == AST_FRAME_VOICE) { + voice = 1; + delivery = &f->delivery; + } else if (f->frametype == AST_FRAME_IAX) { + genuine = 1; + } else if (f->frametype == AST_FRAME_CNG) { + p->notsilenttx = 0; } + if (ast_tvzero(p->offset)) { p->offset = ast_tvnow(); /* Round to nearest 20ms for nice looking traces */ @@ -6988,6 +7000,7 @@ static char *handle_cli_iax2_unregister(struct ast_cli_entry *e, int cmd, struct } else { ast_cli(a->fd, "Peer %s not registered\n", a->argv[2]); } + peer_unref(p); } else { ast_cli(a->fd, "Peer unknown: %s. Not unregistered\n", a->argv[2]); } @@ -8765,6 +8778,7 @@ static void reg_source_db(struct iax2_peer *p) expiry = strrchr(data, ':'); if (!expiry) { ast_log(LOG_NOTICE, "IAX/Registry astdb entry missing expiry: '%s'\n", data); + return; } *expiry++ = '\0'; @@ -9939,6 +9953,7 @@ static int acf_iaxvar_write(struct ast_channel *chan, const char *cmd, char *dat } varlist = ast_calloc(1, sizeof(*varlist)); if (!varlist) { + ast_datastore_free(variablestore); ast_log(LOG_ERROR, "Unable to assign new variable '%s'\n", data); return -1; } @@ -11751,6 +11766,7 @@ static void iax2_process_thread_cleanup(void *data) ast_mutex_destroy(&thread->init_lock); ast_cond_destroy(&thread->init_cond); ast_free(thread); + /* Ignore check_return warning from Coverity for ast_atomic_dec_and_test below */ ast_atomic_dec_and_test(&iaxactivethreadcount); } @@ -12332,7 +12348,10 @@ static int start_network_thread(void) AST_LIST_UNLOCK(&idle_list); } } - ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL); + if (ast_pthread_create_background(&netthreadid, NULL, network_thread, NULL)) { + ast_log(LOG_ERROR, "Failed to create new thread!\n"); + return -1; + } ast_verb(2, "%d helper threads started\n", threadcount); return 0; } @@ -13168,6 +13187,11 @@ static int set_config(const char *config_file, int reload) ast_config_destroy(ucfg); return 0; } + if (!cfg) { + /* should have been able to load the config here */ + ast_log(LOG_ERROR, "Unable to load config %s again\n", config_file); + return -1; + } } else if (cfg == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config_file); return 0; @@ -14045,7 +14069,9 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat } else if (!strncasecmp(colname, "codec[", 6)) { char *codecnum, *ptr; struct ast_format tmpfmt; - codecnum = strchr(colname, '['); + + /* skip over "codec" to the '[' */ + codecnum = colname + 5; *codecnum = '\0'; codecnum++; if ((ptr = strchr(codecnum, ']'))) { diff --git a/channels/chan_local.c b/channels/chan_local.c index ae46a04691..681285602b 100644 --- a/channels/chan_local.c +++ b/channels/chan_local.c @@ -475,17 +475,16 @@ static int local_answer(struct ast_channel *ast) * * \note it is assummed p is locked and reffed before entering this function */ -static void check_bridge(struct local_pvt *p) +static void check_bridge(struct ast_channel *ast, struct local_pvt *p) { - struct ast_channel_monitor *tmp; - struct ast_channel *chan = NULL; - struct ast_channel *bridged_chan = NULL; + struct ast_channel *owner; + struct ast_channel *chan; + struct ast_channel *bridged_chan; + struct ast_frame *f; /* 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) { + if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED) + || !p->chan || !p->owner) { return; } @@ -501,7 +500,9 @@ static void check_bridge(struct local_pvt *p) /* 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)) { + if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED) + || !p->chan || !p->owner + || (p->chan->_bridge != bridged_chan)) { return; } @@ -510,73 +511,114 @@ static void check_bridge(struct local_pvt *p) frames on the owner channel (because they would be transferred to the outbound channel during the masquerade) */ - if (p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { - /* Masquerade bridged channel into owner */ - /* Lock everything we need, one by one, and give up if - we can't get everything. Remember, we'll get another - chance in just a little bit */ - if (!ast_channel_trylock(p->chan->_bridge)) { - if (!ast_check_hangup(p->chan->_bridge)) { - if (!ast_channel_trylock(p->owner)) { - if (!ast_check_hangup(p->owner)) { - if (p->owner->monitor && !p->chan->_bridge->monitor) { - /* If a local channel is being monitored, we don't want a masquerade - * to cause the monitor to go away. Since the masquerade swaps the monitors, - * pre-swapping the monitors before the masquerade will ensure that the monitor - * ends up where it is expected. - */ - tmp = p->owner->monitor; - p->owner->monitor = p->chan->_bridge->monitor; - p->chan->_bridge->monitor = tmp; - } - if (p->chan->audiohooks) { - struct ast_audiohook_list *audiohooks_swapper; - audiohooks_swapper = p->chan->audiohooks; - 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->caller.id.name.valid || p->owner->caller.id.number.valid - || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid - || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) { - struct ast_party_caller tmp; - tmp = p->owner->caller; - p->owner->caller = p->chan->_bridge->caller; - p->chan->_bridge->caller = tmp; - } - if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid - || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid - || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) { - struct ast_party_redirecting tmp; - tmp = p->owner->redirecting; - p->owner->redirecting = p->chan->_bridge->redirecting; - p->chan->_bridge->redirecting = tmp; - } - if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) { - struct ast_party_dialed tmp; - tmp = p->owner->dialed; - p->owner->dialed = p->chan->_bridge->dialed; - p->chan->_bridge->dialed = tmp; - } - - - ast_app_group_update(p->chan, p->owner); - ast_channel_masquerade(p->owner, p->chan->_bridge); - ast_set_flag(p, LOCAL_ALREADY_MASQED); - } - ast_channel_unlock(p->owner); - } - } - ast_channel_unlock(p->chan->_bridge); - } + if (!p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ + || !AST_LIST_EMPTY(&p->owner->readq) + || ast != p->chan /* Sanity check (should always be false) */) { + return; + } + + /* Masquerade bridged channel into owner */ + /* Lock everything we need, one by one, and give up if + we can't get everything. Remember, we'll get another + chance in just a little bit */ + if (ast_channel_trylock(p->chan->_bridge)) { + return; + } + if (ast_check_hangup(p->chan->_bridge) || ast_channel_trylock(p->owner)) { + ast_channel_unlock(p->chan->_bridge); + return; + } + + /* + * At this point we have 4 locks: + * p, p->chan (same as ast), p->chan->_bridge, p->owner + * + * Flush a voice or video frame on the outbound channel to make + * the queue empty faster so we can get optimized out. + */ + f = AST_LIST_FIRST(&p->chan->readq); + if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { + AST_LIST_REMOVE_HEAD(&p->chan->readq, frame_list); + ast_frfree(f); + f = AST_LIST_FIRST(&p->chan->readq); + } + + if (f + || ast_check_hangup(p->owner) + || ast_channel_masquerade(p->owner, p->chan->_bridge)) { + ast_channel_unlock(p->owner); + ast_channel_unlock(p->chan->_bridge); + return; } + + /* Masquerade got setup. */ + ast_debug(4, "Masquerading %s <- %s\n", + p->owner->name, p->chan->_bridge->name); + if (p->owner->monitor && !p->chan->_bridge->monitor) { + struct ast_channel_monitor *tmp; + + /* If a local channel is being monitored, we don't want a masquerade + * to cause the monitor to go away. Since the masquerade swaps the monitors, + * pre-swapping the monitors before the masquerade will ensure that the monitor + * ends up where it is expected. + */ + tmp = p->owner->monitor; + p->owner->monitor = p->chan->_bridge->monitor; + p->chan->_bridge->monitor = tmp; + } + if (p->chan->audiohooks) { + struct ast_audiohook_list *audiohooks_swapper; + audiohooks_swapper = p->chan->audiohooks; + 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->caller.id.name.valid || p->owner->caller.id.number.valid + || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid + || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) { + struct ast_party_caller tmp; + + tmp = p->owner->caller; + p->owner->caller = p->chan->_bridge->caller; + p->chan->_bridge->caller = tmp; + } + if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid + || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid + || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) { + struct ast_party_redirecting tmp; + + tmp = p->owner->redirecting; + p->owner->redirecting = p->chan->_bridge->redirecting; + p->chan->_bridge->redirecting = tmp; + } + if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) { + struct ast_party_dialed tmp; + + tmp = p->owner->dialed; + p->owner->dialed = p->chan->_bridge->dialed; + p->chan->_bridge->dialed = tmp; + } + ast_app_group_update(p->chan, p->owner); + ast_set_flag(p, LOCAL_ALREADY_MASQED); + + ast_channel_unlock(p->owner); + ast_channel_unlock(p->chan->_bridge); + + /* Do the masquerade now. */ + owner = ast_channel_ref(p->owner); + ao2_unlock(p); + ast_channel_unlock(ast); + ast_do_masquerade(owner); + ast_channel_unref(owner); + ast_channel_lock(ast); + ao2_lock(p); } static struct ast_frame *local_read(struct ast_channel *ast) @@ -599,14 +641,16 @@ static int local_write(struct ast_channel *ast, struct ast_frame *f) ao2_lock(p); isoutbound = IS_OUTBOUND(ast, p); - if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { - check_bridge(p); + if (isoutbound + && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { + check_bridge(ast, p); } if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) { res = local_queue_frame(p, isoutbound, f, ast, 1); } else { - ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name); + ast_debug(1, "Not posting to '%s' queue since already masqueraded out\n", + ast->name); res = 0; } ao2_unlock(p); @@ -700,11 +744,20 @@ static int local_indicate(struct ast_channel *ast, int condition, const void *da } else { /* Queue up a frame representing the indication as a control frame */ ao2_lock(p); - isoutbound = IS_OUTBOUND(ast, p); - f.subclass.integer = condition; - f.data.ptr = (void*)data; - f.datalen = datalen; - res = local_queue_frame(p, isoutbound, &f, ast, 1); + /* + * Block -1 stop tones events if we are to be optimized out. We + * don't need a flurry of these events on a local channel chain + * when initially connected to slow the optimization process. + */ + if (0 <= condition || ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) { + isoutbound = IS_OUTBOUND(ast, p); + f.subclass.integer = condition; + f.data.ptr = (void *) data; + f.datalen = datalen; + res = local_queue_frame(p, isoutbound, &f, ast, 1); + } else { + ast_debug(4, "Blocked indication %d\n", condition); + } ao2_unlock(p); } diff --git a/channels/chan_sip.c b/channels/chan_sip.c index e1eb800c4b..b4b6d0b7e1 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -3203,7 +3203,7 @@ static int method_match(enum sipmethod id, const char *name) int len = strlen(sip_methods[id].text); int l_name = name ? strlen(name) : 0; /* true if the string is long enough, and ends with whitespace, and matches */ - return (l_name >= len && name[len] < 33 && + return (l_name >= len && name && name[len] < 33 && !strncasecmp(sip_methods[id].text, name, len)); } @@ -3507,7 +3507,7 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka } ast_debug(1, "Target address %s is not local, substituting externaddr\n", ast_sockaddr_stringify(them)); - } else if (p) { + } else { /* no remapping, but we bind to a specific address, so use it. */ switch (p->socket.type) { case SIP_TRANSPORT_TCP: @@ -3538,8 +3538,6 @@ static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_socka ast_sockaddr_set_port(us, ast_sockaddr_port(&bindaddr)); } } - } else if (!ast_sockaddr_is_any(&bindaddr)) { - ast_sockaddr_copy(us, &bindaddr); } ast_debug(3, "Setting SIP_TRANSPORT_%s with address %s\n", sip_get_transport(p->socket.type), ast_sockaddr_stringify(us)); } @@ -3682,7 +3680,7 @@ static int retrans_pkt(const void *data) pkt->retransid = -1; /* Kill this scheduler item */ - if (pkt->owner && pkt->method != SIP_OPTIONS && xmitres == 0) { + if (pkt->method != SIP_OPTIONS && xmitres == 0) { if (pkt->is_fatal || sipdebug) { /* Tell us if it's critical or if we're debugging */ ast_log(LOG_WARNING, "Retransmission timeout reached on transmission %s for seqno %u (%s %s) -- See https://wiki.asterisk.org/wiki/display/AST/SIP+Retransmissions\n" "Packet timed out after %dms with no response\n", @@ -3913,16 +3911,17 @@ static int __sip_autodestruct(const void *data) /* Reset schedule ID */ p->autokillid = -1; - /* * Lock both the pvt and the channel safely so that we can queue up a frame. */ owner = sip_pvt_lock_full(p); if (owner) { - ast_log(LOG_WARNING, "Autodestruct on dialog '%s' with owner in place (Method: %s)\n", p->callid, sip_methods[p->method].text); + ast_log(LOG_WARNING, "Autodestruct on dialog '%s' with owner in place (Method: %s). Rescheduling destruction for 10000 ms\n", p->callid, sip_methods[p->method].text); ast_queue_hangup_with_cause(owner, AST_CAUSE_PROTOCOL_ERROR); ast_channel_unlock(owner); ast_channel_unref(owner); + sip_pvt_unlock(p); + return 10000; } else if (p->refer && !p->alreadygone) { ast_debug(3, "Finally hanging up channel after transfer: %s\n", p->callid); stop_media_flows(p); @@ -6454,31 +6453,27 @@ static int sip_hangup(struct ast_channel *ast) ast_channel_unlock(bridge); } - if (p->do_history || oldowner) { - if (p->rtp && (quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) { - if (p->do_history) { - append_history(p, "RTCPaudio", "Quality:%s", quality); - } - if (oldowner) { - pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOS", quality); - } + /* + * The channel variables are set below just to get the AMI + * VarSet event because the channel is being hungup. + */ + if (p->rtp && (quality = ast_rtp_instance_get_quality(p->rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) { + if (p->do_history) { + append_history(p, "RTCPaudio", "Quality:%s", quality); } - if (p->vrtp && (quality = ast_rtp_instance_get_quality(p->vrtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) { - if (p->do_history) { - append_history(p, "RTCPvideo", "Quality:%s", quality); - } - if (oldowner) { - pbx_builtin_setvar_helper(oldowner, "RTPVIDEOQOS", quality); - } + pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOS", quality); + } + if (p->vrtp && (quality = ast_rtp_instance_get_quality(p->vrtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) { + if (p->do_history) { + append_history(p, "RTCPvideo", "Quality:%s", quality); } - if (p->trtp && (quality = ast_rtp_instance_get_quality(p->trtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) { - if (p->do_history) { - append_history(p, "RTCPtext", "Quality:%s", quality); - } - if (oldowner) { - pbx_builtin_setvar_helper(oldowner, "RTPTEXTQOS", quality); - } + pbx_builtin_setvar_helper(oldowner, "RTPVIDEOQOS", quality); + } + if (p->trtp && (quality = ast_rtp_instance_get_quality(p->trtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf)))) { + if (p->do_history) { + append_history(p, "RTCPtext", "Quality:%s", quality); } + pbx_builtin_setvar_helper(oldowner, "RTPTEXTQOS", quality); } /* Send a hangup */ @@ -7245,6 +7240,8 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit if (i->rtp) { ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0)); ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1)); + ast_rtp_instance_set_write_format(i->rtp, &fmt); + ast_rtp_instance_set_read_format(i->rtp, &fmt); } if (needvideo && i->vrtp) { ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0)); @@ -7264,11 +7261,9 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit ast_format_copy(&tmp->writeformat, &fmt); ast_format_copy(&tmp->rawwriteformat, &fmt); - ast_rtp_instance_set_write_format(i->rtp, &fmt); ast_format_copy(&tmp->readformat, &fmt); ast_format_copy(&tmp->rawreadformat, &fmt); - ast_rtp_instance_set_read_format(i->rtp, &fmt); tmp->tech_pvt = dialog_ref(i, "sip_new: set chan->tech_pvt to i"); @@ -7579,6 +7574,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p if (f && (f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END) && (ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_RFC2833)) { ast_debug(1, "Ignoring DTMF (%c) RTP frame because dtmfmode is not RFC2833\n", f->subclass.integer); + ast_frfree(f); return &ast_null_frame; } @@ -7591,6 +7587,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p if (!ast_format_cap_iscompatible(p->jointcaps, &f->subclass.format)) { ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n", ast_getformatname(&f->subclass.format), p->owner->name); + ast_frfree(f); return &ast_null_frame; } ast_debug(1, "Oooh, format changed to %s\n", @@ -7654,6 +7651,7 @@ static struct ast_frame *sip_read(struct ast_channel *ast) if (ast_async_goto(ast, target_context, "fax", 1)) { ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context); } + ast_frfree(fr); fr = &ast_null_frame; } else { ast_channel_lock(ast); @@ -7665,6 +7663,7 @@ static struct ast_frame *sip_read(struct ast_channel *ast) /* Only allow audio through if they sent progress with SDP, or if the channel is actually answered */ if (fr && fr->frametype == AST_FRAME_VOICE && p->invitestate != INV_EARLY_MEDIA && ast->_state != AST_STATE_UP) { + ast_frfree(fr); fr = &ast_null_frame; } @@ -8512,7 +8511,7 @@ static int sip_subscribe_mwi(const char *value, int lineno) int portnum = 0; enum sip_transport transport = SIP_TRANSPORT_UDP; char buf[256] = ""; - char *username = NULL, *hostname = NULL, *secret = NULL, *authuser = NULL, *porta = NULL, *mailbox = NULL, *at = NULL; + char *username = NULL, *hostname = NULL, *secret = NULL, *authuser = NULL, *porta = NULL, *mailbox = NULL; if (!value) { return -1; @@ -8520,13 +8519,12 @@ static int sip_subscribe_mwi(const char *value, int lineno) ast_copy_string(buf, value, sizeof(buf)); - if (!(at = strstr(buf, "@"))) { - return -1; - } + username = buf; if ((hostname = strrchr(buf, '@'))) { *hostname++ = '\0'; - username = buf; + } else { + return -1; } if ((secret = strchr(username, ':'))) { @@ -8936,6 +8934,9 @@ static void change_hold_state(struct sip_pvt *dialog, struct sip_request *req, i } /* No address for RTP, we're on hold */ + /* Ensure hold flags are cleared so that overlapping flags do not conflict */ + ast_clear_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD); + if (sendonly == 1) /* One directional hold (sendonly/recvonly) */ ast_set_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD_ONEDIR); else if (sendonly == 2) /* Inactive stream */ @@ -9014,7 +9015,7 @@ static int sockaddr_is_null_or_any(const struct ast_sockaddr *addr) return ast_sockaddr_isnull(addr) || ast_sockaddr_is_any(addr); } -/*! \brief Process SIP SDP offer, select formats and activate RTP channels +/*! \brief Process SIP SDP offer, select formats and activate media channels If offer is rejected, we will not change any properties of the call Return 0 on success, a negative value on errors. Must be called after find_sdp(). @@ -9041,16 +9042,16 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action struct ast_sockaddr videosa; struct ast_sockaddr textsa; struct ast_sockaddr imagesa; - struct ast_sockaddr *sa = NULL; /*!< RTP Audio host IP */ - struct ast_sockaddr *vsa = NULL; /*!< RTP video host IP */ - struct ast_sockaddr *tsa = NULL; /*!< RTP text host IP */ - struct ast_sockaddr *isa = NULL; /*!< UDPTL host ip */ - int portno = -1; /*!< RTP Audio port number */ - int vportno = -1; /*!< RTP Video port number */ - int tportno = -1; /*!< RTP Text port number */ - int udptlportno = -1; /*!< UDPTL Image port number */ - - /* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */ + struct ast_sockaddr *sa = NULL; /*!< RTP audio destination IP address */ + struct ast_sockaddr *vsa = NULL; /*!< RTP video destination IP address */ + struct ast_sockaddr *tsa = NULL; /*!< RTP text destination IP address */ + struct ast_sockaddr *isa = NULL; /*!< UDPTL image destination IP address */ + int portno = -1; /*!< RTP audio destination port number */ + int vportno = -1; /*!< RTP video destination port number */ + int tportno = -1; /*!< RTP text destination port number */ + int udptlportno = -1; /*!< UDPTL image destination port number */ + + /* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */ struct ast_format_cap *peercapability = ast_format_cap_alloc_nolock(); struct ast_format_cap *vpeercapability = ast_format_cap_alloc_nolock(); struct ast_format_cap *tpeercapability = ast_format_cap_alloc_nolock(); @@ -9075,9 +9076,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action int numberofports; int numberofmediastreams = 0; int last_rtpmap_codec = 0; - int red_data_pt[10]; /* For T.140 red */ - int red_num_gen = 0; /* For T.140 red */ - char red_fmtp[100] = "empty"; /* For T.140 red */ + int red_data_pt[10]; /* For T.140 RED */ + int red_num_gen = 0; /* For T.140 RED */ + char red_fmtp[100] = "empty"; /* For T.140 RED */ int debug = sip_debug_test_pvt(p); /* START UNKNOWN */ @@ -9106,14 +9107,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action memset(p->offered_media, 0, sizeof(p->offered_media)); - if (p->vrtp) { - ast_rtp_codecs_payloads_clear(&newvideortp, NULL); - } - - if (p->trtp) { - ast_rtp_codecs_payloads_clear(&newtextrtp, NULL); - } - /* Scan for the first media stream (m=) line to limit scanning of globals */ nextm = get_sdp_iterate(&next, req, "m"); if (ast_strlen_zero(nextm)) { @@ -9160,7 +9153,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action break; } - ast_debug(3, "Processing session-level SDP %c=%s... %s\n", type, value, (processed == TRUE)? "OK." : "UNSUPPORTED."); + ast_debug(3, "Processing session-level SDP %c=%s... %s\n", type, value, (processed == TRUE)? "OK." : "UNSUPPORTED OR FAILED."); } /* default: novideo and notext set */ @@ -9177,153 +9170,207 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action char protocol[5] = {0,}; int x; - numberofports = 1; + numberofports = 0; len = -1; start = next; m = nextm; iterator = next; nextm = get_sdp_iterate(&next, req, "m"); - /* Search for audio media definition */ - if ((sscanf(m, "audio %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) || - (sscanf(m, "audio %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0)) { - if (x == 0) { - ast_log(LOG_WARNING, "ignoring 'audio' media offer because port number is zero\n"); - continue; - } - if (!strcmp(protocol, "SAVP")) { - secure_audio = 1; - } else if (strcmp(protocol, "AVP")) { - ast_log(LOG_WARNING, "unknown SDP media protocol in offer: %s\n", protocol); - continue; - } - if (p->offered_media[SDP_AUDIO].order_offered) { - ast_log(LOG_WARNING, "Multiple audio streams are not supported\n"); - res = -3; - goto process_sdp_cleanup; - } - audio = TRUE; - p->offered_media[SDP_AUDIO].order_offered = ++numberofmediastreams; - portno = x; + /* Check for 'audio' media offer */ + if (strncmp(m, "audio ", 6) == 0) { + if ((sscanf(m, "audio %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) || + (sscanf(m, "audio %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0)) { + if (x == 0) { + ast_log(LOG_WARNING, "Ignoring audio media offer because port number is zero\n"); + continue; + } + + /* Check number of ports offered for stream */ + if (numberofports > 1) { + ast_log(LOG_WARNING, "%d ports offered for audio media, not supported by Asterisk. Will try anyway...\n", numberofports); + } + + if (!strcmp(protocol, "SAVP")) { + secure_audio = 1; + } else if (strcmp(protocol, "AVP")) { + ast_log(LOG_WARNING, "Unknown RTP profile in audio offer: %s\n", m); + continue; + } - /* Scan through the RTP payload types specified in a "m=" line: */ - codecs = m + len; - ast_copy_string(p->offered_media[SDP_AUDIO].codecs, codecs, sizeof(p->offered_media[SDP_AUDIO].codecs)); - for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) { - if (sscanf(codecs, "%30u%n", &codec, &len) != 1) { - ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs); + if (p->offered_media[SDP_AUDIO].order_offered) { + ast_log(LOG_WARNING, "Rejecting non-primary audio stream: %s\n", m); res = -1; goto process_sdp_cleanup; } - if (debug) - ast_verbose("Found RTP audio format %d\n", codec); - ast_rtp_codecs_payloads_set_m_type(&newaudiortp, NULL, codec); - } - /* Search for video media definition */ - } else if ((sscanf(m, "video %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) || - (sscanf(m, "video %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0)) { - if (x == 0) { - ast_log(LOG_WARNING, "ignoring 'video' media offer because port number is zero\n"); - continue; - } - if (!strcmp(protocol, "SAVP")) { - secure_video = 1; - } else if (strcmp(protocol, "AVP")) { - ast_log(LOG_WARNING, "unknown SDP media protocol in offer: %s\n", protocol); - continue; - } - if (p->offered_media[SDP_VIDEO].order_offered) { - ast_log(LOG_WARNING, "Multiple video streams are not supported\n"); - res = -3; + audio = TRUE; + p->offered_media[SDP_AUDIO].order_offered = ++numberofmediastreams; + portno = x; + + /* Scan through the RTP payload types specified in a "m=" line: */ + codecs = m + len; + ast_copy_string(p->offered_media[SDP_AUDIO].codecs, codecs, sizeof(p->offered_media[SDP_AUDIO].codecs)); + for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) { + if (sscanf(codecs, "%30u%n", &codec, &len) != 1) { + ast_log(LOG_WARNING, "Invalid syntax in RTP audio format list: %s\n", codecs); + res = -1; + goto process_sdp_cleanup; + } + if (debug) { + ast_verbose("Found RTP audio format %d\n", codec); + } + + ast_rtp_codecs_payloads_set_m_type(&newaudiortp, NULL, codec); + } + } else { + ast_log(LOG_WARNING, "Rejecting audio media offer due to invalid or unsupported syntax: %s\n", m); + res = -1; goto process_sdp_cleanup; } - video = TRUE; - p->novideo = FALSE; - p->offered_media[SDP_VIDEO].order_offered = ++numberofmediastreams; - vportno = x; - - /* Scan through the RTP payload types specified in a "m=" line: */ - codecs = m + len; - ast_copy_string(p->offered_media[SDP_VIDEO].codecs, codecs, sizeof(p->offered_media[SDP_VIDEO].codecs)); - for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) { - if (sscanf(codecs, "%30u%n", &codec, &len) != 1) { - ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs); + } + /* Check for 'video' media offer */ + else if (strncmp(m, "video ", 6) == 0) { + if ((sscanf(m, "video %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) || + (sscanf(m, "video %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0)) { + if (x == 0) { + ast_log(LOG_WARNING, "Ignoring video media offer because port number is zero\n"); + continue; + } + + /* Check number of ports offered for stream */ + if (numberofports > 1) { + ast_log(LOG_WARNING, "%d ports offered for video media, not supported by Asterisk. Will try anyway...\n", numberofports); + } + + if (!strcmp(protocol, "SAVP")) { + secure_video = 1; + } else if (strcmp(protocol, "AVP")) { + ast_log(LOG_WARNING, "Unknown RTP profile in video offer: %s\n", m); + continue; + } + + if (p->offered_media[SDP_VIDEO].order_offered) { + ast_log(LOG_WARNING, "Rejecting non-primary video stream: %s\n", m); res = -1; goto process_sdp_cleanup; } - if (debug) - ast_verbose("Found RTP video format %d\n", codec); - ast_rtp_codecs_payloads_set_m_type(&newvideortp, NULL, codec); - } - /* Search for text media definition */ - } else if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) || - (sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0)) { - if (x == 0) { - ast_log(LOG_WARNING, "ignoring 'text' media offer because port number is zero\n"); - continue; - } - if (p->offered_media[SDP_TEXT].order_offered) { - ast_log(LOG_WARNING, "Multiple text streams are not supported\n"); - res = -3; + + video = TRUE; + p->novideo = FALSE; + p->offered_media[SDP_VIDEO].order_offered = ++numberofmediastreams; + vportno = x; + + /* Scan through the RTP payload types specified in a "m=" line: */ + codecs = m + len; + ast_copy_string(p->offered_media[SDP_VIDEO].codecs, codecs, sizeof(p->offered_media[SDP_VIDEO].codecs)); + for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) { + if (sscanf(codecs, "%30u%n", &codec, &len) != 1) { + ast_log(LOG_WARNING, "Invalid syntax in RTP video format list: %s\n", codecs); + res = -1; + goto process_sdp_cleanup; + } + if (debug) { + ast_verbose("Found RTP video format %d\n", codec); + } + ast_rtp_codecs_payloads_set_m_type(&newvideortp, NULL, codec); + } + } else { + ast_log(LOG_WARNING, "Rejecting video media offer due to invalid or unsupported syntax: %s\n", m); + res = -1; goto process_sdp_cleanup; } - text = TRUE; - p->notext = FALSE; - p->offered_media[SDP_TEXT].order_offered = ++numberofmediastreams; - tportno = x; - - /* Scan through the RTP payload types specified in a "m=" line: */ - codecs = m + len; - ast_copy_string(p->offered_media[SDP_TEXT].codecs, codecs, sizeof(p->offered_media[SDP_TEXT].codecs)); - for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) { - if (sscanf(codecs, "%30u%n", &codec, &len) != 1) { - ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs); + } + /* Check for 'text' media offer */ + else if (strncmp(m, "text ", 5) == 0) { + if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) || + (sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0)) { + if (x == 0) { + ast_log(LOG_WARNING, "Ignoring text media offer because port number is zero\n"); + continue; + } + + /* Check number of ports offered for stream */ + if (numberofports > 1) { + ast_log(LOG_WARNING, "%d ports offered for text media, not supported by Asterisk. Will try anyway...\n", numberofports); + } + + if (p->offered_media[SDP_TEXT].order_offered) { + ast_log(LOG_WARNING, "Rejecting non-primary text stream: %s\n", m); res = -1; goto process_sdp_cleanup; } - if (debug) - ast_verbose("Found RTP text format %d\n", codec); - ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec); - } - /* Search for image media definition */ - } else if (((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0) || - (sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0))) { - if (x == 0) { - ast_log(LOG_WARNING, "ignoring 'image' media offer because port number is zero\n"); - continue; - } - if (initialize_udptl(p)) { - continue; - } - if (p->offered_media[SDP_IMAGE].order_offered) { - ast_log(LOG_WARNING, "Multiple T.38 streams are not supported\n"); - res = -3; + text = TRUE; + p->notext = FALSE; + p->offered_media[SDP_TEXT].order_offered = ++numberofmediastreams; + tportno = x; + + /* Scan through the RTP payload types specified in a "m=" line: */ + codecs = m + len; + ast_copy_string(p->offered_media[SDP_TEXT].codecs, codecs, sizeof(p->offered_media[SDP_TEXT].codecs)); + for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) { + if (sscanf(codecs, "%30u%n", &codec, &len) != 1) { + ast_log(LOG_WARNING, "Invalid syntax in RTP video format list: %s\n", codecs); + res = -1; + goto process_sdp_cleanup; + } + if (debug) { + ast_verbose("Found RTP text format %d\n", codec); + } + ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec); + } + } else { + ast_log(LOG_WARNING, "Rejecting text media offer due to invalid or unsupported syntax: %s\n", m); + res = -1; goto process_sdp_cleanup; } - image = TRUE; - if (debug) - ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid); - p->offered_media[SDP_IMAGE].order_offered = ++numberofmediastreams; - udptlportno = x; + } + /* Check for 'image' media offer */ + else if (strncmp(m, "image ", 6) == 0) { + if (((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0) || + (sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0))) { + if (x == 0) { + ast_log(LOG_WARNING, "Ignoring image media offer because port number is zero\n"); + continue; + } + + if (initialize_udptl(p)) { + res = -1; + goto process_sdp_cleanup; + } + + if (p->offered_media[SDP_IMAGE].order_offered) { + ast_log(LOG_WARNING, "Rejecting non-primary image stream: %s\n", m); + res = -1; + goto process_sdp_cleanup; + } + + image = TRUE; + if (debug) { + ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid); + } - if (p->t38.state != T38_ENABLED) { - memset(&p->t38.their_parms, 0, sizeof(p->t38.their_parms)); + p->offered_media[SDP_IMAGE].order_offered = ++numberofmediastreams; + udptlportno = x; - /* default EC to none, the remote end should - * respond with the EC they want to use */ - ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE); + if (p->t38.state != T38_ENABLED) { + memset(&p->t38.their_parms, 0, sizeof(p->t38.their_parms)); + + /* default EC to none, the remote end should + * respond with the EC they want to use */ + ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE); + } + } else { + ast_log(LOG_WARNING, "Rejecting image media offer due to invalid or unsupported syntax: %s\n", m); + res = -1; + goto process_sdp_cleanup; } } else { - ast_log(LOG_WARNING, "Unsupported SDP media type in offer: %s\n", m); + ast_log(LOG_WARNING, "Unsupported top-level media type in offer: %s\n", m); continue; } - /* Check for number of ports */ - if (numberofports > 1) - ast_log(LOG_WARNING, "SDP offered %d ports for media, not supported by Asterisk. Will try anyway...\n", numberofports); - /* Media stream specific parameters */ while ((type = get_sdp_line(&iterator, next - 1, req, &value)) != '\0') { int processed = FALSE; @@ -9393,13 +9440,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } ast_debug(3, "Processing media-level (%s) SDP %c=%s... %s\n", - (audio == TRUE)? "audio" : (video == TRUE)? "video" : "image", - type, value, - (processed == TRUE)? "OK." : "UNSUPPORTED."); + (audio == TRUE)? "audio" : (video == TRUE)? "video" : (text == TRUE)? "text" : "image", + type, value, + (processed == TRUE)? "OK." : "UNSUPPORTED OR FAILED."); } } - /* Sanity checks */ if (!sa && !vsa && !tsa && !isa) { ast_log(LOG_WARNING, "Insufficient information in SDP (c=)...\n"); @@ -9407,41 +9453,42 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action goto process_sdp_cleanup; } - if (portno == -1 && vportno == -1 && udptlportno == -1 && tportno == -1) { - /* No acceptable offer found in SDP - we have no ports */ - /* Do not change RTP or VRTP if this is a re-invite */ + if ((portno == -1) && + (vportno == -1) && + (tportno == -1) && + (udptlportno == -1)) { ast_log(LOG_WARNING, "Failing due to no acceptable offer found\n"); - res = -2; + res = -1; goto process_sdp_cleanup; } if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)))) { ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n"); - res = -4; + res = -1; goto process_sdp_cleanup; } if (!secure_audio && p->srtp) { - ast_log(LOG_WARNING, "We are requesting SRTP, but they responded without it!\n"); - res = -4; + ast_log(LOG_WARNING, "We are requesting SRTP for audio, but they responded without it!\n"); + res = -1; goto process_sdp_cleanup; } if (secure_video && !(p->vsrtp && (ast_test_flag(p->vsrtp, SRTP_CRYPTO_OFFER_OK)))) { ast_log(LOG_WARNING, "Can't provide secure video requested in SDP offer\n"); - res = -4; + res = -1; goto process_sdp_cleanup; } if (!p->novideo && !secure_video && p->vsrtp) { - ast_log(LOG_WARNING, "We are requesting SRTP, but they responded without it!\n"); - res = -4; + ast_log(LOG_WARNING, "We are requesting SRTP for video, but they responded without it!\n"); + res = -1; goto process_sdp_cleanup; } if (!(secure_audio || secure_video) && ast_test_flag(&p->flags[1], SIP_PAGE2_USE_SRTP)) { ast_log(LOG_WARNING, "Matched device setup to use SRTP, but request was not!\n"); - res = -4; + res = -1; goto process_sdp_cleanup; } @@ -9491,12 +9538,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action } if (portno != -1 || vportno != -1 || tportno != -1) { - /* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since + /* We are now ready to change the sip session and RTP structures with the offered codecs, since they are acceptable */ ast_format_cap_copy(p->jointcaps, newjointcapability); /* Our joint codec profile for this call */ - ast_format_cap_copy(p->peercaps, newpeercapability); /* The other sides capability in latest offer */ + ast_format_cap_copy(p->peercaps, newpeercapability); /* The other side's capability in latest offer */ p->jointnoncodeccapability = newnoncodeccapability; /* DTMF capabilities */ - + /* respond with single most preferred joint codec, limiting the other side's choice */ if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) { ast_codec_choose(&p->prefs, p->jointcaps, 1, &tmp_fmt); @@ -9590,6 +9637,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_verbose("Peer doesn't provide T.140\n"); } } + /* Setup image address and port */ if (p->udptl) { if (udptlportno > 0) { @@ -12869,13 +12917,14 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi) /* If we have no DNS manager let's do a lookup */ if (!mwi->dnsmgr) { char transport[MAXHOSTNAMELEN]; + struct sip_subscription_mwi *saved; snprintf(transport, sizeof(transport), "_%s._%s", get_srv_service(mwi->transport), get_srv_protocol(mwi->transport)); mwi->us.ss.ss_family = get_address_family_filter(&bindaddr); /* Filter address family */ - ASTOBJ_REF(mwi); /* Add a ref for storing the mwi on the dnsmgr for updates */ - ast_dnsmgr_lookup_cb(mwi->hostname, &mwi->us, &mwi->dnsmgr, sip_cfg.srvlookup ? transport : NULL, on_dns_update_mwi, mwi); + saved = ASTOBJ_REF(mwi); + ast_dnsmgr_lookup_cb(mwi->hostname, &mwi->us, &mwi->dnsmgr, sip_cfg.srvlookup ? transport : NULL, on_dns_update_mwi, saved); if (!mwi->dnsmgr) { - ASTOBJ_UNREF(mwi, sip_subscribe_mwi_destroy); /* dnsmgr disabled, remove reference */ + ASTOBJ_UNREF(saved, sip_subscribe_mwi_destroy); /* dnsmgr disabled, remove reference */ } } @@ -13102,6 +13151,16 @@ static void state_notify_build_xml(struct state_notify_data *data, int full, con if ((data->state & AST_EXTENSION_RINGING) && sip_cfg.notifyringing) { const char *local_display = exten; char *local_target = ast_strdupa(mto); + const char *remote_display = exten; + /* It may seem odd to base the remote_target on the To header here, + * but testing by reporters on issue ASTERISK-16735 found that basing + * on the From header would cause ringing state hints to not work + * properly on certain SNOM devices. If you are using notifycid properly + * (i.e. in the same extension and context as the dialed call) then this + * should not be an issue since the data will be overwritten shortly + * with channel caller ID + */ + char *remote_target = ast_strdupa(mto); /* There are some limitations to how this works. The primary one is that the callee must be dialing the same extension that is being monitored. Simply dialing @@ -13111,16 +13170,28 @@ static void state_notify_build_xml(struct state_notify_data *data, int full, con if ((caller = ast_channel_callback(find_calling_channel, NULL, p, 0))) { char *cid_num; + char *connected_num; int need; ast_channel_lock(caller); cid_num = S_COR(caller->caller.id.number.valid, caller->caller.id.number.str, ""); need = strlen(cid_num) + strlen(p->fromdomain) + sizeof("sip:@"); - local_target = alloca(need); - snprintf(local_target, need, "sip:%s@%s", cid_num, p->fromdomain); - local_display = ast_strdupa(S_COR(caller->caller.id.name.valid, + remote_target = alloca(need); + snprintf(remote_target, need, "sip:%s@%s", cid_num, p->fromdomain); + + remote_display = ast_strdupa(S_COR(caller->caller.id.name.valid, caller->caller.id.name.str, "")); + + connected_num = S_COR(caller->connected.id.number.valid, + caller->connected.id.number.str, ""); + need = strlen(connected_num) + strlen(p->fromdomain) + sizeof("sip:@"); + local_target = alloca(need); + snprintf(local_target, need, "sip:%s@%s", connected_num, p->fromdomain); + + local_display = ast_strdupa(S_COR(caller->connected.id.name.valid, + caller->connected.id.name.str, "")); + ast_channel_unlock(caller); caller = ast_channel_unref(caller); } @@ -13142,10 +13213,10 @@ static void state_notify_build_xml(struct state_notify_data *data, int full, con "\n" "\n" "\n" - "%s\n" + "%s\n" "\n" "\n", - local_display, local_target, local_target, mto, mto); + remote_display, remote_target, remote_target, local_display, local_target, local_target); } else { ast_str_append(tmp, 0, "\n", exten); } @@ -15235,6 +15306,20 @@ static void extract_host_from_hostport(char **hostport) ast_sockaddr_split_hostport(*hostport, hostport, &dont_care, PARSE_PORT_IGNORE); } +/*! \internal \brief Helper function to update a peer's lastmsgssent value + */ +static void update_peer_lastmsgssent(struct sip_peer *peer, int value, int locked) +{ + if (!locked) { + ao2_lock(peer); + } + peer->lastmsgssent = value; + if (!locked) { + ao2_unlock(peer); + } +} + + /*! \brief Verify registration of user - Registration is done in several steps, first a REGISTER without auth to get a challenge (nonce) then a second one with auth @@ -15244,11 +15329,11 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock struct sip_request *req, const char *uri) { enum check_auth_result res = AUTH_NOT_FOUND; - int sendmwi = 0; struct sip_peer *peer; char tmp[256]; char *c, *name, *unused_password, *domain; char *uri2 = ast_strdupa(uri); + int send_mwi = 0; terminate_uri(uri2); @@ -15363,15 +15448,15 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock ast_string_field_set(p, fullcontact, peer->fullcontact); transmit_response_with_date(p, "200 OK", req); res = 0; - sendmwi = 1; + send_mwi = 1; break; case PARSE_REGISTER_UPDATE: ast_string_field_set(p, fullcontact, peer->fullcontact); update_peer(peer, p->expiry); /* Say OK and ask subsystem to retransmit msg counter */ transmit_response_with_date(p, "200 OK", req); + send_mwi = 1; res = 0; - sendmwi = 1; break; } } @@ -15405,26 +15490,28 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock case PARSE_REGISTER_QUERY: ast_string_field_set(p, fullcontact, peer->fullcontact); transmit_response_with_date(p, "200 OK", req); + send_mwi = 1; res = 0; - sendmwi = 1; break; case PARSE_REGISTER_UPDATE: ast_string_field_set(p, fullcontact, peer->fullcontact); /* Say OK and ask subsystem to retransmit msg counter */ transmit_response_with_date(p, "200 OK", req); manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\n", peer->name, ast_sockaddr_stringify(addr)); + send_mwi = 1; res = 0; - sendmwi = 1; break; } ao2_unlock(peer); } } if (!res) { - if (sendmwi) { + if (send_mwi) { ao2_unlock(p); sip_send_mwi_to_peer(peer, 0); ao2_lock(p); + } else { + update_peer_lastmsgssent(peer, -1, 0); } ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name); } @@ -15790,7 +15877,9 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c char *end_quote; rname = tmp + 1; end_quote = strchr(rname, '\"'); - *end_quote = '\0'; + if (end_quote) { + *end_quote = '\0'; + } } if (number) { @@ -16413,7 +16502,9 @@ static void check_via(struct sip_pvt *p, struct sip_request *req) p->sa = p->recv; } - ast_sockaddr_resolve_first(&tmp, c, 0); + if (ast_sockaddr_resolve_first(&tmp, c, 0)) { + ast_log(LOG_WARNING, "Could not resolve socket address for '%s'\n", c); + } port = ast_sockaddr_port(&tmp); ast_sockaddr_set_port(&p->sa, port != 0 ? port : STANDARD_SIP_PORT); @@ -16517,6 +16608,8 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, else p->timer_b = 64 * p->timer_t1; + p->allowtransfer = peer->allowtransfer; + if (ast_test_flag(&peer->flags[0], SIP_INSECURE_INVITE)) { /* Pretend there is no required authentication */ ast_string_field_set(p, peersecret, NULL); @@ -16730,6 +16823,7 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ /* Finally, apply the guest policy */ if (sip_cfg.allowguest) { + /* Ignore check_return warning from Coverity for get_rpid below. */ get_rpid(p, req); p->rtptimeout = global_rtptimeout; p->rtpholdtimeout = global_rtpholdtimeout; @@ -18187,6 +18281,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct ast_cli(fd, " MOH Suggest : %s\n", peer->mohsuggest); ast_cli(fd, " Mailbox : %s\n", mailbox_str->str); ast_cli(fd, " VM Extension : %s\n", peer->vmexten); + ast_cli(fd, " LastMsgsSent : %d/%d\n", (peer->lastmsgssent & 0x7fff0000) >> 16, peer->lastmsgssent & 0xffff); ast_cli(fd, " Call limit : %d\n", peer->call_limit); ast_cli(fd, " Max forwards : %d\n", peer->maxforwards); if (peer->busy_level) @@ -18299,6 +18394,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct peer_mailboxes_to_str(&mailbox_str, peer); astman_append(s, "VoiceMailbox: %s\r\n", mailbox_str->str); astman_append(s, "TransferMode: %s\r\n", transfermode2str(peer->allowtransfer)); + astman_append(s, "LastMsgsSent: %d\r\n", peer->lastmsgssent); astman_append(s, "Maxforwards: %d\r\n", peer->maxforwards); astman_append(s, "Call-limit: %d\r\n", peer->call_limit); astman_append(s, "Busy-level: %d\r\n", peer->busy_level); @@ -18650,7 +18746,10 @@ static int show_chanstats_cb(void *__cur, void *__arg, int flags) return 0; /* don't care, we scan all channels */ } - ast_rtp_instance_get_stats(cur->rtp, &stats, AST_RTP_INSTANCE_STAT_ALL); + if (ast_rtp_instance_get_stats(cur->rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) { + ast_log(LOG_WARNING, "Could not get RTP stats.\n"); + return 0; + } if (c && c->cdr && !ast_tvzero(c->cdr->start)) { duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000); @@ -21016,7 +21115,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest ast_log(LOG_WARNING, "Received response: \"Forbidden\" from '%s'\n", sip_get_header(&p->initreq, "From")); if (!req->ignore && p->owner) { ast_set_hangupsource(p->owner, p->owner->name, 0); - ast_queue_hangup_with_cause(p->owner, AST_CAUSE_CONGESTION); + ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp)); } break; @@ -21024,7 +21123,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE); if (p->owner && !req->ignore) { ast_set_hangupsource(p->owner, p->owner->name, 0); - ast_queue_hangup_with_cause(p->owner, AST_CAUSE_CONGESTION); + ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp)); } break; @@ -21034,7 +21133,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest ast_log(LOG_WARNING, "Re-invite to non-existing call leg on other UA. SIP dialog '%s'. Giving up.\n", p->callid); xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE); if (p->owner) { - ast_queue_hangup_with_cause(p->owner, AST_CAUSE_CONGESTION); + ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp)); } break; @@ -21049,7 +21148,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest append_history(p, "Identity", "SIP identity is required. Not supported by Asterisk."); ast_log(LOG_WARNING, "SIP identity required by proxy. SIP dialog '%s'. Giving up.\n", p->callid); if (p->owner && !req->ignore) { - ast_queue_hangup_with_cause(p->owner, AST_CAUSE_CONGESTION); + ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp)); } break; @@ -21082,7 +21181,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest } else { /* We can't set up this call, so give up */ if (p->owner && !req->ignore) { - ast_queue_hangup_with_cause(p->owner, AST_CAUSE_CONGESTION); + ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp)); } } break; @@ -21090,7 +21189,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE); if (p->owner && !req->ignore) { if (p->owner->_state != AST_STATE_UP) { - ast_queue_hangup_with_cause(p->owner, AST_CAUSE_CONGESTION); + ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp)); } else { /* This is a re-invite that failed. */ /* Reset the flag after a while @@ -21114,7 +21213,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest case 501: /* Not implemented */ xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE); if (p->owner) { - ast_queue_hangup_with_cause(p->owner, AST_CAUSE_CONGESTION); + ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp)); } break; } @@ -22036,7 +22135,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc default: /* Send hangup */ if (owner && sipmethod != SIP_BYE) - ast_queue_hangup_with_cause(p->owner, AST_CAUSE_PROTOCOL_ERROR); + ast_queue_hangup_with_cause(p->owner, hangup_sip2cause(resp)); break; } /* ACK on invite */ @@ -23126,9 +23225,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int } } transmit_response_reliable(p, "491 Request Pending", req); - p->pendinginvite = seqno; check_via(p, req); - copy_request(&p->initreq, req); ast_debug(1, "Got INVITE on call where we already have pending INVITE, deferring that - %s\n", p->callid); /* Don't destroy dialog here */ res = INV_REQ_FAILED; @@ -23148,7 +23245,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int if (p->owner) { ast_debug(3, "INVITE w Replaces on existing call? Refusing action. [%s]\n", p->callid); transmit_response_reliable(p, "400 Bad request", req); /* The best way to not not accept the transfer */ - p->pendinginvite = seqno; check_via(p, req); copy_request(&p->initreq, req); /* Do not destroy existing call */ @@ -23168,7 +23264,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); p->invitestate = INV_COMPLETED; res = INV_REQ_ERROR; - p->pendinginvite = seqno; check_via(p, req); copy_request(&p->initreq, req); goto request_invite_cleanup; @@ -23273,7 +23368,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int refer_locked = 0; p->invitestate = INV_COMPLETED; res = INV_REQ_ERROR; - p->pendinginvite = seqno; check_via(p, req); copy_request(&p->initreq, req); goto request_invite_cleanup; @@ -25177,6 +25271,7 @@ static int cc_esc_publish_handler(struct sip_pvt *pvt, struct sip_request *req, * document earlier. So there's no need to enclose this operation in an if statement. */ tuple_children = ast_xml_node_get_children(tuple_node); + /* coverity[null_returns: FALSE] */ status_node = ast_xml_find_element(tuple_children, "status", NULL, NULL); if (!(status_children = ast_xml_node_get_children(status_node))) { @@ -25507,7 +25602,8 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sip_peer *authpeer = NULL; const char *eventheader = sip_get_header(req, "Event"); /* Get Event package name */ int resubscribe = (p->subscribed != NONE) && !req->ignore; - char *temp, *event; + char *event_end; + ptrdiff_t event_len = 0; if (p->initreq.headers) { /* We already have a dialog */ @@ -25569,13 +25665,10 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, return 0; } - if ( (strchr(eventheader, ';'))) { - event = ast_strdupa(eventheader); /* Since eventheader is a const, we can't change it */ - temp = strchr(event, ';'); - *temp = '\0'; /* Remove any options for now */ - /* We might need to use them later :-) */ - } else - event = (char *) eventheader; /* XXX is this legal ? */ + event_end = strchr(eventheader, ';'); + if (event_end) { + event_len = event_end - eventheader; + } /* Handle authentication if we're new and not a retransmission. We can't just * use if !req->ignore, because then we'll end up sending @@ -25614,7 +25707,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, return 0; } - if (strcmp(event, "message-summary") && strcmp(event, "call-completion")) { + if (strncmp(eventheader, "message-summary", MAX(event_len, 15)) && strncmp(eventheader, "call-completion", MAX(event_len, 15))) { /* Get destination right away */ gotdest = get_destination(p, NULL, NULL); } @@ -25640,7 +25733,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, if (ast_strlen_zero(p->tag)) make_our_tag(p->tag, sizeof(p->tag)); - if (!strcmp(event, "presence") || !strcmp(event, "dialog")) { /* Presence, RFC 3842 */ + if (!strncmp(eventheader, "presence", MAX(event_len, 8)) || !strncmp(eventheader, "dialog", MAX(event_len, 6))) { /* Presence, RFC 3842 */ unsigned int pidf_xml; const char *accept; int start = 0; @@ -25718,7 +25811,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, } else { p->subscribed = subscribed; } - } else if (!strcmp(event, "message-summary")) { + } else if (!strncmp(eventheader, "message-summary", MAX(event_len, 15))) { int start = 0; int found_supported = 0; const char *acceptheader; @@ -25783,11 +25876,11 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, p->relatedpeer = sip_ref_peer(authpeer, "setting dialog's relatedpeer pointer"); } /* Do not release authpeer here */ - } else if (!strcmp(event, "call-completion")) { + } else if (!strncmp(eventheader, "call-completion", MAX(event_len, 15))) { handle_cc_subscribe(p, req); } else { /* At this point, Asterisk does not understand the specified event */ transmit_response(p, "489 Bad Event", req); - ast_debug(2, "Received SIP subscribe for unknown event package: %s\n", event); + ast_debug(2, "Received SIP subscribe for unknown event package: %s\n", eventheader); pvt_set_needdestroy(p, "unknown event package"); if (authpeer) { sip_unref_peer(authpeer, "sip_unref_peer, from handle_request_subscribe (authpeer 5)"); @@ -25808,9 +25901,10 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, } } - if (!req->ignore && p) + if (!req->ignore) { p->lastinvite = seqno; - if (p && !p->needdestroy) { + } + if (!p->needdestroy) { p->expiry = atoi(sip_get_header(req, "Expires")); /* check if the requested expiry-time is within the approved limits from sip.conf */ @@ -26147,13 +26241,13 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct as if (!req->ignore && req->method == SIP_INVITE) { transmit_response_reliable(p, "481 Call/Transaction Does Not Exist", req); /* Will cease to exist after ACK */ + return res; } else if (req->method != SIP_ACK) { transmit_response(p, "481 Call/Transaction Does Not Exist", req); sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); - } else { - ast_debug(1, "Got ACK for unknown dialog... strange.\n"); + return res; } - return res; + /* Otherwise, this is an ACK. It will always have a to-tag */ } } @@ -26567,7 +26661,7 @@ create_tcptls_session_fail: ao2_t_ref(ca, -1, "failed to create client, getting rid of client tcptls_session arguments"); } if (s->tcptls_session) { - ast_tcptls_close_session_file(tcptls_session); + ast_tcptls_close_session_file(s->tcptls_session); s->fd = -1; ao2_ref(s->tcptls_session, -1); s->tcptls_session = NULL; @@ -26624,12 +26718,14 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only) } if (ast_test_flag((&peer->flags[1]), SIP_PAGE2_SUBSCRIBEMWIONLY) && !peer->mwipvt) { + update_peer_lastmsgssent(peer, -1, 1); ao2_unlock(peer); return -1; } /* Do we have an IP address? If not, skip this peer */ if (ast_sockaddr_isnull(&peer->addr) && ast_sockaddr_isnull(&peer->defaddr)) { + update_peer_lastmsgssent(peer, -1, 1); ao2_unlock(peer); return -1; } @@ -26645,6 +26741,11 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only) return -1; } ao2_unlock(peer); + /* If there is no mailbox do nothing */ + if (ast_strlen_zero(mailbox_str->str)) { + update_peer_lastmsgssent(peer, -1, 0); + return 0; + } ast_app_inboxcount(mailbox_str->str, &newmsgs, &oldmsgs); ao2_lock(peer); } @@ -26657,6 +26758,7 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only) ao2_unlock(peer); /* Build temporary dialog for this message */ if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) { + update_peer_lastmsgssent(peer, -1, 0); return -1; } @@ -26669,7 +26771,7 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only) /* Maybe they're not registered, etc. */ dialog_unlink_all(p); dialog_unref(p, "unref dialog p just created via sip_alloc"); - /* sip_destroy(p); */ + update_peer_lastmsgssent(peer, -1, 0); return -1; } /* Recalculate our side, and recalculate Call ID */ @@ -26702,6 +26804,8 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only) sip_pvt_unlock(p); dialog_unref(p, "unref dialog ptr p just before it goes out of scope at the end of sip_send_mwi_to_peer."); + update_peer_lastmsgssent(peer, ((newmsgs > 0x7fff ? 0x7fff0000 : (newmsgs << 16)) | (oldmsgs > 0xffff ? 0xffff : oldmsgs)), 0); + return 0; } @@ -27202,8 +27306,12 @@ enum st_refresher st_get_refresher(struct sip_pvt *p) */ enum st_mode st_get_mode(struct sip_pvt *p, int no_cached) { - if (!p->stimer) + if (!p->stimer) { sip_st_alloc(p); + if (!p->stimer) { + return SESSION_TIMER_MODE_INVALID; + } + } if (!no_cached && p->stimer->st_cached_mode != SESSION_TIMER_MODE_INVALID) return p->stimer->st_cached_mode; @@ -28429,32 +28537,42 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str } else if (!strcasecmp(v->name, "fromuser")) { ast_string_field_set(peer, fromuser, v->value); } else if (!strcasecmp(v->name, "outboundproxy")) { - char *tok, *proxyname; + char *host, *proxyname, *sep; if (ast_strlen_zero(v->value)) { - ast_log(LOG_WARNING, "no value given for outbound proxy on line %d of sip.conf.", v->lineno); + ast_log(LOG_WARNING, "no value given for outbound proxy on line %d of sip.conf\n", v->lineno); continue; } - peer->outboundproxy = - ao2_alloc(sizeof(*peer->outboundproxy), NULL); - - tok = ast_skip_blanks(strtok(ast_strdupa(v->value), ",")); - - sip_parse_host(tok, v->lineno, &proxyname, - &peer->outboundproxy->port, - &peer->outboundproxy->transport); + if (!peer->outboundproxy) { + peer->outboundproxy = ao2_alloc(sizeof(*peer->outboundproxy), NULL); + if (!peer->outboundproxy) { + ast_log(LOG_WARNING, "Unable to allocate config storage for outboundproxy\n"); + continue; + } + } - tok = ast_skip_blanks(strtok(ast_strdupa(v->value), ",")); + host = ast_strdupa(v->value); + if (!host) { + ast_log(LOG_WARNING, "Unable to allocate stack space for parsing outboundproxy\n"); + continue; + } - if ((tok = strtok(NULL, ","))) { - peer->outboundproxy->force = !strncasecmp(ast_skip_blanks(tok), "force", 5); + host = ast_skip_blanks(host); + sep = strchr(host, ','); + if (sep) { + *sep++ = '\0'; + peer->outboundproxy->force = !strncasecmp(ast_skip_blanks(sep), "force", 5); } else { peer->outboundproxy->force = FALSE; } + sip_parse_host(host, v->lineno, &proxyname, + &peer->outboundproxy->port, + &peer->outboundproxy->transport); + if (ast_strlen_zero(proxyname)) { - ast_log(LOG_WARNING, "you must specify a name for the outboundproxy on line %d of sip.conf.", v->lineno); + ast_log(LOG_WARNING, "you must specify a name for the outboundproxy on line %d of sip.conf\n", v->lineno); sip_cfg.outboundproxy.name[0] = '\0'; continue; } @@ -29026,6 +29144,11 @@ static int reload_config(enum channelreloadreason reason) ast_config_destroy(ucfg); return 1; } + if (!cfg) { + /* should have been able to reload here */ + ast_log(LOG_NOTICE, "Unable to load config %s\n", config); + return -1; + } } else if (cfg == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", config); return 1; @@ -29428,27 +29551,34 @@ static int reload_config(enum channelreloadreason reason) default_fromdomainport = STANDARD_SIP_PORT; } } else if (!strcasecmp(v->name, "outboundproxy")) { - char *tok, *proxyname; + char *host, *proxyname, *sep; if (ast_strlen_zero(v->value)) { - ast_log(LOG_WARNING, "no value given for outbound proxy on line %d of sip.conf.", v->lineno); + ast_log(LOG_WARNING, "no value given for outbound proxy on line %d of sip.conf\n", v->lineno); continue; } - tok = ast_skip_blanks(strtok(ast_strdupa(v->value), ",")); - - sip_parse_host(tok, v->lineno, &proxyname, - &sip_cfg.outboundproxy.port, - &sip_cfg.outboundproxy.transport); + host = ast_strdupa(v->value); + if (!host) { + ast_log(LOG_WARNING, "Unable to allocate stack space for parsing outboundproxy\n"); + continue; + } - if ((tok = strtok(NULL, ","))) { - sip_cfg.outboundproxy.force = !strncasecmp(ast_skip_blanks(tok), "force", 5); + host = ast_skip_blanks(host); + sep = strchr(host, ','); + if (sep) { + *sep++ = '\0'; + sip_cfg.outboundproxy.force = !strncasecmp(ast_skip_blanks(sep), "force", 5); } else { sip_cfg.outboundproxy.force = FALSE; } + sip_parse_host(host, v->lineno, &proxyname, + &sip_cfg.outboundproxy.port, + &sip_cfg.outboundproxy.transport); + if (ast_strlen_zero(proxyname)) { - ast_log(LOG_WARNING, "you must specify a name for the outboundproxy on line %d of sip.conf.", v->lineno); + ast_log(LOG_WARNING, "you must specify a name for the outboundproxy on line %d of sip.conf\n", v->lineno); sip_cfg.outboundproxy.name[0] = '\0'; continue; } @@ -30067,15 +30197,15 @@ static int reload_config(enum channelreloadreason reason) return 0; } -static int apply_directmedia_ha(struct sip_pvt *p, const char *op) +static int apply_directmedia_ha(struct sip_pvt *p1, struct sip_pvt *p2, const char *op) { struct ast_sockaddr us = { { 0, }, }, them = { { 0, }, }; int res = AST_SENSE_ALLOW; - ast_rtp_instance_get_remote_address(p->rtp, &them); - ast_rtp_instance_get_local_address(p->rtp, &us); + ast_rtp_instance_get_remote_address(p1->rtp, &them); + ast_rtp_instance_get_local_address(p1->rtp, &us); - if ((res = ast_apply_ha(p->directmediaha, &them)) == AST_SENSE_DENY) { + if ((res = ast_apply_ha(p2->relatedpeer->directmediaha, &them)) == AST_SENSE_DENY) { const char *us_addr = ast_strdupa(ast_sockaddr_stringify(&us)); const char *them_addr = ast_strdupa(ast_sockaddr_stringify(&them)); @@ -30089,19 +30219,35 @@ static int apply_directmedia_ha(struct sip_pvt *p, const char *op) static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan) { struct sip_pvt *p; + struct ast_channel *opp_chan; + struct sip_pvt *opp; struct ast_udptl *udptl = NULL; - + p = chan->tech_pvt; if (!p) { return NULL; } - + + if (!(opp_chan = ast_bridged_channel(chan))) { + return NULL; + } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) { + return NULL; + } + sip_pvt_lock(p); + while (sip_pvt_trylock(opp)) { + sip_pvt_unlock(p); + usleep(1); + sip_pvt_lock(p); + } + if (p->udptl && ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) { - if (apply_directmedia_ha(p, "UDPTL T.38 data")) { + if (apply_directmedia_ha(p, opp, "UDPTL T.38 data")) { udptl = p->udptl; } } + + sip_pvt_unlock(opp); sip_pvt_unlock(p); return udptl; } @@ -30152,14 +30298,29 @@ static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl) static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance) { struct sip_pvt *p = NULL; + struct ast_channel *opp_chan; + struct sip_pvt *opp = NULL; enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL; if (!(p = chan->tech_pvt)) { return AST_RTP_GLUE_RESULT_FORBID; } + if (!(opp_chan = ast_bridged_channel(chan))) { + return AST_RTP_GLUE_RESULT_FORBID; + } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) { + return AST_RTP_GLUE_RESULT_FORBID; + } + sip_pvt_lock(p); + while (sip_pvt_trylock(opp)) { + sip_pvt_unlock(p); + usleep(1); + sip_pvt_lock(p); + } + if (!(p->rtp)) { + sip_pvt_unlock(opp); sip_pvt_unlock(p); return AST_RTP_GLUE_RESULT_FORBID; } @@ -30169,7 +30330,7 @@ static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struc if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) { res = AST_RTP_GLUE_RESULT_REMOTE; - if (!apply_directmedia_ha(p, "audio")) { + if (!apply_directmedia_ha(p, opp, "audio")) { res = AST_RTP_GLUE_RESULT_FORBID; } } else if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)) { @@ -30178,6 +30339,8 @@ static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struc res = AST_RTP_GLUE_RESULT_FORBID; } + sip_pvt_unlock(opp); + if (p->srtp) { res = AST_RTP_GLUE_RESULT_FORBID; } @@ -30190,14 +30353,29 @@ static enum ast_rtp_glue_result sip_get_rtp_peer(struct ast_channel *chan, struc static enum ast_rtp_glue_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance) { struct sip_pvt *p = NULL; + struct ast_channel *opp_chan; + struct sip_pvt *opp = NULL; enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID; if (!(p = chan->tech_pvt)) { return AST_RTP_GLUE_RESULT_FORBID; } + if (!(opp_chan = ast_bridged_channel(chan))) { + return AST_RTP_GLUE_RESULT_FORBID; + } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) { + return AST_RTP_GLUE_RESULT_FORBID; + } + sip_pvt_lock(p); + while (sip_pvt_trylock(opp)) { + sip_pvt_unlock(p); + usleep(1); + sip_pvt_lock(p); + } + if (!(p->vrtp)) { + sip_pvt_unlock(opp); sip_pvt_unlock(p); return AST_RTP_GLUE_RESULT_FORBID; } @@ -30207,11 +30385,12 @@ static enum ast_rtp_glue_result sip_get_vrtp_peer(struct ast_channel *chan, stru if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) { res = AST_RTP_GLUE_RESULT_REMOTE; - if (!apply_directmedia_ha(p, "video")) { + if (!apply_directmedia_ha(p, opp, "video")) { res = AST_RTP_GLUE_RESULT_FORBID; } } + sip_pvt_unlock(opp); sip_pvt_unlock(p); return res; @@ -30220,14 +30399,29 @@ static enum ast_rtp_glue_result sip_get_vrtp_peer(struct ast_channel *chan, stru static enum ast_rtp_glue_result sip_get_trtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance) { struct sip_pvt *p = NULL; + struct ast_channel *opp_chan; + struct sip_pvt *opp = NULL; enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID; if (!(p = chan->tech_pvt)) { return AST_RTP_GLUE_RESULT_FORBID; } + if (!(opp_chan = ast_bridged_channel(chan))) { + return AST_RTP_GLUE_RESULT_FORBID; + } else if ((opp_chan->tech != &sip_tech) || (!(opp = opp_chan->tech_pvt))) { + return AST_RTP_GLUE_RESULT_FORBID; + } + sip_pvt_lock(p); + while (sip_pvt_trylock(opp)) { + sip_pvt_unlock(p); + usleep(1); + sip_pvt_lock(p); + } + if (!(p->trtp)) { + sip_pvt_unlock(opp); sip_pvt_unlock(p); return AST_RTP_GLUE_RESULT_FORBID; } @@ -30237,11 +30431,12 @@ static enum ast_rtp_glue_result sip_get_trtp_peer(struct ast_channel *chan, stru if (ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA)) { res = AST_RTP_GLUE_RESULT_REMOTE; - if (!apply_directmedia_ha(p, "text")) { + if (!apply_directmedia_ha(p, opp, "text")) { res = AST_RTP_GLUE_RESULT_FORBID; } } + sip_pvt_unlock(opp); sip_pvt_unlock(p); return res; @@ -30671,10 +30866,12 @@ static void sip_send_all_registers(void) static void sip_send_all_mwi_subscriptions(void) { ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do { + struct sip_subscription_mwi *saved; ASTOBJ_WRLOCK(iterator); AST_SCHED_DEL(sched, iterator->resub); - if ((iterator->resub = ast_sched_add(sched, 1, sip_subscribe_mwi_do, ASTOBJ_REF(iterator))) < 0) { - ASTOBJ_UNREF(iterator, sip_subscribe_mwi_destroy); + saved = ASTOBJ_REF(iterator); + if ((iterator->resub = ast_sched_add(sched, 1, sip_subscribe_mwi_do, saved)) < 0) { + ASTOBJ_UNREF(saved, sip_subscribe_mwi_destroy); } ASTOBJ_UNLOCK(iterator); } while (0)); @@ -31611,6 +31808,7 @@ static int unload_module(void) if (sip_tls_desc.master) { ast_tcptls_server_stop(&sip_tls_desc); } + ast_ssl_teardown(sip_tls_desc.tls_cfg); /* Kill all existing TCP/TLS threads */ i = ao2_iterator_init(threadt, 0); diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 9ee5979ffd..6d5557cd0a 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -3110,6 +3110,10 @@ static void update_connectedline(struct skinny_subchannel *sub, const void *data struct skinny_line *l = sub->line; struct skinny_device *d = l->device; + if (!d) { + return; + } + if (!c->caller.id.number.valid || ast_strlen_zero(c->caller.id.number.str) || !c->connected.id.number.valid @@ -4230,6 +4234,11 @@ static void *skinny_ss(void *data) int res = 0; int loop_pause = 100; + if (!d) { + ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name); + return NULL; + } + ast_verb(3, "Starting simple switch on '%s@%s'\n", l->name, d->name); len = strlen(sub->exten); @@ -4338,7 +4347,7 @@ static int skinny_call(struct ast_channel *ast, char *dest, int timeout) struct ast_var_t *current; int doautoanswer = 0; - if (!d->registered) { + if (!d || !d->registered) { ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest); return -1; } @@ -4737,7 +4746,13 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s struct skinny_subchannel *sub = ast->tech_pvt; struct skinny_line *l = sub->line; struct skinny_device *d = l->device; - struct skinnysession *s = d->session; + struct skinnysession *s; + + if (!d) { + ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name); + return -1; + } + s = d->session; if (!s) { ast_log(LOG_NOTICE, "Asked to indicate '%s' condition on channel %s, but session does not exist.\n", control2str(ind), ast->name); @@ -5471,6 +5486,11 @@ static int handle_transfer_button(struct skinny_subchannel *sub) l = sub->line; d = l->device; + if (!d) { + ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name); + return -1; + } + if (!sub->related) { /* Another sub has not been created so this must be first XFER press */ if (!(sub->substate == SUBSTATE_HOLD)) { @@ -5515,6 +5535,11 @@ static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype struct skinny_device *d = l->device; struct ast_channel *c = sub->owner; + if (!d) { + ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name); + return 0; + } + if (d->hookstate == SKINNY_ONHOOK) { d->hookstate = SKINNY_OFFHOOK; transmit_speaker_mode(d, SKINNY_SPEAKERON); diff --git a/channels/iax2-parser.c b/channels/iax2-parser.c index ce9af244d8..7b12badf01 100644 --- a/channels/iax2-parser.c +++ b/channels/iax2-parser.c @@ -1192,7 +1192,7 @@ struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheab AST_LIST_TRAVERSE_SAFE_END; } if (!fr) { - if (iax_frames->size >= FRAME_CACHE_MAX_SIZE && smallest) { + if (iax_frames && iax_frames->size >= FRAME_CACHE_MAX_SIZE && smallest) { /* Make useless cache into something more useful */ AST_LIST_REMOVE(&iax_frames->list, smallest, list); if (!(fr = ast_realloc(smallest, sizeof(*fr) + datalen))) { diff --git a/channels/iax2-provision.c b/channels/iax2-provision.c index 26c7a0b5d5..e4af32d212 100644 --- a/channels/iax2-provision.c +++ b/channels/iax2-provision.c @@ -258,7 +258,11 @@ int iax_provision_version(unsigned int *version, const char *template, int force memset(&ied, 0, sizeof(ied)); ast_mutex_lock(&provlock); - ast_db_get("iax/provisioning/cache", template, tmp, sizeof(tmp)); + if (!(ast_db_get("iax/provisioning/cache", template, tmp, sizeof(tmp)))) { + ast_log(LOG_ERROR, "ast_db_get failed to retrieve iax/provisioning/cache\n"); + ast_mutex_unlock(&provlock); + return -1; + } if (sscanf(tmp, "v%30x", version) != 1) { if (strcmp(tmp, "u")) { ret = iax_provision_build(&ied, version, template, force); diff --git a/channels/sig_analog.c b/channels/sig_analog.c index 92d67be197..aded6054d7 100644 --- a/channels/sig_analog.c +++ b/channels/sig_analog.c @@ -2744,7 +2744,10 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_ analog_train_echocanceller(p); ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr)); p->dop.op = ANALOG_DIAL_OP_REPLACE; - analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop); + if (analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop)) { + int dial_err = errno; + ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(dial_err)); + } p->echobreak = 0; } else { analog_set_dialing(p, 0); diff --git a/channels/sig_pri.c b/channels/sig_pri.c index 48633ab7ce..fd01f50606 100644 --- a/channels/sig_pri.c +++ b/channels/sig_pri.c @@ -115,13 +115,6 @@ static int pri_gendigittimeout = 8000; #define DCHAN_AVAILABLE (DCHAN_NOTINALARM | DCHAN_UP) -#define PRI_DEADLOCK_AVOIDANCE(p) \ - do { \ - sig_pri_unlock_private(p); \ - usleep(1); \ - sig_pri_lock_private(p); \ - } while (0) - static int pri_active_dchan_index(struct sig_pri_span *pri); static const char *sig_pri_call_level2str(enum sig_pri_call_level level) @@ -349,23 +342,23 @@ static void sig_pri_deadlock_avoidance_private(struct sig_pri_chan *p) p->calls->deadlock_avoidance_private(p->chan_pvt); } else { /* Fallback to the old way if callback not present. */ - PRI_DEADLOCK_AVOIDANCE(p); + sig_pri_unlock_private(p); + sched_yield(); + sig_pri_lock_private(p); } } static void pri_grab(struct sig_pri_chan *p, struct sig_pri_span *pri) { - int res; - /* Grab the lock first */ - do { - res = ast_mutex_trylock(&pri->lock); - if (res) { - sig_pri_deadlock_avoidance_private(p); - } - } while (res); + while (ast_mutex_trylock(&pri->lock)) { + /* Avoid deadlock */ + sig_pri_deadlock_avoidance_private(p); + } /* Then break the poll */ - pthread_kill(pri->master, SIGURG); + if (pri->master != AST_PTHREADT_NULL) { + pthread_kill(pri->master, SIGURG); + } } /*! @@ -1203,10 +1196,11 @@ static void sig_pri_lock_owner(struct sig_pri_span *pri, int chanpos) /* We got the lock */ break; } - /* We must unlock the PRI to avoid the possibility of a deadlock */ - ast_mutex_unlock(&pri->lock); - sig_pri_deadlock_avoidance_private(pri->pvts[chanpos]); - ast_mutex_lock(&pri->lock); + + /* Avoid deadlock */ + sig_pri_unlock_private(pri->pvts[chanpos]); + DEADLOCK_AVOIDANCE(&pri->lock); + sig_pri_lock_private(pri->pvts[chanpos]); } } diff --git a/channels/sig_ss7.c b/channels/sig_ss7.c index b7472c40a4..a8a3887887 100644 --- a/channels/sig_ss7.c +++ b/channels/sig_ss7.c @@ -67,13 +67,6 @@ static const char *sig_ss7_call_level2str(enum sig_ss7_call_level level) return "Unknown"; } -#define SIG_SS7_DEADLOCK_AVOIDANCE(p) \ - do { \ - sig_ss7_unlock_private(p); \ - usleep(1); \ - sig_ss7_lock_private(p); \ - } while (0) - static void sig_ss7_unlock_private(struct sig_ss7_chan *p) { if (p->calls->unlock_private) { @@ -94,7 +87,9 @@ static void sig_ss7_deadlock_avoidance_private(struct sig_ss7_chan *p) p->calls->deadlock_avoidance_private(p->chan_pvt); } else { /* Fallback to the old way if callback not present. */ - SIG_SS7_DEADLOCK_AVOIDANCE(p); + sig_ss7_unlock_private(p); + sched_yield(); + sig_ss7_lock_private(p); } } @@ -314,10 +309,11 @@ static void sig_ss7_lock_owner(struct sig_ss7_linkset *ss7, int chanpos) /* We got the lock */ break; } - /* We must unlock the SS7 to avoid the possibility of a deadlock */ - ast_mutex_unlock(&ss7->lock); - sig_ss7_deadlock_avoidance_private(ss7->pvts[chanpos]); - ast_mutex_lock(&ss7->lock); + + /* Avoid deadlock */ + sig_ss7_unlock_private(ss7->pvts[chanpos]); + DEADLOCK_AVOIDANCE(&ss7->lock); + sig_ss7_lock_private(ss7->pvts[chanpos]); } } @@ -1266,17 +1262,15 @@ static inline void ss7_rel(struct sig_ss7_linkset *ss7) static void ss7_grab(struct sig_ss7_chan *pvt, struct sig_ss7_linkset *ss7) { - int res; /* Grab the lock first */ - do { - res = ast_mutex_trylock(&ss7->lock); - if (res) { - sig_ss7_deadlock_avoidance_private(pvt); - } - } while (res); + while (ast_mutex_trylock(&ss7->lock)) { + /* Avoid deadlock */ + sig_ss7_deadlock_avoidance_private(pvt); + } /* Then break the poll */ - if (ss7->master != AST_PTHREADT_NULL) + if (ss7->master != AST_PTHREADT_NULL) { pthread_kill(ss7->master, SIGURG); + } } /*! diff --git a/channels/sip/config_parser.c b/channels/sip/config_parser.c index 72a7b2c7d0..0093a23795 100644 --- a/channels/sip/config_parser.c +++ b/channels/sip/config_parser.c @@ -530,7 +530,48 @@ AST_TEST_DEFINE(sip_parse_register_line_test) ast_string_field_free_memory(reg); ast_free(reg); - /* ---Test reg12, add domain port --- */ + /* ---Test reg 9, missing domain, expected to fail --- */ + if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) { + goto alloc_fail; + } else if (!sip_parse_register_line(reg, default_expiry, reg9, 1)) { + ast_test_status_update(test, + "Test 9, missing domain, expected to fail but did not.\n"); + res = AST_TEST_FAIL; + } + ast_string_field_free_memory(reg); + ast_free(reg); + + /* ---Test reg 10, missing user, expected to fail --- */ + if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) { + goto alloc_fail; + } else if (!sip_parse_register_line(reg, default_expiry, reg10, 1)) { + ast_test_status_update(test, + "Test 10, missing user expected to fail but did not\n"); + res = AST_TEST_FAIL; + } + ast_string_field_free_memory(reg); + ast_free(reg); + + /* ---Test reg 11, no registry object, expected to fail--- */ + if (!sip_parse_register_line(NULL, default_expiry, reg1, 1)) { + ast_test_status_update(test, + "Test 11, no registry object, expected to fail but did not.\n"); + res = AST_TEST_FAIL; + } + + /* ---Test reg 12, no registry line, expected to fail --- */ + if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) { + goto alloc_fail; + } else if (!sip_parse_register_line(reg, default_expiry, NULL, 1)) { + + ast_test_status_update(test, + "Test 12, NULL register line expected to fail but did not.\n"); + res = AST_TEST_FAIL; + } + ast_string_field_free_memory(reg); + ast_free(reg); + + /* ---Test reg13, add domain port --- */ if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) { goto alloc_fail; } else if ( @@ -553,11 +594,13 @@ AST_TEST_DEFINE(sip_parse_register_line_test) reg->callid_valid != FALSE || reg->ocseq != INITIAL_CSEQ) { - ast_test_status_update(test, "Test 12, add domain port failed.\n"); + ast_test_status_update(test, "Test 13, add domain port failed.\n"); res = AST_TEST_FAIL; } + ast_string_field_free_memory(reg); + ast_free(reg); - /* ---Test reg13, domain port without secret --- */ + /* ---Test reg14, domain port without secret --- */ if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) { goto alloc_fail; } else if ( @@ -580,46 +623,7 @@ AST_TEST_DEFINE(sip_parse_register_line_test) reg->callid_valid != FALSE || reg->ocseq != INITIAL_CSEQ) { - ast_test_status_update(test, "Test 13, domain port without secret failed.\n"); - res = AST_TEST_FAIL; -} - - /* ---Test reg 9, missing domain, expected to fail --- */ - if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) { - goto alloc_fail; - } else if (!sip_parse_register_line(reg, default_expiry, reg9, 1)) { - ast_test_status_update(test, - "Test 9, missing domain, expected to fail but did not.\n"); - res = AST_TEST_FAIL; - } - ast_string_field_free_memory(reg); - ast_free(reg); - - /* ---Test reg 10, missing user, expected to fail --- */ - if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) { - goto alloc_fail; - } else if (!sip_parse_register_line(reg, default_expiry, reg10, 1)) { - ast_test_status_update(test, - "Test 10, missing user expected to fail but did not\n"); - res = AST_TEST_FAIL; - } - ast_string_field_free_memory(reg); - ast_free(reg); - - /* ---Test reg 11, no registry object, expected to fail--- */ - if (!sip_parse_register_line(NULL, default_expiry, reg1, 1)) { - ast_test_status_update(test, - "Test 11, no registry object, expected to fail but did not.\n"); - res = AST_TEST_FAIL; - } - - /* ---Test reg 11, no registry line, expected to fail --- */ - if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) { - goto alloc_fail; - } else if (!sip_parse_register_line(reg, default_expiry, NULL, 1)) { - - ast_test_status_update(test, - "Test 11, NULL register line expected to fail but did not.\n"); + ast_test_status_update(test, "Test 14, domain port without secret failed.\n"); res = AST_TEST_FAIL; } ast_string_field_free_memory(reg); @@ -638,6 +642,7 @@ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum s char *port; if (ast_strlen_zero(line)) { + *hostname = NULL; return -1; } if ((*hostname = strstr(line, "://"))) { diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 8e0581a01d..a6cf8a425b 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -1275,6 +1275,7 @@ struct sip_peer { int maxforwards; /*!< SIP Loop prevention */ enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */ struct ast_codec_pref prefs; /*!< codec prefs */ + int lastmsgssent; /*!< The last known VM message counts (new/old) */ unsigned int sipoptions; /*!< Supported SIP options */ struct ast_flags flags[3]; /*!< SIP_ flags */ diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c index b646f7bbb5..e37d75b793 100644 --- a/channels/sip/reqresp_parser.c +++ b/channels/sip/reqresp_parser.c @@ -217,7 +217,7 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, } -AST_TEST_DEFINE(sip_parse_uri_fully_test) +AST_TEST_DEFINE(sip_parse_uri_full_test) { int res = AST_TEST_PASS; char uri[1024]; @@ -227,12 +227,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata { char *desc; char *uri; - char **userptr; - char **passptr; - char **hostportptr; - char **headersptr; - char **residueptr; - struct uriparams *paramsptr; char *user; char *pass; char *hostport; @@ -250,12 +244,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata td1 = { .desc = "no headers", .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=residue", - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .user = "user", .pass = "secret", .hostport = "host:5060", @@ -269,12 +257,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata td2 = { .desc = "with headers", .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=discard2?header=blah&header2=blah2;param3=residue", - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .user = "user", .pass = "secret", .hostport = "host:5060", @@ -288,12 +270,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata td3 = { .desc = "difficult user", .uri = "sip:-_.!~*'()&=+$,;?/:secret@host:5060;transport=tcp", - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .user = "-_.!~*'()&=+$,;?/", .pass = "secret", .hostport = "host:5060", @@ -307,12 +283,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata td4 = { .desc = "difficult pass", .uri = "sip:user:-_.!~*'()&=+$,@host:5060;transport=tcp", - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .user = "user", .pass = "-_.!~*'()&=+$,", .hostport = "host:5060", @@ -326,12 +296,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata td5 = { .desc = "difficult host", .uri = "sip:user:secret@1-1.a-1.:5060;transport=tcp", - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .user = "user", .pass = "secret", .hostport = "1-1.a-1.:5060", @@ -345,12 +309,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata td6 = { .desc = "difficult params near transport", .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$;transport=tcp", - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .user = "user", .pass = "secret", .hostport = "host:5060", @@ -364,12 +322,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata td7 = { .desc = "difficult params near headers", .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$?header=blah&header2=blah2;-_.!~*'()[]/:&+$=residue", - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .user = "user", .pass = "secret", .hostport = "host:5060", @@ -383,12 +335,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata td8 = { .desc = "lr parameter", .uri = "sip:user:secret@host:5060;param=discard;lr?header=blah", - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .user = "user", .pass = "secret", .hostport = "host:5060", @@ -402,12 +348,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata td9 = { .desc = "alternative lr parameter", .uri = "sip:user:secret@host:5060;param=discard;lr=yes?header=blah", - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .user = "user", .pass = "secret", .hostport = "host:5060", @@ -421,12 +361,6 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) struct testdata td10 = { .desc = "no lr parameter", .uri = "sip:user:secret@host:5060;paramlr=lr;lr=no;lr=off;lr=0;lr=;=lr;lrextra;lrparam2=lr?header=blah", - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .user = "user", .pass = "secret", .hostport = "host:5060", @@ -469,19 +403,19 @@ AST_TEST_DEFINE(sip_parse_uri_fully_test) params.lr = 0; ast_copy_string(uri,testdataptr->uri,sizeof(uri)); - if (parse_uri_full(uri, "sip:,sips:", testdataptr->userptr, - testdataptr->passptr, testdataptr->hostportptr, - testdataptr->paramsptr, - testdataptr->headersptr, - testdataptr->residueptr) || - ((testdataptr->userptr) && strcmp(testdataptr->user, user)) || - ((testdataptr->passptr) && strcmp(testdataptr->pass, pass)) || - ((testdataptr->hostportptr) && strcmp(testdataptr->hostport, hostport)) || - ((testdataptr->headersptr) && strcmp(testdataptr->headers, headers)) || - ((testdataptr->residueptr) && strcmp(testdataptr->residue, residue)) || - ((testdataptr->paramsptr) && strcmp(testdataptr->params.transport,params.transport)) || - ((testdataptr->paramsptr) && (testdataptr->params.lr != params.lr)) || - ((testdataptr->paramsptr) && strcmp(testdataptr->params.user,params.user)) + if (parse_uri_full(uri, "sip:,sips:", &user, + &pass, &hostport, + ¶ms, + &headers, + &residue) || + (user && strcmp(testdataptr->user, user)) || + (pass && strcmp(testdataptr->pass, pass)) || + (hostport && strcmp(testdataptr->hostport, hostport)) || + (headers && strcmp(testdataptr->headers, headers)) || + (residue && strcmp(testdataptr->residue, residue)) || + (strcmp(testdataptr->params.transport,params.transport)) || + (testdataptr->params.lr != params.lr) || + (strcmp(testdataptr->params.user,params.user)) ) { ast_test_status_update(test, "Sub-Test: %s, failed.\n", testdataptr->desc); res = AST_TEST_FAIL; @@ -1220,13 +1154,6 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) struct testdata { char *desc; char *uri; - char **nameptr; - char **userptr; - char **passptr; - char **hostportptr; - char **headersptr; - char **residueptr; - struct uriparams *paramsptr; char *name; char *user; char *pass; @@ -1244,13 +1171,6 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) struct testdata td1 = { .desc = "quotes and brackets", .uri = "\"name :@ \" ;tag=tag", - .nameptr = &name, - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .name = "name :@ ", .user = "user", .pass = "secret", @@ -1265,13 +1185,6 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) struct testdata td2 = { .desc = "no quotes", .uri = "givenname familyname ;expires=3600", - .nameptr = &name, - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .name = "givenname familyname", .user = "user", .pass = "secret", @@ -1286,13 +1199,6 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) struct testdata td3 = { .desc = "no brackets", .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;q=1", - .nameptr = &name, - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .name = "", .user = "user", .pass = "secret", @@ -1307,13 +1213,6 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) struct testdata td4 = { .desc = "just host", .uri = "sips:host", - .nameptr = &name, - .userptr = &user, - .passptr = &pass, - .hostportptr = &hostport, - .headersptr = &headers, - .residueptr = &residue, - .paramsptr = ¶ms, .name = "", .user = "", .pass = "", @@ -1351,21 +1250,21 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) params.lr = 0; ast_copy_string(uri,testdataptr->uri,sizeof(uri)); if (parse_name_andor_addr(uri, "sip:,sips:", - testdataptr->nameptr, - testdataptr->userptr, - testdataptr->passptr, - testdataptr->hostportptr, - testdataptr->paramsptr, - testdataptr->headersptr, - testdataptr->residueptr) || - ((testdataptr->nameptr) && strcmp(testdataptr->name, name)) || - ((testdataptr->userptr) && strcmp(testdataptr->user, user)) || - ((testdataptr->passptr) && strcmp(testdataptr->pass, pass)) || - ((testdataptr->hostportptr) && strcmp(testdataptr->hostport, hostport)) || - ((testdataptr->headersptr) && strcmp(testdataptr->headers, headers)) || - ((testdataptr->residueptr) && strcmp(testdataptr->residue, residue)) || - ((testdataptr->paramsptr) && strcmp(testdataptr->params.transport,params.transport)) || - ((testdataptr->paramsptr) && strcmp(testdataptr->params.user,params.user)) + &name, + &user, + &pass, + &hostport, + ¶ms, + &headers, + &residue) || + (name && strcmp(testdataptr->name, name)) || + (user && strcmp(testdataptr->user, user)) || + (pass && strcmp(testdataptr->pass, pass)) || + (hostport && strcmp(testdataptr->hostport, hostport)) || + (headers && strcmp(testdataptr->headers, headers)) || + (residue && strcmp(testdataptr->residue, residue)) || + (strcmp(testdataptr->params.transport,params.transport)) || + (strcmp(testdataptr->params.user,params.user)) ) { ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc); res = AST_TEST_FAIL; @@ -2579,7 +2478,7 @@ void sip_request_parser_register_tests(void) AST_TEST_REGISTER(sip_parse_uri_test); AST_TEST_REGISTER(get_in_brackets_test); AST_TEST_REGISTER(get_name_and_number_test); - AST_TEST_REGISTER(sip_parse_uri_fully_test); + AST_TEST_REGISTER(sip_parse_uri_full_test); AST_TEST_REGISTER(parse_name_andor_addr_test); AST_TEST_REGISTER(parse_contact_header_test); AST_TEST_REGISTER(sip_parse_options_test); @@ -2592,7 +2491,7 @@ void sip_request_parser_unregister_tests(void) AST_TEST_UNREGISTER(get_calleridname_test); AST_TEST_UNREGISTER(get_in_brackets_test); AST_TEST_UNREGISTER(get_name_and_number_test); - AST_TEST_UNREGISTER(sip_parse_uri_fully_test); + AST_TEST_UNREGISTER(sip_parse_uri_full_test); AST_TEST_UNREGISTER(parse_name_andor_addr_test); AST_TEST_UNREGISTER(parse_contact_header_test); AST_TEST_UNREGISTER(sip_parse_options_test); diff --git a/codecs/codec_dahdi.c b/codecs/codec_dahdi.c index 2eec96d064..ccd323ae68 100644 --- a/codecs/codec_dahdi.c +++ b/codecs/codec_dahdi.c @@ -56,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define G723_SAMPLES 240 #define G729_SAMPLES 160 +#define ULAW_SAMPLES 160 #ifndef DAHDI_FORMAT_MAX_AUDIO #define DAHDI_FORMAT_G723_1 (1 << 0) @@ -103,6 +104,7 @@ struct codec_dahdi_pvt { unsigned int fake:2; uint16_t required_samples; uint16_t samples_in_buffer; + uint16_t samples_written_to_hardware; uint8_t ulaw_buffer[1024]; }; @@ -174,7 +176,6 @@ static char *handle_cli_transcoder_show(struct ast_cli_entry *e, int cmd, struct static void dahdi_write_frame(struct codec_dahdi_pvt *dahdip, const uint8_t *buffer, const ssize_t count) { int res; - struct pollfd p = {0}; if (!count) return; res = write(dahdip->fd, buffer, count); if (option_verbose > 10) { @@ -185,9 +186,6 @@ static void dahdi_write_frame(struct codec_dahdi_pvt *dahdip, const uint8_t *buf ast_log(LOG_ERROR, "Requested write of %zd bytes, but only wrote %d bytes.\n", count, res); } } - p.fd = dahdip->fd; - p.events = POLLOUT; - res = poll(&p, 1, 50); } static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) @@ -220,8 +218,9 @@ static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) dahdip->samples_in_buffer += f->samples; } - while (dahdip->samples_in_buffer > dahdip->required_samples) { + while (dahdip->samples_in_buffer >= dahdip->required_samples) { dahdi_write_frame(dahdip, dahdip->ulaw_buffer, dahdip->required_samples); + dahdip->samples_written_to_hardware += dahdip->required_samples; dahdip->samples_in_buffer -= dahdip->required_samples; if (dahdip->samples_in_buffer) { /* Shift any remaining bytes down. */ @@ -234,6 +233,14 @@ static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) return -1; } +static void dahdi_wait_for_packet(int fd) +{ + struct pollfd p = {0}; + p.fd = fd; + p.events = POLLIN; + poll(&p, 1, 10); +} + static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt) { struct codec_dahdi_pvt *dahdip = pvt->pvt; @@ -257,6 +264,10 @@ static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt) return NULL; } + if (dahdip->samples_written_to_hardware >= dahdip->required_samples) { + dahdi_wait_for_packet(dahdip->fd); + } + res = read(dahdip->fd, pvt->outbuf.c + pvt->datalen, pvt->t->buf_size - pvt->datalen); if (-1 == res) { if (EWOULDBLOCK == errno) { @@ -276,6 +287,10 @@ static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt) pvt->f.data.ptr = pvt->outbuf.c; pvt->f.samples = ast_codec_get_samples(&pvt->f); + dahdip->samples_written_to_hardware = + (dahdip->samples_written_to_hardware >= pvt->f.samples) ? + dahdip->samples_written_to_hardware - pvt->f.samples : 0; + pvt->samples = 0; pvt->datalen = 0; return ast_frisolate(&pvt->f); @@ -302,6 +317,7 @@ static int dahdi_decoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) } } dahdi_write_frame(dahdip, f->data.ptr, f->datalen); + dahdip->samples_written_to_hardware += f->samples; pvt->samples += f->samples; pvt->datalen = 0; return -1; @@ -329,6 +345,10 @@ static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt) return NULL; } + if (dahdip->samples_written_to_hardware >= ULAW_SAMPLES) { + dahdi_wait_for_packet(dahdip->fd); + } + /* Let's check to see if there is a new frame for us.... */ if (dahdip->softslin) { res = read(dahdip->fd, dahdip->ulaw_buffer, sizeof(dahdip->ulaw_buffer)); @@ -360,6 +380,9 @@ static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt) pvt->f.data.ptr = pvt->outbuf.c; pvt->f.samples = res; pvt->samples = 0; + dahdip->samples_written_to_hardware = + (dahdip->samples_written_to_hardware >= res) ? + dahdip->samples_written_to_hardware - res : 0; return ast_frisolate(&pvt->f); } diff --git a/funcs/func_aes.c b/funcs/func_aes.c index c176f48635..2e1959cd8f 100644 --- a/funcs/func_aes.c +++ b/funcs/func_aes.c @@ -114,6 +114,10 @@ static int aes_helper(struct ast_channel *chan, const char *cmd, char *data, ast_aes_set_encrypt_key((unsigned char *) args.key, &ecx); /* encryption: plaintext -> encryptedtext -> base64 */ ast_aes_set_decrypt_key((unsigned char *) args.key, &dcx); /* decryption: base64 -> encryptedtext -> plaintext */ tmp = ast_calloc(1, len); /* requires a tmp buffer for the base64 decode */ + if (!tmp) { + ast_log(LOG_ERROR, "Unable to allocate memory for data\n"); + return -1; + } tmpP = tmp; encrypt = strcmp("AES_DECRYPT", cmd); /* -1 if encrypting, 0 if decrypting */ diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c index 25e10a2fa4..0e025c0584 100644 --- a/funcs/func_cdr.c +++ b/funcs/func_cdr.c @@ -197,7 +197,7 @@ AST_APP_OPTIONS(cdr_func_options, { static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len) { - char *ret; + char *ret = NULL; struct ast_flags flags = { 0 }; struct ast_cdr *cdr; AST_DECLARE_APP_ARGS(args, diff --git a/funcs/func_channel.c b/funcs/func_channel.c index da015d5d7c..dbf41a1759 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -253,6 +253,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") R/O PRI Nonzero if the channel has no B channel. The channel is either on hold or a call waiting call. + + W/O Change the channel's buffer policy (for the current call only) + This option takes two arguments: + Number of buffers, + Buffer policy being one of: + full + immediate + half + + + W/O Change the configuration of the active echo + canceller on the channel (if any), for the current call + only. + Possible values are: + on Normal mode (the echo canceller is actually reinitalized) + off Disabled + fax FAX/data mode (NLP disabled if possible, otherwise + completely disabled) + voice Voice mode (returns from FAX mode, reverting the changes that were made) + chan_ooh323 provides the following additional options: diff --git a/funcs/func_devstate.c b/funcs/func_devstate.c index 1b1318a5d2..e1f34387a1 100644 --- a/funcs/func_devstate.c +++ b/funcs/func_devstate.c @@ -187,6 +187,7 @@ static enum ast_device_state custom_devstate_callback(const char *data) { char buf[256] = ""; + /* Ignore check_return warning from Coverity fow ast_db_get below */ ast_db_get(astdb_family, data, buf, sizeof(buf)); return ast_devstate_val(buf); diff --git a/funcs/func_dialgroup.c b/funcs/func_dialgroup.c index c3322e3f9b..0e078cd80d 100644 --- a/funcs/func_dialgroup.c +++ b/funcs/func_dialgroup.c @@ -165,6 +165,7 @@ static int dialgroup_read(struct ast_channel *chan, const char *cmd, char *data, ao2_ref(entry, -1); } ao2_iterator_destroy(&i); + ao2_ref(grhead, -1); return res; } diff --git a/funcs/func_lock.c b/funcs/func_lock.c index da01e01b82..ef09ed02fb 100644 --- a/funcs/func_lock.c +++ b/funcs/func_lock.c @@ -373,10 +373,15 @@ static int get_lock(struct ast_channel *chan, char *lockname, int trylock) static int unlock_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { - struct ast_datastore *lock_store = ast_channel_datastore_find(chan, &lock_info, NULL); + struct ast_datastore *lock_store; struct channel_lock_frame *clframe; AST_LIST_HEAD(, channel_lock_frame) *list; + if (!chan) { + return -1; + } + + lock_store = ast_channel_datastore_find(chan, &lock_info, NULL); if (!lock_store) { ast_log(LOG_WARNING, "No datastore for dialplan locks. Nothing was ever locked!\n"); ast_copy_string(buf, "0", len); @@ -417,26 +422,24 @@ static int unlock_read(struct ast_channel *chan, const char *cmd, char *data, ch static int lock_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { - if (chan) - ast_autoservice_start(chan); - + if (!chan) { + return -1; + } + ast_autoservice_start(chan); ast_copy_string(buf, get_lock(chan, data, 0) ? "0" : "1", len); - - if (chan) - ast_autoservice_stop(chan); + ast_autoservice_stop(chan); return 0; } static int trylock_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { - if (chan) - ast_autoservice_start(chan); - + if (!chan) { + return -1; + } + ast_autoservice_start(chan); ast_copy_string(buf, get_lock(chan, data, 1) ? "0" : "1", len); - - if (chan) - ast_autoservice_stop(chan); + ast_autoservice_stop(chan); return 0; } @@ -486,9 +489,11 @@ static int unload_module(void) ast_custom_function_unregister(&trylock_function); ast_custom_function_unregister(&unlock_function); - pthread_cancel(broker_tid); - pthread_kill(broker_tid, SIGURG); - pthread_join(broker_tid, NULL); + if (broker_tid != AST_PTHREADT_NULL) { + pthread_cancel(broker_tid); + pthread_kill(broker_tid, SIGURG); + pthread_join(broker_tid, NULL); + } AST_LIST_UNLOCK(&locklist); @@ -500,7 +505,14 @@ static int load_module(void) int res = ast_custom_function_register(&lock_function); res |= ast_custom_function_register(&trylock_function); res |= ast_custom_function_register(&unlock_function); - ast_pthread_create_background(&broker_tid, NULL, lock_broker, NULL); + + if (ast_pthread_create_background(&broker_tid, NULL, lock_broker, NULL)) { + ast_log(LOG_ERROR, "Failed to start lock broker thread. Unloading func_lock module.\n"); + broker_tid = AST_PTHREADT_NULL; + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } + return res; } diff --git a/funcs/func_math.c b/funcs/func_math.c index e7217c7b3d..e745c4733f 100644 --- a/funcs/func_math.c +++ b/funcs/func_math.c @@ -57,7 +57,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") number1opnumber2 where the possible values for op are: - +,-,/,*,%,<<,>>,^,AND,OR,XOR,<,%gt;,>=,<=,== (and behave as their C equivalents) + +,-,/,*,%,<<,>>,^,AND,OR,XOR,<,>,<=,>=,== (and behave as their C equivalents) Wanted type of result: @@ -254,7 +254,7 @@ static int math(struct ast_channel *chan, const char *cmd, char *parse, } } - if (!mvalue1 || !mvalue2) { + if (!mvalue2) { ast_log(LOG_WARNING, "Supply all the parameters - just this once, please\n"); return -1; diff --git a/funcs/func_odbc.c b/funcs/func_odbc.c index edb69f0930..e2a6a62d5b 100644 --- a/funcs/func_odbc.c +++ b/funcs/func_odbc.c @@ -151,6 +151,11 @@ static void odbc_datastore_free(void *data) { struct odbc_datastore *result = data; struct odbc_datastore_row *row; + + if (!result) { + return; + } + AST_LIST_LOCK(result); while ((row = AST_LIST_REMOVE_HEAD(result, list))) { ast_free(row); @@ -539,6 +544,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); ast_autoservice_stop(chan); } + odbc_datastore_free(resultset); return -1; } @@ -553,6 +559,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha pbx_builtin_setvar_helper(chan, "ODBCROWS", rowcount); ast_autoservice_stop(chan); } + odbc_datastore_free(resultset); return -1; } @@ -578,6 +585,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status); ast_autoservice_stop(chan); } + odbc_datastore_free(resultset); return res1; } @@ -591,7 +599,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha char *ptrcoldata; if (!coldata) { - ast_free(resultset); + odbc_datastore_free(resultset); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); ast_odbc_release_obj(obj); @@ -624,7 +632,7 @@ static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, cha void *tmp = ast_realloc(resultset, sizeof(*resultset) + ast_str_strlen(colnames) + 1); if (!tmp) { ast_log(LOG_ERROR, "No space for a new resultset?\n"); - ast_free(resultset); + odbc_datastore_free(resultset); SQLCloseCursor(stmt); SQLFreeHandle(SQL_HANDLE_STMT, stmt); ast_odbc_release_obj(obj); diff --git a/funcs/func_speex.c b/funcs/func_speex.c index 2b29271f33..fb5addbb4a 100644 --- a/funcs/func_speex.c +++ b/funcs/func_speex.c @@ -202,6 +202,11 @@ static int speex_write(struct ast_channel *chan, const char *cmd, char *data, co struct speex_direction_info **sdi = NULL; int is_new = 0; + if (strcasecmp(data, "rx") && strcasecmp(data, "tx")) { + ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd); + return -1; + } + ast_channel_lock(chan); if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) { ast_channel_unlock(chan); @@ -226,15 +231,8 @@ static int speex_write(struct ast_channel *chan, const char *cmd, char *data, co if (!strcasecmp(data, "rx")) { sdi = &si->rx; - } else if (!strcasecmp(data, "tx")) { - sdi = &si->tx; } else { - ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd); - - if (is_new) { - ast_datastore_free(datastore); - return -1; - } + sdi = &si->tx; } if (!*sdi) { diff --git a/include/asterisk/cel.h b/include/asterisk/cel.h index b388ffd9b5..25a3a4af1d 100644 --- a/include/asterisk/cel.h +++ b/include/asterisk/cel.h @@ -187,6 +187,15 @@ const char *ast_cel_get_ama_flag_name(enum ast_cel_ama_flag flag); */ void ast_cel_check_retire_linkedid(struct ast_channel *chan); +/*! + * \brief Inform CEL that a new linkedid is being used + * \since 11 + * + * \retval -1 error + * \retval 0 success + */ +int ast_cel_linkedid_ref(const char *linkedid); + /*! * \brief Create a fake channel from data in a CEL event * diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 8a371a11f3..4e16b5ae7d 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -2166,9 +2166,12 @@ void ast_begin_shutdown(int hangup); /*! Cancels an existing shutdown and returns to normal operation */ void ast_cancel_shutdown(void); -/*! \return number of active/allocated channels */ +/*! \return number of channels available for lookup */ int ast_active_channels(void); +/*! \return the number of channels not yet destroyed */ +int ast_undestroyed_channels(void); + /*! \return non-zero if Asterisk is being shut down */ int ast_shutting_down(void); diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h index f4b79f4318..e4894f7bbc 100644 --- a/include/asterisk/tcptls.h +++ b/include/asterisk/tcptls.h @@ -190,8 +190,25 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc); * \version 1.6.1 changed desc parameter to be of ast_tcptls_session_args type */ void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc); + +/*! + * \brief Set up an SSL server + * + * \param cfg Configuration for the SSL server + * \retval 1 Success + * \retval 0 Failure + */ int ast_ssl_setup(struct ast_tls_config *cfg); +/*! + * \brief free resources used by an SSL server + * + * \note This only needs to be called if ast_ssl_setup() was + * directly called first. + * \param cfg Configuration for the SSL server + */ +void ast_ssl_teardown(struct ast_tls_config *cfg); + /*! * \brief Used to parse conf files containing tls/ssl options. */ diff --git a/main/acl.c b/main/acl.c index a309d74024..69460ad820 100644 --- a/main/acl.c +++ b/main/acl.c @@ -533,7 +533,11 @@ int ast_apply_ha(const struct ast_ha *ha, const struct ast_sockaddr *addr) if (ast_sockaddr_is_ipv6(addr)) { if (ast_sockaddr_is_ipv4_mapped(addr)) { /* IPv4 ACLs apply to IPv4-mapped addresses */ - ast_sockaddr_ipv4_mapped(addr, &mapped_addr); + if (!ast_sockaddr_ipv4_mapped(addr, &mapped_addr)) { + ast_log(LOG_ERROR, "%s provided to ast_sockaddr_ipv4_mapped could not be converted. That shouldn't be possible.\n", + ast_sockaddr_stringify(addr)); + continue; + } addr_to_use = &mapped_addr; } else { /* An IPv4 ACL does not apply to an IPv6 address */ diff --git a/main/app.c b/main/app.c index 3ea7f769a1..ef782eb569 100644 --- a/main/app.c +++ b/main/app.c @@ -604,6 +604,9 @@ static int control_streamfile(struct ast_channel *chan, long pause_restart_point = 0; long offset = 0; + if (!file) { + return -1; + } if (offsetms) { offset = *offsetms * 8; /* XXX Assumes 8kHz */ } @@ -635,12 +638,10 @@ static int control_streamfile(struct ast_channel *chan, res = ast_answer(chan); } - if (file) { - if ((end = strchr(file, ':'))) { - if (!strcasecmp(end, ":end")) { - *end = '\0'; - end++; - } + if ((end = strchr(file, ':'))) { + if (!strcasecmp(end, ":end")) { + *end = '\0'; + end++; } } diff --git a/main/asterisk.c b/main/asterisk.c index ec33cb187e..16530aa31d 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -1463,7 +1463,11 @@ static int ast_makesocket(void) ast_log(LOG_WARNING, "Unable to register network verboser?\n"); } - ast_pthread_create_background(<hread, NULL, listener, NULL); + if (ast_pthread_create_background(<hread, NULL, listener, NULL)) { + ast_log(LOG_WARNING, "Unable to create listener thread.\n"); + close(ast_socket); + return -1; + } if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) { struct passwd *pw; @@ -1698,7 +1702,7 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart) for (;;) { time(&e); /* Wait up to 15 seconds for all channels to go away */ - if ((e - s) > 15 || !ast_active_channels() || shuttingdown != niceness) { + if ((e - s) > 15 || !ast_undestroyed_channels() || shuttingdown != niceness) { break; } /* Sleep 1/10 of a second */ @@ -1712,7 +1716,7 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart) ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt"); } for (;;) { - if (!ast_active_channels() || shuttingdown != niceness) { + if (!ast_undestroyed_channels() || shuttingdown != niceness) { break; } sleep(1); @@ -3249,9 +3253,8 @@ static void *canary_thread(void *unused) sleep(120); for (;;) { - stat(canary_filename, &canary_stat); now = ast_tvnow(); - if (now.tv_sec > canary_stat.st_mtime + 60) { + if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) { ast_log(LOG_WARNING, "The canary is no more. He has ceased to be! " "He's expired and gone to meet his maker! " diff --git a/main/cdr.c b/main/cdr.c index 2a64ce4f0a..6fa345bebb 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -573,7 +573,9 @@ void ast_cdr_merge(struct ast_cdr *to, struct ast_cdr *from) lfrom = lfrom->next; } /* rip off the last entry and put a copy of the to at the end */ - llfrom->next = to; + if (llfrom) { + llfrom->next = to; + } from = lfrom; } else { /* save copy of the current *to cdr */ @@ -589,10 +591,11 @@ void ast_cdr_merge(struct ast_cdr *to, struct ast_cdr *from) } from->next = NULL; /* rip off the last entry and put a copy of the to at the end */ - if (llfrom == from) + if (llfrom == from) { to = to->next = ast_cdr_dup(&tcdr); - else + } else if (llfrom) { to = llfrom->next = ast_cdr_dup(&tcdr); + } from = lfrom; } } diff --git a/main/cel.c b/main/cel.c index 023fd571a9..ce9a15f97d 100644 --- a/main/cel.c +++ b/main/cel.c @@ -464,6 +464,31 @@ struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event return tchan; } +int ast_cel_linkedid_ref(const char *linkedid) +{ + char *lid; + + if (ast_strlen_zero(linkedid)) { + ast_log(LOG_ERROR, "The linkedid should never be empty\n"); + return -1; + } + + if (!(lid = ao2_find(linkedids, (void *) linkedid, OBJ_POINTER))) { + if (!(lid = ao2_alloc(strlen(linkedid) + 1, NULL))) { + return -1; + } + strcpy(lid, linkedid); + if (!ao2_link(linkedids, lid)) { + ao2_ref(lid, -1); + return -1; + } + /* Leave both the link and the alloc refs to show a count of 1 + the link */ + } + /* If we've found, go ahead and keep the ref to increment count of how many channels + * have this linkedid. We'll clean it up in check_retire */ + return 0; +} + int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type, const char *userdefevname, const char *extra, struct ast_channel *peer2) { @@ -480,22 +505,10 @@ int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event /* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't * reporting on CHANNEL_START so we can track when to send LINKEDID_END */ if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && chan->linkedid) { - char *lid; - if (!(lid = ao2_find(linkedids, (void *) chan->linkedid, OBJ_POINTER))) { - if (!(lid = ao2_alloc(strlen(chan->linkedid) + 1, NULL))) { - ast_mutex_unlock(&reload_lock); - return -1; - } - strcpy(lid, chan->linkedid); - if (!ao2_link(linkedids, lid)) { - ao2_ref(lid, -1); - ast_mutex_unlock(&reload_lock); - return -1; - } - /* Leave both the link and the alloc refs to show a count of 1 + the link */ + if (ast_cel_linkedid_ref(chan->linkedid)) { + ast_mutex_unlock(&reload_lock); + return -1; } - /* If we've found, go ahead and keep the ref to increment count of how many channels - * have this linkedid. We'll clean it up in check_retire */ } if (!cel_enabled || !ast_cel_track_event(event_type)) { diff --git a/main/channel.c b/main/channel.c index e7e63d2b5a..577e64236a 100644 --- a/main/channel.c +++ b/main/channel.c @@ -93,6 +93,7 @@ struct ast_epoll_data { static int shutting_down; static int uniqueint; +static int chancount; unsigned long global_fin, global_fout; @@ -833,6 +834,11 @@ int ast_active_channels(void) return channels ? ao2_container_count(channels) : 0; } +int ast_undestroyed_channels(void) +{ + return ast_atomic_fetchadd_int(&chancount, 0); +} + /*! \brief Cancel a shutdown in progress */ void ast_cancel_shutdown(void) { @@ -1310,6 +1316,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char ast_cdr_init(tmp->cdr, tmp); ast_cdr_start(tmp->cdr); + ast_atomic_fetchadd_int(&chancount, +1); ast_cel_report_event(tmp, AST_CEL_CHANNEL_START, NULL, NULL, NULL); headp = &tmp->varshead; @@ -2507,6 +2514,7 @@ static void ast_channel_destructor(void *obj) } chan->nativeformats = ast_format_cap_destroy(chan->nativeformats); + ast_atomic_fetchadd_int(&chancount, -1); } /*! \brief Free a dummy channel structure */ @@ -2804,13 +2812,7 @@ int ast_hangup(struct ast_channel *chan) */ while (chan->masq) { ast_channel_unlock(chan); - if (ast_do_masquerade(chan)) { - ast_log(LOG_WARNING, "Failed to perform masquerade\n"); - - /* Abort the loop or we might never leave. */ - ast_channel_lock(chan); - break; - } + ast_do_masquerade(chan); ast_channel_lock(chan); } @@ -2826,6 +2828,7 @@ int ast_hangup(struct ast_channel *chan) return 0; } + /* Mark as a zombie so a masquerade cannot be setup on this channel. */ if (!(was_zombie = ast_test_flag(chan, AST_FLAG_ZOMBIE))) { ast_set_flag(chan, AST_FLAG_ZOMBIE); } @@ -3183,22 +3186,23 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int fdno; } *fdmap = NULL; - if ((sz = n * AST_MAX_FDS + nfds)) { - pfds = alloca(sizeof(*pfds) * sz); - fdmap = alloca(sizeof(*fdmap) * sz); - } - if (outfd) *outfd = -99999; if (exception) *exception = 0; + if ((sz = n * AST_MAX_FDS + nfds)) { + pfds = alloca(sizeof(*pfds) * sz); + fdmap = alloca(sizeof(*fdmap) * sz); + } else { + /* nothing to allocate and no FDs to check */ + return NULL; + } + /* Perform any pending masquerades */ for (x = 0; x < n; x++) { - if (c[x]->masq && ast_do_masquerade(c[x])) { - ast_log(LOG_WARNING, "Masquerade failed\n"); - *ms = -1; - return NULL; + while (c[x]->masq) { + ast_do_masquerade(c[x]); } ast_channel_lock(c[x]); @@ -3329,10 +3333,8 @@ static struct ast_channel *ast_waitfor_nandfds_simple(struct ast_channel *chan, /* See if this channel needs to be masqueraded */ - if (chan->masq && ast_do_masquerade(chan)) { - ast_log(LOG_WARNING, "Failed to perform masquerade on %s\n", chan->name); - *ms = -1; - return NULL; + while (chan->masq) { + ast_do_masquerade(chan); } ast_channel_lock(chan); @@ -3411,10 +3413,8 @@ static struct ast_channel *ast_waitfor_nandfds_complex(struct ast_channel **c, i struct ast_channel *winner = NULL; for (i = 0; i < n; i++) { - if (c[i]->masq && ast_do_masquerade(c[i])) { - ast_log(LOG_WARNING, "Masquerade failed\n"); - *ms = -1; - return NULL; + while (c[i]->masq) { + ast_do_masquerade(c[i]); } ast_channel_lock(c[i]); @@ -3793,11 +3793,8 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) */ if (chan->masq) { - if (ast_do_masquerade(chan)) - ast_log(LOG_WARNING, "Failed to perform masquerade\n"); - else - f = &ast_null_frame; - return f; + ast_do_masquerade(chan); + return &ast_null_frame; } /* if here, no masq has happened, lock the channel and proceed */ @@ -4881,12 +4878,9 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) goto done; /* Handle any pending masquerades */ - if (chan->masq) { + while (chan->masq) { ast_channel_unlock(chan); - if (ast_do_masquerade(chan)) { - ast_log(LOG_WARNING, "Failed to perform masquerade\n"); - return res; /* no need to goto done: chan is already unlocked for masq */ - } + ast_do_masquerade(chan); ast_channel_lock(chan); } if (chan->masqr) { @@ -6320,11 +6314,13 @@ static void __ast_change_name_nolink(struct ast_channel *chan, const char *newna void ast_change_name(struct ast_channel *chan, const char *newname) { /* We must re-link, as the hash value will change here. */ - ao2_unlink(channels, chan); + ao2_lock(channels); ast_channel_lock(chan); + ao2_unlink(channels, chan); __ast_change_name_nolink(chan, newname); - ast_channel_unlock(chan); ao2_link(channels, chan); + ast_channel_unlock(chan); + ao2_unlock(channels); } void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child) @@ -6381,8 +6377,7 @@ static void clone_variables(struct ast_channel *original, struct ast_channel *cl struct ast_var_t *current, *newvar; /* Append variables from clone channel into original channel */ /* XXX Is this always correct? We have to in order to keep MACROS working XXX */ - if (AST_LIST_FIRST(&clonechan->varshead)) - AST_LIST_APPEND_LIST(&original->varshead, &clonechan->varshead, entries); + AST_LIST_APPEND_LIST(&original->varshead, &clonechan->varshead, entries); /* then, dup the varshead list into the clone */ @@ -6458,15 +6453,17 @@ static const char *oldest_linkedid(const char *a, const char *b) * see if the channel's old linkedid is now being retired */ static void ast_channel_change_linkedid(struct ast_channel *chan, const char *linkedid) { + ast_assert(linkedid != NULL); /* if the linkedid for this channel is being changed from something, check... */ - if (!ast_strlen_zero(chan->linkedid) && 0 != strcmp(chan->linkedid, linkedid)) { - ast_cel_check_retire_linkedid(chan); + if (!strcmp(chan->linkedid, linkedid)) { + return; } + ast_cel_check_retire_linkedid(chan); ast_string_field_set(chan, linkedid, linkedid); + ast_cel_linkedid_ref(linkedid); } - /*! \brief Propagate the oldest linkedid between associated channels @@ -6632,10 +6629,11 @@ static void masquerade_colp_transfer(struct ast_channel *transferee, struct xfer */ int ast_do_masquerade(struct ast_channel *original) { - int x, i; - int res=0; + int x; + int i; int origstate; int visible_indication; + int clone_was_zombie = 0;/*!< TRUE if the clonechan was a zombie before the masquerade. */ struct ast_frame *current; const struct ast_channel_tech *t; void *t_pvt; @@ -6658,61 +6656,65 @@ int ast_do_masquerade(struct ast_channel *original) char masqn[AST_CHANNEL_NAME]; char zombn[AST_CHANNEL_NAME]; - ast_format_copy(&rformat, &original->readformat); - ast_format_copy(&wformat, &original->writeformat); - /* XXX This operation is a bit odd. We're essentially putting the guts of * the clone channel into the original channel. Start by killing off the * original channel's backend. While the features are nice, which is the * reason we're keeping it, it's still awesomely weird. XXX */ - /* The reasoning for the channels ao2_container lock here is complex. - * - * In order to check for a race condition, the original channel must - * be locked. If it is determined that the masquerade should proceed - * the original channel can absolutely not be unlocked until the end - * of the function. Since after determining the masquerade should - * continue requires the channels to be unlinked from the ao2_container, - * the container lock must be held first to achieve proper locking order. + /* + * The reasoning for the channels ao2_container lock here is + * complex. + * + * There is a race condition that exists for this function. + * Since all pvt and channel locks must be let go before calling + * ast_do_masquerade, it is possible that it could be called + * multiple times for the same channel. In order to prevent the + * race condition with competing threads to do the masquerade + * and new masquerade attempts, the channels container must be + * locked for the entire masquerade. The original and clonechan + * need to be unlocked earlier to avoid potential deadlocks with + * the chan_local deadlock avoidance method. + * + * The container lock blocks competing masquerade attempts from + * starting as well as being necessary for proper locking order + * because the channels must to be unlinked to change their + * names. + * + * The original and clonechan locks must be held while the + * channel contents are shuffled around for the masquerade. + * + * The masq and masqr pointers need to be left alone until the + * masquerade has restabilized the channels to prevent another + * masquerade request until the AST_FLAG_ZOMBIE can be set on + * the clonechan. */ ao2_lock(channels); - /* lock the original channel to determine if the masquerade is required or not */ - ast_channel_lock(original); - /* - * This checks to see if the masquerade has already happened or - * not. There is a race condition that exists for this - * function. Since all pvt and channel locks must be let go - * before calling do_masquerade, it is possible that it could be - * called multiple times for the same channel. This check - * verifies whether or not the masquerade has already been - * completed by another thread. + * Lock the original channel to determine if the masquerade is + * still required. */ - while ((clonechan = original->masq) && ast_channel_trylock(clonechan)) { - /* - * A masq is needed but we could not get the clonechan lock - * immediately. Since this function already holds the global - * container lock, unlocking original for deadlock avoidance - * will not result in any sort of masquerade race condition. If - * masq is called by a different thread while this happens, it - * will be stuck waiting until we unlock the container. - */ - CHANNEL_DEADLOCK_AVOIDANCE(original); - } + ast_channel_lock(original); - /* - * A final masq check must be done after deadlock avoidance for - * clonechan above or we could get a double masq. This is - * posible with ast_hangup at least. - */ + clonechan = original->masq; if (!clonechan) { - /* masq already completed by another thread, or never needed to be done to begin with */ + /* + * The masq is already completed by another thread or never + * needed to be done to begin with. + */ ast_channel_unlock(original); ao2_unlock(channels); return 0; } + /* Bump the refs to ensure that they won't dissapear on us. */ + ast_channel_ref(original); + ast_channel_ref(clonechan); + + /* unlink from channels container as name (which is the hash value) will change */ + ao2_unlink(channels, original); + ao2_unlink(channels, clonechan); + /* Get any transfer masquerade connected line exchange data. */ xfer_ds = ast_channel_datastore_find(original, &xfer_ds_info, NULL); if (xfer_ds) { @@ -6723,31 +6725,27 @@ int ast_do_masquerade(struct ast_channel *original) } /* - * Release any hold on the transferee channel before proceeding - * with the masquerade. + * Stop any visible indication on the original channel so we can + * transfer it to the clonechan taking the original's place. + */ + visible_indication = original->visible_indication; + ast_channel_unlock(original); + ast_indicate(original, -1); + + /* + * Release any hold on the transferee channel before going any + * further with the masquerade. */ if (xfer_colp && xfer_colp->transferee_held) { ast_indicate(clonechan, AST_CONTROL_UNHOLD); } - /* clear the masquerade channels */ - original->masq = NULL; - clonechan->masqr = NULL; - - /* unlink from channels container as name (which is the hash value) will change */ - ao2_unlink(channels, original); - ao2_unlink(channels, clonechan); + /* Start the masquerade channel contents rearangement. */ + ast_channel_lock_both(original, clonechan); ast_debug(4, "Actually Masquerading %s(%d) into the structure of %s(%d)\n", clonechan->name, clonechan->_state, original->name, original->_state); - /* - * Stop any visible indiction on the original channel so we can - * transfer it to the clonechan taking the original's place. - */ - visible_indication = original->visible_indication; - ast_indicate(original, -1); - chans[0] = clonechan; chans[1] = original; ast_manager_event_multichan(EVENT_FLAG_CALL, "Masquerade", 2, chans, @@ -6757,8 +6755,12 @@ int ast_do_masquerade(struct ast_channel *original) "OriginalState: %s\r\n", clonechan->name, ast_state2str(clonechan->_state), original->name, ast_state2str(original->_state)); - /* Having remembered the original read/write formats, we turn off any translation on either - one */ + /* + * Remember the original read/write formats. We turn off any + * translation on either one + */ + ast_format_copy(&rformat, &original->readformat); + ast_format_copy(&wformat, &original->writeformat); free_translation(clonechan); free_translation(original); @@ -6783,15 +6785,15 @@ int ast_do_masquerade(struct ast_channel *original) original->tech = clonechan->tech; clonechan->tech = t; + t_pvt = original->tech_pvt; + original->tech_pvt = clonechan->tech_pvt; + clonechan->tech_pvt = t_pvt; + /* Swap the cdrs */ cdr = original->cdr; original->cdr = clonechan->cdr; clonechan->cdr = cdr; - t_pvt = original->tech_pvt; - original->tech_pvt = clonechan->tech_pvt; - clonechan->tech_pvt = t_pvt; - /* Swap the alertpipes */ for (i = 0; i < 2; i++) { x = original->alertpipe[i]; @@ -6799,7 +6801,7 @@ int ast_do_masquerade(struct ast_channel *original) clonechan->alertpipe[i] = x; } - /* + /* * Swap the readq's. The end result should be this: * * 1) All frames should be on the new (original) channel. @@ -6812,8 +6814,8 @@ int ast_do_masquerade(struct ast_channel *original) */ { AST_LIST_HEAD_NOLOCK(, ast_frame) tmp_readq; - AST_LIST_HEAD_SET_NOLOCK(&tmp_readq, NULL); + AST_LIST_HEAD_INIT_NOLOCK(&tmp_readq); AST_LIST_APPEND_LIST(&tmp_readq, &original->readq, frame_list); AST_LIST_APPEND_LIST(&original->readq, &clonechan->readq, frame_list); @@ -6848,23 +6850,6 @@ int ast_do_masquerade(struct ast_channel *original) original->_state = clonechan->_state; clonechan->_state = origstate; - if (clonechan->tech->fixup && clonechan->tech->fixup(original, clonechan)) { - ast_log(LOG_WARNING, "Fixup failed on channel %s, strange things may happen.\n", clonechan->name); - } - - /* Start by disconnecting the original's physical side */ - if (clonechan->tech->hangup && clonechan->tech->hangup(clonechan)) { - ast_log(LOG_WARNING, "Hangup failed! Strange things may happen!\n"); - res = -1; - goto done; - } - - /* - * We just hung up the physical side of the channel. Set the - * new zombie to use the kill channel driver for safety. - */ - clonechan->tech = &ast_kill_tech; - /* Mangle the name of the clone channel */ snprintf(zombn, sizeof(zombn), "%s", orig); /* quick, hide the brains! */ __ast_change_name_nolink(clonechan, zombn); @@ -6965,63 +6950,89 @@ int ast_do_masquerade(struct ast_channel *original) ast_debug(1, "Putting channel %s in %s/%s formats\n", original->name, ast_getformatname(&wformat), ast_getformatname(&rformat)); - /* Okay. Last thing is to let the channel driver know about all this mess, so he - can fix up everything as best as possible */ - if (original->tech->fixup) { - if (original->tech->fixup(clonechan, original)) { - ast_log(LOG_WARNING, "Channel for type '%s' could not fixup channel %s\n", - original->tech->type, original->name); - res = -1; - goto done; - } - } else - ast_log(LOG_WARNING, "Channel type '%s' does not have a fixup routine (for %s)! Bad things may happen.\n", + /* Fixup the original clonechan's physical side */ + if (original->tech->fixup && original->tech->fixup(clonechan, original)) { + ast_log(LOG_WARNING, "Channel type '%s' could not fixup channel %s, strange things may happen. (clonechan)\n", original->tech->type, original->name); + } - /* - * If an indication is currently playing, maintain it on the channel - * that is taking the place of original - * - * This is needed because the masquerade is swapping out in the internals - * of this channel, and the new channel private data needs to be made - * aware of the current visible indication (RINGING, CONGESTION, etc.) - */ - if (visible_indication) { - ast_indicate(original, visible_indication); + /* Fixup the original original's physical side */ + if (clonechan->tech->fixup && clonechan->tech->fixup(original, clonechan)) { + ast_log(LOG_WARNING, "Channel type '%s' could not fixup channel %s, strange things may happen. (original)\n", + clonechan->tech->type, clonechan->name); } - /* Now, at this point, the "clone" channel is totally F'd up. We mark it as - a zombie so nothing tries to touch it. If it's already been marked as a - zombie, then free it now (since it already is considered invalid). */ + /* + * Now, at this point, the "clone" channel is totally F'd up. + * We mark it as a zombie so nothing tries to touch it. If it's + * already been marked as a zombie, then we must free it (since + * it already is considered invalid). + * + * This must be done before we unlock clonechan to prevent + * setting up another masquerade on the clonechan. + */ if (ast_test_flag(clonechan, AST_FLAG_ZOMBIE)) { - ast_debug(1, "Destroying channel clone '%s'\n", clonechan->name); - ast_channel_unlock(clonechan); - ast_manager_event(clonechan, EVENT_FLAG_CALL, "Hangup", - "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "Cause: %d\r\n" - "Cause-txt: %s\r\n", - clonechan->name, - clonechan->uniqueid, - clonechan->hangupcause, - ast_cause2str(clonechan->hangupcause) - ); - clonechan = ast_channel_release(clonechan); + clone_was_zombie = 1; } else { - ast_debug(1, "Released clone lock on '%s'\n", clonechan->name); ast_set_flag(clonechan, AST_FLAG_ZOMBIE); ast_queue_frame(clonechan, &ast_null_frame); } + /* clear the masquerade channels */ + original->masq = NULL; + clonechan->masqr = NULL; + + /* + * When we unlock original here, it can be immediately setup to + * masquerade again or hungup. The new masquerade or hangup + * will not actually happen until we release the channels + * container lock. + */ + ast_channel_unlock(original); + + /* Disconnect the original original's physical side */ + if (clonechan->tech->hangup && clonechan->tech->hangup(clonechan)) { + ast_log(LOG_WARNING, "Hangup failed! Strange things may happen!\n"); + } else { + /* + * We just hung up the original original's physical side of the + * channel. Set the new zombie to use the kill channel driver + * for safety. + */ + clonechan->tech = &ast_kill_tech; + } + + ast_channel_unlock(clonechan); + + /* + * If an indication is currently playing, maintain it on the + * channel that is taking the place of original. + * + * This is needed because the masquerade is swapping out the + * internals of the channel, and the new channel private data + * needs to be made aware of the current visible indication + * (RINGING, CONGESTION, etc.) + */ + if (visible_indication) { + ast_indicate(original, visible_indication); + } + + ast_channel_lock(original); + /* Signal any blocker */ - if (ast_test_flag(original, AST_FLAG_BLOCKING)) + if (ast_test_flag(original, AST_FLAG_BLOCKING)) { pthread_kill(original->blocker, SIGURG); + } + ast_debug(1, "Done Masquerading %s (%d)\n", original->name, original->_state); if ((bridged = ast_bridged_channel(original))) { - ast_channel_lock(bridged); + ast_channel_ref(bridged); + ast_channel_unlock(original); ast_indicate(bridged, AST_CONTROL_SRCCHANGE); - ast_channel_unlock(bridged); + ast_channel_unref(bridged); + } else { + ast_channel_unlock(original); } ast_indicate(original, AST_CONTROL_SRCCHANGE); @@ -7034,24 +7045,42 @@ int ast_do_masquerade(struct ast_channel *original) masquerade_colp_transfer(original, xfer_colp); } -done: if (xfer_ds) { ast_datastore_free(xfer_ds); } - /* it is possible for the clone channel to disappear during this */ - if (clonechan) { - ast_channel_unlock(original); + + if (clone_was_zombie) { + ast_channel_lock(clonechan); + ast_debug(1, "Destroying channel clone '%s'\n", clonechan->name); + ast_manager_event(clonechan, EVENT_FLAG_CALL, "Hangup", + "Channel: %s\r\n" + "Uniqueid: %s\r\n" + "Cause: %d\r\n" + "Cause-txt: %s\r\n", + clonechan->name, + clonechan->uniqueid, + clonechan->hangupcause, + ast_cause2str(clonechan->hangupcause) + ); ast_channel_unlock(clonechan); - ao2_link(channels, clonechan); - ao2_link(channels, original); + + /* + * Drop the system reference to destroy the channel since it is + * already unlinked. + */ + ast_channel_unref(clonechan); } else { - ast_channel_unlock(original); - ao2_link(channels, original); + ao2_link(channels, clonechan); } + ao2_link(channels, original); ao2_unlock(channels); - return res; + /* Release our held safety references. */ + ast_channel_unref(original); + ast_channel_unref(clonechan); + + return 0; } void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani) diff --git a/main/cli.c b/main/cli.c index c35b941d10..89ec3c4767 100644 --- a/main/cli.c +++ b/main/cli.c @@ -2340,16 +2340,20 @@ char **ast_cli_completion_matches(const char *text, const char *word) max_equal = i; } - if (!(retstr = ast_malloc(max_equal + 1))) + if (!(retstr = ast_malloc(max_equal + 1))) { + ast_free(match_list); return NULL; - + } + ast_copy_string(retstr, match_list[1], max_equal + 1); match_list[0] = retstr; /* ensure that the array is NULL terminated */ if (matches + 1 >= match_list_len) { - if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(*match_list)))) + if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(*match_list)))) { + ast_free(retstr); return NULL; + } } match_list[matches + 1] = NULL; diff --git a/main/config.c b/main/config.c index 68e7f86601..bbb5c80a00 100644 --- a/main/config.c +++ b/main/config.c @@ -565,7 +565,11 @@ struct ast_variable *ast_variable_browse(const struct ast_config *config, const { struct ast_category *cat = NULL; - if (category && config->last_browse && (config->last_browse->name == category)) { + if (!category) { + return NULL; + } + + if (config->last_browse && (config->last_browse->name == category)) { cat = config->last_browse; } else { cat = ast_category_get(config, category); @@ -1486,6 +1490,8 @@ static struct ast_config *config_text_file_load(const char *database, const char if (unchanged) { AST_LIST_UNLOCK(&cfmtime_head); + ast_free(comment_buffer); + ast_free(lline_buffer); return CONFIG_STATUS_FILEUNCHANGED; } } @@ -1640,13 +1646,13 @@ static struct ast_config *config_text_file_load(const char *database, const char } #endif - if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID && cfg->include_level == 1 && ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) { + if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) { ast_free(comment_buffer); ast_free(lline_buffer); comment_buffer = NULL; lline_buffer = NULL; } - + if (count == 0) return NULL; @@ -1899,7 +1905,7 @@ int ast_config_text_file_save(const char *configfile, const struct ast_config *c /* Dump section with any appropriate comment */ for (cmt = cat->precomments; cmt; cmt=cmt->next) { char *cmtp = cmt->cmt; - while (*cmtp == ';' && *(cmtp+1) == '!') { + while (cmtp && *cmtp == ';' && *(cmtp+1) == '!') { char *cmtp2 = strchr(cmtp+1, '\n'); if (cmtp2) cmtp = cmtp2+1; @@ -2121,6 +2127,10 @@ int read_config_maps(void) clear_config_maps(); configtmp = ast_config_new(); + if (!configtmp) { + ast_log(LOG_ERROR, "Unable to allocate memory for new config\n"); + return -1; + } configtmp->max_include_level = 1; config = ast_config_internal_load(extconfig_conf, configtmp, flags, "", "extconfig"); if (config == CONFIG_STATUS_FILEINVALID) { diff --git a/main/data.c b/main/data.c index 2503cb57d6..47e7fd5bda 100644 --- a/main/data.c +++ b/main/data.c @@ -1042,6 +1042,7 @@ static int data_search_cmp_ptr(const struct ast_data_search *root, const char *n cmp_type = child->cmp_type; if (sscanf(child->value, "%p", &node_ptr) <= 0) { + ao2_ref(child, -1); return 1; } @@ -2186,6 +2187,7 @@ struct ast_xml_doc *ast_data_get_xml(const struct ast_data_query *query) doc = ast_xml_new(); if (!doc) { + ast_data_free(res); return NULL; } @@ -2496,18 +2498,20 @@ struct ast_data_iterator *ast_data_iterator_init(struct ast_data *tree, struct ast_data *internal = tree; char *path, *ptr = NULL; + if (!elements) { + return NULL; + } + /* tree is the node we want to use to iterate? or we are going * to iterate thow an internal node? */ - if (elements) { - path = ast_strdupa(elements); - - ptr = strrchr(path, '/'); - if (ptr) { - *ptr = '\0'; - internal = data_result_get_node(tree, path); - if (!internal) { - return NULL; - } + path = ast_strdupa(elements); + + ptr = strrchr(path, '/'); + if (ptr) { + *ptr = '\0'; + internal = data_result_get_node(tree, path); + if (!internal) { + return NULL; } } diff --git a/main/devicestate.c b/main/devicestate.c index cccf159f39..2e801df88e 100644 --- a/main/devicestate.c +++ b/main/devicestate.c @@ -330,9 +330,7 @@ static enum ast_device_state _ast_device_state(const char *device, int check_cac /* We have a provider */ number = tech; tech = NULL; - } - if (provider) { ast_debug(3, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number); return getproviderstate(provider, number); } diff --git a/main/editline/readline.c b/main/editline/readline.c index 4729fa952f..77827c3f91 100644 --- a/main/editline/readline.c +++ b/main/editline/readline.c @@ -549,6 +549,7 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) from = strdup(search); else { from = NULL; + free(line); return (-1); } } @@ -609,8 +610,13 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) end = max - ((end < -1) ? 1 : 0); /* check boundaries ... */ - if (start > max || end > max || start > end) + if (start > max || end > max || start > end) { + for (i = 0; i <= max; i++) { + free(arr[i]); + } + free(arr), arr = (char **) NULL; return (-1); + } for (i = 0; i <= max; i++) { char *temp; diff --git a/main/editline/term.c b/main/editline/term.c index fb627cabb7..63cec6e43e 100644 --- a/main/editline/term.c +++ b/main/editline/term.c @@ -472,7 +472,7 @@ term_rebuffer_display(EditLine *el) private int term_alloc_display(EditLine *el) { - int i; + int i, j; char **b; coord_t *c = &el->el_term.t_size; @@ -481,8 +481,13 @@ term_alloc_display(EditLine *el) return (-1); for (i = 0; i < c->v; i++) { b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); - if (b[i] == NULL) + if (b[i] == NULL) { + for (j = 0; j < i; j++) { + el_free(b[j]); + } + el_free(b); return (-1); + } } b[c->v] = NULL; el->el_display = b; @@ -492,8 +497,13 @@ term_alloc_display(EditLine *el) return (-1); for (i = 0; i < c->v; i++) { b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); - if (b[i] == NULL) + if (b[i] == NULL) { + for (j = 0; j < i; j++) { + el_free(b[j]); + } + el_free(b); return (-1); + } } b[c->v] = NULL; el->el_vdisplay = b; diff --git a/main/editline/tokenizer.c b/main/editline/tokenizer.c index f0de39bc9f..67398c6869 100644 --- a/main/editline/tokenizer.c +++ b/main/editline/tokenizer.c @@ -113,12 +113,17 @@ tok_init(const char *ifs) tok->argc = 0; tok->amax = AINCR; tok->argv = (char **) tok_malloc(sizeof(char *) * tok->amax); - if (tok->argv == NULL) + if (tok->argv == NULL) { + tok_free(tok); return (NULL); + } tok->argv[0] = NULL; tok->wspace = (char *) tok_malloc(WINCR); - if (tok->wspace == NULL) + if (tok->wspace == NULL) { + tok_free(tok->argv); + tok_free(tok); return (NULL); + } tok->wmax = tok->wspace + WINCR; tok->wstart = tok->wspace; tok->wptr = tok->wspace; diff --git a/main/enum.c b/main/enum.c index 92f185c607..d590666519 100644 --- a/main/enum.c +++ b/main/enum.c @@ -790,6 +790,7 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds if (sdl > strlen(number)) { /* Number too short for this sdl? */ ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number); + ast_free(context); return 0; } ast_copy_string(left, number + sdl, sizeof(left)); @@ -802,6 +803,7 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds /* check the space we need for middle */ if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) { ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n"); + ast_free(context); return -1; } @@ -819,6 +821,7 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds if (strlen(left) * 2 + 2 > sizeof(domain)) { ast_log(LOG_WARNING, "string to long in ast_get_enum\n"); + ast_free(context); return -1; } diff --git a/main/event.c b/main/event.c index ccb093038d..63e1daf796 100644 --- a/main/event.c +++ b/main/event.c @@ -1292,8 +1292,9 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...) break; } + /* realloc inside one of the append functions failed */ if (!event) { - break; + return NULL; } } diff --git a/main/features.c b/main/features.c index d66d6e365e..6dfb33e623 100644 --- a/main/features.c +++ b/main/features.c @@ -1021,7 +1021,9 @@ static void bridge_call_thread_launch(void *data) pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - ast_pthread_create(&thread, &attr, bridge_call_thread, data); + if (ast_pthread_create(&thread, &attr, bridge_call_thread, data)) { + ast_log(LOG_WARNING, "Failed to create thread for parked call.\n"); + } pthread_attr_destroy(&attr); memset(&sched, 0, sizeof(sched)); pthread_setschedparam(thread, SCHED_RR, &sched); @@ -2070,6 +2072,9 @@ static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *pee struct ast_channel *caller_chan, *callee_chan; const char *automon_message_start = NULL; const char *automon_message_stop = NULL; + const char *touch_format = NULL; + const char *touch_monitor = NULL; + const char *touch_monitor_prefix = NULL; if (!monitor_ok) { ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); @@ -2083,10 +2088,10 @@ static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *pee } set_peers(&caller_chan, &callee_chan, peer, chan, sense); - if (caller_chan) { /* Find extra messages */ - automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); - automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); - } + + /* Find extra messages */ + automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); + automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { @@ -2103,58 +2108,53 @@ static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *pee return AST_FEATURE_RETURN_SUCCESS; } - if (caller_chan && callee_chan) { - const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); - const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); - const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); + touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); + touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); + touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); - if (!touch_format) - touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); + if (!touch_format) + touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); - if (!touch_monitor) - touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); - - if (!touch_monitor_prefix) - touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); - - if (touch_monitor) { - len = strlen(touch_monitor) + 50; - args = alloca(len); - touch_filename = alloca(len); - snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); - snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); - } else { - caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, - caller_chan->caller.id.number.str, caller_chan->name)); - callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, - callee_chan->caller.id.number.str, callee_chan->name)); - len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; - args = alloca(len); - touch_filename = alloca(len); - snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); - snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); - } + if (!touch_monitor) + touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); - for(x = 0; x < strlen(args); x++) { - if (args[x] == '/') - args[x] = '-'; - } - - ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); + if (!touch_monitor_prefix) + touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); - pbx_exec(callee_chan, monitor_app, args); - pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); - pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); + if (touch_monitor) { + len = strlen(touch_monitor) + 50; + args = alloca(len); + touch_filename = alloca(len); + snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); + snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); + } else { + caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, + caller_chan->caller.id.number.str, caller_chan->name)); + callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, + callee_chan->caller.id.number.str, callee_chan->name)); + len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; + args = alloca(len); + touch_filename = alloca(len); + snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); + snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); + } - if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ - play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); - } - - return AST_FEATURE_RETURN_SUCCESS; + for(x = 0; x < strlen(args); x++) { + if (args[x] == '/') + args[x] = '-'; } - ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); - return -1; + ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); + + pbx_exec(callee_chan, monitor_app, args); + pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); + pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); + + if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ + play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); + } + + return AST_FEATURE_RETURN_SUCCESS; } static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) @@ -2164,6 +2164,8 @@ static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel * size_t len; struct ast_channel *caller_chan, *callee_chan; const char *mixmonitor_spy_type = "MixMonitor"; + const char *touch_format; + const char *touch_monitor; int count = 0; if (!mixmonitor_ok) { @@ -2198,7 +2200,6 @@ static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel * /* This means a mixmonitor is attached to the channel, running or not is unknown. */ if (count > 0) { - ast_verb(3, "User hit '%s' to stop recording call.\n", code); /* Make sure they are running */ @@ -2223,51 +2224,44 @@ static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel * ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); } - if (caller_chan && callee_chan) { - const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); - const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); + touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); + touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); - if (!touch_format) - touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); + if (!touch_format) + touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); - if (!touch_monitor) - touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); + if (!touch_monitor) + touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); - if (touch_monitor) { - len = strlen(touch_monitor) + 50; - args = alloca(len); - touch_filename = alloca(len); - snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); - snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); - } else { - caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, - caller_chan->caller.id.number.str, caller_chan->name)); - callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, - callee_chan->caller.id.number.str, callee_chan->name)); - len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; - args = alloca(len); - touch_filename = alloca(len); - snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); - snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); - } - - for( x = 0; x < strlen(args); x++) { - if (args[x] == '/') - args[x] = '-'; - } - - ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); + if (touch_monitor) { + len = strlen(touch_monitor) + 50; + args = alloca(len); + touch_filename = alloca(len); + snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); + snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); + } else { + caller_chan_id = ast_strdupa(S_COR(caller_chan->caller.id.number.valid, + caller_chan->caller.id.number.str, caller_chan->name)); + callee_chan_id = ast_strdupa(S_COR(callee_chan->caller.id.number.valid, + callee_chan->caller.id.number.str, callee_chan->name)); + len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; + args = alloca(len); + touch_filename = alloca(len); + snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); + snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); + } - pbx_exec(callee_chan, mixmonitor_app, args); - pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); - pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); - return AST_FEATURE_RETURN_SUCCESS; - + for( x = 0; x < strlen(args); x++) { + if (args[x] == '/') + args[x] = '-'; } - ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); - return -1; + ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); + pbx_exec(callee_chan, mixmonitor_app, args); + pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); + pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); + return AST_FEATURE_RETURN_SUCCESS; } static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) @@ -2489,6 +2483,8 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st struct ast_channel *transferer;/* Party B */ struct ast_channel *transferee;/* Party A */ struct ast_exten *park_exten; + const char *chan1_attended_sound; + const char *chan2_attended_sound; const char *transferer_real_context; char xferto[256] = ""; int res; @@ -2561,16 +2557,13 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st /* If we are performing an attended transfer and we have two channels involved then copy sound file information to play upon attended transfer completion */ - if (transferee) { - const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); - const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); - - if (!ast_strlen_zero(chan1_attended_sound)) { - pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); - } - if (!ast_strlen_zero(chan2_attended_sound)) { - pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); - } + chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); + chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); + if (!ast_strlen_zero(chan1_attended_sound)) { + pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); + } + if (!ast_strlen_zero(chan2_attended_sound)) { + pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); } /* Extract redial transferer information from the channel name. */ @@ -3174,12 +3167,10 @@ static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, ast_autoservice_start(idle); ast_autoservice_ignore(idle, AST_FRAME_DTMF_END); - if(work && idle) { - pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name); - pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name); - pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname); - pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname); - } + pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name); + pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name); + pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname); + pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname); if (!ast_strlen_zero(feature->moh_class)) ast_moh_start(idle, feature->moh_class, NULL); @@ -3294,7 +3285,9 @@ static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel if (operation) { res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); } - memcpy(feature, fge->feature, sizeof(*feature)); + if (feature) { + memcpy(feature, fge->feature, sizeof(*feature)); + } if (res != AST_FEATURE_RETURN_KEEPTRYING) { AST_RWLIST_UNLOCK(&feature_groups); break; @@ -3357,9 +3350,11 @@ static int feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags features; struct ast_call_feature feature; if (sense == FEATURE_SENSE_CHAN) { + /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); } else { + /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); } @@ -4753,76 +4748,80 @@ static int manage_parked_call(struct parkeduser *pu, const struct pollfd *pfds, /* And take them out of the parking lot */ parking_complete = 1; } else { /* still within parking time, process descriptors */ - for (x = 0; x < AST_MAX_FDS; x++) { - struct ast_frame *f; - int y; - - if (chan->fds[x] == -1) { - continue; /* nothing on this descriptor */ - } + x = 0; + if (pfds) { + for (; x < AST_MAX_FDS; x++) { + struct ast_frame *f; + int y; + + if (chan->fds[x] == -1) { + continue; /* nothing on this descriptor */ + } - for (y = 0; y < nfds; y++) { - if (pfds[y].fd == chan->fds[x]) { - /* Found poll record! */ - break; + for (y = 0; y < nfds; y++) { + if (pfds[y].fd == chan->fds[x]) { + /* Found poll record! */ + break; + } + } + if (y == nfds) { + /* Not found */ + continue; } - } - if (y == nfds) { - /* Not found */ - continue; - } - if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) { - /* Next x */ - continue; - } + if (!(pfds[y].revents & (POLLIN | POLLERR | POLLPRI))) { + /* Next x */ + continue; + } - if (pfds[y].revents & POLLPRI) { - ast_set_flag(chan, AST_FLAG_EXCEPTION); - } else { - ast_clear_flag(chan, AST_FLAG_EXCEPTION); - } - chan->fdno = x; - - /* See if they need servicing */ - f = ast_read(pu->chan); - /* Hangup? */ - if (!f || (f->frametype == AST_FRAME_CONTROL - && f->subclass.integer == AST_CONTROL_HANGUP)) { - if (f) { - ast_frfree(f); + if (pfds[y].revents & POLLPRI) { + ast_set_flag(chan, AST_FLAG_EXCEPTION); + } else { + ast_clear_flag(chan, AST_FLAG_EXCEPTION); } - post_manager_event("ParkedCallGiveUp", pu); - ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", - NULL); + chan->fdno = x; + + /* See if they need servicing */ + f = ast_read(pu->chan); + /* Hangup? */ + if (!f || (f->frametype == AST_FRAME_CONTROL + && f->subclass.integer == AST_CONTROL_HANGUP)) { + if (f) { + ast_frfree(f); + } + post_manager_event("ParkedCallGiveUp", pu); + ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", + NULL); - /* There's a problem, hang them up */ - ast_verb(2, "%s got tired of being parked\n", chan->name); - ast_hangup(chan); + /* There's a problem, hang them up */ + ast_verb(2, "%s got tired of being parked\n", chan->name); + ast_hangup(chan); - /* And take them out of the parking lot */ - parking_complete = 1; - break; - } else { - /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ - ast_frfree(f); - if (pu->hold_method == AST_CONTROL_HOLD - && pu->moh_trys < 3 - && !chan->generatordata) { - ast_debug(1, - "MOH on parked call stopped by outside source. Restarting on channel %s.\n", - chan->name); - ast_indicate_data(chan, AST_CONTROL_HOLD, - S_OR(pu->parkinglot->cfg.mohclass, NULL), - (!ast_strlen_zero(pu->parkinglot->cfg.mohclass) - ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0)); - pu->moh_trys++; + /* And take them out of the parking lot */ + parking_complete = 1; + break; + } else { + /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ + ast_frfree(f); + if (pu->hold_method == AST_CONTROL_HOLD + && pu->moh_trys < 3 + && !chan->generatordata) { + ast_debug(1, + "MOH on parked call stopped by outside source. Restarting on channel %s.\n", + chan->name); + ast_indicate_data(chan, AST_CONTROL_HOLD, + S_OR(pu->parkinglot->cfg.mohclass, NULL), + (!ast_strlen_zero(pu->parkinglot->cfg.mohclass) + ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0)); + pu->moh_trys++; + } + goto std; /* XXX Ick: jumping into an else statement??? XXX */ } - goto std; /* XXX Ick: jumping into an else statement??? XXX */ - } - } /* End for */ + } /* End for */ + } if (x >= AST_MAX_FDS) { -std: for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */ +std: + for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */ if (chan->fds[x] > -1) { void *tmp = ast_realloc(*new_pfds, (*new_nfds + 1) * sizeof(struct pollfd)); @@ -5083,7 +5082,7 @@ static int park_call_exec(struct ast_channel *chan, const char *data) /*! \brief Pickup parked call */ static int parked_call_exec(struct ast_channel *chan, const char *data) { - int res = 0; + int res; struct ast_channel *peer = NULL; struct parkeduser *pu; struct ast_context *con; @@ -5326,10 +5325,11 @@ static int parked_call_exec(struct ast_channel *chan, const char *data) } ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n", chan->name, park); + res = -1; } parkinglot_unref(parkinglot); - return -1; + return res; } /*! @@ -5672,7 +5672,7 @@ static struct ast_parkinglot *build_parkinglot(const char *pl_name, struct ast_v static void process_applicationmap_line(struct ast_variable *var) { char *tmp_val = ast_strdupa(var->value); - char *activateon; + char *activateon, *new_syn; struct ast_call_feature *feature; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(exten); @@ -5683,10 +5683,10 @@ static void process_applicationmap_line(struct ast_variable *var) ); AST_STANDARD_APP_ARGS(args, tmp_val); - if (strchr(args.app, '(')) { + if ((new_syn = strchr(args.app, '('))) { /* New syntax */ args.moh_class = args.app_args; - args.app_args = strchr(args.app, '('); + args.app_args = new_syn; *args.app_args++ = '\0'; if (args.app_args[strlen(args.app_args) - 1] == ')') { args.app_args[strlen(args.app_args) - 1] = '\0'; @@ -5743,6 +5743,7 @@ static void process_applicationmap_line(struct ast_variable *var) } else { ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," " must be 'self', or 'peer'\n", var->name); + ast_free(feature); return; } @@ -5757,6 +5758,7 @@ static void process_applicationmap_line(struct ast_variable *var) } else { ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," " must be 'caller', or 'callee', or 'both'\n", var->name); + ast_free(feature); return; } @@ -8212,7 +8214,9 @@ int ast_features_init(void) return res; } ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features)); - ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); + if (ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL)) { + return -1; + } ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL); if (!res) diff --git a/main/manager.c b/main/manager.c index 350bcb30dd..357c885994 100644 --- a/main/manager.c +++ b/main/manager.c @@ -4583,10 +4583,22 @@ static int action_reload(struct mansession *s, const struct message *m) const char *module = astman_get_header(m, "Module"); int res = ast_module_reload(S_OR(module, NULL)); - if (res == 2) { + switch (res) { + case -1: + astman_send_error(s, m, "A reload is in progress"); + break; + case 0: + astman_send_error(s, m, "No such module"); + break; + case 1: + astman_send_error(s, m, "Module does not support reload"); + break; + case 2: astman_send_ack(s, m, "Module Reloaded"); - } else { - astman_send_error(s, m, s == 0 ? "No such module" : "Module does not support reload"); + break; + default: + astman_send_error(s, m, "An unknown error occurred"); + break; } return 0; } @@ -6262,7 +6274,7 @@ static int auth_http_callback(struct ast_tcptls_session_instance *ser, ast_md5_hash(resp_hash, resp); } - if (!d.nonce || strncasecmp(d.response, resp_hash, strlen(resp_hash))) { + if (strncasecmp(d.response, resp_hash, strlen(resp_hash))) { /* Something was wrong, so give the client to try with a new challenge */ AST_RWLIST_UNLOCK(&users); nonce = 0; @@ -6968,7 +6980,7 @@ static int __init_manager(int reload) if (user_writetimeout) { int value = atoi(user_writetimeout); if (value < 100) { - ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno); + ast_log(LOG_WARNING, "Invalid writetimeout value '%d' in users.conf\n", value); } else { user->writetimeout = value; } diff --git a/main/netsock2.c b/main/netsock2.c index 1922ac3881..5ae4ceb709 100644 --- a/main/netsock2.c +++ b/main/netsock2.c @@ -270,6 +270,10 @@ int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, res_cnt++; } + if (res_cnt == 0) { + goto cleanup; + } + if ((*addrs = ast_malloc(res_cnt * sizeof(struct ast_sockaddr))) == NULL) { res_cnt = 0; goto cleanup; diff --git a/main/pbx.c b/main/pbx.c index a0284246e0..1d1bbb8aba 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -1753,8 +1753,9 @@ static void cli_match_char_tree(struct match_char *node, char *prefix, int fd) extenstr[0] = '\0'; - if (node && node->exten) + if (node->exten) { snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten); + } if (strlen(node->x) > 1) { ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N', @@ -5540,8 +5541,9 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, * and continue, or we can drop out entirely. */ if (invalid - || !ast_exists_extension(c, c->context, c->exten, 1, - S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) { + || (ast_strlen_zero(dst_exten) && + !ast_exists_extension(c, c->context, c->exten, 1, + S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL)))) { /*!\note * If there is no match at priority 1, it is not a valid extension anymore. * Try to continue at "i" (for invalid) or "e" (for exception) or exit if @@ -6980,8 +6982,10 @@ static int show_debug_helper(int fd, const char *context, const char *exten, str dpc->context_existence = 1; - if (!c->pattern_tree) + if (!c->pattern_tree) { + /* Ignore check_return warning from Coverity for ast_exists_extension below */ ast_exists_extension(NULL, c->name, "s", 1, ""); /* do this to force the trie to built, if it is not already */ + } ast_rdlock_context(c); @@ -7774,6 +7778,8 @@ static void context_merge(struct ast_context **extcontexts, struct ast_hashtab * if (!new) { ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name); + ast_hashtab_end_traversal(prio_iter); + ast_hashtab_end_traversal(exten_iter); return; /* no sense continuing. */ } /* we will not replace existing entries in the new context with stuff from the old context. @@ -8519,6 +8525,7 @@ int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const if (!strcasecmp(ignorepatc->pattern, value)) { /* Already there */ ast_unlock_context(con); + ast_free(ignorepat); errno = EEXIST; return -1; } @@ -9995,6 +10002,11 @@ static int pbx_builtin_gotoiftime(struct ast_channel *chan, const char *data) struct timeval tv = ast_tvnow(); long timesecs; + if (!chan) { + ast_log(LOG_WARNING, "GotoIfTime requires a channel on which to operate\n"); + return -1; + } + if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n