diff --git a/CHANGES b/CHANGES index ad2b96e359457745b32b57119c84c7b7f862a34d..23f8f7c0797194f54eb8976f6edc7435324c2b76 100644 --- 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) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index a85563bd770e417f18e4c61a515d64e0b82cda18..5d0cf0bdda32aaca125c320666f95fd6ae220583 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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", diff --git a/channels/sip/include/dialog.h b/channels/sip/include/dialog.h index 92834b230f6fc84938766d3b158d50ca25249bd3..ea2fb457cc35784ef9c8151e27259339086a8cbf 100644 --- a/channels/sip/include/dialog.h +++ b/channels/sip/include/dialog.h @@ -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); diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 1b257cf9555b80278426ebbe0cadfc4a765f3278..6c9cba75e0239396db904db77efa2449ea91128f 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -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 */ diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index d71b7e5121844e353c1aead46e184cd50565d13f..1a1c998857a505b471dbd2476330b0b1ea11c11d 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -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 */ diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index a495449635ebd35f7fffd4856df3c459aeabdf56..518a4f07a1ab87d01f1a35de5e567371a4c1dcd5 100644 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -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 diff --git a/main/channel.c b/main/channel.c index e46aa3a79331d9570c49a4089474a6baa1e9b140..e7bfa1d33bc6a39f3ce37a2513e5f40508e5d304 100644 --- a/main/channel.c +++ b/main/channel.c @@ -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)) { diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c index 4f89ca78869d921ba874bb7486b7f971296c0b46..5125c6f59d69013534d60aaaaf0caf4678d48877 100644 --- a/main/channel_internal_api.c +++ b/main/channel_internal_api.c @@ -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) { diff --git a/main/cli.c b/main/cli.c index 89bef80230a6f21cef4bd62cdb8959ca93c012c0..6c79c7bb2ae9cccf7ac37e9a7ac44afa1223d0a3 100644 --- a/main/cli.c +++ b/main/cli.c @@ -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)); diff --git a/main/logger.c b/main/logger.c index dcef76218386d0ba5730a42d4fc10d2134853ab0..cdced2701839c60c6c9cff05328b80b7e8b24093 100644 --- a/main/logger.c +++ b/main/logger.c @@ -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 diff --git a/main/pbx.c b/main/pbx.c index 7ea360024f853b2c41c49fe16ccb631cc69b6a2b..2860218af680c064ca9ac8deb7204229fc8d7a26 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -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; }