]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Multiple revisions 377838,377842,377848,377882,377923,377947,377992,378037,378089...
authorJason Parker <jparker@digium.com>
Tue, 8 Jan 2013 19:12:38 +0000 (19:12 +0000)
committerJason Parker <jparker@digium.com>
Tue, 8 Jan 2013 19:12:38 +0000 (19:12 +0000)
........
  r377838 | rmudgett | 2012-12-11 14:42:59 -0600 (Tue, 11 Dec 2012) | 16 lines

  Cleanup taskprocessor on exit.

  * Cleanup CLI commands on exit.

  * v10 only: Merged v1.8 -r374177 change to taskprocessor.c missed in v10 -r374178.

  (issue ASTERISK-20649)
  Reported by: Corey Farrell
  Patches:
        taskprocessor-cleanup-1_8-11-trunk.patch (license #5909) patch uploaded by Corey Farrell
        taskprocessor-cleanup-10-only.patch (license #5909) patch uploaded by Corey Farrell
        Modified
  ........

  Merged revisions 377837 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r377842 | mmichelson | 2012-12-11 14:48:16 -0600 (Tue, 11 Dec 2012) | 13 lines

  Fix crash that can occur if CLI registration fails for an aliased command.

  A recent memory leak fix in main/cli.c causes an ast_cli_entry's command
  field to be freed and NULLed if ast_cli_register() fails. res_clialiases
  was ignoring the return value of ast_cli_register() and was then passing
  the NULL command off to a a hash function. This resulted in a crash.

  The fix is not to ignore the erroneous return value. If ast_cli_register()
  fails, then we do not continue trying to process the current alias.
  ........

  Merged revisions 377840 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r377848 | rmudgett | 2012-12-11 15:07:47 -0600 (Tue, 11 Dec 2012) | 14 lines

  Cleanup udptl on exit.

  * Cleanup CLI commands on exit.

  (issue ASTERISK-20649)
  Reported by: Corey Farrell
  Patches:
        udptl-shutdown-1_8-10.patch (license #5909) patch uploaded by Corey Farrell
        udptl-shutdown-11-trunk.patch (license #5909) patch uploaded by Corey Farrell
        Modified
  ........

  Merged revisions 377847 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r377882 | rmudgett | 2012-12-11 15:57:44 -0600 (Tue, 11 Dec 2012) | 10 lines

  Cleanup CLI commands on exit for several files.

  (issue ASTERISK-20649)
  Reported by: Corey Farrell
  Patches:
        unregister-cli-multiple-all.patch (license #5909) patch uploaded by Corey Farrell
  ........

  Merged revisions 377881 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r377923 | newtonr | 2012-12-12 16:41:24 -0600 (Wed, 12 Dec 2012) | 12 lines

  Incremented EXTRA_SOUNDS_VERSION in sounds/Makefile to 1.4.12 for new Extra Sounds releases

  See CHANGES-* files in English extra 1.4.12 tarballs for new sound prompts added.

  (closes ASTERISK-20328)
  Reported by: Matt Jordan
  (closes AST-755)
  Reported by: John Bigelow
  ........

  Merged revisions 377922 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r377947 | kmoore | 2012-12-13 07:48:32 -0600 (Thu, 13 Dec 2012) | 17 lines

  Ensure Min-SE is included in outbound INVITEs

  Asterisk now includes Min-SE in outbound INVITEs when the value is not
  90 (the default) and session timers are not disabled. This has the
  effect of Asterisk following RFC4028 more closely with regard to 422
  responses and preventing situations in which Asterisk would be forced
  to temporarily accept a call to tear it down based on a Session-Expires
  below the locally configured Min-SE.

  (issue SWP-5051)
  Review: https://reviewboard.asterisk.org/r/2222/
Reported-by: Kinsey Moore
Patch-by: Kinsey Moore
  ........

  Merged revisions 377946 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r377992 | rmudgett | 2012-12-13 14:52:26 -0600 (Thu, 13 Dec 2012) | 29 lines

  confbridge: Fix MOH on simultaneous user entry to a new conference.

  When two users entered a new conference simultaneously, one of the callers
  hears MOH.  This happened if two unmarked users entered simultaneously and
  also if a waitmarked and a marked user entered simultaneously.

  * Created a confbridge internal MOH API to eliminate the inlined MOH
  handling code.  Note that the conference mixing bridge needs to be locked
  when actually starting/stopping MOH because there is a small window
  between the conference join unsuspend MOH and actually joining the mixing
  bridge.

  * Created the concept of suspended MOH so it can be interrupted while
  conference join announcements to the user and DTMF features can operate.

  * Suspend any MOH until the user is about to actually join the mixing
  bridge of the conference.  This way any pre-join file playback does not
  need to worry about MOH.

  * Made post-join actions only play deferred entry announcement files.
  Changing the user/conference state during that time is not protected or
  controlled by the state machine.

  (closes issue ASTERISK-20606)
  Reported by: Eugenia Belova
  Tested by: rmudgett

  Review: https://reviewboard.asterisk.org/r/2232/
........
  r378037 | rmudgett | 2012-12-14 15:30:46 -0600 (Fri, 14 Dec 2012) | 20 lines

  app_queue: Revert bad ringinuse=no patch.

  With the option ringinuse=no set, the patch committed for ASTERISK-16115
  causes non-SIP queue members to never be called because the device state
  is checked after a channel is created to determine if the member is busy.
  These queue members always get the "Member %s is busy, cannot dial"
  message.

  Most channel drivers other than chan_sip use the default device state
  handling.  The default device-state state is considered in use or unknown
  if the channel exists or not respectively.

  (closes issue ASTERISK-20801)
  Reported by: rmudgett
  Patches:
        jira_asterisk_16115_revert_r370418_v1.8.patch (license #5621) patch uploaded by rmudgett
  ........

  Merged revisions 378036 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r378089 | rmudgett | 2012-12-17 16:57:10 -0600 (Mon, 17 Dec 2012) | 16 lines

  Make chan_local module references tied to local_pvt lifetime.

  The chan_local module references were manually tied to the existence of
  the ;1 and ;2 channel links.

  * Made chan_local module references tied to the existence of the local_pvt
  structure as well as automatically take care of the module references.

  * Tweaked the wording of the local_fixup() failure warning message to make
  sense.

  Review: https://reviewboard.asterisk.org/r/2181/
  ........

  Merged revisions 378088 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r378093 | rmudgett | 2012-12-17 17:08:40 -0600 (Mon, 17 Dec 2012) | 5 lines

  Fix potential double free when unloading a module.
  ........

  Merged revisions 378092 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r378120 | kmoore | 2012-12-18 11:38:22 -0600 (Tue, 18 Dec 2012) | 11 lines

  Add test events for time limit-related hangups

  This patch adds hangup-related test events in order to support testing
  of time-limited bridges. This aids in testing the S() and L() bridge
  options.

  (issue SWP-4713)
  ........

  Merged revisions 378119 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r378218 | kmoore | 2012-12-31 08:43:26 -0600 (Mon, 31 Dec 2012) | 12 lines

  Ensure chan_sip rejects encrypted streams without crypto info

  This ensures that Asterisk rejects encrypted media streams (RTP/SAVP
  audio and video) that are missing cryptographic keys and ensures that
  the incoming SDP is consistent with RFC4568 as far as having a crypto
  attribute present for any SAVP streams.

  Review: https://reviewboard.asterisk.org/r/2204/
  ........

  Merged revisions 378217 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r378286 | mjordan | 2013-01-02 09:23:57 -0600 (Wed, 02 Jan 2013) | 30 lines

  Resolve crashes due to large stack allocations when using TCP

  Asterisk had several places where messages received over various network
  transports may be copied in a single stack allocation. In the case of TCP,
  since multiple packets in a stream may be concatenated together, this can
  lead to large allocations that overflow the stack.

  This patch modifies those portions of Asterisk using TCP to either
  favor heap allocations or use an upper bound to ensure that the stack will not
  overflow:
   * For SIP, the allocation now has an upper limit
   * For HTTP, the allocation is now a heap allocation instead of a stack
     allocation
   * For XMPP (in res_jabber), the allocation has been eliminated since it was
     unnecesary.

  Note that the HTTP portion of this issue was independently found by Brandon
  Edwards of Exodus Intelligence.

  (issue ASTERISK-20658)
  Reported by: wdoekes, Brandon Edwards
  Tested by: mmichelson, wdoekes
  patches:
    ASTERISK-20658_res_jabber.c.patch uploaded by mmichelson (license 5049)
    issueA20658_http_postvars_use_malloc2.patch uploaded by wdoekes (license 5674)
    issueA20658_limit_sip_packet_size3.patch uploaded by wdoekes (license 5674)
  ........

  Merged revisions 378269 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
  r378320 | mjordan | 2013-01-02 11:40:28 -0600 (Wed, 02 Jan 2013) | 27 lines

  Prevent exhaustion of system resources through exploitation of event cache

  Asterisk maintains an internal cache for devices in the event subsystem. The
  device state cache holds the state of each device known to Asterisk, such that
  consumers of device state information can query for the last known state for
  a particular device, even if it is not part of an active call. The concept of
  a device in Asterisk can include entities that do not have a physical
  representation. One way that this occurred was when anonymous calls are allowed
  in Asterisk. A device was automatically created and stored in the cache for
  each anonymous call that occurred; this was possible in the SIP and IAX2
  channel drivers and through channel drivers that utilized the
  res_jabber/res_xmpp resource modules (Gtalk, Jingle, and Motif). These devices
  are never removed from the system, allowing anonymous calls to potentially
  exhaust a system's resources.

  This patch changes the event cache subsystem and device state management to
  no longer cache devices that are not associated with a physical entity.

  (issue ASTERISK-20175)
  Reported by: Russell Bryant, Leif Madsen, Joshua Colp
  Tested by: kmoore
  patches:
    event-cachability-3.diff uploaded by jcolp (license 5000)
  ........

  Merged revisions 378303 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 377838,377842,377848,377882,377923,377947,377992,378037,378089,378093,378120,378218,378286,378320 from http://svn.asterisk.org/svn/asterisk/branches/10

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/10-digiumphones@378661 65c4cc65-6c06-0410-ace0-fbb531ad65f3

39 files changed:
apps/app_confbridge.c
apps/app_meetme.c
apps/app_queue.c
apps/confbridge/conf_state.c
apps/confbridge/conf_state_empty.c
apps/confbridge/conf_state_multi_marked.c
apps/confbridge/include/confbridge.h
channels/chan_agent.c
channels/chan_dahdi.c
channels/chan_iax2.c
channels/chan_local.c
channels/chan_sip.c
channels/chan_skinny.c
channels/sip/include/sip.h
funcs/func_devstate.c
include/asterisk/bridging.h
include/asterisk/channel.h
include/asterisk/devicestate.h
include/asterisk/event_defs.h
main/aoc.c
main/ccss.c
main/cel.c
main/channel.c
main/data.c
main/devicestate.c
main/event.c
main/features.c
main/file.c
main/http.c
main/image.c
main/loader.c
main/stun.c
main/taskprocessor.c
main/timing.c
main/udptl.c
res/res_calendar.c
res/res_clialiases.c
res/res_jabber.c
sounds/Makefile

index df72400809b2c1072b96cc12fbff96a2491152cc..08c0516161df3716828e22517aa9eba464272de0 100644 (file)
@@ -848,6 +848,94 @@ static int handle_conf_user_leave(struct conference_bridge_user *cbu)
        return 0;
 }
 
+void conf_moh_stop(struct conference_bridge_user *user)
+{
+       user->playing_moh = 0;
+       if (!user->suspended_moh) {
+               int in_bridge;
+
+               /*
+                * Locking the ast_bridge here is the only way to hold off the
+                * call to ast_bridge_join() in confbridge_exec() from
+                * interfering with the bridge and MOH operations here.
+                */
+               ast_bridge_lock(user->conference_bridge->bridge);
+
+               /*
+                * Temporarily suspend the user from the bridge so we have
+                * control to stop MOH if needed.
+                */
+               in_bridge = !ast_bridge_suspend(user->conference_bridge->bridge, user->chan);
+               ast_moh_stop(user->chan);
+               if (in_bridge) {
+                       ast_bridge_unsuspend(user->conference_bridge->bridge, user->chan);
+               }
+
+               ast_bridge_unlock(user->conference_bridge->bridge);
+       }
+}
+
+void conf_moh_start(struct conference_bridge_user *user)
+{
+       user->playing_moh = 1;
+       if (!user->suspended_moh) {
+               int in_bridge;
+
+               /*
+                * Locking the ast_bridge here is the only way to hold off the
+                * call to ast_bridge_join() in confbridge_exec() from
+                * interfering with the bridge and MOH operations here.
+                */
+               ast_bridge_lock(user->conference_bridge->bridge);
+
+               /*
+                * Temporarily suspend the user from the bridge so we have
+                * control to start MOH if needed.
+                */
+               in_bridge = !ast_bridge_suspend(user->conference_bridge->bridge, user->chan);
+               ast_moh_start(user->chan, user->u_profile.moh_class, NULL);
+               if (in_bridge) {
+                       ast_bridge_unsuspend(user->conference_bridge->bridge, user->chan);
+               }
+
+               ast_bridge_unlock(user->conference_bridge->bridge);
+       }
+}
+
+/*!
+ * \internal
+ * \brief Unsuspend MOH for the conference user.
+ *
+ * \param user Conference user to unsuspend MOH on.
+ *
+ * \return Nothing
+ */
+static void conf_moh_unsuspend(struct conference_bridge_user *user)
+{
+       ao2_lock(user->conference_bridge);
+       if (--user->suspended_moh == 0 && user->playing_moh) {
+               ast_moh_start(user->chan, user->u_profile.moh_class, NULL);
+       }
+       ao2_unlock(user->conference_bridge);
+}
+
+/*!
+ * \internal
+ * \brief Suspend MOH for the conference user.
+ *
+ * \param user Conference user to suspend MOH on.
+ *
+ * \return Nothing
+ */
+static void conf_moh_suspend(struct conference_bridge_user *user)
+{
+       ao2_lock(user->conference_bridge);
+       if (user->suspended_moh++ == 0 && user->playing_moh) {
+               ast_moh_stop(user->chan);
+       }
+       ao2_unlock(user->conference_bridge);
+}
+
 int conf_handle_first_marked_common(struct conference_bridge_user *cbu)
 {
        if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET) && play_prompt_to_user(cbu, conf_get_sound(CONF_SOUND_PLACE_IN_CONF, cbu->b_profile.sounds))) {
@@ -858,19 +946,12 @@ int conf_handle_first_marked_common(struct conference_bridge_user *cbu)
 
 int conf_handle_inactive_waitmarked(struct conference_bridge_user *cbu)
 {
-       /* Be sure we are muted so we can't talk to anybody else waiting */
-       cbu->features.mute = 1;
        /* If we have not been quieted play back that they are waiting for the leader */
        if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET) && play_prompt_to_user(cbu,
                        conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, cbu->b_profile.sounds))) {
                /* user hungup while the sound was playing */
                return -1;
        }
-       /* Start music on hold if needed */
-       if (ast_test_flag(&cbu->u_profile, USER_OPT_MUSICONHOLD)) {
-               ast_moh_start(cbu->chan, cbu->u_profile.moh_class, NULL);
-               cbu->playing_moh = 1;
-       }
        return 0;
 }
 
@@ -901,7 +982,7 @@ int conf_add_post_join_action(struct conference_bridge_user *cbu, int (*func)(st
 
 void conf_handle_first_join(struct conference_bridge *conference_bridge)
 {
-       ast_devstate_changed(AST_DEVICE_INUSE, "confbridge:%s", conference_bridge->name);
+       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference_bridge->name);
 }
 
 void conf_handle_second_active(struct conference_bridge *conference_bridge)
@@ -909,11 +990,8 @@ void conf_handle_second_active(struct conference_bridge *conference_bridge)
        /* If we are the second participant we may need to stop music on hold on the first */
        struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->active_list);
 
-       /* Temporarily suspend the above participant from the bridge so we have control to stop MOH if needed */
-       if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
-               first_participant->playing_moh = 0;
-               ast_moh_stop(first_participant->chan);
-               ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
+       if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD)) {
+               conf_moh_stop(first_participant);
        }
        if (!ast_test_flag(&first_participant->u_profile, USER_OPT_STARTMUTED)) {
                first_participant->features.mute = 0;
@@ -1038,6 +1116,13 @@ static struct conference_bridge *join_conference_bridge(const char *name, struct
 
        ao2_lock(conference_bridge);
 
+       /*
+        * Suspend any MOH until the user actually joins the bridge of
+        * the conference.  This way any pre-join file playback does not
+        * need to worry about MOH.
+        */
+       conference_bridge_user->suspended_moh = 1;
+
        if (handle_conf_user_join(conference_bridge_user)) {
                /* Invalid event, nothing was done, so we don't want to process a leave. */
                ao2_unlock(conference_bridge);
@@ -1455,21 +1540,18 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
        /* Play the Join sound to both the conference and the user entering. */
        if (!quiet) {
                const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, conference_bridge_user.b_profile.sounds);
-               if (conference_bridge_user.playing_moh) {
-                       ast_moh_stop(chan);
-               }
+
                ast_stream_and_wait(chan, join_sound, "");
                ast_autoservice_start(chan);
                play_sound_file(conference_bridge, join_sound);
                ast_autoservice_stop(chan);
-               if (conference_bridge_user.playing_moh) {
-                       ast_moh_start(chan, conference_bridge_user.u_profile.moh_class, NULL);
-               }
        }
 
        /* See if we need to automatically set this user as a video source or not */
        handle_video_on_join(conference_bridge, conference_bridge_user.chan, ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_MARKEDUSER));
 
+       conf_moh_unsuspend(&conference_bridge_user);
+
        /* Join our conference bridge for real */
        send_join_event(conference_bridge_user.chan, conference_bridge->name);
        ast_bridge_join(conference_bridge->bridge,
@@ -1810,25 +1892,14 @@ int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel,
        struct conf_menu_entry *menu_entry,
        struct conf_menu *menu)
 {
-       struct conference_bridge *conference_bridge = conference_bridge_user->conference_bridge;
-
        /* See if music on hold is playing */
-       ao2_lock(conference_bridge);
-       if (conference_bridge_user->playing_moh) {
-               /* MOH is going, let's stop it */
-               ast_moh_stop(bridge_channel->chan);
-       }
-       ao2_unlock(conference_bridge);
+       conf_moh_suspend(conference_bridge_user);
 
        /* execute the list of actions associated with this menu entry */
-       execute_menu_entry(conference_bridge, conference_bridge_user, bridge_channel, menu_entry, menu);
+       execute_menu_entry(conference_bridge_user->conference_bridge, conference_bridge_user, bridge_channel, menu_entry, menu);
 
        /* See if music on hold needs to be started back up again */
-       ao2_lock(conference_bridge);
-       if (conference_bridge_user->playing_moh) {
-               ast_moh_start(bridge_channel->chan, conference_bridge_user->u_profile.moh_class, NULL);
-       }
-       ao2_unlock(conference_bridge);
+       conf_moh_unsuspend(conference_bridge_user);
 
        return 0;
 }
@@ -2718,13 +2789,7 @@ void conf_mute_only_active(struct conference_bridge *conference_bridge)
        /* Turn on MOH/mute if the single participant is set up for it */
        if (ast_test_flag(&only_participant->u_profile, USER_OPT_MUSICONHOLD)) {
                only_participant->features.mute = 1;
-               if (!only_participant->chan->bridge || !ast_bridge_suspend(conference_bridge->bridge, only_participant->chan)) {
-                       ast_moh_start(only_participant->chan, only_participant->u_profile.moh_class, NULL);
-                       only_participant->playing_moh = 1;
-                       if (only_participant->chan->bridge) {
-                               ast_bridge_unsuspend(conference_bridge->bridge, only_participant->chan);
-                       }
-               }
+               conf_moh_start(only_participant);
        }
 }
 
