EMG and custom outbound http requests using DLL

While it is possible (and usually very easy) to implement a connector to perform custom http requests using the EBE approach it is more efficient to do the implementation as a DLL connector.

An EBE connector will fork a new process for every request and any Perl module used by the connector script will be loaded each time. A DLL connector on the other hand will be loaded once, on EMG startup, and stay loaded in memory.

Depending on the exact script used EBE may be limited to 10 messages per second while the same implementation as DLL may be able to reach more than 200 messages per second.

Implementing a perl DLL connector

You find the complete code for a sample perl DLL connector below. The perl script needs to implement the “driver_encodemessage” function. This function will be called at least twice. On the first pass the data for the http request needs to be composed and on the second pass the script must handle the http response and set a result code (ok or error).

Sample DLL connector

Server configuration

Sample connector cofiguration which can be added in server.cfg or via EMG Portal.

The ADDRESS is the url to which the http request will be sent.

You can experiment with the number of instances needed to reach best throughput.

CONNECTOR ebe-dll <
# Ensure second pass even on http errors

Perl code

Download ebe-dll.pl

# ebe-dll.pl
# Sample EMG perl DLL connector for sending via HTTP (GET or POST)
# Function "driver_encodemessage" must be implemented and will be
# called at least twice. Once to compose the data to be sent and
# once to parse the response from the remote end.
# The ADDRESS keyword for the connector must be set to the url to use.

use strict;
use Data::Dumper;
use Encode;
use POSIX qw(strftime);

# Perform logging
my $debug = 0;
# Log file
my $logfile = "/tmp/ebe-dll.log";

sub driver_encodemessage {
my ($ci, $arg) = @_;

# Set to true on first pass
my $first = $arg->{'first'};

if ($first) {
  # First pass, we should compose message
  # If needed we can read value for "NOTE" keyword on connector
  # my $cnote = $ci->{'note'};
  my $data = compose_message($arg->{'message'});
  dolog("data=$data") if $debug;

  # 1 - HTTP GET, 2 - HTTP POST
  $arg->{'smscop'} = 1;
  # Set actual GET / POST data
  $arg->{'data'} = $data;
  # $arg->{'headers'} = ''; # optional extra http headers
  $arg->{'flags'} = 1; # breakable (EMG can break dialog)

  return 1; # continue on to second pass
} else {
  # Second pass, we get http response
  my $http_status = $arg->{'retcode'};
  # The response data, could be json or xml data
  my $resp_data = $arg->{'data'};

  dolog("http_status=$http_status resp=$resp_data") if $debug;
  if ($http_status < 200 || $http_status >= 300) {
    # Set an error code and error text
    $arg->{'error'} = 1;
    $arg->{'errortext'} = $resp_data;
    return 2; # DONE, ERROR
  return 0; # DONE, OK

sub compose_message
my $msginfo = shift;

# EMG message id
my $emg_id = $msginfo->{'id'};
# Source address / sender
my $sourceaddr = $msginfo->{'sourceaddr'};
# Destination address / recipient
my $destaddr = $msginfo->{'destaddr'};
# EMG character code
my $charcode = $msginfo->{'charcode'};
# Message body
my $msg = $msginfo->{'message'};

dolog("compose_message: $msg") if $debug;

# Check whether message is Unicode (UCS2)
if ( $charcode eq '4' ) {
  # Yes, try to convert it
  my $decodedHex = pack( 'H*', $msg );
  eval { $msg = decode( "UCS-2BE", $decodedHex, Encode::FB_QUIET ); };
  if ($@) {
    dolog("Could not decode message, $@");
    $msg = "?";
} else {
  # No, plain text message (we might want to adjust the character encoding here)

# Return request data
return "sender=$sourceaddr&recipient=$destaddr&msg=$msg&msg_id=$emg_id";

sub dolog {
my $str = shift;
my $ts = strftime("%Y-%m-%d %H:%M:%S", localtime);
open(OUT, ">>$logfile");
print OUT "$ts $str\n";