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