index bd63299324aef4bf8cbdb3a07e5173dde8ad4fc3..28ddd6ea2160c173ae9ccc24e2b2dbd51e81ea41 100644 (file)
@@ -2650,7 +2650,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
 
        /* This device changed state now - if this is the first user */
        if (conf->users == 1)
-               ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
+               ast_devstate_changed(AST_DEVICE_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
 
        ast_mutex_unlock(&conf->playlock);
 
@@ -3967,7 +3967,7 @@ bailoutandtrynormal:
 
                /* Change any states */
                if (!conf->users) {
-                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
+                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
                }
 
                /* Return the number of seconds the user was in the conf */
@@ -5457,8 +5457,8 @@ static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk
                                || trunk_ref == exclude)
                                continue;
                        trunk_ref->state = state;
-                       ast_devstate_changed(sla_state_to_devstate(state), 
-                               "SLA:%s_%s", station->name, trunk->name);
+                       ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE,
+                                            "SLA:%s_%s", station->name, trunk->name);
                        break;
                }
        }
@@ -5956,8 +5956,8 @@ static void sla_handle_hold_event(struct sla_event *event)
 {
        ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
        event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
-       ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
-               event->station->name, event->trunk_ref->trunk->name);
+       ast_devstate_changed(AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, "SLA:%s_%s",
+                            event->station->name, event->trunk_ref->trunk->name);
        sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
                INACTIVE_TRUNK_REFS, event->trunk_ref);
 
@@ -6466,8 +6466,8 @@ static int sla_station_exec(struct ast_channel *chan, const char *data)
                        sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
                else {
                        trunk_ref->state = SLA_TRUNK_STATE_UP;
-                       ast_devstate_changed(AST_DEVICE_INUSE, 
-                               "SLA:%s_%s", station->name, trunk_ref->trunk->name);
+                       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE,
+                                            "SLA:%s_%s", station->name, trunk_ref->trunk->name);
                }
        } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
                struct sla_ringing_trunk *ringing_trunk;
