/** Call the driver's sql_query method, reconnecting if necessary. * * @param handle to query the database with. *handle should not be NULL, as this indicates * previous reconnection attempt has failed. * @param inst rlm_sql instance data. * @param query to execute. Should not be zero length. * @return RLM_SQL_OK on success, RLM_SQL_RECONNECT if a new handle is required (also sets *handle = NULL), * RLM_SQL_QUERY_ERROR/RLM_SQL_ERROR on invalid query or connection error, RLM_SQL_DUPLICATE on constraints * violation. */ sql_rcode_t rlm_sql_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query) { int ret = RLM_SQL_ERROR; int i, count; /* There's no query to run, return an error */ if (query[0] == '\0') { ERROR("rlm_sql (%s): Zero length query", inst->config->xlat_name); return RLM_SQL_QUERY_ERROR; } /* There's no handle, we need a new one */ if (!*handle) return RLM_SQL_RECONNECT; /* * inst->pool may be NULL is this function is called by mod_conn_create. */ count = inst->pool ? fr_connection_get_num(inst->pool) : 0; /* * Here we try with each of the existing connections, then try to create * a new connection, then give up. */ for (i = 0; i < (count + 1); i++) { DEBUG("rlm_sql (%s): Executing query: '%s'", inst->config->xlat_name, query); ret = (inst->module->sql_query)(*handle, inst->config, query); switch (ret) { case RLM_SQL_OK: break; /* * Run through all available sockets until we exhaust all existing * sockets in the pool and fail to establish a *new* connection. */ case RLM_SQL_RECONNECT: *handle = fr_connection_reconnect(inst->pool, *handle); /* Reconnection failed */ if (!*handle) return RLM_SQL_RECONNECT; /* Reconnection succeeded, try again with the new handle */ continue; case RLM_SQL_QUERY_ERROR: case RLM_SQL_ERROR: rlm_sql_query_error(*handle, inst); break; case RLM_SQL_DUPLICATE: rlm_sql_query_debug(*handle, inst); break; } return ret; } ERROR("rlm_sql (%s): Hit reconnection limit", inst->config->xlat_name); return RLM_SQL_ERROR; }
/************************************************************************* * * Function: rlm_sql_select_query * * Purpose: call the module's sql_select_query and implement re-connect * *************************************************************************/ int rlm_sql_select_query(SQLSOCK *sqlsocket, SQL_INST *inst, char *query) { int ret; /* * If there's no query, return an error. */ if (!query || !*query) { return -1; } if (sqlsocket->conn) { ret = (inst->module->sql_select_query)(sqlsocket, inst->config, query); } else { ret = SQL_DOWN; } if (ret == SQL_DOWN) { sqlsocket = fr_connection_reconnect(inst->pool, sqlsocket); if (!sqlsocket) return -1; /* retry the query on the newly connected socket */ ret = (inst->module->sql_select_query)(sqlsocket, inst->config, query); if (ret) { radlog(L_ERR, "rlm_sql (%s): failed after re-connect", inst->config->xlat_name); return -1; } } return ret; }
/************************************************************************* * * Function: rlm_sql_fetch_row * * Purpose: call the module's sql_fetch_row and implement re-connect * *************************************************************************/ int rlm_sql_fetch_row(SQLSOCK *sqlsocket, SQL_INST *inst) { int ret; if (sqlsocket->conn) { ret = (inst->module->sql_fetch_row)(sqlsocket, inst->config); } else { ret = SQL_DOWN; } if (ret == SQL_DOWN) { sqlsocket = fr_connection_reconnect(inst->pool, sqlsocket); if (!sqlsocket) return -1; /* retry the query on the newly connected socket */ ret = (inst->module->sql_fetch_row)(sqlsocket, inst->config); if (ret) { radlog(L_ERR, "rlm_sql (%s): failed after re-connect", inst->config->xlat_name); return -1; } } return ret; }
/** Call the driver's sql_select_query method, reconnecting if necessary. * * @note Caller must call ``(inst->module->sql_finish_select_query)(handle, inst->config);`` * after they're done with the result. * * @param inst #rlm_sql_t instance data. * @param request Current request. * @param handle to query the database with. *handle should not be NULL, as this indicates * previous reconnection attempt has failed. * @param query to execute. Should not be zero length. * @return * - #RLM_SQL_OK on success. * - #RLM_SQL_RECONNECT if a new handle is required (also sets *handle = NULL). * - #RLM_SQL_QUERY_INVALID, #RLM_SQL_ERROR on invalid query or connection error. */ sql_rcode_t rlm_sql_select_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query) { int ret = RLM_SQL_ERROR; int i, count; /* Caller should check they have a valid handle */ rad_assert(*handle); /* There's no query to run, return an error */ if (query[0] == '\0') { if (request) REDEBUG("Zero length query"); return RLM_SQL_QUERY_INVALID; } /* * inst->pool may be NULL is this function is called by mod_conn_create. */ count = inst->pool ? fr_connection_get_num(inst->pool) : 0; /* * For sanity, for when no connections are viable, and we can't make a new one */ for (i = 0; i < (count + 1); i++) { ROPTIONAL(RDEBUG2, DEBUG2, "Executing select query: %s", query); ret = (inst->module->sql_select_query)(*handle, inst->config, query); switch (ret) { case RLM_SQL_OK: break; /* * Run through all available sockets until we exhaust all existing * sockets in the pool and fail to establish a *new* connection. */ case RLM_SQL_RECONNECT: *handle = fr_connection_reconnect(inst->pool, *handle); /* Reconnection failed */ if (!*handle) return RLM_SQL_RECONNECT; /* Reconnection succeeded, try again with the new handle */ continue; case RLM_SQL_QUERY_INVALID: case RLM_SQL_ERROR: default: rlm_sql_print_error(inst, request, *handle, false); (inst->module->sql_finish_select_query)(*handle, inst->config); break; } return ret; } ROPTIONAL(RERROR, ERROR, "Hit reconnection limit"); return RLM_SQL_ERROR; }
/* * Query the redis database */ int rlm_redis_query(REDISSOCK **dissocket_p, REDIS_INST *inst, const char *query, REQUEST *request) { REDISSOCK *dissocket; int argc; const char *argv[MAX_REDIS_ARGS]; char argv_buf[MAX_QUERY_LEN]; if (!query || !*query || !inst || !dissocket_p) { return -1; } argc = rad_expand_xlat(request, query, MAX_REDIS_ARGS, argv, 0, sizeof(argv_buf), argv_buf); if (argc <= 0) return -1; dissocket = *dissocket_p; DEBUG2("executing %s ...", argv[0]); dissocket->reply = redisCommandArgv(dissocket->conn, argc, argv, NULL); if (!dissocket->reply) { radlog(L_ERR, "rlm_redis: (%s) REDIS error: %s", inst->xlat_name, dissocket->conn->errstr); dissocket = fr_connection_reconnect(inst->pool, dissocket); if (!dissocket) { error: *dissocket_p = NULL; return -1; } dissocket->reply = redisCommand(dissocket->conn, query); if (!dissocket->reply) { radlog(L_ERR, "rlm_redis (%s): failed after re-connect", inst->xlat_name); fr_connection_del(inst->pool, dissocket); goto error; } *dissocket_p = dissocket; } if (dissocket->reply->type == REDIS_REPLY_ERROR) { radlog(L_ERR, "rlm_redis (%s): query failed, %s", inst->xlat_name, query); return -1; } return 0; }
/** Reconnect a socket * * @param inst main rlm_cache instance. * @param request The current request. * @param handle Pointer to the handle to reconnect (will be set to NULL if reconnection fails). */ static int mod_conn_reconnect(rlm_cache_t *inst, UNUSED REQUEST *request, rlm_cache_handle_t **handle) { rlm_cache_memcached_t *driver = inst->driver; rlm_cache_handle_t *mandle; mandle = fr_connection_reconnect(driver->pool, *handle); if (!mandle) { *handle = NULL; return -1; } *handle = mandle; return 0; }
/** Call the driver's sql_query method, reconnecting if necessary. * * @param handle to query the database with. *handle should not be NULL, as this indicates * previous reconnection attempt has failed. * @param inst rlm_sql instance data. * @param query to execute. Should not be zero length. * @return RLM_SQL_OK on success, RLM_SQL_RECONNECT if a new handle is required (also sets *handle = NULL), * RLM_SQL_QUERY_ERROR/RLM_SQL_ERROR on invalid query or connection error, RLM_SQL_DUPLICATE on constraints * violation. */ sql_rcode_t rlm_sql_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query) { int ret = RLM_SQL_ERROR; int i; /* There's no query to run, return an error */ if (query[0] == '\0') return RLM_SQL_QUERY_ERROR; /* There's no handle, we need a new one */ if (!*handle) return RLM_SQL_RECONNECT; /* For sanity, for when no connections are viable, and we can't make a new one */ for (i = fr_connection_get_num(inst->pool); i >= 0; i--) { DEBUG("rlm_sql (%s): Executing query: '%s'", inst->config->xlat_name, query); ret = (inst->module->sql_query)(*handle, inst->config, query); switch (ret) { case RLM_SQL_OK: break; /* * Run through all available sockets until we exhaust all existing * sockets in the pool and fail to establish a *new* connection. */ case RLM_SQL_RECONNECT: *handle = fr_connection_reconnect(inst->pool, *handle); /* Reconnection failed */ if (!*handle) return RLM_SQL_RECONNECT; /* Reconnection succeeded, try again with the new handle */ continue; case RLM_SQL_QUERY_ERROR: case RLM_SQL_ERROR: rlm_sql_query_error(*handle, inst); break; case RLM_SQL_DUPLICATE: rlm_sql_query_debug(*handle, inst); break; } return ret; } ERROR("rlm_sql (%s): Hit reconnection limit", inst->config->xlat_name); return RLM_SQL_ERROR; }
/************************************************************************* * * Function: rlm_sql_query * * Purpose: call the module's sql_query and implement re-connect * *************************************************************************/ int rlm_sql_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query) { int ret = -1; /* * If there's no query, return an error. */ if (!query || !*query) { return -1; } if (!*handle || !(*handle)->conn) { goto sql_down; } while (true) { DEBUG("rlm_sql (%s): Executing query: '%s'", inst->config->xlat_name, query); ret = (inst->module->sql_query)(*handle, inst->config, query); switch (ret) { case RLM_SQL_OK: break; /* * Run through all available sockets until we exhaust all existing * sockets in the pool and fail to establish a *new* connection. */ case RLM_SQL_RECONNECT: sql_down: *handle = fr_connection_reconnect(inst->pool, *handle); if (!*handle) return RLM_SQL_RECONNECT; continue; case RLM_SQL_QUERY_ERROR: case RLM_SQL_ERROR: rlm_sql_query_error(*handle, inst); break; case RLM_SQL_DUPLICATE: rlm_sql_query_debug(*handle, inst); break; } return ret; } }
/* * Query the redis database */ int rlm_redis_query(REDISSOCK **dissocket_p, REDIS_INST *inst, char *query) { REDISSOCK *dissocket; if (!query || !*query || !inst || !dissocket_p) { return -1; } dissocket = *dissocket_p; DEBUG2("executing query %s", query); dissocket->reply = redisCommand(dissocket->conn, query); if (!dissocket->reply) { radlog(L_ERR, "rlm_redis: (%s) REDIS error: %s", inst->xlat_name, dissocket->conn->errstr); dissocket = fr_connection_reconnect(inst->pool, dissocket); if (!dissocket) { error: *dissocket_p = NULL; return -1; } dissocket->reply = redisCommand(dissocket->conn, query); if (!dissocket->reply) { radlog(L_ERR, "rlm_redis (%s): failed after re-connect", inst->xlat_name); fr_connection_del(inst->pool, dissocket); goto error; } *dissocket_p = dissocket; } if (dissocket->reply->type == REDIS_REPLY_ERROR) { radlog(L_ERR, "rlm_redis (%s): query failed, %s", inst->xlat_name, query); /* Free the reply just in case */ rlm_redis_finish_query(dissocket); return -1; } return 0; }
/************************************************************************* * * Function: rlm_sql_select_query * * Purpose: call the module's sql_select_query and implement re-connect * *************************************************************************/ int rlm_sql_select_query(SQLSOCK **sqlsocket, SQL_INST *inst, char *query) { int ret; /* * If there's no query, return an error. */ if (!query || !*query) { return -1; } if (!*sqlsocket || !(*sqlsocket)->conn) { ret = -1; goto sql_down; } while (1) { DEBUG("rlm_sql (%s): Executing query: '%s'", inst->config->xlat_name, query); ret = (inst->module->sql_select_query)(*sqlsocket, inst->config, query); /* * Run through all available sockets until we exhaust all existing * sockets in the pool and fail to establish a *new* connection. */ if (ret == SQL_DOWN) { sql_down: *sqlsocket = fr_connection_reconnect(inst->pool, *sqlsocket); if (!*sqlsocket) return SQL_DOWN; continue; } if (ret < 0) { radlog(L_ERR, "rlm_sql (%s): Database query error '%s'", inst->config->xlat_name, (inst->module->sql_error)(*sqlsocket, inst->config)); } return ret; } }
/************************************************************************* * * Function: rlm_sql_select_query * * Purpose: call the module's sql_select_query and implement re-connect * *************************************************************************/ int rlm_sql_select_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query) { int ret; /* * If there's no query, return an error. */ if (!query || !*query) { return -1; } if (!*handle || !(*handle)->conn) { ret = -1; goto sql_down; } while (1) { DEBUG("rlm_sql (%s): Executing query: '%s'", inst->config->xlat_name, query); ret = (inst->module->sql_select_query)(*handle, inst->config, query); /* * Run through all available sockets until we exhaust all existing * sockets in the pool and fail to establish a *new* connection. */ if (ret == RLM_SQL_RECONNECT) { sql_down: *handle = fr_connection_reconnect(inst->pool, *handle); if (!*handle) return RLM_SQL_RECONNECT; continue; } if (ret < 0) { char const *error = (inst->module->sql_error)(*handle, inst->config); ERROR("rlm_sql (%s): Database query error '%s'", inst->config->xlat_name, error ? error : "<UNKNOWN>"); } return ret; } }
/** Call the driver's sql_query method, reconnecting if necessary. * * @note Caller must call ``(inst->module->sql_finish_query)(handle, inst->config);`` * after they're done with the result. * * @param handle to query the database with. *handle should not be NULL, as this indicates * previous reconnection attempt has failed. * @param request Current request. * @param inst #rlm_sql_t instance data. * @param query to execute. Should not be zero length. * @return * - #RLM_SQL_OK on success. * - #RLM_SQL_RECONNECT if a new handle is required (also sets *handle = NULL). * - #RLM_SQL_QUERY_INVALID, #RLM_SQL_ERROR on invalid query or connection error. * - #RLM_SQL_ALT_QUERY on constraints violation. */ sql_rcode_t rlm_sql_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query) { int ret = RLM_SQL_ERROR; int i, count; /* Caller should check they have a valid handle */ rad_assert(*handle); /* There's no query to run, return an error */ if (query[0] == '\0') { if (request) REDEBUG("Zero length query"); return RLM_SQL_QUERY_INVALID; } /* * inst->pool may be NULL is this function is called by mod_conn_create. */ count = inst->pool ? fr_connection_get_num(inst->pool) : 0; /* * Here we try with each of the existing connections, then try to create * a new connection, then give up. */ for (i = 0; i < (count + 1); i++) { ROPTIONAL(RDEBUG2, DEBUG2, "Executing query: %s", query); ret = (inst->module->sql_query)(*handle, inst->config, query); switch (ret) { case RLM_SQL_OK: break; /* * Run through all available sockets until we exhaust all existing * sockets in the pool and fail to establish a *new* connection. */ case RLM_SQL_RECONNECT: *handle = fr_connection_reconnect(inst->pool, *handle); /* Reconnection failed */ if (!*handle) return RLM_SQL_RECONNECT; /* Reconnection succeeded, try again with the new handle */ continue; /* * These are bad and should make rlm_sql return invalid */ case RLM_SQL_QUERY_INVALID: rlm_sql_print_error(inst, request, *handle, false); (inst->module->sql_finish_query)(*handle, inst->config); break; /* * Server or client errors. * * If the driver claims to be able to distinguish between * duplicate row errors and other errors, and we hit a * general error treat it as a failure. * * Otherwise rewrite it to RLM_SQL_ALT_QUERY. */ case RLM_SQL_ERROR: if (inst->module->flags & RLM_SQL_RCODE_FLAGS_ALT_QUERY) { rlm_sql_print_error(inst, request, *handle, false); (inst->module->sql_finish_query)(*handle, inst->config); break; } ret = RLM_SQL_ALT_QUERY; /* FALL-THROUGH */ /* * Driver suggested using an alternative query */ case RLM_SQL_ALT_QUERY: rlm_sql_print_error(inst, request, *handle, true); (inst->module->sql_finish_query)(*handle, inst->config); break; } return ret; } ROPTIONAL(RERROR, ERROR, "Hit reconnection limit"); return RLM_SQL_ERROR; }