summaryrefslogtreecommitdiff
path: root/res/res_pjsip_session.c
diff options
context:
space:
mode:
Diffstat (limited to 'res/res_pjsip_session.c')
-rw-r--r--res/res_pjsip_session.c60
1 files changed, 52 insertions, 8 deletions
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index d659684b9..4634ff7e5 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -186,6 +186,26 @@ void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *
ao2_callback_data(sdp_handlers, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, remove_handler, (void *)stream_type, handler);
}
+/*!
+ * \brief Set an SDP stream handler for a corresponding session media.
+ *
+ * \note Always use this function to set the SDP handler for a session media.
+ *
+ * This function will properly free resources on the SDP handler currently being
+ * used by the session media, then set the session media to use the new SDP
+ * handler.
+ */
+static void session_media_set_handler(struct ast_sip_session_media *session_media,
+ struct ast_sip_session_sdp_handler *handler)
+{
+ ast_assert(session_media->handler != handler);
+
+ if (session_media->handler) {
+ session_media->handler->stream_destroy(session_media);
+ }
+ session_media->handler = handler;
+}
+
static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
{
int i;
@@ -235,6 +255,9 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd
continue;
}
AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+ if (handler == session_media->handler) {
+ continue;
+ }
ast_debug(1, "Negotiating incoming SDP media stream '%s' using %s SDP handler\n",
session_media->stream_type,
handler->id);
@@ -249,7 +272,7 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd
session_media->stream_type,
handler->id);
/* Handled by this handler. Move to the next stream */
- session_media->handler = handler;
+ session_media_set_handler(session_media, handler);
handled = 1;
break;
}
@@ -317,6 +340,9 @@ static int handle_negotiated_sdp_session_media(void *obj, void *arg, int flags)
continue;
}
AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+ if (handler == session_media->handler) {
+ continue;
+ }
ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n",
session_media->stream_type,
handler->id);
@@ -331,7 +357,7 @@ static int handle_negotiated_sdp_session_media(void *obj, void *arg, int flags)
session_media->stream_type,
handler->id);
/* Handled by this handler. Move to the next stream */
- session_media->handler = handler;
+ session_media_set_handler(session_media, handler);
return CMP_MATCH;
}
}
@@ -744,6 +770,9 @@ static int sdp_requires_deferral(struct ast_sip_session *session, const pjmedia_
continue;
}
AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+ if (handler == session_media->handler) {
+ continue;
+ }
if (!handler->defer_incoming_sdp_stream) {
continue;
}
@@ -753,15 +782,15 @@ static int sdp_requires_deferral(struct ast_sip_session *session, const pjmedia_
case AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED:
continue;
case AST_SIP_SESSION_SDP_DEFER_ERROR:
- session_media->handler = handler;
+ session_media_set_handler(session_media, handler);
return 0;
case AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED:
/* Handled by this handler. */
- session_media->handler = handler;
+ session_media_set_handler(session_media, handler);
break;
case AST_SIP_SESSION_SDP_DEFER_NEEDED:
/* Handled by this handler. */
- session_media->handler = handler;
+ session_media_set_handler(session_media, handler);
return 1;
}
/* Move to the next stream */
@@ -923,9 +952,21 @@ static int datastore_cmp(void *obj, void *arg, int flags)
static void session_media_dtor(void *obj)
{
struct ast_sip_session_media *session_media = obj;
- if (session_media->handler) {
- session_media->handler->stream_destroy(session_media);
+ struct sdp_handler_list *handler_list;
+ /* It is possible for SDP handlers to allocate memory on a session_media but
+ * not end up getting set as the handler for this session_media. This traversal
+ * ensures that all memory allocated by SDP handlers on the session_media is
+ * cleared (as well as file descriptors, etc.).
+ */
+ handler_list = ao2_find(sdp_handlers, session_media->stream_type, OBJ_KEY);
+ if (handler_list) {
+ struct ast_sip_session_sdp_handler *handler;
+
+ AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+ handler->stream_destroy(session_media);
+ }
}
+ ao2_cleanup(handler_list);
if (session_media->srtp) {
ast_sdp_srtp_destroy(session_media->srtp);
}
@@ -2092,6 +2133,9 @@ static int add_sdp_streams(void *obj, void *arg, void *data, int flags)
/* no handler for this stream type and we have a list to search */
AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
+ if (handler == session_media->handler) {
+ continue;
+ }
res = handler->create_outgoing_sdp_stream(session, session_media, answer);
if (res < 0) {
/* catastrophic error */
@@ -2099,7 +2143,7 @@ static int add_sdp_streams(void *obj, void *arg, void *data, int flags)
}
if (res > 0) {
/* Handled by this handler. Move to the next stream */
- session_media->handler = handler;
+ session_media_set_handler(session_media, handler);
return CMP_MATCH;
}
}