Hi,

We are working on a project which consists in a DB migration (move from a 
proprietary solution to Cassandra).
Among the modules communicating with the DB, there is a Radius Server, based on 
the open source FreeRadius 2.2. So we have modified the source code of this 
server and added a specific module to call Cassandra, but we have an issue.
We are using the DataStax C driver. The FreeRadius is in multithread mode, with 
pthreads.

Our modifications are the following :

*       In the instantiate part of the module (called once by the main process 
at the beginning), we do the following code

ape_main_context = (APE_MAIN_CONTEXT *) malloc(sizeof(APE_MAIN_CONTEXT));
ape_main_context->cluster = cass_cluster_new();
cass_cluster_set_contact_points(ape_main_context->cluster, "dse5");

The APE_MAIN_CONTEXT is a structure used to pass info between the threads, 
which contains among other information, the Cassandra cluster.
Once the cluster is created (with only 1 contact point, called "dse5"), we 
continue with the following code :

ape_main_context->session = cass_session_new();
CassFuture* connect_future = 
cass_session_connect_keyspace(ape_main_context->session, 
ape_main_context->cluster, "ape01");
CassError rc = cass_future_error_code(connect_future);
cass_future_free(connect_future);

This will create the session in the main process.

*       In the authorize part of the module (which is called in a worker 
thread, spawn by the main process), we actually call the Cassandra DB, with the 
following code :

CassString insert_query = cass_string_init("select * from ape01.session where 
ip_user= ? ;");
CassStatement* statement = cass_statement_new(insert_query, 1);
cass_statement_bind_string(statement, 0, 
cass_string_init("10000FFFFFF10000FFFFFF1000000001"));
CassFuture* query_future = 
cass_session_execute(request->thread_context->main_context->session, statement);
CassResult* result = cass_future_get_result(query_future);
if (result == NULL) {
        printf("rlm_cassandra : Query result KO");
        return RLM_MODULE_HANDLED;
}
cass_future_free(query_future);
CassRow* row = cass_result_first_row(result);
CassString key;
cass_value_get_string(cass_row_get_column_by_name(row, "ip_user"), &key);
printf("rlm_cassandra : resultat ip_user : <%s>\n",key.data);
cass_result_free(result);
cass_statement_free(statement);


When we start the server, we notice that the instantiate part of the modules is 
executed without error (we have added some logs).
However, when we use a Radius client to send an authorize request, the module 
function is launched in a worker thread, but remains blocked somewhere.
We suspect a signal issue. The call flow would be the following :

*       Call the instantiate function of the module (create the Cassandra 
cluster and session)
*       Initialize other things (free radius code), erasing a signal handler 
which is useful for the Cassandra driver
*       Spawn the worker threads and enter an event loop in each thread
*       On reception of a request, a worker thread handles it and gets blocked

As a workaround, we have moved the creation  of the Cassandra session in the 
beginning of the working thread (before entering the event loop). We create 
only 1 session (we use a mutex and a static Boolean first=true at the beginning 
and set to false in the protected code).
So the call flow becomes :

*       Call the instantiate function of the module (create the Cassandra 
cluster only)
*       Initialize other things (free radius code)
*       Spawn the worker threads, create 1 Cassandra session for all threads 
(static Boolean + mutex), and enter an event loop in each thread
*       On reception of a request, a worker thread handles it and it works

So, we manage to make a Cassandra call with a workaround, if the Cassandra 
session is created after the FreeRadius init.

Finally, to confirm the idea, we have written a standalone module, in C with a 
main process spawning threads with exactly the same schema.
In this case, the call flow becomes :

*       Call the instantiate function of the module (create the Cassandra 
cluster and session)
*       Spawn the worker threads which make a call to Cassandra using the 
cluster and session created in the main process. The call works.

Our questions are the following :

*       Is the "signal" idea credible for you ?
*       Do you know the useful signals for the Cassandra driver ?
*       Is it a possibility to use another signal which would be compatible 
with freeRadius ?
*       Any other idea to resolve this issue ?

Many thanks in advance.

Ben


Reply via email to