2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * @brief Handle pools of connections (threads, sockets, etc.)
20 * @note This API must be used by all modules in the public distribution that
21 * maintain pools of connections.
23 * @copyright 2012 The FreeRADIUS server project
24 * @copyright 2012 Alan DeKok <aland@deployingradius.com>
28 #include <freeradius-devel/radiusd.h>
29 #include <freeradius-devel/rad_assert.h>
31 typedef struct fr_connection fr_connection_t;
33 static int fr_connection_pool_check(fr_connection_pool_t *pool);
35 /** An individual connection within the connection pool
37 * Defines connection counters, timestamps, and holds a pointer to the
38 * connection handle itself.
40 * @see fr_connection_pool_t
42 struct fr_connection {
43 fr_connection_t *prev; //!< Previous connection in list.
44 fr_connection_t *next; //!< Next connection in list.
46 time_t created; //!< Time connection was created.
47 time_t last_used; //!< Last time the connection was
50 uint64_t num_uses; //!< Number of times the connection
51 //!< has been reserved.
52 int in_use; //!< Whether the connection is currently
54 uint64_t number; //!< Unique ID assigned when the
55 //!< connection is created, these will
56 //!< monotonically increase over the
57 //!< lifetime of the connection pool.
58 void *connection; //!< Pointer to whatever the module
59 //!< uses for a connection handle.
64 * Defines the configuration of the connection pool, all the counters and
65 * timestamps related to the connection pool, the mutex that stops multiple
66 * threads leaving the pool in an inconsistent state, and the callbacks
67 * required to open, close and check the status of connections within the pool.
71 struct fr_connection_pool_t {
72 int start; //!< Number of initial connections
73 int min; //!< Minimum number of concurrent
74 //!< connections to keep open.
75 int max; //!< Maximum number of concurrent
76 //!< connections to allow.
77 int spare; //!< Number of spare connections to try
78 int cleanup_interval; //!< Initial timer for how
79 //!< often we sweep the pool
80 //!< for free connections.
82 int delay_interval; //!< When we next do a
83 //!< cleanup. Initialized to
84 //!< cleanup_interval, and increase
85 //!< from there based on the delay.
86 int next_delay; //!< The next delay time.
87 //!< cleanup. Initialized to
88 //!< cleanup_interval, and decays
90 uint64_t max_uses; //!< Maximum number of times a
91 //!< connection can be used before being
93 int lifetime; //!< How long a connection can be open
94 //!< before being closed (irrespective
95 //!< of whether it's idle or not).
96 int idle_timeout; //!< How long a connection can be idle
97 //!< before being closed.
99 bool trigger; //!< If true execute connection triggers
100 //!< associated with the connection
103 bool spread; //!< If true requests will be spread
104 //!< across all connections, instead of
105 //!< re-using the most recently used
106 //!< connections first.
108 time_t last_checked; //!< Last time we pruned the connection
110 time_t last_spawned; //!< Last time we spawned a connection.
111 time_t last_failed; //!< Last time we tried to spawn a
112 //!< a connection but failed.
113 time_t last_complained;//!< Last time we complained about
114 //!< configuration parameters.
115 time_t last_throttled; //!< Last time we refused to spawn a
116 //!< connection because the last
117 //!< connection failed, or we were
118 //!< already spawning a connection.
119 time_t last_at_max; //!< Last time we hit the maximum number
120 //!< of allowed connections.
122 uint64_t count; //!< Number of connections spawned over
123 //!< the lifetime of the pool.
124 int num; //!< Number of connections in the pool.
125 int active; //!< Number of currently reserved
128 fr_connection_t *head; //!< Start of the connection list.
129 fr_connection_t *tail; //!< End of the connection list.
131 bool spawning; //!< Whether we are currently attempting
132 //!< to spawn a new connection.
134 #ifdef HAVE_PTHREAD_H
135 pthread_mutex_t mutex; //!< Mutex used to keep consistent state
136 //!< when making modifications in
140 CONF_SECTION *cs; //!< Configuration section holding
141 //!< the section of parsed config file
142 //!< that relates to this pool.
143 void *ctx; //!< Pointer to context data that will
144 //!< be passed to callbacks.
146 char *log_prefix; //!< Log prefix to prepend to all log
147 //!< messages created by the connection
150 fr_connection_create_t create; //!< Function used to create new
152 fr_connection_alive_t alive; //!< Function used to check status
154 fr_connection_delete_t delete; //!< Function used to close existing
158 #define LOG_PREFIX "rlm_%s (%s)"
159 #ifndef HAVE_PTHREAD_H
160 #define pthread_mutex_lock(_x)
161 #define pthread_mutex_unlock(_x)
164 static const CONF_PARSER connection_config[] = {
165 { "start", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, start),
167 { "min", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, min),
169 { "max", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, max),
171 { "spare", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, spare),
173 { "uses", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, max_uses),
175 { "lifetime", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, lifetime),
177 { "cleanup_delay", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, cleanup_interval),
179 { "cleanup_interval", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, cleanup_interval),
181 { "idle_timeout", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, idle_timeout),
183 { "spread", PW_TYPE_BOOLEAN, offsetof(fr_connection_pool_t, spread),
185 { NULL, -1, 0, NULL, NULL }
188 /** Removes a connection from the connection list
190 * @note Must be called with the mutex held.
192 * @param[in,out] pool to modify.
193 * @param[in] this Connection to delete.
195 static void fr_connection_unlink(fr_connection_pool_t *pool,
196 fr_connection_t *this)
199 rad_assert(pool->head != this);
200 this->prev->next = this->next;
202 rad_assert(pool->head == this);
203 pool->head = this->next;
206 rad_assert(pool->tail != this);
207 this->next->prev = this->prev;
209 rad_assert(pool->tail == this);
210 pool->tail = this->prev;
213 this->prev = this->next = NULL;
216 /** Adds a connection to the head of the connection list
218 * @note Must be called with the mutex held.
220 * @param[in,out] pool to modify.
221 * @param[in] this Connection to add.
223 static void fr_connection_link_head(fr_connection_pool_t *pool,
224 fr_connection_t *this)
226 rad_assert(pool != NULL);
227 rad_assert(this != NULL);
228 rad_assert(pool->head != this);
229 rad_assert(pool->tail != this);
232 pool->head->prev = this;
235 this->next = pool->head;
239 rad_assert(this->next == NULL);
242 rad_assert(this->next != NULL);
246 /** Adds a connection to the tail of the connection list
248 * @note Must be called with the mutex held.
250 * @param[in,out] pool to modify.
251 * @param[in] this Connection to add.
253 static void fr_connection_link_tail(fr_connection_pool_t *pool,
254 fr_connection_t *this)
256 rad_assert(pool != NULL);
257 rad_assert(this != NULL);
258 rad_assert(pool->head != this);
259 rad_assert(pool->tail != this);
262 pool->tail->next = this;
264 this->prev = pool->tail;
268 rad_assert(this->prev == NULL);
271 rad_assert(this->prev != NULL);
276 /** Spawns a new connection
278 * Spawns a new connection using the create callback, and returns it for
279 * adding to the connection list.
281 * @note Will call the 'open' trigger.
282 * @note Must be called with the mutex free.
284 * @param[in] pool to modify.
285 * @param[in] now Current time.
286 * @return the new connection struct or NULL on error.
288 static fr_connection_t *fr_connection_spawn(fr_connection_pool_t *pool,
291 fr_connection_t *this;
294 rad_assert(pool != NULL);
297 * Prevent all threads from blocking if the resource
298 * were managing connections for appears to be unavailable.
300 if ((pool->num == 0) && pool->spawning) {
304 pthread_mutex_lock(&pool->mutex);
305 rad_assert(pool->num <= pool->max);
307 if ((pool->last_failed == now) || pool->spawning) {
308 bool complain = false;
310 if (pool->last_throttled != now) {
313 pool->last_throttled = now;
316 pthread_mutex_unlock(&pool->mutex);
319 if (pool->spawning) {
320 ERROR("%s: Cannot open new connection, "
321 "connection spawning already in "
322 "progress", pool->log_prefix);
324 ERROR("%s: Last connection failed, "
325 "throttling connection spawn",
333 pool->spawning = true;
336 * Unlock the mutex while we try to open a new
337 * connection. If there are issues with the back-end,
338 * opening a new connection may take a LONG time. In
339 * that case, we want the other connections to continue
342 pthread_mutex_unlock(&pool->mutex);
344 INFO("%s: Opening additional connection (%" PRIu64 ")", pool->log_prefix, pool->count);
346 this = rad_malloc(sizeof(*this));
347 memset(this, 0, sizeof(*this));
350 * This may take a long time, which prevents other
351 * threads from releasing connections. We don't care
352 * about other threads opening new connections, as we
353 * already have no free connections.
355 conn = pool->create(pool->ctx);
357 ERROR("%s: Opening connection failed (%" PRIu64 ")", pool->log_prefix, pool->count);
359 pool->last_failed = now;
361 pool->spawning = false; /* atomic, so no lock is needed */
366 this->connection = conn;
369 * And lock the mutex again while we link the new
370 * connection back into the pool.
372 pthread_mutex_lock(&pool->mutex);
374 this->number = pool->count++;
375 this->last_used = now;
376 fr_connection_link_head(pool, this);
378 pool->spawning = false;
379 pool->last_spawned = time(NULL);
380 pool->delay_interval = pool->cleanup_interval;
381 pool->next_delay = pool->delay_interval + (pool->delay_interval >> 1);
383 pthread_mutex_unlock(&pool->mutex);
385 if (pool->trigger) exec_trigger(NULL, pool->cs, "open", true);
390 /** Add a new connection to the pool
392 * If conn is not NULL will attempt to add that connection handle to the pool.
393 * If conn is NULL will attempt to spawn a new connection using the create
396 * @note Will call the 'open' trigger.
398 * @param[in,out] pool to add connection to.
399 * @param[in] conn to add.
400 * @return 0 if the connection wasn't added else 1.
402 int fr_connection_add(fr_connection_pool_t *pool, void *conn)
404 fr_connection_t *this;
408 pthread_mutex_lock(&pool->mutex);
411 conn = pool->create(pool->ctx);
413 pthread_mutex_unlock(&pool->mutex);
417 INFO("%s: Opening connection successful (%" PRIu64 ")", pool->log_prefix, pool->count);
421 * Too many connections: can't add it.
423 if (pool->num >= pool->max) {
424 pthread_mutex_unlock(&pool->mutex);
428 this = rad_malloc(sizeof(*this));
429 memset(this, 0, sizeof(*this));
431 this->created = time(NULL);
432 this->connection = conn;
434 this->number = pool->count++;
435 this->last_used = time(NULL);
436 fr_connection_link_head(pool, this);
439 pthread_mutex_unlock(&pool->mutex);
441 if (pool->trigger) exec_trigger(NULL, pool->cs, "open", true);
446 /** Close an existing connection.
448 * Removes the connection from the list, calls the delete callback to close
449 * the connection, then frees memory allocated to the connection.
451 * @note Will call the 'close' trigger.
452 * @note Must be called with the mutex held.
454 * @param[in,out] pool to modify.
455 * @param[in,out] this Connection to delete.
458 static void fr_connection_close(fr_connection_pool_t *pool,
459 fr_connection_t *this)
461 if (pool->trigger) exec_trigger(NULL, pool->cs, "close", true);
463 rad_assert(this->in_use == false);
465 fr_connection_unlink(pool, this);
466 pool->delete(pool->ctx, this->connection);
467 rad_assert(pool->num > 0);
472 /** Find a connection handle in the connection list
474 * Walks over the list of connections searching for a specified connection
475 * handle and returns the first connection that contains that pointer.
477 * @note Will lock mutex and only release mutex if connection handle
478 * is not found, so will usually return will mutex held.
479 * @note Must be called with the mutex free.
481 * @param[in] pool to search in.
482 * @param[in] conn handle to search for.
483 * @return the connection containing the specified handle, or NULL if non is
486 static fr_connection_t *fr_connection_find(fr_connection_pool_t *pool, void *conn)
488 fr_connection_t *this;
490 if (!pool || !conn) return NULL;
492 pthread_mutex_lock(&pool->mutex);
495 * FIXME: This loop could be avoided if we passed a 'void
496 * **connection' instead. We could use "offsetof" in
497 * order to find top of the parent structure.
499 for (this = pool->head; this != NULL; this = this->next) {
500 if (this->connection == conn) return this;
503 pthread_mutex_unlock(&pool->mutex);
507 /** Delete a connection from the connection pool.
509 * Resolves the connection handle to a connection, then (if found)
510 * closes, unlinks and frees that connection.
512 * @note Must be called with the mutex free.
514 * @param[in,out] pool Connection pool to modify.
515 * @param[in] conn to delete.
516 * @return 0 if the connection could not be found, else 1.
518 int fr_connection_del(fr_connection_pool_t *pool, void *conn)
520 fr_connection_t *this;
522 this = fr_connection_find(pool, conn);
526 * If it's in use, release it.
529 rad_assert(this->in_use == true);
530 this->in_use = false;
532 rad_assert(pool->active > 0);
536 INFO("%s: Deleting connection (%" PRIu64 ")", pool->log_prefix, this->number);
538 fr_connection_close(pool, this);
539 fr_connection_pool_check(pool);
543 /** Delete a connection pool
545 * Closes, unlinks and frees all connections in the connection pool, then frees
546 * all memory used by the connection pool.
548 * @note Will call the 'stop' trigger.
549 * @note Must be called with the mutex free.
551 * @param[in,out] pool to delete.
553 void fr_connection_pool_delete(fr_connection_pool_t *pool)
555 fr_connection_t *this, *next;
559 DEBUG("%s: Removing connection pool", pool->log_prefix);
561 pthread_mutex_lock(&pool->mutex);
563 for (this = pool->head; this != NULL; this = next) {
566 INFO("%s: Closing connection (%" PRIu64 ")", pool->log_prefix, this->number);
568 fr_connection_close(pool, this);
571 if (pool->trigger) exec_trigger(NULL, pool->cs, "stop", true);
573 rad_assert(pool->head == NULL);
574 rad_assert(pool->tail == NULL);
575 rad_assert(pool->num == 0);
577 free(pool->log_prefix);
581 /** Create a new connection pool
583 * Allocates structures used by the connection pool, initialises the various
584 * configuration options and counters, and sets the callback functions.
586 * Will also spawn the number of connections specified by the 'start'
587 * configuration options.
589 * @note Will call the 'start' trigger.
591 * @param[in] parent configuration section containing a 'pool' subsection.
592 * @param[in] ctx pointer to pass to callbacks.
593 * @param[in] c Callback to create new connections.
594 * @param[in] a Callback to check the status of connections.
595 * @param[in] d Callback to delete connections.
596 * @param[in] prefix to prepend to all log message, if NULL will create prefix
597 * from parent conf section names.
598 * @return A new connection pool or NULL on error.
600 fr_connection_pool_t *fr_connection_pool_init(CONF_SECTION *parent,
602 fr_connection_create_t c,
603 fr_connection_alive_t a,
604 fr_connection_delete_t d,
608 fr_connection_pool_t *pool;
609 fr_connection_t *this;
610 CONF_SECTION *modules;
612 char const *cs_name1, *cs_name2;
613 time_t now = time(NULL);
615 if (!parent || !ctx || !c || !d) return NULL;
617 cs = cf_section_sub_find(parent, "pool");
618 if (!cs) cs = cf_section_sub_find(parent, "limit");
620 pool = rad_malloc(sizeof(*pool));
621 memset(pool, 0, sizeof(*pool));
629 pool->head = pool->tail = NULL;
631 #ifdef HAVE_PTHREAD_H
632 pthread_mutex_init(&pool->mutex, NULL);
636 modules = cf_item_parent(cf_sectiontoitem(parent));
638 cs_name1 = cf_section_name1(modules);
639 if (cs_name1 && (strcmp(cs_name1, "modules") == 0)) {
640 cs_name1 = cf_section_name1(parent);
641 cs_name2 = cf_section_name2(parent);
646 lp_len = (sizeof(LOG_PREFIX) - 4) + strlen(cs_name1) + strlen(cs_name2);
647 pool->log_prefix = rad_malloc(lp_len);
648 snprintf(pool->log_prefix, lp_len, LOG_PREFIX, cs_name1,
651 } else { /* not a module configuration */
652 cs_name1 = cf_section_name1(parent);
654 pool->log_prefix = strdup(cs_name1);
657 pool->log_prefix = strdup(prefix);
660 DEBUG("%s: Initialising connection pool", pool->log_prefix);
663 if (cf_section_parse(cs, pool, connection_config) < 0) {
667 if (cf_section_sub_find(cs, "trigger")) pool->trigger = true;
673 pool->cleanup_interval = 30;
674 pool->idle_timeout = 60;
680 if (pool->max == 0) {
681 cf_log_err_cs(cs, "Cannot set 'max' to zero");
684 if (pool->min > pool->max) {
685 cf_log_err_cs(cs, "Cannot set 'min' to more than 'max'");
689 if (pool->max > 1024) pool->max = 1024;
690 if (pool->start > pool->max) pool->start = pool->max;
691 if (pool->spare > (pool->max - pool->min)) {
692 pool->spare = pool->max - pool->min;
694 if ((pool->lifetime > 0) && (pool->idle_timeout > pool->lifetime)) {
695 pool->idle_timeout = 0;
698 if (pool->cleanup_interval < 0) {
699 pool->cleanup_interval = 30;
702 if ((pool->idle_timeout > 0) && (pool->cleanup_interval > pool->idle_timeout)) {
703 pool->cleanup_interval = pool->idle_timeout;
707 * Create all of the connections, unless the admin says
710 for (i = 0; i < pool->start; i++) {
711 this = fr_connection_spawn(pool, now);
714 fr_connection_pool_delete(pool);
719 if (pool->trigger) exec_trigger(NULL, pool->cs, "start", true);
725 /** Check whether a connection needs to be removed from the pool
727 * Will verify that the connection is within idle_timeout, max_uses, and
728 * lifetime values. If it is not, the connection will be closed.
730 * @note Will only close connections not in use.
731 * @note Must be called with the mutex held.
733 * @param[in,out] pool to modify.
734 * @param[in,out] this Connection to manage.
735 * @param[in] now Current time.
736 * @return 0 if the connection was closed, otherwise 1.
738 static int fr_connection_manage(fr_connection_pool_t *pool,
739 fr_connection_t *this,
742 rad_assert(pool != NULL);
743 rad_assert(this != NULL);
746 * Don't terminated in-use connections
748 if (this->in_use) return 1;
750 if ((pool->max_uses > 0) &&
751 (this->num_uses >= pool->max_uses)) {
752 DEBUG("%s: Closing expired connection (%" PRIu64 "): Hit max_uses limit", pool->log_prefix,
755 if ((pool->num <= pool->min) &&
756 (pool->last_complained < now)) {
757 WARN("%s: You probably need to lower \"min\"", pool->log_prefix);
759 pool->last_complained = now;
761 fr_connection_close(pool, this);
765 if ((pool->lifetime > 0) &&
766 ((this->created + pool->lifetime) < now)) {
767 DEBUG("%s: Closing expired connection (%" PRIu64 ")", pool->log_prefix, this->number);
771 if ((pool->idle_timeout > 0) &&
772 ((this->last_used + pool->idle_timeout) < now)) {
773 INFO("%s: Closing connection (%" PRIu64 "): Hit idle_timeout, was idle for %u seconds",
774 pool->log_prefix, this->number, (int) (now - this->last_used));
782 /** Check whether any connections needs to be removed from the pool
784 * Maintains the number of connections in the pool as per the configuration
785 * parameters for the connection pool.
787 * @note Will only run checks the first time it's called in a given second,
788 * to throttle connection spawning/closing.
789 * @note Will only close connections not in use.
790 * @note Must be called with the mutex held, will release mutex before
793 * @param[in,out] pool to manage.
796 static int fr_connection_pool_check(fr_connection_pool_t *pool)
799 time_t now = time(NULL);
800 fr_connection_t *this, *next;
802 if (pool->last_checked == now) {
803 pthread_mutex_unlock(&pool->mutex);
807 spare = pool->num - pool->active;
809 if ((pool->num < pool->max) && (spare < pool->spare)) {
810 spawn = pool->spare - spare;
811 if ((spawn + pool->num) > pool->max) {
812 spawn = pool->max - pool->num;
814 if (pool->spawning) spawn = 0;
817 pthread_mutex_unlock(&pool->mutex);
818 fr_connection_spawn(pool, now); /* ignore return code */
819 pthread_mutex_lock(&pool->mutex);
824 * We haven't spawned connections in a while, and there
825 * are too many spare ones. Close the one which has been
826 * idle for the longest.
828 if ((now >= (pool->last_spawned + pool->delay_interval)) &&
829 (spare > pool->spare)) {
830 fr_connection_t *idle;
833 for (this = pool->tail; this != NULL; this = this->prev) {
834 if (this->in_use) continue;
837 (this->last_used < idle->last_used)) {
842 rad_assert(idle != NULL);
844 INFO("%s: Closing connection (%" PRIu64 "): Too many free connections (%d > %d)", pool->log_prefix,
845 idle->number, spare, pool->spare);
846 fr_connection_close(pool, idle);
849 * Decrease the delay for the next time we clean
852 pool->next_delay >>= 1;
853 if (pool->next_delay == 0) pool->next_delay = 1;
854 pool->delay_interval += pool->next_delay;
858 * Pass over all of the connections in the pool, limiting
859 * lifetime, idle time, max requests, etc.
861 for (this = pool->head; this != NULL; this = next) {
863 fr_connection_manage(pool, this, now);
866 pool->last_checked = now;
867 pthread_mutex_unlock(&pool->mutex);
872 /** Trigger connection check for a given connection or all connections
874 * If conn is not NULL then we call fr_connection_manage on the connection.
875 * If conn is NULL we call fr_connection_pool_check on the pool.
877 * @note Only connections that are not in use will be closed.
879 * @see fr_connection_manage
880 * @see fr_connection_pool_check
881 * @param[in,out] pool to manage.
882 * @param[in,out] conn to check.
883 * @return 0 if the connection was closed, else 1.
885 int fr_connection_check(fr_connection_pool_t *pool, void *conn)
887 fr_connection_t *this;
894 pthread_mutex_lock(&pool->mutex);
896 if (!conn) return fr_connection_pool_check(pool);
898 for (this = pool->head; this != NULL; this = this->next) {
899 if (this->connection == conn) {
900 ret = fr_connection_manage(pool, conn, now);
905 pthread_mutex_unlock(&pool->mutex);
910 /** Reserve a connection in the connection pool
912 * Will attempt to find an unused connection in the connection pool, if one is
913 * found, will mark it as in in use increment the number of active connections
914 * and return the connection handle.
916 * If no free connections are found will attempt to spawn a new one, conditional
917 * on a connection spawning not already being in progress, and not being at the
918 * 'max' connection limit.
920 * @note fr_connection_release must be called once the caller has finished
921 * using the connection.
923 * @see fr_connection_release
924 * @param[in,out] pool to reserve the connection from.
925 * @return a pointer to the connection handle, or NULL on error.
927 void *fr_connection_get(fr_connection_pool_t *pool)
930 fr_connection_t *this, *next;
932 if (!pool) return NULL;
934 pthread_mutex_lock(&pool->mutex);
937 for (this = pool->head; this != NULL; this = next) {
940 if (!this->in_use) goto do_return;
943 if (pool->num == pool->max) {
944 bool complain = false;
947 * Rate-limit complaints.
949 if (pool->last_at_max != now) {
951 pool->last_at_max = now;
954 pthread_mutex_unlock(&pool->mutex);
957 ERROR("%s: No connections available and at max connection limit", pool->log_prefix);
963 pthread_mutex_unlock(&pool->mutex);
964 this = fr_connection_spawn(pool, now);
965 if (!this) return NULL;
966 pthread_mutex_lock(&pool->mutex);
971 this->last_used = now;
974 pthread_mutex_unlock(&pool->mutex);
976 DEBUG("%s: Reserved connection (%" PRIu64 ")", pool->log_prefix, this->number);
978 return this->connection;
981 /** Release a connection
983 * Will mark a connection as unused and decrement the number of active
986 * @see fr_connection_get
987 * @param[in,out] pool to release the connection in.
988 * @param[in,out] conn to release.
990 void fr_connection_release(fr_connection_pool_t *pool, void *conn)
992 fr_connection_t *this;
994 this = fr_connection_find(pool, conn);
997 rad_assert(this->in_use == true);
998 this->in_use = false;
1001 * Determines whether the last used connection gets
1006 * Put it at the tail of the list, so
1007 * that it will get re-used last.
1009 if (this != pool->tail) {
1010 fr_connection_unlink(pool, this);
1011 fr_connection_link_tail(pool, this);
1015 * Put it at the head of the list, so
1016 * that it will get re-used quickly.
1018 if (this != pool->head) {
1019 fr_connection_unlink(pool, this);
1020 fr_connection_link_head(pool, this);
1024 rad_assert(pool->active > 0);
1027 DEBUG("%s: Released connection (%" PRIu64 ")", pool->log_prefix, this->number);
1030 * We mirror the "spawn on get" functionality by having
1031 * "delete on release". If there are too many spare
1032 * connections, go manage the pool && clean some up.
1034 fr_connection_pool_check(pool);
1037 /** Reconnect a suspected inviable connection
1039 * This should be called by the module if it suspects that a connection is
1040 * not viable (e.g. the server has closed it).
1042 * Will attempt to create a new connection handle using the create callback,
1043 * and if this is successful the new handle will be assigned to the existing
1046 * If this is not successful, the connection will be removed from the pool.
1048 * When implementing a module that uses the connection pool API, it is advisable
1049 * to pass a pointer to the pointer to the handle (void **conn)
1050 * to all functions which may call reconnect. This is so that if a new handle
1051 * is created and returned, the handle pointer can be updated up the callstack,
1052 * and a function higher up the stack doesn't attempt to use a now invalid
1053 * connection handle.
1055 * @warning After calling reconnect the caller *MUST NOT* attempt to use
1056 * the old handle in any other operations, as its memory will have been freed.
1058 * @see fr_connection_get
1059 * @param[in,out] pool to reconnect the connection in.
1060 * @param[in,out] conn to reconnect.
1061 * @return ew connection handle if successful else NULL.
1063 void *fr_connection_reconnect(fr_connection_pool_t *pool, void *conn)
1066 fr_connection_t *this;
1067 uint64_t conn_number;
1069 if (!pool || !conn) return NULL;
1071 this = fr_connection_find(pool, conn);
1072 if (!this) return NULL;
1075 * The pool is now locked.
1077 conn_number = this->number;
1079 DEBUG("%s: Reconnecting (%" PRIu64 ")", pool->log_prefix, conn_number);
1081 new_conn = pool->create(pool->ctx);
1083 time_t now = time(NULL);
1085 if (pool->last_complained == now) {
1088 pool->last_complained = now;
1092 * The caller has said the connection is bad. So
1093 * if it's still in use, mark it as unused, and
1094 * close it. If it's not in use, we just try to
1095 * get a new connection.
1098 this->in_use = false;
1100 rad_assert(pool->active > 0);
1103 fr_connection_close(pool, this);
1107 * We failed to create a new socket.
1108 * Try to grab an existing one.
1110 pthread_mutex_unlock(&pool->mutex);
1111 new_conn = fr_connection_get(pool);
1112 if (new_conn) return new_conn;
1114 if (!now) return NULL;
1116 ERROR("%s: Failed to reconnect (%" PRIu64 "), and no other connections available", pool->log_prefix,
1122 pool->delete(pool->ctx, conn);
1123 this->connection = new_conn;
1124 pthread_mutex_unlock(&pool->mutex);