Summary:ASTERISK-03344: [patch] app_sipredirect for generating '302 Moved Temporarily' messages
Reporter:John Todd (jtodd)Labels:
Date Opened:2005-01-24 23:37:10.000-0600Date Closed:2008-01-15 15:25:45.000-0600
Versions:Frequency of
Environment:Attachments:( 0) sipredirect_in_transfer.diff
( 1) sipredirect_in_transfer2.diff
( 2) sipredirect2.diff
Description:This patch is app_sipredirect.  Here is the modified description from the bounty request on -biz:


 -= Info about application 'SIPRedirect' =-

Sends a SIP 302 message to caller with custom content

 extension := string which contains new extension (mandatory)
 host := hostname or IP address of SIP destination.  If left blank, this host's IP address will be used.
 port := integer.  If left unset, no port will be specified.

This application can only be called before a call is answered. Calling this application after a call has been answered, or if the originating channel is not a SIP channel creates a 0 result.  After being called successfully, the application exits with a -1 result. This seems to be opposite of what should happen, but there isn't much reason to continue processing the dialplan after handing off the 302 redirect, and giving a "0" result would allow for graceful error handling and continued dialplan processing if non-SIP or previously answered calls were handed to the application.

The host information is tricky in the default situation: it uses the externip if specified in sip.conf.  If that is blank, it uses externhost if the timer for the host is still valid.  If that is blank, it uses the IP address:port or hostname:port in the original INVITE.  Of course, you can specify the host and port in the command line if you wish; it will only try the other methods if there is no host[:port] specified in the command.  I would suggest that typically the host should at least be specified unless you are doing really exotic things.  If you're not redirecting the call to a different server, then I'd suggest you look more at Goto as an option instead of SIPRedirect.

The application re-writes the Contact: address on the reply, so that the newly formed URI would be used by the requester to re-initiate the call to a different location.

This nifty trick might be used to create a central "call diverter" which then redirects many end users to multiple endpoints without having to keep state.  The CDR would be very brief on the central host, and would not contain any data about activity that happened on the redirected host/gateway.  However, that's fine - this isn't designed to replace app_dial; it's just a crude method to distribute SIP callers when they might not really need to be attached to this particular Asterisk instance.

The only feature it lacks is the ability to specify the human-readable text in the Contact: field, but that does not seem to be very important.  Currently, it just says "redirect" which seems sufficient.

Written by Martin Pycko as a work for hire by John Todd.  Both John and Martin have disclaimers on file.  John is the "sponsor" for this work, so he explicitly allows it to be added to the project under the same guidelines as usual for patches to be added to *.

This is a seemingly minor item, but will be insanely handy for larger installations or where (due to billing issues) calls need to appear to come from the end-user device no matter how they got the information.  Solves lots of NAT problems, too!  Overall, a useful tool in the toolkit for advanced SIP hacking on Asterisk.

Applies to version 1.367 of chan_sip.c (2005-01-24)
Comments:By: Mark Spencer (markster) 2005-01-24 23:47:59.000-0600

There is already an application called Transfer.  I would suggest that sip_transfer be simply modified to generate "302 Moved" in the right situation (unanswered in-bound calls) or use "REFER" in either outbound or already-answered inbound calls.

By: John Todd (jtodd) 2005-01-25 15:01:49.000-0600

I had considered that and discarded it, but it certainly make sense.  

Here's why I didn't do it that way:  the parameters for SIP "302 Redirect" might not apply for all types of transfers.  In other words, this is a channel-specific application.  MGCP, or IAX, or chan_whatever might require different parameters, or fewer parameters.

I like the "REFER" idea; hadn't really considered it, since my situation only dealt with unanswered calls being handled.  The NOTIFY issues surrounding REFER in RFC3515 (http://www.faqs.org/rfcs/rfc3515.html) are a bit sticky, and I'm unclear on how Asterisk would handle them.   Specifically, section 2.4.4 uses "MUST" in reference to these NOTIFY transmissions that Asterisk would both have to receive and generate to be RFC compliant.  It gets more complex from there, involving lots of modifications to chan_sip.  I don't think this is feasible in the near term without more thought, so unless someone wants to step up to this I'd suggest it gets tabled (sorry, I'd fund it, but I'm out of $$$ for it.)  The methods that REFER uses would actually be fairly nice, since we could then keep track of state on the originating machine via the SUBSCRIBE/NOTIFY sequences that were generated by the third-party gateway.  However, then that would imply that Asterisk handled SUBSCRIBE/NOTIFY for this type of transfer activity... maybe it does, but I don't think so.  SIP spaghetti, as usual.

I am completely behind making all channels behave in the same way when a certain application is called against the channel, if that channel type is capable of accomplishing the action.  However, it seems that app_transfer would either need to have a different sytnax depending on which channel type was being used, which would lead to confusing bloat, or that each channel method would have to be handled in exactly the same way, which would probably mean that only some sub-set of parameters would be handled (thus reducing the usefulness of the method in reference to each specific channel type.)