index 142c5281ba486680ba03f2effdde81b87cc922ab..0aac83dd48613fca83967f6537ca8ada406b2252 100644 (file)
@@ -3192,7 +3192,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
                        if (newstate != tmp->member->status) {
                                ast_log(LOG_WARNING, "Found a channel matching iterface %s while status was %s changed to %s\n",
                                        tmp->member->interface, ast_devstate2str(tmp->member->status), ast_devstate2str(newstate));
-                               ast_devstate_changed_literal(newstate, tmp->member->interface);
+                               ast_devstate_changed_literal(newstate, AST_DEVSTATE_CACHABLE, tmp->member->interface);
                        }
                }
                if ((tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
@@ -3306,18 +3306,8 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
        ast_channel_unlock(tmp->chan);
        ast_channel_unlock(qe->chan);
 
-       ao2_lock(tmp->member);
-       update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
-       if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
-               ast_verb(1, "Member %s is busy, cannot dial", tmp->member->interface);
-               res = -1;
-       }
-       else {
-               /* Place the call, but don't wait on the answer */
-               res = ast_call(tmp->chan, location, 0);
-       }
-       ao2_unlock(tmp->member);
-       if (res) {
+       /* Place the call, but don't wait on the answer */
+       if ((res = ast_call(tmp->chan, location, 0))) {
                /* Again, keep going even if there's an error */
                ast_verb(3, "Couldn't call %s\n", tmp->interface);
                do_hang(tmp);
index e3684058a4b23f1b1e22d2ec097888795d5532bf..ea5ab10f0810c8e8f6879b0041567b00823a49a6 100644 (file)
@@ -47,9 +47,28 @@ void conf_invalid_event_fn(struct conference_bridge_user *cbu)
        ast_log(LOG_ERROR, "Invalid event for confbridge user '%s'\n", cbu->u_profile.name);
 }
 
+/*!
+ * \internal
+ * \brief Mute the user and play MOH if the user requires it.
+ *
+ * \param user Conference user to mute and optionally start MOH on.
+ *
+ * \return Nothing
+ */
+static void conf_mute_moh_inactive_waitmarked(struct conference_bridge_user *user)
+{
+       /* Be sure we are muted so we can't talk to anybody else waiting */
+       user->features.mute = 1;
+       /* Start music on hold if needed */
+       if (ast_test_flag(&user->u_profile, USER_OPT_MUSICONHOLD)) {
+               conf_moh_start(user);
+       }
+}
+
 void conf_default_join_waitmarked(struct conference_bridge_user *cbu)
 {
        conf_add_user_waiting(cbu->conference_bridge, cbu);
+       conf_mute_moh_inactive_waitmarked(cbu);
        conf_add_post_join_action(cbu, conf_handle_inactive_waitmarked);
 }
 
index 22997ad2c6cf08d7243e7020481bf29ae32da3b6..afc736d4a2156143c5035ad6b564b0634d71f621 100644 (file)
@@ -81,6 +81,6 @@ static void join_marked(struct conference_bridge_user *cbu)
 static void transition_to_empty(struct conference_bridge_user *cbu)
 {
        /* Set device state to "not in use" */
-       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "confbridge:%s", cbu->conference_bridge->name);
+       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", cbu->conference_bridge->name);
        conf_ended(cbu->conference_bridge);
 }
index 69850b18dc4bdc3892a382b8cf7973871d427ec5..2529266099f7d0194f8f37dd41352afb8a2c3835 100644 (file)
@@ -107,12 +107,8 @@ static void leave_marked(struct conference_bridge_user *cbu)
                                cbu_iter->conference_bridge->waitingusers++;
                                /* Handle muting/moh of cbu_iter if necessary */
                                if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_MUSICONHOLD)) {
-                                  cbu_iter->features.mute = 1;
-                                       if (!ast_bridge_suspend(cbu_iter->conference_bridge->bridge, cbu_iter->chan)) {
-                                               ast_moh_start(cbu_iter->chan, cbu_iter->u_profile.moh_class, NULL);
-                                               cbu_iter->playing_moh = 1;
-                                               ast_bridge_unsuspend(cbu_iter->conference_bridge->bridge, cbu_iter->chan);
-                                       }
+                                       cbu_iter->features.mute = 1;
+                                       conf_moh_start(cbu_iter);
                                }
                        }
                }
@@ -173,10 +169,8 @@ static void transition_to_marked(struct conference_bridge_user *cbu)
                cbu->conference_bridge->waitingusers--;
                AST_LIST_INSERT_TAIL(&cbu->conference_bridge->active_list, cbu_iter, list);
                cbu->conference_bridge->activeusers++;
-               if (cbu_iter->playing_moh && !ast_bridge_suspend(cbu->conference_bridge->bridge, cbu_iter->chan)) {
-                       cbu_iter->playing_moh = 0;
-                       ast_moh_stop(cbu_iter->chan);
-                       ast_bridge_unsuspend(cbu->conference_bridge->bridge, cbu_iter->chan);
+               if (cbu_iter->playing_moh) {
+                       conf_moh_stop(cbu_iter);
                }
                /* only unmute them if they are not supposed to start muted */
                if (!ast_test_flag(&cbu_iter->u_profile, USER_OPT_STARTMUTED)) {
index ea544513d226c95a34d808e40da46769c13fe29f..c52d3305f4da7fd201fb8f76e840a116cf7b453d 100644 (file)
@@ -231,6 +231,7 @@ struct conference_bridge_user {
        struct ast_channel *chan;                    /*!< Asterisk channel participating */
        struct ast_bridge_features features;         /*!< Bridge features structure */
        struct ast_bridge_tech_optimizations tech_args; /*!< Bridge technology optimizations for talk detection */
+       unsigned int suspended_moh;                  /*!< Count of active suspended MOH actions. */
        unsigned int kicked:1;                       /*!< User has been kicked from the conference */
        unsigned int playing_moh:1;                  /*!< MOH is currently being played to the user */
        AST_LIST_HEAD_NOLOCK(, post_join_action) post_join_list; /*!< List of sounds to play after joining */;
@@ -353,6 +354,24 @@ int play_sound_file(struct conference_bridge *conference_bridge, const char *fil
  */
 void conf_ended(struct conference_bridge *conference_bridge);
 
+/*!
+ * \brief Stop MOH for the conference user.
+ *
+ * \param user Conference user to stop MOH on.
+ *
+ * \return Nothing
+ */
+void conf_moh_stop(struct conference_bridge_user *user);
+
+/*!
+ * \brief Start MOH for the conference user.
+ *
+ * \param user Conference user to start MOH on.
+ *
+ * \return Nothing
+ */
+void conf_moh_start(struct conference_bridge_user *user);
+
 /*! \brief Attempt to mute/play MOH to the only user in the conference if they require it
  * \param conference_bridge A conference bridge containing a single user
  */
index c3454ec2b023cb3cf0d7f5e0a7a54a1f477ec836..b0f868be7ec1b6104b0e10b6312b22ecda2979db 100644 (file)
@@ -617,7 +617,7 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
                if (p->chan) {
                        p->chan->_bridge = NULL;
                        p->chan = NULL;
-                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
+                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
                        p->acknowledged = 0;
                }
        } else {
@@ -875,7 +875,7 @@ static int agent_call(struct ast_channel *ast, char *dest, int timeout)
        } else {
                /* Agent hung-up */
                p->chan = NULL;
-               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
+               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
        }
 
        if (!res) {
@@ -995,7 +995,7 @@ static int agent_hangup(struct ast_channel *ast)
        if (!p->loginstart) {
                p->logincallerid[0] = '\0';
        } else {
-               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
+               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
        }
 
        if (p->abouttograb) {
@@ -2143,7 +2143,7 @@ static int login_exec(struct ast_channel *chan, const char *data)
                                                }
                                                ast_mutex_unlock(&p->lock);
                                                AST_LIST_UNLOCK(&agents);
-                                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
+                                               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
                                                while (res >= 0) {
                                                        ast_mutex_lock(&p->lock);
                                                        if (p->deferlogoff && p->chan) {
@@ -2164,7 +2164,7 @@ static int login_exec(struct ast_channel *chan, const char *data)
                                                                if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
                                                                        ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
                                                                        p->lastdisc = ast_tv(0, 0);
-                                                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
+                                                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
                                                                        if (p->ackcall) {
                                                                                check_beep(p, 0);
                                                                        } else {
@@ -2224,7 +2224,7 @@ static int login_exec(struct ast_channel *chan, const char *data)
                                                ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
                                                ast_verb(2, "Agent '%s' logged out\n", p->agent);
                                                /* If there is no owner, go ahead and kill it now */
-                                               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
+                                               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
                                                if (p->dead && !p->owner) {
                                                        ast_mutex_destroy(&p->lock);
                                                        ast_cond_destroy(&p->app_complete_cond);
index 726c1f9bd22a4999733634ee72756d0640d4e6b4..37e216a55d3c73c2cc786527a4613e48d857b554 100644 (file)
@@ -3401,7 +3401,7 @@ static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
        }
        if (pri->congestion_devstate != new_state) {
                pri->congestion_devstate = new_state;
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "DAHDI/I%d/congestion", pri->span);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, "DAHDI/I%d/congestion", pri->span);
        }
 #if defined(THRESHOLD_DEVSTATE_PLACEHOLDER)
        /* Update the span threshold device state and report any change. */
@@ -3417,7 +3417,7 @@ static void dahdi_pri_update_span_devstate(struct sig_pri_span *pri)
        }
        if (pri->threshold_devstate != new_state) {
                pri->threshold_devstate = new_state;
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "DAHDI/I%d/threshold", pri->span);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, "DAHDI/I%d/threshold", pri->span);
        }
 #endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */
 }
@@ -9888,7 +9888,8 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
        if (dashptr) {
                *dashptr = '\0';
        }
-       ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name);
+       tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
+       ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, device_name);
 
        for (v = i->vars ; v ; v = v->next)
                pbx_builtin_setvar_helper(tmp, v->name, v->value);
index bdbb685c912a536278a0c30d0e353016a54b639c..0e84935d00ab7987d23cdb3d840033812cbbb68e 100644 (file)
@@ -5825,7 +5825,7 @@ static int iax2_getpeertrunk(struct sockaddr_in sin)
 }
 
 /*! \brief  Create new call, interface with the PBX core */
-static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability, const char *linkedid)
+static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability, const char *linkedid, unsigned int cachable)
 {
        struct ast_channel *tmp;
        struct chan_iax2_pvt *i;
@@ -5900,6 +5900,10 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab
        i->owner = tmp;
        i->capability = capability;
 
+       if (!cachable) {
+               tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
+       }
+
        /* Set inherited variables */
        if (i->vars) {
                for (v = i->vars ; v ; v = v->next)
@@ -8188,7 +8192,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                /* if challenge has been sent, but no challenge response if given, reject. */
                goto return_unref;
        }
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
 
        /* either Authentication has taken place, or a REGAUTH must be sent before verifying registration */
        res = 0;
@@ -8742,7 +8746,7 @@ static void __expire_registry(const void *data)
        if (!ast_test_flag64(peer, IAX_TEMPONLY))
                ast_db_del("IAX/Registry", peer->name);
        register_peer_exten(peer, 0);
-       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
+       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
        if (iax2_regfunk)
                iax2_regfunk(peer->name, 0);
 
@@ -8797,7 +8801,7 @@ static void reg_source_db(struct iax2_peer *p)
                }
        }
 
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
 
        p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
        if (p->expire == -1) {
@@ -8874,14 +8878,14 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
                                            ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
                        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\nPost: %d\r\nPort: %d\r\n", p->name, ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), ntohs(sin->sin_port));
                        register_peer_exten(p, 1);
-                       ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
+                       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
                } else if (!ast_test_flag64(p, IAX_TEMPONLY)) {
                        ast_verb(3, "Unregistered IAX2 '%s' (%s)\n", p->name,
                                            ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED");
                        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
                        register_peer_exten(p, 0);
                        ast_db_del("IAX/Registry", p->name);
-                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", p->name); /* Activate notification */
+                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
                }
                /* Update the host */
                /* Verify that the host is really there */
@@ -10397,7 +10401,8 @@ static int socket_process(struct iax2_thread *thread)
                    (f.frametype == AST_FRAME_IAX)) {
                        if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
                                ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART);
-                               if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL)) {
+                               if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL,
+                                                 ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
                                        ast_variables_destroy(ies.vars);
                                        ast_mutex_unlock(&iaxsl[fr->callno]);
                                        return 1;
@@ -11036,13 +11041,13 @@ static int socket_process(struct iax2_thread *thread)
                                                if (iaxs[fr->callno]->pingtime <= peer->maxms) {
                                                        ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %d\n", peer->name, iaxs[fr->callno]->pingtime);
                                                        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Reachable\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime); 
-                                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "IAX2/%s", peer->name); /* Activate notification */
+                                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
                                                }
                                        } else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
                                                if (iaxs[fr->callno]->pingtime > peer->maxms) {
                                                        ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
                                                        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime); 
-                                                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
+                                                       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
                                                }
                                        }
                                        peer->lastms = iaxs[fr->callno]->pingtime;
@@ -11286,7 +11291,7 @@ static int socket_process(struct iax2_thread *thread)
                                                                                        using_prefs);
 
                                                        ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
