Seems like there is some interest in sms service types as loadable modules
so I'm submitting my implementation.

Also included are two sample modules. They are very simple and lack proper
logging and error handling.

As has been mentioned, the loadable module interface has to be carefully
designed with generallity in mind.
The current one feels a bit crude and might need some further refinement.
One way of deriving a good interface could be taking a look at what is
needed to make all current sms service types into loadable libraries.

Note: loading libraries into smsbox requires smsbox to be linked with
-rdynamic.




         /Dennis

  Dennis Malmström
  Erda Technology AB
  S:t Larsgatan 12, 582 24 Linköping, Sweden
  http://www.erda.se
  mail: [EMAIL PROTECTED]
  phone: +46 (0)13 377218
  gsm: +46 (0)706483090





Index: gw/smsbox.c
===================================================================
RCS file: /home/cvs/gateway/gw/smsbox.c,v
retrieving revision 1.170
diff -u -r1.170 smsbox.c
--- gw/smsbox.c 2002/02/07 22:16:35     1.170
+++ gw/smsbox.c 2002/02/22 12:18:57
@@ -6,6 +6,7 @@
 #include <unistd.h>
 #include <signal.h>
 #include <string.h>
+#include <dlfcn.h>
 
 #include "gwlib/gwlib.h"
 
@@ -58,9 +59,21 @@
 static Numhash *black_list;
 
 static List *smsbox_requests = NULL;
+static List *loaded_modules = NULL;
 
 int charset_processing (Octstr *charset, Octstr *text, int coding);
 
+
+
+typedef Octstr* loadable_doit( Msg* msg, Octstr* pattern );
+
+typedef struct {
+    Octstr* name;
+    void* handle;
+    loadable_doit* doit;
+} Module;
+
+
 /***********************************************************************
  * Communication with the bearerbox.
  */
@@ -655,6 +668,87 @@
         }
         break;
 
+    case TRANSTYPE_CALL_LOADABLE_MODULE:
+        {
+            Module* module = NULL;
+            Octstr* moduleName = urltrans_name(trans); /* What is the purpose of 
+name? Is this use appropriate? */
+
+            debug("sms.module", 0, "calling module '%s'", octstr_get_cstr( moduleName 
+) );
+
+              /* is module already loaded? */
+            if ( loaded_modules == NULL ) {
+                loaded_modules = list_create();
+            } else {
+                int I = list_len( loaded_modules );
+                int i = 0;
+
+                for ( i = 0; i < I; i++ ) {
+                    Module* x = (Module*) list_get( loaded_modules, i );
+                    
+                    if ( ! octstr_compare( x->name, moduleName ) ) {
+                        module = x;
+                        break;
+                    }
+                }
+            }
+
+              /* If not, load it */
+            if ( module == NULL ) {
+                void *moduleHandle = NULL;
+                loadable_doit* doit;
+
+                debug("sms.module", 0, "loading module '%s'", octstr_get_cstr( 
+moduleName ) );
+
+                  /* load module */
+                {
+                    Octstr* fileName = octstr_duplicate( moduleName );
+                    octstr_append_cstr( fileName, ".so" );
+                    moduleHandle = dlopen( octstr_get_cstr( fileName ), RTLD_NOW );
+                    octstr_destroy( fileName );
+
+                   if ( ! moduleHandle ) {
+                        error(0, "dlopen failed: %s", dlerror() );
+                        *result = NULL;
+                        octstr_destroy(pattern);
+                        goto error;
+                    }
+                }
+
+                  /* look up symbol */
+                {
+                    const char* errmsg = NULL;
+                    doit = dlsym( moduleHandle, octstr_get_cstr( moduleName ) );
+                    errmsg = dlerror();
+
+                    if ( errmsg ) {
+                        error(0, "dlsym failed: %s", errmsg );
+                        *result = NULL;
+                        octstr_destroy(pattern);
+                        goto error;
+                    }
+
+                    if ( ! doit ) { /* we cant't call NULL */
+                        error(0, "dlsym returned NULL" );
+                        *result = NULL;
+                        octstr_destroy(pattern);
+                        goto error;
+                    }
+                }
+                
+                  /* keep track of this module */
+                module = (Module*) gw_malloc( sizeof( Module ) );
+                module->name = octstr_duplicate( moduleName );
+                module->handle = moduleHandle;
+                module->doit = doit;
+                list_insert( loaded_modules, 0, module );
+            }
+
+              /* call module */
+            *result = (*module->doit)( msg, pattern );
+            octstr_destroy(pattern);
+        }
+        break;
+
     case TRANSTYPE_GET_URL:
        request_headers = http_create_empty_headers();
        http_header_add(request_headers, "User-Agent", "Kannel " VERSION);
