The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_sql_cassandra.c
Go to the documentation of this file.
1 /**
2  * This is free and unencumbered software released into the public domain.
3  *
4  * Anyone is free to copy, modify, publish, use, compile, sell, or
5  * distribute this software, either in source code form or as a compiled
6  * binary, for any purpose, commercial or non-commercial, and by any
7  * means.
8  *
9  * In jurisdictions that recognize copyright laws, the author or authors
10  * of this software dedicate any and all copyright interest in the
11  * software to the public domain. We make this dedication for the benefit
12  * of the public at large and to the detriment of our heirs and
13  * successors. We intend this dedication to be an overt act of
14  * relinquishment in perpetuity of all present and future rights to this
15  * software under copyright law.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  *
25  * For more information, please refer to <http://unlicense.org>
26  */
27 
28 /**
29  * $Id: 1f33130b3c83c78f7fbe2996b4d21828a6c1291e $
30  * @file rlm_sql_cassandra.c
31  * @brief Cassandra SQL driver
32  *
33  * @author Linnaea Von Lavia (le.concorde.4590@gmail.com)
34  * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
35  */
36 #define LOG_PREFIX "sql - cassandra"
37 
38 #include <freeradius-devel/server/base.h>
39 #include <freeradius-devel/util/debug.h>
40 
41 #ifdef HAVE_WDOCUMENTATION
42 DIAG_OFF(documentation)
43 #endif
44 DIAG_OFF(strict-prototypes) /* Seen with homebrew cassandra-cpp-driver 2.15.3 */
45 #include <cassandra.h>
46 DIAG_ON(strict-prototypes)
47 #ifdef HAVE_WDOCUMENTATION
48 DIAG_ON(documentation)
49 #endif
50 
51 #include "rlm_sql.h"
52 
53 /** Cassandra cluster connection
54  *
55  */
56 typedef struct {
57  CassResult const *result; //!< Result from executing a query.
58  CassIterator *iterator; //!< Row set iterator.
59 
60  TALLOC_CTX *log_ctx; //!< Prevent unneeded memory allocation by keeping a
61  //!< permanent pool, to store log entries.
62  sql_log_entry_t last_error;
64 
65 /** Cassandra driver instance
66  *
67  */
68 typedef struct {
69  CassCluster *cluster; //!< Configuration of the cassandra cluster connection.
70  CassSession *session; //!< Cluster's connection pool.
71  CassSsl *ssl; //!< Connection's SSL context.
72  bool done_connect_keyspace; //!< Whether we've connected to a keyspace.
73 
74  pthread_mutex_t connect_mutex; //!< Mutex to prevent multiple connections attempting
75  //!< to connect a keyspace concurrently.
76 
77  /*
78  * Configuration options
79  */
80  char const *consistency_str; //!< Level of consistency required.
81  CassConsistency consistency; //!< Level of consistency converted to a constant.
82 
83  uint32_t protocol_version; //!< The protocol version.
84 
85  uint32_t connections_per_host; //!< Number of connections to each server in each
86  //!< IO thread.
87  uint32_t connections_per_host_max; //!< Maximum number of connections to each server
88  //!< in each IO threads.
89  uint32_t io_threads; //!< Number of IO threads.
90 
91  uint32_t io_queue_size; //!< Size of the the fixed size queue that stores
92  //!< pending requests.
93 
94  uint32_t io_flush_requests_max; //!< Maximum number of requests processed by an
95  //!< IO worker per flush.
96 
97  uint32_t pending_requests_high; //!< Sets the high water mark for the number of requests
98  //!< queued waiting for a connection in a connection
99  //!< pool. Disables writes to a host on an IO worker
100  //!< if the number of requests queued exceed this value.
101 
102  uint32_t pending_requests_low; //!< Sets the low water mark for the number of requests
103  //!< queued waiting for a connection in a connection
104  //!< pool. After exceeding high water mark requests,
105  //!< writes to a host will only resume once the number
106  //!< of requests fall below this value.
107 
108  uint32_t write_bytes_high; //!< High water mark for the number of bytes
109  //!< outstanding on a connection. Disables writes to
110  //!< a connection if the number of bytes queued exceed
111  //!< this value.
112 
113  uint32_t write_bytes_low; //!< Low water mark for number of bytes outstanding on
114  //!< a connection. After exceeding high water mark
115  //!< bytes, writes will only resume once the number of
116  //!< bytes fall below this value.
117 
118  uint32_t event_queue_size; //!< Sets the size of the the fixed size queue
119  //!< that stores events.
120 
121  uint32_t spawn_threshold; //!< Threshold for the maximum number of concurrent
122  //!< requests in-flight on a connection before creating
123  //!< a new connection.
124  uint32_t spawn_max; //!< The maximum number of connections that
125  //!< will be created concurrently.
126 
127  fr_time_delta_t spawn_retry_delay; //!< Amount of time to wait before attempting
128  //!< to reconnect.
130 
131  bool load_balance_round_robin; //!< Enable round robin load balancing.
132 
133  bool token_aware_routing; //!< Whether to use token aware routing.
134 
135  char const *lbdc_local_dc; //!< The primary data center to try first.
136  uint32_t lbdc_hosts_per_remote_dc; //!< The number of host used in each remote DC if
137  //!< no hosts are available in the local dc
138 
139  bool lbdc_allow_remote_dcs_for_local_cl; //!< Allows remote hosts to be used if no local
140  //!< dc hosts are available and the consistency level
141  //!< is LOCAL_ONE or LOCAL_QUORUM.
142 
143  double lar_exclusion_threshold; //!< How much worse the latency me be, compared to
144  //!< the average latency of the best performing node
145  //!< before it's penalized.
146  //!< This gets mangled to a double.
147 
148  fr_time_delta_t lar_scale; //!< Weight given to older latencies when calculating
149  //!< the average latency of a node. A bigger scale will
150  //!< give more weight to older latency measurements.
151 
152  fr_time_delta_t lar_retry_period; //!< The amount of time a node is penalized by the
153  //!< policy before being given a second chance when
154  //!< the current average latency exceeds the calculated
155  //!< threshold
156  //!< (exclusion_threshold * best_average_latency).
157 
158  fr_time_delta_t lar_update_rate; //!< The rate at which the best average latency is
159  //!< recomputed.
160  uint64_t lar_min_measured; //!< The minimum number of measurements per-host
161  //!< required to be considered by the policy.
162 
163  uint32_t tcp_keepalive; //!< How often to send TCP keepalives.
164  bool tcp_nodelay; //!< Disable TCP naggle algorithm.
165 
166  char const *tls_ca_file; //!< Path to the CA used to validate the server's
167  //!< certificate.
168  char const *tls_certificate_file; //!< Public certificate we present to the server.
169  char const *tls_private_key_file; //!< Private key for the certificate we present to the
170  //!< server.
171  char const *tls_private_key_password; //!< String to decrypt private key.
172  char const *tls_verify_cert_str; //!< Whether we validate the cert provided by the
173  //!< server.
175 
177  { L("all"), CASS_CONSISTENCY_ALL },
178  { L("any"), CASS_CONSISTENCY_ANY },
179  { L("each_quorum"), CASS_CONSISTENCY_EACH_QUORUM },
180  { L("local_one"), CASS_CONSISTENCY_LOCAL_ONE },
181  { L("local_quorum"), CASS_CONSISTENCY_LOCAL_QUORUM },
182  { L("one"), CASS_CONSISTENCY_ONE },
183  { L("quorum"), CASS_CONSISTENCY_QUORUM },
184  { L("three"), CASS_CONSISTENCY_THREE },
185  { L("two"), CASS_CONSISTENCY_TWO }
186 };
188 
190  { L("identity"), CASS_SSL_VERIFY_PEER_IDENTITY },
191  { L("no"), CASS_SSL_VERIFY_NONE },
192  { L("yes"), CASS_SSL_VERIFY_PEER_CERT }
193 };
195 
197  { FR_CONF_OFFSET("local_dc", rlm_sql_cassandra_t, lbdc_local_dc) },
198  { FR_CONF_OFFSET("hosts_per_remote_dc", rlm_sql_cassandra_t, lbdc_hosts_per_remote_dc), .dflt = "0" },
199  { FR_CONF_OFFSET("allow_remote_dcs_for_local_cl", rlm_sql_cassandra_t, lbdc_allow_remote_dcs_for_local_cl), .dflt = "no" },
201 };
202 
204  { FR_CONF_OFFSET("exclusion_threshold", rlm_sql_cassandra_t, lar_exclusion_threshold), .dflt = "2.0" },
205  { FR_CONF_OFFSET("scale", rlm_sql_cassandra_t, lar_scale), .dflt = "0.1" },
206  { FR_CONF_OFFSET("retry_period", rlm_sql_cassandra_t, lar_retry_period), .dflt = "10" },
207  { FR_CONF_OFFSET("update_rate", rlm_sql_cassandra_t, lar_update_rate), .dflt = "0.1" },
208  { FR_CONF_OFFSET("min_measured", rlm_sql_cassandra_t, lar_min_measured), .dflt = "50" },
210 };
211 
213  { FR_CONF_OFFSET_FLAGS("ca_file", CONF_FLAG_FILE_INPUT, rlm_sql_cassandra_t, tls_ca_file) },
214  { FR_CONF_OFFSET_FLAGS("certificate_file", CONF_FLAG_FILE_INPUT, rlm_sql_cassandra_t, tls_certificate_file) },
215  { FR_CONF_OFFSET_FLAGS("private_key_file", CONF_FLAG_FILE_INPUT, rlm_sql_cassandra_t, tls_private_key_file) },
216  { FR_CONF_OFFSET_FLAGS("private_key_password", CONF_FLAG_SECRET, rlm_sql_cassandra_t, tls_private_key_password) },
217 
218  { FR_CONF_OFFSET("verify_cert", rlm_sql_cassandra_t, tls_verify_cert_str) },
220 };
221 
222 static const conf_parser_t driver_config[] = {
223  { FR_CONF_OFFSET("consistency", rlm_sql_cassandra_t, consistency_str), .dflt = "quorum" },
224 
225  { FR_CONF_OFFSET("protocol_version", rlm_sql_cassandra_t, protocol_version) },
226 
227  { FR_CONF_OFFSET("connections_per_host", rlm_sql_cassandra_t, connections_per_host) },
228 
229 /*
230  * The below functions was deprecated in 2.10
231  */
232 #if (CASS_VERSION_MAJOR >= 2 && CASS_VERSION_MINOR >= 10)
233  { FR_CONF_DEPRECATED("connections_per_host_max", rlm_sql_cassandra_t, connections_per_host_max) },
234  { FR_CONF_DEPRECATED("io_flush_requests_max", rlm_sql_cassandra_t, io_flush_requests_max) },
235 
236  { FR_CONF_DEPRECATED("pending_requests_high", rlm_sql_cassandra_t, pending_requests_high) },
237  { FR_CONF_DEPRECATED("pending_requests_low", rlm_sql_cassandra_t, pending_requests_low) },
238 
239  { FR_CONF_DEPRECATED("write_bytes_high", rlm_sql_cassandra_t, write_bytes_high) },
240  { FR_CONF_DEPRECATED("write_bytes_low", rlm_sql_cassandra_t, write_bytes_low) },
241 
242  { FR_CONF_DEPRECATED("spawn_threshold", rlm_sql_cassandra_t, spawn_threshold) },
243  { FR_CONF_DEPRECATED("spawn_max", rlm_sql_cassandra_t, spawn_max) },
244  { FR_CONF_DEPRECATED("spawn_retry_delay", rlm_sql_cassandra_t, spawn_retry_delay) },
245 #else
246  { FR_CONF_OFFSET("connections_per_host_max", rlm_sql_cassandra_t, connections_per_host_max) },
247  { FR_CONF_OFFSET("io_flush_requests_max", rlm_sql_cassandra_t, io_flush_requests_max) },
248 
249  { FR_CONF_OFFSET("pending_requests_high", rlm_sql_cassandra_t, pending_requests_high) },
250  { FR_CONF_OFFSET("pending_requests_low", rlm_sql_cassandra_t, pending_requests_low) },
251 
252  { FR_CONF_OFFSET("write_bytes_high", rlm_sql_cassandra_t, write_bytes_high) },
253  { FR_CONF_OFFSET("write_bytes_low", rlm_sql_cassandra_t, write_bytes_low) },
254 
255  { FR_CONF_OFFSET("spawn_threshold", rlm_sql_cassandra_t, spawn_threshold) },
256  { FR_CONF_OFFSET("spawn_max", rlm_sql_cassandra_t, spawn_max) },
257  { FR_CONF_OFFSET_IS_SET("spawn_retry_delay", FR_TYPE_TIME_DELTA, 0, rlm_sql_cassandra_t, spawn_retry_delay) },
258 #endif
259 
260  { FR_CONF_OFFSET("io_threads", rlm_sql_cassandra_t, io_threads) },
261  { FR_CONF_OFFSET("io_queue_size", rlm_sql_cassandra_t, io_queue_size) },
262 
263  { FR_CONF_OFFSET("event_queue_size", rlm_sql_cassandra_t, event_queue_size) },
264 
265  { FR_CONF_POINTER("load_balance_dc_aware", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) load_balance_dc_aware_config },
266  { FR_CONF_OFFSET("load_balance_round_robin", rlm_sql_cassandra_t, load_balance_round_robin), .dflt = "no" },
267 
268  { FR_CONF_OFFSET("token_aware_routing", rlm_sql_cassandra_t, token_aware_routing), .dflt = "yes" },
269  { FR_CONF_POINTER("latency_aware_routing", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) latency_aware_routing_config },
270 
271  { FR_CONF_OFFSET("tcp_keepalive", rlm_sql_cassandra_t, tcp_keepalive) },
272  { FR_CONF_OFFSET("tcp_nodelay", rlm_sql_cassandra_t, tcp_nodelay), .dflt = "no" },
273 
274  { FR_CONF_POINTER("tls", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) tls_config },
276 };
277 
278 /** Log callback for libcassandra
279  *
280  * libcassandra seems to use this to log global events in the library, other messages
281  * like query errors are not logged here, and should be retrieved with functions like
282  * cass_future_error_message();
283  *
284  * Messages here do not need to be made available via sql_error.
285  *
286  * @param message Contains the log message and information about its source.
287  * @param data user data (not used).
288  */
289 static void _rlm_sql_cassandra_log(CassLogMessage const *message, UNUSED void *data)
290 {
291  switch (message->severity) {
292  case CASS_LOG_CRITICAL:
293  case CASS_LOG_ERROR:
294  if (DEBUG_ENABLED3) {
295  ERROR("%s[%d] %s: %s",
296  message->file, message->line, message->function, message->message);
297  } else {
298  ERROR("%s", message->message);
299  }
300  return;
301 
302  case CASS_LOG_WARN:
303  if (DEBUG_ENABLED3) {
304  WARN("%s[%d] %s: %s",
305  message->file, message->line, message->function, message->message);
306  } else {
307  WARN("%s", message->message);
308  }
309  return;
310 
311  case CASS_LOG_INFO:
312  case CASS_LOG_DISABLED:
313  case CASS_LOG_LAST_ENTRY:
314  if (DEBUG_ENABLED3) {
315  INFO("%s[%d] %s: %s",
316  message->file, message->line, message->function, message->message);
317  } else {
318  INFO("%s", message->message);
319  }
320  return;
321 
322  case CASS_LOG_DEBUG:
323  case CASS_LOG_TRACE:
324  default:
325  if (DEBUG_ENABLED3) {
326  DEBUG3("%s[%d] %s: %s",
327  message->file, message->line, message->function, message->message);
328  } else {
329  DEBUG2("%s", message->message);
330  }
331  return;
332  }
333 }
334 
335 /** Replace the last error messages associated with the connection
336  *
337  * This could be modified in future to maintain a circular buffer of log entries,
338  * but it's not required for now.
339  *
340  * @param conn to replace log message in.
341  * @param message from libcassandra.
342  * @param len of message.
343  */
344 static void sql_set_last_error(rlm_sql_cassandra_conn_t *conn, char const *message, size_t len)
345 {
346  talloc_free_children(conn->log_ctx);
347 
348  conn->last_error.msg = fr_asprint(conn->log_ctx, message, len, '\0');
349  conn->last_error.type = L_ERR;
350 }
351 
352 
353 /** Replace the last error messages associated with the connection
354  *
355  * This could be modified in future to maintain a circular buffer of log entries,
356  * but it's not required for now.
357  *
358  * @param conn to replace log message in.
359  * @param fmt of message.
360  * @param ... args.
361  */
362 static void sql_set_last_error_printf(rlm_sql_cassandra_conn_t *conn, char const *fmt, ...)
363  CC_HINT(format (printf, 2, 3));
364 static void sql_set_last_error_printf(rlm_sql_cassandra_conn_t *conn, char const *fmt, ...)
365 {
366  va_list ap;
367 
368  talloc_free_children(conn->log_ctx);
369 
370  va_start(ap, fmt);
371  conn->last_error.msg = talloc_vasprintf(conn->log_ctx, fmt, ap);
372  va_end(ap);
373  conn->last_error.type = L_ERR;
374 }
375 
377 {
378  DEBUG2("Socket destructor called, closing socket");
379 
380  if (conn->iterator) cass_iterator_free(conn->iterator);
381  if (conn->result) cass_result_free(conn->result);
382 
383  return 0;
384 }
385 
387 {
389  rlm_sql_cassandra_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->dl_inst->data, rlm_sql_cassandra_t);
390 
391  MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_cassandra_conn_t));
392  talloc_set_destructor(conn, _sql_socket_destructor);
393 
394  /*
395  * We do this one inside sql_socket_init, to allow pool.start = 0 to
396  * work as expected (allow the server to start if Cassandra is
397  * unavailable).
398  */
399  if (!inst->done_connect_keyspace) {
400  CassFuture *future;
401  CassError ret;
402 
403  pthread_mutex_lock(&inst->connect_mutex);
404  if (!inst->done_connect_keyspace) {
405  /*
406  * Easier to do this here instead of mod_instantiate
407  * as we don't have a pointer to the pool.
408  */
409  cass_cluster_set_connect_timeout(inst->cluster, fr_time_delta_to_msec(timeout));
410 
411  DEBUG2("Connecting to Cassandra cluster");
412  future = cass_session_connect_keyspace(inst->session, inst->cluster, config->sql_db);
413  ret = cass_future_error_code(future);
414  if (ret != CASS_OK) {
415  const char *msg;
416  size_t msg_len;
417 
418  cass_future_error_message(future, &msg, &msg_len);
419  ERROR("Unable to connect: [%x] %s", (int)ret, msg);
420  cass_future_free(future);
421  pthread_mutex_unlock(&inst->connect_mutex);
422 
423  return RLM_SQL_ERROR;
424  }
425  cass_future_free(future);
426  inst->done_connect_keyspace = true;
427  }
428  pthread_mutex_unlock(&inst->connect_mutex);
429  }
430  conn->log_ctx = talloc_pool(conn, 1024); /* Pre-allocate some memory for log messages */
431 
432  return RLM_SQL_OK;
433 }
434 
435 static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config, char const *query)
436 {
437  rlm_sql_cassandra_conn_t *conn = handle->conn;
438  rlm_sql_cassandra_t *inst = talloc_get_type_abort(handle->inst->driver_submodule->dl_inst->data, rlm_sql_cassandra_t);
439 
440  CassStatement *statement;
441  CassFuture *future;
442  CassError ret;
443 
444  statement = cass_statement_new_n(query, talloc_array_length(query) - 1, 0);
445  if (inst->consistency_str) cass_statement_set_consistency(statement, inst->consistency);
446 
447  future = cass_session_execute(inst->session, statement);
448  cass_statement_free(statement);
449 
450  ret = cass_future_error_code(future);
451  if (ret != CASS_OK) {
452  char const *error;
453  size_t len;
454 
455  cass_future_error_message(future, &error, &len);
456  sql_set_last_error(conn, error, len);
457  cass_future_free(future);
458 
459  switch (ret) {
460  case CASS_ERROR_SERVER_SYNTAX_ERROR:
461  case CASS_ERROR_SERVER_INVALID_QUERY:
462  return RLM_SQL_QUERY_INVALID;
463 
464  default:
465  return RLM_SQL_ERROR;
466  }
467  }
468 
469  conn->result = cass_future_get_result(future);
470  cass_future_free(future);
471 
472  return RLM_SQL_OK;
473 }
474 
476 {
477  rlm_sql_cassandra_conn_t *conn = handle->conn;
478 
479  return conn->result ? cass_result_column_count(conn->result) : 0;
480 }
481 
483 {
484  rlm_sql_cassandra_conn_t *conn = handle->conn;
485 
486  return conn->result ? cass_result_row_count(conn->result) : 0;
487 }
488 
489 static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
490 {
491  rlm_sql_cassandra_conn_t *conn = handle->conn;
492 
493  unsigned int fields, i;
494  char const **names;
495 
496  fields = sql_num_fields(handle, config);
497  if (fields == 0) return RLM_SQL_ERROR;
498 
499  MEM(names = talloc_array(handle, char const *, fields));
500 
501  for (i = 0; i < fields; i++) {
502  const char *col_name;
503  size_t col_name_len;
504 
505  /* Writes out a pointer to a buffer in the result */
506  if (cass_result_column_name(conn->result, i, &col_name, &col_name_len) != CASS_OK) {
507  col_name = "<INVALID>";
508  }
509  names[i] = col_name;
510  }
511 
512  *out = names;
513 
514  return RLM_SQL_OK;
515 }
516 
518 {
519 
520  rlm_sql_cassandra_conn_t *conn = handle->conn;
521  CassRow const *cass_row;
522  int fields, i;
523  char **row;
524 
525 #define RLM_CASS_ERR_DATA_RETRIVE(_t) \
526 do {\
527  char const *_col_name;\
528  size_t _col_name_len;\
529  CassError _ret;\
530  if ((_ret = cass_result_column_name(conn->result, i, &_col_name, &_col_name_len)) != CASS_OK) {\
531  _col_name = "<INVALID>";\
532  }\
533  sql_set_last_error_printf(conn, "Failed to retrieve " _t " data at column %s (%d): %s", \
534  _col_name, i, cass_error_desc(_ret));\
535  TALLOC_FREE(handle->row);\
536  return RLM_SQL_ERROR;\
537 } while(0)
538 
539  if (!conn->result) return RLM_SQL_OK; /* no result */
540 
541  *out = NULL;
542 
543  /*
544  * Start of the result set, initialise the iterator.
545  */
546  if (!conn->iterator) conn->iterator = cass_iterator_from_result(conn->result);
547  if (!conn->iterator) return RLM_SQL_OK; /* no result */
548 
549  if (!cass_iterator_next(conn->iterator)) return RLM_SQL_NO_MORE_ROWS; /* no more rows */
550 
551  cass_row = cass_iterator_get_row(conn->iterator); /* this shouldn't fail ? */
552  fields = sql_num_fields(handle, config); /* get the number of fields... */
553 
554  /*
555  * Free the previous result (also gets called on finish_query)
556  */
557  talloc_free(handle->row);
558  MEM(row = handle->row = talloc_zero_array(handle, char *, fields + 1));
559 
560  for (i = 0; i < fields; i++) {
561  CassValue const *value;
562  CassValueType type;
563 
564  value = cass_row_get_column(cass_row, i);
565 
566  if (cass_value_is_null(value) == cass_true) continue;
567 
568  type = cass_value_type(value);
569  switch (type) {
570  case CASS_VALUE_TYPE_ASCII:
571  case CASS_VALUE_TYPE_TEXT:
572  case CASS_VALUE_TYPE_VARCHAR:
573  {
574  const char *str;
575  size_t len;
576 
577  if (cass_value_get_string(value, &str, &len) != CASS_OK) RLM_CASS_ERR_DATA_RETRIVE("string");
578 
579  MEM(row[i] = talloc_array(row, char, len + 1));
580  memcpy(row[i], str, len);
581  row[i][len] = '\0';
582  }
583  break;
584 
585  case CASS_VALUE_TYPE_BOOLEAN:
586  {
587  cass_bool_t bv;
588 
589  if (cass_value_get_bool(value, &bv) != CASS_OK) RLM_CASS_ERR_DATA_RETRIVE("bool");
590 
591  MEM(row[i] = talloc_zero_array(row, char, 2));
592  row[i][0] = (bv == cass_false) ? '0' : '1';
593  }
594  break;
595 
596  case CASS_VALUE_TYPE_INT:
597  {
598  cass_int32_t i32v;
599 
600  if (cass_value_get_int32(value, &i32v) != CASS_OK) RLM_CASS_ERR_DATA_RETRIVE("int32");
601 
602  MEM(row[i] = talloc_typed_asprintf(row, "%"PRId32, (int32_t)i32v));
603  }
604  break;
605 
606  case CASS_VALUE_TYPE_TIMESTAMP:
607  case CASS_VALUE_TYPE_BIGINT:
608  {
609  cass_int64_t i64v;
610 
611  if (cass_value_get_int64(value, &i64v) != CASS_OK) RLM_CASS_ERR_DATA_RETRIVE("int64");
612 
613  MEM(row[i] = talloc_typed_asprintf(row, "%"PRId64, (int64_t)i64v));
614  }
615  break;
616 
617  case CASS_VALUE_TYPE_UUID:
618  case CASS_VALUE_TYPE_TIMEUUID:
619  {
620  CassUuid uuid;
621 
622  if (cass_value_get_uuid(value, &uuid) != CASS_OK) RLM_CASS_ERR_DATA_RETRIVE("UUID");
623  MEM(row[i] = talloc_array(row, char, CASS_UUID_STRING_LENGTH));
624  cass_uuid_string(uuid, row[i]);
625  }
626  break;
627 
628  default:
629  {
630  const char *col_name;
631  size_t col_name_len;
632 
633  if (cass_result_column_name(conn->result, i, &col_name,
634  &col_name_len) != CASS_OK) col_name = "<INVALID>";
635 
637  "Failed to retrieve data at column %s (%d): Unsupported data type",
638  col_name, i);
639  talloc_free(handle->row);
640  return RLM_SQL_ERROR;
641  }
642  }
643  }
644  *out = row;
645 
646  return RLM_SQL_OK;
647 }
648 
650 {
651  rlm_sql_cassandra_conn_t *conn = handle->conn;
652 
653  if (handle->row) TALLOC_FREE(handle->row);
654 
655  if (conn->iterator) {
656  cass_iterator_free(conn->iterator);
657  conn->iterator = NULL;
658  }
659 
660  if (conn->result) {
661  cass_result_free(conn->result);
662  conn->result = NULL;
663  }
664 
665  return RLM_SQL_OK;
666 }
667 
668 static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
670 {
671  rlm_sql_cassandra_conn_t *conn = handle->conn;
672 
673  if (conn->last_error.msg && (outlen >= 1)) {
674  out[0].msg = conn->last_error.msg;
675  out[0].type = conn->last_error.type;
676  conn->last_error.msg = NULL;
677 
678  return 1;
679  }
680 
681  return 0;
682 }
683 
685 {
686  rlm_sql_cassandra_conn_t *conn = handle->conn;
687 
688  /*
689  * Clear our local log buffer, and free any messages which weren't
690  * reconfigured (so we don't leak memory).
691  */
692  talloc_free_children(conn->log_ctx);
693  memset(&conn->last_error, 0, sizeof(conn->last_error));
694 
695  return sql_free_result(handle, config);
696 }
697 
698 /*
699  * The cassandra model is different, as it's distributed, and does
700  * upserts instead of inserts...
701  *
702  * There's a good article on it here:
703  * http://planetcassandra.org/blog/how-to-do-an-upsert-in-cassandra/
704  */
706 {
707  return 1;
708 }
709 
710 static int mod_detach(module_detach_ctx_t const *mctx)
711 {
712  rlm_sql_cassandra_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_sql_cassandra_t);
713 
714  if (inst->ssl) cass_ssl_free(inst->ssl);
715  if (inst->session) cass_session_free(inst->session); /* also synchronously closes the session */
716  if (inst->cluster) cass_cluster_free(inst->cluster);
717 
718  pthread_mutex_destroy(&inst->connect_mutex);
719 
720  return 0;
721 }
722 
723 static int mod_instantiate(module_inst_ctx_t const *mctx)
724 {
725  rlm_sql_t const *parent = talloc_get_type_abort(mctx->inst->parent->data, rlm_sql_t);
726  rlm_sql_config_t const *config = &parent->config;
727  rlm_sql_cassandra_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_sql_cassandra_t);
728  bool do_tls = false;
729  bool do_latency_aware_routing = false;
730  CassCluster *cluster;
731  int ret;
732 
733 #define DO_CASS_OPTION(_opt, _x) \
734 do {\
735  CassError _ret;\
736  if ((_ret = (_x)) != CASS_OK) {\
737  ERROR("Error setting " _opt ": %s", cass_error_desc(_ret));\
738  return RLM_SQL_ERROR;\
739  }\
740 } while (0)
741 
742  if ((ret = pthread_mutex_init(&inst->connect_mutex, NULL)) < 0) {
743  ERROR("Failed initializing mutex: %s", fr_syserror(ret));
744  TALLOC_FREE(inst);
745  return -1;
746  }
747 
748  /*
749  * This has to be done before we call cf_section_parse
750  * as it sets default values, and creates the section.
751  */
752  if (cf_section_find(mctx->inst->conf, "tls", NULL)) do_tls = true;
753  if (cf_section_find(mctx->inst->conf, "latency_aware_routing", NULL)) do_latency_aware_routing = true;
754 
755  DEBUG4("Configuring CassCluster structure");
756  cluster = inst->cluster = cass_cluster_new();
757  if (!cluster) return RLM_SQL_ERROR;
758 
759  /*
760  * Parameters inherited from the top level SQL module config
761  */
762  DO_CASS_OPTION("sql_server", cass_cluster_set_contact_points(cluster, config->sql_server));
763  if (config->sql_port) DO_CASS_OPTION("sql_port", cass_cluster_set_port(cluster, config->sql_port));
764  /* Can't fail */
765  if (fr_time_delta_ispos(config->query_timeout)) {
766  cass_cluster_set_request_timeout(cluster, fr_time_delta_to_msec(config->query_timeout));
767  }
768 
769  /* Can't fail */
770  if (config->sql_login && config->sql_password) cass_cluster_set_credentials(cluster, config->sql_login,
771  config->sql_password);
772 
773  /*
774  * inst specific parameters
775  */
776  if (inst->consistency_str) {
777  int consistency;
778 
779  consistency = fr_table_value_by_str(consistency_levels, inst->consistency_str, -1);
780  if (consistency < 0) {
781  ERROR("Invalid consistency level \"%s\"", inst->consistency_str);
782  return -1;
783  }
784  inst->consistency = (CassConsistency)consistency;
785  }
786 
787  if (inst->protocol_version) {
788  DO_CASS_OPTION("protocol_version",
789  cass_cluster_set_protocol_version(inst->cluster, inst->protocol_version));
790  }
791 
792  if (inst->connections_per_host) {
793  DO_CASS_OPTION("connections_per_host",
794  cass_cluster_set_core_connections_per_host(inst->cluster,
795  inst->connections_per_host));
796  }
797 
798  /*
799  * The below functions was deprecated in 2.10
800  */
801 #if (CASS_VERSION_MAJOR <= 2 && CASS_VERSION_MINOR < 10)
802  if (inst->connections_per_host_max) {
803  DO_CASS_OPTION("connections_per_host_max",
804  cass_cluster_set_max_connections_per_host(inst->cluster,
805  inst->connections_per_host_max));
806  }
807 
808  if (inst->io_flush_requests_max) {
809  DO_CASS_OPTION("io_flush_requests_max",
810  cass_cluster_set_max_requests_per_flush(inst->cluster,
811  inst->io_flush_requests_max));
812  }
813 
814  if (inst->pending_requests_high) {
815  DO_CASS_OPTION("pending_requests_high",
816  cass_cluster_set_pending_requests_high_water_mark(inst->cluster,
817  inst->pending_requests_high));
818  }
819 
820  if (inst->pending_requests_low) {
821  DO_CASS_OPTION("pending_requests_low",
822  cass_cluster_set_pending_requests_high_water_mark(inst->cluster,
823  inst->pending_requests_low));
824  }
825 
826  if (inst->write_bytes_high) {
827  DO_CASS_OPTION("write_bytes_high",
828  cass_cluster_set_write_bytes_high_water_mark(inst->cluster,
829  inst->write_bytes_high));
830  }
831 
832  if (inst->write_bytes_low) {
833  DO_CASS_OPTION("write_bytes_low",
834  cass_cluster_set_write_bytes_low_water_mark(inst->cluster,
835  inst->write_bytes_low));
836  }
837 
838  if (inst->spawn_threshold) {
839  DO_CASS_OPTION("spawn_threshold",
840  cass_cluster_set_max_concurrent_requests_threshold(inst->cluster,
841  inst->spawn_threshold));
842  }
843 
844  if (inst->spawn_max) {
845  DO_CASS_OPTION("spawn_max",
846  cass_cluster_set_max_concurrent_creation(inst->cluster, inst->spawn_max));
847  }
848 
849  if (inst->spawn_retry_delay_is_set) {
850  cass_cluster_set_reconnect_wait_time(inst->cluster, fr_time_delta_to_msec(inst->spawn_retry_delay));
851  }
852 #endif
853 
854  if (inst->event_queue_size) {
855  DO_CASS_OPTION("event_queue_size",
856  cass_cluster_set_num_threads_io(inst->cluster, inst->event_queue_size));
857  }
858 
859  if (inst->io_queue_size) {
860  DO_CASS_OPTION("io_queue_size",
861  cass_cluster_set_num_threads_io(inst->cluster, inst->io_queue_size));
862  }
863 
864  if (inst->io_threads) {
865  DO_CASS_OPTION("io_threads", cass_cluster_set_num_threads_io(inst->cluster, inst->io_threads));
866  }
867 
868  if (inst->load_balance_round_robin) cass_cluster_set_load_balance_round_robin(inst->cluster);
869 
870  cass_cluster_set_token_aware_routing(inst->cluster, inst->token_aware_routing);
871 
872  if (inst->lbdc_local_dc) {
873  DO_CASS_OPTION("load_balance_dc_aware",
874  cass_cluster_set_load_balance_dc_aware(inst->cluster,
875  inst->lbdc_local_dc,
876  inst->lbdc_hosts_per_remote_dc,
877  inst->lbdc_allow_remote_dcs_for_local_cl));
878  }
879 
880  if (do_latency_aware_routing) {
881  /* Can't fail */
882  cass_cluster_set_latency_aware_routing(inst->cluster, true);
883 
884  /* Can't fail */
885  cass_cluster_set_latency_aware_routing_settings(inst->cluster,
886  (cass_double_t)inst->lar_exclusion_threshold,
887  fr_time_delta_to_msec(inst->lar_scale),
888  fr_time_delta_to_msec(inst->lar_retry_period),
889  fr_time_delta_to_msec(inst->lar_update_rate),
890  inst->lar_min_measured);
891  }
892 
893  if (inst->tcp_keepalive) cass_cluster_set_tcp_keepalive(inst->cluster, true, inst->tcp_keepalive);
894  cass_cluster_set_tcp_nodelay(inst->cluster, inst->tcp_nodelay);
895 
896  if (do_tls) {
897  CassSsl *ssl;
898 
899  ssl = inst->ssl = cass_ssl_new();
900  if (!ssl) return RLM_SQL_ERROR;
901 
902  if (inst->tls_verify_cert_str) {
903  int verify_cert;
904 
905  verify_cert = fr_table_value_by_str(verify_cert_table, inst->tls_verify_cert_str, -1);
906  if (verify_cert < 0) {
907  ERROR("Invalid certificate validation type \"%s\", "
908  "must be one of 'yes', 'no', 'identity'", inst->tls_verify_cert_str);
909  return -1;
910  }
911  cass_ssl_set_verify_flags(ssl, verify_cert);
912  }
913 
914  DEBUG2("Enabling TLS");
915 
916  if (inst->tls_ca_file) {
917  DO_CASS_OPTION("ca_file", cass_ssl_add_trusted_cert(ssl, inst->tls_ca_file));
918  }
919 
920  if (inst->tls_certificate_file) {
921  DO_CASS_OPTION("certificate_file", cass_ssl_set_cert(ssl, inst->tls_certificate_file));
922  }
923 
924  if (inst->tls_private_key_file) {
925  DO_CASS_OPTION("private_key", cass_ssl_set_private_key(ssl, inst->tls_private_key_file,
926  inst->tls_private_key_password));
927  }
928 
929  cass_cluster_set_ssl(cluster, ssl);
930  }
931 
932  inst->session = cass_session_new();
933  if (!inst->session) return RLM_SQL_ERROR;
934 
935  return 0;
936 }
937 
938 static void mod_unload(void)
939 {
940  /*
941  * The function cass_log_cleanup() was deprecated in 2.0.1
942  */
943 #if (CASS_VERSION_MAJOR <= 2 && CASS_VERSION_MINOR <= 0)
944  cass_log_cleanup(); /* must be last call to libcassandra */
945 #endif
946 }
947 
948 static int mod_load(void)
949 {
950  INFO("Built against libcassandra version %d.%d.%d%s",
951  CASS_VERSION_MAJOR, CASS_VERSION_MINOR, CASS_VERSION_PATCH, CASS_VERSION_SUFFIX);
952 
953  /*
954  * Setup logging callbacks (only needs to be done once)
955  */
956  cass_log_set_level(CASS_LOG_INFO);
957  cass_log_set_callback(_rlm_sql_cassandra_log, NULL);
958 
959  return 0;
960 }
961 
962 /* Exported to rlm_sql */
965  .common = {
966  .name = "sql_cassandra",
967  .magic = MODULE_MAGIC_INIT,
968  .inst_size = sizeof(rlm_sql_cassandra_t),
969  .onload = mod_load,
970  .unload = mod_unload,
973  .detach = mod_detach
974  },
975  .number = 7,
976  .sql_socket_init = sql_socket_init,
977  .sql_query = sql_query,
978  .sql_select_query = sql_query,
979  .sql_num_fields = sql_num_fields,
980  .sql_num_rows = sql_num_rows,
981  .sql_affected_rows = sql_affected_rows,
982  .sql_fields = sql_fields,
983  .sql_fetch_row = sql_fetch_row,
984  .sql_free_result = sql_free_result,
985  .sql_error = sql_error,
986  .sql_finish_query = sql_finish_query,
987  .sql_finish_select_query = sql_finish_query
988 };
va_end(args)
log_entry msg
Definition: acutest.h:794
static int const char * fmt
Definition: acutest.h:573
va_start(args, fmt)
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define DIAG_ON(_x)
Definition: build.h:419
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#define FR_CONF_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR is found
Definition: cf_parse.h:385
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Definition: cf_parse.h:310
#define FR_CONF_OFFSET_IS_SET(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct,...
Definition: cf_parse.h:282
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:256
@ CONF_FLAG_SECRET
Only print value if debug level >= 3.
Definition: cf_parse.h:410
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Definition: cf_parse.h:412
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition: cf_parse.h:400
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition: cf_util.c:970
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
Test enumeration values.
Definition: dict_test.h:92
void *_CONST data
Module instance's parsed configuration.
Definition: dl_module.h:165
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
CONF_SECTION *_CONST conf
Module's instance configuration.
Definition: dl_module.h:166
dl_module_inst_t const * inst
Definition: dl_module.h:87
dl_module_inst_t const *_CONST parent
Parent module's instance (if any).
Definition: dl_module.h:167
#define DEBUG3(_fmt,...)
Definition: log.h:266
#define DEBUG4(_fmt,...)
Definition: log.h:267
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
Definition: log.h:259
talloc_free(reap)
@ L_ERR
Error message.
Definition: log.h:56
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
Definition: merged_model.c:113
unsigned int uint32_t
Definition: merged_model.c:33
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:52
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:51
char * fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
Escape string that may contain binary data, and write it to a new buffer.
Definition: print.c:430
static const conf_parser_t config[]
Definition: base.c:188
#define DEBUG2(fmt,...)
Definition: radclient.h:43
#define WARN(fmt,...)
Definition: radclient.h:47
#define INFO(fmt,...)
Definition: radict.c:54
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1312
Prototypes and functions for the SQL module.
rlm_sql_t const * inst
The rlm_sql instance this connection belongs to.
Definition: rlm_sql.h:138
void * conn
Database specific connection handle.
Definition: rlm_sql.h:136
sql_rcode_t
Action to take at end of an SQL query.
Definition: rlm_sql.h:42
@ RLM_SQL_QUERY_INVALID
Query syntax error.
Definition: rlm_sql.h:43
@ RLM_SQL_ERROR
General connection/server error.
Definition: rlm_sql.h:44
@ RLM_SQL_OK
Success.
Definition: rlm_sql.h:45
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
Definition: rlm_sql.h:48
char ** rlm_sql_row_t
Definition: rlm_sql.h:57
rlm_sql_row_t row
Row data from the last query.
Definition: rlm_sql.h:137
Definition: rlm_sql.h:59
rlm_sql_cassandra_conn_t
static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, fr_time_delta_t timeout)
static int mod_detach(module_detach_ctx_t const *mctx)
static int mod_load(void)
static sql_rcode_t sql_fetch_row(rlm_sql_row_t *out, rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
uint32_t connections_per_host_max
Maximum number of connections to each server in each IO threads.
#define DO_CASS_OPTION(_opt, _x)
char const * lbdc_local_dc
The primary data center to try first.
uint32_t connections_per_host
Number of connections to each server in each IO thread.
uint32_t spawn_threshold
Threshold for the maximum number of concurrent requests in-flight on a connection before creating a n...
uint32_t protocol_version
The protocol version.
fr_time_delta_t lar_update_rate
The rate at which the best average latency is recomputed.
CassConsistency consistency
Level of consistency converted to a constant.
DIAG_OFF(strict-prototypes) typedef struct
Cassandra cluster connection.
static conf_parser_t load_balance_dc_aware_config[]
static void sql_set_last_error(rlm_sql_cassandra_conn_t *conn, char const *message, size_t len)
Replace the last error messages associated with the connection.
uint32_t pending_requests_high
Sets the high water mark for the number of requests queued waiting for a connection in a connection p...
uint32_t pending_requests_low
Sets the low water mark for the number of requests queued waiting for a connection in a connection po...
static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
CassSsl * ssl
Connection's SSL context.
static conf_parser_t latency_aware_routing_config[]
CassSession * session
Cluster's connection pool.
static int sql_affected_rows(UNUSED rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
uint32_t io_flush_requests_max
Maximum number of requests processed by an IO worker per flush.
pthread_mutex_t connect_mutex
Mutex to prevent multiple connections attempting to connect a keyspace concurrently.
static void sql_set_last_error_printf(rlm_sql_cassandra_conn_t *conn, char const *fmt,...))
Replace the last error messages associated with the connection.
uint32_t lbdc_hosts_per_remote_dc
The number of host used in each remote DC if no hosts are available in the local dc.
static conf_parser_t tls_config[]
fr_time_delta_t spawn_retry_delay
Amount of time to wait before attempting to reconnect.
bool lbdc_allow_remote_dcs_for_local_cl
Allows remote hosts to be used if no local.
static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
char const * tls_ca_file
Path to the CA used to validate the server's certificate.
CassCluster * cluster
Configuration of the cassandra cluster connection.
bool tcp_nodelay
Disable TCP naggle algorithm.
bool done_connect_keyspace
Whether we've connected to a keyspace.
uint32_t write_bytes_high
High water mark for the number of bytes outstanding on a connection.
static void mod_unload(void)
char const * tls_verify_cert_str
Whether we validate the cert provided by the server.
static fr_table_num_sorted_t const consistency_levels[]
char const * tls_certificate_file
Public certificate we present to the server.
uint32_t event_queue_size
Sets the size of the the fixed size queue that stores events.
double lar_exclusion_threshold
How much worse the latency me be, compared to the average latency of the best performing node before ...
char const * tls_private_key_password
String to decrypt private key.
static int sql_num_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
static const conf_parser_t driver_config[]
#define RLM_CASS_ERR_DATA_RETRIVE(_t)
static size_t consistency_levels_len
bool load_balance_round_robin
Enable round robin load balancing.
char const * consistency_str
Level of consistency required.
uint32_t io_queue_size
Size of the the fixed size queue that stores pending requests.
fr_time_delta_t lar_scale
Weight given to older latencies when calculating the average latency of a node.
static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config, char const *query)
static size_t verify_cert_table_len
static fr_table_num_sorted_t const verify_cert_table[]
uint32_t write_bytes_low
Low water mark for number of bytes outstanding on a connection.
bool token_aware_routing
Whether to use token aware routing.
uint32_t tcp_keepalive
How often to send TCP keepalives.
static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
char const * tls_private_key_file
Private key for the certificate we present to the server.
static void _rlm_sql_cassandra_log(CassLogMessage const *message, UNUSED void *data)
Log callback for libcassandra.
uint32_t io_threads
Number of IO threads.
static int mod_instantiate(module_inst_ctx_t const *mctx)
uint32_t spawn_max
The maximum number of connections that will be created concurrently.
fr_time_delta_t lar_retry_period
The amount of time a node is penalized by the policy before being given a second chance when the curr...
rlm_sql_driver_t rlm_sql_cassandra
static int _sql_socket_destructor(rlm_sql_cassandra_conn_t *conn)
uint64_t lar_min_measured
The minimum number of measurements per-host required to be considered by the policy.
Cassandra driver instance.
dl_module_inst_t * dl_inst
Structure containing the module's instance data, configuration, and dl handle.
Definition: module.h:183
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
module_t common
Common fields for all loadable modules.
Definition: rlm_sql.h:183
module_instance_t * driver_submodule
Driver's submodule.
Definition: rlm_sql.h:220
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition: table.h:134
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: talloc.c:380
static const char * names[8]
Definition: time.c:617
#define fr_time_delta_ispos(_a)
Definition: time.h:288
static int64_t fr_time_delta_to_msec(fr_time_delta_t delta)
Definition: time.h:635
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
static fr_slen_t parent
Definition: pair.h:844
static fr_slen_t data
Definition: value.h:1259
int format(printf, 5, 0))
static size_t char ** out
Definition: value.h:984