On Tuesday 24 June 2008 13:57:25 Stipe Tolj wrote:
> Artem Pylypchuk schrieb:
> > Hello users Kannel mailing list!
> > I would like to inform you, that I've written some code for Kannel that
> > can be used for MSISDN provisioning over LDAP queries, with a flexible
> > failover/fallback mechanism (as required by our carrier partner). Please
> > consider adding it to your addons page.
> >
> > The page with the addon is http://juice.org.ua (merged with my personal
> > page), the patch is at http://juice.org.ua/patch
> > Please note, that it's still just a sketch (i.e. [pre-]alpha), so it's
> > not integrated into configure script, and also, the question remains what
> > to do with the existing RADIUS accounting module (disable by config?).
> > Everything else works just fine (lookups, failover, failover fallback
> > dummy checking & configuration reading).
>
> Hi Artem,
>
> thanks a lot for sharing your work with us. We appreciate your
> contribution highly. And I'd like to advocate and support you in getting
> the code into our main CVS HEAD branch so we see it available in
> upcoming releases.
>
> First of all, please switch to the 'devel' mailing list instead for
> this, since it's more related to development itself then usage
> questions. That's why I have cross-posted to devel@ too in this response.
>
> I see 4 points here we need to do to get the code into the mainline CVS
> branch:
>
> - apply our doc/CodingStyle guide lines to your source code files. To be
> honest, they are way to "sloppy" and don't match our "style" ;)
>
> - apply your changes to CVS HEAD instead of 1.4.1 stable and create a
> 'diff -u' patch, so we can post a clean patch to the mailing list for
> letting other developers review it and vote on it's commitment.
>
> - I guess OpenLDAP is the point of choice for the LDAP directory
> backend? I can do the configure[.in] et al preparation for this, so we
> have a clean build process w/o LDAP support.
>
> - Concerning RADIUS acct vs. LDAP I would suggest the following way:
> make the backend storage type configurable via config directive
> 'msisdn-storage' in the wapbox group. This config directive will be
> interpreted and we simply use a neutral function pointer that is pointed
> to the implementation function call name, ergo we don't need runtime
> checks, it's just one check while startup and while runtime our module
> calls the function it has been configured for. The function calls are
> defined as public functions in it's modules, as is.
>
> Looking forward to your updates patch to devel mailing list ;)
>
> > Thanks for your attention.
>
> You're welcome. Good work so far. I hope you understand that we need to
> fit our guide lines before applying changes to the CVS branch.
>
> Stipe
>
> -------------------------------------------------------------------
> Kölner Landstrasse 419
> 40589 Düsseldorf, NRW, Germany
>
> tolj.org system architecture      Kannel Software Foundation (KSF)
> http://www.tolj.org/              http://www.kannel.org/
>
> mailto:st_{at}_tolj.org           mailto:stolj_{at}_kannel.org
> -------------------------------------------------------------------



Per our conversation with Stipe Tolj earlier, I have prepared the ldap msisdn 
provisioning patch against the cvs tree.

There are still some (a lot?) non-conformings to the Kannel coding standards 
and other problems -
1) in several places I use ldap_perror() to dump errors into stderr, because 
of the bugs in openldap library not allowing to get a normal error string 
from it. This problem is still getting fixed (see 
https://savannah.cern.ch/bugs/?17445)
2) I use a struct with pthread_cond_t in pair with pthread_mutex_t instead of 
using gwlib's implementation of mutexes (this can be easily replaced).
3) there are lots of FIXMEs in the code, which are worth paying attention
4) some output may have to be changed from info to debug
5) some debug output should be removed
6) there are commented out stubs in the code
7) I didn't create any testing in configure for openldap version or existance 
(the version I used when developing ldap_acct.c was openldap-2.2.13-4, it can 
easily be minimal; the one I use now is 2.3.41). Possibly, the bug mentioned 
in 1) will be (was) fixed, and some config logic is needed.

In spite of the problems mentioned above, I want you to review this code and 
express your opinions about it.

Some implementation info, you may need:

1) the code (not in cvs tree) should be placed to ldap/ldap_acct.{c,h} and the 
patch should be applied.
2) ldap provisioning can be disabled by --disable-ldap config option 
(NO_LDAP_PROVISIONING symbol)
3) failover scheme is briefly documented at http://juice.org.ua/kannel.htm
4) the ldap_arg struct is supposed to carry the info about a hash table entry, 
and a corresponding lock for the lookup of a msisdn<>ip pair; it includes a 
pthread_cond_t to signal other lookups of the same pair, that get locked.

Looking forward to hearing from you, 
Artem Pylypchuk

/* ====================================================================
 * The Kannel Software License, Version 1.0
 *
 * Copyright (c) 2001-2008 Kannel Group
 * Copyright (c) 1998-2001 WapIT Ltd.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Kannel Group (http://www.kannel.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Kannel" and "Kannel Group" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please
 *    contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Kannel",
 *    nor may "Kannel" appear in their name, without prior written
 *    permission of the Kannel Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Kannel Group.  For more information on
 * the Kannel Group, please see <http://www.kannel.org/>.
 *
 * Portions of this software are based upon software originally written at
 * WapIT Ltd., Helsinki, Finland for the Kannel project.
 */

/*
 * ldap_acct.c - LDAP accounting proxy thread
 *
 * Artem Pylypchuk <[EMAIL PROTECTED]>
 */


#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>

#include <time.h>

#include <ldap.h>


#include "gwlib/gwlib.h"
#include "gwlib/utils.h"

#include "ldap/ldap_acct.h"


static Dict *ldap_table = NULL;      /* maps client ip -> msisdn */

#define LDAP_LOOKUP_TABLE_SIZE    30         /* default ldap hash table size */
#define LDAP_CACHE_STALE_TIME     5          /* hash table ip stale time, sec. */
#define LDAP_RETRIES              2          /* number of lookup retries */
#define LDAP_PORT   389   /* add to options, if you use non-standard ports */
#define DBG_PLACE "wap.ldap"

