diff options
Diffstat (limited to 'include/asterisk/res_sip_session.h')
-rw-r--r-- | include/asterisk/res_sip_session.h | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/include/asterisk/res_sip_session.h b/include/asterisk/res_sip_session.h new file mode 100644 index 000000000..cbed52621 --- /dev/null +++ b/include/asterisk/res_sip_session.h @@ -0,0 +1,468 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2013, Digium, Inc. + * + * Mark Michelson <mmichelson@digium.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. + */ + +#ifndef _RES_SIP_SESSION_H +#define _RES_SIP_SESSION_H + +/* Needed for pj_timer_entry definition */ +#include "pjlib.h" +#include "asterisk/linkedlists.h" +/* Needed for AST_MAX_EXTENSION constant */ +#include "asterisk/channel.h" +/* Needed for ast_sockaddr struct */ +#include "asterisk/netsock.h" + +/* Forward declarations */ +struct ast_sip_endpoint; +struct ast_sip_transport; +struct pjsip_inv_session; +struct ast_channel; +struct ast_datastore; +struct ast_datastore_info; +struct ao2_container; +struct pjsip_tx_data; +struct pjsip_rx_data; +struct ast_party_id; +struct pjmedia_sdp_media; +struct pjmedia_sdp_session; +struct ast_rtp_instance; + +struct ast_sip_session_sdp_handler; + +/*! + * \brief A structure containing SIP session media information + */ +struct ast_sip_session_media { + /*! \brief RTP instance itself */ + struct ast_rtp_instance *rtp; + /*! \brief Direct media address */ + struct ast_sockaddr direct_media_addr; + /*! \brief SDP handler that setup the RTP */ + struct ast_sip_session_sdp_handler *handler; + /*! \brief Stream is on hold */ + unsigned int held:1; + /*! \brief Stream type this session media handles */ + char stream_type[1]; +}; + +/*! + * \brief Opaque structure representing a request that could not be sent + * due to an outstanding INVITE transaction + */ +struct ast_sip_session_delayed_request; + +/*! + * \brief A structure describing a SIP session + * + * For the sake of brevity, a "SIP session" in Asterisk is referring to + * a dialog initiated by an INVITE. While "session" is typically interpreted + * to refer to the negotiated media within a SIP dialog, we have opted + * to use the term "SIP session" to refer to the INVITE dialog itself. + */ +struct ast_sip_session { + /* Dialplan extension where incoming call is destined */ + char exten[AST_MAX_EXTENSION]; + /* The endpoint with which Asterisk is communicating */ + struct ast_sip_endpoint *endpoint; + /* The PJSIP details of the session, which includes the dialog */ + struct pjsip_inv_session *inv_session; + /* The Asterisk channel associated with the session */ + struct ast_channel *channel; + /* Registered session supplements */ + AST_LIST_HEAD(, ast_sip_session_supplement) supplements; + /* Datastores added to the session by supplements to the session */ + struct ao2_container *datastores; + /* Media streams */ + struct ao2_container *media; + /* Serializer for tasks relating to this SIP session */ + struct ast_taskprocessor *serializer; + /* Requests that could not be sent due to current inv_session state */ + AST_LIST_HEAD_NOLOCK(, ast_sip_session_delayed_request) delayed_requests; + /* When we need to reschedule a reinvite, we use this structure to do it */ + pj_timer_entry rescheduled_reinvite; + /* Format capabilities pertaining to direct media */ + struct ast_format_cap *direct_media_cap; + /* Identity of endpoint this session deals with */ + struct ast_party_id id; + /* Requested capabilities */ + struct ast_format_cap *req_caps; +}; + +typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata); +typedef int (*ast_sip_session_response_cb)(struct ast_sip_session *session, pjsip_rx_data *rdata); + +enum ast_sip_session_supplement_priority { + /*! Top priority. Supplements with this priority are those that need to run before any others */ + AST_SIP_SESSION_SUPPLEMENT_PRIORITY_FIRST = 0, + /*! Channel creation priority. + * chan_gulp creates a channel at this priority. If your supplement depends on being run before + * or after channel creation, then set your priority to be lower or higher than this value. + */ + AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL = 1000000, + /*! Lowest priority. Supplements with this priority should be run after all other supplements */ + AST_SIP_SESSION_SUPPLEMENT_PRIORITY_LAST = INT_MAX, +}; + +/*! + * \brief A supplement to SIP message processing + * + * These can be registered by any module in order to add + * processing to incoming and outgoing SIP requests and responses + */ +struct ast_sip_session_supplement { + /*! Method on which to call the callbacks. If NULL, call on all methods */ + const char *method; + /*! Priority for this supplement. Lower numbers are visited before higher numbers */ + enum ast_sip_session_supplement_priority priority; + /*! + * \brief Notification that the session has begun + * This method will always be called from a SIP servant thread. + */ + void (*session_begin)(struct ast_sip_session *session); + /*! + * \brief Notification that the session has ended + * + * This method may or may not be called from a SIP servant thread. Do + * not make assumptions about being able to call PJSIP methods from within + * this method. + */ + void (*session_end)(struct ast_sip_session *session); + /*! + * \brief Notification that the session is being destroyed + */ + void (*session_destroy)(struct ast_sip_session *session); + /*! + * \brief Called on incoming SIP request + * This method can indicate a failure in processing in its return. If there + * is a failure, it is required that this method sends a response to the request. + * This method is always called from a SIP servant thread. + * + * \note + * The following PJSIP methods will not work properly: + * pjsip_rdata_get_dlg() + * pjsip_rdata_get_tsx() + * The reason is that the rdata passed into this function is a cloned rdata structure, + * and its module data is not copied during the cloning operation. + * If you need to get the dialog, you can get it via session->inv_session->dlg. + */ + int (*incoming_request)(struct ast_sip_session *session, struct pjsip_rx_data *rdata); + /*! + * \brief Called on an incoming SIP response + * This method is always called from a SIP servant thread. + * + * \note + * The following PJSIP methods will not work properly: + * pjsip_rdata_get_dlg() + * pjsip_rdata_get_tsx() + * The reason is that the rdata passed into this function is a cloned rdata structure, + * and its module data is not copied during the cloning operation. + * If you need to get the dialog, you can get it via session->inv_session->dlg. + */ + void (*incoming_response)(struct ast_sip_session *session, struct pjsip_rx_data *rdata); + /*! + * \brief Called on an outgoing SIP request + * This method is always called from a SIP servant thread. + */ + void (*outgoing_request)(struct ast_sip_session *session, struct pjsip_tx_data *tdata); + /*! + * \brief Called on an outgoing SIP response + * This method is always called from a SIP servant thread. + */ + void (*outgoing_response)(struct ast_sip_session *session, struct pjsip_tx_data *tdata); + /*! Next item in the list */ + AST_LIST_ENTRY(ast_sip_session_supplement) next; +}; + +/*! + * \brief A handler for SDPs in SIP sessions + * + * An SDP handler is registered by a module that is interested in being the + * responsible party for specific types of SDP streams. + */ +struct ast_sip_session_sdp_handler { + /*! An identifier for this handler */ + const char *id; + /*! + * \brief Set session details based on a stream in an incoming SDP offer or answer + * \param session The session for which the media is being negotiated + * \param session_media The media to be setup for this session + * \param sdp The entire SDP. Useful for getting "global" information, such as connections or attributes + * \param stream The stream on which to operate + * \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called. + * \retval <0 There was an error encountered. No further operation will take place and the current negotiation will be abandoned. + * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called. + */ + int (*negotiate_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream); + /*! + * \brief Create an SDP media stream and add it to the outgoing SDP offer or answer + * \param session The session for which media is being added + * \param session_media The media to be setup for this session + * \param stream The stream on which to operate + * \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called. + * \retval <0 There was an error encountered. No further operation will take place and the current negotiation will be abandoned. + * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called. + */ + int (*handle_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, struct pjmedia_sdp_media *stream); + /*! + * \brief Create an SDP media stream and add it to the outgoing SDP offer or answer + * \param session The session for which media is being added + * \param session_media The media to be setup for this session + * \param sdp The entire SDP as currently built + * \retval 0 This handler has no stream to add. If there are other registered handlers for this stream type, they will be called. + * \retval <0 There was an error encountered. No further operation will take place and the current SDP negotiation will be abandoned. + * \retval >0 The handler has a stream to be added to the SDP. No further handler of this stream type will be called. + */ + int (*create_outgoing_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp); + /*! + * \brief Update media stream with external address if applicable + * \param tdata The outgoing message itself + * \param stream The stream on which to operate + * \param transport The transport the SDP is going out on + */ + void (*change_outgoing_sdp_stream_media_address)(struct pjsip_tx_data *tdata, struct pjmedia_sdp_media *stream, struct ast_sip_transport *transport); + /*! + * \brief Apply a negotiated SDP media stream + * \param session The session for which media is being applied + * \param session_media The media to be setup for this session + * \param local The entire local negotiated SDP + * \param local_stream The local stream which to apply + * \param remote The entire remote negotiated SDP + * \param remote_stream The remote stream which to apply + * \retval 0 The stream was not applied by this handler. If there are other registered handlers for this stream type, they will be called. + * \retval <0 There was an error encountered. No further operation will take place and the current application will be abandoned. + * \retval >0 The stream was handled by this handler. No further handler of this stream type will be called. + */ + int (*apply_negotiated_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream, + const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream); + /*! + * \brief Destroy a session_media created by this handler + * \param session The session for which media is being destroyed + * \param session_media The media to destroy + */ + void (*stream_destroy)(struct ast_sip_session_media *session_media); + /*! Next item in the list. */ + AST_LIST_ENTRY(ast_sip_session_sdp_handler) next; +}; + +/*! + * \brief Allocate a new SIP session + * + * This will take care of allocating the datastores container on the session as well + * as placing all registered supplements onto the session. + * + * The endpoint that is passed in will have its reference count increased by one since + * the session will be keeping a reference to the endpoint. The session will relinquish + * this reference when the session is destroyed. + * + * \param endpoint The endpoint that this session communicates with + * \param inv_session The PJSIP INVITE session data + */ +struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, pjsip_inv_session *inv); + +/*! + * \brief Create a new outgoing SIP session + * + * The endpoint that is passed in will have its reference count increased by one since + * the session will be keeping a reference to the endpoint. The session will relinquish + * this reference when the session is destroyed. + * + * \param endpoint The endpoint that this session uses for settings + * \param location Optional name of the location to call, be it named location or explicit URI + * \param request_user Optional request user to place in the request URI if permitted + * \param req_caps The requested capabilities + */ +struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint, const char *location, const char *request_user, struct ast_format_cap *req_caps); + +/*! + * \brief Register an SDP handler + * + * An SDP handler is responsible for parsing incoming SDP streams and ensuring that + * Asterisk can cope with the contents. Similarly, the SDP handler will be + * responsible for constructing outgoing SDP streams. + * + * Multiple handlers for the same stream type may be registered. They will be + * visited in the order they were registered. Handlers will be visited for each + * stream type until one claims to have handled the stream. + * + * \param handler The SDP handler to register + * \param stream_type The type of media stream for which to call the handler + * \retval 0 Success + * \retval -1 Failure + */ +int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type); + +/*! + * \brief Unregister an SDP handler + * + * \param handler The SDP handler to unregister + * \param stream_type Stream type for which the SDP handler was registered + */ +void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type); + +/*! + * \brief Register a supplement to SIP session processing + * + * This allows for someone to insert themselves in the processing of SIP + * requests and responses. This, for example could allow for a module to + * set channel data based on headers in an incoming message. Similarly, + * a module could reject an incoming request if desired. + * + * \param supplement The supplement to register + * \retval 0 Success + * \retval -1 Failure + */ +int ast_sip_session_register_supplement(struct ast_sip_session_supplement *supplement); + +/*! + * \brief Unregister a an supplement to SIP session processing + * + * \param supplement The supplement to unregister + */ +void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement); + +/*! + * \brief Alternative for ast_datastore_alloc() + * + * There are two major differences between this and ast_datastore_alloc() + * 1) This allocates a refcounted object + * 2) This will fill in a uid if one is not provided + * + * DO NOT call ast_datastore_free() on a datastore allocated in this + * way since that function will attempt to free the datastore rather + * than play nicely with its refcount. + * + * \param info Callbacks for datastore + * \param uid Identifier for datastore + * \retval NULL Failed to allocate datastore + * \retval non-NULL Newly allocated datastore + */ +struct ast_datastore *ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid); + +/*! + * \brief Add a datastore to a SIP session + * + * Note that SIP uses reference counted datastores. The datastore passed into this function + * must have been allocated using ao2_alloc() or there will be serious problems. + * + * \param session The session to add the datastore to + * \param datastore The datastore to be added to the session + * \retval 0 Success + * \retval -1 Failure + */ +int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore); + +/*! + * \brief Retrieve a session datastore + * + * The datastore retrieved will have its reference count incremented. When the caller is done + * with the datastore, the reference counted needs to be decremented using ao2_ref(). + * + * \param session The session from which to retrieve the datastore + * \param name The name of the datastore to retrieve + * \retval NULL Failed to find the specified datastore + * \retval non-NULL The specified datastore + */ +struct ast_datastore *ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name); + +/*! + * \brief Remove a session datastore from the session + * + * This operation may cause the datastore's free() callback to be called if the reference + * count reaches zero. + * + * \param session The session to remove the datastore from + * \param name The name of the datastore to remove + */ +void ast_sip_session_remove_datastore(struct ast_sip_session *session, const char *name); + +/*! + * \brief Retrieve identifying information from an incoming request + * + * This will retrieve identifying information and place it in the + * id parameter. The caller of the function can then apply this to + * caller ID, connected line, or whatever else may be proper. + * + * \param rdata The incoming request or response + * \param[out] id The collected identity information + * \retval 0 Successfully found identifying information + * \retval -1 Identifying information could not be found + */ +int ast_sip_session_get_identity(struct pjsip_rx_data *rdata, struct ast_party_id *id); + +/*! + * \brief Send a reinvite or UPDATE on a session + * + * This method will inspect the session in order to construct an appropriate + * session refresh request. As with any outgoing request in res_sip_session, + * this will call into registered supplements in case they wish to add anything. + * + * Note: The on_request_creation callback may or may not be called in the same + * thread where this function is called. Request creation may need to be delayed + * due to the current INVITE transaction state. + * + * \param session The session on which the reinvite will be sent + * \param on_request_creation Callback called when request is created + * \param on_response Callback called when response for request is received + * \param method The method that should be used when constructing the session refresh + * \param generate_new_sdp Boolean to indicate if a new SDP should be created + * \retval 0 Successfully sent refresh + * \retval -1 Failure to send refresh + */ +int ast_sip_session_refresh(struct ast_sip_session *session, + ast_sip_session_request_creation_cb on_request_creation, + ast_sip_session_response_cb on_response, + enum ast_sip_session_refresh_method method, + int generate_new_sdp); + +/*! + * \brief Send a SIP response + * + * This will send the SIP response specified in tdata and + * call into any registered supplements' outgoing_response callback. + * + * \param session The session on which to send the response. + * \param tdata The response to send + */ +void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata); + +/*! + * \brief Send a SIP request + * + * This will send the SIP request specified in tdata and + * call into any registered supplements' outgoing_request callback. + * + * \param session The session to which to send the request + * \param tdata The request to send + */ +void ast_sip_session_send_request(struct ast_sip_session *session, pjsip_tx_data *tdata); + +/*! + * \brief Send a SIP request and get called back when a response is received + * + * This will send the request out exactly the same as ast_sip_send_request() does. + * The difference is that when a response arrives, the specified callback will be + * called into + * + * \param session The session on which to send the request + * \param tdata The request to send + * \param on_response Callback to be called when a response is received + */ +void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata, + ast_sip_session_response_cb on_response); + +#endif /* _RES_SIP_SESSION_H */ |