-                                                       if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, NULL)))
+                                                       if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, NULL, 1)))
                                                                iax2_destroy(fr->callno);
                                                        else if (ies.vars) {
                                                                struct ast_datastore *variablestore;
@@ -11357,7 +11362,7 @@ immediatedial:
                                                        iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat));
                                                ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                                                send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1);
-                                               if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL)))
+                                               if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL, 1)))
                                                        iax2_destroy(fr->callno);
                                                else if (ies.vars) {
                                                        struct ast_datastore *variablestore;
@@ -12113,7 +12118,7 @@ static void __iax2_poke_noanswer(const void *data)
        if (peer->lastms > -1) {
                ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Time: %d\n", peer->name, peer->lastms);
                manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, peer->lastms);
-               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
+               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
        }
        if ((callno = peer->callno) > 0) {
                ast_mutex_lock(&iaxsl[callno]);
@@ -12279,7 +12284,7 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap
        if (cai.found)
                ast_string_field_set(iaxs[callno], host, pds.peer);
 
-       c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? requestor->linkedid : NULL);
+       c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? requestor->linkedid : NULL, cai.found);
 
        ast_mutex_unlock(&iaxsl[callno]);
 
index 768fafc6a01c0cc31d70935125b9284f2de1e676..4e54ba6ca89555c0fbdc49d7ff3325d4dfd62431 100644 (file)
@@ -150,8 +150,6 @@ struct local_pvt {
        struct ast_jb_conf jb_conf;     /*!< jitterbuffer configuration for this local channel */
        struct ast_channel *owner;      /*!< Master Channel - Bridging happens here */
        struct ast_channel *chan;       /*!< Outbound channel - PBX is run here */
-       struct ast_module_user *u_owner;/*!< reference to keep the module loaded while in use */
-       struct ast_module_user *u_chan; /*!< reference to keep the module loaded while in use */
 };
 
 #define LOCAL_ALREADY_MASQED  (1 << 0) /*!< Already masqueraded */
@@ -577,6 +575,7 @@ static void check_bridge(struct ast_channel *ast, struct local_pvt *p)
        }
        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;
@@ -678,7 +677,7 @@ static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
        ao2_lock(p);
 
        if ((p->owner != oldchan) && (p->chan != oldchan)) {
-               ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
+               ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan);
                ao2_unlock(p);
                return -1;
        }
@@ -1046,16 +1045,15 @@ static int local_hangup(struct ast_channel *ast)
 
        if (isoutbound) {
                const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
-               if ((status) && (p->owner)) {
+
+               if (status && p->owner) {
                        p->owner->hangupcause = p->chan->hangupcause;
                        pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
                }
 
                ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
-               ast_module_user_remove(p->u_chan);
                p->chan = NULL;
        } else {
-               ast_module_user_remove(p->u_owner);
                if (p->chan) {
                        ast_queue_hangup(p->chan);
                }
@@ -1066,6 +1064,7 @@ static int local_hangup(struct ast_channel *ast)
 
        if (!p->owner && !p->chan) {
                ao2_unlock(p);
+
                /* Remove from list */
                ao2_unlink(locals, p);
                ao2_ref(p, -1);
@@ -1085,6 +1084,10 @@ local_hangup_cleanup:
                ao2_unlock(p);
                ao2_ref(p, -1);
        }
+       if (owner) {
+               ast_channel_unlock(owner);
+               owner = ast_channel_unref(owner);
+       }
        if (chan) {
                ast_channel_unlock(chan);
                if (hangup_chan) {
@@ -1092,20 +1095,27 @@ local_hangup_cleanup:
                }
                chan = ast_channel_unref(chan);
        }
-       if (owner) {
-               ast_channel_unlock(owner);
-               owner = ast_channel_unref(owner);
-       }
 
        /* leave with the same stupid channel locked that came in */
        ast_channel_lock(ast);
        return res;
 }
 
-static void local_destroy(void *obj)
+/*!
+ * \internal
+ * \brief struct local_pvt destructor.
+ *
+ * \param vdoomed Void local_pvt to destroy.
+ *
+ * \return Nothing
+ */
+static void local_pvt_destructor(void *vdoomed)
 {
-       struct local_pvt *pvt = obj;
-       pvt->reqcap = ast_format_cap_destroy(pvt->reqcap);
+       struct local_pvt *doomed = vdoomed;
+
+       doomed->reqcap = ast_format_cap_destroy(doomed->reqcap);
+
+       ast_module_unref(ast_module_info->self);
 }
 
 /*! \brief Create a call structure */
@@ -1114,7 +1124,7 @@ static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *ca
        struct local_pvt *tmp = NULL;
        char *c = NULL, *opts = NULL;
 
-       if (!(tmp = ao2_alloc(sizeof(*tmp), local_destroy))) {
+       if (!(tmp = ao2_alloc(sizeof(*tmp), local_pvt_destructor))) {
                return NULL;
        }
        if (!(tmp->reqcap = ast_format_cap_dup(cap))) {
@@ -1122,6 +1132,8 @@ static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *ca
                return NULL;
        }
 
+       ast_module_ref(ast_module_info->self);
+
        /* Initialize private structure information */
        ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
 
@@ -1221,10 +1233,11 @@ static struct ast_channel *local_new(struct local_pvt *p, int state, const char
        tmp->tech_pvt = p;
        tmp2->tech_pvt = p;
 
+       tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
+       tmp2->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
+
        p->owner = tmp;
        p->chan = tmp2;
-       p->u_owner = ast_module_user_add(p->owner);
-       p->u_chan = ast_module_user_add(p->chan);
 
        ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
        ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
@@ -1254,9 +1267,7 @@ static struct ast_channel *local_request(const char *type, struct ast_format_cap
        } else if (ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
                ao2_unlink(locals, p);
                p->owner = ast_channel_release(p->owner);
-               ast_module_user_remove(p->u_owner);
                p->chan = ast_channel_release(p->chan);
-               ast_module_user_remove(p->u_chan);
                chan = NULL;
        }
        ao2_ref(p, -1); /* kill the ref from the alloc */
index 9a101e349e72615d4ce734e84b85e462b3e5d33b..499d592ed9bb254ec0473db5f7b57c06f7770fae 100644 (file)
@@ -2565,19 +2565,20 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
                        int authenticated, time_t start, struct sip_threadinfo *me)
 {
        int res, content_length, after_poll = 1, need_poll = 1;
+       size_t datalen = ast_str_strlen(req->data);
        char buf[1024] = "";
        int timeout = -1;
-
-       /* Read in headers one line at a time */
-       while (ast_str_strlen(req->data) < 4 || strncmp(REQ_OFFSET_TO_STR(req, data->used - 4), "\r\n\r\n", 4)) {
-               if (!tcptls_session->client && !authenticated) {
-                       if ((timeout = sip_check_authtimeout(start)) < 0) {
-                               ast_debug(2, "SIP SSL server failed to determine authentication timeout\n");
+       /* Read in headers one line at a time */
+       while (datalen < 4 || strncmp(REQ_OFFSET_TO_STR(req, data->used - 4), "\r\n\r\n", 4)) {
+               if (!tcptls_session->client && !authenticated) {
+                       if ((timeout = sip_check_authtimeout(start)) < 0) {
+                               ast_debug(2, "SIP TLS server failed to determine authentication timeout\n");
                                return -1;
                        }
 
                        if (timeout == 0) {
-                               ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP");
+                               ast_debug(2, "SIP TLS server timed out\n");
                                return -1;
                        }
                } else {
@@ -2592,11 +2593,11 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
                        after_poll = 1;
                        res = ast_wait_for_input(tcptls_session->fd, timeout);
                        if (res < 0) {
-                               ast_debug(2, "SIP TCP server :: ast_wait_for_input returned %d\n", res);
+                               ast_debug(2, "SIP TLS server :: ast_wait_for_input returned %d\n", res);
                                return -1;
                        } else if (res == 0) {
                                /* timeout */
-                               ast_debug(2, "SIP TCP server timed out\n");
+                               ast_debug(2, "SIP TLS server timed out\n");
                                return -1;
                        }
                }
@@ -2617,6 +2618,13 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
                        return -1;
                }
                ast_str_append(&req->data, 0, "%s", buf);
+
+               datalen = ast_str_strlen(req->data);
+               if (datalen > SIP_MAX_PACKET_SIZE) {
+                       ast_log(LOG_WARNING, "Rejecting TLS packet from '%s' because way too large: %zu\n",
+                               ast_sockaddr_stringify(&tcptls_session->remote_address), datalen);
+                       return -1;
+               }
        }
        copy_request(reqcpy, req);
        parse_request(reqcpy);
@@ -2630,7 +2638,7 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
                                }
 
                                if (timeout == 0) {
-                                       ast_debug(2, "SIP SSL server timed out\n");
+                                       ast_debug(2, "SIP TLS server timed out\n");
                                        return -1;
                                }
                        } else {
@@ -2642,11 +2650,11 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
                                after_poll = 1;
                                res = ast_wait_for_input(tcptls_session->fd, timeout);
                                if (res < 0) {
-                                       ast_debug(2, "SIP TCP server :: ast_wait_for_input returned %d\n", res);
+                                       ast_debug(2, "SIP TLS server :: ast_wait_for_input returned %d\n", res);
                                        return -1;
                                } else if (res == 0) {
                                        /* timeout */
-                                       ast_debug(2, "SIP TCP server timed out\n");
+                                       ast_debug(2, "SIP TLS server timed out\n");
                                        return -1;
                                }
                        }
@@ -2669,6 +2677,13 @@ static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, str
                        }
                        content_length -= strlen(buf);
                        ast_str_append(&req->data, 0, "%s", buf);
+               
+                       datalen = ast_str_strlen(req->data);
+                       if (datalen > SIP_MAX_PACKET_SIZE) {
+                               ast_log(LOG_WARNING, "Rejecting TLS packet from '%s' because way too large: %zu\n",
+                                       ast_sockaddr_stringify(&tcptls_session->remote_address), datalen);
+                               return -1;
+                       }
                }
        }
        /*! \todo XXX If there's no Content-Length or if the content-length and what
@@ -2842,6 +2857,8 @@ static int sip_tcp_read(struct sip_request *req, struct ast_tcptls_session_insta
        enum message_integrity message_integrity = MESSAGE_FRAGMENT;
 
        while (message_integrity == MESSAGE_FRAGMENT) {
+               size_t datalen;
+
                if (ast_str_strlen(tcptls_session->overflow_buf) == 0) {
                        char readbuf[4097];
                        int timeout;
@@ -2881,6 +2898,13 @@ static int sip_tcp_read(struct sip_request *req, struct ast_tcptls_session_insta
                        ast_str_append(&req->data, 0, "%s", ast_str_buffer(tcptls_session->overflow_buf));
                        ast_str_reset(tcptls_session->overflow_buf);
                }
+               
+               datalen = ast_str_strlen(req->data);
+               if (datalen > SIP_MAX_PACKET_SIZE) {
+                       ast_log(LOG_WARNING, "Rejecting TCP packet from '%s' because way too large: %zu\n",
+                               ast_sockaddr_stringify(&tcptls_session->remote_address), datalen);
+                       return -1;
+               }
 
                message_integrity = check_message_integrity(&req->data, &tcptls_session->overflow_buf);
        }
@@ -2952,7 +2976,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
        }
 
        me->threadid = pthread_self();
-       ast_debug(2, "Starting thread for %s server\n", tcptls_session->ssl ? "SSL" : "TCP");
+       ast_debug(2, "Starting thread for %s server\n", tcptls_session->ssl ? "TLS" : "TCP");
 
        /* set up pollfd to watch for reads on both the socket and the alert_pipe */
        fds[0].fd = tcptls_session->fd;