//ldap_lookup_msisdn error codes
#define OK 0
#define LDAPSEARCH_TIMEOUT 1  /*(condition X)*/
#define BIND_ERROR 2 /*(condition Y)*/
#define IP_TIMEOUT 3 /*(condition Z)*/
#define SEARCH_ERROR 4 /*(schema bugs on server or in config)*/
#define CONCURRENT_FAILS_LIM_EXCEEDED 5 /* FIXME to be implemented optionally */
#define NO_RESULT 6
#define NULL_VALUE 7
#define FATAL 8
#define VERY_FATAL 9 /* means a panic shutdown */

#define RESET_RETRIES 2 /* for jumpoff_server(), means reset counters return signal */

static Mutex *ldap_mutex = NULL; /* though, the dictionary itself provides locking, I use this mutex for write sychro */

static Octstr *unified_prefix;

/*static int run_thread = 0; */ /* not here */
static List *ldap_servers_list;
static Octstr *ldap_bind_dn, *ldap_bind_passwd, *ldap_search_dn, *ldap_search_filter, *ldap_search_attr_name;
static int ldap_timeout_s = 2, ldap_timeout_mrs = 0, ldap_cache_stale_time = LDAP_CACHE_STALE_TIME, ldap_retries_x = LDAP_RETRIES, ldap_retries_y = LDAP_RETRIES, ldap_retries_z = LDAP_RETRIES;

static int on_server = 1, num_servers = 2; /* index of the server we run at, number of failover servers */

static int dummy_request_interval = 5, dummy_thread_running = 1, dummy_test_first_server = 0; /* the dummy request interval(for revertion in servers list) in seconds */
static long dummy_request_thread = 0;
static Octstr *dummy_request_ip;

/* use this struct to pass the Octstr with ip + locking cond to the ldap lookup thread or other threads waiting for the same ip */
typedef struct ldap_arg ldap_arg;
struct ldap_arg {
    pthread_cond_t *cond;
    pthread_mutex_t *mutex;
    Octstr *str;
    int fail_flag;
    time_t time;
};

/*
 * ldap_get_errstr - a function that is supposed to return an error string
 * Unfortunately, in some cases it can't be used because of a bug
 * https://savannah.cern.ch/bugs/?17445
 * that is not yet fixed ( openldap 2.2.13-4 )
 */
char *ldap_get_errstr(LDAP *ldap, LDAPMessage *res)
{

    return ldap_err2string(ldap_result2error(ldap, res, 1)); /* 1 stands for freeing res */

}


static char *get_server(int *giveup)
{
    //need to implement an overflow check

    int fetch;

    mutex_lock(ldap_mutex); /* to get a 'right' server number */
    if (on_server > num_servers) {
        fetch = num_servers; /* return the last already known to be failed server to a requester that will most definetly fail */
        if (giveup != NULL) {
            *giveup = 1; /* signal to give up trying */
            mutex_unlock(ldap_mutex);
            return NULL;
        }
    } else fetch = on_server;

    char *server = octstr_get_cstr( (Octstr *)gwlist_get(ldap_servers_list, fetch - 1) );
    mutex_unlock(ldap_mutex);

    debug(DBG_PLACE, 0, "get_server: fetched server %i from %i - %s.", fetch, num_servers, server); /* generally I avoid using output, when locked ;) */

    return server;
}


/*
 * ldap_lookup_msisdn - does the timed out real lookup
 * and returns one of the predefined results:
 *
 *OK
 *LDAPSEARCH_TIMEOUT (condition X)
 *BIND_ERROR (condition Y)
 *IP_TIMEOUT (condition Z)
 *SEARCH_ERROR (schema bugs on server)
 *CONCURRENT_FAILS_LIM_EXCEEDED (to be implemented optionally)
 *NO_RESULT
 *NULL_VALUE
 *FATAL
 *VERY_FATAL (not implemented)
*/

int ldap_lookup_msisdn(Octstr *client_ip, ldap_arg *arg, char *use_server)

