Remove fr_connection_delete
[freeradius.git] / src / main / connection.c
index 68d4549..8cd5e0f 100644 (file)
@@ -86,7 +86,7 @@ struct fr_connection_pool_t {
        uint32_t        max;            //!< Maximum number of concurrent
                                        //!< connections to allow.
        uint32_t        spare;          //!< Number of spare connections to try
-       int             retry_delay;    //!< seconds to delay re-open
+       uint32_t        retry_delay;    //!< seconds to delay re-open
                                        //!< after a failed open.
        uint32_t        cleanup_interval; //!< Initial timer for how
                                          //!< often we sweep the pool
@@ -100,7 +100,7 @@ struct fr_connection_pool_t {
                                        //!< cleanup.  Initialized to
                                        //!< cleanup_interval, and decays
                                        //!< from there.
-       uint32_t        max_uses;       //!< Maximum number of times a
+       uint64_t        max_uses;       //!< Maximum number of times a
                                        //!< connection can be used before being
                                        //!< closed.
        uint32_t        lifetime;       //!< How long a connection can be open
@@ -151,7 +151,7 @@ struct fr_connection_pool_t {
        CONF_SECTION    *cs;            //!< Configuration section holding
                                        //!< the section of parsed config file
                                        //!< that relates to this pool.
-       void            *ctx;           //!< Pointer to context data that will
+       void            *opaque;        //!< Pointer to context data that will
                                        //!< be passed to callbacks.
 
        char            *log_prefix;    //!< Log prefix to prepend to all log
@@ -162,8 +162,6 @@ struct fr_connection_pool_t {
                                        //!< connections.
        fr_connection_alive_t   alive;  //!< Function used to check status
                                        //!< of connections.
-       fr_connection_delete_t  delete; //!< Function used to close existing
-                                       //!< connections.
 };
 
 #define LOG_PREFIX "rlm_%s (%s)"
@@ -173,27 +171,17 @@ struct fr_connection_pool_t {
 #endif
 
 static const CONF_PARSER connection_config[] = {
-       { "start",    FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, start), "5" },
-       { "min",      PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, min),
-         0, "5" },
-       { "max",      PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, max),
-         0, "10" },
-       { "spare",    PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, spare),
-         0, "3" },
-       { "uses",     PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, max_uses),
-         0, "0" },
-       { "lifetime", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, lifetime),
-         0, "0" },
-       { "cleanup_delay", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, cleanup_interval),
-         0, NULL},
-       { "cleanup_interval", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, cleanup_interval),
-         0, "30" },
-       { "idle_timeout",  PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, idle_timeout),
-         0, "60" },
-       { "retry_delay",  PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, retry_delay),
-         0, "1" },
-       { "spread", PW_TYPE_BOOLEAN, offsetof(fr_connection_pool_t, spread),
-         0, "no" },
+       { "start", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, start), "5" },
+       { "min", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, min), "5" },
+       { "max", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, max), "10" },
+       { "spare", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, spare), "3" },
+       { "uses", FR_CONF_OFFSET(PW_TYPE_INTEGER64, fr_connection_pool_t, max_uses), "0" },
+       { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, lifetime), "0" },
+       { "cleanup_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, cleanup_interval), NULL},
+       { "cleanup_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, cleanup_interval), "30" },
+       { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, idle_timeout), "60" },
+       { "retry_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, retry_delay), "1" },
+       { "spread", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_connection_pool_t, spread), "no" },
        { NULL, -1, 0, NULL, NULL }
 };
 