@@ -2986,7 +3010,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
                        }
 
                        if (timeout == 0) {
-                               ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP");
+                               ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "TLS": "TCP");
                                goto cleanup;
                        }
                } else {
@@ -2996,11 +3020,11 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
                if (ast_str_strlen(tcptls_session->overflow_buf) == 0) {
                        res = ast_poll(fds, 2, timeout); /* polls for both socket and alert_pipe */
                        if (res < 0) {
-                               ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "SSL": "TCP", res);
+                               ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "TLS": "TCP", res);
                                goto cleanup;
                        } else if (res == 0) {
                                /* timeout */
-                               ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP");
+                               ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "TLS": "TCP");
                                goto cleanup;
                        }
                }
@@ -3082,7 +3106,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
                }
        }
 
-       ast_debug(2, "Shutting down thread for %s server\n", tcptls_session->ssl ? "SSL" : "TCP");
+       ast_debug(2, "Shutting down thread for %s server\n", tcptls_session->ssl ? "TLS" : "TCP");
 
 cleanup:
        if (tcptls_session && !tcptls_session->client && !authenticated) {
@@ -6462,7 +6486,7 @@ static int update_call_counter(struct sip_pvt *fup, int event)
        }
 
        if (p) {
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", p->name);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", p->name);
                sip_unref_peer(p, "update_call_counter: sip_unref_peer from call counter");
        }
        return 0;
@@ -7714,6 +7738,9 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
                ast_jb_configure(tmp, &global_jbconf);
        }
 
+       if (!i->relatedpeer) {
+               tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
+       }
        /* Set channel variables for this call from configuration */
        for (v = i->chanvars ; v ; v = v->next) {
                char valuebuf[1024];
@@ -9850,6 +9877,15 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                  type, value,
                                  (processed == TRUE)? "OK." : "UNSUPPORTED OR FAILED.");
                }
+
+               /* Ensure crypto lines are provided where necessary */
+               if (audio && secure_audio && !processed_crypto) {
+                       ast_log(LOG_WARNING, "Rejecting secure audio stream without encryption details: %s\n", m);
+                       return -1;
+               } else if (video && secure_video && !processed_crypto) {
+                       ast_log(LOG_WARNING, "Rejecting secure video stream without encryption details: %s\n", m);
+                       return -1;
+               }
        }
 
        /* Sanity checks */
@@ -13137,7 +13173,9 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init,
        }
 
        /* Add Session-Timers related headers */
-       if (st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE) {
+       if (st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE
+               || (st_get_mode(p, 0) == SESSION_TIMER_MODE_ACCEPT
+                       && st_get_se(p, FALSE) != DEFAULT_MIN_SE)) {
                char i2astr[10];
 
                if (!p->stimer->st_interval) {
@@ -13145,9 +13183,11 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init,
                }
 
                p->stimer->st_active = TRUE;
-               
-               snprintf(i2astr, sizeof(i2astr), "%d", p->stimer->st_interval);
-               add_header(&req, "Session-Expires", i2astr);
+               if (st_get_mode(p, 0) == SESSION_TIMER_MODE_ORIGINATE) {        
+                       snprintf(i2astr, sizeof(i2astr), "%d", p->stimer->st_interval);
+                       add_header(&req, "Session-Expires", i2astr);
+               }
+
                snprintf(i2astr, sizeof(i2astr), "%d", st_get_se(p, FALSE));
                add_header(&req, "Min-SE", i2astr);
        }
@@ -14708,7 +14748,7 @@ static int expire_register(const void *data)
 
        manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
        register_peer_exten(peer, FALSE);       /* Remove regexten */
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
 
        /* Do we need to release this peer from memory?
                Only for realtime peers and autocreated peers
@@ -15492,8 +15532,9 @@ static void sip_peer_hold(struct sip_pvt *p, int hold)
        ast_atomic_fetchadd_int(&p->relatedpeer->onHold, (hold ? +1 : -1));
 
        /* Request device state update */
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", p->relatedpeer->name);
-       
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, (p->owner->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE),
+                            "SIP/%s", p->relatedpeer->name);
+
        return;
 }
 
@@ -15938,7 +15979,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
                } else {
                        update_peer_lastmsgssent(peer, -1, 0);
                }
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
        }
        if (res < 0) {
                switch (res) {
@@ -22149,7 +22190,7 @@ static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_req
 
                ast_log(LOG_NOTICE, "Peer '%s' is now %s. (%dms / %dms)\n",
                        peer->name, s, pingtime, peer->maxms);
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
                if (sip_cfg.peer_rtupdate) {
                        ast_update_realtime(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", "name", peer->name, "lastms", str_lastms, SENTINEL);
                }
@@ -27790,7 +27831,10 @@ static void proc_422_rsp(struct sip_pvt *p, struct sip_request *rsp)
                ast_log(LOG_WARNING, "Parsing of Min-SE header failed %s\n", p_hdrval);
                return;
        }
-       p->stimer->st_interval = minse;
+       p->stimer->st_cached_min_se = minse;
+       if (p->stimer->st_interval < minse) {
+               p->stimer->st_interval = minse;
+       }
        transmit_invite(p, SIP_INVITE, 1, 2, NULL);
 }
 
@@ -27902,7 +27946,7 @@ static int sip_poke_noanswer(const void *data)
        /* Don't send a devstate change if nothing changed. */
        if (peer->lastms > -1) {
                peer->lastms = -1;
-               ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
+               ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name);
        }
 
        /* Try again quickly */
@@ -29291,8 +29335,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                                        ast_log(LOG_WARNING, "Invalid session-minse '%s' at line %d of %s\n", v->value, v->lineno, config);
                                        peer->stimer.st_min_se = global_min_se;
                                }
-                               if (peer->stimer.st_min_se < 90) {
-                                       ast_log(LOG_WARNING, "session-minse '%s' at line %d of %s is not allowed to be < 90 secs\n", v->value, v->lineno, config);
+                               if (peer->stimer.st_min_se < DEFAULT_MIN_SE) {
+                                       ast_log(LOG_WARNING, "session-minse '%s' at line %d of %s is not allowed to be < %d secs\n", v->value, v->lineno, config, DEFAULT_MIN_SE);
                                        peer->stimer.st_min_se = global_min_se;
                                }
                        } else if (!strcasecmp(v->name, "session-refresher")) {
@@ -30300,8 +30344,8 @@ static int reload_config(enum channelreloadreason reason)
                                ast_log(LOG_WARNING, "Invalid session-minse '%s' at line %d of %s\n", v->value, v->lineno, config);
                                global_min_se = DEFAULT_MIN_SE;
                        }
-                       if (global_min_se < 90) {
-                               ast_log(LOG_WARNING, "session-minse '%s' at line %d of %s is not allowed to be < 90 secs\n", v->value, v->lineno, config);
+                       if (global_min_se < DEFAULT_MIN_SE) {
+                               ast_log(LOG_WARNING, "session-minse '%s' at line %d of %s is not allowed to be < %d secs\n", v->value, v->lineno, config, DEFAULT_MIN_SE);
                                global_min_se = DEFAULT_MIN_SE;
                        }
                } else if (!strcasecmp(v->name, "session-refresher")) {
index e3e3830e800b79feb6e16c91c4adec2e1b254e89..6605fb836b3689781432de18585a70ec262dbc5b 100644 (file)
@@ -2109,7 +2109,7 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s)
                                        AST_LIST_TRAVERSE(&l->sublines, subline, list) {
                                                ast_extension_state_add(subline->context, subline->exten, skinny_extensionstate_cb, subline->container);
                                        }
-                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s", l->name);
+                                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
                                }
                                --instance;
                        }
@@ -2147,7 +2147,7 @@ static int skinny_unregister(struct skinny_req *req, struct skinnysession *s)
                                l->instance = 0;
                                manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Unregistered\r\n", l->name, d->name);
                                unregister_exten(l);
-                               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Skinny/%s", l->name);
+                               ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
                        }
                }
        }
@@ -5909,7 +5909,7 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession
                        ast_verb(1, "RECEIVED UNKNOWN STIMULUS:  %d(%d/%d)\n", event, instance, callreference);
                break;
        }
-       ast_devstate_changed(AST_DEVICE_UNKNOWN, "Skinny/%s", l->name);
+       ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
 
        return 1;
 }
@@ -5951,7 +5951,7 @@ static int handle_offhook_message(struct skinny_req *req, struct skinnysession *
        transmit_ringer_mode(d, SKINNY_RING_OFF);
        d->hookstate = SKINNY_OFFHOOK;
 
-       ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s", l->name);
+       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
 
        if (sub && sub->substate == SUBSTATE_HOLD) {
                return 1;
@@ -6018,7 +6018,7 @@ static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s
                return 0;
        }
        
-       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s", l->name);
+       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
        
        dumpsub(sub, 0);
 
@@ -6348,7 +6348,7 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                return 0;
        }
 
-       ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s", l->name);
+       ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
 
        switch(event) {
        case SOFTKEY_NONE:
@@ -6509,8 +6509,8 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse
                        return 0;
                }
        
-               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s", l->name);
-       
+               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s", l->name);
+
                if (sub) {
                        dumpsub(sub, 1);
                } else { /* No sub, maybe an SLA call */
index b18435a36d9b244deced13682bfe3564a744eb9d..16fa09906374beffd98d66c2169c5945a0226855 100644 (file)
@@ -97,6 +97,7 @@
 
 #define SIP_MAX_HEADERS           64     /*!< Max amount of SIP headers to read */
 #define SIP_MAX_LINES             256    /*!< Max amount of lines in SIP attachment (like SDP) */
+#define SIP_MAX_PACKET_SIZE       20480  /*!< Max SIP packet size */
 #define SIP_MIN_PACKET            4096   /*!< Initialize size of memory to allocate for packets */
 #define MAX_HISTORY_ENTRIES              50     /*!< Max entires in the history list for a sip_pvt */
 
index e1f34387a116f8d87d2217a5d67edc271a3175dc..6472610c8a70a0b2bfdd5451af2ada658f052d9e 100644 (file)
@@ -132,7 +132,7 @@ static int devstate_write(struct ast_channel *chan, const char *cmd, char *data,
 
        ast_db_put(astdb_family, data, value);
 
-       ast_devstate_changed(state_val, "Custom:%s", data);
+       ast_devstate_changed(state_val, AST_DEVSTATE_CACHABLE, "Custom:%s", data);
 
        return 0;
 }
@@ -295,7 +295,7 @@ static char *handle_cli_devstate_change(struct ast_cli_entry *e, int cmd, struct
 
        ast_db_put(astdb_family, dev, state);
 
-       ast_devstate_changed(state_val, "Custom:%s", dev);
+       ast_devstate_changed(state_val, AST_DEVSTATE_CACHABLE, "Custom:%s", dev);
 
        return CLI_SUCCESS;
 }
@@ -341,7 +341,7 @@ static int load_module(void)
                if (dev_name <= (const char *) 1)
                        continue;
                ast_devstate_changed(ast_devstate_val(db_entry->data),
-                       "Custom:%s\n", dev_name);
+                       AST_DEVSTATE_CACHABLE, "Custom:%s\n", dev_name);
        }
        ast_db_freetree(db_tree);
        db_tree = NULL;
