logger: Adds additional support for call id logging and chan_sip specific stuff
authorJonathan Rose <jrose@digium.com>
Thu, 17 May 2012 16:28:20 +0000 (16:28 +0000)
committerJonathan Rose <jrose@digium.com>
Thu, 17 May 2012 16:28:20 +0000 (16:28 +0000)
This patch improves the handling of call id logging significantly with regard
to transfers and adding APIs to better handle specific aspects of logging.
Also, changes have been made to chan_sip in order to better handle the creation
of callids and to enable the monitor thread to bind itself to a particular
call id when a dialog is determined to be related to a callid. It then unbinds
itself before returning to normal monitoring.

review: https://reviewboard.asterisk.org/r/1886/

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@366842 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
channels/chan_sip.c
channels/sip/include/dialog.h
channels/sip/include/sip.h
include/asterisk/channel.h
include/asterisk/logger.h
main/channel.c
main/channel_internal_api.c
main/cli.c
main/logger.c
main/pbx.c

diff --git a/CHANGES b/CHANGES
index ad2b96e..23f8f7c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -26,7 +26,8 @@ Core
  * Threads belonging to a particular call are now linked with callids which get
    added to any log messages produced by those threads. Log messages can now be
    easily identified as involved with a certain call by looking at their call id.
-   This feature can be disabled in logger.conf with the display_callids option.
+   Call ids may also be attached to log messages for just about any case where
+   it can be determined to be related to a particular call.
  * The minimum DTMF duration can now be configured in asterisk.conf
    as "mindtmfduration". The default value is (as before) set to 80 ms.
    (previously it was only available in source code)
index a85563b..5d0cf0b 100644 (file)
@@ -1942,7 +1942,7 @@ static int sip_cc_monitor_request_cc(struct ast_cc_monitor *monitor, int *availa
                return -1;
        }
 
-       if (!(monitor_instance->subscription_pvt = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE, NULL))) {
+       if (!(monitor_instance->subscription_pvt = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE, NULL, NULL))) {
                return -1;
        }
 
@@ -5976,6 +5976,11 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
        p->peercaps = ast_format_cap_destroy(p->peercaps);
        p->redircaps = ast_format_cap_destroy(p->redircaps);
        p->prefcaps = ast_format_cap_destroy(p->prefcaps);
+
+       /* Lastly, kill the callid associated with the pvt */
+       if (p->logger_callid) {
+               ast_callid_unref(p->logger_callid);
+       }
 }
 
 /*! \brief  update_call_counter: Handle call_limit for SIP devices
@@ -7117,7 +7122,7 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
  *
  * \return New ast_channel locked.
  */
-static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title, const char *linkedid)
+static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title, const char *linkedid, struct ast_callid *callid)
 {
        struct ast_channel *tmp;
        struct ast_variable *v = NULL;
@@ -7146,6 +7151,12 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
                sip_pvt_lock(i);
                return NULL;
        }
+
+       /* If we sent in a callid, bind it to the channel. */
+       if (callid) {
+               ast_channel_callid_set(tmp, callid);
+       }
+
        ast_channel_lock(tmp);
        sip_pvt_lock(i);
        ast_channel_cc_params_init(tmp, i->cc_params);
@@ -7792,12 +7803,21 @@ static struct sip_st_dlg* sip_st_alloc(struct sip_pvt *const p)
        return p->stimer;
 }
 
+static void sip_pvt_callid_set(struct sip_pvt *pvt, struct ast_callid *callid)
+{
+       if (pvt->logger_callid) {
+               ast_callid_unref(pvt->logger_callid);
+       }
+       ast_callid_ref(callid);
+       pvt->logger_callid = callid;
+}
+
 /*! \brief Allocate sip_pvt structure, set defaults and link in the container.
  * Returns a reference to the object so whoever uses it later must
  * remember to release the reference.
  */
 struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
-                                int useglobal_nat, const int intended_method, struct sip_request *req)
+                                int useglobal_nat, const int intended_method, struct sip_request *req, struct ast_callid *logger_callid)
 {
        struct sip_pvt *p;
 
@@ -7813,6 +7833,11 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
                ao2_t_ref(p, -1, "Yuck, couldn't allocate cc_params struct. Get rid o' p");
                return NULL;
        }
