diff options
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_sip.c | 59 | ||||
-rw-r--r-- | channels/sip/include/sip.h | 9 |
2 files changed, 48 insertions, 20 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 51a08690e..31b70281d 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1277,6 +1277,7 @@ static void mwi_event_cb(void *, struct stasis_subscription *, struct stasis_mes static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message); static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message); static void sip_keepalive_all_peers(void); +#define peer_in_destruction(peer) (ao2_ref(peer, 0) == 0) /*--- Applications, functions, CLI and manager command helpers */ static const char *sip_nat_mode(const struct sip_pvt *p); @@ -5197,13 +5198,24 @@ static void destroy_mailbox(struct sip_mailbox *mailbox) ast_free(mailbox); } +#define REMOVE_MAILBOX_WITH_LOCKED_PEER(__peer) \ +({\ + struct sip_mailbox *__mailbox;\ + ao2_lock(__peer);\ + __mailbox = AST_LIST_REMOVE_HEAD(&(__peer->mailboxes), entry);\ + ao2_unlock(__peer);\ + __mailbox;\ +}) + /*! Destroy all peer-related mailbox subscriptions */ static void clear_peer_mailboxes(struct sip_peer *peer) { struct sip_mailbox *mailbox; - while ((mailbox = AST_LIST_REMOVE_HEAD(&peer->mailboxes, entry))) + /* Lock the peer while accessing/updating the linked list but NOT while destroying the mailbox */ + while ((mailbox = REMOVE_MAILBOX_WITH_LOCKED_PEER(peer))) { destroy_mailbox(mailbox); + } } static void sip_destroy_peer_fn(void *peer) @@ -17195,19 +17207,21 @@ static void sip_peer_hold(struct sip_pvt *p, int hold) /*! \brief Receive MWI events that we have subscribed to */ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg) { - char *peer_name = userdata; - struct sip_peer *peer = sip_find_peer(peer_name, NULL, TRUE, FINDALLDEVICES, FALSE, 0); + struct sip_peer *peer = userdata; - if (stasis_subscription_final_message(sub, msg)) { - /* peer can be non-NULL during reload. */ - ao2_cleanup(peer); - ast_free(peer_name); + /* + * peer can't be NULL here but the peer can be in the process of being + * destroyed. If it is, we don't want to send any messages. In most cases, + * the peer is actually gone and there's no sense sending NOTIFYs that will + * never be answered. + */ + if (stasis_subscription_final_message(sub, msg) || peer_in_destruction(peer)) { return; } - if (peer && ast_mwi_state_type() == stasis_message_type(msg)) { + + if (ast_mwi_state_type() == stasis_message_type(msg)) { sip_send_mwi_to_peer(peer, 0); } - ao2_cleanup(peer); } static void network_change_stasis_subscribe(void) @@ -27932,15 +27946,14 @@ static void add_peer_mwi_subs(struct sip_peer *peer) AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { struct stasis_topic *mailbox_specific_topic; - mailbox->event_sub = stasis_unsubscribe(mailbox->event_sub); + + if (mailbox->status != SIP_MAILBOX_STATUS_NEW) { + continue; + } mailbox_specific_topic = ast_mwi_topic(mailbox->id); if (mailbox_specific_topic) { - char *peer_name = ast_strdup(peer->name); - if (!peer_name) { - return; - } - mailbox->event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, peer_name); + mailbox->event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, peer); } } } @@ -29165,7 +29178,9 @@ static int get_cached_mwi(struct sip_peer *peer, int *new, int *old) } /*! \brief Send message waiting indication to alert peer that they've got voicemail - * \note Both peer and associated sip_pvt must be unlocked prior to calling this function + * \note Both peer and associated sip_pvt must be unlocked prior to calling this function. + * It's possible that this function will get called during peer destruction as final messages + * are processed. The peer will still be valid however. * \returns -1 on failure, 0 on success */ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only) @@ -30988,6 +31003,7 @@ static void add_peer_mailboxes(struct sip_peer *peer, const char *value) AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { if (!strcmp(mailbox->id, mbox)) { duplicate = 1; + mailbox->status = SIP_MAILBOX_STATUS_EXISTING; break; } } @@ -31000,14 +31016,18 @@ static void add_peer_mailboxes(struct sip_peer *peer, const char *value) continue; } strcpy(mailbox->id, mbox); /* SAFE */ + mailbox->status = SIP_MAILBOX_STATUS_NEW; + mailbox->peer = peer; AST_LIST_INSERT_TAIL(&peer->mailboxes, mailbox, entry); } } /*! \brief Build peer from configuration (file or realtime static/dynamic) */ -static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime, int devstate_only) +static struct sip_peer *build_peer(const char *name, struct ast_variable *v_head, struct ast_variable *alt, int realtime, int devstate_only) { + /* We preserve the original value of v_head to make analyzing backtraces easier */ + struct ast_variable *v = v_head; struct sip_peer *peer = NULL; struct ast_acl_list *oldacl = NULL; struct ast_acl_list *olddirectmediaacl = NULL; @@ -31071,6 +31091,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str return NULL; } + if (realtime && !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)) { ast_atomic_fetchadd_int(&rpeerobjs, 1); ast_debug(3, "-REALTIME- peer built. Name: %s. Peer objects: %d\n", name, rpeerobjs); @@ -31120,7 +31141,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str if (!devstate_only) { struct sip_mailbox *mailbox; AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { - mailbox->delme = 1; + mailbox->status = SIP_MAILBOX_STATUS_UNKNOWN; } } @@ -31569,7 +31590,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str if (!devstate_only) { struct sip_mailbox *mailbox; AST_LIST_TRAVERSE_SAFE_BEGIN(&peer->mailboxes, mailbox, entry) { - if (mailbox->delme) { + if (mailbox->status == SIP_MAILBOX_STATUS_UNKNOWN) { AST_LIST_REMOVE_CURRENT(entry); destroy_mailbox(mailbox); } diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 3e6832152..44c8ddf35 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -1230,6 +1230,12 @@ struct sip_pkt { struct ast_str *data; }; +enum sip_mailbox_status { + SIP_MAILBOX_STATUS_UNKNOWN = 0, + SIP_MAILBOX_STATUS_EXISTING, + SIP_MAILBOX_STATUS_NEW, +}; + /*! * \brief A peer's mailbox * @@ -1240,7 +1246,8 @@ struct sip_mailbox { /*! Associated MWI subscription */ struct stasis_subscription *event_sub; AST_LIST_ENTRY(sip_mailbox) entry; - unsigned int delme:1; + struct sip_peer *peer; + enum sip_mailbox_status status; char id[1]; }; |