AST_LIST_ENTRY(ast_sip_session_supplement) next;
};
+enum ast_sip_session_sdp_stream_defer {
+ /*! The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called. */
+ AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED,
+ /*! There was an error encountered. No further operations will take place and the current negotiation will be abandoned. */
+ AST_SIP_SESSION_SDP_DEFER_ERROR,
+ /*! Re-invite is not needed */
+ AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED,
+ /*! Re-invite should be deferred and will be resumed later. No further operations will take place. */
+ AST_SIP_SESSION_SDP_DEFER_NEEDED,
+};
+
/*!
* \brief A handler for SDPs in SIP sessions
*
* If a stream can not be immediately negotiated the re-invite can be deferred and
* resumed at a later time. It is up to the handler which caused deferral to occur
* to resume it.
+ *
* \param session The session for which the media is being re-invited
* \param session_media The media being reinvited
- * \param sdp The entire SDP.
- * \retval 0 The stream was unhandled or does not need the re-invite to be deferred.
- * \retval 1 Re-invite should be deferred and will be resumed later. No further operations will take place.
+ * \param sdp The entire SDP. Useful for getting "global" information, such as connections or attributes
+ * \param stream PJSIP incoming SDP media lines to parse by handler.
+ *
+ * \return enum ast_sip_session_defer_stream
+ *
* \note This is optional, if not implemented the stream is assumed to not be deferred.
*/
- int (*defer_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);
+ enum ast_sip_session_sdp_stream_defer (*defer_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 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
static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
{
int i;
+
if (validate_incoming_sdp(sdp)) {
return -1;
}
struct ast_sip_session_sdp_handler *handler;
RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
+ int res;
/* We need a null-terminated version of the media string */
ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
}
if (session_media->handler) {
- int res;
handler = session_media->handler;
- res = handler->negotiate_incoming_sdp_stream(
- session, session_media, sdp, sdp->media[i]);
+ res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp,
+ sdp->media[i]);
if (res <= 0) {
/* Catastrophic failure or ignored by assigned handler. Abort! */
return -1;
}
- if (res > 0) {
- /* Handled by this handler. Move to the next stream */
- continue;
- }
+ /* Handled by this handler. Move to the next stream */
+ continue;
}
handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
continue;
}
AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
- int res;
- if (session_media->handler) {
- /* There is only one slot for this stream type and it has already been claimed
- * so it will go unhandled */
- break;
- }
- res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, sdp->media[i]);
+ res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp,
+ sdp->media[i]);
if (res < 0) {
/* Catastrophic failure. Abort! */
return -1;
char media[20];
struct ast_sip_session_sdp_handler *handler;
RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
+ int res;
if (!remote->media[i]) {
continue;
handler = session_media->handler;
if (handler) {
- int res = handler->apply_negotiated_sdp_stream(session, session_media, local, local->media[i], remote, remote->media[i]);
+ res = handler->apply_negotiated_sdp_stream(session, session_media, local,
+ local->media[i], remote, remote->media[i]);
if (res >= 0) {
return CMP_MATCH;
}
continue;
}
AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
- int res = handler->apply_negotiated_sdp_stream(session, session_media, local, local->media[i], remote, remote->media[i]);
+ res = handler->apply_negotiated_sdp_stream(session, session_media, local,
+ local->media[i], remote, remote->media[i]);
if (res < 0) {
/* Catastrophic failure. Abort! */
return 0;
static int sdp_requires_deferral(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
{
int i;
+
if (validate_incoming_sdp(sdp)) {
return 0;
}
struct ast_sip_session_sdp_handler *handler;
RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
+ enum ast_sip_session_sdp_stream_defer res;
/* We need a null-terminated version of the media string */
ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
continue;
}
- if (session_media->handler && session_media->handler->defer_incoming_sdp_stream) {
- int res;
+ if (session_media->handler) {
handler = session_media->handler;
- res = handler->defer_incoming_sdp_stream(
- session, session_media, sdp, sdp->media[i]);
- if (res) {
- return 1;
+ if (handler->defer_incoming_sdp_stream) {
+ res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
+ sdp->media[i]);
+ switch (res) {
+ case AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED:
+ break;
+ case AST_SIP_SESSION_SDP_DEFER_ERROR:
+ return 0;
+ case AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED:
+ break;
+ case AST_SIP_SESSION_SDP_DEFER_NEEDED:
+ return 1;
+ }
}
+ /* Handled by this handler. Move to the next stream */
+ continue;
}
handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
continue;
}
AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
- int res;
- if (session_media->handler) {
- /* There is only one slot for this stream type and it has already been claimed
- * so it will go unhandled */
- break;
- }
if (!handler->defer_incoming_sdp_stream) {
continue;
}
- res = handler->defer_incoming_sdp_stream(session, session_media, sdp, sdp->media[i]);
- if (res) {
+ res = handler->defer_incoming_sdp_stream(session, session_media, sdp,
+ sdp->media[i]);
+ switch (res) {
+ case AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED:
+ continue;
+ case AST_SIP_SESSION_SDP_DEFER_ERROR:
+ session_media->handler = handler;
+ return 0;
+ case AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED:
+ /* Handled by this handler. */
+ session_media->handler = handler;
+ break;
+ case AST_SIP_SESSION_SDP_DEFER_NEEDED:
+ /* Handled by this handler. */
+ session_media->handler = handler;
return 1;
}
+ /* Move to the next stream */
+ break;
}
}
return 0;
struct ast_sip_session *session = data;
struct ast_sip_session_sdp_handler *handler = session_media->handler;
RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);
+ int res;
if (handler) {
/* if an already assigned handler does not handle the session_media or reports a catastrophic error, fail */
- if (handler->create_outgoing_sdp_stream(session, session_media, answer) <= 0) {
+ res = handler->create_outgoing_sdp_stream(session, session_media, answer);
+ if (res <= 0) {
return 0;
}
return CMP_MATCH;
/* no handler for this stream type and we have a list to search */
AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
- int res = handler->create_outgoing_sdp_stream(session, session_media, answer);
+ res = handler->create_outgoing_sdp_stream(session, session_media, answer);
if (res < 0) {
/* catastrophic error */
return 0;
}
if (res > 0) {
- /* handled */
+ /* Handled by this handler. Move to the next stream */
+ session_media->handler = handler;
return CMP_MATCH;
}
}
}
/*! \brief Function which defers an incoming media stream */
-static int defer_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)
+static enum ast_sip_session_sdp_stream_defer defer_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)
{
struct t38_state *state;
if (!session->endpoint->media.t38.enabled) {
- return 0;
+ return AST_SIP_SESSION_SDP_DEFER_NOT_HANDLED;
}
if (t38_initialize_session(session, session_media)) {
- return 0;
+ return AST_SIP_SESSION_SDP_DEFER_ERROR;
}
if (!(state = t38_state_get_or_alloc(session))) {
- return 0;
+ return AST_SIP_SESSION_SDP_DEFER_ERROR;
}
t38_interpret_sdp(state, session, session_media, stream);
/* If they are initiating the re-invite we need to defer responding until later */
if (session->t38state == T38_DISABLED) {
t38_change_state(session, session_media, state, T38_PEER_REINVITE);
- return 1;
+ return AST_SIP_SESSION_SDP_DEFER_NEEDED;
}
- return 0;
+ return AST_SIP_SESSION_SDP_DEFER_NOT_NEEDED;
}
/*! \brief Function which negotiates an incoming media stream */