To re-design this functionality to include in app_transfer, I can simply say that IAX, MGCP, OSS, Zap, etc. don't support the hostname:port extensions of Transfer?  This would lead to a syntax like this:

Transfer caller to remote extension

 Transfer(exten[@host[:port]]):  Requests the remote caller be transferred to a given extension.  
  extension := string which contains new extension (mandatory)
  host := hostname or IP address of SIP destination. If left blank, this host's IP address will be used.
  port := integer. If left unset, no port will be specified.

SIP: If call is unanswered and inbound, generates a "302 Moved Temporarily" message, and includes the re-written Contact: information.  If host is blank, it uses the externip if specified in sip.conf. If externip is not specified, it uses externhost if the timer for the host is still valid. If externhost is not specified, it uses the IP address or hostname in the original INVITE.  If the port is not specified, it is not included in the re-write.

MGCP, IAX, SCCP: no functionality yet for channel-specific transfers.  Accepts only the "exten" variable, and all other suffixes are ignored; channel is transferred internally to Asterisk, and no messages are visible to the channel drivers nor is any action required by the channels.

Returns -1 on hangup, or 0 on completion regardless of whether the transfer was successful.  If the transfer was *not* supported or successful and there exists a priority n + 101, then that priority will be taken next.


I'm not sure this is a good way to go, the more I look at it, but it could work.

The current SIPRedirect patch is channel-specific.  I think there are going to be some things which are channel-specific, and the "302 Moved Temporarily" seems to be one of the easier things to put in a box and say that it's possible that it may have to always be channel specific.

I'll see what I can do for the extended features of Transfer if it's the only way it will find it's way into the mainline code, but I'd like to hear the comments on acceptance of the patch as-is after these notes above...

By: Mark Spencer (markster) 2005-01-25 17:39:26.000-0600

I suggest as follows:

Transfer(exten): Transfer in generic way

Transfer(Tech/<tech-specific-data>): If calling channel is of type "Tech", then transfer using tech specific data parameters, otherwise treat as NoOp.

I definitely would prefer keeping the Transfer application as the way to do this, and it should obviously be transparent to the user whether this is done with 302 Moved Temporarily or REFER depending on whether the call was answered (The SIP motto, like the perl motto, being "there's more than one way to do it")...

By: Olle Johansson (oej) 2005-01-27 01:49:30.000-0600

jtodd: I believe we do the notify thing around REFER, so you could just add a check to the sip_transfer function if the call is in ringing state and if the parameter is SIP/something@domain - if so, call your sipredirect function. The transfer app ends upp calling sip_transfer.
Then we could add a check in the transfer() app for TECH/ to make sure that we have an incoming call of the same tech.

By: John Todd (jtodd) 2005-01-27 02:43:44.000-0600

Yes, I've asked Martin if he's interested in such a re-write.  Have you done the REFER trick in chan_sip2?   It seems that is quite a bit of work, as it involves both receiving as well as generating NOTIFY/SUBSCRIBE requests for the REFER path to work, which does not seem to be in the scope of chan_sip right now in a robust way (hey, prove me wrong!)

I think what you're suggesting is to leave the app_sipredirect more-or-less intact (perhaps invisible to the dialplan?) but call it from app_transfer in certain circumstances.  This seems reasonable, and does not necessitate the implementation of the wriggling mass of REFER which may be discouraging and may halt the incremental improvement of Transfer() if it is a prerequisite for the "302 Moved Temporarily" patch to be re-worked into Transfer().

By: Olle Johansson (oej) 2005-01-27 03:56:38.000-0600

What I suggest is basically:
* Don't mess with transfers of active calls, it's in there already
* If the call is in ringing state, redirect the transfer to your function
* Remove the actual registration of the application
* Maybe rename the function to "redirect302()" or something that does not suggest it's an app

By: John Todd (jtodd) 2005-02-01 00:45:23.000-0600

OK, suggestions all make sense.

This new patch, named "sipredirect_in_transfer.diff" (same disclaimers as before, written by Martin P) changes the behavior of Transfer for SIP calls that have not been answered.  If the call has not been answered, and Transfer is called, then an optional host and port can be specified in the Transfer arguments to allow a "302 Temporarily Moved" message to appear to the originator.

The only thing that I can see missing here is the modifications to the short-description and syntax of the Transfer application...


So, if one knows the call is SIP, then one can say:


edited on: 02-01-05 00:47

By: Mark Spencer (markster) 2005-02-01 00:52:32.000-0600

Again, if you look at my comment, my suggestion is that you can specify a Tech/dest for the Transfer and if Tech matches the calling channel technology then it uses "dest" as the destination otherwise if no tech is specified the "dest" is always just the extension.

By: John Todd (jtodd) 2005-02-04 10:53:01.000-0600

OK, I understood the initial comment.  However, I can't imagine an instance where "tech" would be valid.  As an example, if you try to "transfer" a SIP call to MGCP, that's not possible, or a Zap call to IAX.  Thus, the "TECH" specifier is kind of redundant, since it is implictly defined by the type of channel that is running the Transfer command.  If it's a SIP call, then the TECH would always be of type SIP; if it's an IAX call, the TECH type would always be IAX, etc. etc. etc.   Is there some administrative reason that one would want to specify the TECH here?