index 3c117b7cd2d12744b0eb42ad5df6c500accafb44..4a11853fca1932c741691a305ee1b33dba658664 100644 (file)
@@ -267,6 +267,32 @@ struct ast_bridge {
  */
 struct ast_bridge *ast_bridge_new(uint32_t capabilities, int flags);
 
+/*!
+ * \brief Lock the bridge.
+ *
+ * \param bridge Bridge to lock
+ *
+ * \return Nothing
+ */
+#define ast_bridge_lock(bridge)        _ast_bridge_lock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge)
+static inline void _ast_bridge_lock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var)
+{
+       __ao2_lock(bridge, file, function, line, var);
+}
+
+/*!
+ * \brief Unlock the bridge.
+ *
+ * \param bridge Bridge to unlock
+ *
+ * \return Nothing
+ */
+#define ast_bridge_unlock(bridge)      _ast_bridge_unlock(bridge, __FILE__, __PRETTY_FUNCTION__, __LINE__, #bridge)
+static inline void _ast_bridge_unlock(struct ast_bridge *bridge, const char *file, const char *function, int line, const char *var)
+{
+       __ao2_unlock(bridge, file, function, line, var);
+}
+
 /*! \brief See if it is possible to create a bridge
  *
  * \param capabilities The capabilities that the bridge will use
index 2820fc09b6b0d744bb31820cea0f6bc7d789354e..4ea50e79588fe00fa574cf4fa2177bdde6b291d8 100644 (file)
@@ -942,6 +942,12 @@ enum {
         *  some non-traditional dialplans (like AGI) to continue to function.
         */
        AST_FLAG_DISABLE_WORKAROUNDS = (1 << 20),
+       /*! Disable device state event caching.  This allows allows channel
+        * drivers to selectively prevent device state events from being cached
+        * by certain channels such as anonymous calls which have no persistent
+        * represenatation that can be tracked.
+        */
+       AST_FLAG_DISABLE_DEVSTATE_CACHE = (1 << 21),
 };
 
 /*! \brief ast_bridge_config flags */
index 66ca2bd1a3ecddb1fd4d0ac44741cc1aa26e43dd..86740bc2fd69b735906d1e9d71adcd4798924d66 100644 (file)
@@ -61,6 +61,14 @@ enum ast_device_state {
        AST_DEVICE_TOTAL,        /*/ Total num of device states, used for testing */
 };
 
+/*! \brief Device State Cachability
+ *  \note This is used to define the cachability of a device state when set.
+ */
+enum ast_devstate_cache {
+       AST_DEVSTATE_NOT_CACHABLE,  /*!< This device state is not cachable */
+       AST_DEVSTATE_CACHABLE,      /*!< This device state is cachable */
+};
+
 /*! \brief Devicestate provider call back */
 typedef enum ast_device_state (*ast_devstate_prov_cb_type)(const char *data);
 
@@ -129,6 +137,7 @@ enum ast_device_state ast_device_state(const char *device);
  * \brief Tells Asterisk the State for Device is changed
  *
  * \param state the new state of the device
+ * \param cachable whether this device state is cachable
  * \param fmt device name like a dial string with format parameters
  *
  * The new state of the device will be sent off to any subscribers
@@ -138,13 +147,14 @@ enum ast_device_state ast_device_state(const char *device);
  * \retval 0 on success
  * \retval -1 on failure
  */
-int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
-       __attribute__((format(printf, 2, 3)));
+int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt, ...)
+       __attribute__((format(printf, 3, 4)));
 
 /*!
  * \brief Tells Asterisk the State for Device is changed
  *
  * \param state the new state of the device
+ * \param cachable whether this device state is cachable
  * \param device device name like a dial string with format parameters
  *
  * The new state of the device will be sent off to any subscribers
@@ -154,7 +164,7 @@ int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
  * \retval 0 on success
  * \retval -1 on failure
  */
-int ast_devstate_changed_literal(enum ast_device_state state, const char *device);
+int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device);
 
 /*!
  * \brief Tells Asterisk the State for Device is changed.
index 88b41699b2aca51157c903a76e0c15fcbc892d3b..fc84173c749afb9c49784919568f68ed094bfa75 100644 (file)
@@ -294,8 +294,14 @@ enum ast_event_ie_type {
        AST_EVENT_IE_PRESENCE_SUBTYPE    = 0x003b,
        AST_EVENT_IE_PRESENCE_MESSAGE    = 0x003c,
 
+       /*!
+        * \brief Event non-cachability flag
+        * Used by: All events
+        * Payload type: UINT
+        */
+       AST_EVENT_IE_CACHABLE            = 0x0039,
        /*! \brief Must be the last IE value +1 */
-       AST_EVENT_IE_TOTAL               = 0x0039,
+       AST_EVENT_IE_TOTAL               = 0x003a,
 };
 
 /*!
index 817bb9225fbf756a586119240bd743f452cc9b7d..dcc00725b43cb0ecc69a83e405976afaa10cd551 100644 (file)
@@ -1605,7 +1605,12 @@ static struct ast_cli_entry aoc_cli[] = {
        AST_CLI_DEFINE(aoc_cli_debug_enable, "enable cli debugging of AOC messages"),
 };
 
+static void aoc_shutdown(void)
+{
+       ast_cli_unregister_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
+}
 int ast_aoc_cli_init(void)
 {
+       ast_register_atexit(aoc_shutdown);
        return ast_cli_register_multiple(aoc_cli, ARRAY_LEN(aoc_cli));
 }
index b7e8fcc1fa97eae8281128d38ff48ac66a2e4d73..c757c1f8268ba2ca19d3ff488b29f43bde05cc8d 100644 (file)
@@ -637,7 +637,7 @@ static void ccss_notify_device_state_change(const char *device, enum cc_state st
                "Notification of CCSS state change to '%s', device state '%s' for device '%s'\n",
                cc_state_to_string(state), ast_devstate2str(devstate), device);
 
-       ast_devstate_changed(devstate, "ccss:%s", device);
+       ast_devstate_changed(devstate, AST_DEVSTATE_CACHABLE, "ccss:%s", device);
 }
 
 #define CC_OFFER_TIMER_DEFAULT                 20              /* Seconds */
index 117c5de4a3f5041c04fc6cf7154b40b7735449a3..02b37dc11d743c9c23933d1dd2a8a5dc40cde2a4 100644 (file)
@@ -715,6 +715,7 @@ static void ast_cel_engine_term(void)
                ao2_ref(linkedids, -1);
                linkedids = NULL;
        }
+       ast_cli_unregister(&cli_status);
 }
 
 int ast_cel_engine_init(void)
index 8f71b05ed7ecc4ede3a32ad481b2e29281c5781f..009931c0e302ad72721a767973f5194595266523 100644 (file)
@@ -72,6 +72,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/global_datastores.h"
 #include "asterisk/data.h"
 #include "asterisk/features.h"
+#include "asterisk/test.h"
 
 #ifdef HAVE_EPOLL
 #include <sys/epoll.h>
@@ -296,6 +297,7 @@ static void channel_data_add_flags(struct ast_data *tree,
        ast_data_add_bool(tree, "BRIDGE_HANGUP_RUN", ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN));
        ast_data_add_bool(tree, "BRIDGE_HANGUP_DONT", ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT));
        ast_data_add_bool(tree, "DISABLE_WORKAROUNDS", ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS));
+       ast_data_add_bool(tree, "DISABLE_DEVSTATE_CACHE", ast_test_flag(chan, AST_FLAG_DISABLE_DEVSTATE_CACHE));
 }
 
 #if defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED)
@@ -2542,7 +2544,7 @@ static void ast_channel_destructor(void *obj)
                 * instance is dead, we don't know the state of all other possible
                 * instances.
                 */
-               ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name);
+               ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (chan->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), device_name);
        }
 
        chan->nativeformats = ast_format_cap_destroy(chan->nativeformats);
@@ -3263,6 +3265,7 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
                                now = ast_tvnow();
                        diff = ast_tvsub(c[x]->whentohangup, now);
                        if (diff.tv_sec < 0 || ast_tvzero(diff)) {
+                               ast_test_suite_event_notify("HANGUP_TIME", "Channel: %s", c[x]->name);
                                /* Should already be hungup */
                                c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
                                ast_channel_unlock(c[x]);
@@ -3331,6 +3334,7 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
                now = ast_tvnow();
                for (x = 0; x < n; x++) {
                        if (!ast_tvzero(c[x]->whentohangup) && ast_tvcmp(c[x]->whentohangup, now) <= 0) {
+                               ast_test_suite_event_notify("HANGUP_TIME", "Channel: %s", c[x]->name);
                                c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
                                if (winner == NULL)
                                        winner = c[x];
@@ -7271,7 +7275,7 @@ int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
        /* We have to pass AST_DEVICE_UNKNOWN here because it is entirely possible that the channel driver
         * for this channel is using the callback method for device state. If we pass in an actual state here
         * we override what they are saying the state is and things go amuck. */
-       ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, name);
+       ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (chan->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), name);
 
        /* setstate used to conditionally report Newchannel; this is no more */
        ast_manager_event(chan, EVENT_FLAG_CALL, "Newstate",
@@ -7767,6 +7771,7 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                        bridge_playfile(c1, c0, config->end_sound, 0);
                                *fo = NULL;
                                res = 0;
+                               ast_test_suite_event_notify("BRIDGE_TIMELIMIT", "Channel1: %s\r\nChannel2: %s", c0->name, c1->name);
                                break;
                        }
 
@@ -8331,6 +8336,7 @@ static const struct ast_data_entry channel_providers[] = {
 static void channels_shutdown(void)
 {
        ast_data_unregister(NULL);
+       ast_cli_unregister_multiple(cli_channel, ARRAY_LEN(cli_channel));
        if (channels) {
                ao2_ref(channels, -1);
                channels = NULL;
index 9205d8a9292a291d48276b7f1c46558d4fa5877c..3d77b573c0c78b98517032e60f76396ef359fe46 100644 (file)
@@ -3318,7 +3318,9 @@ AST_TEST_DEFINE(test_data_get)
 static void data_shutdown(void)
 {
        ast_manager_unregister("DataGet");
+       ast_cli_unregister_multiple(cli_data, ARRAY_LEN(cli_data));
        ao2_t_ref(root_data.container, -1, "Unref root_data.container in data_shutdown");
+       root_data.container = NULL;
        ast_rwlock_destroy(&root_data.lock);
 }
 
index 84eedc81c5d0b7f830a46ab09ac255b69b4222f2..aabf806e749b67c34c83e5e2b79ea5e23b1868b3 100644 (file)
@@ -174,6 +174,7 @@ static AST_RWLIST_HEAD_STATIC(devstate_provs, devstate_prov);
 
 struct state_change {
        AST_LIST_ENTRY(state_change) list;
+       enum ast_devstate_cache cachable;
        char device[1];
 };
 
@@ -191,6 +192,7 @@ struct devstate_change {
        AST_LIST_ENTRY(devstate_change) entry;
        uint32_t state;
        struct ast_eid eid;
+       enum ast_devstate_cache cachable;
        char device[1];
 };
 
@@ -424,7 +426,7 @@ static int getproviderstate(const char *provider, const char *address)
        return res;
 }
 
-static void devstate_event(const char *device, enum ast_device_state state)
+static void devstate_event(const char *device, enum ast_device_state state, int cachable)
 {
        struct ast_event *event;
        enum ast_event_type event_type;
@@ -440,18 +442,23 @@ static void devstate_event(const char *device, enum ast_device_state state)
        ast_debug(3, "device '%s' state '%d'\n", device, state);
 
        if (!(event = ast_event_new(event_type,
-                       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
-                       AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
-                       AST_EVENT_IE_END))) {
+                                   AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+                                   AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
+                                   AST_EVENT_IE_CACHABLE, AST_EVENT_IE_PLTYPE_UINT, cachable,
+                                   AST_EVENT_IE_END))) {
                return;
        }
 
-       ast_event_queue_and_cache(event);
+       if (cachable) {
+               ast_event_queue_and_cache(event);
+       } else {
+               ast_event_queue(event);
+       }
 }
 
 /*! Called by the state change thread to find out what the state is, and then
  *  to queue up the state change event */
-static void do_state_change(const char *device)
+static void do_state_change(const char *device, int cachable)
 {
        enum ast_device_state state;
 
@@ -459,10 +466,10 @@ static void do_state_change(const char *device)
 
        ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, ast_devstate2str(state));
 
-       devstate_event(device, state);
+       devstate_event(device, state, cachable);
 }
 