+
+       if (logger_callid) {
+               sip_pvt_callid_set(p, logger_callid);
+       }
+
        p->caps = ast_format_cap_alloc_nolock();
        p->jointcaps = ast_format_cap_alloc_nolock();
        p->peercaps = ast_format_cap_alloc_nolock();
@@ -8181,7 +8206,7 @@ static void forked_invite_init(struct sip_request *req, const char *new_theirtag
 {
        struct sip_pvt *p;
 
-       if (!(p = sip_alloc(original->callid, addr, 1, SIP_INVITE, req)))  {
+       if (!(p = sip_alloc(original->callid, addr, 1, SIP_INVITE, req, original->logger_callid)))  {
                return; /* alloc error */
        }
        p->invitestate = INV_TERMINATED;
@@ -8430,13 +8455,18 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
        /* See if the method is capable of creating a dialog */
        if (sip_methods[intended_method].can_create == CAN_CREATE_DIALOG) {
                struct sip_pvt *p = NULL;
+               struct ast_callid *logger_callid = NULL;
+
+               if (intended_method == SIP_INVITE) {
+                       logger_callid = ast_create_callid();
+               }
 
                if (intended_method == SIP_REFER) {
                        /* We do support REFER, but not outside of a dialog yet */
                        transmit_response_using_temp(callid, addr, 1, intended_method, req, "603 Declined (no dialog)");
-       
+
                /* Ok, time to create a new SIP dialog object, a pvt */
-               } else if (!(p = sip_alloc(callid, addr, 1, intended_method, req)))  {
+               } else if (!(p = sip_alloc(callid, addr, 1, intended_method, req, logger_callid)))  {
                        /* We have a memory or file/socket error (can't allocate RTP sockets or something) so we're not
                                getting a dialog from sip_alloc.
 
@@ -8448,6 +8478,10 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a
                        transmit_response_using_temp(callid, addr, 1, intended_method, req, "500 Server internal error");
                        ast_debug(4, "Failed allocating SIP dialog, sending 500 Server internal error and giving up\n");
                }
+               /* If we created an ast_callid for an invite, we need to free it now. */
+               if (logger_callid) {
+                       ast_callid_unref(logger_callid);
+               }
                return p; /* can be NULL */
        } else if( sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) {
                /* A method we do not support, let's take it on the volley */
@@ -12597,7 +12631,7 @@ static int transmit_publish(struct sip_epa_entry *epa_entry, enum sip_publish_ty
 
        epa_entry->publish_type = publish_type;
 
-       if (!(pvt = sip_alloc(NULL, NULL, 0, SIP_PUBLISH, NULL))) {
+       if (!(pvt = sip_alloc(NULL, NULL, 0, SIP_PUBLISH, NULL, NULL))) {
                return -1;
        }
 
@@ -12905,7 +12939,7 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
        }
        
        /* Create a dialog that we will use for the subscription */
-       if (!(mwi->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE, NULL))) {
+       if (!(mwi->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE, NULL, NULL))) {
                return -1;
        }
 
@@ -13395,7 +13429,7 @@ static int manager_sipnotify(struct mansession *s, const struct message *m)
                channame += 4;
        }
 
-       if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) {
+       if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL, NULL))) {
                astman_send_error(s, m, "Unable to build sip pvt data for notify (memory/socket error)");
                return 0;
        }
@@ -13716,7 +13750,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
                        r->callid_valid = TRUE;
                }
                /* Allocate SIP dialog for registration */
-               if (!(p = sip_alloc( r->callid, NULL, 0, SIP_REGISTER, NULL))) {
+               if (!(p = sip_alloc( r->callid, NULL, 0, SIP_REGISTER, NULL, NULL))) {
                        ast_log(LOG_WARNING, "Unable to allocate registration transaction (memory or socket error)\n");
                        return 0;
                }
@@ -19816,7 +19850,7 @@ static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
                char buf[512];
                struct ast_variable *header, *var;
 
-               if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) {
+               if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL, NULL))) {
                        ast_log(LOG_WARNING, "Unable to build sip pvt data for notify (memory/socket error)\n");
                        return CLI_FAILURE;
                }
