]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
chan_sip: Prevent deadlock when issuing "sip show channels" 73/3273/4
authorGeorge Joseph <gjoseph@digium.com>
Thu, 21 Jul 2016 14:05:03 +0000 (08:05 -0600)
committerGeorge Joseph <gjoseph@digium.com>
Thu, 21 Jul 2016 21:09:36 +0000 (16:09 -0500)
sip_show_channels locks the dialogs container first then locks each
sip_pvt so it can spit out the details.  The rest of sip dialog
processing locks the sip_pvt first then locks the dialogs container
if it needs to.  Both lock in the order they need but deadlocks can
result.  To fix, sip_show_channels and sip_show_channelstats have
been converted to use an iterator rather than ao2_callback.  This way
the container is locked only while getting the next entry and is
unlocked when the callback is called.

ASTERISK-23013 #close

Change-Id: Id9980419909e811f89484950ed46ef117b9eb990

channels/chan_sip.c

index b30955864625ec13bec521913f86fe967ccbef32..c6c73b472aff46a6e2c164bbe7e97afdc8263d75 100644 (file)
@@ -20639,17 +20639,15 @@ static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 }
 
 /*! \brief Callback for show_chanstats */
-static int show_chanstats_cb(void *__cur, void *__arg, int flags)
+static int show_chanstats_cb(struct sip_pvt *cur, struct __show_chan_arg *arg)
 {
 #define FORMAT2 "%-15.15s  %-11.11s  %-8.8s %-10.10s  %-10.10s (     %%) %-6.6s %-10.10s  %-10.10s (     %%) %-6.6s\n"
 #define FORMAT  "%-15.15s  %-11.11s  %-8.8s %-10.10u%-1.1s %-10.10u (%5.2f%%) %-6.4lf %-10.10u%-1.1s %-10.10u (%5.2f%%) %-6.4lf\n"
-       struct sip_pvt *cur = __cur;
        struct ast_rtp_instance_stats stats;
        char durbuf[10];
        int duration;
        int durh, durm, durs;
        struct ast_channel *c;
-       struct __show_chan_arg *arg = __arg;
        int fd = arg->fd;
 
        sip_pvt_lock(cur);
@@ -20713,6 +20711,8 @@ static int show_chanstats_cb(void *__cur, void *__arg, int flags)
 static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 };
+       struct sip_pvt *cur;
+       struct ao2_iterator i;
 
        switch (cmd) {
        case CLI_INIT:
@@ -20730,8 +20730,14 @@ static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_
                return CLI_SHOWUSAGE;
 
        ast_cli(a->fd, FORMAT2, "Peer", "Call ID", "Duration", "Recv: Pack", "Lost", "Jitter", "Send: Pack", "Lost", "Jitter");
+
        /* iterate on the container and invoke the callback on each item */
-       ao2_t_callback(dialogs, OBJ_NODATA, show_chanstats_cb, &arg, "callback to sip show chanstats");
+       i = ao2_iterator_init(dialogs, 0);
+       for (; (cur = ao2_iterator_next(&i)); ao2_ref(cur, -1)) {
+               show_chanstats_cb(cur, &arg);
+       }
+       ao2_iterator_destroy(&i);
+
        ast_cli(a->fd, "%d active SIP channel%s\n", arg.numchans, (arg.numchans != 1) ? "s" : "");
        return CLI_SUCCESS;
 }
@@ -21046,10 +21052,8 @@ static const struct cfsubscription_types *find_subscription_type(enum subscripti
 #define FORMAT  "%-15.15s  %-15.15s  %-15.15s  %-15.15s  %-3.3s %-3.3s  %-15.15s %-10.10s %-10.10s\n"
 
 /*! \brief callback for show channel|subscription */
-static int show_channels_cb(void *__cur, void *__arg, int flags)
+static int show_channels_cb(struct sip_pvt *cur, struct __show_chan_arg *arg)
 {
-       struct sip_pvt *cur = __cur;
-       struct __show_chan_arg *arg = __arg;
        const struct ast_sockaddr *dst;
 
        sip_pvt_lock(cur);
@@ -21101,7 +21105,8 @@ static int show_channels_cb(void *__cur, void *__arg, int flags)
 static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 };
-
+       struct sip_pvt *cur;
+       struct ao2_iterator i;
 
        if (cmd == CLI_INIT) {
                e->command = "sip show {channels|subscriptions}";
@@ -21123,7 +21128,11 @@ static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_
                ast_cli(arg.fd, FORMAT3, "Peer", "User", "Call ID", "Extension", "Last state", "Type", "Mailbox", "Expiry");
 
        /* iterate on the container and invoke the callback on each item */
-       ao2_t_callback(dialogs, OBJ_NODATA, show_channels_cb, &arg, "callback to show channels");
+       i = ao2_iterator_init(dialogs, 0);
+       for (; (cur = ao2_iterator_next(&i)); ao2_ref(cur, -1)) {
+               show_channels_cb(cur, &arg);
+       }
+       ao2_iterator_destroy(&i);
        
        /* print summary information */
        ast_cli(arg.fd, "%d active SIP %s%s\n", arg.numchans,