-int ast_devstate_changed_literal(enum ast_device_state state, const char *device)
+int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device)
 {
        struct state_change *change;
 
@@ -483,14 +490,15 @@ int ast_devstate_changed_literal(enum ast_device_state state, const char *device
         */
 
        if (state != AST_DEVICE_UNKNOWN) {
-               devstate_event(device, state);
+               devstate_event(device, state, cachable);
        } else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
                /* we could not allocate a change struct, or */
                /* there is no background thread, so process the change now */
-               do_state_change(device);
+               do_state_change(device, cachable);
        } else {
                /* queue the change */
                strcpy(change->device, device);
+               change->cachable = cachable;
                AST_LIST_LOCK(&state_changes);
                AST_LIST_INSERT_TAIL(&state_changes, change, list);
                ast_cond_signal(&change_pending);
@@ -502,10 +510,10 @@ int ast_devstate_changed_literal(enum ast_device_state state, const char *device
 
 int ast_device_state_changed_literal(const char *dev)
 {
-       return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, dev);
+       return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, dev);
 }
 
-int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...) 
+int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt, ...)
 {
        char buf[AST_MAX_EXTENSION];
        va_list ap;
@@ -514,7 +522,7 @@ int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
        vsnprintf(buf, sizeof(buf), fmt, ap);
        va_end(ap);
 
-       return ast_devstate_changed_literal(state, buf);
+       return ast_devstate_changed_literal(state, cachable, buf);
 }
 
 int ast_device_state_changed(const char *fmt, ...) 
@@ -526,7 +534,7 @@ int ast_device_state_changed(const char *fmt, ...)
        vsnprintf(buf, sizeof(buf), fmt, ap);
        va_end(ap);
 
-       return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf);
+       return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, buf);
 }
 
 /*! \brief Go through the dev state change queue and update changes in the dev state thread */
@@ -546,7 +554,7 @@ static void *do_devstate_changes(void *data)
                /* Process each state change */
                while ((current = next)) {
                        next = AST_LIST_NEXT(current, list);
-                       do_state_change(current->device);
+                       do_state_change(current->device, current->cachable);
                        ast_free(current);
                }
        }
@@ -590,7 +598,7 @@ static void devstate_cache_cb(const struct ast_event *event, void *data)
        collection->num_states++;
 }
 
-static void process_collection(const char *device, struct change_collection *collection)
+static void process_collection(const char *device, enum ast_devstate_cache cachable, struct change_collection *collection)
 {
        int i;
        struct ast_devstate_aggregate agg;
@@ -641,7 +649,11 @@ static void process_collection(const char *device, struct change_collection *col
                return;
        }
 
-       ast_event_queue_and_cache(event);
+       if (cachable) {
+               ast_event_queue_and_cache(event);
+       } else {
+               ast_event_queue(event);
+       }
 }
 
 static void handle_devstate_change(struct devstate_change *sc)
@@ -667,7 +679,7 @@ static void handle_devstate_change(struct devstate_change *sc)
        /* Populate the collection of device states from the cache */
        ast_event_dump_cache(tmp_sub);
 
-       process_collection(sc->device, &collection);
+       process_collection(sc->device, sc->cachable, &collection);
 
        ast_event_sub_destroy(tmp_sub);
 }
@@ -696,10 +708,12 @@ static void devstate_change_collector_cb(const struct ast_event *event, void *da
        const char *device;
        const struct ast_eid *eid;
        uint32_t state;
+       enum ast_devstate_cache cachable = AST_DEVSTATE_CACHABLE;
 
        device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
        eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
        state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+       cachable = ast_event_get_ie_uint(event, AST_EVENT_IE_CACHABLE);
 
        if (ast_strlen_zero(device) || !eid) {
                ast_log(LOG_ERROR, "Invalid device state change event received\n");
@@ -712,6 +726,7 @@ static void devstate_change_collector_cb(const struct ast_event *event, void *da
        strcpy(sc->device, device);
        sc->eid = *eid;
        sc->state = state;
+       sc->cachable = cachable;
 
        ast_mutex_lock(&devstate_collector.lock);
        AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry);
index 60535bbae6b8f939b5b59ffb2122aa5c27a2885b..7f80141a4a392bd4fd82b149d00a8e1968f1e35c 100644 (file)
@@ -278,7 +278,7 @@ static const struct ie_map {
        [AST_EVENT_IE_RECEIVED_HASH]       = { AST_EVENT_IE_PLTYPE_STR,  "ReceivedHash" },
        [AST_EVENT_IE_USING_PASSWORD]      = { AST_EVENT_IE_PLTYPE_UINT, "UsingPassword" },
        [AST_EVENT_IE_ATTEMPTED_TRANSPORT] = { AST_EVENT_IE_PLTYPE_STR,  "AttemptedTransport" },
-
+       [AST_EVENT_IE_CACHABLE]            = { AST_EVENT_IE_PLTYPE_UINT,  "Cachable" },
 };
 
 const char *ast_event_get_type_name(const struct ast_event *event)
index 5520135de30eb6cafcde8581cb201826a908e1c9..b6ddab4fae2b16d622c0d69daf9ae59be60457db 100644 (file)
@@ -1106,7 +1106,7 @@ static void notify_metermaids(const char *exten, char *context, enum ast_device_
        ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'",
                exten, context, ast_devstate2str(state));
 
-       ast_devstate_changed(state, "park:%s@%s", exten, context);
+       ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "park:%s@%s", exten, context);
 }
 
 /*! \brief metermaids callback from devicestate.c */
index 31f9239b343fa4a54a2be17c0c58e8a1cd672131..f3fab29f0b8526f32928d101c72d271568511223 100644 (file)
@@ -1584,8 +1584,14 @@ static struct ast_cli_entry cli_file[] = {
        AST_CLI_DEFINE(handle_cli_core_show_file_formats, "Displays file formats")
 };
 
+static void file_shutdown(void)
+{
+       ast_cli_unregister_multiple(cli_file, ARRAY_LEN(cli_file));
+}
+
 int ast_file_init(void)
 {
        ast_cli_register_multiple(cli_file, ARRAY_LEN(cli_file));
+       ast_register_atexit(file_shutdown);
        return 0;
 }
index 55ade21d790e7caec5f38746b1e66b219d279463..6f6bde80e4abb98620851c68513e9cf17f3a83ee 100644 (file)
@@ -603,6 +603,7 @@ struct ast_variable *ast_http_get_post_vars(
        int content_length = 0;
        struct ast_variable *v, *post_vars=NULL, *prev = NULL;
        char *buf, *var, *val;
+       int res;
 
        for (v = headers; v; v = v->next) {
                if (!strcasecmp(v->name, "Content-Type")) {
@@ -615,20 +616,28 @@ struct ast_variable *ast_http_get_post_vars(
 
        for (v = headers; v; v = v->next) {
                if (!strcasecmp(v->name, "Content-Length")) {
-                       content_length = atoi(v->value) + 1;
+                       content_length = atoi(v->value);
                        break;
                }
        }
 
-       if (!content_length) {
+       if (content_length <= 0) {
                return NULL;
        }
 
-       buf = ast_alloca(content_length);
-       if (!fgets(buf, content_length, ser->f)) {
+       buf = ast_malloc(content_length + 1);
+       if (!buf) {
                return NULL;
        }
 
+       res = fread(buf, 1, content_length, ser->f);
+       if (res < content_length) {
+               /* Error, distinguishable by ferror() or feof(), but neither
+                * is good. */
+               goto done;
+       }
+       buf[content_length] = '\0';
+
        while ((val = strsep(&buf, "&"))) {
                var = strsep(&val, "=");
                if (val) {
@@ -646,6 +655,9 @@ struct ast_variable *ast_http_get_post_vars(
                        prev = v;
                }
        }
+       
+done:
+       ast_free(buf);
        return post_vars;
 }
 
@@ -1195,11 +1207,17 @@ static struct ast_cli_entry cli_http[] = {
        AST_CLI_DEFINE(handle_show_http, "Display HTTP server status"),
 };
 
+static void http_shutdown(void)
+{
+       ast_cli_unregister_multiple(cli_http, ARRAY_LEN(cli_http));
+}
+
 int ast_http_init(void)
 {
        ast_http_uri_link(&statusuri);
        ast_http_uri_link(&staticuri);
        ast_cli_register_multiple(cli_http, ARRAY_LEN(cli_http));
+       ast_register_atexit(http_shutdown);
 
        return __ast_http_load(0);
 }
index e9b4758d9c92fd28a9e846535670900f708d6dc7..24316e21f813243ac5053e217b4aca8bfb81c77b 100644 (file)
@@ -206,8 +206,14 @@ static struct ast_cli_entry cli_image[] = {
        AST_CLI_DEFINE(handle_core_show_image_formats, "Displays image formats")
 };
 
+static void image_shutdown(void)
+{
+       ast_cli_unregister_multiple(cli_image, ARRAY_LEN(cli_image));
+}
+
 int ast_image_init(void)
 {
        ast_cli_register_multiple(cli_image, ARRAY_LEN(cli_image));
+       ast_register_atexit(image_shutdown);
        return 0;
 }
index 9cbfaf72425d5e53bebbeee21901d614077a0b20..f4b68c2ef93f6ef949d53db6d62ae34883d83160 100644 (file)
@@ -233,9 +233,18 @@ void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
        if (!u) {
                return;
        }
+
        AST_LIST_LOCK(&mod->users);
-       AST_LIST_REMOVE(&mod->users, u, entry);
+       u = AST_LIST_REMOVE(&mod->users, u, entry);
        AST_LIST_UNLOCK(&mod->users);
+       if (!u) {
+               /*
+                * Was not in the list.  Either a bad pointer or
+                * __ast_module_user_hangup_all() has been called.
+                */
+               return;
+       }
+
        ast_atomic_fetchadd_int(&mod->usecount, -1);
        ast_free(u);
 
@@ -554,15 +563,26 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f
        }
 
        if (!error) {
+               /* Request any channels attached to the module to hangup. */
                __ast_module_user_hangup_all(mod);
-               res = mod->info->unload();
 
+               res = mod->info->unload();
                if (res) {
                        ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
-                       if (force <= AST_FORCE_FIRM)
+                       if (force <= AST_FORCE_FIRM) {
                                error = 1;
-                       else
+                       } else {
                                ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
+                       }
+               }
+
+               if (!error) {
+                       /*
+                        * Request hangup on any channels that managed to get attached
+                        * while we called the module unload function.
+                        */
+                       __ast_module_user_hangup_all(mod);
+                       sched_yield();
                }
        }
 
index ca3183839af067077af478fb73b802f6e00507e1..7203f270c666ee4c2d8edf2d45516c829675a921 100644 (file)
@@ -499,8 +499,14 @@ static struct ast_cli_entry cli_stun[] = {
        AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging"),
 };
 
+static void stun_shutdown(void)
+{
+       ast_cli_unregister_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
+}
+
 /*! \brief Initialize the STUN system in Asterisk */
 void ast_stun_init(void)
 {
        ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
+       ast_register_atexit(stun_shutdown);
 }
index a5e106b2802f0aa9a59ef92fce7ac27ca38ce039..c637ba24fdc6f3fd8c3d483900f2da721a619757 100644 (file)
@@ -122,6 +122,17 @@ static struct ast_cli_entry taskprocessor_clis[] = {
        AST_CLI_DEFINE(cli_tps_report, "List instantiated task processors and statistics"),
 };
 
+/*!
+ * \internal
+ * \brief Clean up resources on Asterisk shutdown
+ */
+static void tps_shutdown(void)
+{
+       ast_cli_unregister_multiple(taskprocessor_clis, ARRAY_LEN(taskprocessor_clis));
+       ao2_t_ref(tps_singletons, -1, "Unref tps_singletons in shutdown");
+       tps_singletons = NULL;
+}
+
 /* initialize the taskprocessor container and register CLI operations */
 int ast_tps_init(void)
 {
@@ -133,6 +144,9 @@ int ast_tps_init(void)
        ast_cond_init(&cli_ping_cond, NULL);
 
        ast_cli_register_multiple(taskprocessor_clis, ARRAY_LEN(taskprocessor_clis));
+
+       ast_register_atexit(tps_shutdown);
+
        return 0;
 }
 
index 05a52214c115c632a2ab482551a935efa82854b9..e5bb7d6728ad30f49f39eaf41e85d88e282915b6 100644 (file)
@@ -299,11 +299,21 @@ static struct ast_cli_entry cli_timing[] = {
        AST_CLI_DEFINE(timing_test, "Run a timing test"),
 };
 
+static void timing_shutdown(void)
+{
+       ast_cli_unregister_multiple(cli_timing, ARRAY_LEN(cli_timing));
+
+       ast_heap_destroy(timing_interfaces);
+       timing_interfaces = NULL;
+}
+
 int ast_timing_init(void)
 {
        if (!(timing_interfaces = ast_heap_create(2, timing_holder_cmp, 0))) {
                return -1;
        }
 
+       ast_register_atexit(timing_shutdown);
+
        return ast_cli_register_multiple(cli_timing, ARRAY_LEN(cli_timing));
 }
index 75c48dcd77e468dd96d331d50a41e592c58a144c..29d24b713a7f881adbf875de7e71705cc271bb43 100644 (file)
@@ -1421,8 +1421,20 @@ int ast_udptl_reload(void)
        return 0;
 }
 
+/*!
+ * \internal
+ * \brief Clean up resources on Asterisk shutdown
+ */
+static void udptl_shutdown(void)
+{
+       ast_cli_unregister_multiple(cli_udptl, ARRAY_LEN(cli_udptl));
+}
+
 void ast_udptl_init(void)
 {
-       ast_cli_register_multiple(cli_udptl, ARRAY_LEN(cli_udptl));
        __ast_udptl_reload(0);
+
+       ast_cli_register_multiple(cli_udptl, ARRAY_LEN(cli_udptl));
+
+       ast_register_atexit(udptl_shutdown);
 }
index 18d778ce4f72c9cacc264f0cc08118166f954b16..369ecd559c188966a69c3b3ab62b16a48b04d7f1 100644 (file)
@@ -599,9 +599,9 @@ static struct ast_calendar_event *destroy_event(struct ast_calendar_event *event
         * but haven't hit the end event yet, go ahead and set the devicestate to the current busy status */
        if (event->bs_start_sched < 0 && event->bs_end_sched >= 0) {
                if (!calendar_is_busy(event->owner)) {
-                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name);
+                       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
                } else {
-                       ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name);
+                       ast_devstate_changed(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
                }
        }
 
@@ -859,9 +859,9 @@ static int calendar_devstate_change(const void *data)
        /* We can have overlapping events, so ignore the event->busy_state and check busy state
         * based on all events in the calendar */
        if (!calendar_is_busy(event->owner)) {
-               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name);
+               ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
        } else {
-               ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name);
+               ast_devstate_changed(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
        }
 
        event = ast_calendar_unref_event(event);
index d67f3ba39b792b377103719390979017c9f4bf04..bb1a78d3b73131df38f8d1614b80d699857cb0d8 100644 (file)
@@ -209,7 +209,10 @@ static void load_config(int reload)
                        alias->cli_entry.command = alias->alias;
                        alias->cli_entry.usage = "Aliased CLI Command\n";
 
-                       ast_cli_register(&alias->cli_entry);
+                       if (ast_cli_register(&alias->cli_entry)) {
+                               ao2_ref(alias, -1);
+                               continue;
+                       }
                        ao2_link(cli_aliases, alias);
                        ast_verbose(VERBOSE_PREFIX_2 "Aliased CLI command '%s' to '%s'\n", v1->name, v1->value);
                        ao2_ref(alias, -1);
index 92ff98cf45ab44cab57faa5a6ec99e3e681f1279..9c6ba740dc681476613071538fc35f50d65755de 100644 (file)
@@ -350,7 +350,7 @@ static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd,
 static void aji_create_affiliations(struct aji_client *client, const char *node);
 static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type);
 static void aji_publish_device_state(struct aji_client *client, const char * device,
-       const char *device_state);
+                                    const char *device_state, unsigned int cachable);
 static int aji_handle_pubsub_error(void *data, ikspak *pak);
 static int aji_handle_pubsub_event(void *data, ikspak *pak);
 static void aji_pubsub_subscribe(struct aji_client *client, const char *node);
@@ -364,7 +364,7 @@ static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
 static void aji_devstate_cb(const struct ast_event *ast_event, void *data);
 static void aji_mwi_cb(const struct ast_event *ast_event, void *data);
 static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
-       const char *event_type);
+                                      const char *event_type, unsigned int cachable);
 /* No transports in this version */
 /*
 static int aji_create_transport(char *label, struct aji_client *client);
@@ -774,7 +774,7 @@ static struct ast_custom_function jabberstatus_function = {
  */
 static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
 {
-       char *aux = NULL, *parse = NULL;
+       char *parse = NULL;
        int timeout;
        int jidlen, resourcelen;
        struct timeval start;
@@ -891,7 +891,7 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch
                                continue;
                        }
                        found = 1;