@@ -23568,7 +23602,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        res = INV_REQ_FAILED;
                        goto request_invite_cleanup;
                } else {
-
                        /* If no extension was specified, use the s one */
                        /* Basically for calling to IP/Host name only */
                        if (ast_strlen_zero(p->exten))
@@ -23578,7 +23611,9 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                        make_our_tag(p->tag, sizeof(p->tag));
                        /* First invitation - create the channel.  Allocation
                         * failures are handled below. */
-                       c = sip_new(p, AST_STATE_DOWN, S_OR(p->peername, NULL), NULL);
+
+                       c = sip_new(p, AST_STATE_DOWN, S_OR(p->peername, NULL), NULL, p->logger_callid);
+
                        if (cc_recall_core_id != -1) {
                                ast_setup_cc_recall_datastore(c, cc_recall_core_id);
                                ast_cc_agent_set_interfaces_chanvar(c);
@@ -24884,7 +24919,7 @@ static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *f
        struct ast_msg_var_iterator *iter;
        struct sip_peer *peer_ptr;
 
-       if (!(pvt = sip_alloc(NULL, NULL, 0, SIP_MESSAGE, NULL))) {
+       if (!(pvt = sip_alloc(NULL, NULL, 0, SIP_MESSAGE, NULL, NULL))) {
                return -1;
        }
 
@@ -26412,6 +26447,10 @@ static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr)
                return 1;
        }
 
+       if (p->logger_callid) {
+               ast_callid_threadassoc_add(p->logger_callid);
+       }
+
        /* Lock both the pvt and the owner if owner is present.  This will
         * not fail. */
        owner_chan_ref = sip_pvt_lock_full(p);
@@ -26446,6 +26485,10 @@ static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr)
        ao2_t_ref(p, -1, "throw away dialog ptr from find_call at end of routine"); /* p is gone after the return */
        ast_mutex_unlock(&netlock);
 
+       if (p->logger_callid) {
+               ast_callid_threadassoc_remove();
+       }
+
        return 1;
 }
 
@@ -26714,7 +26757,7 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only)
        } else {
                ao2_unlock(peer);
                /* Build temporary dialog for this message */
-               if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) {
+               if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL, NULL))) {
                        return -1;
                }
 
@@ -27420,7 +27463,7 @@ static int sip_poke_peer(struct sip_peer *peer, int force)
                peer->call = dialog_unref(peer->call, "unref dialog peer->call");
                /* peer->call = sip_destroy(peer->call); */
        }
-       if (!(p = sip_alloc(NULL, NULL, 0, SIP_OPTIONS, NULL))) {
+       if (!(p = sip_alloc(NULL, NULL, 0, SIP_OPTIONS, NULL, NULL))) {
                return -1;
        }
        peer->call = dialog_ref(p, "copy sip alloc from p to peer->call");
@@ -27607,6 +27650,7 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
        char *remote_address;
        enum sip_transport transport = 0;
        struct ast_sockaddr remote_address_sa = { {0,} };
+       struct ast_callid *callid;
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(peerorhost);
                AST_APP_ARG(exten);
@@ -27635,9 +27679,13 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
                return NULL;
        }
 
-       if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE, NULL))) {
+       callid = ast_read_threadstorage_callid();
+       if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE, NULL, callid))) {
                ast_log(LOG_ERROR, "Unable to build sip pvt data for '%s' (Out of memory or socket error)\n", dest);
                *cause = AST_CAUSE_SWITCH_CONGESTION;
+               if (callid) {
+                       ast_callid_unref(callid);
+               }
                return NULL;
        }
 
@@ -27652,6 +27700,9 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
                /* sip_destroy(p); */
                ast_log(LOG_ERROR, "Unable to build option SIP data structure - Out of memory\n");
                *cause = AST_CAUSE_SWITCH_CONGESTION;
+               if (callid) {
+                       ast_callid_unref(callid);
+               }
                return NULL;
        }
 
@@ -27739,6 +27790,9 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
                dialog_unlink_all(p);
                dialog_unref(p, "unref dialog p UNREGISTERED");
                /* sip_destroy(p); */
+               if (callid) {
+                       ast_callid_unref(callid);
+               }
                return NULL;
        }
        if (ast_strlen_zero(p->peername) && ext)
@@ -27774,7 +27828,12 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
        ast_format_cap_joint_copy(cap, p->caps, p->jointcaps);
 
        sip_pvt_lock(p);
