[asterisk-commits] file: branch file/gulp_fax r394436 - in /team/file/gulp_fax: channels/ includ...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Jul 16 08:37:48 CDT 2013
Author: file
Date: Tue Jul 16 08:37:45 2013
New Revision: 394436
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=394436
Log:
Add current progress!
1. It's now possible for an SDP handler to request that a re-invite be suspended and resumed at a later time. This is preliminary code.
2. chan_gulp will now react to T.38 actions as expected (indicate / queryoption)
3. Incoming T.38 re-invites are now rejected as expected
With all of this I've got the signaling going correctly and UDPTL flowing.
Modified:
team/file/gulp_fax/channels/chan_gulp.c
team/file/gulp_fax/include/asterisk/res_sip_session.h
team/file/gulp_fax/res/res_sip_session.c
team/file/gulp_fax/res/res_sip_session.exports.in
team/file/gulp_fax/res/res_sip_t38.c
Modified: team/file/gulp_fax/channels/chan_gulp.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/channels/chan_gulp.c?view=diff&rev=394436&r1=394435&r2=394436
==============================================================================
--- team/file/gulp_fax/channels/chan_gulp.c (original)
+++ team/file/gulp_fax/channels/chan_gulp.c Tue Jul 16 08:37:45 2013
@@ -788,6 +788,8 @@
res = ast_rtp_instance_write(media->rtp, frame);
}
break;
+ case AST_FRAME_MODEM:
+ break;
default:
ast_log(LOG_WARNING, "Can't send %d type frames with Gulp\n", frame->frametype);
break;
@@ -907,10 +909,29 @@
struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
struct ast_sip_session *session = pvt->session;
int res = -1;
+ enum ast_sip_session_t38state state = T38_STATE_UNAVAILABLE;
switch (option) {
case AST_OPTION_T38_STATE:
- *((enum ast_t38_state *) data) = session->endpoint->t38udptl ? T38_STATE_UNKNOWN : T38_STATE_UNAVAILABLE;
+ if (session->endpoint->t38udptl) {
+ switch (session->t38state) {
+ case T38_LOCAL_REINVITE:
+ case T38_PEER_REINVITE:
+ state = T38_STATE_NEGOTIATING;
+ break;
+ case T38_ENABLED:
+ state = T38_STATE_NEGOTIATED;
+ break;
+ case T38_REJECTED:
+ state = T38_STATE_REJECTED;
+ break;
+ default:
+ state = T38_STATE_UNKNOWN;
+ break;
+ }
+ }
+
+ *((enum ast_t38_state *) data) = state;
res = 0;
break;
@@ -1142,6 +1163,18 @@
} else {
res = -1;
}
+ break;
+ case AST_CONTROL_T38_PARAMETERS:
+ res = 0;
+
+ if (session->t38state == T38_PEER_REINVITE) {
+ const struct ast_control_t38_parameters *parameters = data;
+
+ if (parameters->request_response == AST_T38_REQUEST_PARMS) {
+ res = AST_T38_REQUEST_PARMS;
+ }
+ }
+
break;
case -1:
res = -1;
Modified: team/file/gulp_fax/include/asterisk/res_sip_session.h
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/include/asterisk/res_sip_session.h?view=diff&rev=394436&r1=394435&r2=394436
==============================================================================
--- team/file/gulp_fax/include/asterisk/res_sip_session.h (original)
+++ team/file/gulp_fax/include/asterisk/res_sip_session.h Tue Jul 16 08:37:45 2013
@@ -45,6 +45,15 @@
struct ast_rtp_instance;
struct ast_dsp;
struct ast_udptl;
+
+/*! \brief T.38 states for a session */
+enum ast_sip_session_t38state {
+ T38_DISABLED = 0, /*!< Not enabled */
+ T38_LOCAL_REINVITE, /*!< Offered from local - REINVITE */
+ T38_PEER_REINVITE, /*!< Offered from peer - REINVITE */
+ T38_ENABLED, /*!< Negotiated (enabled) */
+ T38_REJECTED, /*!< Refused */
+};
struct ast_sip_session_sdp_handler;
@@ -119,6 +128,10 @@
struct ast_dsp *dsp;
/* Whether the termination of the session should be deferred */
unsigned int defer_terminate:1;
+ /* Deferred incoming re-invite */
+ pjsip_rx_data *deferred_reinvite;
+ /* Current T.38 state */
+ enum ast_sip_session_t38state t38state;
};
typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);
@@ -216,6 +229,17 @@
/*! An identifier for this handler */
const char *id;
/*!
+ * \brief Defer re-invited stream
+ * \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 not handled by this handler. If there are other registered handlers for this stream type, they will be called.
+ * \retval <0 Re-invite should be deferred. No further operation will take place.
+ * \retval >0 The stream was explicitly not deferred by this handler. No further handler of this stream type will be called.
+ * \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);
+ /*!
* \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
@@ -512,4 +536,13 @@
*/
struct ast_sip_session *ast_sip_dialog_get_session(pjsip_dialog *dlg);
+/*!
+ * \brief Resumes processing of a deferred incoming re-invite
+ *
+ * \param session The session which has a pending incoming re-invite
+ *
+ * \note It is possible for the defer_incoming_sdp_stream callback to be called yet again when this is invoked
+ */
+void ast_sip_session_resume_reinvite(struct ast_sip_session *session);
+
#endif /* _RES_SIP_SESSION_H */
Modified: team/file/gulp_fax/res/res_sip_session.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/res/res_sip_session.c?view=diff&rev=394436&r1=394435&r2=394436
==============================================================================
--- team/file/gulp_fax/res/res_sip_session.c (original)
+++ team/file/gulp_fax/res/res_sip_session.c Tue Jul 16 08:37:45 2013
@@ -787,6 +787,121 @@
.start = session_start,
.stop = session_stop,
.on_rx_request = session_on_rx_request,
+};
+
+static int handle_deferring_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
+{
+ int i;
+ if (validate_incoming_sdp(sdp)) {
+ return -1;
+ }
+
+ for (i = 0; i < sdp->media_count; ++i) {
+ /* See if there are registered handlers for this media stream type */
+ char media[20];
+ 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);
+
+ /* We need a null-terminated version of the media string */
+ ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
+
+ session_media = ao2_find(session->media, media, OBJ_KEY);
+ if (!session_media) {
+ /* if the session_media doesn't exist, there weren't
+ * any handlers at the time of its creation */
+ continue;
+ }
+
+ if (session_media->handler && session_media->handler->defer_incoming_sdp_stream) {
+ int res;
+ handler = session_media->handler;
+ res = handler->defer_incoming_sdp_stream(
+ session, session_media, sdp, sdp->media[i]);
+ if (res <= 0) {
+ return 1;
+ }
+ if (res > 0) {
+ /* Handled by this handler. Move to the next stream */
+ continue;
+ }
+ }
+
+ handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
+ if (!handler_list) {
+ ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
+ 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 < 0) {
+ return 1;
+ }
+ if (res > 0) {
+ /* Handled by this handler. Move to the next stream */
+ session_media->handler = handler;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static pj_bool_t session_reinvite_on_rx_request(pjsip_rx_data *rdata)
+{
+ pjsip_dialog *dlg;
+ pjsip_inv_session *inv_session;
+ struct ast_sip_session *session;
+ pjsip_rdata_sdp_info *sdp_info;
+
+ if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD ||
+ !(dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag, PJ_FALSE)) ||
+ !(inv_session = pjsip_dlg_get_inv_session(dlg)) ||
+ !(session = inv_session->mod_data[session_module.id])) {
+ return PJ_FALSE;
+ }
+
+ /* XXX Reject new re-invite if deferred exists and not a retransmission */
+ if (session->deferred_reinvite) {
+ return PJ_TRUE;
+ }
+
+ if (!(sdp_info = pjsip_rdata_get_sdp_info(rdata)) ||
+ (sdp_info->sdp_err != PJ_SUCCESS) ||
+ !sdp_info->sdp ||
+ !handle_deferring_sdp(session, sdp_info->sdp)) {
+ return PJ_FALSE;
+ }
+
+ pjsip_rx_data_clone(rdata, 0, &session->deferred_reinvite);
+
+ return PJ_TRUE;
+}
+
+void ast_sip_session_resume_reinvite(struct ast_sip_session *session)
+{
+ if (!session->deferred_reinvite) {
+ return;
+ }
+
+ pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(), session->deferred_reinvite, NULL, NULL);
+ pjsip_rx_data_free_cloned(session->deferred_reinvite);
+ session->deferred_reinvite = NULL;
+}
+
+static pjsip_module session_reinvite_module = {
+ .name = { "Session Re-Invite Module", 24 },
+ .priority = PJSIP_MOD_PRIORITY_UA_PROXY_LAYER - 1,
+ .on_rx_request = session_reinvite_on_rx_request,
};
void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata,
@@ -1929,12 +2044,14 @@
if (ast_sip_register_service(&session_module)) {
return AST_MODULE_LOAD_DECLINE;
}
+ ast_sip_register_service(&session_reinvite_module);
return AST_MODULE_LOAD_SUCCESS;
}
static int unload_module(void)
{
ast_sip_unregister_service(&session_module);
+ ast_sip_unregister_service(&session_reinvite_module);
if (nat_hook) {
ast_sorcery_delete(ast_sip_get_sorcery(), nat_hook);
nat_hook = NULL;
Modified: team/file/gulp_fax/res/res_sip_session.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/res/res_sip_session.exports.in?view=diff&rev=394436&r1=394435&r2=394436
==============================================================================
--- team/file/gulp_fax/res/res_sip_session.exports.in (original)
+++ team/file/gulp_fax/res/res_sip_session.exports.in Tue Jul 16 08:37:45 2013
@@ -16,6 +16,7 @@
LINKER_SYMBOL_PREFIXast_sip_session_create_invite;
LINKER_SYMBOL_PREFIXast_sip_session_create_outgoing;
LINKER_SYMBOL_PREFIXast_sip_dialog_get_session;
+ LINKER_SYMBOL_PREFIXast_sip_session_resume_reinvite;
local:
*;
};
Modified: team/file/gulp_fax/res/res_sip_t38.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/res/res_sip_t38.c?view=diff&rev=394436&r1=394435&r2=394436
==============================================================================
--- team/file/gulp_fax/res/res_sip_t38.c (original)
+++ team/file/gulp_fax/res/res_sip_t38.c Tue Jul 16 08:37:45 2013
@@ -70,19 +70,10 @@
/*! \brief Address for IPv4 UDPTL */
static struct ast_sockaddr address_ipv4;
-/*! \brief T.38 states for a session */
-enum t38state {
- T38_DISABLED = 0, /*!< Not enabled */
- T38_LOCAL_REINVITE, /*!< Offered from local - REINVITE */
- T38_PEER_REINVITE, /*!< Offered from peer - REINVITE */
- T38_ENABLED, /*!< Negotiated (enabled) */
- T38_REJECTED /*!< Refused */
-};
-
/*! \brief T.38 state information */
struct t38_state {
/*! \brief Current state */
- enum t38state state;
+ enum ast_sip_session_t38state state;
/*! \brief Our T.38 parameters */
struct ast_control_t38_parameters our_parms;
/*! \brief Their T.38 parameters */
@@ -133,7 +124,11 @@
data->session = session;
ao2_ref(session, +1);
- data->frame = frame;
+
+ if (!(data->frame = ast_frdup(frame))) {
+ ao2_cleanup(data);
+ return NULL;
+ }
return data;
}
@@ -159,16 +154,16 @@
/*! \brief Helper function for changing the T.38 state */
static void t38_change_state(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
- struct t38_state *state, enum t38state new_state)
-{
- enum t38state old_state = state->state;
+ struct t38_state *state, enum ast_sip_session_t38state new_state)
+{
+ enum ast_sip_session_t38state old_state = session->t38state;
struct ast_control_t38_parameters parameters = { .request_response = 0, };
if (old_state == new_state) {
return;
}
- state->state = new_state;
+ session->t38state = new_state;
ast_debug(2, "T.38 state changed to '%d' from '%d' on channel '%s'\n", new_state, old_state, ast_channel_name(session->channel));
if (!session->channel) {
@@ -242,12 +237,12 @@
case AST_T38_REQUEST_NEGOTIATE: /* Request T38 */
/* Negotiation can not take place without a valid max_ifp value. */
if (!parameters->max_ifp) {
- if (state->state == T38_PEER_REINVITE) {
- /* XXX Need to reject their reinvite */
- }
t38_change_state(data->session, session_media, state, T38_REJECTED);
+ if (data->session->t38state == T38_PEER_REINVITE) {
+ ast_sip_session_resume_reinvite(data->session);
+ }
break;
- } else if (state->state == T38_PEER_REINVITE) {
+ } else if (data->session->t38state == T38_PEER_REINVITE) {
state->our_parms = *parameters;
/* modify our parameters to conform to the peer's parameters,
* based on the rules in the ITU T.38 recommendation
@@ -265,8 +260,8 @@
state->our_parms.rate_management = state->their_parms.rate_management;
ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
t38_change_state(data->session, session_media, state, T38_ENABLED);
- /* XXX Need to accept their reinvite */
- } else if (state->state != T38_ENABLED) {
+ ast_sip_session_resume_reinvite(data->session);
+ } else if (data->session->t38state != T38_ENABLED) {
if (t38_initialize_session(data->session, session_media)) {
break;
}
@@ -280,17 +275,19 @@
case AST_T38_TERMINATED:
case AST_T38_REFUSED:
case AST_T38_REQUEST_TERMINATE: /* Shutdown T38 */
- if (state->state == T38_PEER_REINVITE) {
+ if (data->session->t38state == T38_PEER_REINVITE) {
t38_change_state(data->session, session_media, state, T38_REJECTED);
- /* XXX Need to reject their reinvite */
- } else if (state->state == T38_ENABLED) {
- /* XXX Need to send reinvite */
+ ast_sip_session_resume_reinvite(data->session);
+ } else if (data->session->t38state == T38_ENABLED) {
+ /* XXX Need to unsupress other streams */
+ t38_change_state(data->session, session_media, state, T38_DISABLED);
+ ast_sip_session_refresh(data->session, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
}
break;
case AST_T38_REQUEST_PARMS: { /* Application wants remote's parameters re-sent */
struct ast_control_t38_parameters parameters = state->their_parms;
- if (state->state == T38_PEER_REINVITE) {
+ if (data->session->t38state == T38_PEER_REINVITE) {
parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters));
@@ -314,9 +311,6 @@
if (!data) {
return f;
}
-
- /* The frame is now on the task data structure */
- f = &ast_null_frame;
if (ast_sip_push_task(session->serializer, t38_interpret_parameters, data)) {
ao2_ref(data, -1);
@@ -423,33 +417,23 @@
.outgoing_request = t38_outgoing_invite_request,
};
-/*! \brief Function which negotiates an incoming media stream */
-static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+/*! \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)
{
- char host[NI_MAXHOST];
- RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
struct t38_state *state;
unsigned int attr_i;
if (!session->endpoint->t38udptl) {
- return -1;
- }
-
- ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
-
- /* Ensure that the address provided is valid */
- if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) {
- /* The provided host was actually invalid so we error out this negotiation */
- return -1;
+ return 1;
}
if (t38_initialize_session(session, session_media)) {
- return -1;
+ return 1;
}
if (!(state = t38_state_get_or_alloc(session))) {
- return 0;
+ return 1;
}
for (attr_i = 0; attr_i < stream->attr_count; attr_i++) {
@@ -510,12 +494,49 @@
}
- /* If we aren't the one who offered T.38 it is them, so change state */
- if (state->state == T38_DISABLED) {
+ /* 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 0;
+ return -1;
+ }
+
+ return 1;
+}
+
+/*! \brief Function which negotiates an incoming media stream */
+static 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)
+{
+ struct t38_state *state;
+ char host[NI_MAXHOST];
+ RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
+
+ if (!session->endpoint->t38udptl) {
+ return -1;
+ }
+
+ if (!(state = t38_state_get_or_alloc(session))) {
+ return -1;
+ }
+
+ if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
+ t38_change_state(session, session_media, state, T38_DISABLED);
+ return -1;
+ }
+
+ ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
+
+ /* Ensure that the address provided is valid */
+ if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) {
+ /* The provided host was actually invalid so we error out this negotiation */
+ return -1;
+ }
+
+ if (t38_initialize_session(session, session_media)) {
+ return -1;
+ }
+
+ return 1;
}
/*! \brief Function which creates an outgoing stream */
@@ -531,19 +552,20 @@
static const pj_str_t STR_LOCALTCF = { "localTCF", 8 };
static const pj_str_t STR_T38UDPFEC = { "t38UDPFEC", 9 };
static const pj_str_t STR_T38UDPREDUNDANCY = { "t38UDPRedundancy", 16 };
+ struct t38_state *state;
pjmedia_sdp_media *media;
char hostip[PJ_INET6_ADDRSTRLEN+2];
struct ast_sockaddr addr;
- struct t38_state *state;
char tmp[512];
pj_str_t stmp;
if (!session->endpoint->t38udptl) {
return 0;
+ } else if ((session->t38state != T38_LOCAL_REINVITE) && (session->t38state != T38_PEER_REINVITE) &&
+ (session->t38state != T38_ENABLED)) {
+ return 0;
} else if (!(state = t38_state_get_or_alloc(session))) {
- return 0;
- } else if ((state->state != T38_LOCAL_REINVITE) && (state->state != T38_PEER_REINVITE)) {
- return 0;
+ return -1;
} else if (t38_initialize_session(session, session_media)) {
return -1;
}
@@ -675,6 +697,7 @@
/*! \brief SDP handler for 'image' media stream */
static struct ast_sip_session_sdp_handler image_sdp_handler = {
.id = "image",
+ .defer_incoming_sdp_stream = defer_incoming_sdp_stream,
.negotiate_incoming_sdp_stream = negotiate_incoming_sdp_stream,
.create_outgoing_sdp_stream = create_outgoing_sdp_stream,
.apply_negotiated_sdp_stream = apply_negotiated_sdp_stream,
More information about the asterisk-commits
mailing list