I have noted that the pstn.cfg example (or anything built
from its premise) doesn't work right for one very important
situation, that hopefully someone has already discovered
and has a good fix for. The documentation isn't helping.
The situation: I have a call initiated by some SIP
client, with the INVITE passing through SER and sent on
to a PSTN gateway (the SIP to SS7/ISUP conversion occurs
there). The call is in progress (post 200 OK) and both
parties are chatting away. So far, so good.
The problem: Trouble begins when the called-party (somewhere
on the PSTN) hangs up first.
What happens: This event triggers a SS7 REL message,
and the SIP/SS7 switch providing the VOIP gateway service
emits a BYE message, which gets sent to SER. SER receives the
message and doesn't treat it as a reply (because it isn't),
but instead it comes in the door at route {}.
The pstn.cfg-like script quickly determines that this BYE
message is coming from the gateway (correct) and skips all
the authentication checks (good), and does a rewritehostport()
using the PSTN gateway IP address (bad), and finally does a
t_relay() (very bad).
The BYE is now emitted by SER and sent back to the PSTN gateway
switch, rather than on to wherever the INVITE originally
came from, the device that needs to know about this BYE.
This quickly degenerates into a small battle between PSTN gateway
switch and SER, as the PSTN gateway isn't getting the answer back
it is expecting in response to the BYE it sent to SER, and
the PSTN gateway certainly doesn't want to see the message it
just sent out come back over and over. Eventually various
looping checks or timers kick in and the argument ends, but
the calling system remains in the dark over the fact that the
call is now over (other than getting a lot of silence).
So that behavior is obviously wrong, but that's what the
stock copy of pstn.cfg does here. SER obviously wants to
be involved, because it added a Record-Route, but the script
really isn't able to deal with the consequences.
If the calling network was all SIP this would be merely
annoying, but if it is another ISUP network (with a SIP
leg in the middle), the originating ISUP legs of the call
just rack up the toll charges, unaware that the other
legs of the call are gone.
Bad things also happen if the original INVITE included a
Session-Expires: header, which causes the PSTN gateway to
emit its own INVITE back to the calling network (via the
SER) at intervals during the call, starting at 50% of the
time specified in that header. These packets also die a
horrible fate in the PSTN-Gateway and SER packet loop,
which causes the call to collapse 32 seconds later.
(That's unbelieveably bad.)
Recognizing this apparent-shortcoming in the pstn.cfg example,
and using the fact that the script could determine that this
called-party-BYE or INVITE message came from the PSTN gateway
and not somewhere else, I added tests to not perform the
rewritehost that sends the message back to the gateway, but
instead sets the address to that of the known place where the
INVITE originally came from, because in this super simple
example, there is only one place,
eg phone-asterisk-SER-PSTN-SS7network-...
Forcing BYE/INVITEs coming from the PSTN direction sort of
fixes the problem of called-party BYEs, and the PSTN gateway
device emitting re-INVITEs. However, it only works for
ONE source, which is lousy as you have to hard-code the
right place for the call in both directions!
And of course, someone has too many calls for their one
SBC (aka an asterisk box) and they have more than one now.
In fact, many more, and any of them can send me the same
range of calls from the same sources and to the same PSTN
gateway. And it would be really nice if I sent the
called-party-BYE or re-INVITEs back to the right SBC.
But how?
An examination of the numerous variables that SER has (as viewed
via xlog() when the called-party-BYE or called-network-reINVITE
comes in) shows that SER actually has the right IP address
available that the called-party-BYE or re-INVITE should be
sent back to (apparently saved as part of the transaction details
from the original INVITE), but I can't figure out how to reference
this value in "rewritehost()". Like most SER functions, rewritehost()
doesn't appear to accept variable names as parameters, and as
xlog uses cryptic abbreviations for what it displays, I probably
wouldn't know what variable name to specify in rewritehost() anyway.
(Did two different programmers do these parts?)
Now, if you don't use "rewritehost()" in the send-back-to-caller
direction and are hoping that SER will do the right thing on its
own, you will be disappointed. The t_relay() merely sends the
message back itself and you get a much smaller SIP message loop
going. (This is because SER puts its IP address all over the
original INVITE message so that the PSTN gateway would talk to
SER rather than the true source of the call.)
So that appears to means that you must set rewritehost() to a
reasonable destination to get the message to move beyond SER,
and somehow I have to choose a destination from many possible
destinations the original INVITE came from, based on some piece
of trivia that was in the original INVITE that I can somehow
trigger on.
That means if there are 250 different SBCs out there sending me
calls, and one of them was where the original INVITE came
from for the call I just got a called-party-BYE from, how do I
force that called-party-BYE (or a called-network re-INVITE)
to go back to the right place? Must I build a giant if statement
that tests the addresses of all 250 sources and leaves a flag
or something that can be used in 250 if statements later
when the called-party-BYE or called-network-reINVITE shows up?
Sounds horrible and a giant kludge! Any other solutions?
Thanks in advance for thinking about this one!