aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authorfile <file@f38db490-d61c-443f-a65b-d21fe96a405b>2009-03-19 15:40:46 +0000
committerfile <file@f38db490-d61c-443f-a65b-d21fe96a405b>2009-03-19 15:40:46 +0000
commit6152898b4d06bda99265ab0883593fb3d421513a (patch)
treee7dd8a30665c0e8642b612e7152fa397288ccd3c /channels
parent582a21b8e3f75fa009294f1ad3f2f8123cc7afcf (diff)
Merged revisions 183108 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk ........ r183108 | file | 2009-03-19 12:37:23 -0300 (Thu, 19 Mar 2009) | 11 lines Improve our triggering of a T38 switchover internally when triggered by a received reinvite. Previously we reached across the channel bridge to get the other party's SIP dialog structure in order to trigger an outgoing reinvite. This is extremely dangerous to do and only works if bridged to another SIP channel. This patch changes this to use the T38 control frame method of requesting a switchover. This change also causes the SIP channel driver to propogate back whether the switchover worked or not instead of blindly accepting the incoming T38 reinvite. Review: http://reviewboard.digium.com/r/200/ ........ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.0@183109 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_sip.c215
1 files changed, 34 insertions, 181 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 221541268..daa439d62 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1282,6 +1282,7 @@ struct sip_pvt {
int initid; /*!< Auto-congest ID if appropriate (scheduler) */
int waitid; /*!< Wait ID for scheduler after 491 or other delays */
int autokillid; /*!< Auto-kill ID (scheduler) */
+ int t38id; /*!< T.38 Response ID */
enum transfermodes allowtransfer; /*!< REFER: restriction scheme */
struct sip_refer *refer; /*!< REFER: SIP transfer data structure */
enum subscriptiontype subscribed; /*!< SUBSCRIBE: Is this dialog a subscription? */
@@ -2070,7 +2071,6 @@ static int sip_get_codec(struct ast_channel *chan);
static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect);
/*------ T38 Support --------- */
-static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite);
static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
@@ -3968,7 +3968,9 @@ static void change_t38_state(struct sip_pvt *p, int state)
return;
/* Given the state requested and old state determine what control frame we want to queue up */
- if (state == T38_ENABLED)
+ if (state == T38_PEER_REINVITE)
+ message = AST_T38_REQUEST_NEGOTIATE;
+ else if (state == T38_ENABLED)
message = AST_T38_NEGOTIATED;
else if (state == T38_DISABLED && old == T38_ENABLED)
message = AST_T38_TERMINATED;
@@ -4434,6 +4436,7 @@ static int __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
AST_SCHED_DEL(sched, p->waitid);
AST_SCHED_DEL(sched, p->autokillid);
AST_SCHED_DEL(sched, p->request_queue_sched_id);
+ AST_SCHED_DEL(sched, p->t38id);
if (p->rtp) {
ast_rtp_destroy(p->rtp);
@@ -5381,8 +5384,13 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38. Expected %d, got %d\n", (int)sizeof(enum ast_control_t38), (int)datalen);
} else {
switch (*((enum ast_control_t38 *) data)) {
+ case AST_T38_NEGOTIATED:
case AST_T38_REQUEST_NEGOTIATE: /* Request T38 */
- if (p->t38.state != T38_ENABLED) {
+ if (p->t38.state == T38_PEER_REINVITE) {
+ AST_SCHED_DEL(sched, p->t38id);
+ change_t38_state(p, T38_ENABLED);
+ transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
+ } else if (p->t38.state != T38_ENABLED) {
change_t38_state(p, T38_LOCAL_REINVITE);
if (!p->pendinginvite) {
transmit_reinvite_with_sdp(p, TRUE, FALSE);
@@ -5394,7 +5402,11 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
case AST_T38_TERMINATED:
case AST_T38_REFUSED:
case AST_T38_REQUEST_TERMINATE: /* Shutdown T38 */
- if (p->t38.state == T38_ENABLED)
+ if (p->t38.state == T38_PEER_REINVITE) {
+ AST_SCHED_DEL(sched, p->t38id);
+ change_t38_state(p, T38_DISABLED);
+ transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
+ } else if (p->t38.state == T38_ENABLED)
transmit_reinvite_with_sdp(p, FALSE, FALSE);
break;
default:
@@ -5943,6 +5955,7 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
p->waitid = -1;
p->autokillid = -1;
p->request_queue_sched_id = -1;
+ p->t38id = -1;
p->subscribed = NONE;
p->stateid = -1;
p->sessionversion_remote = -1;
@@ -14966,7 +14979,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
int res = 0;
int xmitres = 0;
int reinvite = (p->owner && p->owner->_state == AST_STATE_UP);
- struct ast_channel *bridgepeer = NULL;
char *p_hdrval;
int rtn;
@@ -15078,41 +15090,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
}
}
-
- if (p->owner && (p->owner->_state == AST_STATE_UP) && (bridgepeer = ast_bridged_channel(p->owner))) { /* if this is a re-invite */
- struct sip_pvt *bridgepvt = NULL;
-
- if (!bridgepeer->tech) {
- ast_log(LOG_WARNING, "Ooooh.. no tech! That's REALLY bad\n");
- break;
- }
- if (IS_SIP_TECH(bridgepeer->tech)) {
- bridgepvt = (struct sip_pvt*)(bridgepeer->tech_pvt);
- if (bridgepvt->udptl) {
- if (p->t38.state == T38_ENABLED && bridgepvt->t38.state == T38_PEER_REINVITE) {
- sip_handle_t38_reinvite(bridgepeer, p, 0);
- ast_rtp_set_rtptimers_onhold(p->rtp);
- if (p->vrtp)
- ast_rtp_set_rtptimers_onhold(p->vrtp); /* Turn off RTP timers while we send fax */
- } else if (p->t38.state == T38_DISABLED && bridgepvt->t38.state == T38_ENABLED) {
- ast_log(LOG_WARNING, "RTP re-invite after T38 session not handled yet !\n");
- /* Insted of this we should somehow re-invite the other side of the bridge to RTP */
- /* XXXX Should we really destroy this session here, without any response at all??? */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- } else {
- ast_debug(2, "Strange... The other side of the bridge does not have a udptl struct\n");
- sip_pvt_lock(bridgepvt);
- change_t38_state(bridgepvt, T38_DISABLED);
- sip_pvt_unlock(bridgepvt);
- change_t38_state(p, T38_DISABLED);
- }
- } else {
- /* Other side is not a SIP channel */
- ast_debug(2, "Strange... The other side of the bridge is not a SIP channel\n");
- change_t38_state(p, T38_DISABLED);
- }
- }
if (!req->ignore && p->owner) {
if (!reinvite) {
@@ -16875,6 +16852,16 @@ static int sip_uri_cmp(const char *input1, const char *input2)
return sip_uri_params_cmp(params1, params2);
}
+/*! \brief Called to deny a T38 reinvite if the core does not respond to our request */
+static int sip_t38_abort(const void *data)
+{
+ struct sip_pvt *p = (struct sip_pvt *) data;
+
+ change_t38_state(p, T38_DISABLED);
+ transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
+ p->t38id = -1;
+ return 0;
+}
/*! \brief Handle incoming INVITE request
\note If the INVITE has a Replaces header, it is part of an
@@ -17466,70 +17453,14 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
transmit_response(p, "100 Trying", req);
if (p->t38.state == T38_PEER_REINVITE) {
- struct ast_channel *bridgepeer = NULL;
- struct sip_pvt *bridgepvt = NULL;
-
- if ((bridgepeer = ast_bridged_channel(p->owner))) {
- /* We have a bridge, and this is re-invite to switchover to T38 so we send re-invite with T38 SDP, to other side of bridge*/
- /*! XXX: we should also check here does the other side supports t38 at all !!! XXX */
- if (IS_SIP_TECH(bridgepeer->tech)) {
- bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
- if (bridgepvt->t38.state == T38_DISABLED) {
- if (bridgepvt->udptl) { /* If everything is OK with other side's udptl struct */
- /* Send re-invite to the bridged channel */
- sip_handle_t38_reinvite(bridgepeer, p, 1);
- } else { /* Something is wrong with peers udptl struct */
- ast_log(LOG_WARNING, "Strange... The other side of the bridge don't have udptl struct\n");
- sip_pvt_lock(bridgepvt);
- change_t38_state(bridgepvt, T38_DISABLED);
- sip_pvt_unlock(bridgepvt);
- transmit_response_reliable(p, "488 Not acceptable here", req);
-
- }
- } else {
- /* The other side is already setup for T.38 most likely so we need to acknowledge this too */
- transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
- change_t38_state(p, T38_ENABLED);
- }
- } else {
- /* Other side is not a SIP channel */
- transmit_response_reliable(p, "488 Not acceptable here", req);
- change_t38_state(p, T38_DISABLED);
-
- if (!p->lastinvite) /* Only destroy if this is *not* a re-invite */
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- } else {
- /* we are not bridged in a call */
- transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
- change_t38_state(p, T38_ENABLED);
- }
- } else if (p->t38.state == T38_DISABLED) { /* Channel doesn't have T38 offered or enabled */
- int sendok = TRUE;
-
- /* If we are bridged to a channel that has T38 enabled than this is a case of RTP re-invite after T38 session */
- /* so handle it here (re-invite other party to RTP) */
- struct ast_channel *bridgepeer = NULL;
- struct sip_pvt *bridgepvt = NULL;
- if ((bridgepeer = ast_bridged_channel(p->owner))) {
- if (IS_SIP_TECH(bridgepeer->tech) && !ast_check_hangup(bridgepeer)) {
- bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
- /* Does the bridged peer have T38 ? */
- if (bridgepvt->t38.state == T38_ENABLED) {
- ast_log(LOG_WARNING, "RTP re-invite after T38 session not handled yet !\n");
- /* Insted of this we should somehow re-invite the other side of the bridge to RTP */
- transmit_response_reliable(p, "488 Not Acceptable Here (unsupported)", req);
- sendok = FALSE;
- }
- /* No bridged peer with T38 enabled*/
- }
- }
- /* Respond to normal re-invite */
- if (sendok) {
- /* If this is not a re-invite or something to ignore - it's critical */
- transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)), p->session_modify == TRUE ? FALSE:TRUE);
- }
+ p->t38id = ast_sched_add(sched, 5000, sip_t38_abort, p);
+ } else if (p->t38.state == T38_ENABLED) {
+ transmit_response_with_t38_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)));
+ } else if (p->t38.state == T38_DISABLED) {
+ /* If this is not a re-invite or something to ignore - it's critical */
+ transmit_response_with_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL)), p->session_modify == TRUE ? FALSE:TRUE);
}
+
p->invitestate = INV_TERMINATED;
break;
default:
@@ -22003,84 +21934,6 @@ static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
return 0;
}
-/*! \brief Handle T38 reinvite
- \todo Make sure we don't destroy the call if we can't handle the re-invite.
- Nothing should be changed until we have processed the SDP and know that we
- can handle it.
-*/
-static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite)
-{
- struct sip_pvt *p;
- int flag = 0;
-
- p = chan->tech_pvt;
- if (!p || !pvt->udptl)
- return -1;
-
- /* Setup everything on the other side like offered/responded from first side */
- sip_pvt_lock(p);
-
- /*! \todo check if this is not set earlier when setting up the PVT. If not
- maybe it should move there. */
- p->t38.jointcapability = p->t38.peercapability = pvt->t38.jointcapability;
-
- ast_udptl_set_far_max_datagram(p->udptl, ast_udptl_get_local_max_datagram(pvt->udptl));
- ast_udptl_set_local_max_datagram(p->udptl, ast_udptl_get_local_max_datagram(pvt->udptl));
- ast_udptl_set_error_correction_scheme(p->udptl, ast_udptl_get_error_correction_scheme(pvt->udptl));
-
- if (reinvite) { /* If we are handling sending re-invite to the other side of the bridge */
- /*! \note The SIP_CAN_REINVITE flag is for RTP media redirects,
- not really T38 re-invites which are different. In this
- case it's used properly, to see if we can reinvite over
- NAT
- */
- if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE) && ast_test_flag(&pvt->flags[0], SIP_CAN_REINVITE)) {
- ast_udptl_get_peer(pvt->udptl, &p->udptlredirip);
- flag =1;
- } else {
- memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
- }
- if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
- if (!p->pendinginvite) {
- if (flag)
- ast_debug(3, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
- else
- ast_debug(3, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip.sin_addr));
- change_t38_state(p, T38_LOCAL_REINVITE);
- transmit_reinvite_with_sdp(p, TRUE, FALSE);
- } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
- if (flag)
- ast_debug(3, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
- else
- ast_debug(3, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip.sin_addr));
- ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
- }
- }
- /* Reset lastrtprx timer */
- p->lastrtprx = p->lastrtptx = time(NULL);
- sip_pvt_unlock(p);
- return 0;
- } else { /* If we are handling sending 200 OK to the other side of the bridge */
- if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE) && ast_test_flag(&pvt->flags[0], SIP_CAN_REINVITE)) {
- ast_udptl_get_peer(pvt->udptl, &p->udptlredirip);
- flag = 1;
- } else {
- memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
- }
- if (flag)
- ast_debug(3, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
- else
- ast_debug(3, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip.sin_addr));
- change_t38_state(pvt, T38_ENABLED);
- change_t38_state(p, T38_ENABLED);
- transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
- p->lastrtprx = p->lastrtptx = time(NULL);
- sip_pvt_unlock(p);
- return 0;
- }
-}
-
-
/*! \brief Returns null if we can't reinvite audio (part of RTP interface) */
static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
{