-                       aux = ast_strdupa(tmp->message);
+                       ast_copy_string(buf, tmp->message, buflen);
                        AST_LIST_REMOVE_CURRENT(list);
                        aji_message_destroy(tmp);
                        break;
@@ -916,7 +916,6 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch
                ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid);
                return -1;
        }
-       ast_copy_string(buf, aux, buflen);
 
        return 0;
 }
@@ -3269,6 +3268,7 @@ static void aji_devstate_cb(const struct ast_event *ast_event, void *data)
 {
        const char *device;
        const char *device_state;
+       unsigned int cachable;
        struct aji_client *client;
        if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID)))
        {
@@ -3280,7 +3280,8 @@ static void aji_devstate_cb(const struct ast_event *ast_event, void *data)
        client = ASTOBJ_REF((struct aji_client *) data);
        device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
        device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
-       aji_publish_device_state(client, device, device_state);
+       cachable = ast_event_get_ie_uint(ast_event, AST_EVENT_IE_CACHABLE);
+       aji_publish_device_state(client, device, device_state, cachable);
        ASTOBJ_UNREF(client, ast_aji_client_destroy);
 }
 
@@ -3320,11 +3321,13 @@ static void aji_init_event_distribution(struct aji_client *client)
  */
 static int aji_handle_pubsub_event(void *data, ikspak *pak)
 {
-       char *item_id, *device_state, *context;
+       char *item_id, *device_state, *context, *cachable_str;
        int oldmsgs, newmsgs;
        iks *item, *item_content;
        struct ast_eid pubsub_eid;
        struct ast_event *event;
+       unsigned int cachable = AST_DEVSTATE_CACHABLE;
+
        item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item");
        if (!item) {
                ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n");
@@ -3339,11 +3342,14 @@ static int aji_handle_pubsub_event(void *data, ikspak *pak)
        }
        if (!strcasecmp(iks_name(item_content), "state")) {
                device_state = iks_find_cdata(item, "state");
+               if ((cachable_str = iks_find_cdata(item, "cachable"))) {
+                       sscanf(cachable_str, "%30d", &cachable);
+               }
                if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE,
-                       AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
-                       AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
-                       AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
-                       AST_EVENT_IE_END))) {
+                                           AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE,
+                                           AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID,
+                                           AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid),
+                                           AST_EVENT_IE_END))) {
                        return IKS_FILTER_EAT;
                }
        } else if (!strcasecmp(iks_name(item_content), "mailbox")) {
@@ -3363,7 +3369,13 @@ static int aji_handle_pubsub_event(void *data, ikspak *pak)
                        iks_name(item_content));
                return IKS_FILTER_EAT;
        }
-       ast_event_queue_and_cache(event);
+
+       if (cachable == AST_DEVSTATE_CACHABLE) {
+               ast_event_queue_and_cache(event);
+       } else {
+               ast_event_queue(event);
+       }
+
        return IKS_FILTER_EAT;
 }
 
@@ -3438,7 +3450,7 @@ static void aji_pubsub_subscribe(struct aji_client *client, const char *node)
  * \return iks *
  */
 static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node,
-       const char *event_type)
+                                      const char *event_type, unsigned int cachable)
 {
        iks *request = aji_pubsub_iq_create(client, "set");
        iks *pubsub, *publish, *item;
@@ -3452,8 +3464,24 @@ static iks* aji_build_publish_skeleton(struct aji_client *client, const char *no
        }
        item = iks_insert(publish, "item");
        iks_insert_attrib(item, "id", node);
-       return item;
 
+       if (cachable == AST_DEVSTATE_NOT_CACHABLE) {
+               iks *options, *x, *field_form_type, *field_persist;
+
+               options = iks_insert(pubsub, "publish-options");
+               x = iks_insert(options, "x");
+               iks_insert_attrib(x, "xmlns", "jabber:x:data");
+               iks_insert_attrib(x, "type", "submit");
+               field_form_type = iks_insert(x, "field");
+               iks_insert_attrib(field_form_type, "var", "FORM_TYPE");
+               iks_insert_attrib(field_form_type, "type", "hidden");
+               iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0);
+               field_persist = iks_insert(x, "field");
+               iks_insert_attrib(field_persist, "var", "pubsub#persist_items");
+               iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1);
+       }
+
+       return item;
 }
 
 /*!
@@ -3464,11 +3492,11 @@ static iks* aji_build_publish_skeleton(struct aji_client *client, const char *no
  * \return void
  */
 static void aji_publish_device_state(struct aji_client *client, const char *device,
-       const char *device_state)
+                                    const char *device_state, unsigned int cachable)
 {
-       iks *request = aji_build_publish_skeleton(client, device, "device_state");
+       iks *request = aji_build_publish_skeleton(client, device, "device_state", cachable);
        iks *state;
-       char eid_str[20];
+       char eid_str[20], cachable_str[2];
        if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) {
                if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
                        aji_create_pubsub_node(client, "leaf", device, "device_state");
@@ -3480,6 +3508,8 @@ static void aji_publish_device_state(struct aji_client *client, const char *devi
        state = iks_insert(request, "state");
        iks_insert_attrib(state, "xmlns", "http://asterisk.org");
        iks_insert_attrib(state, "eid", eid_str);
+       snprintf(cachable_str, sizeof(cachable_str), "%u", cachable);
+       iks_insert_attrib(state, "cachable", cachable_str);
        iks_insert_cdata(state, device_state, strlen(device_state));
        ast_aji_send(client, iks_root(request));
        iks_delete(request);
@@ -3499,7 +3529,7 @@ static void aji_publish_mwi(struct aji_client *client, const char *mailbox,
        char eid_str[20];
        iks *mailbox_node, *request;
        snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context);
-       request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting");
+       request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting", 1);
        ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
        mailbox_node = iks_insert(request, "mailbox");
        iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org");
index 7e9d963eac23c0c89e8215737a8e4a8be7ee9382..2bea13bd89591b40da4ccfbd8300e41ec1cf2ff5 100644 (file)
@@ -20,7 +20,7 @@ SOUNDS_DIR:=$(DESTDIR)$(ASTDATADIR)/sounds
 SOUNDS_CACHE_DIR?=
 MOH_DIR:=$(DESTDIR)$(ASTDATADIR)/moh
 CORE_SOUNDS_VERSION:=1.4.22
-EXTRA_SOUNDS_VERSION:=1.4.11
+EXTRA_SOUNDS_VERSION:=1.4.12
 MOH_VERSION:=2.03
 SOUNDS_URL:=http://downloads.asterisk.org/pub/telephony/sounds/releases
 MCS:=$(subst -EN-,-en-,$(MENUSELECT_CORE_SOUNDS))