HLR routing using before_dlr()


Most operators offering HLR lookup services use one of the following APIs.

  1. HTTP. This is easily handled in a route() plugin hook.
  2. ENUM/DNS. This is a bit trickier, but Perl has a good Net::DNS::Resolver class that can be used.
  3. SMPP DLR. This is the one addressed here.

The SMPP variant requires that a message is sent to the operator, either on a special account, with the “service_type” field set to “hlr”, or some other way of telling the operator that this is not a normal message but instead a HLR lookup. The HLR response then arrives in the corresponding delivery report, often in the optional fields 0x1400, 0x1401 etc. The problem is that there is no standard saying which field should be used for what purpose, not to mention the asynchronicity of SMPP. As of EMG version 7.1.9, there is now a much less complicated solution.

The route() plugin hook

Now, we create a “HLR lookup” message, route it to the SMPP connector, and wait for the result. This is done by making a request to an HTTP connector, using the path “/hlrlookup”. For this path we need to specify the username and password as always, but instead of DESTADDR and MESSAGE, we only add MSISDN=xxx. The full request will look like the example below.


The response is an XML object. There may be additional fields here.

<?xml version="1.0"?>

In the server.cfg file, both the HTTP and SMPP connectors are defined as usual. The HTTP connector can use ROUTE=NameOfTheSMPPConnector for the routing.

The before_dlr() plugin hook

When EMG receives a DLR pdu, the fields are stored in a “dlrinfo” object. For a normal DLR this is all that is needed, but for a HLR lookup response we need some operator specific code. For an operator returning the MNC in field 0x1400 and the MCC in field 0x1401, we use the plugin below. It is defined as usual with a PLUGIN section, specifying LIBRARY, INSTANCES etc as necessary, and referenced from the SMPP connector.

sub before_dlr {
  my ($request, $response) = @_;
  my $dlrinfo = ${$request}{dlrinfo};
  my %info = (
    'mnc' => $dlrinfo->{'0x1400'},
    'mcc' => $dlrinfo->{'0x1401'}
  response->{dlrinfo} = \%info;
  return 0;

In the request, the dlrinfo hash contains the following fields: sourceaddr, destaddr, service_type, and all the optional fields in the 0x1400-0xffff range. The first two are available for all protocols, but the others are SMPP specific.

In the response, the dlrinfo hash can contain the fields mnc, mcc, msc and imsi. All other fields are silently ignored.