mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-02 19:16:15 +00:00
core/ari/pjsip: Add refer mechanism
This change adds support for refers that are not session based. It includes a refer implementation for the PJSIP technology which results in out-of-dialog REFERs being sent to a PJSIP endpoint. These can be triggered using the new ARI endpoint `/endpoints/refer`. Resolves: #71 UserNote: There is a new ARI endpoint `/endpoints/refer` for referring an endpoint to some URI or endpoint.
This commit is contained in:
committed by
asterisk-org-access-app[bot]
parent
d16046e41f
commit
51a7b18038
@@ -57,6 +57,7 @@ int ast_msg_init(void); /*!< Provided by message.c */
|
||||
void ast_msg_shutdown(void); /*!< Provided by message.c */
|
||||
int aco_init(void); /*!< Provided by config_options.c */
|
||||
int dns_core_init(void); /*!< Provided by dns_core.c */
|
||||
int ast_refer_init(void); /*!< Provided by refer.c */
|
||||
|
||||
/*!
|
||||
* \brief Initialize malloc debug phase 1.
|
||||
|
325
include/asterisk/refer.h
Normal file
325
include/asterisk/refer.h
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2023, Commend International
|
||||
*
|
||||
* Maximilian Fridrich <m.fridrich@commend.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Out-of-call refer support
|
||||
*
|
||||
* \author Maximilian Fridrich <m.fridrich@commend.com>
|
||||
*
|
||||
* The purpose of this API is to provide support for refers that
|
||||
* are not session based. The refers are passed into the Asterisk core
|
||||
* to be routed through the dialplan or another interface and potentially
|
||||
* sent back out through a refer technology that has been registered
|
||||
* through this API.
|
||||
*/
|
||||
|
||||
#ifndef __AST_REFER_H__
|
||||
#define __AST_REFER_H__
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief A refer structure.
|
||||
*
|
||||
* This is an opaque type that represents a refer.
|
||||
*/
|
||||
struct ast_refer;
|
||||
|
||||
/*!
|
||||
* \brief A refer technology
|
||||
*
|
||||
* A refer technology is capable of transmitting text refers.
|
||||
*/
|
||||
struct ast_refer_tech {
|
||||
/*!
|
||||
* \brief Name of this refer technology
|
||||
*
|
||||
* This is the name that comes at the beginning of a URI for refers
|
||||
* that should be sent to this refer technology implementation.
|
||||
* For example, refers sent to "pjsip:m.fridrich@commend.com" would be
|
||||
* passed to the ast_refer_tech with a name of "pjsip".
|
||||
*/
|
||||
const char * const name;
|
||||
/*!
|
||||
* \brief Send a refer.
|
||||
*
|
||||
* \param refer The refer to send
|
||||
*
|
||||
* The fields of the ast_refer are guaranteed not to change during the
|
||||
* duration of this function call.
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval non-zero failure
|
||||
*/
|
||||
int (* const refer_send)(const struct ast_refer *refer);
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Register a refer technology
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval non-zero failure
|
||||
*/
|
||||
int ast_refer_tech_register(const struct ast_refer_tech *tech);
|
||||
|
||||
/*!
|
||||
* \brief Unregister a refer technology.
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval non-zero failure
|
||||
*/
|
||||
int ast_refer_tech_unregister(const struct ast_refer_tech *tech);
|
||||
|
||||
/*!
|
||||
* \brief Allocate a refer.
|
||||
*
|
||||
* Allocate a refer for the purposes of passing it into the Asterisk core
|
||||
* to be routed through the dialplan. This refer must be destroyed using
|
||||
* ast_refer_destroy().
|
||||
*
|
||||
* \return A refer object. This function will return NULL if an allocation
|
||||
* error occurs.
|
||||
*/
|
||||
struct ast_refer *ast_refer_alloc(void);
|
||||
|
||||
/*!
|
||||
* \brief Destroy an ast_refer
|
||||
*
|
||||
* \retval NULL always.
|
||||
*/
|
||||
struct ast_refer *ast_refer_destroy(struct ast_refer *refer);
|
||||
|
||||
/*!
|
||||
* \brief Bump a refer's ref count
|
||||
*/
|
||||
struct ast_refer *ast_refer_ref(struct ast_refer *refer);
|
||||
|
||||
/*!
|
||||
* \brief Set the 'to' URI of a refer
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int __attribute__((format(printf, 2, 3)))
|
||||
ast_refer_set_to(struct ast_refer *refer, const char *fmt, ...);
|
||||
|
||||
/*!
|
||||
* \brief Set the 'from' URI of a refer
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int __attribute__((format(printf, 2, 3)))
|
||||
ast_refer_set_from(struct ast_refer *refer, const char *fmt, ...);
|
||||
|
||||
/*!
|
||||
* \brief Set the 'refer_to' URI of a refer
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int __attribute__((format(printf, 2, 3)))
|
||||
ast_refer_set_refer_to(struct ast_refer *refer, const char *fmt, ...);
|
||||
|
||||
/*!
|
||||
* \brief Set the 'to_self' value of a refer
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_refer_set_to_self(struct ast_refer *refer, int val);
|
||||
|
||||
/*!
|
||||
* \brief Set the technology associated with this refer
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int __attribute__((format(printf, 2, 3)))
|
||||
ast_refer_set_tech(struct ast_refer *refer, const char *fmt, ...);
|
||||
|
||||
/*!
|
||||
* \brief Set the technology's endpoint associated with this refer
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int __attribute__((format(printf, 2, 3)))
|
||||
ast_refer_set_endpoint(struct ast_refer *refer, const char *fmt, ...);
|
||||
|
||||
/*!
|
||||
* \brief Set a variable on the refer being sent to a refer tech directly.
|
||||
* \note Setting a variable that already exists overwrites the existing variable value
|
||||
*
|
||||
* \param refer
|
||||
* \param name Name of variable to set
|
||||
* \param value Value of variable to set
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_refer_set_var_outbound(struct ast_refer *refer, const char *name, const char *value);
|
||||
|
||||
/*!
|
||||
* \brief Get the specified variable on the refer and unlink it from the container of variables
|
||||
* \note The return value must be freed by the caller.
|
||||
*
|
||||
* \param refer
|
||||
* \param name Name of variable to get
|
||||
*
|
||||
* \return The value associated with variable "name". NULL if variable not found.
|
||||
*/
|
||||
char *ast_refer_get_var_and_unlink(struct ast_refer *refer, const char *name);
|
||||
|
||||
/*!
|
||||
* \brief Get the specified variable on the refer
|
||||
* \note The return value is valid only as long as the ast_refer is valid. Hold a reference
|
||||
* to the refer if you plan on storing the return value. It is possible to re-set the
|
||||
* same refer var name (with ast_refer_set_var_outbound passing the variable name)
|
||||
* while holding a pointer to the result of this function.
|
||||
*
|
||||
* \param refer
|
||||
* \param name Name of variable to get
|
||||
*
|
||||
* \return The value associated with variable "name". NULL if variable not found.
|
||||
*/
|
||||
const char *ast_refer_get_var(struct ast_refer *refer, const char *name);
|
||||
|
||||
/*!
|
||||
* \brief Get the "refer-to" value of a refer.
|
||||
* \note The return value is valid only as long as the ast_refer is valid. Hold a reference
|
||||
* to the refer if you plan on storing the return value.
|
||||
*
|
||||
* \param refer The refer to get the "refer-to" value from
|
||||
*
|
||||
* \return The "refer-to" value of the refer, encoded in UTF-8.
|
||||
*/
|
||||
const char *ast_refer_get_refer_to(const struct ast_refer *refer);
|
||||
|
||||
/*!
|
||||
* \brief Retrieve the source of this refer
|
||||
*
|
||||
* \param refer The refer to get the soure from
|
||||
*
|
||||
* \return The source of the refer
|
||||
* \retval NULL or empty string if the refer has no source
|
||||
*/
|
||||
const char *ast_refer_get_from(const struct ast_refer *refer);
|
||||
|
||||
/*!
|
||||
* \brief Retrieve the destination of this refer
|
||||
*
|
||||
* \param refer The refer to get the destination from
|
||||
*
|
||||
* \return The destination of the refer
|
||||
* \retval NULL or empty string if the refer has no destination
|
||||
*/
|
||||
const char *ast_refer_get_to(const struct ast_refer *refer);
|
||||
|
||||
/*!
|
||||
* \brief Retrieve the "to_self" value of this refer
|
||||
*
|
||||
* \param refer The refer to get the destination from
|
||||
*
|
||||
* \return The to_self value of the refer
|
||||
*/
|
||||
int ast_refer_get_to_self(const struct ast_refer *refer);
|
||||
|
||||
/*!
|
||||
* \brief Retrieve the technology associated with this refer
|
||||
*
|
||||
* \param refer The refer to get the technology from
|
||||
*
|
||||
* \return The technology of the refer
|
||||
* \retval NULL or empty string if the refer has no associated technology
|
||||
*/
|
||||
const char *ast_refer_get_tech(const struct ast_refer *refer);
|
||||
|
||||
/*!
|
||||
* \brief Retrieve the endpoint associated with this refer
|
||||
*
|
||||
* \param refer The refer to get the endpoint from
|
||||
*
|
||||
* \return The endpoint associated with the refer
|
||||
* \retval NULL or empty string if the refer has no associated endpoint
|
||||
*/
|
||||
const char *ast_refer_get_endpoint(const struct ast_refer *refer);
|
||||
|
||||
/*!
|
||||
* \brief Send a refer directly to an endpoint.
|
||||
*
|
||||
* Regardless of the return value of this function, this function will take
|
||||
* care of ensuring that the refer object is properly destroyed when needed.
|
||||
*
|
||||
* \retval 0 refer successfully queued to be sent out
|
||||
* \retval non-zero failure, refer not get sent out.
|
||||
*/
|
||||
int ast_refer_send(struct ast_refer *refer);
|
||||
|
||||
/*!
|
||||
* \brief Opaque iterator for refer variables
|
||||
*/
|
||||
struct ast_refer_var_iterator;
|
||||
|
||||
/*!
|
||||
* \brief Create a new refer variable iterator
|
||||
* \param refer A refer whose variables are to be iterated over
|
||||
*
|
||||
* \return An opaque pointer to the new iterator
|
||||
*/
|
||||
struct ast_refer_var_iterator *ast_refer_var_iterator_init(const struct ast_refer *refer);
|
||||
|
||||
/*!
|
||||
* \brief Get the next variable name and value
|
||||
*
|
||||
* \param iter An iterator created with ast_refer_var_iterator_init
|
||||
* \param name A pointer to the name result pointer
|
||||
* \param value A pointer to the value result pointer
|
||||
*
|
||||
* \note The refcount to iter->current_used must be decremented by the caller
|
||||
* by calling ast_refer_var_unref_current.
|
||||
*
|
||||
* \retval 0 No more entries
|
||||
* \retval 1 Valid entry
|
||||
*/
|
||||
int ast_refer_var_iterator_next(struct ast_refer_var_iterator *iter, const char **name, const char **value);
|
||||
|
||||
/*!
|
||||
* \brief Destroy a refer variable iterator
|
||||
* \param iter Iterator to be destroyed
|
||||
*/
|
||||
void ast_refer_var_iterator_destroy(struct ast_refer_var_iterator *iter);
|
||||
|
||||
/*!
|
||||
* \brief Unref a refer var from inside an iterator loop
|
||||
*/
|
||||
void ast_refer_var_unref_current(struct ast_refer_var_iterator *iter);
|
||||
|
||||
/*!
|
||||
* @}
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AST_REFER_H__ */
|
@@ -339,6 +339,20 @@ struct ast_sip_nat_hook {
|
||||
void (*outgoing_external_message)(struct pjsip_tx_data *tdata, struct ast_sip_transport *transport);
|
||||
};
|
||||
|
||||
/*! \brief Structure which contains information about a transport */
|
||||
struct ast_sip_request_transport_details {
|
||||
/*! \brief Type of transport */
|
||||
enum ast_transport type;
|
||||
/*! \brief Potential pointer to the transport itself, if UDP */
|
||||
pjsip_transport *transport;
|
||||
/*! \brief Potential pointer to the transport factory itself, if TCP/TLS */
|
||||
pjsip_tpfactory *factory;
|
||||
/*! \brief Local address for transport */
|
||||
pj_str_t local_address;
|
||||
/*! \brief Local port for transport */
|
||||
int local_port;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The kind of security negotiation
|
||||
*/
|
||||
@@ -3506,18 +3520,65 @@ struct ast_threadpool *ast_sip_threadpool(void);
|
||||
* \brief Retrieve transport state
|
||||
* \since 13.7.1
|
||||
*
|
||||
* @param transport_id
|
||||
* @returns transport_state
|
||||
* \param transport_id
|
||||
* \retval transport_state
|
||||
*
|
||||
* \note ao2_cleanup(...) or ao2_ref(..., -1) must be called on the returned object
|
||||
*/
|
||||
struct ast_sip_transport_state *ast_sip_get_transport_state(const char *transport_id);
|
||||
|
||||
/*!
|
||||
* \brief Return the SIP URI of the Contact header
|
||||
*
|
||||
* \param tdata
|
||||
* \retval Pointer to SIP URI of Contact
|
||||
* \retval NULL if Contact header not found or not a SIP(S) URI
|
||||
*
|
||||
* \note Do not free the returned object.
|
||||
*/
|
||||
pjsip_sip_uri *ast_sip_get_contact_sip_uri(pjsip_tx_data *tdata);
|
||||
|
||||
/*!
|
||||
* \brief Returns the transport state currently in use based on request transport details
|
||||
*
|
||||
* \param details
|
||||
* \retval transport_state
|
||||
*
|
||||
* \note ao2_cleanup(...) or ao2_ref(..., -1) must be called on the returned object
|
||||
*/
|
||||
struct ast_sip_transport_state *ast_sip_find_transport_state_in_use(struct ast_sip_request_transport_details *details);
|
||||
|
||||
/*!
|
||||
* \brief Sets request transport details based on tdata
|
||||
*
|
||||
* \param details pre-allocated request transport details to set
|
||||
* \param tdata
|
||||
* \param use_ipv6 if non-zero, ipv6 transports will be considered
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int ast_sip_set_request_transport_details(struct ast_sip_request_transport_details *details, pjsip_tx_data *tdata, int use_ipv6);
|
||||
|
||||
/*!
|
||||
* \brief Replace domain and port of SIP URI to point to (external) signaling address of this Asterisk instance
|
||||
*
|
||||
* \param uri
|
||||
* \param tdata
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*
|
||||
* \note Uses domain and port in Contact header if it exists, otherwise the local URI of the dialog is used if the
|
||||
* message is sent within the context of a dialog. Further, NAT settings are considered - i.e. if the target
|
||||
* is not in the localnet, the external_signaling_address and port are used.
|
||||
*/
|
||||
int ast_sip_rewrite_uri_to_local(pjsip_sip_uri *uri, pjsip_tx_data *tdata);
|
||||
|
||||
/*!
|
||||
* \brief Retrieves all transport states
|
||||
* \since 13.7.1
|
||||
*
|
||||
* @returns ao2_container
|
||||
* \retval ao2_container
|
||||
*
|
||||
* \note ao2_cleanup(...) or ao2_ref(..., -1) must be called on the returned object
|
||||
*/
|
||||
@@ -3647,6 +3708,105 @@ int ast_sip_set_id_from_invite(struct pjsip_rx_data *rdata, struct ast_party_id
|
||||
void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr,
|
||||
const struct ast_party_id *id);
|
||||
|
||||
/*!
|
||||
* \brief Retrieves an endpoint and URI from the "to" string.
|
||||
*
|
||||
* This URI is used as the Request URI.
|
||||
*
|
||||
* Expects the given 'to' to be in one of the following formats:
|
||||
* Why we allow so many is a mystery.
|
||||
*
|
||||
* Basic:
|
||||
*
|
||||
* endpoint : We'll get URI from the default aor/contact
|
||||
* endpoint/aor : We'll get the URI from the specific aor/contact
|
||||
* endpoint@domain : We toss the domain part and just use the endpoint
|
||||
*
|
||||
* These all use the endpoint and specified URI:
|
||||
* \verbatim
|
||||
endpoint/<sip[s]:host>
|
||||
endpoint/<sip[s]:user@host>
|
||||
endpoint/"Bob" <sip[s]:host>
|
||||
endpoint/"Bob" <sip[s]:user@host>
|
||||
endpoint/sip[s]:host
|
||||
endpoint/sip[s]:user@host
|
||||
endpoint/host
|
||||
endpoint/user@host
|
||||
\endverbatim
|
||||
*
|
||||
* These all use the default endpoint and specified URI:
|
||||
* \verbatim
|
||||
<sip[s]:host>
|
||||
<sip[s]:user@host>
|
||||
"Bob" <sip[s]:host>
|
||||
"Bob" <sip[s]:user@host>
|
||||
sip[s]:host
|
||||
sip[s]:user@host
|
||||
\endverbatim
|
||||
*
|
||||
* These use the default endpoint and specified host:
|
||||
* \verbatim
|
||||
host
|
||||
user@host
|
||||
\endverbatim
|
||||
*
|
||||
* This form is similar to a dialstring:
|
||||
* \verbatim
|
||||
PJSIP/user@endpoint
|
||||
\endverbatim
|
||||
*
|
||||
* In this case, the user will be added to the endpoint contact's URI.
|
||||
* If the contact URI already has a user, it will be replaced.
|
||||
*
|
||||
* The ones that have the sip[s] scheme are the easiest to parse.
|
||||
* The rest all have some issue.
|
||||
*
|
||||
* endpoint vs host : We have to test for endpoint first
|
||||
* endpoint/aor vs endpoint/host : We have to test for aor first
|
||||
* What if there's an aor with the same
|
||||
* name as the host?
|
||||
* endpoint@domain vs user@host : We have to test for endpoint first.
|
||||
* What if there's an endpoint with the
|
||||
* same name as the user?
|
||||
*
|
||||
* \param to 'To' field with possible endpoint
|
||||
* \param get_default_outbound If nonzero, try to retrieve the default
|
||||
* outbound endpoint if no endpoint was found.
|
||||
* Otherwise, return NULL if no endpoint was found.
|
||||
* \param uri Pointer to a char* which will be set to the URI.
|
||||
* Always must be ast_free'd by the caller - even if the return value is NULL!
|
||||
*
|
||||
* \note The logic below could probably be condensed but then it wouldn't be
|
||||
* as clear.
|
||||
*/
|
||||
struct ast_sip_endpoint *ast_sip_get_endpoint(const char *to, int get_default_outbound, char **uri);
|
||||
|
||||
/*!
|
||||
* \brief Replace the To URI in the tdata with the supplied one
|
||||
*
|
||||
* \param tdata the outbound message data structure
|
||||
* \param to URI to replace the To URI with. Must be a valid SIP URI.
|
||||
*
|
||||
* \retval 0: success, -1: failure
|
||||
*/
|
||||
int ast_sip_update_to_uri(pjsip_tx_data *tdata, const char *to);
|
||||
|
||||
/*!
|
||||
* \brief Overwrite fields in the outbound 'From' header
|
||||
*
|
||||
* The outbound 'From' header is created/added in ast_sip_create_request with
|
||||
* default data. If available that data may be info specified in the 'from_user'
|
||||
* and 'from_domain' options found on the endpoint. That information will be
|
||||
* overwritten with data in the given 'from' parameter.
|
||||
*
|
||||
* \param tdata the outbound message data structure
|
||||
* \param from info to copy into the header.
|
||||
* Can be either a SIP URI, or in the format user[@domain]
|
||||
*
|
||||
* \retval 0: success, -1: failure
|
||||
*/
|
||||
int ast_sip_update_from(pjsip_tx_data *tdata, char *from);
|
||||
|
||||
/*!
|
||||
* \brief Retrieve the unidentified request security event thresholds
|
||||
* \since 13.8.0
|
||||
|
Reference in New Issue
Block a user