Handling SIP URI Dialing in Asterisk

April 30th, 2009

Asterisk, by design, is very “extension” orientated- that is, if you want to dial an end-point, it requires an extension to route the call to. These extensions (defined in the asterisk extensions.conf file), can be extensions registered to phones, DIDs (XXXYYYZZZZ), or simply usernames assigned to users by the network administrator. Extensions are used for both incoming, and outgoing phone calls.asterisk

For example, if I place a call through my SIP phone to 1-444-555-1212, then asterisk will look up the “extension” 14445551212 in the extensions.conf file, to determine how to route the call.

Similarly to how e-mail works, an artifact of these extensions is a direct SIP address, which is basically your SIP extension @ your SIP server- so, if my phone was extension 555, and my SIP server had the IP address 192.168.1.1, then my SIP address would be: sip:555@192.168.1.1, and (if it’s not implictely blocked), I can be dialed directly using that SIP address.

But, because Asterisk is so extension orientated, it doesn’t easily allow for outbound dialing, using remote SIP addresses; If I try to dial the address sip:444@somedomain.com, Asterisk will immediately strip off the host portion (@somedomain.com), and try to route the call based simply on the extension “444″- which, since it’s an extension on a remote server (@somedomain.com), it won’t be able to route it locally, and will fail.

The solution? Well, it’s not ideal, but Asterisk provides the ability to use wild cards in the extensions.conf file (it refers to them as “patterns“) when doing extension look ups; this is handy when you have blocks of extension or DID’s- you can use the wildcard to map like extensions to the same config, keeping your config file small.

The issue, is that the wild card only compares against the local part of the SIP URI, which can look like almost anything, including other phone numbers.

First, define some general config

[general]
;
; Your termination provider (defined in sip.conf)
;
TERM_PROVIDER = SIP/company_peer

;
; The IP address of this asterisk server
;
ASTERISK_IP = 192.168.1.1

The “ASTERISK_IP” address is important later, as we’ll use it to validate outgoing SIP addresses.

Then in your default config, you should have something like this configured already- handling NANPA style dialing, and international dialing

[default]
;
; Dial NANPA style phone numbers directly
;
exten => _1NXXNXXXXXX,n,Dial(${TERM_PROVIDER}/${EXTEN},60)
exten => _1NXXNXXXXXX,n,HangUp()

;
; Dial international numbers directly
;
exten => _011.,n,Dial(${TERM_PROVIDER}/${EXTEN}, 60)
exten => _011.,n,HangUp()

After all the specific matches are done, then add:

;
; very last, assume anything else is a SIP URI
;
exten => _.,n,GotoIf($[${SIPDOMAIN} = ${ASTERISK_IP}]?unhandled)
exten => _.,n,GotoIf($[${SIPDOMAIN} = ${ASTERISK_IP}:5060]?unhandled)
exten => _.,n,Macro(uri-dial,${EXTEN}@${SIPDOMAIN})
exten => _.,n,HangUp()

;
; if the call doesn't match anything
;
[unhandled]
exten => s,n,Congestion()

The reason this has to be last, is because matching the extension “_.” will match *anything*- basically it’s a catch-all. You’re saying that if it doesn’t match anything else before this, then assume it must be a SIP URI.

This section also compares the ${SIPDOMAIN} variable to your ASTERISK_IP address; this ensures that only SIP URI’s with remote hosts are processed as SIP URI’s. If the host matches our ASTERISK_IP address value (ie- it’s a local extension), then it should have already matched something above this catch-all config.

Pass any SIP URI dials to the uri-dial MACRO, merging back together the extension and the SIP domain value.

;
; handle dialing SIP uri's directly
;
[macro-uri-dial]
exten => s,n,NoOp(Calling as SIP address: ${ARG1})
exten => s,n,Dial(SIP/${ARG1},60)

This solution works, but isn’t ideal, as it will match anything that didn’t already match; a better solution would be for it to NOT strip off the SIP domain, and allow for using a regular expression of some kind to check the extension, but there is currently no better way of handling this in Asterisk.

share this post
  • Digg
  • TwitThis
  • Facebook
  • del.icio.us
  • LinkedIn
  • Google
  • StumbleUpon
  • Tumblr

Development, Telephony

Memcache Access From PostgreSQL

March 15th, 2009

A big part of my job is to spend time figuring out how new technologies work, build on it, and then figure out new and inventive ways of merging it into new and existing systems- so I spent a lot of time “playing” around with stuff.

One thing I recently threw together, was some simple stored procedures for PostgreSQL, to give us built-in access to our memcached cluster, using the PL/PERL procedural language, and the Cache::Memcached module. None of this is rocket science, but might be useful for somebody out there that is looking to implement something similar.

First off, you need to build PostgreSQL with PERL support, and create the plperlu (un-trusted) language in our database; you need to use the “un-trusted” language, as we need to “use” the Cache::Memcached module;