@@ -301,6 +289,8 @@ static void fr_connection_link_tail(fr_connection_pool_t *pool,
 static fr_connection_t *fr_connection_spawn(fr_connection_pool_t *pool,
                                            time_t now, bool in_use)
 {
+       TALLOC_CTX *ctx;
+
        fr_connection_t *this;
        void *conn;
 
@@ -366,12 +356,19 @@ static fr_connection_t *fr_connection_spawn(fr_connection_pool_t *pool,
        INFO("%s: Opening additional connection (%" PRIu64 ")", pool->log_prefix, pool->count);
 
        /*
+        *      Allocate a new top level ctx for the create callback
+        *      to hang its memory off of.
+        */
+       ctx = talloc_init("fr_connection_ctx");
+       if (!ctx) return NULL;
+
+       /*
         *      This may take a long time, which prevents other
         *      threads from releasing connections.  We don't care
         *      about other threads opening new connections, as we
         *      already have no free connections.
         */
-       conn = pool->create(pool->ctx);
+       conn = pool->create(ctx, pool->opaque);
        if (!conn) {
                ERROR("%s: Opening connection failed (%" PRIu64 ")", pool->log_prefix, pool->count);
 
@@ -391,6 +388,7 @@ static fr_connection_t *fr_connection_spawn(fr_connection_pool_t *pool,
                pthread_mutex_unlock(&pool->mutex);
                return NULL;
        }
+       fr_link_talloc_ctx_free(this, ctx);
 
        this->created = now;
        this->connection = conn;
@@ -445,7 +443,6 @@ static void fr_connection_close(fr_connection_pool_t *pool,
        if (pool->trigger) exec_trigger(NULL, pool->cs, "close", true);
 
        fr_connection_unlink(pool, this);
-       pool->delete(pool->ctx, this->connection);
        rad_assert(pool->num > 0);
        pool->num--;
        talloc_free(this);
@@ -569,19 +566,17 @@ void fr_connection_pool_delete(fr_connection_pool_t *pool)
  * @note Will call the 'start' trigger.
  *
  * @param[in] parent configuration section containing a 'pool' subsection.
- * @param[in] ctx pointer to pass to callbacks.
+ * @param[in] opaque data pointer to pass to callbacks.
  * @param[in] c Callback to create new connections.
  * @param[in] a Callback to check the status of connections.
- * @param[in] d Callback to delete connections.
  * @param[in] prefix to prepend to all log message, if NULL will create prefix
  *     from parent conf section names.
  * @return A new connection pool or NULL on error.
  */
 fr_connection_pool_t *fr_connection_pool_init(CONF_SECTION *parent,
-                                             void *ctx,
+                                             void *opaque,
                                              fr_connection_create_t c,
                                              fr_connection_alive_t a,
-                                             fr_connection_delete_t d,
                                              char const *prefix)
 {
        uint32_t i;
@@ -592,23 +587,32 @@ fr_connection_pool_t *fr_connection_pool_init(CONF_SECTION *parent,
        char const *cs_name1, *cs_name2;
        time_t now = time(NULL);
 
-       if (!parent || !ctx || !c || !d) return NULL;
+       if (!parent || !opaque || !c) return NULL;
 
        cs = cf_section_sub_find(parent, "pool");
        if (!cs) cs = cf_section_sub_find(parent, "limit");
 
-       if (cs) {
-               pool = talloc_zero(cs, fr_connection_pool_t);
-       } else {
-               pool = talloc_zero(parent, fr_connection_pool_t);
-       }
+       /*
+        *      Pool is allocated in the NULL context as
+        *      threads are likely to allocate memory
+        *      beneath the pool.
+        */
+       pool = talloc_zero(NULL, fr_connection_pool_t);
        if (!pool) return NULL;
 
+       /*
+        *      Ensure the pool is freed at the same time
+        *      as its parent.
+        */
+       if (fr_link_talloc_ctx_free(cs ? cs : parent, pool) < 0) {
+               talloc_free(pool);
+               return NULL;
+       }
+
        pool->cs = cs;
-       pool->ctx = ctx;
+       pool->opaque = opaque;
        pool->create = c;
        pool->alive = a;
-       pool->delete = d;
 
        pool->head = pool->tail = NULL;
 
@@ -1094,20 +1098,35 @@ void *fr_connection_reconnect(fr_connection_pool_t *pool, void *conn)
        void *new_conn;
        fr_connection_t *this;
        uint64_t conn_number;
+       TALLOC_CTX *ctx;
 
        if (!pool || !conn) return NULL;
 
+       /*
+        *      If fr_connection_find is successful the pool is now locked
+        */
        this = fr_connection_find(pool, conn);
        if (!this) return NULL;
 
+
+       conn_number = this->number;
+
        /*
-        *      The pool is now locked.
+        *      Destroy any handles associated with the fr_connection_t
         */
-       conn_number = this->number;
+       talloc_free_children(this);
 
        DEBUG("%s: Reconnecting (%" PRIu64 ")", pool->log_prefix, conn_number);
 
-       new_conn = pool->create(pool->ctx);
+       /*
+        *      Allocate a new top level ctx for the create callback
+        *      to hang its memory off of.
+        */
+       ctx = talloc_init("fr_connection_ctx");
+       if (!ctx) return NULL;
+       fr_link_talloc_ctx_free(this, ctx);
+
+       new_conn = pool->create(ctx, pool->opaque);
        if (!new_conn) {
                /*
                 *      We can't create a new connection, so close
@@ -1123,14 +1142,15 @@ void *fr_connection_reconnect(fr_connection_pool_t *pool, void *conn)
                new_conn = fr_connection_get_internal(pool, false);
                if (new_conn) return new_conn;
 
-               RATE_LIMIT(ERROR("%s: Failed to reconnect (%" PRIu64 "), no free connections are available", pool->log_prefix,
-                                conn_number));
+               RATE_LIMIT(ERROR("%s: Failed to reconnect (%" PRIu64 "), no free connections are available",
+                                pool->log_prefix, conn_number));
+
                return NULL;
        }
 
        if (pool->trigger) exec_trigger(NULL, pool->cs, "close", true);
-       pool->delete(pool->ctx, conn);
        this->connection = new_conn;
        pthread_mutex_unlock(&pool->mutex);
+
        return new_conn;
 }