-       tmpc = sip_new(p, AST_STATE_DOWN, host, requestor ? ast_channel_linkedid(requestor) : NULL);    /* Place the call */
+
+       tmpc = sip_new(p, AST_STATE_DOWN, host, requestor ? ast_channel_linkedid(requestor) : NULL, callid);    /* Place the call */
+       if (callid) {
+               callid = ast_callid_unref(callid);
+       }
+
        if (sip_cfg.callevents)
                manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
                        "Channel: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\nPeername: %s\r\n",
index 92834b2..ea2fb45 100644 (file)
@@ -35,7 +35,7 @@ struct sip_pvt *dialog_ref_debug(struct sip_pvt *p, const char *tag, char *file,
 struct sip_pvt *dialog_unref_debug(struct sip_pvt *p, const char *tag, char *file, int line, const char *func);
 
 struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *sin,
-                                int useglobal_nat, const int intended_method, struct sip_request *req);
+                                int useglobal_nat, const int intended_method, struct sip_request *req, struct ast_callid *logger_callid);
 void sip_scheddestroy_final(struct sip_pvt *p, int ms);
 void sip_scheddestroy(struct sip_pvt *p, int ms);
 int sip_cancel_destroy(struct sip_pvt *p);
index 1b257cf..6c9cba7 100644 (file)
@@ -990,6 +990,7 @@ struct sip_msg_hdr {
 struct sip_pvt {
        struct sip_pvt *next;                   /*!< Next dialog in chain */
        enum invitestates invitestate;          /*!< Track state of SIP_INVITEs */
+       struct ast_callid *logger_callid;               /*!< Identifier for call used in log messages */
        int method;                             /*!< SIP method that opened this dialog */
        AST_DECLARE_STRING_FIELDS(
                AST_STRING_FIELD(callid);       /*!< Global CallID */
index d71b7e5..1a1c998 100644 (file)
@@ -3693,12 +3693,15 @@ void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tec
 enum ast_channel_adsicpe ast_channel_adsicpe(const struct ast_channel *chan);
 void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value);
 enum ast_channel_state ast_channel_state(const struct ast_channel *chan);
+struct ast_callid *ast_channel_callid(const struct ast_channel *chan);
+void ast_channel_callid_set(struct ast_channel *chan, struct ast_callid *value);
 
 /* XXX Internal use only, make sure to move later */
 void ast_channel_state_set(struct ast_channel *chan, enum ast_channel_state);
 void ast_channel_softhangup_internal_flag_set(struct ast_channel *chan, int value);
 void ast_channel_softhangup_internal_flag_add(struct ast_channel *chan, int value);
 void ast_channel_softhangup_internal_flag_clear(struct ast_channel *chan, int value);
+void ast_channel_callid_cleanup(struct ast_channel *chan);
 int ast_channel_softhangup_internal_flag(struct ast_channel *chan);
 
 /* Format getters */
index a495449..518a4f0 100644 (file)
@@ -279,9 +279,43 @@ struct ast_callid *ast_read_threadstorage_callid(void);
  */
 int ast_callid_threadassoc_add(struct ast_callid *callid);
 
-/*
- * May need a function to clean the threadstorage if we want to repurpose a thread.
+/*!
+ * \brief Removes callid from thread storage of the calling thread
+ *
+ * \retval 0 - success
+ * \retval non-zero - failure
+ */
+int ast_callid_threadassoc_remove(void);
+
+/*!
+ * \brief Checks thread storage for a callid and stores a reference if it exists.
+ *        If not, then a new one will be created, bound to the thread, and a reference
+ *        to it will be stored.
+ *
+ * \param callid pointer to struct pointer used to store the referenced callid
+ * \retval 0 - callid was found
+ * \retval 1 - callid was created
+ * \retval -1 - the function failed somehow (presumably memory problems)
+ */
+int ast_callid_threadstorage_auto(struct ast_callid **callid);
+
+/*!
+ * \brief Use in conjunction with ast_callid_threadstorage_auto. Cleans up the
+ *        references and if the callid was created by threadstorage_auto, unbinds
+ *        the callid from the threadstorage
+ * \param callid The callid set by ast_callid_threadstorage_auto
+ * \param callid_created The integer returned through ast_callid_threadstorage_auto
+ */
+void ast_callid_threadstorage_auto_clean(struct ast_callid *callid, int callid_created);
+
+/*!
+ * \brief copy a string representation of the callid into a target string
+ *
+ * \param buffer destination of callid string (should be able to store 13 characters or more)
+ * \param buffer_size maximum writable length of the string (Less than 13 will result in truncation)
+ * \param callid Callid for which string is being requested
  */
+void ast_callid_strnprint(char *buffer, size_t buffer_size, struct ast_callid *callid);
 
 /*!
  * \brief Send a log message to a dynamically registered log level
index e46aa3a..e7bfa1d 100644 (file)
@@ -2177,6 +2177,7 @@ static void ast_channel_destructor(void *obj)
        struct varshead *headp;
        struct ast_datastore *datastore;
        char device_name[AST_CHANNEL_NAME];
+       struct ast_callid *callid;
 
        if (ast_channel_internal_is_finalized(chan)) {
                ast_cel_report_event(chan, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
@@ -2188,6 +2189,11 @@ static void ast_channel_destructor(void *obj)
        while ((datastore = AST_LIST_REMOVE_HEAD(ast_channel_datastores(chan), entry)))
                /* Free the data store */
                ast_datastore_free(datastore);
+
+       /* While the channel is locked, take the reference to its callid while we tear down the call. */
+       callid = ast_channel_callid(chan);
+       ast_channel_callid_cleanup(chan);
+
        ast_channel_unlock(chan);
 
        /* Lock and unlock the channel just to be sure nobody has it locked still
@@ -2196,7 +2202,7 @@ static void ast_channel_destructor(void *obj)
        ast_channel_unlock(chan);
 
        if (ast_channel_tech_pvt(chan)) {
-               ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", ast_channel_name(chan));
+               ast_log_callid(LOG_WARNING, callid, "Channel '%s' may not have been hung up properly\n", ast_channel_name(chan));
                ast_free(ast_channel_tech_pvt(chan));
        }
 
@@ -2229,7 +2235,7 @@ static void ast_channel_destructor(void *obj)
        if (ast_channel_writetrans(chan))
                ast_translator_free_path(ast_channel_writetrans(chan));
        if (ast_channel_pbx(chan))
-               ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", ast_channel_name(chan));
+               ast_log_callid(LOG_WARNING, callid, "PBX may not have been terminated properly on '%s'\n", ast_channel_name(chan));
 
        ast_party_dialed_free(ast_channel_dialed(chan));
        ast_party_caller_free(ast_channel_caller(chan));
@@ -2286,6 +2292,9 @@ static void ast_channel_destructor(void *obj)
        }
 
        ast_channel_nativeformats_set(chan, ast_format_cap_destroy(ast_channel_nativeformats(chan)));
+       if (callid) {
+               ast_callid_unref(callid);
+       }
 }
 
 /*! \brief Free a dummy channel structure */
@@ -5669,6 +5678,16 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request
                        ast_format_cap_destroy(joint_cap);
                        return NULL;
                }
+
+               /* Set newly created channel callid to same as the requestor */
+               if (requestor) {
+                       struct ast_callid *callid = ast_channel_callid(requestor);
+                       if (callid) {
+                               ast_channel_callid_set(c, callid);
+                               callid = ast_callid_unref(callid);
+                       }
+               }
+
                joint_cap = ast_format_cap_destroy(joint_cap);
 
                if (set_security_requirements(requestor, c)) {
index 4f89ca7..5125c6f 100644 (file)
@@ -82,6 +82,7 @@ struct ast_channel {
        struct ast_tone_zone *zone;                     /*!< Tone zone as set in indications.conf or
                                                         *   in the CHANNEL dialplan function */
        struct ast_channel_monitor *monitor;            /*!< Channel monitoring */
+       struct ast_callid *callid;                      /*!< Bound call identifier pointer */
 #ifdef HAVE_EPOLL
        struct ast_epoll_data *epfd_data[AST_MAX_FDS];
 #endif
@@ -829,6 +830,31 @@ enum ast_channel_state ast_channel_state(const struct ast_channel *chan)
 {
        return chan->state;
 }
+struct ast_callid *ast_channel_callid(const struct ast_channel *chan)
+{
+       if (chan->callid) {
+               ast_callid_ref(chan->callid);
+               return chan->callid;
+       }
+       return NULL;
+}
+void ast_channel_callid_set(struct ast_channel *chan, struct ast_callid *callid)
+{
+       if (chan->callid) {
+
+               if ((option_debug >= 3) || (ast_opt_dbg_module && ast_debug_get_by_module(AST_MODULE) >= 3)) {
+                       char call_identifier_from[13];
+                       char call_identifier_to[13];
+                       ast_callid_strnprint(call_identifier_from, sizeof(call_identifier_from), chan->callid);
+                       ast_callid_strnprint(call_identifier_to, sizeof(call_identifier_to), callid);
+                       ast_log(LOG_DEBUG, "Channel Call ID changing from %s to %s\n", call_identifier_from, call_identifier_to);
+               }
+
+               /* unbind if already set */
+               ast_callid_unref(chan->callid);
+       }
+       chan->callid = ast_callid_ref(callid);
+}
 void ast_channel_state_set(struct ast_channel *chan, enum ast_channel_state value)
 {
        chan->state = value;
@@ -956,6 +982,13 @@ void ast_channel_softhangup_internal_flag_clear(struct ast_channel *chan, int va
        chan ->softhangup &= ~value;
 }
 
+void ast_channel_callid_cleanup(struct ast_channel *chan)
+{
+       if (chan->callid) {
+               chan->callid = ast_callid_unref(chan->callid);
+       }
+}
+
 /* Typedef accessors */
 ast_group_t ast_channel_callgroup(const struct ast_channel *chan)
 {
index 89bef80..6c79c7b 100644 (file)
@@ -1393,6 +1393,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
        struct ast_str *output;/*!< Accumulation buffer for all output. */
        long elapsed_seconds=0;
        int hour=0, min=0, sec=0;
+       struct ast_callid *callid;
+       char call_identifier_str[13] = "";
 #ifdef CHANNEL_TRACE
        int trace_enabled;
 #endif
@@ -1440,6 +1442,12 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                strcpy(cdrtime, "N/A");
        }
 
+       /* Construct the call identifier string based on the status of the channel's call identifier */
+       if ((callid = ast_channel_callid(c))) {
+               ast_callid_strnprint(call_identifier_str, sizeof(call_identifier_str), callid);
+               ast_callid_unref(callid);
+       }
+
        ast_str_append(&output, 0,
                " -- General --\n"
                "           Name: %s\n"
@@ -1474,7 +1482,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                "   Pickup Group: %llu\n"
                "    Application: %s\n"
                "           Data: %s\n"
-               "    Blocking in: %s\n",
+               "    Blocking in: %s\n"
+               " Call Identifer: %s\n",
                ast_channel_name(c), ast_channel_tech(c)->type, ast_channel_uniqueid(c), ast_channel_linkedid(c),
                S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "(N/A)"),
                S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "(N/A)"),
@@ -1497,7 +1506,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                cdrtime, ast_channel_internal_bridged_channel(c) ? ast_channel_name(ast_channel_internal_bridged_channel(c)) : "<none>", ast_bridged_channel(c) ? ast_channel_name(ast_bridged_channel(c)) : "<none>",
                ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_channel_callgroup(c), ast_channel_pickupgroup(c), (ast_channel_appl(c) ? ast_channel_appl(c) : "(N/A)" ),
                (ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)"),
-               (ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)"));
+               (ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)"),
+               S_OR(call_identifier_str, "(None)"));
 
        if (pbx_builtin_serialize_variables(c, &obuf)) {
                ast_str_append(&output, 0, "      Variables:\n%s\n", ast_str_buffer(obuf));
index dcef762..cdced27 100644 (file)
@@ -1236,6 +1236,11 @@ void close_logger(void)
        AST_RWLIST_UNLOCK(&logchannels);
 }
 
+void ast_callid_strnprint(char *buffer, size_t buffer_size, struct ast_callid *callid)
+{
+       snprintf(buffer, buffer_size, "[C-%08x]", callid->call_identifier);
+}
+
 struct ast_callid *ast_create_callid(void)
 {
        struct ast_callid *call;
@@ -1249,7 +1254,7 @@ struct ast_callid *ast_create_callid(void)
        using = ast_atomic_fetchadd_int(&next_unique_callid, +1);
 
        call->call_identifier = using;
-       ast_log(LOG_DEBUG, "CALL_ID [C-%08x] created by thread.\n", call->call_identifier);
+       ast_debug(3, "CALL_ID [C-%08x] created by thread.\n", call->call_identifier);
        return call;
 }
 
@@ -1279,7 +1284,7 @@ int ast_callid_threadassoc_add(struct ast_callid *callid)
                /* callid will be unreffed at thread destruction */
                ast_callid_ref(callid);
                *pointing = callid;
-               ast_log(LOG_DEBUG, "CALL_ID [C-%08x] bound to thread.\n", callid->call_identifier);
+               ast_debug(3, "CALL_ID [C-%08x] bound to thread.\n", callid->call_identifier);
        } else {
                ast_log(LOG_WARNING, "Attempted to ast_callid_threadassoc_add on thread already associated with a callid.\n");
                return 1;
@@ -1288,6 +1293,59 @@ int ast_callid_threadassoc_add(struct ast_callid *callid)
        return 0;
 }
 
+int ast_callid_threadassoc_remove()
+{
+       struct ast_callid **pointing;
+       pointing = ast_threadstorage_get(&unique_callid, sizeof(struct ast_callid **));
+       if (!(pointing)) {
+               ast_log(LOG_ERROR, "Failed to allocate thread storage.\n");
+               return -1;
+       }
+
+       if (!(*pointing)) {
+               ast_log(LOG_ERROR, "Tried to clean callid thread storage with no callid in thread storage.\n");
+               return -1;
+       } else {
+               ast_debug(3, "Call_ID [C-%08x] being removed from thread.\n", (*pointing)->call_identifier);
+               *pointing = ast_callid_unref(*pointing);
+               return 0;
+       }
+}
+
+int ast_callid_threadstorage_auto(struct ast_callid **callid)
+{
+       struct ast_callid *tmp;
+
+       /* Start by trying to see if a callid is available from thread storage */
+       tmp = ast_read_threadstorage_callid();
+       if (tmp) {
+               *callid = tmp;
+               return 0;
+       }
+
+       /* If that failed, try to create a new one and bind it. */
+       tmp = ast_create_callid();
+       if (tmp) {
+               ast_callid_threadassoc_add(tmp);
+               *callid = tmp;
+               return 1;
+       }
+
+       /* If neither worked, then something must have gone wrong. */
+       return -1;
+}
+
+void ast_callid_threadstorage_auto_clean(struct ast_callid *callid, int callid_created)
+{
+       if (callid) {
+               /* If the callid was created rather than simply grabbed from the thread storage, we need to unbind here. */
+               if (callid_created == 1) {
+                       ast_callid_threadassoc_remove();
+               }
+               callid = ast_callid_unref(callid);
+       }
+}
+
 /*!
  * \internal
  * \brief thread storage cleanup function for unique_callid
index 7ea3600..2860218 100644 (file)
@@ -5115,6 +5115,20 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
        if (!(pbx = ast_calloc(1, sizeof(*pbx)))) {
                return -1;
        }
+
+       if (!ast_read_threadstorage_callid()) {
+               /* Associate new PBX thread with the channel call id if it is availble.
+                * If not, create a new one instead.
+                */
+               struct ast_callid *callid;
+               if (!(callid = ast_channel_callid(c))) {
+                       callid = ast_create_callid();
+               }
+               ast_callid_threadassoc_add(callid);
+               ast_channel_callid_set(c, callid);
+               callid = ast_callid_unref(callid);
+       }
+
        ast_channel_pbx_set(c, pbx);
        /* Set reasonable defaults */
        ast_channel_pbx(c)->rtimeoutms = 10000;