postgres=# create language plperlu ;
CREATE LANGUAGE

Then you need to install the Cache::Memcached PERL module; I’ll assume you know how to do that; you can either install it through CPAN, or get it from the cpan.org site.

You also need at least one instance of memcached running somewhere; it doesn’t have to be on your local network, it just needs to be accessible by your database.

Then create the following procedures; I’ve only listed the “set” and “get” procedures, but you could easily follow the Cache::Memcached module man page, and create a “replace” and “delete” (and any other) procedures you needed.

So first the “set” procedure:

create or replace function memcache_set(_key text, _value bytea) returns int as $$

        use Cache::Memcached;

        my ($_key, $_value) = @_;

        $m = new Cache::Memcached {
                'debug'	=> 0
        };

        my @list = ("127.0.0.1:9996", "127.0.0.1:9997");
        my $servers = \@list;

        $m->set_servers($servers);
        $m->enable_compress(0);

        if ($m->set($_key, $_value))
        {
                return 0;
        } else
        {
                return 1;
        }

$$ language plperlu;

And then a “get” procedure:

create or replace function memcache_get(_key text) returns bytea as $$

        use Cache::Memcached;       

        my ($_key) = @_;

        $m = new Cache::Memcached {
                'debug'	=> 0
        };

	my @list = ("127.0.0.1:9996", "127.0.0.1:9997");
        my $servers = \@list;       

        $m->set_servers($servers);
        $m->enable_compress(0);

        my $val = $m->get($_key);
        if (defined($val))
        {
                return $val;
        } else
        {
                return undef;
        }

$$ language plperlu;

Now, in this case, I used a list of two different servers, both running on localhost, one on port 9996 and the other on port 9997; these servers could be anywhere, and you could only list one- but a really important thing to remember: if you do list more than one server, make sure you always list it in the same order, between all your procedures and all applications that may use this same data.

memcached calculates which server to store the data on, based on the order of this list; so you’ll get un-expected results if you list these servers differently between your applications.

A Simple Test

Now that you have the functions defined, you can use them to do some really interesting caching, directly from your database. Starting off with a simple test:

postgres=# select memcache_set('foo', 'bar');
 memcache_set 
---------------
               0
(1 row)

Then do a “get” to retrieve the data

postgres=# select memcache_get('foo');
 memcache_get
---------------
 bar
(1 row)

Database Session Handler

Now, lets say you had a database-backed session handler for your website; say maybe a PHP site, using something like this, which simply uses the PHP session_set_save_handler() method. Assume a simple session table like this:

create table sessions (
	session_id char(32) not null,
	data bytea not null default ''
);

“session_id” is the PHP session id (an MD5 string in this case), and “data” is the serialized contents of the PHP session.

Then add two rules- one for insert and one for update; this triggers the new memcache_set() procedure, so that new session data is always pushed out to your memcached servers

create rule session_insert_rule as on insert to sessions
	do also select memcache_set(NEW.session_id::text, NEW.data);

create rule session_update_rule as on update to sessions
	do also select memcache_set(NEW.session_id::text, NEW.data);

Testing this is simple:

postgres=# insert into sessions values ('5cc27b0285c9d2e6dc4125456d308548', 
     'This would be the session data');
INSERT 0 1

postgres=# select memcache_get('5cc27b0285c9d2e6dc4125456d308548');
              memcache_get
--------------------------------
 This would be the session data
(1 row)

And then subsequent updates

postgres=# update sessions set data = 'This is the new data' where
   session_id = '5cc27b0285c9d2e6dc4125456d308548';
UPDATE 1

postgres=# select memcache_get('5cc27b0285c9d2e6dc4125456d308548');
   memcache_get
-------------------
 This is the new data
(1 row)

Now just make your PHP session handler (or whatever) checks memcached first, before selecting from the sessions table; if you build it right, and set your expiration times correctly, you should be able to build a system that (almost) *never* reads this data from the database, as the data is always available from memcached.

share this post
  • Digg
  • TwitThis
  • Facebook
  • del.icio.us
  • LinkedIn
  • Google
  • StumbleUpon
  • Tumblr

Development

Gizmo5 747 Area Code

February 16th, 2009

I was playing with the Gizmo5 service today- we’ve had a few customer now ask if they could have Fonolo call them back at their Gizmo5 address, instead of a regular PSTN number. Their service, which is very Skype-ish, aims as providing cost saving on international phone calls, as well as provides free calls between Gizmo5 users.

One of the first things I noticed (after installing the Gizmo5 client), was that their system allocates each user a “SIP” number, which they made the unfortunate choice of formatting like a standard ten digit phone number (XXX-YYY-ZZZZ)- not only that, but they used the area code 747!2t_gizmo-logo