{
    /* this is the func that does the timed out real lookup */

    LDAP *ldap;
    LDAPMessage *res, *e;
    struct timeval *timeout;
    Octstr *str;
    char **vals;


    /* a nanosleep stub for testing a 'slow' ldap server */
    //struct timespec *tc;
    //tc = gw_malloc(sizeof(struct timespec));
    //tc->tv_sec=2;
    //tc->tv_nsec=0;
    //debug(DBG_PLACE, 0, "LDAP SLEEPING NANOSLEEP %i sec.", tc->tv_sec);
    //nanosleep(tc, NULL);
    //gw_free(tc);
    //arg->str = octstr_create("+380973400664");
    //return 0;


    /* normal function code */
    int err, giveup = 0;
    char *server;

    if (use_server == NULL) {
        server = get_server(&giveup);

        if (giveup) {
            warning(0, "ldap-acct: failover is in the state of no working servers. All requests are skipped. AWAITING RECOVERY.");
            return VERY_FATAL;
        }
    } else server = use_server;

    if ( ldap_initialize(&ldap, server) != 0 ) {
        warning(0, "Servers ldap_init failed \"%s\". Possibly no resources or wrong url (panic, but never stop).", server);
        return FATAL;
    }
    debug(DBG_PLACE, 0, "ldap_initialize: ok. Server %s.", server);

    /* FIXME only plaintext authorization
       FIXME the credentials are the same for all servers :)  .Juice */

    /* authenticate as nobody */

    char *id = NULL, *pass = NULL;

    if (ldap_bind_dn != NULL) {
        id = octstr_get_cstr(ldap_bind_dn); //search for those in the coredumps ;)
    }
    if (ldap_bind_passwd != NULL) {
        pass = octstr_get_cstr(ldap_bind_passwd);
    }

    debug(DBG_PLACE, 0, "bind creds: %s, %s", id, pass);

    if ( (err = ldap_bind_s(ldap, id, pass, LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS ) {
        /*BUG: warning( 0, "ldap-acct.ldap_lookup_msisdn: ldap_simple_bind_s failure: %s.", ldap_get_errstr(ldap, res)); */
        /*bug when meeting an ip timeout or bind error fault with "../../../libraries/liblber/io.c:296: ber_dup: Assertion `ber != ((void *)0)' failed."
        see https://savannah.cern.ch/bugs/?17445 for reference using a stderr dump :( */

        /* FIXME this works just fine - not conforming to coding style thus */
        ldap_perror( ldap, "ldap-acct.ldap_lookup_msisdn: ldap_bind_s failed with " );

        debug(DBG_PLACE, 0, "ldap_bind_s error %i", err);
        ldap_unbind(ldap); /* this also frees up resources */
        switch (err) {
        case LDAP_TIMEOUT:
            return LDAPSEARCH_TIMEOUT;
        case LDAP_INVALID_CREDENTIALS:
            warning(0, "ldap-acct - FATAL: Server bind credentials are wrong. Contact your provider.");
        default:
            return FATAL;
        }
    }
    debug(DBG_PLACE, 0, "ldap_bind_s: ok.");

    timeout = gw_malloc(sizeof(struct timeval));
    timeout->tv_sec  = ldap_timeout_s;
    timeout->tv_usec = ldap_timeout_mrs;

    str = octstr_format(octstr_get_cstr(ldap_search_filter), octstr_get_cstr(client_ip)); /* format the filter - use the octstr */
    if (str == NULL) {
        warning(0, "ldap-acct: the ldap filter format failed. Use the %s symbols to insert the client's ip.");
        return FATAL;
    }


    debug(DBG_PLACE, 0, "ldap_lookup_msisdn: the filter looks like - %s.", octstr_get_cstr(str));

    if ((err = ldap_search_ext_s(ldap, octstr_get_cstr(ldap_search_dn), LDAP_SCOPE_ONELEVEL, octstr_get_cstr(str), NULL, 0, NULL, NULL, timeout, 0, &res)) != LDAP_SUCCESS) {
        /* BUG: warning(0, "ldap_search returned error: %s \n", ldap_get_errstr(ldap, res)); */
        /* ldap_err2string crashes with a wrong assertion r!=NULL,
        see https://savannah.cern.ch/bugs/?17445 ; can't use it to get the right output ;(
        VER: openldap-2.2.13-4 FIXME So, using an stderr dump :( */
        warning(0, "ldap-acct.ldap_lookup_msisdn: error during ldap_search_ext_s operation.");
        ldap_perror( ldap, "ldap-acct.ldap_lookup_msisdn: ldap_search_ext_s failed with " ); //this works just fine
        gw_free(timeout);
        octstr_destroy(str);
        ldap_msgfree(res);
        ldap_unbind(ldap);

        switch (err) {
        case LDAP_TIMELIMIT_EXCEEDED:
            return LDAPSEARCH_TIMEOUT;
        case LDAP_TIMEOUT:
            return LDAPSEARCH_TIMEOUT;
        case LDAP_FILTER_ERROR: {
            warning(0, "ldap-acct - FATAL: the filter is wrong. Reconfigure needed.");
            return FATAL;
        }
        default:
            return FATAL;
        }

    }

    gw_free(timeout);
    octstr_destroy(str);

    e = ldap_first_entry( ldap, res );
    if ( e != NULL) {
        vals = (char **)ldap_get_values(ldap, e, octstr_get_cstr(ldap_search_attr_name));


        if (vals[0] == NULL) {
            warning(0, "ldap-acct.ldap_lookup_msisdn: the return value for ip %s looks like NULL. This shouldn't happen.", octstr_get_cstr(client_ip));
            ldap_value_free(vals);
            ldap_msgfree(res);
            ldap_unbind(ldap);
            return NULL_VALUE; /* this shouldn't normally happen */
        }

        Octstr *return_msisdn;

        return_msisdn = octstr_create(vals[0]);

        ldap_value_free(vals); /*FIXME: Ocststr duplicate needed? */

        debug(DBG_PLACE, 0, "ldap_lookup_msisdn: returning %s.", octstr_get_cstr(return_msisdn));

        ldap_msgfree(res);
        ldap_unbind(ldap);

        debug(DBG_PLACE, 0, "ldap_lookup_msisdn: destroying the previous msisdn, replacing with a new one.");
        octstr_destroy(arg->str);
        arg->str = return_msisdn;

        return 0;
    } else {
        warning(0, "ldap-acct.ldap_lookup_msisdn: the first result in a ldap query is NULL.");
        ldap_msgfree(res);
        ldap_unbind(ldap);
        return NO_RESULT;
    }

    /* should never get here */
    debug(DBG_PLACE, 0, "ldap_lookup_msisdn: reached the end (why?)");
    return FATAL;

}


/* a foo to delete the ldap_dictionary entry: octstr in the struct and the pthread_cond_t */
void ldap_arg_delete(ldap_arg *arg)
{
    /* mutex_lock(ldap_mutex); */ /* FIXME: currently disabled */
    octstr_destroy(arg->str); /* NULL ignored */

    if (arg->cond != NULL)
        pthread_cond_destroy(arg->cond);

    if (arg->mutex != NULL)
        pthread_mutex_destroy(arg->mutex);

    /* FIXME: add error handling here */

    /* mutex_unlock(ldap_mutex); */ /* FIXME: currently disabled */
    gw_free(arg);

}


/*
 * ldap_arg_create - allocate a new struct
*/
ldap_arg *ldap_arg_create()
{

    ldap_arg *la;

    la = gw_malloc(sizeof(ldap_arg));
    debug(DBG_PLACE, 0, "ldap_arg_create: la malloc success");
    la->cond = gw_malloc(sizeof(pthread_cond_t));
    pthread_cond_init(la->cond, NULL);
    debug(DBG_PLACE, 0, "ldap_arg_create: pthread_cond_init success");
    /* FIXME: add error handler */
    la->mutex = gw_malloc(sizeof(pthread_mutex_t)); /*FIXME: rewrite this to use gwlib Mutex struct */
    debug(DBG_PLACE, 0, "ldap_arg_create: la->mutex malloc success");
    pthread_mutex_init(la->mutex, NULL); /* one ip - one mutex */

    debug(DBG_PLACE, 0, "ldap_arg_create: mutex_init success");

    /* FIXME: add mutex creation error handler */

    la->str = NULL;
    la->time = 0;
    debug(DBG_PLACE, 0, "ldap_arg_create: la->time malloc success");
    return la;

}

static void remove_dict_record(ldap_arg *la, Octstr *client_ip)   /* a function to remove an errorneous record.. if there would be some */
{

    mutex_lock(ldap_mutex);
    dict_remove(ldap_table, client_ip);
    ldap_arg_delete(la);
    mutex_unlock(ldap_mutex);

}
/*
 * jumpoff_server - implement failover logic
 * returns:
 * 0: if we can run again
 * 1: if we've failed
 * or RESET_RETRIES to notify the caller about a server switch (and continue trying).
*/
static int jumpoff_server(int *retries_var, int retries_var_limit, char cond)   //failover logic function
{

    int result = 0;

    (*retries_var)++;
    debug(DBG_PLACE, 0, "jumpoff_server, retry %i(limit %i), server %i; after reaching cond: %c", *retries_var, retries_var_limit, on_server, cond);

    if (*retries_var > retries_var_limit) {
        warning(0, "ldap_lookup_msisdn: retries limit reached for a condition: %c. Server switching..", cond);
        mutex_lock(ldap_mutex);
        if (on_server <= num_servers) { //this can lead to *server = num_servers+1 <= this means all our servers are DEAD
            on_server++; //let the others know too
            debug(DBG_PLACE, 0, "Server switched. Now on %i.", on_server); //output when locked ;)
            result = RESET_RETRIES; //can't reset all retries from here :( the reset counters are independent
        } else {
            warning(0, "ldap_lookup_msisdn: All servers failed.");
            result = 1;
        };
        mutex_unlock(ldap_mutex);

    } else { //continue trying
        debug(DBG_PLACE, 0, "moving to the next try %i (limit %i)", *retries_var, retries_var_limit);
        result = 0;
    }

    return result;
}


/*
 * jump_jumpoff_server - a simple workaround, leads to an immediate server switch (jumpoff)
 */
static inline int jump_jumpoff_server()
{
    int tmp = 1;
    return jumpoff_server(&tmp, 0, 'E');

}

/*
 * start_lookup - an entry function of lookup and it's failover
 *
 */
static int start_lookup(Octstr *client_ip, ldap_arg *la)
{
    int retries = 0, retries_x = 0, retries_y = 0, retries_z = 0, i, failed = 0;


    debug(DBG_PLACE, 0, "ldap_lookup_msisdn: locking the mutex for ip %s.", octstr_get_cstr(client_ip));
    pthread_mutex_lock(la->mutex); /* we lock the all ip-specific requests by this, making other wait for the msisdn fetch */
    la->fail_flag = 0;
    info(0, "ldap_acct_get_msisdn: start_lookup for %s ip.", octstr_get_cstr(client_ip));

    while ((i = (ldap_lookup_msisdn(client_ip, la, NULL))) != 0) { /* pass the 2 params here - ip & la; NULL stands for autofetch server  */
        retries++;

        switch (i) {
        case LDAPSEARCH_TIMEOUT: { /*(condition X)*/
            debug(DBG_PLACE, 0, "ldapsearch_timeout reached in start_lookup");
            failed = jumpoff_server(&retries_x, ldap_retries_x, 'X');
            break;
        }

        case BIND_ERROR: { /*(condition Y)*/
            debug(DBG_PLACE, 0, "bind_error reached in start_lookup");
            failed = jumpoff_server(&retries_y, ldap_retries_y, 'Y');
            break;
        }

        case IP_TIMEOUT: { /*(condition Z)*/
            debug(DBG_PLACE, 0, "ip_timeout reached in start_lookup");
            failed = jumpoff_server(&retries_z, ldap_retries_z, 'Z');
            break;
        }

        case SEARCH_ERROR: {/* (schema bugs on server)*/
            debug(DBG_PLACE, 0, "search_error reached in start_lookup");
            failed = jump_jumpoff_server();
            break;
        }

        /*CONCURRENT_FAILS_LIM_EXCEEDED //to be implemented optionally */

        case VERY_FATAL: {
            failed = 1;
            break;
        }

        case NO_RESULT: {
            failed = 1;
            info(0, "ldap-acct: the ldap query has returned an empty result for ip %s.", octstr_get_cstr(client_ip));
            break;
        }

        default: { /* others: NO_RESULT, NULL_VALUE, FATAL */
            debug(DBG_PLACE, 0, "FATAL reached in start_lookup, code %i.", i);
            failed = jump_jumpoff_server();
        }
        }

        if (failed == RESET_RETRIES) {
            retries_x = retries_y = retries_z = 0;
            debug(DBG_PLACE, 0, "retries have been reset..");
        }

        if ( failed == 1 ) {
            warning(0, "The LDAP lookup for IP %s failed after total: %i retries.", octstr_get_cstr(client_ip), retries);
            //mutex_lock(ldap_mutex); //avoid surprizes

            la->fail_flag = 1;

            pthread_mutex_unlock(la->mutex); //avoid lockup
            pthread_cond_signal(la->cond);


            /* remove_dict_record(la, client_ip); */ /* FIXME: Question: do we need to unlock the mutex before destroying it? What happens with the others waiting?? */
            /* mutex_unlock(ldap_mutex); */
            return 1;
        }

        warning(0, "ldap_acct_get_msisdn: start_lookup retrying..");
    }
    /* else - ok, process with the others */

    debug(DBG_PLACE, 0, "Got a positive result at start_lookup");

    /* sign with the time */
    time(&la->time);

    pthread_mutex_unlock(la->mutex);
    pthread_cond_signal(la->cond);


    return 0;

    /* a stub for testing logic & mutexes */
    //octstr_destroy(la->str);

    //mutex_lock(ldap_mutex);
    //la->str = octstr_create("+380973400664");
    //la->str = NULL;
    //mutex_unlock(ldap_mutex);
    //time(&la->time);

}

static Octstr *la_normalize_number(Octstr *str)
{

    Octstr *r;
    char *uf;

    /*FIXME: normalize the number inside la?? --i.e. remove unnecessary actions */
    r = str ? octstr_duplicate(str) : NULL;

    /* apply number normalization */
    uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL;
    normalize_number(uf, &r);

    return r;

}


/*
 * Public functions for accounting
 */


Octstr *ldap_acct_get_msisdn(Octstr *client_ip)
{
    ldap_arg *la = NULL;

    /* if ldap is not running, then pass NULL as result */
    if (ldap_table == NULL)
        return NULL;

    mutex_lock(ldap_mutex);
    la = dict_get(ldap_table, client_ip);



    mutex_unlock(ldap_mutex); /* unlock, unlock!! when exactly?? */

    debug(DBG_PLACE, 0, "ldap_acct_get_msisdn: succesfully got the table.");

    if (la != NULL) { /* ok, here we go - either start a new async lookup or wait for one to finish */
        debug(DBG_PLACE, 0, "Record not NULL, la->str = %s", octstr_get_cstr(la->str));
        if (la->cond != NULL || la->mutex != NULL) {

            if ((pthread_mutex_trylock(la->mutex)) == EBUSY) //(la->str == NULL) /* FIXME: use pthread_mutex_trylock instead, to determine the lookup progresses. */ //FIXME: error handling!
            { /* wait for another lookup to finish */
                info(0, "Waiting for ip %s other lookup to complete.", octstr_get_cstr(client_ip));
                pthread_cond_wait(la->cond, la->mutex);
                pthread_cond_signal(la->cond); //pass the signal to others (if there are some)
                if (la->fail_flag)
                    return NULL; /* the primary thread, who locked us, has failed the lookup, so now the record doesn't exist */
                else
                    return la_normalize_number(la->str);
            } else {
                pthread_mutex_unlock(la->mutex);
                info(0, "The table has a known msisdn %s for ip %s.", octstr_get_cstr(la->str), octstr_get_cstr(client_ip));
                time_t time_now;
                int diff;

                if ((time(&time_now)) != -1) {
                    if ( (la->fail_flag) || ((diff = time_now - la->time) >= ldap_cache_stale_time) ) {

                        if (!(la->fail_flag)) info(0, "but the known ip is already stale %i sec. Looking up again.", diff - ldap_cache_stale_time);
                        else info(0, "but the last known ip lookup failed. Looking up again.");

                        /*FIXME: not sure, but under certain circumstances(ldap response too long compared to ldap_cache_stale_time) - this can possibly get into infinite recursion. Other realization needed. */
                        if ((start_lookup(client_ip, la)) == 0) {
                            debug(DBG_PLACE, 0, "lcap_acct_lookup_msisdn: Relookup success.");
                            debug(DBG_PLACE, 0, "Returning the NEW re-looked-up number %s for ip %s", octstr_get_cstr(la->str), octstr_get_cstr(client_ip));
                            return la_normalize_number(la->str);
                        } else
                            return NULL; /*total failure */

                    }
                    debug(DBG_PLACE, 0, "The time difference calculated is %i (limit %i).", diff, ldap_cache_stale_time);
                } else
                    warning(0, "ldap-acct.ldap_acct_get_msisdn: can't get the system time, ignoring.");

                debug(DBG_PLACE, 0, "Returning the old known number %s for ip %s", octstr_get_cstr(la->str), octstr_get_cstr(client_ip));
                return la_normalize_number(la->str);
            };

        } else {
            warning(0, "ldap_acct_get_msisdn - logic error. The mutex associated with the ip %s is NULL. A bug somewhere. Destroying this record.", octstr_get_cstr(client_ip));
            remove_dict_record(la, client_ip);
            return NULL;
        }

    } else { /* ok, we're not in the dictionary - roll */
        debug(DBG_PLACE, 0, "ldap_acct_get_msisdn: creating a new table entry for ip %s.", octstr_get_cstr(client_ip));

        mutex_lock(ldap_mutex);

        la = ldap_arg_create();

        debug(DBG_PLACE, 0, "ldap_acct_get_msisdn: about to put record for ip %s.", octstr_get_cstr(client_ip));

        dict_put(ldap_table, client_ip, la);

        debug(DBG_PLACE, 0, "ldap_acct_get_msisdn: Succesfully put the table item for ip %s.", octstr_get_cstr(client_ip));
        mutex_unlock(ldap_mutex);


        if ((start_lookup(client_ip, la)) == 0) {
            debug(DBG_PLACE, 0, "ldap_acct_get_msisdn: at the end of the new record creation, la->str = %s.", octstr_get_cstr(la->str));
            return la_normalize_number(la->str);
        } else
            //FIXME: insert record deletion code here <= records won't be deleted
            return NULL; /* total failure */

    }
}


static void dummy_checker()
{

    debug(DBG_PLACE, 0, "ldap dummy checker timer.");

    mutex_lock(ldap_mutex);
    int on_server_local = on_server;
    mutex_unlock(ldap_mutex);


    if ((on_server_local > 1 ) || (dummy_test_first_server)) {
//do a lookup for failover revertion
        int num = on_server_local - 2; //get the previous and counting from zero
        if (num < 0 ) num = 0;
        char *server = octstr_get_cstr( (Octstr *)gwlist_get(ldap_servers_list, num) ); /* FIXME: this piece of code is not safe to server table modifications */

        ldap_arg *la;
        int result = 0;

        info(0, "Because of previous lookups failing, testing the failed server: %s.", server);
        result = ldap_lookup_msisdn(dummy_request_ip, la, server);
        debug(DBG_PLACE, 0, "the result of a dummy query was: %i", result);
        if ( (result != LDAPSEARCH_TIMEOUT) && (result != BIND_ERROR) && (result != IP_TIMEOUT) && (result != SEARCH_ERROR) && (result != FATAL ) ) { /*looks like everything's fine */

            mutex_lock(ldap_mutex); //required
            if (on_server_local == on_server) {
                if (dummy_test_first_server) dummy_test_first_server = 0;
                if (on_server == 2) dummy_test_first_server = 1;
                --on_server;
                mutex_unlock(ldap_mutex);

                info(0, "ldap-acct: switched to server %i as a result of a positive reverse dummy test.", on_server);
            } //else -> do nothing, as we somehow moved down
        } else debug(DBG_PLACE, 0, "the dummy query has failed. Running on server: %i", on_server);



    }



}

/*
 *  dummy_checker_thread - a thread that does the dummy queries, used for revertion in server list
 */
static void dummy_checker_thread()
{
//return;
    while (dummy_thread_running) {
        dummy_checker();
        gwthread_sleep(dummy_request_interval);
    }

}


/*
 * check if a required cfg entry exists
 */
static void init_cfg_check(char *name, Octstr **var, CfgGroup *grp)
{
    Octstr *str;

    debug(DBG_PLACE, 0, "Doing a check for %s variable in the config.", name);
    if ((str = cfg_get(grp, octstr_imm(name))) != NULL) {
        *var = str;
        debug(DBG_PLACE, 0, "%s = %s", name, octstr_get_cstr(*var));
    } else
        panic(0, "There's no '%s' variable in the LDAP config group!", name);

}

/*
 * set an integer variable according to the config, or leave untouched with the default value
 */
static void init_cfg_get_int(int *var, CfgGroup *grp, char *name)
{

    unsigned long tmp_var;

    Octstr *str;
    str = octstr_create(name);

    if (cfg_get_integer(&tmp_var, grp, str) == 0) {
        *var = tmp_var;
    }

    octstr_destroy(str);
    /* else leave untouched */

}



void ldap_acct_init(CfgGroup *grp)
{

    int table_size = LDAP_LOOKUP_TABLE_SIZE;
    Octstr *str;
    /*
    if ((cfg_get_integer(&table_size, grp, octstr_imm("lookup_table_size"))) == -1)
    {
      table_size = LDAP_LOOKUP_TABLE_SIZE;
    } */

    init_cfg_get_int(&table_size, grp, "lookup_table_size");

    /*FIXME: get the rest of the config here */

    ldap_servers_list = cfg_get_list(grp, octstr_imm("servers"));
    if (ldap_servers_list == NULL) {
        panic(0, "ldap-acct: there's no servers list in the config! Exiting.");
    }
    num_servers = gwlist_len(ldap_servers_list);
    debug(DBG_PLACE, 0, "we have %i servers", num_servers);

    ldap_bind_dn = cfg_get(grp, octstr_imm("bind_dn"));
    ldap_bind_passwd = cfg_get(grp, octstr_imm("bind_passwd"));

    init_cfg_check("search_dn", &ldap_search_dn, grp);
    /*ldap_search_dn="ou=msisdn dc=sonopia dc=com";*/

    init_cfg_check("search_filter", &ldap_search_filter, grp);
    /*ldap_search_filter="msisdn=%s" */

    init_cfg_check("search_attr_name", &ldap_search_attr_name, grp);

    init_cfg_get_int(&ldap_cache_stale_time, grp, "cache_stale_time");
    init_cfg_get_int(&ldap_timeout_s, grp, "ip_timeout_s");
    init_cfg_get_int(&ldap_timeout_mrs, grp, "ip_timeout_mrs");
    init_cfg_get_int(&ldap_retries_x, grp, "retries_x");
    init_cfg_get_int(&ldap_retries_y, grp, "retries_y");
    init_cfg_get_int(&ldap_retries_z, grp, "retries_z");
    init_cfg_get_int(&dummy_request_interval, grp, "dummy_request_interval");


    ldap_mutex = mutex_create();

    /* init hash tables */
    ldap_table = dict_create(table_size, (void (*)(void *))ldap_arg_delete); /* LDAP hash table will be using a struct containing the
 ip octstr, last lookup time and a pthread_cond_t */
    info(0, "ldap_acct: dictionary created");

    dummy_request_thread = gwthread_create(dummy_checker_thread, NULL);
    info(0, "ldap_acct: dummy request thread created.");

    if ( (dummy_request_ip = cfg_get(grp, octstr_imm("dummy_request_ip"))) == NULL ) dummy_request_ip = octstr_imm("0.0.0.0");

}



void ldap_acct_shutdown(void)
{
    if (ldap_mutex == NULL) /* haven't init'ed at all */
        return ;
    info(0, "LDAP: stopping..");
    /* FIXME: stop the threads that are waiting - here we wait for them */

    dummy_thread_running = 0;
    gwthread_wakeup(dummy_request_thread);
    gwthread_join(dummy_request_thread);

    mutex_lock(ldap_mutex);
    debug(DBG_PLACE, 0, "in progress..");

    dict_destroy(ldap_table);

    octstr_destroy(unified_prefix);
    octstr_destroy(dummy_request_ip);

    gwlist_destroy(ldap_servers_list, octstr_destroy_item);

    octstr_destroy(ldap_bind_dn);
    octstr_destroy(ldap_bind_passwd);
    octstr_destroy(ldap_search_dn);
    octstr_destroy(ldap_search_filter);
    octstr_destroy(ldap_search_attr_name);

    mutex_unlock(ldap_mutex);
    mutex_destroy(ldap_mutex);

    info(0, "LDAP: accounting stopped.");
}
/* ==================================================================== 
 * The Kannel Software License, Version 1.0 
 * 
 * Copyright (c) 2001-2008 Kannel Group  
 * Copyright (c) 1998-2001 WapIT Ltd.   
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 
 * 1. Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer. 
 * 
 * 2. Redistributions in binary form must reproduce the above copyright 
 *    notice, this list of conditions and the following disclaimer in 
 *    the documentation and/or other materials provided with the 
 *    distribution. 
 * 
 * 3. The end-user documentation included with the redistribution, 
 *    if any, must include the following acknowledgment: 
 *       "This product includes software developed by the 
 *        Kannel Group (http://www.kannel.org/)." 
 *    Alternately, this acknowledgment may appear in the software itself, 
 *    if and wherever such third-party acknowledgments normally appear. 
 * 
 * 4. The names "Kannel" and "Kannel Group" must not be used to 
 *    endorse or promote products derived from this software without 
 *    prior written permission. For written permission, please  
 *    contact [EMAIL PROTECTED] 
 * 
 * 5. Products derived from this software may not be called "Kannel", 
 *    nor may "Kannel" appear in their name, without prior written 
 *    permission of the Kannel Group. 
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 * ==================================================================== 
 * 
 * This software consists of voluntary contributions made by many 
 * individuals on behalf of the Kannel Group.  For more information on  
 * the Kannel Group, please see <http://www.kannel.org/>. 
 * 
 * Portions of this software are based upon software originally written at  
 * WapIT Ltd., Helsinki, Finland for the Kannel project.  
 */ 

/*
 * ldap_acct.h - LDAP accounting proxy thread declarations
 *
 * Artem Pylypchuk <[EMAIL PROTECTED]>
 */



#ifndef LDAP_ACCT_H
#define LDAP_ACCT_H

/* start the LDAP provisioning module */
void ldap_acct_init(CfgGroup *grp); 
/* a proc to lookup an msisdn from a hash table (delivered there through a LDAP guery) */
Octstr *ldap_acct_get_msisdn(Octstr *client_ip); 
/* stop the LDAP provisioning module */
void ldap_acct_shutdown(void); 


#endif
? ldap
Index: Makefile.in
===================================================================
RCS file: /home/cvs/gateway/Makefile.in,v
retrieving revision 1.85
diff -u -r1.85 Makefile.in
--- Makefile.in	24 Jun 2008 15:05:24 -0000	1.85
+++ Makefile.in	4 Jul 2008 13:44:43 -0000
@@ -91,6 +91,8 @@
 [EMAIL PROTECTED]@
 [EMAIL PROTECTED]@
 
[EMAIL PROTECTED]@
+
 # Set this to something if you want all installed binaries to have a suffix.
 # Version number is common.
 suffix = $(SUFFIX)
@@ -125,7 +127,7 @@
 libsrcs = $(wildcard gwlib/*.c) $(LIBSRCS)
 libobjs = $(libsrcs:.c=.o) $(LIBOBJS)
 
-wapsrcs = $(wildcard wap/*.c) $(wildcard radius/*.c)
+wapsrcs = $(wildcard wap/*.c) $(wildcard radius/*.c) $(WAPSRCS)
 wapobjs = $(wapsrcs:.c=.o)
 
 wmlscriptsrcs = $(wildcard wmlscript/*.c)
Index: configure
===================================================================
RCS file: /home/cvs/gateway/configure,v
retrieving revision 1.169
diff -u -r1.169 configure
--- configure	2 Jul 2008 14:56:31 -0000	1.169
+++ configure	4 Jul 2008 13:44:45 -0000
@@ -711,7 +711,8 @@
 SQLITE
 SQLITE3
 PGSQL_CONFIG
-LTLIBOBJS'
+LTLIBOBJS
+WAPSRCS'
 ac_subst_files=''
       ac_precious_vars='build_alias
 host_alias
@@ -13335,6 +13336,32 @@
 
 
 
+    { echo "$as_me:$LINENO: checking whether to compile with LDAP provisioning support" >&5
+echo $ECHO_N "checking whether to compile with LDAP provisioning support... $ECHO_C" >&6; }
+# Check whether --disable-ldap was given.
+if test "${enable_ldap+set}" = set; then
+  enableval="$enable_ldap"
+
+  if test "$enableval" = "no"
+  then
+    { echo "$as_me:$LINENO:result: disabled" >&5
+echo "${ECHO_T}disabled" >&6;}
+
+cat >>confdefs.h <<\_ACEOF
+#define NO_LDAP_PROVISIONING 1
+_ACEOF
+  else
+    { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6;}
+     LIBS="$LIBS -lldap"
+     WAPSRCS="ldap/ldap_acct.c"
+  fi
+ else
+    { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6;}
+     LIBS="$LIBS -lldap"
+     WAPSRCS="ldap/ldap_acct.c"
+fi;
 
 
 
@@ -14304,9 +14331,10 @@
 SDB_CONFIG!$SDB_CONFIG$ac_delim
 SQLITE!$SQLITE$ac_delim
 SQLITE3!$SQLITE3$ac_delim
+WAPSRCS!$WAPSRCS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 98; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
Index: gw-config.h.in
===================================================================
RCS file: /home/cvs/gateway/gw-config.h.in,v
retrieving revision 1.20
diff -u -r1.20 gw-config.h.in
--- gw-config.h.in	9 Jan 2008 20:07:01 -0000	1.20
+++ gw-config.h.in	4 Jul 2008 13:44:45 -0000
@@ -241,6 +241,9 @@
 /* Define not to include the SMS gateway parts */
 #undef NO_SMS
 
+/* Define not to include LDAP msisdn provisioning in wapbox */
+#undef NO_LDAP_PROVISIONING
+
 /* Define for various gethostbyname_r functions */
 #undef HAVE_FUNC_GETHOSTBYNAME_R_6
 #undef HAVE_FUNC_GETHOSTBYNAME_R_5
Index: gw/wap-appl.c
===================================================================
RCS file: /home/cvs/gateway/gw/wap-appl.c,v
retrieving revision 1.123
diff -u -r1.123 wap-appl.c
--- gw/wap-appl.c	5 Mar 2008 08:01:06 -0000	1.123
+++ gw/wap-appl.c	4 Jul 2008 13:44:45 -0000
@@ -98,7 +98,7 @@
 #ifdef ENABLE_COOKIES
 #include "wap/cookies.h"
 #endif
-#include "radius/radius_acct.h"
+/* #include "radius/radius_acct.h" */ /* not needed anymore */
 #include "wap-error.h"
 #include "wap-maps.h"
 
@@ -176,6 +176,11 @@
 static int have_ppg = 0;
 
 /*
+ * Storage backend msisdn provisioning
+ */
+extern Octstr (*(*storage_acct_get_msisdn)(Octstr *client_ip));
+
+/*
  * Private functions.
  */
 
@@ -631,7 +636,7 @@
      */
 
     /* We do not accept NULL values to be added to the HTTP header */
-    if ((msisdn = radius_acct_get_msisdn(addr_tuple->remote->address)) != NULL) {
+    if ((msisdn = (*storage_acct_get_msisdn)(addr_tuple->remote->address)) != NULL) {
         http_header_add(headers, octstr_get_cstr(send_msisdn_header), octstr_get_cstr(msisdn));
     }
 
@@ -1151,7 +1156,7 @@
         method = p->method;
     }
 
-    msisdn = radius_acct_get_msisdn(addr_tuple->remote->address);
+    msisdn = (*storage_acct_get_msisdn)(addr_tuple->remote->address); /* use a general call to a storage backend */
     info(0, "Fetching URL <%s> for MSISDN <%s>, IP <%s:%ld>", octstr_get_cstr(url),
          msisdn ? octstr_get_cstr(msisdn) : "", 
          addr_tuple->remote->address ? octstr_get_cstr(addr_tuple->remote->address) : "",
Index: gw/wapbox.c
===================================================================
RCS file: /home/cvs/gateway/gw/wapbox.c,v
retrieving revision 1.185
diff -u -r1.185 wapbox.c
--- gw/wapbox.c	9 Jan 2008 20:06:57 -0000	1.185
+++ gw/wapbox.c	4 Jul 2008 13:44:45 -0000
@@ -85,6 +85,10 @@
 #endif
 #include "radius/radius_acct.h"
 
+#ifndef NO_LDAP_PROVISIONING
+#include "ldap/ldap_acct.h"
+#endif
+
 static void config_reload(int reload);
 static long logfilelevel=-1;
 
@@ -120,6 +124,34 @@
 X509* x509_cert = NULL;
 #endif
 
+/* The pointer to a function doing the actual provisioning lookup via one of the backends */
+Octstr (*(*storage_acct_get_msisdn)(Octstr *client_ip));
+/* Functions for starting/stopping storage backends */
+static void (*storage_acct_init)(CfgGroup *grp);
+static void (*storage_acct_shutdown)(void);
+static Octstr *msisdn_storage; /* for reference */
+
+/* two functions for switching storages */
+#ifndef NO_LDAP_PROVISIONING
+static void switch_ldap_msisdn_storage() {
+storage_acct_get_msisdn = ldap_acct_get_msisdn;
+storage_acct_init = ldap_acct_init;
+storage_acct_shutdown = ldap_acct_shutdown;
+msisdn_storage = octstr_imm("ldap-acct");
+}
+#endif
+
+static void switch_radius_msisdn_storage() {
+storage_acct_get_msisdn = radius_acct_get_msisdn;
+storage_acct_init = radius_acct_init;
+storage_acct_shutdown = radius_acct_shutdown;
+msisdn_storage = octstr_imm("radius-acct");
+}
+
+static Octstr *get_msisdn_storage() {
+return msisdn_storage;
+}
+
 static Cfg *init_wapbox(Cfg *cfg)
 {
     CfgGroup *grp;
@@ -200,6 +232,27 @@
         octstr_destroy(s);
     }
 
+    /* choose msisdn provisioning type */
+    if ((s = cfg_get(grp, octstr_imm("msisdn-storage"))) != NULL) {
+#ifndef NO_LDAP_PROVISIONING
+	if (octstr_compare(s, octstr_imm("ldap")) == 0) {
+	switch_ldap_msisdn_storage();
+	}
+	else 
+#endif
+	     if (octstr_compare(s, octstr_imm("radius")) == 0) {
+		switch_radius_msisdn_storage();
+		} else panic(0, "msisdn-storage: unknown storage type in wapbox group.");
+
+    info(0, "Using %s as the msisdn provisioning backend.", octstr_get_cstr(s));
+#ifndef NO_LDAP_PROVISIONING
+    } else {
+    /* radius is the default behavior */
+    switch_radius_msisdn_storage();
+#endif
+    }
+
+
     /* configure the 'wtls' group */
 #if (HAVE_WTLS_OPENSSL)
     /* Load up the necessary keys */
@@ -237,14 +290,13 @@
             panic(0, "No 'privatekey-file' in wtls group");
     }
 #endif
-
     /*
-     * Check if we have a 'radius-acct' proxy group and start the
+     * Check if we have a 'radius-acct' or 'ldap-acct' proxy group and start the
      * corresponding thread for the proxy.
      */
-    grp = cfg_get_single_group(cfg, octstr_imm("radius-acct"));
+    grp = cfg_get_single_group(cfg, get_msisdn_storage());
     if (grp) {
-        radius_acct_init(grp);
+        storage_acct_init(grp); /* start msisdn storage backend */
     }
 
     /*
@@ -822,7 +874,8 @@
     wsp_unit_shutdown();
     wsp_session_shutdown();
     wap_appl_shutdown();
-    radius_acct_shutdown();
+
+    storage_acct_shutdown();
 
     if (cfg) {
         wap_push_ota_shutdown();
Index: gw/wapkannel.conf
===================================================================
RCS file: /home/cvs/gateway/gw/wapkannel.conf,v
retrieving revision 1.14
diff -u -r1.14 wapkannel.conf
--- gw/wapkannel.conf	9 Jan 2006 20:42:08 -0000	1.14
+++ gw/wapkannel.conf	4 Jul 2008 13:44:45 -0000
@@ -44,5 +44,24 @@
 #log-level = 0
 syslog-level = none
 #access-log = "/tmp/wapaccess.log"
+msisdn-storage = ldap
+
+group = ldap-acct
+lookup_table_size = 30
+servers = "ldap://host1 ldap://10.1.1.1:389 ldap://otherhost";
+#bind_dn = "cn:uid=pylypchuk,ou=people,dc=sonopia,dc=com"
+#bind_passwd = "secret"
+search_dn = "ou=people,dc=sonopia,dc=com"
+search_filter = "msisdn=%s"
+search_attr_name = "ip"
+cache_stale_time = 1
+ip_timeout_s = 2
+ip_timeout_mrs = 0
+retries_x = 2
+retries_y = 2
+retries_z = 2
+dummy_request_interval = 5
+dummy_request_ip = 10.1.3.223
+
 
 
Index: gwlib/cfg.def
===================================================================
RCS file: /home/cvs/gateway/gwlib/cfg.def,v
retrieving revision 1.133
diff -u -r1.133 cfg.def
--- gwlib/cfg.def	24 Jun 2008 09:10:04 -0000	1.133
+++ gwlib/cfg.def	4 Jul 2008 13:44:45 -0000
@@ -159,6 +159,7 @@
     OCTSTR(concatenation)
     OCTSTR(max-messages)
     OCTSTR(wml-strict)
+    OCTSTR(msisdn-storage)
 )
 
 
@@ -581,6 +582,24 @@
     OCTSTR(unified-prefix)
 )
 
+SINGLE_GROUP(ldap-acct,
+    OCTSTR(lookup_table_size)
+    OCTSTR(servers)
+    OCTSTR(bind_dn)
+    OCTSTR(bind_passwd)
+    OCTSTR(search_dn)
+    OCTSTR(search_filter)
+    OCTSTR(search_attr_name)
+    OCTSTR(cache_stale_time)
+    OCTSTR(ip_timeout_s)
+    OCTSTR(ip_timeout_mrs)
+    OCTSTR(retries_x)
+    OCTSTR(retries_y)
+    OCTSTR(retries_z)
+    OCTSTR(dummy_request_interval)
+    OCTSTR(dummy_request_ip);
+)
+
 #undef OCTSTR
 #undef SINGLE_GROUP
 #undef MULTI_GROUP

Reply via email to