@@ -5489,11 +5503,6 @@ static void *pbx_thread(void *data)
         */
        struct ast_channel *c = data;
 
-       /* Associate new PBX thread with a call-id */
-       struct ast_callid *callid = ast_create_callid();
-       ast_callid_threadassoc_add(callid);
-       callid = ast_callid_unref(callid);
-
        __ast_pbx_run(c, NULL);
        decrease_call_count();
 
@@ -8953,9 +8962,13 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c
 {
        struct ast_channel *chan;
        struct async_stat *as;
+       struct ast_callid *callid;
+       int callid_created = 0;
        int res = -1, cdr_res = -1;
        struct outgoing_helper oh;
 
+       callid_created = ast_callid_threadstorage_auto(&callid);
+
        if (synchronous) {
                oh.context = context;
                oh.exten = exten;
@@ -8973,6 +8986,16 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c
                                ast_channel_lock(chan);
                }
                if (chan) {
+                       /* Bind the callid to the channel if it doesn't already have one on creation */
+                       struct ast_callid *channel_callid = ast_channel_callid(chan);
+                       if (channel_callid) {
+                               ast_callid_unref(channel_callid);
+                       } else {
+                               if (callid) {
+                                       ast_channel_callid_set(chan, callid);
+                               }
+                       }
+
                        if (ast_channel_state(chan) == AST_STATE_UP) {
                                        res = 0;
                                ast_verb(4, "Channel %s was answered.\n", ast_channel_name(chan));
@@ -9052,6 +9075,7 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c
                        }
                }
        } else {
+               struct ast_callid *channel_callid;
                if (!(as = ast_calloc(1, sizeof(*as)))) {
                        res = -1;
                        goto outgoing_exten_cleanup;
@@ -9067,6 +9091,17 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c
                        res = -1;
                        goto outgoing_exten_cleanup;
                }
+
+               /* Bind the newly created callid to the channel if it doesn't already have one on creation. */
+               channel_callid = ast_channel_callid(chan);
+               if (channel_callid) {
+                       ast_callid_unref(channel_callid);
+               } else {
+                       if (callid) {
+                               ast_channel_callid_set(chan, callid);
+                       }
+               }
+
                as->chan = chan;
                ast_copy_string(as->context, context, sizeof(as->context));
                set_ext_pri(as->chan,  exten, priority);
@@ -9087,7 +9122,9 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c
                }
                res = 0;
        }