Unfortunately, they don’t have any stake in the *real* 747 area code controlled through NANPA- even worst, looking at the NANPA database, the 747 area code is already allocated as an overlay to the 818 area code (in California), and is set to be put in service May 18th, 2009 (~3 months from now).

Now, the Gizmo5 site doesn’t seem to make any mention of this, and there are only a few posts out there I can find- but they all simply say that the “SIP number” was never meant to be used as a normal PSTN number- it can only be called from one client to another, or as a full SIP address (by tacking on @proxy01.sipphone.com)- if that’s the case, it seems really weird that they opted to use phone numbers, instead of just usernames.

I’m not sure how they plan to handle it when *real* PSTN numbers in the 747 area code start getting allocated to people in California, and then one of their users with a DialOut package tries to call one of them? I’m sure it’s not going to take long before phone numbers start being duplicated, and they’re going to have to solve this issue.

Not to mention general confusion; I’ve read post after post about people being confused about why they can’t dial their 747 phone number from PSTN number.

As far as Fonolo support, I was hoping to simply trunk any calls to the 747 area code over SIP to the Gizmo5 system, as if they were just regular phone numbers; in testing, it seems to work well, but I’d just run into the same issue they will, come May.

I’ll have to just add them into the system as generic SIP addresses- hopefully I’ll have this working soon.

share this post
  • Digg
  • TwitThis
  • Facebook
  • del.icio.us
  • LinkedIn
  • Google
  • StumbleUpon
  • Tumblr

Fonolo, Telephony

White Spaces in Canada?

February 6th, 2009

I’ve been of the opinion for years, that at some point soon, people will no longer have to pay for Internet access; that it will devolve from a product itself, into simply a product delivery system.

Not only that, but all our services (cell phones, home phones, TV, and of course, “Internet access”) will be delivered over this network- which, if everybody is connected (end-users and businesses alike), will open up huge opportunities for competitive companies in all sorts of markets.

And, of course, it will all be that much easier if this magical Internet connection was fast, and wireless; just give your new TV some power, and it will connect to your services provider automatically using it’s wireless card; forget about cellular- your new portable VOIP phone will connect over the same wireless network.
dtv
No longer will whole provinces/cites/states be subject to incumbent providers, who’s only grip on our patronage, is that they happen to be the current guardians of the copper.

Well last Nov, the FCC voted unanimously to approve the use of the unused airwaves between broadcast TV channels (aka the “white space”), for wireless broadband service for the public (which, I have to say is pretty surprising that the FCC would support something good for the people, and not special interest groups)- of course, it was only after years of testing and poking and prodding by the Wireless Innovation Alliance (of whom some notable members are Google and Microsoft).

The spectrum itself is also ideal, as it has a much longer range than wifi, which means fewer base-stations to cover larger areas, which ultimately means lower costs to operate- so while it’s been hinted at, it doesn’t say this wireless Internet connection is going to be free- but definitely affordable (cheap even)- and one step closer to free.

On the coat-tails of the FCC, the CRTC (Canadian Radio-television and Telecommunications Commission) is meeting on Feb 17th to discuss doing the same for Canadians, but Canada isn’t set to shut off analogue TV until February 2011- which means a few years until it’s even possible.

Maybe I can fake my geo-location, and get access through Buffalo. ;)

share this post
  • Digg
  • TwitThis
  • Facebook
  • del.icio.us
  • LinkedIn
  • Google
  • StumbleUpon
  • Tumblr

Telephony

Fonolo Launches Call Recording Feature

January 29th, 2009

We’ve been hard at work here at fonolo, and we’re happy to announce the availability of several new features, including the ability to add custom bookmarks, an improved company search bar, and probably the most exciting, the ability to record your calls, and then play them back through the web interface.

 

Bookmarks:fonolo_bookmarks
The bookmarks feature lets you personalize a list of companies, and points in a companies’ phone tree, that you call frequently. Entries in your bookmarks list can then be deep-dialed with a single click.

 

Improved Search:
We’ve added a much improved search bar at the top of every page inside the interface. The new search will provide an auto-complete drop-down as you type, with searches that can be based on partial/full company names, partial/full phone numbers, as well as keywords found within the companies phone tree.

 

Call Recording:

One of the most exciting new features, is the ability to record your phone calls directly through the fonolo web portal. While you’re on a call initiated through the fonolo portal, simply hit the “Start Recording” button, and fonolo will start recording your phone call for you.

fonolo_recording

After you’ve completed your call, the recording will appear in your history (available from the home page, or from the company page); you can then playback the recording online, or download and play it back locally through your favorite mp3 player (like winamp or windows media player).

This is a beta release of call recording; enhanced features will be included in our next major release.

Visit the fonolo website to sign up today, and come see Shai Berger in person at the 2009 Emerging Communications Conference.

share this post
  • Digg
  • TwitThis
  • Facebook
  • del.icio.us
  • LinkedIn
  • Google
  • StumbleUpon
  • Tumblr

Fonolo