@@ -2105,8 +2199,30 @@
     octstr_destroy(reply_couldnotrepresent);
     numhash_destroy(black_list);
     numhash_destroy(white_list);
+
+      /* close all loaded modules */
+    if ( loaded_modules != NULL ) {
+        int I = list_len( loaded_modules );
+        int i = 0;
+        for ( i = 0; i < I; i++ ) {
+            Module* module = (Module*) list_get( loaded_modules, i );
+ 
+            if ( dlclose( module->handle ) ) {
+                error(0, "dlclose failed: %s", dlerror() );
+            }
+            module->handle = NULL;
+
+            octstr_destroy( module->name );
+            gw_free( module );
+        }
+
+        list_destroy( loaded_modules, NULL );
+    }
+
+
     cfg_destroy(cfg);
     gwlib_shutdown();
+
     return 0;
 }
 
Index: gw/urltrans.c
===================================================================
RCS file: /home/cvs/gateway/gw/urltrans.c,v
retrieving revision 1.70
diff -u -r1.70 urltrans.c
--- gw/urltrans.c       2002/02/07 22:16:46     1.70
+++ gw/urltrans.c       2002/02/22 12:19:00
@@ -670,7 +670,7 @@
 static URLTranslation *create_onetrans(CfgGroup *grp)
 {
     URLTranslation *ot;
-    Octstr *aliases, *url, *post_url, *text, *file, *exec;
+    Octstr *aliases, *url, *post_url, *text, *file, *exec, *module;
     Octstr *accepted_smsc, *forced_smsc, *default_smsc;
     Octstr *grpname, *sendsms_user, *sms_service;
     int is_sms_service;
@@ -730,6 +730,7 @@
        file = cfg_get(grp, octstr_imm("file"));
        text = cfg_get(grp, octstr_imm("text"));
        exec = cfg_get(grp, octstr_imm("exec"));
+       module = cfg_get(grp, octstr_imm("module"));
        if (url != NULL) {
            ot->type = TRANSTYPE_GET_URL;
            ot->pattern = url;
@@ -743,9 +744,12 @@
        } else if (text != NULL) {
            ot->type = TRANSTYPE_TEXT;
            ot->pattern = text;
-    } else if (exec != NULL) {
-        ot->type = TRANSTYPE_EXECUTE;
-        ot->pattern = exec;
+  } else if (exec != NULL) {
+      ot->type = TRANSTYPE_EXECUTE;
+      ot->pattern = exec;
+  } else if (module != NULL) {
+      ot->type = TRANSTYPE_CALL_LOADABLE_MODULE;
+      ot->pattern = module;
        } else {
            error(0, "Configuration group `sms-service' "
                     "did not specify get-url, post-url, file or text.");
Index: gw/urltrans.h
===================================================================
RCS file: /home/cvs/gateway/gw/urltrans.h,v
retrieving revision 1.24
diff -u -r1.24 urltrans.h
--- gw/urltrans.h       2002/02/07 22:16:46     1.24
+++ gw/urltrans.h       2002/02/22 12:19:00
@@ -48,7 +48,8 @@
     TRANSTYPE_TEXT,
     TRANSTYPE_FILE,
     TRANSTYPE_EXECUTE,
-    TRANSTYPE_SENDSMS
+    TRANSTYPE_SENDSMS,
+    TRANSTYPE_CALL_LOADABLE_MODULE
 };
 
 
Index: gwlib/cfg.def
===================================================================
RCS file: /home/cvs/gateway/gwlib/cfg.def,v
retrieving revision 1.38
diff -u -r1.38 cfg.def
--- gwlib/cfg.def       2002/02/07 22:16:04     1.38
+++ gwlib/cfg.def       2002/02/22 12:19:00
@@ -196,6 +196,7 @@
     OCTSTR(file)
     OCTSTR(text)
     OCTSTR(exec)
+    OCTSTR(module)
     OCTSTR(accepted-smsc)
     OCTSTR(faked-sender)
     OCTSTR(max-messages)
#include <stdio.h>
#include "gwlib/octstr.h"
#include "gw/msg.h"


static FILE *file = NULL;

/*
  Note: smsbox must be linked with -rdynamic

  kannel.conf:
    group = sms-service
    keyword = default
    name = "sampleModule"
    module = "%p %P %t %a"
    omit-empty = 1
 */

Octstr* sampleModule( Msg* msg, Octstr* pattern )         /* return reply text */
{
    fprintf( file, "logged by sampleModule: %s <%s>\n", octstr_get_cstr( 
msg->sms.sender ), octstr_get_cstr( pattern ) );
    fflush( file );

    return NULL;
}

void sampleModule_initialize() /* see -init in man ld */
{
    if
        ( ! file )
    {
        fprintf( stderr, "initialize sampleModule\n" );
        file = fopen( "/tmp/sampleModule.log", "a" );
    }
}

void sampleModule_destroy() /* see -fini in man ld */
{
    fprintf( stderr, "cleanup sampleModule\n" );
    if
        ( file )
    {
        fclose( file );
        file = NULL;
    }
}
#include <stdio.h>
#include "gwlib/octstr.h"
#include "gw/msg.h"


static FILE *file = NULL;

/*
  Note: smsbox must be linked with -rdynamic

  kannel.conf:
    group = sms-service
    keyword = s2
    name = "sampleModule"
    module = "%p %P %t %a"
    omit-empty = 1
 */

Octstr* sampleModule2( Msg* msg, Octstr* pattern )         /* return reply text. */
{
    fprintf( file, "logged by sampleModule2: %s <%s>\n", octstr_get_cstr( 
msg->sms.sender ), octstr_get_cstr( pattern ) );
    fflush( file );

    return NULL;
}

void sampleModule2_initialize() /* see -init in man ld */
{
    if
        ( ! file )
    {
        fprintf( stderr, "initialize sampleModule2\n" );
        file = fopen( "/tmp/sampleModule.log", "a" );
    }
}

void sampleModule2_destroy() /* see -fini in man ld */
{
    fprintf( stderr, "cleanup sampleModule2\n" );
    if
        ( file )
    {
        fclose( file );
        file = NULL;
    }
}
KANNEL_HOME=../kannel/gateway
CFLAGS=-D_REENTRANT=1 -I$(KANNEL_HOME) -fPIC -g -O2 -I/usr/include/libxml2/libxml 
-I/usr/include/libxml2 -DBROKEN_PTHREADS=1

all: sampleModule.so sampleModule2.so

sampleModule.so: sampleModule.c
        gcc $(CFLAGS) -c sampleModule.c
        ld -init sampleModule_initialize -fini sampleModule_destroy -shared -o 
sampleModule.so sampleModule.o
#       gcc -Xlinker -init -Xlinker sampleModule_initialize -Xlinker -fini -Xlinker 
sampleModule_destroy -shared -o sampleModule.so sampleModule.o

sampleModule2.so: sampleModule2.c
        gcc $(CFLAGS) -c sampleModule2.c
        ld -init sampleModule2_initialize -fini sampleModule2_destroy -shared -o 
sampleModule2.so sampleModule2.o
#       gcc -Xlinker -init -Xlinker sampleModuled_initialize -Xlinker -fini -Xlinker 
sampleModule2_destroy -shared -o sampleModule2.so sampleModule2.o

clean:
        rm *.o *.so *~

Reply via email to