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