By: Mark Spencer (markster) 2005-02-04 11:48:16.000-0600

I think you misunderstand my point.  My point is that if tech matches the technology of the incoming channel, then that tech-specific destination is used, otherwise, it is treated as a NoOp.  For example:

exten => _XXXX,1,Transfer(SIP/${EXTEN}@mysipserver) ; transfer sip calls here
exten => _XXXX,n,Transfer(IAX2/user:pass@myiaxserver/${EXTEN}) ; transfer iax calls here
exten => _XXXX,n,Playback(dunno-what-to-do)

If no technology is specified, then the transfer is assumed to be a different extension on the calling server in a technology agnostic way.

By: x martinp (martinp) 2005-02-05 12:33:50.000-0600

Well the only problem is that virtually "NO" channel driver supports Tech/whatever syntax.

So (to Mark) you want to have a patch modifying all the channel drivers to support
if Tech/whatever != chan/Tech
 call chan->transfer ?

By: x martinp (martinp) 2005-02-05 12:39:34.000-0600

Besides IMHO each channel driver is capable of getting the calls to a diffrent incoming context. And IMHO most ppl do not dump all the calls from all the channel drivers to one context. It first goes to a tech specific one

1) for simplicity
2) easier to update/change dialplan

The tech/whatever is simply making the dialplan more complicated in my oppinion.

Suppose this:

exten => s,1,Transfer(SIP/blah)
exten => s,2,Transfer(H323/blah)
exten => s,3,Transfer(skinny/blah)
exten => s,4,Transfer(oss/blah)
exten => s,5,Transfer(IAX/blah) (yeah, I know -> noone is using it)
exten => s,6,Transfer(IAX2/blag)
exten => s,7,Transfer(MGCP/blah)
exten => s,8,Transfer(Zap/blah)
exten => s,9,Transfer(new-voip-protocol/blah)
exten => s,10,Transfer(Martins-voip-protocol/blah)
exten => s,11,Transfer(bri_chan_driver/blah)

Now how does that look ? hehe

edited on: 02-05-05 12:39

edited on: 02-05-05 12:40

By: Mark Spencer (markster) 2005-02-05 14:42:08.000-0600

The tech/transfer would be implemented within the Transfer application -- it would be silly to require the underlying implementations to make the call.

By: x martinp (martinp) 2005-02-05 18:50:36.000-0600

And now ...?

By: John Todd (jtodd) 2005-02-09 13:37:14.000-0600

I'd lean towards a tech-agnostic way of doing this, as well, but I really don't care one way or the other.  The only reason one would find the fall-through process useful (Mark's method) would be to take some specific action based on a failure, not on a success.  You only need one failure to determine that the call is impossible to transfer, and cascading through mutliple TECH formats does not seem to have any advantage, other than perhaps providing a reductionist method of determining what kind of channel type the originator was, which does not appear to have much value.

Since a "transfer" implies loss of call control at the moment the transfer is executed (if pre-answer) what data can be extracted from having it fail on TECH mismatches?

Looking at the first three characters of the $CHANNEL-ID of the current channel could give you the channel type if you were really looking to determine what the TECH was, and some simple GotoIf could then take action based on that value.

This all being said, I really don't care what way this is implemented.  If it's got a TECH string in front of it: great!  If it doesn't: great!  The difference is minimal, and I don't need to split hairs.  The functionality would help a lot, and the semantics are mostly irrelevant.  All I want to be able to do is use the method: how I type the command into the dialplan is an insignificant detail.

By: x martinp (martinp) 2005-02-09 14:41:57.000-0600

Did you see that I already did it the way Mark wanted ... but no response from Mark ....

By: John Todd (jtodd) 2005-02-09 18:07:41.000-0600

OK, I didn't notice the new patch.    I'll try and test as well.

By: Mark Spencer (markster) 2005-02-10 00:51:31.000-0600

Looks pretty good here, does it pass your tests, jtodd?

By: John Todd (jtodd) 2005-02-15 00:30:32.000-0600

Passes my preliminary tests for transfers with SIP 302's, yes.  The patch needs to be updated because sip_transfer has moved, but there is no code change (just position within the file.)

By: John Todd (jtodd) 2005-02-18 14:14:48.000-0600

Other than the extremely minor patch offset (probably does not require a new patch being created) I see no reason to not have this go in.

By: Mark Spencer (markster) 2005-02-19 11:35:22.000-0600

Added to CVS with mods.  Thanks!

By: Russell Bryant (russell) 2005-02-26 12:52:14.000-0600

not included in 1.0 since it's a new feature

By: Digium Subversion (svnbot) 2008-01-15 15:25:45.000-0600

Repository: asterisk
Revision: 5055

U   trunk/apps/app_transfer.c
U   trunk/channels/chan_sip.c

r5055 | markster | 2008-01-15 15:25:44 -0600 (Tue, 15 Jan 2008) | 2 lines

Add sip redirect support (bug #3419i, with mods)