+
 outgoing_exten_cleanup:
+       ast_callid_threadstorage_auto_clean(callid, callid_created);
        ast_variables_destroy(vars);
        return res;
 }
@@ -9122,9 +9159,14 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha
 {
        struct ast_channel *chan;
        struct app_tmp *tmp;
+       struct ast_callid *callid;
+       int callid_created;
        int res = -1, cdr_res = -1;
        struct outgoing_helper oh;
 
+       /* Start by checking for a callid in threadstorage, and if none is found, bind one. */
+       callid_created = ast_callid_threadstorage_auto(&callid);
+
        memset(&oh, 0, sizeof(oh));
        oh.vars = vars;
        oh.account = account;
@@ -9138,6 +9180,16 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha
        if (synchronous) {
                chan = __ast_request_and_dial(type, cap, NULL, addr, timeout, reason, cid_num, cid_name, &oh);
                if (chan) {
+                       /* Bind the newly created callid to the channel if it doesn't already have one on creation */
+                       struct ast_callid *channel_callid = ast_channel_callid(chan);
+                       if (channel_callid) {
+                               ast_callid_unref(channel_callid);
+                       } else {
+                               if (callid) {
+                                       ast_channel_callid_set(chan, callid);
+                               }
+                       }
+
                        ast_set_variables(chan, vars);
                        if (account)
                                ast_cdr_setaccount(chan, account);
@@ -9200,6 +9252,7 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha
 
        } else {
                struct async_stat *as;
+               struct ast_callid *channel_callid;
                if (!(as = ast_calloc(1, sizeof(*as)))) {
                        res = -1;
                        goto outgoing_app_cleanup;
@@ -9210,6 +9263,17 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha
                        res = -1;
                        goto outgoing_app_cleanup;
                }
+
+               /* Bind the newly created callid to the channel if it doesn't already have one on creation. */
+               channel_callid = ast_channel_callid(chan);
+               if (channel_callid) {
+                       ast_callid_unref(channel_callid);
+               } else {
+                       if (callid) {
+                               ast_channel_callid_set(chan, callid);
+                       }
+               }
+
                as->chan = chan;
                ast_copy_string(as->app, app, sizeof(as->app));
                if (appdata)
@@ -9235,7 +9299,9 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha
                }
                res = 0;
        }
+
 outgoing_app_cleanup:
+       ast_callid_threadstorage_auto_clean(callid, callid_created);
        ast_variables_destroy(vars);
        return res;
 }